[win32, io, wip] add win32 io impl. for open/close/seek/read/write
This commit is contained in:
parent
41b6128a35
commit
3667ab30e0
|
@ -17,6 +17,8 @@
|
||||||
#if PLATFORM_WINDOWS
|
#if PLATFORM_WINDOWS
|
||||||
#include"platform/win32_memory.c"
|
#include"platform/win32_memory.c"
|
||||||
#include"platform/win32_clock.c"
|
#include"platform/win32_clock.c"
|
||||||
|
#include"platform/win32_io.c"
|
||||||
|
#include"platform/win32_path.c"
|
||||||
//TODO
|
//TODO
|
||||||
#elif PLATFORM_MACOS
|
#elif PLATFORM_MACOS
|
||||||
#include"platform/unix_memory.c"
|
#include"platform/unix_memory.c"
|
||||||
|
|
|
@ -121,58 +121,59 @@ typedef struct io_cmp
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
//TODO: complete io queue api
|
//TODO: complete io queue api
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
io_cmp io_wait_single_req(io_req* req);
|
MP_API io_cmp io_wait_single_req(io_req* req);
|
||||||
|
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
// File IO wrapper API
|
// File IO wrapper API
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
|
|
||||||
file_handle file_open(str8 path, file_open_flags flags);
|
MP_API file_handle file_open(str8 path, file_open_flags flags);
|
||||||
file_handle file_open_relative(file_handle base, str8 path, file_open_flags flags);
|
MP_API file_handle file_open_relative(file_handle base, str8 path, file_open_flags flags);
|
||||||
void file_close(file_handle file);
|
MP_API void file_close(file_handle file);
|
||||||
|
|
||||||
i64 file_pos(file_handle file);
|
MP_API i64 file_pos(file_handle file);
|
||||||
i64 file_seek(file_handle file, long offset, file_whence whence);
|
MP_API i64 file_seek(file_handle file, i64 offset, file_whence whence);
|
||||||
|
|
||||||
u64 file_write(file_handle file, u64 size, char* buffer);
|
MP_API u64 file_write(file_handle file, u64 size, char* buffer);
|
||||||
u64 file_read(file_handle file, u64 size, char* buffer);
|
MP_API u64 file_read(file_handle file, u64 size, char* buffer);
|
||||||
|
|
||||||
io_error file_last_error(file_handle handle);
|
MP_API io_error file_last_error(file_handle handle);
|
||||||
|
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
// File System wrapper API
|
// File System wrapper API
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
|
|
||||||
typedef enum
|
typedef enum file_type
|
||||||
{
|
{
|
||||||
FILE_UNKNOWN,
|
MP_FILE_UNKNOWN,
|
||||||
FILE_REGULAR,
|
MP_FILE_REGULAR,
|
||||||
FILE_DIRECTORY,
|
MP_FILE_DIRECTORY,
|
||||||
FILE_SYMLINK,
|
MP_FILE_SYMLINK,
|
||||||
FILE_BLOCK,
|
MP_FILE_BLOCK,
|
||||||
FILE_CHARACTER,
|
MP_FILE_CHARACTER,
|
||||||
FILE_FIFO,
|
MP_FILE_FIFO,
|
||||||
FILE_SOCKET,
|
MP_FILE_SOCKET,
|
||||||
|
|
||||||
} file_type;
|
} file_type;
|
||||||
|
|
||||||
typedef u16 file_perm;
|
typedef u16 file_perm;
|
||||||
enum file_perm
|
enum file_perm
|
||||||
{
|
{
|
||||||
FILE_OTHER_EXEC = 1<<0,
|
MP_FILE_OTHER_EXEC = 1<<0,
|
||||||
FILE_OTHER_WRITE = 1<<1,
|
MP_FILE_OTHER_WRITE = 1<<1,
|
||||||
FILE_OTHER_READ = 1<<2,
|
MP_FILE_OTHER_READ = 1<<2,
|
||||||
|
|
||||||
FILE_GROUP_EXEC = 1<<3,
|
MP_FILE_GROUP_EXEC = 1<<3,
|
||||||
FILE_GROUP_WRITE = 1<<4,
|
MP_FILE_GROUP_WRITE = 1<<4,
|
||||||
FILE_GROUP_READ = 1<<5,
|
MP_FILE_GROUP_READ = 1<<5,
|
||||||
|
|
||||||
FILE_OWNER_EXEC = 1<<6,
|
MP_FILE_OWNER_EXEC = 1<<6,
|
||||||
FILE_OWNER_WRITE = 1<<7,
|
MP_FILE_OWNER_WRITE = 1<<7,
|
||||||
FILE_OWNER_READ = 1<<8,
|
MP_FILE_OWNER_READ = 1<<8,
|
||||||
|
|
||||||
FILE_STICKY_BIT = 1<<9,
|
MP_FILE_STICKY_BIT = 1<<9,
|
||||||
FILE_SET_GID = 1<<10,
|
MP_FILE_SET_GID = 1<<10,
|
||||||
FILE_SET_UID = 1<<11,
|
MP_FILE_SET_UID = 1<<11,
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct file_status
|
typedef struct file_status
|
||||||
|
@ -185,8 +186,8 @@ typedef struct file_status
|
||||||
|
|
||||||
} file_status;
|
} file_status;
|
||||||
|
|
||||||
file_status file_get_status(file_handle file);
|
MP_API file_status file_get_status(file_handle file);
|
||||||
u64 file_size(file_handle file);
|
MP_API u64 file_size(file_handle file);
|
||||||
|
|
||||||
//TODO: Complete as needed...
|
//TODO: Complete as needed...
|
||||||
|
|
||||||
|
|
|
@ -42,11 +42,11 @@ i64 file_pos(file_handle file)
|
||||||
return(cmp.offset);
|
return(cmp.offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
i64 file_seek(file_handle file, long offset, file_whence whence)
|
i64 file_seek(file_handle file, i64 offset, file_whence whence)
|
||||||
{
|
{
|
||||||
io_req req = {.op = IO_OP_SEEK,
|
io_req req = {.op = IO_OP_SEEK,
|
||||||
.handle = file,
|
.handle = file,
|
||||||
.size = offset,
|
.offset = offset,
|
||||||
.whence = whence};
|
.whence = whence};
|
||||||
|
|
||||||
io_cmp cmp = io_wait_single_req(&req);
|
io_cmp cmp = io_wait_single_req(&req);
|
||||||
|
|
|
@ -92,7 +92,7 @@ str8 path_append(mem_arena* arena, str8 parent, str8 relPath)
|
||||||
|
|
||||||
str8 path_executable_relative(mem_arena* arena, str8 relPath)
|
str8 path_executable_relative(mem_arena* arena, str8 relPath)
|
||||||
{
|
{
|
||||||
str8_list list = {};
|
str8_list list = {0};
|
||||||
mem_arena_scope scratch = mem_scratch_begin_next(arena);
|
mem_arena_scope scratch = mem_scratch_begin_next(arena);
|
||||||
|
|
||||||
str8 executablePath = path_executable(scratch.arena);
|
str8 executablePath = path_executable(scratch.arena);
|
||||||
|
|
|
@ -302,35 +302,35 @@ file_type io_convert_type_from_stat(u16 mode)
|
||||||
switch(mode & S_IFMT)
|
switch(mode & S_IFMT)
|
||||||
{
|
{
|
||||||
case S_IFIFO:
|
case S_IFIFO:
|
||||||
type = FILE_FIFO;
|
type = MP_FILE_FIFO;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case S_IFCHR:
|
case S_IFCHR:
|
||||||
type = FILE_CHARACTER;
|
type = MP_FILE_CHARACTER;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case S_IFDIR:
|
case S_IFDIR:
|
||||||
type = FILE_DIRECTORY;
|
type = MP_FILE_DIRECTORY;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case S_IFBLK:
|
case S_IFBLK:
|
||||||
type = FILE_BLOCK;
|
type = MP_FILE_BLOCK;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case S_IFREG:
|
case S_IFREG:
|
||||||
type = FILE_REGULAR;
|
type = MP_FILE_REGULAR;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case S_IFLNK:
|
case S_IFLNK:
|
||||||
type = FILE_SYMLINK;
|
type = MP_FILE_SYMLINK;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case S_IFSOCK:
|
case S_IFSOCK:
|
||||||
type = FILE_SOCKET;
|
type = MP_FILE_SOCKET;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
type = FILE_UNKNOWN;
|
type = MP_FILE_UNKNOWN;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return(type);
|
return(type);
|
||||||
|
@ -395,7 +395,7 @@ io_cmp io_seek(file_slot* slot, io_req* req)
|
||||||
case FILE_SEEK_END:
|
case FILE_SEEK_END:
|
||||||
whence = SEEK_END;
|
whence = SEEK_END;
|
||||||
}
|
}
|
||||||
cmp.result = lseek(slot->fd, req->size, whence);
|
cmp.result = lseek(slot->fd, req->offset, whence);
|
||||||
|
|
||||||
if(cmp.result < 0)
|
if(cmp.result < 0)
|
||||||
{
|
{
|
||||||
|
|
|
@ -0,0 +1,484 @@
|
||||||
|
/************************************************************//**
|
||||||
|
*
|
||||||
|
* @file: win32_io.c
|
||||||
|
* @author: Martin Fouilleul
|
||||||
|
* @date: 25/05/2023
|
||||||
|
*
|
||||||
|
*****************************************************************/
|
||||||
|
|
||||||
|
#include<errno.h>
|
||||||
|
#include<limits.h>
|
||||||
|
|
||||||
|
#include"platform_io_common.c"
|
||||||
|
|
||||||
|
typedef struct file_slot
|
||||||
|
{
|
||||||
|
u32 generation;
|
||||||
|
HANDLE h;
|
||||||
|
io_error error;
|
||||||
|
bool fatal;
|
||||||
|
list_elt freeListElt;
|
||||||
|
|
||||||
|
} file_slot;
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
ORCA_MAX_FILE_SLOTS = 256,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct file_table
|
||||||
|
{
|
||||||
|
file_slot slots[ORCA_MAX_FILE_SLOTS];
|
||||||
|
u32 nextSlot;
|
||||||
|
list_info freeList;
|
||||||
|
} file_table;
|
||||||
|
|
||||||
|
file_table __globalFileTable = {0};
|
||||||
|
|
||||||
|
file_slot* file_slot_alloc(file_table* table)
|
||||||
|
{
|
||||||
|
file_slot* slot = list_pop_entry(&table->freeList, file_slot, freeListElt);
|
||||||
|
if(!slot && table->nextSlot < ORCA_MAX_FILE_SLOTS)
|
||||||
|
{
|
||||||
|
slot = &table->slots[table->nextSlot];
|
||||||
|
slot->generation = 1;
|
||||||
|
slot->h = NULL;
|
||||||
|
table->nextSlot++;
|
||||||
|
}
|
||||||
|
return(slot);
|
||||||
|
}
|
||||||
|
|
||||||
|
void file_slot_recycle(file_table* table, file_slot* slot)
|
||||||
|
{
|
||||||
|
slot->generation++;
|
||||||
|
list_push(&table->freeList, &slot->freeListElt);
|
||||||
|
}
|
||||||
|
|
||||||
|
file_handle file_handle_from_slot(file_table* table, file_slot* slot)
|
||||||
|
{
|
||||||
|
u64 index = slot - table->slots;
|
||||||
|
u64 generation = slot->generation;
|
||||||
|
file_handle handle = {.h = (generation<<32) | index };
|
||||||
|
return(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
file_slot* file_slot_from_handle(file_table* table, file_handle handle)
|
||||||
|
{
|
||||||
|
file_slot* slot = 0;
|
||||||
|
|
||||||
|
u64 index = handle.h & 0xffffffff;
|
||||||
|
u64 generation = handle.h>>32;
|
||||||
|
|
||||||
|
if(index < table->nextSlot)
|
||||||
|
{
|
||||||
|
file_slot* candidate = &table->slots[index];
|
||||||
|
if(candidate->generation == generation)
|
||||||
|
{
|
||||||
|
slot = candidate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return(slot);
|
||||||
|
}
|
||||||
|
|
||||||
|
io_error io_convert_win32_error(int winError)
|
||||||
|
{
|
||||||
|
io_error error = 0;
|
||||||
|
switch(winError)
|
||||||
|
{
|
||||||
|
case ERROR_SUCCESS:
|
||||||
|
error = IO_OK;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ERROR_ACCESS_DENIED:
|
||||||
|
error = IO_ERR_PERM;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ERROR_FILE_NOT_FOUND:
|
||||||
|
case ERROR_PATH_NOT_FOUND:
|
||||||
|
case ERROR_INVALID_DRIVE:
|
||||||
|
case ERROR_DIRECTORY:
|
||||||
|
error = IO_ERR_NO_ENTRY;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ERROR_TOO_MANY_OPEN_FILES:
|
||||||
|
error = IO_ERR_MAX_FILES;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ERROR_NOT_ENOUGH_MEMORY:
|
||||||
|
case ERROR_OUTOFMEMORY:
|
||||||
|
error = IO_ERR_MEM;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ERROR_DEV_NOT_EXIST:
|
||||||
|
error = IO_ERR_NO_DEVICE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ERROR_FILE_EXISTS:
|
||||||
|
case ERROR_ALREADY_EXISTS:
|
||||||
|
error = IO_ERR_EXISTS;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ERROR_BUFFER_OVERFLOW:
|
||||||
|
case ERROR_FILENAME_EXCED_RANGE:
|
||||||
|
error = IO_ERR_PATH_LENGTH;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ERROR_FILE_TOO_LARGE:
|
||||||
|
error = IO_ERR_FILE_SIZE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
//TODO: complete
|
||||||
|
|
||||||
|
default:
|
||||||
|
error = IO_ERR_UNKNOWN;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
io_cmp io_open_at(file_slot* atSlot, io_req* req)
|
||||||
|
{
|
||||||
|
io_cmp cmp = {0};
|
||||||
|
|
||||||
|
file_slot* slot = file_slot_alloc(&__globalFileTable);
|
||||||
|
if(!slot)
|
||||||
|
{
|
||||||
|
cmp.error = IO_ERR_MAX_FILES;
|
||||||
|
cmp.result = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cmp.handle = file_handle_from_slot(&__globalFileTable, slot);
|
||||||
|
|
||||||
|
//NOTE: open
|
||||||
|
mem_arena_scope scratch = mem_scratch_begin();
|
||||||
|
|
||||||
|
int sizeWide = 1 + MultiByteToWideChar(CP_UTF8, 0, req->buffer, req->size, NULL, 0);
|
||||||
|
LPWSTR pathWide = mem_arena_alloc_array(scratch.arena, wchar_t, sizeWide);
|
||||||
|
MultiByteToWideChar(CP_UTF8, 0, req->buffer, req->size, pathWide, sizeWide);
|
||||||
|
pathWide[sizeWide-1] = '\0';
|
||||||
|
|
||||||
|
DWORD accessFlags = 0;
|
||||||
|
DWORD createFlags = 0;
|
||||||
|
DWORD attributesFlags = FILE_ATTRIBUTE_NORMAL;
|
||||||
|
|
||||||
|
if(req->openFlags & FILE_OPEN_READ)
|
||||||
|
{
|
||||||
|
accessFlags |= GENERIC_READ;
|
||||||
|
}
|
||||||
|
if(req->openFlags & FILE_OPEN_WRITE)
|
||||||
|
{
|
||||||
|
if(req->openFlags & FILE_OPEN_APPEND)
|
||||||
|
{
|
||||||
|
accessFlags |= FILE_APPEND_DATA;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
accessFlags |= GENERIC_WRITE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(req->openFlags & FILE_OPEN_TRUNCATE)
|
||||||
|
{
|
||||||
|
if(req->openFlags & FILE_OPEN_CREATE)
|
||||||
|
{
|
||||||
|
createFlags |= CREATE_ALWAYS;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
createFlags |= TRUNCATE_EXISTING;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(req->openFlags & FILE_OPEN_CREATE)
|
||||||
|
{
|
||||||
|
if(!createFlags & CREATE_ALWAYS)
|
||||||
|
{
|
||||||
|
createFlags |= OPEN_ALWAYS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if( !(createFlags & OPEN_ALWAYS)
|
||||||
|
&& !(createFlags & CREATE_ALWAYS)
|
||||||
|
&& !(createFlags & TRUNCATE_EXISTING))
|
||||||
|
{
|
||||||
|
createFlags |= OPEN_EXISTING;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(req->openFlags & FILE_OPEN_SYMLINK)
|
||||||
|
{
|
||||||
|
attributesFlags |= FILE_FLAG_OPEN_REPARSE_POINT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(req->openFlags & FILE_OPEN_RESTRICT)
|
||||||
|
{
|
||||||
|
//TODO: if FILE_OPEN_RESTRICT, do the file traversal to check that path is in the
|
||||||
|
// subtree rooted at atSlot->fd
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: open at
|
||||||
|
|
||||||
|
//TODO: take care of share mode and security attributes, make it consistent with posix impl
|
||||||
|
slot->h = CreateFileW(pathWide, accessFlags, 0, NULL, createFlags, attributesFlags, NULL);
|
||||||
|
|
||||||
|
mem_scratch_end(scratch);
|
||||||
|
|
||||||
|
if(slot->h == INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
slot->fatal = true;
|
||||||
|
slot->error = io_convert_win32_error(GetLastError());
|
||||||
|
}
|
||||||
|
cmp.error = slot->error;
|
||||||
|
}
|
||||||
|
|
||||||
|
return(cmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
io_cmp io_close(file_slot* slot, io_req* req)
|
||||||
|
{
|
||||||
|
io_cmp cmp = {0};
|
||||||
|
if(slot->h)
|
||||||
|
{
|
||||||
|
CloseHandle(slot->h);
|
||||||
|
}
|
||||||
|
file_slot_recycle(&__globalFileTable, slot);
|
||||||
|
return(cmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
file_perm io_convert_perm_from_stat(u16 mode)
|
||||||
|
{
|
||||||
|
file_perm perm = mode & 07777;
|
||||||
|
return(perm);
|
||||||
|
}
|
||||||
|
|
||||||
|
file_type io_convert_type_from_stat(u16 mode)
|
||||||
|
{
|
||||||
|
file_type type;
|
||||||
|
switch(mode & S_IFMT)
|
||||||
|
{
|
||||||
|
case S_IFIFO:
|
||||||
|
type = FILE_FIFO;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case S_IFCHR:
|
||||||
|
type = FILE_CHARACTER;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case S_IFDIR:
|
||||||
|
type = FILE_DIRECTORY;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case S_IFBLK:
|
||||||
|
type = FILE_BLOCK;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case S_IFREG:
|
||||||
|
type = FILE_REGULAR;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case S_IFLNK:
|
||||||
|
type = FILE_SYMLINK;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case S_IFSOCK:
|
||||||
|
type = FILE_SOCKET;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
type = FILE_UNKNOWN;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
io_cmp io_fstat(file_slot* slot, io_req* req)
|
||||||
|
{
|
||||||
|
io_cmp cmp = {0};
|
||||||
|
|
||||||
|
if(req->size < sizeof(file_status))
|
||||||
|
{
|
||||||
|
cmp.error = IO_ERR_ARG;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
struct stat s;
|
||||||
|
if(fstat(slot->fd, &s))
|
||||||
|
{
|
||||||
|
slot->error = io_convert_errno(errno);
|
||||||
|
cmp.error = slot->error;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
file_status* status = (file_status*)req->buffer;
|
||||||
|
status->perm = io_convert_perm_from_stat(s.st_mode);
|
||||||
|
status->type = io_convert_type_from_stat(s.st_mode);
|
||||||
|
status->size = s.st_size;
|
||||||
|
//TODO: times
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return(cmp);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
io_cmp io_pos(file_slot* slot, io_req* req)
|
||||||
|
{
|
||||||
|
io_cmp cmp = {0};
|
||||||
|
LARGE_INTEGER off = {.QuadPart = req->offset};
|
||||||
|
LARGE_INTEGER newPos = {0};
|
||||||
|
|
||||||
|
if(!SetFilePointerEx(slot->h, off, &newPos, FILE_CURRENT))
|
||||||
|
{
|
||||||
|
slot->error = io_convert_win32_error(GetLastError());
|
||||||
|
cmp.error = slot->error;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cmp.result = newPos.QuadPart;
|
||||||
|
}
|
||||||
|
return(cmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
io_cmp io_seek(file_slot* slot, io_req* req)
|
||||||
|
{
|
||||||
|
io_cmp cmp = {0};
|
||||||
|
|
||||||
|
DWORD whence;
|
||||||
|
switch(req->whence)
|
||||||
|
{
|
||||||
|
case FILE_SEEK_CURRENT:
|
||||||
|
whence = FILE_CURRENT;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FILE_SEEK_SET:
|
||||||
|
whence = FILE_BEGIN;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FILE_SEEK_END:
|
||||||
|
whence = FILE_END;
|
||||||
|
}
|
||||||
|
|
||||||
|
LARGE_INTEGER off = {.QuadPart = req->offset};
|
||||||
|
LARGE_INTEGER newPos = {0};
|
||||||
|
|
||||||
|
if(!SetFilePointerEx(slot->h, off, &newPos, whence))
|
||||||
|
{
|
||||||
|
slot->error = io_convert_win32_error(GetLastError());
|
||||||
|
cmp.error = slot->error;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cmp.result = newPos.QuadPart;
|
||||||
|
}
|
||||||
|
|
||||||
|
return(cmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
io_cmp io_read(file_slot* slot, io_req* req)
|
||||||
|
{
|
||||||
|
io_cmp cmp = {0};
|
||||||
|
|
||||||
|
DWORD bytesRead = 0;
|
||||||
|
|
||||||
|
if(!ReadFile(slot->h, req->buffer, req->size, &bytesRead, NULL))
|
||||||
|
{
|
||||||
|
cmp.result = -1;
|
||||||
|
slot->error = io_convert_win32_error(GetLastError());
|
||||||
|
cmp.error = slot->error;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cmp.result = bytesRead;
|
||||||
|
}
|
||||||
|
return(cmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
io_cmp io_write(file_slot* slot, io_req* req)
|
||||||
|
{
|
||||||
|
io_cmp cmp = {0};
|
||||||
|
|
||||||
|
DWORD bytesWritten = 0;
|
||||||
|
|
||||||
|
if(!WriteFile(slot->h, req->buffer, req->size, &bytesWritten, NULL))
|
||||||
|
{
|
||||||
|
cmp.result = -1;
|
||||||
|
slot->error = io_convert_win32_error(GetLastError());
|
||||||
|
cmp.error = slot->error;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cmp.result = bytesWritten;
|
||||||
|
}
|
||||||
|
|
||||||
|
return(cmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
io_cmp io_get_error(file_slot* slot, io_req* req)
|
||||||
|
{
|
||||||
|
io_cmp cmp = {0};
|
||||||
|
cmp.result = slot->error;
|
||||||
|
return(cmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
io_cmp io_wait_single_req(io_req* req)
|
||||||
|
{
|
||||||
|
io_cmp cmp = {0};
|
||||||
|
|
||||||
|
file_slot* slot = file_slot_from_handle(&__globalFileTable, req->handle);
|
||||||
|
if(!slot)
|
||||||
|
{
|
||||||
|
if(req->op != IO_OP_OPEN_AT)
|
||||||
|
{
|
||||||
|
cmp.error = IO_ERR_HANDLE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(slot->fatal && req->op != IO_OP_CLOSE)
|
||||||
|
{
|
||||||
|
cmp.error = IO_ERR_PREV;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(cmp.error == IO_OK)
|
||||||
|
{
|
||||||
|
switch(req->op)
|
||||||
|
{
|
||||||
|
case IO_OP_OPEN_AT:
|
||||||
|
cmp = io_open_at(slot, req);
|
||||||
|
break;
|
||||||
|
/*
|
||||||
|
case IO_OP_FSTAT:
|
||||||
|
cmp = io_fstat(slot, req);
|
||||||
|
break;
|
||||||
|
*/
|
||||||
|
case IO_OP_CLOSE:
|
||||||
|
cmp = io_close(slot, req);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IO_OP_READ:
|
||||||
|
cmp = io_read(slot, req);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IO_OP_WRITE:
|
||||||
|
cmp = io_write(slot, req);
|
||||||
|
break;
|
||||||
|
/*
|
||||||
|
case IO_OP_POS:
|
||||||
|
cmp = io_pos(slot, req);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IO_OP_SEEK:
|
||||||
|
cmp = io_seek(slot, req);
|
||||||
|
break;
|
||||||
|
*/
|
||||||
|
case IO_OP_ERROR:
|
||||||
|
cmp = io_get_error(slot, req);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
cmp.error = IO_ERR_OP;
|
||||||
|
if(slot)
|
||||||
|
{
|
||||||
|
slot->error = cmp.error;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return(cmp);
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
/************************************************************//**
|
||||||
|
*
|
||||||
|
* @file: win32_path.c
|
||||||
|
* @author: Martin Fouilleul
|
||||||
|
* @date: 24/05/2023
|
||||||
|
*
|
||||||
|
*****************************************************************/
|
||||||
|
|
||||||
|
#include"platform_path.c"
|
||||||
|
|
||||||
|
str8 path_executable(mem_arena* arena)
|
||||||
|
{
|
||||||
|
//TODO use wide chars
|
||||||
|
char* buffer = mem_arena_alloc_array(arena, char, MAX_PATH+1);
|
||||||
|
int size = GetModuleFileName(NULL, buffer, MAX_PATH+1);
|
||||||
|
//TODO: check for errors...
|
||||||
|
for(int i=0; i<size; i++)
|
||||||
|
{
|
||||||
|
if(buffer[i] == '\\')
|
||||||
|
{
|
||||||
|
buffer[i] = '/';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return(str8_from_buffer(size, buffer));
|
||||||
|
}
|
||||||
|
|
||||||
|
str8 path_canonical(mem_arena* arena, str8 path); //TODO
|
|
@ -1036,51 +1036,6 @@ mg_surface_data* mg_win32_surface_create_host(mp_window window)
|
||||||
return(surface);
|
return(surface);
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////// WIP ///////////////////////////////////////////////
|
|
||||||
//TODO: this is thrown here for a quick test. We should:
|
|
||||||
// - check for errors
|
|
||||||
// - use utf8 version of API
|
|
||||||
str8 mp_app_get_executable_path(mem_arena* arena)
|
|
||||||
{
|
|
||||||
char* buffer = mem_arena_alloc_array(arena, char, MAX_PATH+1);
|
|
||||||
int size = GetModuleFileName(NULL, buffer, MAX_PATH+1);
|
|
||||||
//TODO: check for errors...
|
|
||||||
|
|
||||||
return(str8_from_buffer(size, buffer));
|
|
||||||
}
|
|
||||||
|
|
||||||
str8 mp_app_get_resource_path(mem_arena* arena, const char* name)
|
|
||||||
{
|
|
||||||
str8_list list = {0};
|
|
||||||
mem_arena* scratch = mem_scratch();
|
|
||||||
|
|
||||||
str8 executablePath = mp_app_get_executable_path(scratch);
|
|
||||||
char* executablePathCString = str8_to_cstring(scratch, executablePath);
|
|
||||||
|
|
||||||
char* driveBuffer = mem_arena_alloc_array(scratch, char, MAX_PATH);
|
|
||||||
char* dirBuffer = mem_arena_alloc_array(scratch, char, MAX_PATH);
|
|
||||||
|
|
||||||
_splitpath_s(executablePathCString, driveBuffer, MAX_PATH, dirBuffer, MAX_PATH, 0, 0, 0, 0);
|
|
||||||
|
|
||||||
str8 drive = STR8(driveBuffer);
|
|
||||||
str8 dirPath = STR8(dirBuffer);
|
|
||||||
|
|
||||||
str8_list_push(scratch, &list, drive);
|
|
||||||
str8_list_push(scratch, &list, dirPath);
|
|
||||||
str8_list_push(scratch, &list, STR8("\\"));
|
|
||||||
str8_list_push(scratch, &list, str8_push_cstring(scratch, name));
|
|
||||||
str8 path = str8_list_join(scratch, list);
|
|
||||||
char* pathCString = str8_to_cstring(scratch, path);
|
|
||||||
|
|
||||||
char* buffer = mem_arena_alloc_array(arena, char, path.len+1);
|
|
||||||
char* filePart = 0;
|
|
||||||
int size = GetFullPathName(pathCString, MAX_PATH, buffer, &filePart);
|
|
||||||
|
|
||||||
str8 result = str8_from_buffer(size, buffer);
|
|
||||||
return(result);
|
|
||||||
}
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------
|
//--------------------------------------------------------------------
|
||||||
// native open/save/alert windows
|
// native open/save/alert windows
|
||||||
//--------------------------------------------------------------------
|
//--------------------------------------------------------------------
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
|
||||||
|
set INCLUDES=/I ..\..\src /I ..\..\src\util /I ..\..\src\platform /I ../../ext
|
||||||
|
|
||||||
|
cl /we4013 /Zi /Zc:preprocessor /std:c11 %INCLUDES% main.c /link /LIBPATH:../../bin milepost.dll.lib /out:../../bin/test_files.exe
|
|
@ -115,7 +115,7 @@ int test_stat_type(mem_arena* arena, str8 dataDir)
|
||||||
log_error("Error while retrieving file status\n");
|
log_error("Error while retrieving file status\n");
|
||||||
return(-1);
|
return(-1);
|
||||||
}
|
}
|
||||||
if(status.type != FILE_REGULAR)
|
if(status.type != MP_FILE_REGULAR)
|
||||||
{
|
{
|
||||||
log_error("file type doesn't match\n");
|
log_error("file type doesn't match\n");
|
||||||
return(-1);
|
return(-1);
|
||||||
|
@ -131,7 +131,7 @@ int test_stat_type(mem_arena* arena, str8 dataDir)
|
||||||
log_error("Error while retrieving file status\n");
|
log_error("Error while retrieving file status\n");
|
||||||
return(-1);
|
return(-1);
|
||||||
}
|
}
|
||||||
if(status.type != FILE_DIRECTORY)
|
if(status.type != MP_FILE_DIRECTORY)
|
||||||
{
|
{
|
||||||
log_error("file type doesn't match\n");
|
log_error("file type doesn't match\n");
|
||||||
return(-1);
|
return(-1);
|
||||||
|
@ -147,7 +147,7 @@ int test_stat_type(mem_arena* arena, str8 dataDir)
|
||||||
log_error("Error while retrieving file status\n");
|
log_error("Error while retrieving file status\n");
|
||||||
return(-1);
|
return(-1);
|
||||||
}
|
}
|
||||||
if(status.type != FILE_SYMLINK)
|
if(status.type != MP_FILE_SYMLINK)
|
||||||
{
|
{
|
||||||
log_error("file type doesn't match\n");
|
log_error("file type doesn't match\n");
|
||||||
return(-1);
|
return(-1);
|
||||||
|
|
Loading…
Reference in New Issue