[wip, win32, io] win32 file io passing tests (still work to do though)
This commit is contained in:
parent
0fa6dcd2ea
commit
5d2bf9eab9
|
@ -350,6 +350,9 @@ io_open_restrict_result io_open_restrict(int dirFd, str8 path, int flags, mode_t
|
||||||
result.error = IO_ERR_NOT_DIR;
|
result.error = IO_ERR_NOT_DIR;
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
////////////////////////////////////////////////////////
|
||||||
|
//TODO: else open the file with correct flags
|
||||||
|
////////////////////////////////////////////////////////
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include<errno.h>
|
#include<errno.h>
|
||||||
#include<limits.h>
|
#include<limits.h>
|
||||||
#include<shlwapi.h>
|
#include<shlwapi.h>
|
||||||
|
#include<winioctl.h>
|
||||||
|
|
||||||
#include"platform_io_internal.c"
|
#include"platform_io_internal.c"
|
||||||
#include"platform_io_common.c"
|
#include"platform_io_common.c"
|
||||||
|
@ -69,13 +70,6 @@ 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 win32_utf8_to_wide_null_terminated(mem_arena* arena, str8 s)
|
||||||
{
|
{
|
||||||
str16 res = {0};
|
str16 res = {0};
|
||||||
|
@ -86,6 +80,15 @@ str16 win32_utf8_to_wide_null_terminated(mem_arena* arena, str8 s)
|
||||||
return(res);
|
return(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
str8 win32_wide_to_utf8(mem_arena* arena, str16 s)
|
||||||
|
{
|
||||||
|
str8 res = {0};
|
||||||
|
res.len = WideCharToMultiByte(CP_UTF8, 0, s.ptr, s.len, NULL, 0, NULL, NULL);
|
||||||
|
res.ptr = mem_arena_alloc_array(arena, u8, res.len);
|
||||||
|
WideCharToMultiByte(CP_UTF8, 0, s.ptr, s.len, res.ptr, res.len, NULL, NULL);
|
||||||
|
return(res);
|
||||||
|
}
|
||||||
|
|
||||||
str16 win32_path_from_handle_null_terminated(mem_arena* arena, HANDLE handle)
|
str16 win32_path_from_handle_null_terminated(mem_arena* arena, HANDLE handle)
|
||||||
{
|
{
|
||||||
str16 res = {0};
|
str16 res = {0};
|
||||||
|
@ -103,35 +106,242 @@ str16 win32_path_from_handle_null_terminated(mem_arena* arena, HANDLE handle)
|
||||||
return(res);
|
return(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
HANDLE io_open_relative(HANDLE dirHandle, str8 path, DWORD accessFlags, DWORD createFlags, DWORD attributesFlags)
|
HANDLE io_open_relative(HANDLE dirHandle, str8 path, file_access_rights accessRights, file_open_flags openFlags)
|
||||||
{
|
{
|
||||||
HANDLE handle = INVALID_HANDLE_VALUE;
|
HANDLE handle = INVALID_HANDLE_VALUE;
|
||||||
|
|
||||||
mem_arena_scope scratch = mem_scratch_begin();
|
// convert flags
|
||||||
|
DWORD win32AccessFlags = 0;
|
||||||
|
DWORD win32ShareMode = FILE_SHARE_READ|FILE_SHARE_WRITE;
|
||||||
|
DWORD win32CreateFlags = 0;
|
||||||
|
DWORD win32AttributeFlags = FILE_ATTRIBUTE_NORMAL
|
||||||
|
| FILE_FLAG_BACKUP_SEMANTICS;
|
||||||
|
|
||||||
str16 dirPathW = win32_path_from_handle_null_terminated(scratch.arena, dirHandle);
|
if(accessRights & FILE_ACCESS_READ)
|
||||||
|
{
|
||||||
|
win32AccessFlags |= GENERIC_READ;
|
||||||
|
}
|
||||||
|
if(accessRights & FILE_ACCESS_WRITE)
|
||||||
|
{
|
||||||
|
if(accessRights & FILE_OPEN_APPEND)
|
||||||
|
{
|
||||||
|
win32AccessFlags |= FILE_APPEND_DATA;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
win32AccessFlags |= GENERIC_WRITE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(openFlags & FILE_OPEN_TRUNCATE)
|
||||||
|
{
|
||||||
|
if(openFlags & FILE_OPEN_CREATE)
|
||||||
|
{
|
||||||
|
win32CreateFlags |= CREATE_ALWAYS;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
win32CreateFlags |= TRUNCATE_EXISTING;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(openFlags & FILE_OPEN_CREATE)
|
||||||
|
{
|
||||||
|
if(!(win32CreateFlags & CREATE_ALWAYS))
|
||||||
|
{
|
||||||
|
win32CreateFlags |= OPEN_ALWAYS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if( !(win32CreateFlags & OPEN_ALWAYS)
|
||||||
|
&& !(win32CreateFlags & CREATE_ALWAYS)
|
||||||
|
&& !(win32CreateFlags & TRUNCATE_EXISTING))
|
||||||
|
{
|
||||||
|
win32CreateFlags |= OPEN_EXISTING;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(openFlags & FILE_OPEN_SYMLINK)
|
||||||
|
{
|
||||||
|
win32AttributeFlags |= FILE_FLAG_OPEN_REPARSE_POINT;
|
||||||
|
}
|
||||||
|
|
||||||
|
mem_arena_scope scratch = mem_scratch_begin();
|
||||||
str16 pathW = win32_utf8_to_wide_null_terminated(scratch.arena, path);
|
str16 pathW = win32_utf8_to_wide_null_terminated(scratch.arena, path);
|
||||||
|
|
||||||
if(dirPathW.len && pathW.len)
|
if(dirHandle == NULL || dirHandle == INVALID_HANDLE_VALUE)
|
||||||
{
|
{
|
||||||
u64 fullPathWSize = dirPathW.len + pathW.len;
|
handle = CreateFileW(pathW.ptr, win32AccessFlags, win32ShareMode, NULL, win32CreateFlags, win32AttributeFlags, NULL);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
str16 dirPathW = win32_path_from_handle_null_terminated(scratch.arena, dirHandle);
|
||||||
|
|
||||||
|
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, win32AccessFlags, win32ShareMode, NULL, win32CreateFlags, win32AttributeFlags, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mem_scratch_end(scratch);
|
||||||
return(handle);
|
return(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
u64 io_win32_file_uid(HANDLE h)
|
||||||
io_open_restrict_result io_open_path_restrict(HANDLE dirHandle, str8 path, DWORD accessFlags, DWORD createFlags, DWORD attributesFalgs)
|
|
||||||
{
|
{
|
||||||
io_open_restrict_result res = {0};
|
BY_HANDLE_FILE_INFORMATION fileInfo;
|
||||||
|
GetFileInformationByHandle(h, &fileInfo);
|
||||||
|
u64 id = ((u64)fileInfo.nFileIndexHigh<<32) | ((u64)fileInfo.nFileIndexLow);
|
||||||
|
return(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
io_error io_win32_stat_from_handle(HANDLE h, file_status* status)
|
||||||
|
{
|
||||||
|
io_error error = IO_OK;
|
||||||
|
|
||||||
|
BY_HANDLE_FILE_INFORMATION info;
|
||||||
|
if(!GetFileInformationByHandle(h, &info))
|
||||||
|
{
|
||||||
|
error = io_convert_win32_error(GetLastError());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
status->size = (((u64)info.nFileSizeHigh)<<32) | ((u64)info.nFileSizeLow);
|
||||||
|
|
||||||
|
DWORD attrRegularSet = FILE_ATTRIBUTE_ARCHIVE
|
||||||
|
| FILE_ATTRIBUTE_COMPRESSED
|
||||||
|
| FILE_ATTRIBUTE_ENCRYPTED
|
||||||
|
| FILE_ATTRIBUTE_HIDDEN
|
||||||
|
| FILE_ATTRIBUTE_NORMAL
|
||||||
|
| FILE_ATTRIBUTE_NOT_CONTENT_INDEXED
|
||||||
|
| FILE_ATTRIBUTE_OFFLINE
|
||||||
|
| FILE_ATTRIBUTE_READONLY
|
||||||
|
| FILE_ATTRIBUTE_SPARSE_FILE
|
||||||
|
| FILE_ATTRIBUTE_SYSTEM
|
||||||
|
| FILE_ATTRIBUTE_TEMPORARY;
|
||||||
|
|
||||||
|
if((info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT))
|
||||||
|
{
|
||||||
|
FILE_ATTRIBUTE_TAG_INFO tagInfo;
|
||||||
|
if(!GetFileInformationByHandleEx(h, FileAttributeTagInfo, &tagInfo, sizeof(tagInfo)))
|
||||||
|
{
|
||||||
|
error = io_convert_win32_error(GetLastError());
|
||||||
|
}
|
||||||
|
else if(tagInfo.ReparseTag == IO_REPARSE_TAG_SYMLINK)
|
||||||
|
{
|
||||||
|
status->type = MP_FILE_SYMLINK;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
status->type = MP_FILE_UNKNOWN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
||||||
|
{
|
||||||
|
status->type = MP_FILE_DIRECTORY;
|
||||||
|
}
|
||||||
|
else if(info.dwFileAttributes & attrRegularSet)
|
||||||
|
{
|
||||||
|
status->type = MP_FILE_REGULAR;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//TODO: might want to check for socket/block/character devices? (otoh MS STL impl. doesn't seem to do it)
|
||||||
|
status->type = MP_FILE_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
status->perm = MP_FILE_OWNER_READ | MP_FILE_GROUP_READ | MP_FILE_OTHER_READ;
|
||||||
|
if(!(info.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
|
||||||
|
{
|
||||||
|
status->perm = MP_FILE_OWNER_WRITE | MP_FILE_GROUP_WRITE | MP_FILE_OTHER_WRITE;
|
||||||
|
}
|
||||||
|
//TODO: times
|
||||||
|
}
|
||||||
|
return(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
ULONG ReparseTag;
|
||||||
|
USHORT ReparseDataLength;
|
||||||
|
USHORT Reserved;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
USHORT SubstituteNameOffset;
|
||||||
|
USHORT SubstituteNameLength;
|
||||||
|
USHORT PrintNameOffset;
|
||||||
|
USHORT PrintNameLength;
|
||||||
|
ULONG Flags;
|
||||||
|
WCHAR PathBuffer[1];
|
||||||
|
} SymbolicLinkReparseBuffer;
|
||||||
|
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
USHORT SubstituteNameOffset;
|
||||||
|
USHORT SubstituteNameLength;
|
||||||
|
USHORT PrintNameOffset;
|
||||||
|
USHORT PrintNameLength;
|
||||||
|
WCHAR PathBuffer[1];
|
||||||
|
} MountPointReparseBuffer;
|
||||||
|
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
UCHAR DataBuffer[1];
|
||||||
|
} GenericReparseBuffer;
|
||||||
|
};
|
||||||
|
} REPARSE_DATA_BUFFER;
|
||||||
|
|
||||||
|
typedef struct io_win32_read_link_result
|
||||||
|
{
|
||||||
|
io_error error;
|
||||||
|
str8 targetPath;
|
||||||
|
} io_win32_read_link_result;
|
||||||
|
|
||||||
|
io_win32_read_link_result io_win32_read_link(mem_arena* arena, HANDLE handle)
|
||||||
|
{
|
||||||
|
io_win32_read_link_result result = {0};
|
||||||
|
|
||||||
|
char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
|
||||||
|
DWORD bytesReturned;
|
||||||
|
|
||||||
|
if(!DeviceIoControl(handle, FSCTL_GET_REPARSE_POINT, NULL, 0, buffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &bytesReturned, 0))
|
||||||
|
{
|
||||||
|
result.error = io_convert_win32_error(GetLastError());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
REPARSE_DATA_BUFFER* reparse = (REPARSE_DATA_BUFFER*)buffer;
|
||||||
|
if(reparse->ReparseTag == IO_REPARSE_TAG_SYMLINK)
|
||||||
|
{
|
||||||
|
str16 nameW = {0};
|
||||||
|
nameW.len = reparse->SymbolicLinkReparseBuffer.SubstituteNameLength / sizeof(wchar_t);
|
||||||
|
nameW.ptr = (u16*)((char*)reparse->SymbolicLinkReparseBuffer.PathBuffer + reparse->SymbolicLinkReparseBuffer.SubstituteNameOffset);
|
||||||
|
result.targetPath = win32_wide_to_utf8(arena, nameW);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result.error = IO_ERR_UNKNOWN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct io_open_restrict_result
|
||||||
|
{
|
||||||
|
io_error error;
|
||||||
|
HANDLE h;
|
||||||
|
} io_open_restrict_result;
|
||||||
|
|
||||||
|
io_open_restrict_result io_open_path_restrict(HANDLE dirHandle, str8 path, file_access_rights accessRights, file_open_flags openFlags)
|
||||||
|
{
|
||||||
|
io_open_restrict_result result = {0};
|
||||||
|
|
||||||
mem_arena_scope scratch = mem_scratch_begin();
|
mem_arena_scope scratch = mem_scratch_begin();
|
||||||
|
|
||||||
|
@ -139,8 +349,9 @@ io_open_restrict_result io_open_path_restrict(HANDLE dirHandle, str8 path, DWORD
|
||||||
str8_list_push(scratch.arena, &sep, STR8("/"));
|
str8_list_push(scratch.arena, &sep, STR8("/"));
|
||||||
str8_list pathElements = str8_split(scratch.arena, path, sep);
|
str8_list pathElements = str8_split(scratch.arena, path, sep);
|
||||||
|
|
||||||
HANDLE handle = NULL;
|
u64 rootUID = io_win32_file_uid(dirHandle);
|
||||||
DuplicateHandle(GetCurrentProcess(), dirHandle, GetCurrentProcess(), &handle);
|
|
||||||
|
HANDLE handle = dirHandle;
|
||||||
|
|
||||||
for_list(&pathElements.list, elt, str8_elt, listElt)
|
for_list(&pathElements.list, elt, str8_elt, listElt)
|
||||||
{
|
{
|
||||||
|
@ -149,12 +360,12 @@ io_open_restrict_result io_open_path_restrict(HANDLE dirHandle, str8 path, DWORD
|
||||||
if(!str8_cmp(name, STR8(".")))
|
if(!str8_cmp(name, STR8(".")))
|
||||||
{
|
{
|
||||||
//NOTE: skip;
|
//NOTE: skip;
|
||||||
continue
|
continue;
|
||||||
}
|
}
|
||||||
else if(!str8_cmp(name, STR8("..")))
|
else if(!str8_cmp(name, STR8("..")))
|
||||||
{
|
{
|
||||||
//NOTE: check that we don't escape root dir
|
//NOTE: check that we don't escape root dir
|
||||||
if(CompareObjectHandles(dirHandle, handle))
|
if(io_win32_file_uid(handle) == rootUID)
|
||||||
{
|
{
|
||||||
result.error = IO_ERR_WALKOUT;
|
result.error = IO_ERR_WALKOUT;
|
||||||
goto error;
|
goto error;
|
||||||
|
@ -162,37 +373,151 @@ io_open_restrict_result io_open_path_restrict(HANDLE dirHandle, str8 path, DWORD
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Open parent and continue
|
// Open parent and continue
|
||||||
|
HANDLE nextHandle = io_open_relative(handle, STR8(".."), FILE_ACCESS_READ, 0);
|
||||||
HANDLE nextHandle = NULL;
|
if(nextHandle == INVALID_HANDLE_VALUE)
|
||||||
OBJECT_ATTRIBUTES attributes;
|
{
|
||||||
//TODO initialize attributes
|
result.error = io_convert_win32_error(GetLastError());
|
||||||
|
goto error;
|
||||||
IO_STATUS_BLOCK status;
|
}
|
||||||
|
else
|
||||||
NtCreateFile(&nextHandle,
|
{
|
||||||
FILE_LIST_DIRECTORY|FILE_TRAVERSE,
|
if(handle != dirHandle)
|
||||||
&attributes,
|
{
|
||||||
&status,
|
CloseHandle(handle);
|
||||||
0,
|
}
|
||||||
FILE_ATTRIBUTE_NORMAL,
|
handle = nextHandle;
|
||||||
FILE_SHARE_READ,
|
}
|
||||||
FILE_OPEN,
|
|
||||||
FILE_DIRECTORY_FILE,
|
|
||||||
NULL,
|
|
||||||
0);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//NOTE: open that dir, check if dir/symlink/etc
|
//TODO: open that dir, check if dir/symlink/etc
|
||||||
|
|
||||||
|
HANDLE statHandle = io_open_relative(handle, name, FILE_ACCESS_READ, FILE_OPEN_SYMLINK);
|
||||||
|
if(statHandle == INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
result.error = io_convert_win32_error(GetLastError());
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
file_status status = {0};
|
||||||
|
result.error = io_win32_stat_from_handle(statHandle, &status);
|
||||||
|
CloseHandle(statHandle);
|
||||||
|
if(result.error)
|
||||||
|
{
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(status.type == MP_FILE_SYMLINK)
|
||||||
|
{
|
||||||
|
//TODO: read link target and add to file
|
||||||
|
HANDLE link = io_open_relative(handle, name, FILE_ACCESS_READ, FILE_OPEN_SYMLINK);
|
||||||
|
if(link == INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
result.error = io_convert_win32_error(GetLastError());
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
io_win32_read_link_result linkResult = io_win32_read_link(scratch.arena, link);
|
||||||
|
CloseHandle(link);
|
||||||
|
|
||||||
|
if(linkResult.error)
|
||||||
|
{
|
||||||
|
result.error = linkResult.error;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
if(linkResult.targetPath.len == 0)
|
||||||
|
{
|
||||||
|
// skip
|
||||||
|
}
|
||||||
|
else if(linkResult.targetPath.ptr[0] == '/'
|
||||||
|
||linkResult.targetPath.ptr[0] == '\\')
|
||||||
|
{
|
||||||
|
result.error = IO_ERR_WALKOUT;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
str8_list linkElements = str8_split(scratch.arena, linkResult.targetPath, 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
|
||||||
|
HANDLE nextHandle = io_open_relative(handle, name, FILE_ACCESS_READ, 0);
|
||||||
|
|
||||||
|
if(nextHandle == INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
result.error = io_convert_win32_error(GetLastError());
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(handle != dirHandle)
|
||||||
|
{
|
||||||
|
CloseHandle(handle);
|
||||||
|
}
|
||||||
|
handle = nextHandle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(status.type == MP_FILE_REGULAR)
|
||||||
|
{
|
||||||
|
//TODO: check that we're at the end and open that file
|
||||||
|
if(&elt->listElt != list_last(&pathElements.list))
|
||||||
|
{
|
||||||
|
result.error = IO_ERR_NOT_DIR;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//NOTE: open the file
|
||||||
|
HANDLE nextHandle = io_open_relative(handle, name, accessRights, openFlags);
|
||||||
|
if(nextHandle == INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
result.error = io_convert_win32_error(GetLastError());
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(handle != dirHandle)
|
||||||
|
{
|
||||||
|
CloseHandle(handle);
|
||||||
|
}
|
||||||
|
handle = nextHandle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result.error = IO_ERR_NOT_DIR;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
goto end;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
return(res);
|
{
|
||||||
|
if(handle != dirHandle)
|
||||||
|
{
|
||||||
|
CloseHandle(handle);
|
||||||
|
handle = INVALID_HANDLE_VALUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end:
|
||||||
|
result.h = handle;
|
||||||
|
mem_scratch_end(scratch);
|
||||||
|
return(result);
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
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)
|
||||||
{
|
{
|
||||||
|
@ -221,71 +546,18 @@ io_cmp io_open_at(file_slot* atSlot, io_req* req, file_table* table)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//NOTE: open
|
|
||||||
mem_arena_scope scratch = mem_scratch_begin();
|
mem_arena_scope scratch = mem_scratch_begin();
|
||||||
|
|
||||||
str8 path = str8_from_buffer(req->size, req->buffer);
|
str8 path = str8_from_buffer(req->size, req->buffer);
|
||||||
str16 pathW = win32_utf8_to_wide_null_terminated(scratch.arena, path);
|
str16 pathW = win32_utf8_to_wide_null_terminated(scratch.arena, path);
|
||||||
|
|
||||||
DWORD accessFlags = 0;
|
|
||||||
DWORD createFlags = 0;
|
|
||||||
DWORD attributesFlags = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS;
|
|
||||||
|
|
||||||
if(req->open.rights & FILE_ACCESS_READ)
|
|
||||||
{
|
|
||||||
accessFlags |= GENERIC_READ;
|
|
||||||
}
|
|
||||||
if(req->open.rights & FILE_ACCESS_WRITE)
|
|
||||||
{
|
|
||||||
if(req->open.rights & FILE_OPEN_APPEND)
|
|
||||||
{
|
|
||||||
accessFlags |= FILE_APPEND_DATA;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
accessFlags |= GENERIC_WRITE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(req->open.flags & FILE_OPEN_TRUNCATE)
|
|
||||||
{
|
|
||||||
if(req->open.flags & FILE_OPEN_CREATE)
|
|
||||||
{
|
|
||||||
createFlags |= CREATE_ALWAYS;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
createFlags |= TRUNCATE_EXISTING;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(req->open.flags & FILE_OPEN_CREATE)
|
|
||||||
{
|
|
||||||
if(!createFlags & CREATE_ALWAYS)
|
|
||||||
{
|
|
||||||
createFlags |= OPEN_ALWAYS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if( !(createFlags & OPEN_ALWAYS)
|
|
||||||
&& !(createFlags & CREATE_ALWAYS)
|
|
||||||
&& !(createFlags & TRUNCATE_EXISTING))
|
|
||||||
{
|
|
||||||
createFlags |= OPEN_EXISTING;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(req->open.flags & FILE_OPEN_SYMLINK)
|
|
||||||
{
|
|
||||||
attributesFlags |= FILE_FLAG_OPEN_REPARSE_POINT;
|
|
||||||
}
|
|
||||||
|
|
||||||
slot->h = INVALID_HANDLE_VALUE;
|
slot->h = INVALID_HANDLE_VALUE;
|
||||||
if(atSlot)
|
if(atSlot)
|
||||||
{
|
{
|
||||||
/*
|
|
||||||
if(req->open.flags & FILE_OPEN_RESTRICT)
|
if(req->open.flags & FILE_OPEN_RESTRICT)
|
||||||
{
|
{
|
||||||
//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);
|
io_open_restrict_result res = io_open_path_restrict(atSlot->h, path, req->open.rights, req->open.flags);
|
||||||
if(res.error)
|
if(res.error)
|
||||||
{
|
{
|
||||||
slot->fatal = true;
|
slot->fatal = true;
|
||||||
|
@ -293,9 +565,8 @@ io_cmp io_open_at(file_slot* atSlot, io_req* req, file_table* table)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
*/
|
|
||||||
{
|
{
|
||||||
slot->h = io_open_relative(atSlot->h, path, accessFlags, createFlags, attributesFlags);
|
slot->h = io_open_relative(atSlot->h, path, req->open.rights, req->open.flags);
|
||||||
if(slot->h == INVALID_HANDLE_VALUE)
|
if(slot->h == INVALID_HANDLE_VALUE)
|
||||||
{
|
{
|
||||||
slot->fatal = true;
|
slot->fatal = true;
|
||||||
|
@ -306,7 +577,7 @@ io_cmp io_open_at(file_slot* atSlot, io_req* req, file_table* table)
|
||||||
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(pathW.ptr, accessFlags, 0, NULL, createFlags, attributesFlags, NULL);
|
slot->h = io_open_relative(NULL, path, req->open.rights, req->open.flags);
|
||||||
if(slot->h == INVALID_HANDLE_VALUE)
|
if(slot->h == INVALID_HANDLE_VALUE)
|
||||||
{
|
{
|
||||||
slot->fatal = true;
|
slot->fatal = true;
|
||||||
|
@ -343,69 +614,8 @@ io_cmp io_fstat(file_slot* slot, io_req* req)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
BY_HANDLE_FILE_INFORMATION info;
|
slot->error = io_win32_stat_from_handle(slot->h, (file_status*)req->buffer);
|
||||||
if(!GetFileInformationByHandle(slot->h, &info))
|
cmp.error = slot->error;
|
||||||
{
|
|
||||||
slot->error = io_convert_win32_error(GetLastError());
|
|
||||||
cmp.error = slot->error;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
file_status* status = (file_status*)req->buffer;
|
|
||||||
|
|
||||||
status->size = (((u64)info.nFileSizeHigh)<<32) | ((u64)info.nFileSizeLow);
|
|
||||||
|
|
||||||
DWORD attrRegularSet = FILE_ATTRIBUTE_ARCHIVE
|
|
||||||
| FILE_ATTRIBUTE_COMPRESSED
|
|
||||||
| FILE_ATTRIBUTE_ENCRYPTED
|
|
||||||
| FILE_ATTRIBUTE_HIDDEN
|
|
||||||
| FILE_ATTRIBUTE_NORMAL
|
|
||||||
| FILE_ATTRIBUTE_NOT_CONTENT_INDEXED
|
|
||||||
| FILE_ATTRIBUTE_OFFLINE
|
|
||||||
| FILE_ATTRIBUTE_READONLY
|
|
||||||
| FILE_ATTRIBUTE_SPARSE_FILE
|
|
||||||
| FILE_ATTRIBUTE_SYSTEM
|
|
||||||
| FILE_ATTRIBUTE_TEMPORARY;
|
|
||||||
|
|
||||||
if(info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
|
||||||
{
|
|
||||||
status->type = MP_FILE_DIRECTORY;
|
|
||||||
}
|
|
||||||
else if((info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT))
|
|
||||||
{
|
|
||||||
FILE_ATTRIBUTE_TAG_INFO tagInfo;
|
|
||||||
if(!GetFileInformationByHandleEx(slot->h, FileAttributeTagInfo, &tagInfo, sizeof(tagInfo)))
|
|
||||||
{
|
|
||||||
slot->error = io_convert_win32_error(GetLastError());
|
|
||||||
cmp.error = slot->error;
|
|
||||||
}
|
|
||||||
else if(tagInfo.ReparseTag == IO_REPARSE_TAG_SYMLINK)
|
|
||||||
{
|
|
||||||
status->type = MP_FILE_SYMLINK;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
status->type = MP_FILE_UNKNOWN;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if(info.dwFileAttributes & attrRegularSet)
|
|
||||||
{
|
|
||||||
status->type = MP_FILE_REGULAR;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//TODO: might want to check for socket/block/character devices? (otoh MS STL impl. doesn't seem to do it)
|
|
||||||
status->type = MP_FILE_UNKNOWN;
|
|
||||||
}
|
|
||||||
|
|
||||||
status->perm = MP_FILE_OWNER_READ | MP_FILE_GROUP_READ | MP_FILE_OTHER_READ;
|
|
||||||
if(!(info.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
|
|
||||||
{
|
|
||||||
status->perm = MP_FILE_OWNER_WRITE | MP_FILE_GROUP_WRITE | MP_FILE_OTHER_WRITE;
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO: times
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return(cmp);
|
return(cmp);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue