diff --git a/src/common/io/io.h b/src/common/io/io.h index 8787f9858..d9c24c351 100644 --- a/src/common/io/io.h +++ b/src/common/io/io.h @@ -254,4 +254,5 @@ bool ffRemoveFile(const char* fileName); #ifdef _WIN32 // Only O_RDONLY is supported HANDLE openat(HANDLE dfd, const char* fileName, bool directory); +HANDLE openatW(HANDLE dfd, const wchar_t* fileName, uint16_t fileNameLen, bool directory); #endif diff --git a/src/common/io/io_windows.c b/src/common/io/io_windows.c index ae1d584e9..8724d0ee9 100644 --- a/src/common/io/io_windows.c +++ b/src/common/io/io_windows.c @@ -3,8 +3,8 @@ #include "util/stringUtils.h" #include +#include "util/windows/nt.h" #include -#include static void createSubfolders(const char* fileName) { @@ -102,31 +102,48 @@ bool ffAppendFileBuffer(const char* fileName, FFstrbuf* buffer) return ffAppendFDBuffer(handle, buffer); } -HANDLE openat(HANDLE dfd, const char* fileName, bool directory) +HANDLE openatW(HANDLE dfd, const wchar_t* fileName, uint16_t fileNameLen, bool directory) { - NTSTATUS ret; - UNICODE_STRING fileNameW; - ret = RtlAnsiStringToUnicodeString(&fileNameW, &(ANSI_STRING) { - .Length = (USHORT) strlen(fileName), - .Buffer = (PCHAR) fileName - }, TRUE); - if (!NT_SUCCESS(ret)) return INVALID_HANDLE_VALUE; + assert(fileNameLen <= 0x7FFF); - FF_AUTO_CLOSE_FD HANDLE hFile; + HANDLE hFile; IO_STATUS_BLOCK iosb = {}; - ret = NtOpenFile(&hFile, FILE_READ_DATA | SYNCHRONIZE, &(OBJECT_ATTRIBUTES) { - .Length = sizeof(OBJECT_ATTRIBUTES), - .RootDirectory = dfd, - .ObjectName = &fileNameW, - }, &iosb, FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_NONALERT | (directory ? FILE_DIRECTORY_FILE : FILE_NON_DIRECTORY_FILE)); - RtlFreeUnicodeString(&fileNameW); - - if(!NT_SUCCESS(ret) || iosb.Information != FILE_OPENED) + if(!NT_SUCCESS(NtOpenFile(&hFile, + (directory ? FILE_LIST_DIRECTORY | FILE_TRAVERSE : FILE_READ_DATA | FILE_READ_EA) | FILE_READ_ATTRIBUTES | SYNCHRONIZE, &(OBJECT_ATTRIBUTES) { + .Length = sizeof(OBJECT_ATTRIBUTES), + .RootDirectory = dfd, + .ObjectName = &(UNICODE_STRING) { + .Buffer = (PWSTR) fileName, + .Length = fileNameLen * (USHORT) sizeof(wchar_t), + .MaximumLength = (fileNameLen + 1) * (USHORT) sizeof(wchar_t), + }, + .Attributes = OBJ_CASE_INSENSITIVE, + }, + &iosb, + FILE_SHARE_READ | (directory ? FILE_SHARE_WRITE | FILE_SHARE_DELETE : 0), + FILE_SYNCHRONOUS_IO_NONALERT | (directory ? FILE_DIRECTORY_FILE : FILE_NON_DIRECTORY_FILE) + ))) return INVALID_HANDLE_VALUE; return hFile; } +HANDLE openat(HANDLE dfd, const char* fileName, bool directory) +{ + wchar_t fileNameW[MAX_PATH]; + int len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, fileName, -1, fileNameW, ARRAY_SIZE(fileNameW)); + if (len == 0) return INVALID_HANDLE_VALUE; + fileNameW[len] = L'\0'; + + for (int i = 0; i < len - 1; ++i) + { + if (fileNameW[i] == L'/') + fileNameW[i] = L'\\'; + } + + return openatW(dfd, fileNameW, (uint16_t)(len - 1), directory); +} + bool ffAppendFileBufferRelative(HANDLE dfd, const char* fileName, FFstrbuf* buffer) { HANDLE FF_AUTO_CLOSE_FD fd = openat(dfd, fileName, false);