Index: include/llvm/Object/Archive.h =================================================================== --- include/llvm/Object/Archive.h +++ include/llvm/Object/Archive.h @@ -175,8 +175,16 @@ } }; + // We supply two flavours of constructors, one that can work with an existing + // buffer, and another that takes over ownership of a buffer. It is sometimes + // important to link ownership of the buffer with the archive in the case where + // the buffer is an mmap'ed file that must be closed when the archive is + // finished being used (before clobbering it with a new file). Archive(MemoryBufferRef Source, std::error_code &EC); + Archive(std::unique_ptr Source, std::error_code &EC); static ErrorOr> create(MemoryBufferRef Source); + static ErrorOr> create( + std::unique_ptr Source); enum Kind { K_GNU, @@ -227,6 +235,7 @@ unsigned Format : 2; unsigned IsThin : 1; mutable std::vector> ThinBuffers; + std::unique_ptr BackingBuffer; }; } Index: include/llvm/Object/ArchiveWriter.h =================================================================== --- include/llvm/Object/ArchiveWriter.h +++ include/llvm/Object/ArchiveWriter.h @@ -42,7 +42,7 @@ std::pair writeArchive(StringRef ArcName, std::vector &NewMembers, bool WriteSymtab, object::Archive::Kind Kind, bool Deterministic, - bool Thin); + bool Thin, std::unique_ptr OldArchive = nullptr); } #endif Index: lib/Object/Archive.cpp =================================================================== --- lib/Object/Archive.cpp +++ lib/Object/Archive.cpp @@ -259,6 +259,14 @@ return std::move(Ret); } +ErrorOr> Archive::create(std::unique_ptr Source) { + std::error_code EC; + std::unique_ptr Ret(new Archive(std::move(Source), EC)); + if (EC) + return EC; + return std::move(Ret); +} + void Archive::setFirstRegular(const Child &C) { FirstRegularData = C.Data; FirstRegularStartOfFile = C.StartOfFile; @@ -424,6 +432,12 @@ ec = std::error_code(); } +Archive::Archive(std::unique_ptr Source, std::error_code &ec) + : Archive(Source->getMemBufferRef(), ec) +{ + BackingBuffer = std::move(Source); +} + Archive::child_iterator Archive::child_begin(bool SkipInternal) const { if (Data.getBufferSize() == 8) // empty archive. return child_end(); Index: lib/Object/ArchiveWriter.cpp =================================================================== --- lib/Object/ArchiveWriter.cpp +++ lib/Object/ArchiveWriter.cpp @@ -307,7 +307,8 @@ llvm::writeArchive(StringRef ArcName, std::vector &NewMembers, bool WriteSymtab, object::Archive::Kind Kind, - bool Deterministic, bool Thin) { + bool Deterministic, bool Thin, + std::unique_ptr OldArchive) { SmallString<128> TmpArchive; int TmpArchiveFD; if (auto EC = sys::fs::createUniqueFile(ArcName + ".temp-archive-%%%%%%%.a", @@ -442,6 +443,7 @@ Output.keep(); Out.close(); + OldArchive.reset(); // In case it has an open handle to the file we're replacing sys::fs::rename(TmpArchive, ArcName); return std::make_pair("", std::error_code()); } Index: tools/llvm-ar/llvm-ar.cpp =================================================================== --- tools/llvm-ar/llvm-ar.cpp +++ tools/llvm-ar/llvm-ar.cpp @@ -579,7 +579,8 @@ } static void -performWriteOperation(ArchiveOperation Operation, object::Archive *OldArchive, +performWriteOperation(ArchiveOperation Operation, + std::unique_ptr OldArchive, std::vector *NewMembersP) { object::Archive::Kind Kind; switch (FormatOpt) { @@ -600,18 +601,20 @@ } if (NewMembersP) { std::pair Result = writeArchive( - ArchiveName, *NewMembersP, Symtab, Kind, Deterministic, Thin); + ArchiveName, *NewMembersP, Symtab, Kind, Deterministic, Thin, + std::move(OldArchive)); failIfError(Result.second, Result.first); return; } std::vector NewMembers = - computeNewArchiveMembers(Operation, OldArchive); + computeNewArchiveMembers(Operation, OldArchive.get()); auto Result = - writeArchive(ArchiveName, NewMembers, Symtab, Kind, Deterministic, Thin); + writeArchive(ArchiveName, NewMembers, Symtab, Kind, Deterministic, Thin, + std::move(OldArchive)); failIfError(Result.second, Result.first); } -static void createSymbolTable(object::Archive *OldArchive) { +static void createSymbolTable(std::unique_ptr OldArchive) { // When an archive is created or modified, if the s option is given, the // resulting archive will have a current symbol table. If the S option // is given, it will have no symbol table. @@ -621,27 +624,27 @@ if (OldArchive->hasSymbolTable()) return; - performWriteOperation(CreateSymTab, OldArchive, nullptr); + performWriteOperation(CreateSymTab, std::move(OldArchive), nullptr); } static void performOperation(ArchiveOperation Operation, - object::Archive *OldArchive, + std::unique_ptr OldArchive, std::vector *NewMembers) { switch (Operation) { case Print: case DisplayTable: case Extract: - performReadOperation(Operation, OldArchive); + performReadOperation(Operation, OldArchive.get()); return; case Delete: case Move: case QuickAppend: case ReplaceOrInsert: - performWriteOperation(Operation, OldArchive, NewMembers); + performWriteOperation(Operation, std::move(OldArchive), NewMembers); return; case CreateSymTab: - createSymbolTable(OldArchive); + createSymbolTable(std::move(OldArchive)); return; } llvm_unreachable("Unknown operation."); @@ -657,10 +660,12 @@ fail("error opening '" + ArchiveName + "': " + EC.message() + "!"); if (!EC) { - object::Archive Archive(Buf.get()->getMemBufferRef(), EC); + ErrorOr> Archive = + object::Archive::create(std::move(Buf.get())); + EC = Archive.getError(); failIfError(EC, "error loading '" + ArchiveName + "': " + EC.message() + "!"); - performOperation(Operation, &Archive, NewMembers); + performOperation(Operation, std::move(Archive.get()), NewMembers); return 0; }