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