For PR789:
Make the sys::Path::getFileStatus function more efficient by having it
return a pointer to the FileStatus structure rather than copy it. Adjust
uses of the function accordingly. Also, fix some memory issues in sys::Path.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@35476 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Archive/Archive.cpp b/lib/Archive/Archive.cpp
index aff7ab8..f9fa807 100644
--- a/lib/Archive/Archive.cpp
+++ b/lib/Archive/Archive.cpp
@@ -116,7 +116,10 @@
     path.getMagicNumber(magic,4);
     signature = magic.c_str();
     std::string err;
-    if (path.getFileStatus(info, false, ErrMsg))
+    const sys::FileStatus *FSinfo = path.getFileStatus(false, ErrMsg);
+    if (FSinfo)
+      info = *FSinfo;
+    else
       return true;
   }
 
diff --git a/lib/Archive/ArchiveWriter.cpp b/lib/Archive/ArchiveWriter.cpp
index 9d5b025..fc85374 100644
--- a/lib/Archive/ArchiveWriter.cpp
+++ b/lib/Archive/ArchiveWriter.cpp
@@ -163,7 +163,10 @@
 
   mbr->data = 0;
   mbr->path = filePath;
-  if (mbr->path.getFileStatus(mbr->info, false, ErrMsg))
+  const sys::FileStatus *FSInfo = mbr->path.getFileStatus(false, ErrMsg);
+  if (FSInfo)
+    mbr->info = *FSInfo;
+  else
     return true;
 
   unsigned flags = 0;
diff --git a/lib/Bytecode/Archive/Archive.cpp b/lib/Bytecode/Archive/Archive.cpp
index aff7ab8..f9fa807 100644
--- a/lib/Bytecode/Archive/Archive.cpp
+++ b/lib/Bytecode/Archive/Archive.cpp
@@ -116,7 +116,10 @@
     path.getMagicNumber(magic,4);
     signature = magic.c_str();
     std::string err;
-    if (path.getFileStatus(info, false, ErrMsg))
+    const sys::FileStatus *FSinfo = path.getFileStatus(false, ErrMsg);
+    if (FSinfo)
+      info = *FSinfo;
+    else
       return true;
   }
 
diff --git a/lib/Bytecode/Archive/ArchiveWriter.cpp b/lib/Bytecode/Archive/ArchiveWriter.cpp
index 9d5b025..fc85374 100644
--- a/lib/Bytecode/Archive/ArchiveWriter.cpp
+++ b/lib/Bytecode/Archive/ArchiveWriter.cpp
@@ -163,7 +163,10 @@
 
   mbr->data = 0;
   mbr->path = filePath;
-  if (mbr->path.getFileStatus(mbr->info, false, ErrMsg))
+  const sys::FileStatus *FSInfo = mbr->path.getFileStatus(false, ErrMsg);
+  if (FSInfo)
+    mbr->info = *FSInfo;
+  else
     return true;
 
   unsigned flags = 0;
diff --git a/lib/Debugger/ProgramInfo.cpp b/lib/Debugger/ProgramInfo.cpp
index a315a2d..d811f60 100644
--- a/lib/Debugger/ProgramInfo.cpp
+++ b/lib/Debugger/ProgramInfo.cpp
@@ -194,9 +194,10 @@
 
 ProgramInfo::ProgramInfo(Module *m) : M(m), ProgramTimeStamp(0,0) {
   assert(M && "Cannot create program information with a null module!");
-  sys::FileStatus Stat;
-  if (!sys::Path(M->getModuleIdentifier()).getFileStatus(Stat))
-    ProgramTimeStamp = Stat.getTimestamp();
+  const sys::FileStatus *Stat;
+  Stat = sys::Path(M->getModuleIdentifier()).getFileStatus();
+  if (Stat)
+    ProgramTimeStamp = Stat->getTimestamp();
 
   SourceFilesIsComplete = false;
   SourceFunctionsIsComplete = false;
diff --git a/lib/Support/FileUtilities.cpp b/lib/Support/FileUtilities.cpp
index a0cdf09..1ea5dda 100644
--- a/lib/Support/FileUtilities.cpp
+++ b/lib/Support/FileUtilities.cpp
@@ -152,16 +152,17 @@
                                  const sys::Path &FileB,
                                  double AbsTol, double RelTol,
                                  std::string *Error) {
-  sys::FileStatus FileAStat, FileBStat;
-  if (FileA.getFileStatus(FileAStat, false, Error))
+  const sys::FileStatus *FileAStat = FileA.getFileStatus(false, Error);
+  if (!FileAStat)
     return 2;
-  if (FileB.getFileStatus(FileBStat, false, Error))
+  const sys::FileStatus *FileBStat = FileB.getFileStatus(false, Error);
+  if (!FileBStat)
     return 2;
 
   // Check for zero length files because some systems croak when you try to
   // mmap an empty file.
-  size_t A_size = FileAStat.getSize();
-  size_t B_size = FileBStat.getSize();
+  size_t A_size = FileAStat->getSize();
+  size_t B_size = FileBStat->getSize();
 
   // If they are both zero sized then they're the same
   if (A_size == 0 && B_size == 0)
diff --git a/lib/System/Unix/Path.inc b/lib/System/Unix/Path.inc
index 5557282..6ceffcd 100644
--- a/lib/System/Unix/Path.inc
+++ b/lib/System/Unix/Path.inc
@@ -333,9 +333,10 @@
 Path::canExecute() const {
   if (0 != access(path.c_str(), R_OK | X_OK ))
     return false;
-  struct stat st;
-  int r = stat(path.c_str(), &st);
-  if (r != 0 || !S_ISREG(st.st_mode))
+  if (const FileStatus *fs = getFileStatus(true, 0)) {
+    if (!S_ISREG(fs->mode))
+      return false;
+  } else
     return false;
   return true;
 }
@@ -362,12 +363,14 @@
   return path.substr(pos+1);
 }
 
-bool
-Path::getFileStatus(FileStatus &info, bool update, std::string *ErrStr) const {
+const FileStatus*
+Path::getFileStatus(bool update, std::string *ErrStr) const {
   if (status == 0 || update) {
     struct stat buf;
-    if (0 != stat(path.c_str(), &buf))
-      return MakeErrMsg(ErrStr, path + ": can't get status of file");
+    if (0 != stat(path.c_str(), &buf)) {
+      MakeErrMsg(ErrStr, path + ": can't get status of file");
+      return 0;
+    }
     if (status == 0)
       status = new FileStatus;
     status->fileSize = buf.st_size;
@@ -379,8 +382,7 @@
     status->isDir  = S_ISDIR(buf.st_mode);
     status->isFile = S_ISREG(buf.st_mode);
   }
-  info = *status;
-  return false;
+  return status;
 }
 
 static bool AddPermissionBits(const Path &File, int bits) {
@@ -392,12 +394,12 @@
   umask(mask);            // Restore the umask.
 
   // Get the file's current mode.
-  FileStatus Stat;
-  if (File.getFileStatus(Stat)) return false;
-
-  // Change the file to have whichever permissions bits from 'bits'
-  // that the umask would not disable.
-  if ((chmod(File.c_str(), (Stat.getMode() | (bits & ~mask)))) == -1)
+  if (const FileStatus *fs = File.getFileStatus()) {
+    // Change the file to have whichever permissions bits from 'bits'
+    // that the umask would not disable.
+    if ((chmod(File.c_str(), (fs->getMode() | (bits & ~mask)))) == -1)
+      return false;
+  } else 
     return false;
 
   return true;
@@ -593,24 +595,25 @@
 bool
 Path::eraseFromDisk(bool remove_contents, std::string *ErrStr) const {
   FileStatus Status;
-  if (getFileStatus(Status, ErrStr))
-    return true;
+  if (const FileStatus *Status = getFileStatus(false, ErrStr)) {
+    // Note: this check catches strange situations. In all cases, LLVM should 
+    // only be involved in the creation and deletion of regular files.  This 
+    // check ensures that what we're trying to erase is a regular file. It 
+    // effectively prevents LLVM from erasing things like /dev/null, any block 
+    // special file, or other things that aren't "regular" files. 
+    if (Status->isFile) {
+      if (unlink(path.c_str()) != 0)
+        return MakeErrMsg(ErrStr, path + ": can't destroy file");
+      return false;
+    }
     
-  // Note: this check catches strange situations. In all cases, LLVM should only
-  // be involved in the creation and deletion of regular files.  This check 
-  // ensures that what we're trying to erase is a regular file. It effectively
-  // prevents LLVM from erasing things like /dev/null, any block special file,
-  // or other things that aren't "regular" files. 
-  if (Status.isFile) {
-    if (unlink(path.c_str()) != 0)
-      return MakeErrMsg(ErrStr, path + ": can't destroy file");
-    return false;
-  }
-  
-  if (!Status.isDir) {
-    if (ErrStr) *ErrStr = "not a file or directory";
+    if (!Status->isDir) {
+      if (ErrStr) *ErrStr = "not a file or directory";
+      return true;
+    }
+  } else
     return true;
-  }
+
   if (remove_contents) {
     // Recursively descend the directory to remove its contents.
     std::string cmd = "/bin/rm -rf " + path;
@@ -629,7 +632,7 @@
     
   if (rmdir(pathname) != 0)
     return MakeErrMsg(ErrStr, 
-      std::string(pathname) + ": can't destroy directory");
+      std::string(pathname) + ": can't erase directory");
   return false;
 }
 
diff --git a/lib/System/Unix/Signals.inc b/lib/System/Unix/Signals.inc
index 35c628b..a471b95 100644
--- a/lib/System/Unix/Signals.inc
+++ b/lib/System/Unix/Signals.inc
@@ -168,8 +168,10 @@
 // RemoveDirectoryOnSignal - The public API
 bool sys::RemoveDirectoryOnSignal(const sys::Path& path, std::string* ErrMsg) {
   // Not a directory?
-  sys::FileStatus Status;
-  if (path.getFileStatus(Status) || !Status.isDir) {
+  const sys::FileStatus *Status = path.getFileStatus(false, ErrMsg);
+  if (!Status)
+    return true;
+  if (!Status->isDir) {
     if (ErrMsg)
       *ErrMsg = path.toString() + " is not a directory";
     return true;
diff --git a/lib/System/Win32/Path.inc b/lib/System/Win32/Path.inc
index 5bb2e39..57d7535 100644
--- a/lib/System/Win32/Path.inc
+++ b/lib/System/Win32/Path.inc
@@ -306,13 +306,15 @@
   return path.substr(pos+1);
 }
 
-bool
-Path::getFileStatus(FileStatus &info, bool update, std::string *ErrStr) const {
+const FileStatus *
+Path::getFileStatus(bool update, std::string *ErrStr) const {
   if (status == 0 || update) {
     WIN32_FILE_ATTRIBUTE_DATA fi;
-    if (!GetFileAttributesEx(path.c_str(), GetFileExInfoStandard, &fi))
-      return MakeErrMsg(ErrStr, "getStatusInfo():" + std::string(path) +
+    if (!GetFileAttributesEx(path.c_str(), GetFileExInfoStandard, &fi)) {
+      MakeErrMsg(ErrStr, "getStatusInfo():" + std::string(path) +
                       ": Can't get status: ");
+      return 0;
+    }
 
     if (status == 0)
       status = new FileStatus;
@@ -337,8 +339,7 @@
 
     status->isDir = fi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
   }
-  info = *status;
-  return false;
+  return status;
 }
 
 bool Path::makeReadableOnDisk(std::string* ErrMsg) {
@@ -369,11 +370,10 @@
 
 bool
 Path::getDirectoryContents(std::set<Path>& result, std::string* ErrMsg) const {
-  FileStatus Status;
-  if (getFileStatus(Status, ErrMsg))
+  const FileStatus *Status = getFileStatus(false, ErrMsg);
+  if (!Status)
     return true;
-
-  if (!Status.isDir) {
+  if (!Status->isDir) {
     MakeErrMsg(ErrMsg, path + ": not a directory");
     return true;
   }
@@ -567,11 +567,11 @@
 
 bool
 Path::eraseFromDisk(bool remove_contents, std::string *ErrStr) const {
-  FileStatus Status;
-  if (getFileStatus(Status, ErrStr))
+  const FileStatus *Status = getFileStatus(false, ErrStr);
+  if (!Status)
     return false;
     
-  if (Status.isFile) {
+  if (Status->isFile) {
     DWORD attr = GetFileAttributes(path.c_str());
 
     // If it doesn't exist, we're done.
@@ -588,7 +588,7 @@
     if (!DeleteFile(path.c_str()))
       return MakeErrMsg(ErrStr, path + ": Can't destroy file: ");
     return false;
-  } else if (Status.isDir) {
+  } else if (Status->isDir) {
     // If it doesn't exist, we're done.
     if (!exists())
       return false;
diff --git a/lib/System/Win32/Signals.inc b/lib/System/Win32/Signals.inc
index 0c93b22..8adf767 100644
--- a/lib/System/Win32/Signals.inc
+++ b/lib/System/Win32/Signals.inc
@@ -101,8 +101,10 @@
 // RemoveDirectoryOnSignal - The public API
 bool sys::RemoveDirectoryOnSignal(const sys::Path& path, std::string* ErrMsg) {
   // Not a directory?
-  sys::FileStatus Status;
-  if (path.getFileStatus(Status) || !Status.isDir) {
+  const sys::FileStatus *Status =  path.getFileStatus(false, ErrMsg);
+  if (!Status)
+    return true;
+  if (!Status->isDir) {
     if (ErrMsg)
       *ErrMsg = path.toString() + " is not a directory";
     return true;