From 6d23dd7e455a7b2088c4ec6dce760d8243b84ee6 Mon Sep 17 00:00:00 2001
From: Ben Boeckel <ben.boeckel@kitware.com>
Date: Tue, 2 Aug 2016 16:02:37 -0400
Subject: [PATCH] SystemTools: add a PathExists method

This method checks if a path by the given name exists. The problem with
FileExists is that it returns `false` even for broken (or
self-referential) symlinks which may not be what the user wants.

Change-Id: I71b8af6e12a5ae4b1319a3bec83db6c3cef36f90
---
 SystemTools.cxx     | 26 ++++++++++++++++++++++++++
 SystemTools.hxx.in  |  5 +++++
 testSystemTools.cxx | 42 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 73 insertions(+)

diff --git a/SystemTools.cxx b/SystemTools.cxx
index d479ee1..eb2bec6 100644
--- a/SystemTools.cxx
+++ b/SystemTools.cxx
@@ -1291,6 +1291,32 @@ bool SystemTools::SameFile(const std::string& file1, const std::string& file2)
 #endif
 }
 
+//----------------------------------------------------------------------------
+bool SystemTools::PathExists(const std::string& path)
+{
+  if(path.empty())
+    {
+    return false;
+    }
+#if defined(__CYGWIN__)
+  // Convert path to native windows path if possible.
+  char winpath[MAX_PATH];
+  if(SystemTools::PathCygwinToWin32(path.c_str(), winpath))
+    {
+    return (GetFileAttributesA(winpath) != INVALID_FILE_ATTRIBUTES);
+    }
+  struct stat st;
+  return lstat(path.c_str(), &st) == 0;
+#elif defined(_WIN32)
+  return (GetFileAttributesW(
+            SystemTools::ConvertToWindowsExtendedPath(path).c_str())
+          != INVALID_FILE_ATTRIBUTES);
+#else
+  struct stat st;
+  return lstat(path.c_str(), &st) == 0;
+#endif
+}
+
 //----------------------------------------------------------------------------
 bool SystemTools::FileExists(const char* filename)
 {
diff --git a/SystemTools.hxx.in b/SystemTools.hxx.in
index aa1bf1b..28ff0b3 100644
--- a/SystemTools.hxx.in
+++ b/SystemTools.hxx.in
@@ -305,6 +305,11 @@ public:
    */
   static std::string ConvertToWindowsOutputPath(const std::string&);
 
+  /**
+   * Return true if a path with the given name exists in the current directory.
+   */
+  static bool PathExists(const std::string& path);
+
   /**
    * Return true if a file exists in the current directory.
    * If isFile = true, then make sure the file is a file and
diff --git a/testSystemTools.cxx b/testSystemTools.cxx
index 4dab347..9252ea6 100644
--- a/testSystemTools.cxx
+++ b/testSystemTools.cxx
@@ -204,6 +204,14 @@ static bool CheckFileOperations()
       << testNewDir << std::endl;
     res = false;
     }
+  // check existence
+  if (!kwsys::SystemTools::PathExists(testNewDir))
+    {
+    std::cerr
+      << "Problem with PathExists for: "
+      << testNewDir << std::endl;
+    res = false;
+    }
   // remove it
   if (!kwsys::SystemTools::RemoveADirectory(testNewDir))
     {
@@ -221,6 +229,15 @@ static bool CheckFileOperations()
       << testNewDir << std::endl;
     res = false;
     }
+  // check existence
+  if (kwsys::SystemTools::PathExists(testNewDir))
+    {
+    std::cerr
+      << "After RemoveADirectory: "
+      << "Problem with PathExists for: "
+      << testNewDir << std::endl;
+    res = false;
+    }
   // create it using the char* version
   if (!kwsys::SystemTools::MakeDirectory(testNewDir.c_str()))
     {
@@ -329,6 +346,31 @@ static bool CheckFileOperations()
     res = false;
     }
 
+  // calling with an empty string should return false
+  if (kwsys::SystemTools::PathExists(std::string()))
+    {
+    std::cerr
+      << "Problem with PathExists(std::string())"
+      << std::endl;
+    res = false;
+    }
+  // PathExists(x) should return true on a directory
+  if (!kwsys::SystemTools::PathExists(testNewDir))
+    {
+    std::cerr
+      << "Problem with PathExists for: "
+      << testNewDir << std::endl;
+    res = false;
+    }
+  // should work, was created as new file before
+  if (!kwsys::SystemTools::PathExists(testNewFile))
+    {
+    std::cerr
+      << "Problem with PathExists for: "
+      << testNewDir << std::endl;
+    res = false;
+    }
+
   // Reset umask
 #if defined(_WIN32) && !defined(__CYGWIN__)
   // NOTE:  Windows doesn't support toggling _S_IREAD.
-- 
GitLab