diff options
-rwxr-xr-x | third_party/ijar/test/zip_test.sh | 36 | ||||
-rw-r--r-- | third_party/ijar/zip_main.cc | 118 |
2 files changed, 125 insertions, 29 deletions
diff --git a/third_party/ijar/test/zip_test.sh b/third_party/ijar/test/zip_test.sh index 379f9b7891..719f70a908 100755 --- a/third_party/ijar/test/zip_test.sh +++ b/third_party/ijar/test/zip_test.sh @@ -32,8 +32,10 @@ source ${DIR}/testenv.sh || { echo "testenv.sh not found!" >&2; exit 1; } function assert_unzip_same_as_zipper() { local folder1=$(mktemp -d ${TEST_TMPDIR}/output.XXXXXXXX) local folder2=$(mktemp -d ${TEST_TMPDIR}/output.XXXXXXXX) - (cd $folder1 && $UNZIP -q $1 || true) # ignore CRC32 errors - (cd $folder2 && $ZIPPER x $1) + local zipfile=$1 + shift + (cd $folder1 && $UNZIP -q $zipfile $@ || true) # ignore CRC32 errors + (cd $folder2 && $ZIPPER x $zipfile $@) diff -r $folder1 $folder2 &> $TEST_log \ || fail "Unzip and Zipper resulted in different output" } @@ -93,6 +95,36 @@ function test_zipper() { expect_not_log "path" } +function test_zipper_unzip_selective_files() { + mkdir -p ${TEST_TMPDIR}/test/path/to/some + mkdir -p ${TEST_TMPDIR}/test/some/other/path + touch ${TEST_TMPDIR}/test/path/to/some/empty_file + echo "toto" > ${TEST_TMPDIR}/test/path/to/some/file + echo "titi" > ${TEST_TMPDIR}/test/path/to/some/other_file + chmod +x ${TEST_TMPDIR}/test/path/to/some/other_file + echo "tata" > ${TEST_TMPDIR}/test/file + filelist="$(cd ${TEST_TMPDIR}/test && find . | sed 's|^./||' | grep -v '^.$')" + + assert_zipper_same_after_unzip ${TEST_TMPDIR}/test ${filelist} + assert_unzip_same_as_zipper ${TEST_TMPDIR}/output.zip \ + path/to/some/empty_file path/to/some/other_file +} + +function test_zipper_unzip_to_optional_dir() { + mkdir -p ${TEST_TMPDIR}/test/path/to/some + mkdir -p ${TEST_TMPDIR}/test/some/other/path + touch ${TEST_TMPDIR}/test/path/to/some/empty_file + echo "toto" > ${TEST_TMPDIR}/test/path/to/some/file + echo "titi" > ${TEST_TMPDIR}/test/path/to/some/other_file + chmod +x ${TEST_TMPDIR}/test/path/to/some/other_file + echo "tata" > ${TEST_TMPDIR}/test/file + filelist="$(cd ${TEST_TMPDIR}/test && find . | sed 's|^./||' | grep -v '^.$')" + + assert_zipper_same_after_unzip ${TEST_TMPDIR}/test ${filelist} + assert_unzip_same_as_zipper ${TEST_TMPDIR}/output.zip -d output_dir2 \ + path/to/some/empty_file path/to/some/other_file +} + function test_zipper_compression() { echo -n > ${TEST_TMPDIR}/a for i in $(seq 1 1000); do diff --git a/third_party/ijar/zip_main.cc b/third_party/ijar/zip_main.cc index 1c55ee9fdc..68c226e9bd 100644 --- a/third_party/ijar/zip_main.cc +++ b/third_party/ijar/zip_main.cc @@ -29,6 +29,8 @@ #include <string.h> #include <unistd.h> #include <memory> +#include <set> +#include <string> #include "third_party/ijar/zip.h" @@ -42,27 +44,43 @@ namespace devtools_ijar { } while (0) // -// A ZipExtractorProcessor that extract all files in the ZIP file. +// A ZipExtractorProcessor that extract files in the ZIP file. // class UnzipProcessor : public ZipExtractorProcessor { public: - // Create a processor who will extract the files into output_root - // if "extract" is set to true and will print the list of files and - // their unix modes if "verbose" is set to true. - UnzipProcessor(const char *output_root, bool verbose, bool extract) - : output_root_(output_root), verbose_(verbose), extract_(extract) {} + // Create a processor who will extract the given files (or all files if NULL) + // into output_root if "extract" is set to true and will print the list of + // files and their unix modes if "verbose" is set to true. + UnzipProcessor(const char *output_root, char **files, bool verbose, + bool extract) : output_root_(output_root), + verbose_(verbose), + extract_(extract) { + if (files != NULL) { + for (int i = 0; files[i] != NULL; i++) { + file_names.insert(std::string(files[i])); + } + } + } + virtual ~UnzipProcessor() {} virtual void Process(const char* filename, const u4 attr, const u1* data, const size_t size); virtual bool Accept(const char* filename, const u4 attr) { - return true; + // All entry files are accepted by default. + if (file_names.empty()) { + return true; + } else { + // If users have specified file entries, only accept those files. + return file_names.count(std::string(filename)) == 1; + } } private: const char *output_root_; const bool verbose_; const bool extract_; + std::set<std::string> file_names; }; // Concatene 2 path, path1 and path2, using / as a directory separator and @@ -125,7 +143,9 @@ void UnzipProcessor::Process(const char* filename, const u4 attr, char path[PATH_MAX]; int fd; concat_path(path, PATH_MAX, output_root_, filename); - mkdirs(path, perm); + // Directories created must have executable bit set. Otherwise, we cannot + // write or create any file inside. + mkdirs(path, perm | S_IXUSR); if (!isdir) { fd = open(path, O_CREAT | O_WRONLY, perm); if (fd < 0) { @@ -170,14 +190,22 @@ int copy_file_to_buffer(int fd, size_t size, void *buffer) { } // Execute the extraction (or just listing if just v is provided) -int extract(char *zipfile, bool verbose, bool extract) { - char output_root[PATH_MAX]; - if (getcwd(output_root, PATH_MAX) == NULL) { +int extract(char *zipfile, char* exdir, char **files, bool verbose, + bool extract) { + char cwd[PATH_MAX]; + if (getcwd(cwd, PATH_MAX) == NULL) { fprintf(stderr, "getcwd() failed: %s.\n", strerror(errno)); return -1; } - UnzipProcessor processor(output_root, verbose, extract); + char output_root[PATH_MAX]; + if (exdir != NULL) { + concat_path(output_root, PATH_MAX, cwd, exdir); + } else { + strncpy(output_root, cwd, PATH_MAX); + } + + UnzipProcessor processor(output_root, files, verbose, extract); std::unique_ptr<ZipExtractor> extractor(ZipExtractor::Create(zipfile, &processor)); if (extractor.get() == NULL) { @@ -337,9 +365,13 @@ int create(char *zipfile, char **files, bool flatten, bool verbose, // main method // static void usage(char *progname) { - fprintf(stderr, "Usage: %s [vxc[fC]] x.zip [file1...filen]\n", progname); + fprintf(stderr, "Usage: %s [vxc[fC]] x.zip [-d exdir] [file1...filen]\n", + progname); fprintf(stderr, " v verbose - list all file in x.zip\n"); - fprintf(stderr, " x extract - extract file in x.zip in current directory\n"); + fprintf(stderr, + " x extract - extract files in x.zip to current directory, or " + " an optional directory relative to the current directory " + " specified through -d option\n"); fprintf(stderr, " c create - add files to x.zip\n"); fprintf(stderr, " f flatten - flatten files to use with create operation\n"); fprintf(stderr, @@ -380,26 +412,58 @@ int main(int argc, char **argv) { usage(argv[0]); } } - if (create) { - if (extract) { - usage(argv[0]); + + // x and c cannot be used in the same command-line. + if (create && extract) { + usage(argv[0]); + } + + // Calculate the argument index of the first entry file. + int filelist_start_index; + if (argc > 3 && strcmp(argv[3], "-d") == 0) { + filelist_start_index = 5; + } else { + filelist_start_index = 3; + } + + char** filelist = NULL; + + // We have one option file. Read and extract the content. + if (argc == filelist_start_index + 1 && + argv[filelist_start_index][0] == '@') { + char* filelist_name = argv[filelist_start_index]; + filelist = devtools_ijar::read_filelist(filelist_name + 1); + if (filelist == NULL) { + fprintf(stderr, "Can't read file list %s: %s.\n", filelist_name, + strerror(errno)); + return -1; } - // Create a zip - char **filelist = argv + 3; - if (argc == 4 && argv[3][0] == '@') { - // We never free that list because it needs to be allocated during the - // whole execution, the system will reclaim memory. - filelist = devtools_ijar::read_filelist(argv[3] + 1); - if (filelist == NULL) { - return -1; - } + // We have more than one files. Assume that they are all file entries. + } else if (argc >= filelist_start_index + 1) { + filelist = argv + filelist_start_index; + } else { + // There are no entry files specified. This is forbidden if we are creating + // a zip file. + if (create) { + fprintf(stderr, "Can't create zip without input files specified."); + return -1; } + } + + if (create) { + // Create a zip return devtools_ijar::create(argv[2], filelist, flatten, verbose, compress); } else { if (flatten) { usage(argv[0]); } + + char* exdir = NULL; + if (argc > 3 && strcmp(argv[3], "-d") == 0) { + exdir = argv[4]; + } + // Extraction / list mode - return devtools_ijar::extract(argv[2], verbose, extract); + return devtools_ijar::extract(argv[2], exdir, filelist, verbose, extract); } } |