| Index: third_party/ijar/zip_main.cc
|
| diff --git a/third_party/ijar/zip_main.cc b/third_party/ijar/zip_main.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..6c2a97439734cd70020f5da3c0e67c5eb315c6de
|
| --- /dev/null
|
| +++ b/third_party/ijar/zip_main.cc
|
| @@ -0,0 +1,312 @@
|
| +// Copyright 2015 Google Inc. All rights reserved.
|
| +//
|
| +// Author: Alan Donovan <adonovan@google.com>
|
| +//
|
| +// 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.
|
| +
|
| +//
|
| +// Zip / Unzip file using ijar zip implementation.
|
| +//
|
| +// Note that this Zip implementation intentionally don't compute CRC-32
|
| +// because it is useless computation for jar because Java doesn't care.
|
| +// CRC-32 of all files in the zip file will be set to 0.
|
| +//
|
| +
|
| +#include <stdio.h>
|
| +#include <string.h>
|
| +#include <stdlib.h>
|
| +#include <limits.h>
|
| +#include <fcntl.h>
|
| +#include <unistd.h>
|
| +#include <sys/mman.h>
|
| +#include <errno.h>
|
| +#include <memory>
|
| +
|
| +#include "third_party/ijar/zip.h"
|
| +
|
| +namespace devtools_ijar {
|
| +
|
| +#define SYSCALL(expr) do { \
|
| + if ((expr) < 0) { \
|
| + perror(#expr); \
|
| + abort(); \
|
| + } \
|
| + } while (0)
|
| +
|
| +//
|
| +// A ZipExtractorProcessor that extract all 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) {}
|
| + 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;
|
| + }
|
| +
|
| + private:
|
| + const char *output_root_;
|
| + const bool verbose_;
|
| + const bool extract_;
|
| +};
|
| +
|
| +// Concatene 2 path, path1 and path2, using / as a directory separator and
|
| +// puting the result in "out". "size" specify the size of the output buffer
|
| +void concat_path(char* out, const size_t size,
|
| + const char *path1, const char *path2) {
|
| + int len1 = strlen(path1);
|
| + int l = len1;
|
| + strncpy(out, path1, size-1);
|
| + out[size-1] = 0;
|
| + if (l < size - 1 && path1[len1] != '/' && path2[0] != '/') {
|
| + out[l] = '/';
|
| + l++;
|
| + out[l] = 0;
|
| + }
|
| + if (l < size - 1) {
|
| + strncat(out, path2, size - 1 - l);
|
| + }
|
| +}
|
| +
|
| +// Do a recursive mkdir of all folders of path except the last path
|
| +// segment (if path ends with a / then the last path segment is empty).
|
| +// All folders are created using "mode" for creation mode.
|
| +void mkdirs(const char *path, mode_t mode) {
|
| + char path_[PATH_MAX];
|
| + struct stat statst;
|
| + strncpy(path_, path, PATH_MAX);
|
| + path_[PATH_MAX-1] = 0;
|
| + char *pointer = path_;
|
| + while ((pointer = strchr(pointer, '/')) != NULL) {
|
| + if (path_ != pointer) { // skip leading slash
|
| + *pointer = 0;
|
| + if (stat(path_, &statst) != 0) {
|
| + if (mkdir(path_, mode) < 0) {
|
| + fprintf(stderr, "Cannot create folder %s: %s\n",
|
| + path_, strerror(errno));
|
| + abort();
|
| + }
|
| + }
|
| + *pointer = '/';
|
| + }
|
| + pointer++;
|
| + }
|
| +}
|
| +
|
| +void UnzipProcessor::Process(const char* filename, const u4 attr,
|
| + const u1* data, const size_t size) {
|
| + mode_t mode = zipattr_to_mode(attr);
|
| + mode_t perm = mode & 0777;
|
| + bool isdir = (mode & S_IFDIR) != 0;
|
| + if (attr == 0) {
|
| + // Fallback when the external attribute is not set.
|
| + isdir = filename[strlen(filename)-1] == '/';
|
| + perm = 0777;
|
| + }
|
| + if (verbose_) {
|
| + printf("%c %o %s\n", isdir ? 'd' : 'f', perm, filename);
|
| + }
|
| + if (extract_) {
|
| + char path[PATH_MAX];
|
| + int fd;
|
| + concat_path(path, PATH_MAX, output_root_, filename);
|
| + mkdirs(path, perm);
|
| + if (!isdir) {
|
| + fd = open(path, O_CREAT | O_WRONLY, perm);
|
| + if (fd < 0) {
|
| + fprintf(stderr, "Cannot open file %s for writing: %s\n",
|
| + path, strerror(errno));
|
| + abort();
|
| + }
|
| + SYSCALL(write(fd, data, size));
|
| + SYSCALL(close(fd));
|
| + }
|
| + }
|
| +}
|
| +
|
| +// Get the basename of path and store it in output. output_size
|
| +// is the size of the output buffer.
|
| +void basename(const char *path, char *output, size_t output_size) {
|
| + const char *pointer = strrchr(path, '/');
|
| + if (pointer == NULL) {
|
| + pointer = path;
|
| + } else {
|
| + pointer++; // Skip the leading slash.
|
| + }
|
| + strncpy(output, pointer, output_size);
|
| + output[output_size-1] = 0;
|
| +}
|
| +
|
| +
|
| +// Execute the extraction (or just listing if just v is provided)
|
| +int extract(char *zipfile, bool verbose, bool extract) {
|
| + char output_root[PATH_MAX];
|
| + getcwd(output_root, PATH_MAX);
|
| +
|
| + UnzipProcessor processor(output_root, verbose, extract);
|
| + std::unique_ptr<ZipExtractor> extractor(ZipExtractor::Create(zipfile,
|
| + &processor));
|
| + if (extractor.get() == NULL) {
|
| + fprintf(stderr, "Unable to open zip file %s: %s.\n", zipfile,
|
| + strerror(errno));
|
| + return -1;
|
| + }
|
| +
|
| + if (extractor->ProcessAll() < 0) {
|
| + fprintf(stderr, "%s.\n", extractor->GetError());
|
| + return -1;
|
| + }
|
| + return 0;
|
| +}
|
| +
|
| +// Execute the create operation
|
| +int create(char *zipfile, char **files, bool flatten, bool verbose,
|
| + bool compress) {
|
| + struct stat statst;
|
| + u8 size = ZipBuilder::EstimateSize(files);
|
| + if (size == 0) {
|
| + return -1;
|
| + }
|
| + std::unique_ptr<ZipBuilder> builder(ZipBuilder::Create(zipfile, size));
|
| + if (builder.get() == NULL) {
|
| + fprintf(stderr, "Unable to create zip file %s: %s.\n",
|
| + zipfile, strerror(errno));
|
| + return -1;
|
| + }
|
| + for (int i = 0; files[i] != NULL; i++) {
|
| + stat(files[i], &statst);
|
| + char path[PATH_MAX];
|
| + bool isdir = (statst.st_mode & S_IFDIR) != 0;
|
| +
|
| + if (flatten && isdir) {
|
| + continue;
|
| + }
|
| +
|
| + // Compute the path, flattening it if requested
|
| + if (flatten) {
|
| + basename(files[i], path, PATH_MAX);
|
| + } else {
|
| + strncpy(path, files[i], PATH_MAX);
|
| + path[PATH_MAX-1] = 0;
|
| + size_t len = strlen(path);
|
| + if (isdir && len < PATH_MAX - 1) {
|
| + // Add the trailing slash for folders
|
| + path[len] = '/';
|
| + path[len+1] = 0;
|
| + }
|
| + }
|
| +
|
| + if (verbose) {
|
| + mode_t perm = statst.st_mode & 0777;
|
| + printf("%c %o %s\n", isdir ? 'd' : 'f', perm, path);
|
| + }
|
| +
|
| + u1 *buffer = builder->NewFile(path, mode_to_zipattr(statst.st_mode));
|
| + if (isdir || statst.st_size == 0) {
|
| + builder->FinishFile(0);
|
| + } else {
|
| + // mmap the input file and memcpy
|
| + int fd = open(files[i], O_RDONLY);
|
| + if (fd < 0) {
|
| + fprintf(stderr, "Can't open file %s for reading: %s.\n",
|
| + files[i], strerror(errno));
|
| + return -1;
|
| + }
|
| + void *data = mmap(NULL, statst.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
|
| + if (data == MAP_FAILED) {
|
| + fprintf(stderr, "Can't mmap file %s for reading: %s.\n",
|
| + files[i], strerror(errno));
|
| + return -1;
|
| + }
|
| + memcpy(buffer, data, statst.st_size);
|
| + munmap(data, statst.st_size);
|
| + builder->FinishFile(statst.st_size, compress);
|
| + }
|
| + }
|
| + if (builder->Finish() < 0) {
|
| + fprintf(stderr, "%s\n", builder->GetError());
|
| + return -1;
|
| + }
|
| + return 0;
|
| +}
|
| +
|
| +} // namespace devtools_ijar
|
| +
|
| +//
|
| +// main method
|
| +//
|
| +static void usage(char *progname) {
|
| + fprintf(stderr, "Usage: %s [vxc[fC]] x.zip [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, " c create - add files to x.zip\n");
|
| + fprintf(stderr, " f flatten - flatten files to use with create operation\n");
|
| + fprintf(stderr,
|
| + " C compress - compress files when using the create operation\n");
|
| + fprintf(stderr, "x and c cannot be used in the same command-line.\n");
|
| + exit(1);
|
| +}
|
| +
|
| +int main(int argc, char **argv) {
|
| + bool extract = false;
|
| + bool verbose = false;
|
| + bool create = false;
|
| + bool compress = false;
|
| + bool flatten = false;
|
| +
|
| + if (argc < 3) {
|
| + usage(argv[0]);
|
| + }
|
| +
|
| + for (int i = 0; argv[1][i] != 0; i++) {
|
| + switch (argv[1][i]) {
|
| + case 'x':
|
| + extract = true;
|
| + break;
|
| + case 'v':
|
| + verbose = true;
|
| + break;
|
| + case 'c':
|
| + create = true;
|
| + break;
|
| + case 'f':
|
| + flatten = true;
|
| + break;
|
| + case 'C':
|
| + compress = true;
|
| + break;
|
| + default:
|
| + usage(argv[0]);
|
| + }
|
| + }
|
| + if (create) {
|
| + if (extract) {
|
| + usage(argv[0]);
|
| + }
|
| + // Create a zip
|
| + return devtools_ijar::create(argv[2], argv + 3, flatten, verbose, compress);
|
| + } else {
|
| + if (flatten) {
|
| + usage(argv[0]);
|
| + }
|
| + // Extraction / list mode
|
| + return devtools_ijar::extract(argv[2], verbose, extract);
|
| + }
|
| +}
|
|
|