> FYI, the proposed GetCanonicalPath already exists in KWSys as
> SystemTools::GetRealPath.  It returns the unchanged path on error.
> That could be extended to take an optional second argument as a
> pointer to a buffer describing the error.  If the argument is NULL
> use the current behavior.  Otherwise return an empty string and
> populate the error info.  Then make your new call sites use the
> new argument.

Hm I missed this one... My old nightly version Code::Blocks seems to
have missed it in search. Thanks.

Attached are patches for KWSys Glob and SystemTools (with changes
required by Glob).

Thanks,
Domen
From 88566a6912e795b435be585a7bf009ba40d1f73c Mon Sep 17 00:00:00 2001
From: Domen Vrankar <[email protected]>
Date: Sat, 21 Feb 2015 10:54:34 +0100
Subject: [PATCH 1/4] glob recurse cyclic recursion handling

Prevent cyclic recursion of type a/b/c->a when
glob recurse is used with follow symlinks so
that each directory symbolic link is traversed
only once and skipped on revisit.
---
 Source/kwsys/Glob.cxx           | 81 ++++++++++++++++++++++++++++++++++++-----
 Source/kwsys/Glob.hxx.in        | 36 ++++++++++++++++--
 Source/kwsys/SystemTools.cxx    | 59 +++++++++++++++++++++++++++---
 Source/kwsys/SystemTools.hxx.in |  7 +++-
 4 files changed, 161 insertions(+), 22 deletions(-)

diff --git a/Source/kwsys/Glob.cxx b/Source/kwsys/Glob.cxx
index 5a96aed..43da52f 100644
--- a/Source/kwsys/Glob.cxx
+++ b/Source/kwsys/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>
@@ -214,13 +217,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 fullname;
@@ -265,8 +268,64 @@ 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(VisitedSymlinks.begin(), VisitedSymlinks.end(),
+          canonicalPath) == VisitedSymlinks.end())
+          {
+          struct ScopedSymlinkPath
+          {
+            ScopedSymlinkPath(
+              kwsys_stl::vector<kwsys_stl::string>& visitedSymlinks,
+              const std::string& canonicalPath)
+              : RefVisitedSymlinks(visitedSymlinks)
+              {
+              RefVisitedSymlinks.push_back(canonicalPath);
+              }
+            ~ScopedSymlinkPath() {RefVisitedSymlinks.pop_back();}
+            kwsys_stl::vector<kwsys_stl::string>& RefVisitedSymlinks;
+          } scopedSymlinkPath(VisitedSymlinks, canonicalPath);
+
+          if(!this->RecurseDirectory(start+1, realname, messages))
+            {
+            return false;
+            }
+          }
+        // else we have already visited this symlink - prevent cyclic recursion
+        else if(messages)
+          {
+          kwsys_stl::vector<kwsys_stl::string>::const_iterator pathIt =
+              kwsys_stl::find(VisitedSymlinks.begin(), VisitedSymlinks.end(),
+                canonicalPath);
+          kwsys_stl::string message;
+          for(pathIt; pathIt != VisitedSymlinks.end(); ++pathIt)
+            {
+            message += *pathIt + "\n";
+            }
+          message += canonicalPath + "/" + fname;
+          messages->push_back(Message(Glob::cyclicRecursion, message));
+          }
+        }
+      else
+        {
+        if(!this->RecurseDirectory(start+1, realname, messages))
+          {
+          return false;
+          }
         }
-      this->RecurseDirectory(start+1, realname);
       }
     else
       {
@@ -277,17 +336,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;
     }
 
@@ -355,14 +416,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;
@@ -458,11 +519,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/Source/kwsys/Glob.hxx.in b/Source/kwsys/Glob.hxx.in
index d8b8491..f5b80b5 100644
--- a/Source/kwsys/Glob.hxx.in
+++ b/Source/kwsys/Glob.hxx.in
@@ -40,11 +40,36 @@ class GlobInternals;
 class @KWSYS_NAMESPACE@_EXPORT Glob
 {
 public:
+  enum MessageType
+  {
+    error,
+    cyclicRecursion
+  };
+
+  struct Message
+  {
+    MessageType type;
+    kwsys_stl::string content;
+
+    Message(MessageType t, 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();
@@ -83,12 +108,14 @@ public:
 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 +128,7 @@ protected:
   kwsys_stl::string Relative;
   bool RecurseThroughSymlinks;
   unsigned int FollowedSymlinkCount;
+  kwsys_stl::vector<kwsys_stl::string> VisitedSymlinks;
 
 private:
   Glob(const Glob&);  // Not implemented.
diff --git a/Source/kwsys/SystemTools.cxx b/Source/kwsys/SystemTools.cxx
index 2708211..28fd312 100644
--- a/Source/kwsys/SystemTools.cxx
+++ b/Source/kwsys/SystemTools.cxx
@@ -250,17 +250,46 @@ inline int Chdir(const kwsys_stl::string& dir)
   return _wchdir(KWSYS_NAMESPACE::Encoding::ToWide(dir).c_str());
   #endif
 }
-inline void Realpath(const kwsys_stl::string& path, kwsys_stl::string & resolved_path)
+inline void Realpath(const kwsys_stl::string& path,
+                     kwsys_stl::string & resolved_path,
+                     kwsys_stl::string* errorMessage = 0)
 {
   kwsys_stl::wstring tmp = KWSYS_NAMESPACE::Encoding::ToWide(path);
   wchar_t *ptemp;
   wchar_t fullpath[MAX_PATH];
-  if( GetFullPathNameW(tmp.c_str(), sizeof(fullpath)/sizeof(fullpath[0]),
-                       fullpath, &ptemp) )
+  DWORD bufferLen = GetFullPathNameW(tmp.c_str(),
+      sizeof(fullpath) / sizeof(fullpath[0]),
+      fullpath, &ptemp);
+  if( bufferLen < sizeof(fullpath)/sizeof(fullpath[0]) )
     {
     resolved_path = KWSYS_NAMESPACE::Encoding::ToNarrow(fullpath);
     KWSYS_NAMESPACE::SystemTools::ConvertToUnixSlashes(resolved_path);
     }
+  else if(errorMessage)
+    {
+    if(bufferLen)
+      {
+      *errorMessage = "Destination path buffer size too small.";
+      }
+    else if(unsigned int errorId = GetLastError() != 0)
+      {
+      LPSTR message = nullptr;
+      DWORD size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER
+                                   | FORMAT_MESSAGE_FROM_SYSTEM
+                                   | FORMAT_MESSAGE_IGNORE_INSERTS,
+                                   NULL, errorId,
+                                   MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+                                   (LPSTR)&message, 0, NULL);
+      *errorMessage = std::string(message, size);
+      LocalFree(message);
+      }
+    else
+      {
+      *errorMessage = "Unknown error.";
+      }
+
+    resolved_path.clear();
+    }
   else
     {
     resolved_path = path;
@@ -287,15 +316,32 @@ inline int Chdir(const kwsys_stl::string& dir)
 {
   return chdir(dir.c_str());
 }
-inline void Realpath(const kwsys_stl::string& path, kwsys_stl::string & resolved_path)
+inline void Realpath(const kwsys_stl::string& path,
+                     kwsys_stl::string & resolved_path,
+                     kwsys_stl::string* errorMessage = 0)
 {
   char resolved_name[KWSYS_SYSTEMTOOLS_MAXPATH];
 
+  errno = 0;
   char *ret = realpath(path.c_str(), resolved_name);
   if(ret)
     {
     resolved_path = ret;
     }
+  else if(errorMessage)
+    {
+    if(errno)
+      {
+      char buffer[256];
+      *errorMessage = strerror_r(errno, buffer, 256);
+      }
+    else
+      {
+      *errorMessage = "Unknown error.";
+      }
+
+    resolved_path.clear();
+    }
   else
     {
     // if path resolution fails, return what was passed in
@@ -3046,10 +3092,11 @@ kwsys_stl::string SystemTools
   return "";
 }
 
-kwsys_stl::string SystemTools::GetRealPath(const kwsys_stl::string& path)
+kwsys_stl::string SystemTools::GetRealPath(const kwsys_stl::string& path,
+                                           kwsys_stl::string* errorMessage)
 {
   kwsys_stl::string ret;
-  Realpath(path, ret);
+  Realpath(path, ret, errorMessage);
   return ret;
 }
 
diff --git a/Source/kwsys/SystemTools.hxx.in b/Source/kwsys/SystemTools.hxx.in
index beb2a7e..b2e4032 100644
--- a/Source/kwsys/SystemTools.hxx.in
+++ b/Source/kwsys/SystemTools.hxx.in
@@ -385,9 +385,12 @@ public:
   /** 
    * Get the real path for a given path, removing all symlinks.  In
    * the event of an error (non-existent path, permissions issue,
-   * etc.) the original path is returned.
+   * etc.) the original path is returned if errorMessage pointer is
+   * uninitialized otherwise empty string is returned and errorMessage
+   * contains error description.
    */
-  static kwsys_stl::string GetRealPath(const kwsys_stl::string& path);
+  static kwsys_stl::string GetRealPath(const kwsys_stl::string& path,
+                                       kwsys_stl::string* errorMessage = 0);
 
   /**
    * Split a path name into its root component and the rest of the
-- 
2.1.0

From 84defcc3850b96ee3e48de802f2a192d6b64915a Mon Sep 17 00:00:00 2001
From: Domen Vrankar <[email protected]>
Date: Sat, 21 Feb 2015 10:55:15 +0100
Subject: [PATCH 2/4] dead code cleanup from glob

---
 Source/kwsys/Glob.cxx | 22 +---------------------
 1 file changed, 1 insertion(+), 21 deletions(-)

diff --git a/Source/kwsys/Glob.cxx b/Source/kwsys/Glob.cxx
index 43da52f..997c867 100644
--- a/Source/kwsys/Glob.cxx
+++ b/Source/kwsys/Glob.cxx
@@ -226,7 +226,6 @@ bool Glob::RecurseDirectory(kwsys_stl::string::size_type start,
     return true;
     }
   unsigned long cc;
-  kwsys_stl::string fullname;
   kwsys_stl::string realname;
   kwsys_stl::string fname;
   for ( cc = 0; cc < d.GetNumberOfFiles(); cc ++ )
@@ -251,15 +250,6 @@ bool Glob::RecurseDirectory(kwsys_stl::string::size_type start,
     fname = kwsys::SystemTools::LowerCase(fname);
 #endif
 
-    if ( start == 0 )
-      {
-      fullname = dir + fname;
-      }
-    else
-      {
-      fullname = dir + "/" + fname;
-      }
-
     bool isDir = kwsys::SystemTools::FileIsDirectory(realname);
     bool isSymLink = kwsys::SystemTools::FileIsSymlink(realname);
 
@@ -363,7 +353,6 @@ void Glob::ProcessDirectory(kwsys_stl::string::size_type start,
     return;
     }
   unsigned long cc;
-  kwsys_stl::string fullname;
   kwsys_stl::string realname;
   kwsys_stl::string fname;
   for ( cc = 0; cc < d.GetNumberOfFiles(); cc ++ )
@@ -388,19 +377,10 @@ void Glob::ProcessDirectory(kwsys_stl::string::size_type start,
     fname = kwsys::SystemTools::LowerCase(fname);
 #endif
 
-    if ( start == 0 )
-      {
-      fullname = dir + fname;
-      }
-    else
-      {
-      fullname = dir + "/" + fname;
-      }
-
     //kwsys_ios::cout << "Look at file: " << fname << kwsys_ios::endl;
     //kwsys_ios::cout << "Match: "
     // << this->Internals->TextExpressions[start].c_str() << kwsys_ios::endl;
-    //kwsys_ios::cout << "Full name: " << fullname << kwsys_ios::endl;
+    //kwsys_ios::cout << "Real name: " << realname << kwsys_ios::endl;
 
     if ( !last &&
       !kwsys::SystemTools::FileIsDirectory(realname) )
-- 
2.1.0

From ee20e4dc947056fed732567621dd80d62d98b5f0 Mon Sep 17 00:00:00 2001
From: Domen Vrankar <[email protected]>
Date: Sat, 21 Feb 2015 10:56:27 +0100
Subject: [PATCH 3/4] glob support for directory listing

Glob now supports listing of directories
in recursive mode and disabling listing
of directories in non recursive mode.
In recursive mode when directory listing
is enabled directory symlinks are also
listed.
---
 Source/kwsys/Glob.cxx    | 14 ++++++++++++--
 Source/kwsys/Glob.hxx.in | 11 +++++++++++
 2 files changed, 23 insertions(+), 2 deletions(-)

diff --git a/Source/kwsys/Glob.cxx b/Source/kwsys/Glob.cxx
index 997c867..3b29abc 100644
--- a/Source/kwsys/Glob.cxx
+++ b/Source/kwsys/Glob.cxx
@@ -69,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;
 }
 
 //----------------------------------------------------------------------------
@@ -289,6 +293,12 @@ bool Glob::RecurseDirectory(kwsys_stl::string::size_type start,
             kwsys_stl::vector<kwsys_stl::string>& RefVisitedSymlinks;
           } scopedSymlinkPath(VisitedSymlinks, canonicalPath);
 
+          if(RecurseListDirs)
+            {
+            // symlinks are treated as directories
+            this->AddFile(this->Internals->Files, realname);
+            }
+
           if(!this->RecurseDirectory(start+1, realname, messages))
             {
             return false;
@@ -382,8 +392,8 @@ 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))
+      || (!ListDirs && last && kwsys::SystemTools::FileIsDirectory(realname)) )
       {
       continue;
       }
diff --git a/Source/kwsys/Glob.hxx.in b/Source/kwsys/Glob.hxx.in
index f5b80b5..156b21f 100644
--- a/Source/kwsys/Glob.hxx.in
+++ b/Source/kwsys/Glob.hxx.in
@@ -105,6 +105,15 @@ 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) {ListDirs=list;}
+  bool GetListDirs() const {return ListDirs;}
+  void SetRecurseListDirs(bool list) {RecurseListDirs=list;}
+  bool GetRecurseListDirs() const {return RecurseListDirs;}
+
 protected:
   //! Process directory
   void ProcessDirectory(kwsys_stl::string::size_type start,
@@ -129,6 +138,8 @@ protected:
   bool RecurseThroughSymlinks;
   unsigned int FollowedSymlinkCount;
   kwsys_stl::vector<kwsys_stl::string> VisitedSymlinks;
+  bool ListDirs;
+  bool RecurseListDirs;
 
 private:
   Glob(const Glob&);  // Not implemented.
-- 
2.1.0

From 25c52b0d985d67cf06e255aa5d2d99361d0e1db3 Mon Sep 17 00:00:00 2001
From: Domen Vrankar <[email protected]>
Date: Sat, 21 Feb 2015 10:56:48 +0100
Subject: [PATCH 4/4] glob removed addition of a slash

When globing non recursive with for eg.
/a/*/* the result contained // instead
of a single slash between directories.
---
 Source/kwsys/Glob.cxx | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Source/kwsys/Glob.cxx b/Source/kwsys/Glob.cxx
index 3b29abc..7ffa34d 100644
--- a/Source/kwsys/Glob.cxx
+++ b/Source/kwsys/Glob.cxx
@@ -406,7 +406,7 @@ void Glob::ProcessDirectory(kwsys_stl::string::size_type start,
         }
       else
         {
-        this->ProcessDirectory(start+1, realname + "/", messages);
+        this->ProcessDirectory(start+1, realname, messages);
         }
       }
     }
-- 
2.1.0

-- 

Powered by www.kitware.com

Please keep messages on-topic and check the CMake FAQ at: 
http://www.cmake.org/Wiki/CMake_FAQ

Kitware offers various services to support the CMake community. For more 
information on each offering, please visit:

CMake Support: http://cmake.org/cmake/help/support.html
CMake Consulting: http://cmake.org/cmake/help/consulting.html
CMake Training Courses: http://cmake.org/cmake/help/training.html

Visit other Kitware open-source projects at 
http://www.kitware.com/opensource/opensource.html

Follow this link to subscribe/unsubscribe:
http://public.kitware.com/mailman/listinfo/cmake-developers

Reply via email to