From d977ac231e995250c169ac1778b7de34f7f57ead Mon Sep 17 00:00:00 2001 From: Robert Schumacher Date: Sat, 7 Jul 2018 02:55:03 -0700 Subject: [vcpkg] Remove vcpkg::Archives from vcpkg::base. Add vcpkg::Hash. --- toolsrc/include/vcpkg/archives.h | 9 ++ toolsrc/include/vcpkg/base/archives.h | 9 -- toolsrc/include/vcpkg/base/downloads.h | 32 ++-- toolsrc/include/vcpkg/base/hash.h | 11 ++ toolsrc/include/vcpkg/commands.h | 3 - toolsrc/src/vcpkg/archives.cpp | 106 +++++++++++++ toolsrc/src/vcpkg/base/archives.cpp | 106 ------------- toolsrc/src/vcpkg/base/downloads.cpp | 17 ++- toolsrc/src/vcpkg/base/hash.cpp | 214 ++++++++++++++++++++++++++ toolsrc/src/vcpkg/build.cpp | 10 +- toolsrc/src/vcpkg/commands.cpp | 25 +++ toolsrc/src/vcpkg/commands.hash.cpp | 244 ------------------------------ toolsrc/src/vcpkg/metrics.cpp | 3 +- toolsrc/src/vcpkg/tools.cpp | 5 +- toolsrc/vcpkglib/vcpkglib.vcxproj | 7 +- toolsrc/vcpkglib/vcpkglib.vcxproj.filters | 31 ++-- 16 files changed, 424 insertions(+), 408 deletions(-) create mode 100644 toolsrc/include/vcpkg/archives.h delete mode 100644 toolsrc/include/vcpkg/base/archives.h create mode 100644 toolsrc/include/vcpkg/base/hash.h create mode 100644 toolsrc/src/vcpkg/archives.cpp delete mode 100644 toolsrc/src/vcpkg/base/archives.cpp create mode 100644 toolsrc/src/vcpkg/base/hash.cpp delete mode 100644 toolsrc/src/vcpkg/commands.hash.cpp diff --git a/toolsrc/include/vcpkg/archives.h b/toolsrc/include/vcpkg/archives.h new file mode 100644 index 000000000..2298f9e1e --- /dev/null +++ b/toolsrc/include/vcpkg/archives.h @@ -0,0 +1,9 @@ +#pragma once + +#include +#include + +namespace vcpkg::Archives +{ + void extract_archive(const VcpkgPaths& paths, const fs::path& archive, const fs::path& to_path); +} diff --git a/toolsrc/include/vcpkg/base/archives.h b/toolsrc/include/vcpkg/base/archives.h deleted file mode 100644 index cfb9f84c0..000000000 --- a/toolsrc/include/vcpkg/base/archives.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once - -#include -#include - -namespace vcpkg::Archives -{ - void extract_archive(const VcpkgPaths& paths, const fs::path& archive, const fs::path& to_path); -} diff --git a/toolsrc/include/vcpkg/base/downloads.h b/toolsrc/include/vcpkg/base/downloads.h index f30e865a6..61c792488 100644 --- a/toolsrc/include/vcpkg/base/downloads.h +++ b/toolsrc/include/vcpkg/base/downloads.h @@ -1,16 +1,16 @@ -#pragma once - -#include - -namespace vcpkg::Downloads -{ - void verify_downloaded_file_hash(const Files::Filesystem& fs, - const std::string& url, - const fs::path& path, - const std::string& sha512); - - void download_file(vcpkg::Files::Filesystem& fs, - const std::string& url, - const fs::path& download_path, - const std::string& sha512); -} +#pragma once + +#include + +namespace vcpkg::Downloads +{ + void verify_downloaded_file_hash(const Files::Filesystem& fs, + const std::string& url, + const fs::path& path, + const std::string& sha512); + + void download_file(Files::Filesystem& fs, + const std::string& url, + const fs::path& download_path, + const std::string& sha512); +} diff --git a/toolsrc/include/vcpkg/base/hash.h b/toolsrc/include/vcpkg/base/hash.h new file mode 100644 index 000000000..9e6f118c0 --- /dev/null +++ b/toolsrc/include/vcpkg/base/hash.h @@ -0,0 +1,11 @@ +#pragma once + +#include + +#include + +namespace vcpkg::Hash +{ + std::string get_string_hash(const std::string& s, const std::string& hash_type); + std::string get_file_hash(const Files::Filesystem& fs, const fs::path& path, const std::string& hash_type); +} diff --git a/toolsrc/include/vcpkg/commands.h b/toolsrc/include/vcpkg/commands.h index 78b4dda50..57bd83db9 100644 --- a/toolsrc/include/vcpkg/commands.h +++ b/toolsrc/include/vcpkg/commands.h @@ -131,9 +131,6 @@ namespace vcpkg::Commands namespace Hash { - std::string get_string_hash(const std::string& s, const std::string& hash_type); - std::string get_file_hash(const Files::Filesystem& fs, const fs::path& path, const std::string& hash_type); - void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths); } diff --git a/toolsrc/src/vcpkg/archives.cpp b/toolsrc/src/vcpkg/archives.cpp new file mode 100644 index 000000000..8943893d6 --- /dev/null +++ b/toolsrc/src/vcpkg/archives.cpp @@ -0,0 +1,106 @@ +#include "pch.h" + +#include +#include + +namespace vcpkg::Archives +{ + void extract_archive(const VcpkgPaths& paths, const fs::path& archive, const fs::path& to_path) + { + Files::Filesystem& fs = paths.get_filesystem(); + const fs::path to_path_partial = to_path.u8string() + ".partial"; + + std::error_code ec; + fs.remove_all(to_path, ec); + fs.remove_all(to_path_partial, ec); + fs.create_directories(to_path_partial, ec); + const auto ext = archive.extension(); +#if defined(_WIN32) + if (ext == ".nupkg") + { + static bool recursion_limiter_sevenzip_old = false; + Checks::check_exit(VCPKG_LINE_INFO, !recursion_limiter_sevenzip_old); + recursion_limiter_sevenzip_old = true; + const auto nuget_exe = paths.get_tool_exe(Tools::NUGET); + + const std::string stem = archive.stem().u8string(); + // assuming format of [name].[version in the form d.d.d] + // This assumption may not always hold + std::smatch match; + const bool has_match = std::regex_match(stem, match, std::regex{R"###(^(.+)\.(\d+\.\d+\.\d+)$)###"}); + Checks::check_exit(VCPKG_LINE_INFO, + has_match, + "Could not deduce nuget id and version from filename: %s", + archive.u8string()); + + const std::string nugetid = match[1]; + const std::string version = match[2]; + + const auto code_and_output = System::cmd_execute_and_capture_output(Strings::format( + R"("%s" install %s -Version %s -OutputDirectory "%s" -Source "%s" -nocache -DirectDownload -NonInteractive -ForceEnglishOutput -PackageSaveMode nuspec)", + nuget_exe.u8string(), + nugetid, + version, + to_path_partial.u8string(), + paths.downloads.u8string())); + + Checks::check_exit(VCPKG_LINE_INFO, + code_and_output.exit_code == 0, + "Failed to extract '%s' with message:\n%s", + archive.u8string(), + code_and_output.output); + recursion_limiter_sevenzip_old = false; + } + else + { + static bool recursion_limiter_sevenzip = false; + Checks::check_exit(VCPKG_LINE_INFO, !recursion_limiter_sevenzip); + recursion_limiter_sevenzip = true; + const auto seven_zip = paths.get_tool_exe(Tools::SEVEN_ZIP); + const auto code_and_output = System::cmd_execute_and_capture_output(Strings::format( + R"("%s" x "%s" -o"%s" -y)", seven_zip.u8string(), archive.u8string(), to_path_partial.u8string())); + Checks::check_exit(VCPKG_LINE_INFO, + code_and_output.exit_code == 0, + "7zip failed while extracting '%s' with message:\n%s", + archive.u8string(), + code_and_output.output); + recursion_limiter_sevenzip = false; + } +#else + if (ext == ".gz" && ext.extension() != ".tar") + { + const auto code = System::cmd_execute( + Strings::format(R"(cd '%s' && tar xzf '%s')", to_path_partial.u8string(), archive.u8string())); + Checks::check_exit(VCPKG_LINE_INFO, code == 0, "tar failed while extracting %s", archive.u8string()); + } + else if (ext == ".zip") + { + const auto code = System::cmd_execute( + Strings::format(R"(cd '%s' && unzip -qqo '%s')", to_path_partial.u8string(), archive.u8string())); + Checks::check_exit(VCPKG_LINE_INFO, code == 0, "unzip failed while extracting %s", archive.u8string()); + } + else + { + Checks::exit_with_message(VCPKG_LINE_INFO, "Unexpected archive extension: %s", ext.u8string()); + } +#endif + + fs.rename(to_path_partial, to_path, ec); + + for (int i = 0; i < 5 && ec; i++) + { + i++; + using namespace std::chrono_literals; + std::this_thread::sleep_for(i * 100ms); + fs.rename(to_path_partial, to_path, ec); + } + + Checks::check_exit(VCPKG_LINE_INFO, + !ec, + "Failed to do post-extract rename-in-place.\n" + "fs.rename(%s, %s, %s)", + to_path_partial.u8string(), + to_path.u8string(), + ec.message()); + } +} diff --git a/toolsrc/src/vcpkg/base/archives.cpp b/toolsrc/src/vcpkg/base/archives.cpp deleted file mode 100644 index 5d0f1c7a1..000000000 --- a/toolsrc/src/vcpkg/base/archives.cpp +++ /dev/null @@ -1,106 +0,0 @@ -#include "pch.h" - -#include -#include - -namespace vcpkg::Archives -{ - void extract_archive(const VcpkgPaths& paths, const fs::path& archive, const fs::path& to_path) - { - Files::Filesystem& fs = paths.get_filesystem(); - const fs::path to_path_partial = to_path.u8string() + ".partial"; - - std::error_code ec; - fs.remove_all(to_path, ec); - fs.remove_all(to_path_partial, ec); - fs.create_directories(to_path_partial, ec); - const auto ext = archive.extension(); -#if defined(_WIN32) - if (ext == ".nupkg") - { - static bool recursion_limiter_sevenzip_old = false; - Checks::check_exit(VCPKG_LINE_INFO, !recursion_limiter_sevenzip_old); - recursion_limiter_sevenzip_old = true; - const auto nuget_exe = paths.get_tool_exe(Tools::NUGET); - - const std::string stem = archive.stem().u8string(); - // assuming format of [name].[version in the form d.d.d] - // This assumption may not always hold - std::smatch match; - const bool has_match = std::regex_match(stem, match, std::regex{R"###(^(.+)\.(\d+\.\d+\.\d+)$)###"}); - Checks::check_exit(VCPKG_LINE_INFO, - has_match, - "Could not deduce nuget id and version from filename: %s", - archive.u8string()); - - const std::string nugetid = match[1]; - const std::string version = match[2]; - - const auto code_and_output = System::cmd_execute_and_capture_output(Strings::format( - R"("%s" install %s -Version %s -OutputDirectory "%s" -Source "%s" -nocache -DirectDownload -NonInteractive -ForceEnglishOutput -PackageSaveMode nuspec)", - nuget_exe.u8string(), - nugetid, - version, - to_path_partial.u8string(), - paths.downloads.u8string())); - - Checks::check_exit(VCPKG_LINE_INFO, - code_and_output.exit_code == 0, - "Failed to extract '%s' with message:\n%s", - archive.u8string(), - code_and_output.output); - recursion_limiter_sevenzip_old = false; - } - else - { - static bool recursion_limiter_sevenzip = false; - Checks::check_exit(VCPKG_LINE_INFO, !recursion_limiter_sevenzip); - recursion_limiter_sevenzip = true; - const auto seven_zip = paths.get_tool_exe(Tools::SEVEN_ZIP); - const auto code_and_output = System::cmd_execute_and_capture_output(Strings::format( - R"("%s" x "%s" -o"%s" -y)", seven_zip.u8string(), archive.u8string(), to_path_partial.u8string())); - Checks::check_exit(VCPKG_LINE_INFO, - code_and_output.exit_code == 0, - "7zip failed while extracting '%s' with message:\n%s", - archive.u8string(), - code_and_output.output); - recursion_limiter_sevenzip = false; - } -#else - if (ext == ".gz" && ext.extension() != ".tar") - { - const auto code = System::cmd_execute( - Strings::format(R"(cd '%s' && tar xzf '%s')", to_path_partial.u8string(), archive.u8string())); - Checks::check_exit(VCPKG_LINE_INFO, code == 0, "tar failed while extracting %s", archive.u8string()); - } - else if (ext == ".zip") - { - const auto code = System::cmd_execute( - Strings::format(R"(cd '%s' && unzip -qqo '%s')", to_path_partial.u8string(), archive.u8string())); - Checks::check_exit(VCPKG_LINE_INFO, code == 0, "unzip failed while extracting %s", archive.u8string()); - } - else - { - Checks::exit_with_message(VCPKG_LINE_INFO, "Unexpected archive extension: %s", ext.u8string()); - } -#endif - - fs.rename(to_path_partial, to_path, ec); - - for (int i = 0; i < 5 && ec; i++) - { - i++; - using namespace std::chrono_literals; - std::this_thread::sleep_for(i * 100ms); - fs.rename(to_path_partial, to_path, ec); - } - - Checks::check_exit(VCPKG_LINE_INFO, - !ec, - "Failed to do post-extract rename-in-place.\n" - "fs.rename(%s, %s, %s)", - to_path_partial.u8string(), - to_path.u8string(), - ec.message()); - } -} diff --git a/toolsrc/src/vcpkg/base/downloads.cpp b/toolsrc/src/vcpkg/base/downloads.cpp index 746e457d3..1d7b3527d 100644 --- a/toolsrc/src/vcpkg/base/downloads.cpp +++ b/toolsrc/src/vcpkg/base/downloads.cpp @@ -1,11 +1,13 @@ #include "pch.h" #include +#include #include -#include #if defined(_WIN32) #include +#else +#include #endif namespace vcpkg::Downloads @@ -32,10 +34,12 @@ namespace vcpkg::Downloads target_file_path, std::to_string(err)); - auto hSession = WinHttpOpen( - L"vcpkg/1.0", - IsWindows8Point1OrGreater() ? WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY : WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, - WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0); + auto hSession = WinHttpOpen(L"vcpkg/1.0", + IsWindows8Point1OrGreater() ? WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY + : WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, + WINHTTP_NO_PROXY_NAME, + WINHTTP_NO_PROXY_BYPASS, + 0); Checks::check_exit(VCPKG_LINE_INFO, hSession, "WinHttpOpen() failed: %d", GetLastError()); // Use Windows 10 defaults on Windows 7 @@ -98,7 +102,7 @@ namespace vcpkg::Downloads const fs::path& path, const std::string& sha512) { - const std::string actual_hash = Commands::Hash::get_file_hash(fs, path, "SHA512"); + const std::string actual_hash = vcpkg::Hash::get_file_hash(fs, path, "SHA512"); Checks::check_exit(VCPKG_LINE_INFO, sha512 == actual_hash, "File does not have the expected hash:\n" @@ -144,5 +148,4 @@ namespace vcpkg::Downloads download_path.u8string(), ec.message()); } - } diff --git a/toolsrc/src/vcpkg/base/hash.cpp b/toolsrc/src/vcpkg/base/hash.cpp new file mode 100644 index 000000000..31bd8d05e --- /dev/null +++ b/toolsrc/src/vcpkg/base/hash.cpp @@ -0,0 +1,214 @@ +#include "pch.h" + +#include +#include +#include +#include + +#if defined(_WIN32) +#include + +#ifndef NT_SUCCESS +#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0) +#endif +#endif + +namespace vcpkg::Hash +{ + static void verify_has_only_allowed_chars(const std::string& s) + { + static const std::regex ALLOWED_CHARS{"^[a-zA-Z0-9-]*$"}; + Checks::check_exit(VCPKG_LINE_INFO, + std::regex_match(s, ALLOWED_CHARS), + "Only alphanumeric chars and dashes are currently allowed. String was:\n" + " % s", + s); + } +#if defined(_WIN32) + namespace + { + std::string to_hex(const unsigned char* string, const size_t bytes) + { + static constexpr char HEX_MAP[] = "0123456789abcdef"; + + std::string output; + output.resize(2 * bytes); + + size_t current_char = 0; + for (size_t i = 0; i < bytes; i++) + { + // high + output[current_char] = HEX_MAP[(string[i] & 0xF0) >> 4]; + ++current_char; + // low + output[current_char] = HEX_MAP[(string[i] & 0x0F)]; + ++current_char; + } + + return output; + } + + class BCryptHasher + { + struct BCryptAlgorithmHandle : Util::ResourceBase + { + BCRYPT_ALG_HANDLE handle = nullptr; + + ~BCryptAlgorithmHandle() + { + if (handle) BCryptCloseAlgorithmProvider(handle, 0); + } + }; + + struct BCryptHashHandle : Util::ResourceBase + { + BCRYPT_HASH_HANDLE handle = nullptr; + + ~BCryptHashHandle() + { + if (handle) BCryptDestroyHash(handle); + } + }; + + static void initialize_hash_handle(BCryptHashHandle& hash_handle, + const BCryptAlgorithmHandle& algorithm_handle) + { + const NTSTATUS error_code = + BCryptCreateHash(algorithm_handle.handle, &hash_handle.handle, nullptr, 0, nullptr, 0, 0); + Checks::check_exit(VCPKG_LINE_INFO, NT_SUCCESS(error_code), "Failed to initialize the hasher"); + } + + static void hash_data(BCryptHashHandle& hash_handle, const unsigned char* buffer, const size_t& data_size) + { + const NTSTATUS error_code = BCryptHashData( + hash_handle.handle, const_cast(buffer), static_cast(data_size), 0); + Checks::check_exit(VCPKG_LINE_INFO, NT_SUCCESS(error_code), "Failed to hash data"); + } + + static std::string finalize_hash_handle(const BCryptHashHandle& hash_handle, const ULONG length_in_bytes) + { + std::unique_ptr hash_buffer = std::make_unique(length_in_bytes); + const NTSTATUS error_code = BCryptFinishHash(hash_handle.handle, hash_buffer.get(), length_in_bytes, 0); + Checks::check_exit(VCPKG_LINE_INFO, NT_SUCCESS(error_code), "Failed to finalize the hash"); + return to_hex(hash_buffer.get(), length_in_bytes); + } + + public: + explicit BCryptHasher(const std::string& hash_type) + { + NTSTATUS error_code = + BCryptOpenAlgorithmProvider(&this->algorithm_handle.handle, + Strings::to_utf16(Strings::ascii_to_uppercase(hash_type)).c_str(), + nullptr, + 0); + Checks::check_exit(VCPKG_LINE_INFO, NT_SUCCESS(error_code), "Failed to open the algorithm provider"); + + DWORD hash_buffer_bytes; + DWORD cb_data; + error_code = BCryptGetProperty(this->algorithm_handle.handle, + BCRYPT_HASH_LENGTH, + reinterpret_cast(&hash_buffer_bytes), + sizeof(DWORD), + &cb_data, + 0); + Checks::check_exit(VCPKG_LINE_INFO, NT_SUCCESS(error_code), "Failed to get hash length"); + this->length_in_bytes = hash_buffer_bytes; + } + + std::string hash_file(const fs::path& path) const + { + BCryptHashHandle hash_handle; + initialize_hash_handle(hash_handle, this->algorithm_handle); + + FILE* file = nullptr; + const auto ec = _wfopen_s(&file, path.c_str(), L"rb"); + Checks::check_exit(VCPKG_LINE_INFO, ec == 0, "Failed to open file: %s", path.u8string()); + if (file != nullptr) + { + unsigned char buffer[4096]; + while (const auto actual_size = fread(buffer, 1, sizeof(buffer), file)) + { + hash_data(hash_handle, buffer, actual_size); + } + fclose(file); + } + + return finalize_hash_handle(hash_handle, length_in_bytes); + } + + std::string hash_string(const std::string& s) const + { + BCryptHashHandle hash_handle; + initialize_hash_handle(hash_handle, this->algorithm_handle); + hash_data(hash_handle, reinterpret_cast(s.c_str()), s.size()); + return finalize_hash_handle(hash_handle, length_in_bytes); + } + + private: + BCryptAlgorithmHandle algorithm_handle; + ULONG length_in_bytes; + }; + } + + std::string get_file_hash(const Files::Filesystem& fs, const fs::path& path, const std::string& hash_type) + { + Checks::check_exit(VCPKG_LINE_INFO, fs.exists(path), "File %s does not exist", path.u8string()); + return BCryptHasher{hash_type}.hash_file(path); + } + + std::string get_string_hash(const std::string& s, const std::string& hash_type) + { + verify_has_only_allowed_chars(s); + return BCryptHasher{hash_type}.hash_string(s); + } + +#else + static std::string get_digest_size(const std::string& hash_type) + { + if (!Strings::case_insensitive_ascii_starts_with(hash_type, "SHA")) + { + Checks::exit_with_message( + VCPKG_LINE_INFO, "shasum only supports SHA hashes, but %s was provided", hash_type); + } + + return hash_type.substr(3, hash_type.length() - 3); + } + + static std::string run_shasum_and_post_process(const std::string& cmd_line) + { + const auto ec_data = System::cmd_execute_and_capture_output(cmd_line); + Checks::check_exit(VCPKG_LINE_INFO, + ec_data.exit_code == 0, + "Failed to run:\n" + " %s", + cmd_line); + + std::vector split = Strings::split(ec_data.output, " "); + Checks::check_exit(VCPKG_LINE_INFO, + split.size() == 3, + "Expected output of the form [hash filename\n] (3 tokens), but got\n" + "[%s] (%s tokens)", + ec_data.output, + std::to_string(split.size())); + + return split[0]; + } + + std::string get_file_hash(const Files::Filesystem& fs, const fs::path& path, const std::string& hash_type) + { + const std::string digest_size = get_digest_size(hash_type); + Checks::check_exit(VCPKG_LINE_INFO, fs.exists(path), "File %s does not exist", path.u8string()); + const std::string cmd_line = Strings::format(R"(shasum -a %s "%s")", digest_size, path.u8string()); + return run_shasum_and_post_process(cmd_line); + } + + std::string get_string_hash(const std::string& s, const std::string& hash_type) + { + const std::string digest_size = get_digest_size(hash_type); + verify_has_only_allowed_chars(s); + + const std::string cmd_line = Strings::format(R"(echo -n "%s" | shasum -a %s)", s, digest_size); + return run_shasum_and_post_process(cmd_line); + } +#endif +} diff --git a/toolsrc/src/vcpkg/build.cpp b/toolsrc/src/vcpkg/build.cpp index 4e7a58048..dc7653795 100644 --- a/toolsrc/src/vcpkg/build.cpp +++ b/toolsrc/src/vcpkg/build.cpp @@ -1,11 +1,13 @@ #include "pch.h" +#include #include #include #include #include #include #include + #include #include #include @@ -467,9 +469,9 @@ namespace vcpkg::Build abi_tag_entries.insert(abi_tag_entries.end(), dependency_abis.begin(), dependency_abis.end()); abi_tag_entries.emplace_back( - AbiEntry{"portfile", Commands::Hash::get_file_hash(fs, config.port_dir / "portfile.cmake", "SHA1")}); + AbiEntry{"portfile", vcpkg::Hash::get_file_hash(fs, config.port_dir / "portfile.cmake", "SHA1")}); abi_tag_entries.emplace_back( - AbiEntry{"control", Commands::Hash::get_file_hash(fs, config.port_dir / "CONTROL", "SHA1")}); + AbiEntry{"control", vcpkg::Hash::get_file_hash(fs, config.port_dir / "CONTROL", "SHA1")}); if (pre_build_info.cmake_system_name == "Linux") { @@ -509,7 +511,7 @@ namespace vcpkg::Build const auto abi_file_path = paths.buildtrees / name / (triplet.canonical_name() + ".vcpkg_abi_info.txt"); fs.write_contents(abi_file_path, full_abi_info); - return AbiTagAndFile{Commands::Hash::get_file_hash(fs, abi_file_path, "SHA1"), abi_file_path}; + return AbiTagAndFile{Hash::get_file_hash(fs, abi_file_path, "SHA1"), abi_file_path}; } System::println( @@ -804,7 +806,7 @@ namespace vcpkg::Build { return it_hash->second; } - auto hash = Commands::Hash::get_file_hash(paths.get_filesystem(), triplet_file_path, "SHA1"); + auto hash = Hash::get_file_hash(paths.get_filesystem(), triplet_file_path, "SHA1"); s_hash_cache.emplace(triplet_file_path, hash); return hash; diff --git a/toolsrc/src/vcpkg/commands.cpp b/toolsrc/src/vcpkg/commands.cpp index 76fdf54fc..7204b6e78 100644 --- a/toolsrc/src/vcpkg/commands.cpp +++ b/toolsrc/src/vcpkg/commands.cpp @@ -1,5 +1,7 @@ #include "pch.h" +#include + #include #include #include @@ -78,3 +80,26 @@ namespace vcpkg::Commands::Fetch Checks::exit_success(VCPKG_LINE_INFO); } } + +namespace vcpkg::Commands::Hash +{ + const CommandStructure COMMAND_STRUCTURE = { + Strings::format("The argument should be a file path\n%s", + Help::create_example_string("hash boost_1_62_0.tar.bz2")), + 1, + 2, + {}, + nullptr, + }; + + void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths) + { + Util::unused(args.parse_arguments(COMMAND_STRUCTURE)); + + const fs::path file_to_hash = args.command_arguments[0]; + const std::string algorithm = args.command_arguments.size() == 2 ? args.command_arguments[1] : "SHA512"; + const std::string hash = vcpkg::Hash::get_file_hash(paths.get_filesystem(), file_to_hash, algorithm); + System::println(hash); + Checks::exit_success(VCPKG_LINE_INFO); + } +} diff --git a/toolsrc/src/vcpkg/commands.hash.cpp b/toolsrc/src/vcpkg/commands.hash.cpp deleted file mode 100644 index 0c7aa72c4..000000000 --- a/toolsrc/src/vcpkg/commands.hash.cpp +++ /dev/null @@ -1,244 +0,0 @@ -#include "pch.h" - -#include -#include -#include -#include -#include -#include - -namespace vcpkg::Commands::Hash -{ - static void verify_has_only_allowed_chars(const std::string& s) - { - static const std::regex ALLOWED_CHARS{"^[a-zA-Z0-9-]*$"}; - Checks::check_exit(VCPKG_LINE_INFO, - std::regex_match(s, ALLOWED_CHARS), - "Only alphanumeric chars and dashes are currently allowed. String was:\n" - " % s", - s); - } -} - -#if defined(_WIN32) -#include - -#ifndef NT_SUCCESS -#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0) -#endif - -namespace vcpkg::Commands::Hash -{ - namespace - { - std::string to_hex(const unsigned char* string, const size_t bytes) - { - static constexpr char HEX_MAP[] = "0123456789abcdef"; - - std::string output; - output.resize(2 * bytes); - - size_t current_char = 0; - for (size_t i = 0; i < bytes; i++) - { - // high - output[current_char] = HEX_MAP[(string[i] & 0xF0) >> 4]; - ++current_char; - // low - output[current_char] = HEX_MAP[(string[i] & 0x0F)]; - ++current_char; - } - - return output; - } - - class BCryptHasher - { - struct BCryptAlgorithmHandle : Util::ResourceBase - { - BCRYPT_ALG_HANDLE handle = nullptr; - - ~BCryptAlgorithmHandle() - { - if (handle) BCryptCloseAlgorithmProvider(handle, 0); - } - }; - - struct BCryptHashHandle : Util::ResourceBase - { - BCRYPT_HASH_HANDLE handle = nullptr; - - ~BCryptHashHandle() - { - if (handle) BCryptDestroyHash(handle); - } - }; - - static void initialize_hash_handle(BCryptHashHandle& hash_handle, - const BCryptAlgorithmHandle& algorithm_handle) - { - const NTSTATUS error_code = - BCryptCreateHash(algorithm_handle.handle, &hash_handle.handle, nullptr, 0, nullptr, 0, 0); - Checks::check_exit(VCPKG_LINE_INFO, NT_SUCCESS(error_code), "Failed to initialize the hasher"); - } - - static void hash_data(BCryptHashHandle& hash_handle, const unsigned char* buffer, const size_t& data_size) - { - const NTSTATUS error_code = BCryptHashData( - hash_handle.handle, const_cast(buffer), static_cast(data_size), 0); - Checks::check_exit(VCPKG_LINE_INFO, NT_SUCCESS(error_code), "Failed to hash data"); - } - - static std::string finalize_hash_handle(const BCryptHashHandle& hash_handle, const ULONG length_in_bytes) - { - std::unique_ptr hash_buffer = std::make_unique(length_in_bytes); - const NTSTATUS error_code = BCryptFinishHash(hash_handle.handle, hash_buffer.get(), length_in_bytes, 0); - Checks::check_exit(VCPKG_LINE_INFO, NT_SUCCESS(error_code), "Failed to finalize the hash"); - return to_hex(hash_buffer.get(), length_in_bytes); - } - - public: - explicit BCryptHasher(const std::string& hash_type) - { - NTSTATUS error_code = - BCryptOpenAlgorithmProvider(&this->algorithm_handle.handle, - Strings::to_utf16(Strings::ascii_to_uppercase(hash_type)).c_str(), - nullptr, - 0); - Checks::check_exit(VCPKG_LINE_INFO, NT_SUCCESS(error_code), "Failed to open the algorithm provider"); - - DWORD hash_buffer_bytes; - DWORD cb_data; - error_code = BCryptGetProperty(this->algorithm_handle.handle, - BCRYPT_HASH_LENGTH, - reinterpret_cast(&hash_buffer_bytes), - sizeof(DWORD), - &cb_data, - 0); - Checks::check_exit(VCPKG_LINE_INFO, NT_SUCCESS(error_code), "Failed to get hash length"); - this->length_in_bytes = hash_buffer_bytes; - } - - std::string hash_file(const fs::path& path) const - { - BCryptHashHandle hash_handle; - initialize_hash_handle(hash_handle, this->algorithm_handle); - - FILE* file = nullptr; - const auto ec = _wfopen_s(&file, path.c_str(), L"rb"); - Checks::check_exit(VCPKG_LINE_INFO, ec == 0, "Failed to open file: %s", path.u8string()); - if (file != nullptr) - { - unsigned char buffer[4096]; - while (const auto actual_size = fread(buffer, 1, sizeof(buffer), file)) - { - hash_data(hash_handle, buffer, actual_size); - } - fclose(file); - } - - return finalize_hash_handle(hash_handle, length_in_bytes); - } - - std::string hash_string(const std::string& s) const - { - BCryptHashHandle hash_handle; - initialize_hash_handle(hash_handle, this->algorithm_handle); - hash_data(hash_handle, reinterpret_cast(s.c_str()), s.size()); - return finalize_hash_handle(hash_handle, length_in_bytes); - } - - private: - BCryptAlgorithmHandle algorithm_handle; - ULONG length_in_bytes; - }; - } - - std::string get_file_hash(const Files::Filesystem& fs, const fs::path& path, const std::string& hash_type) - { - Checks::check_exit(VCPKG_LINE_INFO, fs.exists(path), "File %s does not exist", path.u8string()); - return BCryptHasher{hash_type}.hash_file(path); - } - - std::string get_string_hash(const std::string& s, const std::string& hash_type) - { - verify_has_only_allowed_chars(s); - return BCryptHasher{hash_type}.hash_string(s); - } -} - -#else -namespace vcpkg::Commands::Hash -{ - static std::string get_digest_size(const std::string& hash_type) - { - if (!Strings::case_insensitive_ascii_starts_with(hash_type, "SHA")) - { - Checks::exit_with_message( - VCPKG_LINE_INFO, "shasum only supports SHA hashes, but %s was provided", hash_type); - } - - return hash_type.substr(3, hash_type.length() - 3); - } - - static std::string run_shasum_and_post_process(const std::string& cmd_line) - { - const auto ec_data = System::cmd_execute_and_capture_output(cmd_line); - Checks::check_exit(VCPKG_LINE_INFO, - ec_data.exit_code == 0, - "Failed to run:\n" - " %s", - cmd_line); - - std::vector split = Strings::split(ec_data.output, " "); - Checks::check_exit(VCPKG_LINE_INFO, - split.size() == 3, - "Expected output of the form [hash filename\n] (3 tokens), but got\n" - "[%s] (%s tokens)", - ec_data.output, - std::to_string(split.size())); - - return split[0]; - } - - std::string get_file_hash(const Files::Filesystem& fs, const fs::path& path, const std::string& hash_type) - { - const std::string digest_size = get_digest_size(hash_type); - Checks::check_exit(VCPKG_LINE_INFO, fs.exists(path), "File %s does not exist", path.u8string()); - const std::string cmd_line = Strings::format(R"(shasum -a %s "%s")", digest_size, path.u8string()); - return run_shasum_and_post_process(cmd_line); - } - - std::string get_string_hash(const std::string& s, const std::string& hash_type) - { - const std::string digest_size = get_digest_size(hash_type); - verify_has_only_allowed_chars(s); - - const std::string cmd_line = Strings::format(R"(echo -n "%s" | shasum -a %s)", s, digest_size); - return run_shasum_and_post_process(cmd_line); - } -} -#endif - -namespace vcpkg::Commands::Hash -{ - const CommandStructure COMMAND_STRUCTURE = { - Strings::format("The argument should be a file path\n%s", - Help::create_example_string("hash boost_1_62_0.tar.bz2")), - 1, - 2, - {}, - nullptr, - }; - - void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths) - { - Util::unused(args.parse_arguments(COMMAND_STRUCTURE)); - - const fs::path file_to_hash = args.command_arguments[0]; - const std::string algorithm = args.command_arguments.size() == 2 ? args.command_arguments[1] : "SHA512"; - const std::string hash = get_file_hash(paths.get_filesystem(), file_to_hash, algorithm); - System::println(hash); - Checks::exit_success(VCPKG_LINE_INFO); - } -} diff --git a/toolsrc/src/vcpkg/metrics.cpp b/toolsrc/src/vcpkg/metrics.cpp index 1d5bb381b..2a73dba89 100644 --- a/toolsrc/src/vcpkg/metrics.cpp +++ b/toolsrc/src/vcpkg/metrics.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include @@ -261,7 +262,7 @@ namespace vcpkg::Metrics const auto match = *next; if (match[0] != "00-00-00-00-00-00") { - return vcpkg::Commands::Hash::get_string_hash(match[0], "SHA256"); + return vcpkg::Hash::get_string_hash(match[0], "SHA256"); } ++next; } diff --git a/toolsrc/src/vcpkg/tools.cpp b/toolsrc/src/vcpkg/tools.cpp index d47035edf..313b5997b 100644 --- a/toolsrc/src/vcpkg/tools.cpp +++ b/toolsrc/src/vcpkg/tools.cpp @@ -1,13 +1,16 @@ #include "pch.h" +#include #include #include -#include +#include #include #include #include #include +#include +#include #include namespace vcpkg diff --git a/toolsrc/vcpkglib/vcpkglib.vcxproj b/toolsrc/vcpkglib/vcpkglib.vcxproj index 512d8d35b..abfe8a242 100644 --- a/toolsrc/vcpkglib/vcpkglib.vcxproj +++ b/toolsrc/vcpkglib/vcpkglib.vcxproj @@ -137,7 +137,7 @@ - + @@ -148,6 +148,7 @@ + @@ -198,13 +199,14 @@ Create Create - + + @@ -223,7 +225,6 @@ - diff --git a/toolsrc/vcpkglib/vcpkglib.vcxproj.filters b/toolsrc/vcpkglib/vcpkglib.vcxproj.filters index 6ea71febc..42493d623 100644 --- a/toolsrc/vcpkglib/vcpkglib.vcxproj.filters +++ b/toolsrc/vcpkglib/vcpkglib.vcxproj.filters @@ -69,9 +69,6 @@ Source Files\vcpkg - - Source Files\vcpkg - Source Files\vcpkg @@ -198,11 +195,8 @@ Source Files\vcpkg - - Source Files\vcpkg\base - - - Source Files\vcpkg\base + + Source Files\vcpkg Source Files\vcpkg @@ -213,6 +207,12 @@ Source Files\vcpkg + + Source Files\vcpkg\base + + + Source Files\vcpkg\base + @@ -359,14 +359,11 @@ Header Files\vcpkg\base - - Header Files\vcpkg\base - - - Header Files\vcpkg\base + + Header Files\vcpkg - Header Files\vcpkg\base + Header Files\vcpkg Header Files\vcpkg\base @@ -377,5 +374,11 @@ Header Files\vcpkg + + Header Files\vcpkg\base + + + Header Files\vcpkg\base + \ No newline at end of file -- cgit v1.2.3