Windows is a nightmare.

This commit is contained in:
Kyle Isom 2023-10-10 16:44:29 -07:00
parent 138bf8267b
commit 67d4a1ebce
8 changed files with 266 additions and 137 deletions

View File

@ -13,10 +13,8 @@
#define PROT_RW (PROT_WRITE|PROT_READ) #define PROT_RW (PROT_WRITE|PROT_READ)
#elif defined(__WIN64__) || defined(__WIN32__) || defined(WIN32) #elif defined(__WIN64__) || defined(__WIN32__) || defined(WIN32)
#include <Windows.h> #include "WinHelpers.h"
#include <winbase.h> #pragma comment(lib, "advapi32.lib")
#include <fileapi.h>
#include <strsafe.h>
#endif #endif
#include <ios> #include <ios>
@ -136,40 +134,6 @@ Arena::Create(const char *path, size_t fileSize)
return this->Open(path); return this->Open(path);
} }
#elif defined(__WIN64__) || defined(__WIN32__) || defined(WIN32) #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 int
Arena::Open(const char *path) Arena::Open(const char *path)
{ {
@ -189,20 +153,16 @@ Arena::Open(const char *path)
FILE_ATTRIBUTE_NORMAL, FILE_ATTRIBUTE_NORMAL,
NULL); NULL);
if (fHandle == INVALID_HANDLE_VALUE) { if (fHandle == INVALID_HANDLE_VALUE) {
displayWinErr("CreateFileA"); return Windows::DisplayWinError("CreateFileA", NULL);
return -1;
} }
if (SetFilePointer(fHandle, 0, 0, FILE_BEGIN) != 0) { if (SetFilePointer(fHandle, 0, 0, FILE_BEGIN) != 0) {
displayWinErr("SetFilePointer"); return Windows::DisplayWinError("SetFilePointer", fHandle);
CloseHandle(fHandle);
return -1;
} }
if (GetFileSizeEx(fHandle, reinterpret_cast<PLARGE_INTEGER>(&fSize)) != TRUE) { if (GetFileSizeEx(fHandle, reinterpret_cast<PLARGE_INTEGER>(&fSize)) !=
displayWinErr("GetFileSizeEx"); TRUE) {
CloseHandle(fHandle); return Windows::DisplayWinError("GetFileSizeEx", fHandle);
return -1;
} }
this->SetAlloc(fSize); this->SetAlloc(fSize);
@ -217,10 +177,9 @@ Arena::Open(const char *path)
&overlap) != TRUE) { &overlap) != TRUE) {
auto errorCode = GetLastError(); auto errorCode = GetLastError();
if (errorCode != ERROR_HANDLE_EOF) { if (errorCode != ERROR_HANDLE_EOF) {
displayWinErr("ReadFile");
CloseHandle(fHandle);
this->Destroy(); this->Destroy();
return -1;
return Windows::DisplayWinError("ReadFile", fHandle);
} }
break; break;
} }
@ -235,32 +194,15 @@ Arena::Open(const char *path)
int int
Arena::Create(const char *path, size_t fileSize, DWORD mode) Arena::Create(const char *path, size_t fileSize)
{ {
HANDLE fHandle; auto errorCode = Windows::CreateFixedSizeFile(path, fileSize);
if (errorCode != 0) {
fHandle = CreateFileA( return errorCode;
(LPSTR)path,
GENERIC_READ|GENERIC_WRITE,
mode,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (fHandle == INVALID_HANDLE_VALUE) {
displayWinErr("Create::CreateFileA");
return -1;
} }
if (SetFileValidData(fHandle, fileSize) != fileSize) {
displayWinErr("SetFileValidData");
CloseHandle(fHandle);
return -1;
}
CloseHandle(fHandle);
return this->Open(path); return this->Open(path);
} }
#endif #endif
bool bool

View File

@ -116,7 +116,7 @@ public:
int Create(const char *path, size_t fileSize); int Create(const char *path, size_t fileSize);
#elif defined(__WIN64__) || defined(__WIN32__) || defined(WIN32) #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 #endif
/// Open reads a file into the arena; the file must already exist. On /// Open reads a file into the arena; the file must already exist. On

View File

@ -26,7 +26,8 @@ set(HEADER_FILES
Dictionary.h Dictionary.h
Exceptions.h Exceptions.h
Test.h Test.h
TLV.h) TLV.h
WinHelpers.h)
set(SOURCE_FILES set(SOURCE_FILES
Arena.cc Arena.cc
@ -36,7 +37,8 @@ set(SOURCE_FILES
Test.cc Test.cc
TLV.cc TLV.cc
Commander.cpp Commander.cpp
Commander.h) Commander.h
WinHelpers.cpp)
add_library(klib STATIC ${SOURCE_FILES} ${HEADER_FILES}) add_library(klib STATIC ${SOURCE_FILES} ${HEADER_FILES})

142
WinHelpers.cpp Normal file
View File

@ -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

39
WinHelpers.h Normal file
View File

@ -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 <Windows.h>
#include <winbase.h>
#include <fileapi.h>
#include <strsafe.h>
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

View File

@ -16,43 +16,43 @@ main(int argc, char *argv[])
Buffer goodbyeWorld("goodbye, world"); Buffer goodbyeWorld("goodbye, world");
Buffer goodbyeCruelWorld("goodbye, cruel world"); Buffer goodbyeCruelWorld("goodbye, cruel world");
std::cout << buffer << std::endl; std::cout << buffer << "\n";
buffer.Insert(1, (uint8_t *) "el", 2); buffer.Insert(1, (uint8_t *) "el", 2);
buffer.Append('!'); buffer.Append('!');
assert(buffer == helloWorld); assert(buffer == helloWorld);
std::cout << buffer << std::endl; std::cout << buffer << "\n";
buffer.Remove(buffer.Length() - 1); buffer.Remove(buffer.Length() - 1);
std::cout << buffer << std::endl; std::cout << buffer << "\n";
buffer.Remove(0, 5); buffer.Remove(0, 5);
std::cout << buffer << std::endl; std::cout << buffer << "\n";
buffer.Insert(0, 'g'); buffer.Insert(0, 'g');
std::cout << buffer << std::endl; std::cout << buffer << "\n";
buffer.Insert(1, (uint8_t *) "oodbye", 6); buffer.Insert(1, (uint8_t *) "oodbye", 6);
std::cout << buffer << std::endl; std::cout << buffer << "\n";
assert(buffer == goodbyeWorld); assert(buffer == goodbyeWorld);
buffer.Insert(9, (uint8_t *)"cruel ", 6); buffer.Insert(9, (uint8_t *)"cruel ", 6);
std::cout << buffer << std::endl; std::cout << buffer << "\n";
buffer.HexDump(std::cout); buffer.HexDump(std::cout);
buffer.Reclaim(); buffer.Reclaim();
buffer.Append("and now for something completely different..."); buffer.Append("and now for something completely different...");
std::cout << buffer.Contents() << std::endl; std::cout << buffer.Contents() << "\n";
std::cout << "Length: " << buffer.Length() << ", capacity " << buffer.Capacity() << std::endl; std::cout << "Length: " << buffer.Length() << ", capacity " << buffer.Capacity() << "\n";
buffer.Resize(128); buffer.Resize(128);
std::cout << "Length: " << buffer.Length() << ", capacity " << buffer.Capacity() << std::endl; std::cout << "Length: " << buffer.Length() << ", capacity " << buffer.Capacity() << "\n";
buffer.Trim(); 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..."); Buffer buffer2("and now for something completely different...");
assert(buffer == buffer2); assert(buffer == buffer2);
buffer2.Remove(buffer2.Length()-3, 3); buffer2.Remove(buffer2.Length()-3, 3);
std::cout << buffer << std::endl; std::cout << buffer << "\n";
assert(buffer != buffer2); assert(buffer != buffer2);
return 0; return 0;

View File

@ -26,7 +26,7 @@ testSetKV(Dictionary &pb, const char *k, uint8_t kl, const char *v,
uint8_t vl) uint8_t vl)
{ {
bool ok; 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; ok = pb.Set(k, kl, v, vl) == 0;
std::cout << "\tSet complete\n"; std::cout << "\tSet complete\n";
return ok; return ok;
@ -42,7 +42,7 @@ main(int argc, const char *argv[])
TLV::Record value; TLV::Record value;
TLV::Record expect; TLV::Record expect;
std::cout << "TESTPROG: " << argv[0] << std::endl; std::cout << "TESTPROG: " << argv[0] << "\n";
#if defined(__linux__) #if defined(__linux__)
if (arena.Create(ARENA_FILE, ARENA_SIZE) == -1) { if (arena.Create(ARENA_FILE, ARENA_SIZE) == -1) {
@ -53,7 +53,7 @@ main(int argc, const char *argv[])
abort(); abort();
} }
#endif #endif
std::cout << arena << std::endl; std::cout << arena << "\n";
TLV::SetRecord(expect, DICTIONARY_TAG_VAL, TEST_KVSTRLEN3, TEST_KVSTR3); TLV::SetRecord(expect, DICTIONARY_TAG_VAL, TEST_KVSTRLEN3, TEST_KVSTR3);
Dictionary dict(arena); Dictionary dict(arena);
@ -73,17 +73,17 @@ main(int argc, const char *argv[])
assert(cmpRecord(value, expect)); 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, assert(testSetKV(dict, TEST_KVSTR2, TEST_KVSTRLEN2, TEST_KVSTR6,
TEST_KVSTRLEN6)); TEST_KVSTRLEN6));
std::cout << dict; std::cout << dict;
TLV::SetRecord(expect, DICTIONARY_TAG_VAL, TEST_KVSTRLEN6, TEST_KVSTR6); 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)); assert(dict.Lookup(TEST_KVSTR2, TEST_KVSTRLEN2, value));
std::cout << "\tcompare records" << std::endl; std::cout << "\tcompare records" << "\n";
assert(cmpRecord(value, expect)); 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, assert(testSetKV(dict, TEST_KVSTR3, TEST_KVSTRLEN3, TEST_KVSTR5,
TEST_KVSTRLEN5)); TEST_KVSTRLEN5));
std::cout << dict; std::cout << dict;
@ -92,7 +92,7 @@ main(int argc, const char *argv[])
assert(dict.Lookup(TEST_KVSTR4, TEST_KVSTRLEN4, value)); assert(dict.Lookup(TEST_KVSTR4, TEST_KVSTRLEN4, value));
assert(cmpRecord(value, expect)); assert(cmpRecord(value, expect));
std::cout << "OK" <<std::endl; std::cout << "OK" <<"\n";
// Dump the generated arena for inspection later. // Dump the generated arena for inspection later.
#if defined(__linux__) #if defined(__linux__)

View File

@ -21,29 +21,29 @@ tlvTestSuite(Arena &backend)
TLV::Record rec1, rec2, rec3, rec4; TLV::Record rec1, rec2, rec3, rec4;
uint8_t *cursor = nullptr; uint8_t *cursor = nullptr;
std::cout << "\tSetting first three records." << std::endl; std::cout << "\tSetting first three records." << "\n";
TLV::SetRecord(rec1, 1, TEST_STRLEN1, TEST_STR1); TLV::SetRecord(rec1, 1, TEST_STRLEN1, TEST_STR1);
TLV::SetRecord(rec2, 2, TEST_STRLEN2, TEST_STR2); TLV::SetRecord(rec2, 2, TEST_STRLEN2, TEST_STR2);
TLV::SetRecord(rec3, 1, TEST_STRLEN4, TEST_STR4); TLV::SetRecord(rec3, 1, TEST_STRLEN4, TEST_STR4);
rec4.Tag = 1; rec4.Tag = 1;
std::cout << "\twriting new rec1" << std::endl; std::cout << "\twriting new rec1" << "\n";
assert(TLV::WriteToMemory(backend, cursor, rec1) != nullptr); assert(TLV::WriteToMemory(backend, cursor, rec1) != nullptr);
std::cout << "\twriting new rec2" << std::endl; std::cout << "\twriting new rec2" << "\n";
assert((cursor = TLV::WriteToMemory(backend, cursor, rec2)) != nullptr); assert((cursor = TLV::WriteToMemory(backend, cursor, rec2)) != nullptr);
std::cout << "\twriting new rec3" << std::endl; std::cout << "\twriting new rec3" << "\n";
assert(TLV::WriteToMemory(backend, cursor, rec3) != nullptr); assert(TLV::WriteToMemory(backend, cursor, rec3) != nullptr);
cursor = nullptr; cursor = nullptr;
// the cursor should point at the next record, // the cursor should point at the next record,
// and rec4 should contain the same data as rec1. // and rec4 should contain the same data as rec1.
std::cout << "\tFindTag 1" << std::endl; std::cout << "\tFindTag 1" << "\n";
cursor = TLV::FindTag(backend, cursor, rec4); cursor = TLV::FindTag(backend, cursor, rec4);
assert(cursor != nullptr); assert(cursor != nullptr);
assert(cursor != backend.NewCursor()); assert(cursor != backend.NewCursor());
assert(cmpRecord(rec1, rec4)); assert(cmpRecord(rec1, rec4));
std::cout << "\tFindTag 2" << std::endl; std::cout << "\tFindTag 2" << "\n";
cursor = TLV::FindTag(backend, cursor, rec4); cursor = TLV::FindTag(backend, cursor, rec4);
assert(cursor != nullptr); assert(cursor != nullptr);
assert(cmpRecord(rec3, rec4)); assert(cmpRecord(rec3, rec4));
@ -62,20 +62,22 @@ tlvTestSuite(Arena &backend)
bool bool
runSuite(Arena &backend, const char *label) runSuite(Arena &backend, const char *label)
{ {
std::cout << backend << std::endl; std::exception exc;
std::cout << backend << "\n";
std::cout << "running test suite " << label << ": "; std::cout << "running test suite " << label << ": ";
try { try {
tlvTestSuite(backend); tlvTestSuite(backend);
} catch (std::exception &exc){ } catch (std::exception &exc){
std::cout << "FAILED" << std::endl; std::cout << "FAILED: " << exc.what() << "\n";
return false; return false;
} }
std::cout << "OK" << std::endl; std::cout << "OK" << "\n";
std::cout << "\tdestroying arena: "; std::cout << "\tdestroying arena: ";
backend.Destroy(); backend.Destroy();
std::cout << "OK" << std::endl; std::cout << "OK" << "\n";
return true; return true;
} }
@ -88,7 +90,7 @@ main(int argc, const char *argv[])
Arena arenaStatic; Arena arenaStatic;
Arena arenaMem; Arena arenaMem;
std::cout << "TESTPROG: " << argv[0] << std::endl; std::cout << "TESTPROG: " << argv[0] << "\n";
if (-1 == arenaStatic.SetStatic(arenaBuffer, ARENA_SIZE)) { if (-1 == arenaStatic.SetStatic(arenaBuffer, ARENA_SIZE)) {
abort(); abort();
@ -98,8 +100,10 @@ main(int argc, const char *argv[])
arenaStatic.Clear(); arenaStatic.Clear();
Arena arenaFile; Arena arenaFile;
auto status = arenaFile.Create(ARENA_FILE, ARENA_SIZE);
if (-1 == arenaFile.Create(ARENA_FILE, ARENA_SIZE)) { if (status != 0) {
std::cerr << "Create failed with error " << status << "\n";
abort(); abort();
} else if (!runSuite(arenaFile, "arenaFile")) { } else if (!runSuite(arenaFile, "arenaFile")) {
abort(); abort();
@ -112,6 +116,6 @@ main(int argc, const char *argv[])
} }
arenaMem.Clear(); arenaMem.Clear();
std::cout << "OK" << std::endl; std::cout << "OK" << "\n";
return 0; return 0;
} }