From 67d4a1ebceba190ee5239b9b398022a0b010f47d Mon Sep 17 00:00:00 2001 From: Kyle Isom Date: Tue, 10 Oct 2023 16:44:29 -0700 Subject: [PATCH] Windows is a nightmare. --- Arena.cc | 144 ++++++++++++++-------------------------------- Arena.h | 2 +- CMakeLists.txt | 6 +- WinHelpers.cpp | 142 +++++++++++++++++++++++++++++++++++++++++++++ WinHelpers.h | 39 +++++++++++++ bufferTest.cc | 24 ++++---- dictionaryTest.cc | 16 +++--- tlvTest.cc | 30 +++++----- 8 files changed, 266 insertions(+), 137 deletions(-) create mode 100644 WinHelpers.cpp create mode 100644 WinHelpers.h diff --git a/Arena.cc b/Arena.cc index 37f8f6b..723b324 100644 --- a/Arena.cc +++ b/Arena.cc @@ -13,10 +13,8 @@ #define PROT_RW (PROT_WRITE|PROT_READ) #elif defined(__WIN64__) || defined(__WIN32__) || defined(WIN32) -#include -#include -#include -#include +#include "WinHelpers.h" +#pragma comment(lib, "advapi32.lib") #endif #include @@ -136,73 +134,35 @@ Arena::Create(const char *path, size_t fileSize) return this->Open(path); } #elif defined(__WIN64__) || defined(__WIN32__) || defined(WIN32) -static void -displayWinErr(LPTSTR lpszFunction) -{ - // Retrieve the system error message for the last-error code - - LPVOID lpMsgBuf; - LPVOID lpDisplayBuf; - DWORD dw = GetLastError(); - - FormatMessage( - FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - dw, - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (LPTSTR) &lpMsgBuf, - 0, NULL ); - - // Display the error message and exit the process - - lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT, - (lstrlen((LPCTSTR)lpMsgBuf) + lstrlen((LPCTSTR)lpszFunction) + 40) * sizeof(TCHAR)); - StringCchPrintf((LPTSTR)lpDisplayBuf, - LocalSize(lpDisplayBuf) / sizeof(TCHAR), - TEXT("%s failed with error %d: %s"), - lpszFunction, dw, lpMsgBuf); - MessageBox(NULL, (LPCTSTR)lpDisplayBuf, TEXT("Error"), MB_OK); - - LocalFree(lpMsgBuf); - LocalFree(lpDisplayBuf); -} - - int Arena::Open(const char *path) { - HANDLE fHandle; - DWORD fRead = 0; - size_t fSize; - size_t fRemaining; - auto *cursor = this->store; - OVERLAPPED overlap = {0}; + HANDLE fHandle; + DWORD fRead = 0; + size_t fSize; + size_t fRemaining; + auto *cursor = this->store; + OVERLAPPED overlap = {0}; fHandle = CreateFileA( - (LPSTR)path, + (LPSTR) path, GENERIC_READ, - (FILE_SHARE_DELETE|FILE_SHARE_READ|FILE_SHARE_WRITE), + (FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE), NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (fHandle == INVALID_HANDLE_VALUE) { - displayWinErr("CreateFileA"); - return -1; + return Windows::DisplayWinError("CreateFileA", NULL); } if (SetFilePointer(fHandle, 0, 0, FILE_BEGIN) != 0) { - displayWinErr("SetFilePointer"); - CloseHandle(fHandle); - return -1; + return Windows::DisplayWinError("SetFilePointer", fHandle); } - if (GetFileSizeEx(fHandle, reinterpret_cast(&fSize)) != TRUE) { - displayWinErr("GetFileSizeEx"); - CloseHandle(fHandle); - return -1; + if (GetFileSizeEx(fHandle, reinterpret_cast(&fSize)) != + TRUE) { + return Windows::DisplayWinError("GetFileSizeEx", fHandle); } this->SetAlloc(fSize); @@ -212,15 +172,14 @@ Arena::Open(const char *path) fRemaining = fSize; while (fRemaining != 0) { overlap.Offset = (fSize - fRemaining); - if (ReadFile(fHandle, cursor, fSize-1, + if (ReadFile(fHandle, cursor, fSize - 1, &fRead, &overlap) != TRUE) { auto errorCode = GetLastError(); if (errorCode != ERROR_HANDLE_EOF) { - displayWinErr("ReadFile"); - CloseHandle(fHandle); this->Destroy(); - return -1; + + return Windows::DisplayWinError("ReadFile", fHandle); } break; } @@ -235,32 +194,15 @@ Arena::Open(const char *path) int -Arena::Create(const char *path, size_t fileSize, DWORD mode) +Arena::Create(const char *path, size_t fileSize) { - HANDLE fHandle; - - fHandle = CreateFileA( - (LPSTR)path, - GENERIC_READ|GENERIC_WRITE, - mode, - NULL, - CREATE_ALWAYS, - FILE_ATTRIBUTE_NORMAL, - NULL); - if (fHandle == INVALID_HANDLE_VALUE) { - displayWinErr("Create::CreateFileA"); - return -1; + auto errorCode = Windows::CreateFixedSizeFile(path, fileSize); + if (errorCode != 0) { + return errorCode; } - - if (SetFileValidData(fHandle, fileSize) != fileSize) { - displayWinErr("SetFileValidData"); - CloseHandle(fHandle); - return -1; - } - - CloseHandle(fHandle); return this->Open(path); } + #endif bool @@ -308,18 +250,18 @@ Arena::Destroy() delete this->store; break; #if defined(__linux__) - case ArenaType::MemoryMapped: - if (munmap(this->store, this->size) == -1) { - abort(); - return; - } + case ArenaType::MemoryMapped: + if (munmap(this->store, this->size) == -1) { + abort(); + return; + } - if (close(this->fd) == -1) { - abort(); - } + if (close(this->fd) == -1) { + abort(); + } - this->fd = 0; - break; + this->fd = 0; + break; #endif default: #if defined(NDEBUG) @@ -342,7 +284,7 @@ operator<<(std::ostream &os, Arena &arena) auto cursor = arena.NewCursor(); char cursorString[33] = {0}; snprintf(cursorString, 32, "%#016llx", - (long long unsigned int)cursor); + (long long unsigned int) cursor); os << "Arena<"; switch (arena.Type()) { @@ -356,9 +298,9 @@ operator<<(std::ostream &os, Arena &arena) os << "allocated"; break; #if defined(__linux__) - case ArenaType::MemoryMapped: - os << "mmap/file"; - break; + case ArenaType::MemoryMapped: + os << "mmap/file"; + break; #endif default: os << "unknown (this is a bug)"; @@ -384,7 +326,7 @@ Arena::Write(const char *path) arenaFile = fopen(path, "w"); if (arenaFile == nullptr) { #else - if (fopen_s(&arenaFile, path, "w") != 0) { + if (fopen_s(&arenaFile, path, "w") != 0) { #endif return -1; } @@ -404,14 +346,14 @@ Arena::Write(const char *path) uint8_t & Arena::operator[](size_t index) { - if (index > this->size) { + if (index > this->size) { #if defined(DESKTOP_BUILD) and !defined(KLIB_NO_ASSERT) - throw std::range_error("index out of range"); + throw std::range_error("index out of range"); #else - abort(); + abort(); #endif - } - return this->store[index]; + } + return this->store[index]; } diff --git a/Arena.h b/Arena.h index 0d75d90..8807e32 100644 --- a/Arena.h +++ b/Arena.h @@ -116,7 +116,7 @@ public: int Create(const char *path, size_t fileSize); #elif defined(__WIN64__) || defined(__WIN32__) || defined(WIN32) - int Create(const char *path, size_t fileSize, DWORD mode); + int Create(const char *path, size_t fileSize); #endif /// Open reads a file into the arena; the file must already exist. On diff --git a/CMakeLists.txt b/CMakeLists.txt index d458748..d0c9974 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,7 +26,8 @@ set(HEADER_FILES Dictionary.h Exceptions.h Test.h - TLV.h) + TLV.h + WinHelpers.h) set(SOURCE_FILES Arena.cc @@ -36,7 +37,8 @@ set(SOURCE_FILES Test.cc TLV.cc Commander.cpp - Commander.h) + Commander.h + WinHelpers.cpp) add_library(klib STATIC ${SOURCE_FILES} ${HEADER_FILES}) diff --git a/WinHelpers.cpp b/WinHelpers.cpp new file mode 100644 index 0000000..2236926 --- /dev/null +++ b/WinHelpers.cpp @@ -0,0 +1,142 @@ +// +// Created by kyle on 2023-10-10. +// + +#if defined(__WIN64__) || defined(__WIN32__) || defined(WIN32) + +#include "WinHelpers.h" + + +namespace klib { +namespace Windows { + + +int +DisplayWinError(LPTSTR lpszFunction, HANDLE handle) +{ + // Retrieve the system error message for the last-error code + DWORD dw = GetLastError(); +#ifndef NDEBUG + LPVOID lpMsgBuf; + LPVOID lpDisplayBuf; + + FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + dw, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR) &lpMsgBuf, + 0, NULL); + + // Display the error message and exit the process + lpDisplayBuf = (LPVOID) LocalAlloc(LMEM_ZEROINIT, + (lstrlen((LPCTSTR) lpMsgBuf) + + lstrlen((LPCTSTR) lpszFunction) + + 40) * sizeof(TCHAR)); + StringCchPrintf((LPTSTR) lpDisplayBuf, + LocalSize(lpDisplayBuf) / sizeof(TCHAR), + TEXT("%s failed with error %d: %s"), + lpszFunction, dw, lpMsgBuf); + MessageBox(NULL, (LPCTSTR) lpDisplayBuf, TEXT("Error"), MB_OK); + + LocalFree(lpMsgBuf); + LocalFree(lpDisplayBuf); +#endif + if ((handle != NULL) && (handle != INVALID_HANDLE_VALUE)) { + CloseHandle(handle); + } + return dw; +} + + +BOOL SetPrivilege( + HANDLE hToken, // access token handle + LPCTSTR lpszPrivilege, // name of privilege to enable/disable + BOOL bEnablePrivilege // to enable or disable privilege +) +{ + TOKEN_PRIVILEGES tp; + LUID luid; + + if (!LookupPrivilegeValue( + NULL, // lookup privilege on local system + lpszPrivilege, // privilege to lookup + &luid)) // receives LUID of privilege + { + printf("LookupPrivilegeValue error: %u\n", GetLastError()); + return FALSE; + } + + tp.PrivilegeCount = 1; + tp.Privileges[0].Luid = luid; + if (bEnablePrivilege) + tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + else + tp.Privileges[0].Attributes = 0; + + // Enable the privilege or disable all privileges. + + if (!AdjustTokenPrivileges( + hToken, + FALSE, + &tp, + sizeof(TOKEN_PRIVILEGES), + (PTOKEN_PRIVILEGES) NULL, + (PDWORD) NULL)) { + printf("AdjustTokenPrivileges error: %u\n", GetLastError()); + return FALSE; + } + + if (GetLastError() == ERROR_NOT_ALL_ASSIGNED) { + printf("The token does not have the specified privilege. \n"); + return FALSE; + } + + return TRUE; +} + + +HANDLE +CreateFileWindows(const char *path) +{ + HANDLE fHandle; + + return CreateFileA( + (LPSTR) path, + (GENERIC_READ | GENERIC_WRITE), + (FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE), + NULL, + CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, + NULL); +} + + +int +CreateFixedSizeFile(const char *path, size_t size) +{ + _LARGE_INTEGER fileSize; + + fileSize.QuadPart = size; + + HANDLE fHandle = CreateFileWindows(path); + if (SetFilePointerEx(fHandle, fileSize, nullptr, FILE_BEGIN) != TRUE) { + return DisplayWinError("SetFilePointerEx", fHandle); + } + + if (SetEndOfFile(fHandle) != TRUE) { + return DisplayWinError("SetEndOfFile", fHandle); + } + + CloseHandle(fHandle); + return 0; +} + + +} // namespace Windows +} // namespace klib + + +#endif \ No newline at end of file diff --git a/WinHelpers.h b/WinHelpers.h new file mode 100644 index 0000000..e1cd98b --- /dev/null +++ b/WinHelpers.h @@ -0,0 +1,39 @@ +// +// Created by kyle on 2023-10-10. +// + +#ifndef KLIB_WINHELPERS_H +#define KLIB_WINHELPERS_H + +#if defined(__WIN64__) || defined(__WIN32__) || defined(WIN32) + +#include +#include +#include +#include + +namespace klib { +namespace Windows { + + +int DisplayWinError(LPTSTR lpszFunction, HANDLE handle); + +BOOL SetPrivilege( + HANDLE hToken, // access token handle + LPCTSTR lpszPrivilege, // name of privilege to enable/disable + BOOL bEnablePrivilege // to enable or disable privilege +); + +HANDLE CreateFileWindows(const char *path); + +int CreateFixedSizeFile(const char *path, size_t size); + + + + +} // namespace Windows +} // namespace klib + +#endif // Windows-only guards. + +#endif //KLIB_WINHELPERS_H diff --git a/bufferTest.cc b/bufferTest.cc index 3be94b7..5c22080 100644 --- a/bufferTest.cc +++ b/bufferTest.cc @@ -16,43 +16,43 @@ main(int argc, char *argv[]) Buffer goodbyeWorld("goodbye, world"); Buffer goodbyeCruelWorld("goodbye, cruel world"); - std::cout << buffer << std::endl; + std::cout << buffer << "\n"; buffer.Insert(1, (uint8_t *) "el", 2); buffer.Append('!'); assert(buffer == helloWorld); - std::cout << buffer << std::endl; + std::cout << buffer << "\n"; buffer.Remove(buffer.Length() - 1); - std::cout << buffer << std::endl; + std::cout << buffer << "\n"; buffer.Remove(0, 5); - std::cout << buffer << std::endl; + std::cout << buffer << "\n"; buffer.Insert(0, 'g'); - std::cout << buffer << std::endl; + std::cout << buffer << "\n"; buffer.Insert(1, (uint8_t *) "oodbye", 6); - std::cout << buffer << std::endl; + std::cout << buffer << "\n"; assert(buffer == goodbyeWorld); buffer.Insert(9, (uint8_t *)"cruel ", 6); - std::cout << buffer << std::endl; + std::cout << buffer << "\n"; buffer.HexDump(std::cout); buffer.Reclaim(); buffer.Append("and now for something completely different..."); - std::cout << buffer.Contents() << std::endl; - std::cout << "Length: " << buffer.Length() << ", capacity " << buffer.Capacity() << std::endl; + std::cout << buffer.Contents() << "\n"; + std::cout << "Length: " << buffer.Length() << ", capacity " << buffer.Capacity() << "\n"; buffer.Resize(128); - std::cout << "Length: " << buffer.Length() << ", capacity " << buffer.Capacity() << std::endl; + std::cout << "Length: " << buffer.Length() << ", capacity " << buffer.Capacity() << "\n"; buffer.Trim(); - std::cout << "Length: " << buffer.Length() << ", capacity " << buffer.Capacity() << std::endl; + std::cout << "Length: " << buffer.Length() << ", capacity " << buffer.Capacity() << "\n"; Buffer buffer2("and now for something completely different..."); assert(buffer == buffer2); buffer2.Remove(buffer2.Length()-3, 3); - std::cout << buffer << std::endl; + std::cout << buffer << "\n"; assert(buffer != buffer2); return 0; diff --git a/dictionaryTest.cc b/dictionaryTest.cc index 074bff9..7161925 100644 --- a/dictionaryTest.cc +++ b/dictionaryTest.cc @@ -26,7 +26,7 @@ testSetKV(Dictionary &pb, const char *k, uint8_t kl, const char *v, uint8_t vl) { bool ok; - std::cout << "test Set " << k << "->" << v << std::endl; + std::cout << "test Set " << k << "->" << v << "\n"; ok = pb.Set(k, kl, v, vl) == 0; std::cout << "\tSet complete\n"; return ok; @@ -42,7 +42,7 @@ main(int argc, const char *argv[]) TLV::Record value; TLV::Record expect; - std::cout << "TESTPROG: " << argv[0] << std::endl; + std::cout << "TESTPROG: " << argv[0] << "\n"; #if defined(__linux__) if (arena.Create(ARENA_FILE, ARENA_SIZE) == -1) { @@ -53,7 +53,7 @@ main(int argc, const char *argv[]) abort(); } #endif - std::cout << arena << std::endl; + std::cout << arena << "\n"; TLV::SetRecord(expect, DICTIONARY_TAG_VAL, TEST_KVSTRLEN3, TEST_KVSTR3); Dictionary dict(arena); @@ -73,17 +73,17 @@ main(int argc, const char *argv[]) assert(cmpRecord(value, expect)); - std::cout << "test overwriting key" << std::endl; + std::cout << "test overwriting key" << "\n"; assert(testSetKV(dict, TEST_KVSTR2, TEST_KVSTRLEN2, TEST_KVSTR6, TEST_KVSTRLEN6)); std::cout << dict; TLV::SetRecord(expect, DICTIONARY_TAG_VAL, TEST_KVSTRLEN6, TEST_KVSTR6); - std::cout << "\tlookup" << std::endl; + std::cout << "\tlookup" << "\n"; assert(dict.Lookup(TEST_KVSTR2, TEST_KVSTRLEN2, value)); - std::cout << "\tcompare records" << std::endl; + std::cout << "\tcompare records" << "\n"; assert(cmpRecord(value, expect)); - std::cout << "\tadd new key to dictionary" << std::endl; + std::cout << "\tadd new key to dictionary" << "\n"; assert(testSetKV(dict, TEST_KVSTR3, TEST_KVSTRLEN3, TEST_KVSTR5, TEST_KVSTRLEN5)); std::cout << dict; @@ -92,7 +92,7 @@ main(int argc, const char *argv[]) assert(dict.Lookup(TEST_KVSTR4, TEST_KVSTRLEN4, value)); assert(cmpRecord(value, expect)); - std::cout << "OK" <