Add new function
[oota-llvm.git] / lib / Support / FileUtilities.cpp
index 01d7ca2126cdfa9f17359affe538155b2f29009f..1b8df43629a2681703efb31d3ab799280693d394 100644 (file)
@@ -1,4 +1,11 @@
 //===- Support/FileUtilities.cpp - File System Utilities ------------------===//
+// 
+//                     The LLVM Compiler Infrastructure
+//
+// This file was developed by the LLVM research group and is distributed under
+// the University of Illinois Open Source License. See LICENSE.TXT for details.
+// 
+//===----------------------------------------------------------------------===//
 //
 // This file implements a family of utility functions which are useful for doing
 // various things with files.
 #include <fstream>
 #include <iostream>
 #include <cstdio>
+using namespace llvm;
+
+/// CheckMagic - Returns true IFF the file named FN begins with Magic. FN must
+/// name a readable file.
+///
+bool llvm::CheckMagic(const std::string &FN, const std::string &Magic) {
+  char buf[1 + Magic.size ()];
+  std::ifstream f (FN.c_str ());
+  f.read (buf, Magic.size ());
+  buf[Magic.size ()] = '\0';
+  return Magic == buf;
+}
+
+/// IsArchive - Returns true IFF the file named FN appears to be a "ar" library
+/// archive. The file named FN must exist.
+///
+bool llvm::IsArchive(const std::string &FN) {
+  // Inspect the beginning of the file to see if it contains the "ar"
+  // library archive format magic string.
+  return CheckMagic (FN, "!<arch>\012");
+}
+
+/// IsBytecode - Returns true IFF the file named FN appears to be an LLVM
+/// bytecode file. The file named FN must exist.
+///
+bool llvm::IsBytecode(const std::string &FN) {
+  // Inspect the beginning of the file to see if it contains the LLVM
+  // bytecode format magic string.
+  return CheckMagic (FN, "llvm");
+}
+
+/// IsSharedObject - Returns trus IFF the file named FN appears to be a shared
+/// object with an ELF header. The file named FN must exist.
+///
+bool llvm::IsSharedObject(const std::string &FN) {
+  // Inspect the beginning of the file to see if it contains the ELF shared
+  // object magic string.
+  static const char elfMagic[] = { 0x7f, 'E', 'L', 'F', '\0' };
+  return CheckMagic(FN, elfMagic);
+}
+
+/// FileOpenable - Returns true IFF Filename names an existing regular
+/// file which we can successfully open.
+///
+bool llvm::FileOpenable(const std::string &Filename) {
+  struct stat s;
+  if (stat (Filename.c_str (), &s) == -1)
+    return false; // Cannot stat file
+  if (!S_ISREG (s.st_mode))
+    return false; // File is not a regular file
+  std::ifstream FileStream (Filename.c_str ());
+  if (!FileStream)
+    return false; // File is not openable
+  return true;
+}
 
 /// DiffFiles - Compare the two files specified, returning true if they are
 /// different or if there is a file error.  If you specify a string to fill in
@@ -19,8 +81,8 @@
 /// occurs, allowing the caller to distinguish between a failed diff and a file
 /// system error.
 ///
-bool DiffFiles(const std::string &FileA, const std::string &FileB,
-               std::string *Error) {
+bool llvm::DiffFiles(const std::string &FileA, const std::string &FileB,
+                     std::string *Error) {
   std::ifstream FileAStream(FileA.c_str());
   if (!FileAStream) {
     if (Error) *Error = "Couldn't open file '" + FileA + "'";
@@ -49,7 +111,8 @@ bool DiffFiles(const std::string &FileA, const std::string &FileB,
 /// or if Old does not exist, move the New file over the Old file.  Otherwise,
 /// remove the New file.
 ///
-void MoveFileOverIfUpdated(const std::string &New, const std::string &Old) {
+void llvm::MoveFileOverIfUpdated(const std::string &New,
+                                 const std::string &Old) {
   if (DiffFiles(New, Old)) {
     if (std::rename(New.c_str(), Old.c_str()))
       std::cerr << "Error renaming '" << New << "' to '" << Old << "'!\n";
@@ -60,7 +123,7 @@ void MoveFileOverIfUpdated(const std::string &New, const std::string &Old) {
 
 /// removeFile - Delete the specified file
 ///
-void removeFile(const std::string &Filename) {
+void llvm::removeFile(const std::string &Filename) {
   std::remove(Filename.c_str());
 }
 
@@ -68,7 +131,7 @@ void removeFile(const std::string &Filename) {
 /// file does not exist yet, return it, otherwise add a suffix to make it
 /// unique.
 ///
-std::string getUniqueFilename(const std::string &FilenameBase) {
+std::string llvm::getUniqueFilename(const std::string &FilenameBase) {
   if (!std::ifstream(FilenameBase.c_str()))
     return FilenameBase;    // Couldn't open the file? Use it!
 
@@ -85,7 +148,7 @@ std::string getUniqueFilename(const std::string &FilenameBase) {
     exit(1);
   }
 
-  // We don't need to hold the temp file descriptor... we will trust that noone
+  // We don't need to hold the temp file descriptor... we will trust that no one
   // will overwrite/delete the file while we are working on it...
   close(TempFD);
   std::string Result(FNBuffer);
@@ -93,50 +156,79 @@ std::string getUniqueFilename(const std::string &FilenameBase) {
   return Result;
 }
 
-///
-/// Method: MakeFileExecutable ()
-///
-/// Description:
-///    This method makes the specified filename executable by giving it
-///    execute permission.
-///
-///    For the UNIX version of this method, we turn on all of the read and
-///    execute bits and then turn off anything specified in the umask.  This
-///    should help ensure that access to the file remains at the level that
-///    the user desires.
-///
-bool
-MakeFileExecutable (const std::string & Filename)
-{
-  // Permissions masking value of the user
-  mode_t mask;
-
-  // Permissions currently enabled on the file
-  struct stat fstat;
-
-  //
-  // Grab the umask value from the operating system.  We want to use it when
-  // changing the file's permissions.
-  //
-  // Note:
-  //  Umask() is one of those annoying system calls.  You have to call it
-  //  to get the current value and then set it back.
-  //
-  mask = umask (0x777);
+static bool AddPermissionsBits (const std::string &Filename, mode_t bits) {
+  // Get the umask value from the operating system.  We want to use it
+  // when changing the file's permissions. Since calling umask() sets
+  // the umask and returns its old value, we must call it a second
+  // time to reset it to the user's preference.
+  mode_t mask = umask (0777); // The arg. to umask is arbitrary...
   umask (mask);
 
-  //
-  // Go fetch the file's current permission bits.  We want to *add* execute
-  // access to the file.
-  //
-  if ((stat (Filename.c_str(), &fstat)) == -1)
-  {
+  // Get the file's current mode.
+  struct stat st;
+  if ((stat (Filename.c_str(), &st)) == -1)
     return false;
-  }
 
-  // Make the script executable...
-  chmod(Filename.c_str(), (fstat.st_mode | (0111 & ~mask)));
+  // Change the file to have whichever permissions bits from 'bits'
+  // that the umask would not disable.
+  if ((chmod(Filename.c_str(), (st.st_mode | (bits & ~mask)))) == -1)
+    return false;
 
   return true;
 }
 
+/// MakeFileExecutable - Make the file named Filename executable by
+/// setting whichever execute permissions bits the process's current
+/// umask would allow. Filename must name an existing file or
+/// directory.  Returns true on success, false on error.
+///
+bool llvm::MakeFileExecutable(const std::string &Filename) {
+  return AddPermissionsBits(Filename, 0111);
+}
+
+/// MakeFileReadable - Make the file named Filename readable by
+/// setting whichever read permissions bits the process's current
+/// umask would allow. Filename must name an existing file or
+/// directory.  Returns true on success, false on error.
+///
+bool llvm::MakeFileReadable(const std::string &Filename) {
+  return AddPermissionsBits(Filename, 0444);
+}
+
+/// getFileSize - Return the size of the specified file in bytes, or -1 if the
+/// file cannot be read or does not exist.
+long long llvm::getFileSize(const std::string &Filename) {
+  struct stat StatBuf;
+  if (stat(Filename.c_str(), &StatBuf) == -1)
+    return -1;
+  return StatBuf.st_size;  
+}
+
+/// getFileTimestamp - Get the last modified time for the specified file in an
+/// unspecified format.  This is useful to allow checking to see if a file was
+/// updated since that last time the timestampt was aquired.  If the file does
+/// not exist or there is an error getting the time-stamp, zero is returned.
+unsigned long long llvm::getFileTimestamp(const std::string &Filename) {
+  struct stat StatBuf;
+  if (stat(Filename.c_str(), &StatBuf) == -1)
+    return 0;
+  return StatBuf.st_mtime;  
+}
+
+
+
+
+//===----------------------------------------------------------------------===//
+// FDHandle class implementation
+//
+
+FDHandle::~FDHandle() throw() {
+  if (FD != -1) close(FD);
+}
+
+FDHandle &FDHandle::operator=(int fd) throw() {
+  if (FD != -1) close(FD);
+  FD = fd;
+  return *this;
+}
+