diff --git a/CHANGELOG.md b/CHANGELOG.md index f7c535cd..0be4b585 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,24 @@ # ChangeLog +## [10.1.0-rc3] - 2020-12-02 +### Changed +- Log: enhance FileSink synchronisation + +### Fixed +- WolfLauncher: fix log file format for a configurated DFIR-Orc +- Log: add support for SPDLOG_LEVEL env variable +- Values incorrectly displayed as addresses instead of readable strings +- Outline: missing 'qfe', 'network', 'environment' sections +- GetSectors: failure when no disk was specified +- Column filter processing inserting some empty lines (',,,,,,,,,,,,,,,') +- GetThis: fix compression level + +### Added +- WolfLauncher: print a 'Ended' line in the journal with statistics + +### Removed +- Dead code: ByteStreamSink + ## [10.1.0-rc2] - 2020-11-20 ### Changed - Column 'ParentName': remove trailing '\' diff --git a/src/OrcCommand/CMakeLists.txt b/src/OrcCommand/CMakeLists.txt index 6437a691..2591eb9d 100644 --- a/src/OrcCommand/CMakeLists.txt +++ b/src/OrcCommand/CMakeLists.txt @@ -235,6 +235,8 @@ set(SRC_WOLFLAUNCHER "WolfLauncher_Run.cpp" "WolfTask.cpp" "WolfTask.h" + "Output/Text/Fmt/WolfPriority.h" + "Output/Text/Print/Recipient.h" "WolfLauncherSqlSchema.xml" ) diff --git a/src/OrcCommand/FastFind_Run.cpp b/src/OrcCommand/FastFind_Run.cpp index 02489222..b50fd6ca 100644 --- a/src/OrcCommand/FastFind_Run.cpp +++ b/src/OrcCommand/FastFind_Run.cpp @@ -463,7 +463,7 @@ HRESULT Main::Run() if (config.outObject.Type != OutputSpec::Kind::None) pObjectTableOutput = TableOutput::GetWriter(config.outObject); - if (config.outStructured.Type & OutputSpec::Kind::StructuredFile) + if (HasFlag(config.outStructured.Type, OutputSpec::Kind::StructuredFile)) { pStructuredOutput = StructuredOutputWriter::GetWriter(config.outStructured, nullptr); } diff --git a/src/OrcCommand/GetSamples_Run.cpp b/src/OrcCommand/GetSamples_Run.cpp index e3a2b3a2..adb36edc 100644 --- a/src/OrcCommand/GetSamples_Run.cpp +++ b/src/OrcCommand/GetSamples_Run.cpp @@ -473,7 +473,7 @@ HRESULT Main::Run() Log::Info(L"Verifying code signatures... Done"); } - if (config.sampleinfoOutput.Type & OutputSpec::Kind::TableFile) + if (HasFlag(config.sampleinfoOutput.Type, OutputSpec::Kind::TableFile)) { hr = WriteSampleInformation(results); if (FAILED(hr)) @@ -483,7 +483,7 @@ HRESULT Main::Run() } } - if (config.timelineOutput.Type & OutputSpec::Kind::TableFile) + if (HasFlag(config.timelineOutput.Type, OutputSpec::Kind::TableFile)) { // Collect time line related information const TaskTracker::TimeLine& timeline = tk.GetTimeLine(); diff --git a/src/OrcCommand/GetSectors_Run.cpp b/src/OrcCommand/GetSectors_Run.cpp index a183c4a9..64e602da 100644 --- a/src/OrcCommand/GetSectors_Run.cpp +++ b/src/OrcCommand/GetSectors_Run.cpp @@ -117,7 +117,7 @@ std::wstring Main::getBootDiskName() return {}; } - Guard::ScopeGuard([&hVolume]() { + Guard::ScopeGuard sg([&hVolume]() { if (hVolume != INVALID_HANDLE_VALUE) { CloseHandle(hVolume); diff --git a/src/OrcCommand/Mothership.h b/src/OrcCommand/Mothership.h index 6a33b0f8..128fac42 100644 --- a/src/OrcCommand/Mothership.h +++ b/src/OrcCommand/Mothership.h @@ -120,6 +120,8 @@ class ORCUTILS_API Main : public UtilitiesMain HRESULT DownloadLocalCopy(); public: + void Configure(int argc, const wchar_t* argv[]) override; + static LPCWSTR ToolName() { return L"Mothership"; } static LPCWSTR ToolDescription() { return nullptr; } diff --git a/src/OrcCommand/Mothership_Run.cpp b/src/OrcCommand/Mothership_Run.cpp index efad4971..f892a147 100644 --- a/src/OrcCommand/Mothership_Run.cpp +++ b/src/OrcCommand/Mothership_Run.cpp @@ -84,6 +84,11 @@ class MotherShipTerminate : public TerminationHandler }; }; +void Main::Configure(int argc, const wchar_t* argv[]) +{ + UtilitiesMain::Configure(argc, argv); +} + HRESULT Main::ChangeTemporaryEnvironment() { HRESULT hr = E_FAIL; diff --git a/src/OrcCommand/NTFSInfo_Output.cpp b/src/OrcCommand/NTFSInfo_Output.cpp index 125f269a..83b764ec 100644 --- a/src/OrcCommand/NTFSInfo_Output.cpp +++ b/src/OrcCommand/NTFSInfo_Output.cpp @@ -20,6 +20,7 @@ #include "Output/Text/Print/Intentions.h" #include "Output/Text/Print/Filter.h" #include "Output/Text/Print/LocationSet.h" +#include "Output/Text/Print/Location.h" #include "Usage.h" diff --git a/src/OrcCommand/Output/Text/Fmt/WolfPriority.h b/src/OrcCommand/Output/Text/Fmt/WolfPriority.h new file mode 100644 index 00000000..58b7433f --- /dev/null +++ b/src/OrcCommand/Output/Text/Fmt/WolfPriority.h @@ -0,0 +1,44 @@ +// +// SPDX-License-Identifier: LGPL-2.1-or-later +// +// Copyright © 2020 ANSSI. All Rights Reserved. +// +// Author(s): fabienfl (ANSSI) +// + +#pragma once + +#include "WolfLauncher.h" + +#include + +#include "Output/Text/Format.h" +#include "Utils/Iconv.h" + +template<> +struct fmt::formatter : public fmt::formatter +{ + template + auto format(const Orc::Command::Wolf::Main::WolfPriority& priority, FormatContext& ctx) -> decltype(ctx.out()) + { + std::error_code ec; + const auto utf8 = Orc::Utf16ToUtf8(Orc::Command::Wolf::WolfLauncher::ToString(priority), ec); + if (ec) + { + return formatter::format(Orc::kFailedConversion, ctx); + } + + return formatter::format(utf8, ctx); + } +}; + +template<> +struct fmt::formatter + : public fmt::formatter +{ + template + auto format(Orc::Command::Wolf::Main::WolfPriority priority, FormatContext& ctx) -> decltype(ctx.out()) + { + return formatter::format(Orc::Command::Wolf::Main::ToString(priority), ctx); + } +}; diff --git a/src/OrcCommand/Output/Text/Print/Recipient.h b/src/OrcCommand/Output/Text/Print/Recipient.h new file mode 100644 index 00000000..feae5071 --- /dev/null +++ b/src/OrcCommand/Output/Text/Print/Recipient.h @@ -0,0 +1,40 @@ +// +// SPDX-License-Identifier: LGPL-2.1-or-later +// +// Copyright © 2020 ANSSI. All Rights Reserved. +// +// Author(s): fabienfl (ANSSI) +// + +#pragma once + +#include "Output/Text/Print.h" + +#include + +#include "WolfExecution.h" + +namespace Orc { +namespace Text { + +template <> +struct Printer +{ + template + static void Output(Orc::Text::Tree& node, const Orc::Command::Wolf::WolfExecution::Recipient& recipient) + { + std::vector ArchiveSpec; + auto archiveSpecs = boost::join(recipient.ArchiveSpec, L","); + if (archiveSpecs.empty()) + { + Print(node, recipient.Name); + } + else + { + Print(node, fmt::format(L"{} [{}]", recipient.Name, archiveSpecs)); + } + } +}; + +} // namespace Text +} // namespace Orc diff --git a/src/OrcCommand/RegInfo_Config.cpp b/src/OrcCommand/RegInfo_Config.cpp index efd08ab0..aa9b7557 100644 --- a/src/OrcCommand/RegInfo_Config.cpp +++ b/src/OrcCommand/RegInfo_Config.cpp @@ -241,12 +241,12 @@ HRESULT Main::CheckConfiguration() { config.m_HiveQuery.m_HivesLocation.Consolidate(false, FSVBR::FSType::NTFS); - if (config.Output.Type == OutputSpec::Kind::None) + if (HasFlag(config.Output.Type, OutputSpec::Kind::None)) { Log::Error("No valid output specified (only directory or csv|tsv are allowed"); return E_INVALIDARG; } - if (config.Output.Type & OutputSpec::Kind::Archive) + if (HasFlag(config.Output.Type, OutputSpec::Kind::Archive)) { Log::Error("Archive output is not supported (only directory or csv|tsv are allowed"); return E_INVALIDARG; diff --git a/src/OrcCommand/RegInfo_Run.cpp b/src/OrcCommand/RegInfo_Run.cpp index 108de7ad..6a4564c4 100644 --- a/src/OrcCommand/RegInfo_Run.cpp +++ b/src/OrcCommand/RegInfo_Run.cpp @@ -467,7 +467,7 @@ HRESULT Main::Run() std::shared_ptr pRegInfoWriter; - if (config.Output.Type & OutputSpec::Kind::TableFile) + if (HasFlag(config.Output.Type, OutputSpec::Kind::TableFile)) { pRegInfoWriter = GetRegInfoWriter(config.Output); if (nullptr == pRegInfoWriter) @@ -482,7 +482,7 @@ HRESULT Main::Run() { auto node = root.AddNode("Parsing hive '{}'", hive.FileName); - if (config.Output.Type & OutputSpec::Kind::Directory) + if (HasFlag(config.Output.Type, OutputSpec::Kind::Directory)) { std::wstring fileName(hive.FileName); std::replace(fileName.begin(), fileName.end(), L'\\', L'_'); diff --git a/src/OrcCommand/Usage.h b/src/OrcCommand/Usage.h index ff55eac0..29819d36 100644 --- a/src/OrcCommand/Usage.h +++ b/src/OrcCommand/Usage.h @@ -255,7 +255,7 @@ auto PrintColumnSelectionParameter( const ColumnNameDef* pCurCol = pColumnNames; while (pCurCol->dwIntention != Intentions::FILEINFO_NONE) { - if (pCurAlias->dwIntention & pCurCol->dwIntention) + if (HasFlag(pCurAlias->dwIntention, pCurCol->dwIntention)) { PrintValue(aliasNode, pCurCol->szColumnName, pCurCol->szColumnDesc); dwNumCol++; diff --git a/src/OrcCommand/UtilitiesLogger.cpp b/src/OrcCommand/UtilitiesLogger.cpp index f096edca..09d3cad0 100644 --- a/src/OrcCommand/UtilitiesLogger.cpp +++ b/src/OrcCommand/UtilitiesLogger.cpp @@ -11,51 +11,85 @@ #include +#include + +#ifdef ORC_BUILD_BOOST_STACKTRACE +# include +#endif + #include "UtilitiesLogger.h" #include "ParameterCheck.h" #include "Utils/Result.h" +using namespace Orc::Command; +using namespace Orc::Log; using namespace Orc; namespace { -std::shared_ptr CreateConsoleSink() +std::unique_ptr CreateSpdlogLogger(const std::string& name) +{ + auto logger = std::make_unique(name); + + // This is error handler will help to fix log formatting error + logger->SetErrorHandler([](const std::string& msg) { + std::cerr << msg << std::endl; + +#ifdef ORC_BUILD_BOOST_STACKTRACE + std::cerr << "Stack trace:" << std::endl; + std::cerr << boost::stacktrace::stacktrace(); +#endif + }); + + // Default upstream log level filter (sinks will not received filtered logs) + logger->SetLevel(spdlog::level::debug); + + return logger; +} + +std::shared_ptr CreateConsoleSink() { - auto console = std::make_shared(); - console->set_level(spdlog::level::critical); - return console; + auto sink = std::make_shared(); + sink->SetLevel(spdlog::level::critical); + return sink; } -std::shared_ptr CreateFileSink() +std::shared_ptr CreateFileSink() { - auto file = std::make_shared(); + auto sink = std::make_shared(); // Allow all logs to be print, they will be filtered by the upstream level set by spdlog::set_level - file->set_level(spdlog::level::trace); - return file; + sink->SetLevel(spdlog::level::trace); + return sink; } -std::pair, std::shared_ptr> -CreateFacilities(std::shared_ptr consoleSink, std::shared_ptr fileSink) +std::pair CreateFacilities(SpdlogSink::Ptr consoleSink, SpdlogSink::Ptr fileSink) { std::vector> loggers; - auto defaultLogger = std::make_shared("default", spdlog::sinks_init_list {consoleSink, fileSink}); + auto defaultLogger = ::CreateSpdlogLogger("default"); + defaultLogger->Add(consoleSink); + defaultLogger->Add(fileSink); + defaultLogger->EnableBacktrace(512); + defaultLogger->SetFormatter( + std::make_unique(Log::kDefaultLogPattern, spdlog::pattern_time_type::utc)); - auto fileLogger = std::make_shared("file", fileSink); - fileSink->set_level(spdlog::level::trace); // delegate filtering to the sink + auto fileLogger = ::CreateSpdlogLogger("file"); + fileLogger->Add(fileSink); + fileLogger->SetFormatter( + std::make_unique(Log::kDefaultLogPattern, spdlog::pattern_time_type::utc)); - return {defaultLogger, fileLogger}; + return {std::move(defaultLogger), std::move(fileLogger)}; } } // namespace Orc::Command::UtilitiesLogger::UtilitiesLogger() { - m_fileSink = CreateFileSink(); - m_consoleSink = CreateConsoleSink(); + m_fileSink = ::CreateFileSink(); + m_consoleSink = ::CreateConsoleSink(); - auto [defaultLogger, fileLogger] = CreateFacilities(m_consoleSink, m_fileSink); + auto [defaultLogger, fileLogger] = ::CreateFacilities(m_consoleSink, m_fileSink); auto loggers = { std::make_pair(Logger::Facility::kDefault, defaultLogger), @@ -152,6 +186,9 @@ void Orc::Command::UtilitiesLogger::Configure(int argc, const wchar_t* argv[]) c } } + // Load log levels from environment variable (ex: "SPDLOG_LEVEL=info,mylogger=trace") + spdlog::cfg::load_env_levels(); + if (verbose) { if (!level) @@ -159,11 +196,12 @@ void Orc::Command::UtilitiesLogger::Configure(int argc, const wchar_t* argv[]) c level = spdlog::level::debug; } - m_consoleSink->set_level(*level); + m_consoleSink->SetLevel(*level); } if (level) { - spdlog::set_level(*level); + m_logger->Get(Logger::Facility::kDefault)->SetLevel(*level); + m_logger->Get(Logger::Facility::kLogFile)->SetLevel(*level); } } diff --git a/src/OrcCommand/UtilitiesLogger.h b/src/OrcCommand/UtilitiesLogger.h index 734fb8f9..517664d1 100644 --- a/src/OrcCommand/UtilitiesLogger.h +++ b/src/OrcCommand/UtilitiesLogger.h @@ -11,15 +11,45 @@ #include "Log/Logger.h" +#include +#include "Log/Sink/FileSink.h" + #pragma managed(push, off) namespace Orc { - namespace Command { class UtilitiesLogger { public: + class ConsoleSink : public Log::SpdlogSink + { + public: + ConsoleSink() + : SpdlogSink(std::make_unique()) + { + } + }; + + class FileSink : public Log::SpdlogSink + { + public: + using FileSinkT = Log::FileSink; + + FileSink() + : SpdlogSink(std::make_unique()) + , m_fileSink(reinterpret_cast(m_sink.get())) + { + } + + void Open(const std::filesystem::path& path, std::error_code& ec) { m_fileSink->Open(path, ec); } + bool IsOpen() const { return m_fileSink->IsOpen(); } + void Close() { return m_fileSink->Close(); } + + private: + FileSinkT* m_fileSink; + }; + UtilitiesLogger(); ~UtilitiesLogger(); @@ -39,8 +69,8 @@ class UtilitiesLogger private: std::shared_ptr m_logger; - std::shared_ptr m_fileSink; - std::shared_ptr m_consoleSink; + std::shared_ptr m_fileSink; + std::shared_ptr m_consoleSink; }; } // namespace Command diff --git a/src/OrcCommand/UtilitiesMain.h b/src/OrcCommand/UtilitiesMain.h index 01cb2e9f..e2fee238 100644 --- a/src/OrcCommand/UtilitiesMain.h +++ b/src/OrcCommand/UtilitiesMain.h @@ -442,7 +442,7 @@ class ORCLIB_API UtilitiesMain HRESULT LoadEvtLibrary(); HRESULT LoadPSAPI(); - auto Configure(int argc, const wchar_t* argv[]) + virtual void Configure(int argc, const wchar_t* argv[]) { m_logging.Configure(argc, argv); diff --git a/src/OrcCommand/WolfExecution.h b/src/OrcCommand/WolfExecution.h index 71e3ab8a..70a947c9 100644 --- a/src/OrcCommand/WolfExecution.h +++ b/src/OrcCommand/WolfExecution.h @@ -175,12 +175,12 @@ class WolfExecution m_Temporary = temporary; m_JobStatisticsOutput = jobstats; - if (m_JobStatisticsOutput.Type & OutputSpec::Kind::TableFile) + if (HasFlag(m_JobStatisticsOutput.Type, OutputSpec::Kind::TableFile)) { m_JobStatisticsOutput.Path = m_Temporary.Path + L"\\" + m_JobStatisticsOutput.Path; } m_ProcessStatisticsOutput = processstats; - if (m_ProcessStatisticsOutput.Type & OutputSpec::Kind::TableFile) + if (HasFlag(m_ProcessStatisticsOutput.Type, OutputSpec::Kind::TableFile)) { m_ProcessStatisticsOutput.Path = m_Temporary.Path + L"\\" + m_ProcessStatisticsOutput.Path; } diff --git a/src/OrcCommand/WolfExecution_Config.cpp b/src/OrcCommand/WolfExecution_Config.cpp index 295f1ae9..11e87ba3 100644 --- a/src/OrcCommand/WolfExecution_Config.cpp +++ b/src/OrcCommand/WolfExecution_Config.cpp @@ -808,11 +808,15 @@ HRESULT WolfExecution::SetRepeatBehaviour(const Repeat behavior) return S_OK; } -HRESULT WolfExecution::SetCompressionLevel(const std::wstring& strCompressionLevel) +HRESULT WolfExecution::SetCompressionLevel(const std::wstring& level) { - if (strCompressionLevel.empty()) + if (level.empty()) + { + Log::Debug(L"Specified compression level is empty"); return S_OK; + } - m_strCompressionLevel = strCompressionLevel; + Log::Debug(L"Set compression level to {}", level); + m_strCompressionLevel = level; return S_OK; } diff --git a/src/OrcCommand/WolfExecution_Execute.cpp b/src/OrcCommand/WolfExecution_Execute.cpp index 3c948180..80a7946a 100644 --- a/src/OrcCommand/WolfExecution_Execute.cpp +++ b/src/OrcCommand/WolfExecution_Execute.cpp @@ -504,7 +504,7 @@ HRESULT WolfExecution::CreateCommandAgent( m_pTermination = std::make_shared(m_commandSet, this); Robustness::AddTerminationHandler(m_pTermination); - if (m_ProcessStatisticsOutput.Type & OutputSpec::Kind::TableFile) + if (HasFlag(m_ProcessStatisticsOutput.Type, OutputSpec::Kind::TableFile)) { m_ProcessStatisticsWriter = TableOutput::GetWriter(m_ProcessStatisticsOutput); @@ -514,7 +514,7 @@ HRESULT WolfExecution::CreateCommandAgent( } } - if (m_JobStatisticsOutput.Type & OutputSpec::Kind::TableFile) + if (HasFlag(m_JobStatisticsOutput.Type, OutputSpec::Kind::TableFile)) { m_JobStatisticsWriter = TableOutput::GetWriter(m_JobStatisticsOutput); if (m_JobStatisticsWriter == nullptr) @@ -741,8 +741,16 @@ HRESULT WolfExecution::TerminateAllAndComplete() HRESULT WolfExecution::CompleteArchive(UploadMessage::ITarget* pUploadMessageQueue) { HRESULT hr = E_FAIL; - m_ProcessStatisticsWriter->Close(); - m_JobStatisticsWriter->Close(); + + if (m_ProcessStatisticsWriter) + { + m_ProcessStatisticsWriter->Close(); + } + + if (m_JobStatisticsWriter) + { + m_JobStatisticsWriter->Close(); + } if (VerifyFileExists(m_ProcessStatisticsOutput.Path.c_str()) == S_OK) { @@ -818,6 +826,9 @@ HRESULT WolfExecution::CompleteArchive(UploadMessage::ITarget* pUploadMessageQue auto end = Orc::ConvertTo(m_ArchiveFinishTime); auto duration = end - start; + m_journal.Print( + GetKeyword(), L"Archive", L"Ended (output: {} bytes, elapsed: {:%T})", archiveSize(), duration); + Log::Info( L"{}: {} (took {} seconds, size {} bytes)", GetKeyword(), diff --git a/src/OrcCommand/WolfLauncher.h b/src/OrcCommand/WolfLauncher.h index 5698746c..7edde347 100644 --- a/src/OrcCommand/WolfLauncher.h +++ b/src/OrcCommand/WolfLauncher.h @@ -46,14 +46,17 @@ class ORCUTILS_API Main : public UtilitiesMain FromDump }; - enum WolfPriority + enum class WolfPriority { Low, Normal, High }; + static std::wstring ToString(WolfPriority value); + enum class WolfPowerState + { Unmodified = 0L, SystemRequired = ES_SYSTEM_REQUIRED, @@ -133,6 +136,8 @@ class ORCUTILS_API Main : public UtilitiesMain }; public: + void Configure(int argc, const wchar_t* argv[]) override; + static LPCWSTR ToolName() { return L"WolfLauncher"; } static LPCWSTR ToolDescription() { return L"DFIR-ORC command scheduler"; } diff --git a/src/OrcCommand/WolfLauncher_Config.cpp b/src/OrcCommand/WolfLauncher_Config.cpp index a983e4e6..ed03a321 100644 --- a/src/OrcCommand/WolfLauncher_Config.cpp +++ b/src/OrcCommand/WolfLauncher_Config.cpp @@ -379,11 +379,11 @@ HRESULT Main::GetLocalConfigurationFromConfig(const ConfigItem& configitem) if (configitem[ORC_PRIORITY]) { if (!_wcsicmp(L"Normal", configitem[ORC_PRIORITY].c_str())) - config.Priority = Normal; + config.Priority = WolfPriority::Normal; else if (!_wcsicmp(L"Low", configitem[ORC_PRIORITY].c_str())) - config.Priority = Low; + config.Priority = WolfPriority::Low; else if (!_wcsicmp(L"High", configitem[ORC_PRIORITY].c_str())) - config.Priority = High; + config.Priority = WolfPriority::High; } if (configitem[ORC_POWERSTATE]) @@ -499,11 +499,11 @@ HRESULT Main::GetConfigurationFromArgcArgv(int argc, LPCWSTR argv[]) else if (ParameterOption(argv[i] + 1, L"Priority", strPriority)) { if (!_wcsicmp(L"Normal", strPriority.c_str())) - config.Priority = Normal; + config.Priority = WolfPriority::Normal; else if (!_wcsicmp(L"Low", strPriority.c_str())) - config.Priority = Low; + config.Priority = WolfPriority::Low; else if (!_wcsicmp(L"High", strPriority.c_str())) - config.Priority = High; + config.Priority = WolfPriority::High; } else if (BooleanOption(argv[i] + 1, L"WERDontShowUI", config.bWERDontShowUI)) ; @@ -693,6 +693,8 @@ HRESULT Main::CheckConfiguration() if (!config.strCompressionLevel.empty()) { + Log::Debug( + L"Command has no compression level, using main compression level: {}", config.strCompressionLevel); wolfexec->SetCompressionLevel(config.strCompressionLevel); } diff --git a/src/OrcCommand/WolfLauncher_Output.cpp b/src/OrcCommand/WolfLauncher_Output.cpp index 88afff5b..9b3e5121 100644 --- a/src/OrcCommand/WolfLauncher_Output.cpp +++ b/src/OrcCommand/WolfLauncher_Output.cpp @@ -12,9 +12,11 @@ #include "SystemDetails.h" #include "ToolVersion.h" #include "Usage.h" +#include "Output/Text/Fmt/WolfPriority.h" #include "Output/Text/Print/OutputSpec.h" #include "Output/Text/Print/LocationSet.h" #include "Output/Text/Print/Bool.h" +#include "Output/Text/Print/Recipient.h" using namespace Orc::Command::Wolf; using namespace Orc::Text; @@ -24,6 +26,21 @@ namespace Orc { namespace Command { namespace Wolf { +std::wstring Main::ToString(WolfPriority value) +{ + switch (value) + { + case WolfPriority::Low: + return L"Low"; + case WolfPriority::Normal: + return L"Normal"; + case WolfPriority::High: + return L"High"; + default: + return L""; + } +} + std::wstring Main::ToString(Main::WolfPowerState value) { std::vector properties; @@ -33,22 +50,22 @@ std::wstring Main::ToString(Main::WolfPowerState value) return L""; } - if (value & Main::WolfPowerState::SystemRequired) + if (HasFlag(value, Main::WolfPowerState::SystemRequired)) { properties.push_back(L"SystemRequired"); } - if (value & Main::WolfPowerState::DisplayRequired) + if (HasFlag(value, Main::WolfPowerState::DisplayRequired)) { properties.push_back(L"DisplayRequired"); } - if (value & Main::WolfPowerState::UserPresent) + if (HasFlag(value, Main::WolfPowerState::UserPresent)) { properties.push_back(L"UserPresent"); } - if (value & Main::WolfPowerState::AwayMode) + if (HasFlag(value, Main::WolfPowerState::AwayMode)) { properties.push_back(L"AwayMode"); } @@ -153,7 +170,8 @@ void Main::PrintParameters() PrintValue(node, L"Outline file", config.Outline.Path); PrintValue(node, L"Priority", config.Priority); PrintValue(node, L"Power State", ToString(config.PowerState)); - PrintValue(node, L"Key selection", fmt::format(L"{}", boost::join(config.OnlyTheseKeywords, L", "))); + auto keySelection = boost::join(config.OnlyTheseKeywords, L", "); + PrintValue(node, L"Key selection", keySelection.empty() ? Text::kNoneW : keySelection); PrintValues(node, L"Enable keys", config.EnableKeywords); PrintValues(node, L"Disable keys", config.DisableKeywords); @@ -165,7 +183,7 @@ void Main::PrintFooter() m_console.PrintNewLine(); auto root = m_console.OutputTree(); - auto node = root.AddNode("Statistics"); + auto node = root.AddNode("DFIR-Orc WolfLauncher statistics"); PrintCommonFooter(node); m_console.PrintNewLine(); diff --git a/src/OrcCommand/WolfLauncher_Run.cpp b/src/OrcCommand/WolfLauncher_Run.cpp index 10bc80fe..3f0a40eb 100644 --- a/src/OrcCommand/WolfLauncher_Run.cpp +++ b/src/OrcCommand/WolfLauncher_Run.cpp @@ -106,6 +106,16 @@ namespace Wolf { const wchar_t kWolfLauncher[] = L"WolfLauncher"; +void Main::Configure(int argc, const wchar_t* argv[]) +{ + UtilitiesMain::Configure(argc, argv); + + // As WolfLauncher output is already kind of log journal, let's keep it and avoid Logger to add another timestamp + auto defaultLogger = m_logging.logger().Get(Logger::Facility::kDefault); + defaultLogger->SetLevel(m_logging.consoleSink()->Level()); + defaultLogger->SetPattern("%v"); +} + std::shared_ptr Main::GetRecipient(const std::wstring& strName) { const auto it = std::find_if( @@ -402,15 +412,15 @@ HRESULT Main::SetLauncherPriority(WolfPriority priority) { switch (priority) { - case Low: + case WolfPriority::Low: SetPriorityClass(GetCurrentProcess(), BELOW_NORMAL_PRIORITY_CLASS); SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL); break; - case Normal: + case WolfPriority::Normal: SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS); SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL); break; - case High: + case WolfPriority::High: SetPriorityClass(GetCurrentProcess(), ABOVE_NORMAL_PRIORITY_CLASS); SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL); break; @@ -576,6 +586,7 @@ HRESULT Main::Run_Execute() { auto [lock, console] = m_journal.Console(); + console.PrintNewLine(); auto commandSetNode = console.OutputTree().AddNode("Command set '{}'", exec->GetKeyword()); auto parametersNode = commandSetNode.AddNode("Parameters"); PrintValue( diff --git a/src/OrcCommand/WolfTask.cpp b/src/OrcCommand/WolfTask.cpp index 9c7b9a4f..ca67bf24 100644 --- a/src/OrcCommand/WolfTask.cpp +++ b/src/OrcCommand/WolfTask.cpp @@ -59,7 +59,6 @@ HRESULT WolfTask::ApplyNotification( break; case CommandNotification::Running: // Process is still running, checking if it hangs... - Log::Debug(L"Task {} is running (pid: {})", m_command, m_dwPID); { HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, static_cast(notification->GetProcessID())); diff --git a/src/OrcLib/Archive/7z/Archive7z.cpp b/src/OrcLib/Archive/7z/Archive7z.cpp index 2a5b6539..2930d262 100644 --- a/src/OrcLib/Archive/7z/Archive7z.cpp +++ b/src/OrcLib/Archive/7z/Archive7z.cpp @@ -107,12 +107,14 @@ Lib7zCompressionLevel ToLib7zLevel(CompressionLevel level) void SetCompressionLevel(const CComPtr& archiver, CompressionLevel level, std::error_code& ec) { + Log::Debug("Archive7z: SetCompressionLevel to {}", level); + CMyComPtr setProperties; HRESULT hr = archiver->QueryInterface(IID_ISetProperties, (void**)&setProperties); if (setProperties == nullptr) { ec.assign(hr, std::system_category()); - // TODO: spdlog::warn("Failed retrieve IID_ISetProperties: {}", ec.message()); + Log::Error("Failed to set compresion level on IID_ISetProperties [{}]", ec); return; } @@ -124,7 +126,7 @@ void SetCompressionLevel(const CComPtr& archiver, CompressionLevel if (FAILED(hr)) { ec.assign(hr, std::system_category()); - // TODO: spdlog::warn("Failed to set property: {}", ec.message()); + Log::Error("Failed to change compresion level while setting property [{}]", ec); return; } } @@ -168,14 +170,14 @@ void Archive7z::Compress( if (FAILED(hr)) { ec.assign(hr, std::system_category()); - // TODO: spdlog::debug("Failed to get IID_IOutArchive: {}", ec.message()); + Log::Error(L"Failed to retrieve IID_IOutArchive [{}]", ec); return; } ::SetCompressionLevel(archiver, m_compressionLevel, ec); if (ec) { - // TODO: spdlog::debug("Failed to update compression level"); + Log::Error(L"Failed to update compression level to {} [{}]", m_compressionLevel, ec); return; } @@ -186,7 +188,7 @@ void Archive7z::Compress( if (FAILED(hr)) { ec.assign(hr, std::system_category()); - // TODO: log::Error(_L_, hr, L"Temp archive stream cannot be read\r\n"); + Log::Error(L"Failed to read 'inputArchive' [{}]", ec); return; } @@ -194,7 +196,7 @@ void Archive7z::Compress( if (FAILED(hr)) { ec.assign(hr, std::system_category()); - // TODO: log::Error(_L_, hr, L"Failed to rewind Temp stream\r\n"); + Log::Error(L"Failed to seek input archive to the begining [{}]", ec); return; } @@ -205,7 +207,7 @@ void Archive7z::Compress( if (FAILED(hr)) { ec.assign(hr, std::system_category()); - // TODO: log::Error(_L_, hr, L"Failed to open archive stream\r\n"); + Log::Error(L"Failed to open input archive [{}]", ec); return; } @@ -213,6 +215,7 @@ void Archive7z::Compress( if (FAILED(hr)) { ec.assign(hr, std::system_category()); + Log::Error(L"Failed to retrieve number of items [{}]", ec); return; } } @@ -229,7 +232,7 @@ void Archive7z::Compress( if (FAILED(hr)) { ec.assign(hr, std::system_category()); - // TODO: spdlog::debug("Failed to compress: {}", ec.message()); + Log::Error("Failed to update archive [{}]", ec); return; } diff --git a/src/OrcLib/Archive/7z/ArchiveUpdateCallback.cpp b/src/OrcLib/Archive/7z/ArchiveUpdateCallback.cpp index 031c990b..869878fd 100644 --- a/src/OrcLib/Archive/7z/ArchiveUpdateCallback.cpp +++ b/src/OrcLib/Archive/7z/ArchiveUpdateCallback.cpp @@ -11,8 +11,10 @@ #include "Archive/7z/ArchiveUpdateCallback.h" #include "Archive/7z/InStreamAdapter.h" +#include "Utils/Result.h" using namespace Orc::Archive; +using namespace Orc; namespace { @@ -25,7 +27,7 @@ FILETIME NowTimestamp() BOOL ret = SystemTimeToFileTime(&st, &ft); if (ret == FALSE) { - // TODO: add log + Log::Error("Failed to convert SystemTime to FileTime [{}]", LastWin32Error()); return {0}; } @@ -34,6 +36,9 @@ FILETIME NowTimestamp() } // namespace +namespace Orc { +namespace Archive { + ArchiveUpdateCallback::ArchiveUpdateCallback(Items items, std::wstring password, uint64_t numberOfInputArchiveItems) : m_newItems(std::move(items)) , m_password(std::move(password)) @@ -235,7 +240,7 @@ STDMETHODIMP ArchiveUpdateCallback::SetOperationResult(Int32 operationResult) if (operationResult != NArchive::NUpdate::NOperationResult::kOK) { - // TODO: add log + Log::Error("Failure code for operation result"); m_ec.assign(E_FAIL, std::system_category()); } @@ -280,3 +285,6 @@ STDMETHODIMP ArchiveUpdateCallback::CryptoGetTextPassword2(Int32* pPasswordIsDef return S_OK; } + +} // namespace Archive +} // namespace Orc diff --git a/src/OrcLib/Archive/Appender.h b/src/OrcLib/Archive/Appender.h index 8039b3e7..b7a4b536 100644 --- a/src/OrcLib/Archive/Appender.h +++ b/src/OrcLib/Archive/Appender.h @@ -44,6 +44,7 @@ class Appender const auto tempPath = GetTempPathApi(ec); if (ec) { + Log::Error("Failed to get temporary path [{}]", ec); return {}; } @@ -51,6 +52,7 @@ class Appender if (FAILED(hr)) { ec.assign(hr, std::system_category()); + Log::Error(L"Failed to open temporary path {} [{}]", tempPath, ec); return {}; } } @@ -71,15 +73,7 @@ class Appender , m_tempStreams({std::move(tempStream1), std::move(tempStream2)}) , m_srcStreamIndex(0) , m_isFirstFlush(true) - , m_compressionLevel(m_archiver.CompressionLevel()) { - // Put some low compression until the final call from 'Close' method - std::error_code ec; - m_archiver.SetCompressionLevel(CompressionLevel::kFastest, ec); - if (ec) - { - // TODO: add log - } } void Add(std::unique_ptr item) { m_archiver.Add(std::move(item)); } @@ -106,6 +100,7 @@ class Appender m_archiver.Compress(dstStream, srcStream, ec); if (ec) { + Log::Error("Failed to compress stream [{}]", ec); return; } @@ -113,6 +108,7 @@ class Appender if (FAILED(hr)) { ec.assign(hr, std::system_category()); + Log::Error("Failed to seek source stream [{}]", ec); return; } @@ -120,6 +116,7 @@ class Appender if (FAILED(hr)) { ec.assign(hr, std::system_category()); + Log::Error("Failed to resize source stream [{}]", ec); return; } @@ -128,15 +125,10 @@ class Appender void Close(std::error_code& ec) { - m_archiver.SetCompressionLevel(m_compressionLevel, ec); - if (ec) - { - return; - } - Flush(ec); if (ec) { + Log::Error("Failed to flush stream [{}]", ec); return; } @@ -144,8 +136,8 @@ class Appender HRESULT hr = tempStream->MoveTo(m_output.c_str()); if (FAILED(hr)) { - // TODO: add log ec.assign(hr, std::system_category()); + Log::Error(L"Failed to move stream to {} [{}]", m_output, ec); return; } } @@ -158,7 +150,6 @@ class Appender const std::array, 2> m_tempStreams; uint8_t m_srcStreamIndex; bool m_isFirstFlush; - CompressionLevel m_compressionLevel; }; } // namespace Archive diff --git a/src/OrcLib/CMakeLists.txt b/src/OrcLib/CMakeLists.txt index 80fba566..9dc20aae 100644 --- a/src/OrcLib/CMakeLists.txt +++ b/src/OrcLib/CMakeLists.txt @@ -651,13 +651,15 @@ set(SRC_INOUT_UPLOAD source_group(In&Out\\Upload FILES ${SRC_INOUT_UPLOAD}) set(SRC_LOG - "Log/ByteStreamSink.h" - "Log/FileSink.h" + "Log/Sink/FileSink.h" + "Log/Sink/MemorySink.h" "Log/Log.cpp" "Log/Log.h" "Log/Logger.cpp" "Log/Logger.h" - "Log/MemorySink.h" + "Log/SpdlogLogger.h" + "Log/SpdlogLogger.cpp" + "Log/SpdlogSink.h" ) source_group(Log FILES ${SRC_LOG}) diff --git a/src/OrcLib/CommandAgent.cpp b/src/OrcLib/CommandAgent.cpp index 98eee685..b1b85b0b 100644 --- a/src/OrcLib/CommandAgent.cpp +++ b/src/OrcLib/CommandAgent.cpp @@ -1004,8 +1004,6 @@ void CommandAgent::run() } break; case CommandMessage::RefreshRunningList: { - Log::Debug("CommandAgent: Refreshing running command list"); - Concurrency::critical_section::scoped_lock s(m_cs); auto new_end = std::remove_if( m_RunningCommands.begin(), diff --git a/src/OrcLib/CryptoHashStream.cpp b/src/OrcLib/CryptoHashStream.cpp index 08ef34d6..3d5b16d8 100644 --- a/src/OrcLib/CryptoHashStream.cpp +++ b/src/OrcLib/CryptoHashStream.cpp @@ -102,18 +102,18 @@ HRESULT CryptoHashStream::ResetHash(bool bContinue) } m_bHashIsValid = true; - if ((m_Algorithms & Algorithm::MD5) && !CryptCreateHash(g_hProv, CALG_MD5, 0, 0, &m_MD5)) + if (HasFlag(m_Algorithms, Algorithm::MD5) && !CryptCreateHash(g_hProv, CALG_MD5, 0, 0, &m_MD5)) { hr = HRESULT_FROM_WIN32(GetLastError()); Log::Debug(L"Failed to initialise MD5 hash [{}]", SystemError(hr)); } - if ((m_Algorithms & Algorithm::SHA1) && !CryptCreateHash(g_hProv, CALG_SHA1, 0, 0, &m_Sha1)) + if (HasFlag(m_Algorithms, Algorithm::SHA1) && !CryptCreateHash(g_hProv, CALG_SHA1, 0, 0, &m_Sha1)) { hr = HRESULT_FROM_WIN32(GetLastError()); Log::Debug(L"Failed to initialise SHA1 hash [{}]", SystemError(hr)); } - if ((m_Algorithms & Algorithm::SHA256) && !CryptCreateHash(g_hProv, CALG_SHA_256, 0, 0, &m_Sha256)) + if (HasFlag(m_Algorithms, Algorithm::SHA256) && !CryptCreateHash(g_hProv, CALG_SHA_256, 0, 0, &m_Sha256)) { hr = HRESULT_FROM_WIN32(GetLastError()); Log::Debug(L"Failed to initialise SHA256 hash [{}]", SystemError(hr)); @@ -227,18 +227,18 @@ std::wstring CryptoHashStream::GetSupportedAlgorithm(Algorithm algs) retval.reserve(16); - if (algs & Algorithm::MD5) + if (HasFlag(algs, Algorithm::MD5)) { retval.append(L"MD5"sv); } - if (algs & Algorithm::SHA1) + if (HasFlag(algs, Algorithm::SHA1)) { if (retval.empty()) retval.append(L"SHA1"sv); else retval.append(L",SHA1"sv); } - if (algs & Algorithm::SHA256) + if (HasFlag(algs, Algorithm::SHA256)) { if (retval.empty()) retval.append(L"SHA256"sv); diff --git a/src/OrcLib/CsvFileWriter.h b/src/OrcLib/CsvFileWriter.h index e0eba1ca..1fd64c97 100644 --- a/src/OrcLib/CsvFileWriter.h +++ b/src/OrcLib/CsvFileWriter.h @@ -310,9 +310,9 @@ class ORCLIB_API Writer return E_INVALIDARG; } + // Flush when buffer is over 80% of its capacity if (m_buffer.size() > (80 * m_buffer.capacity() / 100)) { - // Flush cache buffer 'm_pBuffer' first then process the one allocated for formatting if (auto hr = Flush(); FAILED(hr)) { return hr; diff --git a/src/OrcLib/FileFind.cpp b/src/OrcLib/FileFind.cpp index 7aa847f4..2fa23f99 100644 --- a/src/OrcLib/FileFind.cpp +++ b/src/OrcLib/FileFind.cpp @@ -3496,11 +3496,11 @@ HRESULT FileFind::ComputeMatchHashes(const std::shared_ptr& aMatch) for (auto& attr_match : aMatch->MatchingAttributes) { CryptoHashStream::Algorithm needed = CryptoHashStream::Algorithm::Undefined; - if (m_MatchHash & CryptoHashStream::Algorithm::MD5 && attr_match.MD5.empty()) + if (HasFlag(m_MatchHash, CryptoHashStream::Algorithm::MD5) && attr_match.MD5.empty()) needed |= CryptoHashStream::Algorithm::MD5; - if (m_MatchHash & CryptoHashStream::Algorithm::SHA1 && attr_match.SHA1.empty()) + if (HasFlag(m_MatchHash, CryptoHashStream::Algorithm::SHA1) && attr_match.SHA1.empty()) needed |= CryptoHashStream::Algorithm::SHA1; - if (m_MatchHash & CryptoHashStream::Algorithm::SHA256 && attr_match.SHA256.empty()) + if (HasFlag(m_MatchHash, CryptoHashStream::Algorithm::SHA256) && attr_match.SHA256.empty()) needed |= CryptoHashStream::Algorithm::SHA256; if (needed != CryptoHashStream::Algorithm::Undefined) @@ -3525,19 +3525,19 @@ HRESULT FileFind::ComputeMatchHashes(const std::shared_ptr& aMatch) if (ullWritten > 0) { - if (needed & CryptoHashStream::Algorithm::MD5 + if (HasFlag(needed, CryptoHashStream::Algorithm::MD5) && FAILED(hr = hashstream->GetHash(CryptoHashStream::Algorithm::MD5, attr_match.MD5))) { if (hr != MK_E_UNAVAILABLE) return hr; } - if (needed & CryptoHashStream::Algorithm::SHA1 + if (HasFlag(needed, CryptoHashStream::Algorithm::SHA1) && FAILED(hr = hashstream->GetHash(CryptoHashStream::Algorithm::SHA1, attr_match.SHA1))) { if (hr != MK_E_UNAVAILABLE) return hr; } - if (needed & CryptoHashStream::Algorithm::SHA256 + if (HasFlag(needed, CryptoHashStream::Algorithm::SHA256) && FAILED(hr = hashstream->GetHash(CryptoHashStream::Algorithm::SHA256, attr_match.SHA256))) { if (hr != MK_E_UNAVAILABLE) diff --git a/src/OrcLib/FileInfo.cpp b/src/OrcLib/FileInfo.cpp index cf65d0cb..1559d09d 100644 --- a/src/OrcLib/FileInfo.cpp +++ b/src/OrcLib/FileInfo.cpp @@ -269,7 +269,7 @@ HRESULT FileInfo::WriteFileInformation( try { - if (localIntentions & pCurCol->dwIntention) + if (HasFlag(localIntentions, pCurCol->dwIntention)) { if (FAILED(hr = HandleIntentions(pCurCol->dwIntention, output))) { @@ -413,7 +413,7 @@ HRESULT FileInfo::BindColumns( while (pCurCol->dwIntention != Intentions::FILEINFO_NONE) { - if (dwIntentions & pCurCol->dwIntention) + if (HasFlag(dwIntentions, pCurCol->dwIntention)) { dwIndex++; @@ -451,7 +451,7 @@ DWORD FileInfo::GetRequiredAccessMask(const ColumnNameDef columnNames[]) const ColumnNameDef* pCurCol = columnNames; while (pCurCol->dwIntention != Intentions::FILEINFO_NONE) { - if (m_DefaultIntentions & pCurCol->dwIntention) + if (HasFlag(m_DefaultIntentions, pCurCol->dwIntention)) dwRequiredAccess |= pCurCol->dwRequiredAccess; pCurCol++; } @@ -460,7 +460,7 @@ DWORD FileInfo::GetRequiredAccessMask(const ColumnNameDef columnNames[]) const ColumnNameDef* pCurCol = columnNames; while (pCurCol->dwIntention != Intentions::FILEINFO_NONE) { - if (filter.intent & pCurCol->dwIntention) + if (HasFlag(filter.intent, pCurCol->dwIntention)) dwRequiredAccess |= pCurCol->dwRequiredAccess; pCurCol++; } @@ -559,14 +559,15 @@ HRESULT FileInfo::OpenHash() Intentions localIntentions = FilterIntentions(m_Filters); - if (localIntentions & Intentions::FILEINFO_MD5 || localIntentions & Intentions::FILEINFO_SHA1 - || localIntentions & Intentions::FILEINFO_SHA256 || localIntentions & Intentions::FILEINFO_SSDEEP - || localIntentions & Intentions::FILEINFO_TLSH) + if (HasAnyFlag( + localIntentions, + Intentions::FILEINFO_MD5 | Intentions::FILEINFO_SHA1 | Intentions::FILEINFO_SHA256 + | Intentions::FILEINFO_SSDEEP | Intentions::FILEINFO_TLSH)) { - if (localIntentions & Intentions::FILEINFO_PE_MD5 || localIntentions & Intentions::FILEINFO_PE_SHA1 - || localIntentions & Intentions::FILEINFO_PE_SHA256 - || localIntentions & Intentions::FILEINFO_AUTHENTICODE_STATUS - || localIntentions & Intentions::FILEINFO_AUTHENTICODE_SIGNER) + if (HasAnyFlag( + localIntentions, + Intentions::FILEINFO_PE_MD5 | Intentions::FILEINFO_PE_SHA1 | Intentions::FILEINFO_PE_SHA256 + | Intentions::FILEINFO_AUTHENTICODE_STATUS | Intentions::FILEINFO_AUTHENTICODE_SIGNER)) { if (FAILED(hr = m_PEInfo.CheckPEInformation())) return hr; @@ -578,11 +579,10 @@ HRESULT FileInfo::OpenHash() else return OpenCryptoAndFuzzyHash(localIntentions); } - else if ( - localIntentions & Intentions::FILEINFO_PE_MD5 || localIntentions & Intentions::FILEINFO_PE_SHA1 - || localIntentions & Intentions::FILEINFO_PE_SHA256 - || localIntentions & Intentions::FILEINFO_AUTHENTICODE_STATUS - || localIntentions & Intentions::FILEINFO_AUTHENTICODE_SIGNER) + else if (HasAnyFlag( + localIntentions, + Intentions::FILEINFO_PE_MD5 | Intentions::FILEINFO_PE_SHA1 | Intentions::FILEINFO_PE_SHA256 + | Intentions::FILEINFO_AUTHENTICODE_STATUS | Intentions::FILEINFO_AUTHENTICODE_SIGNER)) { if (FAILED(hr = m_PEInfo.CheckPEInformation())) return hr; @@ -600,11 +600,11 @@ HRESULT FileInfo::OpenCryptoHash(Intentions localIntentions) return S_OK; CryptoHashStream::Algorithm algs = CryptoHashStream::Algorithm::Undefined; - if (localIntentions & Intentions::FILEINFO_MD5) + if (HasFlag(localIntentions, Intentions::FILEINFO_MD5)) algs |= CryptoHashStream::Algorithm::MD5; - if (localIntentions & Intentions::FILEINFO_SHA1) + if (HasFlag(localIntentions, Intentions::FILEINFO_SHA1)) algs |= CryptoHashStream::Algorithm::SHA1; - if (localIntentions & Intentions::FILEINFO_SHA256) + if (HasFlag(localIntentions, Intentions::FILEINFO_SHA256)) algs |= CryptoHashStream::Algorithm::SHA256; auto stream = GetDetails()->GetDataStream(); @@ -627,19 +627,19 @@ HRESULT FileInfo::OpenCryptoHash(Intentions localIntentions) if (ullWritten > 0) { - if (algs & CryptoHashStream::Algorithm::MD5 + if (HasFlag(algs, CryptoHashStream::Algorithm::MD5) && FAILED(hr = hashstream->GetHash(CryptoHashStream::Algorithm::MD5, GetDetails()->MD5()))) { if (hr != MK_E_UNAVAILABLE) return hr; } - if (algs & CryptoHashStream::Algorithm::SHA1 + if (HasFlag(algs, CryptoHashStream::Algorithm::SHA1) && FAILED(hr = hashstream->GetHash(CryptoHashStream::Algorithm::SHA1, GetDetails()->SHA1()))) { if (hr != MK_E_UNAVAILABLE) return hr; } - if (algs & CryptoHashStream::Algorithm::SHA256 + if (HasFlag(algs, CryptoHashStream::Algorithm::SHA256) && FAILED(hr = hashstream->GetHash(CryptoHashStream::Algorithm::SHA256, GetDetails()->SHA256()))) { if (hr != MK_E_UNAVAILABLE) @@ -658,9 +658,9 @@ HRESULT FileInfo::OpenFuzzyHash(Intentions localIntentions) return S_OK; FuzzyHashStream::Algorithm algs = FuzzyHashStream::Algorithm::Undefined; - if (localIntentions & Intentions::FILEINFO_SSDEEP) + if (HasFlag(localIntentions, Intentions::FILEINFO_SSDEEP)) algs |= FuzzyHashStream::Algorithm::SSDeep; - if (localIntentions & Intentions::FILEINFO_TLSH) + if (HasFlag(localIntentions, Intentions::FILEINFO_TLSH)) algs |= FuzzyHashStream::Algorithm::TLSH; auto stream = GetDetails()->GetDataStream(); @@ -683,7 +683,7 @@ HRESULT FileInfo::OpenFuzzyHash(Intentions localIntentions) if (ullWritten > 0) { - if (algs & FuzzyHashStream::Algorithm::SSDeep) + if (HasFlag(algs, FuzzyHashStream::Algorithm::SSDeep)) { hr = hashstream->GetHash(FuzzyHashStream::Algorithm::SSDeep, GetDetails()->SSDeep()); if (FAILED(hr) && hr != MK_E_UNAVAILABLE) @@ -692,7 +692,7 @@ HRESULT FileInfo::OpenFuzzyHash(Intentions localIntentions) } } - if (algs & FuzzyHashStream::Algorithm::TLSH) + if (HasFlag(algs, FuzzyHashStream::Algorithm::TLSH)) { hr = hashstream->GetHash(FuzzyHashStream::Algorithm::TLSH, GetDetails()->TLSH()); if (FAILED(hr) && hr != MK_E_UNAVAILABLE) @@ -713,17 +713,17 @@ HRESULT FileInfo::OpenCryptoAndFuzzyHash(Intentions localIntentions) return S_OK; CryptoHashStream::Algorithm crypto_algs = CryptoHashStream::Algorithm::Undefined; - if (localIntentions & Intentions::FILEINFO_MD5) + if (HasFlag(localIntentions, Intentions::FILEINFO_MD5)) crypto_algs |= CryptoHashStream::Algorithm::MD5; - if (localIntentions & Intentions::FILEINFO_SHA1) + if (HasFlag(localIntentions, Intentions::FILEINFO_SHA1)) crypto_algs |= CryptoHashStream::Algorithm::SHA1; - if (localIntentions & Intentions::FILEINFO_SHA256) + if (HasFlag(localIntentions, Intentions::FILEINFO_SHA256)) crypto_algs |= CryptoHashStream::Algorithm::SHA256; FuzzyHashStream::Algorithm fuzzy_algs = FuzzyHashStream::Algorithm::Undefined; - if (localIntentions & Intentions::FILEINFO_SSDEEP) + if (HasFlag(localIntentions, Intentions::FILEINFO_SSDEEP)) fuzzy_algs |= FuzzyHashStream::Algorithm::SSDeep; - if (localIntentions & Intentions::FILEINFO_TLSH) + if (HasFlag(localIntentions, Intentions::FILEINFO_TLSH)) fuzzy_algs |= FuzzyHashStream::Algorithm::TLSH; auto stream = GetDetails()->GetDataStream(); @@ -767,33 +767,33 @@ HRESULT FileInfo::OpenCryptoAndFuzzyHash(Intentions localIntentions) if (ullWritten > 0) { - if (crypto_algs & CryptoHashStream::Algorithm::MD5 + if (HasFlag(crypto_algs, CryptoHashStream::Algorithm::MD5) && FAILED(hr = crypto_hashstream->GetHash(CryptoHashStream::Algorithm::MD5, GetDetails()->MD5()))) { if (hr != MK_E_UNAVAILABLE) return hr; } - if (crypto_algs & CryptoHashStream::Algorithm::SHA1 + if (HasFlag(crypto_algs, CryptoHashStream::Algorithm::SHA1) && FAILED(hr = crypto_hashstream->GetHash(CryptoHashStream::Algorithm::SHA1, GetDetails()->SHA1()))) { if (hr != MK_E_UNAVAILABLE) return hr; } - if (crypto_algs & CryptoHashStream::Algorithm::SHA256 + if (HasFlag(crypto_algs, CryptoHashStream::Algorithm::SHA256) && FAILED(hr = crypto_hashstream->GetHash(CryptoHashStream::Algorithm::SHA256, GetDetails()->SHA256()))) { if (hr != MK_E_UNAVAILABLE) return hr; } #ifdef ORC_BUILD_SSDEEP - if (fuzzy_algs & FuzzyHashStream::Algorithm::SSDeep + if (HasFlag(fuzzy_algs, FuzzyHashStream::Algorithm::SSDeep) && FAILED(hr = fuzzy_hashstream->GetHash(FuzzyHashStream::Algorithm::SSDeep, GetDetails()->SSDeep()))) { if (hr != MK_E_UNAVAILABLE) return hr; } #endif - if (fuzzy_algs & FuzzyHashStream::Algorithm::TLSH + if (HasFlag(fuzzy_algs, FuzzyHashStream::Algorithm::TLSH) && FAILED(hr = fuzzy_hashstream->GetHash(FuzzyHashStream::Algorithm::TLSH, GetDetails()->TLSH()))) { if (hr != MK_E_UNAVAILABLE) diff --git a/src/OrcLib/FileStream.cpp b/src/OrcLib/FileStream.cpp index 41746b5a..2f999ad5 100644 --- a/src/OrcLib/FileStream.cpp +++ b/src/OrcLib/FileStream.cpp @@ -244,8 +244,6 @@ __data_entrypoint(File) HRESULT FileStream::Read( return hr; } - Log::Trace(L"ReadFile read {} bytes (hFile: {:p})", dwBytesRead, m_hFile); - *pcbBytesRead = dwBytesRead; return S_OK; } @@ -279,7 +277,6 @@ FileStream::Write(__in_bcount(cbBytes) const PVOID pBuffer, __in ULONGLONG cbByt return hr; } - Log::Trace("WriteFile {} bytes succeeded (hFile: {:p})", cbBytesWritten, m_hFile); *pcbBytesWritten = cbBytesWritten; return S_OK; } diff --git a/src/OrcLib/FuzzyHashStream.cpp b/src/OrcLib/FuzzyHashStream.cpp index 17f0cfa0..33b17568 100644 --- a/src/OrcLib/FuzzyHashStream.cpp +++ b/src/OrcLib/FuzzyHashStream.cpp @@ -46,7 +46,7 @@ std::wstring FuzzyHashStream::GetSupportedAlgorithm(Algorithm algs) retval.append(L"SSDeep"); } #endif // ORC_BUILD_SSDEEP - if (algs & FuzzyHashStream::Algorithm::TLSH) + if (HasFlag(algs, FuzzyHashStream::Algorithm::TLSH)) { if (retval.empty()) retval.append(L"TLSH"); @@ -128,7 +128,7 @@ HRESULT FuzzyHashStream::ResetHash(bool bContinue) } #endif // ORC_BUILD_SSDEEP - if (m_Algorithms & FuzzyHashStream::Algorithm::TLSH) + if (HasFlag(m_Algorithms, FuzzyHashStream::Algorithm::TLSH)) { m_tlsh = std::make_unique(); } @@ -173,7 +173,7 @@ HRESULT FuzzyHashStream::GetHash(FuzzyHashStream::Algorithm alg, CBinaryBuffer& #endif // ORC_BUILD_SSDEEP break; case FuzzyHashStream::Algorithm::TLSH: - if (m_Algorithms & FuzzyHashStream::Algorithm::TLSH && m_tlsh) + if (HasFlag(m_Algorithms, FuzzyHashStream::Algorithm::TLSH) && m_tlsh) { if (!m_tlsh->isValid()) { diff --git a/src/OrcLib/Log/ByteStreamSink.h b/src/OrcLib/Log/ByteStreamSink.h deleted file mode 100644 index 8e0ea743..00000000 --- a/src/OrcLib/Log/ByteStreamSink.h +++ /dev/null @@ -1,66 +0,0 @@ -// -// SPDX-License-Identifier: LGPL-2.1-or-later -// -// Copyright © 2020 ANSSI. All Rights Reserved. -// -// Author(s): fabienfl -// - -// -// WARNING: This sink requires the ByteStream to avoid calling any spdlog method -// that would provoke an endless recursion. -// - -#pragma once - -#include - -#include -#include - -#include "ByteStream.h" - -template -class ByteStreamSink : public spdlog::sinks::base_sink -{ -public: - ByteStreamSink() {} - - ByteStreamSink(std::shared_ptr stream) - : m_byteStream(std::move(stream)) - { - } - - void SetStream(std::shared_ptr stream) { m_stream = std::move(stream); } - - void CloseStream() - { - auto stream = std::move(m_stream); - m_stream.reset(); - stream->Close(); - } - - const std::shared_ptr& stream() { return m_stream; } - -protected: - void sink_it_(const spdlog::details::log_msg& msg) override - { - if (m_stream == nullptr) - { - return; - } - - spdlog::memory_buf_t formatted; - base_sink::formatter_->format(msg, formatted); - const std::string buffer = fmt::to_string(formatted); - - ULONGLONG cbWritten = 0; - HRESULT hr = m_stream->Write((const PVOID)(buffer.data()), buffer.size(), &cbWritten); - _ASSERT(SUCCEEDED(hr) && cbWritten == buffer.size()); - } - - void flush_() override { return; } - -private: - std::shared_ptr m_stream; -}; diff --git a/src/OrcLib/Log/Logger.cpp b/src/OrcLib/Log/Logger.cpp index 80fc54a1..c09272b8 100644 --- a/src/OrcLib/Log/Logger.cpp +++ b/src/OrcLib/Log/Logger.cpp @@ -19,41 +19,19 @@ #include -#ifdef ORC_BUILD_BOOST_STACKTRACE -# include -#endif +#include "Log/Sink/FileSink.h" +#include "Log/Sink/MemorySink.h" +using namespace Orc::Log; using namespace Orc; -namespace { - -std::shared_ptr CreateConsoleSink() -{ - auto console = std::make_shared(); - console->set_level(spdlog::level::critical); - return console; -} - -std::shared_ptr CreateFileSink() -{ - auto file = std::make_shared(); - - // Allow all logs to be print, they will be filtered by the upstream level set by spdlog::set_level - file->set_level(spdlog::level::trace); - return file; -} - -} // namespace - -namespace Orc { - -Logger::Logger(std::initializer_list>> loggers) +Logger::Logger(std::initializer_list> loggers) : m_warningCount(0) , m_errorCount(0) , m_criticalCount(0) { auto facility_count = std::underlying_type_t(Facility::kFacilityCount); - m_loggers.resize(facility_count); + m_loggers.resize(facility_count - 1); for (auto&& [facility, logger] : loggers) { @@ -65,27 +43,11 @@ Logger::Logger(std::initializer_listSetAsDefaultLogger(); + } } uint64_t Logger::warningCount() const @@ -103,30 +65,7 @@ uint64_t Logger::criticalCount() const return m_criticalCount; } -// TODO: This feature is only supported by default logger. To be able to use a backtrace with multiple loggers a -// dedicated sink should be done so all logs would be automatically sorted. -void Logger::DumpBacktrace() -{ - const auto& sinks = Get(Facility::kDefault)->sinks(); - - std::vector levels; - for (size_t i = 0; i < sinks.size(); ++i) - { - levels.push_back(sinks[i]->level()); - - // set trace level to ensure the stack of logs will be displayed even if configurated level would be too high - sinks[i]->set_level(spdlog::level::trace); - } - - spdlog::dump_backtrace(); - - for (size_t i = 0; i < sinks.size(); ++i) - { - sinks[i]->set_level(levels[i]); - } -} - -void Logger::Set(Facility id, std::shared_ptr logger) +void Logger::Set(Facility id, SpdlogLogger::Ptr logger) { const auto facilityNum = std::underlying_type_t(id); if (m_loggers.size() <= facilityNum) @@ -134,7 +73,5 @@ void Logger::Set(Facility id, std::shared_ptr logger) m_loggers.resize(facilityNum + 1); } - m_loggers[facilityNum] = logger; + m_loggers[facilityNum] = std::move(logger); } - -} // namespace Orc diff --git a/src/OrcLib/Log/Logger.h b/src/OrcLib/Log/Logger.h index fc138a82..64bd3427 100644 --- a/src/OrcLib/Log/Logger.h +++ b/src/OrcLib/Log/Logger.h @@ -13,12 +13,11 @@ #include #include -#include -#include "Log/MemorySink.h" -#include "Log/FileSink.h" +#include "SpdlogLogger.h" namespace Orc { +namespace Log { /*! * \brief Wrapper over spdlog that dispatches logging on spdlog::logger. @@ -29,9 +28,6 @@ namespace Orc { class Logger { public: - using ConsoleSink = spdlog::sinks::wincolor_stderr_sink_mt; - using FileSink = FileSink; - enum class Facility : size_t { kDefault = 0, @@ -40,18 +36,16 @@ class Logger kFacilityCount }; - Logger(std::initializer_list>> loggers); + Logger(std::initializer_list> loggers); uint64_t warningCount() const; uint64_t errorCount() const; uint64_t criticalCount() const; - void DumpBacktrace(); - template void Trace(Facility id, Args&&... args) { - Get(id)->trace(std::forward(args)...); + Get(id)->Trace(std::forward(args)...); } template @@ -63,7 +57,7 @@ class Logger template void Debug(Facility id, Args&&... args) { - Get(id)->debug(std::forward(args)...); + Get(id)->Debug(std::forward(args)...); } template @@ -75,7 +69,7 @@ class Logger template void Info(Facility id, Args&&... args) { - Get(id)->info(std::forward(args)...); + Get(id)->Info(std::forward(args)...); } template @@ -87,7 +81,7 @@ class Logger template void Warn(Facility id, Args&&... args) { - Get(id)->warn(std::forward(args)...); + Get(id)->Warn(std::forward(args)...); ++m_warningCount; } @@ -100,7 +94,7 @@ class Logger template void Error(Facility id, Args&&... args) { - Get(id)->error(std::forward(args)...); + Get(id)->Error(std::forward(args)...); ++m_errorCount; } @@ -113,10 +107,14 @@ class Logger template void Critical(Facility id, Args&&... args) { - Get(id)->critical(std::forward(args)...); + Get(id)->Critical(std::forward(args)...); ++m_criticalCount; - DumpBacktrace(); + auto defaultLogger = Get(Facility::kDefault); + if (defaultLogger) + { + defaultLogger->DumpBacktrace(); + } } template @@ -125,7 +123,7 @@ class Logger Critical(Facility::kDefault, std::forward(args)...); } - const std::shared_ptr& Get(Facility id) const + const SpdlogLogger::Ptr& Get(Facility id) const { const auto facilityNumber = std::underlying_type_t(id); @@ -136,14 +134,18 @@ class Logger return logger; } - void Set(Facility id, std::shared_ptr logger); + void Set(Facility id, SpdlogLogger::Ptr logger); private: - std::vector> m_loggers; + std::vector m_loggers; std::atomic m_warningCount; std::atomic m_errorCount; std::atomic m_criticalCount; }; +} // namespace Log + +using Logger = Orc::Log::Logger; + } // namespace Orc diff --git a/src/OrcLib/Log/FileSink.h b/src/OrcLib/Log/Sink/FileSink.h similarity index 52% rename from src/OrcLib/Log/FileSink.h rename to src/OrcLib/Log/Sink/FileSink.h index 6ce6aa18..a06f18bf 100644 --- a/src/OrcLib/Log/FileSink.h +++ b/src/OrcLib/Log/Sink/FileSink.h @@ -16,107 +16,97 @@ #include #include -#include "Log/MemorySink.h" +#include "Log/Sink/MemorySink.h" // // FileSink will cache some logs into a MemorySink until the log file is opened // namespace Orc { +namespace Log { template class FileSink : public spdlog::sinks::base_sink { public: - using SpdlogFileSink = spdlog::sinks::basic_file_sink; - using MemorySink = MemorySink, Mutex>; + // No need of mutexes since FileSink synchronisation will be made on 'Mutex' + using SpdlogFileSink = spdlog::sinks::basic_file_sink_st; + using MemorySink = MemorySink, spdlog::details::null_mutex>; + + const size_t kMemorySinkSize = 4096; FileSink() : m_fileSink() - , m_memorySink(std::make_unique(4096)) - , m_path() - , m_lazyClose(false) + , m_memorySink(std::make_unique(kMemorySinkSize)) { } void Open(const std::filesystem::path& path, std::error_code& ec) { - // Log file cannot be opened directly from a multithreaded context - if (IsOpen()) + std::lock_guard lock(mutex_); + + if (m_fileSink != nullptr) { ec = std::make_error_code(std::errc::device_or_resource_busy); return; } - m_path = path; - } - - bool IsOpen() const { return m_fileSink != nullptr; } - - void Close() - { - m_lazyClose = true; - - // Calling flush with lazyclose will close the file sink behind the base_sink mutex - spdlog::sinks::base_sink::flush(); - } - -protected: - std::unique_ptr LazyOpen( - const std::filesystem::path& path, - const std::unique_ptr& memorySink, - std::error_code& ec) const - { std::filesystem::remove(path); - if (memorySink) + // Dump memorySink if any + if (m_memorySink) { try { std::fstream log; log.open(path, std::ios::out | std::ios::binary); - const auto& in = memorySink->buffer(); + const auto& in = m_memorySink->buffer(); std::ostream_iterator out(log); std::copy(std::cbegin(in), std::cend(in), out); } catch (const std::system_error& e) { ec = e.code(); - return {}; + return; } catch (...) { ec = std::make_error_code(std::errc::interrupted); - return {}; + return; } + + m_memorySink.reset(); } - auto fileSink = std::make_unique(path.string()); + m_fileSink = std::make_unique(path.string()); // Current sink_it_ will handle filtering - fileSink->set_level(spdlog::level::trace); + m_fileSink->set_level(spdlog::level::trace); if (m_formatter) { - fileSink->set_formatter(m_formatter->clone()); + m_fileSink->set_formatter(m_formatter->clone()); } - - return fileSink; } - void set_pattern_(const std::string& pattern) override + bool IsOpen() { - m_pattern = pattern; + std::lock_guard lock(mutex_); + return m_fileSink != nullptr; + } - if (m_fileSink) - { - m_fileSink->set_pattern(pattern); - } + void Close() + { + std::lock_guard lock(mutex_); + flush_(); + m_memorySink = std::make_unique(kMemorySinkSize); + m_fileSink.reset(); + } - if (m_memorySink) - { - m_memorySink->set_pattern(pattern); - } +protected: + void set_pattern_(const std::string& pattern) override + { + set_formatter_(std::make_unique(pattern)); } void set_formatter_(std::unique_ptr formatter) override @@ -142,24 +132,6 @@ class FileSink : public spdlog::sinks::base_sink return; } - if (m_path.empty() == false && m_lazyClose == false) - { - // Lazy open file is made here for thread safety - std::error_code ec; - auto fileSink = LazyOpen(m_path, m_memorySink, ec); - if (ec) - { - std::cerr << "Failed to open log file: " << m_path << " (" << ec.message() << ")" << std::endl; - } - else - { - m_fileSink = std::move(fileSink); - m_memorySink.reset(); - m_fileSink->log(msg); - return; - } - } - if (m_memorySink) { m_memorySink->log(msg); @@ -171,26 +143,14 @@ class FileSink : public spdlog::sinks::base_sink if (m_fileSink) { m_fileSink->flush(); - - // Lazy reset sink is made here for thread safety - if (m_lazyClose) - { - m_fileSink.reset(); - } - } - else - { - m_memorySink->flush(); } } private: std::unique_ptr m_fileSink; std::unique_ptr m_memorySink; - std::filesystem::path m_path; - std::atomic_bool m_lazyClose; - std::string m_pattern; std::unique_ptr m_formatter; }; +} // namespace Log } // namespace Orc diff --git a/src/OrcLib/Log/MemorySink.h b/src/OrcLib/Log/Sink/MemorySink.h similarity index 96% rename from src/OrcLib/Log/MemorySink.h rename to src/OrcLib/Log/Sink/MemorySink.h index 327693dd..fa8078f1 100644 --- a/src/OrcLib/Log/MemorySink.h +++ b/src/OrcLib/Log/Sink/MemorySink.h @@ -14,6 +14,7 @@ #include namespace Orc { +namespace Log { template class MemorySink : public spdlog::sinks::base_sink @@ -41,4 +42,5 @@ class MemorySink : public spdlog::sinks::base_sink T m_buffer; }; +} // namespace Log } // namespace Orc diff --git a/src/OrcLib/Log/SpdlogLogger.cpp b/src/OrcLib/Log/SpdlogLogger.cpp new file mode 100644 index 00000000..b05c30dc --- /dev/null +++ b/src/OrcLib/Log/SpdlogLogger.cpp @@ -0,0 +1,119 @@ +// +// SPDX-License-Identifier: LGPL-2.1-or-later +// +// Copyright © 2020 ANSSI. All Rights Reserved. +// +// Author(s): fabienfl +// + +#pragma once + +#include "Log/SpdlogLogger.h" + +namespace Orc { +namespace Log { + +SpdlogLogger::SpdlogLogger(const std::string& name) + : m_logger(std::make_shared(name)) + , m_backtraceFormatter( + std::make_unique(kDefaultLogPattern, spdlog::pattern_time_type::utc)) +{ +} + +void SpdlogLogger::Add(SpdlogSink::Ptr sink) +{ + sink->AddTo(*m_logger); + m_sinks.push_back(std::move(sink)); +} + +spdlog::level::level_enum SpdlogLogger::Level() const +{ + return m_logger->level(); +} + +void SpdlogLogger::SetLevel(spdlog::level::level_enum level) +{ + m_logger->set_level(level); +} + +void SpdlogLogger::EnableBacktrace(size_t messageCount) +{ + m_logger->enable_backtrace(messageCount); +} + +void SpdlogLogger::DisableBacktrace() +{ + m_logger->disable_backtrace(); +} + +void SpdlogLogger::DumpBacktrace() +{ + // Backup log settings + const auto loggerLevel = m_logger->level(); + m_logger->set_level(spdlog::level::trace); + + struct SinkSettings + { + spdlog::level::level_enum level; + std::unique_ptr formatter; + }; + + std::vector sinksSettings(m_sinks.size()); + for (size_t i = 0; i < m_sinks.size(); ++i) + { + sinksSettings[i] = {m_sinks[i]->Level(), m_sinks[i]->CloneFormatter()}; + + m_sinks[i]->SetLevel(spdlog::level::trace); + m_sinks[i]->SetFormatter(m_backtraceFormatter->clone()); + } + + m_logger->dump_backtrace(); + + // Restore log settings + for (size_t i = 0; i < m_sinks.size(); ++i) + { + m_sinks[i]->SetLevel(sinksSettings[i].level); + m_sinks[i]->SetFormatter(std::move(sinksSettings[i].formatter)); + } + + SetLevel(loggerLevel); +} + +void SpdlogLogger::SetErrorHandler(std::function handler) +{ + m_logger->set_error_handler(handler); +} + +void SpdlogLogger::SetFormatter(std::unique_ptr formatter) +{ + if (formatter == nullptr) + { + // spdlog sinks does not allow set_formatter with nullptr + return; + } + + // see spldog implementation, spdlog::logger does not keep any formatter reference + for (auto& sink : m_sinks) + { + sink->SetFormatter(formatter->clone()); + } +} + +void SpdlogLogger::SetPattern(const std::string& pattern) +{ + auto formatter = std::make_unique(pattern); + SetFormatter(std::move(formatter)); +} + +void SpdlogLogger::SetAsDefaultLogger() +{ + spdlog::set_default_logger(m_logger); +} + +const std::vector& SpdlogLogger::Sinks() +{ + return m_sinks; +} + +} // namespace Log +} // namespace Orc diff --git a/src/OrcLib/Log/SpdlogLogger.h b/src/OrcLib/Log/SpdlogLogger.h new file mode 100644 index 00000000..cba26fa1 --- /dev/null +++ b/src/OrcLib/Log/SpdlogLogger.h @@ -0,0 +1,93 @@ +// +// SPDX-License-Identifier: LGPL-2.1-or-later +// +// Copyright © 2020 ANSSI. All Rights Reserved. +// +// Author(s): fabienfl +// + +#pragma once + +#include + +#include + +#include "Log/SpdlogSink.h" + +namespace Orc { +namespace Log { + +// https://github.com/gabime/spdlog/wiki/3.-Custom-formatting +// The following could output: '2020-09-30T13:43:41.256Z [I] this is a foobar log' +// The %^...%$ options specify coloring range, only one is currently supported +const std::string kDefaultLogPattern("%^%Y-%m-%dT%T.%eZ [%L] %v%$"); + +class SpdlogLogger +{ +public: + using Ptr = std::shared_ptr; + + SpdlogLogger(const std::string& name); + + void Add(SpdlogSink::Ptr sink); + + spdlog::level::level_enum Level() const; + void SetLevel(spdlog::level::level_enum level); + + void SetPattern(const std::string& pattern); + void SetFormatter(std::unique_ptr formatter); + + void EnableBacktrace(size_t messageCount); + void DisableBacktrace(); + void DumpBacktrace(); + + void SetErrorHandler(std::function handler); + + void SetAsDefaultLogger(); + + const std::vector& Sinks(); + + template + void Trace(Args&&... args) + { + m_logger->trace(std::forward(args)...); + } + + template + void Debug(Args&&... args) + { + m_logger->debug(std::forward(args)...); + } + + template + void Info(Args&&... args) + { + m_logger->info(std::forward(args)...); + } + + template + void Warn(Args&&... args) + { + m_logger->warn(std::forward(args)...); + } + + template + void Error(Args&&... args) + { + m_logger->error(std::forward(args)...); + } + + template + void Critical(Args&&... args) + { + m_logger->critical(std::forward(args)...); + } + +private: + std::shared_ptr m_logger; + std::unique_ptr m_backtraceFormatter; + std::vector m_sinks; +}; + +} // namespace Log +} // namespace Orc diff --git a/src/OrcLib/Log/SpdlogSink.h b/src/OrcLib/Log/SpdlogSink.h new file mode 100644 index 00000000..d17b1818 --- /dev/null +++ b/src/OrcLib/Log/SpdlogSink.h @@ -0,0 +1,75 @@ +// +// SPDX-License-Identifier: LGPL-2.1-or-later +// +// Copyright © 2020 ANSSI. All Rights Reserved. +// +// Author(s): fabienfl +// + +#pragma once + +#include + +#include + +namespace Orc { +namespace Log { + +class SpdlogSink +{ +public: + using Ptr = std::shared_ptr; + + // Use a template to control over the sink creation (no custom formatter or level without using the provided API). + template + static std::unique_ptr Create(Args&&... args) + { + return std::make_unique(std::make_unique(std::forward(args)...)); + } + + void AddTo(spdlog::logger& logger) { logger.sinks().push_back(m_sink); } + + spdlog::level::level_enum Level() const { return m_sink->level(); } + void SetLevel(spdlog::level::level_enum level) { m_sink->set_level(level); } + + std::unique_ptr CloneFormatter() const + { + if (m_formatter == nullptr) + { + return nullptr; + } + + return m_formatter->clone(); + } + + void SetFormatter(std::unique_ptr formatter) + { + if (formatter == nullptr) + { + // spdlog sinks does not allow set_formatter with nullptr + formatter = std::make_unique(); + } + + m_formatter = std::move(formatter); + m_sink->set_formatter(m_formatter->clone()); + } + + void SetPattern(const std::string& pattern) + { + auto formatter = std::make_unique(pattern); + SetFormatter(std::move(formatter)); + } + +protected: + SpdlogSink(std::unique_ptr sink) + : m_sink(std::move(sink)) + { + } + +protected: + std::shared_ptr m_sink; + std::unique_ptr m_formatter; +}; + +} // namespace Log +} // namespace Orc diff --git a/src/OrcLib/MftRecordAttribute.cpp b/src/OrcLib/MftRecordAttribute.cpp index 157695db..2cf955e0 100644 --- a/src/OrcLib/MftRecordAttribute.cpp +++ b/src/OrcLib/MftRecordAttribute.cpp @@ -438,11 +438,11 @@ HRESULT MftRecordAttribute::GetHashInformation( CryptoHashStream::Algorithm needed = CryptoHashStream::Algorithm::Undefined; - if (required & CryptoHashStream::Algorithm::MD5 && m_Details->MD5().empty()) + if (HasFlag(required, CryptoHashStream::Algorithm::MD5) && m_Details->MD5().empty()) needed |= CryptoHashStream::Algorithm::MD5; - if (required & CryptoHashStream::Algorithm::SHA1 && m_Details->SHA1().empty()) + if (HasFlag(required, CryptoHashStream::Algorithm::SHA1) && m_Details->SHA1().empty()) needed |= CryptoHashStream::Algorithm::SHA1; - if (required & CryptoHashStream::Algorithm::SHA256 && m_Details->SHA256().empty()) + if (HasFlag(required, CryptoHashStream::Algorithm::SHA256) && m_Details->SHA256().empty()) needed |= CryptoHashStream::Algorithm::SHA256; if (needed == CryptoHashStream::Algorithm::Undefined) @@ -475,21 +475,21 @@ HRESULT MftRecordAttribute::GetHashInformation( return hr; } - if (needed & CryptoHashStream::Algorithm::MD5) + if (HasFlag(needed, CryptoHashStream::Algorithm::MD5)) { CBinaryBuffer md5; if (FAILED(hr = pHashStream->GetMD5(md5))) return hr; m_Details->SetMD5(std::move(md5)); } - if (needed & CryptoHashStream::Algorithm::SHA1) + if (HasFlag(needed, CryptoHashStream::Algorithm::SHA1)) { CBinaryBuffer sha1; if (FAILED(hr = pHashStream->GetSHA1(sha1))) return hr; m_Details->SetSHA1(std::move(sha1)); } - if (needed & CryptoHashStream::Algorithm::SHA256) + if (HasFlag(needed, CryptoHashStream::Algorithm::SHA256)) { CBinaryBuffer sha256; if (FAILED(hr = pHashStream->GetSHA256(sha256))) diff --git a/src/OrcLib/Output/Console/Console.h b/src/OrcLib/Output/Console/Console.h index 361295b7..1952754c 100644 --- a/src/OrcLib/Output/Console/Console.h +++ b/src/OrcLib/Output/Console/Console.h @@ -30,6 +30,11 @@ struct StdoutContainerAdapter using value_type = T; void push_back(T c) { + if (c == 0) + { + return; + } + Traits::get_std_out() << c; // Using stdout with multiple threads requires synchronization so it should not be bothering to have a 'static' @@ -37,11 +42,8 @@ struct StdoutContainerAdapter static std::basic_string line; if (c == Traits::newline_v) { - if (line.size() > 1) - { - Log::Debug(Logger::Facility::kLogFile, line); - line.clear(); - } + Log::Info(Logger::Facility::kLogFile, line); + line.clear(); } else { diff --git a/src/OrcLib/Output/Text/Print.h b/src/OrcLib/Output/Text/Print.h index 79fd83f5..a9217fea 100644 --- a/src/OrcLib/Output/Text/Print.h +++ b/src/OrcLib/Output/Text/Print.h @@ -10,16 +10,23 @@ #include #include +#include +#include #include "Output/Text/Tree.h" namespace Orc { namespace Text { -constexpr auto kStringEmpty = std::string_view(""); -constexpr auto kStringEmptyW = std::wstring_view(L""); +constexpr auto kEmpty = std::string_view(""); +constexpr auto kEmptyW = std::wstring_view(L""); +constexpr auto kError = std::string_view(""); +constexpr auto kErrorW = std::wstring_view(L""); +constexpr auto kNoneAvailable = std::string_view("N/A"); +constexpr auto kNoneAvailableW = std::wstring_view(L"N/A"); +constexpr auto kNone = std::string_view("None"); +constexpr auto kNoneW = std::wstring_view(L"None"); -// Default function to be specialized for custom output template void PrintKey(Orc::Text::Tree& root, const N& key) { @@ -30,11 +37,45 @@ void PrintKey(Orc::Text::Tree& root, const N& key) root.AddWithoutEOL(L"{:<34}", decoratedKey); } -// Default function to be specialized for custom output +// To be specialized... +template +struct Printer +{ + template + static void Output(Orc::Text::Tree& root, const V& value) + { + root.Add(L"{}", value); + } +}; + template void Print(Orc::Text::Tree& root, const V& value) { - root.Add(L"{}", value); + Printer::Output(root, value); +} + +template +void Print(Orc::Text::Tree& root, const std::shared_ptr& value) +{ + if (value == nullptr) + { + Print(root, kErrorW); + return; + } + + Printer::Output(root, *value); +} + +template +void Print(Orc::Text::Tree& root, const std::optional& item) +{ + if (!item.has_value()) + { + Print(root, kNoneAvailableW); + return; + } + + Printer::Print(root, *item); } template @@ -56,7 +97,7 @@ void PrintValues(Orc::Text::Tree& root, const N& name, const V& values) { if (values.size() == 0) { - PrintValue(root, name, L"None"); + PrintValue(root, name, kNoneW); return; } diff --git a/src/OrcLib/Output/Text/Print/Bool.h b/src/OrcLib/Output/Text/Print/Bool.h index 7ce71b01..0902a48e 100644 --- a/src/OrcLib/Output/Text/Print/Bool.h +++ b/src/OrcLib/Output/Text/Print/Bool.h @@ -13,11 +13,15 @@ namespace Orc { namespace Text { -template -void Print(Orc::Text::Tree& root, const bool& value) +template <> +struct Printer { - Print(root, value ? L"On" : L"Off"); -} + template + static void Output(Orc::Text::Tree& node, bool value) + { + Print(node, value ? L"On" : L"Off"); + } +}; } // namespace Text } // namespace Orc diff --git a/src/OrcLib/Output/Text/Print/EmbedSpec.h b/src/OrcLib/Output/Text/Print/EmbedSpec.h index faa1646d..1bedcce7 100644 --- a/src/OrcLib/Output/Text/Print/EmbedSpec.h +++ b/src/OrcLib/Output/Text/Print/EmbedSpec.h @@ -15,30 +15,34 @@ namespace Orc { namespace Text { -template -void Print(Orc::Text::Tree& node, const EmbeddedResource::EmbedSpec& embedItem) +template <> +struct Printer { - switch (embedItem.Type) + template + static void Output(Orc::Text::Tree& node, const EmbeddedResource::EmbedSpec& embedItem) { - case EmbeddedResource::EmbedSpec::EmbedType::File: - node.Add(L"File: {} {}", embedItem.Name, embedItem.Value); - break; - case EmbeddedResource::EmbedSpec::EmbedType::NameValuePair: - node.Add(L"Value: {}={}", embedItem.Name, embedItem.Value); - break; - case EmbeddedResource::EmbedSpec::EmbedType::Archive: { - for (const auto& archive : embedItem.ArchiveItems) - { - node.Add(L"Archive: {} -> {}", archive.Path, archive.Name); + switch (embedItem.Type) + { + case EmbeddedResource::EmbedSpec::EmbedType::File: + node.Add(L"File: {} {}", embedItem.Name, embedItem.Value); + break; + case EmbeddedResource::EmbedSpec::EmbedType::NameValuePair: + node.Add(L"Value: {}={}", embedItem.Name, embedItem.Value); + break; + case EmbeddedResource::EmbedSpec::EmbedType::Archive: { + for (const auto& archive : embedItem.ArchiveItems) + { + node.Add(L"Archive: {} -> {}", archive.Path, archive.Name); + } + break; } - break; + case EmbeddedResource::EmbedSpec::EmbedType::ValuesDeletion: + case EmbeddedResource::EmbedSpec::EmbedType::BinaryDeletion: + node.Add(L"Remove ID: {}", embedItem.Name); + break; } - case EmbeddedResource::EmbedSpec::EmbedType::ValuesDeletion: - case EmbeddedResource::EmbedSpec::EmbedType::BinaryDeletion: - node.Add(L"Remove ID: {}", embedItem.Name); - break; } -} +}; } // namespace Text } // namespace Orc diff --git a/src/OrcLib/Output/Text/Print/FILE_NAME.h b/src/OrcLib/Output/Text/Print/FILE_NAME.h index 374b56f7..00ef77cc 100644 --- a/src/OrcLib/Output/Text/Print/FILE_NAME.h +++ b/src/OrcLib/Output/Text/Print/FILE_NAME.h @@ -15,22 +15,26 @@ namespace Orc { namespace Text { -template -void Print(Orc::Text::Tree& root, const FILE_NAME& file_name) +template <> +struct Printer { - const auto parentFRN = NtfsFullSegmentNumber(&file_name.ParentDirectory); - const auto& creation = *(reinterpret_cast(&file_name.Info.CreationTime)); - const auto& lastModification = *(reinterpret_cast(&file_name.Info.LastModificationTime)); - const auto& lastAccess = *(reinterpret_cast(&file_name.Info.LastAccessTime)); - const auto& lastChange = *(reinterpret_cast(&file_name.Info.LastChangeTime)); + template + static void Output(Orc::Text::Tree& node, const FILE_NAME& value) + { + const auto parentFRN = NtfsFullSegmentNumber(&file_name.ParentDirectory); + const auto& creation = *(reinterpret_cast(&file_name.Info.CreationTime)); + const auto& lastModification = *(reinterpret_cast(&file_name.Info.LastModificationTime)); + const auto& lastAccess = *(reinterpret_cast(&file_name.Info.LastAccessTime)); + const auto& lastChange = *(reinterpret_cast(&file_name.Info.LastChangeTime)); - auto node = root.AddNode(file_name); - node.Add("Parent directory FRN: {:#016x}", parentFRN); - node.Add("CreationTime: {}", creation); - node.Add("LastModificationTime: {}", lastModification); - node.Add("LastAccessTime: {}", lastAccess); - node.Add("LastChangeTime: {}", lastChange); -} + auto node = root.AddNode(file_name); + node.Add("Parent directory FRN: {:#016x}", parentFRN); + node.Add("CreationTime: {}", creation); + node.Add("LastModificationTime: {}", lastModification); + node.Add("LastAccessTime: {}", lastAccess); + node.Add("LastChangeTime: {}", lastChange); + } +}; } // namespace Text } // namespace Orc diff --git a/src/OrcLib/Output/Text/Print/Filter.h b/src/OrcLib/Output/Text/Print/Filter.h index 1e3a2791..2f38a2ac 100644 --- a/src/OrcLib/Output/Text/Print/Filter.h +++ b/src/OrcLib/Output/Text/Print/Filter.h @@ -28,7 +28,7 @@ void PrintValue( { if (filters.empty()) { - PrintValue(node, name, kStringEmpty); + PrintValue(node, name, kEmpty); return; } diff --git a/src/OrcLib/Output/Text/Print/Intentions.h b/src/OrcLib/Output/Text/Print/Intentions.h index 2df20099..e183c191 100644 --- a/src/OrcLib/Output/Text/Print/Intentions.h +++ b/src/OrcLib/Output/Text/Print/Intentions.h @@ -22,7 +22,7 @@ void PrintValue(Orc::Text::Tree& root, const N& name, Orc::Intentions intenti while (pCurCol->dwIntention != Intentions::FILEINFO_NONE) { - if (intentions & pCurCol->dwIntention) + if (HasFlag(intentions, pCurCol->dwIntention)) { columns.push_back(pCurCol->szColumnName); } diff --git a/src/OrcLib/Output/Text/Print/Location.h b/src/OrcLib/Output/Text/Print/Location.h index 8f18fe9f..1ecc003c 100644 --- a/src/OrcLib/Output/Text/Print/Location.h +++ b/src/OrcLib/Output/Text/Print/Location.h @@ -23,35 +23,32 @@ namespace detail { std::vector GetMountPointList(const Location& location); } -template -void Print(Orc::Text::Tree& node, const std::shared_ptr& location) +template <> +struct Printer { - assert(location); - Print(node, *location); -} + template + static void Output(Orc::Text::Tree& node, const Orc::Location& location) + { + std::vector properties; -template -void Print(Orc::Text::Tree& node, const Orc::Location& location) -{ - std::vector properties; + properties.push_back(ToString(location.GetType())); - properties.push_back(ToString(location.GetType())); + if (location.IsValid()) + { + properties.push_back(fmt::format(L"Serial: {:0>16X}", location.SerialNumber())); + } - if (location.IsValid()) - { - properties.push_back(fmt::format(L"Serial: {:0>16X}", location.SerialNumber())); - } + properties.push_back(location.IsValid() ? L"Valid" : L"Invalid"); + properties.push_back(ToString(location.GetFSType())); + const auto mountPointList = detail::GetMountPointList(location); + if (mountPointList.size()) + { + properties.push_back(fmt::format(L"[{}]", boost::join(mountPointList, L", "))); + } - properties.push_back(location.IsValid() ? L"Valid" : L"Invalid"); - properties.push_back(ToString(location.GetFSType())); - const auto mountPointList = detail::GetMountPointList(location); - if (mountPointList.size()) - { - properties.push_back(fmt::format(L"[{}]", boost::join(mountPointList, L", "))); + Print(node, fmt::format(L"{} [{}]", location.GetLocation(), boost::join(properties, L", "))); } - - Print(node, fmt::format(L"{} [{}]", location.GetLocation(), boost::join(properties, L", "))); -} +}; } // namespace Text } // namespace Orc diff --git a/src/OrcLib/Output/Text/Print/LocationSet.h b/src/OrcLib/Output/Text/Print/LocationSet.h index e77db73f..6f0f66cd 100644 --- a/src/OrcLib/Output/Text/Print/LocationSet.h +++ b/src/OrcLib/Output/Text/Print/LocationSet.h @@ -38,85 +38,88 @@ bool HasSameAttributes(InputIt first, InputIt last) } // namespace detail -template -void Print(Orc::Text::Tree& root, const LocationSet& locationSet) +template <> +struct Printer { - using SerialNumber = ULONGLONG; - std::map> locationsBySerial; - for (const auto& [serial, location] : locationSet.GetLocations()) + template + static void Output(Orc::Text::Tree& root, const LocationSet& locationSet) { - assert(location); - if (location->IsValid()) + using SerialNumber = ULONGLONG; + std::map> locationsBySerial; + for (const auto& [serial, location] : locationSet.GetLocations()) { - locationsBySerial[location->SerialNumber()].insert(location.get()); - } - else - { - locationsBySerial[ULLONG_MAX].insert(location.get()); + assert(location); + if (location->IsValid()) + { + locationsBySerial[location->SerialNumber()].insert(location.get()); + } + else + { + locationsBySerial[ULLONG_MAX].insert(location.get()); + } } - } - - for (const auto& [serial, locations] : locationsBySerial) - { - const std::wstring serialW = - serial != ULLONG_MAX ? fmt::format(L"{:0>16X}", serial) : fmt::format(L"{:>16}", L""); - - // Verify for each volume that informations are consitent/identical to display them once or always - const auto constantAttributes = detail::HasSameAttributes(std::cbegin(locations), std::cend(locations)); - std::wstring serialNodeString; - if (constantAttributes) + for (const auto& [serial, locations] : locationsBySerial) { - const auto location = *locations.cbegin(); + const std::wstring serialW = + serial != ULLONG_MAX ? fmt::format(L"{:0>16X}", serial) : fmt::format(L"{:>16}", L""); - std::vector attributes; - attributes.push_back(serialW); - attributes.push_back(location->IsValid() ? L"Valid" : L"Invalid"); - attributes.push_back(ToString(location->GetFSType())); + // Verify for each volume that informations are consitent/identical to display them once or always + const auto constantAttributes = detail::HasSameAttributes(std::cbegin(locations), std::cend(locations)); - serialNodeString = fmt::format(L"Volume: {}", boost::join(attributes, L", ")); - } - else - { - serialNodeString = fmt::format(L"Volume: {}", serialW); - } + std::wstring serialNodeString; + if (constantAttributes) + { + const auto location = *locations.cbegin(); - auto serialNode = root.AddNode(serialNodeString); + std::vector attributes; + attributes.push_back(serialW); + attributes.push_back(location->IsValid() ? L"Valid" : L"Invalid"); + attributes.push_back(ToString(location->GetFSType())); - for (const auto location : locations) - { - if (!constantAttributes) + serialNodeString = fmt::format(L"Volume: {}", boost::join(attributes, L", ")); + } + else { - PrintValue(serialNode, L"", *location); - continue; + serialNodeString = fmt::format(L"Volume: {}", serialW); } - std::wstring mountPoints; - const auto mountPointList = detail::GetMountPointList(*location); - if (mountPointList.size()) + auto serialNode = root.AddNode(serialNodeString); + + for (const auto location : locations) { - mountPoints = fmt::format(L" [{}]", boost::join(mountPointList, L", ")); + if (!constantAttributes) + { + PrintValue(serialNode, L"", *location); + continue; + } + + std::wstring mountPoints; + const auto mountPointList = detail::GetMountPointList(*location); + if (mountPointList.size()) + { + mountPoints = fmt::format(L" [{}]", boost::join(mountPointList, L", ")); + } + + serialNode.Add( + L"{:<34} {}{}", fmt::format(L"{}:", location->GetType()), location->GetLocation(), mountPoints); + + // TODO: Having access to FormatTo would be good. A version without header, conversion to FmtArg0 + // encoding, conversion to container's encoding auto value = FormatTo(L"{:<34} {}{}", + // fmt::format(L"{}:", location->GetType()), location->GetLocation(), mountPoints); Print(node, value); } - serialNode.Add( - L"{:<34} {}{}", fmt::format(L"{}:", location->GetType()), location->GetLocation(), mountPoints); - - // TODO: Having access to FormatTo would be good. A version without header, conversion to FmtArg0 encoding, - // conversion to container's encoding - // auto value = FormatTo(L"{:<34} {}{}", fmt::format(L"{}:", location->GetType()), location->GetLocation(), - // mountPoints); Print(node, value); + serialNode.AddEmptyLine(); } - - serialNode.AddEmptyLine(); } -} +}; template void PrintValue(Orc::Text::Tree& root, const U& name, const LocationSet& locationSet) { if (locationSet.GetLocations().empty()) { - PrintValue(root, name, kStringEmpty); + PrintValue(root, name, kEmpty); return; } diff --git a/src/OrcLib/Output/Text/Print/Ntfs/AttributeListEntry.h b/src/OrcLib/Output/Text/Print/Ntfs/AttributeListEntry.h index 1b81fcdf..efc0645b 100644 --- a/src/OrcLib/Output/Text/Print/Ntfs/AttributeListEntry.h +++ b/src/OrcLib/Output/Text/Print/Ntfs/AttributeListEntry.h @@ -17,33 +17,38 @@ namespace Orc { namespace Text { -template -void Print(Orc::Text::Tree& root, const AttributeListEntry& entry) +template <> +struct Printer { - std::error_code ec; - - const auto attributeName = Utf16ToUtf8(std::wstring_view(entry.AttributeName(), entry.AttributeNameLength()), ec); - assert(!ec); - - const auto attributeType = Utf16ToUtf8(std::wstring_view(entry.TypeStr()), ec); - assert(!ec); - - root.AddWithoutEOL( - "Id: {:02}, Type: '{}', Name: '{}', Form: '{}'", - entry.Instance(), - attributeType, - attributeName, - entry.FormCode() == RESIDENT_FORM ? "R" : "NR"); - - if (entry.LowestVCN() > 0) - { - root.Append(", LowestVCN={:#018x}\n", entry.LowestVCN()); - } - else + template + static void Output(Orc::Text::Tree& root, const AttributeListEntry& entry) { - root.Append("\n"); + std::error_code ec; + + const auto attributeName = + Utf16ToUtf8(std::wstring_view(entry.AttributeName(), entry.AttributeNameLength()), ec); + assert(!ec); + + const auto attributeType = Utf16ToUtf8(std::wstring_view(entry.TypeStr()), ec); + assert(!ec); + + root.AddWithoutEOL( + "Id: {:02}, Type: '{}', Name: '{}', Form: '{}'", + entry.Instance(), + attributeType, + attributeName, + entry.FormCode() == RESIDENT_FORM ? "R" : "NR"); + + if (entry.LowestVCN() > 0) + { + root.Append(", LowestVCN={:#018x}\n", entry.LowestVCN()); + } + else + { + root.Append("\n"); + } } -} +}; } // namespace Text } // namespace Orc diff --git a/src/OrcLib/Output/Text/Print/Ntfs/MFTRecord.h b/src/OrcLib/Output/Text/Print/Ntfs/MFTRecord.h index e0d3b414..42240bb9 100644 --- a/src/OrcLib/Output/Text/Print/Ntfs/MFTRecord.h +++ b/src/OrcLib/Output/Text/Print/Ntfs/MFTRecord.h @@ -178,22 +178,6 @@ void Print(Orc::Text::Tree& root, const MFTRecord& record, const std::shared_ } } } - - // if (record.IsDirectory() && volume) - //{ - // FormatDirectoryAttributes(root, record, volume, std::error_code()); - //} - - // if (!attributes.empty()) - //{ - // auto attributesNode = root.AddNode("Attributes"); - - // for (size_t i = 0; i < attributes.size(); ++i) - // { - // auto attributeNode = attributesNode.AddNode("Attribute #{}", i); - // ::Format(attributeNode, attributes[i].Attribute(), volume); - // } - //} } } // namespace Text diff --git a/src/OrcLib/Output/Text/Print/Ntfs/NonResidentAttributeExtent.h b/src/OrcLib/Output/Text/Print/Ntfs/NonResidentAttributeExtent.h index aaba0b69..afdde0f4 100644 --- a/src/OrcLib/Output/Text/Print/Ntfs/NonResidentAttributeExtent.h +++ b/src/OrcLib/Output/Text/Print/Ntfs/NonResidentAttributeExtent.h @@ -16,24 +16,28 @@ namespace Orc { namespace Text { -template -void Print(Orc::Text::Tree& root, const Orc::MFTUtils::NonResidentAttributeExtent& extent) +template <> +struct Printer { - if (!extent.bZero) + template + static void Output(Orc::Text::Tree& root, const Orc::MFTUtils::NonResidentAttributeExtent& extent) { - root.Add( - L"LowestVCN: {:#018x}, Offset: {}, Allocated size: {}, Size: {}", - extent.LowestVCN, - Traits::Offset(extent.DiskOffset), - Traits::ByteQuantity(extent.DiskAlloc), - Traits::ByteQuantity(extent.DataSize)); + if (!extent.bZero) + { + root.Add( + L"LowestVCN: {:#018x}, Offset: {}, Allocated size: {}, Size: {}", + extent.LowestVCN, + Traits::Offset(extent.DiskOffset), + Traits::ByteQuantity(extent.DiskAlloc), + Traits::ByteQuantity(extent.DataSize)); + } + else + { + // Segment is SPARSE, only unallocated zeroes + root.Add(L"Sparse entry, Size: {}", Traits::ByteQuantity(extent.DataSize)); + } } - else - { - // Segment is SPARSE, only unallocated zeroes - root.Add(L"Sparse entry, Size: {}", Traits::ByteQuantity(extent.DataSize)); - } -} +}; } // namespace Text } // namespace Orc diff --git a/src/OrcLib/Output/Text/Print/OutputSpec.h b/src/OrcLib/Output/Text/Print/OutputSpec.h index f254cedb..e1f8774f 100644 --- a/src/OrcLib/Output/Text/Print/OutputSpec.h +++ b/src/OrcLib/Output/Text/Print/OutputSpec.h @@ -20,81 +20,78 @@ namespace Orc { namespace Text { -template -void PrintValue(Orc::Text::Tree& node, const U& name, const OutputSpec::Upload& upload) +template <> +struct Printer { - auto uploadNode = node.AddNode(name); - - const auto serverInfo = fmt::format(L"{} ({})", upload.ServerName, upload.RootPath); - PrintValue(uploadNode, "Server", serverInfo); - - PrintValue(uploadNode, "Method", upload.Method); - PrintValue(uploadNode, "Operation", upload.Operation); - PrintValue(uploadNode, "Mode", upload.Mode); - PrintValue(uploadNode, "User", upload.UserName.empty() ? kStringEmptyW : upload.UserName); - PrintValue(uploadNode, "Password", upload.Password.empty() ? L"" : L""); - PrintValue(uploadNode, "Auth", upload.AuthScheme); - PrintValue(uploadNode, "Job", upload.JobName.empty() ? kStringEmptyW : upload.JobName); - - const auto includes = boost::join(upload.FilterInclude, L", "); - PrintValue(uploadNode, "Include", includes.empty() ? kStringEmptyW : includes); - - const auto excludes = boost::join(upload.FilterExclude, L", "); - PrintValue(uploadNode, "Exclude", excludes.empty() ? kStringEmptyW : excludes); -} - -template -void PrintValue(Orc::Text::Tree& node, const U& name, const OutputSpec& output) -{ - if (output.Path.empty() && output.Type != OutputSpec::Kind::SQL) + template + static void Output(Orc::Text::Tree& root, const OutputSpec::Upload& upload) { - PrintValue(node, fmt::format(L"{}", name), kStringEmpty); - return; + const auto serverInfo = fmt::format(L"{} ({})", upload.ServerName, upload.RootPath); + PrintValue(root, "Server", serverInfo); + + PrintValue(root, "Method", upload.Method); + PrintValue(root, "Operation", upload.Operation); + PrintValue(root, "Mode", upload.Mode); + PrintValue(root, "User", upload.UserName.empty() ? kEmptyW : upload.UserName); + PrintValue(root, "Password", upload.Password.empty() ? L"" : L""); + PrintValue(root, "Auth", upload.AuthScheme); + PrintValue(root, "Job", upload.JobName.empty() ? kEmptyW : upload.JobName); + + const auto includes = boost::join(upload.FilterInclude, L", "); + PrintValue(root, "Include", includes.empty() ? kEmptyW : includes); + + const auto excludes = boost::join(upload.FilterExclude, L", "); + PrintValue(root, "Exclude", excludes.empty() ? kEmptyW : excludes); } +}; - std::vector properties {ToString(output.Type)}; - - if (output.Type != OutputSpec::Kind::None) +template <> +struct Printer +{ + template + static void Output(Orc::Text::Tree& root, const OutputSpec& output) { - properties.push_back(ToString(output.OutputEncoding)); - } + if (output.Path.empty() && output.Type != OutputSpec::Kind::SQL) + { + Print(root, kEmpty); + return; + } - if (output.Type == OutputSpec::Kind::Archive) - { - // This parameter would be filled by the user - if (output.Compression.size()) + std::vector properties {ToString(output.Type)}; + + if (output.Type != OutputSpec::Kind::None) { - properties.push_back(output.Compression); + properties.push_back(ToString(output.OutputEncoding)); } - } - if (output.Type == OutputSpec::Kind::SQL) - { - properties.push_back(output.ConnectionString); - } + if (output.Type == OutputSpec::Kind::Archive) + { + // This parameter would be filled by the user + if (output.Compression.size()) + { + properties.push_back(output.Compression); + } + } - auto outputPath = output.Path; - if (properties.size()) - { - fmt::format_to(std::back_inserter(outputPath), L" ({})", boost::join(properties, L", ")); - } + if (output.Type == OutputSpec::Kind::SQL) + { + properties.push_back(output.ConnectionString); + } - PrintValue(node, name, outputPath); + auto outputPath = output.Path; + if (properties.size()) + { + fmt::format_to(std::back_inserter(outputPath), L" ({})", boost::join(properties, L", ")); + } - if (output.UploadOutput != nullptr) - { - PrintValue(node, L"Upload configuration:", *(output.UploadOutput)); - } -} + Print(root, outputPath); -template -void PrintValue(Orc::Text::Tree& node, const U& name, const std::optional& output) -{ - if (output.has_value()) - { - PrintValue(node, name, *output); + if (output.UploadOutput != nullptr) + { + PrintValue(root, L"Upload configuration:", *(output.UploadOutput)); + } } -} +}; } // namespace Text } // namespace Orc diff --git a/src/OrcLib/Output/Text/Print/Partition.h b/src/OrcLib/Output/Text/Print/Partition.h index 3bb3b88b..5df5275d 100644 --- a/src/OrcLib/Output/Text/Print/Partition.h +++ b/src/OrcLib/Output/Text/Print/Partition.h @@ -15,31 +15,35 @@ namespace Orc { namespace Text { -template -void Print(Orc::Text::Tree& root, const Partition& partition) +template <> +struct Printer { - if (partition.IsValid()) + template + static void Output(Orc::Text::Tree& root, const Partition& partition) { - auto flags = Partition::ToString(partition.PartitionFlags); - if (flags.size()) + if (partition.IsValid()) { - flags = fmt::format(L", flags: {}", flags); - } + auto flags = Partition::ToString(partition.PartitionFlags); + if (flags.size()) + { + flags = fmt::format(L", flags: {}", flags); + } - root.Add( - "Partition: #{}, type: {}, offsets: {:#x}-{:#x}, size: {}{}", - partition.PartitionNumber, - partition.PartitionType, - partition.Start, - partition.End, - partition.Size, - flags); - } - else - { - root.Add("Partition type: {}{}", partition.PartitionType); + root.Add( + "Partition: #{}, type: {}, offsets: {:#x}-{:#x}, size: {}{}", + partition.PartitionNumber, + partition.PartitionType, + partition.Start, + partition.End, + partition.Size, + flags); + } + else + { + root.Add("Partition type: {}{}", partition.PartitionType); + } } -} +}; } // namespace Text } // namespace Orc diff --git a/src/OrcLib/Output/Text/Print/SearchTerm.h b/src/OrcLib/Output/Text/Print/SearchTerm.h index c93b07da..e7c66e94 100644 --- a/src/OrcLib/Output/Text/Print/SearchTerm.h +++ b/src/OrcLib/Output/Text/Print/SearchTerm.h @@ -15,18 +15,15 @@ namespace Orc { namespace Text { -template -void Print(Orc::Text::Tree& root, const std::shared_ptr& term) +template <> +struct Printer { - assert(term); - Print(root, *term); -} - -template -void Print(Orc::Text::Tree& root, const FileFind::SearchTerm& term) -{ - Print(root, term.GetDescription()); -} + template + static void Output(Orc::Text::Tree& root, const FileFind::SearchTerm& term) + { + Print(root, term.GetDescription()); + } +}; } // namespace Text } // namespace Orc diff --git a/src/OrcLib/Output/Text/Print/Tribool.h b/src/OrcLib/Output/Text/Print/Tribool.h index 5f5c26d7..8199f2be 100644 --- a/src/OrcLib/Output/Text/Print/Tribool.h +++ b/src/OrcLib/Output/Text/Print/Tribool.h @@ -15,26 +15,30 @@ namespace Orc { namespace Text { -template -void Print(Orc::Text::Tree& root, const boost::logic::tribool& value) +template <> +struct Printer { - std::wstring_view valueString; - - if (value) - { - valueString = L"On"; - } - else if (!value) + template + static void Output(Orc::Text::Tree& root, const boost::logic::tribool& value) { - valueString = L"Off"; + std::wstring_view valueString; + + if (value) + { + valueString = L"On"; + } + else if (!value) + { + valueString = L"Off"; + } + else + { + valueString = L"Indeterminate"; + } + + Print(root, valueString); } - else - { - valueString = L"Indeterminate"; - } - - Print(root, valueString); -} +}; } // namespace Text } // namespace Orc diff --git a/src/OrcLib/OutputSpec.cpp b/src/OrcLib/OutputSpec.cpp index f3643fce..fd0bda24 100644 --- a/src/OrcLib/OutputSpec.cpp +++ b/src/OrcLib/OutputSpec.cpp @@ -97,36 +97,39 @@ OutputSpec::ApplyPattern(const std::wstring& strPattern, const std::wstring& str bool OutputSpec::IsDirectory() const { - return Type & Kind::Directory; + return HasFlag(Type, Kind::Directory); }; bool OutputSpec::IsFile() const { - return Type & Kind::File || Type & Kind::TableFile || Type & Kind::StructuredFile || Type & Kind::Archive - || Type & Kind::CSV || Type & Kind::TSV || Type & Kind::Parquet || Type & Kind::ORC || Type & Kind::XML - || Type & Kind::JSON; + return HasAnyFlag( + Type, + Kind::File | Kind::TableFile | Kind::StructuredFile | Kind::Archive | Kind::CSV | Kind::TSV | Kind::Parquet + | Kind::ORC | Kind::XML | Kind::JSON); } // the same but without archive bool OutputSpec::IsRegularFile() const { - return Type & Kind::File || Type & Kind::TableFile || Type & Kind::StructuredFile || Type & Kind::CSV - || Type & Kind::TSV || Type & Kind::Parquet || Type & Kind::ORC || Type & Kind::XML || Type & Kind::JSON; + return HasAnyFlag( + Type, + Kind::File | Kind::TableFile | Kind::StructuredFile | Kind::CSV | Kind::TSV | Kind::Parquet | Kind::ORC + | Kind::XML | Kind::JSON); } bool OutputSpec::IsTableFile() const { - return Type & Kind::TableFile || Type & Kind::CSV || Type & Kind::TSV || Type & Kind::Parquet || Type & Kind::ORC; + return HasAnyFlag(Type, Kind::TableFile | Kind::CSV | Kind::TSV | Kind::Parquet | Kind::ORC); } bool OutputSpec::IsStructuredFile() const { - return Type & Kind::StructuredFile || Type & Kind::XML || Type & Kind::JSON; + return HasAnyFlag(Type, Kind::StructuredFile | Kind::XML | Kind::JSON); } bool OutputSpec::IsArchive() const { - return Type & Kind::Archive; + return HasFlag(Type, Kind::Archive); } HRESULT OutputSpec::Configure( @@ -138,7 +141,7 @@ HRESULT OutputSpec::Configure( Type = OutputSpec::Kind::None; - if (OutputSpec::Kind::SQL & supported) // Getting the SQL stuff out of the door asap + if (HasFlag(supported, OutputSpec::Kind::SQL)) // Getting the SQL stuff out of the door asap { static std::wregex reConnectionString(LR"RAW(^(([\w\s]+=[\w\s{}.]+;?)+)#([\w]+)$)RAW"); @@ -188,7 +191,7 @@ HRESULT OutputSpec::Configure( auto extension = outPath.extension(); - if (OutputSpec::Kind::TableFile & supported) + if (HasFlag(supported, OutputSpec::Kind::TableFile)) { if (equalCaseInsensitive(extension.c_str(), L".csv"sv)) { @@ -219,7 +222,7 @@ HRESULT OutputSpec::Configure( return Orc::GetOutputFile(outPath.c_str(), Path, true); } } - if (OutputSpec::Kind::StructuredFile & supported) + if (HasFlag(supported, OutputSpec::Kind::StructuredFile)) { if (equalCaseInsensitive(extension.c_str(), L".xml"sv)) { @@ -228,7 +231,7 @@ HRESULT OutputSpec::Configure( return Orc::GetOutputFile(outPath.c_str(), Path, true); } } - if (OutputSpec::Kind::StructuredFile & supported) + if (HasFlag(supported, OutputSpec::Kind::StructuredFile)) { if (equalCaseInsensitive(extension.c_str(), L".json"sv)) { @@ -237,7 +240,7 @@ HRESULT OutputSpec::Configure( return Orc::GetOutputFile(outPath.c_str(), Path, true); } } - if (OutputSpec::Kind::Archive & supported) + if (HasFlag(supported, OutputSpec::Kind::Archive)) { auto fmt = OrcArchive::GetArchiveFormat(extension.c_str()); if (fmt != ArchiveFormat::Unknown) @@ -248,7 +251,7 @@ HRESULT OutputSpec::Configure( } } - if (OutputSpec::Kind::Directory & supported && wcslen(extension.c_str()) == 0L && !outPath.empty()) + if (HasFlag(supported, OutputSpec::Kind::Directory) && wcslen(extension.c_str()) == 0L && !outPath.empty()) { // Output without extension could very well be a dir if (SUCCEEDED(VerifyDirectoryExists(outPath.c_str()))) @@ -266,7 +269,7 @@ HRESULT OutputSpec::Configure( } } - if (OutputSpec::Kind::File & supported) + if (HasFlag(supported, OutputSpec::Kind::File)) { Type = OutputSpec::Kind::File; return Orc::GetOutputFile(outPath.c_str(), Path, true); @@ -284,7 +287,7 @@ OutputSpec::Configure(OutputSpec::Kind supported, const ConfigItem& item, std::o Type = OutputSpec::Kind::None; - if (supported & static_cast(OutputSpec::Kind::SQL)) + if (HasFlag(supported, OutputSpec::Kind::SQL)) { bool bDone = false; if (::HasValue(item, CONFIG_OUTPUT_CONNECTION)) diff --git a/src/OrcLib/PEInfo.cpp b/src/OrcLib/PEInfo.cpp index 99c89880..bea41fa6 100644 --- a/src/OrcLib/PEInfo.cpp +++ b/src/OrcLib/PEInfo.cpp @@ -532,33 +532,32 @@ HRESULT PEInfo::OpenAllHash(Intentions localIntentions) return S_OK; CryptoHashStream::Algorithm algs = CryptoHashStream::Algorithm::Undefined; - if (localIntentions & Intentions::FILEINFO_MD5) + if (HasFlag(localIntentions, Intentions::FILEINFO_MD5)) algs |= CryptoHashStream::Algorithm::MD5; - if (localIntentions & Intentions::FILEINFO_SHA1) + if (HasFlag(localIntentions, Intentions::FILEINFO_SHA1)) algs |= CryptoHashStream::Algorithm::SHA1; - if (localIntentions & Intentions::FILEINFO_SHA256) + if (HasFlag(localIntentions, Intentions::FILEINFO_SHA256)) algs |= CryptoHashStream::Algorithm::SHA256; CryptoHashStream::Algorithm pe_algs = CryptoHashStream::Algorithm::Undefined; - if (localIntentions & Intentions::FILEINFO_PE_MD5) + if (HasFlag(localIntentions, Intentions::FILEINFO_PE_MD5)) pe_algs |= CryptoHashStream::Algorithm::MD5; - if (localIntentions & Intentions::FILEINFO_PE_SHA1) + if (HasFlag(localIntentions, Intentions::FILEINFO_PE_SHA1)) pe_algs |= CryptoHashStream::Algorithm::SHA1; - if (localIntentions & Intentions::FILEINFO_PE_SHA256) + if (HasFlag(localIntentions, Intentions::FILEINFO_PE_SHA256)) pe_algs |= CryptoHashStream::Algorithm::SHA256; FuzzyHashStream::Algorithm fuzzy_algs = FuzzyHashStream::Algorithm::Undefined; #ifdef ORC_BUILD_SSDEEP - if (localIntentions & Intentions::FILEINFO_SSDEEP) + if (HasFlag(localIntentions, Intentions::FILEINFO_SSDEEP) fuzzy_algs = fuzzy_algs | FuzzyHashStream::Algorithm::SSDeep; #endif - if (localIntentions & Intentions::FILEINFO_TLSH) + if (HasFlag(localIntentions, Intentions::FILEINFO_TLSH)) fuzzy_algs |= FuzzyHashStream::Algorithm::TLSH; - if (localIntentions & Intentions::FILEINFO_AUTHENTICODE_STATUS - || localIntentions & Intentions::FILEINFO_AUTHENTICODE_SIGNER) + if (HasAnyFlag(localIntentions, Intentions::FILEINFO_AUTHENTICODE_STATUS | Intentions::FILEINFO_AUTHENTICODE_SIGNER)) { pe_algs |= CryptoHashStream::Algorithm::MD5 | CryptoHashStream::Algorithm::SHA1 | CryptoHashStream::Algorithm::SHA256; @@ -595,7 +594,7 @@ HRESULT PEInfo::OpenAllHash(Intentions localIntentions) ULONGLONG ullHashed = 0LL; hashstream->Write(pData.GetData(), ullWritten, &ullHashed); - if (algs & CryptoHashStream::Algorithm::MD5) + if (HasFlag(algs, CryptoHashStream::Algorithm::MD5)) { hr = hashstream->GetHash(CryptoHashStream::Algorithm::MD5, m_FileInfo.GetDetails()->MD5()); if (FAILED(hr) && hr != MK_E_UNAVAILABLE) @@ -604,7 +603,7 @@ HRESULT PEInfo::OpenAllHash(Intentions localIntentions) } } - if (algs & CryptoHashStream::Algorithm::SHA1) + if (HasFlag(algs, CryptoHashStream::Algorithm::SHA1)) { hr = hashstream->GetHash(CryptoHashStream::Algorithm::SHA1, m_FileInfo.GetDetails()->SHA1()); if (FAILED(hr) && hr != MK_E_UNAVAILABLE) @@ -613,7 +612,7 @@ HRESULT PEInfo::OpenAllHash(Intentions localIntentions) } } - if (algs & CryptoHashStream::Algorithm::SHA256) + if (HasFlag(algs, CryptoHashStream::Algorithm::SHA256)) { hashstream->GetHash(CryptoHashStream::Algorithm::SHA256, m_FileInfo.GetDetails()->SHA256()); if (FAILED(hr) && hr != MK_E_UNAVAILABLE) @@ -631,7 +630,7 @@ HRESULT PEInfo::OpenAllHash(Intentions localIntentions) ULONGLONG ullHashed = 0LL; hashstream->Write(pData.GetData(), ullWritten, &ullHashed); - if (fuzzy_algs & FuzzyHashStream::Algorithm::SSDeep) + if (HasFlag(fuzzy_algs, FuzzyHashStream::Algorithm::SSDeep)) { hr = hashstream->GetHash(FuzzyHashStream::Algorithm::SSDeep, m_FileInfo.GetDetails()->SSDeep()); if (FAILED(hr) && hr != MK_E_UNAVAILABLE) @@ -640,7 +639,7 @@ HRESULT PEInfo::OpenAllHash(Intentions localIntentions) } } - if (fuzzy_algs & FuzzyHashStream::Algorithm::TLSH) + if (HasFlag(fuzzy_algs, FuzzyHashStream::Algorithm::TLSH)) { hr = hashstream->GetHash(FuzzyHashStream::Algorithm::TLSH, m_FileInfo.GetDetails()->TLSH()); if (FAILED(hr) && hr != MK_E_UNAVAILABLE) @@ -691,7 +690,7 @@ HRESULT PEInfo::OpenAllHash(Intentions localIntentions) ullPeHashed += ullThisWriteHashed; } - if (pe_algs & CryptoHashStream::Algorithm::MD5) + if (HasFlag(pe_algs, CryptoHashStream::Algorithm::MD5)) { hr = pe_hashstream->GetHash(CryptoHashStream::Algorithm::MD5, m_FileInfo.GetDetails()->PeMD5()); if (FAILED(hr) && hr != MK_E_UNAVAILABLE) @@ -700,7 +699,7 @@ HRESULT PEInfo::OpenAllHash(Intentions localIntentions) } } - if (pe_algs & CryptoHashStream::Algorithm::SHA1) + if (HasFlag(pe_algs, CryptoHashStream::Algorithm::SHA1)) { hr = pe_hashstream->GetHash(CryptoHashStream::Algorithm::SHA1, m_FileInfo.GetDetails()->PeSHA1()); if (FAILED(hr) && hr != MK_E_UNAVAILABLE) @@ -709,7 +708,7 @@ HRESULT PEInfo::OpenAllHash(Intentions localIntentions) } } - if (pe_algs & CryptoHashStream::Algorithm::SHA256) + if (HasFlag(pe_algs, CryptoHashStream::Algorithm::SHA256)) { hr = pe_hashstream->GetHash(CryptoHashStream::Algorithm::SHA256, m_FileInfo.GetDetails()->PeSHA256()); if (FAILED(hr) && hr != MK_E_UNAVAILABLE) @@ -783,14 +782,14 @@ HRESULT PEInfo::OpenPeHash(Intentions localIntentions) auto hashstream = std::make_shared(); CryptoHashStream::Algorithm algs = CryptoHashStream::Algorithm::Undefined; - if (localIntentions & Intentions::FILEINFO_PE_MD5) + if (HasFlag(localIntentions, Intentions::FILEINFO_PE_MD5)) algs |= CryptoHashStream::Algorithm::MD5; - if (localIntentions & Intentions::FILEINFO_PE_SHA1) + if (HasFlag(localIntentions, Intentions::FILEINFO_PE_SHA1)) algs |= CryptoHashStream::Algorithm::SHA1; - if (localIntentions & Intentions::FILEINFO_PE_SHA256) + if (HasFlag(localIntentions, Intentions::FILEINFO_PE_SHA256)) algs |= CryptoHashStream::Algorithm::SHA256; - if (localIntentions & Intentions::FILEINFO_AUTHENTICODE_STATUS - || localIntentions & Intentions::FILEINFO_AUTHENTICODE_SIGNER) + if (HasAnyFlag( + localIntentions, Intentions::FILEINFO_AUTHENTICODE_STATUS | Intentions::FILEINFO_AUTHENTICODE_SIGNER)) { algs |= CryptoHashStream::Algorithm::MD5 | CryptoHashStream::Algorithm::SHA1 | CryptoHashStream::Algorithm::SHA256; @@ -806,19 +805,19 @@ HRESULT PEInfo::OpenPeHash(Intentions localIntentions) ullHashed += ullThisWriteHashed; } - if (algs & CryptoHashStream::Algorithm::MD5 + if (HasFlag(algs, CryptoHashStream::Algorithm::MD5) && FAILED(hr = hashstream->GetHash(CryptoHashStream::Algorithm::MD5, m_FileInfo.GetDetails()->PeMD5()))) { if (hr != MK_E_UNAVAILABLE) return hr; } - if (algs & CryptoHashStream::Algorithm::SHA1 + if (HasFlag(algs, CryptoHashStream::Algorithm::SHA1) && FAILED(hr = hashstream->GetHash(CryptoHashStream::Algorithm::SHA1, m_FileInfo.GetDetails()->PeSHA1()))) { if (hr != MK_E_UNAVAILABLE) return hr; } - if (algs & CryptoHashStream::Algorithm::SHA256 + if (HasFlag(algs, CryptoHashStream::Algorithm::SHA256) && FAILED(hr = hashstream->GetHash(CryptoHashStream::Algorithm::SHA256, m_FileInfo.GetDetails()->PeSHA256()))) { if (hr != MK_E_UNAVAILABLE) diff --git a/src/OrcLib/Partition.cpp b/src/OrcLib/Partition.cpp index 908ae7f7..4193a788 100644 --- a/src/OrcLib/Partition.cpp +++ b/src/OrcLib/Partition.cpp @@ -16,27 +16,27 @@ namespace Orc { bool Partition::IsBootable() const { - return PartitionFlags & Flags::Bootable; + return HasFlag(PartitionFlags, Flags::Bootable); } bool Partition::IsSystem() const { - return PartitionFlags & Flags::System; + return HasFlag(PartitionFlags, Flags::System); } bool Partition::IsReadOnly() const { - return PartitionFlags & Flags::ReadOnly; + return HasFlag(PartitionFlags, Flags::ReadOnly); } bool Partition::IsHidden() const { - return PartitionFlags & Flags::Hidden; + return HasFlag(PartitionFlags, Flags::Hidden); } bool Partition::IsNotAutoMountable() const { - return PartitionFlags & Flags::NoAutoMount; + return HasFlag(PartitionFlags, Flags::NoAutoMount); } bool Partition::IsFAT12() const diff --git a/src/OrcLib/PartitionFlags.cpp b/src/OrcLib/PartitionFlags.cpp index 578773ee..1342ae15 100644 --- a/src/OrcLib/PartitionFlags.cpp +++ b/src/OrcLib/PartitionFlags.cpp @@ -19,37 +19,37 @@ std::wstring ToString(PartitionFlags flags) { std::vector activeFlags; - if (flags & PartitionFlags::Bootable) + if (HasFlag(flags, PartitionFlags::Bootable)) { activeFlags.push_back(L"BOOTABLE"); } - if (flags & PartitionFlags::Hidden) + if (HasFlag(flags, PartitionFlags::Hidden)) { activeFlags.push_back(L"HIDDEN"); } - if (flags & PartitionFlags::Invalid) + if (HasFlag(flags, PartitionFlags::Invalid)) { activeFlags.push_back(L"INVALID"); } - if (flags & PartitionFlags::NoAutoMount) + if (HasFlag(flags, PartitionFlags::NoAutoMount)) { activeFlags.push_back(L"NO_AUTO_MOUNT"); } - if (flags & PartitionFlags::None) + if (HasFlag(flags, PartitionFlags::None)) { activeFlags.push_back(L"NONE"); } - if (flags & PartitionFlags::ReadOnly) + if (HasFlag(flags, PartitionFlags::ReadOnly)) { activeFlags.push_back(L"READONLY"); } - if (flags & PartitionFlags::System) + if (HasFlag(flags, PartitionFlags::System)) { activeFlags.push_back(L"SYSTEM"); } diff --git a/src/OrcLib/PipeStream.cpp b/src/OrcLib/PipeStream.cpp index e50f63fa..ea55ca37 100644 --- a/src/OrcLib/PipeStream.cpp +++ b/src/OrcLib/PipeStream.cpp @@ -64,7 +64,7 @@ __data_entrypoint(File) HRESULT PipeStream::Read( return hr; } } - Log::Debug("ReadFile read {} bytes (hFile={:p})", dwBytesRead, m_hReadPipe); + *pcbBytesRead = dwBytesRead; return S_OK; } diff --git a/src/OrcLib/Privilege.cpp b/src/OrcLib/Privilege.cpp index eed478f4..c1a24ca4 100644 --- a/src/OrcLib/Privilege.cpp +++ b/src/OrcLib/Privilege.cpp @@ -143,7 +143,7 @@ HRESULT Orc::GetMyCurrentSID(PSID& pSid) return hr; } - if (Log::DefaultLogger()->Get(Logger::Facility::kDefault)->level() == spdlog::level::debug) + if (Log::DefaultLogger()->Get(Logger::Facility::kDefault)->Level() == spdlog::level::debug) { LPWSTR pszSid = nullptr; if (!ConvertSidToStringSid(pSid, &pszSid)) diff --git a/src/OrcLib/ProfileList.cpp b/src/OrcLib/ProfileList.cpp index 50f587b4..41d31d70 100644 --- a/src/OrcLib/ProfileList.cpp +++ b/src/OrcLib/ProfileList.cpp @@ -68,11 +68,11 @@ ProfileResult ProfileList::GetProfiles() auto rSID = Registry::Read(hKey, keyName.get(), L"Sid"); if (rSID.has_error()) { - Log::Debug(L"Failed to read SID for profile {}, using key name", keyName.get()); + Log::Warn(L"Failed to read SID for profile using key name: '{}'", keyName.get()); PSID pSID = NULL; if (!ConvertStringSidToSidW(keyName.get(), &pSID)) { - Log::Debug(L"Failed profile key name {} is not a valid sid", keyName.get()); + Log::Error(L"Failed to convert to SID the key '{}'", keyName.get()); continue; } sid.assign((LPBYTE)pSID, GetLengthSid(pSID)); diff --git a/src/OrcLib/Registry.cpp b/src/OrcLib/Registry.cpp index 1ac6bd81..f2190a7d 100644 --- a/src/OrcLib/Registry.cpp +++ b/src/OrcLib/Registry.cpp @@ -25,7 +25,7 @@ Result Orc::Registry::Read(HKEY hParentKey, LPWSTR szKeyName, status != ERROR_SUCCESS) { const auto ec = Win32Error(status); - Log::Error(L"Failed to registry key {} [{}]", szKeyName, ec); + Log::Debug(L"Failed to open registry key {} [{}]", szKeyName, ec); return ec; } } @@ -53,12 +53,12 @@ Result Orc::Registry::Read(HKEY hParentKey, LPWSTR szKeyName, if (status == ERROR_MORE_DATA) { - Log::Error(L"Unexepected registry value '{}' is bigger than expected (ULONG32)", szValueName); + Log::Error(L"Unexpected registry value '{}' is bigger than expected (ULONG32)", szValueName); return ec; } else { - Log::Error(L"Failed to open registry '{}' value [{}]", szValueName, ec); + Log::Debug(L"Failed to open registry value '{}' [{}]", szValueName, ec); return ec; } } @@ -69,7 +69,7 @@ Result Orc::Registry::Read(HKEY hParentKey, LPWSTR szKeyName, if (dwValueType != REG_DWORD || (dwValueType != REG_BINARY && cbBytes != sizeof(ULONG32))) { - Log::Error(L"Unexpected value \"{}\" type (not ULONG32 compatible)", szValueName); + Log::Error(L"Unexpected value '{}' type (not ULONG32 compatible)", szValueName); return Win32Error(ERROR_DATATYPE_MISMATCH); } @@ -87,7 +87,7 @@ Result Orc::Registry::Read(HKEY hParentKey, LPWSTR szKeyName, status != ERROR_SUCCESS) { const auto ec = Win32Error(status); - Log::Error(L"Failed to registry key {} [{}]", szKeyName, ec); + Log::Error(L"Failed to open registry key {} [{}]", szKeyName, ec); return ec; } } @@ -114,12 +114,12 @@ Result Orc::Registry::Read(HKEY hParentKey, LPWSTR szKeyName, const auto ec = Win32Error(status); if (status == ERROR_MORE_DATA) { - Log::Error(L"Unexepected registry value '{}' is bigger than expected (ULONG32)", szValueName); + Log::Error(L"Unexpected registry value '{}' is bigger than expected (ULONG32)", szValueName); return ec; } else { - Log::Error(L"Failed to open registry '{}' value [{}]", szValueName, ec); + Log::Debug(L"Failed to query registry '{}' value [{}]", szValueName, ec); return ec; } } @@ -129,7 +129,7 @@ Result Orc::Registry::Read(HKEY hParentKey, LPWSTR szKeyName, } if (dwValueType != REG_QWORD || (dwValueType != REG_BINARY && cbBytes != sizeof(ULONG64))) { - Log::Error(L"Unexpected value \"{}\" type (not ULONG32 compatible)", szValueName); + Log::Error(L"Unexpected value '{}' type (not ULONG32 compatible)", szValueName); return Win32Error(ERROR_DATATYPE_MISMATCH); } @@ -147,7 +147,7 @@ Result Orc::Registry::Read(HKEY hParentKey, LP status != ERROR_SUCCESS) { const auto ec = Win32Error(status); - Log::Error(L"Failed to registry key {} [{}]", szKeyName, ec); + Log::Debug(L"Failed to open registry key {} [{}]", szKeyName, ec); return ec; } } @@ -178,14 +178,15 @@ Result Orc::Registry::Read(HKEY hParentKey, LP if (auto status = RegQueryValueExW(hKey, szValueName, NULL, NULL, (LPBYTE)valueBuffer.get(), &cbBytes); status != ERROR_SUCCESS) { - Log::Error(L"Failed to reg value '{}:{}' value [{}]", szKeyName ? szKeyName : L"", szValueName, ec); + Log::Debug( + L"Failed to query registry value '{}:{}' value [{}]", szKeyName ? szKeyName : L"", szValueName, ec); return ec; } } else { - Log::Error( - L"Failed to query registry value \"{}:{}\" value [{}]", szKeyName ? szKeyName : L"", szValueName, ec); + Log::Debug( + L"Failed to query registry value '{}:{}' value [{}]", szKeyName ? szKeyName : L"", szValueName, ec); return ec; } } @@ -207,7 +208,7 @@ Result Orc::Registry::Read(HKEY hParentKey, LPWSTR s status != ERROR_SUCCESS) { const auto result = Win32Error(status); - Log::Error(L"Failed to registry key '{}' [{}]", szKeyName, result); + Log::Error(L"Failed to open registry key '{}' [{}]", szKeyName, result); return result; } } @@ -238,13 +239,13 @@ Result Orc::Registry::Read(HKEY hParentKey, LPWSTR s if (auto status = RegQueryValueExW(hKey, szValueName, NULL, NULL, (LPBYTE)valueBuffer.get(), &cbBytes); status != ERROR_SUCCESS) { - Log::Error(L"Failed to reg value '{}' value [{}])", szValueName, ec); + Log::Debug(L"Failed to query registry value '{}' value [{}])", szValueName, ec); return ec; } } else { - Log::Error(L"Failed to open profile list '{}' value [{}]", szValueName, ec); + Log::Debug(L"Failed to query registry value '{}' [{}]", szValueName, ec); return ec; } } diff --git a/src/OrcLib/SystemIdentity.cpp b/src/OrcLib/SystemIdentity.cpp index 80260a04..87f34fa2 100644 --- a/src/OrcLib/SystemIdentity.cpp +++ b/src/OrcLib/SystemIdentity.cpp @@ -121,7 +121,7 @@ Orc::SystemIdentity::CurrentProcess(const std::shared_ptrBeginCollection(L"environment"); BOOST_SCOPE_EXIT(&writer) { writer->EndCollection(L"environment"); } @@ -258,7 +258,7 @@ HRESULT Orc::SystemIdentity::OperatingSystem(const std::shared_ptrBeginCollection(L"qfe"); for (const auto& qfe : qfes.value()) @@ -282,7 +282,7 @@ HRESULT Orc::SystemIdentity::Network(const std::shared_ptrEndElement(elt); } BOOST_SCOPE_EXIT_END; { - if (auto result = SystemDetails::GetNetworkAdapters(); result.has_error()) + if (auto result = SystemDetails::GetNetworkAdapters(); result.has_value()) { writer->BeginCollection(L"adapter"); BOOST_SCOPE_EXIT(&writer, &elt) { writer->EndCollection(L"adapter"); } diff --git a/src/OrcLib/Utils/EnumFlags.h b/src/OrcLib/Utils/EnumFlags.h index c10ac836..1cbecab9 100644 --- a/src/OrcLib/Utils/EnumFlags.h +++ b/src/OrcLib/Utils/EnumFlags.h @@ -10,76 +10,85 @@ // ENABLE_BITMASK_OPERATORS(FilesystemAttributes); // } // -// From http://blog.bitwigglers.org/using-enum-classes-as-type-safe-bitmasks/ -// #include namespace Orc { -template -struct EnableBitMaskOperators +template +struct EnumFlagsOperator : std::false_type { - static const bool enable = false; }; template -typename std::enable_if::enable, bool>::type constexpr operator&(Enum lhs, Enum rhs) +typename std::enable_if::value, Enum>::type constexpr operator&(Enum lhs, Enum rhs) { - using underlying = typename std::underlying_type::type; - return static_cast(lhs) & static_cast(rhs); + using underlying = typename std::underlying_type_t; + return static_cast(static_cast(lhs) & static_cast(rhs)); } template -typename std::enable_if::enable, bool>::type constexpr operator&=(Enum& lhs, Enum rhs) +typename std::enable_if::value, Enum>::type constexpr operator&=(Enum& lhs, Enum rhs) { - using underlying = typename std::underlying_type::type; - lhs = static_cast(lhs) & static_cast(rhs); + using underlying = typename std::underlying_type_t; + lhs = static_cast(static_cast(lhs) & static_cast(rhs)); return lhs; } template -typename std::enable_if::enable, Enum>::type constexpr operator|(Enum lhs, Enum rhs) +typename std::enable_if::value, Enum>::type constexpr operator|(Enum lhs, Enum rhs) { - using underlying = typename std::underlying_type::type; + using underlying = typename std::underlying_type_t; return static_cast(static_cast(lhs) | static_cast(rhs)); } template -typename std::enable_if::enable, Enum>::type constexpr operator|=(Enum& lhs, Enum rhs) +typename std::enable_if::value, Enum>::type constexpr operator|=(Enum& lhs, Enum rhs) { - using underlying = typename std::underlying_type::type; + using underlying = typename std::underlying_type_t; lhs = static_cast(static_cast(lhs) | static_cast(rhs)); return lhs; } template -typename std::enable_if::enable, Enum>::type constexpr operator^(Enum lhs, Enum rhs) +typename std::enable_if::value, Enum>::type constexpr operator^(Enum lhs, Enum rhs) { - using underlying = typename std::underlying_type::type; + using underlying = typename std::underlying_type_t; return static_cast(static_cast(lhs) ^ static_cast(rhs)); } template -typename std::enable_if::enable, Enum>::type constexpr operator^=(Enum& lhs, Enum rhs) +typename std::enable_if::value, Enum>::type constexpr operator^=(Enum& lhs, Enum rhs) { - using underlying = typename std::underlying_type::type; + using underlying = typename std::underlying_type_t; lhs = static_cast(static_cast(lhs) ^ static_cast(rhs)); return lhs; } template -typename std::enable_if::enable, Enum>::type constexpr operator~(Enum value) +typename std::enable_if::value, Enum>::type constexpr operator~(Enum value) { - using underlying = typename std::underlying_type::type; - return static_cast(static_cast(value)); + using underlying = typename std::underlying_type_t; + return static_cast(~static_cast(value)); } #define ENABLE_BITMASK_OPERATORS(x) \ template <> \ - struct EnableBitMaskOperators \ + struct EnumFlagsOperator : public std::true_type \ { \ - static const bool enable = true; \ }; +template +inline typename std::enable_if::value, bool>::type HasFlag(Enum value, Enum flag) +{ + return (value & flag) == flag; +} + +template +inline typename std::enable_if::value, bool>::type HasAnyFlag(Enum value, Enum flag) +{ + using underlying = typename std::underlying_type_t; + return (static_cast(value) & static_cast(flag)) != 0; +} + } // namespace Orc diff --git a/src/OrcLib/ZipCreate.cpp b/src/OrcLib/ZipCreate.cpp index 41468540..a7dee040 100644 --- a/src/OrcLib/ZipCreate.cpp +++ b/src/OrcLib/ZipCreate.cpp @@ -110,8 +110,11 @@ HRESULT ZipCreate::SetCompressionLevel(const CComPtr& pArchiver, Co { HRESULT hr = E_FAIL; + Log::Debug(L"ZipCreate: {}: set compression level to {}", m_ArchiveName, level); + if (!pArchiver) { + Log::Error("ZipCreate: Failed to update compression level: invalid pointer"); return E_POINTER; } @@ -121,10 +124,16 @@ HRESULT ZipCreate::SetCompressionLevel(const CComPtr& pArchiver, Co CComPtr setter; if (FAILED(hr = pArchiver->QueryInterface(IID_ISetProperties, reinterpret_cast(&setter)))) + { + Log::Error("Failed to retrieve IID_ISetProperties [{}]", SystemError(hr)); return hr; + } if (FAILED(hr = setter->SetProperties(names, values, numProps))) + { + Log::Error("Failed to set properties [{}]", SystemError(hr)); return hr; + } return S_OK; } @@ -181,9 +190,16 @@ ZipCreate::InitArchive(__in const std::shared_ptr& pOutputStream, Or return S_OK; } -HRESULT ZipCreate::SetCompressionLevel(__in const std::wstring& strLevel) +HRESULT ZipCreate::SetCompressionLevel(__in const std::wstring& level) { - m_CompressionLevel = GetCompressionLevel(strLevel); + if (level.empty()) + { + Log::Debug(L"Specified compression level is empty"); + return S_OK; + } + + Log::Debug(L"Updated internal compression level to {}", level); + m_CompressionLevel = GetCompressionLevel(level); return S_OK; } @@ -210,7 +226,10 @@ STDMETHODIMP ZipCreate::Internal_FlushQueue(bool bFinal) } if (FAILED(hr = SetCompressionLevel(pArchiver, m_CompressionLevel))) + { + Log::Error(L"Failed to set compression level to {} [{}]", m_CompressionLevel, SystemError(hr)); return hr; + } if (pArchiver == nullptr) return E_NOT_VALID_STATE;