[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:
parent
529a13867c
commit
0fa6dcd2ea
|
@ -69,6 +69,131 @@ io_error io_convert_win32_error(int winError)
|
||||||
return(error);
|
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 io_open_at(file_slot* atSlot, io_req* req, file_table* table)
|
||||||
{
|
{
|
||||||
io_cmp cmp = {0};
|
io_cmp cmp = {0};
|
||||||
|
@ -99,10 +224,8 @@ io_cmp io_open_at(file_slot* atSlot, io_req* req, file_table* table)
|
||||||
//NOTE: open
|
//NOTE: open
|
||||||
mem_arena_scope scratch = mem_scratch_begin();
|
mem_arena_scope scratch = mem_scratch_begin();
|
||||||
|
|
||||||
int pathWideSize = 1 + MultiByteToWideChar(CP_UTF8, 0, req->buffer, req->size, NULL, 0);
|
str8 path = str8_from_buffer(req->size, req->buffer);
|
||||||
LPWSTR pathWide = mem_arena_alloc_array(scratch.arena, wchar_t, pathWideSize);
|
str16 pathW = win32_utf8_to_wide_null_terminated(scratch.arena, path);
|
||||||
MultiByteToWideChar(CP_UTF8, 0, req->buffer, req->size, pathWide, pathWideSize);
|
|
||||||
pathWide[pathWideSize-1] = '\0';
|
|
||||||
|
|
||||||
DWORD accessFlags = 0;
|
DWORD accessFlags = 0;
|
||||||
DWORD createFlags = 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
|
//TODO: if FILE_OPEN_RESTRICT, do the full path traversal to check that path is in the
|
||||||
// subtree rooted at atSlot->fd
|
// 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
|
else
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
DWORD atPathWideSize = GetFinalPathNameByHandleW(atSlot->h, NULL, 0, FILE_NAME_NORMALIZED);
|
slot->h = io_open_relative(atSlot->h, path, accessFlags, createFlags, attributesFlags);
|
||||||
if(atPathWideSize)
|
if(slot->h == INVALID_HANDLE_VALUE)
|
||||||
{
|
{
|
||||||
LPWSTR fullPathWide = mem_arena_alloc_array(scratch.arena, wchar_t, atPathWideSize + pathWideSize + 1);
|
slot->fatal = true;
|
||||||
if(GetFinalPathNameByHandleW(atSlot->h, fullPathWide, atPathWideSize, FILE_NAME_NORMALIZED))
|
slot->error = io_convert_win32_error(GetLastError());
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//TODO: take care of share mode and security attributes, make it consistent with posix impl
|
//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);
|
slot->h = CreateFileW(pathW.ptr, accessFlags, 0, NULL, createFlags, attributesFlags, NULL);
|
||||||
}
|
|
||||||
|
|
||||||
mem_scratch_end(scratch);
|
|
||||||
|
|
||||||
if(slot->h == INVALID_HANDLE_VALUE)
|
if(slot->h == INVALID_HANDLE_VALUE)
|
||||||
{
|
{
|
||||||
slot->fatal = true;
|
slot->fatal = true;
|
||||||
slot->error = io_convert_win32_error(GetLastError());
|
slot->error = io_convert_win32_error(GetLastError());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mem_scratch_end(scratch);
|
||||||
|
}
|
||||||
cmp.error = slot->error;
|
cmp.error = slot->error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -221,6 +221,90 @@ str8_list str8_split(mem_arena* arena, str8 str, str8_list separators)
|
||||||
return(list);
|
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
|
// u32 strings
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
|
|
|
@ -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 str8_list_join(mem_arena* arena, str8_list list);
|
||||||
MP_API str8_list str8_split(mem_arena* arena, str8 str, str8_list separators);
|
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
|
// u32 strings
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
|
|
Loading…
Reference in New Issue