diff --git a/examples/atlas/main.c b/examples/atlas/main.c index 093a401..5038276 100644 --- a/examples/atlas/main.c +++ b/examples/atlas/main.c @@ -48,8 +48,8 @@ int main() mg_rect_atlas* atlas = mg_rect_atlas_create(&permanentArena, 16000, 16000); mg_image atlasImage = mg_image_create(16000, 16000); - str8 path1 = path_find_resource(mem_scratch(), STR8("../resources/triceratops.png")); - str8 path2 = path_find_resource(mem_scratch(), STR8("../resources/Top512.png")); + str8 path1 = path_executable_relative(mem_scratch(), STR8("../resources/triceratops.png")); + str8 path2 = path_executable_relative(mem_scratch(), STR8("../resources/Top512.png")); mg_image_region image1 = mg_image_atlas_alloc_from_file(atlas, atlasImage, path1, false); mg_image_region image2 = mg_image_atlas_alloc_from_file(atlas, atlasImage, path2, false); diff --git a/examples/canvas/main.c b/examples/canvas/main.c index 8013ecf..a0cbf81 100644 --- a/examples/canvas/main.c +++ b/examples/canvas/main.c @@ -22,7 +22,7 @@ mg_font create_font() { //NOTE(martin): create font - str8 fontPath = path_find_resource(mem_scratch(), STR8("../resources/OpenSansLatinSubset.ttf")); + str8 fontPath = path_executable_relative(mem_scratch(), STR8("../resources/OpenSansLatinSubset.ttf")); char* fontPathCString = str8_to_cstring(mem_scratch(), fontPath); FILE* fontFile = fopen(fontPathCString, "r"); diff --git a/examples/image/main.c b/examples/image/main.c index 28c2ccb..e54af88 100644 --- a/examples/image/main.c +++ b/examples/image/main.c @@ -38,11 +38,11 @@ int main() } //NOTE: create image - str8 imagePath = path_find_resource(mem_scratch(), STR8("../resources/triceratops.png")); + str8 imagePath = path_executable_relative(mem_scratch(), STR8("../resources/triceratops.png")); mg_image image = mg_image_create_from_file(surface, imagePath, false); vec2 imageSize = mg_image_size(image); - str8 imagePath2 = path_find_resource(mem_scratch(), STR8("../resources/Top512.png")); + str8 imagePath2 = path_executable_relative(mem_scratch(), STR8("../resources/Top512.png")); mg_image image2 = mg_image_create_from_file(surface, imagePath2, false); vec2 imageSize2 = mg_image_size(image2); diff --git a/examples/perf_text/main.c b/examples/perf_text/main.c index 98f31cf..af63a14 100644 --- a/examples/perf_text/main.c +++ b/examples/perf_text/main.c @@ -63,7 +63,7 @@ static const char* TEST_STRING = mg_font create_font(const char* path) { //NOTE(martin): create font - str8 fontPath = path_find_resource(mem_scratch(), STR8(path)); + str8 fontPath = path_executable_relative(mem_scratch(), STR8(path)); char* fontPathCString = str8_to_cstring(mem_scratch(), fontPath); FILE* fontFile = fopen(fontPathCString, "r"); diff --git a/examples/smooth_resize/main.c b/examples/smooth_resize/main.c index 4ebe7f5..645828d 100644 --- a/examples/smooth_resize/main.c +++ b/examples/smooth_resize/main.c @@ -23,7 +23,7 @@ mg_font create_font() { //NOTE(martin): create font - str8 fontPath = path_find_resource(mem_scratch(), STR8("../resources/OpenSansLatinSubset.ttf")); + str8 fontPath = path_executable_relative(mem_scratch(), STR8("../resources/OpenSansLatinSubset.ttf")); char* fontPathCString = str8_to_cstring(mem_scratch(), fontPath); FILE* fontFile = fopen(fontPathCString, "r"); diff --git a/examples/tiger/main.c b/examples/tiger/main.c index 226b2d7..ea51073 100644 --- a/examples/tiger/main.c +++ b/examples/tiger/main.c @@ -21,7 +21,7 @@ mg_font create_font() { //NOTE(martin): create font - str8 fontPath = path_find_resource(mem_scratch(), STR8("../resources/OpenSansLatinSubset.ttf")); + str8 fontPath = path_executable_relative(mem_scratch(), STR8("../resources/OpenSansLatinSubset.ttf")); char* fontPathCString = str8_to_cstring(mem_scratch(), fontPath); FILE* fontFile = fopen(fontPathCString, "r"); diff --git a/examples/triangleMetal/main.m b/examples/triangleMetal/main.m index b8a2142..4000c6f 100644 --- a/examples/triangleMetal/main.m +++ b/examples/triangleMetal/main.m @@ -41,7 +41,7 @@ int main() //NOTE(martin): load the library id device = MTLCreateSystemDefaultDevice(); - str8 shaderPath = path_find_resource(mem_scratch(), STR8("triangle_shader.metallib")); + str8 shaderPath = path_executable_relative(mem_scratch(), STR8("triangle_shader.metallib")); const char* shaderPathCString = str8_to_cstring(mem_scratch(), shaderPath); NSString* metalFileName = [[NSString alloc] initWithCString: shaderPathCString encoding: NSUTF8StringEncoding]; NSError* err = 0; diff --git a/examples/ui/main.c b/examples/ui/main.c index 7234b8e..d743057 100644 --- a/examples/ui/main.c +++ b/examples/ui/main.c @@ -152,7 +152,7 @@ void debug_print_styles(ui_box* box, int indent) mg_font create_font() { //NOTE(martin): create font - str8 fontPath = path_find_resource(mem_scratch(), STR8("../resources/OpenSansLatinSubset.ttf")); + str8 fontPath = path_executable_relative(mem_scratch(), STR8("../resources/OpenSansLatinSubset.ttf")); char* fontPathCString = str8_to_cstring(mem_scratch(), fontPath); FILE* fontFile = fopen(fontPathCString, "r"); diff --git a/src/milepost.c b/src/milepost.c index bd72332..78de00c 100644 --- a/src/milepost.c +++ b/src/milepost.c @@ -21,6 +21,7 @@ #elif PLATFORM_MACOS #include"platform/unix_memory.c" #include"platform/osx_clock.c" + #include"platform/posix_io.c" /* #include"platform/unix_rng.c" #include"platform/posix_thread.c" @@ -30,6 +31,7 @@ #elif PLATFORM_LINUX #include"platform/unix_base_memory.c" #include"platform/linux_clock.c" + #include"platform/posix_io.c" /* #include"platform/unix_rng.c" #include"platform/posix_thread.c" diff --git a/src/milepost.h b/src/milepost.h index cc77276..82ad415 100644 --- a/src/milepost.h +++ b/src/milepost.h @@ -25,8 +25,9 @@ //---------------------------------------------------------------- // platform layer //---------------------------------------------------------------- -#include"platform_path.h" #include"platform_clock.h" +#include"platform_path.h" +#include"platform_io.h" /* #include"platform_rng.h" #include"platform_socket.h" diff --git a/src/mtl_renderer.m b/src/mtl_renderer.m index 0546342..460d7dd 100644 --- a/src/mtl_renderer.m +++ b/src/mtl_renderer.m @@ -1329,7 +1329,7 @@ mg_canvas_backend* mtl_canvas_backend_create(mg_mtl_surface* surface) @autoreleasepool{ //NOTE: load metal library - str8 shaderPath = path_find_resource(mem_scratch(), STR8("mtl_renderer.metallib")); + str8 shaderPath = path_executable_relative(mem_scratch(), STR8("mtl_renderer.metallib")); NSString* metalFileName = [[NSString alloc] initWithBytes: shaderPath.ptr length:shaderPath.len encoding: NSUTF8StringEncoding]; NSError* err = 0; id library = [surface->device newLibraryWithFile: metalFileName error:&err]; diff --git a/src/platform/osx_path.m b/src/platform/osx_path.m index 6973d94..519ae98 100644 --- a/src/platform/osx_path.m +++ b/src/platform/osx_path.m @@ -12,7 +12,7 @@ #include"platform_path.c" -str8 path_find_executable(mem_arena* arena) +str8 path_executable(mem_arena* arena) {@autoreleasepool{ str8 result = {}; u32 size = 0; @@ -23,32 +23,7 @@ str8 path_find_executable(mem_arena* arena) return(result); }} -str8 path_find_resource(mem_arena* arena, str8 relPath) -{ - str8_list list = {}; - mem_arena_scope scratch = mem_scratch_begin_next(arena); - - str8 executablePath = path_find_executable(scratch.arena); - str8 dirPath = path_slice_directory(executablePath); - - str8_list_push(scratch.arena, &list, dirPath); - str8_list_push(scratch.arena, &list, STR8("/")); - str8_list_push(scratch.arena, &list, relPath); - str8 path = str8_list_join(scratch.arena, list); - char* pathCString = str8_to_cstring(scratch.arena, path); - - char* real = realpath(pathCString, 0); - - str8 result = str8_push_cstring(arena, real); - - free(real); - - mem_scratch_end(scratch); - - return(result); -} - -str8 path_find_canonical(mem_arena* arena, str8 path) +str8 path_canonical(mem_arena* arena, str8 path) { mem_arena_scope scratch = mem_scratch_begin_next(arena); char* pathCString = str8_to_cstring(scratch.arena, path); diff --git a/src/platform/platform_io.h b/src/platform/platform_io.h new file mode 100644 index 0000000..9fa4c84 --- /dev/null +++ b/src/platform/platform_io.h @@ -0,0 +1,193 @@ +/************************************************************//** +* +* @file: platform_io.h +* @author: Martin Fouilleul +* @date: 25/05/2023 +* +*****************************************************************/ +#ifndef __PLATFORM_IO_H_ +#define __PLATFORM_IO_H_ + +#include"util/typedefs.h" +#include"util/strings.h" + +//---------------------------------------------------------------- +// IO API +//---------------------------------------------------------------- + +typedef struct { u64 h; } file_handle; + +typedef u32 file_open_flags; +enum { + FILE_OPEN_READ = 1<<0, + FILE_OPEN_WRITE = 1<<1, + FILE_OPEN_APPEND = 1<<2, + FILE_OPEN_TRUNCATE = 1<<3, + FILE_OPEN_CREATE = 1<<4, + + FILE_OPEN_NO_FOLLOW = 1<<5, + FILE_OPEN_RESTRICT = 1<<6, + //... +}; + +typedef enum { FILE_SEEK_SET, FILE_SEEK_END, FILE_SEEK_CURRENT } file_whence; + +typedef u64 io_req_id; + +typedef u32 io_op; +enum +{ + IO_OP_OPEN_AT, + IO_OP_CLOSE, + + IO_OP_FSTAT, + + IO_OP_POS, + IO_OP_SEEK, + IO_OP_READ, + IO_OP_WRITE, + + IO_OP_ERROR, + //... +}; + +typedef struct io_req +{ + io_req_id id; + io_op op; + file_handle handle; + + i64 offset; + u64 size; + union + { + char* buffer; + u64 unused; // This is a horrible hack to get the same layout on wasm and on host + }; + + union + { + file_open_flags openFlags; + file_whence whence; + }; + +} io_req; + +typedef i32 io_error; +enum { + IO_OK = 0, + IO_ERR_UNKNOWN, + IO_ERR_OP, // unsupported operation + IO_ERR_HANDLE, // invalid handle + IO_ERR_PREV, // previously had a fatal error (last error stored on handle) + IO_ERR_ARG, // invalid argument or argument combination + IO_ERR_PERM, // access denied + IO_ERR_SPACE, // no space left + IO_ERR_NO_ENTRY, // file or directory does not exist + IO_ERR_EXISTS, // file already exists + IO_ERR_NOT_DIR, // path element is not a directory + IO_ERR_DIR, // attempted to write directory + IO_ERR_MAX_FILES, // max open files reached + IO_ERR_MAX_LINKS, // too many symbolic links in path + IO_ERR_PATH_LENGTH, // path too long + IO_ERR_FILE_SIZE, // file too big + IO_ERR_OVERFLOW, // offset too big + IO_ERR_NOT_READY, // no data ready to be read/written + IO_ERR_MEM, // failed to allocate memory + IO_ERR_INTERRUPT, // operation interrupted by a signal + IO_ERR_PHYSICAL, // physical IO error + IO_ERR_NO_DEVICE, // device not found + IO_ERR_WALKOUT, // attempted to walk out of root directory + + //... +}; + +typedef struct io_cmp +{ + io_req id; + io_error error; + + union + { + u64 result; + u64 size; + i64 offset; + file_handle handle; + //... + }; +} io_cmp; + +//---------------------------------------------------------------- +//TODO: complete io queue 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); + +off_t file_pos(file_handle file); +off_t file_seek(file_handle file, long offset, file_whence whence); + +size_t file_write(file_handle file, size_t size, char* buffer); +size_t file_read(file_handle file, size_t size, char* buffer); + +io_error io_last_error(file_handle handle); + +//---------------------------------------------------------------- +// File System wrapper API +//---------------------------------------------------------------- + +typedef enum +{ + FILE_UNKNOWN, + FILE_REGULAR, + FILE_DIRECTORY, + FILE_SYMLINK, + FILE_BLOCK, + FILE_CHARACTER, + FILE_FIFO, + 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, + + FILE_GROUP_EXEC = 1<<3, + FILE_GROUP_WRITE = 1<<4, + FILE_GROUP_READ = 1<<5, + + FILE_OWNER_EXEC = 1<<6, + FILE_OWNER_WRITE = 1<<7, + FILE_OWNER_READ = 1<<8, + + FILE_STICKY_BIT = 1<<9, + FILE_SET_GID = 1<<10, + FILE_SET_UID = 1<<11, +}; + +typedef struct file_status +{ + file_type type; + file_perm perm; + u64 size; + + //TODO times + +} file_status; + +file_status file_get_status(file_handle file); +size_t file_size(file_handle file); + +//TODO: Complete as needed... + + +#endif //__PLATFORM_IO_H_ diff --git a/src/platform/platform_io_common.c b/src/platform/platform_io_common.c new file mode 100644 index 0000000..942036c --- /dev/null +++ b/src/platform/platform_io_common.c @@ -0,0 +1,104 @@ +/************************************************************//** +* +* @file: platform_io_common.c +* @author: Martin Fouilleul +* @date: 25/05/2023 +* +*****************************************************************/ + +#include"platform_io.h" + +//------------------------------------------------------------------------------ +// File stream read/write API +//------------------------------------------------------------------------------ + +file_handle file_open(str8 path, file_open_flags flags) +{ + io_req req = {.op = IO_OP_OPEN, + .size = path.len, + .buffer = path.ptr, + .openFlags = flags}; + + io_cmp cmp = io_wait_single_req(&req); + + //WARN: we always return a handle that can be queried for errors. Handles must be closed + // even if there was an error when opening + file_handle handle = { cmp.result }; + return(handle); +} + +void file_close(file_handle file) +{ + io_req req = {.op = IO_OP_CLOSE, + .handle = file}; + io_wait_single_req(&req); +} + +off_t file_pos(file_handle file) +{ + io_req req = {.op = IO_OP_POS, + .handle = file}; + + io_cmp cmp = io_wait_single_req(&req); + return((size_t)cmp.result); +} + +off_t file_seek(file_handle file, long offset, file_whence whence) +{ + io_req req = {.op = IO_OP_SEEK, + .handle = file, + .size = offset, + .whence = whence}; + + io_cmp cmp = io_wait_single_req(&req); + return((size_t)cmp.result); +} + +size_t file_write(file_handle file, size_t size, char* buffer) +{ + io_req req = {.op = IO_OP_WRITE, + .handle = file, + .size = size, + .buffer = buffer}; + + io_cmp cmp = io_wait_single_req(&req); + return((size_t)cmp.result); +} + +size_t file_read(file_handle file, size_t size, char* buffer) +{ + io_req req = {.op = IO_OP_READ, + .handle = file, + .size = size, + .buffer = buffer}; + + io_cmp cmp = io_wait_single_req(&req); + return((size_t)cmp.result); +} + +io_error io_last_error(file_handle file) +{ + io_req req = {.op = IO_OP_ERROR, + .handle = file}; + + io_cmp cmp = io_wait_single_req(&req); + return((int)cmp.result); +} + +file_status file_get_status(file_handle file) +{ + file_status status = {0}; + io_req req = {.op = IO_OP_FSTAT, + .handle = file, + .size = sizeof(file_status), + .buffer = (char*)status}; + + io_cmp cmp = io_wait_single_req(&req); + return(status); +} + +size_t file_size(file_handle file) +{ + file_status status = file_get_status(file); + return(status.size); +} diff --git a/src/platform/platform_path.c b/src/platform/platform_path.c index fcff779..72de1f7 100644 --- a/src/platform/platform_path.c +++ b/src/platform/platform_path.c @@ -53,6 +53,7 @@ str8_list path_split(mem_arena* arena, str8 path) str8 path_join(mem_arena* arena, str8_list elements) { + //TODO: check if elements have ending/begining '/' ? str8 res = str8_list_collate(arena, elements, STR8("/"), STR8("/"), (str8){0}); return(res); } @@ -88,3 +89,17 @@ str8 path_append(mem_arena* arena, str8 parent, str8 relPath) } return(result); } + +str8 path_executable_relative(mem_arena* arena, str8 relPath) +{ + str8_list list = {}; + mem_arena_scope scratch = mem_scratch_begin_next(arena); + + str8 executablePath = path_executable(scratch.arena); + str8 dirPath = path_slice_directory(executablePath); + + str8 path = path_append(arena, dirPath, relPath); + + mem_scratch_end(scratch); + return(path); +} diff --git a/src/platform/platform_path.h b/src/platform/platform_path.h index 1a386c6..b316186 100644 --- a/src/platform/platform_path.h +++ b/src/platform/platform_path.h @@ -17,8 +17,10 @@ MP_API str8_list path_split(mem_arena* arena, str8 path); MP_API str8 path_join(mem_arena* arena, str8_list elements); MP_API str8 path_append(mem_arena* arena, str8 parent, str8 relPath); -MP_API str8 path_find_executable(mem_arena* arena); -MP_API str8 path_find_resource(mem_arena* arena, str8 relPath); -MP_API str8 path_find_canonical(mem_arena* arena, str8 path); +MP_API str8 path_executable(mem_arena* arena); +MP_API str8 path_canonical(mem_arena* arena, str8 path); + +// helper: gets the path from path_executable() and appends relPath +MP_API str8 path_executable_relative(mem_arena* arena, str8 relPath); #endif //__PLATFORM_PATH_H_ diff --git a/src/platform/posix_io.c b/src/platform/posix_io.c new file mode 100644 index 0000000..db34b2c --- /dev/null +++ b/src/platform/posix_io.c @@ -0,0 +1,498 @@ +/************************************************************//** +* +* @file: posix_io.c +* @author: Martin Fouilleul +* @date: 25/05/2023 +* +*****************************************************************/ + +#include +#include +#include +#include +#include + +#include"platform_io.h" + +typedef struct file_slot +{ + u32 generation; + int fd; + 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; + 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 < ORCA_MAX_FILE_SLOTS) + { + file_slot* candidate = &table->slots[index]; + if(candidate->generation == generation) + { + slot = candidate; + } + } + return(slot); +} + +io_error io_convert_errno(int e) +{ + io_error error; + switch(e) + { + case EPERM: + case EACCES: + case EROFS: + error = IO_ERR_PERM; + break; + + case ENOENT: + error = IO_ERR_NO_ENTRY; + break; + + case EINTR: + error = IO_ERR_INTERRUPT; + break; + + case EIO: + error = IO_ERR_PHYSICAL; + break; + + case ENXIO: + error = IO_ERR_NO_DEVICE; + break; + + case EBADF: + // this should only happen when user tries to write/read to a file handle + // opened with readonly/writeonly access + error = IO_ERR_PERM; + break; + + case ENOMEM: + error = IO_ERR_MEM; + break; + + case EFAULT: + case EINVAL: + case EDOM: + error = IO_ERR_ARG; + break; + + case EBUSY: + case EAGAIN: + error = IO_ERR_NOT_READY; + break; + + case EEXIST: + error = IO_ERR_EXISTS; + break; + + case ENOTDIR: + error = IO_ERR_NOT_DIR; + break; + + case EISDIR: + error = IO_ERR_DIR; + break; + + case ENFILE: + case EMFILE: + error = IO_ERR_MAX_FILES; + break; + + case EFBIG: + error = IO_ERR_FILE_SIZE; + break; + + case ENOSPC: + case EDQUOT: + error = IO_ERR_SPACE; + break; + + case ELOOP: + error = IO_ERR_MAX_LINKS; + break; + + case ENAMETOOLONG: + error = IO_ERR_PATH_LENGTH; + break; + + case EOVERFLOW: + error = IO_ERR_OVERFLOW; + break; + + default: + error = IO_ERR_UNKNOWN; + break; + } + return(error); +} + +int io_convert_open_flags(file_open_flags flags) +{ + int oflags = 0; + + if(flags & FILE_OPEN_READ) + { + if(flags & FILE_OPEN_WRITE) + { + oflags = O_RDWR; + } + else + { + oflags = O_RDONLY; + } + } + else if(flags & FILE_OPEN_WRITE) + { + oflags = O_WRONLY; + } + + if(flags & FILE_OPEN_TRUNCATE) + { + oflags |= O_TRUNC; + } + if(flags & FILE_OPEN_APPEND) + { + oflags |= O_APPEND; + } + if(flags & FILE_OPEN_CREATE) + { + oflags |= O_CREAT; + } + if(flags & FILE_OPEN_NO_FOLLOW) + { + oflags |= O_NOFOLLOW; + } + return(oflags); +} + +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 + { + file_handle handle = file_handle_from_slot(&__globalFileTable, slot); + cmp.result = handle.h; + + int flags = io_convert_open_flags(req->openFlags); + + //TODO: allow specifying access + mode_t mode = S_IRUSR + | S_IWUSR + | S_IRGRP + | S_IWGRP + | S_IROTH + | S_IWOTH; + + //NOTE: open + mem_arena_scope scratch = mem_scratch_begin(); + + str8 path = str8_from_buffer(req->size, req->buffer); + char* pathCStr = str8_to_cstring(scratch.arena, path); + + //TODO: if FILE_OPEN_RESTRICT, do the file traversal to check that path is in the + // subtree rooted at atSlot->fd + int fd = -1; + if(atSlot) + { + fd = openat(atSlot->fd, pathCStr, flags, mode); + } + else + { + fd = open(pathCStr, flags, mode); + } + + mem_scratch_end(scratch); + + if(fd >= 0) + { + slot->fd = fd; + } + else + { + slot->fd = -1; + slot->fatal = true; + slot->error = io_convert_errno(errno); + } + cmp.error = slot->error; + } + + return(cmp); +} + +io_cmp io_close(file_slot* slot, io_req* req) +{ + io_cmp cmp = {0}; + if(slot->fd >= 0) + { + close(slot->fd); + } + 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}; + cmp.result = lseek(slot->fd, 0, SEEK_CUR); + if(cmp.result < 0) + { + slot->error = io_convert_errno(errno); + cmp.error = slot->error; + } + + return(cmp); +} + +io_cmp io_seek(file_slot* slot, io_req* req) +{ + io_cmp cmp = {0}; + + int whence; + switch(req->whence) + { + case FILE_SEEK_CURRENT: + whence = SEEK_CUR; + break; + + case FILE_SEEK_SET: + whence = SEEK_SET; + break; + + case FILE_SEEK_END: + whence = SEEK_END; + } + cmp.result = lseek(slot->fd, req->size, whence); + + if(cmp.result < 0) + { + slot->error = io_convert_errno(errno); + cmp.error = slot->error; + } + + return(cmp); +} + +io_cmp io_read(file_slot* slot, io_req* req) +{ + io_cmp cmp = {0}; + + cmp.result = read(slot->fd, req->buffer, req->size); + + if(cmp.result < 0) + { + slot->error = io_convert_errno(errno); + cmp.error = slot->error; + } + + return(cmp); +} + +io_cmp io_write(file_slot* slot, io_req* req) +{ + io_cmp cmp = {0}; + + cmp.result = write(slot->fd, req->buffer, req->size); + + if(cmp.result < 0) + { + slot->error = io_convert_errno(errno); + cmp.error = slot->error; + } + + 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 && (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; + break; + } + } + return(cmp); +}