Don't include directory names in archives.
[oota-llvm.git] / tools / llvm-ar / llvm-ar.cpp
index 2a4a3deecddf90598da3313b0b91e1b308463180..941b6310804d3376c40765433f47a8ff18c41e1f 100644 (file)
@@ -19,6 +19,7 @@
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/Format.h"
 #include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/PathV1.h"
 #include "llvm/Support/PrettyStackTrace.h"
 #include "llvm/Support/Signals.h"
 #include "llvm/Support/raw_ostream.h"
@@ -96,11 +97,9 @@ bool DontSkipBitcode = false;    ///< 'k' modifier
 bool UseCount = false;           ///< 'N' modifier
 bool OriginalDates = false;      ///< 'o' modifier
 bool FullPath = false;           ///< 'P' modifier
-bool RecurseDirectories = false; ///< 'R' modifier
 bool SymTable = true;            ///< 's' & 'S' modifiers
 bool OnlyUpdate = false;         ///< 'u' modifier
 bool Verbose = false;            ///< 'v' modifier
-bool ReallyVerbose = false;      ///< 'V' modifier
 
 // Relative Positional Argument (for insert/move). This variable holds
 // the name of the archive member to which the 'a', 'b' or 'i' modifier
@@ -122,7 +121,7 @@ std::vector<std::string> Members;
 
 // This variable holds the (possibly expanded) list of path objects that
 // correspond to files we will
-std::set<sys::Path> Paths;
+std::set<std::string> Paths;
 
 // The Archive object to which all the editing operations will be sent.
 Archive* TheArchive = 0;
@@ -217,13 +216,11 @@ ArchiveOperation parseCommandLine() {
     case 'k': DontSkipBitcode = true; break;
     case 'l': /* accepted but unused */ break;
     case 'o': OriginalDates = true; break;
+    case 's': break; // Ignore for now.
+    case 'S': break; // Ignore for now.
     case 'P': FullPath = true; break;
-    case 'R': RecurseDirectories = true; break;
-    case 's': SymTable = true; break;
-    case 'S': SymTable = false; break;
     case 'u': OnlyUpdate = true; break;
     case 'v': Verbose = true; break;
-    case 'V': Verbose = ReallyVerbose = true; break;
     case 'a':
       getRelPos();
       AddAfter = true;
@@ -268,8 +265,6 @@ ArchiveOperation parseCommandLine() {
       show_help("The 'a', 'b' and 'i' modifiers can only be specified with "
             "the 'm' or 'r' operations");
   }
-  if (RecurseDirectories && Operation != ReplaceOrInsert)
-    show_help("The 'R' modifiers is only applicabe to the 'r' operation");
   if (OriginalDates && Operation != Extract)
     show_help("The 'o' modifier is only applicable to the 'x' operation");
   if (TruncateNames && Operation!=QuickAppend && Operation!=ReplaceOrInsert)
@@ -284,64 +279,21 @@ ArchiveOperation parseCommandLine() {
   return Operation;
 }
 
-// recurseDirectories - Implements the "R" modifier. This function scans through
-// the Paths vector (built by buildPaths, below) and replaces any directories it
-// finds with all the files in that directory (recursively). It uses the
-// sys::Path::getDirectoryContent method to perform the actual directory scans.
-bool
-recurseDirectories(const sys::Path& path,
-                   std::set<sys::Path>& result, std::string* ErrMsg) {
-  result.clear();
-  if (RecurseDirectories) {
-    std::set<sys::Path> content;
-    if (path.getDirectoryContents(content, ErrMsg))
-      return true;
-
-    for (std::set<sys::Path>::iterator I = content.begin(), E = content.end();
-         I != E; ++I) {
-      // Make sure it exists and is a directory
-      sys::PathWithStatus PwS(*I);
-      const sys::FileStatus *Status = PwS.getFileStatus(false, ErrMsg);
-      if (!Status)
-        return true;
-      if (Status->isDir) {
-        std::set<sys::Path> moreResults;
-        if (recurseDirectories(*I, moreResults, ErrMsg))
-          return true;
-        result.insert(moreResults.begin(), moreResults.end());
-      } else {
-          result.insert(*I);
-      }
-    }
-  }
-  return false;
-}
-
 // buildPaths - Convert the strings in the Members vector to sys::Path objects
 // and make sure they are valid and exist exist. This check is only needed for
 // the operations that add/replace files to the archive ('q' and 'r')
 bool buildPaths(bool checkExistence, std::string* ErrMsg) {
   for (unsigned i = 0; i < Members.size(); i++) {
-    sys::Path aPath;
-    if (!aPath.set(Members[i]))
-      fail(std::string("File member name invalid: ") + Members[i]);
+    std::string aPath = Members[i];
     if (checkExistence) {
-      bool Exists;
-      if (sys::fs::exists(aPath.str(), Exists) || !Exists)
-        fail(std::string("File does not exist: ") + Members[i]);
-      std::string Err;
-      sys::PathWithStatus PwS(aPath);
-      const sys::FileStatus *si = PwS.getFileStatus(false, &Err);
-      if (!si)
-        fail(Err);
-      if (si->isDir) {
-        std::set<sys::Path> dirpaths;
-        if (recurseDirectories(aPath, dirpaths, ErrMsg))
-          return true;
-        Paths.insert(dirpaths.begin(),dirpaths.end());
-      } else {
-        Paths.insert(aPath);
-      }
+      bool IsDirectory;
+      error_code EC = sys::fs::is_directory(aPath, IsDirectory);
+      if (EC)
+        fail(aPath + ": " + EC.message());
+      if (IsDirectory)
+        fail(aPath + " Is a directory");
+
+      Paths.insert(aPath);
     } else {
       Paths.insert(aPath);
     }
@@ -349,17 +301,6 @@ bool buildPaths(bool checkExistence, std::string* ErrMsg) {
   return false;
 }
 
-// printSymbolTable - print out the archive's symbol table.
-void printSymbolTable() {
-  outs() << "\nArchive Symbol Table:\n";
-  const Archive::SymTabType& symtab = TheArchive->getSymbolTable();
-  for (Archive::SymTabType::const_iterator I=symtab.begin(), E=symtab.end();
-       I != E; ++I ) {
-    unsigned offset = TheArchive->getFirstFileOffset() + I->second;
-    outs() << " " << format("%9u", offset) << "\t" << I->first <<"\n";
-  }
-}
-
 // doPrint - Implements the 'p' operation. This function traverses the archive
 // looking for members that match the path list. It is careful to uncompress
 // things that should be and to skip bitcode files unless the 'k' modifier was
@@ -444,8 +385,6 @@ doDisplayTable(std::string* ErrMsg) {
       }
     }
   }
-  if (ReallyVerbose)
-    printSymbolTable();
   return false;
 }
 
@@ -460,18 +399,10 @@ doExtract(std::string* ErrMsg) {
     if (Paths.empty() ||
         (std::find(Paths.begin(), Paths.end(), I->getPath()) != Paths.end())) {
 
-      // Make sure the intervening directories are created
-      if (I->hasPath()) {
-        sys::Path dirs(I->getPath());
-        dirs.eraseComponent();
-        if (dirs.createDirectoryOnDisk(/*create_parents=*/true, ErrMsg))
-          return true;
-      }
-
       // Open up a file stream for writing
       std::ios::openmode io_mode = std::ios::out | std::ios::trunc |
                                    std::ios::binary;
-      std::ofstream file(I->getPath().c_str(), io_mode);
+      std::ofstream file(I->getPath().str().c_str(), io_mode);
 
       // Get the data and its length
       const char* data = reinterpret_cast<const char*>(I->getData());
@@ -481,10 +412,18 @@ doExtract(std::string* ErrMsg) {
       file.write(data,len);
       file.close();
 
+      sys::PathWithStatus PWS(I->getPath());
+      sys::FileStatus Status = *PWS.getFileStatus();
+
+      // Retain the original mode.
+      Status.mode = I->getMode();
+
       // If we're supposed to retain the original modification times, etc. do so
       // now.
       if (OriginalDates)
-        I->getPath().setStatusInfoOnDisk(I->getFileStatus());
+        Status.modTime = I->getModTime();
+
+      PWS.setStatusInfoOnDisk(Status);
     }
   }
   return false;
@@ -516,10 +455,8 @@ doDelete(std::string* ErrMsg) {
   }
 
   // We're done editting, reconstruct the archive.
-  if (TheArchive->writeToDisk(SymTable,TruncateNames,ErrMsg))
+  if (TheArchive->writeToDisk(TruncateNames,ErrMsg))
     return true;
-  if (ReallyVerbose)
-    printSymbolTable();
   return false;
 }
 
@@ -555,14 +492,14 @@ doMove(std::string* ErrMsg) {
   }
 
   // Keep a list of the paths remaining to be moved
-  std::set<sys::Path> remaining(Paths);
+  std::set<std::string> remaining(Paths);
 
   // Scan the archive again, this time looking for the members to move to the
   // moveto_spot.
   for (Archive::iterator I = TheArchive->begin(), E= TheArchive->end();
        I != E && !remaining.empty(); ++I ) {
-    std::set<sys::Path>::iterator found =
-      std::find(remaining.begin(),remaining.end(),I->getPath());
+    std::set<std::string>::iterator found =
+      std::find(remaining.begin(),remaining.end(), I->getPath());
     if (found != remaining.end()) {
       if (I != moveto_spot)
         TheArchive->splice(moveto_spot,*TheArchive,I);
@@ -571,10 +508,8 @@ doMove(std::string* ErrMsg) {
   }
 
   // We're done editting, reconstruct the archive.
-  if (TheArchive->writeToDisk(SymTable,TruncateNames,ErrMsg))
+  if (TheArchive->writeToDisk(TruncateNames,ErrMsg))
     return true;
-  if (ReallyVerbose)
-    printSymbolTable();
   return false;
 }
 
@@ -589,17 +524,15 @@ doQuickAppend(std::string* ErrMsg) {
     return false;
 
   // Append them quickly.
-  for (std::set<sys::Path>::iterator PI = Paths.begin(), PE = Paths.end();
+  for (std::set<std::string>::iterator PI = Paths.begin(), PE = Paths.end();
        PI != PE; ++PI) {
-    if (TheArchive->addFileBefore(*PI,TheArchive->end(),ErrMsg))
+    if (TheArchive->addFileBefore(*PI, TheArchive->end(), ErrMsg))
       return true;
   }
 
   // We're done editting, reconstruct the archive.
-  if (TheArchive->writeToDisk(SymTable,TruncateNames,ErrMsg))
+  if (TheArchive->writeToDisk(TruncateNames,ErrMsg))
     return true;
-  if (ReallyVerbose)
-    printSymbolTable();
   return false;
 }
 
@@ -615,7 +548,7 @@ doReplaceOrInsert(std::string* ErrMsg) {
     return false;
 
   // Keep track of the paths that remain to be inserted.
-  std::set<sys::Path> remaining(Paths);
+  std::set<std::string> remaining(Paths);
 
   // Default the insertion spot to the end of the archive
   Archive::iterator insert_spot = TheArchive->end();
@@ -627,10 +560,10 @@ doReplaceOrInsert(std::string* ErrMsg) {
     // Determine if this archive member matches one of the paths we're trying
     // to replace.
 
-    std::set<sys::Path>::iterator found = remaining.end();
-    for (std::set<sys::Path>::iterator RI = remaining.begin(),
+    std::set<std::string>::iterator found = remaining.end();
+    for (std::set<std::string>::iterator RI = remaining.begin(),
          RE = remaining.end(); RI != RE; ++RI ) {
-      std::string compare(RI->str());
+      std::string compare(*RI);
       if (TruncateNames && compare.length() > 15) {
         const char* nm = compare.c_str();
         unsigned len = compare.length();
@@ -686,18 +619,16 @@ doReplaceOrInsert(std::string* ErrMsg) {
   // If we didn't replace all the members, some will remain and need to be
   // inserted at the previously computed insert-spot.
   if (!remaining.empty()) {
-    for (std::set<sys::Path>::iterator PI = remaining.begin(),
+    for (std::set<std::string>::iterator PI = remaining.begin(),
          PE = remaining.end(); PI != PE; ++PI) {
-      if (TheArchive->addFileBefore(*PI,insert_spot, ErrMsg))
+      if (TheArchive->addFileBefore(*PI, insert_spot, ErrMsg))
         return true;
     }
   }
 
   // We're done editting, reconstruct the archive.
-  if (TheArchive->writeToDisk(SymTable,TruncateNames,ErrMsg))
+  if (TheArchive->writeToDisk(TruncateNames,ErrMsg))
     return true;
-  if (ReallyVerbose)
-    printSymbolTable();
   return false;
 }
 
@@ -736,11 +667,11 @@ int main(int argc, char **argv) {
     // Produce a warning if we should and we're creating the archive
     if (!Create)
       errs() << argv[0] << ": creating " << ArchivePath.str() << "\n";
-    TheArchive = Archive::CreateEmpty(ArchivePath, Context);
+    TheArchive = Archive::CreateEmpty(ArchivePath.str(), Context);
     TheArchive->writeToDisk();
   } else {
     std::string Error;
-    TheArchive = Archive::OpenAndLoad(ArchivePath, Context, &Error);
+    TheArchive = Archive::OpenAndLoad(ArchivePath.str(), Context, &Error);
     if (TheArchive == 0) {
       errs() << argv[0] << ": error loading '" << ArchivePath.str() << "': "
              << Error << "!\n";