[wip, osx, io] reorganizing io_open_restrict, fix opening last element with the correct flags

This commit is contained in:
Martin Fouilleul 2023-06-15 18:27:33 +02:00
parent c71da9e761
commit d363c8b607
7 changed files with 530 additions and 383 deletions

View File

@ -12,6 +12,11 @@
#include"platform_path.c" #include"platform_path.c"
bool path_is_absolute(str8 path)
{
return(path.len && (path.ptr[0] == '/'));
}
str8 path_executable(mem_arena* arena) str8 path_executable(mem_arena* arena)
{@autoreleasepool{ {@autoreleasepool{
str8 result = {}; str8 result = {};

View File

@ -7,6 +7,7 @@
*****************************************************************/ *****************************************************************/
#include"platform_io_internal.h" #include"platform_io_internal.h"
#include"platform_path.h"
file_table __globalFileTable = {0}; 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)); 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);
}

View File

@ -12,11 +12,11 @@
#include"platform.h" #include"platform.h"
#if PLATFORM_MACOS || PLATFORM_LINUX #if PLATFORM_MACOS || PLATFORM_LINUX
#define PLATFORM_IO_NATIVE_MEMBER int fd typedef int io_file_desc;
#elif PLATFORM_WINDOWS #elif PLATFORM_WINDOWS
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#include<windows.h> #include<windows.h>
#define PLATFORM_IO_NATIVE_MEMBER HANDLE h typedef HANDLE io_file_desc;
#endif #endif
typedef struct file_slot typedef struct file_slot
@ -27,7 +27,7 @@ typedef struct file_slot
list_elt freeListElt; list_elt freeListElt;
file_access_rights rights; file_access_rights rights;
PLATFORM_IO_NATIVE_MEMBER; io_file_desc fd;
} file_slot; } 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); 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_ #endif //__PLATFORM_IO_INTERNAL_H_

View File

@ -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_join(mem_arena* arena, str8_list elements);
MP_API str8 path_append(mem_arena* arena, str8 parent, str8 relPath); 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_executable(mem_arena* arena);
MP_API str8 path_canonical(mem_arena* arena, str8 path); MP_API str8 path_canonical(mem_arena* arena, str8 path);

View File

@ -15,10 +15,20 @@
#include"platform_io_common.c" #include"platform_io_common.c"
#include"platform_io_internal.c" #include"platform_io_internal.c"
io_error io_convert_errno(int e) io_file_desc io_file_desc_nil()
{ {
io_error error; return(-1);
switch(e) }
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 EPERM:
case EACCES: case EACCES:
@ -178,232 +188,10 @@ int io_update_dir_flags_at(int dirFd, char* path, int flags)
return(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 flags = io_convert_access_rights(accessRights);
int fd; 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};
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)
{
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(".")))
{
//NOTE: skip
continue;
}
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 mode_t mode = S_IRUSR
| S_IWUSR | S_IWUSR
@ -413,10 +201,9 @@ io_cmp io_open_at(file_slot* atSlot, io_req* req, file_table* table)
| S_IWOTH; | S_IWOTH;
mem_arena_scope scratch = mem_scratch_begin(); mem_arena_scope scratch = mem_scratch_begin();
str8 path = str8_from_buffer(req->size, req->buffer);
slot->fd = -1; io_file_desc fd = -1;
if(atSlot) if(dirFd >= 0)
{ {
if(path.len && path.ptr[0] == '/') if(path.len && path.ptr[0] == '/')
{ {
@ -426,63 +213,25 @@ io_cmp io_open_at(file_slot* atSlot, io_req* req, file_table* table)
str8_list_push(scratch.arena, &list, path); str8_list_push(scratch.arena, &list, path);
path = str8_list_join(scratch.arena, list); path = str8_list_join(scratch.arena, list);
} }
}
else
{
dirFd = AT_FDCWD;
}
char* pathCStr = str8_to_cstring(scratch.arena, path); char* pathCStr = str8_to_cstring(scratch.arena, path);
if(req->open.flags & FILE_OPEN_RESTRICT) flags = io_update_dir_flags_at(dirFd, pathCStr, flags);
{
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); fd = openat(dirFd, 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); mem_scratch_end(scratch);
}
cmp.error = slot->error; return(fd);
} }
return(cmp); void io_raw_close(io_file_desc fd)
}
io_cmp io_close(file_slot* slot, io_req* req, file_table* table)
{ {
io_cmp cmp = {0}; close(fd);
if(slot->fd >= 0)
{
close(slot->fd);
}
file_slot_recycle(table, slot);
return(cmp);
} }
file_perm io_convert_perm_from_stat(u16 mode) file_perm io_convert_perm_from_stat(u16 mode)
@ -531,6 +280,148 @@ file_type io_convert_type_from_stat(u16 mode)
return(type); 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 io_fstat(file_slot* slot, io_req* req)
{ {
io_cmp cmp = {0}; io_cmp cmp = {0};
@ -544,7 +435,7 @@ io_cmp io_fstat(file_slot* slot, io_req* req)
struct stat s; struct stat s;
if(fstat(slot->fd, &s)) if(fstat(slot->fd, &s))
{ {
slot->error = io_convert_errno(errno); slot->error = io_raw_last_error();
cmp.error = slot->error; cmp.error = slot->error;
} }
else else
@ -581,7 +472,7 @@ io_cmp io_seek(file_slot* slot, io_req* req)
if(cmp.result < 0) if(cmp.result < 0)
{ {
slot->error = io_convert_errno(errno); slot->error = io_raw_last_error();
cmp.error = slot->error; cmp.error = slot->error;
} }
@ -596,7 +487,7 @@ io_cmp io_read(file_slot* slot, io_req* req)
if(cmp.result < 0) if(cmp.result < 0)
{ {
slot->error = io_convert_errno(errno); slot->error = io_raw_last_error();
cmp.result = 0; cmp.result = 0;
cmp.error = slot->error; cmp.error = slot->error;
} }
@ -612,7 +503,7 @@ io_cmp io_write(file_slot* slot, io_req* req)
if(cmp.result < 0) if(cmp.result < 0)
{ {
slot->error = io_convert_errno(errno); slot->error = io_raw_last_error();
cmp.result = 0; cmp.result = 0;
cmp.error = slot->error; cmp.error = slot->error;
} }

View File

@ -115,7 +115,7 @@ io_file_desc io_file_desc_nil()
return(INVALID_HANDLE_VALUE); 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); 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_error error = IO_OK;
io_file_desc fd = io_raw_open_at(dirFd, name, FILE_ACCESS_READ, FILE_OPEN_SYMLINK); 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(); 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_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); 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(); 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); 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 io_close(file_slot* slot, io_req* req, file_table* table)
{ {
io_cmp cmp = {0}; io_cmp cmp = {0};
if(slot->h) if(slot->fd)
{ {
CloseHandle(slot->h); CloseHandle(slot->fd);
} }
file_slot_recycle(table, slot); file_slot_recycle(table, slot);
return(cmp); return(cmp);
@ -631,7 +557,7 @@ io_cmp io_fstat(file_slot* slot, io_req* req)
} }
else 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; cmp.error = slot->error;
} }
return(cmp); return(cmp);
@ -659,7 +585,7 @@ io_cmp io_seek(file_slot* slot, io_req* req)
LARGE_INTEGER off = {.QuadPart = req->offset}; LARGE_INTEGER off = {.QuadPart = req->offset};
LARGE_INTEGER newPos = {0}; LARGE_INTEGER newPos = {0};
if(!SetFilePointerEx(slot->h, off, &newPos, whence)) if(!SetFilePointerEx(slot->fd, off, &newPos, whence))
{ {
slot->error = io_raw_last_error(); slot->error = io_raw_last_error();
cmp.error = slot->error; cmp.error = slot->error;
@ -678,7 +604,7 @@ io_cmp io_read(file_slot* slot, io_req* req)
DWORD bytesRead = 0; 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(); slot->error = io_raw_last_error();
cmp.result = 0; cmp.result = 0;
@ -697,7 +623,7 @@ io_cmp io_write(file_slot* slot, io_req* req)
DWORD bytesWritten = 0; 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(); slot->error = io_raw_last_error();
cmp.result = 0; cmp.result = 0;

View File

@ -1 +0,0 @@
Hello, world!