From 2b042ff6fef545e2c8974285cf60eec2314a802f Mon Sep 17 00:00:00 2001
From: Domen Vrankar <domen.vrankar@gmail.com>
Date: Sat, 21 Feb 2015 10:54:34 +0100
Subject: [PATCH] SystemTools: Optionally report error from GetRealPath

Allow the caller to specify a pointer to a string to receive the error
message on failure.

Change-Id: Ibe537812bd18cd9cbac7bf735546a276c259402d
---
 SystemTools.cxx    | 58 +++++++++++++++++++++++++++++++++++++++++-----
 SystemTools.hxx.in |  7 ++++--
 2 files changed, 57 insertions(+), 8 deletions(-)

diff --git a/SystemTools.cxx b/SystemTools.cxx
index 27082115..bf6f458e 100644
--- a/SystemTools.cxx
+++ b/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())
+      {
+      LPSTR message = NULL;
+      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 = "";
+    }
   else
     {
     resolved_path = path;
@@ -287,15 +316,31 @@ 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)
+      {
+      *errorMessage = strerror(errno);
+      }
+    else
+      {
+      *errorMessage = "Unknown error.";
+      }
+
+    resolved_path = "";
+    }
   else
     {
     // if path resolution fails, return what was passed in
@@ -3046,10 +3091,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/SystemTools.hxx.in b/SystemTools.hxx.in
index beb2a7e1..93cde026 100644
--- a/SystemTools.hxx.in
+++ b/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
+   * NULL.  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
-- 
GitLab