From 101e2e231c934a2b579ea1a5181708442640906f Mon Sep 17 00:00:00 2001 From: John Parent Date: Fri, 30 Jan 2026 18:33:44 -0500 Subject: [PATCH 01/11] Utils: Expand api Adds support for * Path canonicalization * Making paths absolute * Add path padding character to padding signature * Stripping quotes * Backslash escaping * Corrects regex "match" bug * Adds error handling to SFN name processing * Adds file creation to sfn processing so sfns can be generated for "non existent" files * Adds method to validate a path is the proper length * Updates path padding to leverage the above api additions * Corrects a missing return statement * Adds new error types for current and future use Signed-off-by: John Parent --- src/utils.cxx | 135 +++++++++++++++++++++++++++++++++++++++++++------- src/utils.h | 32 +++++++++++- 2 files changed, 148 insertions(+), 19 deletions(-) diff --git a/src/utils.cxx b/src/utils.cxx index 6bb8c6c..5d7c319 100644 --- a/src/utils.cxx +++ b/src/utils.cxx @@ -6,12 +6,14 @@ #include "utils.h" #include #include +#include #include #include #include #include #include #include +#include #include #include #include @@ -27,12 +29,17 @@ #include #include #include +#include #include +#include #include #include #include +#include #include +#include #include "shlwapi.h" +#include "PathCch.h" ////////////////////////////////////////////////////////// // String helper methods adding cxx20 features to cxx14 // @@ -181,6 +188,17 @@ std::string lstrip(const std::string& str, const std::string& substr) { return str.substr(substr.size(), str.size()); } +/** + * Strips double quotes from front and back of string + * + * Returns str with no leading or trailing quotes + * + * Note: removes only one set of quotes + */ +std::string stripquotes(const std::string& str) { + return strip(lstrip(str, "\""), "\""); +} + /** * combines list of strings into one string joined on join_char */ @@ -337,7 +355,7 @@ std::string regexMatch( if (!std::regex_match(searchDomain, match, reg, flag)) { result_str = std::string(); } else { - result_str = match.str(); + result_str = match.str(1); } return result_str; } @@ -529,7 +547,8 @@ void replace_path_characters(char* path, size_t len) { * null terminators. * \param bsize the lengh of the padding to add */ -char* pad_path(const char* pth, DWORD str_size, DWORD bsize) { +char* pad_path(const char* pth, DWORD str_size, char padding_char, + DWORD bsize) { // If str_size > bsize we get inappropriate conversion // from signed to unsigned if (str_size > bsize) { @@ -543,13 +562,26 @@ char* pad_path(const char* pth, DWORD str_size, DWORD bsize) { padded_path[i] = pth[j]; ++j; } else { - padded_path[i] = '|'; + padded_path[i] = padding_char; } } padded_path[bsize] = '\0'; return padded_path; } +std::string escape_backslash(const std::string& path) { + std::string escaped; + escaped.reserve(path.length() * 2); + for (char const c : path) { + if (c == '\\') { + escaped += "\\\\"; + } else { + escaped += c; + } + } + return escaped; +} + /** * Given a padded library path, return how much the path * has been padded @@ -591,11 +623,37 @@ std::string getSFN(const std::string& path) { // Use "disable string parsing" prefix in case // the path is too long std::string const escaped = R"(\\?\)" + path; + // We cannot get the sfn for a path that doesn't exist + // if we find that the sfn we're looking for doesn't exist + // create a stub of the file, and allow the subsequent + // commands to overwrite it + if (!PathFileExistsA(path.c_str())) { + HANDLE h_file = CreateFileA(path.c_str(), GENERIC_WRITE, 0, nullptr, + CREATE_NEW, FILE_ATTRIBUTE_NORMAL, nullptr); + if (h_file == INVALID_HANDLE_VALUE) { + debug("File " + path + + " does not exist, nor can it be created, unable to " + "compute SFN\n"); + CloseHandle(h_file); + return std::string(); + } + CloseHandle(h_file); + } // Get SFN length so we can create buffer DWORD const sfn_size = GetShortPathNameA(escaped.c_str(), NULL, 0); //NOLINT char* sfn = new char[sfn_size + 1]; - GetShortPathNameA(escaped.c_str(), sfn, escaped.length()); + DWORD const res = GetShortPathNameA(escaped.c_str(), sfn, escaped.length()); + if (!res) { + + std::cerr << "Failed to process short name for " << path + << " Error: " << reportLastError() << "\n"; + } + if (!sfn && res) { + // buffer was too small + debug("buffer too small; had: " + std::to_string(sfn_size) + + " needed: " + std::to_string(res)); + } // sfn is null terminated per win32 api // Ensure we strip out the disable string parsing prefix std::string s_sfn = lstrip(sfn, R"(\\?\)"); @@ -623,6 +681,44 @@ std::string short_name(const std::string& path) { return new_abs_out; } +std::string MakePathAbsolute(const std::string& path) { + if (IsPathAbsolute(path)) { + return path; + } + // relative paths, assume they're relative to the CWD of the linker (as they have to be) + return join({GetCWD(), path}, "\\"); +} + +std::string CannonicalizePath(const std::string& path) { + std::wstring const wpath = ConvertASCIIToWide(path); + wchar_t canonicalized_path[PATHCCH_MAX_CCH]; + const size_t buffer_size = ARRAYSIZE(canonicalized_path); + + HRESULT const status = PathCchCanonicalizeEx( + canonicalized_path, buffer_size, wpath.c_str(), + PATHCCH_ALLOW_LONG_PATHS // Flags for long path support + ); + + if (!SUCCEEDED(status)) { + std::stringstream status_report; + status_report << "Cannot canonicalize path " + path + " error: " + << std::hex << status; + throw NameTooLongError(status_report.str().c_str()); + } + return ConvertWideToASCII(canonicalized_path); +} + +std::string EnsureValidLengthPath(const std::string& path) { + std::string proper_length_path = path; + if (path.length() > MAX_NAME_LEN) { + // Name is too long we need to attempt to shorten + std::string const short_path = short_name(path); + // If new, shortened path is too long, bail + proper_length_path = short_path; + } + return proper_length_path; +} + /** * Mangles a string representing a path to have no path characters * instead path characters (i.e. \\, :, etc) are replaced with @@ -633,19 +729,10 @@ std::string short_name(const std::string& path) { std::string mangle_name(const std::string& name) { std::string abs_out; std::string mangled_abs_out; - if (IsPathAbsolute(name)) { - abs_out = name; - } else { - // relative paths, assume they're relative to the CWD of the linker (as they have to be) - abs_out = join({GetCWD(), name}, "\\"); - } + abs_out = MakePathAbsolute(name); + abs_out = CannonicalizePath(abs_out); // Now that we have the full path, check size - if (abs_out.length() > MAX_NAME_LEN) { - // Name is too long we need to attempt to shorten - std::string const new_abs_out = short_name(abs_out); - // If new, shortened path is too long, bail - abs_out = new_abs_out; - } + abs_out = EnsureValidLengthPath(abs_out); char* chr_abs_out = new char[abs_out.length() + 1]; strcpy(chr_abs_out, abs_out.c_str()); replace_path_characters(chr_abs_out, abs_out.length()); @@ -688,7 +775,7 @@ bool SpackInstalledLib(const std::string& lib) { return false; } std::string const stripped_lib = strip_padding(lib); - startswith(stripped_lib, prefix); + return startswith(stripped_lib, prefix); } LibraryFinder::LibraryFinder() : search_vars{"SPACK_RELOCATE_PATH"} {} @@ -846,4 +933,18 @@ NameTooLongError::NameTooLongError(char const* const message) char const* NameTooLongError::what() const { return exception::what(); +} + +RCCompilerFailure::RCCompilerFailure(char const* const message) + : std::runtime_error(message) {} + +char const* RCCompilerFailure::what() const { + return exception::what(); +} + +FileIOError::FileIOError(char const* const message) + : std::runtime_error(message) {} + +char const* FileIOError::what() const { + return exception::what(); } \ No newline at end of file diff --git a/src/utils.h b/src/utils.h index b04d929..377ee91 100644 --- a/src/utils.h +++ b/src/utils.h @@ -16,6 +16,9 @@ #include #include #include +#include +#include +#include #include "version.h" @@ -52,7 +55,8 @@ enum ExitConditions { LIB_REMOVE_FAILURE, NORMALIZE_NAME_FAILURE, COFF_PARSE_FAILURE, - FILE_RENAME_FAILURE + FILE_RENAME_FAILURE, + CANNOT_OPEN_FILE_FAILURE }; typedef std::vector StrList; @@ -95,6 +99,9 @@ std::string strip(const std::string& s, const std::string& substr); //Strips substr of LHS of the larger string std::string lstrip(const std::string& s, const std::string& substr); +//Strips off leading and trailing quotes +std::string stripquotes(const std::string& str); + // Joins vector of strings by join character std::string join(const StrList& args, const std::string& join_char = " "); @@ -186,9 +193,14 @@ std::string short_name(const std::string& path); std::string mangle_name(const std::string& name); +std::string CannonicalizePath(const std::string& path); + int get_padding_length(const std::string& name); -char* pad_path(const char* pth, DWORD str_size, DWORD bsize = MAX_NAME_LEN); +char* pad_path(const char* pth, DWORD str_size, char padding_char = '|', + DWORD bsize = MAX_NAME_LEN); + +std::string escape_backslash(const std::string& path); void replace_path_characters(char* path, size_t len); @@ -196,6 +208,10 @@ void replace_special_characters(char* mangled, size_t len); bool SpackInstalledLib(const std::string& lib); +std::string MakePathAbsolute(const std::string& path); + +std::string EnsureValidLengthPath(const std::string& path); + // File and File handle helpers // /** * @brief Returns boolean indicating whether @@ -274,4 +290,16 @@ class NameTooLongError : public std::runtime_error { virtual char const* what() const; }; +class RCCompilerFailure : public std::runtime_error { + public: + RCCompilerFailure(char const* const message); + virtual char const* what() const; +}; + +class FileIOError : public std::runtime_error { + public: + FileIOError(char const* const message); + virtual char const* what() const; +}; + static bool DEBUG = false; From 634fd1f44bdaad4865d456a6a591684c623b5e1b Mon Sep 17 00:00:00 2001 From: John Parent Date: Fri, 30 Jan 2026 18:43:22 -0500 Subject: [PATCH 02/11] misc updates Signed-off-by: John Parent --- .github/workflows/ci.yaml | 5 ++--- .gitignore | 7 ++++++- Makefile | 7 +++++-- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 9979ea1..7c106b1 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -6,7 +6,6 @@ name: ci on: [pull_request, push] - concurrency: group: ci-${{github.ref}}-${{github.event.pull_request.number || github.run_number}} cancel-in-progress: true @@ -35,5 +34,5 @@ jobs: - uses: actions/upload-artifact@v4 if: always() with: - name: tester - path: tmp/test/tester.exe + name: tests + path: tmp diff --git a/.gitignore b/.gitignore index 6a74ea7..846f9c0 100644 --- a/.gitignore +++ b/.gitignore @@ -14,9 +14,14 @@ *.exp *.hex *.def +*.res +*.rc # Vscode /.vscode/ # ignore patch files -*.patch \ No newline at end of file +*.patch + +.clang-tidy +.clang-format \ No newline at end of file diff --git a/Makefile b/Makefile index 54646df..a2ee6ba 100644 --- a/Makefile +++ b/Makefile @@ -29,6 +29,9 @@ BUILD_LINK = /DEBUG BASE_CFLAGS = /EHsc CFLAGS = $(BASE_CFLAGS) $(BUILD_CFLAGS) $(CLFLAGS) LFLAGS = $(BUILD_LINK) $(LINKFLAGS) +API_LIBS = Shlwapi.lib \ +Pathcch.lib \ +Advapi32.lib SRCS = cl.obj \ execute.obj \ @@ -55,7 +58,7 @@ linker_invocation.obj all : install test cl.exe : $(SRCS) - link $(LFLAGS) $** Shlwapi.lib /out:cl.exe + link $(LFLAGS) $** $(API_LIBS) /out:cl.exe install : cl.exe mkdir $(PREFIX) @@ -151,7 +154,7 @@ test_pipe_overflow: build_and_check_test_sample set SPACK_CC=%SPACK_CC_TMP% build_zerowrite_test: test\writezero.obj - link $(LFLAGS) $** Shlwapi.lib /out:writezero.exe + link $(LFLAGS) $** $(API_LIBS) /out:writezero.exe test_zerowrite: build_zerowrite_test echo "-----------------------" From e988b91b848a72a9e43c0d7a4665848b153e59cc Mon Sep 17 00:00:00 2001 From: John Parent Date: Wed, 25 Mar 2026 17:23:05 -0400 Subject: [PATCH 03/11] Makefile: document use for additional libraries Signed-off-by: John Parent --- Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index a2ee6ba..a99fc4d 100644 --- a/Makefile +++ b/Makefile @@ -29,9 +29,9 @@ BUILD_LINK = /DEBUG BASE_CFLAGS = /EHsc CFLAGS = $(BASE_CFLAGS) $(BUILD_CFLAGS) $(CLFLAGS) LFLAGS = $(BUILD_LINK) $(LINKFLAGS) -API_LIBS = Shlwapi.lib \ -Pathcch.lib \ -Advapi32.lib +API_LIBS = Shlwapi.lib \ # needed for basic path operations +Pathcch.lib \ # needed for path cannonicalization with long paths +Advapi32.lib # needed for win ACL functions SRCS = cl.obj \ execute.obj \ From bb4be86b788d71de1f85900284ac25fb4d1eaf6e Mon Sep 17 00:00:00 2001 From: John Parent Date: Wed, 25 Mar 2026 18:07:22 -0400 Subject: [PATCH 04/11] Update SFN failure handling Signed-off-by: John Parent --- src/utils.cxx | 46 +++++++++++++++++++++++++++++++++------------- src/utils.h | 14 +++++++++++++- src/winrpath.cxx | 4 ++++ 3 files changed, 50 insertions(+), 14 deletions(-) diff --git a/src/utils.cxx b/src/utils.cxx index 5d7c319..152b4e4 100644 --- a/src/utils.cxx +++ b/src/utils.cxx @@ -29,15 +29,12 @@ #include #include #include -#include #include #include #include #include #include -#include #include -#include #include "shlwapi.h" #include "PathCch.h" @@ -189,13 +186,16 @@ std::string lstrip(const std::string& str, const std::string& substr) { } /** - * Strips double quotes from front and back of string - * - * Returns str with no leading or trailing quotes - * - * Note: removes only one set of quotes + * Strips pair of double or single quotes from front and back of string + * Checks single quotes before double + * + * Returns str with at most one fewer pair of enclosing single/double quotes + * */ std::string stripquotes(const std::string& str) { + // if we have single quotes, strip those + if (startswith(str, "'")) return strip(lstrip(str, "'"), "'"); + // if we have double, do that instead. return strip(lstrip(str, "\""), "\""); } @@ -619,7 +619,7 @@ std::string strip_padding(const std::string& lib) { * than the system MAX_PATH_LENGTH * (different from MAX_NAME_LEN) */ -std::string getSFN(const std::string& path) { +std::string getSFN(const std::string& path, const bool make_file = false) { // Use "disable string parsing" prefix in case // the path is too long std::string const escaped = R"(\\?\)" + path; @@ -628,6 +628,11 @@ std::string getSFN(const std::string& path) { // create a stub of the file, and allow the subsequent // commands to overwrite it if (!PathFileExistsA(path.c_str())) { + if (!make_file) { + char message[50]; + std::snprintf(message, sizeof(message), "File %s does not exist to create an SFN name.", path.c_str()); + throw FileNotExist(message); + } HANDLE h_file = CreateFileA(path.c_str(), GENERIC_WRITE, 0, nullptr, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, nullptr); if (h_file == INVALID_HANDLE_VALUE) { @@ -648,6 +653,7 @@ std::string getSFN(const std::string& path) { std::cerr << "Failed to process short name for " << path << " Error: " << reportLastError() << "\n"; + throw } if (!sfn && res) { // buffer was too small @@ -669,7 +675,7 @@ std::string getSFN(const std::string& path) { */ std::string short_name(const std::string& path) { // Get SFN for path to name - std::string const new_abs_out = getSFN(path); + std::string const new_abs_out = getSFN(path, true); if (new_abs_out.length() > MAX_NAME_LEN) { std::cerr << "DLL path " << path << " too long to relocate.\n"; std::cerr << "Shortened DLL path " << new_abs_out @@ -689,7 +695,7 @@ std::string MakePathAbsolute(const std::string& path) { return join({GetCWD(), path}, "\\"); } -std::string CannonicalizePath(const std::string& path) { +std::string CanonicalizePath(const std::string& path) { std::wstring const wpath = ConvertASCIIToWide(path); wchar_t canonicalized_path[PATHCCH_MAX_CCH]; const size_t buffer_size = ARRAYSIZE(canonicalized_path); @@ -713,7 +719,6 @@ std::string EnsureValidLengthPath(const std::string& path) { if (path.length() > MAX_NAME_LEN) { // Name is too long we need to attempt to shorten std::string const short_path = short_name(path); - // If new, shortened path is too long, bail proper_length_path = short_path; } return proper_length_path; @@ -730,7 +735,7 @@ std::string mangle_name(const std::string& name) { std::string abs_out; std::string mangled_abs_out; abs_out = MakePathAbsolute(name); - abs_out = CannonicalizePath(abs_out); + abs_out = CanonicalizePath(abs_out); // Now that we have the full path, check size abs_out = EnsureValidLengthPath(abs_out); char* chr_abs_out = new char[abs_out.length() + 1]; @@ -935,6 +940,14 @@ char const* NameTooLongError::what() const { return exception::what(); } + +FileNotExist::FileNotExist(char const* const message) + : std::runtime_error(message) {} + +char const* FileNotExist::what() const { + return exception::what(); +} + RCCompilerFailure::RCCompilerFailure(char const* const message) : std::runtime_error(message) {} @@ -947,4 +960,11 @@ FileIOError::FileIOError(char const* const message) char const* FileIOError::what() const { return exception::what(); +} + +SFNProcessingError::SFNProcessingError(char const* const message) + : std::runtime_error(message) {} + +char const* SFNProcessingError::what() const { + return exception::what(); } \ No newline at end of file diff --git a/src/utils.h b/src/utils.h index 377ee91..42f2785 100644 --- a/src/utils.h +++ b/src/utils.h @@ -193,7 +193,7 @@ std::string short_name(const std::string& path); std::string mangle_name(const std::string& name); -std::string CannonicalizePath(const std::string& path); +std::string CanonicalizePath(const std::string& path); int get_padding_length(const std::string& name); @@ -302,4 +302,16 @@ class FileIOError : public std::runtime_error { virtual char const* what() const; }; +class FileNotExist : public std::runtime_error { + public: + FileNotExist(char const* const message); + virtual char const * what() const; +}; + +class SFNProcessingError : public std::runtime_error { + public: + SFNProcessingError(char const * const message); + virtual char const* what() const; +}; + static bool DEBUG = false; diff --git a/src/winrpath.cxx b/src/winrpath.cxx index f98e063..2eaf6a6 100644 --- a/src/winrpath.cxx +++ b/src/winrpath.cxx @@ -104,6 +104,10 @@ bool LibRename::RenameDll(char* name_loc, const std::string& dll_path) const { new_library_loc = short_name(new_library_loc); } catch (NameTooLongError& e) { return false; + } catch (FileNotExist &e) { + return false; + } catch (SFNProcessingError &e) { + return false; } } char* new_lib_pth = From 2865713de0f75132ce3b686864dedcff9200afe4 Mon Sep 17 00:00:00 2001 From: John Parent Date: Wed, 25 Mar 2026 18:44:50 -0400 Subject: [PATCH 05/11] Update regex return handling Signed-off-by: John Parent --- src/utils.cxx | 20 +++++++------------- src/utils.h | 14 +++++++------- src/winrpath.cxx | 5 ++++- 3 files changed, 18 insertions(+), 21 deletions(-) diff --git a/src/utils.cxx b/src/utils.cxx index 152b4e4..b579f02 100644 --- a/src/utils.cxx +++ b/src/utils.cxx @@ -324,40 +324,34 @@ std::regex_constants::match_flag_type composeMatchTypes( return composed_flag; } -std::string regexSearch( +std::smatch regexSearch( const std::string& searchDomain, const std::string& regex, const std::vector& opts, const std::vector& flags) { - std::string result_str; std::regex_constants::syntax_option_type const opt = composeRegexOptions(opts); std::regex_constants::match_flag_type const flag = composeMatchTypes(flags); std::regex const reg(regex, opt); std::smatch match; if (!std::regex_search(searchDomain, match, reg, flag)) { - result_str = std::string(); - } else { - result_str = match.str(); - } - return result_str; + return std::smatch(); + } + return match; } -std::string regexMatch( +std::smatch regexMatch( const std::string& searchDomain, const std::string& regex, const std::vector& opts, const std::vector& flags) { - std::string result_str; std::regex_constants::syntax_option_type const opt = composeRegexOptions(opts); std::regex_constants::match_flag_type const flag = composeMatchTypes(flags); std::regex const reg(regex, opt); std::smatch match; if (!std::regex_match(searchDomain, match, reg, flag)) { - result_str = std::string(); - } else { - result_str = match.str(1); + return std::smatch(); } - return result_str; + return match; } std::string regexReplace( diff --git a/src/utils.h b/src/utils.h index 42f2785..bd04a0f 100644 --- a/src/utils.h +++ b/src/utils.h @@ -149,7 +149,7 @@ std::string quoteAsNeeded(std::string& str); /// @param regex - regex used to search /// @param opts - optional argument, list of regex tuning options to adapt the search behavior /// @return Character sequence matching search regex -std::string regexSearch( +std::smatch regexSearch( const std::string& searchDomain, const std::string& regex, const std::vector& opts = {}, const std::vector& flags = {}); @@ -160,7 +160,7 @@ std::string regexSearch( /// @param regex - regex used to match /// @param opts - optional argument, list of regex tuning options to adapt the match behavior /// @return Character sequence matching regex -std::string regexMatch( +std::smatch regexMatch( const std::string& searchDomain, const std::string& regex, const std::vector& opts = {}, const std::vector& flags = {}); @@ -286,31 +286,31 @@ const std::map path_to_special_characters{{'\\', '|'}, class NameTooLongError : public std::runtime_error { public: - NameTooLongError(char const* const message); + explicit NameTooLongError(char const* const message); virtual char const* what() const; }; class RCCompilerFailure : public std::runtime_error { public: - RCCompilerFailure(char const* const message); + explicit RCCompilerFailure(char const* const message); virtual char const* what() const; }; class FileIOError : public std::runtime_error { public: - FileIOError(char const* const message); + explicit FileIOError(char const* const message); virtual char const* what() const; }; class FileNotExist : public std::runtime_error { public: - FileNotExist(char const* const message); + explicit FileNotExist(char const* const message); virtual char const * what() const; }; class SFNProcessingError : public std::runtime_error { public: - SFNProcessingError(char const * const message); + explicit SFNProcessingError(char const * const message); virtual char const* what() const; }; diff --git a/src/winrpath.cxx b/src/winrpath.cxx index 2eaf6a6..c895315 100644 --- a/src/winrpath.cxx +++ b/src/winrpath.cxx @@ -24,6 +24,7 @@ #include #include #include +#include /* * Checks a DLL name for special characters, if we're deploying, a path character, if we're @@ -312,7 +313,9 @@ bool LibRename::ComputeDefFile() { std::string line; // Read until the output column titles while (std::getline(input_file, line)) { - std::string const res = regexSearch(line, R"(ordinal\s+name)"); + std::smatch search_res = regexSearch(line, R"(ordinal\s+name)"); + if (search_res.empty()) break; + std::string const res = search_res.str(); if (!res.empty()) { break; } From 948d82f1fe4cb3a11cac09f28f7a9b33e53a5f45 Mon Sep 17 00:00:00 2001 From: John Parent Date: Wed, 25 Mar 2026 18:52:25 -0400 Subject: [PATCH 06/11] no inline makefile comments apparently Signed-off-by: John Parent --- Makefile | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index a99fc4d..2fac1fa 100644 --- a/Makefile +++ b/Makefile @@ -29,9 +29,12 @@ BUILD_LINK = /DEBUG BASE_CFLAGS = /EHsc CFLAGS = $(BASE_CFLAGS) $(BUILD_CFLAGS) $(CLFLAGS) LFLAGS = $(BUILD_LINK) $(LINKFLAGS) -API_LIBS = Shlwapi.lib \ # needed for basic path operations -Pathcch.lib \ # needed for path cannonicalization with long paths -Advapi32.lib # needed for win ACL functions +# shlwapi: needed for basic path operations +# pathcch: needed for long path canonicalization +# advapi32: needed for win32 ACL interactions +API_LIBS = Shlwapi.lib \ +Pathcch.lib \ +Advapi32.lib SRCS = cl.obj \ execute.obj \ From f5f547fad31932171b6a2284f7fdb9cd8cffd8df Mon Sep 17 00:00:00 2001 From: John Parent Date: Wed, 25 Mar 2026 18:56:21 -0400 Subject: [PATCH 07/11] add missing exception Signed-off-by: John Parent --- src/utils.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils.cxx b/src/utils.cxx index b579f02..dc4bdc6 100644 --- a/src/utils.cxx +++ b/src/utils.cxx @@ -647,7 +647,7 @@ std::string getSFN(const std::string& path, const bool make_file = false) { std::cerr << "Failed to process short name for " << path << " Error: " << reportLastError() << "\n"; - throw + throw SFNProcessingError("Unable to create SFN"); } if (!sfn && res) { // buffer was too small From 1f15689e564c6bd0a097e6c5ec608c49e2a9987f Mon Sep 17 00:00:00 2001 From: John Parent Date: Tue, 31 Mar 2026 14:14:30 -0400 Subject: [PATCH 08/11] RM unused exception definitions Signed-off-by: John Parent --- src/utils.cxx | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/src/utils.cxx b/src/utils.cxx index dc4bdc6..44d91ae 100644 --- a/src/utils.cxx +++ b/src/utils.cxx @@ -942,20 +942,6 @@ char const* FileNotExist::what() const { return exception::what(); } -RCCompilerFailure::RCCompilerFailure(char const* const message) - : std::runtime_error(message) {} - -char const* RCCompilerFailure::what() const { - return exception::what(); -} - -FileIOError::FileIOError(char const* const message) - : std::runtime_error(message) {} - -char const* FileIOError::what() const { - return exception::what(); -} - SFNProcessingError::SFNProcessingError(char const* const message) : std::runtime_error(message) {} From 2fcd94406c3b932afa527c4e26267a8570bd0985 Mon Sep 17 00:00:00 2001 From: John Parent Date: Tue, 31 Mar 2026 14:15:57 -0400 Subject: [PATCH 09/11] RM unused exception declarations Signed-off-by: John Parent --- src/utils.h | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/utils.h b/src/utils.h index bd04a0f..5dda860 100644 --- a/src/utils.h +++ b/src/utils.h @@ -290,18 +290,6 @@ class NameTooLongError : public std::runtime_error { virtual char const* what() const; }; -class RCCompilerFailure : public std::runtime_error { - public: - explicit RCCompilerFailure(char const* const message); - virtual char const* what() const; -}; - -class FileIOError : public std::runtime_error { - public: - explicit FileIOError(char const* const message); - virtual char const* what() const; -}; - class FileNotExist : public std::runtime_error { public: explicit FileNotExist(char const* const message); From 2d0b52c10e57a5d6ced7f533baee40bf520a5b5c Mon Sep 17 00:00:00 2001 From: John Parent Date: Tue, 31 Mar 2026 14:19:10 -0400 Subject: [PATCH 10/11] Throw on sfn Signed-off-by: John Parent --- src/utils.cxx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/utils.cxx b/src/utils.cxx index 44d91ae..e45190e 100644 --- a/src/utils.cxx +++ b/src/utils.cxx @@ -651,8 +651,7 @@ std::string getSFN(const std::string& path, const bool make_file = false) { } if (!sfn && res) { // buffer was too small - debug("buffer too small; had: " + std::to_string(sfn_size) + - " needed: " + std::to_string(res)); + throw SFNProcessingError("Cannot create SFN name, cannot allocate sufficient space") } // sfn is null terminated per win32 api // Ensure we strip out the disable string parsing prefix From c16d83b667e153e4bc3dd237bc12b8de057c4424 Mon Sep 17 00:00:00 2001 From: John Parent Date: Tue, 31 Mar 2026 14:19:28 -0400 Subject: [PATCH 11/11] oop Signed-off-by: John Parent --- src/utils.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils.cxx b/src/utils.cxx index e45190e..76f9783 100644 --- a/src/utils.cxx +++ b/src/utils.cxx @@ -651,7 +651,7 @@ std::string getSFN(const std::string& path, const bool make_file = false) { } if (!sfn && res) { // buffer was too small - throw SFNProcessingError("Cannot create SFN name, cannot allocate sufficient space") + throw SFNProcessingError("Cannot create SFN name, cannot allocate sufficient space"); } // sfn is null terminated per win32 api // Ensure we strip out the disable string parsing prefix