[win32, io]

- Added str16 functions for dealing with win32 wide char strings
- Added io_open_relative to open a path relative to an already opened handle (with no escape checking)
This commit is contained in:
martinfouilleul 2023-06-14 12:03:50 +02:00
parent 529a13867c
commit 0fa6dcd2ea
3 changed files with 262 additions and 26 deletions

View File

@ -69,6 +69,131 @@ io_error io_convert_win32_error(int winError)
return(error);
}
typedef struct io_open_restrict_result
{
io_error error;
HANDLE h;
} io_open_restrict_result;
str16 win32_utf8_to_wide_null_terminated(mem_arena* arena, str8 s)
{
str16 res = {0};
res.len = 1 + MultiByteToWideChar(CP_UTF8, 0, s.ptr, s.len, NULL, 0);
res.ptr = mem_arena_alloc_array(arena, u16, res.len);
MultiByteToWideChar(CP_UTF8, 0, s.ptr, s.len, res.ptr, res.len);
res.ptr[res.len-1] = '\0';
return(res);
}
str16 win32_path_from_handle_null_terminated(mem_arena* arena, HANDLE handle)
{
str16 res = {0};
res.len = GetFinalPathNameByHandleW(handle, NULL, 0, FILE_NAME_NORMALIZED);
if(res.len)
{
res.ptr = mem_arena_alloc_array(arena, u16, res.len);
if(!GetFinalPathNameByHandleW(handle, res.ptr, res.len, FILE_NAME_NORMALIZED))
{
res.len = 0;
res.ptr = 0;
}
}
return(res);
}
HANDLE io_open_relative(HANDLE dirHandle, str8 path, DWORD accessFlags, DWORD createFlags, DWORD attributesFlags)
{
HANDLE handle = INVALID_HANDLE_VALUE;
mem_arena_scope scratch = mem_scratch_begin();
str16 dirPathW = win32_path_from_handle_null_terminated(scratch.arena, dirHandle);
str16 pathW = win32_utf8_to_wide_null_terminated(scratch.arena, path);
if(dirPathW.len && pathW.len)
{
u64 fullPathWSize = dirPathW.len + pathW.len;
LPWSTR fullPathW = mem_arena_alloc_array(scratch.arena, u16, fullPathWSize);
memcpy(fullPathW, dirPathW.ptr, (dirPathW.len-1)*sizeof(u16));
fullPathW[dirPathW.len-1] = '\\';
memcpy(fullPathW + dirPathW.len, pathW.ptr, pathW.len*sizeof(u16));
LPWSTR canonical = mem_arena_alloc_array(scratch.arena, wchar_t, fullPathWSize);
PathCanonicalizeW(canonical, fullPathW);
handle = CreateFileW(canonical, accessFlags, 0, NULL, createFlags, attributesFlags, NULL);
}
return(handle);
}
/*
io_open_restrict_result io_open_path_restrict(HANDLE dirHandle, str8 path, DWORD accessFlags, DWORD createFlags, DWORD attributesFalgs)
{
io_open_restrict_result res = {0};
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);
HANDLE handle = NULL;
DuplicateHandle(GetCurrentProcess(), dirHandle, GetCurrentProcess(), &handle);
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(CompareObjectHandles(dirHandle, handle))
{
result.error = IO_ERR_WALKOUT;
goto error;
}
else
{
// Open parent and continue
HANDLE nextHandle = NULL;
OBJECT_ATTRIBUTES attributes;
//TODO initialize attributes
IO_STATUS_BLOCK status;
NtCreateFile(&nextHandle,
FILE_LIST_DIRECTORY|FILE_TRAVERSE,
&attributes,
&status,
0,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ,
FILE_OPEN,
FILE_DIRECTORY_FILE,
NULL,
0);
}
}
else
{
//NOTE: open that dir, check if dir/symlink/etc
}
}
error:
return(res);
}
*/
io_cmp io_open_at(file_slot* atSlot, io_req* req, file_table* table)
{
io_cmp cmp = {0};
@ -99,10 +224,8 @@ io_cmp io_open_at(file_slot* atSlot, io_req* req, file_table* table)
//NOTE: open
mem_arena_scope scratch = mem_scratch_begin();
int pathWideSize = 1 + MultiByteToWideChar(CP_UTF8, 0, req->buffer, req->size, NULL, 0);
LPWSTR pathWide = mem_arena_alloc_array(scratch.arena, wchar_t, pathWideSize);
MultiByteToWideChar(CP_UTF8, 0, req->buffer, req->size, pathWide, pathWideSize);
pathWide[pathWideSize-1] = '\0';
str8 path = str8_from_buffer(req->size, req->buffer);
str16 pathW = win32_utf8_to_wide_null_terminated(scratch.arena, path);
DWORD accessFlags = 0;
DWORD createFlags = 0;
@ -162,41 +285,37 @@ io_cmp io_open_at(file_slot* atSlot, io_req* req, file_table* table)
{
//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, accessFlags, createFlags, attributesFalgs);
if(res.error)
{
slot->fatal = true;
slot->error = res.error;
}
}
else
*/
{
DWORD atPathWideSize = GetFinalPathNameByHandleW(atSlot->h, NULL, 0, FILE_NAME_NORMALIZED);
if(atPathWideSize)
slot->h = io_open_relative(atSlot->h, path, accessFlags, createFlags, attributesFlags);
if(slot->h == INVALID_HANDLE_VALUE)
{
LPWSTR fullPathWide = mem_arena_alloc_array(scratch.arena, wchar_t, atPathWideSize + pathWideSize + 1);
if(GetFinalPathNameByHandleW(atSlot->h, fullPathWide, atPathWideSize, FILE_NAME_NORMALIZED))
{
fullPathWide[atPathWideSize-1] = '\\';
memcpy(fullPathWide + atPathWideSize, pathWide, pathWideSize*sizeof(wchar_t));
LPWSTR canonical = mem_arena_alloc_array(scratch.arena, wchar_t, atPathWideSize + pathWideSize + 1);
PathCanonicalizeW(canonical, fullPathWide);
slot->h = CreateFileW(canonical, accessFlags, 0, NULL, createFlags, attributesFlags, NULL);
}
slot->fatal = true;
slot->error = io_convert_win32_error(GetLastError());
}
}
}
else
{
//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);
slot->h = CreateFileW(pathW.ptr, accessFlags, 0, NULL, createFlags, attributesFlags, NULL);
if(slot->h == INVALID_HANDLE_VALUE)
{
slot->fatal = true;
slot->error = io_convert_win32_error(GetLastError());
}
}
mem_scratch_end(scratch);
}
cmp.error = slot->error;
}

View File

@ -221,6 +221,90 @@ str8_list str8_split(mem_arena* arena, str8 str, str8_list separators)
return(list);
}
//----------------------------------------------------------------------------------
// u16 strings
//----------------------------------------------------------------------------------
str16 str16_from_buffer(u64 len, u16* buffer)
{
return((str16){.len = len, .ptr = buffer});
}
str16 str16_slice(str16 s, u64 start, u64 end)
{
ASSERT(start <= end && start <= s.len && end <= s.len);
return((str16){.len = end - start, .ptr = s.ptr + start});
}
str16 str16_push_buffer(mem_arena* arena, u64 len, u16* buffer)
{
str16 str = {0};
str.len = len;
str.ptr = mem_arena_alloc_array(arena, u16, len);
memcpy(str.ptr, buffer, len*sizeof(u16));
return(str);
}
str16 str16_push_copy(mem_arena* arena, str16 s)
{
return(str16_push_buffer(arena, s.len, s.ptr));
}
str16 str16_push_slice(mem_arena* arena, str16 s, u64 start, u64 end)
{
str16 slice = str16_slice(s, start, end);
return(str16_push_copy(arena, slice));
}
void str16_list_init(str16_list* list)
{
list_init(&list->list);
list->eltCount = 0;
list->len = 0;
}
void str16_list_push(mem_arena* arena, str16_list* list, str16 str)
{
str16_elt* elt = mem_arena_alloc_type(arena, str16_elt);
elt->string = str;
list_append(&list->list, &elt->listElt);
list->eltCount++;
list->len += str.len;
}
str16 str16_list_collate(mem_arena* arena, str16_list list, str16 prefix, str16 separator, str16 postfix)
{
str16 str = {0};
str.len = prefix.len + list.len + list.eltCount*separator.len + postfix.len;
str.ptr = mem_arena_alloc_array(arena, u16, str.len);
char* dst = (char*)str.ptr;
memcpy(dst, prefix.ptr, prefix.len*sizeof(u16));
dst += prefix.len*sizeof(u16);
str16_elt* elt = list_first_entry(&list.list, str16_elt, listElt);
if(elt)
{
memcpy(dst, elt->string.ptr, elt->string.len*sizeof(u16));
dst += elt->string.len*sizeof(u16);
elt = list_next_entry(&list.list, elt, str16_elt, listElt);
}
for( ; elt != 0; elt = list_next_entry(&list.list, elt, str16_elt, listElt))
{
memcpy(dst, separator.ptr, separator.len*sizeof(u16));
dst += separator.len*sizeof(u16);
memcpy(dst, elt->string.ptr, elt->string.len*sizeof(u16));
dst += elt->string.len*sizeof(u16);
}
memcpy(dst, postfix.ptr, postfix.len*sizeof(u16));
return(str);
}
str16 str16_list_join(mem_arena* arena, str16_list list)
{
str16 empty = {.len = 0, .ptr = 0};
return(str16_list_collate(arena, list, empty, empty, empty));
}
//----------------------------------------------------------------------------------
// u32 strings
//----------------------------------------------------------------------------------

View File

@ -70,6 +70,39 @@ MP_API str8 str8_list_collate(mem_arena* arena, str8_list list, str8 prefix, str
MP_API str8 str8_list_join(mem_arena* arena, str8_list list);
MP_API str8_list str8_split(mem_arena* arena, str8 str, str8_list separators);
//----------------------------------------------------------------------------------
// u16 strings
//----------------------------------------------------------------------------------
typedef struct str16
{
u64 len;
u16* ptr;
} str16;
MP_API str16 str16_from_buffer(u64 len, u16* buffer);
MP_API str16 str16_slice(str16 s, u64 start, u64 end);
MP_API str16 str16_push_buffer(mem_arena* arena, u64 len, u16* buffer);
MP_API str16 str16_push_copy(mem_arena* arena, str16 s);
MP_API str16 str16_push_slice(mem_arena* arena, str16 s, u64 start, u64 end);
typedef struct str16_elt
{
list_elt listElt;
str16 string;
} str16_elt;
typedef struct str16_list
{
list_info list;
u64 eltCount;
u64 len;
} str16_list;
MP_API void str16_list_push(mem_arena* arena, str16_list* list, str16 str);
MP_API str16 str16_list_join(mem_arena* arena, str16_list list);
MP_API str16_list str16_split(mem_arena* arena, str16 str, str16_list separators);
//----------------------------------------------------------------------------------
// u32 strings
//----------------------------------------------------------------------------------