diff --git a/src/OrcLib/DbgHelpLibrary.cpp b/src/OrcLib/DbgHelpLibrary.cpp index 8ca9de22..da221c48 100644 --- a/src/OrcLib/DbgHelpLibrary.cpp +++ b/src/OrcLib/DbgHelpLibrary.cpp @@ -17,7 +17,7 @@ using namespace Orc; using namespace std::string_literals; DbgHelpLibrary::DbgHelpLibrary() - : ExtensionLibrary(L"DbgHelp.dll"s, L"DBGHELP_X86DLL"s, L"DBGHELP_X64DLL"s, L""s) + : ExtensionLibrary(L"DbgHelp.dll"s, L"DBGHELP_X86DLL"s, L"DBGHELP_X64DLL"s) { m_strDesiredName = L"DbgHelp.dll"s; } diff --git a/src/OrcLib/DiskExtent.cpp b/src/OrcLib/DiskExtent.cpp index e748c58a..83eaff4f 100644 --- a/src/OrcLib/DiskExtent.cpp +++ b/src/OrcLib/DiskExtent.cpp @@ -229,7 +229,7 @@ CDiskExtent CDiskExtent::ReOpen(DWORD dwDesiredAccess, DWORD dwShareMode, DWORD ext.m_PhysicalSectorSize = m_PhysicalSectorSize; ext.m_Start = m_Start; - const auto k32 = ExtensionLibrary::GetLibrary(true); + const auto k32 = ExtensionLibrary::GetLibrary(); if (k32 != nullptr) { diff --git a/src/OrcLib/ExtensionLibrary.cpp b/src/OrcLib/ExtensionLibrary.cpp index 09f79a93..8b96d15c 100644 --- a/src/OrcLib/ExtensionLibrary.cpp +++ b/src/OrcLib/ExtensionLibrary.cpp @@ -15,6 +15,10 @@ #include "SystemDetails.h" #include "Robustness.h" +#include "Output/Text/Fmt/path.h" +#include "Output/Text/Fmt/optional.h" + +#include "Log/Log.h" #include "WideAnsi.h" @@ -23,8 +27,6 @@ #include #include -#include "Log/Log.h" - using namespace std; using namespace Orc; @@ -35,38 +37,11 @@ namespace Orc { ExtensionLibrary::ExtensionLibrary( const std::wstring& strKeyword, const std::wstring& strX86LibRef, - const std::wstring& strX64LibRef, - const std::wstring& strTempDir) + const std::wstring& strX64LibRef) : m_strKeyword(strKeyword) , m_strX86LibRef(strX86LibRef) , m_strX64LibRef(strX64LibRef) - , m_strTempDir(strTempDir) -{ -} - -bool Orc::ExtensionLibrary::CheckInitialized() -{ - HRESULT hr = E_FAIL; - if (!IsInitialized()) - { - if (FAILED(hr = Initialize())) - { - Log::Error("Failed to initialize library (code: {:#x})", hr); - return false; - } - } - return true; -} - -bool Orc::ExtensionLibrary::CheckLoaded() { - HRESULT hr = E_FAIL; - if (FAILED(hr = Load())) - { - Log::Error(L"Failed to load library (code: {:#x})", hr); - return false; - } - return true; } HRESULT ExtensionLibrary::TryLoad(const std::wstring& strFileRef) @@ -89,26 +64,36 @@ HRESULT ExtensionLibrary::TryLoad(const std::wstring& strFileRef) m_strKeyword, RESSOURCE_READ_EXECUTE_SID, strSID.c_str(), - m_strTempDir, + m_tempDir.wstring(), strExtractedFile))) { Log::Debug( - L"Failed to extract resource '{}' into temp dir '{}' (code: {:#x})", strFileRef, m_strTempDir, hr); + L"Failed to extract resource '{}' into temp dir '{}' (code: {:#x})", + strFileRef, + m_tempDir.wstring(), + hr); return hr; } m_bDeleteOnClose = true; if (FAILED(hr = ToDesiredName(strExtractedFile))) - return hr; + { + Log::Warn( + L"Failed to extract rename extracted file from '{}' to '{}' (code: {:#x})", + strExtractedFile, + m_strDesiredName, + hr); + m_libFile = strExtractedFile; + } - auto [hr, hModule] = LoadThisLibrary(m_strLibFile); + auto [hr, hModule] = LoadThisLibrary(m_libFile); if (hModule == NULL || FAILED(hr)) { - Log::Debug(L"Failed to load extension lib using '{}' path (code: {:#x})", m_strLibFile, hr); + Log::Debug(L"Failed to load extension lib using '{}' path (code: {:#x})", m_libFile, hr); return hr; } m_hModule = hModule; - Log::Debug(L"ExtensionLibrary: Loaded '{}' successfully", m_strLibFile); + Log::Debug(L"ExtensionLibrary: Loaded '{}' successfully", m_libFile); return S_OK; } @@ -127,29 +112,33 @@ HRESULT ExtensionLibrary::TryLoad(const std::wstring& strFileRef) m_strKeyword, RESSOURCE_READ_EXECUTE_SID, strSID.c_str(), - m_strTempDir, + m_tempDir.wstring(), strExtractedFile))) { Log::Debug( - L"Failed to extract resource '{}' into temp dir '{}' (code: {:#x})", - strNewLibRef, - m_strTempDir, - hr); + L"Failed to extract resource '{}' into temp dir '{}' (code: {:#x})", strNewLibRef, m_tempDir, hr); return hr; } m_bDeleteOnClose = true; if (FAILED(hr = ToDesiredName(strExtractedFile))) - return hr; + { + Log::Warn( + L"Failed to extract rename extracted file from '{}' to '{}' (code: {:#x})", + strExtractedFile, + m_strDesiredName, + hr); + m_libFile = strExtractedFile; + } - auto [hr, hModule] = LoadThisLibrary(m_strLibFile); + auto [hr, hModule] = LoadThisLibrary(m_libFile); if (hModule == NULL || FAILED(hr)) { - Log::Debug(L"Failed to load extension lib using '{}' path (code: {:#x})", m_strLibFile, hr); + Log::Debug(L"Failed to load extension lib using '{}' path (code: {:#x})", m_libFile, hr); return hr; } m_hModule = hModule; - Log::Debug(L"ExtensionLibrary: Loaded '{}' successfully", m_strLibFile); + Log::Debug(L"ExtensionLibrary: Loaded '{}' successfully", m_libFile); return S_OK; } @@ -174,7 +163,7 @@ HRESULT ExtensionLibrary::TryLoad(const std::wstring& strFileRef) Log::Debug(L"Failed to get file path for extension lib '{}' (code: {:#x})", strNewLibRef, SystemError(hr)); return hr; } - m_strLibFile = szFullPath; + m_libFile = szFullPath; Log::Debug(L"ExtensionLibrary: Loaded '{}' successfully", strNewLibRef); return S_OK; } @@ -201,15 +190,15 @@ HRESULT ExtensionLibrary::TryLoad(const std::wstring& strFileRef) Log::Debug(L"Failed to get file path for extension lib '{}' (code: {:#x})", strFileRef, hr); return hr; } - m_strLibFile = szFullPath; - Log::Debug(L"ExtensionLibrary: Loaded '{}' successfully", m_strLibFile); + m_libFile = szFullPath; + Log::Debug(L"ExtensionLibrary: Loaded '{}' successfully", m_libFile); return S_OK; } -std::pair Orc::ExtensionLibrary::LoadThisLibrary(const std::wstring& strLibFile) +std::pair Orc::ExtensionLibrary::LoadThisLibrary(const std::filesystem::path& libFile) { - auto hInst = LoadLibraryEx(strLibFile.c_str(), NULL, LOAD_WITH_ALTERED_SEARCH_PATH); + auto hInst = LoadLibraryEx(libFile.c_str(), NULL, LOAD_WITH_ALTERED_SEARCH_PATH); if (hInst == NULL) { auto hr = HRESULT_FROM_WIN32(GetLastError()); @@ -238,14 +227,12 @@ HRESULT Orc::ExtensionLibrary::ToDesiredName(const std::wstring& libName) std::filesystem::rename(extractedFileName, finalName, ec); if (ec) - { - Log::Error(L"Failed to rename file '{}' to '{}': {})", extractedFileName, finalName, ec); - return E_FAIL; - } - m_strLibFile = finalName.wstring(); + Log::Warn(L"Failed to rename file '{}' to '{}': {})", extractedFileName, finalName, ec); + + m_libFile = finalName; } else - m_strLibFile = libName; + m_libFile = libName; return S_OK; } @@ -277,38 +264,68 @@ FARPROC Orc::ExtensionLibrary::GetEntryPoint(const CHAR* szFunctionName, bool bM return retval; } -HRESULT ExtensionLibrary::Load(const std::wstring& strAlternateRef) +HRESULT ExtensionLibrary::Load(std::optional tempDir) { - HRESULT hr = E_FAIL; + using namespace std::filesystem; if (m_hModule != NULL) return S_OK; - if (!strAlternateRef.empty()) + WORD wArch = 0; + if (auto hr = SystemDetails::GetArchitecture(wArch); FAILED(hr)) + return hr; + + if (tempDir.has_value()) { - m_strLibRef = strAlternateRef; + if (exists(*tempDir)) + { + if (is_directory(*tempDir)) + { + Log::Debug(L"Using existing directory {} to load extension library", tempDir); + m_tempDir = std::move(*tempDir); + } + else + Log::Warn( + L"Specified temporary directory {} for extenstion library exists and is not a directory -> ignored", + tempDir); + } + else + { + Log::Debug(L"Creating temporary directory {} for extension library", tempDir); + std::error_code ec; + if (!create_directories(*tempDir, ec)) + { + Log::Error( + L"Specified temporary directory {} for extenstion library could not be created -> ignored", + tempDir); + } + else if (!ec) + { + m_tempDir = std::move(*tempDir); + m_bDeleteTemp = true; + } + } } - else + + if (m_tempDir.empty()) { - WORD wArch = 0; - if (FAILED(hr = SystemDetails::GetArchitecture(wArch))) - return hr; + m_tempDir = DefaultExtensionDirectory(); + } - switch (wArch) - { - case PROCESSOR_ARCHITECTURE_INTEL: + switch (wArch) + { + case PROCESSOR_ARCHITECTURE_INTEL: + m_strLibRef = m_strX86LibRef; + break; + case PROCESSOR_ARCHITECTURE_AMD64: + if (SystemDetails::IsWOW64()) m_strLibRef = m_strX86LibRef; - break; - case PROCESSOR_ARCHITECTURE_AMD64: - if (SystemDetails::IsWOW64()) - m_strLibRef = m_strX86LibRef; - else - m_strLibRef = m_strX64LibRef; - break; - default: - Log::Error(L"Unsupported architecture: {}", wArch); - return hr; - } + else + m_strLibRef = m_strX64LibRef; + break; + default: + Log::Error(L"Unsupported architecture: {}", wArch); + return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); } std::vector refs; @@ -317,9 +334,10 @@ HRESULT ExtensionLibrary::Load(const std::wstring& strAlternateRef) boost::split(refs, m_strLibRef, boost::is_any_of(L";,")); + auto last_hr = E_FAIL; for (auto& ref : refs) { - if (SUCCEEDED(hr = TryLoad(ref))) + if (auto hr = TryLoad(ref); SUCCEEDED(hr)) { Log::Debug(L"TryLoad succeeded for reference '{}'", ref); return S_OK; @@ -327,10 +345,11 @@ HRESULT ExtensionLibrary::Load(const std::wstring& strAlternateRef) else { Log::Debug(L"TryLoad failed for reference '{}' (code: {:#x})", ref, hr); + last_hr = hr; } } Log::Error(L"Failed to load extension DLL '{}' using the reference values: '{}'", m_strKeyword, m_strLibRef); - return hr; + return last_hr; } STDMETHODIMP ExtensionLibrary::UnLoad() @@ -343,7 +362,6 @@ STDMETHODIMP ExtensionLibrary::UnLoad() if (m_hModule != NULL) { - ScopedLock lock(m_cs); HMODULE hmod = m_hModule; m_hModule = NULL; @@ -355,15 +373,17 @@ STDMETHODIMP ExtensionLibrary::UnLoad() STDMETHODIMP ExtensionLibrary::Cleanup() { UnLoad(); - if (!m_strLibFile.empty() && m_bDeleteOnClose) + if (!m_libFile.empty() && m_bDeleteOnClose) { ScopedLock lock(m_cs); - HRESULT hr = E_FAIL; - if (FAILED(hr = UtilDeleteTemporaryFile(m_strLibFile.c_str()))) - { + if (auto hr = UtilDeleteTemporaryFile(m_libFile); FAILED(hr)) + return hr; + } + if (m_bDeleteTemp && !m_tempDir.empty() && std::filesystem::exists(m_tempDir)) + { + if (auto hr = UtilDeleteTemporaryDirectory(m_tempDir); FAILED(hr)) return hr; - } } return S_OK; @@ -385,13 +405,13 @@ STDMETHODIMP Orc::ExtensionLibrary::UnloadAndCleanup() FreeThisLibrary(hmod); - if (!m_strLibFile.empty() && m_bDeleteOnClose) + if (!m_libFile.empty() && m_bDeleteOnClose) { DWORD dwRetries = 0L; while (dwRetries < Orc::DELETION_RETRIES) { HRESULT hr = E_FAIL; - if (SUCCEEDED(hr = UtilDeleteTemporaryFile(m_strLibFile.c_str(), 1))) + if (SUCCEEDED(hr = UtilDeleteTemporaryFile(m_libFile.c_str(), 1))) { return S_OK; } @@ -407,3 +427,51 @@ ExtensionLibrary::~ExtensionLibrary(void) { UnloadAndCleanup(); } + +const std::filesystem::path& +Orc::ExtensionLibrary::DefaultExtensionDirectory(std::optional aDefaultDir) +{ + static std::filesystem::path defaultDir; + + if (aDefaultDir.has_value()) + { + if (exists(*aDefaultDir)) + { + if (is_directory(*aDefaultDir)) + { + Log::Debug(L"Using existing directory {} as default to load extension library", aDefaultDir); + defaultDir = std::move(*aDefaultDir); + } + else + Log::Warn( + L"Specified temporary directory {} as default for extenstion library exists and is not a directory " + L"-> ignored", + aDefaultDir); + } + else + { + Log::Debug(L"Creating temporary directory {} as default for extension library", aDefaultDir); + std::error_code ec; + if (!create_directories(*aDefaultDir, ec)) + { + Log::Error( + L"Specified temporary directory {} as default for extenstion library could not be created -> " + L"ignored", + aDefaultDir); + } + else if (!ec) + { + defaultDir = std::move(*aDefaultDir); + } + } + } + + if (defaultDir.empty()) + { + WCHAR szTempDir[MAX_PATH]; + if (auto hr = UtilGetTempDirPath(szTempDir, MAX_PATH); SUCCEEDED(hr)) + defaultDir = szTempDir; + } + + return defaultDir; +} diff --git a/src/OrcLib/ExtensionLibrary.h b/src/OrcLib/ExtensionLibrary.h index 6e5b3cb3..87182a51 100644 --- a/src/OrcLib/ExtensionLibrary.h +++ b/src/OrcLib/ExtensionLibrary.h @@ -12,7 +12,7 @@ #include "OrcLib.h" #include "CriticalSection.h" - +#include "WideAnsi.h" #include "Robustness.h" #include @@ -42,54 +42,71 @@ class ORCLIB_API ExtensionLibrary ExtensionLibrary( const std::wstring& strKeyword, const std::wstring& strX86LibRef, - const std::wstring& strX64LibRef, - const std::wstring& strTempDir = L""); + const std::wstring& strX64LibRef); ExtensionLibrary(ExtensionLibrary&&) noexcept = default; - bool CheckInitialized(); - bool CheckLoaded(); + template + static std::wstring Name() + { + using namespace std::string_literals; + if (auto [hr, wstr] = AnsiToWide(typeid(Library).name()); SUCCEEDED(hr)) + return wstr; + else + return L"(invalid library name)"s; + } template - static const std::shared_ptr GetLibrary(bool bInitialize = true) + static const std::shared_ptr GetLibrary(std::optional tempDir = std::nullopt) { try { const std::shared_ptr& pLib = GetShared(true); + if (!pLib) + { + Log::Error(L"Failed to get shared ptr to library {}", Name()); + return nullptr; + } - if (!bInitialize) - return pLib; + if (!pLib->IsLoaded()) + { + Log::Debug(L"Library {} is not yet loaded", Name()); - if (pLib != nullptr) + if (auto hr = pLib->Load(tempDir); FAILED(hr)) + { + Log::Error(L"Library {} is not be loaded", Name()); + return nullptr; + } + } + + if (!pLib->IsInitialized()) { - if (!pLib->IsLoaded()) + if (auto hr = pLib->Initialize(); FAILED(hr)) { - if (pLib->CheckLoaded()) - { - if (!pLib->m_UnLoadHandler) - { - pLib->m_UnLoadHandler = - std::make_shared>(L"ExtensionLibraryUnLoad"); - Robustness::AddTerminationHandler(pLib->m_UnLoadHandler); - } - return pLib; - } - else - return nullptr; + Log::Error(L"Library {} is loaded but could not be initialized", Name()); + return nullptr; } + } + Log::Debug(L"Library {} is loaded and initialized", Name()); - return pLib->CheckInitialized() ? pLib : nullptr; + if (!pLib->m_UnLoadHandler) + { + pLib->m_UnLoadHandler = std::make_shared>(L"ExtensionLibraryUnLoad"); + Robustness::AddTerminationHandler(pLib->m_UnLoadHandler); } - return nullptr; + return pLib; } - catch (std::exception e) + catch (const std::exception& e) { + auto [hr, wstr] = AnsiToWide(e.what()); + Log::Critical(L"Library {} raised an exception: {}", Name(), wstr); return nullptr; } } - HRESULT Load(const std::wstring& strAlternateFileRef = L""); - const std::wstring& LibraryFile() const { return m_strLibFile; } + HRESULT + Load(std::optional tempDir = std::nullopt); + const std::filesystem::path& LibraryFile() const { return m_libFile; } STDMETHOD(UnLoad()); STDMETHOD(Cleanup()); @@ -100,6 +117,9 @@ class ORCLIB_API ExtensionLibrary virtual ~ExtensionLibrary(void); + static const std::filesystem::path& + DefaultExtensionDirectory(std::optional aDefaultDir = std::nullopt); + protected: bool m_bInitialized = false; @@ -124,7 +144,7 @@ class ORCLIB_API ExtensionLibrary return S_OK; }; - virtual std::pair LoadThisLibrary(const std::wstring& strLibFile); + virtual std::pair LoadThisLibrary(const std::filesystem::path& libFile); virtual void FreeThisLibrary(HINSTANCE hInstance) { @@ -183,13 +203,13 @@ class ORCLIB_API ExtensionLibrary std::wstring m_strLibRef; // Effective, contextual ref used to locate extension lib - std::wstring m_strLibFile; - std::wstring m_strTempDir; + std::filesystem::path m_libFile; + std::filesystem::path m_tempDir; + bool m_bDeleteTemp = false; std::optional m_strDesiredName; bool m_bDeleteOnClose = false; - std::shared_ptr m_UnLoadHandler; HRESULT ToDesiredName(const std::wstring& libName); @@ -220,7 +240,7 @@ class ORCLIB_API ExtensionLibrary { return (T)GetEntryPoint(szFunctionName, bMandatory); }; -}; +}; // namespace Orc template HRESULT ExtensionLibraryHandler::operator()() diff --git a/src/OrcLib/FileStream.cpp b/src/OrcLib/FileStream.cpp index b107656e..7648b551 100644 --- a/src/OrcLib/FileStream.cpp +++ b/src/OrcLib/FileStream.cpp @@ -194,7 +194,7 @@ HRESULT FileStream::Duplicate(const FileStream& other) return E_INVALIDARG; } - const auto pk32 = ExtensionLibrary::GetLibrary(true); + const auto pk32 = ExtensionLibrary::GetLibrary(); HANDLE hFile = INVALID_HANDLE_VALUE; if ((hFile = pk32->ReOpenFile(other.m_hFile, GENERIC_READ, FILE_SHARE_READ, FILE_FLAG_SEQUENTIAL_SCAN))