From 5c777f2d485d5de787b420d5cf77271ce6de7966 Mon Sep 17 00:00:00 2001
From: Brad King <brad.king@kitware.com>
Date: Tue, 22 Sep 2009 13:02:20 -0400
Subject: [PATCH] Optimize KWSys SystemTools::FileExists on Windows

We optimize this method by using the GetFileAttributesExA native Windows
API to check for file existence when possible.  For real Windows builds
we always use it.  For Cygwin we use cygwin_conv_to_win32_path to get a
native Windows path if possible and otherwise fall back to 'access'.

Cygwin-to-Windows path conversion and cache by Wojciech Migda.
See issue #8826.
---
 SystemTools.cxx      | 86 +++++++++++++++++++++++++++++++++-----------
 SystemTools.hxx.in   | 15 +++++++-
 kwsysDateStamp.cmake |  2 +-
 3 files changed, 80 insertions(+), 23 deletions(-)

diff --git a/SystemTools.cxx b/SystemTools.cxx
index ac158988..dc9977c8 100644
--- a/SystemTools.cxx
+++ b/SystemTools.cxx
@@ -65,10 +65,15 @@
 #endif
 
 // Windows API.  Some parts used even on cygwin.
-#if defined(_WIN32)
+#if defined(_WIN32) || defined (__CYGWIN__)
 # include <windows.h>
 #endif
 
+#ifdef __CYGWIN__
+# undef _WIN32
+extern "C" void cygwin_conv_to_win32_path(const char *path, char *win32_path);
+#endif
+
 // getpwnam doesn't exist on Windows and Cray Xt3/Catamount
 // same for TIOCGWINSZ
 #if defined(_WIN32) || defined (__LIBCATAMOUNT__)
@@ -892,39 +897,69 @@ bool SystemTools::SameFile(const char* file1, const char* file2)
 #endif
 }
 
-
-// return true if the file exists
-bool SystemTools::FileExists(const char* filename, bool isFile)
+//----------------------------------------------------------------------------
+#if defined(_WIN32) || defined(__CYGWIN__)
+static bool WindowsFileExists(const char* filename)
 {
-#ifdef _MSC_VER
-# define access _access
-#endif
-#ifndef R_OK
-# define R_OK 04
+  WIN32_FILE_ATTRIBUTE_DATA fd;
+  return GetFileAttributesExA(filename, GetFileExInfoStandard, &fd) != 0;
+}
 #endif
 
-#ifdef __SYLLABLE__
-  if ((filename !=0) && (*filename == 0))
+//----------------------------------------------------------------------------
+bool SystemTools::FileExists(const char* filename)
+{
+  if(!(filename && *filename))
     {
     return false;
-  }
+    }
+#if defined(__CYGWIN__)
+  // Convert filename to native windows path if possible.
+  char winpath[MAX_PATH];
+  if(SystemTools::PathCygwinToWin32(filename, winpath))
+    {
+    return WindowsFileExists(winpath);
+    }
+  return access(filename, R_OK) == 0;
+#elif defined(_WIN32)
+  return WindowsFileExists(filename);
+#else
+  return access(filename, R_OK) == 0;
 #endif
+}
 
-  if ( access(filename, R_OK) != 0 )
+//----------------------------------------------------------------------------
+bool SystemTools::FileExists(const char* filename, bool isFile)
+{
+  if(SystemTools::FileExists(filename))
     {
-    return false;
+    // If isFile is set return not FileIsDirectory,
+    // so this will only be true if it is a file
+    return !isFile || !SystemTools::FileIsDirectory(filename);
+    }
+  return false;
+}
+
+//----------------------------------------------------------------------------
+#ifdef __CYGWIN__
+bool SystemTools::PathCygwinToWin32(const char *path, char *win32_path)
+{
+  SystemToolsTranslationMap::iterator i =
+    SystemTools::Cyg2Win32Map->find(path);
+
+  if (i != SystemTools::Cyg2Win32Map->end())
+    {
+    strncpy(win32_path, i->second.c_str(), MAX_PATH);
     }
   else
     {
-    // If isFile is set return not FileIsDirectory,
-    // so this will only be true if it is a file
-    if(isFile)
-      {
-      return !SystemTools::FileIsDirectory(filename);
-      }
-    return true;
+    cygwin_conv_to_win32_path(path, win32_path);
+    SystemToolsTranslationMap::value_type entry(path, win32_path);
+    SystemTools::Cyg2Win32Map->insert(entry);
     }
+  return win32_path[0] != 0;
 }
+#endif
 
 bool SystemTools::Touch(const char* filename, bool create)
 {
@@ -4536,6 +4571,9 @@ bool SystemTools::ParseURL( const kwsys_stl::string& URL,
 unsigned int SystemToolsManagerCount;
 SystemToolsTranslationMap *SystemTools::TranslationMap;
 SystemToolsTranslationMap *SystemTools::LongPathMap;
+#ifdef __CYGWIN__
+SystemToolsTranslationMap *SystemTools::Cyg2Win32Map;
+#endif
 
 // SystemToolsManager manages the SystemTools singleton.
 // SystemToolsManager should be included in any translation unit
@@ -4581,6 +4619,9 @@ void SystemTools::ClassInitialize()
   // Allocate the translation map first.
   SystemTools::TranslationMap = new SystemToolsTranslationMap;
   SystemTools::LongPathMap = new SystemToolsTranslationMap;
+#ifdef __CYGWIN__
+  SystemTools::Cyg2Win32Map = new SystemToolsTranslationMap;
+#endif
 
   // Add some special translation paths for unix.  These are not added
   // for windows because drive letters need to be maintained.  Also,
@@ -4637,6 +4678,9 @@ void SystemTools::ClassFinalize()
 {
   delete SystemTools::TranslationMap;
   delete SystemTools::LongPathMap;
+#ifdef __CYGWIN__
+  delete SystemTools::Cyg2Win32Map;
+#endif
 }
 
 
diff --git a/SystemTools.hxx.in b/SystemTools.hxx.in
index 6fad2172..7f030b56 100644
--- a/SystemTools.hxx.in
+++ b/SystemTools.hxx.in
@@ -275,7 +275,17 @@ public:
    * not a directory.  If isFile = false, then return true
    * if it is a file or a directory.
    */
-  static bool FileExists(const char* filename, bool isFile=false);
+  static bool FileExists(const char* filename, bool isFile);
+  static bool FileExists(const char* filename);
+
+  /**
+   * Converts Cygwin path to Win32 path. Uses dictionary container for
+   * caching and calls to cygwin_conv_to_win32_path from Cygwin dll
+   * for actual translation.  Returns true on success, else false.
+   */
+#ifdef __CYGWIN__
+  static bool PathCygwinToWin32(const char *path, char *win32_path);
+#endif
 
   /**
    * Return file length
@@ -890,6 +900,9 @@ private:
    */
   static SystemToolsTranslationMap *TranslationMap;
   static SystemToolsTranslationMap *LongPathMap;
+#ifdef __CYGWIN__
+  static SystemToolsTranslationMap *Cyg2Win32Map;
+#endif
   friend class SystemToolsManager;
 };
 
diff --git a/kwsysDateStamp.cmake b/kwsysDateStamp.cmake
index 8e64e4a5..b37b5d9a 100644
--- a/kwsysDateStamp.cmake
+++ b/kwsysDateStamp.cmake
@@ -7,4 +7,4 @@ SET(KWSYS_DATE_STAMP_YEAR  2009)
 SET(KWSYS_DATE_STAMP_MONTH 09)
 
 # KWSys version date day component.  Format is DD.
-SET(KWSYS_DATE_STAMP_DAY   14)
+SET(KWSYS_DATE_STAMP_DAY   22)
-- 
GitLab