[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 | ||||
| 	#include"platform/win32_memory.c" | ||||
| 	#include"platform/win32_clock.c" | ||||
| 	#include"platform/win32_io.c" | ||||
| 	#include"platform/win32_path.c" | ||||
| 	//TODO
 | ||||
| #elif PLATFORM_MACOS | ||||
| 	#include"platform/unix_memory.c" | ||||
|  |  | |||
|  | @ -121,58 +121,59 @@ typedef struct io_cmp | |||
| //----------------------------------------------------------------
 | ||||
| //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_handle file_open(str8 path, file_open_flags flags); | ||||
| file_handle file_open_relative(file_handle base, str8 path, file_open_flags flags); | ||||
| void file_close(file_handle file); | ||||
| MP_API file_handle file_open(str8 path, file_open_flags flags); | ||||
| MP_API file_handle file_open_relative(file_handle base, str8 path, file_open_flags flags); | ||||
| MP_API void file_close(file_handle file); | ||||
| 
 | ||||
| i64 file_pos(file_handle file); | ||||
| i64 file_seek(file_handle file, long offset, file_whence whence); | ||||
| MP_API i64 file_pos(file_handle file); | ||||
| MP_API i64 file_seek(file_handle file, i64 offset, file_whence whence); | ||||
| 
 | ||||
| u64 file_write(file_handle file, u64 size, char* buffer); | ||||
| u64 file_read(file_handle file, u64 size, char* buffer); | ||||
| MP_API u64 file_write(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
 | ||||
| //----------------------------------------------------------------
 | ||||
| 
 | ||||
| typedef enum | ||||
| typedef enum file_type | ||||
| { | ||||
| 	FILE_UNKNOWN, | ||||
| 	FILE_REGULAR, | ||||
| 	FILE_DIRECTORY, | ||||
| 	FILE_SYMLINK, | ||||
| 	FILE_BLOCK, | ||||
| 	FILE_CHARACTER, | ||||
| 	FILE_FIFO, | ||||
| 	FILE_SOCKET, | ||||
| 	MP_FILE_UNKNOWN, | ||||
| 	MP_FILE_REGULAR, | ||||
| 	MP_FILE_DIRECTORY, | ||||
| 	MP_FILE_SYMLINK, | ||||
| 	MP_FILE_BLOCK, | ||||
| 	MP_FILE_CHARACTER, | ||||
| 	MP_FILE_FIFO, | ||||
| 	MP_FILE_SOCKET, | ||||
| 
 | ||||
| } file_type; | ||||
| 
 | ||||
| typedef u16 file_perm; | ||||
| enum file_perm | ||||
| { | ||||
| 	FILE_OTHER_EXEC  = 1<<0, | ||||
| 	FILE_OTHER_WRITE = 1<<1, | ||||
| 	FILE_OTHER_READ  = 1<<2, | ||||
| 	MP_FILE_OTHER_EXEC  = 1<<0, | ||||
| 	MP_FILE_OTHER_WRITE = 1<<1, | ||||
| 	MP_FILE_OTHER_READ  = 1<<2, | ||||
| 
 | ||||
| 	FILE_GROUP_EXEC  = 1<<3, | ||||
| 	FILE_GROUP_WRITE = 1<<4, | ||||
| 	FILE_GROUP_READ  = 1<<5, | ||||
| 	MP_FILE_GROUP_EXEC  = 1<<3, | ||||
| 	MP_FILE_GROUP_WRITE = 1<<4, | ||||
| 	MP_FILE_GROUP_READ  = 1<<5, | ||||
| 
 | ||||
| 	FILE_OWNER_EXEC  = 1<<6, | ||||
| 	FILE_OWNER_WRITE = 1<<7, | ||||
| 	FILE_OWNER_READ  = 1<<8, | ||||
| 	MP_FILE_OWNER_EXEC  = 1<<6, | ||||
| 	MP_FILE_OWNER_WRITE = 1<<7, | ||||
| 	MP_FILE_OWNER_READ  = 1<<8, | ||||
| 
 | ||||
| 	FILE_STICKY_BIT  = 1<<9, | ||||
| 	FILE_SET_GID     = 1<<10, | ||||
| 	FILE_SET_UID     = 1<<11, | ||||
| 	MP_FILE_STICKY_BIT  = 1<<9, | ||||
| 	MP_FILE_SET_GID     = 1<<10, | ||||
| 	MP_FILE_SET_UID     = 1<<11, | ||||
| }; | ||||
| 
 | ||||
| typedef struct file_status | ||||
|  | @ -185,8 +186,8 @@ typedef struct file_status | |||
| 
 | ||||
| } file_status; | ||||
| 
 | ||||
| file_status file_get_status(file_handle file); | ||||
| u64 file_size(file_handle file); | ||||
| MP_API file_status file_get_status(file_handle file); | ||||
| MP_API u64 file_size(file_handle file); | ||||
| 
 | ||||
| //TODO: Complete as needed...
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -42,11 +42,11 @@ i64 file_pos(file_handle file) | |||
| 	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, | ||||
| 	              .handle = file, | ||||
| 	              .size = offset, | ||||
| 	              .offset = offset, | ||||
| 	              .whence = whence}; | ||||
| 
 | ||||
| 	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_list list = {}; | ||||
| 	str8_list list = {0}; | ||||
| 	mem_arena_scope scratch = mem_scratch_begin_next(arena); | ||||
| 
 | ||||
| 	str8 executablePath = path_executable(scratch.arena); | ||||
|  |  | |||
|  | @ -302,35 +302,35 @@ file_type io_convert_type_from_stat(u16 mode) | |||
| 	switch(mode & S_IFMT) | ||||
| 	{ | ||||
| 		case S_IFIFO: | ||||
| 			type = FILE_FIFO; | ||||
| 			type = MP_FILE_FIFO; | ||||
| 			break; | ||||
| 
 | ||||
| 		case S_IFCHR: | ||||
| 			type = FILE_CHARACTER; | ||||
| 			type = MP_FILE_CHARACTER; | ||||
| 			break; | ||||
| 
 | ||||
| 		case S_IFDIR: | ||||
| 			type = FILE_DIRECTORY; | ||||
| 			type = MP_FILE_DIRECTORY; | ||||
| 			break; | ||||
| 
 | ||||
| 		case S_IFBLK: | ||||
| 			type = FILE_BLOCK; | ||||
| 			type = MP_FILE_BLOCK; | ||||
| 			break; | ||||
| 
 | ||||
| 		case S_IFREG: | ||||
| 			type = FILE_REGULAR; | ||||
| 			type = MP_FILE_REGULAR; | ||||
| 			break; | ||||
| 
 | ||||
| 		case S_IFLNK: | ||||
| 			type = FILE_SYMLINK; | ||||
| 			type = MP_FILE_SYMLINK; | ||||
| 			break; | ||||
| 
 | ||||
| 		case S_IFSOCK: | ||||
| 			type = FILE_SOCKET; | ||||
| 			type = MP_FILE_SOCKET; | ||||
| 			break; | ||||
| 
 | ||||
| 		default: | ||||
| 			type = FILE_UNKNOWN; | ||||
| 			type = MP_FILE_UNKNOWN; | ||||
| 			break; | ||||
| 	} | ||||
| 	return(type); | ||||
|  | @ -395,7 +395,7 @@ io_cmp io_seek(file_slot* slot, io_req* req) | |||
| 		case FILE_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) | ||||
| 	{ | ||||
|  |  | |||
|  | @ -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); | ||||
| } | ||||
| 
 | ||||
| /////////////////////////////////////////// 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
 | ||||
| //--------------------------------------------------------------------
 | ||||
|  |  | |||
|  | @ -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"); | ||||
| 		return(-1); | ||||
| 	} | ||||
| 	if(status.type != FILE_REGULAR) | ||||
| 	if(status.type != MP_FILE_REGULAR) | ||||
| 	{ | ||||
| 		log_error("file type doesn't match\n"); | ||||
| 		return(-1); | ||||
|  | @ -131,7 +131,7 @@ int test_stat_type(mem_arena* arena, str8 dataDir) | |||
| 		log_error("Error while retrieving file status\n"); | ||||
| 		return(-1); | ||||
| 	} | ||||
| 	if(status.type != FILE_DIRECTORY) | ||||
| 	if(status.type != MP_FILE_DIRECTORY) | ||||
| 	{ | ||||
| 		log_error("file type doesn't match\n"); | ||||
| 		return(-1); | ||||
|  | @ -147,7 +147,7 @@ int test_stat_type(mem_arena* arena, str8 dataDir) | |||
| 		log_error("Error while retrieving file status\n"); | ||||
| 		return(-1); | ||||
| 	} | ||||
| 	if(status.type != FILE_SYMLINK) | ||||
| 	if(status.type != MP_FILE_SYMLINK) | ||||
| 	{ | ||||
| 		log_error("file type doesn't match\n"); | ||||
| 		return(-1); | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue