#include "winbase.h" #include "errors.h" #include "files.h" #include "handles.h" #include "internal.h" #include "strutil.h" #include #include #include #include #include #include #include #include #include #include #include #include #include namespace { constexpr UINT GMEM_MOVEABLE = 0x0002; constexpr UINT GMEM_ZEROINIT = 0x0040; constexpr UINT GMEM_MODIFY = 0x0080; constexpr UINT LMEM_MOVEABLE = 0x0002; constexpr UINT LMEM_ZEROINIT = 0x0040; void *doAlloc(UINT dwBytes, bool zero) { if (dwBytes == 0) { dwBytes = 1; } void *ret = mi_malloc_aligned(dwBytes, 8); if (ret && zero) { std::memset(ret, 0, mi_usable_size(ret)); } return ret; } void *doRealloc(void *mem, UINT dwBytes, bool zero) { if (dwBytes == 0) { dwBytes = 1; } size_t oldSize = mi_usable_size(mem); void *ret = mi_realloc_aligned(mem, dwBytes, 8); size_t newSize = mi_usable_size(ret); if (ret && zero && newSize > oldSize) { std::memset(static_cast(ret) + oldSize, 0, newSize - oldSize); } return ret; } bool tryGetCurrentDirectoryPath(std::string &outPath) { std::error_code ec; std::filesystem::path cwd = std::filesystem::current_path(ec); if (ec) { errno = ec.value(); kernel32::setLastErrorFromErrno(); return false; } outPath = files::pathToWindows(cwd); return true; } bool computeLongWindowsPath(const std::string &inputPath, std::string &longPath) { bool hasTrailingSlash = false; if (!inputPath.empty()) { char last = inputPath.back(); hasTrailingSlash = (last == '\\' || last == '/'); } auto hostPath = files::pathFromWindows(inputPath.c_str()); if (hostPath.empty()) { wibo::lastError = ERROR_PATH_NOT_FOUND; return false; } std::error_code ec; if (!std::filesystem::exists(hostPath, ec)) { wibo::lastError = ERROR_FILE_NOT_FOUND; return false; } longPath = files::pathToWindows(hostPath); if (hasTrailingSlash && !longPath.empty() && longPath.back() != '\\') { longPath.push_back('\\'); } wibo::lastError = ERROR_SUCCESS; return true; } bool resolveDiskFreeSpaceStat(const char *rootPathName, struct statvfs &outBuf, std::string &resolvedPath) { std::filesystem::path hostPath; if (rootPathName && *rootPathName) { hostPath = files::pathFromWindows(rootPathName); } else { std::error_code ec; hostPath = std::filesystem::current_path(ec); if (ec) { wibo::lastError = ERROR_PATH_NOT_FOUND; return false; } } if (hostPath.empty()) { wibo::lastError = ERROR_PATH_NOT_FOUND; return false; } hostPath = hostPath.lexically_normal(); if (hostPath.empty()) { hostPath = std::filesystem::path("/"); } std::error_code ec; if (!hostPath.is_absolute()) { auto abs = std::filesystem::absolute(hostPath, ec); if (ec) { wibo::lastError = ERROR_PATH_NOT_FOUND; return false; } hostPath = abs; } std::filesystem::path queryPath = hostPath; while (true) { std::string query = queryPath.empty() ? std::string("/") : queryPath.string(); if (query.empty()) { query = "/"; } if (statvfs(query.c_str(), &outBuf) == 0) { resolvedPath = query; wibo::lastError = ERROR_SUCCESS; return true; } int savedErrno = errno; if (savedErrno != ENOENT && savedErrno != ENOTDIR) { errno = savedErrno; kernel32::setLastErrorFromErrno(); return false; } std::filesystem::path parent = queryPath.parent_path(); if (parent == queryPath) { errno = savedErrno; kernel32::setLastErrorFromErrno(); return false; } if (parent.empty()) { parent = std::filesystem::path("/"); } queryPath = parent; } } 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 0x3FFE; } 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; } size_t usable = mi_usable_size(mem); if (usable == 0) { return; } long pageSize = sysconf(_SC_PAGESIZE); if (pageSize <= 0) { return; } uintptr_t start = reinterpret_cast(mem); uintptr_t alignedStart = start & ~static_cast(pageSize - 1); uintptr_t end = (start + usable + pageSize - 1) & ~static_cast(pageSize - 1); size_t length = static_cast(end - alignedStart); if (length == 0) { return; } mprotect(reinterpret_cast(alignedStart), length, PROT_READ | PROT_WRITE | PROT_EXEC); } BOOL WIN_FUNC IsBadReadPtr(LPCVOID lp, UINT_PTR ucb) { DEBUG_LOG("STUB: IsBadReadPtr(ptr=%p, size=%zu)\n", lp, static_cast(ucb)); if (!lp) { return TRUE; } return FALSE; } BOOL WIN_FUNC IsBadWritePtr(LPVOID lp, UINT_PTR ucb) { DEBUG_LOG("STUB: IsBadWritePtr(ptr=%p, size=%zu)\n", lp, static_cast(ucb)); if (!lp && ucb != 0) { return TRUE; } 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) { // not implemented rn assert(0); return nullptr; } bool zero = (uFlags & GMEM_ZEROINIT) != 0; return doAlloc(static_cast(dwBytes), zero); } HGLOBAL WIN_FUNC GlobalFree(HGLOBAL hMem) { VERBOSE_LOG("GlobalFree(%p)\n", hMem); std::free(hMem); return nullptr; } HGLOBAL WIN_FUNC GlobalReAlloc(HGLOBAL hMem, SIZE_T dwBytes, UINT uFlags) { VERBOSE_LOG("GlobalReAlloc(%p, %zu, %x)\n", hMem, static_cast(dwBytes), uFlags); if (uFlags & GMEM_MODIFY) { assert(0); return nullptr; } bool zero = (uFlags & GMEM_ZEROINIT) != 0; return doRealloc(hMem, static_cast(dwBytes), zero); } UINT WIN_FUNC GlobalFlags(HGLOBAL hMem) { VERBOSE_LOG("GlobalFlags(%p)\n", hMem); (void)hMem; return 0; } HLOCAL WIN_FUNC LocalAlloc(UINT uFlags, SIZE_T uBytes) { VERBOSE_LOG("LocalAlloc(%x, %zu)\n", uFlags, static_cast(uBytes)); bool zero = (uFlags & LMEM_ZEROINIT) != 0; if ((uFlags & LMEM_MOVEABLE) != 0) { DEBUG_LOG(" ignoring LMEM_MOVEABLE\n"); } void *result = doAlloc(static_cast(uBytes), zero); if (!result) { wibo::lastError = ERROR_NOT_SUPPORTED; return nullptr; } // Legacy Windows applications (pre-NX and DEP) may expect executable memory from LocalAlloc. tryMarkExecutable(result); DEBUG_LOG(" -> %p\n", result); wibo::lastError = ERROR_SUCCESS; return result; } HLOCAL WIN_FUNC LocalFree(HLOCAL hMem) { VERBOSE_LOG("LocalFree(%p)\n", hMem); // Windows returns NULL on success. std::free(hMem); wibo::lastError = ERROR_SUCCESS; return nullptr; } HLOCAL WIN_FUNC LocalReAlloc(HLOCAL hMem, SIZE_T uBytes, UINT uFlags) { VERBOSE_LOG("LocalReAlloc(%p, %zu, %x)\n", hMem, static_cast(uBytes), uFlags); bool zero = (uFlags & LMEM_ZEROINIT) != 0; if ((uFlags & LMEM_MOVEABLE) != 0) { DEBUG_LOG(" ignoring LMEM_MOVEABLE\n"); } void *result = doRealloc(hMem, static_cast(uBytes), zero); if (!result && uBytes != 0) { wibo::lastError = ERROR_NOT_SUPPORTED; return nullptr; } // Legacy Windows applications (pre-NX and DEP) may expect executable memory from LocalReAlloc. tryMarkExecutable(result); DEBUG_LOG(" -> %p\n", result); wibo::lastError = ERROR_SUCCESS; return result; } HLOCAL WIN_FUNC LocalHandle(LPCVOID pMem) { VERBOSE_LOG("LocalHandle(%p)\n", pMem); return const_cast(pMem); } LPVOID WIN_FUNC LocalLock(HLOCAL hMem) { VERBOSE_LOG("LocalLock(%p)\n", hMem); wibo::lastError = ERROR_SUCCESS; return hMem; } BOOL WIN_FUNC LocalUnlock(HLOCAL hMem) { VERBOSE_LOG("LocalUnlock(%p)\n", hMem); (void)hMem; wibo::lastError = ERROR_SUCCESS; return TRUE; } SIZE_T WIN_FUNC LocalSize(HLOCAL hMem) { VERBOSE_LOG("LocalSize(%p)\n", hMem); return hMem ? mi_usable_size(hMem) : 0; } UINT WIN_FUNC LocalFlags(HLOCAL hMem) { VERBOSE_LOG("LocalFlags(%p)\n", hMem); (void)hMem; return 0; } static constexpr const char *kSystemDirectoryA = "C:\\Windows\\System32"; UINT WIN_FUNC GetSystemDirectoryA(LPSTR lpBuffer, UINT uSize) { DEBUG_LOG("GetSystemDirectoryA(%p, %u)\n", lpBuffer, uSize); if (!lpBuffer) { return 0; } const auto len = std::strlen(kSystemDirectoryA); if (uSize < len + 1) { return static_cast(len + 1); } std::strcpy(lpBuffer, kSystemDirectoryA); return static_cast(len); } UINT WIN_FUNC GetSystemDirectoryW(LPWSTR lpBuffer, UINT uSize) { DEBUG_LOG("GetSystemDirectoryW(%p, %u)\n", lpBuffer, uSize); if (!lpBuffer) { return 0; } auto wide = stringToWideString(kSystemDirectoryA); UINT length = static_cast(wide.size() - 1); if (uSize < length + 1) { return length + 1; } std::memcpy(lpBuffer, wide.data(), (length + 1) * sizeof(uint16_t)); return length; } UINT WIN_FUNC GetSystemWow64DirectoryA(LPSTR lpBuffer, UINT uSize) { DEBUG_LOG("GetSystemWow64DirectoryA(%p, %u)\n", lpBuffer, uSize); (void)lpBuffer; (void)uSize; wibo::lastError = ERROR_CALL_NOT_IMPLEMENTED; return 0; } UINT WIN_FUNC GetSystemWow64DirectoryW(LPWSTR lpBuffer, UINT uSize) { DEBUG_LOG("GetSystemWow64DirectoryW(%p, %u)\n", lpBuffer, uSize); (void)lpBuffer; (void)uSize; wibo::lastError = ERROR_CALL_NOT_IMPLEMENTED; return 0; } UINT WIN_FUNC GetWindowsDirectoryA(LPSTR lpBuffer, UINT uSize) { DEBUG_LOG("GetWindowsDirectoryA(%p, %u)\n", lpBuffer, uSize); if (!lpBuffer) { return 0; } const char *windowsDir = "C:\\Windows"; const auto len = std::strlen(windowsDir); if (uSize < len + 1) { return static_cast(len + 1); } std::strcpy(lpBuffer, windowsDir); return static_cast(len); } DWORD WIN_FUNC GetCurrentDirectoryA(DWORD nBufferLength, LPSTR lpBuffer) { DEBUG_LOG("GetCurrentDirectoryA(%u, %p)\n", nBufferLength, lpBuffer); std::string path; if (!tryGetCurrentDirectoryPath(path)) { return 0; } const DWORD required = static_cast(path.size() + 1); if (nBufferLength == 0) { return required; } if (!lpBuffer) { wibo::lastError = ERROR_INVALID_PARAMETER; return 0; } if (nBufferLength < required) { wibo::lastError = ERROR_INSUFFICIENT_BUFFER; return required; } std::memcpy(lpBuffer, path.c_str(), required); wibo::lastError = ERROR_SUCCESS; return required - 1; } DWORD WIN_FUNC GetCurrentDirectoryW(DWORD nBufferLength, LPWSTR lpBuffer) { DEBUG_LOG("GetCurrentDirectoryW(%u, %p)\n", nBufferLength, lpBuffer); std::string path; if (!tryGetCurrentDirectoryPath(path)) { return 0; } auto widePath = stringToWideString(path.c_str()); const DWORD required = static_cast(widePath.size()); if (nBufferLength == 0) { return required; } if (!lpBuffer) { wibo::lastError = ERROR_INVALID_PARAMETER; return 0; } if (nBufferLength < required) { wibo::lastError = ERROR_INSUFFICIENT_BUFFER; return required; } std::copy(widePath.begin(), widePath.end(), lpBuffer); wibo::lastError = ERROR_SUCCESS; return required - 1; } int WIN_FUNC SetCurrentDirectoryA(LPCSTR lpPathName) { DEBUG_LOG("SetCurrentDirectoryA(%s)\n", lpPathName ? lpPathName : "(null)"); if (!lpPathName) { wibo::lastError = ERROR_INVALID_PARAMETER; return 0; } auto hostPath = files::pathFromWindows(lpPathName); std::error_code ec; std::filesystem::current_path(hostPath, ec); if (ec) { errno = ec.value(); kernel32::setLastErrorFromErrno(); return 0; } wibo::lastError = ERROR_SUCCESS; return 1; } int WIN_FUNC SetCurrentDirectoryW(LPCWSTR lpPathName) { DEBUG_LOG("SetCurrentDirectoryW\n"); if (!lpPathName) { wibo::lastError = ERROR_INVALID_PARAMETER; return 0; } std::string path = wideStringToString(lpPathName); return SetCurrentDirectoryA(path.c_str()); } DWORD WIN_FUNC GetLongPathNameA(LPCSTR lpszShortPath, LPSTR lpszLongPath, DWORD cchBuffer) { DEBUG_LOG("GetLongPathNameA(%s, %p, %u)\n", lpszShortPath ? lpszShortPath : "(null)", lpszLongPath, cchBuffer); if (!lpszShortPath) { wibo::lastError = ERROR_INVALID_PARAMETER; return 0; } std::string input(lpszShortPath); std::string longPath; if (!computeLongWindowsPath(input, longPath)) { return 0; } DWORD required = static_cast(longPath.size() + 1); if (cchBuffer == 0) { return required; } if (!lpszLongPath) { wibo::lastError = ERROR_INVALID_PARAMETER; return 0; } if (cchBuffer < required) { wibo::lastError = ERROR_INSUFFICIENT_BUFFER; return required; } std::memcpy(lpszLongPath, longPath.c_str(), required); wibo::lastError = ERROR_SUCCESS; return required - 1; } DWORD WIN_FUNC GetLongPathNameW(LPCWSTR lpszShortPath, LPWSTR lpszLongPath, DWORD cchBuffer) { DEBUG_LOG("GetLongPathNameW(%p, %p, %u)\n", lpszShortPath, lpszLongPath, cchBuffer); if (!lpszShortPath) { wibo::lastError = ERROR_INVALID_PARAMETER; return 0; } std::string input = wideStringToString(lpszShortPath); std::string longPath; if (!computeLongWindowsPath(input, longPath)) { return 0; } auto wideLong = stringToWideString(longPath.c_str()); DWORD required = static_cast(wideLong.size()); if (cchBuffer == 0) { return required; } if (!lpszLongPath) { wibo::lastError = ERROR_INVALID_PARAMETER; return 0; } if (cchBuffer < required) { wibo::lastError = ERROR_INSUFFICIENT_BUFFER; return required; } std::copy(wideLong.begin(), wideLong.end(), lpszLongPath); wibo::lastError = ERROR_SUCCESS; return required - 1; } BOOL WIN_FUNC GetDiskFreeSpaceA(LPCSTR lpRootPathName, LPDWORD lpSectorsPerCluster, LPDWORD lpBytesPerSector, LPDWORD lpNumberOfFreeClusters, LPDWORD lpTotalNumberOfClusters) { DEBUG_LOG("GetDiskFreeSpaceA(%s)\n", lpRootPathName ? lpRootPathName : "(null)"); struct statvfs buf{}; std::string resolvedPath; if (!resolveDiskFreeSpaceStat(lpRootPathName, buf, resolvedPath)) { return FALSE; } uint64_t blockSize = buf.f_frsize ? buf.f_frsize : buf.f_bsize; if (blockSize == 0) { blockSize = 4096; } unsigned int bytesPerSector = 512; if (blockSize % bytesPerSector != 0) { bytesPerSector = static_cast(std::min(blockSize, std::numeric_limits::max())); } unsigned int sectorsPerCluster = static_cast(blockSize / bytesPerSector); if (sectorsPerCluster == 0) { sectorsPerCluster = 1; bytesPerSector = static_cast(std::min(blockSize, std::numeric_limits::max())); } uint64_t totalClusters64 = buf.f_blocks; uint64_t freeClusters64 = buf.f_bavail; if (lpSectorsPerCluster) { *lpSectorsPerCluster = sectorsPerCluster; } if (lpBytesPerSector) { *lpBytesPerSector = bytesPerSector; } if (lpNumberOfFreeClusters) { uint64_t clamped = std::min(freeClusters64, std::numeric_limits::max()); *lpNumberOfFreeClusters = static_cast(clamped); } if (lpTotalNumberOfClusters) { uint64_t clamped = std::min(totalClusters64, std::numeric_limits::max()); *lpTotalNumberOfClusters = static_cast(clamped); } DEBUG_LOG("\t-> host %s, spc %u, bps %u, free clusters %u, total clusters %u\n", resolvedPath.c_str(), lpSectorsPerCluster ? *lpSectorsPerCluster : 0, lpBytesPerSector ? *lpBytesPerSector : 0, lpNumberOfFreeClusters ? *lpNumberOfFreeClusters : 0, lpTotalNumberOfClusters ? *lpTotalNumberOfClusters : 0); wibo::lastError = ERROR_SUCCESS; return TRUE; } BOOL WIN_FUNC GetDiskFreeSpaceW(LPCWSTR lpRootPathName, LPDWORD lpSectorsPerCluster, LPDWORD lpBytesPerSector, LPDWORD lpNumberOfFreeClusters, LPDWORD lpTotalNumberOfClusters) { std::string rootPath = wideStringToString(lpRootPathName); return GetDiskFreeSpaceA(lpRootPathName ? rootPath.c_str() : nullptr, lpSectorsPerCluster, lpBytesPerSector, lpNumberOfFreeClusters, lpTotalNumberOfClusters); } BOOL WIN_FUNC GetDiskFreeSpaceExA(LPCSTR lpDirectoryName, uint64_t *lpFreeBytesAvailableToCaller, uint64_t *lpTotalNumberOfBytes, uint64_t *lpTotalNumberOfFreeBytes) { DEBUG_LOG("GetDiskFreeSpaceExA(%s)\n", lpDirectoryName ? lpDirectoryName : "(null)"); struct statvfs buf{}; std::string resolvedPath; if (!resolveDiskFreeSpaceStat(lpDirectoryName, buf, resolvedPath)) { return FALSE; } uint64_t blockSize = buf.f_frsize ? buf.f_frsize : buf.f_bsize; if (blockSize == 0) { blockSize = 4096; } uint64_t freeToCaller = static_cast(buf.f_bavail) * blockSize; uint64_t totalBytes = static_cast(buf.f_blocks) * blockSize; uint64_t totalFree = static_cast(buf.f_bfree) * blockSize; if (lpFreeBytesAvailableToCaller) { *lpFreeBytesAvailableToCaller = freeToCaller; } if (lpTotalNumberOfBytes) { *lpTotalNumberOfBytes = totalBytes; } if (lpTotalNumberOfFreeBytes) { *lpTotalNumberOfFreeBytes = totalFree; } DEBUG_LOG("\t-> host %s, free %llu, total %llu, total free %llu\n", resolvedPath.c_str(), static_cast(freeToCaller), static_cast(totalBytes), static_cast(totalFree)); wibo::lastError = ERROR_SUCCESS; return TRUE; } BOOL WIN_FUNC GetDiskFreeSpaceExW(LPCWSTR lpDirectoryName, uint64_t *lpFreeBytesAvailableToCaller, uint64_t *lpTotalNumberOfBytes, uint64_t *lpTotalNumberOfFreeBytes) { DEBUG_LOG("GetDiskFreeSpaceExW -> "); std::string directoryName = wideStringToString(lpDirectoryName); return GetDiskFreeSpaceExA(lpDirectoryName ? directoryName.c_str() : nullptr, lpFreeBytesAvailableToCaller, lpTotalNumberOfBytes, lpTotalNumberOfFreeBytes); } } // namespace kernel32