From 042f7965c3a5db7420363fdb76f9ebaa8e93efdc Mon Sep 17 00:00:00 2001 From: Brad King Date: Tue, 15 Nov 2011 20:39:36 -0500 Subject: [PATCH] Add file(MD5) command to compute cryptographic hash Provide a CMake-language binding to the md5sum function previously available only by "cmake -E md5sum". --- Source/cmFileCommand.cxx | 36 +++++++++++++++++++++++++ Source/cmFileCommand.h | 4 +++ Tests/CMakeTests/CheckCMakeTest.cmake | 2 +- Tests/CMakeTests/File-MD5-BadArg1.cmake | 1 + Tests/CMakeTests/File-MD5-BadArg2.cmake | 1 + Tests/CMakeTests/File-MD5-BadArg4.cmake | 1 + Tests/CMakeTests/File-MD5-NoFile.cmake | 1 + Tests/CMakeTests/File-MD5-Works.cmake | 2 ++ Tests/CMakeTests/FileTest.cmake.in | 15 +++++++++++ 9 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 Tests/CMakeTests/File-MD5-BadArg1.cmake create mode 100644 Tests/CMakeTests/File-MD5-BadArg2.cmake create mode 100644 Tests/CMakeTests/File-MD5-BadArg4.cmake create mode 100644 Tests/CMakeTests/File-MD5-NoFile.cmake create mode 100644 Tests/CMakeTests/File-MD5-Works.cmake diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx index f933666ae..32454f5c5 100644 --- a/Source/cmFileCommand.cxx +++ b/Source/cmFileCommand.cxx @@ -13,6 +13,7 @@ #include "cmake.h" #include "cmHexFileConverter.h" #include "cmFileTimeComparison.h" +#include "cmCryptoHash.h" #if defined(CMAKE_BUILD_WITH_CMAKE) #include "cm_curl.h" @@ -22,6 +23,7 @@ #include #include +#include #include #include #include @@ -83,6 +85,10 @@ bool cmFileCommand { return this->HandleReadCommand(args); } + else if ( subCommand == "MD5" ) + { + return this->HandleHashCommand(args); + } else if ( subCommand == "STRINGS" ) { return this->HandleStringsCommand(args); @@ -338,6 +344,36 @@ bool cmFileCommand::HandleReadCommand(std::vector const& args) return true; } +//---------------------------------------------------------------------------- +bool cmFileCommand::HandleHashCommand(std::vector const& args) +{ + if(args.size() != 3) + { + cmOStringStream e; + e << args[0] << " requires a file name and output variable"; + this->SetError(e.str().c_str()); + return false; + } + + cmsys::auto_ptr hash; + if(args[0] == "MD5") + { hash.reset(new cmCryptoHashMD5); } + if(hash.get()) + { + std::string out = hash->HashFile(args[1].c_str()); + if(!out.empty()) + { + this->Makefile->AddDefinition(args[2].c_str(), out.c_str()); + return true; + } + cmOStringStream e; + e << args[0] << " failed to read file \"" << args[1] << "\": " + << cmSystemTools::GetLastSystemError(); + this->SetError(e.str().c_str()); + } + return false; +} + //---------------------------------------------------------------------------- bool cmFileCommand::HandleStringsCommand(std::vector const& args) { diff --git a/Source/cmFileCommand.h b/Source/cmFileCommand.h index 162890abf..dce647832 100644 --- a/Source/cmFileCommand.h +++ b/Source/cmFileCommand.h @@ -65,6 +65,7 @@ public: " file(WRITE filename \"message to write\"... )\n" " file(APPEND filename \"message to write\"... )\n" " file(READ filename variable [LIMIT numBytes] [OFFSET offset] [HEX])\n" + " file(MD5 filename variable)\n" " file(STRINGS filename variable [LIMIT_COUNT num]\n" " [LIMIT_INPUT numBytes] [LIMIT_OUTPUT numBytes]\n" " [LENGTH_MINIMUM numBytes] [LENGTH_MAXIMUM numBytes]\n" @@ -94,6 +95,8 @@ public: "variable. It will start at the given offset and read up to numBytes. " "If the argument HEX is given, the binary data will be converted to " "hexadecimal representation and this will be stored in the variable.\n" + "MD5 " + "will compute a cryptographic hash of the content of a file.\n" "STRINGS will parse a list of ASCII strings from a file and " "store it in a variable. Binary data in the file are ignored. Carriage " "return (CR) characters are ignored. It works also for Intel Hex and " @@ -227,6 +230,7 @@ protected: bool HandleRemove(std::vector const& args, bool recurse); bool HandleWriteCommand(std::vector const& args, bool append); bool HandleReadCommand(std::vector const& args); + bool HandleHashCommand(std::vector const& args); bool HandleStringsCommand(std::vector const& args); bool HandleGlobCommand(std::vector const& args, bool recurse); bool HandleMakeDirectoryCommand(std::vector const& args); diff --git a/Tests/CMakeTests/CheckCMakeTest.cmake b/Tests/CMakeTests/CheckCMakeTest.cmake index 2e4feddd3..db9290522 100644 --- a/Tests/CMakeTests/CheckCMakeTest.cmake +++ b/Tests/CMakeTests/CheckCMakeTest.cmake @@ -12,7 +12,7 @@ function(check_cmake_test prefix) ) string(REGEX REPLACE "\n" "\n out> " out " out> ${stdout}") string(REGEX REPLACE "\n" "\n err> " err " err> ${stderr}") - if(NOT "${result}" STREQUAL ${${test}-RESULT}) + if(NOT "${result}" STREQUAL "${${test}-RESULT}") message(FATAL_ERROR "Test ${test} result is [${result}], not [${${test}-RESULT}].\n" "Test ${test} output:\n" diff --git a/Tests/CMakeTests/File-MD5-BadArg1.cmake b/Tests/CMakeTests/File-MD5-BadArg1.cmake new file mode 100644 index 000000000..ac5f67ae2 --- /dev/null +++ b/Tests/CMakeTests/File-MD5-BadArg1.cmake @@ -0,0 +1 @@ +file(MD5) diff --git a/Tests/CMakeTests/File-MD5-BadArg2.cmake b/Tests/CMakeTests/File-MD5-BadArg2.cmake new file mode 100644 index 000000000..68a172fef --- /dev/null +++ b/Tests/CMakeTests/File-MD5-BadArg2.cmake @@ -0,0 +1 @@ +file(MD5 ${CMAKE_CURRENT_LIST_DIR}/File-Copy-NoDest.cmake) diff --git a/Tests/CMakeTests/File-MD5-BadArg4.cmake b/Tests/CMakeTests/File-MD5-BadArg4.cmake new file mode 100644 index 000000000..a11efcb60 --- /dev/null +++ b/Tests/CMakeTests/File-MD5-BadArg4.cmake @@ -0,0 +1 @@ +file(MD5 ${CMAKE_CURRENT_LIST_DIR}/File-Copy-NoDest.cmake md5 extra_arg) diff --git a/Tests/CMakeTests/File-MD5-NoFile.cmake b/Tests/CMakeTests/File-MD5-NoFile.cmake new file mode 100644 index 000000000..1b91bc8d8 --- /dev/null +++ b/Tests/CMakeTests/File-MD5-NoFile.cmake @@ -0,0 +1 @@ +file(MD5 ${CMAKE_CURRENT_LIST_DIR}/DoesNotExist.cmake md5) diff --git a/Tests/CMakeTests/File-MD5-Works.cmake b/Tests/CMakeTests/File-MD5-Works.cmake new file mode 100644 index 000000000..2989e98c5 --- /dev/null +++ b/Tests/CMakeTests/File-MD5-Works.cmake @@ -0,0 +1,2 @@ +file(MD5 ${CMAKE_CURRENT_LIST_DIR}/File-Copy-NoDest.cmake md5) +message("${md5}") diff --git a/Tests/CMakeTests/FileTest.cmake.in b/Tests/CMakeTests/FileTest.cmake.in index b6dcaa6d1..3aa88a740 100644 --- a/Tests/CMakeTests/FileTest.cmake.in +++ b/Tests/CMakeTests/FileTest.cmake.in @@ -12,6 +12,16 @@ set(Copy-NoDest-RESULT 1) set(Copy-NoDest-STDERR "given no DESTINATION") set(Copy-NoFile-RESULT 1) set(Copy-NoFile-STDERR "COPY cannot find.*/does_not_exist\\.txt") +set(MD5-NoFile-RESULT 1) +set(MD5-NoFile-STDERR "file MD5 failed to read file") +set(MD5-BadArg1-RESULT 1) +set(MD5-BadArg1-STDERR "file must be called with at least two arguments") +set(MD5-BadArg2-RESULT 1) +set(MD5-BadArg2-STDERR "file MD5 requires a file name and output variable") +set(MD5-BadArg4-RESULT 1) +set(MD5-BadArg4-STDERR "file MD5 requires a file name and output variable") +set(MD5-Works-RESULT 0) +set(MD5-Works-STDERR "a28a44fb5b58a6acf0cbec46557bc775") include("@CMAKE_CURRENT_SOURCE_DIR@/CheckCMakeTest.cmake") check_cmake_test(File @@ -22,6 +32,11 @@ check_cmake_test(File Copy-LateArg Copy-NoDest Copy-NoFile + MD5-NoFile + MD5-BadArg1 + MD5-BadArg2 + MD5-BadArg4 + MD5-Works ) # Also execute each test listed in FileTestScript.cmake: