Index: third_party/ijar/zip_main.cc |
diff --git a/third_party/ijar/zip_main.cc b/third_party/ijar/zip_main.cc |
index 6c2a97439734cd70020f5da3c0e67c5eb315c6de..1c55ee9fdcf44cf2251242d92a0821927ac981aa 100644 |
--- a/third_party/ijar/zip_main.cc |
+++ b/third_party/ijar/zip_main.cc |
@@ -1,6 +1,4 @@ |
-// Copyright 2015 Google Inc. All rights reserved. |
-// |
-// Author: Alan Donovan <adonovan@google.com> |
+// Copyright 2015 The Bazel Authors. All rights reserved. |
// |
// Licensed under the Apache License, Version 2.0 (the "License"); |
// you may not use this file except in compliance with the License. |
@@ -22,14 +20,14 @@ |
// CRC-32 of all files in the zip file will be set to 0. |
// |
+#include <errno.h> |
+#include <fcntl.h> |
+#include <limits.h> |
+#include <stdint.h> |
#include <stdio.h> |
-#include <string.h> |
#include <stdlib.h> |
-#include <limits.h> |
-#include <fcntl.h> |
+#include <string.h> |
#include <unistd.h> |
-#include <sys/mman.h> |
-#include <errno.h> |
#include <memory> |
#include "third_party/ijar/zip.h" |
@@ -72,8 +70,8 @@ class UnzipProcessor : public ZipExtractorProcessor { |
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); |
+ size_t l = len1; |
+ strncpy(out, path1, size - 1); |
out[size-1] = 0; |
if (l < size - 1 && path1[len1] != '/' && path2[0] != '/') { |
out[l] = '/'; |
@@ -154,11 +152,30 @@ void basename(const char *path, char *output, size_t output_size) { |
output[output_size-1] = 0; |
} |
+// copy size bytes from file descriptor fd into buffer. |
+int copy_file_to_buffer(int fd, size_t size, void *buffer) { |
+ size_t nb_read = 0; |
+ while (nb_read < size) { |
+ size_t to_read = size - nb_read; |
+ if (to_read > 16384 /* 16K */) { |
+ to_read = 16384; |
+ } |
+ ssize_t r = read(fd, static_cast<uint8_t *>(buffer) + nb_read, to_read); |
+ if (r < 0) { |
+ return -1; |
+ } |
+ nb_read += r; |
+ } |
+ return 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); |
+ if (getcwd(output_root, PATH_MAX) == NULL) { |
+ fprintf(stderr, "getcwd() failed: %s.\n", strerror(errno)); |
+ return -1; |
+ } |
UnzipProcessor processor(output_root, verbose, extract); |
std::unique_ptr<ZipExtractor> extractor(ZipExtractor::Create(zipfile, |
@@ -176,10 +193,122 @@ int extract(char *zipfile, bool verbose, bool extract) { |
return 0; |
} |
+// add a file to the zip |
+int add_file(std::unique_ptr<ZipBuilder> const &builder, char *file, |
+ bool flatten, bool verbose, bool compress) { |
+ struct stat statst; |
+ if (stat(file, &statst) < 0) { |
+ fprintf(stderr, "Cannot stat file %s: %s.\n", file, strerror(errno)); |
+ return -1; |
+ } |
+ bool isdir = (statst.st_mode & S_IFDIR) != 0; |
+ |
+ if (flatten && isdir) { |
+ return 0; |
+ } |
+ |
+ // Compute the path, flattening it if requested |
+ char path[PATH_MAX]; |
+ size_t len = strlen(file); |
+ if (len > PATH_MAX) { |
+ fprintf(stderr, "Path too long: %s.\n", file); |
+ return -1; |
+ } |
+ if (flatten) { |
+ basename(file, path, PATH_MAX); |
+ } else { |
+ strncpy(path, file, PATH_MAX); |
+ path[PATH_MAX - 1] = 0; |
+ 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 { |
+ // read the input file |
+ int fd = open(file, O_RDONLY); |
+ if (fd < 0) { |
+ fprintf(stderr, "Can't open file %s for reading: %s.\n", file, |
+ strerror(errno)); |
+ return -1; |
+ } |
+ if (copy_file_to_buffer(fd, statst.st_size, buffer) < 0) { |
+ fprintf(stderr, "Can't read file %s: %s.\n", file, strerror(errno)); |
+ close(fd); |
+ return -1; |
+ } |
+ close(fd); |
+ builder->FinishFile(statst.st_size, compress, true); |
+ } |
+ return 0; |
+} |
+ |
+// Read a list of files separated by newlines. The resulting array can be |
+// freed using the free method. |
+char **read_filelist(char *filename) { |
+ struct stat statst; |
+ int fd = open(filename, O_RDONLY); |
+ if (fd < 0) { |
+ fprintf(stderr, "Can't open file %s for reading: %s.\n", filename, |
+ strerror(errno)); |
+ return NULL; |
+ } |
+ if (fstat(fd, &statst) < 0) { |
+ fprintf(stderr, "Cannot stat file %s: %s.\n", filename, strerror(errno)); |
+ return NULL; |
+ } |
+ |
+ char *data = static_cast<char *>(malloc(statst.st_size)); |
+ if (copy_file_to_buffer(fd, statst.st_size, data) < 0) { |
+ fprintf(stderr, "Can't read file %s: %s.\n", filename, strerror(errno)); |
+ close(fd); |
+ return NULL; |
+ } |
+ close(fd); |
+ |
+ int nb_entries = 1; |
+ for (int i = 0; i < statst.st_size; i++) { |
+ if (data[i] == '\n') { |
+ nb_entries++; |
+ } |
+ } |
+ |
+ size_t sizeof_array = sizeof(char *) * (nb_entries + 1); |
+ void *result = malloc(sizeof_array + statst.st_size); |
+ // copy the content |
+ char **filelist = static_cast<char **>(result); |
+ char *content = static_cast<char *>(result) + sizeof_array; |
+ memcpy(content, data, statst.st_size); |
+ free(data); |
+ // Create the corresponding array |
+ int j = 1; |
+ filelist[0] = content; |
+ for (int i = 0; i < statst.st_size; i++) { |
+ if (content[i] == '\n') { |
+ content[i] = 0; |
+ if (i + 1 < statst.st_size) { |
+ filelist[j] = content + i + 1; |
+ j++; |
+ } |
+ } |
+ } |
+ filelist[j] = NULL; |
+ return filelist; |
+} |
+ |
// 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; |
@@ -191,53 +320,8 @@ int create(char *zipfile, char **files, bool flatten, bool verbose, |
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 (add_file(builder, files[i], flatten, verbose, compress) < 0) { |
+ return -1; |
} |
} |
if (builder->Finish() < 0) { |
@@ -301,7 +385,16 @@ int main(int argc, char **argv) { |
usage(argv[0]); |
} |
// Create a zip |
- return devtools_ijar::create(argv[2], argv + 3, flatten, verbose, compress); |
+ 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; |
+ } |
+ } |
+ return devtools_ijar::create(argv[2], filelist, flatten, verbose, compress); |
} else { |
if (flatten) { |
usage(argv[0]); |