-// doExtract - Implement the 'x' operation. This function extracts files back to
-// the file system.
-bool
-doExtract(std::string* ErrMsg) {
- if (buildPaths(false, ErrMsg))
- return true;
- for (Archive::iterator I = TheArchive->begin(), E = TheArchive->end();
- I != E; ++I ) {
- if (Paths.empty() ||
- (std::find(Paths.begin(), Paths.end(), I->getPath()) != Paths.end())) {
-
- // Open up a file stream for writing
- int OpenFlags = O_TRUNC | O_WRONLY | O_CREAT;
-#ifdef O_BINARY
- OpenFlags |= O_BINARY;
-#endif
+namespace {
+class NewArchiveIterator {
+ bool IsNewMember;
+ StringRef Name;
+
+ object::Archive::child_iterator OldI;
+
+ StringRef NewFilename;
+ mutable int NewFD;
+ mutable sys::fs::file_status NewStatus;
+
+public:
+ NewArchiveIterator(object::Archive::child_iterator I, StringRef Name);
+ NewArchiveIterator(StringRef I, StringRef Name);
+ NewArchiveIterator();
+ bool isNewMember() const;
+ StringRef getName() const;
+
+ object::Archive::child_iterator getOld() const;
+
+ StringRef getNew() const;
+ int getFD() const;
+ const sys::fs::file_status &getStatus() const;
+};
+}
+
+NewArchiveIterator::NewArchiveIterator() {}
+
+NewArchiveIterator::NewArchiveIterator(object::Archive::child_iterator I,
+ StringRef Name)
+ : IsNewMember(false), Name(Name), OldI(I) {}
+
+NewArchiveIterator::NewArchiveIterator(StringRef NewFilename, StringRef Name)
+ : IsNewMember(true), Name(Name), NewFilename(NewFilename), NewFD(-1) {}
+
+StringRef NewArchiveIterator::getName() const { return Name; }
+
+bool NewArchiveIterator::isNewMember() const { return IsNewMember; }
+
+object::Archive::child_iterator NewArchiveIterator::getOld() const {
+ assert(!IsNewMember);
+ return OldI;
+}
+
+StringRef NewArchiveIterator::getNew() const {
+ assert(IsNewMember);
+ return NewFilename;
+}
+
+int NewArchiveIterator::getFD() const {
+ assert(IsNewMember);
+ if (NewFD != -1)
+ return NewFD;
+ failIfError(sys::fs::openFileForRead(NewFilename, NewFD), NewFilename);
+ assert(NewFD != -1);
+
+ failIfError(sys::fs::status(NewFD, NewStatus), NewFilename);
+
+ // Opening a directory doesn't make sense. Let it fail.
+ // Linux cannot open directories with open(2), although
+ // cygwin and *bsd can.
+ if (NewStatus.type() == sys::fs::file_type::directory_file)
+ failIfError(make_error_code(errc::is_a_directory), NewFilename);
+
+ return NewFD;
+}
+
+const sys::fs::file_status &NewArchiveIterator::getStatus() const {
+ assert(IsNewMember);
+ assert(NewFD != -1 && "Must call getFD first");
+ return NewStatus;
+}
+
+template <typename T>
+void addMember(std::vector<NewArchiveIterator> &Members, T I, StringRef Name,
+ int Pos = -1) {
+ NewArchiveIterator NI(I, Name);
+ if (Pos == -1)
+ Members.push_back(NI);
+ else
+ Members[Pos] = NI;
+}
+
+enum InsertAction {
+ IA_AddOldMember,
+ IA_AddNewMeber,
+ IA_Delete,
+ IA_MoveOldMember,
+ IA_MoveNewMember
+};
+
+static InsertAction computeInsertAction(ArchiveOperation Operation,
+ object::Archive::child_iterator I,
+ StringRef Name,
+ std::vector<StringRef>::iterator &Pos) {
+ if (Operation == QuickAppend || Members.empty())
+ return IA_AddOldMember;
+
+ auto MI =
+ std::find_if(Members.begin(), Members.end(), [Name](StringRef Path) {
+ return Name == sys::path::filename(Path);
+ });