[win32, io] implement IO_OP_OPEN_AT with non-null base directory handle

This commit is contained in:
martinfouilleul 2023-06-13 19:53:06 +02:00
parent 0bd985efbc
commit 9954b69eda
6 changed files with 143 additions and 97 deletions

View File

@ -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

View File

@ -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++;
} }

View File

@ -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

View File

@ -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

View File

@ -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);
} }
} }

View File

@ -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");