mirror of
https://github.com/decompals/wibo.git
synced 2025-12-12 22:56:13 +00:00
Split kernel32 into separate files (part 2)
This commit is contained in:
575
dll/kernel32/winbase.cpp
Normal file
575
dll/kernel32/winbase.cpp
Normal file
@@ -0,0 +1,575 @@
|
||||
#include "winbase.h"
|
||||
|
||||
#include "errors.h"
|
||||
#include "files.h"
|
||||
#include "internal.h"
|
||||
#include "strutil.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cerrno>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <filesystem>
|
||||
#include <limits>
|
||||
#include <mimalloc.h>
|
||||
#include <string>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/statvfs.h>
|
||||
#include <system_error>
|
||||
|
||||
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<char *>(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;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace kernel32 {
|
||||
|
||||
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<uintptr_t>(mem);
|
||||
uintptr_t alignedStart = start & ~static_cast<uintptr_t>(pageSize - 1);
|
||||
uintptr_t end = (start + usable + pageSize - 1) & ~static_cast<uintptr_t>(pageSize - 1);
|
||||
size_t length = static_cast<size_t>(end - alignedStart);
|
||||
if (length == 0) {
|
||||
return;
|
||||
}
|
||||
mprotect(reinterpret_cast<void *>(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<size_t>(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<size_t>(ucb));
|
||||
if (!lp && ucb != 0) {
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
HGLOBAL WIN_FUNC GlobalAlloc(UINT uFlags, SIZE_T dwBytes) {
|
||||
VERBOSE_LOG("GlobalAlloc(%x, %zu)\n", uFlags, static_cast<size_t>(dwBytes));
|
||||
if (uFlags & GMEM_MOVEABLE) {
|
||||
// not implemented rn
|
||||
assert(0);
|
||||
return nullptr;
|
||||
}
|
||||
bool zero = (uFlags & GMEM_ZEROINIT) != 0;
|
||||
return doAlloc(static_cast<UINT>(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<size_t>(dwBytes), uFlags);
|
||||
if (uFlags & GMEM_MODIFY) {
|
||||
assert(0);
|
||||
return nullptr;
|
||||
}
|
||||
bool zero = (uFlags & GMEM_ZEROINIT) != 0;
|
||||
return doRealloc(hMem, static_cast<UINT>(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<size_t>(uBytes));
|
||||
bool zero = (uFlags & LMEM_ZEROINIT) != 0;
|
||||
if ((uFlags & LMEM_MOVEABLE) != 0) {
|
||||
DEBUG_LOG(" ignoring LMEM_MOVEABLE\n");
|
||||
}
|
||||
void *result = doAlloc(static_cast<UINT>(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<size_t>(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<UINT>(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<LPVOID>(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;
|
||||
}
|
||||
|
||||
UINT WIN_FUNC GetSystemDirectoryA(LPSTR lpBuffer, UINT uSize) {
|
||||
DEBUG_LOG("GetSystemDirectoryA(%p, %u)\n", lpBuffer, uSize);
|
||||
if (!lpBuffer) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *systemDir = "C:\\Windows\\System32";
|
||||
const auto len = std::strlen(systemDir);
|
||||
if (uSize < len + 1) {
|
||||
return static_cast<UINT>(len + 1);
|
||||
}
|
||||
std::strcpy(lpBuffer, systemDir);
|
||||
return static_cast<UINT>(len);
|
||||
}
|
||||
|
||||
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<UINT>(len + 1);
|
||||
}
|
||||
std::strcpy(lpBuffer, windowsDir);
|
||||
return static_cast<UINT>(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<DWORD>(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<DWORD>(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<DWORD>(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<DWORD>(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<unsigned int>(std::min<uint64_t>(blockSize, std::numeric_limits<unsigned int>::max()));
|
||||
}
|
||||
unsigned int sectorsPerCluster = static_cast<unsigned int>(blockSize / bytesPerSector);
|
||||
if (sectorsPerCluster == 0) {
|
||||
sectorsPerCluster = 1;
|
||||
bytesPerSector =
|
||||
static_cast<unsigned int>(std::min<uint64_t>(blockSize, std::numeric_limits<unsigned int>::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<uint64_t>(freeClusters64, std::numeric_limits<unsigned int>::max());
|
||||
*lpNumberOfFreeClusters = static_cast<DWORD>(clamped);
|
||||
}
|
||||
if (lpTotalNumberOfClusters) {
|
||||
uint64_t clamped = std::min<uint64_t>(totalClusters64, std::numeric_limits<unsigned int>::max());
|
||||
*lpTotalNumberOfClusters = static_cast<DWORD>(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<uint64_t>(buf.f_bavail) * blockSize;
|
||||
uint64_t totalBytes = static_cast<uint64_t>(buf.f_blocks) * blockSize;
|
||||
uint64_t totalFree = static_cast<uint64_t>(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<unsigned long long>(freeToCaller), static_cast<unsigned long long>(totalBytes),
|
||||
static_cast<unsigned long long>(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
|
||||
Reference in New Issue
Block a user