From f9a3f13415bb6d6f1750cfe5a45ce4aa9e329907 Mon Sep 17 00:00:00 2001 From: KWSys Upstream Date: Thu, 29 Aug 2019 11:30:45 -0400 Subject: KWSys 2019-08-29 (08f14d96) Code extracted from: https://gitlab.kitware.com/utils/kwsys.git at commit 08f14d96b449e5d1e166998b363da16167a3ac82 (master). Upstream Shortlog ----------------- Ben Boeckel (1): 9afecb09 SystemTools: fix typo in junction functions Jon Chronopoulos (1): 38486236 SystemTools: do not special case a junction in RemoveFile Rolf Eike Beer (3): b747462d CMake: drop needless x${VAR} tricks 1ed70242 tests: verify SystemTools::CopyFileIfDifferent() f73d1b4f SystemTools: factor out "dest is directory" case from CopyFileIfDifferent() --- CMakeLists.txt | 8 ++-- SystemTools.cxx | 123 ++++++---------------------------------------------- testSystemTools.cxx | 83 +++++++++++++++++++++++++++-------- 3 files changed, 82 insertions(+), 132 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 79e813e..09bcdb9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -121,8 +121,8 @@ if(KWSYS_CXX_STANDARD) set(CMAKE_CXX_STANDARD "${KWSYS_CXX_STANDARD}") elseif(NOT DEFINED CMAKE_CXX_STANDARD AND NOT DEFINED KWSYS_CXX_STANDARD) if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" - AND "x${CMAKE_CXX_SIMULATE_ID}" STREQUAL "xMSVC" - AND "x${CMAKE_CXX_COMPILER_FRONTEND_VARIANT}" STREQUAL "xGNU" + AND CMAKE_CXX_SIMULATE_ID STREQUAL "MSVC" + AND CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "GNU" ) set(CMAKE_CXX_STANDARD 14) else() @@ -1013,7 +1013,7 @@ ADD_DEFINITIONS("-DKWSYS_NAMESPACE=${KWSYS_NAMESPACE}") # Disable deprecation warnings for standard C functions. IF(MSVC OR (WIN32 AND (CMAKE_C_COMPILER_ID STREQUAL "Intel" OR - (CMAKE_C_COMPILER_ID STREQUAL "Clang" AND "x${CMAKE_CXX_SIMULATE_ID}" STREQUAL "xMSVC")))) + (CMAKE_C_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_SIMULATE_ID STREQUAL "MSVC")))) ADD_DEFINITIONS( -D_CRT_NONSTDC_NO_DEPRECATE -D_CRT_SECURE_NO_DEPRECATE @@ -1104,7 +1104,7 @@ IF(KWSYS_STANDALONE OR CMake_SOURCE_DIR) SET(KWSYS_CXX_TESTS ${KWSYS_CXX_TESTS} testConsoleBuf.cxx ) - IF("x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xMSVC" AND + IF(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER "19.0.23506") set_property(SOURCE testConsoleBuf.cxx testConsoleBufChild.cxx PROPERTY COMPILE_FLAGS /utf-8) ENDIF() diff --git a/SystemTools.cxx b/SystemTools.cxx index 36f24c7..8571477 100644 --- a/SystemTools.cxx +++ b/SystemTools.cxx @@ -2169,24 +2169,24 @@ std::string SystemTools::ConvertToWindowsOutputPath(const std::string& path) return ret; } +/** + * Append the filename from the path source to the directory name dir. + */ +static std::string FileInDir(const std::string& source, const std::string& dir) +{ + std::string new_destination = dir; + SystemTools::ConvertToUnixSlashes(new_destination); + return new_destination + '/' + SystemTools::GetFilenameName(source); +} + bool SystemTools::CopyFileIfDifferent(const std::string& source, const std::string& destination) { // special check for a destination that is a directory // FilesDiffer does not handle file to directory compare if (SystemTools::FileIsDirectory(destination)) { - std::string new_destination = destination; - SystemTools::ConvertToUnixSlashes(new_destination); - new_destination += '/'; - std::string source_name = source; - new_destination += SystemTools::GetFilenameName(source_name); - if (SystemTools::FilesDiffer(source, new_destination)) { - return SystemTools::CopyFileAlways(source, destination); - } else { - // the files are the same so the copy is done return - // true - return true; - } + const std::string new_destination = FileInDir(source, destination); + return SystemTools::CopyFileIfDifferent(source, new_destination); } // source and destination are files so do a copy if they // are different @@ -2612,101 +2612,6 @@ std::string SystemTools::GetLastSystemError() return strerror(e); } -#ifdef _WIN32 - -static bool IsJunction(const std::wstring& source) -{ -# ifdef FSCTL_GET_REPARSE_POINT - const DWORD JUNCTION_ATTRS = - FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT; - DWORD attrs = GetFileAttributesW(source.c_str()); - if (attrs == INVALID_FILE_ATTRIBUTES) { - return false; - } - if ((attrs & JUNCTION_ATTRS) != JUNCTION_ATTRS) { - return false; - } - - // Adjust privileges so that we can succefully open junction points. - HANDLE token; - TOKEN_PRIVILEGES privs; - OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &token); - LookupPrivilegeValue(NULL, SE_BACKUP_NAME, &privs.Privileges[0].Luid); - privs.PrivilegeCount = 1; - privs.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; - AdjustTokenPrivileges(token, FALSE, &privs, sizeof(TOKEN_PRIVILEGES), NULL, - NULL); - CloseHandle(token); - - HANDLE dir = CreateFileW( - source.c_str(), GENERIC_READ, 0, NULL, OPEN_EXISTING, - FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, NULL); - if (dir == INVALID_HANDLE_VALUE) { - return false; - } - - // Query whether this is a reparse point or not. - BYTE buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; - REPARSE_GUID_DATA_BUFFER* reparse_buffer = (REPARSE_GUID_DATA_BUFFER*)buffer; - DWORD sentinel; - - BOOL success = - DeviceIoControl(dir, FSCTL_GET_REPARSE_POINT, NULL, 0, reparse_buffer, - MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &sentinel, NULL); - - CloseHandle(dir); - - return (success && - (reparse_buffer->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT)); -# else - return false; -# endif -} - -static bool DeleteJunction(const std::wstring& source) -{ -# ifdef FSCTL_DELETE_REPARSE_POINT - // Adjust privileges so that we can succefully open junction points as - // read/write. - HANDLE token; - TOKEN_PRIVILEGES privs; - OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &token); - LookupPrivilegeValue(NULL, SE_RESTORE_NAME, &privs.Privileges[0].Luid); - privs.PrivilegeCount = 1; - privs.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; - AdjustTokenPrivileges(token, FALSE, &privs, sizeof(TOKEN_PRIVILEGES), NULL, - NULL); - CloseHandle(token); - - HANDLE dir = CreateFileW( - source.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, - FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, NULL); - if (dir == INVALID_HANDLE_VALUE) { - return false; - } - - // Set up the structure so that we can delete the junction. - std::vector buffer(REPARSE_GUID_DATA_BUFFER_HEADER_SIZE, 0); - REPARSE_GUID_DATA_BUFFER* reparse_buffer = - (REPARSE_GUID_DATA_BUFFER*)&buffer[0]; - DWORD sentinel; - - reparse_buffer->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT; - - BOOL success = DeviceIoControl( - dir, FSCTL_DELETE_REPARSE_POINT, reparse_buffer, - REPARSE_GUID_DATA_BUFFER_HEADER_SIZE, NULL, 0, &sentinel, NULL); - - CloseHandle(dir); - - return !!success; -# else - return false; -# endif -} - -#endif - bool SystemTools::RemoveFile(const std::string& source) { #ifdef _WIN32 @@ -2728,9 +2633,7 @@ bool SystemTools::RemoveFile(const std::string& source) SetLastError(err); return false; } - if (IsJunction(ws) && DeleteJunction(ws)) { - return true; - } + const DWORD DIRECTORY_SOFT_LINK_ATTRS = FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT; DWORD attrs = GetFileAttributesW(ws.c_str()); diff --git a/testSystemTools.cxx b/testSystemTools.cxx index ffa6a29..88277de 100644 --- a/testSystemTools.cxx +++ b/testSystemTools.cxx @@ -999,30 +999,45 @@ static bool writeFile(const char* fileName, const char* data) return true; } +static std::string readFile(const char* fileName) +{ + kwsys::ifstream in(fileName, std::ios::binary); + std::stringstream sstr; + sstr << in.rdbuf(); + std::string data = sstr.str(); + if (!in) { + std::cerr << "Failed to read file: " << fileName << std::endl; + return std::string(); + } + return data; +} + +struct +{ + const char* a; + const char* b; + bool differ; +} diff_test_cases[] = { { "one", "one", false }, + { "one", "two", true }, + { "", "", false }, + { "\n", "\r\n", false }, + { "one\n", "one\n", false }, + { "one\r\n", "one\n", false }, + { "one\n", "one", false }, + { "one\ntwo", "one\ntwo", false }, + { "one\ntwo", "one\r\ntwo", false } }; + static bool CheckTextFilesDiffer() { - struct - { - const char* a; - const char* b; - bool differ; - } test_cases[] = { { "one", "one", false }, - { "one", "two", true }, - { "", "", false }, - { "\n", "\r\n", false }, - { "one\n", "one\n", false }, - { "one\r\n", "one\n", false }, - { "one\n", "one", false }, - { "one\ntwo", "one\ntwo", false }, - { "one\ntwo", "one\r\ntwo", false } }; - const int num_test_cases = sizeof(test_cases) / sizeof(test_cases[0]); + const int num_test_cases = + sizeof(diff_test_cases) / sizeof(diff_test_cases[0]); for (int i = 0; i < num_test_cases; ++i) { - if (!writeFile("file_a", test_cases[i].a) || - !writeFile("file_b", test_cases[i].b)) { + if (!writeFile("file_a", diff_test_cases[i].a) || + !writeFile("file_b", diff_test_cases[i].b)) { return false; } if (kwsys::SystemTools::TextFilesDiffer("file_a", "file_b") != - test_cases[i].differ) { + diff_test_cases[i].differ) { std::cerr << "Incorrect TextFilesDiffer result for test case " << i + 1 << "." << std::endl; return false; @@ -1032,6 +1047,36 @@ static bool CheckTextFilesDiffer() return true; } +static bool CheckCopyFileIfDifferent() +{ + bool ret = true; + const int num_test_cases = + sizeof(diff_test_cases) / sizeof(diff_test_cases[0]); + for (int i = 0; i < num_test_cases; ++i) { + if (!writeFile("file_a", diff_test_cases[i].a) || + !writeFile("file_b", diff_test_cases[i].b)) { + return false; + } + const char* cptarget = + i < 4 ? TEST_SYSTEMTOOLS_BINARY_DIR "/file_b" : "file_b"; + if (!kwsys::SystemTools::CopyFileIfDifferent("file_a", cptarget)) { + std::cerr << "CopyFileIfDifferent() returned false for test case " + << i + 1 << "." << std::endl; + ret = false; + continue; + } + std::string bdata = readFile("file_b"); + if (diff_test_cases[i].a != bdata) { + std::cerr << "Incorrect CopyFileIfDifferent file contents in test case " + << i + 1 << "." << std::endl; + ret = false; + continue; + } + } + + return ret; +} + int testSystemTools(int, char* []) { bool res = true; @@ -1077,5 +1122,7 @@ int testSystemTools(int, char* []) res &= CheckTextFilesDiffer(); + res &= CheckCopyFileIfDifferent(); + return res ? 0 : 1; } -- cgit v0.12