From 8d4b4e6f8ad04fce563c186b6472d99dfde4a965 Mon Sep 17 00:00:00 2001 From: Rui Ueyama Date: Sat, 7 Jan 2017 08:28:56 +0000 Subject: [PATCH] TarWriter: Use Ustar header's "prefix" field to store long filenames. Tar's Ustar header has the "prefix" field to store a directory part of a filename. It is not as flexible as the PAX-extended filename because there's still a limitation on the maximum filename size, but it mitigates the situation. This patch should unbreak some Windows buildbots that uses very old tar command. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@291340 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Support/TarWriter.cpp | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/lib/Support/TarWriter.cpp b/lib/Support/TarWriter.cpp index 5fc17d27637..5e45b36771f 100644 --- a/lib/Support/TarWriter.cpp +++ b/lib/Support/TarWriter.cpp @@ -109,14 +109,40 @@ static void writePaxHeader(raw_fd_ostream &OS, StringRef Path) { pad(OS); } +// In the Ustar header, a path can be split at any '/' to store +// a path into UstarHeader::Name and UstarHeader::Prefix. This +// function splits a given path for that purpose. +static std::pair splitPath(StringRef Path) { + if (Path.size() <= sizeof(UstarHeader::Name)) + return {"", Path}; + size_t Sep = Path.rfind('/', sizeof(UstarHeader::Name) + 1); + if (Sep == StringRef::npos) + return {"", Path}; + return {Path.substr(0, Sep), Path.substr(Sep + 1)}; +} + +// Returns true if a given path can be stored to a Ustar header +// without the PAX extension. +static bool fitInUstar(StringRef Path) { + StringRef Prefix; + StringRef Name; + std::tie(Prefix, Name) = splitPath(Path); + return Name.size() <= sizeof(UstarHeader::Name); +} + // The PAX header is an extended format, so a PAX header needs // to be followed by a "real" header. static void writeUstarHeader(raw_fd_ostream &OS, StringRef Path, size_t Size) { + StringRef Prefix; + StringRef Name; + std::tie(Prefix, Name) = splitPath(Path); + UstarHeader Hdr = {}; - memcpy(Hdr.Name, Path.data(), Path.size()); + memcpy(Hdr.Name, Name.data(), Name.size()); memcpy(Hdr.Mode, "0000664", 8); snprintf(Hdr.Size, sizeof(Hdr.Size), "%011zo", Size); memcpy(Hdr.Magic, "ustar", 6); + memcpy(Hdr.Prefix, Prefix.data(), Prefix.size()); computeChecksum(Hdr); OS << StringRef(reinterpret_cast(&Hdr), sizeof(Hdr)); } -- 2.50.1