From 9954b69eda2c56f6730f609773230c77de497367 Mon Sep 17 00:00:00 2001 From: martinfouilleul Date: Tue, 13 Jun 2023 19:53:06 +0200 Subject: [PATCH] [win32, io] implement IO_OP_OPEN_AT with non-null base directory handle --- build.bat | 2 +- src/platform/platform_io_internal.c | 1 - src/platform/platform_io_internal.h | 2 +- src/platform/win32_io.c | 183 +++++++++++++++++----------- src/win32_app.c | 5 + test/files/main.c | 47 +++---- 6 files changed, 143 insertions(+), 97 deletions(-) diff --git a/build.bat b/build.bat index 9d1c053..b5998bd 100644 --- a/build.bat +++ b/build.bat @@ -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 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 diff --git a/src/platform/platform_io_internal.c b/src/platform/platform_io_internal.c index 22d97e6..4094653 100644 --- a/src/platform/platform_io_internal.c +++ b/src/platform/platform_io_internal.c @@ -17,7 +17,6 @@ file_slot* file_slot_alloc(file_table* table) { slot = &table->slots[table->nextSlot]; slot->generation = 1; - slot->fd = -1; table->nextSlot++; } diff --git a/src/platform/platform_io_internal.h b/src/platform/platform_io_internal.h index d5fa461..1d9f79a 100644 --- a/src/platform/platform_io_internal.h +++ b/src/platform/platform_io_internal.h @@ -15,7 +15,7 @@ #define PLATFORM_IO_NATIVE_MEMBER int fd #elif PLATFORM_WINDOWS #define WIN32_LEAN_AND_MEAN - #include + #include #define PLATFORM_IO_NATIVE_MEMBER HANDLE h #endif diff --git a/src/platform/win32_io.c b/src/platform/win32_io.c index 54263ad..bf49e92 100644 --- a/src/platform/win32_io.c +++ b/src/platform/win32_io.c @@ -8,6 +8,7 @@ #include #include +#include #include"platform_io_internal.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); - //NOTE: open - mem_arena_scope scratch = mem_scratch_begin(); - - 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) + slot->rights = req->open.rights; + if(atSlot) { - accessFlags |= GENERIC_READ; - } - if(req->openFlags & FILE_OPEN_WRITE) - { - if(req->openFlags & FILE_OPEN_APPEND) - { - accessFlags |= FILE_APPEND_DATA; - } - else - { - accessFlags |= GENERIC_WRITE; - } + slot->rights &= atSlot->rights; } - if(req->openFlags & FILE_OPEN_TRUNCATE) - { - 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) + if(slot->rights != req->open.rights) { + slot->error = IO_ERR_PERM; 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; } @@ -295,8 +334,8 @@ io_cmp io_read(file_slot* slot, io_req* req) if(!ReadFile(slot->h, req->buffer, req->size, &bytesRead, NULL)) { - cmp.result = -1; slot->error = io_convert_win32_error(GetLastError()); + cmp.result = 0; cmp.error = slot->error; } 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)) { - cmp.result = -1; slot->error = io_convert_win32_error(GetLastError()); + cmp.result = 0; cmp.error = slot->error; } else diff --git a/src/win32_app.c b/src/win32_app.c index 8b7eedc..c0cac7c 100644 --- a/src/win32_app.c +++ b/src/win32_app.c @@ -155,6 +155,11 @@ void mp_init() __mpApp.win32.savedConsoleCodePage = GetConsoleOutputCP(); 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); } } diff --git a/test/files/main.c b/test/files/main.c index 9cb05df..a6ce32e 100644 --- a/test/files/main.c +++ b/test/files/main.c @@ -197,25 +197,8 @@ int test_jail() 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 - 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) { log_error("Escaped jail with relative path ..\n"); @@ -239,6 +222,24 @@ int test_jail() } 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); } @@ -253,7 +254,7 @@ int test_rights(mem_arena* arena, str8 dirPath) file_handle dir = file_open(dirPath, FILE_ACCESS_NONE, 0); 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); } @@ -273,7 +274,7 @@ int test_rights(mem_arena* arena, str8 dirPath) file_handle dir = file_open(dirPath, FILE_ACCESS_READ, 0); 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); } @@ -317,7 +318,7 @@ int test_rights(mem_arena* arena, str8 dirPath) file_handle dir = file_open(dirPath, FILE_ACCESS_WRITE, 0); 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); } @@ -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); 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); } @@ -390,6 +391,8 @@ int test_rights(mem_arena* arena, str8 dirPath) int main(int argc, char** argv) { + mp_init(); + mem_arena* arena = mem_scratch(); str8 dataDir = STR8("./data");