From d363c8b607258ed7257ec04add91e1d505ad937b Mon Sep 17 00:00:00 2001 From: Martin Fouilleul Date: Thu, 15 Jun 2023 18:27:33 +0200 Subject: [PATCH] [wip, osx, io] reorganizing io_open_restrict, fix opening last element with the correct flags --- src/platform/osx_path.m | 5 + src/platform/platform_io_internal.c | 291 +++++++++++++++++ src/platform/platform_io_internal.h | 40 ++- src/platform/platform_path.h | 1 + src/platform/posix_io.c | 483 +++++++++++----------------- src/platform/win32_io.c | 92 +----- test/files/data/jail/test.txt | 1 - 7 files changed, 530 insertions(+), 383 deletions(-) diff --git a/src/platform/osx_path.m b/src/platform/osx_path.m index 519ae98..575f6c8 100644 --- a/src/platform/osx_path.m +++ b/src/platform/osx_path.m @@ -12,6 +12,11 @@ #include"platform_path.c" +bool path_is_absolute(str8 path) +{ + return(path.len && (path.ptr[0] == '/')); +} + str8 path_executable(mem_arena* arena) {@autoreleasepool{ str8 result = {}; diff --git a/src/platform/platform_io_internal.c b/src/platform/platform_io_internal.c index 4094653..8819ba7 100644 --- a/src/platform/platform_io_internal.c +++ b/src/platform/platform_io_internal.c @@ -7,6 +7,7 @@ *****************************************************************/ #include"platform_io_internal.h" +#include"platform_path.h" file_table __globalFileTable = {0}; @@ -63,3 +64,293 @@ io_cmp io_wait_single_req(io_req* req) { return(io_wait_single_req_with_table(req, &__globalFileTable)); } + +//----------------------------------------------------------------------- +// io common primitives +//----------------------------------------------------------------------- + +typedef struct io_open_restrict_context +{ + io_error error; + u64 rootUID; + io_file_desc rootFd; + io_file_desc fd; + +} io_open_restrict_context; + +io_error io_open_restrict_enter(io_open_restrict_context* context, str8 name, file_access_rights accessRights, file_open_flags openFlags) +{ + io_file_desc nextFd = io_raw_open_at(context->fd, name, accessRights, openFlags); + if(io_file_desc_is_nil(nextFd)) + { + context->error = io_raw_last_error(); + } + else + { + if(context->fd != context->rootFd) + { + io_raw_close(context->fd); + } + context->fd = nextFd; + } + return(context->error); +} + +typedef struct io_open_restrict_result +{ + io_error error; + io_file_desc fd; +} io_open_restrict_result; + + +io_open_restrict_result io_open_restrict(io_file_desc dirFd, str8 path, file_access_rights accessRights, file_open_flags openFlags) +{ + mem_arena_scope scratch = mem_scratch_begin(); + + str8_list sep = {0}; + str8_list_push(scratch.arena, &sep, STR8("/")); + str8_list pathElements = str8_split(scratch.arena, path, sep); + + io_open_restrict_context context = { + .error = IO_OK, + .rootFd = dirFd, + .fd = dirFd, + }; + + file_status status; + context.error = io_raw_fstat(dirFd, &status); + context.rootUID = status.uid; + + for_list(&pathElements.list, elt, str8_elt, listElt) + { + str8 name = elt->string; + + /*TODO: + The last element should be treated a bit differently: + + - if it doesn't exists, and FILE_OPEN_CREATE is set, we can create it + - it must be opened with the correct flags + */ + + if(!str8_cmp(name, STR8("."))) + { + if(&elt->listElt == list_last(&pathElements.list)) + { + //NOTE: if we're at the last element, re-enter current directory with correct flags + io_open_restrict_enter(&context, name, accessRights, openFlags); + } + else + { + //NOTE: else we can just skip the element + } + } + else if(!str8_cmp(name, STR8(".."))) + { + //NOTE: check that we don't escape root dir + file_status status; + context.error = io_raw_fstat(context.fd, &status); + if(context.error) + { + break; + } + else if(status.uid == context.rootUID) + { + context.error = IO_ERR_WALKOUT; + break; + } + else if(&elt->listElt == list_last(&pathElements.list)) + { + //NOTE: if we're at the last element, enter parent directory with correct flags + io_open_restrict_enter(&context, name, accessRights, openFlags); + } + else + { + io_open_restrict_enter(&context, name, FILE_ACCESS_READ, 0); + } + } + else + { + if(!io_raw_file_exists_at(context.fd, name, FILE_OPEN_SYMLINK)) + { + //NOTE: if the file doesn't exists, but we're at the last element and FILE_OPEN_CREATE + // is set, we create the file. Otherwise it is a IO_ERROR_NO_ENTRY error. + if( (&elt->listElt == list_last(&pathElements.list)) + &&(openFlags & FILE_OPEN_CREATE)) + { + io_open_restrict_enter(&context, name, accessRights, openFlags); + } + else + { + context.error = IO_ERR_NO_ENTRY; + break; + } + } + else + { + //NOTE: if the file exists, we check the type of file + file_status status = {0}; + context.error = io_raw_fstat_at(context.fd, name, FILE_OPEN_SYMLINK, &status); + if(context.error) + { + break; + } + + if(status.type == MP_FILE_SYMLINK) + { + //TODO - do we need a FILE_OPEN_NO_FOLLOW that fails if last element is a symlink? + // - do we need a FILE_OPEN_NO_SYMLINKS that fails if _any_ element is a symlink? + + if( (&elt->listElt == list_last(&pathElements.list)) + &&(openFlags & FILE_OPEN_SYMLINK)) + { + io_open_restrict_enter(&context, name, accessRights, openFlags); + } + else + { + io_raw_read_link_result link = io_raw_read_link_at(scratch.arena, context.fd, name); + if(link.error) + { + context.error = link.error; + break; + } + + if(path_is_absolute(link.target)) + { + context.error = IO_ERR_WALKOUT; + break; + } + else + { + if(link.target.len == 0) + { + //NOTE: treat an empty target as a '.' + link.target = STR8("."); + } + + str8_list linkElements = str8_split(scratch.arena, link.target, sep); + if(!list_empty(&linkElements.list)) + { + //NOTE: insert linkElements into pathElements after elt + list_elt* tmp = elt->listElt.next; + elt->listElt.next = linkElements.list.first; + linkElements.list.last->next = tmp; + if(!tmp) + { + pathElements.list.last = linkElements.list.last; + } + } + } + } + } + else if(status.type == MP_FILE_DIRECTORY) + { + //NOTE: descend in directory + if(&elt->listElt == list_last(&pathElements.list)) + { + io_open_restrict_enter(&context, name, accessRights, openFlags); + } + else + { + io_open_restrict_enter(&context, name, FILE_ACCESS_READ, 0); + } + } + else if(status.type == MP_FILE_REGULAR) + { + //NOTE: check that we're at the end of path and open that file + if(&elt->listElt != list_last(&pathElements.list)) + { + context.error = IO_ERR_NOT_DIR; + break; + } + else + { + io_open_restrict_enter(&context, name, accessRights, openFlags); + } + } + else + { + context.error = IO_ERR_NO_ENTRY; + } + } + } + } + + if(context.error) + { + if(context.fd != context.rootFd) + { + io_raw_close(context.fd); + context.fd = io_file_desc_nil(); + } + } + + io_open_restrict_result result = { + .error = context.error, + .fd = context.fd + }; + + mem_scratch_end(scratch); + return(result); +} + +io_cmp io_open_at(file_slot* atSlot, io_req* req, file_table* table) +{ + io_cmp cmp = {0}; + + file_slot* slot = file_slot_alloc(table); + if(!slot) + { + cmp.error = IO_ERR_MAX_FILES; + cmp.result = 0; + } + else + { + slot->fd = -1; + + cmp.handle = file_handle_from_slot(table, slot); + + slot->rights = req->open.rights; + if(atSlot) + { + slot->rights &= atSlot->rights; + } + + if(slot->rights != req->open.rights) + { + slot->error = IO_ERR_PERM; + slot->fatal = true; + } + else + { + str8 path = str8_from_buffer(req->size, req->buffer); + + io_file_desc dirFd = atSlot ? atSlot->fd : io_file_desc_nil(); + slot->fd = -1; + + if(req->open.flags & FILE_OPEN_RESTRICT) + { + io_open_restrict_result res = io_open_restrict(dirFd, path, slot->rights, req->open.flags); + if(res.error == IO_OK) + { + slot->fd = res.fd; + } + else + { + slot->fatal = true; + slot->error = res.error; + } + } + else + { + slot->fd = io_raw_open_at(dirFd, path, slot->rights, req->open.flags); + if(slot->fd < 0) + { + slot->fatal = true; + slot->error = io_raw_last_error(); + } + } + } + cmp.error = slot->error; + } + return(cmp); +} diff --git a/src/platform/platform_io_internal.h b/src/platform/platform_io_internal.h index 1d9f79a..0df09d7 100644 --- a/src/platform/platform_io_internal.h +++ b/src/platform/platform_io_internal.h @@ -12,11 +12,11 @@ #include"platform.h" #if PLATFORM_MACOS || PLATFORM_LINUX - #define PLATFORM_IO_NATIVE_MEMBER int fd + typedef int io_file_desc; #elif PLATFORM_WINDOWS #define WIN32_LEAN_AND_MEAN #include - #define PLATFORM_IO_NATIVE_MEMBER HANDLE h + typedef HANDLE io_file_desc; #endif typedef struct file_slot @@ -27,7 +27,7 @@ typedef struct file_slot list_elt freeListElt; file_access_rights rights; - PLATFORM_IO_NATIVE_MEMBER; + io_file_desc fd; } file_slot; @@ -50,4 +50,38 @@ file_slot* file_slot_from_handle(file_table* table, file_handle handle); io_cmp io_wait_single_req_with_table(io_req* req, file_table* table); + +//----------------------------------------------------------------------- +// raw io primitives +//----------------------------------------------------------------------- + +io_file_desc io_file_desc_nil(); +bool io_file_desc_is_nil(io_file_desc fd); + +/*WARN + io_raw_xxx_at functions are similar to posix openat() regarding path resolution, + but with some important differences: + - If dirFd is a non-nil fd, path is considered relative to dirFd _even if it is an absolute path_ + - If dirFd is a nil fd, it is _ignored_ (i.e., path can be absolute, or relative to the current directory) + + This means that: + - dirFd behaves more like the _root_ of path, ie dirFd won't be ignore if we pass an absolute path, + - we don't need a special handle value to use a path relative to the current working directory + (we just pass a nil dirFd with a relative path) +*/ +io_file_desc io_raw_open_at(io_file_desc dirFd, str8 path, file_access_rights accessRights, file_open_flags openFlags); +void io_raw_close(io_file_desc fd); +io_error io_raw_last_error(); +bool io_raw_file_exists_at(io_file_desc dirFd, str8 path, file_open_flags openFlags); +io_error io_raw_fstat(io_file_desc fd, file_status* status); +io_error io_raw_fstat_at(io_file_desc dirFd, str8 path, file_open_flags openFlags, file_status* status); + +typedef struct io_raw_read_link_result +{ + io_error error; + str8 target; +} io_raw_read_link_result; + +io_raw_read_link_result io_raw_read_link_at(mem_arena* arena, io_file_desc dirFd, str8 path); + #endif //__PLATFORM_IO_INTERNAL_H_ diff --git a/src/platform/platform_path.h b/src/platform/platform_path.h index b316186..7665204 100644 --- a/src/platform/platform_path.h +++ b/src/platform/platform_path.h @@ -17,6 +17,7 @@ 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 bool path_is_absolute(str8 path); MP_API str8 path_executable(mem_arena* arena); MP_API str8 path_canonical(mem_arena* arena, str8 path); diff --git a/src/platform/posix_io.c b/src/platform/posix_io.c index fa43b96..0b9449c 100644 --- a/src/platform/posix_io.c +++ b/src/platform/posix_io.c @@ -15,10 +15,20 @@ #include"platform_io_common.c" #include"platform_io_internal.c" -io_error io_convert_errno(int e) +io_file_desc io_file_desc_nil() { - io_error error; - switch(e) + return(-1); +} + +bool io_file_desc_is_nil(io_file_desc fd) +{ + return(fd < 0); +} + +io_error io_raw_last_error() +{ + io_error error = IO_OK; + switch(errno) { case EPERM: case EACCES: @@ -178,311 +188,50 @@ int io_update_dir_flags_at(int dirFd, char* path, int flags) return(flags); } -typedef struct io_open_restrict_result +io_file_desc io_raw_open_at(io_file_desc dirFd, str8 path, file_access_rights accessRights, file_open_flags openFlags) { - io_error error; - int fd; + int flags = io_convert_access_rights(accessRights); + flags |= io_convert_open_flags(openFlags); -} io_open_restrict_result; - -io_open_restrict_result io_open_restrict(int dirFd, str8 path, int flags, mode_t mode) -{ - io_open_restrict_result result = {.fd = -1}; + mode_t mode = S_IRUSR + | S_IWUSR + | S_IRGRP + | S_IWGRP + | S_IROTH + | S_IWOTH; mem_arena_scope scratch = mem_scratch_begin(); - str8_list sep = {0}; - str8_list_push(scratch.arena, &sep, STR8("/")); - str8_list pathElements = str8_split(scratch.arena, path, sep); - - result.fd = dup(dirFd); - if(result.fd < 0) + io_file_desc fd = -1; + if(dirFd >= 0) { - result.error = io_convert_errno(errno); - goto error; - } - struct stat dirStat; - if(fstat(result.fd, &dirStat)) - { - result.error = io_convert_errno(errno); - goto error; - } - ino_t baseInode = dirStat.st_ino; - ino_t currentInode = baseInode; - - for_list(&pathElements.list, elt, str8_elt, listElt) - { - str8 name = elt->string; - - if(!str8_cmp(name, STR8("."))) + if(path.len && path.ptr[0] == '/') { - //NOTE: skip - continue; + //NOTE: if path is absolute, change for a relative one, otherwise openat ignores fd. + str8_list list = {0}; + str8_list_push(scratch.arena, &list, STR8(".")); + str8_list_push(scratch.arena, &list, path); + path = str8_list_join(scratch.arena, list); } - else if(!str8_cmp(name, STR8(".."))) - { - //NOTE: check that we don't escape 'root' dir - if(currentInode == baseInode) - { - result.error = IO_ERR_WALKOUT; - goto error; - } - else - { - // open that dir and continue - int nextFd = openat(result.fd, "..", O_RDONLY); - if(!nextFd) - { - result.error = io_convert_errno(errno); - goto error; - } - else - { - close(result.fd); - result.fd = nextFd; - if(fstat(result.fd, &dirStat)) - { - result.error = io_convert_errno(errno); - goto error; - } - currentInode = dirStat.st_ino; - } - } - } - else - { - char* nameCStr = str8_to_cstring(scratch.arena, name); - - if(faccessat(result.fd, nameCStr, F_OK, AT_SYMLINK_NOFOLLOW)) - { - //NOTE: file does not exist. if we're not at the end of path, or we don't have create flag, - // return a IO_ERR_NO_ENTRY - if(&elt->listElt != list_last(&pathElements.list) && !(flags & O_CREAT)) - { - result.error = IO_ERR_NO_ENTRY; - goto error; - } - else - { - //NOTE create the flag and return - int nextFd = openat(result.fd, nameCStr, flags); - if(!nextFd) - { - result.error = io_convert_errno(errno); - goto error; - } - else - { - close(result.fd); - result.fd = nextFd; - } - continue; - } - } - - struct stat st; - if(fstatat(result.fd, nameCStr, &st, AT_SYMLINK_NOFOLLOW)) - { - result.error = io_convert_errno(errno); - goto error; - } - - int type = st.st_mode & S_IFMT; - - if(type == S_IFLNK) - { - // symlink, check that it's relative, and insert it in elements - char buff[PATH_MAX+1]; - int r = readlinkat(result.fd, nameCStr, buff, PATH_MAX); - if(r<0) - { - result.error = io_convert_errno(errno); - goto error; - } - else if(r == 0) - { - //NOTE: skip - } - else if(buff[0] == '/') - { - result.error = IO_ERR_WALKOUT; - goto error; - } - else - { - buff[r] = '\0'; - - str8_list linkElements = str8_split(scratch.arena, str8_from_buffer(r, buff), sep); - if(!list_empty(&linkElements.list)) - { - //NOTE: insert linkElements into pathElements after elt - list_elt* tmp = elt->listElt.next; - elt->listElt.next = linkElements.list.first; - linkElements.list.last->next = tmp; - if(!tmp) - { - pathElements.list.last = linkElements.list.last; - } - } - } - } - else if(type == S_IFDIR) - { - // dir, open it and continue - int nextFd = openat(result.fd, nameCStr, O_RDONLY); - if(!nextFd) - { - result.error = io_convert_errno(errno); - goto error; - } - else - { - close(result.fd); - result.fd = nextFd; - currentInode = st.st_ino; - } - } - else if(type == S_IFREG) - { - // regular file, check that we're at the last element - if(&elt->listElt != list_last(&pathElements.list)) - { - result.error = IO_ERR_NOT_DIR; - goto error; - } - //////////////////////////////////////////////////////// - //TODO: else open the file with correct flags - //////////////////////////////////////////////////////// - } - else - { - result.error = IO_ERR_NOT_DIR; - goto error; - } - } - } - goto end; - - error: - { - close(result.fd); - result.fd = -1; - } - end: - mem_scratch_end(scratch); - return(result); -} - -io_cmp io_open_at(file_slot* atSlot, io_req* req, file_table* table) -{ - io_cmp cmp = {0}; - - file_slot* slot = file_slot_alloc(table); - if(!slot) - { - cmp.error = IO_ERR_MAX_FILES; - cmp.result = 0; } else { - slot->fd = -1; - - cmp.handle = file_handle_from_slot(table, slot); - - slot->rights = req->open.rights; - if(atSlot) - { - slot->rights &= atSlot->rights; - } - - if(slot->rights != req->open.rights) - { - slot->error = IO_ERR_PERM; - slot->fatal = true; - } - else - { - int flags = io_convert_access_rights(slot->rights); - flags |= io_convert_open_flags(req->open.flags); - - mode_t mode = S_IRUSR - | S_IWUSR - | S_IRGRP - | S_IWGRP - | S_IROTH - | S_IWOTH; - - mem_arena_scope scratch = mem_scratch_begin(); - str8 path = str8_from_buffer(req->size, req->buffer); - - slot->fd = -1; - if(atSlot) - { - if(path.len && path.ptr[0] == '/') - { - //NOTE: if path is absolute, change for a relative one, otherwise openat ignores fd. - str8_list list = {0}; - str8_list_push(scratch.arena, &list, STR8(".")); - str8_list_push(scratch.arena, &list, path); - path = str8_list_join(scratch.arena, list); - } - char* pathCStr = str8_to_cstring(scratch.arena, path); - - if(req->open.flags & FILE_OPEN_RESTRICT) - { - io_open_restrict_result res = io_open_restrict(atSlot->fd, path, flags, mode); - if(res.error == IO_OK) - { - slot->fd = res.fd; - } - else - { - slot->fatal = true; - slot->error = res.error; - } - } - else - { - flags = io_update_dir_flags_at(atSlot->fd, pathCStr, flags); - - slot->fd = openat(atSlot->fd, pathCStr, flags, mode); - if(slot->fd < 0) - { - slot->fatal = true; - slot->error = io_convert_errno(errno); - } - } - } - else - { - char* pathCStr = str8_to_cstring(scratch.arena, path); - - flags = io_update_dir_flags_at(AT_FDCWD, pathCStr, flags); - - slot->fd = open(pathCStr, flags, mode); - if(slot->fd < 0) - { - slot->fatal = true; - slot->error = io_convert_errno(errno); - } - } - mem_scratch_end(scratch); - } - cmp.error = slot->error; + dirFd = AT_FDCWD; } - return(cmp); + char* pathCStr = str8_to_cstring(scratch.arena, path); + + flags = io_update_dir_flags_at(dirFd, pathCStr, flags); + + fd = openat(dirFd, pathCStr, flags, mode); + mem_scratch_end(scratch); + + return(fd); } -io_cmp io_close(file_slot* slot, io_req* req, file_table* table) +void io_raw_close(io_file_desc fd) { - io_cmp cmp = {0}; - if(slot->fd >= 0) - { - close(slot->fd); - } - file_slot_recycle(table, slot); - return(cmp); + close(fd); } file_perm io_convert_perm_from_stat(u16 mode) @@ -531,6 +280,148 @@ file_type io_convert_type_from_stat(u16 mode) return(type); } +io_error io_raw_fstat(io_file_desc fd, file_status* status) +{ + io_error error = IO_OK; + struct stat s; + if(fstat(fd, &s)) + { + error = io_raw_last_error(); + } + else + { + status->uid = s.st_ino; + 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(error); +} + +io_error io_raw_fstat_at(io_file_desc dirFd, str8 path, file_open_flags flags, file_status* status) +{ + mem_arena_scope scratch = mem_scratch_begin(); + + if(dirFd >= 0) + { + if(path.len && path.ptr[0] == '/') + { + str8_list list = {0}; + str8_list_push(scratch.arena, &list, STR8(".")); + str8_list_push(scratch.arena, &list, path); + path = str8_list_join(scratch.arena, list); + } + } + else + { + dirFd = AT_FDCWD; + } + + char* pathCStr = str8_to_cstring(scratch.arena, path); + + int statFlag = (flags & FILE_OPEN_SYMLINK)? AT_SYMLINK_NOFOLLOW : 0; + io_error error = IO_OK; + struct stat s; + if(fstatat(dirFd, pathCStr, &s, statFlag)) + { + error = io_raw_last_error(); + } + else + { + status->uid = s.st_ino; + 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 + } + + mem_scratch_end(scratch); + return(error); +} + +io_raw_read_link_result io_raw_read_link_at(mem_arena* arena, io_file_desc dirFd, str8 path) +{ + mem_arena_scope scratch = mem_scratch_begin_next(arena); + + if(dirFd >= 0) + { + if(path.len && path.ptr[0] == '/') + { + str8_list list = {0}; + str8_list_push(scratch.arena, &list, STR8(".")); + str8_list_push(scratch.arena, &list, path); + path = str8_list_join(scratch.arena, list); + } + } + else + { + dirFd = AT_FDCWD; + } + + char* pathCStr = str8_to_cstring(scratch.arena, path); + + io_raw_read_link_result result = {0}; + + char buffer[PATH_MAX]; + u64 bufferSize = PATH_MAX; + i64 r = readlinkat(dirFd, pathCStr, buffer, bufferSize); + + if(r<0) + { + result.error = io_raw_last_error(); + } + else + { + result.target.len = r; + result.target.ptr = mem_arena_alloc_array(arena, char, result.target.len); + memcpy(result.target.ptr, buffer, result.target.len); + } + + mem_scratch_end(scratch); + return(result); +} + +bool io_raw_file_exists_at(io_file_desc dirFd, str8 path, file_open_flags openFlags) +{ + mem_arena_scope scratch = mem_scratch_begin(); + + if(dirFd >= 0) + { + if(path.len && path.ptr[0] == '/') + { + str8_list list = {0}; + str8_list_push(scratch.arena, &list, STR8(".")); + str8_list_push(scratch.arena, &list, path); + path = str8_list_join(scratch.arena, list); + } + } + else + { + dirFd = AT_FDCWD; + } + + char* pathCStr = str8_to_cstring(scratch.arena, path); + + int flags = (openFlags & FILE_OPEN_SYMLINK)? AT_SYMLINK_NOFOLLOW : 0; + int r = faccessat(dirFd, pathCStr, F_OK, flags); + bool result = (r == 0); + + mem_scratch_end(scratch); + return(result); +} + +io_cmp io_close(file_slot* slot, io_req* req, file_table* table) +{ + io_cmp cmp = {0}; + if(slot->fd >= 0) + { + close(slot->fd); + } + file_slot_recycle(table, slot); + return(cmp); +} + io_cmp io_fstat(file_slot* slot, io_req* req) { io_cmp cmp = {0}; @@ -544,7 +435,7 @@ io_cmp io_fstat(file_slot* slot, io_req* req) struct stat s; if(fstat(slot->fd, &s)) { - slot->error = io_convert_errno(errno); + slot->error = io_raw_last_error(); cmp.error = slot->error; } else @@ -581,7 +472,7 @@ io_cmp io_seek(file_slot* slot, io_req* req) if(cmp.result < 0) { - slot->error = io_convert_errno(errno); + slot->error = io_raw_last_error(); cmp.error = slot->error; } @@ -596,7 +487,7 @@ io_cmp io_read(file_slot* slot, io_req* req) if(cmp.result < 0) { - slot->error = io_convert_errno(errno); + slot->error = io_raw_last_error(); cmp.result = 0; cmp.error = slot->error; } @@ -612,7 +503,7 @@ io_cmp io_write(file_slot* slot, io_req* req) if(cmp.result < 0) { - slot->error = io_convert_errno(errno); + slot->error = io_raw_last_error(); cmp.result = 0; cmp.error = slot->error; } diff --git a/src/platform/win32_io.c b/src/platform/win32_io.c index 7d41031..b7c8a28 100644 --- a/src/platform/win32_io.c +++ b/src/platform/win32_io.c @@ -115,7 +115,7 @@ io_file_desc io_file_desc_nil() return(INVALID_HANDLE_VALUE); } -bool io_file_desc_invalid(io_file_desc fd) +bool io_file_desc_is_nil(io_file_desc fd) { return(fd == NULL || fd == INVALID_HANDLE_VALUE); } @@ -288,7 +288,7 @@ io_error io_raw_stat_at(io_file_desc dirFd, str8 name, file_open_flags openFlags { io_error error = IO_OK; io_file_desc fd = io_raw_open_at(dirFd, name, FILE_ACCESS_READ, FILE_OPEN_SYMLINK); - if(io_file_desc_invalid(fd)) + if(io_file_desc_is_nil(fd)) { error = io_raw_last_error(); } @@ -388,7 +388,7 @@ typedef struct io_open_restrict_context io_error io_open_restrict_enter(io_open_restrict_context* context, str8 name, file_access_rights accessRights, file_open_flags openFlags) { io_file_desc nextFd = io_raw_open_at(context->fd, name, accessRights, openFlags); - if(io_file_desc_invalid(nextFd)) + if(io_file_desc_is_nil(nextFd)) { context->error = io_raw_last_error(); } @@ -536,86 +536,12 @@ io_open_restrict_result io_open_path_restrict(io_file_desc dirFd, str8 path, fil return(result); } -io_cmp io_open_at(file_slot* atSlot, io_req* req, file_table* table) -{ - io_cmp cmp = {0}; - - file_slot* slot = file_slot_alloc(table); - if(!slot) - { - cmp.error = IO_ERR_MAX_FILES; - cmp.result = 0; - } - else - { - cmp.handle = file_handle_from_slot(table, slot); - - slot->rights = req->open.rights; - if(atSlot) - { - slot->rights &= atSlot->rights; - } - - if(slot->rights != req->open.rights) - { - slot->error = IO_ERR_PERM; - slot->fatal = true; - } - else - { - mem_arena_scope scratch = mem_scratch_begin(); - str8 path = str8_from_buffer(req->size, req->buffer); - str16 pathW = win32_utf8_to_wide_null_terminated(scratch.arena, path); - - slot->h = INVALID_HANDLE_VALUE; - if(atSlot) - { - if(req->open.flags & FILE_OPEN_RESTRICT) - { - //TODO: if FILE_OPEN_RESTRICT, do the full path traversal to check that path is in the - // subtree rooted at atSlot->fd - io_open_restrict_result res = io_open_path_restrict(atSlot->h, path, req->open.rights, req->open.flags); - if(res.error) - { - slot->fatal = true; - slot->error = res.error; - } - } - else - { - slot->h = io_raw_open_at(atSlot->h, path, req->open.rights, req->open.flags); - if(slot->h == INVALID_HANDLE_VALUE) - { - slot->fatal = true; - slot->error = io_raw_last_error(); - } - } - } - else - { - //TODO: take care of share mode and security attributes, make it consistent with posix impl - slot->h = io_raw_open_at(NULL, path, req->open.rights, req->open.flags); - if(slot->h == INVALID_HANDLE_VALUE) - { - slot->fatal = true; - slot->error = io_raw_last_error(); - } - } - - mem_scratch_end(scratch); - } - cmp.error = slot->error; - } - - return(cmp); -} - io_cmp io_close(file_slot* slot, io_req* req, file_table* table) { io_cmp cmp = {0}; - if(slot->h) + if(slot->fd) { - CloseHandle(slot->h); + CloseHandle(slot->fd); } file_slot_recycle(table, slot); return(cmp); @@ -631,7 +557,7 @@ io_cmp io_fstat(file_slot* slot, io_req* req) } else { - slot->error = io_raw_stat(slot->h, (file_status*)req->buffer); + slot->error = io_raw_stat(slot->fd, (file_status*)req->buffer); cmp.error = slot->error; } return(cmp); @@ -659,7 +585,7 @@ io_cmp io_seek(file_slot* slot, io_req* req) LARGE_INTEGER off = {.QuadPart = req->offset}; LARGE_INTEGER newPos = {0}; - if(!SetFilePointerEx(slot->h, off, &newPos, whence)) + if(!SetFilePointerEx(slot->fd, off, &newPos, whence)) { slot->error = io_raw_last_error(); cmp.error = slot->error; @@ -678,7 +604,7 @@ io_cmp io_read(file_slot* slot, io_req* req) DWORD bytesRead = 0; - if(!ReadFile(slot->h, req->buffer, req->size, &bytesRead, NULL)) + if(!ReadFile(slot->fd, req->buffer, req->size, &bytesRead, NULL)) { slot->error = io_raw_last_error(); cmp.result = 0; @@ -697,7 +623,7 @@ io_cmp io_write(file_slot* slot, io_req* req) DWORD bytesWritten = 0; - if(!WriteFile(slot->h, req->buffer, req->size, &bytesWritten, NULL)) + if(!WriteFile(slot->fd, req->buffer, req->size, &bytesWritten, NULL)) { slot->error = io_raw_last_error(); cmp.result = 0; diff --git a/test/files/data/jail/test.txt b/test/files/data/jail/test.txt index 5dd01c1..e69de29 100644 --- a/test/files/data/jail/test.txt +++ b/test/files/data/jail/test.txt @@ -1 +0,0 @@ -Hello, world! \ No newline at end of file