1 | //===- llvm/unittest/Support/TarWriterTest.cpp ----------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "llvm/Support/TarWriter.h" |
10 | #include "llvm/Support/FileSystem.h" |
11 | #include "llvm/Support/MemoryBuffer.h" |
12 | #include "llvm/Testing/Support/SupportHelpers.h" |
13 | #include "gtest/gtest.h" |
14 | #include <vector> |
15 | |
16 | using namespace llvm; |
17 | using llvm::unittest::TempFile; |
18 | |
19 | namespace { |
20 | |
21 | struct { |
22 | char [100]; |
23 | char [8]; |
24 | char [8]; |
25 | char [8]; |
26 | char [12]; |
27 | char [12]; |
28 | char [8]; |
29 | char ; |
30 | char [100]; |
31 | char [6]; |
32 | char [2]; |
33 | char [32]; |
34 | char [32]; |
35 | char [8]; |
36 | char [8]; |
37 | char [155]; |
38 | char [12]; |
39 | }; |
40 | |
41 | class TarWriterTest : public ::testing::Test {}; |
42 | |
43 | static std::vector<uint8_t> createTar(StringRef Base, StringRef Filename) { |
44 | TempFile TarWriterTest("TarWriterTest" , "tar" , "" , /*Unique*/ true); |
45 | |
46 | // Create a tar file. |
47 | Expected<std::unique_ptr<TarWriter>> TarOrErr = |
48 | TarWriter::create(OutputPath: TarWriterTest.path(), BaseDir: Base); |
49 | EXPECT_TRUE((bool)TarOrErr); |
50 | std::unique_ptr<TarWriter> Tar = std::move(*TarOrErr); |
51 | Tar->append(Path: Filename, Data: "contents" ); |
52 | Tar.reset(); |
53 | |
54 | // Read the tar file. |
55 | ErrorOr<std::unique_ptr<MemoryBuffer>> MBOrErr = |
56 | MemoryBuffer::getFile(Filename: TarWriterTest.path()); |
57 | EXPECT_TRUE((bool)MBOrErr); |
58 | std::unique_ptr<MemoryBuffer> MB = std::move(*MBOrErr); |
59 | std::vector<uint8_t> Buf((const uint8_t *)MB->getBufferStart(), |
60 | (const uint8_t *)MB->getBufferEnd()); |
61 | |
62 | // Windows does not allow us to remove a mmap'ed files, so |
63 | // unmap first and then remove the temporary file. |
64 | MB = nullptr; |
65 | |
66 | return Buf; |
67 | } |
68 | |
69 | static UstarHeader createUstar(StringRef Base, StringRef Filename) { |
70 | std::vector<uint8_t> Buf = createTar(Base, Filename); |
71 | EXPECT_GE(Buf.size(), sizeof(UstarHeader)); |
72 | return *reinterpret_cast<const UstarHeader *>(Buf.data()); |
73 | } |
74 | |
75 | TEST_F(TarWriterTest, Basics) { |
76 | UstarHeader Hdr = createUstar(Base: "base" , Filename: "file" ); |
77 | EXPECT_EQ("ustar" , StringRef(Hdr.Magic)); |
78 | EXPECT_EQ("00" , StringRef(Hdr.Version, 2)); |
79 | EXPECT_EQ("base/file" , StringRef(Hdr.Name)); |
80 | EXPECT_EQ("00000000010" , StringRef(Hdr.Size)); |
81 | } |
82 | |
83 | TEST_F(TarWriterTest, LongFilename) { |
84 | // The prefix is prefixed by an additional '/' so it's one longer than the |
85 | // number of x's here. |
86 | std::string x136(136, 'x'); |
87 | std::string x137(137, 'x'); |
88 | std::string y99(99, 'y'); |
89 | std::string y100(100, 'y'); |
90 | |
91 | UstarHeader Hdr1 = createUstar(Base: "" , Filename: x136 + "/" + y99); |
92 | EXPECT_EQ("/" + x136, StringRef(Hdr1.Prefix)); |
93 | EXPECT_EQ(y99, StringRef(Hdr1.Name)); |
94 | |
95 | UstarHeader Hdr2 = createUstar(Base: "" , Filename: x137 + "/" + y99); |
96 | EXPECT_EQ("" , StringRef(Hdr2.Prefix)); |
97 | EXPECT_EQ("" , StringRef(Hdr2.Name)); |
98 | |
99 | UstarHeader Hdr3 = createUstar(Base: "" , Filename: x136 + "/" + y100); |
100 | EXPECT_EQ("" , StringRef(Hdr3.Prefix)); |
101 | EXPECT_EQ("" , StringRef(Hdr3.Name)); |
102 | |
103 | UstarHeader Hdr4 = createUstar(Base: "" , Filename: x137 + "/" + y100); |
104 | EXPECT_EQ("" , StringRef(Hdr4.Prefix)); |
105 | EXPECT_EQ("" , StringRef(Hdr4.Name)); |
106 | |
107 | std::string yz = "yyyyyyyyyyyyyyyyyyyy/zzzzzzzzzzzzzzzzzzzz" ; |
108 | UstarHeader Hdr5 = createUstar(Base: "" , Filename: x136 + "/" + yz); |
109 | EXPECT_EQ("/" + x136, StringRef(Hdr5.Prefix)); |
110 | EXPECT_EQ(yz, StringRef(Hdr5.Name)); |
111 | } |
112 | |
113 | TEST_F(TarWriterTest, Pax) { |
114 | std::vector<uint8_t> Buf = createTar(Base: "" , Filename: std::string(200, 'x')); |
115 | EXPECT_GE(Buf.size(), 1024u); |
116 | |
117 | auto *Hdr = reinterpret_cast<const UstarHeader *>(Buf.data()); |
118 | EXPECT_EQ("" , StringRef(Hdr->Prefix)); |
119 | EXPECT_EQ("" , StringRef(Hdr->Name)); |
120 | |
121 | StringRef Pax = StringRef((char *)(Buf.data() + 512), 512); |
122 | EXPECT_TRUE(Pax.starts_with("211 path=/" + std::string(200, 'x'))); |
123 | } |
124 | |
125 | TEST_F(TarWriterTest, SingleFile) { |
126 | TempFile TarWriterTest("TarWriterTest" , "tar" , "" , /*Unique*/ true); |
127 | |
128 | Expected<std::unique_ptr<TarWriter>> TarOrErr = |
129 | TarWriter::create(OutputPath: TarWriterTest.path(), BaseDir: "" ); |
130 | EXPECT_TRUE((bool)TarOrErr); |
131 | std::unique_ptr<TarWriter> Tar = std::move(*TarOrErr); |
132 | Tar->append(Path: "FooPath" , Data: "foo" ); |
133 | Tar.reset(); |
134 | |
135 | uint64_t TarSize; |
136 | std::error_code EC = sys::fs::file_size(Path: TarWriterTest.path(), Result&: TarSize); |
137 | EXPECT_FALSE((bool)EC); |
138 | EXPECT_EQ(TarSize, 2048ULL); |
139 | } |
140 | |
141 | TEST_F(TarWriterTest, NoDuplicate) { |
142 | TempFile TarWriterTest("TarWriterTest" , "tar" , "" , /*Unique*/ true); |
143 | |
144 | Expected<std::unique_ptr<TarWriter>> TarOrErr = |
145 | TarWriter::create(OutputPath: TarWriterTest.path(), BaseDir: "" ); |
146 | EXPECT_TRUE((bool)TarOrErr); |
147 | std::unique_ptr<TarWriter> Tar = std::move(*TarOrErr); |
148 | Tar->append(Path: "FooPath" , Data: "foo" ); |
149 | Tar->append(Path: "BarPath" , Data: "bar" ); |
150 | Tar.reset(); |
151 | |
152 | uint64_t TarSize; |
153 | std::error_code EC = sys::fs::file_size(Path: TarWriterTest.path(), Result&: TarSize); |
154 | EXPECT_FALSE((bool)EC); |
155 | EXPECT_EQ(TarSize, 3072ULL); |
156 | } |
157 | |
158 | TEST_F(TarWriterTest, Duplicate) { |
159 | TempFile TarWriterTest("TarWriterTest" , "tar" , "" , /*Unique*/ true); |
160 | |
161 | Expected<std::unique_ptr<TarWriter>> TarOrErr = |
162 | TarWriter::create(OutputPath: TarWriterTest.path(), BaseDir: "" ); |
163 | EXPECT_TRUE((bool)TarOrErr); |
164 | std::unique_ptr<TarWriter> Tar = std::move(*TarOrErr); |
165 | Tar->append(Path: "FooPath" , Data: "foo" ); |
166 | Tar->append(Path: "FooPath" , Data: "bar" ); |
167 | Tar.reset(); |
168 | |
169 | uint64_t TarSize; |
170 | std::error_code EC = sys::fs::file_size(Path: TarWriterTest.path(), Result&: TarSize); |
171 | EXPECT_FALSE((bool)EC); |
172 | EXPECT_EQ(TarSize, 2048ULL); |
173 | } |
174 | } // namespace |
175 | |