diff --git a/oss-internship-2020/libarchive/CMakeLists.txt b/oss-internship-2020/libarchive/CMakeLists.txt index 7f07923..b2bf8d0 100644 --- a/oss-internship-2020/libarchive/CMakeLists.txt +++ b/oss-internship-2020/libarchive/CMakeLists.txt @@ -18,10 +18,10 @@ project(libarchive_sapi CXX) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED 17) +set(CMAKE_POSITION_INDEPENDENT_CODE TRUE) # Build SAPI library -#set(SAPI_ROOT "" CACHE PATH "Path to the Sandboxed API source tree") -set(SAPI_ROOT "/usr/local/google/home/amedar/internship/sandboxed-api" CACHE PATH "Path to the Sandboxed API source tree") +set(SAPI_ROOT "" CACHE PATH "Path to the Sandboxed API source tree") include(FetchContent) FetchContent_Declare( @@ -58,4 +58,4 @@ target_include_directories(libarchive_sapi INTERFACE add_subdirectory(examples) add_subdirectory(test) - +add_subdirectory(ld_preload_example) diff --git a/oss-internship-2020/libarchive/ld_preload_example/CMakeLists.txt b/oss-internship-2020/libarchive/ld_preload_example/CMakeLists.txt new file mode 100644 index 0000000..da41ede --- /dev/null +++ b/oss-internship-2020/libarchive/ld_preload_example/CMakeLists.txt @@ -0,0 +1,64 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +add_library(minitar_lib SHARED + minitar.cc + minitar.h +) + +target_link_libraries(minitar_lib PRIVATE + archive +) + +add_executable(minitar_original + minitar_main.cc +) + +target_link_libraries(minitar_original PRIVATE + minitar_lib +) + + +#=========== + +add_library(sapi_minitar_lib_shared SHARED + ../examples/sapi_minitar.cc + ../examples/sapi_minitar.h + ../examples/sandbox.h +) + +target_link_libraries(sapi_minitar_lib_shared PUBLIC + glog::glog + libarchive_sapi + sandbox2::executor + sandbox2::fileops + sandbox2::file_base + sandbox2::util + sandbox2::temp_file + sapi::sapi +) + +target_include_directories(sapi_minitar_lib_shared INTERFACE + "${PROJECT_SOURCE_DIR}/examples" +) + +#=========== + +add_library(minitar_preload SHARED + sapi_minitar.cc +) + +target_link_libraries(minitar_preload PRIVATE + sapi_minitar_lib_shared +) diff --git a/oss-internship-2020/libarchive/ld_preload_example/README.md b/oss-internship-2020/libarchive/ld_preload_example/README.md new file mode 100644 index 0000000..3d2ba80 --- /dev/null +++ b/oss-internship-2020/libarchive/ld_preload_example/README.md @@ -0,0 +1,25 @@ +# Sandboxing the minitar example (only the extraction function) using LD_PRELOAD + +## Description +Using `LD_PRELOAD` we can create our own functions with the same signatures as the ones from the libarchive that are called in the original code and call those instead. +This example only implements the extract part of the original tool. + +## Structure +- **minitar_main.cc** - the original main function. +- **minitar.cc** and **minitar.h** - original functions called from main, built into a shared library. +- **sapi_minitar.cc** - libarchive functions with our own implementation, built into a shared library which will be used with `LD_PRELOAD`. + +Most of the functions simply convert the arguments to sapi::v objects and calls the sandboxed version of the function. Also, there is a custom *extract* implementation that also created the sandbox object. If the sandbox could be created without special arguments then this would not be needed and could be done inside of the first function called. However, in our case, the sandbox requires the file path and so we do this in the *create* function where we have access to that path. Aftert this, we call the original function (the "next" function symbol). + +## Files changed from the original libarchive sandboxed version +The only changes are in the root CMakeLists.txt: + +- `add_subdirectory(ld_preload_example)` to add this current folder to the build process. + +- `set(CMAKE_POSITION_INDEPENDENT_CODE TRUE)` to make sure that shared libraries are built with position independent code. + +## Usage +`LD_PRELOAD= build/ld_preload_example/libminitar_preload.so build/ld_preload_example/minitar_original -xvf archive_file` + + +Instead of the *x* option, *t* can be used as well only to print the archive entries. \ No newline at end of file diff --git a/oss-internship-2020/libarchive/ld_preload_example/minitar.cc b/oss-internship-2020/libarchive/ld_preload_example/minitar.cc new file mode 100644 index 0000000..1de890b --- /dev/null +++ b/oss-internship-2020/libarchive/ld_preload_example/minitar.cc @@ -0,0 +1,310 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "minitar.h" // NOLINT(build/include) + +/* + * NO_CREATE implies NO_BZIP2_CREATE and NO_GZIP_CREATE and NO_COMPRESS_CREATE. + */ +#ifdef NO_CREATE +#undef NO_BZIP2_CREATE +#define NO_BZIP2_CREATE +#undef NO_COMPRESS_CREATE +#define NO_COMPRESS_CREATE +#undef NO_GZIP_CREATE +#define NO_GZIP_CREATE +#endif + +/* + * The combination of NO_BZIP2_CREATE and NO_BZIP2_EXTRACT is + * equivalent to NO_BZIP2. + */ +#ifdef NO_BZIP2_CREATE +#ifdef NO_BZIP2_EXTRACT +#undef NO_BZIP2 +#define NO_BZIP2 +#endif +#endif + +#ifdef NO_BZIP2 +#undef NO_BZIP2_EXTRACT +#define NO_BZIP2_EXTRACT +#undef NO_BZIP2_CREATE +#define NO_BZIP2_CREATE +#endif + +/* + * The combination of NO_COMPRESS_CREATE and NO_COMPRESS_EXTRACT is + * equivalent to NO_COMPRESS. + */ +#ifdef NO_COMPRESS_CREATE +#ifdef NO_COMPRESS_EXTRACT +#undef NO_COMPRESS +#define NO_COMPRESS +#endif +#endif + +#ifdef NO_COMPRESS +#undef NO_COMPRESS_EXTRACT +#define NO_COMPRESS_EXTRACT +#undef NO_COMPRESS_CREATE +#define NO_COMPRESS_CREATE +#endif + +/* + * The combination of NO_GZIP_CREATE and NO_GZIP_EXTRACT is + * equivalent to NO_GZIP. + */ +#ifdef NO_GZIP_CREATE +#ifdef NO_GZIP_EXTRACT +#undef NO_GZIP +#define NO_GZIP +#endif +#endif + +#ifdef NO_GZIP +#undef NO_GZIP_EXTRACT +#define NO_GZIP_EXTRACT +#undef NO_GZIP_CREATE +#define NO_GZIP_CREATE +#endif + +#ifndef NO_CREATE +void create(const char* filename, int compress, const char** argv); +#endif +void errmsg(const char*); +void extract(const char* filename, int do_extract, int flags); +int copy_data(struct archive*, struct archive*); +void msg(const char*); +void usage(void); + +#ifndef NO_CREATE + +void create(const char* filename, int compress, const char** argv, + int verbose) { + struct archive* a; + struct archive_entry* entry; + ssize_t len; + int fd; + + a = archive_write_new(); + switch (compress) { +#ifndef NO_BZIP2_CREATE + case 'j': + case 'y': + archive_write_add_filter_bzip2(a); + break; +#endif +#ifndef NO_COMPRESS_CREATE + case 'Z': + archive_write_add_filter_compress(a); + break; +#endif +#ifndef NO_GZIP_CREATE + case 'z': + archive_write_add_filter_gzip(a); + break; +#endif + default: + archive_write_add_filter_none(a); + break; + } + archive_write_set_format_ustar(a); + if (filename != NULL && strcmp(filename, "-") == 0) filename = NULL; + archive_write_open_filename(a, filename); + + while (*argv != NULL) { + struct archive* disk = archive_read_disk_new(); +#ifndef NO_LOOKUP + archive_read_disk_set_standard_lookup(disk); +#endif + int r; + + r = archive_read_disk_open(disk, *argv); + if (r != ARCHIVE_OK) { + errmsg(archive_error_string(disk)); + errmsg("\n"); + exit(1); + } + + for (;;) { + int needcr = 0; + + entry = archive_entry_new(); + r = archive_read_next_header2(disk, entry); + if (r == ARCHIVE_EOF) break; + if (r != ARCHIVE_OK) { + errmsg(archive_error_string(disk)); + errmsg("\n"); + exit(1); + } + archive_read_disk_descend(disk); + if (verbose) { + msg("a "); + msg(archive_entry_pathname(entry)); + needcr = 1; + } + r = archive_write_header(a, entry); + if (r < ARCHIVE_OK) { + errmsg(": "); + errmsg(archive_error_string(a)); + needcr = 1; + } + if (r == ARCHIVE_FATAL) exit(1); + if (r > ARCHIVE_FAILED) { + static char buff[16384]; + fd = open(archive_entry_sourcepath(entry), O_RDONLY); + len = read(fd, buff, sizeof(buff)); + while (len > 0) { + archive_write_data(a, buff, len); + len = read(fd, buff, sizeof(buff)); + } + close(fd); + } + archive_entry_free(entry); + if (needcr) msg("\n"); + } + archive_read_close(disk); + archive_read_free(disk); + argv++; + } + archive_write_close(a); + archive_write_free(a); +} +#endif + +void extract(const char* filename, int do_extract, int flags, int verbose) { + struct archive* a; + struct archive* ext; + struct archive_entry* entry; + int r; + + a = archive_read_new(); + ext = archive_write_disk_new(); + archive_write_disk_set_options(ext, flags); +#ifndef NO_BZIP2_EXTRACT + archive_read_support_filter_bzip2(a); +#endif +#ifndef NO_GZIP_EXTRACT + archive_read_support_filter_gzip(a); +#endif +#ifndef NO_COMPRESS_EXTRACT + archive_read_support_filter_compress(a); +#endif +#ifndef NO_TAR_EXTRACT + archive_read_support_format_tar(a); +#endif +#ifndef NO_CPIO_EXTRACT + archive_read_support_format_cpio(a); +#endif +#ifndef NO_LOOKUP + archive_write_disk_set_standard_lookup(ext); +#endif + if (filename != NULL && strcmp(filename, "-") == 0) filename = NULL; + if ((r = archive_read_open_filename(a, filename, 10240))) { + errmsg(archive_error_string(a)); + errmsg("\n"); + exit(r); + } + for (;;) { + int needcr = 0; + r = archive_read_next_header(a, &entry); + if (r == ARCHIVE_EOF) break; + if (r != ARCHIVE_OK) { + errmsg(archive_error_string(a)); + errmsg("\n"); + exit(1); + } + if (verbose && do_extract) msg("x "); + + if (verbose || !do_extract) { + std::cout << archive_entry_pathname(entry) << std::endl; + msg(" "); + needcr = 1; + } + if (do_extract) { + r = archive_write_header(ext, entry); + if (r != ARCHIVE_OK) { + errmsg(archive_error_string(a)); + needcr = 1; + } else { + r = copy_data(a, ext); + if (r != ARCHIVE_OK) needcr = 1; + } + } + if (needcr) msg("\n"); + } + archive_read_close(a); + archive_read_free(a); + + archive_write_close(ext); + archive_write_free(ext); + exit(0); +} + +int copy_data(struct archive* ar, struct archive* aw) { + int r; + const void* buff; + size_t size; + int64_t offset; + + for (;;) { + r = archive_read_data_block(ar, &buff, &size, &offset); + if (r == ARCHIVE_EOF) return (ARCHIVE_OK); + if (r != ARCHIVE_OK) { + errmsg(archive_error_string(ar)); + return (r); + } + r = archive_write_data_block(aw, buff, size, offset); + if (r != ARCHIVE_OK) { + errmsg(archive_error_string(ar)); + return (r); + } + } +} + +void msg(const char* m) { write(1, m, strlen(m)); } + +void errmsg(const char* m) { + if (m == NULL) { + m = "Error: No error description provided.\n"; + } + write(2, m, strlen(m)); +} + +void usage(void) { + /* Many program options depend on compile options. */ + const char* m = + "Usage: minitar [-" +#ifndef NO_CREATE + "c" +#endif +#ifndef NO_BZIP2 + "j" +#endif + "tvx" +#ifndef NO_BZIP2 + "y" +#endif +#ifndef NO_COMPRESS + "Z" +#endif +#ifndef NO_GZIP + "z" +#endif + "] [-f file] [file]\n"; + + errmsg(m); + exit(1); +} diff --git a/oss-internship-2020/libarchive/ld_preload_example/minitar.h b/oss-internship-2020/libarchive/ld_preload_example/minitar.h new file mode 100644 index 0000000..7c76f10 --- /dev/null +++ b/oss-internship-2020/libarchive/ld_preload_example/minitar.h @@ -0,0 +1,100 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * NO_CREATE implies NO_BZIP2_CREATE and NO_GZIP_CREATE and NO_COMPRESS_CREATE. + */ +#ifdef NO_CREATE +#undef NO_BZIP2_CREATE +#define NO_BZIP2_CREATE +#undef NO_COMPRESS_CREATE +#define NO_COMPRESS_CREATE +#undef NO_GZIP_CREATE +#define NO_GZIP_CREATE +#endif + +/* + * The combination of NO_BZIP2_CREATE and NO_BZIP2_EXTRACT is + * equivalent to NO_BZIP2. + */ +#ifdef NO_BZIP2_CREATE +#ifdef NO_BZIP2_EXTRACT +#undef NO_BZIP2 +#define NO_BZIP2 +#endif +#endif + +#ifdef NO_BZIP2 +#undef NO_BZIP2_EXTRACT +#define NO_BZIP2_EXTRACT +#undef NO_BZIP2_CREATE +#define NO_BZIP2_CREATE +#endif + +/* + * The combination of NO_COMPRESS_CREATE and NO_COMPRESS_EXTRACT is + * equivalent to NO_COMPRESS. + */ +#ifdef NO_COMPRESS_CREATE +#ifdef NO_COMPRESS_EXTRACT +#undef NO_COMPRESS +#define NO_COMPRESS +#endif +#endif + +#ifdef NO_COMPRESS +#undef NO_COMPRESS_EXTRACT +#define NO_COMPRESS_EXTRACT +#undef NO_COMPRESS_CREATE +#define NO_COMPRESS_CREATE +#endif + +/* + * The combination of NO_GZIP_CREATE and NO_GZIP_EXTRACT is + * equivalent to NO_GZIP. + */ +#ifdef NO_GZIP_CREATE +#ifdef NO_GZIP_EXTRACT +#undef NO_GZIP +#define NO_GZIP +#endif +#endif + +#ifdef NO_GZIP +#undef NO_GZIP_EXTRACT +#define NO_GZIP_EXTRACT +#undef NO_GZIP_CREATE +#define NO_GZIP_CREATE +#endif + +#ifndef NO_CREATE +void create(const char *filename, int compress, const char **argv, int verbose = 1); +#endif +void errmsg(const char *); +void extract(const char *filename, int do_extract, int flags, int verbose = 1); +int copy_data(struct archive *, struct archive *); +void msg(const char *); +void usage(void); diff --git a/oss-internship-2020/libarchive/ld_preload_example/minitar_main.cc b/oss-internship-2020/libarchive/ld_preload_example/minitar_main.cc new file mode 100644 index 0000000..a59719d --- /dev/null +++ b/oss-internship-2020/libarchive/ld_preload_example/minitar_main.cc @@ -0,0 +1,195 @@ +/*- + * This file is in the public domain. + * Do with it as you will. + */ + +/*- + * This is a compact "tar" program whose primary goal is small size. + * Statically linked, it can be very small indeed. This serves a number + * of goals: + * o a testbed for libarchive (to check for link pollution), + * o a useful tool for space-constrained systems (boot floppies, etc), + * o a place to experiment with new implementation ideas for bsdtar, + * o a small program to demonstrate libarchive usage. + * + * Use the following macros to suppress features: + * NO_BZIP2 - Implies NO_BZIP2_CREATE and NO_BZIP2_EXTRACT + * NO_BZIP2_CREATE - Suppress bzip2 compression support. + * NO_BZIP2_EXTRACT - Suppress bzip2 auto-detection and decompression. + * NO_COMPRESS - Implies NO_COMPRESS_CREATE and NO_COMPRESS_EXTRACT + * NO_COMPRESS_CREATE - Suppress compress(1) compression support + * NO_COMPRESS_EXTRACT - Suppress compress(1) auto-detect and decompression. + * NO_CREATE - Suppress all archive creation support. + * NO_CPIO_EXTRACT - Suppress auto-detect and dearchiving of cpio archives. + * NO_GZIP - Implies NO_GZIP_CREATE and NO_GZIP_EXTRACT + * NO_GZIP_CREATE - Suppress gzip compression support. + * NO_GZIP_EXTRACT - Suppress gzip auto-detection and decompression. + * NO_LOOKUP - Try to avoid getpw/getgr routines, which can be very large + * NO_TAR_EXTRACT - Suppress tar extraction + * + * With all of the above macros defined (except NO_TAR_EXTRACT), you + * get a very small program that can recognize and extract essentially + * any uncompressed tar archive. On FreeBSD 5.1, this minimal program + * is under 64k, statically linked, which compares rather favorably to + * main(){printf("hello, world");} + * which is over 60k statically linked on the same operating system. + * Without any of the above macros, you get a static executable of + * about 180k with a lot of very sophisticated modern features. + * Obviously, it's trivial to add support for ISO, Zip, mtree, + * lzma/xz, etc. Just fill in the appropriate setup calls. + */ + +#include "minitar.h" // NOLINT(build/include) + +/* + * NO_CREATE implies NO_BZIP2_CREATE and NO_GZIP_CREATE and NO_COMPRESS_CREATE. + */ +#ifdef NO_CREATE +#undef NO_BZIP2_CREATE +#define NO_BZIP2_CREATE +#undef NO_COMPRESS_CREATE +#define NO_COMPRESS_CREATE +#undef NO_GZIP_CREATE +#define NO_GZIP_CREATE +#endif + +/* + * The combination of NO_BZIP2_CREATE and NO_BZIP2_EXTRACT is + * equivalent to NO_BZIP2. + */ +#ifdef NO_BZIP2_CREATE +#ifdef NO_BZIP2_EXTRACT +#undef NO_BZIP2 +#define NO_BZIP2 +#endif +#endif + +#ifdef NO_BZIP2 +#undef NO_BZIP2_EXTRACT +#define NO_BZIP2_EXTRACT +#undef NO_BZIP2_CREATE +#define NO_BZIP2_CREATE +#endif + +/* + * The combination of NO_COMPRESS_CREATE and NO_COMPRESS_EXTRACT is + * equivalent to NO_COMPRESS. + */ +#ifdef NO_COMPRESS_CREATE +#ifdef NO_COMPRESS_EXTRACT +#undef NO_COMPRESS +#define NO_COMPRESS +#endif +#endif + +#ifdef NO_COMPRESS +#undef NO_COMPRESS_EXTRACT +#define NO_COMPRESS_EXTRACT +#undef NO_COMPRESS_CREATE +#define NO_COMPRESS_CREATE +#endif + +/* + * The combination of NO_GZIP_CREATE and NO_GZIP_EXTRACT is + * equivalent to NO_GZIP. + */ +#ifdef NO_GZIP_CREATE +#ifdef NO_GZIP_EXTRACT +#undef NO_GZIP +#define NO_GZIP +#endif +#endif + +#ifdef NO_GZIP +#undef NO_GZIP_EXTRACT +#define NO_GZIP_EXTRACT +#undef NO_GZIP_CREATE +#define NO_GZIP_CREATE +#endif + +int main(int unused_argc, const char** argv) { + const char* filename = nullptr; + int compress; + int flags; + int mode; + int opt; + + mode = 'x'; + int verbose = 0; + compress = '\0'; + flags = ARCHIVE_EXTRACT_TIME; + + /* Among other sins, getopt(3) pulls in printf(3). */ + while (*++argv != nullptr && **argv == '-') { + const char* p = *argv + 1; + + while ((opt = *p++) != '\0') { + switch (opt) { +#ifndef NO_CREATE + case 'c': + mode = opt; + break; +#endif + case 'f': + if (*p != '\0') + filename = p; + else + filename = *++argv; + p += strlen(p); + break; +#ifndef NO_BZIP2_CREATE + case 'j': + compress = opt; + break; +#endif + case 'p': + flags |= ARCHIVE_EXTRACT_PERM; + flags |= ARCHIVE_EXTRACT_ACL; + flags |= ARCHIVE_EXTRACT_FFLAGS; + break; + case 't': + mode = opt; + break; + case 'v': + verbose++; + break; + case 'x': + mode = opt; + break; +#ifndef NO_BZIP2_CREATE + case 'y': + compress = opt; + break; +#endif +#ifndef NO_COMPRESS_CREATE + case 'Z': + compress = opt; + break; +#endif +#ifndef NO_GZIP_CREATE + case 'z': + compress = opt; + break; +#endif + default: + usage(); + } + } + } + + switch (mode) { +#ifndef NO_CREATE + case 'c': + create(filename, compress, argv, verbose); + break; +#endif + case 't': + extract(filename, 0, flags, verbose); + break; + case 'x': + extract(filename, 1, flags, verbose); + break; + } + + return (0); +} diff --git a/oss-internship-2020/libarchive/ld_preload_example/sapi_minitar.cc b/oss-internship-2020/libarchive/ld_preload_example/sapi_minitar.cc new file mode 100644 index 0000000..a83ffd8 --- /dev/null +++ b/oss-internship-2020/libarchive/ld_preload_example/sapi_minitar.cc @@ -0,0 +1,207 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "sapi_minitar.h" // NOLINT(build/include) + +#include + +#include +#include + +#include "libarchive_sapi.sapi.h" // NOLINT(build/include) +#include "sandbox.h" // NOLINT(build/include) +#include "sandboxed_api/var_array.h" +#include "sandboxed_api/var_ptr.h" + +std::unique_ptr sandbox_extract; +std::unique_ptr api; + +struct ExtractTempDirectoryCleanup { + ExtractTempDirectoryCleanup(const std::string& dir) : dir_(dir) {} + ~ExtractTempDirectoryCleanup() { + sandbox2::file_util::fileops::DeleteRecursively(dir_); + } + + private: + std::string dir_; +}; + +std::unique_ptr cleanup_ptr; + +typedef void (*real_extract)(const char*, int, int, int); + +void extract(const char* filename, int do_extract, int flags, int verbose) { + // Here we initialize the sandbox and other objects. + std::string tmp_dir; + if (do_extract) { + tmp_dir = CreateTempDirAtCWD().value(); + cleanup_ptr = absl::make_unique(tmp_dir); + } + + std::string filename_absolute = MakeAbsolutePathAtCWD(filename); + + // Initialize sandbox and api objects. + sandbox_extract = absl::make_unique( + filename_absolute, do_extract, tmp_dir); + CHECK(sandbox_extract->Init().ok()) << "Error during sandbox initialization"; + api = absl::make_unique(sandbox_extract.get()); + + // After everything is set up, call the original function (next symbol). + + // TODO getting the mangled name of the function at runtime does not work + // as intended. At the moment just use the symbol directly. + const char* y = "_Z7extractPKciii"; + void* x = dlsym(RTLD_NEXT, y); + + CHECK(x != nullptr) << "dlsym call could not find function symbol"; + ((real_extract)x)(filename_absolute.c_str(), do_extract, flags, verbose); +} + +archive* archive_read_new() { + archive* ret = api->archive_read_new().value(); + CHECK(ret != nullptr) << "Failed to create archive"; + return ret; +} + +archive* archive_write_disk_new() { + archive* ret = api->archive_write_disk_new().value(); + CHECK(ret != nullptr) << "Failed to create archive"; + return ret; +} + +int archive_write_disk_set_options(archive* ext, int flags) { + sapi::v::RemotePtr ext_ptr(ext); + + return api->archive_write_disk_set_options(&ext_ptr, flags).value(); +} + +int archive_read_support_filter_bzip2(archive* a) { + sapi::v::RemotePtr a_ptr(a); + return api->archive_read_support_filter_bzip2(&a_ptr).value(); +} + +int archive_read_support_filter_gzip(archive* a) { + sapi::v::RemotePtr a_ptr(a); + return api->archive_read_support_filter_gzip(&a_ptr).value(); +} + +int archive_read_support_filter_compress(archive* a) { + sapi::v::RemotePtr a_ptr(a); + return api->archive_read_support_filter_compress(&a_ptr).value(); +} +int archive_read_support_format_tar(archive* a) { + sapi::v::RemotePtr a_ptr(a); + return api->archive_read_support_format_tar(&a_ptr).value(); +} + +int archive_read_support_format_cpio(archive* a) { + sapi::v::RemotePtr a_ptr(a); + return api->archive_read_support_format_cpio(&a_ptr).value(); +} + +int archive_write_disk_set_standard_lookup(archive* ext) { + sapi::v::RemotePtr ext_ptr(ext); + + return api->archive_write_disk_set_standard_lookup(&ext_ptr).value(); +} + +int archive_read_open_filename(archive* a, const char* _filename, + size_t _block_size) { + sapi::v::RemotePtr a_ptr(a); + + return api + ->archive_read_open_filename( + &a_ptr, sapi::v::ConstCStr(_filename).PtrBefore(), _block_size) + .value(); +} + +const char* archive_error_string(archive* a) { + sapi::v::RemotePtr a_ptr(a); + char* str = api->archive_error_string(&a_ptr).value(); + CHECK(str != nullptr) << "Could not get error message"; + return sandbox_extract->GetCString(sapi::v::RemotePtr(str)).value().c_str(); +} + +int archive_read_next_header(archive* a, archive_entry** entry) { + sapi::v::IntBase entry_ptr_tmp(0); + sapi::v::RemotePtr a_ptr(a); + int rc = + api->archive_read_next_header(&a_ptr, entry_ptr_tmp.PtrAfter()).value(); + *entry = entry_ptr_tmp.GetValue(); + return rc; +} + +// Keep a global variable so that it does not go out of scope. +std::string str_tmp; + +const char* archive_entry_pathname(archive_entry* entry) { + sapi::v::RemotePtr entry_ptr(entry); + char* str = api->archive_entry_pathname(&entry_ptr).value(); + CHECK(str != nullptr) << "Could not get error message"; + + str_tmp = sandbox_extract->GetCString(sapi::v::RemotePtr(str)).value(); + + return str_tmp.c_str(); +} + +int archive_read_close(archive* a) { + sapi::v::RemotePtr a_ptr(a); + return api->archive_read_close(&a_ptr).value(); +} + +int archive_read_free(archive* a) { + sapi::v::RemotePtr a_ptr(a); + return api->archive_read_free(&a_ptr).value(); +} + +int archive_write_close(archive* a) { + sapi::v::RemotePtr a_ptr(a); + return api->archive_write_close(&a_ptr).value(); +} + +int archive_write_free(archive* a) { + sapi::v::RemotePtr a_ptr(a); + return api->archive_write_free(&a_ptr).value(); +} + +int archive_write_header(archive* a, archive_entry* entry) { + sapi::v::RemotePtr a_ptr(a), entry_ptr(entry); + return api->archive_write_header(&a_ptr, &entry_ptr).value(); +} + +int archive_read_data_block(archive* a, const void** buff, size_t* size, + la_int64_t* offset) { + sapi::v::IntBase buff_ptr_tmp(0); + sapi::v::ULLong size_tmp; + sapi::v::SLLong offset_tmp; + sapi::v::RemotePtr a_ptr(a); + + int rv = + api->archive_read_data_block(&a_ptr, buff_ptr_tmp.PtrAfter(), + size_tmp.PtrAfter(), offset_tmp.PtrAfter()) + .value(); + *buff = buff_ptr_tmp.GetValue(); + *size = size_tmp.GetValue(); + *offset = offset_tmp.GetValue(); + + return rv; +} + +la_ssize_t archive_write_data_block(archive* a, const void* buff, size_t s, + la_int64_t o) { + sapi::v::RemotePtr buff_ptr((void*)(buff)); + sapi::v::RemotePtr a_ptr(a); + + return api->archive_write_data_block(&a_ptr, &buff_ptr, s, o).value(); +}