diff options
Diffstat (limited to 'Source/kwsys')
-rw-r--r-- | Source/kwsys/CMakeLists.txt | 16 | ||||
-rw-r--r-- | Source/kwsys/Directory.cxx | 39 | ||||
-rw-r--r-- | Source/kwsys/Directory.hxx.in | 6 | ||||
-rw-r--r-- | Source/kwsys/EncodingC.c | 2 | ||||
-rw-r--r-- | Source/kwsys/Glob.hxx.in | 7 | ||||
-rw-r--r-- | Source/kwsys/ProcessUNIX.c | 12 | ||||
-rw-r--r-- | Source/kwsys/Status.cxx | 60 | ||||
-rw-r--r-- | Source/kwsys/Status.hxx.in | 101 | ||||
-rw-r--r-- | Source/kwsys/SystemInformation.cxx | 23 | ||||
-rw-r--r-- | Source/kwsys/SystemTools.cxx | 418 | ||||
-rw-r--r-- | Source/kwsys/SystemTools.hxx.in | 68 | ||||
-rw-r--r-- | Source/kwsys/Terminal.c | 10 | ||||
-rw-r--r-- | Source/kwsys/testDirectory.cxx | 4 | ||||
-rw-r--r-- | Source/kwsys/testDynamicLoader.cxx | 23 | ||||
-rw-r--r-- | Source/kwsys/testStatus.cxx | 117 | ||||
-rw-r--r-- | Source/kwsys/testSystemTools.cxx | 47 |
16 files changed, 732 insertions, 221 deletions
diff --git a/Source/kwsys/CMakeLists.txt b/Source/kwsys/CMakeLists.txt index b0a854292..ef615b3fe 100644 --- a/Source/kwsys/CMakeLists.txt +++ b/Source/kwsys/CMakeLists.txt @@ -98,6 +98,16 @@ foreach(p endif() endforeach() +# Some configure checks depend upon the deployment target. Clear checks when +# the deployment target changes. +if (APPLE) + if (NOT CMAKE_OSX_DEPLOYMENT_TARGET STREQUAL KWSYS_LAST_OSX_DEPLOYMENT_TARGET) + unset(KWSYS_CXX_HAS_UTIMENSAT CACHE) + endif () + set(KWSYS_LAST_OSX_DEPLOYMENT_TARGET "${CMAKE_OSX_DEPLOYMENT_TARGET}" + CACHE INTERNAL "remember the last deployment target to trigger configure rechecks") +endif () + #----------------------------------------------------------------------------- # If a namespace is not specified, use "kwsys" and enable testing. # This should be the case only when kwsys is not included inside @@ -142,6 +152,7 @@ if(KWSYS_STANDALONE OR CMake_SOURCE_DIR) set(KWSYS_USE_MD5 1) set(KWSYS_USE_Process 1) set(KWSYS_USE_RegularExpression 1) + set(KWSYS_USE_Status 1) set(KWSYS_USE_System 1) set(KWSYS_USE_SystemTools 1) set(KWSYS_USE_CommandLineArguments 1) @@ -157,6 +168,7 @@ if(KWSYS_USE_SystemTools) set(KWSYS_USE_Directory 1) set(KWSYS_USE_FStream 1) set(KWSYS_USE_Encoding 1) + set(KWSYS_USE_Status 1) endif() if(KWSYS_USE_Glob) set(KWSYS_USE_Directory 1) @@ -177,6 +189,7 @@ if(KWSYS_USE_System) endif() if(KWSYS_USE_Directory) set(KWSYS_USE_Encoding 1) + set(KWSYS_USE_Status 1) endif() if(KWSYS_USE_DynamicLoader) set(KWSYS_USE_Encoding 1) @@ -630,7 +643,7 @@ set(KWSYS_HXX_FILES Configure String) # Add selected C++ classes. set(cppclasses Directory DynamicLoader Encoding Glob RegularExpression SystemTools - CommandLineArguments FStream SystemInformation ConsoleBuf + CommandLineArguments FStream SystemInformation ConsoleBuf Status ) foreach(cpp ${cppclasses}) if(KWSYS_USE_${cpp}) @@ -963,6 +976,7 @@ if(KWSYS_STANDALONE OR CMake_SOURCE_DIR) # C++ tests set(KWSYS_CXX_TESTS ${KWSYS_CXX_TESTS} testConfigure.cxx + testStatus.cxx testSystemTools.cxx testCommandLineArguments.cxx testCommandLineArguments1.cxx diff --git a/Source/kwsys/Directory.cxx b/Source/kwsys/Directory.cxx index 0c2190aee..2e8aa83f4 100644 --- a/Source/kwsys/Directory.cxx +++ b/Source/kwsys/Directory.cxx @@ -94,7 +94,7 @@ void Directory::Clear() namespace KWSYS_NAMESPACE { -bool Directory::Load(const std::string& name, std::string* errorMessage) +Status Directory::Load(std::string const& name, std::string* errorMessage) { this->Clear(); intptr_t srchHandle; @@ -121,7 +121,11 @@ bool Directory::Load(const std::string& name, std::string* errorMessage) delete[] buf; if (srchHandle == -1) { - return 0; + Status status = Status::POSIX_errno(); + if (errorMessage) { + *errorMessage = status.GetString(); + } + return status; } // Loop through names @@ -129,7 +133,14 @@ bool Directory::Load(const std::string& name, std::string* errorMessage) this->Internal->Files.push_back(Encoding::ToNarrow(data.name)); } while (_wfindnext(srchHandle, &data) != -1); this->Internal->Path = name; - return _findclose(srchHandle) != -1; + if (_findclose(srchHandle) == -1) { + Status status = Status::POSIX_errno(); + if (errorMessage) { + *errorMessage = status.GetString(); + } + return status; + } + return Status::Success(); } unsigned long Directory::GetNumberOfFilesInDirectory(const std::string& name, @@ -152,6 +163,20 @@ unsigned long Directory::GetNumberOfFilesInDirectory(const std::string& name, delete[] buf; if (srchHandle == -1) { + if (errorMessage) { + if (unsigned int errorId = GetLastError()) { + LPSTR message = nullptr; + DWORD size = FormatMessageA( + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + nullptr, errorId, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPSTR)&message, 0, nullptr); + *errorMessage = std::string(message, size); + LocalFree(message); + } else { + *errorMessage = "Unknown error."; + } + } return 0; } @@ -192,7 +217,7 @@ unsigned long Directory::GetNumberOfFilesInDirectory(const std::string& name, namespace KWSYS_NAMESPACE { -bool Directory::Load(const std::string& name, std::string* errorMessage) +Status Directory::Load(std::string const& name, std::string* errorMessage) { this->Clear(); @@ -203,7 +228,7 @@ bool Directory::Load(const std::string& name, std::string* errorMessage) if (errorMessage != nullptr) { *errorMessage = std::string(strerror(errno)); } - return false; + return Status::POSIX_errno(); } errno = 0; @@ -214,12 +239,12 @@ bool Directory::Load(const std::string& name, std::string* errorMessage) if (errorMessage != nullptr) { *errorMessage = std::string(strerror(errno)); } - return false; + return Status::POSIX_errno(); } this->Internal->Path = name; closedir(dir); - return true; + return Status::Success(); } unsigned long Directory::GetNumberOfFilesInDirectory(const std::string& name, diff --git a/Source/kwsys/Directory.hxx.in b/Source/kwsys/Directory.hxx.in index 7bc9db024..d50111615 100644 --- a/Source/kwsys/Directory.hxx.in +++ b/Source/kwsys/Directory.hxx.in @@ -4,6 +4,7 @@ #define @KWSYS_NAMESPACE@_Directory_hxx #include <@KWSYS_NAMESPACE@/Configure.h> +#include <@KWSYS_NAMESPACE@/Status.hxx> #include <string> @@ -32,10 +33,9 @@ public: /** * Load the specified directory and load the names of the files - * in that directory. 0 is returned if the directory can not be - * opened, 1 if it is opened. + * in that directory. */ - bool Load(const std::string&, std::string* errorMessage = nullptr); + Status Load(std::string const&, std::string* errorMessage = nullptr); /** * Return the number of files in the current directory. diff --git a/Source/kwsys/EncodingC.c b/Source/kwsys/EncodingC.c index e12236afe..13127f1ac 100644 --- a/Source/kwsys/EncodingC.c +++ b/Source/kwsys/EncodingC.c @@ -60,7 +60,7 @@ size_t kwsysEncoding_wcstombs(char* dest, const wchar_t* str, size_t n) char* kwsysEncoding_DupToNarrow(const wchar_t* str) { char* ret = NULL; - size_t length = kwsysEncoding_wcstombs(0, str, 0) + 1; + size_t length = kwsysEncoding_wcstombs(NULL, str, 0) + 1; if (length > 0) { ret = (char*)malloc(length); if (ret) { diff --git a/Source/kwsys/Glob.hxx.in b/Source/kwsys/Glob.hxx.in index e8474e200..fd3977541 100644 --- a/Source/kwsys/Glob.hxx.in +++ b/Source/kwsys/Glob.hxx.in @@ -54,6 +54,9 @@ public: Glob(); ~Glob(); + Glob(const Glob&) = delete; + void operator=(const Glob&) = delete; + //! Find all files that match the pattern. bool FindFiles(const std::string& inexpr, GlobMessages* messages = nullptr); @@ -124,10 +127,6 @@ protected: std::vector<std::string> VisitedSymlinks; bool ListDirs; bool RecurseListDirs; - -private: - Glob(const Glob&) = delete; - void operator=(const Glob&) = delete; }; } // namespace @KWSYS_NAMESPACE@ diff --git a/Source/kwsys/ProcessUNIX.c b/Source/kwsys/ProcessUNIX.c index e1e7721b4..a8a15ddb0 100644 --- a/Source/kwsys/ProcessUNIX.c +++ b/Source/kwsys/ProcessUNIX.c @@ -122,6 +122,10 @@ static inline void kwsysProcess_usleep(unsigned int msec) /* The maximum amount to read from a pipe at a time. */ #define KWSYSPE_PIPE_BUFFER_SIZE 1024 +#if defined(__NVCOMPILER) +# pragma diag_suppress 550 /* variable set but never used (in FD_ZERO) */ +#endif + /* Keep track of times using a signed representation. Switch to the native (possibly unsigned) representation only when calling native functions. */ @@ -2890,10 +2894,10 @@ static void kwsysProcessesSignalHandler(int signum /* Re-Install our handler. Repeat call until it is not interrupted. */ { struct sigaction newSigAction; - struct sigaction& oldSigAction; + struct sigaction* oldSigAction; memset(&newSigAction, 0, sizeof(struct sigaction)); - newSigChldAction.sa_handler = kwsysProcessesSignalHandler; - newSigChldAction.sa_flags = SA_NOCLDSTOP; + newSigAction.sa_handler = kwsysProcessesSignalHandler; + newSigAction.sa_flags = SA_NOCLDSTOP; sigemptyset(&newSigAction.sa_mask); switch (signum) { case SIGCHLD: @@ -2908,7 +2912,7 @@ static void kwsysProcessesSignalHandler(int signum oldSigAction = &kwsysProcessesOldSigTermAction; break; default: - return 0; + return; } while ((sigaction(signum, &newSigAction, oldSigAction) < 0) && (errno == EINTR)) diff --git a/Source/kwsys/Status.cxx b/Source/kwsys/Status.cxx new file mode 100644 index 000000000..503d1e1d5 --- /dev/null +++ b/Source/kwsys/Status.cxx @@ -0,0 +1,60 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#include "kwsysPrivate.h" +#include KWSYS_HEADER(Status.hxx) + +// Work-around CMake dependency scanning limitation. This must +// duplicate the above list of headers. +#if 0 +# include "Status.hxx.in" +#endif + +#include <cerrno> +#include <cstring> +#include <string> + +#if defined(_WIN32) +# include <windows.h> +#endif + +namespace KWSYS_NAMESPACE { + +Status Status::POSIX_errno() +{ + return Status::POSIX(errno); +} + +#ifdef _WIN32 +Status Status::Windows_GetLastError() +{ + return Status::Windows(GetLastError()); +} +#endif + +std::string Status::GetString() const +{ + std::string err; + switch (this->Kind_) { + case Kind::Success: + err = "Success"; + break; + case Kind::POSIX: + err = strerror(this->POSIX_); + break; +#ifdef _WIN32 + case Kind::Windows: { + LPSTR message = NULL; + DWORD size = FormatMessageA( + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, this->Windows_, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPSTR)&message, 0, NULL); + err = std::string(message, size); + LocalFree(message); + } break; +#endif + }; + return err; +} + +} // namespace KWSYS_NAMESPACE diff --git a/Source/kwsys/Status.hxx.in b/Source/kwsys/Status.hxx.in new file mode 100644 index 000000000..ed46d5c2b --- /dev/null +++ b/Source/kwsys/Status.hxx.in @@ -0,0 +1,101 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#ifndef @KWSYS_NAMESPACE@_Status_hxx +#define @KWSYS_NAMESPACE@_Status_hxx + +#include <@KWSYS_NAMESPACE@/Configure.hxx> + +#include <string> + +namespace @KWSYS_NAMESPACE@ { + +/** \class Status + * \brief OS-specific status of a system operation. + */ +class @KWSYS_NAMESPACE@_EXPORT Status +{ +public: + enum class Kind + { + Success, + POSIX, +#ifdef _WIN32 + Windows, +#endif + }; + + /** Construct with kind "Success". */ + Status() = default; + + /** Construct with kind "Success". */ + static Status Success() { return Status(); } + + /** Construct with kind "POSIX" using given errno-style value. */ + static Status POSIX(int e) + { + Status s(Kind::POSIX); + s.POSIX_ = e; + return s; + } + + /** Construct with kind "POSIX" using errno. */ + static Status POSIX_errno(); + +#ifdef _WIN32 + /** Construct with kind "Windows" using given GetLastError()-style value. */ + static Status Windows(unsigned int e) + { + Status s(Kind::Windows); + s.Windows_ = e; + return s; + } + + /** Construct with kind "Windows" using GetLastError(). */ + static Status Windows_GetLastError(); +#endif + + /** Return true on "Success", false otherwise. */ + explicit operator bool() const { return this->Kind_ == Kind::Success; } + + /** Return the kind of status. */ + Kind GetKind() const { return this->Kind_; } + + /** If the kind is "POSIX", returns the errno-style value. + Otherwise, returns 0. */ + int GetPOSIX() const + { + return this->Kind_ == Kind::POSIX ? this->POSIX_ : 0; + } + +#ifdef _WIN32 + /** If the kind is "Windows", returns the GetLastError()-style value. + Otherwise, returns 0. */ + unsigned int GetWindows() const + { + return this->Kind_ == Kind::Windows ? this->Windows_ : 0; + } +#endif + + /** Return a human-readable description of the status. */ + std::string GetString() const; + +private: + Status(Kind kind) + : Kind_(kind) + { + } + + Kind Kind_ = Kind::Success; + + union + { + int POSIX_; +#ifdef _WIN32 + unsigned int Windows_; +#endif + }; +}; + +} // namespace @KWSYS_NAMESPACE@ + +#endif diff --git a/Source/kwsys/SystemInformation.cxx b/Source/kwsys/SystemInformation.cxx index 7743eabe9..12f9139cc 100644 --- a/Source/kwsys/SystemInformation.cxx +++ b/Source/kwsys/SystemInformation.cxx @@ -1383,7 +1383,7 @@ void SymbolProperties::Initialize(void* address) } # else // second fallback use builtin backtrace_symbols -// to decode the bactrace. +// to decode the backtrace. # endif } #endif // don't define this class if we're not using it @@ -3472,6 +3472,10 @@ bool SystemInformationImplementation::RetreiveInformationFromCpuInfoFile() // We want to record the total number of cores in this->NumberOfPhysicalCPU // (checking only the first proc) std::string Cores = this->ExtractValueFromCpuInfoFile(buffer, "cpu cores"); + if (Cores.empty()) { + // Linux Sparc is different + Cores = this->ExtractValueFromCpuInfoFile(buffer, "ncpus probed"); + } auto NumberOfCoresPerSocket = (unsigned int)atoi(Cores.c_str()); NumberOfCoresPerSocket = std::max(NumberOfCoresPerSocket, 1u); this->NumberOfPhysicalCPU = @@ -3490,6 +3494,9 @@ bool SystemInformationImplementation::RetreiveInformationFromCpuInfoFile() if (this->NumberOfPhysicalCPU <= 0) { this->NumberOfPhysicalCPU = 1; } + if (this->NumberOfLogicalCPU == 0) { + this->NumberOfLogicalCPU = this->NumberOfPhysicalCPU; + } // LogicalProcessorsPerPhysical>1 => SMT. this->Features.ExtendedFeatures.LogicalProcessorsPerPhysical = this->NumberOfLogicalCPU / this->NumberOfPhysicalCPU; @@ -3503,8 +3510,18 @@ bool SystemInformationImplementation::RetreiveInformationFromCpuInfoFile() else { // Linux Sparc: CPU speed is in Hz and encoded in hexadecimal CPUSpeed = this->ExtractValueFromCpuInfoFile(buffer, "Cpu0ClkTck"); - this->CPUSpeedInMHz = - static_cast<float>(strtoull(CPUSpeed.c_str(), nullptr, 16)) / 1000000.0f; + if (!CPUSpeed.empty()) { + this->CPUSpeedInMHz = + static_cast<float>(strtoull(CPUSpeed.c_str(), nullptr, 16)) / + 1000000.0f; + } else { + // if the kernel is build as Sparc32 it's in decimal, note the different + // case + CPUSpeed = this->ExtractValueFromCpuInfoFile(buffer, "CPU0ClkTck"); + this->CPUSpeedInMHz = + static_cast<float>(strtoull(CPUSpeed.c_str(), nullptr, 10)) / + 1000000.0f; + } } #endif diff --git a/Source/kwsys/SystemTools.cxx b/Source/kwsys/SystemTools.cxx index 6144d9c04..006495d3c 100644 --- a/Source/kwsys/SystemTools.cxx +++ b/Source/kwsys/SystemTools.cxx @@ -93,9 +93,43 @@ # ifndef INVALID_FILE_ATTRIBUTES # define INVALID_FILE_ATTRIBUTES ((DWORD)-1) # endif +# ifndef SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE +# define SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE (0x2) +# endif # if defined(_MSC_VER) && _MSC_VER >= 1800 # define KWSYS_WINDOWS_DEPRECATED_GetVersionEx # endif +// from ntifs.h, which can only be used by drivers +typedef struct _REPARSE_DATA_BUFFER +{ + ULONG ReparseTag; + USHORT ReparseDataLength; + USHORT Reserved; + union + { + struct + { + USHORT SubstituteNameOffset; + USHORT SubstituteNameLength; + USHORT PrintNameOffset; + USHORT PrintNameLength; + ULONG Flags; + WCHAR PathBuffer[1]; + } SymbolicLinkReparseBuffer; + struct + { + USHORT SubstituteNameOffset; + USHORT SubstituteNameLength; + USHORT PrintNameOffset; + USHORT PrintNameLength; + WCHAR PathBuffer[1]; + } MountPointReparseBuffer; + struct + { + UCHAR DataBuffer[1]; + } GenericReparseBuffer; + } DUMMYUNIONNAME; +} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER; #endif #if !KWSYS_CXX_HAS_ENVIRON_IN_STDLIB_H @@ -244,7 +278,7 @@ inline int Chdir(const std::string& dir) return _wchdir(KWSYS_NAMESPACE::Encoding::ToWide(dir).c_str()); } inline void Realpath(const std::string& path, std::string& resolved_path, - std::string* errorMessage = 0) + std::string* errorMessage = nullptr) { std::wstring tmp = KWSYS_NAMESPACE::Encoding::ToWide(path); wchar_t* ptemp; @@ -882,21 +916,24 @@ FILE* SystemTools::Fopen(const std::string& file, const char* mode) #endif } -bool SystemTools::MakeDirectory(const char* path, const mode_t* mode) +Status SystemTools::MakeDirectory(const char* path, const mode_t* mode) { if (!path) { - return false; + return Status::POSIX(EINVAL); } return SystemTools::MakeDirectory(std::string(path), mode); } -bool SystemTools::MakeDirectory(const std::string& path, const mode_t* mode) +Status SystemTools::MakeDirectory(std::string const& path, const mode_t* mode) { - if (SystemTools::PathExists(path)) { - return SystemTools::FileIsDirectory(path); - } if (path.empty()) { - return false; + return Status::POSIX(EINVAL); + } + if (SystemTools::PathExists(path)) { + if (SystemTools::FileIsDirectory(path)) { + return Status::Success(); + } + return Status::POSIX(EEXIST); } std::string dir = path; SystemTools::ConvertToUnixSlashes(dir); @@ -914,15 +951,11 @@ bool SystemTools::MakeDirectory(const std::string& path, const mode_t* mode) ++pos; } topdir = dir; - if (Mkdir(topdir, mode) != 0) { - // if it is some other error besides directory exists - // then return false - if (errno != EEXIST) { - return false; - } + if (Mkdir(topdir, mode) != 0 && errno != EEXIST) { + return Status::POSIX_errno(); } - return true; + return Status::Success(); } // replace replace with with as many times as it shows up in source. @@ -1411,18 +1444,18 @@ int SystemTools::Stat(const std::string& path, SystemTools::Stat_t* buf) #endif } -bool SystemTools::Touch(const std::string& filename, bool create) +Status SystemTools::Touch(std::string const& filename, bool create) { if (!SystemTools::FileExists(filename)) { if (create) { FILE* file = Fopen(filename, "a+b"); if (file) { fclose(file); - return true; + return Status::Success(); } - return false; + return Status::POSIX_errno(); } else { - return true; + return Status::Success(); } } #if defined(_WIN32) && !defined(__CYGWIN__) @@ -1430,31 +1463,32 @@ bool SystemTools::Touch(const std::string& filename, bool create) FILE_WRITE_ATTRIBUTES, FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0); if (!h) { - return false; + return Status::Windows_GetLastError(); } FILETIME mtime; GetSystemTimeAsFileTime(&mtime); if (!SetFileTime(h, 0, 0, &mtime)) { + Status status = Status::Windows_GetLastError(); CloseHandle(h); - return false; + return status; } CloseHandle(h); #elif KWSYS_CXX_HAS_UTIMENSAT // utimensat is only available on newer Unixes and macOS 10.13+ if (utimensat(AT_FDCWD, filename.c_str(), nullptr, 0) < 0) { - return false; + return Status::POSIX_errno(); } #else // fall back to utimes if (utimes(filename.c_str(), nullptr) < 0) { - return false; + return Status::POSIX_errno(); } #endif - return true; + return Status::Success(); } -bool SystemTools::FileTimeCompare(const std::string& f1, const std::string& f2, - int* result) +Status SystemTools::FileTimeCompare(std::string const& f1, + std::string const& f2, int* result) { // Default to same time. *result = 0; @@ -1462,11 +1496,11 @@ bool SystemTools::FileTimeCompare(const std::string& f1, const std::string& f2, // POSIX version. Use stat function to get file modification time. struct stat s1; if (stat(f1.c_str(), &s1) != 0) { - return false; + return Status::POSIX_errno(); } struct stat s2; if (stat(f2.c_str(), &s2) != 0) { - return false; + return Status::POSIX_errno(); } # if KWSYS_CXX_STAT_HAS_ST_MTIM // Compare using nanosecond resolution. @@ -1504,17 +1538,17 @@ bool SystemTools::FileTimeCompare(const std::string& f1, const std::string& f2, WIN32_FILE_ATTRIBUTE_DATA f2d; if (!GetFileAttributesExW(Encoding::ToWindowsExtendedPath(f1).c_str(), GetFileExInfoStandard, &f1d)) { - return false; + return Status::Windows_GetLastError(); } if (!GetFileAttributesExW(Encoding::ToWindowsExtendedPath(f2).c_str(), GetFileExInfoStandard, &f2d)) { - return false; + return Status::Windows_GetLastError(); } // Compare the file times using resolution provided by system call. *result = (int)CompareFileTime(&f1d.ftLastWriteTime, &f2d.ftLastWriteTime); #endif - return true; + return Status::Success(); } // Return a capitalized string (i.e the first letter is uppercased, all other @@ -2129,8 +2163,8 @@ static std::string FileInDir(const std::string& source, const std::string& dir) return new_destination + '/' + SystemTools::GetFilenameName(source); } -bool SystemTools::CopyFileIfDifferent(const std::string& source, - const std::string& destination) +Status SystemTools::CopyFileIfDifferent(std::string const& source, + std::string const& destination) { // special check for a destination that is a directory // FilesDiffer does not handle file to directory compare @@ -2147,7 +2181,7 @@ bool SystemTools::CopyFileIfDifferent(const std::string& source, } } // at this point the files must be the same so return true - return true; + return Status::Success(); } #define KWSYS_ST_BUFFER 4096 @@ -2273,16 +2307,13 @@ bool SystemTools::TextFilesDiffer(const std::string& path1, return false; } -/** - * Blockwise copy source to destination file - */ -static bool CopyFileContentBlockwise(const std::string& source, - const std::string& destination) +Status SystemTools::CopyFileContentBlockwise(std::string const& source, + std::string const& destination) { // Open files kwsys::ifstream fin(source.c_str(), std::ios::in | std::ios::binary); if (!fin) { - return false; + return Status::POSIX_errno(); } // try and remove the destination file so that read only destination files @@ -2294,7 +2325,7 @@ static bool CopyFileContentBlockwise(const std::string& source, kwsys::ofstream fout(destination.c_str(), std::ios::out | std::ios::trunc | std::ios::binary); if (!fout) { - return false; + return Status::POSIX_errno(); } // This copy loop is very sensitive on certain platforms with @@ -2323,10 +2354,10 @@ static bool CopyFileContentBlockwise(const std::string& source, fout.close(); if (!fout) { - return false; + return Status::POSIX_errno(); } - return true; + return Status::Success(); } /** @@ -2341,13 +2372,13 @@ static bool CopyFileContentBlockwise(const std::string& source, * - The underlying filesystem does not support file cloning * - An unspecified error occurred */ -static bool CloneFileContent(const std::string& source, - const std::string& destination) +Status SystemTools::CloneFileContent(std::string const& source, + std::string const& destination) { #if defined(__linux) && defined(FICLONE) int in = open(source.c_str(), O_RDONLY); if (in < 0) { - return false; + return Status::POSIX_errno(); } SystemTools::RemoveFile(destination); @@ -2355,38 +2386,42 @@ static bool CloneFileContent(const std::string& source, int out = open(destination.c_str(), O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); if (out < 0) { + Status status = Status::POSIX_errno(); close(in); - return false; + return status; } - int result = ioctl(out, FICLONE, in); + Status status = Status::Success(); + if (ioctl(out, FICLONE, in) < 0) { + status = Status::POSIX_errno(); + } close(in); close(out); - if (result < 0) { - return false; - } - - return true; + return status; #else (void)source; (void)destination; - return false; + return Status::POSIX(ENOSYS); #endif } /** * Copy a file named by "source" to the file named by "destination". */ -bool SystemTools::CopyFileAlways(const std::string& source, - const std::string& destination) +Status SystemTools::CopyFileAlways(std::string const& source, + std::string const& destination) { + Status status; mode_t perm = 0; - bool perms = SystemTools::GetPermissions(source, perm); + Status perms = SystemTools::GetPermissions(source, perm); std::string real_destination = destination; if (SystemTools::FileIsDirectory(source)) { - SystemTools::MakeDirectory(destination); + status = SystemTools::MakeDirectory(destination); + if (!status) { + return status; + } } else { // If destination is a directory, try to create a file with the same // name as the source in that directory. @@ -2403,30 +2438,34 @@ bool SystemTools::CopyFileAlways(const std::string& source, } // If files are the same do not copy if (SystemTools::SameFile(source, real_destination)) { - return true; + return status; } // Create destination directory - - SystemTools::MakeDirectory(destination_dir); - - if (!CloneFileContent(source, real_destination)) { - // if cloning did not succeed, fall back to blockwise copy - if (!CopyFileContentBlockwise(source, real_destination)) { - return false; + if (!destination_dir.empty()) { + status = SystemTools::MakeDirectory(destination_dir); + if (!status) { + return status; } } + + status = SystemTools::CloneFileContent(source, real_destination); + // if cloning did not succeed, fall back to blockwise copy + if (!status) { + status = SystemTools::CopyFileContentBlockwise(source, real_destination); + } + if (!status) { + return status; + } } if (perms) { - if (!SystemTools::SetPermissions(real_destination, perm)) { - return false; - } + status = SystemTools::SetPermissions(real_destination, perm); } - return true; + return status; } -bool SystemTools::CopyAFile(const std::string& source, - const std::string& destination, bool always) +Status SystemTools::CopyAFile(std::string const& source, + std::string const& destination, bool always) { if (always) { return SystemTools::CopyFileAlways(source, destination); @@ -2439,18 +2478,21 @@ bool SystemTools::CopyAFile(const std::string& source, * Copy a directory content from "source" directory to the directory named by * "destination". */ -bool SystemTools::CopyADirectory(const std::string& source, - const std::string& destination, bool always) +Status SystemTools::CopyADirectory(std::string const& source, + std::string const& destination, bool always) { + Status status; Directory dir; - if (dir.Load(source) == 0) { - return false; + status = dir.Load(source); + if (!status) { + return status; } - size_t fileNum; - if (!SystemTools::MakeDirectory(destination)) { - return false; + status = SystemTools::MakeDirectory(destination); + if (!status) { + return status; } - for (fileNum = 0; fileNum < dir.GetNumberOfFiles(); ++fileNum) { + + for (size_t fileNum = 0; fileNum < dir.GetNumberOfFiles(); ++fileNum) { if (strcmp(dir.GetFile(static_cast<unsigned long>(fileNum)), ".") != 0 && strcmp(dir.GetFile(static_cast<unsigned long>(fileNum)), "..") != 0) { std::string fullPath = source; @@ -2460,18 +2502,20 @@ bool SystemTools::CopyADirectory(const std::string& source, std::string fullDestPath = destination; fullDestPath += "/"; fullDestPath += dir.GetFile(static_cast<unsigned long>(fileNum)); - if (!SystemTools::CopyADirectory(fullPath, fullDestPath, always)) { - return false; + status = SystemTools::CopyADirectory(fullPath, fullDestPath, always); + if (!status) { + return status; } } else { - if (!SystemTools::CopyAFile(fullPath, destination, always)) { - return false; + status = SystemTools::CopyAFile(fullPath, destination, always); + if (!status) { + return status; } } } } - return true; + return status; } // return size of file; also returns zero if no file exists @@ -2553,26 +2597,26 @@ std::string SystemTools::GetLastSystemError() return strerror(e); } -bool SystemTools::RemoveFile(const std::string& source) +Status SystemTools::RemoveFile(std::string const& source) { #ifdef _WIN32 std::wstring const& ws = Encoding::ToWindowsExtendedPath(source); if (DeleteFileW(ws.c_str())) { - return true; + return Status::Success(); } DWORD err = GetLastError(); if (err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND) { - return true; + return Status::Success(); } if (err != ERROR_ACCESS_DENIED) { - return false; + return Status::Windows(err); } /* The file may be read-only. Try adding write permission. */ mode_t mode; if (!SystemTools::GetPermissions(source, mode) || !SystemTools::SetPermissions(source, S_IWRITE)) { SetLastError(err); - return false; + return Status::Windows(err); } const DWORD DIRECTORY_SOFT_LINK_ATTRS = @@ -2581,26 +2625,29 @@ bool SystemTools::RemoveFile(const std::string& source) if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & DIRECTORY_SOFT_LINK_ATTRS) == DIRECTORY_SOFT_LINK_ATTRS && RemoveDirectoryW(ws.c_str())) { - return true; + return Status::Success(); } if (DeleteFileW(ws.c_str()) || GetLastError() == ERROR_FILE_NOT_FOUND || GetLastError() == ERROR_PATH_NOT_FOUND) { - return true; + return Status::Success(); } /* Try to restore the original permissions. */ SystemTools::SetPermissions(source, mode); SetLastError(err); - return false; + return Status::Windows(err); #else - return unlink(source.c_str()) == 0 || errno == ENOENT; + if (unlink(source.c_str()) != 0 && errno != ENOENT) { + return Status::POSIX_errno(); + } + return Status::Success(); #endif } -bool SystemTools::RemoveADirectory(const std::string& source) +Status SystemTools::RemoveADirectory(std::string const& source) { // Add write permission to the directory so we can modify its // content to remove files and directories from it. - mode_t mode; + mode_t mode = 0; if (SystemTools::GetPermissions(source, mode)) { #if defined(_WIN32) && !defined(__CYGWIN__) mode |= S_IWRITE; @@ -2610,8 +2657,13 @@ bool SystemTools::RemoveADirectory(const std::string& source) SystemTools::SetPermissions(source, mode); } + Status status; Directory dir; - dir.Load(source); + status = dir.Load(source); + if (!status) { + return status; + } + size_t fileNum; for (fileNum = 0; fileNum < dir.GetNumberOfFiles(); ++fileNum) { if (strcmp(dir.GetFile(static_cast<unsigned long>(fileNum)), ".") != 0 && @@ -2621,18 +2673,23 @@ bool SystemTools::RemoveADirectory(const std::string& source) fullPath += dir.GetFile(static_cast<unsigned long>(fileNum)); if (SystemTools::FileIsDirectory(fullPath) && !SystemTools::FileIsSymlink(fullPath)) { - if (!SystemTools::RemoveADirectory(fullPath)) { - return false; + status = SystemTools::RemoveADirectory(fullPath); + if (!status) { + return status; } } else { - if (!SystemTools::RemoveFile(fullPath)) { - return false; + status = SystemTools::RemoveFile(fullPath); + if (!status) { + return status; } } } } - return (Rmdir(source) == 0); + if (Rmdir(source) != 0) { + status = Status::POSIX_errno(); + } + return status; } /** @@ -2985,7 +3042,7 @@ bool SystemTools::FileIsSymlink(const std::string& name) } CloseHandle(hFile); ULONG reparseTag = - reinterpret_cast<PREPARSE_GUID_DATA_BUFFER>(&buffer[0])->ReparseTag; + reinterpret_cast<PREPARSE_DATA_BUFFER>(&buffer[0])->ReparseTag; return (reparseTag == IO_REPARSE_TAG_SYMLINK) || (reparseTag == IO_REPARSE_TAG_MOUNT_POINT); } @@ -3025,45 +3082,109 @@ bool SystemTools::FileIsFIFO(const std::string& name) #endif } -#if defined(_WIN32) && !defined(__CYGWIN__) -bool SystemTools::CreateSymlink(const std::string&, const std::string&) +Status SystemTools::CreateSymlink(std::string const& origName, + std::string const& newName) { - return false; -} +#if defined(_WIN32) && !defined(__CYGWIN__) + DWORD flags; + if (FileIsDirectory(origName)) { + flags = SYMBOLIC_LINK_FLAG_DIRECTORY; + } else { + flags = 0; + } + + std::wstring origPath = Encoding::ToWindowsExtendedPath(origName); + std::wstring newPath = Encoding::ToWindowsExtendedPath(newName); + + Status status; + if (!CreateSymbolicLinkW(newPath.c_str(), origPath.c_str(), + flags | + SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE)) { + status = Status::Windows_GetLastError(); + } + // Older Windows versions do not understand + // SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE + if (status.GetWindows() == ERROR_INVALID_PARAMETER) { + status = Status::Success(); + if (!CreateSymbolicLinkW(newPath.c_str(), origPath.c_str(), flags)) { + status = Status::Windows_GetLastError(); + } + } + + return status; #else -bool SystemTools::CreateSymlink(const std::string& origName, - const std::string& newName) -{ - return symlink(origName.c_str(), newName.c_str()) >= 0; -} + if (symlink(origName.c_str(), newName.c_str()) < 0) { + return Status::POSIX_errno(); + } + return Status::Success(); #endif +} -#if defined(_WIN32) && !defined(__CYGWIN__) -bool SystemTools::ReadSymlink(const std::string&, std::string&) +Status SystemTools::ReadSymlink(std::string const& newName, + std::string& origName) { - return false; -} +#if defined(_WIN32) && !defined(__CYGWIN__) + std::wstring newPath = Encoding::ToWindowsExtendedPath(newName); + // FILE_ATTRIBUTE_REPARSE_POINT means: + // * a file or directory that has an associated reparse point, or + // * a file that is a symbolic link. + HANDLE hFile = CreateFileW( + newPath.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, + FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, nullptr); + if (hFile == INVALID_HANDLE_VALUE) { + return Status::Windows_GetLastError(); + } + byte buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; + DWORD bytesReturned = 0; + Status status; + if (!DeviceIoControl(hFile, FSCTL_GET_REPARSE_POINT, nullptr, 0, buffer, + MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &bytesReturned, + nullptr)) { + status = Status::Windows_GetLastError(); + } + CloseHandle(hFile); + if (!status) { + return status; + } + PREPARSE_DATA_BUFFER data = + reinterpret_cast<PREPARSE_DATA_BUFFER>(&buffer[0]); + USHORT substituteNameLength; + PCWSTR substituteNameData; + if (data->ReparseTag == IO_REPARSE_TAG_SYMLINK) { + substituteNameLength = + data->SymbolicLinkReparseBuffer.SubstituteNameLength / sizeof(WCHAR); + substituteNameData = data->SymbolicLinkReparseBuffer.PathBuffer + + data->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(WCHAR); + } else if (data->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) { + substituteNameLength = + data->MountPointReparseBuffer.SubstituteNameLength / sizeof(WCHAR); + substituteNameData = data->MountPointReparseBuffer.PathBuffer + + data->MountPointReparseBuffer.SubstituteNameOffset / sizeof(WCHAR); + } else { + return Status::Windows(ERROR_REPARSE_TAG_MISMATCH); + } + std::wstring substituteName(substituteNameData, substituteNameLength); + origName = Encoding::ToNarrow(substituteName); #else -bool SystemTools::ReadSymlink(const std::string& newName, - std::string& origName) -{ char buf[KWSYS_SYSTEMTOOLS_MAXPATH + 1]; int count = static_cast<int>( readlink(newName.c_str(), buf, KWSYS_SYSTEMTOOLS_MAXPATH)); - if (count >= 0) { - // Add null-terminator. - buf[count] = 0; - origName = buf; - return true; - } else { - return false; + if (count < 0) { + return Status::POSIX_errno(); } -} + // Add null-terminator. + buf[count] = 0; + origName = buf; #endif + return Status::Success(); +} -int SystemTools::ChangeDirectory(const std::string& dir) +Status SystemTools::ChangeDirectory(std::string const& dir) { - return Chdir(dir); + if (Chdir(dir) < 0) { + return Status::POSIX_errno(); + } + return Status::Success(); } std::string SystemTools::GetCurrentWorkingDirectory() @@ -3929,7 +4050,7 @@ bool SystemTools::FileIsFullPath(const char* in_name) bool SystemToolsStatic::FileIsFullPath(const char* in_name, size_t len) { -#if defined(_WIN32) || defined(__CYGWIN__) +#if defined(_WIN32) && !defined(__CYGWIN__) // On Windows, the name must be at least two characters long. if (len < 2) { return false; @@ -3960,7 +4081,8 @@ bool SystemToolsStatic::FileIsFullPath(const char* in_name, size_t len) return false; } -bool SystemTools::GetShortPath(const std::string& path, std::string& shortPath) +Status SystemTools::GetShortPath(std::string const& path, + std::string& shortPath) { #if defined(_WIN32) && !defined(__CYGWIN__) std::string tempPath = path; // create a buffer @@ -3980,14 +4102,14 @@ bool SystemTools::GetShortPath(const std::string& path, std::string& shortPath) } if (ret == 0) { - return false; + return Status::Windows_GetLastError(); } else { shortPath = Encoding::ToNarrow(&buffer[0]); - return true; + return Status::Success(); } #else shortPath = path; - return true; + return Status::Success(); #endif } @@ -4088,21 +4210,21 @@ int SystemTools::GetTerminalWidth() return width; } -bool SystemTools::GetPermissions(const char* file, mode_t& mode) +Status SystemTools::GetPermissions(const char* file, mode_t& mode) { if (!file) { - return false; + return Status::POSIX(EINVAL); } return SystemTools::GetPermissions(std::string(file), mode); } -bool SystemTools::GetPermissions(const std::string& file, mode_t& mode) +Status SystemTools::GetPermissions(std::string const& file, mode_t& mode) { #if defined(_WIN32) DWORD attr = GetFileAttributesW(Encoding::ToWindowsExtendedPath(file).c_str()); if (attr == INVALID_FILE_ATTRIBUTES) { - return false; + return Status::Windows_GetLastError(); } if ((attr & FILE_ATTRIBUTE_READONLY) != 0) { mode = (_S_IREAD | (_S_IREAD >> 3) | (_S_IREAD >> 6)); @@ -4125,27 +4247,27 @@ bool SystemTools::GetPermissions(const std::string& file, mode_t& mode) #else struct stat st; if (stat(file.c_str(), &st) < 0) { - return false; + return Status::POSIX_errno(); } mode = st.st_mode; #endif - return true; + return Status::Success(); } -bool SystemTools::SetPermissions(const char* file, mode_t mode, - bool honor_umask) +Status SystemTools::SetPermissions(const char* file, mode_t mode, + bool honor_umask) { if (!file) { - return false; + return Status::POSIX(EINVAL); } return SystemTools::SetPermissions(std::string(file), mode, honor_umask); } -bool SystemTools::SetPermissions(const std::string& file, mode_t mode, - bool honor_umask) +Status SystemTools::SetPermissions(std::string const& file, mode_t mode, + bool honor_umask) { if (!SystemTools::PathExists(file)) { - return false; + return Status::POSIX(ENOENT); } if (honor_umask) { mode_t currentMask = umask(0); @@ -4158,10 +4280,10 @@ bool SystemTools::SetPermissions(const std::string& file, mode_t mode, if (chmod(file.c_str(), mode) < 0) #endif { - return false; + return Status::POSIX_errno(); } - return true; + return Status::Success(); } std::string SystemTools::GetParentDirectory(const std::string& fileOrDir) diff --git a/Source/kwsys/SystemTools.hxx.in b/Source/kwsys/SystemTools.hxx.in index 74dc17651..e5d115e08 100644 --- a/Source/kwsys/SystemTools.hxx.in +++ b/Source/kwsys/SystemTools.hxx.in @@ -4,6 +4,7 @@ #define @KWSYS_NAMESPACE@_SystemTools_hxx #include <@KWSYS_NAMESPACE@/Configure.hxx> +#include <@KWSYS_NAMESPACE@/Status.hxx> #include <iosfwd> #include <map> @@ -339,7 +340,7 @@ public: /** Change the modification time or create a file */ - static bool Touch(const std::string& filename, bool create); + static Status Touch(std::string const& filename, bool create); /** * Compare file modification times. @@ -347,8 +348,8 @@ public: * When true is returned, result has -1, 0, +1 for * f1 older, same, or newer than f2. */ - static bool FileTimeCompare(const std::string& f1, const std::string& f2, - int* result); + static Status FileTimeCompare(std::string const& f1, std::string const& f2, + int* result); /** * Get the file extension (including ".") needed for an executable @@ -507,7 +508,7 @@ public: * For windows return the short path for the given path, * Unix just a pass through */ - static bool GetShortPath(const std::string& path, std::string& result); + static Status GetShortPath(std::string const& path, std::string& result); /** * Read line from file. Make sure to read a full line and truncates it if @@ -553,16 +554,16 @@ public: * can make a full path even if none of the directories existed * prior to calling this function. */ - static bool MakeDirectory(const char* path, const mode_t* mode = nullptr); - static bool MakeDirectory(const std::string& path, - const mode_t* mode = nullptr); + static Status MakeDirectory(const char* path, const mode_t* mode = nullptr); + static Status MakeDirectory(std::string const& path, + const mode_t* mode = nullptr); /** * Copy the source file to the destination file only * if the two files differ. */ - static bool CopyFileIfDifferent(const std::string& source, - const std::string& destination); + static Status CopyFileIfDifferent(std::string const& source, + std::string const& destination); /** * Compare the contents of two files. Return true if different @@ -578,6 +579,17 @@ public: const std::string& path2); /** + * Blockwise copy source to destination file + */ + static Status CopyFileContentBlockwise(std::string const& source, + std::string const& destination); + /** + * Clone the source file to the destination file + */ + static Status CloneFileContent(std::string const& source, + std::string const& destination); + + /** * Return true if the two files are the same file */ static bool SameFile(const std::string& file1, const std::string& file2); @@ -585,16 +597,16 @@ public: /** * Copy a file. */ - static bool CopyFileAlways(const std::string& source, - const std::string& destination); + static Status CopyFileAlways(std::string const& source, + std::string const& destination); /** * Copy a file. If the "always" argument is true the file is always * copied. If it is false, the file is copied only if it is new or * has changed. */ - static bool CopyAFile(const std::string& source, - const std::string& destination, bool always = true); + static Status CopyAFile(std::string const& source, + std::string const& destination, bool always = true); /** * Copy content directory to another directory with all files and @@ -602,19 +614,19 @@ public: * always copied. If it is false, only files that have changed or * are new are copied. */ - static bool CopyADirectory(const std::string& source, - const std::string& destination, - bool always = true); + static Status CopyADirectory(std::string const& source, + std::string const& destination, + bool always = true); /** * Remove a file */ - static bool RemoveFile(const std::string& source); + static Status RemoveFile(std::string const& source); /** * Remove a directory */ - static bool RemoveADirectory(const std::string& source); + static Status RemoveADirectory(std::string const& source); /** * Get the maximum full file path length @@ -708,14 +720,14 @@ public: * Create a symbolic link if the platform supports it. Returns whether * creation succeeded. */ - static bool CreateSymlink(const std::string& origName, - const std::string& newName); + static Status CreateSymlink(std::string const& origName, + std::string const& newName); /** * Read the contents of a symbolic link. Returns whether reading * succeeded. */ - static bool ReadSymlink(const std::string& newName, std::string& origName); + static Status ReadSymlink(std::string const& newName, std::string& origName); /** * Try to locate the file 'filename' in the directory 'dir'. @@ -765,12 +777,12 @@ public: * WARNING: A non-thread-safe method is currently used to get the umask * if a honor_umask parameter is set to true. */ - static bool GetPermissions(const char* file, mode_t& mode); - static bool GetPermissions(const std::string& file, mode_t& mode); - static bool SetPermissions(const char* file, mode_t mode, - bool honor_umask = false); - static bool SetPermissions(const std::string& file, mode_t mode, - bool honor_umask = false); + static Status GetPermissions(const char* file, mode_t& mode); + static Status GetPermissions(std::string const& file, mode_t& mode); + static Status SetPermissions(const char* file, mode_t mode, + bool honor_umask = false); + static Status SetPermissions(std::string const& file, mode_t mode, + bool honor_umask = false); /** ----------------------------------------------------------------- * Time Manipulation Routines @@ -867,7 +879,7 @@ public: /** * Change directory to the directory specified */ - static int ChangeDirectory(const std::string& dir); + static Status ChangeDirectory(std::string const& dir); /** * Get the result of strerror(errno) diff --git a/Source/kwsys/Terminal.c b/Source/kwsys/Terminal.c index 4d1b46c87..20bb5fe6d 100644 --- a/Source/kwsys/Terminal.c +++ b/Source/kwsys/Terminal.c @@ -10,7 +10,7 @@ #endif /* Configure support for this platform. */ -#if defined(_WIN32) || defined(__CYGWIN__) +#if defined(_WIN32) # define KWSYS_TERMINAL_SUPPORT_CONSOLE #endif #if !defined(_WIN32) @@ -173,6 +173,14 @@ static int kwsysTerminalStreamIsVT100(FILE* stream, int default_vt100, } } + /* Disable color according to http://bixense.com/clicolors/ convention. */ + { + const char* clicolor = getenv("CLICOLOR"); + if (clicolor && strcmp(clicolor, "0") == 0) { + return 0; + } + } + /* GNU make 4.1+ may tell us that its output is destined for a TTY. */ { const char* termout = getenv("MAKE_TERMOUT"); diff --git a/Source/kwsys/testDirectory.cxx b/Source/kwsys/testDirectory.cxx index eb3ca3254..06a22dc47 100644 --- a/Source/kwsys/testDirectory.cxx +++ b/Source/kwsys/testDirectory.cxx @@ -88,7 +88,7 @@ int _nonExistentDirectoryTest() errorMessage = "foo"; // Increment res failure if directory lists - res += testdir.Load(testdirpath, &errorMessage); + res += testdir.Load(testdirpath, &errorMessage) ? 1 : 0; #if !defined(_WIN32) || defined(__CYGWIN__) // Increment res failure if errorMessage is unmodified res += (errorMessage == "foo"); @@ -120,7 +120,7 @@ int _copyDirectoryTest() std::cerr << destination << " shouldn't exist before test" << std::endl; return 2; } - const bool copysuccess = SystemTools::CopyADirectory(source, destination); + const Status copysuccess = SystemTools::CopyADirectory(source, destination); const bool destinationexists = SystemTools::PathExists(destination); if (copysuccess) { std::cerr << "CopyADirectory should have returned false" << std::endl; diff --git a/Source/kwsys/testDynamicLoader.cxx b/Source/kwsys/testDynamicLoader.cxx index 703ad4dcd..9ba204e78 100644 --- a/Source/kwsys/testDynamicLoader.cxx +++ b/Source/kwsys/testDynamicLoader.cxx @@ -8,6 +8,25 @@ # include <be/kernel/OS.h> /* disable_debugger() API. */ #endif +// Needed for __GLIBC__ test macro. +#ifdef __linux__ +# include <features.h> +#endif + +// Will define LIBDL_SO macro on systems with glibc. +#ifdef __GLIBC__ +# include <gnu/lib-names.h> +// Define to LIBC_SO, if not defined by above header. +# ifndef LIBDL_SO +# define LIBDL_SO LIBC_SO +# endif +#endif + +// Define the LIBDL_SO macro, if not defined above. +#ifndef LIBDL_SO +# define LIBDL_SO "libdl.so" +#endif + // Work-around CMake dependency scanning limitation. This must // duplicate the above list of headers. #if 0 @@ -107,8 +126,8 @@ int testDynamicLoader(int argc, char* argv[]) // This one is actually fun to test, since dlopen is by default // loaded...wonder why :) res += TestDynamicLoader("foobar.lib", "dlopen", 0, 1, 0); - res += TestDynamicLoader("libdl.so", "dlopen", 1, 1, 1); - res += TestDynamicLoader("libdl.so", "TestDynamicLoader", 1, 0, 1); + res += TestDynamicLoader(LIBDL_SO, "dlopen", 1, 1, 1); + res += TestDynamicLoader(LIBDL_SO, "TestDynamicLoader", 1, 0, 1); #endif // Now try on the generated library std::string libname = GetLibName(KWSYS_NAMESPACE_STRING "TestDynload"); diff --git a/Source/kwsys/testStatus.cxx b/Source/kwsys/testStatus.cxx new file mode 100644 index 000000000..f85ef422d --- /dev/null +++ b/Source/kwsys/testStatus.cxx @@ -0,0 +1,117 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying +file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#include "kwsysPrivate.h" +#include KWSYS_HEADER(Status.hxx) + +// Work-around CMake dependency scanning limitation. This must +// duplicate the above list of headers. +#if 0 +# include "Status.hxx.in" +#endif + +#include <cerrno> +#include <iostream> + +#ifdef _WIN32 +# include <windows.h> +#endif + +int testStatus(int, char* []) +{ + bool res = true; + { + kwsys::Status status; + if (status.GetKind() != kwsys::Status::Kind::Success) { + std::cerr << "Status default constructor does not produce Success\n"; + res = false; + } + + status = kwsys::Status::Success(); + if (status.GetKind() != kwsys::Status::Kind::Success) { + std::cerr << "Status Success constructor does not produce Success\n"; + res = false; + } + if (!status) { + std::cerr << "Status Success kind is not true\n"; + res = false; + } + if (status.GetPOSIX() != 0) { + std::cerr << "Status Success kind does not return POSIX 0\n"; + res = false; + } +#ifdef _WIN32 + if (status.GetWindows() != 0) { + std::cerr << "Status Success kind does not return Windows 0\n"; + res = false; + } +#endif + if (status.GetString() != "Success") { + std::cerr << "Status Success kind does not return \"Success\" string\n"; + res = false; + } + + status = kwsys::Status::POSIX(EINVAL); + if (status.GetKind() != kwsys::Status::Kind::POSIX) { + std::cerr << "Status POSIX constructor does not produce POSIX\n"; + res = false; + } + if (status) { + std::cerr << "Status POSIX kind is not false\n"; + res = false; + } + if (status.GetPOSIX() != EINVAL) { + std::cerr << "Status POSIX kind does not preserve POSIX value\n"; + res = false; + } +#ifdef _WIN32 + if (status.GetWindows() != 0) { + std::cerr << "Status POSIX kind does not return Windows 0\n"; + res = false; + } +#endif + if (status.GetString().empty()) { + std::cerr << "Status POSIX kind returns empty string\n"; + res = false; + } + errno = ENOENT; + status = kwsys::Status::POSIX_errno(); + if (status.GetPOSIX() != ENOENT) { + std::cerr << "Status POSIX_errno did not use errno\n"; + res = false; + } + errno = 0; + +#ifdef _WIN32 + status = kwsys::Status::Windows(ERROR_INVALID_PARAMETER); + if (status.GetKind() != kwsys::Status::Kind::Windows) { + std::cerr << "Status Windows constructor does not produce Windows\n"; + res = false; + } + if (status) { + std::cerr << "Status Windows kind is not false\n"; + res = false; + } + if (status.GetWindows() != ERROR_INVALID_PARAMETER) { + std::cerr << "Status Windows kind does not preserve Windows value\n"; + res = false; + } + if (status.GetPOSIX() != 0) { + std::cerr << "Status Windows kind does not return POSIX 0\n"; + res = false; + } + if (status.GetString().empty()) { + std::cerr << "Status Windows kind returns empty string\n"; + res = false; + } + + SetLastError(ERROR_FILE_NOT_FOUND); + status = kwsys::Status::Windows_GetLastError(); + if (status.GetWindows() != ERROR_FILE_NOT_FOUND) { + std::cerr << "Status Windows_GetLastError did not use GetLastError()\n"; + res = false; + } + SetLastError(ERROR_SUCCESS); +#endif + } + return res ? 0 : 1; +} diff --git a/Source/kwsys/testSystemTools.cxx b/Source/kwsys/testSystemTools.cxx index cfa420df4..39a19cbf2 100644 --- a/Source/kwsys/testSystemTools.cxx +++ b/Source/kwsys/testSystemTools.cxx @@ -29,6 +29,7 @@ # ifdef _MSC_VER # define umask _umask # endif +# include <windows.h> #endif #include <sys/stat.h> /* umask (POSIX), _S_I* constants (Windows) */ // Visual C++ does not define mode_t. @@ -290,15 +291,17 @@ static bool CheckFileOperations() res = false; } + std::cerr << std::oct; // Reset umask -#if defined(_WIN32) && !defined(__CYGWIN__) +#ifdef __MSYS__ + mode_t fullMask = S_IWRITE; +#elif defined(_WIN32) && !defined(__CYGWIN__) // NOTE: Windows doesn't support toggling _S_IREAD. mode_t fullMask = _S_IWRITE; #else // On a normal POSIX platform, we can toggle all permissions. mode_t fullMask = S_IRWXU | S_IRWXG | S_IRWXO; #endif - mode_t orig_umask = umask(fullMask); // Test file permissions without umask mode_t origPerm, thisPerm; @@ -329,9 +332,10 @@ static bool CheckFileOperations() // While we're at it, check proper TestFileAccess functionality. bool do_write_test = true; -#if defined(__linux__) - // If we are running as root on linux ignore this check, as - // root can always write to files +#if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || \ + defined(__NetBSD__) || defined(__DragonFly__) + // If we are running as root on POSIX-ish systems (Linux and the BSDs, + // at least), ignore this check, as root can always write to files. do_write_test = (getuid() != 0); #endif if (do_write_test && @@ -370,6 +374,7 @@ static bool CheckFileOperations() res = false; } + mode_t orig_umask = umask(fullMask); // Test setting file permissions while honoring umask if (!kwsys::SystemTools::SetPermissions(testNewFile, fullMask, true)) { std::cerr << "Problem with SetPermissions (3) for: " << testNewFile @@ -422,21 +427,28 @@ static bool CheckFileOperations() res = false; } -#if !defined(_WIN32) std::string const testBadSymlink(testNewDir + "/badSymlink.txt"); std::string const testBadSymlinkTgt(testNewDir + "/missing/symlinkTgt.txt"); - if (!kwsys::SystemTools::CreateSymlink(testBadSymlinkTgt, testBadSymlink)) { - std::cerr << "Problem with CreateSymlink for: " << testBadSymlink << " -> " - << testBadSymlinkTgt << std::endl; - res = false; - } + kwsys::Status const symlinkStatus = + kwsys::SystemTools::CreateSymlink(testBadSymlinkTgt, testBadSymlink); +#if defined(_WIN32) + // Under Windows, the user may not have enough privileges to create symlinks + if (symlinkStatus.GetWindows() != ERROR_PRIVILEGE_NOT_HELD) +#endif + { + if (!symlinkStatus) { + std::cerr << "CreateSymlink for: " << testBadSymlink << " -> " + << testBadSymlinkTgt + << " failed: " << symlinkStatus.GetString() << std::endl; + res = false; + } - if (!kwsys::SystemTools::Touch(testBadSymlink, false)) { - std::cerr << "Problem with Touch (no create) for: " << testBadSymlink - << std::endl; - res = false; + if (!kwsys::SystemTools::Touch(testBadSymlink, false)) { + std::cerr << "Problem with Touch (no create) for: " << testBadSymlink + << std::endl; + res = false; + } } -#endif if (!kwsys::SystemTools::Touch(testNewDir, false)) { std::cerr << "Problem with Touch (no create) for: " << testNewDir @@ -496,6 +508,7 @@ static bool CheckFileOperations() } #endif + std::cerr << std::dec; return res; } @@ -1093,7 +1106,7 @@ static bool CheckCopyFileIfDifferent() ret = false; continue; } - std::string bdata = readFile("file_b"); + std::string bdata = readFile(cptarget); if (diff_test_cases[i].a != bdata) { std::cerr << "Incorrect CopyFileIfDifferent file contents in test case " << i + 1 << "." << std::endl; |