mirror of
https://github.com/google/sandboxed-api.git
synced 2024-03-22 13:11:30 +08:00
Added unit tests. Cleaned up the code and added comments. Added README
This commit is contained in:
parent
7e6872ee26
commit
efe48ccca6
|
@ -22,33 +22,8 @@ set(CMAKE_CXX_STANDARD_REQUIRED 17)
|
||||||
# Build SAPI library
|
# Build SAPI library
|
||||||
set(SAPI_ROOT "/usr/local/google/home/amedar/internship/sandboxed-api" 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")
|
||||||
|
|
||||||
file(MAKE_DIRECTORY "${PROJECT_BINARY_DIR}/patches")
|
|
||||||
|
|
||||||
#add_custom_command(
|
|
||||||
# OUTPUT "${PROJECT_BINARY_DIR}/patches/archive.h"
|
|
||||||
# COMMENT "Applying patches."
|
|
||||||
# COMMAND cp "${PROJECT_SOURCE_DIR}/patches/header.patch" "${PROJECT_BINARY_DIR}/patches/"
|
|
||||||
# COMMAND cp "${PROJECT_SOURCE_DIR}/libarchive/libarchive/archive.h" "${PROJECT_BINARY_DIR}/patches/"
|
|
||||||
# COMMAND cd "${PROJECT_BINARY_DIR}/patches" && patch < header.patch
|
|
||||||
# COMMAND cp "${PROJECT_BINARY_DIR}/patches/archive.h" "${PROJECT_SOURCE_DIR}/libarchive/libarchive/"
|
|
||||||
#)
|
|
||||||
#
|
|
||||||
#set_property(
|
|
||||||
# SOURCE
|
|
||||||
# "${PROJECT_SOURCE_DIR}/libarchive/libarchive/archive.h"
|
|
||||||
# APPEND PROPERTY OBJECT_DEPENDS
|
|
||||||
# "${PROJECT_BINARY_DIR}/patches/archive.h"
|
|
||||||
#)
|
|
||||||
|
|
||||||
|
|
||||||
add_subdirectory(libarchive)
|
add_subdirectory(libarchive)
|
||||||
|
|
||||||
#set_property(SOURCE
|
|
||||||
# "${PROJECT_SOURCE_DIR}/libarchive/libarchive/archive.h"
|
|
||||||
# APPEND PROPERTY OBJECT_DEPENDS
|
|
||||||
# "${PROJECT_SOURCE_DIR}/patches/archive.h"
|
|
||||||
#)
|
|
||||||
|
|
||||||
add_subdirectory("${SAPI_ROOT}"
|
add_subdirectory("${SAPI_ROOT}"
|
||||||
"${CMAKE_BINARY_DIR}/sandboxed-api-build"
|
"${CMAKE_BINARY_DIR}/sandboxed-api-build"
|
||||||
EXCLUDE_FROM_ALL
|
EXCLUDE_FROM_ALL
|
||||||
|
@ -62,8 +37,8 @@ add_sapi_library(
|
||||||
FUNCTIONS ${FUNCTIONS_LIST}
|
FUNCTIONS ${FUNCTIONS_LIST}
|
||||||
|
|
||||||
INPUTS
|
INPUTS
|
||||||
libarchive/libarchive/archive.h
|
libarchive/libarchive/archive.h
|
||||||
libarchive/libarchive/archive_entry.h
|
libarchive/libarchive/archive_entry.h
|
||||||
|
|
||||||
LIBRARY archive_static
|
LIBRARY archive_static
|
||||||
LIBRARY_NAME Libarchive
|
LIBRARY_NAME Libarchive
|
||||||
|
@ -74,6 +49,5 @@ target_include_directories(libarchive_sapi INTERFACE
|
||||||
"${PROJECT_BINARY_DIR}" # To find the generated SAPI header
|
"${PROJECT_BINARY_DIR}" # To find the generated SAPI header
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
add_subdirectory(examples)
|
add_subdirectory(examples)
|
||||||
add_subdirectory(test)
|
add_subdirectory(test)
|
|
@ -0,0 +1,53 @@
|
||||||
|
# libarchive Sandboxed API
|
||||||
|
|
||||||
|
Sandboxed version of the [libarchive](https://www.libarchive.org/) minitar [example](https://github.com/libarchive/libarchive/blob/master/examples/minitar/minitar.c) using [Sandboxed API](https://github.com/google/sandboxed-api).
|
||||||
|
|
||||||
|
## Build
|
||||||
|
|
||||||
|
First, run `git submodule update --init --recursive` to update submodules.
|
||||||
|
After this, run the following commands:
|
||||||
|
|
||||||
|
`mkdir -p build && cd build`
|
||||||
|
|
||||||
|
`cmake .. -G Ninja`
|
||||||
|
|
||||||
|
`cmake --build .`
|
||||||
|
|
||||||
|
|
||||||
|
The example binary file can be found at `build/examples/sapi_minitar` and the unit tests at `build/test/sapi_minitar_test`.
|
||||||
|
|
||||||
|
## Patches
|
||||||
|
TODO
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
In this project, the minitar example is sandboxed.
|
||||||
|
The code is found in the **examples** directory and is structured as follows:
|
||||||
|
- **sapi_minitar_main.cc** - ***main*** function of the minitar tool. This is mostly similar to the original example.
|
||||||
|
- **sapi_minitar.h** and **sapi_minitar.cc** - The two main functions (***create*** and ***extract***) and also other helper functions.
|
||||||
|
- **sandbox.h** - Custom security policies, depending on the whether the user creates or extracts an archive.
|
||||||
|
|
||||||
|
|
||||||
|
On top of that, unit tests can be found in the **test/minitar_test.cc** file.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
The unit tests can be executed with `./build/test/sapi_minitar_test`.
|
||||||
|
|
||||||
|
The **sapi_minitar** command line tool can be used in the same way as the original example. It is also similar to the [tar](https://man7.org/linux/man-pages/man1/tar.1.html) command, only with fewer options:
|
||||||
|
|
||||||
|
`./build/examples/sapi_minitar -[options] [-f file] [files]`
|
||||||
|
|
||||||
|
The available options are:
|
||||||
|
- *c* - Create archive.
|
||||||
|
- *x* - Extract archive.
|
||||||
|
- *t* - Extract archive but only print entries.
|
||||||
|
- *p* - Preserve.
|
||||||
|
- *v* - Verbose.
|
||||||
|
- *j* or *y* - Compress with BZIP2.
|
||||||
|
- *Z* - Default compression.
|
||||||
|
- *z* - Compress with GZIP.
|
||||||
|
|
||||||
|
If no compression method is chosen (in the case of archive creation) the files will only be archived.
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,7 @@ target_link_libraries(sapi_minitar_lib PUBLIC
|
||||||
)
|
)
|
||||||
|
|
||||||
target_include_directories(sapi_minitar_lib INTERFACE
|
target_include_directories(sapi_minitar_lib INTERFACE
|
||||||
"${PROJECT_SOURCE_DIR}/examples"
|
"${PROJECT_SOURCE_DIR}/examples"
|
||||||
)
|
)
|
||||||
|
|
||||||
add_executable(sapi_minitar
|
add_executable(sapi_minitar
|
||||||
|
@ -38,16 +38,5 @@ add_executable(sapi_minitar
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(sapi_minitar PRIVATE
|
target_link_libraries(sapi_minitar PRIVATE
|
||||||
#libarchive_sapi
|
|
||||||
#sapi::sapi
|
|
||||||
sapi_minitar_lib
|
sapi_minitar_lib
|
||||||
#glog::glog
|
)
|
||||||
)
|
|
||||||
|
|
||||||
add_executable(minitar
|
|
||||||
orig/minitar.cc
|
|
||||||
)
|
|
||||||
|
|
||||||
target_link_libraries(minitar PRIVATE
|
|
||||||
archive
|
|
||||||
)
|
|
|
@ -1,478 +0,0 @@
|
||||||
/*-
|
|
||||||
* 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 <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
|
|
||||||
#include <archive.h>
|
|
||||||
#include <archive_entry.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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
|
|
||||||
static void create(const char *filename, int compress, const char **argv);
|
|
||||||
#endif
|
|
||||||
static void errmsg(const char *);
|
|
||||||
static void extract(const char *filename, int do_extract, int flags);
|
|
||||||
static int copy_data(struct archive *, struct archive *);
|
|
||||||
static void msg(const char *);
|
|
||||||
static void usage(void);
|
|
||||||
|
|
||||||
static int verbose = 0;
|
|
||||||
|
|
||||||
int
|
|
||||||
main(int argc, const char **argv)
|
|
||||||
{
|
|
||||||
std::cout << "BEGIN\n";
|
|
||||||
const char *filename = NULL;
|
|
||||||
int compress, flags, mode, opt;
|
|
||||||
|
|
||||||
(void)argc;
|
|
||||||
mode = 'x';
|
|
||||||
verbose = 0;
|
|
||||||
compress = '\0';
|
|
||||||
flags = ARCHIVE_EXTRACT_TIME;
|
|
||||||
|
|
||||||
/* Among other sins, getopt(3) pulls in printf(3). */
|
|
||||||
while (*++argv != NULL && **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);
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
case 't':
|
|
||||||
extract(filename, 0, flags);
|
|
||||||
break;
|
|
||||||
case 'x':
|
|
||||||
extract(filename, 1, flags);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef NO_CREATE
|
|
||||||
static char buff[16384];
|
|
||||||
|
|
||||||
static void
|
|
||||||
create(const char *filename, int compress, const char **argv)
|
|
||||||
{
|
|
||||||
|
|
||||||
std::cout << "CREATE FILENAME=" << filename << std::endl;
|
|
||||||
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) {
|
|
||||||
std::cout << "handling file = " << *argv << std::endl;
|
|
||||||
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) {
|
|
||||||
std::cout << " --- error here, code = " << r << " --- " << std::endl;
|
|
||||||
errmsg(": ");
|
|
||||||
errmsg(archive_error_string(a));
|
|
||||||
needcr = 1;
|
|
||||||
}
|
|
||||||
if (r == ARCHIVE_FATAL)
|
|
||||||
exit(1);
|
|
||||||
if (r > ARCHIVE_FAILED) {
|
|
||||||
#if 0
|
|
||||||
/* Ideally, we would be able to use
|
|
||||||
* the same code to copy a body from
|
|
||||||
* an archive_read_disk to an
|
|
||||||
* archive_write that we use for
|
|
||||||
* copying data from an archive_read
|
|
||||||
* to an archive_write_disk.
|
|
||||||
* Unfortunately, this doesn't quite
|
|
||||||
* work yet. */
|
|
||||||
copy_data(disk, a);
|
|
||||||
#else
|
|
||||||
/* For now, we use a simpler loop to copy data
|
|
||||||
* into the target archive. */
|
|
||||||
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);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
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
|
|
||||||
|
|
||||||
static void
|
|
||||||
extract(const char *filename, int do_extract, int flags)
|
|
||||||
{
|
|
||||||
|
|
||||||
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) {
|
|
||||||
msg(archive_entry_pathname(entry));
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
static 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
msg(const char *m)
|
|
||||||
{
|
|
||||||
write(1, m, strlen(m));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
errmsg(const char *m)
|
|
||||||
{
|
|
||||||
if (m == NULL) {
|
|
||||||
m = "Error: No error description provided.\n";
|
|
||||||
}
|
|
||||||
write(2, m, strlen(m));
|
|
||||||
}
|
|
||||||
|
|
||||||
static 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);
|
|
||||||
}
|
|
|
@ -1,113 +0,0 @@
|
||||||
/*
|
|
||||||
* This file is in the public domain.
|
|
||||||
*
|
|
||||||
* Feel free to use it as you wish.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This example program reads an archive from stdin (which can be in
|
|
||||||
* any format recognized by libarchive) and writes certain entries to
|
|
||||||
* an uncompressed ustar archive on stdout. This is a template for
|
|
||||||
* many kinds of archive manipulation: converting formats, resetting
|
|
||||||
* ownership, inserting entries, removing entries, etc.
|
|
||||||
*
|
|
||||||
* To compile:
|
|
||||||
* gcc -Wall -o tarfilter tarfilter.c -larchive -lz -lbz2
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <archive.h>
|
|
||||||
#include <archive_entry.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
static void
|
|
||||||
die(char *fmt, ...)
|
|
||||||
{
|
|
||||||
va_list ap;
|
|
||||||
|
|
||||||
va_start(ap, fmt);
|
|
||||||
vfprintf(stderr, fmt, ap);
|
|
||||||
va_end(ap);
|
|
||||||
fprintf(stderr, "\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
main(int argc, char **argv)
|
|
||||||
{
|
|
||||||
char buff[8192];
|
|
||||||
ssize_t len;
|
|
||||||
int r;
|
|
||||||
mode_t m;
|
|
||||||
struct archive *ina;
|
|
||||||
struct archive *outa;
|
|
||||||
struct archive_entry *entry;
|
|
||||||
|
|
||||||
/* Read an archive from stdin, with automatic format detection. */
|
|
||||||
ina = archive_read_new();
|
|
||||||
if (ina == NULL)
|
|
||||||
die("Couldn't create archive reader.");
|
|
||||||
if (archive_read_support_filter_all(ina) != ARCHIVE_OK)
|
|
||||||
die("Couldn't enable decompression");
|
|
||||||
if (archive_read_support_format_all(ina) != ARCHIVE_OK)
|
|
||||||
die("Couldn't enable read formats");
|
|
||||||
if (archive_read_open_fd(ina, 0, 10240) != ARCHIVE_OK)
|
|
||||||
die("Couldn't open input archive");
|
|
||||||
|
|
||||||
/* Write an uncompressed ustar archive to stdout. */
|
|
||||||
outa = archive_write_new();
|
|
||||||
if (outa == NULL)
|
|
||||||
die("Couldn't create archive writer.");
|
|
||||||
if (archive_write_set_compression_none(outa) != ARCHIVE_OK)
|
|
||||||
die("Couldn't enable compression");
|
|
||||||
if (archive_write_set_format_ustar(outa) != ARCHIVE_OK)
|
|
||||||
die("Couldn't set output format");
|
|
||||||
if (archive_write_open_fd(outa, 1) != ARCHIVE_OK)
|
|
||||||
die("Couldn't open output archive");
|
|
||||||
|
|
||||||
/* Examine each entry in the input archive. */
|
|
||||||
while ((r = archive_read_next_header(ina, &entry)) == ARCHIVE_OK) {
|
|
||||||
fprintf(stderr, "%s: ", archive_entry_pathname(entry));
|
|
||||||
|
|
||||||
/* Skip anything that isn't a regular file. */
|
|
||||||
if (!S_ISREG(archive_entry_mode(entry))) {
|
|
||||||
fprintf(stderr, "skipped\n");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Make everything owned by root/wheel. */
|
|
||||||
archive_entry_set_uid(entry, 0);
|
|
||||||
archive_entry_set_uname(entry, "root");
|
|
||||||
archive_entry_set_gid(entry, 0);
|
|
||||||
archive_entry_set_gname(entry, "wheel");
|
|
||||||
|
|
||||||
/* Make everything permission 0744, strip SUID, etc. */
|
|
||||||
m = archive_entry_mode(entry);
|
|
||||||
archive_entry_set_mode(entry, (m & ~07777) | 0744);
|
|
||||||
|
|
||||||
/* Copy input entries to output archive. */
|
|
||||||
if (archive_write_header(outa, entry) != ARCHIVE_OK)
|
|
||||||
die("Error writing output archive");
|
|
||||||
if (archive_entry_size(entry) > 0) {
|
|
||||||
len = archive_read_data(ina, buff, sizeof(buff));
|
|
||||||
while (len > 0) {
|
|
||||||
if (archive_write_data(outa, buff, len) != len)
|
|
||||||
die("Error writing output archive");
|
|
||||||
len = archive_read_data(ina, buff, sizeof(buff));
|
|
||||||
}
|
|
||||||
if (len < 0)
|
|
||||||
die("Error reading input archive");
|
|
||||||
}
|
|
||||||
fprintf(stderr, "copied\n");
|
|
||||||
}
|
|
||||||
if (r != ARCHIVE_EOF)
|
|
||||||
die("Error reading archive");
|
|
||||||
/* Close the archives. */
|
|
||||||
if (archive_read_free(ina) != ARCHIVE_OK)
|
|
||||||
die("Error closing input archive");
|
|
||||||
if (archive_write_free(outa) != ARCHIVE_OK)
|
|
||||||
die("Error closing output archive");
|
|
||||||
return (0);
|
|
||||||
}
|
|
|
@ -1,277 +0,0 @@
|
||||||
/*
|
|
||||||
* This file is in the public domain.
|
|
||||||
* Use it as you wish.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This is a compact tar extraction program using libarchive whose
|
|
||||||
* primary goal is small executable size. Statically linked, it can
|
|
||||||
* be very small, depending in large part on how cleanly factored your
|
|
||||||
* system libraries are. Note that this uses the standard libarchive,
|
|
||||||
* without any special recompilation. The only functional concession
|
|
||||||
* is that this program uses the uid/gid from the archive instead of
|
|
||||||
* doing uname/gname lookups. (Add a call to
|
|
||||||
* archive_write_disk_set_standard_lookup() to enable uname/gname
|
|
||||||
* lookups, but be aware that this can add 500k or more to a static
|
|
||||||
* executable, depending on the system libraries, since user/group
|
|
||||||
* lookups frequently pull in password, YP/LDAP, networking, and DNS
|
|
||||||
* resolver libraries.)
|
|
||||||
*
|
|
||||||
* To build:
|
|
||||||
* $ gcc -static -Wall -o untar untar.c -larchive
|
|
||||||
* $ strip untar
|
|
||||||
*
|
|
||||||
* NOTE: On some systems, you may need to add additional flags
|
|
||||||
* to ensure that untar.c is compiled the same way as libarchive
|
|
||||||
* was compiled. In particular, Linux users will probably
|
|
||||||
* have to add -D_FILE_OFFSET_BITS=64 to the command line above.
|
|
||||||
*
|
|
||||||
* For fun, statically compile the following simple hello.c program
|
|
||||||
* using the same flags as for untar and compare the size:
|
|
||||||
*
|
|
||||||
* #include <stdio.h>
|
|
||||||
* int main(int argc, char **argv) {
|
|
||||||
* printf("hello, world\n");
|
|
||||||
* return(0);
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* You may be even more surprised by the compiled size of true.c listed here:
|
|
||||||
*
|
|
||||||
* int main(int argc, char **argv) {
|
|
||||||
* return (0);
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* On a slightly customized FreeBSD 5 system that I used around
|
|
||||||
* 2005, hello above compiled to 89k compared to untar of 69k. So at
|
|
||||||
* that time, libarchive's tar reader and extract-to-disk routines
|
|
||||||
* compiled to less code than printf().
|
|
||||||
*
|
|
||||||
* On my FreeBSD development system today (August, 2009):
|
|
||||||
* hello: 195024 bytes
|
|
||||||
* true: 194912 bytes
|
|
||||||
* untar: 259924 bytes
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <sys/types.h>
|
|
||||||
|
|
||||||
#include <sys/stat.h>
|
|
||||||
|
|
||||||
#include <archive.h>
|
|
||||||
#include <archive_entry.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
static void errmsg(const char *);
|
|
||||||
static void extract(const char *filename, int do_extract, int flags);
|
|
||||||
static void fail(const char *, const char *, int);
|
|
||||||
static int copy_data(struct archive *, struct archive *);
|
|
||||||
static void msg(const char *);
|
|
||||||
static void usage(void);
|
|
||||||
static void warn(const char *, const char *);
|
|
||||||
|
|
||||||
static int verbose = 0;
|
|
||||||
|
|
||||||
int
|
|
||||||
main(int argc, const char **argv)
|
|
||||||
{
|
|
||||||
const char *filename = NULL;
|
|
||||||
int compress, flags, mode, opt;
|
|
||||||
|
|
||||||
(void)argc;
|
|
||||||
mode = 'x';
|
|
||||||
verbose = 0;
|
|
||||||
compress = '\0';
|
|
||||||
flags = ARCHIVE_EXTRACT_TIME;
|
|
||||||
|
|
||||||
/* Among other sins, getopt(3) pulls in printf(3). */
|
|
||||||
while (*++argv != NULL && **argv == '-') {
|
|
||||||
const char *p = *argv + 1;
|
|
||||||
|
|
||||||
while ((opt = *p++) != '\0') {
|
|
||||||
switch (opt) {
|
|
||||||
case 'f':
|
|
||||||
if (*p != '\0')
|
|
||||||
filename = p;
|
|
||||||
else
|
|
||||||
filename = *++argv;
|
|
||||||
p += strlen(p);
|
|
||||||
break;
|
|
||||||
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;
|
|
||||||
default:
|
|
||||||
usage();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::cout << "begin\n";
|
|
||||||
|
|
||||||
switch (mode) {
|
|
||||||
case 't':
|
|
||||||
extract(filename, 0, flags);
|
|
||||||
break;
|
|
||||||
case 'x':
|
|
||||||
extract(filename, 1, flags);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::cout << "end";
|
|
||||||
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
extract(const char *filename, int do_extract, int flags)
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
/*
|
|
||||||
* Note: archive_write_disk_set_standard_lookup() is useful
|
|
||||||
* here, but it requires library routines that can add 500k or
|
|
||||||
* more to a static executable.
|
|
||||||
*/
|
|
||||||
archive_read_support_format_tar(a);
|
|
||||||
/*
|
|
||||||
* On my system, enabling other archive formats adds 20k-30k
|
|
||||||
* each. Enabling gzip decompression adds about 20k.
|
|
||||||
* Enabling bzip2 is more expensive because the libbz2 library
|
|
||||||
* isn't very well factored.
|
|
||||||
*/
|
|
||||||
|
|
||||||
std::cout <<"AAA\n";
|
|
||||||
if (filename != NULL && strcmp(filename, "-") == 0)
|
|
||||||
filename = NULL;
|
|
||||||
if ((r = archive_read_open_filename(a, filename, 10240)))
|
|
||||||
fail("archive_read_open_filename()",
|
|
||||||
archive_error_string(a), r);
|
|
||||||
|
|
||||||
std::cout << "BBB\n";
|
|
||||||
for (;;) {
|
|
||||||
r = archive_read_next_header(a, &entry);
|
|
||||||
if (r == ARCHIVE_EOF)
|
|
||||||
break;
|
|
||||||
if (r != ARCHIVE_OK)
|
|
||||||
fail("archive_read_next_header()",
|
|
||||||
archive_error_string(a), 1);
|
|
||||||
if (verbose && do_extract)
|
|
||||||
msg("x ");
|
|
||||||
if (verbose || !do_extract)
|
|
||||||
msg(archive_entry_pathname(entry));
|
|
||||||
if (do_extract) {
|
|
||||||
r = archive_write_header(ext, entry);
|
|
||||||
if (r != ARCHIVE_OK)
|
|
||||||
warn("archive_write_header()",
|
|
||||||
archive_error_string(ext));
|
|
||||||
else {
|
|
||||||
copy_data(a, ext);
|
|
||||||
r = archive_write_finish_entry(ext);
|
|
||||||
if (r != ARCHIVE_OK)
|
|
||||||
fail("archive_write_finish_entry()",
|
|
||||||
archive_error_string(ext), 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
if (verbose || !do_extract)
|
|
||||||
msg("\n");
|
|
||||||
}
|
|
||||||
archive_read_close(a);
|
|
||||||
archive_read_free(a);
|
|
||||||
|
|
||||||
archive_write_close(ext);
|
|
||||||
archive_write_free(ext);
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
copy_data(struct archive *ar, struct archive *aw)
|
|
||||||
{
|
|
||||||
int r;
|
|
||||||
const void *buff;
|
|
||||||
size_t size;
|
|
||||||
#if ARCHIVE_VERSION_NUMBER >= 3000000
|
|
||||||
int64_t offset;
|
|
||||||
#else
|
|
||||||
off_t offset;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
r = archive_read_data_block(ar, &buff, &size, &offset);
|
|
||||||
if (r == ARCHIVE_EOF)
|
|
||||||
return (ARCHIVE_OK);
|
|
||||||
if (r != ARCHIVE_OK)
|
|
||||||
return (r);
|
|
||||||
r = archive_write_data_block(aw, buff, size, offset);
|
|
||||||
if (r != ARCHIVE_OK) {
|
|
||||||
warn("archive_write_data_block()",
|
|
||||||
archive_error_string(aw));
|
|
||||||
return (r);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* These reporting functions use low-level I/O; on some systems, this
|
|
||||||
* is a significant code reduction. Of course, on many server and
|
|
||||||
* desktop operating systems, malloc() and even crt rely on printf(),
|
|
||||||
* which in turn pulls in most of the rest of stdio, so this is not an
|
|
||||||
* optimization at all there. (If you're going to pay 100k or more
|
|
||||||
* for printf() anyway, you may as well use it!)
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
msg(const char *m)
|
|
||||||
{
|
|
||||||
write(1, m, strlen(m));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
errmsg(const char *m)
|
|
||||||
{
|
|
||||||
write(2, m, strlen(m));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
warn(const char *f, const char *m)
|
|
||||||
{
|
|
||||||
errmsg(f);
|
|
||||||
errmsg(" failed: ");
|
|
||||||
errmsg(m);
|
|
||||||
errmsg("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
fail(const char *f, const char *m, int r)
|
|
||||||
{
|
|
||||||
warn(f, m);
|
|
||||||
exit(r);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
usage(void)
|
|
||||||
{
|
|
||||||
const char *m = "Usage: untar [-tvx] [-f file] [file]\n";
|
|
||||||
errmsg(m);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
|
@ -1,20 +1,28 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
#ifndef SAPI_LIBARCHIVE_SANDBOX_H
|
#ifndef SAPI_LIBARCHIVE_SANDBOX_H
|
||||||
#define SAPI_LIBARCHIVE_SANDBOX_H
|
#define SAPI_LIBARCHIVE_SANDBOX_H
|
||||||
|
|
||||||
#include <asm/unistd_64.h>
|
#include <asm/unistd_64.h>
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <syscall.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#include "libarchive_sapi.sapi.h"
|
#include "libarchive_sapi.sapi.h"
|
||||||
#include "sandboxed_api/sandbox2/util/fileops.h"
|
#include "sandboxed_api/sandbox2/util/fileops.h"
|
||||||
#include "sapi_minitar.h"
|
|
||||||
// #include "sandboxed_api/sandbox2/util/fileops.h"
|
|
||||||
|
|
||||||
// When creating an archive, we need read permissions on each of the
|
// When creating an archive, we need read permissions on each of the
|
||||||
// file/directory added in the archive. Also, in order to create the archive, we
|
// file/directory added in the archive. Also, in order to create the archive, we
|
||||||
// map /output with the basename of the archive. This way, the program can
|
// map "/output" with the basename of the archive. This way, the program can
|
||||||
// create the file without having access to anything else.
|
// create the file without having access to anything else.
|
||||||
class SapiLibarchiveSandboxCreate : public LibarchiveSandbox {
|
class SapiLibarchiveSandboxCreate : public LibarchiveSandbox {
|
||||||
public:
|
public:
|
||||||
|
@ -54,7 +62,7 @@ class SapiLibarchiveSandboxCreate : public LibarchiveSandbox {
|
||||||
__NR_getdents64,
|
__NR_getdents64,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Here we only check whether the entry is a file or a directory.
|
// We check whether the entry is a file or a directory.
|
||||||
for (const auto& i : files_) {
|
for (const auto& i : files_) {
|
||||||
struct stat s;
|
struct stat s;
|
||||||
stat(i.c_str(), &s);
|
stat(i.c_str(), &s);
|
||||||
|
@ -133,4 +141,4 @@ class SapiLibarchiveSandboxExtract : public LibarchiveSandbox {
|
||||||
const int do_extract_;
|
const int do_extract_;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // SAPI_LIBARCHIVE_SANDBOX_H
|
#endif // SAPI_LIBARCHIVE_SANDBOX_H
|
||||||
|
|
|
@ -1,10 +1,23 @@
|
||||||
|
// 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"
|
#include "sapi_minitar.h"
|
||||||
|
|
||||||
void create(const char* initial_filename, int compress, const char** argv,
|
void create(const char* initial_filename, int compress, const char** argv,
|
||||||
bool verbose /* = true */) {
|
bool verbose /* = true */) {
|
||||||
// We split the filename path into dirname and filename. To the filename we
|
// We split the filename path into dirname and filename. To the filename we
|
||||||
// prepend "/output/"" so that it will work with the security policy.
|
// prepend "/output/"" so that it will work with the security policy.
|
||||||
|
|
||||||
std::string abs_path = MakeAbsolutePathAtCWD(std::string(initial_filename));
|
std::string abs_path = MakeAbsolutePathAtCWD(std::string(initial_filename));
|
||||||
auto [archive_path, filename_tmp] =
|
auto [archive_path, filename_tmp] =
|
||||||
std::move(sandbox2::file::SplitPath(abs_path));
|
std::move(sandbox2::file::SplitPath(abs_path));
|
||||||
|
@ -24,16 +37,14 @@ void create(const char* initial_filename, int compress, const char** argv,
|
||||||
std::transform(relative_paths.begin(), relative_paths.end(),
|
std::transform(relative_paths.begin(), relative_paths.end(),
|
||||||
relative_paths.begin(), sandbox2::file::CleanPath);
|
relative_paths.begin(), sandbox2::file::CleanPath);
|
||||||
|
|
||||||
// At this point, we have the cleaned relative and absolute paths saved
|
// At this point, we have the relative and absolute paths (cleaned) saved
|
||||||
// in vectors.
|
// in vectors.
|
||||||
|
|
||||||
// Initialize sandbox and api object
|
// Initialize sandbox and api objects.
|
||||||
SapiLibarchiveSandboxCreate sandbox(absolute_paths, archive_path);
|
SapiLibarchiveSandboxCreate sandbox(absolute_paths, archive_path);
|
||||||
CHECK(sandbox.Init().ok()) << "Error during sandbox initialization";
|
CHECK(sandbox.Init().ok()) << "Error during sandbox initialization";
|
||||||
LibarchiveApi api(&sandbox);
|
LibarchiveApi api(&sandbox);
|
||||||
|
|
||||||
std::cout << "AJUNGE AICI" << std::endl;
|
|
||||||
|
|
||||||
absl::StatusOr<archive*> ret = api.archive_write_new();
|
absl::StatusOr<archive*> ret = api.archive_write_new();
|
||||||
CHECK(ret.ok()) << "write_new call failed";
|
CHECK(ret.ok()) << "write_new call failed";
|
||||||
CHECK(ret.value() != NULL) << "Failed to create write archive";
|
CHECK(ret.value() != NULL) << "Failed to create write archive";
|
||||||
|
@ -42,8 +53,6 @@ void create(const char* initial_filename, int compress, const char** argv,
|
||||||
// to the client process.
|
// to the client process.
|
||||||
sapi::v::RemotePtr a(ret.value());
|
sapi::v::RemotePtr a(ret.value());
|
||||||
|
|
||||||
std::cout << "AJUNGE AICI" << std::endl;
|
|
||||||
|
|
||||||
absl::StatusOr<int> ret2;
|
absl::StatusOr<int> ret2;
|
||||||
|
|
||||||
switch (compress) {
|
switch (compress) {
|
||||||
|
@ -114,8 +123,6 @@ void create(const char* initial_filename, int compress, const char** argv,
|
||||||
<< CheckStatusAndGetString(api.archive_error_string(&disk), sandbox);
|
<< CheckStatusAndGetString(api.archive_error_string(&disk), sandbox);
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
int needcr = 0;
|
|
||||||
|
|
||||||
absl::StatusOr<archive_entry*> ret3;
|
absl::StatusOr<archive_entry*> ret3;
|
||||||
ret3 = api.archive_entry_new();
|
ret3 = api.archive_entry_new();
|
||||||
|
|
||||||
|
@ -139,14 +146,15 @@ void create(const char* initial_filename, int compress, const char** argv,
|
||||||
|
|
||||||
// After using the absolute path before, we now need to add the pathname
|
// After using the absolute path before, we now need to add the pathname
|
||||||
// to the archive entry. This would help store the files by their relative
|
// to the archive entry. This would help store the files by their relative
|
||||||
// paths. However, in the case where a directory is added to the archive,
|
// paths(similar to the usual tar command).
|
||||||
// all of the files inside of it are addes as well so we replace the
|
// However, in the case where a directory is added to the archive,
|
||||||
// absolute path prefix with the relative one. Example: we add the folder
|
// all of the files inside of it are added as well so we replace the
|
||||||
// test_files which becomes /absolute/path/test_files and the files inside
|
// absolute path prefix with the relative one.
|
||||||
// of it will become /absolute/path/test_files/file1 and we change it to
|
// Example:
|
||||||
// test_files/file1 so that it is relative. This only changes the pathname
|
// we add the folder "test_files" which becomes
|
||||||
// so that relative paths are preserved.
|
// "/absolute/path/test_files" and the files inside of it will become
|
||||||
|
// similar to "/absolute/path/test_files/file1"
|
||||||
|
// which we then change to "test_files/file1" so that it is relative.
|
||||||
std::string path_name =
|
std::string path_name =
|
||||||
CheckStatusAndGetString(api.archive_entry_pathname(&entry), sandbox);
|
CheckStatusAndGetString(api.archive_entry_pathname(&entry), sandbox);
|
||||||
|
|
||||||
|
@ -156,7 +164,6 @@ void create(const char* initial_filename, int compress, const char** argv,
|
||||||
|
|
||||||
// On top of those changes, we need to remove leading '/' characters
|
// On top of those changes, we need to remove leading '/' characters
|
||||||
// and also remove everything up to the last occurrence of '../'.
|
// and also remove everything up to the last occurrence of '../'.
|
||||||
|
|
||||||
size_t found = path_name.find_first_not_of("/");
|
size_t found = path_name.find_first_not_of("/");
|
||||||
if (found != std::string::npos) {
|
if (found != std::string::npos) {
|
||||||
path_name.erase(path_name.begin(), path_name.begin() + found);
|
path_name.erase(path_name.begin(), path_name.begin() + found);
|
||||||
|
@ -174,8 +181,8 @@ void create(const char* initial_filename, int compress, const char** argv,
|
||||||
|
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
std::cout << CheckStatusAndGetString(api.archive_entry_pathname(&entry),
|
std::cout << CheckStatusAndGetString(api.archive_entry_pathname(&entry),
|
||||||
sandbox);
|
sandbox)
|
||||||
needcr = 1;
|
<< std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret2 = api.archive_write_header(&a, &entry);
|
ret2 = api.archive_write_header(&a, &entry);
|
||||||
|
@ -183,8 +190,8 @@ void create(const char* initial_filename, int compress, const char** argv,
|
||||||
|
|
||||||
if (ret2.value() < ARCHIVE_OK) {
|
if (ret2.value() < ARCHIVE_OK) {
|
||||||
std::cout << CheckStatusAndGetString(api.archive_error_string(&a),
|
std::cout << CheckStatusAndGetString(api.archive_error_string(&a),
|
||||||
sandbox);
|
sandbox)
|
||||||
needcr = 1;
|
<< std::endl;
|
||||||
}
|
}
|
||||||
CHECK(ret2.value() != ARCHIVE_FATAL)
|
CHECK(ret2.value() != ARCHIVE_FATAL)
|
||||||
<< "Unexpected result from write_header call";
|
<< "Unexpected result from write_header call";
|
||||||
|
@ -204,12 +211,12 @@ void create(const char* initial_filename, int compress, const char** argv,
|
||||||
sapi::v::Array<char> buff(kBuffSize);
|
sapi::v::Array<char> buff(kBuffSize);
|
||||||
sapi::v::UInt ssize(kBuffSize);
|
sapi::v::UInt ssize(kBuffSize);
|
||||||
|
|
||||||
// We allocate the buffer remotely and then we can simply use the remote
|
// We allocate the buffer remotely and then we can simply use the
|
||||||
// pointer.
|
// remote pointer(with PtrNone).
|
||||||
CHECK(sandbox.Allocate(&buff, true).ok())
|
CHECK(sandbox.Allocate(&buff, true).ok())
|
||||||
<< "Could not allocate remote buffer";
|
<< "Could not allocate remote buffer";
|
||||||
|
|
||||||
// We can use sapi objects that help us with file descriptors.
|
// We can use sapi methods that help us with file descriptors.
|
||||||
CHECK(sandbox.TransferToSandboxee(&sapi_fd).ok())
|
CHECK(sandbox.TransferToSandboxee(&sapi_fd).ok())
|
||||||
<< "Could not transfer file descriptor";
|
<< "Could not transfer file descriptor";
|
||||||
|
|
||||||
|
@ -230,12 +237,7 @@ void create(const char* initial_filename, int compress, const char** argv,
|
||||||
// sapi_fd variable goes out of scope here so both the local and the
|
// sapi_fd variable goes out of scope here so both the local and the
|
||||||
// remote file descriptors are closed.
|
// remote file descriptors are closed.
|
||||||
}
|
}
|
||||||
|
|
||||||
CHECK(api.archive_entry_free(&entry).ok()) << "entry_free call failed";
|
CHECK(api.archive_entry_free(&entry).ok()) << "entry_free call failed";
|
||||||
|
|
||||||
if (needcr) {
|
|
||||||
std::cout << std::endl;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ret2 = api.archive_read_close(&disk);
|
ret2 = api.archive_read_close(&disk);
|
||||||
|
@ -258,7 +260,6 @@ void create(const char* initial_filename, int compress, const char** argv,
|
||||||
|
|
||||||
void extract(const char* filename, int do_extract, int flags,
|
void extract(const char* filename, int do_extract, int flags,
|
||||||
bool verbose /* = true */) {
|
bool verbose /* = true */) {
|
||||||
std::cout << "flags = " << flags << std::endl;
|
|
||||||
std::string tmp_dir;
|
std::string tmp_dir;
|
||||||
if (do_extract) {
|
if (do_extract) {
|
||||||
tmp_dir = CreateTempDirAtCWD();
|
tmp_dir = CreateTempDirAtCWD();
|
||||||
|
@ -275,17 +276,17 @@ void extract(const char* filename, int do_extract, int flags,
|
||||||
|
|
||||||
// We should only delete it if the do_extract flag is true which
|
// We should only delete it if the do_extract flag is true which
|
||||||
// means that this struct is instantiated only in that case.
|
// means that this struct is instantiated only in that case.
|
||||||
std::shared_ptr<ExtractTempDirectoryCleanup> cleanup_ptr;
|
std::unique_ptr<ExtractTempDirectoryCleanup> cleanup_ptr;
|
||||||
if (do_extract) {
|
if (do_extract) {
|
||||||
cleanup_ptr = std::make_unique<ExtractTempDirectoryCleanup>();
|
cleanup_ptr = absl::make_unique<ExtractTempDirectoryCleanup>();
|
||||||
cleanup_ptr->dir = tmp_dir;
|
cleanup_ptr->dir = tmp_dir;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string filename_absolute = MakeAbsolutePathAtCWD(filename);
|
std::string filename_absolute = MakeAbsolutePathAtCWD(filename);
|
||||||
|
|
||||||
|
// Initialize sandbox and api objects.
|
||||||
SapiLibarchiveSandboxExtract sandbox(filename_absolute, do_extract, tmp_dir);
|
SapiLibarchiveSandboxExtract sandbox(filename_absolute, do_extract, tmp_dir);
|
||||||
CHECK(sandbox.Init().ok()) << "Error during sandbox initialization";
|
CHECK(sandbox.Init().ok()) << "Error during sandbox initialization";
|
||||||
|
|
||||||
LibarchiveApi api(&sandbox);
|
LibarchiveApi api(&sandbox);
|
||||||
|
|
||||||
absl::StatusOr<archive*> ret = api.archive_read_new();
|
absl::StatusOr<archive*> ret = api.archive_read_new();
|
||||||
|
@ -350,7 +351,6 @@ void extract(const char* filename, int do_extract, int flags,
|
||||||
sandbox);
|
sandbox);
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
int needcr = 0;
|
|
||||||
sapi::v::IntBase<struct archive_entry*> entry_ptr_tmp(0);
|
sapi::v::IntBase<struct archive_entry*> entry_ptr_tmp(0);
|
||||||
|
|
||||||
ret2 = api.archive_read_next_header(&a, entry_ptr_tmp.PtrAfter());
|
ret2 = api.archive_read_next_header(&a, entry_ptr_tmp.PtrAfter());
|
||||||
|
@ -372,8 +372,7 @@ void extract(const char* filename, int do_extract, int flags,
|
||||||
if (verbose || !do_extract) {
|
if (verbose || !do_extract) {
|
||||||
std::cout << CheckStatusAndGetString(api.archive_entry_pathname(&entry),
|
std::cout << CheckStatusAndGetString(api.archive_entry_pathname(&entry),
|
||||||
sandbox)
|
sandbox)
|
||||||
<< " ";
|
<< std::endl;
|
||||||
needcr = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (do_extract) {
|
if (do_extract) {
|
||||||
|
@ -383,15 +382,10 @@ void extract(const char* filename, int do_extract, int flags,
|
||||||
if (ret2.value() != ARCHIVE_OK) {
|
if (ret2.value() != ARCHIVE_OK) {
|
||||||
std::cout << CheckStatusAndGetString(api.archive_error_string(&a),
|
std::cout << CheckStatusAndGetString(api.archive_error_string(&a),
|
||||||
sandbox);
|
sandbox);
|
||||||
needcr = 1;
|
} else {
|
||||||
} else if (copy_data(&a, &ext, api, sandbox) != ARCHIVE_OK) {
|
copy_data(&a, &ext, api, sandbox);
|
||||||
needcr = 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (needcr) {
|
|
||||||
std::cout << std::endl;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ret2 = api.archive_read_close(&a);
|
ret2 = api.archive_read_close(&a);
|
||||||
|
@ -411,8 +405,6 @@ void extract(const char* filename, int do_extract, int flags,
|
||||||
CHECK(!ret2.value()) << "Unexpected result from write_free call";
|
CHECK(!ret2.value()) << "Unexpected result from write_free call";
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function is only called from the "extract function". It is still
|
|
||||||
// isolated in order to not modify the code structure as much.
|
|
||||||
int copy_data(sapi::v::RemotePtr* ar, sapi::v::RemotePtr* aw,
|
int copy_data(sapi::v::RemotePtr* ar, sapi::v::RemotePtr* aw,
|
||||||
LibarchiveApi& api, SapiLibarchiveSandboxExtract& sandbox) {
|
LibarchiveApi& api, SapiLibarchiveSandboxExtract& sandbox) {
|
||||||
absl::StatusOr<int> ret;
|
absl::StatusOr<int> ret;
|
||||||
|
|
|
@ -1,54 +1,62 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
#ifndef SAPI_LIBARCHIVE_MINITAR_H
|
#ifndef SAPI_LIBARCHIVE_MINITAR_H
|
||||||
#define SAPI_LIBARCHIVE_MINITAR_H
|
#define SAPI_LIBARCHIVE_MINITAR_H
|
||||||
|
|
||||||
#include <archive.h>
|
#include <archive.h>
|
||||||
#include <archive_entry.h>
|
#include <archive_entry.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <glog/logging.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#include <cstdlib>
|
|
||||||
#include <iostream>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
#include "libarchive_sapi.sapi.h"
|
#include "libarchive_sapi.sapi.h"
|
||||||
#include "sandbox.h"
|
#include "sandbox.h"
|
||||||
#include "sandboxed_api/sandbox2/util.h"
|
#include "sandboxed_api/sandbox2/util.h"
|
||||||
#include "sandboxed_api/sandbox2/util/fileops.h"
|
|
||||||
#include "sandboxed_api/sandbox2/util/path.h"
|
#include "sandboxed_api/sandbox2/util/path.h"
|
||||||
#include "sandboxed_api/sandbox2/util/temp_file.h"
|
#include "sandboxed_api/sandbox2/util/temp_file.h"
|
||||||
#include "sandboxed_api/var_array.h"
|
|
||||||
|
|
||||||
|
// Creates an archive file at the given filename.
|
||||||
void create(const char* filename, int compress, const char** argv,
|
void create(const char* filename, int compress, const char** argv,
|
||||||
bool verbose = true);
|
bool verbose = true);
|
||||||
|
|
||||||
|
// Extracts an archive file. If do_extract is true, the files will
|
||||||
|
// be created relative to the current working directory. If do_extract
|
||||||
|
// is false then the function will just print the entries of the archive.
|
||||||
void extract(const char* filename, int do_extract, int flags,
|
void extract(const char* filename, int do_extract, int flags,
|
||||||
bool verbose = true);
|
bool verbose = true);
|
||||||
|
|
||||||
|
// This function is only called from the "extract function". It is still
|
||||||
|
// isolated in order to not modify the code structure as much.
|
||||||
int copy_data(sapi::v::RemotePtr* ar, sapi::v::RemotePtr* aw,
|
int copy_data(sapi::v::RemotePtr* ar, sapi::v::RemotePtr* aw,
|
||||||
LibarchiveApi& api, SapiLibarchiveSandboxExtract& sandbox);
|
LibarchiveApi& api, SapiLibarchiveSandboxExtract& sandbox);
|
||||||
|
|
||||||
inline constexpr size_t kBlockSize = 10240;
|
inline constexpr size_t kBlockSize = 10240;
|
||||||
inline constexpr size_t kBuffSize = 16384;
|
inline constexpr size_t kBuffSize = 16384;
|
||||||
|
|
||||||
// Converts only one string to an absolute path by prepending the current
|
// Converts one string to an absolute path by prepending the current
|
||||||
// working directory to the relative path
|
// working directory to the relative path.
|
||||||
|
// The path is also cleaned at the end.
|
||||||
std::string MakeAbsolutePathAtCWD(const std::string& path);
|
std::string MakeAbsolutePathAtCWD(const std::string& path);
|
||||||
|
|
||||||
// This function takes a status as argument and after checking the status
|
// This function takes a status as argument and after checking the status
|
||||||
// it transfers the string. This is used mostly with archive_error_string
|
// it transfers the string. This is used mostly with archive_error_string
|
||||||
// and other library functions that return a char *.
|
// and other library functions that return a char*.
|
||||||
std::string CheckStatusAndGetString(const absl::StatusOr<char*>& status,
|
std::string CheckStatusAndGetString(const absl::StatusOr<char*>& status,
|
||||||
LibarchiveSandbox& sandbox);
|
LibarchiveSandbox& sandbox);
|
||||||
|
|
||||||
// Creates a temporary directory in the current working directory and
|
// Creates a temporary directory in the current working directory and
|
||||||
// returns the path. This is used in the extract function where the sandbox
|
// returns the path. This is used in the extract function where the sandboxed
|
||||||
// changes the current working directory to this temporary directory.
|
// process changes the current working directory to this temporary directory.
|
||||||
std::string CreateTempDirAtCWD();
|
std::string CreateTempDirAtCWD();
|
||||||
|
|
||||||
#endif // SAPI_LIBARCHIVE_MINITAR_H
|
#endif // SAPI_LIBARCHIVE_MINITAR_H
|
||||||
|
|
|
@ -1,4 +1,22 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
// This file contains the main function from the original minitar example:
|
||||||
|
// https://github.com/libarchive/libarchive/blob/master/examples/minitar/minitar.c
|
||||||
|
// Most of the logic is the same, it was only simplified a bit since this is
|
||||||
|
// only used for the command line tool.
|
||||||
|
// No sandboxing takes place in this function.
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,163 +0,0 @@
|
||||||
/*-
|
|
||||||
* Copyright (c) 2003-2007 Tim Kientzle
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions
|
|
||||||
* are met:
|
|
||||||
* 1. Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
|
|
||||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
||||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
||||||
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
||||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
||||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
||||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
||||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
||||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "archive_platform.h"
|
|
||||||
__FBSDID("$FreeBSD: head/lib/libarchive/archive_virtual.c 201098 2009-12-28 02:58:14Z kientzle $");
|
|
||||||
|
|
||||||
#include "archive.h"
|
|
||||||
#include "archive_entry.h"
|
|
||||||
#include "archive_private.h"
|
|
||||||
|
|
||||||
int
|
|
||||||
archive_filter_code(struct archive *a, int n)
|
|
||||||
{
|
|
||||||
return ((a->vtable->archive_filter_code)(a, n));
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
archive_filter_count(struct archive *a)
|
|
||||||
{
|
|
||||||
return ((a->vtable->archive_filter_count)(a));
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *
|
|
||||||
archive_filter_name(struct archive *a, int n)
|
|
||||||
{
|
|
||||||
return ((a->vtable->archive_filter_name)(a, n));
|
|
||||||
}
|
|
||||||
|
|
||||||
la_int64_t
|
|
||||||
archive_filter_bytes(struct archive *a, int n)
|
|
||||||
{
|
|
||||||
return ((a->vtable->archive_filter_bytes)(a, n));
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
archive_free(struct archive *a)
|
|
||||||
{
|
|
||||||
if (a == NULL)
|
|
||||||
return (ARCHIVE_OK);
|
|
||||||
return ((a->vtable->archive_free)(a));
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
archive_write_close(struct archive *a)
|
|
||||||
{
|
|
||||||
return ((a->vtable->archive_close)(a));
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
archive_read_close(struct archive *a)
|
|
||||||
{
|
|
||||||
return ((a->vtable->archive_close)(a));
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
archive_write_fail(struct archive *a)
|
|
||||||
{
|
|
||||||
a->state = ARCHIVE_STATE_FATAL;
|
|
||||||
return a->state;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
archive_write_free(struct archive *a)
|
|
||||||
{
|
|
||||||
return archive_free(a);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if ARCHIVE_VERSION_NUMBER < 4000000
|
|
||||||
/* For backwards compatibility; will be removed with libarchive 4.0. */
|
|
||||||
int
|
|
||||||
archive_write_finish(struct archive *a)
|
|
||||||
{
|
|
||||||
return archive_write_free(a);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int
|
|
||||||
archive_read_free(struct archive *a)
|
|
||||||
{
|
|
||||||
return archive_free(a);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if ARCHIVE_VERSION_NUMBER < 4000000
|
|
||||||
/* For backwards compatibility; will be removed with libarchive 4.0. */
|
|
||||||
int
|
|
||||||
archive_read_finish(struct archive *a)
|
|
||||||
{
|
|
||||||
return archive_read_free(a);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int
|
|
||||||
archive_write_header(struct archive *a, struct archive_entry *entry)
|
|
||||||
{
|
|
||||||
++a->file_count;
|
|
||||||
return ((a->vtable->archive_write_header)(a, entry));
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
archive_write_finish_entry(struct archive *a)
|
|
||||||
{
|
|
||||||
return ((a->vtable->archive_write_finish_entry)(a));
|
|
||||||
}
|
|
||||||
|
|
||||||
la_ssize_t
|
|
||||||
archive_write_data(struct archive *a, const void *buff, size_t s)
|
|
||||||
{
|
|
||||||
return ((a->vtable->archive_write_data)(a, buff, s));
|
|
||||||
}
|
|
||||||
|
|
||||||
la_ssize_t
|
|
||||||
archive_write_data_block(struct archive *a, const void *buff, size_t s,
|
|
||||||
la_int64_t o)
|
|
||||||
{
|
|
||||||
if (a->vtable->archive_write_data_block == NULL) {
|
|
||||||
archive_set_error(a, ARCHIVE_ERRNO_MISC,
|
|
||||||
"archive_write_data_block not supported");
|
|
||||||
a->state = ARCHIVE_STATE_FATAL;
|
|
||||||
return (ARCHIVE_FATAL);
|
|
||||||
}
|
|
||||||
return ((a->vtable->archive_write_data_block)(a, buff, s, o));
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
archive_read_next_header(struct archive *a, struct archive_entry **entry)
|
|
||||||
{
|
|
||||||
return ((a->vtable->archive_read_next_header)(a, entry));
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
archive_read_next_header2(struct archive *a, struct archive_entry *entry)
|
|
||||||
{
|
|
||||||
return ((a->vtable->archive_read_next_header2)(a, entry));
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
archive_read_data_block(struct archive *a,
|
|
||||||
const void **buff, size_t *s, la_int64_t *o)
|
|
||||||
{
|
|
||||||
return ((a->vtable->archive_read_data_block)(a, buff, s, o));
|
|
||||||
}
|
|
|
@ -1,163 +0,0 @@
|
||||||
/*-
|
|
||||||
* Copyright (c) 2003-2007 Tim Kientzle
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions
|
|
||||||
* are met:
|
|
||||||
* 1. Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
|
|
||||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
||||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
||||||
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
||||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
||||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
||||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
||||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
||||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "archive_platform.h"
|
|
||||||
__FBSDID("$FreeBSD: head/lib/libarchive/archive_virtual.c 201098 2009-12-28 02:58:14Z kientzle $");
|
|
||||||
|
|
||||||
#include "archive.h"
|
|
||||||
#include "archive_entry.h"
|
|
||||||
#include "archive_private.h"
|
|
||||||
|
|
||||||
int
|
|
||||||
archive_filter_code(struct archive *a, int n)
|
|
||||||
{
|
|
||||||
return ((a->vtable->archive_filter_code)(a, n));
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
archive_filter_count(struct archive *a)
|
|
||||||
{
|
|
||||||
return ((a->vtable->archive_filter_count)(a));
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *
|
|
||||||
archive_filter_name(struct archive *a, int n)
|
|
||||||
{
|
|
||||||
return ((a->vtable->archive_filter_name)(a, n));
|
|
||||||
}
|
|
||||||
|
|
||||||
la_int64_t
|
|
||||||
archive_filter_bytes(struct archive *a, int n)
|
|
||||||
{
|
|
||||||
return ((a->vtable->archive_filter_bytes)(a, n));
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
archive_free(struct archive *a)
|
|
||||||
{
|
|
||||||
if (a == NULL)
|
|
||||||
return (ARCHIVE_OK);
|
|
||||||
return ((a->vtable->archive_free)(a));
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
archive_write_close(struct archive *a)
|
|
||||||
{
|
|
||||||
return ((a->vtable->archive_close)(a));
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
archive_read_close(struct archive *a)
|
|
||||||
{
|
|
||||||
return ((a->vtable->archive_close)(a));
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
archive_write_fail(struct archive *a)
|
|
||||||
{
|
|
||||||
a->state = ARCHIVE_STATE_FATAL;
|
|
||||||
return a->state;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
archive_write_free(struct archive *a)
|
|
||||||
{
|
|
||||||
return archive_free(a);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if ARCHIVE_VERSION_NUMBER < 4000000
|
|
||||||
/* For backwards compatibility; will be removed with libarchive 4.0. */
|
|
||||||
int
|
|
||||||
archive_write_finish(struct archive *a)
|
|
||||||
{
|
|
||||||
return archive_write_free(a);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int
|
|
||||||
archive_read_free(struct archive *a)
|
|
||||||
{
|
|
||||||
return archive_free(a);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if ARCHIVE_VERSION_NUMBER < 4000000
|
|
||||||
/* For backwards compatibility; will be removed with libarchive 4.0. */
|
|
||||||
int
|
|
||||||
archive_read_finish(struct archive *a)
|
|
||||||
{
|
|
||||||
return archive_read_free(a);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int
|
|
||||||
archive_write_header(struct archive *a, struct archive_entry *entry)
|
|
||||||
{
|
|
||||||
++a->file_count;
|
|
||||||
return ((a->vtable->archive_write_header)(a, entry));
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
archive_write_finish_entry(struct archive *a)
|
|
||||||
{
|
|
||||||
return ((a->vtable->archive_write_finish_entry)(a));
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
archive_write_data(struct archive *a, const void *buff, size_t s)
|
|
||||||
{
|
|
||||||
return ((a->vtable->archive_write_data)(a, buff, s));
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
archive_write_data_block(struct archive *a, const void *buff, size_t s,
|
|
||||||
la_int64_t o)
|
|
||||||
{
|
|
||||||
if (a->vtable->archive_write_data_block == NULL) {
|
|
||||||
archive_set_error(a, ARCHIVE_ERRNO_MISC,
|
|
||||||
"archive_write_data_block not supported");
|
|
||||||
a->state = ARCHIVE_STATE_FATAL;
|
|
||||||
return (ARCHIVE_FATAL);
|
|
||||||
}
|
|
||||||
return ((a->vtable->archive_write_data_block)(a, buff, s, o));
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
archive_read_next_header(struct archive *a, struct archive_entry **entry)
|
|
||||||
{
|
|
||||||
return ((a->vtable->archive_read_next_header)(a, entry));
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
archive_read_next_header2(struct archive *a, struct archive_entry *entry)
|
|
||||||
{
|
|
||||||
return ((a->vtable->archive_read_next_header2)(a, entry));
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
archive_read_data_block(struct archive *a,
|
|
||||||
const void **buff, size_t *s, la_int64_t *o)
|
|
||||||
{
|
|
||||||
return ((a->vtable->archive_read_data_block)(a, buff, s, o));
|
|
||||||
}
|
|
|
@ -1,3 +1,16 @@
|
||||||
|
# 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(GoogleTest)
|
include(GoogleTest)
|
||||||
enable_testing()
|
enable_testing()
|
||||||
|
@ -9,8 +22,7 @@ add_executable(sapi_minitar_test
|
||||||
target_link_libraries(sapi_minitar_test PRIVATE
|
target_link_libraries(sapi_minitar_test PRIVATE
|
||||||
sapi_minitar_lib
|
sapi_minitar_lib
|
||||||
gtest
|
gtest
|
||||||
gmock
|
|
||||||
sapi::test_main
|
sapi::test_main
|
||||||
)
|
)
|
||||||
|
|
||||||
gtest_discover_tests(sapi_minitar_test)
|
gtest_discover_tests(sapi_minitar_test)
|
|
@ -1,39 +1,63 @@
|
||||||
// #include <gmock/gmock-more-matchers.h>
|
// Copyright 2020 Google LLC
|
||||||
#include <gmock/gmock-more-matchers.h>
|
//
|
||||||
#include <unistd.h>
|
// 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 <fstream>
|
#include <fstream>
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#include "absl/strings/string_view.h"
|
#include "build/googletest-src/googlemock/include/gmock/gmock-more-matchers.h"
|
||||||
#include "gmock/gmock.h"
|
|
||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
#include "sandboxed_api/sandbox2/util/fileops.h"
|
|
||||||
#include "sandboxed_api/sandbox2/util/path.h"
|
|
||||||
#include "sandboxed_api/util/status_matchers.h"
|
#include "sandboxed_api/util/status_matchers.h"
|
||||||
#include "sapi_minitar.h"
|
#include "sapi_minitar.h"
|
||||||
// #include "testing/base/public/gunit.h"
|
|
||||||
// #include "testing/base/public/gunit.h"
|
|
||||||
|
|
||||||
using ::sandbox2::file::JoinPath;
|
using ::sandbox2::file::JoinPath;
|
||||||
using ::testing::Eq;
|
using ::testing::Eq;
|
||||||
using ::testing::IsTrue;
|
using ::testing::IsTrue;
|
||||||
|
using ::testing::StrEq;
|
||||||
|
|
||||||
using ::sandbox2::file_util::fileops::Exists;
|
using ::sandbox2::file_util::fileops::Exists;
|
||||||
|
using ::sandbox2::util::VecStringToCharPtrArr;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
// We will use a fixture class for testing which allows us to override the
|
||||||
|
// SetUp and TearDown functions. Also, data that needs to be initialized
|
||||||
|
// or destroyed only once (the test files and directories) will be handled
|
||||||
|
// in the SetUpTestSuite and TearDownTestSuite functions which are executed
|
||||||
|
// only once.
|
||||||
|
// All of the testing data will be placed in a temporary directory and each
|
||||||
|
// test will have it's own temporary directory. At the end of each test
|
||||||
|
// and all of the tests, the temporary data is deleted.
|
||||||
class MiniTarTest : public ::testing::Test {
|
class MiniTarTest : public ::testing::Test {
|
||||||
protected:
|
protected:
|
||||||
|
// Before running the tests, we create a temporary directory which will
|
||||||
|
// store generated files and directories used for testing.
|
||||||
|
// The directory will look as follows:
|
||||||
|
// -file1
|
||||||
|
// -dir1 - file2
|
||||||
|
// - dir2 - file3
|
||||||
static void SetUpTestSuite() {
|
static void SetUpTestSuite() {
|
||||||
data_dir_ = CreateTempDirAtCWD();
|
data_dir_ = CreateTempDirAtCWD();
|
||||||
init_wd_ = sandbox2::file_util::fileops::GetCWD();
|
init_wd_ = sandbox2::file_util::fileops::GetCWD();
|
||||||
ASSERT_THAT(Exists(data_dir_, false), IsTrue())
|
ASSERT_THAT(Exists(data_dir_, false), IsTrue())
|
||||||
<< "Test data directory was not created";
|
<< "Test data directory was not created";
|
||||||
ASSERT_THAT(chdir(data_dir_.c_str()), Eq(0))
|
ASSERT_THAT(chdir(data_dir_.data()), Eq(0))
|
||||||
<< "Could not chdir into test data directory";
|
<< "Could not chdir into test data directory";
|
||||||
|
|
||||||
CreateAndWriteToFile("file1");
|
CreateAndWriteToFile(kFile1_);
|
||||||
|
ASSERT_THAT(mkdir(kDir1_.data(), 0755), Eq(0)) << "Could not create dir1";
|
||||||
|
CreateAndWriteToFile(kFile2_);
|
||||||
|
ASSERT_THAT(mkdir(kDir2_.data(), 0755), Eq(0)) << "Could not create dir2";
|
||||||
|
CreateAndWriteToFile(kFile3_);
|
||||||
|
|
||||||
test_count_ = 0;
|
test_count_ = 0;
|
||||||
}
|
}
|
||||||
|
@ -42,7 +66,7 @@ class MiniTarTest : public ::testing::Test {
|
||||||
// The tests have the data directory as their working directory at the end
|
// The tests have the data directory as their working directory at the end
|
||||||
// so we move to the initial working directory in order to not delete the
|
// so we move to the initial working directory in order to not delete the
|
||||||
// directory that we are inside of.
|
// directory that we are inside of.
|
||||||
ASSERT_THAT(chdir(init_wd_.c_str()), Eq(0))
|
ASSERT_THAT(chdir(init_wd_.data()), Eq(0))
|
||||||
<< "Could not chdir into initial working directory";
|
<< "Could not chdir into initial working directory";
|
||||||
EXPECT_THAT(sandbox2::file_util::fileops::DeleteRecursively(data_dir_),
|
EXPECT_THAT(sandbox2::file_util::fileops::DeleteRecursively(data_dir_),
|
||||||
IsTrue)
|
IsTrue)
|
||||||
|
@ -50,17 +74,19 @@ class MiniTarTest : public ::testing::Test {
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetUp() override {
|
void SetUp() override {
|
||||||
|
// We use a unique id based on test count to make sure that files created
|
||||||
|
// during tests do not overlap.
|
||||||
id_ = "test" + std::to_string(test_count_);
|
id_ = "test" + std::to_string(test_count_);
|
||||||
tmp_dir_ = CreateTempDirAtCWD();
|
tmp_dir_ = CreateTempDirAtCWD();
|
||||||
ASSERT_THAT(Exists(tmp_dir_, false), IsTrue)
|
ASSERT_THAT(Exists(tmp_dir_, false), IsTrue)
|
||||||
<< "Could not create test specific temporary directory";
|
<< "Could not create test specific temporary directory";
|
||||||
ASSERT_THAT(chdir(data_dir_.c_str()), Eq(0))
|
ASSERT_THAT(chdir(data_dir_.data()), Eq(0))
|
||||||
<< "Could not chdir into test data directory";
|
<< "Could not chdir into test data directory";
|
||||||
}
|
}
|
||||||
|
|
||||||
void TearDown() override {
|
void TearDown() override {
|
||||||
// Move to another directory before deleting the temporary folder
|
// Move to another directory before deleting the temporary folder.
|
||||||
ASSERT_THAT(chdir(data_dir_.c_str()), Eq(0))
|
ASSERT_THAT(chdir(data_dir_.data()), Eq(0))
|
||||||
<< "Could not chdir into test data directory";
|
<< "Could not chdir into test data directory";
|
||||||
|
|
||||||
EXPECT_THAT(sandbox2::file_util::fileops::DeleteRecursively(tmp_dir_),
|
EXPECT_THAT(sandbox2::file_util::fileops::DeleteRecursively(tmp_dir_),
|
||||||
|
@ -70,8 +96,8 @@ class MiniTarTest : public ::testing::Test {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creates the file specified and writes the same filename.
|
// Creates the file specified and writes the same filename.
|
||||||
// This is done in order to not have completely empty files for the archiving
|
// This is done in order to not have completely empty files for the
|
||||||
// step.
|
// archiving step.
|
||||||
static void CreateAndWriteToFile(absl::string_view file) {
|
static void CreateAndWriteToFile(absl::string_view file) {
|
||||||
std::ofstream fin(file.data());
|
std::ofstream fin(file.data());
|
||||||
ASSERT_THAT(fin.is_open(), IsTrue()) << "Could not create" << file;
|
ASSERT_THAT(fin.is_open(), IsTrue()) << "Could not create" << file;
|
||||||
|
@ -79,30 +105,158 @@ class MiniTarTest : public ::testing::Test {
|
||||||
fin.close();
|
fin.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Checks if the files exists and if the contents are correct.
|
||||||
|
// In these tests, each file contains the relative path from the test
|
||||||
|
// directory.
|
||||||
|
// Example: dir1/dir2/file3 will contain dir1/dir2/file3.
|
||||||
|
// What the files contain does not matter as much, the only important thing
|
||||||
|
// is that they are not empty so we can check if the contents are preserved.
|
||||||
|
static void CheckFile(const std::string& file) {
|
||||||
|
ASSERT_THAT(Exists(file, false), IsTrue()) << "Could not find " << file;
|
||||||
|
std::ifstream fin(file);
|
||||||
|
ASSERT_THAT(fin.is_open(), IsTrue()) << "Error when opening " << file;
|
||||||
|
|
||||||
|
std::string file_contents((std::istreambuf_iterator<char>(fin)),
|
||||||
|
std::istreambuf_iterator<char>());
|
||||||
|
|
||||||
|
EXPECT_THAT(file_contents, StrEq(file))
|
||||||
|
<< "Contents of " << file << " are different after extraction";
|
||||||
|
fin.close();
|
||||||
|
}
|
||||||
|
|
||||||
static int test_count_;
|
static int test_count_;
|
||||||
static std::string data_dir_;
|
static std::string data_dir_;
|
||||||
static std::string init_wd_;
|
static std::string init_wd_;
|
||||||
std::string tmp_dir_, id_;
|
std::string tmp_dir_, id_;
|
||||||
|
|
||||||
|
static constexpr absl::string_view kFile1_ = "file1";
|
||||||
|
static constexpr absl::string_view kFile2_ = "dir1/file2";
|
||||||
|
static constexpr absl::string_view kFile3_ = "dir1/dir2/file3";
|
||||||
|
static constexpr absl::string_view kDir1_ = "dir1";
|
||||||
|
static constexpr absl::string_view kDir2_ = "dir1/dir2";
|
||||||
};
|
};
|
||||||
|
|
||||||
int MiniTarTest::test_count_ = 0;
|
int MiniTarTest::test_count_;
|
||||||
std::string MiniTarTest::data_dir_;
|
std::string MiniTarTest::data_dir_;
|
||||||
std::string MiniTarTest::init_wd_;
|
std::string MiniTarTest::init_wd_;
|
||||||
|
|
||||||
TEST_F(MiniTarTest, Test1) {
|
// The tests have the following pattern:
|
||||||
// ASSERT_THAT(true, IsTrue()) << "TEST";
|
// 1) From inside the test data directory, call the create function with
|
||||||
const char* args[] = {"file1", nullptr};
|
// different arguments.
|
||||||
create(id_.c_str(), 0, args, false);
|
// 2) Move to the test specific temporary directory created during the
|
||||||
|
// set up phase.
|
||||||
|
// 3) Extract the archive created at step 1.
|
||||||
|
// 4) Check that the files in the archive have been extracted correctly
|
||||||
|
// by first checking if they exist and then checking if the content is the
|
||||||
|
// same as in the original file.
|
||||||
|
TEST_F(MiniTarTest, TestFileSimple) {
|
||||||
|
std::vector<std::string> v = {kFile1_.data()};
|
||||||
|
|
||||||
ASSERT_THAT(chdir(tmp_dir_.c_str()), Eq(0))
|
create(id_.data(), 0, VecStringToCharPtrArr(v), false);
|
||||||
|
|
||||||
|
ASSERT_THAT(chdir(tmp_dir_.data()), Eq(0))
|
||||||
<< "Could not chdir into test data directory";
|
<< "Could not chdir into test data directory";
|
||||||
|
|
||||||
extract(JoinPath(data_dir_, id_).c_str(), 1, 0, false);
|
extract(JoinPath(data_dir_, id_).data(), 1, 0, false);
|
||||||
EXPECT_THAT(Exists("file1", false), IsTrue()) << "Could not find file1";
|
|
||||||
|
CheckFile(std::string(kFile1_));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(MiniTarTest, Test2) { ASSERT_THAT(true, IsTrue()) << "TEST"; }
|
TEST_F(MiniTarTest, TestMultipleFiles) {
|
||||||
|
std::vector<std::string> v = {kFile1_.data(), kFile2_.data(), kFile3_.data()};
|
||||||
|
create(id_.data(), 0, VecStringToCharPtrArr(v), false);
|
||||||
|
ASSERT_THAT(Exists(id_.data(), false), IsTrue())
|
||||||
|
<< "Archive file was not created";
|
||||||
|
|
||||||
TEST(TESTEX1, TESTEX2) { ASSERT_THAT(true, IsTrue()) << "TEST"; }
|
ASSERT_THAT(chdir(tmp_dir_.data()), Eq(0))
|
||||||
|
<< "Could not chdir into test data directory";
|
||||||
|
|
||||||
|
extract(JoinPath(data_dir_, id_).data(), 1, 0, false);
|
||||||
|
|
||||||
|
CheckFile(std::string(kFile1_));
|
||||||
|
CheckFile(std::string(kFile2_));
|
||||||
|
CheckFile(std::string(kFile3_));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(MiniTarTest, TestDirectorySimple) {
|
||||||
|
std::vector<std::string> v = {kDir2_.data()};
|
||||||
|
create(id_.data(), 0, VecStringToCharPtrArr(v), false);
|
||||||
|
|
||||||
|
ASSERT_THAT(chdir(tmp_dir_.data()), Eq(0))
|
||||||
|
<< "Could not chdir into test data directory";
|
||||||
|
|
||||||
|
extract(JoinPath(data_dir_, id_).data(), 1, 0, false);
|
||||||
|
|
||||||
|
CheckFile(std::string(kFile3_));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(MiniTarTest, TestDirectoryNested) {
|
||||||
|
std::vector<std::string> v = {kDir1_.data()};
|
||||||
|
create(id_.data(), 0, VecStringToCharPtrArr(v), false);
|
||||||
|
|
||||||
|
ASSERT_THAT(chdir(tmp_dir_.data()), Eq(0))
|
||||||
|
<< "Could not chdir into test data directory";
|
||||||
|
|
||||||
|
extract(JoinPath(data_dir_, id_).data(), 1, 0, false);
|
||||||
|
|
||||||
|
CheckFile(std::string(kFile2_));
|
||||||
|
CheckFile(std::string(kFile3_));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(MiniTarTest, TestComplex) {
|
||||||
|
std::vector<std::string> v = {kFile1_.data(), kDir1_.data()};
|
||||||
|
create(id_.data(), 0, VecStringToCharPtrArr(v), false);
|
||||||
|
|
||||||
|
ASSERT_THAT(chdir(tmp_dir_.data()), Eq(0))
|
||||||
|
<< "Could not chdir into test data directory";
|
||||||
|
|
||||||
|
extract(JoinPath(data_dir_, id_).data(), 1, 0, false);
|
||||||
|
|
||||||
|
CheckFile(std::string(kFile1_));
|
||||||
|
CheckFile(std::string(kFile2_));
|
||||||
|
CheckFile(std::string(kFile3_));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(MiniTarTest, TestCompress) {
|
||||||
|
std::vector<std::string> v = {kFile1_.data(), kDir1_.data()};
|
||||||
|
int compress = 'Z';
|
||||||
|
create(id_.data(), compress, VecStringToCharPtrArr(v), false);
|
||||||
|
|
||||||
|
ASSERT_THAT(chdir(tmp_dir_.data()), Eq(0))
|
||||||
|
<< "Could not chdir into test data directory";
|
||||||
|
extract(JoinPath(data_dir_, id_).data(), 1, 0, false);
|
||||||
|
|
||||||
|
CheckFile(std::string(kFile1_));
|
||||||
|
CheckFile(std::string(kFile2_));
|
||||||
|
CheckFile(std::string(kFile3_));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(MiniTarTest, TestGZIP) {
|
||||||
|
std::vector<std::string> v = {kFile1_.data(), kDir1_.data()};
|
||||||
|
int compress = 'z';
|
||||||
|
create(id_.data(), compress, VecStringToCharPtrArr(v), false);
|
||||||
|
|
||||||
|
ASSERT_THAT(chdir(tmp_dir_.data()), Eq(0))
|
||||||
|
<< "Could not chdir into test data directory";
|
||||||
|
extract(JoinPath(data_dir_, id_).data(), 1, 0, false);
|
||||||
|
|
||||||
|
CheckFile(std::string(kFile1_));
|
||||||
|
CheckFile(std::string(kFile2_));
|
||||||
|
CheckFile(std::string(kFile3_));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(MiniTarTest, TestBZIP2) {
|
||||||
|
std::vector<std::string> v = {kFile1_.data(), kDir1_.data()};
|
||||||
|
int compress = 'j';
|
||||||
|
create(id_.data(), compress, VecStringToCharPtrArr(v), false);
|
||||||
|
|
||||||
|
ASSERT_THAT(chdir(tmp_dir_.data()), Eq(0))
|
||||||
|
<< "Could not chdir into test data directory";
|
||||||
|
extract(JoinPath(data_dir_, id_).data(), 1, 0, false);
|
||||||
|
|
||||||
|
CheckFile(std::string(kFile1_));
|
||||||
|
CheckFile(std::string(kFile2_));
|
||||||
|
CheckFile(std::string(kFile3_));
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
Loading…
Reference in New Issue
Block a user