浏览代码

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
KWSys Robot 10 年之前
父节点
当前提交
aa84d26e63
共有 2 个文件被更改,包括 124 次插入16 次删除
  1. 81 12
      Glob.cxx
  2. 43 4
      Glob.hxx.in

+ 81 - 12
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 <ctype.h>
@@ -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<kwsys_stl::string>::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;
 }

+ 43 - 4
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<Message> GlobMessages;
+  typedef kwsys_stl::vector<Message>::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<kwsys_stl::string>& 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<kwsys_stl::string> VisitedSymlinks;
+  bool ListDirs;
+  bool RecurseListDirs;
 
 private:
   Glob(const Glob&);  // Not implemented.