[win32, io] implement IO_OP_OPEN_AT with non-null base directory handle
This commit is contained in:
parent
0bd985efbc
commit
9954b69eda
|
@ -6,6 +6,6 @@ set glsl_shaders=src\glsl_shaders\common.glsl src\glsl_shaders\blit_vertex.glsl
|
||||||
call python3 scripts\embed_text.py %glsl_shaders% --prefix=glsl_ --output src\glsl_shaders.h
|
call python3 scripts\embed_text.py %glsl_shaders% --prefix=glsl_ --output src\glsl_shaders.h
|
||||||
|
|
||||||
set INCLUDES=/I src /I src/util /I src/platform /I ext /I ext/angle_headers
|
set INCLUDES=/I src /I src/util /I src/platform /I ext /I ext/angle_headers
|
||||||
set LIBS=user32.lib opengl32.lib gdi32.lib shcore.lib delayimp.lib dwmapi.lib comctl32.lib ole32.lib shell32.lib /LIBPATH:./bin libEGL.dll.lib libGLESv2.dll.lib /DELAYLOAD:libEGL.dll /DELAYLOAD:libGLESv2.dll
|
set LIBS=user32.lib opengl32.lib gdi32.lib shcore.lib delayimp.lib dwmapi.lib comctl32.lib ole32.lib shell32.lib shlwapi.lib /LIBPATH:./bin libEGL.dll.lib libGLESv2.dll.lib /DELAYLOAD:libEGL.dll /DELAYLOAD:libGLESv2.dll
|
||||||
|
|
||||||
cl /we4013 /Zi /Zc:preprocessor /DMP_BUILD_DLL /std:c11 %INCLUDES% src/milepost.c /Fo:bin/milepost.o /LD /link /MANIFEST:EMBED /MANIFESTINPUT:src/win32_manifest.xml %LIBS% /OUT:bin/milepost.dll /IMPLIB:bin/milepost.dll.lib
|
cl /we4013 /Zi /Zc:preprocessor /DMP_BUILD_DLL /std:c11 %INCLUDES% src/milepost.c /Fo:bin/milepost.o /LD /link /MANIFEST:EMBED /MANIFESTINPUT:src/win32_manifest.xml %LIBS% /OUT:bin/milepost.dll /IMPLIB:bin/milepost.dll.lib
|
||||||
|
|
|
@ -17,7 +17,6 @@ file_slot* file_slot_alloc(file_table* table)
|
||||||
{
|
{
|
||||||
slot = &table->slots[table->nextSlot];
|
slot = &table->slots[table->nextSlot];
|
||||||
slot->generation = 1;
|
slot->generation = 1;
|
||||||
slot->fd = -1;
|
|
||||||
table->nextSlot++;
|
table->nextSlot++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
#define PLATFORM_IO_NATIVE_MEMBER int fd
|
#define PLATFORM_IO_NATIVE_MEMBER int fd
|
||||||
#elif PLATFORM_WINDOWS
|
#elif PLATFORM_WINDOWS
|
||||||
#define WIN32_LEAN_AND_MEAN
|
#define WIN32_LEAN_AND_MEAN
|
||||||
#include<windows>
|
#include<windows.h>
|
||||||
#define PLATFORM_IO_NATIVE_MEMBER HANDLE h
|
#define PLATFORM_IO_NATIVE_MEMBER HANDLE h
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
#include<errno.h>
|
#include<errno.h>
|
||||||
#include<limits.h>
|
#include<limits.h>
|
||||||
|
#include<shlwapi.h>
|
||||||
|
|
||||||
#include"platform_io_internal.c"
|
#include"platform_io_internal.c"
|
||||||
#include"platform_io_common.c"
|
#include"platform_io_common.c"
|
||||||
|
@ -82,81 +83,119 @@ io_cmp io_open_at(file_slot* atSlot, io_req* req, file_table* table)
|
||||||
{
|
{
|
||||||
cmp.handle = file_handle_from_slot(table, slot);
|
cmp.handle = file_handle_from_slot(table, slot);
|
||||||
|
|
||||||
//NOTE: open
|
slot->rights = req->open.rights;
|
||||||
mem_arena_scope scratch = mem_scratch_begin();
|
if(atSlot)
|
||||||
|
|
||||||
int sizeWide = 1 + MultiByteToWideChar(CP_UTF8, 0, req->buffer, req->size, NULL, 0);
|
|
||||||
LPWSTR pathWide = mem_arena_alloc_array(scratch.arena, wchar_t, sizeWide);
|
|
||||||
MultiByteToWideChar(CP_UTF8, 0, req->buffer, req->size, pathWide, sizeWide);
|
|
||||||
pathWide[sizeWide-1] = '\0';
|
|
||||||
|
|
||||||
DWORD accessFlags = 0;
|
|
||||||
DWORD createFlags = 0;
|
|
||||||
DWORD attributesFlags = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS;
|
|
||||||
|
|
||||||
if(req->openFlags & FILE_OPEN_READ)
|
|
||||||
{
|
{
|
||||||
accessFlags |= GENERIC_READ;
|
slot->rights &= atSlot->rights;
|
||||||
}
|
|
||||||
if(req->openFlags & FILE_OPEN_WRITE)
|
|
||||||
{
|
|
||||||
if(req->openFlags & FILE_OPEN_APPEND)
|
|
||||||
{
|
|
||||||
accessFlags |= FILE_APPEND_DATA;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
accessFlags |= GENERIC_WRITE;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(req->openFlags & FILE_OPEN_TRUNCATE)
|
if(slot->rights != req->open.rights)
|
||||||
{
|
|
||||||
if(req->openFlags & FILE_OPEN_CREATE)
|
|
||||||
{
|
|
||||||
createFlags |= CREATE_ALWAYS;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
createFlags |= TRUNCATE_EXISTING;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(req->openFlags & 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->openFlags & FILE_OPEN_SYMLINK)
|
|
||||||
{
|
|
||||||
attributesFlags |= FILE_FLAG_OPEN_REPARSE_POINT;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(req->openFlags & FILE_OPEN_RESTRICT)
|
|
||||||
{
|
|
||||||
//TODO: if FILE_OPEN_RESTRICT, do the file traversal to check that path is in the
|
|
||||||
// subtree rooted at atSlot->fd
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO: open at
|
|
||||||
|
|
||||||
//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);
|
|
||||||
|
|
||||||
if(slot->h == INVALID_HANDLE_VALUE)
|
|
||||||
{
|
{
|
||||||
|
slot->error = IO_ERR_PERM;
|
||||||
slot->fatal = true;
|
slot->fatal = true;
|
||||||
slot->error = io_convert_win32_error(GetLastError());
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//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';
|
||||||
|
|
||||||
|
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;
|
||||||
|
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
|
||||||
|
}
|
||||||
|
else
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
DWORD atPathWideSize = GetFinalPathNameByHandleW(atSlot->h, NULL, 0, FILE_NAME_NORMALIZED);
|
||||||
|
if(atPathWideSize)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
|
||||||
|
if(slot->h == INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
slot->fatal = true;
|
||||||
|
slot->error = io_convert_win32_error(GetLastError());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
cmp.error = slot->error;
|
cmp.error = slot->error;
|
||||||
}
|
}
|
||||||
|
@ -295,8 +334,8 @@ io_cmp io_read(file_slot* slot, io_req* req)
|
||||||
|
|
||||||
if(!ReadFile(slot->h, req->buffer, req->size, &bytesRead, NULL))
|
if(!ReadFile(slot->h, req->buffer, req->size, &bytesRead, NULL))
|
||||||
{
|
{
|
||||||
cmp.result = -1;
|
|
||||||
slot->error = io_convert_win32_error(GetLastError());
|
slot->error = io_convert_win32_error(GetLastError());
|
||||||
|
cmp.result = 0;
|
||||||
cmp.error = slot->error;
|
cmp.error = slot->error;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -314,8 +353,8 @@ io_cmp io_write(file_slot* slot, io_req* req)
|
||||||
|
|
||||||
if(!WriteFile(slot->h, req->buffer, req->size, &bytesWritten, NULL))
|
if(!WriteFile(slot->h, req->buffer, req->size, &bytesWritten, NULL))
|
||||||
{
|
{
|
||||||
cmp.result = -1;
|
|
||||||
slot->error = io_convert_win32_error(GetLastError());
|
slot->error = io_convert_win32_error(GetLastError());
|
||||||
|
cmp.result = 0;
|
||||||
cmp.error = slot->error;
|
cmp.error = slot->error;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -155,6 +155,11 @@ void mp_init()
|
||||||
__mpApp.win32.savedConsoleCodePage = GetConsoleOutputCP();
|
__mpApp.win32.savedConsoleCodePage = GetConsoleOutputCP();
|
||||||
SetConsoleOutputCP(CP_UTF8);
|
SetConsoleOutputCP(CP_UTF8);
|
||||||
|
|
||||||
|
DWORD mode;
|
||||||
|
GetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE), &mode);
|
||||||
|
mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
|
||||||
|
SetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE), mode);
|
||||||
|
|
||||||
SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
|
SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -197,25 +197,8 @@ int test_jail()
|
||||||
return(-1);
|
return(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check legitimates open
|
|
||||||
file_handle f = file_open_at(jail, STR8("/test.txt"), FILE_ACCESS_READ, FILE_OPEN_RESTRICT);
|
|
||||||
if(file_last_error(f) != IO_OK)
|
|
||||||
{
|
|
||||||
log_error("Can't open jail/test.txt\n");
|
|
||||||
return(-1);
|
|
||||||
}
|
|
||||||
file_close(f);
|
|
||||||
|
|
||||||
f = file_open_at(jail, STR8("/dir1/../test.txt"), FILE_ACCESS_READ, FILE_OPEN_RESTRICT);
|
|
||||||
if(file_last_error(f) != IO_OK)
|
|
||||||
{
|
|
||||||
log_error("Can't open jail/dir1/../test.txt\n");
|
|
||||||
return(-1);
|
|
||||||
}
|
|
||||||
file_close(f);
|
|
||||||
|
|
||||||
// Check escapes
|
// Check escapes
|
||||||
f = file_open_at(jail, STR8(".."), FILE_ACCESS_READ, FILE_OPEN_RESTRICT);
|
file_handle f = file_open_at(jail, STR8(".."), FILE_ACCESS_READ, FILE_OPEN_RESTRICT);
|
||||||
if(file_last_error(f) != IO_ERR_WALKOUT)
|
if(file_last_error(f) != IO_ERR_WALKOUT)
|
||||||
{
|
{
|
||||||
log_error("Escaped jail with relative path ..\n");
|
log_error("Escaped jail with relative path ..\n");
|
||||||
|
@ -239,6 +222,24 @@ int test_jail()
|
||||||
}
|
}
|
||||||
file_close(f);
|
file_close(f);
|
||||||
|
|
||||||
|
// Check legitimates open
|
||||||
|
f = file_open_at(jail, STR8("/test.txt"), FILE_ACCESS_READ, FILE_OPEN_RESTRICT);
|
||||||
|
if(file_last_error(f) != IO_OK)
|
||||||
|
{
|
||||||
|
log_error("Can't open jail/test.txt\n");
|
||||||
|
return(-1);
|
||||||
|
}
|
||||||
|
file_close(f);
|
||||||
|
|
||||||
|
f = file_open_at(jail, STR8("/dir1/../test.txt"), FILE_ACCESS_READ, FILE_OPEN_RESTRICT);
|
||||||
|
if(file_last_error(f) != IO_OK)
|
||||||
|
{
|
||||||
|
log_error("Can't open jail/dir1/../test.txt\n");
|
||||||
|
return(-1);
|
||||||
|
}
|
||||||
|
file_close(f);
|
||||||
|
|
||||||
|
|
||||||
return(0);
|
return(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -253,7 +254,7 @@ int test_rights(mem_arena* arena, str8 dirPath)
|
||||||
file_handle dir = file_open(dirPath, FILE_ACCESS_NONE, 0);
|
file_handle dir = file_open(dirPath, FILE_ACCESS_NONE, 0);
|
||||||
if(file_last_error(dir))
|
if(file_last_error(dir))
|
||||||
{
|
{
|
||||||
log_error("Couldn't open ./dir1 with no access rights\n");
|
log_error("Couldn't open ./data with no access rights\n");
|
||||||
return(-1);
|
return(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -273,7 +274,7 @@ int test_rights(mem_arena* arena, str8 dirPath)
|
||||||
file_handle dir = file_open(dirPath, FILE_ACCESS_READ, 0);
|
file_handle dir = file_open(dirPath, FILE_ACCESS_READ, 0);
|
||||||
if(file_last_error(dir))
|
if(file_last_error(dir))
|
||||||
{
|
{
|
||||||
log_error("Couldn't open ./dir1 with read rights\n");
|
log_error("Couldn't open ./data with read rights\n");
|
||||||
return(-1);
|
return(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -317,7 +318,7 @@ int test_rights(mem_arena* arena, str8 dirPath)
|
||||||
file_handle dir = file_open(dirPath, FILE_ACCESS_WRITE, 0);
|
file_handle dir = file_open(dirPath, FILE_ACCESS_WRITE, 0);
|
||||||
if(file_last_error(dir))
|
if(file_last_error(dir))
|
||||||
{
|
{
|
||||||
log_error("Couldn't open ./dir1 with write rights\n");
|
log_error("Couldn't open ./data with write rights\n");
|
||||||
return(-1);
|
return(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -361,7 +362,7 @@ int test_rights(mem_arena* arena, str8 dirPath)
|
||||||
file_handle dir = file_open(dirPath, FILE_ACCESS_READ|FILE_ACCESS_WRITE, 0);
|
file_handle dir = file_open(dirPath, FILE_ACCESS_READ|FILE_ACCESS_WRITE, 0);
|
||||||
if(file_last_error(dir))
|
if(file_last_error(dir))
|
||||||
{
|
{
|
||||||
log_error("Couldn't open ./dir1 with read rights\n");
|
log_error("Couldn't open ./data with read rights\n");
|
||||||
return(-1);
|
return(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -390,6 +391,8 @@ int test_rights(mem_arena* arena, str8 dirPath)
|
||||||
|
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
|
mp_init();
|
||||||
|
|
||||||
mem_arena* arena = mem_scratch();
|
mem_arena* arena = mem_scratch();
|
||||||
|
|
||||||
str8 dataDir = STR8("./data");
|
str8 dataDir = STR8("./data");
|
||||||
|
|
Loading…
Reference in New Issue