xref: /aosp_15_r20/external/sandboxed-api/oss-internship-2020/libarchive/examples/sapi_minitar.cc (revision ec63e07ab9515d95e79c211197c445ef84cefa6a)
1*ec63e07aSXin Li // Copyright 2020 Google LLC
2*ec63e07aSXin Li //
3*ec63e07aSXin Li // Licensed under the Apache License, Version 2.0 (the "License");
4*ec63e07aSXin Li // you may not use this file except in compliance with the License.
5*ec63e07aSXin Li // You may obtain a copy of the License at
6*ec63e07aSXin Li //
7*ec63e07aSXin Li //     https://www.apache.org/licenses/LICENSE-2.0
8*ec63e07aSXin Li //
9*ec63e07aSXin Li // Unless required by applicable law or agreed to in writing, software
10*ec63e07aSXin Li // distributed under the License is distributed on an "AS IS" BASIS,
11*ec63e07aSXin Li // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*ec63e07aSXin Li // See the License for the specific language governing permissions and
13*ec63e07aSXin Li // limitations under the License.
14*ec63e07aSXin Li 
15*ec63e07aSXin Li #include "sapi_minitar.h"  // NOLINT(build/include)
16*ec63e07aSXin Li 
17*ec63e07aSXin Li #include "absl/status/status.h"
18*ec63e07aSXin Li #include "sandboxed_api/util/path.h"
19*ec63e07aSXin Li #include "sandboxed_api/util/status_macros.h"
20*ec63e07aSXin Li 
CreateArchive(const char * initial_filename,int compress,const std::vector<std::string> & argv,bool verbose)21*ec63e07aSXin Li absl::Status CreateArchive(const char* initial_filename, int compress,
22*ec63e07aSXin Li                            const std::vector<std::string>& argv, bool verbose) {
23*ec63e07aSXin Li   // We split the filename path into dirname and filename. To the filename we
24*ec63e07aSXin Li   // prepend "/output/"" so that it will work with the security policy.
25*ec63e07aSXin Li   std::string abs_path = MakeAbsolutePathAtCWD(std::string(initial_filename));
26*ec63e07aSXin Li   auto [archive_path, filename_tmp] =
27*ec63e07aSXin Li       std::move(sandbox2::file::SplitPath(abs_path));
28*ec63e07aSXin Li 
29*ec63e07aSXin Li   std::string filename = sandbox2::file::JoinPath("/output/", filename_tmp);
30*ec63e07aSXin Li 
31*ec63e07aSXin Li   std::vector<std::string> absolute_paths = argv;
32*ec63e07aSXin Li 
33*ec63e07aSXin Li   std::vector<std::string> relative_paths = absolute_paths;
34*ec63e07aSXin Li 
35*ec63e07aSXin Li   std::transform(absolute_paths.begin(), absolute_paths.end(),
36*ec63e07aSXin Li                  absolute_paths.begin(), MakeAbsolutePathAtCWD);
37*ec63e07aSXin Li 
38*ec63e07aSXin Li   std::transform(relative_paths.begin(), relative_paths.end(),
39*ec63e07aSXin Li                  relative_paths.begin(), sandbox2::file::CleanPath);
40*ec63e07aSXin Li   // At this point, we have the relative and absolute paths (cleaned) saved
41*ec63e07aSXin Li   // in vectors.
42*ec63e07aSXin Li 
43*ec63e07aSXin Li   // Initialize sandbox and api objects.
44*ec63e07aSXin Li   SapiLibarchiveSandboxCreate sandbox(absolute_paths, archive_path);
45*ec63e07aSXin Li   SAPI_RETURN_IF_ERROR(sandbox.Init());
46*ec63e07aSXin Li   LibarchiveApi api(&sandbox);
47*ec63e07aSXin Li 
48*ec63e07aSXin Li   SAPI_ASSIGN_OR_RETURN(archive * ret_archive, api.archive_write_new());
49*ec63e07aSXin Li   if (ret_archive == nullptr) {
50*ec63e07aSXin Li     return absl::FailedPreconditionError("Failed to create write archive");
51*ec63e07aSXin Li   }
52*ec63e07aSXin Li 
53*ec63e07aSXin Li   // Treat the pointer as remote. There is no need to copy the data
54*ec63e07aSXin Li   // to the client process.
55*ec63e07aSXin Li   sapi::v::RemotePtr a(ret_archive);
56*ec63e07aSXin Li 
57*ec63e07aSXin Li   int rc;
58*ec63e07aSXin Li   std::string msg;
59*ec63e07aSXin Li 
60*ec63e07aSXin Li   //   switch (compress) {
61*ec63e07aSXin Li   //     case 'j':
62*ec63e07aSXin Li   //     case 'y':
63*ec63e07aSXin Li   if (compress == 'j' || compress == 'y') {
64*ec63e07aSXin Li     SAPI_ASSIGN_OR_RETURN(rc, api.archive_write_add_filter_bzip2(&a));
65*ec63e07aSXin Li     if (rc != ARCHIVE_OK) {
66*ec63e07aSXin Li       return absl::FailedPreconditionError(
67*ec63e07aSXin Li           "Unexpected result from write_add_filter_bzip2 call");
68*ec63e07aSXin Li     }
69*ec63e07aSXin Li     //   break;
70*ec63e07aSXin Li   } else if (compress == 'Z') {
71*ec63e07aSXin Li     // case 'Z':
72*ec63e07aSXin Li     SAPI_ASSIGN_OR_RETURN(rc, api.archive_write_add_filter_compress(&a));
73*ec63e07aSXin Li     if (rc != ARCHIVE_OK) {
74*ec63e07aSXin Li       return absl::FailedPreconditionError(
75*ec63e07aSXin Li           "Unexpected result from write_add_filter_compress call");
76*ec63e07aSXin Li     }
77*ec63e07aSXin Li     //   break;
78*ec63e07aSXin Li   } else if (compress == 'z') {
79*ec63e07aSXin Li     // case 'z':
80*ec63e07aSXin Li     SAPI_ASSIGN_OR_RETURN(rc, api.archive_write_add_filter_gzip(&a));
81*ec63e07aSXin Li     if (rc != ARCHIVE_OK) {
82*ec63e07aSXin Li       return absl::FailedPreconditionError(
83*ec63e07aSXin Li           "Unexpected result from write_add_filter_gzip call");
84*ec63e07aSXin Li     }
85*ec63e07aSXin Li     //   break;
86*ec63e07aSXin Li   } else {
87*ec63e07aSXin Li     // default:
88*ec63e07aSXin Li     SAPI_ASSIGN_OR_RETURN(rc, api.archive_write_add_filter_none(&a));
89*ec63e07aSXin Li     if (rc != ARCHIVE_OK) {
90*ec63e07aSXin Li       return absl::FailedPreconditionError(
91*ec63e07aSXin Li           "Unexpected result from write_add_filter_none call");
92*ec63e07aSXin Li     }
93*ec63e07aSXin Li     //   break;
94*ec63e07aSXin Li   }
95*ec63e07aSXin Li 
96*ec63e07aSXin Li   SAPI_ASSIGN_OR_RETURN(rc, api.archive_write_set_format_ustar(&a));
97*ec63e07aSXin Li   if (rc != ARCHIVE_OK) {
98*ec63e07aSXin Li     return absl::FailedPreconditionError(
99*ec63e07aSXin Li         "Unexpected result from write_set_format_ustar call");
100*ec63e07aSXin Li   }
101*ec63e07aSXin Li 
102*ec63e07aSXin Li   const char* filename_ptr = filename.data();
103*ec63e07aSXin Li   if (filename_ptr != nullptr && strcmp(filename_ptr, "-") == 0) {
104*ec63e07aSXin Li     filename_ptr = nullptr;
105*ec63e07aSXin Li   }
106*ec63e07aSXin Li 
107*ec63e07aSXin Li   SAPI_ASSIGN_OR_RETURN(rc,
108*ec63e07aSXin Li                         api.archive_write_open_filename(
109*ec63e07aSXin Li                             &a, sapi::v::ConstCStr(filename_ptr).PtrBefore()));
110*ec63e07aSXin Li   if (rc != ARCHIVE_OK) {
111*ec63e07aSXin Li     return absl::FailedPreconditionError(
112*ec63e07aSXin Li         "Unexpected result from write_open_filename call");
113*ec63e07aSXin Li   }
114*ec63e07aSXin Li 
115*ec63e07aSXin Li   int file_idx = 0;
116*ec63e07aSXin Li 
117*ec63e07aSXin Li   // We can directly use the vectors defined before.
118*ec63e07aSXin Li   for (int file_idx = 0; file_idx < absolute_paths.size(); ++file_idx) {
119*ec63e07aSXin Li     SAPI_ASSIGN_OR_RETURN(ret_archive, api.archive_read_disk_new());
120*ec63e07aSXin Li     if (ret_archive == nullptr) {
121*ec63e07aSXin Li       return absl::FailedPreconditionError(
122*ec63e07aSXin Li           "Failed to create read_disk archive");
123*ec63e07aSXin Li     }
124*ec63e07aSXin Li 
125*ec63e07aSXin Li     sapi::v::RemotePtr disk(ret_archive);
126*ec63e07aSXin Li 
127*ec63e07aSXin Li     SAPI_ASSIGN_OR_RETURN(rc, api.archive_read_disk_set_standard_lookup(&disk));
128*ec63e07aSXin Li     if (rc != ARCHIVE_OK) {
129*ec63e07aSXin Li       return absl::FailedPreconditionError(
130*ec63e07aSXin Li           "Unexpected result from read_disk_set_standard_lookup call");
131*ec63e07aSXin Li     }
132*ec63e07aSXin Li 
133*ec63e07aSXin Li     // We use the absolute path first.
134*ec63e07aSXin Li     SAPI_ASSIGN_OR_RETURN(
135*ec63e07aSXin Li         rc,
136*ec63e07aSXin Li         api.archive_read_disk_open(
137*ec63e07aSXin Li             &disk,
138*ec63e07aSXin Li             sapi::v::ConstCStr(absolute_paths[file_idx].c_str()).PtrBefore()));
139*ec63e07aSXin Li     if (rc != ARCHIVE_OK) {
140*ec63e07aSXin Li       SAPI_ASSIGN_OR_RETURN(msg, CheckStatusAndGetString(
141*ec63e07aSXin Li                                      api.archive_error_string(&disk), sandbox));
142*ec63e07aSXin Li       return absl::FailedPreconditionError(msg);
143*ec63e07aSXin Li     }
144*ec63e07aSXin Li 
145*ec63e07aSXin Li     while (true) {
146*ec63e07aSXin Li       archive_entry* ret_archive_entry;
147*ec63e07aSXin Li       SAPI_ASSIGN_OR_RETURN(ret_archive_entry, api.archive_entry_new());
148*ec63e07aSXin Li 
149*ec63e07aSXin Li       if (ret_archive_entry == nullptr) {
150*ec63e07aSXin Li         return absl::FailedPreconditionError("Failed to create archive_entry");
151*ec63e07aSXin Li       }
152*ec63e07aSXin Li 
153*ec63e07aSXin Li       sapi::v::RemotePtr entry(ret_archive_entry);
154*ec63e07aSXin Li 
155*ec63e07aSXin Li       SAPI_ASSIGN_OR_RETURN(rc, api.archive_read_next_header2(&disk, &entry));
156*ec63e07aSXin Li 
157*ec63e07aSXin Li       if (rc == ARCHIVE_EOF) {
158*ec63e07aSXin Li         break;
159*ec63e07aSXin Li       }
160*ec63e07aSXin Li 
161*ec63e07aSXin Li       if (rc != ARCHIVE_OK) {
162*ec63e07aSXin Li         SAPI_ASSIGN_OR_RETURN(
163*ec63e07aSXin Li             msg,
164*ec63e07aSXin Li             CheckStatusAndGetString(api.archive_error_string(&disk), sandbox));
165*ec63e07aSXin Li         return absl::FailedPreconditionError(msg);
166*ec63e07aSXin Li       }
167*ec63e07aSXin Li 
168*ec63e07aSXin Li       SAPI_ASSIGN_OR_RETURN(rc, api.archive_read_disk_descend(&disk));
169*ec63e07aSXin Li       if (rc != ARCHIVE_OK) {
170*ec63e07aSXin Li         return absl::FailedPreconditionError("read_disk_descend call failed");
171*ec63e07aSXin Li       }
172*ec63e07aSXin Li 
173*ec63e07aSXin Li       // After using the absolute path before, we now need to add the pathname
174*ec63e07aSXin Li       // to the archive entry. This would help store the files by their relative
175*ec63e07aSXin Li       // paths(similar to the usual tar command).
176*ec63e07aSXin Li       // However, in the case where a directory is added to the archive,
177*ec63e07aSXin Li       // all of the files inside of it are added as well so we replace the
178*ec63e07aSXin Li       // absolute path prefix with the relative one.
179*ec63e07aSXin Li       // Example:
180*ec63e07aSXin Li       // we add the folder "test_files" which becomes
181*ec63e07aSXin Li       // "/absolute/path/test_files" and the files inside of it will become
182*ec63e07aSXin Li       // similar to "/absolute/path/test_files/file1"
183*ec63e07aSXin Li       // which we then change to "test_files/file1" so that it is relative.
184*ec63e07aSXin Li       SAPI_ASSIGN_OR_RETURN(
185*ec63e07aSXin Li           std::string path_name,
186*ec63e07aSXin Li           CheckStatusAndGetString(api.archive_entry_pathname(&entry), sandbox));
187*ec63e07aSXin Li 
188*ec63e07aSXin Li       path_name.replace(path_name.begin(),
189*ec63e07aSXin Li                         path_name.begin() + absolute_paths[file_idx].length(),
190*ec63e07aSXin Li                         relative_paths[file_idx]);
191*ec63e07aSXin Li 
192*ec63e07aSXin Li       // On top of those changes, we need to remove leading '/' characters
193*ec63e07aSXin Li       // and also remove everything up to the last occurrence of '../'.
194*ec63e07aSXin Li       size_t found = path_name.find_first_not_of("/");
195*ec63e07aSXin Li       if (found != std::string::npos) {
196*ec63e07aSXin Li         path_name.erase(path_name.begin(), path_name.begin() + found);
197*ec63e07aSXin Li       }
198*ec63e07aSXin Li 
199*ec63e07aSXin Li       // Search either for the last '/../' or check if
200*ec63e07aSXin Li       // the path has '../' in the beginning.
201*ec63e07aSXin Li       found = path_name.rfind("/../");
202*ec63e07aSXin Li       if (found != std::string::npos) {
203*ec63e07aSXin Li         path_name = path_name.substr(found + 4);
204*ec63e07aSXin Li       } else if (path_name.substr(0, 3) == "../") {
205*ec63e07aSXin Li         path_name = path_name.substr(3);
206*ec63e07aSXin Li       }
207*ec63e07aSXin Li 
208*ec63e07aSXin Li       SAPI_RETURN_IF_ERROR(api.archive_entry_set_pathname(
209*ec63e07aSXin Li           &entry, sapi::v::ConstCStr(path_name.c_str()).PtrBefore()));
210*ec63e07aSXin Li 
211*ec63e07aSXin Li       if (verbose) {
212*ec63e07aSXin Li         SAPI_ASSIGN_OR_RETURN(
213*ec63e07aSXin Li             msg, CheckStatusAndGetString(api.archive_entry_pathname(&entry),
214*ec63e07aSXin Li                                          sandbox));
215*ec63e07aSXin Li         std::cout << msg << std::endl;
216*ec63e07aSXin Li       }
217*ec63e07aSXin Li 
218*ec63e07aSXin Li       SAPI_ASSIGN_OR_RETURN(rc, api.archive_write_header(&a, &entry));
219*ec63e07aSXin Li 
220*ec63e07aSXin Li       if (rc < ARCHIVE_OK) {
221*ec63e07aSXin Li         SAPI_ASSIGN_OR_RETURN(msg, CheckStatusAndGetString(
222*ec63e07aSXin Li                                        api.archive_error_string(&a), sandbox));
223*ec63e07aSXin Li         std::cout << msg << std::endl;
224*ec63e07aSXin Li       }
225*ec63e07aSXin Li       if (rc == ARCHIVE_FATAL) {
226*ec63e07aSXin Li         return absl::FailedPreconditionError(
227*ec63e07aSXin Li             "Unexpected result from write_header call");
228*ec63e07aSXin Li       }
229*ec63e07aSXin Li 
230*ec63e07aSXin Li       // In the following section, the calls (read, archive_write_data) are done
231*ec63e07aSXin Li       // on the sandboxed process since we do not need to transfer the data in
232*ec63e07aSXin Li       // the client process.
233*ec63e07aSXin Li       if (rc > ARCHIVE_FAILED) {
234*ec63e07aSXin Li         SAPI_ASSIGN_OR_RETURN(
235*ec63e07aSXin Li             msg, CheckStatusAndGetString(api.archive_entry_sourcepath(&entry),
236*ec63e07aSXin Li                                          sandbox));
237*ec63e07aSXin Li         int fd = open(msg.c_str(), O_RDONLY);
238*ec63e07aSXin Li         if (fd < 0) {
239*ec63e07aSXin Li           return absl::FailedPreconditionError("Could not open file");
240*ec63e07aSXin Li         }
241*ec63e07aSXin Li 
242*ec63e07aSXin Li         sapi::v::Fd sapi_fd(fd);
243*ec63e07aSXin Li         sapi::v::Int read_ret;
244*ec63e07aSXin Li         sapi::v::Array<char> buff(kBuffSize);
245*ec63e07aSXin Li         sapi::v::UInt ssize(kBuffSize);
246*ec63e07aSXin Li 
247*ec63e07aSXin Li         // We allocate the buffer remotely and then we can simply use the
248*ec63e07aSXin Li         // remote pointer(with PtrNone).
249*ec63e07aSXin Li         // This allows us to keep the data in the remote process without always
250*ec63e07aSXin Li         // transferring the memory.
251*ec63e07aSXin Li         SAPI_RETURN_IF_ERROR(sandbox.Allocate(&buff, true));
252*ec63e07aSXin Li 
253*ec63e07aSXin Li         // We can use sapi methods that help us with file descriptors.
254*ec63e07aSXin Li         SAPI_RETURN_IF_ERROR(sandbox.TransferToSandboxee(&sapi_fd));
255*ec63e07aSXin Li 
256*ec63e07aSXin Li         SAPI_RETURN_IF_ERROR(
257*ec63e07aSXin Li             sandbox.Call("read", &read_ret, &sapi_fd, buff.PtrNone(), &ssize));
258*ec63e07aSXin Li 
259*ec63e07aSXin Li         while (read_ret.GetValue() > 0) {
260*ec63e07aSXin Li           SAPI_ASSIGN_OR_RETURN(
261*ec63e07aSXin Li               rc,
262*ec63e07aSXin Li               api.archive_write_data(&a, buff.PtrNone(), read_ret.GetValue()));
263*ec63e07aSXin Li 
264*ec63e07aSXin Li           SAPI_RETURN_IF_ERROR(sandbox.Call("read", &read_ret, &sapi_fd,
265*ec63e07aSXin Li                                             buff.PtrNone(), &ssize));
266*ec63e07aSXin Li         }
267*ec63e07aSXin Li         // sapi_fd variable goes out of scope here so both the local and the
268*ec63e07aSXin Li         // remote file descriptors are closed.
269*ec63e07aSXin Li       }
270*ec63e07aSXin Li       SAPI_RETURN_IF_ERROR(api.archive_entry_free(&entry));
271*ec63e07aSXin Li     }
272*ec63e07aSXin Li 
273*ec63e07aSXin Li     SAPI_ASSIGN_OR_RETURN(rc, api.archive_read_close(&disk));
274*ec63e07aSXin Li     if (rc != ARCHIVE_OK) {
275*ec63e07aSXin Li       return absl::FailedPreconditionError(
276*ec63e07aSXin Li           "Unexpected result from read_close call");
277*ec63e07aSXin Li     }
278*ec63e07aSXin Li 
279*ec63e07aSXin Li     SAPI_ASSIGN_OR_RETURN(rc, api.archive_read_free(&disk));
280*ec63e07aSXin Li     if (rc != ARCHIVE_OK) {
281*ec63e07aSXin Li       return absl::FailedPreconditionError(
282*ec63e07aSXin Li           "Unexpected result from read_free call");
283*ec63e07aSXin Li     }
284*ec63e07aSXin Li   }
285*ec63e07aSXin Li 
286*ec63e07aSXin Li   SAPI_ASSIGN_OR_RETURN(rc, api.archive_write_close(&a));
287*ec63e07aSXin Li   if (rc != ARCHIVE_OK) {
288*ec63e07aSXin Li     return absl::FailedPreconditionError(
289*ec63e07aSXin Li         "Unexpected result from write_close call");
290*ec63e07aSXin Li   }
291*ec63e07aSXin Li 
292*ec63e07aSXin Li   SAPI_ASSIGN_OR_RETURN(rc, api.archive_write_free(&a));
293*ec63e07aSXin Li   if (rc != ARCHIVE_OK) {
294*ec63e07aSXin Li     return absl::FailedPreconditionError(
295*ec63e07aSXin Li         "Unexpected result from write_free call");
296*ec63e07aSXin Li   }
297*ec63e07aSXin Li 
298*ec63e07aSXin Li   return absl::OkStatus();
299*ec63e07aSXin Li }
300*ec63e07aSXin Li 
ExtractArchive(const char * filename,int do_extract,int flags,bool verbose)301*ec63e07aSXin Li absl::Status ExtractArchive(const char* filename, int do_extract, int flags,
302*ec63e07aSXin Li                             bool verbose) {
303*ec63e07aSXin Li   std::string tmp_dir;
304*ec63e07aSXin Li   if (do_extract) {
305*ec63e07aSXin Li     SAPI_ASSIGN_OR_RETURN(tmp_dir, CreateTempDirAtCWD());
306*ec63e07aSXin Li   }
307*ec63e07aSXin Li 
308*ec63e07aSXin Li   // We can use a struct like this in order to delete the temporary
309*ec63e07aSXin Li   // directory that was created earlier whenever the function ends.
310*ec63e07aSXin Li   struct ExtractTempDirectoryCleanup {
311*ec63e07aSXin Li     ExtractTempDirectoryCleanup(const std::string& dir) : dir_(dir) {}
312*ec63e07aSXin Li     ~ExtractTempDirectoryCleanup() {
313*ec63e07aSXin Li       sandbox2::file_util::fileops::DeleteRecursively(dir_);
314*ec63e07aSXin Li     }
315*ec63e07aSXin Li 
316*ec63e07aSXin Li    private:
317*ec63e07aSXin Li     std::string dir_;
318*ec63e07aSXin Li   };
319*ec63e07aSXin Li 
320*ec63e07aSXin Li   // We should only delete it if the do_extract flag is true which
321*ec63e07aSXin Li   // means that this struct is instantiated only in that case.
322*ec63e07aSXin Li   auto cleanup_ptr =
323*ec63e07aSXin Li       do_extract ? std::make_unique<ExtractTempDirectoryCleanup>(tmp_dir)
324*ec63e07aSXin Li                  : nullptr;
325*ec63e07aSXin Li 
326*ec63e07aSXin Li   std::string filename_absolute = MakeAbsolutePathAtCWD(filename);
327*ec63e07aSXin Li 
328*ec63e07aSXin Li   // Initialize sandbox and api objects.
329*ec63e07aSXin Li   SapiLibarchiveSandboxExtract sandbox(filename_absolute, do_extract, tmp_dir);
330*ec63e07aSXin Li   SAPI_RETURN_IF_ERROR(sandbox.Init());
331*ec63e07aSXin Li   LibarchiveApi api(&sandbox);
332*ec63e07aSXin Li 
333*ec63e07aSXin Li   SAPI_ASSIGN_OR_RETURN(archive * ret_archive, api.archive_read_new());
334*ec63e07aSXin Li   if (ret_archive == nullptr) {
335*ec63e07aSXin Li     return absl::FailedPreconditionError("Failed to create read archive");
336*ec63e07aSXin Li   }
337*ec63e07aSXin Li 
338*ec63e07aSXin Li   sapi::v::RemotePtr a(ret_archive);
339*ec63e07aSXin Li 
340*ec63e07aSXin Li   SAPI_ASSIGN_OR_RETURN(ret_archive, api.archive_write_disk_new());
341*ec63e07aSXin Li   if (ret_archive == nullptr) {
342*ec63e07aSXin Li     return absl::FailedPreconditionError("Failed to create write disk archive");
343*ec63e07aSXin Li   }
344*ec63e07aSXin Li 
345*ec63e07aSXin Li   sapi::v::RemotePtr ext(ret_archive);
346*ec63e07aSXin Li 
347*ec63e07aSXin Li   int rc;
348*ec63e07aSXin Li   std::string msg;
349*ec63e07aSXin Li 
350*ec63e07aSXin Li   SAPI_ASSIGN_OR_RETURN(rc, api.archive_write_disk_set_options(&ext, flags));
351*ec63e07aSXin Li   if (rc != ARCHIVE_OK) {
352*ec63e07aSXin Li     return absl::FailedPreconditionError(
353*ec63e07aSXin Li         "Unexpected result from write_disk_set_options call");
354*ec63e07aSXin Li   }
355*ec63e07aSXin Li 
356*ec63e07aSXin Li   SAPI_ASSIGN_OR_RETURN(rc, api.archive_read_support_filter_bzip2(&a));
357*ec63e07aSXin Li   if (rc != ARCHIVE_OK) {
358*ec63e07aSXin Li     return absl::FailedPreconditionError(
359*ec63e07aSXin Li         "Unexpected result from read_support_filter_bzip2 call");
360*ec63e07aSXin Li   }
361*ec63e07aSXin Li 
362*ec63e07aSXin Li   SAPI_ASSIGN_OR_RETURN(rc, api.archive_read_support_filter_gzip(&a));
363*ec63e07aSXin Li   if (rc != ARCHIVE_OK) {
364*ec63e07aSXin Li     return absl::FailedPreconditionError(
365*ec63e07aSXin Li         "Unexpected result from read_suppport_filter_gzip call");
366*ec63e07aSXin Li   }
367*ec63e07aSXin Li 
368*ec63e07aSXin Li   SAPI_ASSIGN_OR_RETURN(rc, api.archive_read_support_filter_compress(&a));
369*ec63e07aSXin Li   if (rc != ARCHIVE_OK) {
370*ec63e07aSXin Li     return absl::FailedPreconditionError(
371*ec63e07aSXin Li         "Unexpected result from read_support_filter_compress call");
372*ec63e07aSXin Li   }
373*ec63e07aSXin Li 
374*ec63e07aSXin Li   SAPI_ASSIGN_OR_RETURN(rc, api.archive_read_support_format_tar(&a));
375*ec63e07aSXin Li   if (rc != ARCHIVE_OK) {
376*ec63e07aSXin Li     return absl::FailedPreconditionError(
377*ec63e07aSXin Li         "Unexpected result fromread_support_format_tar call");
378*ec63e07aSXin Li   }
379*ec63e07aSXin Li 
380*ec63e07aSXin Li   SAPI_ASSIGN_OR_RETURN(rc, api.archive_read_support_format_cpio(&a));
381*ec63e07aSXin Li   if (rc != ARCHIVE_OK) {
382*ec63e07aSXin Li     return absl::FailedPreconditionError(
383*ec63e07aSXin Li         "Unexpected result from read_support_format_tar call");
384*ec63e07aSXin Li   }
385*ec63e07aSXin Li 
386*ec63e07aSXin Li   SAPI_ASSIGN_OR_RETURN(rc, api.archive_write_disk_set_standard_lookup(&ext));
387*ec63e07aSXin Li   if (rc != ARCHIVE_OK) {
388*ec63e07aSXin Li     return absl::FailedPreconditionError(
389*ec63e07aSXin Li         "Unexpected result from write_disk_set_standard_lookup call");
390*ec63e07aSXin Li   }
391*ec63e07aSXin Li 
392*ec63e07aSXin Li   const char* filename_ptr = filename_absolute.c_str();
393*ec63e07aSXin Li   if (filename_ptr != nullptr && strcmp(filename_ptr, "-") == 0) {
394*ec63e07aSXin Li     filename_ptr = nullptr;
395*ec63e07aSXin Li   }
396*ec63e07aSXin Li 
397*ec63e07aSXin Li   // The entries are saved with a relative path so they are all created
398*ec63e07aSXin Li   // relative to the current working directory.
399*ec63e07aSXin Li   SAPI_ASSIGN_OR_RETURN(
400*ec63e07aSXin Li       rc, api.archive_read_open_filename(
401*ec63e07aSXin Li               &a, sapi::v::ConstCStr(filename_ptr).PtrBefore(), kBlockSize));
402*ec63e07aSXin Li   if (rc != ARCHIVE_OK) {
403*ec63e07aSXin Li     SAPI_ASSIGN_OR_RETURN(
404*ec63e07aSXin Li         msg, CheckStatusAndGetString(api.archive_error_string(&a), sandbox));
405*ec63e07aSXin Li     return absl::FailedPreconditionError(msg);
406*ec63e07aSXin Li   }
407*ec63e07aSXin Li 
408*ec63e07aSXin Li   while (true) {
409*ec63e07aSXin Li     sapi::v::IntBase<archive_entry*> entry_ptr_tmp(0);
410*ec63e07aSXin Li 
411*ec63e07aSXin Li     SAPI_ASSIGN_OR_RETURN(
412*ec63e07aSXin Li         rc, api.archive_read_next_header(&a, entry_ptr_tmp.PtrAfter()));
413*ec63e07aSXin Li 
414*ec63e07aSXin Li     if (rc == ARCHIVE_EOF) {
415*ec63e07aSXin Li       break;
416*ec63e07aSXin Li     }
417*ec63e07aSXin Li 
418*ec63e07aSXin Li     if (rc != ARCHIVE_OK) {
419*ec63e07aSXin Li       SAPI_ASSIGN_OR_RETURN(
420*ec63e07aSXin Li           msg, CheckStatusAndGetString(api.archive_error_string(&a), sandbox));
421*ec63e07aSXin Li       return absl::FailedPreconditionError(msg);
422*ec63e07aSXin Li     }
423*ec63e07aSXin Li 
424*ec63e07aSXin Li     sapi::v::RemotePtr entry(entry_ptr_tmp.GetValue());
425*ec63e07aSXin Li 
426*ec63e07aSXin Li     if (verbose && do_extract) {
427*ec63e07aSXin Li       std::cout << "x ";
428*ec63e07aSXin Li     }
429*ec63e07aSXin Li 
430*ec63e07aSXin Li     if (verbose || !do_extract) {
431*ec63e07aSXin Li       SAPI_ASSIGN_OR_RETURN(
432*ec63e07aSXin Li           msg,
433*ec63e07aSXin Li           CheckStatusAndGetString(api.archive_entry_pathname(&entry), sandbox));
434*ec63e07aSXin Li       std::cout << msg << std::endl;
435*ec63e07aSXin Li     }
436*ec63e07aSXin Li 
437*ec63e07aSXin Li     if (do_extract) {
438*ec63e07aSXin Li       SAPI_ASSIGN_OR_RETURN(rc, api.archive_write_header(&ext, &entry));
439*ec63e07aSXin Li 
440*ec63e07aSXin Li       if (rc != ARCHIVE_OK) {
441*ec63e07aSXin Li         SAPI_ASSIGN_OR_RETURN(msg, CheckStatusAndGetString(
442*ec63e07aSXin Li                                        api.archive_error_string(&a), sandbox));
443*ec63e07aSXin Li         std::cout << msg << std::endl;
444*ec63e07aSXin Li       } else {
445*ec63e07aSXin Li         SAPI_ASSIGN_OR_RETURN(rc, CopyData(&a, &ext, api, sandbox));
446*ec63e07aSXin Li         if (rc != ARCHIVE_OK) {
447*ec63e07aSXin Li           return absl::FailedPreconditionError(
448*ec63e07aSXin Li               "Failed to copy data between archive structs.");
449*ec63e07aSXin Li         }
450*ec63e07aSXin Li       }
451*ec63e07aSXin Li     }
452*ec63e07aSXin Li   }
453*ec63e07aSXin Li 
454*ec63e07aSXin Li   SAPI_ASSIGN_OR_RETURN(rc, api.archive_read_close(&a));
455*ec63e07aSXin Li   if (rc != ARCHIVE_OK) {
456*ec63e07aSXin Li     return absl::FailedPreconditionError(
457*ec63e07aSXin Li         "Unexpected value from read_close call");
458*ec63e07aSXin Li   }
459*ec63e07aSXin Li 
460*ec63e07aSXin Li   SAPI_ASSIGN_OR_RETURN(rc, api.archive_read_free(&a));
461*ec63e07aSXin Li   if (rc != ARCHIVE_OK) {
462*ec63e07aSXin Li     return absl::FailedPreconditionError(
463*ec63e07aSXin Li         "Unexpected result from read_free call");
464*ec63e07aSXin Li   }
465*ec63e07aSXin Li 
466*ec63e07aSXin Li   SAPI_ASSIGN_OR_RETURN(rc, api.archive_write_close(&ext));
467*ec63e07aSXin Li   if (rc != ARCHIVE_OK) {
468*ec63e07aSXin Li     return absl::FailedPreconditionError(
469*ec63e07aSXin Li         "Unexpected result from write_close call");
470*ec63e07aSXin Li   }
471*ec63e07aSXin Li 
472*ec63e07aSXin Li   SAPI_ASSIGN_OR_RETURN(rc, api.archive_write_free(&ext));
473*ec63e07aSXin Li   if (rc != ARCHIVE_OK) {
474*ec63e07aSXin Li     return absl::FailedPreconditionError(
475*ec63e07aSXin Li         "Unexpected result from write_free call");
476*ec63e07aSXin Li   }
477*ec63e07aSXin Li 
478*ec63e07aSXin Li   return absl::OkStatus();
479*ec63e07aSXin Li }
480*ec63e07aSXin Li 
CopyData(sapi::v::RemotePtr * ar,sapi::v::RemotePtr * aw,LibarchiveApi & api,SapiLibarchiveSandboxExtract & sandbox)481*ec63e07aSXin Li absl::StatusOr<int> CopyData(sapi::v::RemotePtr* ar, sapi::v::RemotePtr* aw,
482*ec63e07aSXin Li                              LibarchiveApi& api,
483*ec63e07aSXin Li                              SapiLibarchiveSandboxExtract& sandbox) {
484*ec63e07aSXin Li   int rc;
485*ec63e07aSXin Li   std::string msg;
486*ec63e07aSXin Li 
487*ec63e07aSXin Li   sapi::v::IntBase<archive_entry*> buff_ptr_tmp(0);
488*ec63e07aSXin Li   sapi::v::ULLong size;
489*ec63e07aSXin Li   sapi::v::SLLong offset;
490*ec63e07aSXin Li 
491*ec63e07aSXin Li   while (true) {
492*ec63e07aSXin Li     SAPI_ASSIGN_OR_RETURN(
493*ec63e07aSXin Li         rc, api.archive_read_data_block(ar, buff_ptr_tmp.PtrAfter(),
494*ec63e07aSXin Li                                         size.PtrAfter(), offset.PtrAfter()));
495*ec63e07aSXin Li 
496*ec63e07aSXin Li     if (rc == ARCHIVE_EOF) {
497*ec63e07aSXin Li       return ARCHIVE_OK;
498*ec63e07aSXin Li     }
499*ec63e07aSXin Li     if (rc != ARCHIVE_OK) {
500*ec63e07aSXin Li       SAPI_ASSIGN_OR_RETURN(
501*ec63e07aSXin Li           msg, CheckStatusAndGetString(api.archive_error_string(ar), sandbox));
502*ec63e07aSXin Li       std::cout << msg << std::endl;
503*ec63e07aSXin Li       return rc;
504*ec63e07aSXin Li     }
505*ec63e07aSXin Li 
506*ec63e07aSXin Li     sapi::v::RemotePtr buff(buff_ptr_tmp.GetValue());
507*ec63e07aSXin Li 
508*ec63e07aSXin Li     SAPI_ASSIGN_OR_RETURN(
509*ec63e07aSXin Li         rc, api.archive_write_data_block(aw, &buff, size.GetValue(),
510*ec63e07aSXin Li                                          offset.GetValue()));
511*ec63e07aSXin Li 
512*ec63e07aSXin Li     if (rc != ARCHIVE_OK) {
513*ec63e07aSXin Li       SAPI_ASSIGN_OR_RETURN(
514*ec63e07aSXin Li           msg, CheckStatusAndGetString(api.archive_error_string(ar), sandbox));
515*ec63e07aSXin Li       std::cout << msg << std::endl;
516*ec63e07aSXin Li       return rc;
517*ec63e07aSXin Li     }
518*ec63e07aSXin Li   }
519*ec63e07aSXin Li }
520*ec63e07aSXin Li 
MakeAbsolutePathAtCWD(const std::string & path)521*ec63e07aSXin Li std::string MakeAbsolutePathAtCWD(const std::string& path) {
522*ec63e07aSXin Li   std::string result = sandbox2::file_util::fileops::MakeAbsolute(
523*ec63e07aSXin Li       path, sandbox2::file_util::fileops::GetCWD());
524*ec63e07aSXin Li   CHECK(result != "") << "Could not create absolute path for: " << path;
525*ec63e07aSXin Li   return sandbox2::file::CleanPath(result);
526*ec63e07aSXin Li }
527*ec63e07aSXin Li 
CheckStatusAndGetString(const absl::StatusOr<char * > & status,LibarchiveSandbox & sandbox)528*ec63e07aSXin Li absl::StatusOr<std::string> CheckStatusAndGetString(
529*ec63e07aSXin Li     const absl::StatusOr<char*>& status, LibarchiveSandbox& sandbox) {
530*ec63e07aSXin Li   SAPI_ASSIGN_OR_RETURN(char* str, status);
531*ec63e07aSXin Li   if (str == nullptr) {
532*ec63e07aSXin Li     return absl::FailedPreconditionError("Could not get string from archive");
533*ec63e07aSXin Li   }
534*ec63e07aSXin Li   return sandbox.GetCString(sapi::v::RemotePtr(str));
535*ec63e07aSXin Li }
536*ec63e07aSXin Li 
CreateTempDirAtCWD()537*ec63e07aSXin Li absl::StatusOr<std::string> CreateTempDirAtCWD() {
538*ec63e07aSXin Li   std::string cwd = sandbox2::file_util::fileops::GetCWD();
539*ec63e07aSXin Li   CHECK(!cwd.empty()) << "Could not get current working directory";
540*ec63e07aSXin Li   cwd.append("/");
541*ec63e07aSXin Li 
542*ec63e07aSXin Li   SAPI_ASSIGN_OR_RETURN(std::string result, sandbox2::CreateTempDir(cwd));
543*ec63e07aSXin Li   return result;
544*ec63e07aSXin Li }
545