From ca03a9be6c629bec1ff989057bc3974d74b2904a Mon Sep 17 00:00:00 2001 From: KWSys Upstream Date: Sat, 22 Jan 2022 05:51:23 -0500 Subject: KWSys 2022-01-22 (16e180ad) Code extracted from: https://gitlab.kitware.com/utils/kwsys.git at commit 16e180ad8ae26f896adf1c30929b1d53b3e13dac (master). Upstream Shortlog ----------------- Brad King (2): 929b6c6c Glob: Revert "Optimize directory/symlink checks on Windows" 4b552447 Directory: Replace FileData with methods accepting file index Clemens Wasser (5): 43ce7a20 SystemTools: Factor out FileIsSymlinkWithAttr helper d078f9e6 Directory: Store FIND_DATA for files in Directory 7573b0fd Directory: Add Is{Directory,Symlink} to FileData 99c7831e Glob: Optimize directory/symlink checks on Windows d4c5ed92 Glob: Optimize directory/symlink checks on Windows Markus87 (1): 5f2dcc13 SystemTools: Fix FilesDiffer 32-bit signed integer overflow on Windows --- CMakeLists.txt | 1 + Directory.cxx | 90 +++++++++++++++++++++++++++++++++++++++++++++--------- Directory.hxx.in | 21 +++++++++++++ Glob.cxx | 4 +-- SystemTools.cxx | 21 ++++++++----- SystemTools.hxx.in | 10 ++++++ 6 files changed, 123 insertions(+), 24 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7da5971..2253a83 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -192,6 +192,7 @@ endif() if(KWSYS_USE_Directory) set(KWSYS_USE_Encoding 1) set(KWSYS_USE_Status 1) + set(KWSYS_USE_SystemTools 1) endif() if(KWSYS_USE_DynamicLoader) set(KWSYS_USE_Encoding 1) diff --git a/Directory.cxx b/Directory.cxx index 6e31cbf..d520c14 100644 --- a/Directory.cxx +++ b/Directory.cxx @@ -7,6 +7,8 @@ #include KWSYS_HEADER(Encoding.hxx) +#include KWSYS_HEADER(SystemTools.hxx) + // Work-around CMake dependency scanning limitation. This must // duplicate the above list of headers. #if 0 @@ -16,15 +18,48 @@ #endif #include +#include #include +#if defined(_WIN32) && !defined(__CYGWIN__) +# include + +# include +# include +# include +# include +# include +# include +# include +# include +#endif + namespace KWSYS_NAMESPACE { class DirectoryInternals { public: + struct FileData + { + std::string Name; +#if defined(_WIN32) && !defined(__CYGWIN__) + _wfinddata_t FindData; +#endif + FileData(std::string name +#if defined(_WIN32) && !defined(__CYGWIN__) + , + _wfinddata_t data +#endif + ) + : Name(std::move(name)) +#if defined(_WIN32) && !defined(__CYGWIN__) + , FindData(std::move(data)) +#endif + { + } + }; // Array of Files - std::vector Files; + std::vector Files; // Path to Open'ed directory std::string Path; @@ -59,10 +94,45 @@ unsigned long Directory::GetNumberOfFiles() const const char* Directory::GetFile(unsigned long dindex) const { - if (dindex >= this->Internal->Files.size()) { - return nullptr; + return this->Internal->Files[dindex].Name.c_str(); +} + +std::string const& Directory::GetFileName(std::size_t i) const +{ + return this->Internal->Files[i].Name; +} + +std::string Directory::GetFilePath(std::size_t i) const +{ + std::string abs = this->Internal->Path; + if (!abs.empty() && abs.back() != '/') { + abs += '/'; } - return this->Internal->Files[dindex].c_str(); + abs += this->Internal->Files[i].Name; + return abs; +} + +bool Directory::FileIsDirectory(std::size_t i) const +{ +#if defined(_WIN32) && !defined(__CYGWIN__) + _wfinddata_t const& data = this->Internal->Files[i].FindData; + return (data.attrib & FILE_ATTRIBUTE_DIRECTORY) != 0; +#else + std::string const& path = this->GetFilePath(i); + return kwsys::SystemTools::FileIsDirectory(path); +#endif +} + +bool Directory::FileIsSymlink(std::size_t i) const +{ + std::string const& path = this->GetFilePath(i); +#if defined(_WIN32) && !defined(__CYGWIN__) + _wfinddata_t const& data = this->Internal->Files[i].FindData; + return kwsys::SystemTools::FileIsSymlinkWithAttr( + Encoding::ToWindowsExtendedPath(path), data.attrib); +#else + return kwsys::SystemTools::FileIsSymlink(path); +#endif } const char* Directory::GetPath() const @@ -81,16 +151,6 @@ void Directory::Clear() // First Windows platforms #if defined(_WIN32) && !defined(__CYGWIN__) -# include - -# include -# include -# include -# include -# include -# include -# include -# include namespace KWSYS_NAMESPACE { @@ -133,7 +193,7 @@ Status Directory::Load(std::string const& name, std::string* errorMessage) // Loop through names do { - this->Internal->Files.push_back(Encoding::ToNarrow(data.name)); + this->Internal->Files.emplace_back(Encoding::ToNarrow(data.name), data); } while (_wfindnext(srchHandle, &data) != -1); this->Internal->Path = name; if (_findclose(srchHandle) == -1) { diff --git a/Directory.hxx.in b/Directory.hxx.in index d501116..9d0f462 100644 --- a/Directory.hxx.in +++ b/Directory.hxx.in @@ -6,6 +6,7 @@ #include <@KWSYS_NAMESPACE@/Configure.h> #include <@KWSYS_NAMESPACE@/Status.hxx> +#include #include namespace @KWSYS_NAMESPACE@ { @@ -55,6 +56,26 @@ public: const char* GetFile(unsigned long) const; /** + * Return the name of the file at the given 0-based index. + */ + std::string const& GetFileName(std::size_t i) const; + + /** + * Return the absolute path to the file at the given 0-based index. + */ + std::string GetFilePath(std::size_t i) const; + + /** + * Return whether the file at the given 0-based index is a directory. + */ + bool FileIsDirectory(std::size_t i) const; + + /** + * Return whether the file at the given 0-based index is a symlink. + */ + bool FileIsSymlink(std::size_t i) const; + + /** * Return the path to Open'ed directory */ const char* GetPath() const; diff --git a/Glob.cxx b/Glob.cxx index c6d4b19..fa2c295 100644 --- a/Glob.cxx +++ b/Glob.cxx @@ -213,8 +213,8 @@ bool Glob::RecurseDirectory(std::string::size_type start, fname = kwsys::SystemTools::LowerCase(fname); #endif - bool isDir = kwsys::SystemTools::FileIsDirectory(realname); - bool isSymLink = kwsys::SystemTools::FileIsSymlink(realname); + bool isDir = d.FileIsDirectory(cc); + bool isSymLink = d.FileIsSymlink(cc); if (isDir && (!isSymLink || this->RecurseThroughSymlinks)) { if (isSymLink) { diff --git a/SystemTools.cxx b/SystemTools.cxx index c339fd5..c38b456 100644 --- a/SystemTools.cxx +++ b/SystemTools.cxx @@ -2287,7 +2287,7 @@ bool SystemTools::FilesDiffer(const std::string& source, if (statSource.nFileSizeHigh == 0 && statSource.nFileSizeLow == 0) { return false; } - off_t nleft = + auto nleft = ((__int64)statSource.nFileSizeHigh << 32) + statSource.nFileSizeLow; #else @@ -3085,11 +3085,10 @@ bool SystemTools::FileIsExecutable(const std::string& name) return !FileIsDirectory(name) && TestFileAccess(name, TEST_FILE_EXECUTE); } -bool SystemTools::FileIsSymlink(const std::string& name) -{ #if defined(_WIN32) - std::wstring path = Encoding::ToWindowsExtendedPath(name); - DWORD attr = GetFileAttributesW(path.c_str()); +bool SystemTools::FileIsSymlinkWithAttr(const std::wstring& path, + unsigned long attr) +{ if (attr != INVALID_FILE_ATTRIBUTES) { if ((attr & FILE_ATTRIBUTE_REPARSE_POINT) != 0) { // FILE_ATTRIBUTE_REPARSE_POINT means: @@ -3118,9 +3117,17 @@ bool SystemTools::FileIsSymlink(const std::string& name) (reparseTag == IO_REPARSE_TAG_MOUNT_POINT); } return false; - } else { - return false; } + + return false; +} +#endif + +bool SystemTools::FileIsSymlink(const std::string& name) +{ +#if defined(_WIN32) + std::wstring path = Encoding::ToWindowsExtendedPath(name); + return FileIsSymlinkWithAttr(path, GetFileAttributesW(path.c_str())); #else struct stat fs; if (lstat(name.c_str(), &fs) == 0) { diff --git a/SystemTools.hxx.in b/SystemTools.hxx.in index 6684695..acce015 100644 --- a/SystemTools.hxx.in +++ b/SystemTools.hxx.in @@ -688,6 +688,16 @@ public: */ static bool FileIsExecutable(const std::string& name); +#if defined(_WIN32) + /** + * Return true if the file with FileAttributes `attr` is a symlink + * Only available on Windows. This avoids an expensive `GetFileAttributesW` + * call. + */ + static bool FileIsSymlinkWithAttr(const std::wstring& path, + unsigned long attr); +#endif + /** * Return true if the file is a symlink */ -- cgit v0.12