| 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]);
 | 
| 
 |