From b1e51b91d2996e6657d1c149a38224aad1f84547 Mon Sep 17 00:00:00 2001 From: John Date: Sun, 27 Apr 2025 21:30:25 +1200 Subject: [PATCH] Add fancy hashing --- CMakeLists.txt | 6 ++ install_prerequisites.sh | 2 +- src/utils/hash.cpp | 99 ++++++++++++++++++++++++++++ src/utils/hash.hpp | 16 +++++ templates/example-nginx/uninstall.sh | 2 +- 5 files changed, 123 insertions(+), 2 deletions(-) create mode 100644 src/utils/hash.cpp create mode 100644 src/utils/hash.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index fcadf8a..9fb0d93 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,8 +27,12 @@ configure_file( @ONLY ) +# Set CMAKE_MODULE_PATH to include our custom find modules +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake) + # Find required packages find_package(TBB REQUIRED) +find_package(xxHash REQUIRED) # Auto-detect source files file(GLOB_RECURSE SOURCES "src/*.cpp") @@ -41,11 +45,13 @@ add_executable(dropshell ${SOURCES}) target_include_directories(dropshell PRIVATE src ${CMAKE_CURRENT_BINARY_DIR}/src + ${xxHash_INCLUDE_DIRS} ) # Link libraries target_link_libraries(dropshell PRIVATE TBB::tbb + ${xxHash_LIBRARIES} ) # Install targets diff --git a/install_prerequisites.sh b/install_prerequisites.sh index 9ca91c5..1b2e478 100755 --- a/install_prerequisites.sh +++ b/install_prerequisites.sh @@ -41,7 +41,7 @@ print_status "Detected OS: $OS $VER" case $OS in "Ubuntu"|"Debian GNU/Linux") # Common packages for both Ubuntu and Debian - PACKAGES="cmake make g++ devscripts debhelper libtbb-dev" + PACKAGES="cmake make g++ devscripts debhelper libtbb-dev libxxhash-dev" ;; *) print_error "Unsupported distribution: $OS" diff --git a/src/utils/hash.cpp b/src/utils/hash.cpp new file mode 100644 index 0000000..234a7c0 --- /dev/null +++ b/src/utils/hash.cpp @@ -0,0 +1,99 @@ +#include "hash.hpp" +#include +#include +#include + +namespace dropshell { + +XXH64_hash_t hash_file(const std::string &path) { + // Create hash state + XXH64_state_t* const state = XXH64_createState(); + if (state == nullptr) { + std::cerr << "Failed to create hash state" << std::endl; + return 0; + } + + // Initialize state with seed 0 + if (XXH64_reset(state, 0) == XXH_ERROR) { + std::cerr << "Failed to reset hash state" << std::endl; + XXH64_freeState(state); + return 0; + } + + // Open file + std::ifstream file(path, std::ios::binary); + if (!file.is_open()) { + std::cerr << "Failed to open file: " << path << std::endl; + XXH64_freeState(state); + return 0; + } + + // Read file in chunks and update hash + const size_t buffer_size = 4096; + char buffer[buffer_size]; + while (file.read(buffer, buffer_size)) { + if (XXH64_update(state, buffer, file.gcount()) == XXH_ERROR) { + std::cerr << "Failed to update hash" << std::endl; + XXH64_freeState(state); + return 0; + } + } + + // Handle any remaining bytes + if (file.gcount() > 0) { + if (XXH64_update(state, buffer, file.gcount()) == XXH_ERROR) { + std::cerr << "Failed to update hash" << std::endl; + XXH64_freeState(state); + return 0; + } + } + + // Get final hash + XXH64_hash_t hash = XXH64_digest(state); + XXH64_freeState(state); + return hash; +} + +XXH64_hash_t hash_directory_recursive(const std::string &path) { + // Create hash state + XXH64_state_t* const state = XXH64_createState(); + if (state == nullptr) { + std::cerr << "Failed to create hash state" << std::endl; + return 0; + } + + // Initialize state with seed 0 + if (XXH64_reset(state, 0) == XXH_ERROR) { + std::cerr << "Failed to reset hash state" << std::endl; + XXH64_freeState(state); + return 0; + } + + try { + // Iterate through all files in directory recursively + for (const auto& entry : std::filesystem::recursive_directory_iterator(path)) { + if (entry.is_regular_file()) { + // Get file hash + XXH64_hash_t file_hash = hash_file(entry.path().string()); + + // Update directory hash with file hash + if (XXH64_update(state, &file_hash, sizeof(file_hash)) == XXH_ERROR) { + std::cerr << "Failed to update hash" << std::endl; + XXH64_freeState(state); + return 0; + } + } + } + } catch (const std::filesystem::filesystem_error& e) { + std::cerr << "Filesystem error: " << e.what() << std::endl; + XXH64_freeState(state); + return 0; + } + + // Get final hash + XXH64_hash_t hash = XXH64_digest(state); + XXH64_freeState(state); + return hash; +} + +} // namespace dropshell diff --git a/src/utils/hash.hpp b/src/utils/hash.hpp new file mode 100644 index 0000000..de96840 --- /dev/null +++ b/src/utils/hash.hpp @@ -0,0 +1,16 @@ +#ifndef HASH_HPP +#define HASH_HPP + +#include +#include + +namespace dropshell { + + XXH64_hash_t hash_file(const std::string &path); + + XXH64_hash_t hash_directory_recursive(const std::string &path); + +} // namespace dropshell + + +#endif \ No newline at end of file diff --git a/templates/example-nginx/uninstall.sh b/templates/example-nginx/uninstall.sh index 58afb63..185a91b 100644 --- a/templates/example-nginx/uninstall.sh +++ b/templates/example-nginx/uninstall.sh @@ -16,4 +16,4 @@ _is_container_exists && die "Couldn't remove existing container" docker rmi "$IMAGE_REGISTRY/$IMAGE_REPO:$IMAGE_TAG" || echo "Failed to remove image $IMAGE_REGISTRY/$IMAGE_REPO:$IMAGE_TAG" echo "Uninstallation of ${CONTAINER_NAME} complete." -echo "Leaving local data folder ${LOCAL_DATA_FOLDER} in place." +echo "Local data folder ${LOCAL_DATA_FOLDER} still in place."