Index: include/llvm/Object/ArchiveWriter.h =================================================================== --- include/llvm/Object/ArchiveWriter.h +++ include/llvm/Object/ArchiveWriter.h @@ -20,27 +20,20 @@ namespace llvm { -class NewArchiveIterator { - bool IsNewMember; - StringRef Name; - - object::Archive::Child OldMember; - -public: - NewArchiveIterator(const object::Archive::Child &OldMember, StringRef Name); - NewArchiveIterator(StringRef FileName); - bool isNewMember() const; - StringRef getName() const; - - const object::Archive::Child &getOld() const; - - StringRef getNew() const; - llvm::ErrorOr getFD(sys::fs::file_status &NewStatus) const; - const sys::fs::file_status &getStatus() const; +struct NewArchiveMember { + std::unique_ptr Buf; + sys::TimeValue ModTime = sys::TimeValue::PosixZeroTime(); + unsigned UID = 0, GID = 0, Perms = 0644; + + NewArchiveMember() = default; + NewArchiveMember(MemoryBufferRef BufRef); + NewArchiveMember(const object::Archive::Child &OldMember, bool Deterministic, + std::error_code &EC); + NewArchiveMember(StringRef FileName, bool Deterministic, std::error_code &EC); }; std::pair -writeArchive(StringRef ArcName, std::vector &NewMembers, +writeArchive(StringRef ArcName, std::vector &NewMembers, bool WriteSymtab, object::Archive::Kind Kind, bool Deterministic, bool Thin, std::unique_ptr OldArchiveBuf = nullptr); } Index: lib/LibDriver/LibDriver.cpp =================================================================== --- lib/LibDriver/LibDriver.cpp +++ lib/LibDriver/LibDriver.cpp @@ -57,10 +57,10 @@ } static std::string getOutputPath(llvm::opt::InputArgList *Args, - const llvm::NewArchiveIterator &FirstMember) { + const llvm::NewArchiveMember &FirstMember) { if (auto *Arg = Args->getLastArg(OPT_out)) return Arg->getValue(); - SmallString<128> Val = FirstMember.getNew(); + SmallString<128> Val = StringRef(FirstMember.Buf->getBufferIdentifier()); llvm::sys::path::replace_extension(Val, ".lib"); return Val.str(); } @@ -128,14 +128,19 @@ std::vector SearchPaths = getSearchPaths(&Args, Saver); - std::vector Members; + std::vector Members; for (auto *Arg : Args.filtered(OPT_INPUT)) { Optional Path = findInputFile(Arg->getValue(), SearchPaths); if (!Path.hasValue()) { llvm::errs() << Arg->getValue() << ": no such file or directory\n"; return 1; } - Members.emplace_back(Saver.save(*Path)); + std::error_code EC; + Members.emplace_back(Saver.save(*Path), /*Deterministic=*/true, EC); + if (EC) { + llvm::errs() << Arg->getValue() << ": " << EC.message() << "\n"; + return 1; + } } std::pair Result = Index: lib/Object/ArchiveWriter.cpp =================================================================== --- lib/Object/ArchiveWriter.cpp +++ lib/Object/ArchiveWriter.cpp @@ -34,45 +34,63 @@ using namespace llvm; -NewArchiveIterator::NewArchiveIterator(const object::Archive::Child &OldMember, - StringRef Name) - : IsNewMember(false), Name(Name), OldMember(OldMember) {} - -NewArchiveIterator::NewArchiveIterator(StringRef FileName) - : IsNewMember(true), Name(FileName), OldMember(nullptr, nullptr, nullptr) {} - -StringRef NewArchiveIterator::getName() const { return Name; } - -bool NewArchiveIterator::isNewMember() const { return IsNewMember; } - -const object::Archive::Child &NewArchiveIterator::getOld() const { - assert(!IsNewMember); - return OldMember; -} - -StringRef NewArchiveIterator::getNew() const { - assert(IsNewMember); - return Name; +NewArchiveMember::NewArchiveMember(MemoryBufferRef BufRef) + : Buf(MemoryBuffer::getMemBuffer(BufRef, false)) {} + +NewArchiveMember::NewArchiveMember(const object::Archive::Child &OldMember, + bool Deterministic, std::error_code &EC) { + ErrorOr BufOrErr = OldMember.getMemoryBufferRef(); + if (!BufOrErr) { + EC = BufOrErr.getError(); + return; + } + Buf = MemoryBuffer::getMemBuffer(*BufOrErr, false); + if (!Deterministic) { + ModTime = OldMember.getLastModified(); + UID = OldMember.getUID(); + GID = OldMember.getGID(); + Perms = OldMember.getAccessMode(); + } } -llvm::ErrorOr -NewArchiveIterator::getFD(sys::fs::file_status &NewStatus) const { - assert(IsNewMember); - int NewFD; - if (auto EC = sys::fs::openFileForRead(Name, NewFD)) - return EC; - assert(NewFD != -1); +NewArchiveMember::NewArchiveMember(StringRef FileName, bool Deterministic, + std::error_code &EC) { + sys::fs::file_status Status; + int FD; + if ((EC = sys::fs::openFileForRead(FileName, FD))) + return; + assert(FD != -1); - if (auto EC = sys::fs::status(NewFD, NewStatus)) - return EC; + if ((EC = sys::fs::status(FD, Status))) + return; // 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) - return make_error_code(errc::is_a_directory); + if (Status.type() == sys::fs::file_type::directory_file) { + EC = make_error_code(errc::is_a_directory); + return; + } - return NewFD; + ErrorOr> MemberBufferOrErr = + MemoryBuffer::getOpenFile(FD, FileName, Status.getSize(), false); + if (!MemberBufferOrErr) { + EC = MemberBufferOrErr.getError(); + return; + } + + if (close(FD) != 0) { + EC = std::error_code(errno, std::generic_category()); + return; + } + + Buf = std::move(*MemberBufferOrErr); + if (!Deterministic) { + ModTime = Status.getLastModificationTime(); + UID = Status.getUser(); + GID = Status.getGroup(); + Perms = Status.permissions(); + } } template @@ -178,12 +196,13 @@ } static void writeStringTable(raw_fd_ostream &Out, StringRef ArcName, - ArrayRef Members, + ArrayRef Members, std::vector &StringMapIndexes, bool Thin) { unsigned StartOffset = 0; - for (const NewArchiveIterator &I : Members) { - StringRef Name = sys::path::filename(I.getName()); + for (const NewArchiveMember &M : Members) { + StringRef Path = M.Buf->getBufferIdentifier(); + StringRef Name = sys::path::filename(Path); if (!useStringTable(Thin, Name)) continue; if (StartOffset == 0) { @@ -194,7 +213,7 @@ StringMapIndexes.push_back(Out.tell() - StartOffset); if (Thin) - Out << computeRelativePath(ArcName, I.getName()); + Out << computeRelativePath(ArcName, Path); else Out << Name; @@ -221,8 +240,7 @@ // Returns the offset of the first reference to a member offset. static ErrorOr writeSymbolTable(raw_fd_ostream &Out, object::Archive::Kind Kind, - ArrayRef Members, - ArrayRef Buffers, + ArrayRef Members, std::vector &MemberOffsetRefs, bool Deterministic) { unsigned HeaderStartOffset = 0; unsigned BodyStartOffset = 0; @@ -230,7 +248,7 @@ raw_svector_ostream NameOS(NameBuf); LLVMContext Context; for (unsigned MemberNum = 0, N = Members.size(); MemberNum < N; ++MemberNum) { - MemoryBufferRef MemberBuffer = Buffers[MemberNum]; + MemoryBufferRef MemberBuffer = Members[MemberNum].Buf->getMemBufferRef(); Expected> ObjOrErr = object::SymbolicFile::createSymbolicFile( MemberBuffer, sys::fs::file_magic::unknown, &Context); @@ -305,7 +323,7 @@ std::pair llvm::writeArchive(StringRef ArcName, - std::vector &NewMembers, + std::vector &NewMembers, bool WriteSymtab, object::Archive::Kind Kind, bool Deterministic, bool Thin, std::unique_ptr OldArchiveBuf) { @@ -330,43 +348,10 @@ std::vector Members; std::vector NewMemberStatus; - for (NewArchiveIterator &Member : NewMembers) { - MemoryBufferRef MemberRef; - - if (Member.isNewMember()) { - StringRef Filename = Member.getNew(); - NewMemberStatus.resize(NewMemberStatus.size() + 1); - sys::fs::file_status &Status = NewMemberStatus.back(); - ErrorOr FD = Member.getFD(Status); - if (auto EC = FD.getError()) - return std::make_pair(Filename, EC); - ErrorOr> MemberBufferOrErr = - MemoryBuffer::getOpenFile(FD.get(), Filename, Status.getSize(), - false); - if (auto EC = MemberBufferOrErr.getError()) - return std::make_pair(Filename, EC); - if (close(FD.get()) != 0) - return std::make_pair(Filename, - std::error_code(errno, std::generic_category())); - Buffers.push_back(std::move(MemberBufferOrErr.get())); - MemberRef = Buffers.back()->getMemBufferRef(); - } else { - const object::Archive::Child &OldMember = Member.getOld(); - assert((!Thin || OldMember.getParent()->isThin()) && - "Thin archives cannot refers to member of other archives"); - ErrorOr MemberBufferOrErr = - OldMember.getMemoryBufferRef(); - if (auto EC = MemberBufferOrErr.getError()) - return std::make_pair("", EC); - MemberRef = MemberBufferOrErr.get(); - } - Members.push_back(MemberRef); - } - unsigned MemberReferenceOffset = 0; if (WriteSymtab) { ErrorOr MemberReferenceOffsetOrErr = writeSymbolTable( - Out, Kind, NewMembers, Members, MemberOffsetRefs, Deterministic); + Out, Kind, NewMembers, MemberOffsetRefs, Deterministic); if (auto EC = MemberReferenceOffsetOrErr.getError()) return std::make_pair(ArcName, EC); MemberReferenceOffset = MemberReferenceOffsetOrErr.get(); @@ -376,55 +361,18 @@ if (Kind != object::Archive::K_BSD) writeStringTable(Out, ArcName, NewMembers, StringMapIndexes, Thin); - unsigned MemberNum = 0; - unsigned NewMemberNum = 0; std::vector::iterator StringMapIndexIter = StringMapIndexes.begin(); std::vector MemberOffset; - for (const NewArchiveIterator &I : NewMembers) { - MemoryBufferRef File = Members[MemberNum++]; + for (const NewArchiveMember &M : NewMembers) { + MemoryBufferRef File = M.Buf->getMemBufferRef(); unsigned Pos = Out.tell(); MemberOffset.push_back(Pos); - sys::TimeValue ModTime; - unsigned UID; - unsigned GID; - unsigned Perms; - if (Deterministic) { - ModTime.fromEpochTime(0); - UID = 0; - GID = 0; - Perms = 0644; - } else if (I.isNewMember()) { - const sys::fs::file_status &Status = NewMemberStatus[NewMemberNum]; - ModTime = Status.getLastModificationTime(); - UID = Status.getUser(); - GID = Status.getGroup(); - Perms = Status.permissions(); - } else { - const object::Archive::Child &OldMember = I.getOld(); - ModTime = OldMember.getLastModified(); - UID = OldMember.getUID(); - GID = OldMember.getGID(); - Perms = OldMember.getAccessMode(); - } - - if (I.isNewMember()) { - StringRef FileName = I.getNew(); - const sys::fs::file_status &Status = NewMemberStatus[NewMemberNum++]; - printMemberHeader(Out, Kind, Thin, sys::path::filename(FileName), - StringMapIndexIter, ModTime, UID, GID, Perms, - Status.getSize()); - } else { - const object::Archive::Child &OldMember = I.getOld(); - ErrorOr Size = OldMember.getSize(); - if (std::error_code EC = Size.getError()) - return std::make_pair("", EC); - StringRef FileName = I.getName(); - printMemberHeader(Out, Kind, Thin, sys::path::filename(FileName), - StringMapIndexIter, ModTime, UID, GID, Perms, - Size.get()); - } + printMemberHeader(Out, Kind, Thin, + sys::path::filename(M.Buf->getBufferIdentifier()), + StringMapIndexIter, M.ModTime, M.UID, M.GID, M.Perms, + M.Buf->getBufferSize()); if (!Thin) Out << File.getBuffer(); Index: tools/llvm-ar/llvm-ar.cpp =================================================================== --- tools/llvm-ar/llvm-ar.cpp +++ tools/llvm-ar/llvm-ar.cpp @@ -428,25 +428,28 @@ std::exit(1); } -static void addMember(std::vector &Members, +static void addMember(std::vector &Members, StringRef FileName, int Pos = -1) { - NewArchiveIterator NI(FileName); + std::error_code EC; + NewArchiveMember NM(FileName, Deterministic, EC); + failIfError(EC, FileName); if (Pos == -1) - Members.push_back(NI); + Members.push_back(std::move(NM)); else - Members[Pos] = NI; + Members[Pos] = std::move(NM); } -static void addMember(std::vector &Members, - const object::Archive::Child &M, StringRef Name, - int Pos = -1) { +static void addMember(std::vector &Members, + const object::Archive::Child &M, int Pos = -1) { if (Thin && !M.getParent()->isThin()) fail("Cannot convert a regular archive to a thin one"); - NewArchiveIterator NI(M, Name); + std::error_code EC; + NewArchiveMember NM(M, Deterministic, EC); + failIfError(EC); if (Pos == -1) - Members.push_back(NI); + Members.push_back(std::move(NM)); else - Members[Pos] = NI; + Members[Pos] = std::move(NM); } enum InsertAction { @@ -507,11 +510,11 @@ // We have to walk this twice and computing it is not trivial, so creating an // explicit std::vector is actually fairly efficient. -static std::vector +static std::vector computeNewArchiveMembers(ArchiveOperation Operation, object::Archive *OldArchive) { - std::vector Ret; - std::vector Moved; + std::vector Ret; + std::vector Moved; int InsertPos = -1; StringRef PosName = sys::path::filename(RelPos); if (OldArchive) { @@ -535,7 +538,7 @@ computeInsertAction(Operation, Child, Name, MemberI); switch (Action) { case IA_AddOldMember: - addMember(Ret, Child, Name); + addMember(Ret, Child); break; case IA_AddNewMeber: addMember(Ret, *MemberI); @@ -543,7 +546,7 @@ case IA_Delete: break; case IA_MoveOldMember: - addMember(Moved, Child, Name); + addMember(Moved, Child); break; case IA_MoveNewMember: addMember(Moved, *MemberI); @@ -564,10 +567,15 @@ InsertPos = Ret.size(); assert(unsigned(InsertPos) <= Ret.size()); - Ret.insert(Ret.begin() + InsertPos, Moved.begin(), Moved.end()); - - Ret.insert(Ret.begin() + InsertPos, Members.size(), NewArchiveIterator("")); int Pos = InsertPos; + for (auto &M : Moved) { + Ret.insert(Ret.begin() + Pos, std::move(M)); + ++Pos; + } + + for (unsigned I = 0; I != Members.size(); ++I) + Ret.insert(Ret.begin() + InsertPos, NewArchiveMember()); + Pos = InsertPos; for (auto &Member : Members) { addMember(Ret, Member, Pos); ++Pos; @@ -581,56 +589,26 @@ : object::Archive::K_GNU; } -static object::Archive::Kind -getKindFromMember(const NewArchiveIterator &Member) { - auto getKindFromMemberInner = - [](MemoryBufferRef Buffer) -> object::Archive::Kind { - Expected> OptionalObject = - object::ObjectFile::createObjectFile(Buffer); +static object::Archive::Kind getKindFromMember(const NewArchiveMember &Member) { + Expected> OptionalObject = + object::ObjectFile::createObjectFile(Member.Buf->getMemBufferRef()); - if (OptionalObject) - return isa(**OptionalObject) - ? object::Archive::K_BSD - : object::Archive::K_GNU; + if (OptionalObject) + return isa(**OptionalObject) + ? object::Archive::K_BSD + : object::Archive::K_GNU; - // squelch the error in case we had a non-object file - consumeError(OptionalObject.takeError()); - return getDefaultForHost(); - }; - - if (Member.isNewMember()) { - object::Archive::Kind Kind = getDefaultForHost(); - - sys::fs::file_status Status; - if (auto OptionalFD = Member.getFD(Status)) { - if (auto MB = MemoryBuffer::getOpenFile(*OptionalFD, Member.getName(), - Status.getSize(), false)) - Kind = getKindFromMemberInner((*MB)->getMemBufferRef()); - - if (close(*OptionalFD) != 0) - failIfError(std::error_code(errno, std::generic_category()), - "failed to close file"); - } - - return Kind; - } else { - const object::Archive::Child &OldMember = Member.getOld(); - if (OldMember.getParent()->isThin()) - return object::Archive::Kind::K_GNU; - - auto OptionalMB = OldMember.getMemoryBufferRef(); - failIfError(OptionalMB.getError()); - - return getKindFromMemberInner(*OptionalMB); - } + // squelch the error in case we had a non-object file + consumeError(OptionalObject.takeError()); + return getDefaultForHost(); } static void performWriteOperation(ArchiveOperation Operation, object::Archive *OldArchive, std::unique_ptr OldArchiveBuf, - std::vector *NewMembersP) { - std::vector NewMembers; + std::vector *NewMembersP) { + std::vector NewMembers; if (!NewMembersP) NewMembers = computeNewArchiveMembers(Operation, OldArchive); @@ -680,7 +658,7 @@ static void performOperation(ArchiveOperation Operation, object::Archive *OldArchive, std::unique_ptr OldArchiveBuf, - std::vector *NewMembers) { + std::vector *NewMembers) { switch (Operation) { case Print: case DisplayTable: @@ -703,7 +681,7 @@ } static int performOperation(ArchiveOperation Operation, - std::vector *NewMembers) { + std::vector *NewMembers) { // Create or open the archive object. ErrorOr> Buf = MemoryBuffer::getFile(ArchiveName, -1, false); @@ -741,7 +719,7 @@ failIfError(Buf.getError()); const MemoryBuffer &Ref = *Buf.get(); bool Saved = false; - std::vector NewMembers; + std::vector NewMembers; std::vector> ArchiveBuffers; std::vector> Archives; @@ -772,10 +750,7 @@ object::Archive &Lib = *Archives.back(); for (auto &MemberOrErr : Lib.children()) { failIfError(MemberOrErr.getError()); - auto &Member = MemberOrErr.get(); - ErrorOr NameOrErr = Member.getName(); - failIfError(NameOrErr.getError()); - addMember(NewMembers, Member, *NameOrErr); + addMember(NewMembers, *MemberOrErr); } break; }