1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <stdlib.h>
18 
19 #include "test/Test.h"
20 
21 namespace aapt {
22 
23 using ArchiveTest = TestDirectoryFixture;
24 
25 constexpr size_t kTestDataLength = 100;
26 
27 class TestData : public io::MallocData {
28  public:
TestData(std::unique_ptr<uint8_t[]> & data,size_t size)29   TestData(std::unique_ptr<uint8_t[]>& data, size_t size)
30       : MallocData(std::move(data), size) {}
31 
HadError() const32   bool HadError() const override { return !error_.empty(); }
33 
GetError() const34   std::string GetError() const override { return error_; }
35 
36   std::string error_;
37 };
38 
39 class TzSetter {
40  public:
TzSetter(const std::string & new_tz)41   explicit TzSetter(const std::string& new_tz) {
42     old_tz_ = getenv("TZ");
43     new_tz_ = "TZ=" + new_tz;
44     putenv(const_cast<char*>(new_tz_.c_str()));
45     tzset();
46   }
47 
~TzSetter()48   ~TzSetter() {
49     if (old_tz_) {
50       putenv(old_tz_);
51     } else {
52       putenv(const_cast<char*>("TZ"));
53     }
54     tzset();
55   }
56 
57  private:
58   char* old_tz_;
59   std::string new_tz_;
60 };
61 
MakeTestArray()62 std::unique_ptr<uint8_t[]> MakeTestArray() {
63   auto array = std::make_unique<uint8_t[]>(kTestDataLength);
64   for (int index = 0; index < kTestDataLength; ++index) {
65     array[index] = static_cast<uint8_t>(rand());
66   }
67   return array;
68 }
69 
MakeDirectoryWriter(const std::string & output_path)70 std::unique_ptr<IArchiveWriter> MakeDirectoryWriter(const std::string& output_path) {
71   file::mkdirs(output_path);
72 
73   StdErrDiagnostics diag;
74   return CreateDirectoryArchiveWriter(&diag, output_path);
75 }
76 
MakeZipFileWriter(const std::string & output_path)77 std::unique_ptr<IArchiveWriter> MakeZipFileWriter(const std::string& output_path) {
78   file::mkdirs(std::string(file::GetStem(output_path)));
79   std::remove(output_path.c_str());
80 
81   StdErrDiagnostics diag;
82   return CreateZipFileArchiveWriter(&diag, output_path);
83 }
84 
VerifyDirectory(const std::string & path,const std::string & file,const uint8_t array[])85 void VerifyDirectory(const std::string& path, const std::string& file, const uint8_t array[]) {
86   std::string file_path = file::BuildPath({path, file});
87   auto buffer = std::make_unique<char[]>(kTestDataLength);
88   std::ifstream stream(file_path);
89   stream.read(buffer.get(), kTestDataLength);
90 
91   for (int index = 0; index < kTestDataLength; ++index) {
92     ASSERT_EQ(array[index], static_cast<uint8_t>(buffer[index]));
93   }
94 }
95 
VerifyZipFile(const std::string & output_path,const std::string & file,const uint8_t array[])96 void VerifyZipFile(const std::string& output_path, const std::string& file, const uint8_t array[]) {
97   std::unique_ptr<io::ZipFileCollection> zip = io::ZipFileCollection::Create(output_path, nullptr);
98   std::unique_ptr<android::InputStream> stream = zip->FindFile(file)->OpenInputStream();
99 
100   std::vector<uint8_t> buffer;
101   const void* data;
102   size_t size;
103 
104   while (stream->Next(&data, &size)) {
105     auto pointer = static_cast<const uint8_t*>(data);
106     buffer.insert(buffer.end(), pointer, pointer + size);
107   }
108 
109   for (int index = 0; index < kTestDataLength; ++index) {
110     ASSERT_EQ(array[index], buffer[index]);
111   }
112 }
113 
VerifyZipFileTimestamps(const std::string & output_path)114 void VerifyZipFileTimestamps(const std::string& output_path) {
115   std::unique_ptr<io::ZipFileCollection> zip = io::ZipFileCollection::Create(output_path, nullptr);
116   auto it = zip->Iterator();
117   while (it->HasNext()) {
118     auto file = it->Next();
119     struct tm modification_time;
120     ASSERT_TRUE(file->GetModificationTime(&modification_time));
121     EXPECT_EQ(modification_time.tm_year, 80);
122     EXPECT_EQ(modification_time.tm_mon, 0);
123     EXPECT_EQ(modification_time.tm_mday, 1);
124     EXPECT_EQ(modification_time.tm_hour, 0);
125     EXPECT_EQ(modification_time.tm_min, 0);
126     EXPECT_EQ(modification_time.tm_sec, 0);
127   }
128 }
129 
TEST_F(ArchiveTest,DirectoryWriteEntrySuccess)130 TEST_F(ArchiveTest, DirectoryWriteEntrySuccess) {
131   std::string output_path = GetTestPath("output");
132   std::unique_ptr<IArchiveWriter> writer = MakeDirectoryWriter(output_path);
133   std::unique_ptr<uint8_t[]> data1 = MakeTestArray();
134   std::unique_ptr<uint8_t[]> data2 = MakeTestArray();
135 
136   ASSERT_TRUE(writer->StartEntry("test1", 0));
137   ASSERT_TRUE(writer->Write(static_cast<const void*>(data1.get()), kTestDataLength));
138   ASSERT_TRUE(writer->FinishEntry());
139   ASSERT_FALSE(writer->HadError());
140 
141   ASSERT_TRUE(writer->StartEntry("test2", 0));
142   ASSERT_TRUE(writer->Write(static_cast<const void*>(data2.get()), kTestDataLength));
143   ASSERT_TRUE(writer->FinishEntry());
144   ASSERT_FALSE(writer->HadError());
145 
146   writer.reset();
147 
148   VerifyDirectory(output_path, "test1", data1.get());
149   VerifyDirectory(output_path, "test2", data2.get());
150 }
151 
TEST_F(ArchiveTest,DirectoryWriteFileSuccess)152 TEST_F(ArchiveTest, DirectoryWriteFileSuccess) {
153   std::string output_path = GetTestPath("output");
154   std::unique_ptr<IArchiveWriter> writer = MakeDirectoryWriter(output_path);
155 
156   std::unique_ptr<uint8_t[]> data1 = MakeTestArray();
157   auto data1_copy = std::make_unique<uint8_t[]>(kTestDataLength);
158   std::copy(data1.get(), data1.get() + kTestDataLength, data1_copy.get());
159 
160   std::unique_ptr<uint8_t[]> data2 = MakeTestArray();
161   auto data2_copy = std::make_unique<uint8_t[]>(kTestDataLength);
162   std::copy(data2.get(), data2.get() + kTestDataLength, data2_copy.get());
163 
164   auto input1 = std::make_unique<TestData>(data1_copy, kTestDataLength);
165   auto input2 = std::make_unique<TestData>(data2_copy, kTestDataLength);
166 
167   ASSERT_TRUE(writer->WriteFile("test1", 0, input1.get()));
168   ASSERT_FALSE(writer->HadError());
169   ASSERT_TRUE(writer->WriteFile("test2", 0, input2.get()));
170   ASSERT_FALSE(writer->HadError());
171 
172   writer.reset();
173 
174   VerifyDirectory(output_path, "test1", data1.get());
175   VerifyDirectory(output_path, "test2", data2.get());
176 }
177 
TEST_F(ArchiveTest,DirectoryWriteFileError)178 TEST_F(ArchiveTest, DirectoryWriteFileError) {
179   std::string output_path = GetTestPath("output");
180   std::unique_ptr<IArchiveWriter> writer = MakeDirectoryWriter(output_path);
181   std::unique_ptr<uint8_t[]> data = MakeTestArray();
182   auto input = std::make_unique<TestData>(data, kTestDataLength);
183   input->error_ = "DirectoryWriteFileError";
184 
185   ASSERT_FALSE(writer->WriteFile("test", 0, input.get()));
186   ASSERT_TRUE(writer->HadError());
187   ASSERT_EQ("DirectoryWriteFileError", writer->GetError());
188 }
189 
TEST_F(ArchiveTest,ZipFileWriteEntrySuccess)190 TEST_F(ArchiveTest, ZipFileWriteEntrySuccess) {
191   std::string output_path = GetTestPath("output.apk");
192   std::unique_ptr<IArchiveWriter> writer = MakeZipFileWriter(output_path);
193   std::unique_ptr<uint8_t[]> data1 = MakeTestArray();
194   std::unique_ptr<uint8_t[]> data2 = MakeTestArray();
195 
196   ASSERT_TRUE(writer->StartEntry("test1", 0));
197   ASSERT_TRUE(writer->Write(static_cast<const void*>(data1.get()), kTestDataLength));
198   ASSERT_TRUE(writer->FinishEntry());
199   ASSERT_FALSE(writer->HadError());
200 
201   ASSERT_TRUE(writer->StartEntry("test2", 0));
202   ASSERT_TRUE(writer->Write(static_cast<const void*>(data2.get()), kTestDataLength));
203   ASSERT_TRUE(writer->FinishEntry());
204   ASSERT_FALSE(writer->HadError());
205 
206   writer.reset();
207 
208   VerifyZipFile(output_path, "test1", data1.get());
209   VerifyZipFile(output_path, "test2", data2.get());
210 }
211 
TEST_F(ArchiveTest,ZipFileWriteFileSuccess)212 TEST_F(ArchiveTest, ZipFileWriteFileSuccess) {
213   std::string output_path = GetTestPath("output.apk");
214   std::unique_ptr<IArchiveWriter> writer = MakeZipFileWriter(output_path);
215 
216   std::unique_ptr<uint8_t[]> data1 = MakeTestArray();
217   auto data1_copy = std::make_unique<uint8_t[]>(kTestDataLength);
218   std::copy(data1.get(), data1.get() + kTestDataLength, data1_copy.get());
219 
220   std::unique_ptr<uint8_t[]> data2 = MakeTestArray();
221   auto data2_copy = std::make_unique<uint8_t[]>(kTestDataLength);
222   std::copy(data2.get(), data2.get() + kTestDataLength, data2_copy.get());
223 
224   auto input1 = std::make_unique<TestData>(data1_copy, kTestDataLength);
225   auto input2 = std::make_unique<TestData>(data2_copy, kTestDataLength);
226 
227   ASSERT_TRUE(writer->WriteFile("test1", 0, input1.get()));
228   ASSERT_FALSE(writer->HadError());
229   ASSERT_TRUE(writer->WriteFile("test2", 0, input2.get()));
230   ASSERT_FALSE(writer->HadError());
231 
232   writer.reset();
233 
234   VerifyZipFile(output_path, "test1", data1.get());
235   VerifyZipFile(output_path, "test2", data2.get());
236 }
237 
TEST_F(ArchiveTest,ZipFileWriteFileError)238 TEST_F(ArchiveTest, ZipFileWriteFileError) {
239   std::string output_path = GetTestPath("output.apk");
240   std::unique_ptr<IArchiveWriter> writer = MakeZipFileWriter(output_path);
241   std::unique_ptr<uint8_t[]> data = MakeTestArray();
242   auto input = std::make_unique<TestData>(data, kTestDataLength);
243   input->error_ = "ZipFileWriteFileError";
244 
245   ASSERT_FALSE(writer->WriteFile("test", 0, input.get()));
246   ASSERT_TRUE(writer->HadError());
247   ASSERT_EQ("ZipFileWriteFileError", writer->GetError());
248 }
249 
TEST_F(ArchiveTest,ZipFileTimeZoneUTC)250 TEST_F(ArchiveTest, ZipFileTimeZoneUTC) {
251   TzSetter tz("UTC0");
252   std::string output_path = GetTestPath("output.apk");
253   std::unique_ptr<IArchiveWriter> writer = MakeZipFileWriter(output_path);
254   std::unique_ptr<uint8_t[]> data1 = MakeTestArray();
255   std::unique_ptr<uint8_t[]> data2 = MakeTestArray();
256 
257   ASSERT_TRUE(writer->StartEntry("test1", 0));
258   ASSERT_TRUE(writer->Write(static_cast<const void*>(data1.get()), kTestDataLength));
259   ASSERT_TRUE(writer->FinishEntry());
260   ASSERT_FALSE(writer->HadError());
261 
262   ASSERT_TRUE(writer->StartEntry("test2", 0));
263   ASSERT_TRUE(writer->Write(static_cast<const void*>(data2.get()), kTestDataLength));
264   ASSERT_TRUE(writer->FinishEntry());
265   ASSERT_FALSE(writer->HadError());
266 
267   writer.reset();
268 
269   // All zip file entries must have the same timestamp, regardless of time zone. See: b/277978832
270   VerifyZipFileTimestamps(output_path);
271 }
272 
TEST_F(ArchiveTest,ZipFileTimeZoneWestOfUTC)273 TEST_F(ArchiveTest, ZipFileTimeZoneWestOfUTC) {
274   TzSetter tz("PST8");
275   std::string output_path = GetTestPath("output.apk");
276   std::unique_ptr<IArchiveWriter> writer = MakeZipFileWriter(output_path);
277   std::unique_ptr<uint8_t[]> data1 = MakeTestArray();
278   std::unique_ptr<uint8_t[]> data2 = MakeTestArray();
279 
280   ASSERT_TRUE(writer->StartEntry("test1", 0));
281   ASSERT_TRUE(writer->Write(static_cast<const void*>(data1.get()), kTestDataLength));
282   ASSERT_TRUE(writer->FinishEntry());
283   ASSERT_FALSE(writer->HadError());
284 
285   ASSERT_TRUE(writer->StartEntry("test2", 0));
286   ASSERT_TRUE(writer->Write(static_cast<const void*>(data2.get()), kTestDataLength));
287   ASSERT_TRUE(writer->FinishEntry());
288   ASSERT_FALSE(writer->HadError());
289 
290   writer.reset();
291 
292   // All zip file entries must have the same timestamp, regardless of time zone. See: b/277978832
293   VerifyZipFileTimestamps(output_path);
294 }
295 
TEST_F(ArchiveTest,ZipFileTimeZoneEastOfUTC)296 TEST_F(ArchiveTest, ZipFileTimeZoneEastOfUTC) {
297   TzSetter tz("EET-2");
298   std::string output_path = GetTestPath("output.apk");
299   std::unique_ptr<IArchiveWriter> writer = MakeZipFileWriter(output_path);
300   std::unique_ptr<uint8_t[]> data1 = MakeTestArray();
301   std::unique_ptr<uint8_t[]> data2 = MakeTestArray();
302 
303   ASSERT_TRUE(writer->StartEntry("test1", 0));
304   ASSERT_TRUE(writer->Write(static_cast<const void*>(data1.get()), kTestDataLength));
305   ASSERT_TRUE(writer->FinishEntry());
306   ASSERT_FALSE(writer->HadError());
307 
308   ASSERT_TRUE(writer->StartEntry("test2", 0));
309   ASSERT_TRUE(writer->Write(static_cast<const void*>(data2.get()), kTestDataLength));
310   ASSERT_TRUE(writer->FinishEntry());
311   ASSERT_FALSE(writer->HadError());
312 
313   writer.reset();
314 
315   // All zip file entries must have the same timestamp, regardless of time zone. See: b/277978832
316   VerifyZipFileTimestamps(output_path);
317 }
318 
319 }  // namespace aapt
320