diff --git a/AGENTS.md b/AGENTS.md index d11ad4a..eced3f9 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -17,6 +17,7 @@ - Formatting follows `.clang-format` (LLVM base, tabbed indentation width 4, 120 column limit); never hand-wrap differently. - Use PascalCase for Win32 entry points, camelCase for internal helpers, SCREAMING_SNAKE_CASE for Win32 constants, kCamelCase for internal constants, and g_camelCase for globals. - Put static functions and variables in anonymous namespaces at the top of the file. +- Prefer scoping types to the header or source file that uses them; avoid polluting `common.h` unless widely shared. ## Shim Implementation Guidelines - Target pre-XP behavior; our binaries are old and don't expect modern WinAPI behavior. diff --git a/CMakeLists.txt b/CMakeLists.txt index 2fb4794..335307a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,25 +36,27 @@ add_executable(wibo dll/bcrypt.cpp dll/crt.cpp dll/kernel32.cpp + dll/kernel32/debugapi.cpp dll/kernel32/errhandlingapi.cpp dll/kernel32/fibersapi.cpp - dll/kernel32/heapapi.cpp - dll/kernel32/memoryapi.cpp - dll/kernel32/handleapi.cpp dll/kernel32/fileapi.cpp - dll/kernel32/debugapi.cpp + dll/kernel32/handleapi.cpp + dll/kernel32/heapapi.cpp dll/kernel32/interlockedapi.cpp + dll/kernel32/ioapiset.cpp dll/kernel32/libloaderapi.cpp - dll/kernel32/winbase.cpp - dll/kernel32/wincon.cpp + dll/kernel32/memoryapi.cpp dll/kernel32/processenv.cpp - dll/kernel32/profileapi.cpp dll/kernel32/processthreadsapi.cpp + dll/kernel32/profileapi.cpp dll/kernel32/stringapiset.cpp + dll/kernel32/synchapi.cpp dll/kernel32/sysinfoapi.cpp dll/kernel32/timezoneapi.cpp - dll/kernel32/synchapi.cpp + dll/kernel32/winbase.cpp + dll/kernel32/wincon.cpp dll/kernel32/winnls.cpp + dll/kernel32/winnt.cpp dll/kernel32/wow64apiset.cpp dll/lmgr.cpp dll/mscoree.cpp diff --git a/dll/kernel32.cpp b/dll/kernel32.cpp index d1bb369..cb19e50 100644 --- a/dll/kernel32.cpp +++ b/dll/kernel32.cpp @@ -1,7 +1,5 @@ #include "common.h" -#include "errors.h" -#include "files.h" -#include "handles.h" + #include "kernel32/debugapi.h" #include "kernel32/errhandlingapi.h" #include "kernel32/fibersapi.h" @@ -9,940 +7,21 @@ #include "kernel32/handleapi.h" #include "kernel32/heapapi.h" #include "kernel32/interlockedapi.h" -#include "kernel32/internal.h" +#include "kernel32/ioapiset.h" #include "kernel32/libloaderapi.h" #include "kernel32/memoryapi.h" -#include "kernel32/minwinbase.h" #include "kernel32/processenv.h" #include "kernel32/processthreadsapi.h" #include "kernel32/profileapi.h" #include "kernel32/stringapiset.h" #include "kernel32/synchapi.h" #include "kernel32/sysinfoapi.h" -#include "kernel32/timeutil.h" #include "kernel32/timezoneapi.h" #include "kernel32/winbase.h" #include "kernel32/wincon.h" #include "kernel32/winnls.h" +#include "kernel32/winnt.h" #include "kernel32/wow64apiset.h" -#include "processes.h" -#include "resources.h" -#include "strutil.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace kernel32 { - -int64_t getFileSize(HANDLE hFile) { - FILE *fp = files::fpFromHandle(hFile); - if (!fp) { - wibo::lastError = ERROR_INVALID_HANDLE; - return -1; // INVALID_FILE_SIZE - } - struct stat64 st; - fflush(fp); - if (fstat64(fileno(fp), &st) == -1 || !S_ISREG(st.st_mode)) { - setLastErrorFromErrno(); - return -1; // INVALID_FILE_SIZE - } - return st.st_size; -} - -static const FILETIME defaultFiletime = {static_cast(UNIX_TIME_ZERO & 0xFFFFFFFFULL), - static_cast(UNIX_TIME_ZERO >> 32)}; - -unsigned int WIN_FUNC GetFileAttributesA(const char *lpFileName) { - auto path = files::pathFromWindows(lpFileName); - DEBUG_LOG("GetFileAttributesA(%s) -> %s\n", lpFileName, path.c_str()); - - // See ole32::CoCreateInstance - if (endsWith(path, "/license.dat")) { - DEBUG_LOG("MWCC license override\n"); - return 0x80; // FILE_ATTRIBUTE_NORMAL - } - - auto status = std::filesystem::status(path); - - wibo::lastError = 0; - - switch (status.type()) { - case std::filesystem::file_type::regular: - DEBUG_LOG("File exists\n"); - return 0x80; // FILE_ATTRIBUTE_NORMAL - case std::filesystem::file_type::directory: - return 0x10; // FILE_ATTRIBUTE_DIRECTORY - case std::filesystem::file_type::not_found: - default: - DEBUG_LOG("File does not exist\n"); - wibo::lastError = 2; // ERROR_FILE_NOT_FOUND - return 0xFFFFFFFF; // INVALID_FILE_ATTRIBUTES - } -} - -unsigned int WIN_FUNC GetFileAttributesW(const uint16_t *lpFileName) { - DEBUG_LOG("GetFileAttributesW -> "); - std::string str = wideStringToString(lpFileName); - return GetFileAttributesA(str.c_str()); -} - -unsigned int WIN_FUNC WriteFile(void *hFile, const void *lpBuffer, unsigned int nNumberOfBytesToWrite, - unsigned int *lpNumberOfBytesWritten, void *lpOverlapped) { - DEBUG_LOG("WriteFile(%p, %u)\n", hFile, nNumberOfBytesToWrite); - wibo::lastError = ERROR_SUCCESS; - - auto file = files::fileHandleFromHandle(hFile); - if (!file || !file->fp) { - wibo::lastError = ERROR_INVALID_HANDLE; - return FALSE; - } - - bool handleOverlapped = (file->flags & FILE_FLAG_OVERLAPPED) != 0; - auto *overlapped = reinterpret_cast(lpOverlapped); - bool usingOverlapped = overlapped != nullptr; - if (!usingOverlapped && lpNumberOfBytesWritten == nullptr) { - wibo::lastError = ERROR_INVALID_PARAMETER; - return FALSE; - } - - std::optional offset; - bool updateFilePointer = true; - if (usingOverlapped) { - offset = (static_cast(overlapped->Offset) | (static_cast(overlapped->OffsetHigh) << 32)); - overlapped->Internal = STATUS_PENDING; - overlapped->InternalHigh = 0; - updateFilePointer = !handleOverlapped; - resetOverlappedEvent(overlapped); - } - - auto io = files::write(file, lpBuffer, nNumberOfBytesToWrite, offset, updateFilePointer); - DWORD completionStatus = STATUS_SUCCESS; - if (io.unixError != 0) { - completionStatus = wibo::winErrorFromErrno(io.unixError); - wibo::lastError = completionStatus; - if (lpNumberOfBytesWritten) { - *lpNumberOfBytesWritten = static_cast(io.bytesTransferred); - } - if (usingOverlapped) { - overlapped->Internal = completionStatus; - overlapped->InternalHigh = io.bytesTransferred; - signalOverlappedEvent(overlapped); - } - return FALSE; - } - - if (lpNumberOfBytesWritten && (!handleOverlapped || !usingOverlapped)) { - *lpNumberOfBytesWritten = static_cast(io.bytesTransferred); - } - - if (usingOverlapped) { - overlapped->Internal = completionStatus; - overlapped->InternalHigh = io.bytesTransferred; - if (!handleOverlapped) { - uint64_t baseOffset = offset.value_or(0); - uint64_t newOffset = baseOffset + io.bytesTransferred; - overlapped->Offset = static_cast(newOffset & 0xFFFFFFFFu); - overlapped->OffsetHigh = static_cast(newOffset >> 32); - } - signalOverlappedEvent(overlapped); - } - - return (io.bytesTransferred == nNumberOfBytesToWrite); -} - -BOOL WIN_FUNC FlushFileBuffers(HANDLE hFile) { - DEBUG_LOG("FlushFileBuffers(%p)\n", hFile); - auto data = handles::dataFromHandle(hFile, false); - if (data.type != handles::TYPE_FILE || data.ptr == nullptr) { - wibo::lastError = ERROR_INVALID_HANDLE; - return FALSE; - } - auto file = reinterpret_cast(data.ptr); - if (!file || !file->fp) { - wibo::lastError = ERROR_INVALID_HANDLE; - return FALSE; - } - FILE *fp = file->fp; - if (fflush(fp) != 0) { - wibo::lastError = ERROR_ACCESS_DENIED; - return FALSE; - } - int fd = file->fd; - if (fd >= 0 && fsync(fd) != 0) { - wibo::lastError = ERROR_ACCESS_DENIED; - return FALSE; - } - wibo::lastError = ERROR_SUCCESS; - return TRUE; -} - -unsigned int WIN_FUNC ReadFile(void *hFile, void *lpBuffer, unsigned int nNumberOfBytesToRead, - unsigned int *lpNumberOfBytesRead, void *lpOverlapped) { - DEBUG_LOG("ReadFile(%p, %u)\n", hFile, nNumberOfBytesToRead); - wibo::lastError = ERROR_SUCCESS; - - auto file = files::fileHandleFromHandle(hFile); - if (!file || !file->fp) { - wibo::lastError = ERROR_INVALID_HANDLE; - return FALSE; - } - - bool handleOverlapped = (file->flags & FILE_FLAG_OVERLAPPED) != 0; - auto *overlapped = reinterpret_cast(lpOverlapped); - bool usingOverlapped = overlapped != nullptr; - if (!usingOverlapped && lpNumberOfBytesRead == nullptr) { - wibo::lastError = ERROR_INVALID_PARAMETER; - return FALSE; - } - - std::optional offset; - bool updateFilePointer = true; - if (usingOverlapped) { - offset = (static_cast(overlapped->Offset) | (static_cast(overlapped->OffsetHigh) << 32)); - overlapped->Internal = STATUS_PENDING; - overlapped->InternalHigh = 0; - updateFilePointer = !handleOverlapped; - resetOverlappedEvent(overlapped); - } - - auto io = files::read(file, lpBuffer, nNumberOfBytesToRead, offset, updateFilePointer); - DWORD completionStatus = STATUS_SUCCESS; - if (io.unixError != 0) { - completionStatus = wibo::winErrorFromErrno(io.unixError); - wibo::lastError = completionStatus; - if (lpNumberOfBytesRead) { - *lpNumberOfBytesRead = static_cast(io.bytesTransferred); - } - if (usingOverlapped) { - overlapped->Internal = completionStatus; - overlapped->InternalHigh = io.bytesTransferred; - signalOverlappedEvent(overlapped); - } - return FALSE; - } - - if (io.reachedEnd && io.bytesTransferred == 0 && handleOverlapped) { - completionStatus = ERROR_HANDLE_EOF; - } - - if (lpNumberOfBytesRead && (!handleOverlapped || !usingOverlapped)) { - *lpNumberOfBytesRead = static_cast(io.bytesTransferred); - } - - if (usingOverlapped) { - overlapped->Internal = completionStatus; - overlapped->InternalHigh = io.bytesTransferred; - if (!handleOverlapped) { - uint64_t baseOffset = offset.value_or(0); - uint64_t newOffset = baseOffset + io.bytesTransferred; - overlapped->Offset = static_cast(newOffset & 0xFFFFFFFFu); - overlapped->OffsetHigh = static_cast(newOffset >> 32); - } - signalOverlappedEvent(overlapped); - } - - return TRUE; -} - -enum { - CREATE_NEW = 1, - CREATE_ALWAYS = 2, - OPEN_EXISTING = 3, - OPEN_ALWAYS = 4, - TRUNCATE_EXISTING = 5, -}; -void *WIN_FUNC CreateFileA(const char *lpFileName, unsigned int dwDesiredAccess, unsigned int dwShareMode, - void *lpSecurityAttributes, unsigned int dwCreationDisposition, - unsigned int dwFlagsAndAttributes, void *hTemplateFile) { - std::string path = files::pathFromWindows(lpFileName); - DEBUG_LOG("CreateFileA(filename=%s (%s), desiredAccess=0x%x, shareMode=%u, securityAttributes=%p, " - "creationDisposition=%u, flagsAndAttributes=%u)\n", - lpFileName, path.c_str(), dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, - dwFlagsAndAttributes); - - wibo::lastError = 0; // possibly overwritten later in this function - - // Based on https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea#parameters - // and this table: https://stackoverflow.com/a/14469641 - bool fileExists = (access(path.c_str(), F_OK) == 0); - bool shouldTruncate = false; - switch (dwCreationDisposition) { - case CREATE_ALWAYS: - if (fileExists) { - wibo::lastError = 183; // ERROR_ALREADY_EXISTS - shouldTruncate = true; // "The function overwrites the file" - // Function succeeds - } - break; - case CREATE_NEW: - if (fileExists) { - wibo::lastError = 80; // ERROR_FILE_EXISTS - return INVALID_HANDLE_VALUE; - } - break; - case OPEN_ALWAYS: - if (fileExists) { - wibo::lastError = 183; // ERROR_ALREADY_EXISTS - // Function succeeds - } - break; - case OPEN_EXISTING: - if (!fileExists) { - wibo::lastError = 2; // ERROR_FILE_NOT_FOUND - return INVALID_HANDLE_VALUE; - } - break; - case TRUNCATE_EXISTING: - shouldTruncate = true; - if (!fileExists) { - wibo::lastError = 2; // ERROR_FILE_NOT_FOUND - return INVALID_HANDLE_VALUE; - } - break; - default: - assert(0); - } - - FILE *fp; - if (dwDesiredAccess == 0x80000000) { // read - fp = fopen(path.c_str(), "rb"); - } else if (dwDesiredAccess == 0x40000000) { // write - if (shouldTruncate || !fileExists) { - fp = fopen(path.c_str(), "wb"); - } else { - // There is no way to fopen with only write permissions - // and without truncating the file... - fp = fopen(path.c_str(), "rb+"); - } - } else if (dwDesiredAccess == 0xc0000000) { // read/write - if (shouldTruncate || !fileExists) { - fp = fopen(path.c_str(), "wb+"); - } else { - fp = fopen(path.c_str(), "rb+"); - } - } else { - assert(0); - } - - if (fp) { - void *handle = files::allocFpHandle(fp, dwDesiredAccess, dwShareMode, dwFlagsAndAttributes, true); - DEBUG_LOG("-> %p\n", handle); - return handle; - } else { - setLastErrorFromErrno(); - return INVALID_HANDLE_VALUE; - } -} - -void *WIN_FUNC CreateFileW(const uint16_t *lpFileName, unsigned int dwDesiredAccess, unsigned int dwShareMode, - void *lpSecurityAttributes, unsigned int dwCreationDisposition, - unsigned int dwFlagsAndAttributes, void *hTemplateFile) { - DEBUG_LOG("CreateFileW -> "); - const auto lpFileNameA = wideStringToString(lpFileName); - return CreateFileA(lpFileNameA.c_str(), dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, - dwFlagsAndAttributes, hTemplateFile); -} - -BOOL WIN_FUNC DeleteFileA(const char *lpFileName) { - if (!lpFileName) { - wibo::lastError = ERROR_INVALID_PARAMETER; - DEBUG_LOG("DeleteFileA(NULL) -> ERROR_INVALID_PARAMETER\n"); - return FALSE; - } - std::string path = files::pathFromWindows(lpFileName); - DEBUG_LOG("DeleteFileA(%s) -> %s\n", lpFileName, path.c_str()); - if (unlink(path.c_str()) == 0) { - wibo::lastError = ERROR_SUCCESS; - return TRUE; - } - setLastErrorFromErrno(); - return FALSE; -} - -BOOL WIN_FUNC DeleteFileW(const uint16_t *lpFileName) { - DEBUG_LOG("DeleteFileW -> "); - if (!lpFileName) { - wibo::lastError = ERROR_INVALID_PARAMETER; - DEBUG_LOG("ERROR_INVALID_PARAMETER\n"); - return FALSE; - } - std::string name = wideStringToString(lpFileName); - return DeleteFileA(name.c_str()); -} - -BOOL WIN_FUNC MoveFileA(const char *lpExistingFileName, const char *lpNewFileName) { - DEBUG_LOG("MoveFileA(%s, %s)\n", lpExistingFileName ? lpExistingFileName : "(null)", - lpNewFileName ? lpNewFileName : "(null)"); - if (!lpExistingFileName || !lpNewFileName) { - wibo::lastError = ERROR_INVALID_PARAMETER; - return FALSE; - } - auto fromPath = files::pathFromWindows(lpExistingFileName); - auto toPath = files::pathFromWindows(lpNewFileName); - std::error_code ec; - if (std::filesystem::exists(toPath, ec)) { - wibo::lastError = ERROR_ALREADY_EXISTS; - return FALSE; - } - if (ec) { - errno = ec.value(); - setLastErrorFromErrno(); - return FALSE; - } - std::filesystem::rename(fromPath, toPath, ec); - if (ec) { - errno = ec.value(); - setLastErrorFromErrno(); - return FALSE; - } - wibo::lastError = ERROR_SUCCESS; - return TRUE; -} - -BOOL WIN_FUNC MoveFileW(const uint16_t *lpExistingFileName, const uint16_t *lpNewFileName) { - DEBUG_LOG("MoveFileW -> "); - if (!lpExistingFileName || !lpNewFileName) { - wibo::lastError = ERROR_INVALID_PARAMETER; - DEBUG_LOG("ERROR_INVALID_PARAMETER\n"); - return FALSE; - } - std::string from = wideStringToString(lpExistingFileName); - std::string to = wideStringToString(lpNewFileName); - return MoveFileA(from.c_str(), to.c_str()); -} - -DWORD WIN_FUNC SetFilePointer(HANDLE hFile, LONG lDistanceToMove, PLONG lpDistanceToMoveHigh, DWORD dwMoveMethod) { - DEBUG_LOG("SetFilePointer(%p, %d, %d)\n", hFile, lDistanceToMove, dwMoveMethod); - if (hFile == nullptr) { - wibo::lastError = ERROR_INVALID_HANDLE; - return INVALID_SET_FILE_POINTER; - } - assert(!lpDistanceToMoveHigh || *lpDistanceToMoveHigh == 0); - FILE *fp = files::fpFromHandle(hFile); - if (!fp) { - wibo::lastError = ERROR_INVALID_HANDLE; - return INVALID_SET_FILE_POINTER; - } - wibo::lastError = ERROR_SUCCESS; - int r = fseek(fp, lDistanceToMove, dwMoveMethod == 0 ? SEEK_SET : dwMoveMethod == 1 ? SEEK_CUR : SEEK_END); - - if (r < 0) { - if (errno == EINVAL) - wibo::lastError = ERROR_NEGATIVE_SEEK; - else - wibo::lastError = ERROR_INVALID_PARAMETER; - return INVALID_SET_FILE_POINTER; - } - - r = ftell(fp); - assert(r >= 0); - return r; -} - -BOOL WIN_FUNC SetFilePointerEx(HANDLE hFile, LARGE_INTEGER lDistanceToMove, PLARGE_INTEGER lpDistanceToMoveHigh, - DWORD dwMoveMethod) { - if (hFile == nullptr) { - wibo::lastError = ERROR_INVALID_HANDLE; - return 0; - } - assert(!lpDistanceToMoveHigh || *lpDistanceToMoveHigh == 0); - DEBUG_LOG("SetFilePointerEx(%p, %ld, %d)\n", hFile, lDistanceToMove, dwMoveMethod); - FILE *fp = files::fpFromHandle(hFile); - if (!fp) { - wibo::lastError = ERROR_INVALID_HANDLE; - return 0; - } - wibo::lastError = ERROR_SUCCESS; - int r = fseeko64(fp, lDistanceToMove, dwMoveMethod == 0 ? SEEK_SET : dwMoveMethod == 1 ? SEEK_CUR : SEEK_END); - - if (r < 0) { - if (errno == EINVAL) - wibo::lastError = ERROR_NEGATIVE_SEEK; - else - wibo::lastError = ERROR_INVALID_PARAMETER; - return FALSE; - } - - r = ftell(fp); - assert(r >= 0); - return TRUE; -} - -BOOL WIN_FUNC SetEndOfFile(HANDLE hFile) { - DEBUG_LOG("SetEndOfFile(%p)\n", hFile); - FILE *fp = files::fpFromHandle(hFile); - if (!fp) { - wibo::lastError = ERROR_INVALID_HANDLE; - return FALSE; - } - if (fflush(fp) != 0 || ftruncate(fileno(fp), ftell(fp)) != 0) { - setLastErrorFromErrno(); - return FALSE; - } - return TRUE; -} - -int WIN_FUNC CreateDirectoryA(const char *lpPathName, void *lpSecurityAttributes) { - std::string path = files::pathFromWindows(lpPathName); - DEBUG_LOG("CreateDirectoryA(%s, %p)\n", path.c_str(), lpSecurityAttributes); - return mkdir(path.c_str(), 0755) == 0; -} - -int WIN_FUNC RemoveDirectoryA(const char *lpPathName) { - std::string path = files::pathFromWindows(lpPathName); - DEBUG_LOG("RemoveDirectoryA(%s)\n", path.c_str()); - return rmdir(path.c_str()) == 0; -} - -int WIN_FUNC SetFileAttributesA(const char *lpPathName, unsigned int dwFileAttributes) { - std::string path = files::pathFromWindows(lpPathName); - DEBUG_LOG("SetFileAttributesA(%s, %u)\n", path.c_str(), dwFileAttributes); - return 1; -} - -DWORD WIN_FUNC GetFileSize(HANDLE hFile, LPDWORD lpFileSizeHigh) { - DEBUG_LOG("GetFileSize(%p, %p) ", hFile, lpFileSizeHigh); - int64_t size = getFileSize(hFile); - if (size == -1) { - DEBUG_LOG("-> INVALID_FILE_SIZE\n"); - return 0xFFFFFFFF; // INVALID_FILE_SIZE - } - DEBUG_LOG("-> %ld\n", size); - if (lpFileSizeHigh != nullptr) { - *lpFileSizeHigh = size >> 32; - } - return static_cast(size); -} - -/* - * Time - */ -int WIN_FUNC GetFileTime(void *hFile, FILETIME *lpCreationTime, FILETIME *lpLastAccessTime, FILETIME *lpLastWriteTime) { - DEBUG_LOG("GetFileTime(%p, %p, %p, %p)\n", hFile, lpCreationTime, lpLastAccessTime, lpLastWriteTime); - FILE *fp = files::fpFromHandle(hFile); - if (!fp) { - wibo::lastError = ERROR_INVALID_HANDLE; - return 0; - } - int fd = fileno(fp); - if (fd < 0) { - setLastErrorFromErrno(); - return 0; - } - struct stat st; - if (fstat(fd, &st) != 0) { - setLastErrorFromErrno(); - return 0; - } - auto makeFileTime = [](time_t sec, long nanos) { - uint64_t ticks = UNIX_TIME_ZERO; - ticks += static_cast(sec) * 10000000ULL; - ticks += static_cast(nanos) / 100ULL; - return fileTimeFromDuration(ticks); - }; - if (lpCreationTime) { -#if defined(__APPLE__) - *lpCreationTime = makeFileTime(st.st_ctimespec.tv_sec, st.st_ctimespec.tv_nsec); -#elif defined(__linux__) - *lpCreationTime = makeFileTime(st.st_ctim.tv_sec, st.st_ctim.tv_nsec); -#else - *lpCreationTime = makeFileTime(st.st_ctime, 0); -#endif - } - if (lpLastAccessTime) { -#if defined(__APPLE__) - *lpLastAccessTime = makeFileTime(st.st_atimespec.tv_sec, st.st_atimespec.tv_nsec); -#elif defined(__linux__) - *lpLastAccessTime = makeFileTime(st.st_atim.tv_sec, st.st_atim.tv_nsec); -#else - *lpLastAccessTime = makeFileTime(st.st_atime, 0); -#endif - } - if (lpLastWriteTime) { -#if defined(__APPLE__) - *lpLastWriteTime = makeFileTime(st.st_mtimespec.tv_sec, st.st_mtimespec.tv_nsec); -#elif defined(__linux__) - *lpLastWriteTime = makeFileTime(st.st_mtim.tv_sec, st.st_mtim.tv_nsec); -#else - *lpLastWriteTime = makeFileTime(st.st_mtime, 0); -#endif - } - wibo::lastError = ERROR_SUCCESS; - return 1; -} - -static struct timespec statAccessTimespec(const struct stat &st) { -#if defined(__APPLE__) - return st.st_atimespec; -#elif defined(__linux__) - return st.st_atim; -#else - struct timespec ts{}; - ts.tv_sec = st.st_atime; - ts.tv_nsec = 0; - return ts; -#endif -} - -static struct timespec statModifyTimespec(const struct stat &st) { -#if defined(__APPLE__) - return st.st_mtimespec; -#elif defined(__linux__) - return st.st_mtim; -#else - struct timespec ts{}; - ts.tv_sec = st.st_mtime; - ts.tv_nsec = 0; - return ts; -#endif -} - -int WIN_FUNC SetFileTime(void *hFile, const FILETIME *lpCreationTime, const FILETIME *lpLastAccessTime, - const FILETIME *lpLastWriteTime) { - DEBUG_LOG("SetFileTime(%p, %p, %p, %p)\n", hFile, lpCreationTime, lpLastAccessTime, lpLastWriteTime); - FILE *fp = files::fpFromHandle(hFile); - if (!fp) { - wibo::lastError = ERROR_INVALID_HANDLE; - return 0; - } - int fd = fileno(fp); - if (fd < 0) { - setLastErrorFromErrno(); - return 0; - } - bool changeAccess = !shouldIgnoreFileTimeParam(lpLastAccessTime); - bool changeWrite = !shouldIgnoreFileTimeParam(lpLastWriteTime); - if (!changeAccess && !changeWrite) { - wibo::lastError = ERROR_SUCCESS; - return 1; - } - struct stat st{}; - if (fstat(fd, &st) != 0) { - setLastErrorFromErrno(); - return 0; - } - struct timespec accessSpec = statAccessTimespec(st); - struct timespec writeSpec = statModifyTimespec(st); - if (changeAccess) { - int64_t seconds = 0; - uint32_t hundreds = 0; - if (!fileTimeToUnixParts(*lpLastAccessTime, seconds, hundreds) || - !unixPartsToTimespec(seconds, hundreds, accessSpec)) { - wibo::lastError = ERROR_INVALID_PARAMETER; - return 0; - } - } - if (changeWrite) { - int64_t seconds = 0; - uint32_t hundreds = 0; - if (!fileTimeToUnixParts(*lpLastWriteTime, seconds, hundreds) || - !unixPartsToTimespec(seconds, hundreds, writeSpec)) { - wibo::lastError = ERROR_INVALID_PARAMETER; - return 0; - } - } -#if defined(__APPLE__) || defined(__FreeBSD__) - struct timeval tv[2]; - tv[0].tv_sec = accessSpec.tv_sec; - tv[0].tv_usec = accessSpec.tv_nsec / 1000L; - tv[1].tv_sec = writeSpec.tv_sec; - tv[1].tv_usec = writeSpec.tv_nsec / 1000L; - if (futimes(fd, tv) != 0) { - setLastErrorFromErrno(); - return 0; - } -#else - struct timespec times[2] = {accessSpec, writeSpec}; - if (futimens(fd, times) != 0) { - setLastErrorFromErrno(); - return 0; - } -#endif - if (!shouldIgnoreFileTimeParam(lpCreationTime) && lpCreationTime) { - DEBUG_LOG("SetFileTime: creation time not supported\n"); - } - wibo::lastError = ERROR_SUCCESS; - return 1; -} - -struct BY_HANDLE_FILE_INFORMATION { - unsigned long dwFileAttributes; - FILETIME ftCreationTime; - FILETIME ftLastAccessTime; - FILETIME ftLastWriteTime; - unsigned long dwVolumeSerialNumber; - unsigned long nFileSizeHigh; - unsigned long nFileSizeLow; - unsigned long nNumberOfLinks; - unsigned long nFileIndexHigh; - unsigned long nFileIndexLow; -}; - -int WIN_FUNC GetFileInformationByHandle(void *hFile, BY_HANDLE_FILE_INFORMATION *lpFileInformation) { - DEBUG_LOG("GetFileInformationByHandle(%p, %p)\n", hFile, lpFileInformation); - FILE *fp = files::fpFromHandle(hFile); - if (fp == nullptr) { - wibo::lastError = 6; // ERROR_INVALID_HANDLE - return 0; - } - struct stat64 st{}; - if (fstat64(fileno(fp), &st)) { - setLastErrorFromErrno(); - return 0; - } - - if (lpFileInformation != nullptr) { - lpFileInformation->dwFileAttributes = 0; - if (S_ISDIR(st.st_mode)) { - lpFileInformation->dwFileAttributes |= 0x10; - } - if (S_ISREG(st.st_mode)) { - lpFileInformation->dwFileAttributes |= 0x80; - } - lpFileInformation->ftCreationTime = defaultFiletime; - lpFileInformation->ftLastAccessTime = defaultFiletime; - lpFileInformation->ftLastWriteTime = defaultFiletime; - lpFileInformation->dwVolumeSerialNumber = 0; - lpFileInformation->nFileSizeHigh = (unsigned long)(st.st_size >> 32); - lpFileInformation->nFileSizeLow = (unsigned long)st.st_size; - lpFileInformation->nNumberOfLinks = 0; - lpFileInformation->nFileIndexHigh = 0; - lpFileInformation->nFileIndexLow = 0; - } - return 1; -} - -constexpr DWORD FILE_TYPE_UNKNOWN = 0x0000; -constexpr DWORD FILE_TYPE_DISK = 0x0001; -constexpr DWORD FILE_TYPE_CHAR = 0x0002; -constexpr DWORD FILE_TYPE_PIPE = 0x0003; - -DWORD WIN_FUNC GetFileType(HANDLE hFile) { - DEBUG_LOG("GetFileType(%p) ", hFile); - - auto *file = files::fileHandleFromHandle(hFile); - if (!file || file->fd < 0) { - wibo::lastError = ERROR_INVALID_HANDLE; - DEBUG_LOG("-> ERROR_INVALID_HANDLE\n"); - return FILE_TYPE_UNKNOWN; - } - - struct stat st{}; - if (fstat(file->fd, &st) != 0) { - setLastErrorFromErrno(); - DEBUG_LOG("-> fstat error\n"); - return FILE_TYPE_UNKNOWN; - } - - wibo::lastError = ERROR_SUCCESS; - DWORD type = FILE_TYPE_UNKNOWN; - if (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode) || S_ISBLK(st.st_mode)) { - type = FILE_TYPE_DISK; - } - if (S_ISCHR(st.st_mode)) { - type = FILE_TYPE_CHAR; - } - if (S_ISSOCK(st.st_mode) || S_ISFIFO(st.st_mode)) { - type = FILE_TYPE_PIPE; - } - DEBUG_LOG("-> %u\n", type); - return type; -} - -UINT WIN_FUNC SetHandleCount(UINT uNumber) { - DEBUG_LOG("SetHandleCount(%u)\n", uNumber); - return handles::MAX_HANDLES; -} - -void WIN_FUNC Sleep(DWORD dwMilliseconds) { - DEBUG_LOG("Sleep(%u)\n", dwMilliseconds); - usleep(static_cast(dwMilliseconds) * 1000); -} - -unsigned int WIN_FUNC IsProcessorFeaturePresent(unsigned int processorFeature) { - DEBUG_LOG("IsProcessorFeaturePresent(%u)\n", processorFeature); - - if (processorFeature == 0) // PF_FLOATING_POINT_PRECISION_ERRATA - return 1; - if (processorFeature == 10) // PF_XMMI64_INSTRUCTIONS_AVAILABLE (SSE2) - return 1; - if (processorFeature == 23) // PF_FASTFAIL_AVAILABLE (__fastfail() supported) - return 1; - - // sure.. we have that feature... - DEBUG_LOG(" IsProcessorFeaturePresent: we don't know about feature %u, lying...\n", processorFeature); - return 1; -} - -unsigned int WIN_FUNC FormatMessageA(unsigned int dwFlags, void *lpSource, unsigned int dwMessageId, - unsigned int dwLanguageId, char *lpBuffer, unsigned int nSize, va_list *argument) { - DEBUG_LOG("FormatMessageA(%u, %p, %u, %u, %p, %u, %p)\n", dwFlags, lpSource, dwMessageId, dwLanguageId, lpBuffer, - nSize, argument); - - if (dwFlags & 0x00000100) { - // FORMAT_MESSAGE_ALLOCATE_BUFFER - } else if (dwFlags & 0x00002000) { - // FORMAT_MESSAGE_ARGUMENT_ARRAY - } else if (dwFlags & 0x00000800) { - // FORMAT_MESSAGE_FROM_HMODULE - } else if (dwFlags & 0x00000400) { - // FORMAT_MESSAGE_FROM_STRING - } else if (dwFlags & 0x00001000) { - // FORMAT_MESSAGE_FROM_SYSTEM - std::string message = std::system_category().message(dwMessageId); - size_t length = message.length(); - strcpy(lpBuffer, message.c_str()); - return length; - } else if (dwFlags & 0x00000200) { - // FORMAT_MESSAGE_IGNORE_INSERTS - } else { - // unhandled? - } - - *lpBuffer = '\0'; - return 0; -} - -int WIN_FUNC GetComputerNameA(char *lpBuffer, unsigned int *nSize) { - DEBUG_LOG("GetComputerNameA(%p, %p)\n", lpBuffer, nSize); - if (!nSize || !lpBuffer) { - if (nSize) { - *nSize = 0; - } - wibo::lastError = ERROR_INVALID_PARAMETER; - return 0; - } - constexpr unsigned int required = 9; // "COMPNAME" + null terminator - if (*nSize < required) { - *nSize = required; - wibo::lastError = ERROR_BUFFER_OVERFLOW; - return 0; - } - strcpy(lpBuffer, "COMPNAME"); - *nSize = required - 1; - wibo::lastError = ERROR_SUCCESS; - return 1; -} - -int WIN_FUNC GetComputerNameW(uint16_t *lpBuffer, unsigned int *nSize) { - DEBUG_LOG("GetComputerNameW(%p, %p)\n", lpBuffer, nSize); - if (!nSize || !lpBuffer) { - if (nSize) { - *nSize = 0; - } - wibo::lastError = ERROR_INVALID_PARAMETER; - return 0; - } - constexpr uint16_t computerName[] = {'C', 'O', 'M', 'P', 'N', 'A', 'M', 'E', 0}; - constexpr unsigned int nameLength = 8; - constexpr unsigned int required = nameLength + 1; - if (*nSize < required) { - *nSize = required; - wibo::lastError = ERROR_BUFFER_OVERFLOW; - return 0; - } - wstrncpy(lpBuffer, computerName, required); - *nSize = nameLength; - wibo::lastError = ERROR_SUCCESS; - return 1; -} - -void *WIN_FUNC EncodePointer(void *Ptr) { - DEBUG_LOG("EncodePointer(%p)\n", Ptr); - return Ptr; -} - -void *WIN_FUNC DecodePointer(void *Ptr) { - DEBUG_LOG("DecodePointer(%p)\n", Ptr); - return Ptr; -} - -BOOL WIN_FUNC SetDllDirectoryA(LPCSTR lpPathName) { - DEBUG_LOG("SetDllDirectoryA(%s)\n", lpPathName); - if (!lpPathName || lpPathName[0] == '\0') { - wibo::clearDllDirectoryOverride(); - wibo::lastError = ERROR_SUCCESS; - return TRUE; - } - - auto hostPath = files::pathFromWindows(lpPathName); - if (hostPath.empty() || !std::filesystem::exists(hostPath)) { - wibo::lastError = ERROR_PATH_NOT_FOUND; - return FALSE; - } - - wibo::setDllDirectoryOverride(std::filesystem::absolute(hostPath)); - wibo::lastError = ERROR_SUCCESS; - return TRUE; -} - -void WIN_FUNC RtlUnwind(void *TargetFrame, void *TargetIp, EXCEPTION_RECORD *ExceptionRecord, void *ReturnValue) { - DEBUG_LOG("RtlUnwind(%p, %p, %p, %p)\n", TargetFrame, TargetIp, ExceptionRecord, ReturnValue); - DEBUG_LOG("WARNING: Silently returning from RtlUnwind - exception handlers and clean up code may not be run"); -} - -BOOL WIN_FUNC GetOverlappedResult(HANDLE hFile, LPOVERLAPPED lpOverlapped, LPDWORD lpNumberOfBytesTransferred, - BOOL bWait) { - DEBUG_LOG("GetOverlappedResult(%p, %p, %p, %d)\n", hFile, lpOverlapped, lpNumberOfBytesTransferred, bWait); - (void)hFile; - if (!lpOverlapped) { - wibo::lastError = ERROR_INVALID_PARAMETER; - return FALSE; - } - if (bWait && lpOverlapped->Internal == STATUS_PENDING) { - if (lpOverlapped->hEvent) { - WaitForSingleObject(lpOverlapped->hEvent, 0xFFFFFFFF); - } - } - - const auto status = static_cast(lpOverlapped->Internal); - if (status == STATUS_PENDING) { - wibo::lastError = ERROR_IO_INCOMPLETE; - if (lpNumberOfBytesTransferred) { - *lpNumberOfBytesTransferred = static_cast(lpOverlapped->InternalHigh); - } - return FALSE; - } - - if (lpNumberOfBytesTransferred) { - *lpNumberOfBytesTransferred = static_cast(lpOverlapped->InternalHigh); - } - - if (status == STATUS_SUCCESS) { - wibo::lastError = ERROR_SUCCESS; - return TRUE; - } - if (status == STATUS_END_OF_FILE || status == ERROR_HANDLE_EOF) { - wibo::lastError = ERROR_HANDLE_EOF; - return FALSE; - } - - wibo::lastError = status; - return FALSE; -} -} // namespace kernel32 static void *resolveByName(const char *name) { // errhandlingapi.h @@ -954,16 +33,16 @@ static void *resolveByName(const char *name) { return (void *)kernel32::IsBadReadPtr; if (strcmp(name, "IsBadWritePtr") == 0) return (void *)kernel32::IsBadWritePtr; - if (strcmp(name, "Wow64DisableWow64FsRedirection") == 0) - return (void *)kernel32::Wow64DisableWow64FsRedirection; - if (strcmp(name, "Wow64RevertWow64FsRedirection") == 0) - return (void *)kernel32::Wow64RevertWow64FsRedirection; - if (strcmp(name, "IsWow64Process") == 0) - return (void *)kernel32::IsWow64Process; if (strcmp(name, "RaiseException") == 0) return (void *)kernel32::RaiseException; if (strcmp(name, "AddVectoredExceptionHandler") == 0) return (void *)kernel32::AddVectoredExceptionHandler; + if (strcmp(name, "SetUnhandledExceptionFilter") == 0) + return (void *)kernel32::SetUnhandledExceptionFilter; + if (strcmp(name, "UnhandledExceptionFilter") == 0) + return (void *)kernel32::UnhandledExceptionFilter; + if (strcmp(name, "SetErrorMode") == 0) + return (void *)kernel32::SetErrorMode; // processthreadsapi.h if (strcmp(name, "IsProcessorFeaturePresent") == 0) @@ -1010,6 +89,18 @@ static void *resolveByName(const char *name) { return (void *)kernel32::GetThreadTimes; if (strcmp(name, "SetThreadDescription") == 0) return (void *)kernel32::SetThreadDescription; + if (strcmp(name, "SetThreadAffinityMask") == 0) + return (void *)kernel32::SetThreadAffinityMask; + if (strcmp(name, "ResumeThread") == 0) + return (void *)kernel32::ResumeThread; + if (strcmp(name, "SetThreadPriority") == 0) + return (void *)kernel32::SetThreadPriority; + if (strcmp(name, "GetThreadPriority") == 0) + return (void *)kernel32::GetThreadPriority; + if (strcmp(name, "GetProcessAffinityMask") == 0) + return (void *)kernel32::GetProcessAffinityMask; + if (strcmp(name, "SetProcessAffinityMask") == 0) + return (void *)kernel32::SetProcessAffinityMask; // winnls.h if (strcmp(name, "GetSystemDefaultLangID") == 0) @@ -1094,14 +185,8 @@ static void *resolveByName(const char *name) { return (void *)kernel32::ReleaseMutex; if (strcmp(name, "ReleaseSemaphore") == 0) return (void *)kernel32::ReleaseSemaphore; - if (strcmp(name, "SetThreadAffinityMask") == 0) - return (void *)kernel32::SetThreadAffinityMask; - if (strcmp(name, "ResumeThread") == 0) - return (void *)kernel32::ResumeThread; - if (strcmp(name, "SetThreadPriority") == 0) - return (void *)kernel32::SetThreadPriority; - if (strcmp(name, "GetThreadPriority") == 0) - return (void *)kernel32::GetThreadPriority; + if (strcmp(name, "Sleep") == 0) + return (void *)kernel32::Sleep; // winbase.h if (strcmp(name, "GlobalAlloc") == 0) @@ -1136,20 +221,8 @@ static void *resolveByName(const char *name) { return (void *)kernel32::SetCurrentDirectoryA; if (strcmp(name, "SetCurrentDirectoryW") == 0) return (void *)kernel32::SetCurrentDirectoryW; - if (strcmp(name, "FindResourceA") == 0) - return (void *)kernel32::FindResourceA; - if (strcmp(name, "FindResourceExA") == 0) - return (void *)kernel32::FindResourceExA; - if (strcmp(name, "FindResourceW") == 0) - return (void *)kernel32::FindResourceW; - if (strcmp(name, "FindResourceExW") == 0) - return (void *)kernel32::FindResourceExW; if (strcmp(name, "SetHandleCount") == 0) return (void *)kernel32::SetHandleCount; - if (strcmp(name, "GetProcessAffinityMask") == 0) - return (void *)kernel32::GetProcessAffinityMask; - if (strcmp(name, "SetProcessAffinityMask") == 0) - return (void *)kernel32::SetProcessAffinityMask; if (strcmp(name, "FormatMessageA") == 0) return (void *)kernel32::FormatMessageA; if (strcmp(name, "GetComputerNameA") == 0) @@ -1162,8 +235,18 @@ static void *resolveByName(const char *name) { return (void *)kernel32::DecodePointer; if (strcmp(name, "SetDllDirectoryA") == 0) return (void *)kernel32::SetDllDirectoryA; - if (strcmp(name, "Sleep") == 0) - return (void *)kernel32::Sleep; + if (strcmp(name, "GetLongPathNameA") == 0) + return (void *)kernel32::GetLongPathNameA; + if (strcmp(name, "GetLongPathNameW") == 0) + return (void *)kernel32::GetLongPathNameW; + if (strcmp(name, "GetDiskFreeSpaceA") == 0) + return (void *)kernel32::GetDiskFreeSpaceA; + if (strcmp(name, "GetDiskFreeSpaceW") == 0) + return (void *)kernel32::GetDiskFreeSpaceW; + if (strcmp(name, "GetDiskFreeSpaceExA") == 0) + return (void *)kernel32::GetDiskFreeSpaceExA; + if (strcmp(name, "GetDiskFreeSpaceExW") == 0) + return (void *)kernel32::GetDiskFreeSpaceExW; // processenv.h if (strcmp(name, "GetCommandLineA") == 0) @@ -1186,16 +269,18 @@ static void *resolveByName(const char *name) { return (void *)kernel32::SetEnvironmentVariableW; if (strcmp(name, "GetEnvironmentVariableW") == 0) return (void *)kernel32::GetEnvironmentVariableW; - - // console api if (strcmp(name, "GetStdHandle") == 0) return (void *)kernel32::GetStdHandle; if (strcmp(name, "SetStdHandle") == 0) return (void *)kernel32::SetStdHandle; + + // handleapi.h if (strcmp(name, "DuplicateHandle") == 0) return (void *)kernel32::DuplicateHandle; if (strcmp(name, "CloseHandle") == 0) return (void *)kernel32::CloseHandle; + + // wincon.h if (strcmp(name, "GetConsoleMode") == 0) return (void *)kernel32::GetConsoleMode; if (strcmp(name, "SetConsoleMode") == 0) @@ -1298,18 +383,6 @@ static void *resolveByName(const char *name) { return (void *)kernel32::GetTempFileNameA; if (strcmp(name, "GetTempPathA") == 0) return (void *)kernel32::GetTempPathA; - if (strcmp(name, "GetLongPathNameA") == 0) - return (void *)kernel32::GetLongPathNameA; - if (strcmp(name, "GetLongPathNameW") == 0) - return (void *)kernel32::GetLongPathNameW; - if (strcmp(name, "GetDiskFreeSpaceA") == 0) - return (void *)kernel32::GetDiskFreeSpaceA; - if (strcmp(name, "GetDiskFreeSpaceW") == 0) - return (void *)kernel32::GetDiskFreeSpaceW; - if (strcmp(name, "GetDiskFreeSpaceExA") == 0) - return (void *)kernel32::GetDiskFreeSpaceExA; - if (strcmp(name, "GetDiskFreeSpaceExW") == 0) - return (void *)kernel32::GetDiskFreeSpaceExW; // sysinfoapi.h if (strcmp(name, "GetSystemInfo") == 0) @@ -1366,6 +439,14 @@ static void *resolveByName(const char *name) { return (void *)kernel32::FreeLibrary; if (strcmp(name, "GetProcAddress") == 0) return (void *)kernel32::GetProcAddress; + if (strcmp(name, "FindResourceA") == 0) + return (void *)kernel32::FindResourceA; + if (strcmp(name, "FindResourceExA") == 0) + return (void *)kernel32::FindResourceExA; + if (strcmp(name, "FindResourceW") == 0) + return (void *)kernel32::FindResourceW; + if (strcmp(name, "FindResourceExW") == 0) + return (void *)kernel32::FindResourceExW; // heapapi.h if (strcmp(name, "HeapCreate") == 0) @@ -1419,21 +500,9 @@ static void *resolveByName(const char *name) { if (strcmp(name, "IsDebuggerPresent") == 0) return (void *)kernel32::IsDebuggerPresent; - // errhandlingapi.h - if (strcmp(name, "SetUnhandledExceptionFilter") == 0) - return (void *)kernel32::SetUnhandledExceptionFilter; - if (strcmp(name, "UnhandledExceptionFilter") == 0) - return (void *)kernel32::UnhandledExceptionFilter; - if (strcmp(name, "SetErrorMode") == 0) - return (void *)kernel32::SetErrorMode; - // interlockedapi.h if (strcmp(name, "InitializeSListHead") == 0) return (void *)kernel32::InitializeSListHead; - - // winnt.h - if (strcmp(name, "RtlUnwind") == 0) - return (void *)kernel32::RtlUnwind; if (strcmp(name, "InterlockedIncrement") == 0) return (void *)kernel32::InterlockedIncrement; if (strcmp(name, "InterlockedDecrement") == 0) @@ -1443,6 +512,10 @@ static void *resolveByName(const char *name) { if (strcmp(name, "InterlockedCompareExchange") == 0) return (void *)kernel32::InterlockedCompareExchange; + // winnt.h + if (strcmp(name, "RtlUnwind") == 0) + return (void *)kernel32::RtlUnwind; + // fibersapi.h if (strcmp(name, "FlsAlloc") == 0) return (void *)kernel32::FlsAlloc; @@ -1457,6 +530,14 @@ static void *resolveByName(const char *name) { if (strcmp(name, "GetOverlappedResult") == 0) return (void *)kernel32::GetOverlappedResult; + // wow64apiset.h + if (strcmp(name, "Wow64DisableWow64FsRedirection") == 0) + return (void *)kernel32::Wow64DisableWow64FsRedirection; + if (strcmp(name, "Wow64RevertWow64FsRedirection") == 0) + return (void *)kernel32::Wow64RevertWow64FsRedirection; + if (strcmp(name, "IsWow64Process") == 0) + return (void *)kernel32::IsWow64Process; + return 0; } diff --git a/dll/kernel32/fileapi.cpp b/dll/kernel32/fileapi.cpp index 5585026..aa2f5d4 100644 --- a/dll/kernel32/fileapi.cpp +++ b/dll/kernel32/fileapi.cpp @@ -2,8 +2,10 @@ #include "errors.h" #include "files.h" +#include "handles.h" #include "internal.h" #include "strutil.h" +#include "timeutil.h" #include #include @@ -12,8 +14,12 @@ #include #include #include +#include +#include #include #include +#include +#include #include #include @@ -31,6 +37,48 @@ const FILETIME kDefaultFindFileTime = { static_cast((kSecondsBetween1601And1970 * kWindowsTicksPerSecond) & 0xFFFFFFFFULL), static_cast((kSecondsBetween1601And1970 * kWindowsTicksPerSecond) >> 32)}; +const FILETIME kDefaultFileInformationTime = {static_cast(UNIX_TIME_ZERO & 0xFFFFFFFFULL), + static_cast(UNIX_TIME_ZERO >> 32)}; + +struct timespec accessTimespec(const struct stat &st) { +#if defined(__APPLE__) + return st.st_atimespec; +#elif defined(__linux__) + return st.st_atim; +#else + struct timespec ts{}; + ts.tv_sec = st.st_atime; + ts.tv_nsec = 0; + return ts; +#endif +} + +struct timespec modifyTimespec(const struct stat &st) { +#if defined(__APPLE__) + return st.st_mtimespec; +#elif defined(__linux__) + return st.st_mtim; +#else + struct timespec ts{}; + ts.tv_sec = st.st_mtime; + ts.tv_nsec = 0; + return ts; +#endif +} + +struct timespec changeTimespec(const struct stat &st) { +#if defined(__APPLE__) + return st.st_ctimespec; +#elif defined(__linux__) + return st.st_ctim; +#else + struct timespec ts{}; + ts.tv_sec = st.st_ctime; + ts.tv_nsec = 0; + return ts; +#endif +} + struct FindFirstFileHandle { std::filesystem::directory_iterator it; std::filesystem::directory_iterator end; @@ -177,6 +225,701 @@ bool initializeEnumeration(const std::filesystem::path &parent, const std::strin namespace kernel32 { +int64_t getFileSizeFromHandle(HANDLE hFile) { + FILE *fp = files::fpFromHandle(hFile); + if (!fp) { + wibo::lastError = ERROR_INVALID_HANDLE; + return -1; + } + struct stat64 st{}; + fflush(fp); + if (fstat64(fileno(fp), &st) == -1 || !S_ISREG(st.st_mode)) { + setLastErrorFromErrno(); + return -1; + } + return st.st_size; +} + +DWORD WIN_FUNC GetFileAttributesA(LPCSTR lpFileName) { + if (!lpFileName) { + wibo::lastError = ERROR_INVALID_PARAMETER; + return INVALID_FILE_ATTRIBUTES; + } + std::filesystem::path path = files::pathFromWindows(lpFileName); + std::string pathStr = path.string(); + DEBUG_LOG("GetFileAttributesA(%s) -> %s\n", lpFileName, pathStr.c_str()); + + if (endsWith(pathStr, "/license.dat")) { + DEBUG_LOG("MWCC license override\n"); + wibo::lastError = ERROR_SUCCESS; + return FILE_ATTRIBUTE_NORMAL; + } + + std::error_code ec; + auto status = std::filesystem::status(path, ec); + if (ec) { + errno = ec.value(); + setLastErrorFromErrno(); + return INVALID_FILE_ATTRIBUTES; + } + + wibo::lastError = ERROR_SUCCESS; + switch (status.type()) { + case std::filesystem::file_type::regular: + DEBUG_LOG("File exists\n"); + return FILE_ATTRIBUTE_NORMAL; + case std::filesystem::file_type::directory: + return FILE_ATTRIBUTE_DIRECTORY; + case std::filesystem::file_type::not_found: + default: + DEBUG_LOG("File does not exist\n"); + wibo::lastError = ERROR_FILE_NOT_FOUND; + return INVALID_FILE_ATTRIBUTES; + } +} + +DWORD WIN_FUNC GetFileAttributesW(LPCWSTR lpFileName) { + DEBUG_LOG("GetFileAttributesW -> "); + if (!lpFileName) { + wibo::lastError = ERROR_INVALID_PARAMETER; + return INVALID_FILE_ATTRIBUTES; + } + std::string str = wideStringToString(lpFileName); + return GetFileAttributesA(str.c_str()); +} + +BOOL WIN_FUNC WriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, + LPOVERLAPPED lpOverlapped) { + DEBUG_LOG("WriteFile(%p, %u)\n", hFile, nNumberOfBytesToWrite); + wibo::lastError = ERROR_SUCCESS; + + auto file = files::fileHandleFromHandle(hFile); + if (!file || !file->fp) { + wibo::lastError = ERROR_INVALID_HANDLE; + return FALSE; + } + + bool handleOverlapped = (file->flags & FILE_FLAG_OVERLAPPED) != 0; + auto *overlapped = reinterpret_cast(lpOverlapped); + bool usingOverlapped = overlapped != nullptr; + if (!usingOverlapped && lpNumberOfBytesWritten == nullptr) { + wibo::lastError = ERROR_INVALID_PARAMETER; + return FALSE; + } + + std::optional offset; + bool updateFilePointer = true; + if (usingOverlapped) { + offset = (static_cast(overlapped->Offset) | (static_cast(overlapped->OffsetHigh) << 32)); + overlapped->Internal = STATUS_PENDING; + overlapped->InternalHigh = 0; + updateFilePointer = !handleOverlapped; + resetOverlappedEvent(overlapped); + } + + auto io = files::write(file, lpBuffer, nNumberOfBytesToWrite, offset, updateFilePointer); + DWORD completionStatus = STATUS_SUCCESS; + if (io.unixError != 0) { + completionStatus = wibo::winErrorFromErrno(io.unixError); + wibo::lastError = completionStatus; + if (lpNumberOfBytesWritten) { + *lpNumberOfBytesWritten = static_cast(io.bytesTransferred); + } + if (usingOverlapped) { + overlapped->Internal = completionStatus; + overlapped->InternalHigh = io.bytesTransferred; + signalOverlappedEvent(overlapped); + } + return FALSE; + } + + if (lpNumberOfBytesWritten && (!handleOverlapped || !usingOverlapped)) { + *lpNumberOfBytesWritten = static_cast(io.bytesTransferred); + } + + if (usingOverlapped) { + overlapped->Internal = completionStatus; + overlapped->InternalHigh = io.bytesTransferred; + if (!handleOverlapped) { + uint64_t baseOffset = offset.value_or(0); + uint64_t newOffset = baseOffset + io.bytesTransferred; + overlapped->Offset = static_cast(newOffset & 0xFFFFFFFFu); + overlapped->OffsetHigh = static_cast(newOffset >> 32); + } + signalOverlappedEvent(overlapped); + } + + return (io.bytesTransferred == nNumberOfBytesToWrite) ? TRUE : FALSE; +} + +BOOL WIN_FUNC FlushFileBuffers(HANDLE hFile) { + DEBUG_LOG("FlushFileBuffers(%p)\n", hFile); + auto data = handles::dataFromHandle(hFile, false); + if (data.type != handles::TYPE_FILE || data.ptr == nullptr) { + wibo::lastError = ERROR_INVALID_HANDLE; + return FALSE; + } + auto file = reinterpret_cast(data.ptr); + if (!file || !file->fp) { + wibo::lastError = ERROR_INVALID_HANDLE; + return FALSE; + } + FILE *fp = file->fp; + if (fflush(fp) != 0) { + wibo::lastError = ERROR_ACCESS_DENIED; + return FALSE; + } + int fd = file->fd; + if (fd >= 0 && fsync(fd) != 0) { + wibo::lastError = ERROR_ACCESS_DENIED; + return FALSE; + } + wibo::lastError = ERROR_SUCCESS; + return TRUE; +} + +BOOL WIN_FUNC ReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead, + LPOVERLAPPED lpOverlapped) { + DEBUG_LOG("ReadFile(%p, %u)\n", hFile, nNumberOfBytesToRead); + wibo::lastError = ERROR_SUCCESS; + + auto file = files::fileHandleFromHandle(hFile); + if (!file || !file->fp) { + wibo::lastError = ERROR_INVALID_HANDLE; + return FALSE; + } + + bool handleOverlapped = (file->flags & FILE_FLAG_OVERLAPPED) != 0; + auto *overlapped = reinterpret_cast(lpOverlapped); + bool usingOverlapped = overlapped != nullptr; + if (!usingOverlapped && lpNumberOfBytesRead == nullptr) { + wibo::lastError = ERROR_INVALID_PARAMETER; + return FALSE; + } + + std::optional offset; + bool updateFilePointer = true; + if (usingOverlapped) { + offset = (static_cast(overlapped->Offset) | (static_cast(overlapped->OffsetHigh) << 32)); + overlapped->Internal = STATUS_PENDING; + overlapped->InternalHigh = 0; + updateFilePointer = !handleOverlapped; + resetOverlappedEvent(overlapped); + } + + auto io = files::read(file, lpBuffer, nNumberOfBytesToRead, offset, updateFilePointer); + DWORD completionStatus = STATUS_SUCCESS; + if (io.unixError != 0) { + completionStatus = wibo::winErrorFromErrno(io.unixError); + wibo::lastError = completionStatus; + if (lpNumberOfBytesRead) { + *lpNumberOfBytesRead = static_cast(io.bytesTransferred); + } + if (usingOverlapped) { + overlapped->Internal = completionStatus; + overlapped->InternalHigh = io.bytesTransferred; + signalOverlappedEvent(overlapped); + } + return FALSE; + } + + if (io.reachedEnd && io.bytesTransferred == 0 && handleOverlapped) { + completionStatus = ERROR_HANDLE_EOF; + } + + if (lpNumberOfBytesRead && (!handleOverlapped || !usingOverlapped)) { + *lpNumberOfBytesRead = static_cast(io.bytesTransferred); + } + + if (usingOverlapped) { + overlapped->Internal = completionStatus; + overlapped->InternalHigh = io.bytesTransferred; + if (!handleOverlapped) { + uint64_t baseOffset = offset.value_or(0); + uint64_t newOffset = baseOffset + io.bytesTransferred; + overlapped->Offset = static_cast(newOffset & 0xFFFFFFFFu); + overlapped->OffsetHigh = static_cast(newOffset >> 32); + } + signalOverlappedEvent(overlapped); + } + + return TRUE; +} + +HANDLE WIN_FUNC CreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, + LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, + DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) { + (void)lpSecurityAttributes; + (void)hTemplateFile; + if (!lpFileName) { + wibo::lastError = ERROR_INVALID_PARAMETER; + return INVALID_HANDLE_VALUE; + } + std::string path = files::pathFromWindows(lpFileName); + DEBUG_LOG("CreateFileA(filename=%s (%s), desiredAccess=0x%x, shareMode=%u, securityAttributes=%p, " + "creationDisposition=%u, flagsAndAttributes=%u)\n", + lpFileName, path.c_str(), dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, + dwFlagsAndAttributes); + + wibo::lastError = ERROR_SUCCESS; + bool fileExists = (access(path.c_str(), F_OK) == 0); + bool shouldTruncate = false; + switch (dwCreationDisposition) { + case CREATE_ALWAYS: + if (fileExists) { + wibo::lastError = ERROR_ALREADY_EXISTS; + shouldTruncate = true; + } + break; + case CREATE_NEW: + if (fileExists) { + wibo::lastError = ERROR_FILE_EXISTS; + return INVALID_HANDLE_VALUE; + } + break; + case OPEN_ALWAYS: + if (fileExists) { + wibo::lastError = ERROR_ALREADY_EXISTS; + } + break; + case OPEN_EXISTING: + if (!fileExists) { + wibo::lastError = ERROR_FILE_NOT_FOUND; + return INVALID_HANDLE_VALUE; + } + break; + case TRUNCATE_EXISTING: + shouldTruncate = true; + if (!fileExists) { + wibo::lastError = ERROR_FILE_NOT_FOUND; + return INVALID_HANDLE_VALUE; + } + break; + default: + assert(false); + } + + FILE *fp = nullptr; + if (dwDesiredAccess == GENERIC_READ) { + fp = fopen(path.c_str(), "rb"); + } else if (dwDesiredAccess == GENERIC_WRITE) { + if (shouldTruncate || !fileExists) { + fp = fopen(path.c_str(), "wb"); + } else { + fp = fopen(path.c_str(), "rb+"); + } + } else if (dwDesiredAccess == (GENERIC_READ | GENERIC_WRITE)) { + if (shouldTruncate || !fileExists) { + fp = fopen(path.c_str(), "wb+"); + } else { + fp = fopen(path.c_str(), "rb+"); + } + } else { + assert(false); + } + + if (fp) { + void *handle = files::allocFpHandle(fp, dwDesiredAccess, dwShareMode, dwFlagsAndAttributes, true); + DEBUG_LOG("-> %p\n", handle); + return handle; + } + setLastErrorFromErrno(); + return INVALID_HANDLE_VALUE; +} + +HANDLE WIN_FUNC CreateFileW(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, + LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, + DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) { + DEBUG_LOG("CreateFileW -> "); + if (!lpFileName) { + wibo::lastError = ERROR_INVALID_PARAMETER; + return INVALID_HANDLE_VALUE; + } + std::string lpFileNameA = wideStringToString(lpFileName); + return CreateFileA(lpFileNameA.c_str(), dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, + dwFlagsAndAttributes, hTemplateFile); +} + +BOOL WIN_FUNC DeleteFileA(LPCSTR lpFileName) { + if (!lpFileName) { + wibo::lastError = ERROR_INVALID_PARAMETER; + DEBUG_LOG("DeleteFileA(NULL) -> ERROR_INVALID_PARAMETER\n"); + return FALSE; + } + std::string path = files::pathFromWindows(lpFileName); + DEBUG_LOG("DeleteFileA(%s) -> %s\n", lpFileName, path.c_str()); + if (unlink(path.c_str()) == 0) { + wibo::lastError = ERROR_SUCCESS; + return TRUE; + } + setLastErrorFromErrno(); + return FALSE; +} + +BOOL WIN_FUNC DeleteFileW(LPCWSTR lpFileName) { + DEBUG_LOG("DeleteFileW -> "); + if (!lpFileName) { + wibo::lastError = ERROR_INVALID_PARAMETER; + return FALSE; + } + std::string name = wideStringToString(lpFileName); + return DeleteFileA(name.c_str()); +} + +BOOL WIN_FUNC MoveFileA(LPCSTR lpExistingFileName, LPCSTR lpNewFileName) { + DEBUG_LOG("MoveFileA(%s, %s)\n", lpExistingFileName ? lpExistingFileName : "(null)", + lpNewFileName ? lpNewFileName : "(null)"); + if (!lpExistingFileName || !lpNewFileName) { + wibo::lastError = ERROR_INVALID_PARAMETER; + return FALSE; + } + auto fromPath = files::pathFromWindows(lpExistingFileName); + auto toPath = files::pathFromWindows(lpNewFileName); + std::error_code ec; + if (std::filesystem::exists(toPath, ec)) { + wibo::lastError = ERROR_ALREADY_EXISTS; + return FALSE; + } + if (ec) { + errno = ec.value(); + setLastErrorFromErrno(); + return FALSE; + } + std::filesystem::rename(fromPath, toPath, ec); + if (ec) { + errno = ec.value(); + setLastErrorFromErrno(); + return FALSE; + } + wibo::lastError = ERROR_SUCCESS; + return TRUE; +} + +BOOL WIN_FUNC MoveFileW(LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName) { + DEBUG_LOG("MoveFileW -> "); + if (!lpExistingFileName || !lpNewFileName) { + wibo::lastError = ERROR_INVALID_PARAMETER; + return FALSE; + } + std::string from = wideStringToString(lpExistingFileName); + std::string to = wideStringToString(lpNewFileName); + return MoveFileA(from.c_str(), to.c_str()); +} + +DWORD WIN_FUNC SetFilePointer(HANDLE hFile, LONG lDistanceToMove, PLONG lpDistanceToMoveHigh, DWORD dwMoveMethod) { + DEBUG_LOG("SetFilePointer(%p, %ld, %p, %u)\n", hFile, static_cast(lDistanceToMove), lpDistanceToMoveHigh, + dwMoveMethod); + if (hFile == nullptr) { + wibo::lastError = ERROR_INVALID_HANDLE; + return INVALID_SET_FILE_POINTER; + } + FILE *fp = files::fpFromHandle(hFile); + if (!fp) { + wibo::lastError = ERROR_INVALID_HANDLE; + return INVALID_SET_FILE_POINTER; + } + int origin = SEEK_SET; + if (dwMoveMethod == FILE_CURRENT) { + origin = SEEK_CUR; + } else if (dwMoveMethod == FILE_END) { + origin = SEEK_END; + } + wibo::lastError = ERROR_SUCCESS; + if (fseek(fp, lDistanceToMove, origin) < 0) { + if (errno == EINVAL) { + wibo::lastError = ERROR_NEGATIVE_SEEK; + } else { + wibo::lastError = ERROR_INVALID_PARAMETER; + } + return INVALID_SET_FILE_POINTER; + } + long position = ftell(fp); + if (position < 0) { + setLastErrorFromErrno(); + return INVALID_SET_FILE_POINTER; + } + if (lpDistanceToMoveHigh) { + *lpDistanceToMoveHigh = static_cast(static_cast(position) >> 32); + } + return static_cast(static_cast(position) & 0xFFFFFFFFu); +} + +BOOL WIN_FUNC SetFilePointerEx(HANDLE hFile, LARGE_INTEGER liDistanceToMove, PLARGE_INTEGER lpNewFilePointer, + DWORD dwMoveMethod) { + if (hFile == nullptr) { + wibo::lastError = ERROR_INVALID_HANDLE; + return FALSE; + } + FILE *fp = files::fpFromHandle(hFile); + if (!fp) { + wibo::lastError = ERROR_INVALID_HANDLE; + return FALSE; + } + int origin = SEEK_SET; + if (dwMoveMethod == FILE_CURRENT) { + origin = SEEK_CUR; + } else if (dwMoveMethod == FILE_END) { + origin = SEEK_END; + } + wibo::lastError = ERROR_SUCCESS; + if (fseeko(fp, static_cast(liDistanceToMove), origin) < 0) { + if (errno == EINVAL) { + wibo::lastError = ERROR_NEGATIVE_SEEK; + } else { + wibo::lastError = ERROR_INVALID_PARAMETER; + } + return FALSE; + } + off_t position = ftello(fp); + if (position < 0) { + setLastErrorFromErrno(); + return FALSE; + } + if (lpNewFilePointer) { + *lpNewFilePointer = static_cast(position); + } + return TRUE; +} + +BOOL WIN_FUNC SetEndOfFile(HANDLE hFile) { + DEBUG_LOG("SetEndOfFile(%p)\n", hFile); + FILE *fp = files::fpFromHandle(hFile); + if (!fp) { + wibo::lastError = ERROR_INVALID_HANDLE; + return FALSE; + } + if (fflush(fp) != 0 || ftruncate(fileno(fp), ftell(fp)) != 0) { + setLastErrorFromErrno(); + return FALSE; + } + wibo::lastError = ERROR_SUCCESS; + return TRUE; +} + +BOOL WIN_FUNC CreateDirectoryA(LPCSTR lpPathName, LPSECURITY_ATTRIBUTES lpSecurityAttributes) { + (void)lpSecurityAttributes; + if (!lpPathName) { + wibo::lastError = ERROR_INVALID_PARAMETER; + return FALSE; + } + std::string path = files::pathFromWindows(lpPathName); + DEBUG_LOG("CreateDirectoryA(%s, %p)\n", path.c_str(), lpSecurityAttributes); + if (mkdir(path.c_str(), 0755) == 0) { + wibo::lastError = ERROR_SUCCESS; + return TRUE; + } + setLastErrorFromErrno(); + return FALSE; +} + +BOOL WIN_FUNC RemoveDirectoryA(LPCSTR lpPathName) { + if (!lpPathName) { + wibo::lastError = ERROR_INVALID_PARAMETER; + return FALSE; + } + std::string path = files::pathFromWindows(lpPathName); + DEBUG_LOG("RemoveDirectoryA(%s)\n", path.c_str()); + if (rmdir(path.c_str()) == 0) { + wibo::lastError = ERROR_SUCCESS; + return TRUE; + } + setLastErrorFromErrno(); + return FALSE; +} + +BOOL WIN_FUNC SetFileAttributesA(LPCSTR lpFileName, DWORD dwFileAttributes) { + (void)dwFileAttributes; + if (!lpFileName) { + wibo::lastError = ERROR_INVALID_PARAMETER; + return FALSE; + } + DEBUG_LOG("SetFileAttributesA(%s, %u)\n", lpFileName, dwFileAttributes); + wibo::lastError = ERROR_SUCCESS; + return TRUE; +} + +DWORD WIN_FUNC GetFileSize(HANDLE hFile, LPDWORD lpFileSizeHigh) { + DEBUG_LOG("GetFileSize(%p, %p) ", hFile, lpFileSizeHigh); + int64_t size = getFileSizeFromHandle(hFile); + if (size < 0) { + if (lpFileSizeHigh) { + *lpFileSizeHigh = 0; + } + return INVALID_FILE_SIZE; + } + uint64_t uSize = static_cast(size); + if (lpFileSizeHigh) { + *lpFileSizeHigh = static_cast(uSize >> 32); + } + wibo::lastError = ERROR_SUCCESS; + return static_cast(uSize & 0xFFFFFFFFu); +} + +BOOL WIN_FUNC GetFileTime(HANDLE hFile, LPFILETIME lpCreationTime, LPFILETIME lpLastAccessTime, + LPFILETIME lpLastWriteTime) { + DEBUG_LOG("GetFileTime(%p, %p, %p, %p)\n", hFile, lpCreationTime, lpLastAccessTime, lpLastWriteTime); + auto file = files::fileHandleFromHandle(hFile); + if (!file || !file->fp) { + wibo::lastError = ERROR_INVALID_HANDLE; + return FALSE; + } + struct stat st{}; + if (fstat(fileno(file->fp), &st) != 0) { + setLastErrorFromErrno(); + return FALSE; + } + auto assignFileTime = [](LPFILETIME target, const struct timespec &spec) -> bool { + if (!target) { + return true; + } + FILETIME result{}; + uint32_t hundreds = static_cast(spec.tv_nsec / 100L); + if (!unixPartsToFileTime(static_cast(spec.tv_sec), hundreds, result)) { + return false; + } + *target = result; + return true; + }; + if (!assignFileTime(lpCreationTime, changeTimespec(st)) || !assignFileTime(lpLastAccessTime, accessTimespec(st)) || + !assignFileTime(lpLastWriteTime, modifyTimespec(st))) { + wibo::lastError = ERROR_INVALID_PARAMETER; + return FALSE; + } + wibo::lastError = ERROR_SUCCESS; + return TRUE; +} + +BOOL WIN_FUNC SetFileTime(HANDLE hFile, const FILETIME *lpCreationTime, const FILETIME *lpLastAccessTime, + const FILETIME *lpLastWriteTime) { + DEBUG_LOG("SetFileTime(%p, %p, %p, %p)\n", hFile, lpCreationTime, lpLastAccessTime, lpLastWriteTime); + FILE *fp = files::fpFromHandle(hFile); + if (!fp) { + wibo::lastError = ERROR_INVALID_HANDLE; + return FALSE; + } + int fd = fileno(fp); + if (fd < 0) { + setLastErrorFromErrno(); + return FALSE; + } + bool changeAccess = !shouldIgnoreFileTimeParam(lpLastAccessTime); + bool changeWrite = !shouldIgnoreFileTimeParam(lpLastWriteTime); + if (!changeAccess && !changeWrite) { + wibo::lastError = ERROR_SUCCESS; + return TRUE; + } + struct stat st{}; + if (fstat(fd, &st) != 0) { + setLastErrorFromErrno(); + return FALSE; + } + struct timespec accessSpec = accessTimespec(st); + struct timespec writeSpec = modifyTimespec(st); + if (changeAccess) { + int64_t seconds = 0; + uint32_t hundreds = 0; + if (!fileTimeToUnixParts(*lpLastAccessTime, seconds, hundreds) || + !unixPartsToTimespec(seconds, hundreds, accessSpec)) { + wibo::lastError = ERROR_INVALID_PARAMETER; + return FALSE; + } + } + if (changeWrite) { + int64_t seconds = 0; + uint32_t hundreds = 0; + if (!fileTimeToUnixParts(*lpLastWriteTime, seconds, hundreds) || + !unixPartsToTimespec(seconds, hundreds, writeSpec)) { + wibo::lastError = ERROR_INVALID_PARAMETER; + return FALSE; + } + } +#if defined(__APPLE__) || defined(__FreeBSD__) + struct timeval tv[2]; + tv[0].tv_sec = accessSpec.tv_sec; + tv[0].tv_usec = accessSpec.tv_nsec / 1000L; + tv[1].tv_sec = writeSpec.tv_sec; + tv[1].tv_usec = writeSpec.tv_nsec / 1000L; + if (futimes(fd, tv) != 0) { + setLastErrorFromErrno(); + return FALSE; + } +#else + struct timespec times[2] = {accessSpec, writeSpec}; + if (futimens(fd, times) != 0) { + setLastErrorFromErrno(); + return FALSE; + } +#endif + if (!shouldIgnoreFileTimeParam(lpCreationTime) && lpCreationTime) { + DEBUG_LOG("SetFileTime: creation time not supported\n"); + } + wibo::lastError = ERROR_SUCCESS; + return TRUE; +} + +BOOL WIN_FUNC GetFileInformationByHandle(HANDLE hFile, LPBY_HANDLE_FILE_INFORMATION lpFileInformation) { + DEBUG_LOG("GetFileInformationByHandle(%p, %p)\n", hFile, lpFileInformation); + FILE *fp = files::fpFromHandle(hFile); + if (fp == nullptr) { + wibo::lastError = ERROR_INVALID_HANDLE; + return FALSE; + } + struct stat64 st{}; + if (fstat64(fileno(fp), &st) != 0) { + setLastErrorFromErrno(); + return FALSE; + } + if (lpFileInformation) { + lpFileInformation->dwFileAttributes = 0; + if (S_ISDIR(st.st_mode)) { + lpFileInformation->dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY; + } + if (S_ISREG(st.st_mode)) { + lpFileInformation->dwFileAttributes |= FILE_ATTRIBUTE_NORMAL; + } + lpFileInformation->ftCreationTime = kDefaultFileInformationTime; + lpFileInformation->ftLastAccessTime = kDefaultFileInformationTime; + lpFileInformation->ftLastWriteTime = kDefaultFileInformationTime; + lpFileInformation->dwVolumeSerialNumber = 0; + lpFileInformation->nFileSizeHigh = static_cast(static_cast(st.st_size) >> 32); + lpFileInformation->nFileSizeLow = static_cast(st.st_size & 0xFFFFFFFFULL); + lpFileInformation->nNumberOfLinks = 0; + lpFileInformation->nFileIndexHigh = 0; + lpFileInformation->nFileIndexLow = 0; + } + wibo::lastError = ERROR_SUCCESS; + return TRUE; +} + +DWORD WIN_FUNC GetFileType(HANDLE hFile) { + DEBUG_LOG("GetFileType(%p) ", hFile); + auto *file = files::fileHandleFromHandle(hFile); + if (!file || file->fd < 0) { + wibo::lastError = ERROR_INVALID_HANDLE; + DEBUG_LOG("-> ERROR_INVALID_HANDLE\n"); + return FILE_TYPE_UNKNOWN; + } + struct stat st{}; + if (fstat(file->fd, &st) != 0) { + setLastErrorFromErrno(); + DEBUG_LOG("-> fstat error\n"); + return FILE_TYPE_UNKNOWN; + } + wibo::lastError = ERROR_SUCCESS; + DWORD type = FILE_TYPE_UNKNOWN; + if (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode) || S_ISBLK(st.st_mode)) { + type = FILE_TYPE_DISK; + } + if (S_ISCHR(st.st_mode)) { + type = FILE_TYPE_CHAR; + } + if (S_ISSOCK(st.st_mode) || S_ISFIFO(st.st_mode)) { + type = FILE_TYPE_PIPE; + } + DEBUG_LOG("-> %u\n", type); + return type; +} + DWORD WIN_FUNC GetFullPathNameA(LPCSTR lpFileName, DWORD nBufferLength, LPSTR lpBuffer, LPSTR *lpFilePart) { DEBUG_LOG("GetFullPathNameA(%s, %u)\n", lpFileName ? lpFileName : "(null)", nBufferLength); diff --git a/dll/kernel32/fileapi.h b/dll/kernel32/fileapi.h index 9d07385..a5c1388 100644 --- a/dll/kernel32/fileapi.h +++ b/dll/kernel32/fileapi.h @@ -3,6 +3,58 @@ #include "common.h" #include "minwinbase.h" +struct BY_HANDLE_FILE_INFORMATION { + DWORD dwFileAttributes; + FILETIME ftCreationTime; + FILETIME ftLastAccessTime; + FILETIME ftLastWriteTime; + DWORD dwVolumeSerialNumber; + DWORD nFileSizeHigh; + DWORD nFileSizeLow; + DWORD nNumberOfLinks; + DWORD nFileIndexHigh; + DWORD nFileIndexLow; +}; + +using PBY_HANDLE_FILE_INFORMATION = BY_HANDLE_FILE_INFORMATION *; +using LPBY_HANDLE_FILE_INFORMATION = BY_HANDLE_FILE_INFORMATION *; + +constexpr DWORD GENERIC_READ = 0x80000000; +constexpr DWORD GENERIC_WRITE = 0x40000000; +constexpr DWORD GENERIC_EXECUTE = 0x20000000; +constexpr DWORD GENERIC_ALL = 0x10000000; + +constexpr DWORD FILE_SHARE_READ = 0x00000001; +constexpr DWORD FILE_SHARE_WRITE = 0x00000002; +constexpr DWORD FILE_SHARE_DELETE = 0x00000004; + +constexpr DWORD CREATE_NEW = 1; +constexpr DWORD CREATE_ALWAYS = 2; +constexpr DWORD OPEN_EXISTING = 3; +constexpr DWORD OPEN_ALWAYS = 4; +constexpr DWORD TRUNCATE_EXISTING = 5; + +constexpr DWORD FILE_BEGIN = 0; +constexpr DWORD FILE_CURRENT = 1; +constexpr DWORD FILE_END = 2; + +constexpr DWORD FILE_ATTRIBUTE_READONLY = 0x00000001; +constexpr DWORD FILE_ATTRIBUTE_HIDDEN = 0x00000002; +constexpr DWORD FILE_ATTRIBUTE_SYSTEM = 0x00000004; +constexpr DWORD FILE_ATTRIBUTE_ARCHIVE = 0x00000020; +constexpr DWORD FILE_ATTRIBUTE_TEMPORARY = 0x00000100; +constexpr DWORD FILE_ATTRIBUTE_OFFLINE = 0x00001000; +constexpr DWORD FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x00002000; +constexpr DWORD FILE_ATTRIBUTE_ENCRYPTED = 0x00004000; + +constexpr DWORD FILE_TYPE_UNKNOWN = 0x0000; +constexpr DWORD FILE_TYPE_DISK = 0x0001; +constexpr DWORD FILE_TYPE_CHAR = 0x0002; +constexpr DWORD FILE_TYPE_PIPE = 0x0003; + +constexpr DWORD INVALID_FILE_ATTRIBUTES = 0xFFFFFFFF; +constexpr DWORD INVALID_FILE_SIZE = 0xFFFFFFFF; + namespace kernel32 { DWORD WIN_FUNC GetFullPathNameA(LPCSTR lpFileName, DWORD nBufferLength, LPSTR lpBuffer, LPSTR *lpFilePart); @@ -18,5 +70,36 @@ HANDLE WIN_FUNC FindFirstFileExA(LPCSTR lpFileName, FINDEX_INFO_LEVELS fInfoLeve BOOL WIN_FUNC FindNextFileA(HANDLE hFindFile, LPWIN32_FIND_DATAA lpFindFileData); BOOL WIN_FUNC FindNextFileW(HANDLE hFindFile, LPWIN32_FIND_DATAW lpFindFileData); BOOL WIN_FUNC FindClose(HANDLE hFindFile); +DWORD WIN_FUNC GetFileAttributesA(LPCSTR lpFileName); +DWORD WIN_FUNC GetFileAttributesW(LPCWSTR lpFileName); +BOOL WIN_FUNC WriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, + LPOVERLAPPED lpOverlapped); +BOOL WIN_FUNC ReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead, + LPOVERLAPPED lpOverlapped); +BOOL WIN_FUNC FlushFileBuffers(HANDLE hFile); +HANDLE WIN_FUNC CreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, + LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, + DWORD dwFlagsAndAttributes, HANDLE hTemplateFile); +HANDLE WIN_FUNC CreateFileW(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, + LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, + DWORD dwFlagsAndAttributes, HANDLE hTemplateFile); +BOOL WIN_FUNC DeleteFileA(LPCSTR lpFileName); +BOOL WIN_FUNC DeleteFileW(LPCWSTR lpFileName); +BOOL WIN_FUNC MoveFileA(LPCSTR lpExistingFileName, LPCSTR lpNewFileName); +BOOL WIN_FUNC MoveFileW(LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName); +DWORD WIN_FUNC SetFilePointer(HANDLE hFile, LONG lDistanceToMove, PLONG lpDistanceToMoveHigh, DWORD dwMoveMethod); +BOOL WIN_FUNC SetFilePointerEx(HANDLE hFile, LARGE_INTEGER liDistanceToMove, PLARGE_INTEGER lpNewFilePointer, + DWORD dwMoveMethod); +BOOL WIN_FUNC SetEndOfFile(HANDLE hFile); +BOOL WIN_FUNC CreateDirectoryA(LPCSTR lpPathName, LPSECURITY_ATTRIBUTES lpSecurityAttributes); +BOOL WIN_FUNC RemoveDirectoryA(LPCSTR lpPathName); +BOOL WIN_FUNC SetFileAttributesA(LPCSTR lpFileName, DWORD dwFileAttributes); +DWORD WIN_FUNC GetFileSize(HANDLE hFile, LPDWORD lpFileSizeHigh); +BOOL WIN_FUNC GetFileTime(HANDLE hFile, LPFILETIME lpCreationTime, LPFILETIME lpLastAccessTime, + LPFILETIME lpLastWriteTime); +BOOL WIN_FUNC SetFileTime(HANDLE hFile, const FILETIME *lpCreationTime, const FILETIME *lpLastAccessTime, + const FILETIME *lpLastWriteTime); +BOOL WIN_FUNC GetFileInformationByHandle(HANDLE hFile, LPBY_HANDLE_FILE_INFORMATION lpFileInformation); +DWORD WIN_FUNC GetFileType(HANDLE hFile); } // namespace kernel32 diff --git a/dll/kernel32/internal.h b/dll/kernel32/internal.h index 7cf7115..74c27b2 100644 --- a/dll/kernel32/internal.h +++ b/dll/kernel32/internal.h @@ -1,6 +1,8 @@ #pragma once #include "common.h" +#include "minwinbase.h" + #include #include @@ -56,6 +58,7 @@ void signalOverlappedEvent(OVERLAPPED *ov); void tryMarkExecutable(void *mem); void setLastErrorFromErrno(); bool closeFileMappingHandle(void *mappingPtr); +int64_t getFileSizeFromHandle(HANDLE hFile); ThreadObject *ensureCurrentThreadObject(); ThreadObject *threadObjectFromHandle(HANDLE hThread); ThreadObject *retainThreadObject(ThreadObject *obj); diff --git a/dll/kernel32/ioapiset.cpp b/dll/kernel32/ioapiset.cpp new file mode 100644 index 0000000..8d5d064 --- /dev/null +++ b/dll/kernel32/ioapiset.cpp @@ -0,0 +1,49 @@ +#include "ioapiset.h" + +#include "errors.h" +#include "synchapi.h" + +namespace kernel32 { + +BOOL WIN_FUNC GetOverlappedResult(HANDLE hFile, LPOVERLAPPED lpOverlapped, LPDWORD lpNumberOfBytesTransferred, + BOOL bWait) { + DEBUG_LOG("GetOverlappedResult(%p, %p, %p, %d)\n", hFile, lpOverlapped, lpNumberOfBytesTransferred, bWait); + (void)hFile; + if (!lpOverlapped) { + wibo::lastError = ERROR_INVALID_PARAMETER; + return FALSE; + } + if (bWait && lpOverlapped->Internal == STATUS_PENDING) { + if (lpOverlapped->hEvent) { + WaitForSingleObject(lpOverlapped->hEvent, 0xFFFFFFFF); + } + } + + const auto status = static_cast(lpOverlapped->Internal); + if (status == STATUS_PENDING) { + wibo::lastError = ERROR_IO_INCOMPLETE; + if (lpNumberOfBytesTransferred) { + *lpNumberOfBytesTransferred = static_cast(lpOverlapped->InternalHigh); + } + return FALSE; + } + + if (lpNumberOfBytesTransferred) { + *lpNumberOfBytesTransferred = static_cast(lpOverlapped->InternalHigh); + } + + if (status == STATUS_SUCCESS) { + wibo::lastError = ERROR_SUCCESS; + return TRUE; + } + if (status == STATUS_END_OF_FILE || status == ERROR_HANDLE_EOF) { + wibo::lastError = ERROR_HANDLE_EOF; + return FALSE; + } + + wibo::lastError = status; + return FALSE; +} + +} // namespace kernel32 + diff --git a/dll/kernel32/ioapiset.h b/dll/kernel32/ioapiset.h new file mode 100644 index 0000000..9fa4ea4 --- /dev/null +++ b/dll/kernel32/ioapiset.h @@ -0,0 +1,12 @@ +#pragma once + +#include "common.h" +#include "minwinbase.h" + +namespace kernel32 { + +BOOL WIN_FUNC GetOverlappedResult(HANDLE hFile, LPOVERLAPPED lpOverlapped, LPDWORD lpNumberOfBytesTransferred, + BOOL bWait); + +} // namespace kernel32 + diff --git a/dll/kernel32/memoryapi.cpp b/dll/kernel32/memoryapi.cpp index 49d30bd..35f3c9b 100644 --- a/dll/kernel32/memoryapi.cpp +++ b/dll/kernel32/memoryapi.cpp @@ -19,10 +19,6 @@ #include #include -namespace kernel32 { -int64_t getFileSize(HANDLE hFile); -} - namespace { constexpr size_t kVirtualAllocationGranularity = 64 * 1024; @@ -285,7 +281,7 @@ HANDLE WIN_FUNC CreateFileMappingA(HANDLE hFile, LPSECURITY_ATTRIBUTES lpFileMap } mapping->fd = dupFd; if (size == 0) { - int64_t fileSize = getFileSize(hFile); + int64_t fileSize = getFileSizeFromHandle(hFile); if (fileSize < 0) { closeMappingIfPossible(mapping); return nullptr; diff --git a/dll/kernel32/processthreadsapi.cpp b/dll/kernel32/processthreadsapi.cpp index ba49862..b0228a7 100644 --- a/dll/kernel32/processthreadsapi.cpp +++ b/dll/kernel32/processthreadsapi.cpp @@ -103,6 +103,21 @@ template void populateStartupInfo(StartupInfo *info) { namespace kernel32 { +BOOL WIN_FUNC IsProcessorFeaturePresent(DWORD ProcessorFeature) { + DEBUG_LOG("IsProcessorFeaturePresent(%u)\n", ProcessorFeature); + if (ProcessorFeature == 0) { // PF_FLOATING_POINT_PRECISION_ERRATA + return TRUE; + } + if (ProcessorFeature == 10) { // PF_XMMI64_INSTRUCTIONS_AVAILABLE (SSE2) + return TRUE; + } + if (ProcessorFeature == 23) { // PF_FASTFAIL_AVAILABLE (__fastfail() supported) + return TRUE; + } + DEBUG_LOG(" IsProcessorFeaturePresent: unknown feature %u, returning TRUE\n", ProcessorFeature); + return TRUE; +} + thread_local ThreadObject *g_currentThreadObject = nullptr; ThreadObject *ensureCurrentThreadObject() { diff --git a/dll/kernel32/processthreadsapi.h b/dll/kernel32/processthreadsapi.h index 1a776ed..99d6116 100644 --- a/dll/kernel32/processthreadsapi.h +++ b/dll/kernel32/processthreadsapi.h @@ -70,6 +70,7 @@ HANDLE WIN_FUNC GetCurrentProcess(); DWORD WIN_FUNC GetCurrentProcessId(); DWORD WIN_FUNC GetCurrentThreadId(); HANDLE WIN_FUNC GetCurrentThread(); +BOOL WIN_FUNC IsProcessorFeaturePresent(DWORD ProcessorFeature); BOOL WIN_FUNC GetProcessAffinityMask(HANDLE hProcess, PDWORD_PTR lpProcessAffinityMask, PDWORD_PTR lpSystemAffinityMask); BOOL WIN_FUNC SetProcessAffinityMask(HANDLE hProcess, DWORD_PTR dwProcessAffinityMask); diff --git a/dll/kernel32/synchapi.cpp b/dll/kernel32/synchapi.cpp index bbaa2a1..cbc7967 100644 --- a/dll/kernel32/synchapi.cpp +++ b/dll/kernel32/synchapi.cpp @@ -38,6 +38,11 @@ void makeWideNameFromAnsi(LPCSTR ansiName, std::vector &outWide) { namespace kernel32 { +void WIN_FUNC Sleep(DWORD dwMilliseconds) { + DEBUG_LOG("Sleep(%u)\n", dwMilliseconds); + usleep(static_cast(dwMilliseconds) * 1000); +} + namespace { std::mutex mutexRegistryLock; diff --git a/dll/kernel32/synchapi.h b/dll/kernel32/synchapi.h index 67242b0..8b1dd32 100644 --- a/dll/kernel32/synchapi.h +++ b/dll/kernel32/synchapi.h @@ -73,6 +73,7 @@ constexpr SRWLOCK SRWLOCK_INIT{nullptr}; namespace kernel32 { +void WIN_FUNC Sleep(DWORD dwMilliseconds); HANDLE WIN_FUNC CreateMutexA(LPSECURITY_ATTRIBUTES lpMutexAttributes, BOOL bInitialOwner, LPCSTR lpName); HANDLE WIN_FUNC CreateMutexW(LPSECURITY_ATTRIBUTES lpMutexAttributes, BOOL bInitialOwner, LPCWSTR lpName); BOOL WIN_FUNC ReleaseMutex(HANDLE hMutex); diff --git a/dll/kernel32/winbase.cpp b/dll/kernel32/winbase.cpp index 6db448c..bba33ef 100644 --- a/dll/kernel32/winbase.cpp +++ b/dll/kernel32/winbase.cpp @@ -2,6 +2,7 @@ #include "errors.h" #include "files.h" +#include "handles.h" #include "internal.h" #include "strutil.h" @@ -9,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -154,10 +156,95 @@ bool resolveDiskFreeSpaceStat(const char *rootPathName, struct statvfs &outBuf, } } +constexpr DWORD kComputerNameLength = 8; +constexpr DWORD kComputerNameRequiredSize = kComputerNameLength + 1; +constexpr const char kComputerNameAnsi[] = "COMPNAME"; +const uint16_t kComputerNameWide[] = {u'C', u'O', u'M', u'P', u'N', u'A', u'M', u'E', 0}; + } // namespace namespace kernel32 { +UINT WIN_FUNC SetHandleCount(UINT uNumber) { + DEBUG_LOG("SetHandleCount(%u)\n", uNumber); + (void)uNumber; + return handles::MAX_HANDLES; +} + +DWORD WIN_FUNC FormatMessageA(DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId, DWORD dwLanguageId, + LPSTR lpBuffer, DWORD nSize, va_list *Arguments) { + DEBUG_LOG("FormatMessageA(%u, %p, %u, %u, %p, %u, %p)\n", dwFlags, lpSource, dwMessageId, dwLanguageId, + lpBuffer, nSize, Arguments); + + if (dwFlags & 0x00000100) { + // FORMAT_MESSAGE_ALLOCATE_BUFFER + } else if (dwFlags & 0x00002000) { + // FORMAT_MESSAGE_ARGUMENT_ARRAY + } else if (dwFlags & 0x00000800) { + // FORMAT_MESSAGE_FROM_HMODULE + } else if (dwFlags & 0x00000400) { + // FORMAT_MESSAGE_FROM_STRING + } else if (dwFlags & 0x00001000) { + // FORMAT_MESSAGE_FROM_SYSTEM + std::string message = std::system_category().message(static_cast(dwMessageId)); + size_t length = message.length(); + if (!lpBuffer || nSize == 0) { + wibo::lastError = ERROR_INSUFFICIENT_BUFFER; + return 0; + } + std::strncpy(lpBuffer, message.c_str(), static_cast(nSize)); + if (static_cast(nSize) <= length) { + if (static_cast(nSize) > 0) { + lpBuffer[nSize - 1] = '\0'; + } + wibo::lastError = ERROR_INSUFFICIENT_BUFFER; + return 0; + } + lpBuffer[length] = '\0'; + wibo::lastError = ERROR_SUCCESS; + return static_cast(length); + } else if (dwFlags & 0x00000200) { + // FORMAT_MESSAGE_IGNORE_INSERTS + } else { + // unhandled? + } + + if (lpBuffer && nSize > 0) { + lpBuffer[0] = '\0'; + } + wibo::lastError = ERROR_CALL_NOT_IMPLEMENTED; + return 0; +} + +PVOID WIN_FUNC EncodePointer(PVOID Ptr) { + DEBUG_LOG("EncodePointer(%p)\n", Ptr); + return Ptr; +} + +PVOID WIN_FUNC DecodePointer(PVOID Ptr) { + DEBUG_LOG("DecodePointer(%p)\n", Ptr); + return Ptr; +} + +BOOL WIN_FUNC SetDllDirectoryA(LPCSTR lpPathName) { + DEBUG_LOG("SetDllDirectoryA(%s)\n", lpPathName); + if (!lpPathName || lpPathName[0] == '\0') { + wibo::clearDllDirectoryOverride(); + wibo::lastError = ERROR_SUCCESS; + return TRUE; + } + + std::filesystem::path hostPath = files::pathFromWindows(lpPathName); + if (hostPath.empty() || !std::filesystem::exists(hostPath)) { + wibo::lastError = ERROR_PATH_NOT_FOUND; + return FALSE; + } + + wibo::setDllDirectoryOverride(std::filesystem::absolute(hostPath)); + wibo::lastError = ERROR_SUCCESS; + return TRUE; +} + void tryMarkExecutable(void *mem) { if (!mem) { return; @@ -196,6 +283,50 @@ BOOL WIN_FUNC IsBadWritePtr(LPVOID lp, UINT_PTR ucb) { return FALSE; } +BOOL WIN_FUNC GetComputerNameA(LPSTR lpBuffer, LPDWORD nSize) { + DEBUG_LOG("GetComputerNameA(%p, %p)\n", lpBuffer, nSize); + if (!nSize || !lpBuffer) { + if (nSize) { + *nSize = 0; + } + wibo::lastError = ERROR_INVALID_PARAMETER; + return FALSE; + } + + if (*nSize < kComputerNameRequiredSize) { + *nSize = kComputerNameRequiredSize; + wibo::lastError = ERROR_BUFFER_OVERFLOW; + return FALSE; + } + + std::strcpy(lpBuffer, kComputerNameAnsi); + *nSize = kComputerNameLength; + wibo::lastError = ERROR_SUCCESS; + return TRUE; +} + +BOOL WIN_FUNC GetComputerNameW(LPWSTR lpBuffer, LPDWORD nSize) { + DEBUG_LOG("GetComputerNameW(%p, %p)\n", lpBuffer, nSize); + if (!nSize || !lpBuffer) { + if (nSize) { + *nSize = 0; + } + wibo::lastError = ERROR_INVALID_PARAMETER; + return FALSE; + } + + if (*nSize < kComputerNameRequiredSize) { + *nSize = kComputerNameRequiredSize; + wibo::lastError = ERROR_BUFFER_OVERFLOW; + return FALSE; + } + + wstrncpy(lpBuffer, kComputerNameWide, static_cast(kComputerNameRequiredSize)); + *nSize = kComputerNameLength; + wibo::lastError = ERROR_SUCCESS; + return TRUE; +} + HGLOBAL WIN_FUNC GlobalAlloc(UINT uFlags, SIZE_T dwBytes) { VERBOSE_LOG("GlobalAlloc(%x, %zu)\n", uFlags, static_cast(dwBytes)); if (uFlags & GMEM_MOVEABLE) { diff --git a/dll/kernel32/winbase.h b/dll/kernel32/winbase.h index f4ef751..48e87ba 100644 --- a/dll/kernel32/winbase.h +++ b/dll/kernel32/winbase.h @@ -2,10 +2,21 @@ #include "common.h" +#include + namespace kernel32 { BOOL WIN_FUNC IsBadReadPtr(LPCVOID lp, UINT_PTR ucb); BOOL WIN_FUNC IsBadWritePtr(LPVOID lp, UINT_PTR ucb); +UINT WIN_FUNC SetHandleCount(UINT uNumber); +DWORD WIN_FUNC FormatMessageA(DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId, DWORD dwLanguageId, + LPSTR lpBuffer, DWORD nSize, va_list *Arguments); +PVOID WIN_FUNC EncodePointer(PVOID Ptr); +PVOID WIN_FUNC DecodePointer(PVOID Ptr); +BOOL WIN_FUNC SetDllDirectoryA(LPCSTR lpPathName); + +BOOL WIN_FUNC GetComputerNameA(LPSTR lpBuffer, LPDWORD nSize); +BOOL WIN_FUNC GetComputerNameW(LPWSTR lpBuffer, LPDWORD nSize); HGLOBAL WIN_FUNC GlobalAlloc(UINT uFlags, SIZE_T dwBytes); HGLOBAL WIN_FUNC GlobalFree(HGLOBAL hMem); diff --git a/dll/kernel32/winnt.cpp b/dll/kernel32/winnt.cpp new file mode 100644 index 0000000..fd4e9ed --- /dev/null +++ b/dll/kernel32/winnt.cpp @@ -0,0 +1,13 @@ +#include "winnt.h" + +#include "common.h" + +namespace kernel32 { + +void WIN_FUNC RtlUnwind(PVOID TargetFrame, PVOID TargetIp, PEXCEPTION_RECORD ExceptionRecord, PVOID ReturnValue) { + DEBUG_LOG("RtlUnwind(%p, %p, %p, %p)\n", TargetFrame, TargetIp, ExceptionRecord, ReturnValue); + DEBUG_LOG("WARNING: Silently returning from RtlUnwind - exception handlers and clean up code may not be run\n"); +} + +} // namespace kernel32 + diff --git a/dll/kernel32/winnt.h b/dll/kernel32/winnt.h new file mode 100644 index 0000000..46c0b87 --- /dev/null +++ b/dll/kernel32/winnt.h @@ -0,0 +1,11 @@ +#pragma once + +#include "common.h" +#include "errhandlingapi.h" + +namespace kernel32 { + +void WIN_FUNC RtlUnwind(PVOID TargetFrame, PVOID TargetIp, PEXCEPTION_RECORD ExceptionRecord, PVOID ReturnValue); + +} // namespace kernel32 + diff --git a/errors.h b/errors.h index e2bed44..a8241a4 100644 --- a/errors.h +++ b/errors.h @@ -9,6 +9,7 @@ #define ERROR_INVALID_HANDLE 6 #define ERROR_NOT_ENOUGH_MEMORY 8 #define ERROR_NO_MORE_FILES 18 +#define ERROR_FILE_EXISTS 80 #define ERROR_READ_FAULT 30 #define ERROR_HANDLE_EOF 38 #define ERROR_INVALID_ADDRESS 487 @@ -35,8 +36,8 @@ #define ERROR_ALREADY_EXISTS 183 #define ERROR_NOT_OWNER 288 -#define INVALID_SET_FILE_POINTER ((DWORD)-1) -#define INVALID_HANDLE_VALUE ((HANDLE)-1) +#define INVALID_SET_FILE_POINTER ((DWORD) - 1) +#define INVALID_HANDLE_VALUE ((HANDLE) - 1) typedef int NTSTATUS; #define STATUS_SUCCESS ((NTSTATUS)0x00000000) @@ -54,4 +55,4 @@ typedef int HRESULT; namespace wibo { DWORD winErrorFromErrno(int err); NTSTATUS statusFromWinError(DWORD error); -} +} // namespace wibo