llvm.org GIT mirror llvm / 8f777ee
[llvm-ar][libObject] Fix relative paths when nesting thin archives. Summary: When adding one thin archive to another, we currently chop off the relative path to the flattened members. For instance, when adding `foo/child.a` (which contains `x.txt`) to `parent.a`, when flattening it we should add it as `foo/x.txt` (which exists) instead of `x.txt` (which does not exist). As a note, this also undoes the `IsNew` parameter of handling relative paths in r288280. The unit test there still passes. This was reported as part of testing the kernel build with llvm-ar: https://patchwork.kernel.org/patch/10767545/ (see the second point). Reviewers: mstorsjo, pcc, ruiu, davide, david2050 Subscribers: hiraditya, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D57842 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@353424 91177308-0d34-0410-b5e6-96231b3b80d8 Jordan Rupprecht 6 months ago
5 changed file(s) with 79 addition(s) and 67 deletion(s). Raw diff Collapse all Expand all
2525 sys::TimePoint ModTime;
2626 unsigned UID = 0, GID = 0, Perms = 0644;
2727
28 bool IsNew = false;
2928 NewArchiveMember() = default;
3029 NewArchiveMember(MemoryBufferRef BufRef);
3130
4747 return BufOrErr.takeError();
4848
4949 NewArchiveMember M;
50 assert(M.IsNew == false);
5150 M.Buf = MemoryBuffer::getMemBuffer(*BufOrErr, false);
5251 M.MemberName = M.Buf->getBufferIdentifier();
5352 if (!Deterministic) {
9796 return errorCodeToError(std::error_code(errno, std::generic_category()));
9897
9998 NewArchiveMember M;
100 M.IsNew = true;
10199 M.Buf = std::move(*MemberBufferOrErr);
102100 M.MemberName = M.Buf->getBufferIdentifier();
103101 if (!Deterministic) {
190188 return Thin || Name.size() >= 16 || Name.contains('/');
191189 }
192190
193 // Compute the relative path from From to To.
194 static std::string computeRelativePath(StringRef From, StringRef To) {
195 if (sys::path::is_absolute(From) || sys::path::is_absolute(To))
196 return To;
197
198 StringRef DirFrom = sys::path::parent_path(From);
199 auto FromI = sys::path::begin(DirFrom);
200 auto ToI = sys::path::begin(To);
201 while (*FromI == *ToI) {
202 ++FromI;
203 ++ToI;
204 }
205
206 SmallString<128> Relative;
207 for (auto FromE = sys::path::end(DirFrom); FromI != FromE; ++FromI)
208 sys::path::append(Relative, "..");
209
210 for (auto ToE = sys::path::end(To); ToI != ToE; ++ToI)
211 sys::path::append(Relative, *ToI);
212
213 #ifdef _WIN32
214 // Replace backslashes with slashes so that the path is portable between *nix
215 // and Windows.
216 std::replace(Relative.begin(), Relative.end(), '\\', '/');
217 #endif
218
219 return Relative.str();
220 }
221
222191 static bool is64BitKind(object::Archive::Kind Kind) {
223192 switch (Kind) {
224193 case object::Archive::K_GNU:
233202 llvm_unreachable("not supported for writting");
234203 }
235204
236 static void addToStringTable(raw_ostream &Out, StringRef ArcName,
237 const NewArchiveMember &M, bool Thin) {
238 StringRef ID = M.Buf->getBufferIdentifier();
239 if (Thin) {
240 if (M.IsNew)
241 Out << computeRelativePath(ArcName, ID);
242 else
243 Out << ID;
244 } else
245 Out << M.MemberName;
246 Out << "/\n";
247 }
248
249 static void printMemberHeader(raw_ostream &Out, uint64_t Pos,
250 raw_ostream &StringTable,
251 StringMap &MemberNames,
252 object::Archive::Kind Kind, bool Thin,
253 StringRef ArcName, const NewArchiveMember &M,
254 sys::TimePoint ModTime,
255 unsigned Size) {
256
205 static void
206 printMemberHeader(raw_ostream &Out, uint64_t Pos, raw_ostream &StringTable,
207 StringMap &MemberNames, object::Archive::Kind Kind,
208 bool Thin, const NewArchiveMember &M,
209 sys::TimePoint ModTime, unsigned Size) {
257210 if (isBSDLike(Kind))
258211 return printBSDMemberHeader(Out, Pos, M.MemberName, ModTime, M.UID, M.GID,
259212 M.Perms, Size);
264217 uint64_t NamePos;
265218 if (Thin) {
266219 NamePos = StringTable.tell();
267 addToStringTable(StringTable, ArcName, M, Thin);
220 StringTable << M.MemberName << "/\n";
268221 } else {
269222 auto Insertion = MemberNames.insert({M.MemberName, uint64_t(0)});
270223 if (Insertion.second) {
271224 Insertion.first->second = StringTable.tell();
272 addToStringTable(StringTable, ArcName, M, Thin);
225 StringTable << M.MemberName << "/\n";
273226 }
274227 NamePos = Insertion.first->second;
275228 }
431384
432385 static Expected>
433386 computeMemberData(raw_ostream &StringTable, raw_ostream &SymNames,
434 object::Archive::Kind Kind, bool Thin, StringRef ArcName,
435 bool Deterministic, ArrayRef NewMembers) {
387 object::Archive::Kind Kind, bool Thin, bool Deterministic,
388 ArrayRef NewMembers) {
436389 static char PaddingData[8] = {'\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n'};
437390
438391 // This ignores the symbol table, but we only need the value mod 8 and the
519472 ModTime = sys::toTimePoint(FilenameCount[M.MemberName]++);
520473 else
521474 ModTime = M.ModTime;
522 printMemberHeader(Out, Pos, StringTable, MemberNames, Kind, Thin, ArcName,
523 M, ModTime, Buf.getBufferSize() + MemberPadding);
475 printMemberHeader(Out, Pos, StringTable, MemberNames, Kind, Thin, M,
476 ModTime, Buf.getBufferSize() + MemberPadding);
524477 Out.flush();
525478
526479 Expected> Symbols =
552505 raw_svector_ostream StringTable(StringTableBuf);
553506
554507 Expected> DataOrErr = computeMemberData(
555 StringTable, SymNames, Kind, Thin, ArcName, Deterministic, NewMembers);
508 StringTable, SymNames, Kind, Thin, Deterministic, NewMembers);
556509 if (Error E = DataOrErr.takeError())
557510 return E;
558511 std::vector &Data = *DataOrErr;
0 # This test creates a thin archive in a directory and adds it to a thin archive
1 # in the parent directory. The relative path should be included when flattening
2 # the archive.
3
4 RUN: mkdir -p %t/foo
5 RUN: touch %t/foo/a.txt
6 RUN: rm -f %t/archive.a %t/foo/archive.a
7
8 # These tests must be run in the same directory as %t/archive.a. cd %t is
9 # included on each line to make debugging this test case easier.
10 RUN: cd %t && llvm-ar rcST foo/archive.a foo/a.txt
11 RUN: cd %t && llvm-ar rcST archive.a foo/archive.a
12 RUN: cd %t && llvm-ar t archive.a | FileCheck %s --match-full-lines
13
14 CHECK: foo/a.txt
55 # flattened members appearing together.
66
77 RUN: touch %t-a.txt %t-b.txt %t-c.txt %t-d.txt %t-e.txt
8 RUN: rm -f %t-a-plus-b.a %t.a
8 RUN: rm -f %t-a-plus-b.a %t-d-plus-e.a %t.a
99 RUN: llvm-ar rcsT %t-a-plus-b.a %t-a.txt %t-b.txt
1010 RUN: llvm-ar rcs %t-d-plus-e.a %t-d.txt %t-e.txt
1111 RUN: llvm-ar rcsT %t.a %t-a-plus-b.a %t-c.txt %t-d-plus-e.a
191191 // This variable holds the list of member files to proecess, as given
192192 // on the command line.
193193 static std::vector Members;
194
195 // Static buffer to hold StringRefs.
196 static BumpPtrAllocator Alloc;
194197
195198 // Extract the member filename from the command line for the [relpos] argument
196199 // associated with a, b, and i modifiers
536539 exit(1);
537540 }
538541
542 // Compute the relative path from From to To.
543 static std::string computeRelativePath(StringRef From, StringRef To) {
544 if (sys::path::is_absolute(From) || sys::path::is_absolute(To))
545 return To;
546
547 StringRef DirFrom = sys::path::parent_path(From);
548 auto FromI = sys::path::begin(DirFrom);
549 auto ToI = sys::path::begin(To);
550 while (*FromI == *ToI) {
551 ++FromI;
552 ++ToI;
553 }
554
555 SmallString<128> Relative;
556 for (auto FromE = sys::path::end(DirFrom); FromI != FromE; ++FromI)
557 sys::path::append(Relative, "..");
558
559 for (auto ToE = sys::path::end(To); ToI != ToE; ++ToI)
560 sys::path::append(Relative, *ToI);
561
562 #ifdef _WIN32
563 // Replace backslashes with slashes so that the path is portable between *nix
564 // and Windows.
565 std::replace(Relative.begin(), Relative.end(), '\\', '/');
566 #endif
567
568 return Relative.str();
569 }
570
539571 static void addChildMember(std::vector &Members,
540572 const object::Archive::Child &M,
541573 bool FlattenArchive = false) {
544576 Expected NMOrErr =
545577 NewArchiveMember::getOldMember(M, Deterministic);
546578 failIfError(NMOrErr.takeError());
579 // If the child member we're trying to add is thin, use the path relative to
580 // the archive it's in, so the file resolves correctly.
581 if (Thin && FlattenArchive) {
582 StringSaver Saver(Alloc);
583 Expected FileNameOrErr = M.getFullName();
584 failIfError(FileNameOrErr.takeError());
585 NMOrErr->MemberName =
586 Saver.save(computeRelativePath(ArchiveName, *FileNameOrErr));
587 }
547588 if (FlattenArchive &&
548589 identify_magic(NMOrErr->Buf->getBuffer()) == file_magic::archive) {
549590 Expected FileNameOrErr = M.getFullName();
567608 Expected NMOrErr =
568609 NewArchiveMember::getFile(FileName, Deterministic);
569610 failIfError(NMOrErr.takeError(), FileName);
611 StringSaver Saver(Alloc);
612 // For regular archives, use the basename of the object path for the member
613 // name. For thin archives, use the full relative paths so the file resolves
614 // correctly.
615 NMOrErr->MemberName =
616 Thin ? Saver.save(computeRelativePath(ArchiveName, FileName))
617 : sys::path::filename(NMOrErr->MemberName);
570618 if (FlattenArchive &&
571619 identify_magic(NMOrErr->Buf->getBuffer()) == file_magic::archive) {
572620 object::Archive &Lib = readLibrary(FileName);
580628 return;
581629 }
582630 }
583 // Use the basename of the object path for the member name.
584 NMOrErr->MemberName = sys::path::filename(NMOrErr->MemberName);
585631 Members.push_back(std::move(*NMOrErr));
586632 }
587633
671717 computeInsertAction(Operation, Child, Name, MemberI);
672718 switch (Action) {
673719 case IA_AddOldMember:
674 addChildMember(Ret, Child);
720 addChildMember(Ret, Child, /*FlattenArchive=*/Thin);
675721 break;
676722 case IA_AddNewMember:
677723 addMember(Ret, *MemberI);
679725 case IA_Delete:
680726 break;
681727 case IA_MoveOldMember:
682 addChildMember(Moved, Child);
728 addChildMember(Moved, Child, /*FlattenArchive=*/Thin);
683729 break;
684730 case IA_MoveNewMember:
685731 addMember(Moved, *MemberI);
898944 {
899945 Error Err = Error::success();
900946 for (auto &Member : Lib.children(Err))
901 addChildMember(NewMembers, Member);
947 addChildMember(NewMembers, Member, /*FlattenArchive=*/Thin);
902948 failIfError(std::move(Err));
903949 }
904950 break;
950996
951997 static int ar_main(int argc, char **argv) {
952998 SmallVector Argv(argv, argv + argc);
953 BumpPtrAllocator Alloc;
954999 StringSaver Saver(Alloc);
9551000 cl::ExpandResponseFiles(Saver, cl::TokenizeGNUCommandLine, Argv);
9561001 for (size_t i = 1; i < Argv.size(); ++i) {