static void writeStringTable(raw_fd_ostream &Out, ArrayRef<NewArchiveIterator> Members, std::vector<unsigned> &StringMapIndexes) { unsigned StartOffset = 0; for (ArrayRef<NewArchiveIterator>::iterator I = Members.begin(), E = Members.end(); I != E; ++I) { StringRef Name = I->getName(); if (Name.size() < 16) continue; if (StartOffset == 0) { printWithSpacePadding(Out, "//", 58); Out << "`\n"; StartOffset = Out.tell(); } StringMapIndexes.push_back(Out.tell() - StartOffset); Out << Name << "/\n"; } if (StartOffset == 0) return; if (Out.tell() % 2) Out << '\n'; int Pos = Out.tell(); Out.seek(StartOffset - 12); printWithSpacePadding(Out, Pos - StartOffset, 10); Out.seek(Pos); }
static void writeStringTable(raw_fd_ostream &Out, StringRef ArcName, ArrayRef<NewArchiveMember> Members, std::vector<unsigned> &StringMapIndexes, bool Thin) { unsigned StartOffset = 0; for (const NewArchiveMember &M : Members) { StringRef Path = M.Buf->getBufferIdentifier(); StringRef Name = sys::path::filename(Path); if (!useStringTable(Thin, Name)) continue; if (StartOffset == 0) { printWithSpacePadding(Out, "//", 58); Out << "`\n"; StartOffset = Out.tell(); } StringMapIndexes.push_back(Out.tell() - StartOffset); if (Thin) Out << computeRelativePath(ArcName, Path); else Out << Name; Out << "/\n"; } if (StartOffset == 0) return; if (Out.tell() % 2) Out << '\n'; int Pos = Out.tell(); Out.seek(StartOffset - 12); printWithSpacePadding(Out, Pos - StartOffset, 10); Out.seek(Pos); }
static void writeSymbolTable(raw_fd_ostream &Out, ArrayRef<NewArchiveIterator> Members, MutableArrayRef<std::unique_ptr<MemoryBuffer>> Buffers, std::vector<std::pair<unsigned, unsigned>> &MemberOffsetRefs) { unsigned StartOffset = 0; unsigned MemberNum = 0; std::string NameBuf; raw_string_ostream NameOS(NameBuf); unsigned NumSyms = 0; LLVMContext &Context = getGlobalContext(); for (ArrayRef<NewArchiveIterator>::iterator I = Members.begin(), E = Members.end(); I != E; ++I, ++MemberNum) { std::unique_ptr<MemoryBuffer> &MemberBuffer = Buffers[MemberNum]; ErrorOr<std::unique_ptr<object::SymbolicFile>> ObjOrErr = object::SymbolicFile::createSymbolicFile( MemberBuffer, sys::fs::file_magic::unknown, &Context); if (!ObjOrErr) continue; // FIXME: check only for "not an object file" errors. object::SymbolicFile &Obj = *ObjOrErr.get(); if (!StartOffset) { printMemberHeader(Out, "", sys::TimeValue::now(), 0, 0, 0, 0); StartOffset = Out.tell(); print32BE(Out, 0); } for (const object::BasicSymbolRef &S : Obj.symbols()) { uint32_t Symflags = S.getFlags(); if (Symflags & object::SymbolRef::SF_FormatSpecific) continue; if (!(Symflags & object::SymbolRef::SF_Global)) continue; if (Symflags & object::SymbolRef::SF_Undefined) continue; failIfError(S.printName(NameOS)); NameOS << '\0'; ++NumSyms; MemberOffsetRefs.push_back(std::make_pair(Out.tell(), MemberNum)); print32BE(Out, 0); } MemberBuffer.reset(Obj.releaseBuffer()); } Out << NameOS.str(); if (StartOffset == 0) return; if (Out.tell() % 2) Out << '\0'; unsigned Pos = Out.tell(); Out.seek(StartOffset - 12); printWithSpacePadding(Out, Pos - StartOffset, 10); Out.seek(StartOffset); print32BE(Out, NumSyms); Out.seek(Pos); }
// Write one member out to the file. bool Archive::writeMember( const ArchiveMember& member, raw_fd_ostream& ARFile, std::string* ErrMsg ) { uint64_t filepos = ARFile.tell(); filepos -= 8; // Get the data and its size either from the // member's in-memory data or directly from the file. size_t fSize = member.getSize(); const char *data = (const char*)member.getData(); MemoryBuffer *mFile = 0; if (!data) { ErrorOr<std::unique_ptr<MemoryBuffer> > FileOrErr = MemoryBuffer::getFile(member.getPath()); if (!FileOrErr) { if (ErrMsg) *ErrMsg = FileOrErr.getError().message(); return true; } mFile = FileOrErr.get().release(); data = mFile->getBufferStart(); fSize = mFile->getBufferSize(); } int hdrSize = fSize; // Compute the fields of the header ArchiveMemberHeader Hdr; bool writeLongName = fillHeader(member,Hdr,hdrSize); // Write header to archive file ARFile.write((char*)&Hdr, sizeof(Hdr)); // Write the long filename if its long if (writeLongName) { StringRef Name = sys::path::filename(member.getPath()); ARFile.write(Name.data(), Name.size()); } // Write the (possibly compressed) member's content to the file. ARFile.write(data,fSize); // Make sure the member is an even length if ((ARFile.tell() & 1) == 1) ARFile << ARFILE_PAD; // Close the mapped file if it was opened delete mFile; return false; }
static void printWithSpacePadding(raw_fd_ostream &OS, T Data, unsigned Size, bool MayTruncate = false) { uint64_t OldPos = OS.tell(); OS << Data; unsigned SizeSoFar = OS.tell() - OldPos; if (Size > SizeSoFar) { OS.indent(Size - SizeSoFar); } else if (Size < SizeSoFar) { assert(MayTruncate && "Data doesn't fit in Size"); // Some of the data this is used for (like UID) can be larger than the // space available in the archive format. Truncate in that case. OS.seek(OldPos + Size); } }
static void printBSDMemberHeader(raw_fd_ostream &Out, StringRef Name, const sys::TimeValue &ModTime, unsigned UID, unsigned GID, unsigned Perms, unsigned Size) { uint64_t PosAfterHeader = Out.tell() + 60 + Name.size(); // Pad so that even 64 bit object files are aligned. unsigned Pad = OffsetToAlignment(PosAfterHeader, 8); unsigned NameWithPadding = Name.size() + Pad; printWithSpacePadding(Out, Twine("#1/") + Twine(NameWithPadding), 16); printRestOfMemberHeader(Out, ModTime, UID, GID, Perms, NameWithPadding + Size); Out << Name; assert(PosAfterHeader == Out.tell()); while (Pad--) Out.write(uint8_t(0)); }
// Returns the offset of the first reference to a member offset. static ErrorOr<unsigned> writeSymbolTable(raw_fd_ostream &Out, object::Archive::Kind Kind, ArrayRef<NewArchiveMember> Members, std::vector<unsigned> &MemberOffsetRefs, bool Deterministic) { unsigned HeaderStartOffset = 0; unsigned BodyStartOffset = 0; SmallString<128> NameBuf; raw_svector_ostream NameOS(NameBuf); LLVMContext Context; for (unsigned MemberNum = 0, N = Members.size(); MemberNum < N; ++MemberNum) { MemoryBufferRef MemberBuffer = Members[MemberNum].Buf->getMemBufferRef(); Expected<std::unique_ptr<object::SymbolicFile>> ObjOrErr = object::SymbolicFile::createSymbolicFile( MemberBuffer, sys::fs::file_magic::unknown, &Context); if (!ObjOrErr) { // FIXME: check only for "not an object file" errors. consumeError(ObjOrErr.takeError()); continue; } object::SymbolicFile &Obj = *ObjOrErr.get(); if (!HeaderStartOffset) { HeaderStartOffset = Out.tell(); if (Kind == object::Archive::K_GNU) printGNUSmallMemberHeader(Out, "", now(Deterministic), 0, 0, 0, 0); else printBSDMemberHeader(Out, "__.SYMDEF", now(Deterministic), 0, 0, 0, 0); BodyStartOffset = Out.tell(); print32(Out, Kind, 0); // number of entries or bytes } for (const object::BasicSymbolRef &S : Obj.symbols()) { uint32_t Symflags = S.getFlags(); if (Symflags & object::SymbolRef::SF_FormatSpecific) continue; if (!(Symflags & object::SymbolRef::SF_Global)) continue; if (Symflags & object::SymbolRef::SF_Undefined) continue; unsigned NameOffset = NameOS.tell(); if (auto EC = S.printName(NameOS)) return EC; NameOS << '\0'; MemberOffsetRefs.push_back(MemberNum); if (Kind == object::Archive::K_BSD) print32(Out, Kind, NameOffset); print32(Out, Kind, 0); // member offset } } if (HeaderStartOffset == 0) return 0; StringRef StringTable = NameOS.str(); if (Kind == object::Archive::K_BSD) print32(Out, Kind, StringTable.size()); // byte count of the string table Out << StringTable; // ld64 requires the next member header to start at an offset that is // 4 bytes aligned. unsigned Pad = OffsetToAlignment(Out.tell(), 4); while (Pad--) Out.write(uint8_t(0)); // Patch up the size of the symbol table now that we know how big it is. unsigned Pos = Out.tell(); const unsigned MemberHeaderSize = 60; Out.seek(HeaderStartOffset + 48); // offset of the size field. printWithSpacePadding(Out, Pos - MemberHeaderSize - HeaderStartOffset, 10); // Patch up the number of symbols. Out.seek(BodyStartOffset); unsigned NumSyms = MemberOffsetRefs.size(); if (Kind == object::Archive::K_GNU) print32(Out, Kind, NumSyms); else print32(Out, Kind, NumSyms * 8); Out.seek(Pos); return BodyStartOffset + 4; }
static void writeSymbolTable( raw_fd_ostream &Out, ArrayRef<NewArchiveIterator> Members, std::vector<std::pair<unsigned, unsigned> > &MemberOffsetRefs) { unsigned StartOffset = 0; unsigned MemberNum = 0; std::vector<StringRef> SymNames; std::vector<object::ObjectFile *> DeleteIt; for (ArrayRef<NewArchiveIterator>::iterator I = Members.begin(), E = Members.end(); I != E; ++I, ++MemberNum) { object::ObjectFile *Obj; if (I->isNewMember()) { const char *Filename = I->getNew(); Obj = object::ObjectFile::createObjectFile(Filename); } else { object::Archive::child_iterator OldMember = I->getOld(); OwningPtr<object::Binary> Binary; error_code EC = OldMember->getAsBinary(Binary); if (EC) { // FIXME: check only for "not an object file" errors. Obj = NULL; } else { Obj = dyn_cast<object::ObjectFile>(Binary.get()); if (Obj) Binary.take(); } } if (!Obj) continue; DeleteIt.push_back(Obj); if (!StartOffset) { printMemberHeader(Out, "", sys::TimeValue::now(), 0, 0, 0, 0); StartOffset = Out.tell(); print32BE(Out, 0); } error_code Err; for (object::symbol_iterator I = Obj->begin_symbols(), E = Obj->end_symbols(); I != E; I.increment(Err), failIfError(Err)) { uint32_t Symflags; failIfError(I->getFlags(Symflags)); if (Symflags & object::SymbolRef::SF_FormatSpecific) continue; if (!(Symflags & object::SymbolRef::SF_Global)) continue; if (Symflags & object::SymbolRef::SF_Undefined) continue; StringRef Name; failIfError(I->getName(Name)); SymNames.push_back(Name); MemberOffsetRefs.push_back(std::make_pair(Out.tell(), MemberNum)); print32BE(Out, 0); } } for (std::vector<StringRef>::iterator I = SymNames.begin(), E = SymNames.end(); I != E; ++I) { Out << *I; Out << '\0'; } for (std::vector<object::ObjectFile *>::iterator I = DeleteIt.begin(), E = DeleteIt.end(); I != E; ++I) { object::ObjectFile *O = *I; delete O; } if (StartOffset == 0) return; if (Out.tell() % 2) Out << '\0'; unsigned Pos = Out.tell(); Out.seek(StartOffset - 12); printWithSpacePadding(Out, Pos - StartOffset, 10); Out.seek(StartOffset); print32BE(Out, SymNames.size()); Out.seek(Pos); }
static void writeSymbolTable( raw_fd_ostream &Out, ArrayRef<NewArchiveIterator> Members, ArrayRef<MemoryBuffer *> Buffers, std::vector<std::pair<unsigned, unsigned> > &MemberOffsetRefs) { unsigned StartOffset = 0; unsigned MemberNum = 0; std::string NameBuf; raw_string_ostream NameOS(NameBuf); unsigned NumSyms = 0; std::vector<object::SymbolicFile *> DeleteIt; LLVMContext &Context = getGlobalContext(); for (ArrayRef<NewArchiveIterator>::iterator I = Members.begin(), E = Members.end(); I != E; ++I, ++MemberNum) { MemoryBuffer *MemberBuffer = Buffers[MemberNum]; ErrorOr<object::SymbolicFile *> ObjOrErr = object::SymbolicFile::createSymbolicFile( MemberBuffer, false, sys::fs::file_magic::unknown, &Context); if (!ObjOrErr) continue; // FIXME: check only for "not an object file" errors. object::SymbolicFile *Obj = ObjOrErr.get(); DeleteIt.push_back(Obj); if (!StartOffset) { printMemberHeader(Out, "", sys::TimeValue::now(), 0, 0, 0, 0); StartOffset = Out.tell(); print32BE(Out, 0); } for (object::basic_symbol_iterator I = Obj->symbol_begin(), E = Obj->symbol_end(); I != E; ++I) { uint32_t Symflags = I->getFlags(); if (Symflags & object::SymbolRef::SF_FormatSpecific) continue; if (!(Symflags & object::SymbolRef::SF_Global)) continue; if (Symflags & object::SymbolRef::SF_Undefined) continue; failIfError(I->printName(NameOS)); NameOS << '\0'; ++NumSyms; MemberOffsetRefs.push_back(std::make_pair(Out.tell(), MemberNum)); print32BE(Out, 0); } } Out << NameOS.str(); for (std::vector<object::SymbolicFile *>::iterator I = DeleteIt.begin(), E = DeleteIt.end(); I != E; ++I) { object::SymbolicFile *O = *I; delete O; } if (StartOffset == 0) return; if (Out.tell() % 2) Out << '\0'; unsigned Pos = Out.tell(); Out.seek(StartOffset - 12); printWithSpacePadding(Out, Pos - StartOffset, 10); Out.seek(StartOffset); print32BE(Out, NumSyms); Out.seek(Pos); }
// Headers in tar files must be aligned to 512 byte boundaries. // This function forwards the current file position to the next boundary. static void pad(raw_fd_ostream &OS) { uint64_t Pos = OS.tell(); OS.seek(alignTo(Pos, BlockSize)); }