xref: /aosp_15_r20/external/sandboxed-api/contrib/libzip/test/test_zip.cc (revision ec63e07ab9515d95e79c211197c445ef84cefa6a)
1 // Copyright 2022 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include <fstream>
16 
17 #include "contrib/libzip/sandboxed.h"
18 #include "contrib/libzip/utils/utils_zip.h"
19 #include "sandboxed_api/util/path.h"
20 #include "sandboxed_api/util/status_matchers.h"
21 #include "sandboxed_api/util/temp_file.h"
22 
23 namespace {
24 
25 using ::sapi::IsOk;
26 
27 class ZipBase : public testing::Test {
28  protected:
29   std::string GetTestFilePath(const std::string& filename);
30   std::string GetTemporaryFile(const std::string& filename);
31   std::streamsize GetStreamSize(std::ifstream& stream);
32 
33   absl::StatusOr<std::vector<uint8_t>> ReadFile(const std::string& filename);
34 
35   void SetUp() override;
36 
37   const char* test_files_dir_;
38   std::string test_path_zip_;
39 
40   std::unique_ptr<ZipSapiSandbox> sandbox_;
41 };
42 
43 class ZipMultiFiles
44     : public ZipBase,
45       public testing::WithParamInterface<std::pair<uint64_t, std::string>> {};
46 
SetUp()47 void ZipBase::SetUp() {
48   test_files_dir_ = getenv("TEST_FILES_DIR");
49   ASSERT_NE(test_files_dir_, nullptr);
50 
51   test_path_zip_ = GetTestFilePath("zip.zip");
52 
53   sandbox_ = std::make_unique<ZipSapiSandbox>();
54   ASSERT_THAT(sandbox_->Init(), IsOk());
55 }
56 
ReadFile(const std::string & filename)57 absl::StatusOr<std::vector<uint8_t>> ZipBase::ReadFile(
58     const std::string& filename) {
59   std::ifstream file(filename, std::ios::binary);
60   if (!file.is_open()) {
61     return absl::UnavailableError("Unable to open file");
62   }
63 
64   std::streamsize size = GetStreamSize(file);
65   std::vector<uint8_t> buf(size);
66 
67   file.read(reinterpret_cast<char*>(buf.data()), size);
68 
69   if (file.gcount() != size) {
70     return absl::UnavailableError("Unable to read data");
71   }
72 
73   return buf;
74 }
75 
GetTestFilePath(const std::string & filename)76 std::string ZipBase::GetTestFilePath(const std::string& filename) {
77   return sapi::file::JoinPath(test_files_dir_, filename);
78 }
79 
GetTemporaryFile(const std::string & filename)80 std::string ZipBase::GetTemporaryFile(const std::string& filename) {
81   absl::StatusOr<std::string> tmp_file =
82       sapi::CreateNamedTempFileAndClose(filename);
83   if (!tmp_file.ok()) {
84     return "";
85   }
86 
87   return sapi::file::JoinPath(sapi::file_util::fileops::GetCWD(), *tmp_file);
88 }
89 
GetStreamSize(std::ifstream & stream)90 std::streamsize ZipBase::GetStreamSize(std::ifstream& stream) {
91   stream.seekg(0, std::ios_base::end);
92   std::streamsize ssize = stream.tellg();
93   stream.seekg(0, std::ios_base::beg);
94 
95   return ssize;
96 }
97 
TEST_F(ZipBase,CheckInit)98 TEST_F(ZipBase, CheckInit) {
99   LibZip zip(sandbox_.get(), test_path_zip_, 0);
100   ASSERT_THAT(zip.IsOpen(), true);
101 }
102 
TEST_F(ZipBase,CheckFileCount)103 TEST_F(ZipBase, CheckFileCount) {
104   LibZip zip(sandbox_.get(), test_path_zip_, 0);
105   ASSERT_THAT(zip.IsOpen(), true);
106 
107   SAPI_ASSERT_OK_AND_ASSIGN(uint64_t count, zip.GetNumberEntries());
108   ASSERT_EQ(count, 2);
109 }
110 
TEST_F(ZipBase,AddFileBuf)111 TEST_F(ZipBase, AddFileBuf) {
112   LibZip zip(sandbox_.get(), test_path_zip_, 0);
113   ASSERT_THAT(zip.IsOpen(), true);
114 
115   SAPI_ASSERT_OK_AND_ASSIGN(auto newdata,
116                             ReadFile(GetTestFilePath("notinzip")));
117 
118   SAPI_ASSERT_OK_AND_ASSIGN(uint64_t index, zip.AddFile("test", newdata));
119   SAPI_ASSERT_OK_AND_ASSIGN(uint64_t count, zip.GetNumberEntries());
120   ASSERT_EQ(count, 3);
121 
122   SAPI_ASSERT_OK_AND_ASSIGN(std::string newname, zip.GetName(index));
123   ASSERT_EQ(newname, "test");
124 }
125 
TEST_F(ZipBase,AddFileFd)126 TEST_F(ZipBase, AddFileFd) {
127   LibZip zip(sandbox_.get(), test_path_zip_, 0);
128   ASSERT_THAT(zip.IsOpen(), true);
129 
130   int fd = open(GetTestFilePath("notinzip").c_str(), O_RDONLY);
131   ASSERT_GE(fd, 0);
132 
133   SAPI_ASSERT_OK_AND_ASSIGN(uint64_t index, zip.AddFile("test", fd));
134   SAPI_ASSERT_OK_AND_ASSIGN(uint64_t count, zip.GetNumberEntries());
135   ASSERT_EQ(count, 3);
136 
137   SAPI_ASSERT_OK_AND_ASSIGN(std::string newname, zip.GetName(index));
138   ASSERT_EQ(newname, "test");
139 }
140 
TEST_F(ZipMultiFiles,AddFileBufInplaceStore)141 TEST_F(ZipMultiFiles, AddFileBufInplaceStore) {
142   std::string new_path_zip = GetTemporaryFile("newzip.zip");
143 
144   ASSERT_TRUE(
145       sapi::file_util::fileops::CopyFile(test_path_zip_, new_path_zip, 0644));
146   LibZip zip(sandbox_.get(), new_path_zip, 0);
147   ASSERT_THAT(zip.IsOpen(), true);
148 
149   SAPI_ASSERT_OK_AND_ASSIGN(auto newdata,
150                             ReadFile(GetTestFilePath("notinzip")));
151   SAPI_ASSERT_OK_AND_ASSIGN(uint64_t index, zip.AddFile("test", newdata));
152 
153   ASSERT_THAT(zip.Finish(), IsOk());
154   ASSERT_THAT(zip.Save(), IsOk());
155 
156   LibZip newzip(sandbox_.get(), new_path_zip, 0);
157   ASSERT_THAT(newzip.IsOpen(), true);
158 
159   SAPI_ASSERT_OK_AND_ASSIGN(auto nameddata, newzip.ReadFile("test"));
160   ASSERT_EQ(newdata, newdata);
161 
162   SAPI_ASSERT_OK_AND_ASSIGN(auto indexeddata, newzip.ReadFile(index));
163   ASSERT_EQ(indexeddata, newdata);
164 }
165 
TEST_P(ZipMultiFiles,CheckFileNames)166 TEST_P(ZipMultiFiles, CheckFileNames) {
167   LibZip zip(sandbox_.get(), test_path_zip_, 0);
168   ASSERT_THAT(zip.IsOpen(), true);
169 
170   uint64_t index = GetParam().first;
171   std::string origname = GetParam().second;
172 
173   SAPI_ASSERT_OK_AND_ASSIGN(std::string name, zip.GetName(index));
174   ASSERT_EQ(name, origname);
175 }
176 
TEST_P(ZipMultiFiles,DeleteFile)177 TEST_P(ZipMultiFiles, DeleteFile) {
178   LibZip zip(sandbox_.get(), test_path_zip_, 0);
179   ASSERT_THAT(zip.IsOpen(), true);
180 
181   uint64_t index = GetParam().first;
182   std::string origname = GetParam().second;
183 
184   SAPI_ASSERT_OK_AND_ASSIGN(uint64_t count, zip.GetNumberEntries());
185   ASSERT_THAT(zip.DeleteFile(index), IsOk());
186 
187   for (uint64_t i = 0; i < count; i++) {
188     absl::StatusOr<std::string> name = zip.GetName(i);
189     if (i == index) {
190       ASSERT_FALSE(name.ok());
191     } else {
192       ASSERT_THAT(name, IsOk());
193       ASSERT_NE(*name, origname);
194     }
195   }
196 }
197 
TEST_P(ZipMultiFiles,ReadFileName)198 TEST_P(ZipMultiFiles, ReadFileName) {
199   LibZip zip(sandbox_.get(), test_path_zip_, 0);
200   ASSERT_THAT(zip.IsOpen(), true);
201 
202   std::string name = GetParam().second;
203 
204   SAPI_ASSERT_OK_AND_ASSIGN(auto zipdata, zip.ReadFile(name));
205   SAPI_ASSERT_OK_AND_ASSIGN(auto origdata, ReadFile(GetTestFilePath(name)));
206 
207   ASSERT_EQ(zipdata, origdata);
208 }
209 
TEST_P(ZipMultiFiles,ReadFileIndex)210 TEST_P(ZipMultiFiles, ReadFileIndex) {
211   LibZip zip(sandbox_.get(), test_path_zip_, 0);
212   ASSERT_THAT(zip.IsOpen(), true);
213 
214   uint64_t index = GetParam().first;
215   std::string name = GetParam().second;
216 
217   SAPI_ASSERT_OK_AND_ASSIGN(auto zipdata, zip.ReadFile(index));
218   SAPI_ASSERT_OK_AND_ASSIGN(auto origdata, ReadFile(GetTestFilePath(name)));
219 
220   ASSERT_EQ(zipdata, origdata);
221 }
222 
TEST_P(ZipMultiFiles,AddFileBufNewStore)223 TEST_P(ZipMultiFiles, AddFileBufNewStore) {
224   LibZip zip(sandbox_.get(), test_path_zip_, 0);
225   ASSERT_THAT(zip.IsOpen(), true);
226 
227   SAPI_ASSERT_OK_AND_ASSIGN(auto newdata,
228                             ReadFile(GetTestFilePath("notinzip")));
229   SAPI_ASSERT_OK_AND_ASSIGN(uint64_t index, zip.AddFile("test", newdata));
230 
231   std::string new_zip_file_name = GetTemporaryFile("newzip.zip");
232   int newfdzip = open(new_zip_file_name.c_str(), O_WRONLY);
233   ASSERT_GE(newfdzip, 0);
234   ASSERT_THAT(zip.Finish(), IsOk());
235   ASSERT_THAT(zip.Save(newfdzip), IsOk());
236   close(newfdzip);
237 
238   LibZip newzip(sandbox_.get(), new_zip_file_name, 0);
239   ASSERT_THAT(newzip.IsOpen(), true);
240 
241   SAPI_ASSERT_OK_AND_ASSIGN(auto nameddata, newzip.ReadFile("test"));
242   ASSERT_EQ(newdata, newdata);
243 
244   SAPI_ASSERT_OK_AND_ASSIGN(auto indexeddata, newzip.ReadFile(index));
245   ASSERT_EQ(indexeddata, newdata);
246 
247   // We also check if non other data was corrupted
248   uint64_t oldindex = GetParam().first;
249   std::string name = GetParam().second;
250 
251   SAPI_ASSERT_OK_AND_ASSIGN(auto zipdata, newzip.ReadFile(oldindex));
252   SAPI_ASSERT_OK_AND_ASSIGN(auto origdata, ReadFile(GetTestFilePath(name)));
253 
254   ASSERT_EQ(zipdata, origdata);
255 }
256 
TEST_P(ZipMultiFiles,AddFileFdStore)257 TEST_P(ZipMultiFiles, AddFileFdStore) {
258   LibZip zip(sandbox_.get(), test_path_zip_, 0);
259   ASSERT_THAT(zip.IsOpen(), true);
260 
261   SAPI_ASSERT_OK_AND_ASSIGN(auto newdata,
262                             ReadFile(GetTestFilePath("notinzip")));
263   int fd = open(GetTestFilePath("notinzip").c_str(), O_RDONLY);
264   ASSERT_GE(fd, 0);
265   SAPI_ASSERT_OK_AND_ASSIGN(uint64_t index, zip.AddFile("test", fd));
266 
267   std::string new_zip_file_name = GetTemporaryFile("newzip.zip");
268   int newfdzip = open(new_zip_file_name.c_str(), O_WRONLY);
269   ASSERT_GE(newfdzip, 0);
270   ASSERT_THAT(zip.Finish(), IsOk());
271   ASSERT_THAT(zip.Save(newfdzip), IsOk());
272   close(newfdzip);
273 
274   LibZip newzip(sandbox_.get(), new_zip_file_name, 0);
275   ASSERT_THAT(newzip.IsOpen(), true);
276 
277   SAPI_ASSERT_OK_AND_ASSIGN(auto nameddata, newzip.ReadFile("test"));
278   ASSERT_EQ(nameddata, newdata);
279 
280   SAPI_ASSERT_OK_AND_ASSIGN(auto indexeddata, newzip.ReadFile(index));
281   ASSERT_EQ(indexeddata, newdata);
282 
283   // We also check if non other data was corrupted
284   uint64_t oldindex = GetParam().first;
285   std::string name = GetParam().second;
286 
287   SAPI_ASSERT_OK_AND_ASSIGN(auto zipdata, newzip.ReadFile(oldindex));
288   SAPI_ASSERT_OK_AND_ASSIGN(auto origdata, ReadFile(GetTestFilePath(name)));
289 
290   ASSERT_EQ(zipdata, origdata);
291 }
292 
TEST_P(ZipMultiFiles,ReplaceFileBufStore)293 TEST_P(ZipMultiFiles, ReplaceFileBufStore) {
294   LibZip zip(sandbox_.get(), test_path_zip_, 0);
295   ASSERT_THAT(zip.IsOpen(), true);
296 
297   uint64_t index = GetParam().first;
298   std::string name = GetParam().second;
299 
300   SAPI_ASSERT_OK_AND_ASSIGN(auto newdata,
301                             ReadFile(GetTestFilePath("notinzip")));
302   SAPI_ASSERT_OK_AND_ASSIGN(auto zipdata, zip.ReadFile(index));
303   ASSERT_NE(zipdata, newdata);
304 
305   ASSERT_THAT(zip.ReplaceFile(index, newdata), IsOk());
306 
307   std::string new_zip_file_name = GetTemporaryFile("newzip.zip");
308   int newfdzip = open(new_zip_file_name.c_str(), O_WRONLY);
309   ASSERT_GE(newfdzip, 0);
310   ASSERT_THAT(zip.Finish(), IsOk());
311   ASSERT_THAT(zip.Save(newfdzip), IsOk());
312   close(newfdzip);
313 
314   LibZip newzip(sandbox_.get(), new_zip_file_name, 0);
315   ASSERT_THAT(newzip.IsOpen(), true);
316 
317   SAPI_ASSERT_OK_AND_ASSIGN(auto nameddata, newzip.ReadFile(name));
318   ASSERT_EQ(nameddata, newdata);
319 
320   SAPI_ASSERT_OK_AND_ASSIGN(auto indexeddata, newzip.ReadFile(index));
321   ASSERT_EQ(indexeddata, newdata);
322 }
323 
TEST_P(ZipMultiFiles,ReplaceFileFdStore)324 TEST_P(ZipMultiFiles, ReplaceFileFdStore) {
325   LibZip zip(sandbox_.get(), test_path_zip_, 0);
326   ASSERT_THAT(zip.IsOpen(), true);
327 
328   uint64_t index = GetParam().first;
329   std::string name = GetParam().second;
330 
331   SAPI_ASSERT_OK_AND_ASSIGN(auto newdata,
332                             ReadFile(GetTestFilePath("notinzip")));
333   SAPI_ASSERT_OK_AND_ASSIGN(auto zipdata, zip.ReadFile(index));
334   ASSERT_NE(zipdata, newdata);
335 
336   int fd = open(GetTestFilePath("notinzip").c_str(), O_RDONLY);
337   ASSERT_GE(fd, 0);
338 
339   ASSERT_THAT(zip.ReplaceFile(index, fd), IsOk());
340 
341   std::string new_zip_file_name = GetTemporaryFile("newzip.zip");
342   int newfdzip = open(new_zip_file_name.c_str(), O_WRONLY);
343   ASSERT_GE(newfdzip, 0);
344   ASSERT_THAT(zip.Finish(), IsOk());
345   ASSERT_THAT(zip.Save(newfdzip), IsOk());
346   close(newfdzip);
347 
348   LibZip newzip(sandbox_.get(), new_zip_file_name, 0);
349   ASSERT_THAT(newzip.IsOpen(), true);
350 
351   SAPI_ASSERT_OK_AND_ASSIGN(auto nameddata, newzip.ReadFile(name));
352   ASSERT_EQ(nameddata, newdata);
353 
354   SAPI_ASSERT_OK_AND_ASSIGN(auto indexeddata, newzip.ReadFile(index));
355   ASSERT_EQ(indexeddata, newdata);
356 }
357 
TEST_P(ZipMultiFiles,DeleteFileStore)358 TEST_P(ZipMultiFiles, DeleteFileStore) {
359   LibZip zip(sandbox_.get(), test_path_zip_, 0);
360   ASSERT_THAT(zip.IsOpen(), true);
361 
362   uint64_t index = GetParam().first;
363   std::string origname = GetParam().second;
364 
365   SAPI_ASSERT_OK_AND_ASSIGN(uint64_t oldcount, zip.GetNumberEntries());
366 
367   ASSERT_THAT(zip.DeleteFile(index), IsOk());
368 
369   std::string new_zip_file_name = GetTemporaryFile("newzip.zip");
370   int newfdzip = open(new_zip_file_name.c_str(), O_WRONLY);
371   ASSERT_GE(newfdzip, 0);
372   ASSERT_THAT(zip.Finish(), IsOk());
373   ASSERT_THAT(zip.Save(newfdzip), IsOk());
374   close(newfdzip);
375 
376   LibZip newzip(sandbox_.get(), new_zip_file_name, 0);
377   ASSERT_THAT(newzip.IsOpen(), true);
378 
379   SAPI_ASSERT_OK_AND_ASSIGN(uint64_t newcount, newzip.GetNumberEntries());
380   ASSERT_LT(newcount, oldcount);
381 
382   for (uint64_t i = 0; i < newcount; i++) {
383     absl::StatusOr<std::string> name = newzip.GetName(i);
384     ASSERT_THAT(name, IsOk());
385     ASSERT_NE(*name, origname);
386   }
387 }
388 
389 INSTANTIATE_TEST_SUITE_P(ZipBase, ZipMultiFiles,
390                          testing::Values(std::make_pair(0, "binary"),
391                                          std::make_pair(1, "text")));
392 }  // namespace
393