From f80d7dda62248153a4dc65a935a4de073d3c0430 Mon Sep 17 00:00:00 2001 From: rjkiv <76180273+rjkiv@users.noreply.github.com> Date: Sat, 9 Aug 2025 14:53:56 -0700 Subject: [PATCH] FindFirstFileW --- dll/kernel32.cpp | 66 ++++++++++++++++++++++++++++++++++++++++++++++++ dll/msvcrt.cpp | 4 +-- strutil.cpp | 6 +++++ strutil.h | 1 + 4 files changed, 75 insertions(+), 2 deletions(-) diff --git a/dll/kernel32.cpp b/dll/kernel32.cpp index 056ce25..ef0e663 100644 --- a/dll/kernel32.cpp +++ b/dll/kernel32.cpp @@ -4,6 +4,7 @@ #include "handles.h" #include #include +#include #include #include #include @@ -780,6 +781,27 @@ namespace kernel32 { strcpy(data->cAlternateFileName, "8P3FMTFN.BAD"); } + void setFindFileDataFromPathW(WIN32_FIND_DATA* data, const std::filesystem::path &path){ + auto status = std::filesystem::status(path); + uint64_t fileSize = 0; + data->dwFileAttributes = 0; + if (std::filesystem::is_directory(status)) { + data->dwFileAttributes |= 0x10; + } + if (std::filesystem::is_regular_file(status)) { + data->dwFileAttributes |= 0x80; + fileSize = std::filesystem::file_size(path); + } + data->nFileSizeHigh = (uint32_t)(fileSize >> 32); + data->nFileSizeLow = (uint32_t)fileSize; + auto fileName = path.filename().string(); + assert(fileName.size() < 260); + auto wideFileName = stringToWideString(fileName.c_str()); + wstrcpy(data->cFileName, wideFileName.data()); + auto wideBad = stringToWideString("8P3FMTFN.BAD"); + wstrcpy(data->cAlternateFileName, wideBad.data()); + } + void *WIN_FUNC FindFirstFileA(const char *lpFileName, WIN32_FIND_DATA *lpFindFileData) { // This should handle wildcards too, but whatever. auto path = files::pathFromWindows(lpFileName); @@ -822,6 +844,49 @@ namespace kernel32 { return handle; } + void *WIN_FUNC FindFirstFileW(const uint16_t *lpFileName, WIN32_FIND_DATA *lpFindFileData) { + std::string filename = wideStringToString(lpFileName); + // This should handle wildcards too, but whatever. + auto path = files::pathFromWindows(filename.c_str()); + DEBUG_LOG("FindFirstFileW %s (%s)\n", filename.c_str(), path.c_str()); + + lpFindFileData->ftCreationTime = defaultFiletime; + lpFindFileData->ftLastAccessTime = defaultFiletime; + lpFindFileData->ftLastWriteTime = defaultFiletime; + + auto status = std::filesystem::status(path); + if (status.type() == std::filesystem::file_type::regular) { + setFindFileDataFromPathW(lpFindFileData, path); + return (void *) 1; + } + + // If the parent path is empty then we assume the parent path is the current directory. + auto parent_path = path.parent_path(); + if (parent_path == "") { + parent_path = "."; + } + + if (!std::filesystem::exists(parent_path)) { + wibo::lastError = ERROR_PATH_NOT_FOUND; + return INVALID_HANDLE_VALUE; + } + + auto *handle = new FindFirstFileHandle(); + + std::filesystem::directory_iterator it(parent_path); + handle->it = it; + handle->pattern = path.filename().string(); + + if (!findNextFile(handle)) { + wibo::lastError = ERROR_FILE_NOT_FOUND; + delete handle; + return INVALID_HANDLE_VALUE; + } + + setFindFileDataFromPathW(lpFindFileData, *handle->it++); + return handle; + } + typedef enum _FINDEX_INFO_LEVELS { FindExInfoStandard, FindExInfoBasic, @@ -2529,6 +2594,7 @@ static void *resolveByName(const char *name) { if (strcmp(name, "GetFullPathNameW") == 0) return (void *) kernel32::GetFullPathNameW; if (strcmp(name, "GetShortPathNameA") == 0) return (void *) kernel32::GetShortPathNameA; if (strcmp(name, "FindFirstFileA") == 0) return (void *) kernel32::FindFirstFileA; + if (strcmp(name, "FindFirstFileW") == 0) return (void *) kernel32::FindFirstFileW; if (strcmp(name, "FindFirstFileExA") == 0) return (void *) kernel32::FindFirstFileExA; if (strcmp(name, "FindNextFileA") == 0) return (void *) kernel32::FindNextFileA; if (strcmp(name, "FindClose") == 0) return (void *) kernel32::FindClose; diff --git a/dll/msvcrt.cpp b/dll/msvcrt.cpp index 21d3aae..6c3a10e 100644 --- a/dll/msvcrt.cpp +++ b/dll/msvcrt.cpp @@ -310,11 +310,11 @@ namespace msvcrt { int WIN_ENTRY _itow_s(int value, uint16_t *buffer, size_t size, int radix){ DEBUG_LOG("_itow_s value %d, size %d, radix %d\n", value, size, radix); if (!buffer || size == 0) return -1; - if (radix != 10) return -1; // only base 10 supported for now + assert(radix == 10); // only base 10 supported for now std::string str = std::to_string(value); std::vector wstr = stringToWideString(str.c_str()); - buffer = wstr.data(); + wstrcpy(buffer, wstr.data()); return 0; } diff --git a/strutil.cpp b/strutil.cpp index 6319a38..6212312 100644 --- a/strutil.cpp +++ b/strutil.cpp @@ -77,6 +77,12 @@ uint16_t* wstrncat(uint16_t* dest, const uint16_t* src, size_t count){ return dest; } +uint16_t* wstrcpy(uint16_t* dest, const uint16_t* src){ + uint16_t* d = dest; + while ((*d++ = *src++) != 0); + return dest; +} + size_t wstrncpy(uint16_t *dst, const uint16_t *src, size_t n) { size_t i = 0; while (i < n && src[i] != 0) { diff --git a/strutil.h b/strutil.h index 0a50237..12fa42a 100644 --- a/strutil.h +++ b/strutil.h @@ -8,6 +8,7 @@ const uint16_t* wstrstr(const uint16_t *dest, const uint16_t *src); uint16_t* wstrrchr(const uint16_t* str, uint16_t c); uint16_t* wstrcat(uint16_t* dest, const uint16_t* src); uint16_t* wstrncat(uint16_t* dest, const uint16_t* src, size_t count); +uint16_t* wstrcpy(uint16_t* dest, const uint16_t* src); size_t wstrncpy(uint16_t *dst, const uint16_t *src, size_t n); std::string wideStringToString(const uint16_t *src, int len = -1); std::vector stringToWideString(const char *src);