xref: /aosp_15_r20/external/sandboxed-api/contrib/libzip/utils/utils_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 "contrib/libzip/utils/utils_zip.h"
16 
17 #include <fstream>
18 #include <iostream>
19 #include <string>
20 
21 #include "absl/cleanup/cleanup.h"
22 #include "contrib/libzip/sandboxed.h"
23 
24 constexpr uint64_t kFileMaxSize = 1024 * 1024 * 1024;  // 1GB
25 
26 #define ZIP_FL_ENC_GUESS 0
27 #define ZIP_FL_OVERWRITE 8192u
28 
~LibZip()29 LibZip::~LibZip() {
30   if (IsOpen()) {
31     api_.zip_close(zip_.get()).IgnoreError();
32   }
33   api_.zip_source_free(&(*zipsource_)).IgnoreError();
34 }
35 
IsOpen()36 bool LibZip::IsOpen() { return zip_ != nullptr; }
37 
IsOpenLocal()38 bool LibZip::IsOpenLocal() { return rfd_.GetValue() >= 0; }
39 
CheckOpen()40 absl::Status LibZip::CheckOpen() {
41   if (!IsOpen()) {
42     return absl::UnavailableError("Modification stage finished");
43   }
44 
45   return absl::OkStatus();
46 }
47 
CheckFinished()48 absl::Status LibZip::CheckFinished() {
49   if (IsOpen()) {
50     return absl::UnavailableError("Still in modification stage");
51   }
52 
53   return absl::OkStatus();
54 }
55 
OpenRemote()56 absl::Status LibZip::OpenRemote() {
57   if (!IsOpenLocal()) {
58     return absl::UnavailableError("Zip file is not open");
59   }
60 
61   SAPI_RETURN_IF_ERROR(sandbox_->TransferToSandboxee(&rfd_));
62 
63   SAPI_ASSIGN_OR_RETURN(void* zipsource, CreateSourceFromFd(rfd_));
64   zipsource_ = std::make_unique<sapi::v::RemotePtr>(zipsource);
65 
66   sapi::v::NullPtr null_ptr;
67   absl::StatusOr<zip_t*> status_or_zip =
68       api_.zip_open_from_source(&(*zipsource_), flags_, &null_ptr);
69   if (!status_or_zip.ok() || *status_or_zip == nullptr) {
70     api_.zip_source_free(&(*zipsource_)).IgnoreError();
71     zipsource_ = nullptr;
72     return absl::UnavailableError("Unable to open remote");
73   }
74 
75   SAPI_RETURN_IF_ERROR(api_.zip_source_keep(&(*zipsource_)));
76 
77   zip_ = std::make_unique<sapi::v::RemotePtr>(*status_or_zip);
78 
79   return absl::OkStatus();
80 }
81 
Finish()82 absl::Status LibZip::Finish() {
83   SAPI_ASSIGN_OR_RETURN(int ret, api_.zip_close(zip_.get()));
84   if (ret < 0) {
85     return absl::UnavailableError("Unable to close remote");
86   }
87   zip_ = nullptr;
88 
89   return absl::OkStatus();
90 }
91 
Save(int fd)92 absl::Status LibZip::Save(int fd) {
93   SAPI_RETURN_IF_ERROR(CheckFinished());
94   sapi::v::Fd rfd(fd);
95   SAPI_RETURN_IF_ERROR(sandbox_->TransferToSandboxee(&rfd));
96   return Save(rfd);
97 }
98 
Save()99 absl::Status LibZip::Save() {
100   SAPI_RETURN_IF_ERROR(CheckFinished());
101   return Save(rfd_);
102 }
103 
Save(sapi::v::Fd & rfd)104 absl::Status LibZip::Save(sapi::v::Fd& rfd) {
105   SAPI_RETURN_IF_ERROR(CheckFinished());
106   SAPI_ASSIGN_OR_RETURN(
107       bool ret, api_.zip_source_to_fd(&(*zipsource_), rfd.GetRemoteFd()));
108 
109   if (!ret) {
110     return absl::UnavailableError("Unable to store data");
111   }
112 
113   return absl::OkStatus();
114 }
115 
GetName(uint64_t index)116 absl::StatusOr<std::string> LibZip::GetName(uint64_t index) {
117   SAPI_RETURN_IF_ERROR(CheckOpen());
118   SAPI_ASSIGN_OR_RETURN(const char* name,
119                         api_.zip_get_name(zip_.get(), index, ZIP_FL_ENC_GUESS));
120   if (name == nullptr) {
121     return absl::UnavailableError("Unable to find name under index");
122   }
123 
124   return sandbox_->GetCString(sapi::v::RemotePtr(const_cast<char*>(name)));
125 }
126 
GetNumberEntries()127 absl::StatusOr<uint64_t> LibZip::GetNumberEntries() {
128   SAPI_RETURN_IF_ERROR(CheckOpen());
129   SAPI_ASSIGN_OR_RETURN(int64_t num, api_.zip_get_num_entries(zip_.get(), 0));
130   if (num < 0) {
131     /* Imposible as zip != nullptr */
132     return absl::UnavailableError("Internal error");
133   }
134   return num;
135 }
136 
ReadFile(sapi::v::RemotePtr & rzipfile,uint32_t size)137 absl::StatusOr<std::vector<uint8_t>> LibZip::ReadFile(
138     sapi::v::RemotePtr& rzipfile, uint32_t size) {
139   SAPI_RETURN_IF_ERROR(CheckOpen());
140   if (size > kFileMaxSize) {
141     return absl::UnavailableError("File is to large");
142   }
143 
144   std::vector<uint8_t> buf(size);
145   sapi::v::Array<uint8_t> arr(buf.data(), size);
146 
147   SAPI_ASSIGN_OR_RETURN(uint64_t ret,
148                         api_.zip_fread(&rzipfile, arr.PtrAfter(), size));
149   if (ret != size) {
150     return absl::UnavailableError("Unable to read file");
151   }
152 
153   return buf;
154 }
155 
ReadFile(const std::string & filename)156 absl::StatusOr<std::vector<uint8_t>> LibZip::ReadFile(
157     const std::string& filename) {
158   SAPI_RETURN_IF_ERROR(CheckOpen());
159   sapi::v::Struct<zip_stat_t> zipstat;
160   sapi::v::ConstCStr cfilename(filename.c_str());
161 
162   SAPI_ASSIGN_OR_RETURN(
163       int err,
164       api_.zip_stat(zip_.get(), cfilename.PtrBefore(), 0, zipstat.PtrAfter()));
165   if (err < 0) {
166     return absl::UnavailableError("Unable to get file stat");
167   }
168 
169   SAPI_ASSIGN_OR_RETURN(zip_file_t * zipfile,
170                         api_.zip_fopen(zip_.get(), cfilename.PtrBefore(), 0));
171   if (zipfile == nullptr) {
172     return absl::UnavailableError("Unable to open file in archaive");
173   }
174 
175   sapi::v::RemotePtr rzipfile(zipfile);
176   absl::Cleanup rzipfile_cleanup = [this, &rzipfile] {
177     api_.zip_fclose(&rzipfile).IgnoreError();
178   };
179   return ReadFile(rzipfile, zipstat.mutable_data()->size);
180 }
181 
ReadFile(uint64_t index)182 absl::StatusOr<std::vector<uint8_t>> LibZip::ReadFile(uint64_t index) {
183   SAPI_RETURN_IF_ERROR(CheckOpen());
184   sapi::v::Struct<zip_stat_t> zipstat;
185 
186   SAPI_ASSIGN_OR_RETURN(
187       int err, api_.zip_stat_index(zip_.get(), index, 0, zipstat.PtrAfter()));
188   if (err < 0) {
189     return absl::UnavailableError("Unable to get file stat");
190   }
191 
192   SAPI_ASSIGN_OR_RETURN(zip_file_t * zipfile,
193                         api_.zip_fopen_index(zip_.get(), index, 0));
194   if (zipfile == nullptr) {
195     return absl::UnavailableError("Unable to open file in archaive");
196   }
197   sapi::v::RemotePtr rzipfile(zipfile);
198   absl::Cleanup rzipfile_cleanup = [this, &rzipfile] {
199     api_.zip_fclose(&rzipfile).IgnoreError();
200   };
201 
202   return ReadFile(rzipfile, zipstat.mutable_data()->size);
203 }
204 
AddFile(const std::string & filename,sapi::v::RemotePtr & rzipsource)205 absl::StatusOr<uint64_t> LibZip::AddFile(const std::string& filename,
206                                          sapi::v::RemotePtr& rzipsource) {
207   SAPI_RETURN_IF_ERROR(CheckOpen());
208   sapi::v::ConstCStr cfilename(filename.c_str());
209 
210   SAPI_ASSIGN_OR_RETURN(int64_t index,
211                         api_.zip_file_add(zip_.get(), cfilename.PtrBefore(),
212                                           &rzipsource, ZIP_FL_OVERWRITE));
213   if (index < 0) {
214     SAPI_ASSIGN_OR_RETURN(std::string errs, GetError());
215     api_.zip_source_free(&rzipsource).IgnoreError();
216     return absl::UnavailableError("Unable to add file");
217   }
218 
219   return index;
220 }
221 
CreateSourceFromFd(sapi::v::Fd & rfd)222 absl::StatusOr<void*> LibZip::CreateSourceFromFd(sapi::v::Fd& rfd) {
223   sapi::v::NullPtr null_ptr;
224 
225   SAPI_ASSIGN_OR_RETURN(void* zipsource, api_.zip_read_fd_to_source(
226                                              rfd.GetRemoteFd(), &null_ptr));
227   if (zipsource == nullptr) {
228     return absl::UnavailableError("Unable to create buffer");
229   }
230 
231   return zipsource;
232 }
233 
GetSource(std::vector<uint8_t> & buf)234 absl::StatusOr<void*> LibZip::GetSource(std::vector<uint8_t>& buf) {
235   sapi::v::Array<uint8_t> arr(buf.data(), buf.size());
236 
237   SAPI_ASSIGN_OR_RETURN(
238       zip_source_t * zipsource,
239       api_.zip_source_buffer(zip_.get(), arr.PtrBefore(), arr.GetSize(),
240                              1 /* autofree */));
241   if (zipsource == nullptr) {
242     return absl::UnavailableError("Unable to create buffer");
243   }
244   arr.SetRemote(nullptr);  // We don't want to free automaticlt buffer
245                            // leave memory menagment to the zip process
246   return zipsource;
247 }
248 
GetSource(int fd,const std::string & mode)249 absl::StatusOr<void*> LibZip::GetSource(int fd, const std::string& mode) {
250   sapi::v::Fd rfd(fd);
251   SAPI_RETURN_IF_ERROR(sandbox_->TransferToSandboxee(&rfd));
252 
253   sapi::v::ConstCStr cmode(mode.c_str());
254   SAPI_ASSIGN_OR_RETURN(void* zipsource,
255                         api_.zip_source_filefd(zip_.get(), rfd.GetRemoteFd(),
256                                                cmode.PtrBefore(), 0, 0));
257   if (zipsource == nullptr) {
258     return absl::UnavailableError("Unable to create buffer");
259   }
260   rfd.OwnRemoteFd(false);
261 
262   return zipsource;
263 }
264 
AddFile(const std::string & filename,std::vector<uint8_t> & buf)265 absl::StatusOr<uint64_t> LibZip::AddFile(const std::string& filename,
266                                          std::vector<uint8_t>& buf) {
267   SAPI_RETURN_IF_ERROR(CheckOpen());
268   SAPI_ASSIGN_OR_RETURN(void* zipsource, GetSource(buf));
269   sapi::v::RemotePtr rzipsource(zipsource);
270   return AddFile(filename, rzipsource);
271 }
272 
AddFile(const std::string & filename,int fd)273 absl::StatusOr<uint64_t> LibZip::AddFile(const std::string& filename, int fd) {
274   SAPI_RETURN_IF_ERROR(CheckOpen());
275   SAPI_ASSIGN_OR_RETURN(void* zipsource, GetSource(fd, "rb"));
276   sapi::v::RemotePtr rzipsource(zipsource);
277   return AddFile(filename, rzipsource);
278 }
279 
ReplaceFile(uint64_t index,sapi::v::RemotePtr & rzipsource)280 absl::Status LibZip::ReplaceFile(uint64_t index,
281                                  sapi::v::RemotePtr& rzipsource) {
282   SAPI_RETURN_IF_ERROR(CheckOpen());
283   SAPI_ASSIGN_OR_RETURN(
284       int64_t ret, api_.zip_file_replace(zip_.get(), index, &rzipsource, 0));
285   if (ret < 0) {
286     api_.zip_source_free(&rzipsource).IgnoreError();
287     return absl::UnavailableError("Unable to replace file");
288   }
289 
290   return absl::OkStatus();
291 }
292 
ReplaceFile(uint64_t index,int fd)293 absl::Status LibZip::ReplaceFile(uint64_t index, int fd) {
294   SAPI_RETURN_IF_ERROR(CheckOpen());
295   SAPI_ASSIGN_OR_RETURN(void* zipsource, GetSource(fd, "rb"));
296   sapi::v::RemotePtr rzipsource(zipsource);
297   return ReplaceFile(index, rzipsource);
298 }
299 
ReplaceFile(uint64_t index,std::vector<uint8_t> & buf)300 absl::Status LibZip::ReplaceFile(uint64_t index, std::vector<uint8_t>& buf) {
301   SAPI_RETURN_IF_ERROR(CheckOpen());
302   SAPI_ASSIGN_OR_RETURN(void* zipsource, GetSource(buf));
303   sapi::v::RemotePtr rzipsource(zipsource);
304   return ReplaceFile(index, rzipsource);
305 }
306 
DeleteFile(uint64_t index)307 absl::Status LibZip::DeleteFile(uint64_t index) {
308   SAPI_RETURN_IF_ERROR(CheckOpen());
309   SAPI_ASSIGN_OR_RETURN(int ret, api_.zip_delete(zip_.get(), index));
310   if (ret < 0) {
311     return absl::UnavailableError("Unable to delete file");
312   }
313 
314   return absl::OkStatus();
315 }
316 
GetError()317 absl::StatusOr<std::string> LibZip::GetError() {
318   SAPI_RETURN_IF_ERROR(CheckOpen());
319   SAPI_ASSIGN_OR_RETURN(const char* err, api_.zip_strerror(zip_.get()));
320   if (err == nullptr) {
321     return absl::UnavailableError("No error");
322   }
323   return sandbox_->GetCString(sapi::v::RemotePtr(const_cast<char*>(err)));
324 }
325