Hi everyone,

I am having problems with a patch for Glob functionality because Glob
is part of KWSys repository.

I tried to register to http://review.source.kitware.com so that I
would be able to commit patches to KWSys repository but after I put in
my OpenID I got a "Not Found" error.

How can I contribute this patch?

Attached are KWSys patch and KWSys+CMake patch.

Thanks,
Domen
From 9c113fe546669a064d461004ae7e74be07744e40 Mon Sep 17 00:00:00 2001
From: Domen Vrankar <domen.vran...@gmail.com>
Date: Sun, 15 Feb 2015 20:42:16 +0100
Subject: [PATCH] handle cyclic recursion when using glob recurse with follow
 symlinks

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/Directory.cxx                         | 35 ++++++++++++++++++++++
 Source/kwsys/Directory.hxx.in                      |  7 +++++
 Source/kwsys/Glob.cxx                              | 32 +++++++++++++++++++-
 Source/kwsys/Glob.hxx.in                           |  2 ++
 .../file/GLOB_RECURSE-symlink-recursion-stderr.txt |  2 ++
 .../file/GLOB_RECURSE-symlink-recursion.cmake      | 10 +++++++
 Tests/RunCMake/file/RunCMakeTest.cmake             |  1 +
 7 files changed, 88 insertions(+), 1 deletion(-)
 create mode 100644 Tests/RunCMake/file/GLOB_RECURSE-symlink-recursion-stderr.txt
 create mode 100644 Tests/RunCMake/file/GLOB_RECURSE-symlink-recursion.cmake

diff --git a/Source/kwsys/Directory.cxx b/Source/kwsys/Directory.cxx
index 58cea63..5494908 100644
--- a/Source/kwsys/Directory.cxx
+++ b/Source/kwsys/Directory.cxx
@@ -18,6 +18,7 @@
 
 #include KWSYS_HEADER(stl/string)
 #include KWSYS_HEADER(stl/vector)
+#include KWSYS_HEADER(stl/stdexcept)
 
 // Work-around CMake dependency scanning limitation.  This must
 // duplicate the above list of headers.
@@ -28,8 +29,11 @@
 # include "kwsys_stl.hxx.in"
 # include "kwsys_stl_string.hxx.in"
 # include "kwsys_stl_vector.hxx.in"
+# include "kwsys_stl_stdexcept.hxx.in"
 #endif
 
+#include <stdlib.h>
+
 namespace KWSYS_NAMESPACE
 {
 
@@ -79,6 +83,37 @@ const char* Directory::GetPath() const
 }
 
 //----------------------------------------------------------------------------
+kwsys_stl::string Directory::GetCanonicalPath() const
+{
+/* The maximum length of a file name. */
+#if defined(PATH_MAX)
+  #define CANONICAL_PATH_MAX_LEN PATH_MAX
+#elif defined(MAXPATHLEN)
+  #define CANONICAL_PATH_MAX_LEN MAXPATHLEN
+#else
+  #define CANONICAL_PATH_MAX_LEN 16384
+#endif
+
+  char out_path[CANONICAL_PATH_MAX_LEN];
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+  /* Implementation for Windows.  */
+  DWORD n = GetFullPathNameA(this->Internal->Path.c_str(),
+              CANONICAL_PATH_MAX_LEN], out_path, 0);
+  if( n > 0 && n <= CANONICAL_PATH_MAX_LEN )
+#else
+  /* Implementation for UNIX.  */
+  if( !realpath(this->Internal->Path.c_str(), out_path) )
+#endif
+    {
+    throw kwsys_stl::runtime_error("Failed to convert path '"
+      + this->Internal->Path + "' to canonical form.");
+    }
+
+  return out_path;
+}
+
+//----------------------------------------------------------------------------
 void Directory::Clear()
 {
   this->Internal->Path.resize(0);
diff --git a/Source/kwsys/Directory.hxx.in b/Source/kwsys/Directory.hxx.in
index 1bcf90e..453b578 100644
--- a/Source/kwsys/Directory.hxx.in
+++ b/Source/kwsys/Directory.hxx.in
@@ -68,6 +68,13 @@ public:
   const char* GetPath() const;
 
   /**
+   * Return path to Open'ed directory without symbolic links, dot or
+   * dot-dot elements. runtime_error is thrown if canonical path
+   * could not be created.
+   */
+   kwsys_stl::string GetCanonicalPath() const;
+
+  /**
    * Clear the internal structure. Used internally at beginning of Load(...)
    * to clear the cache.
    */
diff --git a/Source/kwsys/Glob.cxx b/Source/kwsys/Glob.cxx
index 5a96aed..22bab9f 100644
--- a/Source/kwsys/Glob.cxx
+++ b/Source/kwsys/Glob.cxx
@@ -30,11 +30,14 @@
 # include "SystemTools.hxx.in"
 # include "kwsys_stl.hxx.in"
 # include "kwsys_stl_string.hxx.in"
+# include "kwsys_stl_vector.hxx.in"
 #endif
 
 #include <ctype.h>
 #include <stdio.h>
 #include <string.h>
+#include <stdlib.h>
+#include <iostream>
 namespace KWSYS_NAMESPACE
 {
 #if defined(_WIN32) || defined(__APPLE__) || defined(__CYGWIN__)
@@ -265,8 +268,35 @@ void Glob::RecurseDirectory(kwsys_stl::string::size_type start,
       if (isSymLink)
         {
         ++this->FollowedSymlinkCount;
+        kwsys_stl::string canonicalPath(d.GetCanonicalPath());
+
+        if(VisitedSymlinks.find(canonicalPath) == VisitedSymlinks.end())
+          {
+          // structure for handling symbolic link path even if an exception
+          // is thrown
+          struct ScopedSymlinkPath
+          {
+            ScopedSymlinkPath(
+              kwsys_stl::set<kwsys_stl::string>& visitedSymlinks,
+              const std::string& canonicalPath)
+              : RefVisitedSymlinks(visitedSymlinks)
+              , RefCanonicalPath(canonicalPath)
+              {
+              RefVisitedSymlinks.insert(RefCanonicalPath);
+              }
+            ~ScopedSymlinkPath() {RefVisitedSymlinks.erase(RefCanonicalPath);}
+            kwsys_stl::set<kwsys_stl::string>& RefVisitedSymlinks;
+            const kwsys_stl::string& RefCanonicalPath;
+          } scopedSymlinkPath(VisitedSymlinks, canonicalPath);
+
+          this->RecurseDirectory(start+1, realname);
+          }
+        // else we have already visited this symlink - prevent cyclic recursion
+        }
+      else
+        {
+        this->RecurseDirectory(start+1, realname);
         }
-      this->RecurseDirectory(start+1, realname);
       }
     else
       {
diff --git a/Source/kwsys/Glob.hxx.in b/Source/kwsys/Glob.hxx.in
index d8b8491..61bbd35 100644
--- a/Source/kwsys/Glob.hxx.in
+++ b/Source/kwsys/Glob.hxx.in
@@ -17,6 +17,7 @@
 
 #include <@KWSYS_NAMESPACE@/stl/string>
 #include <@KWSYS_NAMESPACE@/stl/vector>
+#include <@KWSYS_NAMESPACE@/stl/set>
 
 /* Define this macro temporarily to keep the code readable.  */
 #if !defined (KWSYS_NAMESPACE) && !@KWSYS_NAMESPACE@_NAME_IS_KWSYS
@@ -101,6 +102,7 @@ protected:
   kwsys_stl::string Relative;
   bool RecurseThroughSymlinks;
   unsigned int FollowedSymlinkCount;
+  kwsys_stl::set<kwsys_stl::string> VisitedSymlinks;
 
 private:
   Glob(const Glob&);  // Not implemented.
diff --git a/Tests/RunCMake/file/GLOB_RECURSE-symlink-recursion-stderr.txt b/Tests/RunCMake/file/GLOB_RECURSE-symlink-recursion-stderr.txt
new file mode 100644
index 0000000..865545a
--- /dev/null
+++ b/Tests/RunCMake/file/GLOB_RECURSE-symlink-recursion-stderr.txt
@@ -0,0 +1,2 @@
+.*files: 4 .*
+.*/test/abc;.*/test/depth1/depth2/depth3/recursion/abc;.*/test/depth1/depth2/depth3/recursion/depth1/depth2/depth3/file_symlink;.*/test/depth1/depth2/depth3/file_symlink.*
diff --git a/Tests/RunCMake/file/GLOB_RECURSE-symlink-recursion.cmake b/Tests/RunCMake/file/GLOB_RECURSE-symlink-recursion.cmake
new file mode 100644
index 0000000..d114737
--- /dev/null
+++ b/Tests/RunCMake/file/GLOB_RECURSE-symlink-recursion.cmake
@@ -0,0 +1,10 @@
+file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/test/depth1/depth2/depth3")
+execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink "${CMAKE_CURRENT_BINARY_DIR}/test" "${CMAKE_CURRENT_BINARY_DIR}/test/depth1/depth2/depth3/recursion")
+
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/test/abc" "message to write")
+execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink "${CMAKE_CURRENT_BINARY_DIR}/test/abc" "${CMAKE_CURRENT_BINARY_DIR}/test/depth1/depth2/depth3/file_symlink")
+
+file(GLOB_RECURSE FILE_LIST FOLLOW_SYMLINKS "${CMAKE_CURRENT_BINARY_DIR}/test/*")
+list(LENGTH FILE_LIST FILES_COUNT)
+message("files: ${FILES_COUNT} ")
+message("${FILE_LIST}")
diff --git a/Tests/RunCMake/file/RunCMakeTest.cmake b/Tests/RunCMake/file/RunCMakeTest.cmake
index 14819e7..1afae62 100644
--- a/Tests/RunCMake/file/RunCMakeTest.cmake
+++ b/Tests/RunCMake/file/RunCMakeTest.cmake
@@ -17,3 +17,4 @@ run_cmake(LOCK-error-no-result-variable)
 run_cmake(LOCK-error-no-timeout)
 run_cmake(LOCK-error-timeout)
 run_cmake(LOCK-error-unknown-option)
+run_cmake(GLOB_RECURSE-symlink-recursion)
-- 
2.1.0

From d70ceb156cf801026086e3ba009c68a029523baf Mon Sep 17 00:00:00 2001
From: Domen Vrankar <domen.vran...@gmail.com>
Date: Sun, 15 Feb 2015 20:58:48 +0100
Subject: [PATCH] handle glob symlink cyclic recursion

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.
---
 Directory.cxx    | 35 +++++++++++++++++++++++++++++++++++
 Directory.hxx.in |  7 +++++++
 Glob.cxx         | 32 +++++++++++++++++++++++++++++++-
 Glob.hxx.in      |  2 ++
 4 files changed, 75 insertions(+), 1 deletion(-)

diff --git a/Directory.cxx b/Directory.cxx
index 58cea63..5494908 100644
--- a/Directory.cxx
+++ b/Directory.cxx
@@ -18,6 +18,7 @@
 
 #include KWSYS_HEADER(stl/string)
 #include KWSYS_HEADER(stl/vector)
+#include KWSYS_HEADER(stl/stdexcept)
 
 // Work-around CMake dependency scanning limitation.  This must
 // duplicate the above list of headers.
@@ -28,8 +29,11 @@
 # include "kwsys_stl.hxx.in"
 # include "kwsys_stl_string.hxx.in"
 # include "kwsys_stl_vector.hxx.in"
+# include "kwsys_stl_stdexcept.hxx.in"
 #endif
 
+#include <stdlib.h>
+
 namespace KWSYS_NAMESPACE
 {
 
@@ -79,6 +83,37 @@ const char* Directory::GetPath() const
 }
 
 //----------------------------------------------------------------------------
+kwsys_stl::string Directory::GetCanonicalPath() const
+{
+/* The maximum length of a file name. */
+#if defined(PATH_MAX)
+  #define CANONICAL_PATH_MAX_LEN PATH_MAX
+#elif defined(MAXPATHLEN)
+  #define CANONICAL_PATH_MAX_LEN MAXPATHLEN
+#else
+  #define CANONICAL_PATH_MAX_LEN 16384
+#endif
+
+  char out_path[CANONICAL_PATH_MAX_LEN];
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+  /* Implementation for Windows.  */
+  DWORD n = GetFullPathNameA(this->Internal->Path.c_str(),
+              CANONICAL_PATH_MAX_LEN], out_path, 0);
+  if( n > 0 && n <= CANONICAL_PATH_MAX_LEN )
+#else
+  /* Implementation for UNIX.  */
+  if( !realpath(this->Internal->Path.c_str(), out_path) )
+#endif
+    {
+    throw kwsys_stl::runtime_error("Failed to convert path '"
+      + this->Internal->Path + "' to canonical form.");
+    }
+
+  return out_path;
+}
+
+//----------------------------------------------------------------------------
 void Directory::Clear()
 {
   this->Internal->Path.resize(0);
diff --git a/Directory.hxx.in b/Directory.hxx.in
index 1bcf90e..453b578 100644
--- a/Directory.hxx.in
+++ b/Directory.hxx.in
@@ -68,6 +68,13 @@ public:
   const char* GetPath() const;
 
   /**
+   * Return path to Open'ed directory without symbolic links, dot or
+   * dot-dot elements. runtime_error is thrown if canonical path
+   * could not be created.
+   */
+   kwsys_stl::string GetCanonicalPath() const;
+
+  /**
    * Clear the internal structure. Used internally at beginning of Load(...)
    * to clear the cache.
    */
diff --git a/Glob.cxx b/Glob.cxx
index 5a96aed..22bab9f 100644
--- a/Glob.cxx
+++ b/Glob.cxx
@@ -30,11 +30,14 @@
 # include "SystemTools.hxx.in"
 # include "kwsys_stl.hxx.in"
 # include "kwsys_stl_string.hxx.in"
+# include "kwsys_stl_vector.hxx.in"
 #endif
 
 #include <ctype.h>
 #include <stdio.h>
 #include <string.h>
+#include <stdlib.h>
+#include <iostream>
 namespace KWSYS_NAMESPACE
 {
 #if defined(_WIN32) || defined(__APPLE__) || defined(__CYGWIN__)
@@ -265,8 +268,35 @@ void Glob::RecurseDirectory(kwsys_stl::string::size_type start,
       if (isSymLink)
         {
         ++this->FollowedSymlinkCount;
+        kwsys_stl::string canonicalPath(d.GetCanonicalPath());
+
+        if(VisitedSymlinks.find(canonicalPath) == VisitedSymlinks.end())
+          {
+          // structure for handling symbolic link path even if an exception
+          // is thrown
+          struct ScopedSymlinkPath
+          {
+            ScopedSymlinkPath(
+              kwsys_stl::set<kwsys_stl::string>& visitedSymlinks,
+              const std::string& canonicalPath)
+              : RefVisitedSymlinks(visitedSymlinks)
+              , RefCanonicalPath(canonicalPath)
+              {
+              RefVisitedSymlinks.insert(RefCanonicalPath);
+              }
+            ~ScopedSymlinkPath() {RefVisitedSymlinks.erase(RefCanonicalPath);}
+            kwsys_stl::set<kwsys_stl::string>& RefVisitedSymlinks;
+            const kwsys_stl::string& RefCanonicalPath;
+          } scopedSymlinkPath(VisitedSymlinks, canonicalPath);
+
+          this->RecurseDirectory(start+1, realname);
+          }
+        // else we have already visited this symlink - prevent cyclic recursion
+        }
+      else
+        {
+        this->RecurseDirectory(start+1, realname);
         }
-      this->RecurseDirectory(start+1, realname);
       }
     else
       {
diff --git a/Glob.hxx.in b/Glob.hxx.in
index d8b8491..61bbd35 100644
--- a/Glob.hxx.in
+++ b/Glob.hxx.in
@@ -17,6 +17,7 @@
 
 #include <@KWSYS_NAMESPACE@/stl/string>
 #include <@KWSYS_NAMESPACE@/stl/vector>
+#include <@KWSYS_NAMESPACE@/stl/set>
 
 /* Define this macro temporarily to keep the code readable.  */
 #if !defined (KWSYS_NAMESPACE) && !@KWSYS_NAMESPACE@_NAME_IS_KWSYS
@@ -101,6 +102,7 @@ protected:
   kwsys_stl::string Relative;
   bool RecurseThroughSymlinks;
   unsigned int FollowedSymlinkCount;
+  kwsys_stl::set<kwsys_stl::string> VisitedSymlinks;
 
 private:
   Glob(const Glob&);  // Not implemented.
-- 
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