From aa84d26e631e11d73328c24ac0301c43f661869b Mon Sep 17 00:00:00 2001 From: KWSys Robot Date: Tue, 3 Mar 2015 08:50:09 -0500 Subject: [PATCH] KWSys 2015-03-03 (4890f30c) Extract upstream KWSys using the following shell commands. $ git archive --prefix=upstream-kwsys/ 4890f30c | tar x $ git shortlog --no-merges --abbrev=8 --format='%h %s' d2aa1afd..4890f30c Domen Vrankar (2): 5d6204e9 Glob: Handle symlink cycles in directory paths 4890f30c Glob: Add support for directory listing Change-Id: Id8b77dabf8f50efeffdeaf1c826154fd2a25e17b --- Glob.cxx | 93 ++++++++++++++++++++++++++++++++++++++++++++++------- Glob.hxx.in | 47 ++++++++++++++++++++++++--- 2 files changed, 124 insertions(+), 16 deletions(-) diff --git a/Glob.cxx b/Glob.cxx index 1476c25e3..11bfd16b1 100644 --- a/Glob.cxx +++ b/Glob.cxx @@ -19,6 +19,7 @@ #include KWSYS_HEADER(Directory.hxx) #include KWSYS_HEADER(stl/string) #include KWSYS_HEADER(stl/vector) +#include KWSYS_HEADER(stl/algorithm) // Work-around CMake dependency scanning limitation. This must // duplicate the above list of headers. @@ -30,6 +31,8 @@ # include "SystemTools.hxx.in" # include "kwsys_stl.hxx.in" # include "kwsys_stl_string.hxx.in" +# include "kwsys_stl_vector.hxx.in" +# include "kwsys_stl_algorithm.hxx.in" #endif #include @@ -66,6 +69,10 @@ Glob::Glob() // RecurseThroughSymlinks is true by default for backwards compatibility, // not because it's a good idea... this->FollowedSymlinkCount = 0; + + // Keep separate variables for directory listing for back compatibility + this->ListDirs = true; + this->RecurseListDirs = false; } //---------------------------------------------------------------------------- @@ -214,13 +221,13 @@ kwsys_stl::string Glob::PatternToRegex(const kwsys_stl::string& pattern, } //---------------------------------------------------------------------------- -void Glob::RecurseDirectory(kwsys_stl::string::size_type start, - const kwsys_stl::string& dir) +bool Glob::RecurseDirectory(kwsys_stl::string::size_type start, + const kwsys_stl::string& dir, GlobMessages* messages) { kwsys::Directory d; if ( !d.Load(dir) ) { - return; + return true; } unsigned long cc; kwsys_stl::string realname; @@ -255,8 +262,67 @@ void Glob::RecurseDirectory(kwsys_stl::string::size_type start, if (isSymLink) { ++this->FollowedSymlinkCount; + kwsys_stl::string realPathErrorMessage; + kwsys_stl::string canonicalPath(SystemTools::GetRealPath(dir, + &realPathErrorMessage)); + + if(!realPathErrorMessage.empty()) + { + if(messages) + { + messages->push_back(Message( + Glob::error, "Canonical path generation from path '" + + dir + "' failed! Reason: '" + realPathErrorMessage + "'")); + } + return false; + } + + if(kwsys_stl::find(this->VisitedSymlinks.begin(), + this->VisitedSymlinks.end(), + canonicalPath) == this->VisitedSymlinks.end()) + { + if(this->RecurseListDirs) + { + // symlinks are treated as directories + this->AddFile(this->Internals->Files, realname); + } + + this->VisitedSymlinks.push_back(canonicalPath); + if(!this->RecurseDirectory(start+1, realname, messages)) + { + this->VisitedSymlinks.pop_back(); + + return false; + } + this->VisitedSymlinks.pop_back(); + } + // else we have already visited this symlink - prevent cyclic recursion + else if(messages) + { + kwsys_stl::string message; + for(kwsys_stl::vector::const_iterator + pathIt = kwsys_stl::find(this->VisitedSymlinks.begin(), + this->VisitedSymlinks.end(), + canonicalPath); + pathIt != this->VisitedSymlinks.end(); ++pathIt) + { + message += *pathIt + "\n"; + } + message += canonicalPath + "/" + fname; + messages->push_back(Message(Glob::cyclicRecursion, message)); + } + } + else + { + if(this->RecurseListDirs) + { + this->AddFile(this->Internals->Files, realname); + } + if(!this->RecurseDirectory(start+1, realname, messages)) + { + return false; + } } - this->RecurseDirectory(start+1, realname); } else { @@ -267,17 +333,19 @@ void Glob::RecurseDirectory(kwsys_stl::string::size_type start, } } } + + return true; } //---------------------------------------------------------------------------- void Glob::ProcessDirectory(kwsys_stl::string::size_type start, - const kwsys_stl::string& dir) + const kwsys_stl::string& dir, GlobMessages* messages) { //kwsys_ios::cout << "ProcessDirectory: " << dir << kwsys_ios::endl; bool last = ( start == this->Internals->Expressions.size()-1 ); if ( last && this->Recurse ) { - this->RecurseDirectory(start, dir); + this->RecurseDirectory(start, dir, messages); return; } @@ -321,8 +389,9 @@ void Glob::ProcessDirectory(kwsys_stl::string::size_type start, // << this->Internals->TextExpressions[start].c_str() << kwsys_ios::endl; //kwsys_ios::cout << "Real name: " << realname << kwsys_ios::endl; - if ( !last && - !kwsys::SystemTools::FileIsDirectory(realname) ) + if( (!last && !kwsys::SystemTools::FileIsDirectory(realname)) + || (!this->ListDirs && last && + kwsys::SystemTools::FileIsDirectory(realname)) ) { continue; } @@ -335,14 +404,14 @@ void Glob::ProcessDirectory(kwsys_stl::string::size_type start, } else { - this->ProcessDirectory(start+1, realname); + this->ProcessDirectory(start+1, realname, messages); } } } } //---------------------------------------------------------------------------- -bool Glob::FindFiles(const kwsys_stl::string& inexpr) +bool Glob::FindFiles(const kwsys_stl::string& inexpr, GlobMessages* messages) { kwsys_stl::string cexpr; kwsys_stl::string::size_type cc; @@ -438,11 +507,11 @@ bool Glob::FindFiles(const kwsys_stl::string& inexpr) // Handle network paths if ( skip > 0 ) { - this->ProcessDirectory(0, fexpr.substr(0, skip) + "/"); + this->ProcessDirectory(0, fexpr.substr(0, skip) + "/", messages); } else { - this->ProcessDirectory(0, "/"); + this->ProcessDirectory(0, "/", messages); } return true; } diff --git a/Glob.hxx.in b/Glob.hxx.in index d8b8491dc..39b7ce7e7 100644 --- a/Glob.hxx.in +++ b/Glob.hxx.in @@ -39,12 +39,37 @@ class GlobInternals; */ class @KWSYS_NAMESPACE@_EXPORT Glob { +public: + enum MessageType + { + error, + cyclicRecursion + }; + + struct Message + { + MessageType type; + kwsys_stl::string content; + + Message(MessageType t, const kwsys_stl::string& c) : + type(t), + content(c) + {} + Message(const Message& msg) : + type(msg.type), + content(msg.content) + {} + }; + + typedef kwsys_stl::vector GlobMessages; + typedef kwsys_stl::vector::iterator GlobMessagesIterator; public: Glob(); ~Glob(); //! Find all files that match the pattern. - bool FindFiles(const kwsys_stl::string& inexpr); + bool FindFiles(const kwsys_stl::string& inexpr, + GlobMessages* messages = 0); //! Return the list of files that matched. kwsys_stl::vector& GetFiles(); @@ -80,15 +105,26 @@ public: bool require_whole_string = true, bool preserve_case = false); + /** Getters and setters for enabling and disabling directory + listing in recursive and non recursive globbing mode. + If listing is enabled in recursive mode it also lists + directory symbolic links even if follow symlinks is enabled. */ + void SetListDirs(bool list) { this->ListDirs=list; } + bool GetListDirs() const { return this->ListDirs; } + void SetRecurseListDirs(bool list) { this->RecurseListDirs=list; } + bool GetRecurseListDirs() const { return this->RecurseListDirs; } + protected: //! Process directory void ProcessDirectory(kwsys_stl::string::size_type start, - const kwsys_stl::string& dir); + const kwsys_stl::string& dir, + GlobMessages* messages); //! Process last directory, but only when recurse flags is on. That is // effectively like saying: /path/to/file/**/file - void RecurseDirectory(kwsys_stl::string::size_type start, - const kwsys_stl::string& dir); + bool RecurseDirectory(kwsys_stl::string::size_type start, + const kwsys_stl::string& dir, + GlobMessages* messages); //! Add regular expression void AddExpression(const kwsys_stl::string& expr); @@ -101,6 +137,9 @@ protected: kwsys_stl::string Relative; bool RecurseThroughSymlinks; unsigned int FollowedSymlinkCount; + kwsys_stl::vector VisitedSymlinks; + bool ListDirs; + bool RecurseListDirs; private: Glob(const Glob&); // Not implemented.