| OLD | NEW | 
|    1 // Copyright 2015 Google Inc. All rights reserved. |    1 // Copyright 2015 The Bazel Authors. All rights reserved. | 
|    2 // |    2 // | 
|    3 // Author: Alan Donovan <adonovan@google.com> |  | 
|    4 // |  | 
|    5 // Licensed under the Apache License, Version 2.0 (the "License"); |    3 // Licensed under the Apache License, Version 2.0 (the "License"); | 
|    6 // you may not use this file except in compliance with the License. |    4 // you may not use this file except in compliance with the License. | 
|    7 // You may obtain a copy of the License at |    5 // You may obtain a copy of the License at | 
|    8 // |    6 // | 
|    9 //    http://www.apache.org/licenses/LICENSE-2.0 |    7 //    http://www.apache.org/licenses/LICENSE-2.0 | 
|   10 // |    8 // | 
|   11 // Unless required by applicable law or agreed to in writing, software |    9 // Unless required by applicable law or agreed to in writing, software | 
|   12 // distributed under the License is distributed on an "AS IS" BASIS, |   10 // distributed under the License is distributed on an "AS IS" BASIS, | 
|   13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |   11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|   14 // See the License for the specific language governing permissions and |   12 // See the License for the specific language governing permissions and | 
|   15 // limitations under the License. |   13 // limitations under the License. | 
|   16  |   14  | 
|   17 // |   15 // | 
|   18 // Zip / Unzip file using ijar zip implementation. |   16 // Zip / Unzip file using ijar zip implementation. | 
|   19 // |   17 // | 
|   20 // Note that this Zip implementation intentionally don't compute CRC-32 |   18 // Note that this Zip implementation intentionally don't compute CRC-32 | 
|   21 // because it is useless computation for jar because Java doesn't care. |   19 // because it is useless computation for jar because Java doesn't care. | 
|   22 // CRC-32 of all files in the zip file will be set to 0. |   20 // CRC-32 of all files in the zip file will be set to 0. | 
|   23 // |   21 // | 
|   24  |   22  | 
 |   23 #include <errno.h> | 
 |   24 #include <fcntl.h> | 
 |   25 #include <limits.h> | 
 |   26 #include <stdint.h> | 
|   25 #include <stdio.h> |   27 #include <stdio.h> | 
 |   28 #include <stdlib.h> | 
|   26 #include <string.h> |   29 #include <string.h> | 
|   27 #include <stdlib.h> |  | 
|   28 #include <limits.h> |  | 
|   29 #include <fcntl.h> |  | 
|   30 #include <unistd.h> |   30 #include <unistd.h> | 
|   31 #include <sys/mman.h> |  | 
|   32 #include <errno.h> |  | 
|   33 #include <memory> |   31 #include <memory> | 
|   34  |   32  | 
|   35 #include "third_party/ijar/zip.h" |   33 #include "third_party/ijar/zip.h" | 
|   36  |   34  | 
|   37 namespace devtools_ijar { |   35 namespace devtools_ijar { | 
|   38  |   36  | 
|   39 #define SYSCALL(expr)  do { \ |   37 #define SYSCALL(expr)  do { \ | 
|   40                          if ((expr) < 0) { \ |   38                          if ((expr) < 0) { \ | 
|   41                            perror(#expr); \ |   39                            perror(#expr); \ | 
|   42                            abort(); \ |   40                            abort(); \ | 
| (...skipping 22 matching lines...) Expand all  Loading... | 
|   65   const char *output_root_; |   63   const char *output_root_; | 
|   66   const bool verbose_; |   64   const bool verbose_; | 
|   67   const bool extract_; |   65   const bool extract_; | 
|   68 }; |   66 }; | 
|   69  |   67  | 
|   70 // Concatene 2 path, path1 and path2, using / as a directory separator and |   68 // Concatene 2 path, path1 and path2, using / as a directory separator and | 
|   71 // puting the result in "out". "size" specify the size of the output buffer |   69 // puting the result in "out". "size" specify the size of the output buffer | 
|   72 void concat_path(char* out, const size_t size, |   70 void concat_path(char* out, const size_t size, | 
|   73                  const char *path1, const char *path2) { |   71                  const char *path1, const char *path2) { | 
|   74   int len1 = strlen(path1); |   72   int len1 = strlen(path1); | 
|   75   int l = len1; |   73   size_t l = len1; | 
|   76   strncpy(out, path1, size-1); |   74   strncpy(out, path1, size - 1); | 
|   77   out[size-1] = 0; |   75   out[size-1] = 0; | 
|   78   if (l < size - 1 && path1[len1] != '/' && path2[0] != '/') { |   76   if (l < size - 1 && path1[len1] != '/' && path2[0] != '/') { | 
|   79     out[l] = '/'; |   77     out[l] = '/'; | 
|   80     l++; |   78     l++; | 
|   81     out[l] = 0; |   79     out[l] = 0; | 
|   82   } |   80   } | 
|   83   if (l < size - 1) { |   81   if (l < size - 1) { | 
|   84     strncat(out, path2, size - 1 - l); |   82     strncat(out, path2, size - 1 - l); | 
|   85   } |   83   } | 
|   86 } |   84 } | 
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  147   const char *pointer = strrchr(path, '/'); |  145   const char *pointer = strrchr(path, '/'); | 
|  148   if (pointer == NULL) { |  146   if (pointer == NULL) { | 
|  149     pointer = path; |  147     pointer = path; | 
|  150   } else { |  148   } else { | 
|  151     pointer++;  // Skip the leading slash. |  149     pointer++;  // Skip the leading slash. | 
|  152   } |  150   } | 
|  153   strncpy(output, pointer, output_size); |  151   strncpy(output, pointer, output_size); | 
|  154   output[output_size-1] = 0; |  152   output[output_size-1] = 0; | 
|  155 } |  153 } | 
|  156  |  154  | 
 |  155 // copy size bytes from file descriptor fd into buffer. | 
 |  156 int copy_file_to_buffer(int fd, size_t size, void *buffer) { | 
 |  157   size_t nb_read = 0; | 
 |  158   while (nb_read < size) { | 
 |  159     size_t to_read = size - nb_read; | 
 |  160     if (to_read > 16384 /* 16K */) { | 
 |  161       to_read = 16384; | 
 |  162     } | 
 |  163     ssize_t r = read(fd, static_cast<uint8_t *>(buffer) + nb_read, to_read); | 
 |  164     if (r < 0) { | 
 |  165       return -1; | 
 |  166     } | 
 |  167     nb_read += r; | 
 |  168   } | 
 |  169   return 0; | 
 |  170 } | 
|  157  |  171  | 
|  158 // Execute the extraction (or just listing if just v is provided) |  172 // Execute the extraction (or just listing if just v is provided) | 
|  159 int extract(char *zipfile, bool verbose, bool extract) { |  173 int extract(char *zipfile, bool verbose, bool extract) { | 
|  160   char output_root[PATH_MAX]; |  174   char output_root[PATH_MAX]; | 
|  161   getcwd(output_root, PATH_MAX); |  175   if (getcwd(output_root, PATH_MAX) == NULL) { | 
 |  176     fprintf(stderr, "getcwd() failed: %s.\n", strerror(errno)); | 
 |  177     return -1; | 
 |  178   } | 
|  162  |  179  | 
|  163   UnzipProcessor processor(output_root, verbose, extract); |  180   UnzipProcessor processor(output_root, verbose, extract); | 
|  164   std::unique_ptr<ZipExtractor> extractor(ZipExtractor::Create(zipfile, |  181   std::unique_ptr<ZipExtractor> extractor(ZipExtractor::Create(zipfile, | 
|  165                                                                &processor)); |  182                                                                &processor)); | 
|  166   if (extractor.get() == NULL) { |  183   if (extractor.get() == NULL) { | 
|  167     fprintf(stderr, "Unable to open zip file %s: %s.\n", zipfile, |  184     fprintf(stderr, "Unable to open zip file %s: %s.\n", zipfile, | 
|  168             strerror(errno)); |  185             strerror(errno)); | 
|  169     return -1; |  186     return -1; | 
|  170   } |  187   } | 
|  171  |  188  | 
|  172   if (extractor->ProcessAll() < 0) { |  189   if (extractor->ProcessAll() < 0) { | 
|  173     fprintf(stderr, "%s.\n", extractor->GetError()); |  190     fprintf(stderr, "%s.\n", extractor->GetError()); | 
|  174     return -1; |  191     return -1; | 
|  175   } |  192   } | 
|  176   return 0; |  193   return 0; | 
|  177 } |  194 } | 
|  178  |  195  | 
 |  196 // add a file to the zip | 
 |  197 int add_file(std::unique_ptr<ZipBuilder> const &builder, char *file, | 
 |  198              bool flatten, bool verbose, bool compress) { | 
 |  199   struct stat statst; | 
 |  200   if (stat(file, &statst) < 0) { | 
 |  201     fprintf(stderr, "Cannot stat file %s: %s.\n", file, strerror(errno)); | 
 |  202     return -1; | 
 |  203   } | 
 |  204   bool isdir = (statst.st_mode & S_IFDIR) != 0; | 
 |  205  | 
 |  206   if (flatten && isdir) { | 
 |  207     return 0; | 
 |  208   } | 
 |  209  | 
 |  210   // Compute the path, flattening it if requested | 
 |  211   char path[PATH_MAX]; | 
 |  212   size_t len = strlen(file); | 
 |  213   if (len > PATH_MAX) { | 
 |  214     fprintf(stderr, "Path too long: %s.\n", file); | 
 |  215     return -1; | 
 |  216   } | 
 |  217   if (flatten) { | 
 |  218     basename(file, path, PATH_MAX); | 
 |  219   } else { | 
 |  220     strncpy(path, file, PATH_MAX); | 
 |  221     path[PATH_MAX - 1] = 0; | 
 |  222     if (isdir && len < PATH_MAX - 1) { | 
 |  223       // Add the trailing slash for folders | 
 |  224       path[len] = '/'; | 
 |  225       path[len + 1] = 0; | 
 |  226     } | 
 |  227   } | 
 |  228  | 
 |  229   if (verbose) { | 
 |  230     mode_t perm = statst.st_mode & 0777; | 
 |  231     printf("%c %o %s\n", isdir ? 'd' : 'f', perm, path); | 
 |  232   } | 
 |  233  | 
 |  234   u1 *buffer = builder->NewFile(path, mode_to_zipattr(statst.st_mode)); | 
 |  235   if (isdir || statst.st_size == 0) { | 
 |  236     builder->FinishFile(0); | 
 |  237   } else { | 
 |  238     // read the input file | 
 |  239     int fd = open(file, O_RDONLY); | 
 |  240     if (fd < 0) { | 
 |  241       fprintf(stderr, "Can't open file %s for reading: %s.\n", file, | 
 |  242               strerror(errno)); | 
 |  243       return -1; | 
 |  244     } | 
 |  245     if (copy_file_to_buffer(fd, statst.st_size, buffer) < 0) { | 
 |  246       fprintf(stderr, "Can't read file %s: %s.\n", file, strerror(errno)); | 
 |  247       close(fd); | 
 |  248       return -1; | 
 |  249     } | 
 |  250     close(fd); | 
 |  251     builder->FinishFile(statst.st_size, compress, true); | 
 |  252   } | 
 |  253   return 0; | 
 |  254 } | 
 |  255  | 
 |  256 // Read a list of files separated by newlines. The resulting array can be | 
 |  257 // freed using the free method. | 
 |  258 char **read_filelist(char *filename) { | 
 |  259   struct stat statst; | 
 |  260   int fd = open(filename, O_RDONLY); | 
 |  261   if (fd < 0) { | 
 |  262     fprintf(stderr, "Can't open file %s for reading: %s.\n", filename, | 
 |  263             strerror(errno)); | 
 |  264     return NULL; | 
 |  265   } | 
 |  266   if (fstat(fd, &statst) < 0) { | 
 |  267     fprintf(stderr, "Cannot stat file %s: %s.\n", filename, strerror(errno)); | 
 |  268     return NULL; | 
 |  269   } | 
 |  270  | 
 |  271   char *data = static_cast<char *>(malloc(statst.st_size)); | 
 |  272   if (copy_file_to_buffer(fd, statst.st_size, data) < 0) { | 
 |  273     fprintf(stderr, "Can't read file %s: %s.\n", filename, strerror(errno)); | 
 |  274     close(fd); | 
 |  275     return NULL; | 
 |  276   } | 
 |  277   close(fd); | 
 |  278  | 
 |  279   int nb_entries = 1; | 
 |  280   for (int i = 0; i < statst.st_size; i++) { | 
 |  281     if (data[i] == '\n') { | 
 |  282       nb_entries++; | 
 |  283     } | 
 |  284   } | 
 |  285  | 
 |  286   size_t sizeof_array = sizeof(char *) * (nb_entries + 1); | 
 |  287   void *result = malloc(sizeof_array + statst.st_size); | 
 |  288   // copy the content | 
 |  289   char **filelist = static_cast<char **>(result); | 
 |  290   char *content = static_cast<char *>(result) + sizeof_array; | 
 |  291   memcpy(content, data, statst.st_size); | 
 |  292   free(data); | 
 |  293   // Create the corresponding array | 
 |  294   int j = 1; | 
 |  295   filelist[0] = content; | 
 |  296   for (int i = 0; i < statst.st_size; i++) { | 
 |  297     if (content[i] == '\n') { | 
 |  298       content[i] = 0; | 
 |  299       if (i + 1 < statst.st_size) { | 
 |  300         filelist[j] = content + i + 1; | 
 |  301         j++; | 
 |  302       } | 
 |  303     } | 
 |  304   } | 
 |  305   filelist[j] = NULL; | 
 |  306   return filelist; | 
 |  307 } | 
 |  308  | 
|  179 // Execute the create operation |  309 // Execute the create operation | 
|  180 int create(char *zipfile, char **files, bool flatten, bool verbose, |  310 int create(char *zipfile, char **files, bool flatten, bool verbose, | 
|  181            bool compress) { |  311            bool compress) { | 
|  182   struct stat statst; |  | 
|  183   u8 size = ZipBuilder::EstimateSize(files); |  312   u8 size = ZipBuilder::EstimateSize(files); | 
|  184   if (size == 0) { |  313   if (size == 0) { | 
|  185     return -1; |  314     return -1; | 
|  186   } |  315   } | 
|  187   std::unique_ptr<ZipBuilder> builder(ZipBuilder::Create(zipfile, size)); |  316   std::unique_ptr<ZipBuilder> builder(ZipBuilder::Create(zipfile, size)); | 
|  188   if (builder.get() == NULL) { |  317   if (builder.get() == NULL) { | 
|  189     fprintf(stderr, "Unable to create zip file %s: %s.\n", |  318     fprintf(stderr, "Unable to create zip file %s: %s.\n", | 
|  190             zipfile, strerror(errno)); |  319             zipfile, strerror(errno)); | 
|  191     return -1; |  320     return -1; | 
|  192   } |  321   } | 
|  193   for (int i = 0; files[i] != NULL; i++) { |  322   for (int i = 0; files[i] != NULL; i++) { | 
|  194     stat(files[i], &statst); |  323     if (add_file(builder, files[i], flatten, verbose, compress) < 0) { | 
|  195     char path[PATH_MAX]; |  324       return -1; | 
|  196     bool isdir = (statst.st_mode & S_IFDIR) != 0; |  | 
|  197  |  | 
|  198     if (flatten && isdir) { |  | 
|  199       continue; |  | 
|  200     } |  | 
|  201  |  | 
|  202     // Compute the path, flattening it if requested |  | 
|  203     if (flatten) { |  | 
|  204       basename(files[i], path, PATH_MAX); |  | 
|  205     } else { |  | 
|  206       strncpy(path, files[i], PATH_MAX); |  | 
|  207       path[PATH_MAX-1] = 0; |  | 
|  208       size_t len = strlen(path); |  | 
|  209       if (isdir && len < PATH_MAX - 1) { |  | 
|  210         // Add the trailing slash for folders |  | 
|  211         path[len] = '/'; |  | 
|  212         path[len+1] = 0; |  | 
|  213       } |  | 
|  214     } |  | 
|  215  |  | 
|  216     if (verbose) { |  | 
|  217       mode_t perm = statst.st_mode & 0777; |  | 
|  218       printf("%c %o %s\n", isdir ? 'd' : 'f', perm, path); |  | 
|  219     } |  | 
|  220  |  | 
|  221     u1 *buffer = builder->NewFile(path, mode_to_zipattr(statst.st_mode)); |  | 
|  222     if (isdir || statst.st_size == 0) { |  | 
|  223       builder->FinishFile(0); |  | 
|  224     } else { |  | 
|  225       // mmap the input file and memcpy |  | 
|  226       int fd = open(files[i], O_RDONLY); |  | 
|  227       if (fd < 0) { |  | 
|  228         fprintf(stderr, "Can't open file %s for reading: %s.\n", |  | 
|  229                 files[i], strerror(errno)); |  | 
|  230         return -1; |  | 
|  231       } |  | 
|  232       void *data = mmap(NULL, statst.st_size, PROT_READ, MAP_PRIVATE, fd, 0); |  | 
|  233       if (data == MAP_FAILED) { |  | 
|  234         fprintf(stderr, "Can't mmap file %s for reading: %s.\n", |  | 
|  235                 files[i], strerror(errno)); |  | 
|  236         return -1; |  | 
|  237       } |  | 
|  238       memcpy(buffer, data, statst.st_size); |  | 
|  239       munmap(data, statst.st_size); |  | 
|  240       builder->FinishFile(statst.st_size, compress); |  | 
|  241     } |  325     } | 
|  242   } |  326   } | 
|  243   if (builder->Finish() < 0) { |  327   if (builder->Finish() < 0) { | 
|  244     fprintf(stderr, "%s\n", builder->GetError()); |  328     fprintf(stderr, "%s\n", builder->GetError()); | 
|  245     return -1; |  329     return -1; | 
|  246   } |  330   } | 
|  247   return 0; |  331   return 0; | 
|  248 } |  332 } | 
|  249  |  333  | 
|  250 }  // namespace devtools_ijar |  334 }  // namespace devtools_ijar | 
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  294       break; |  378       break; | 
|  295     default: |  379     default: | 
|  296       usage(argv[0]); |  380       usage(argv[0]); | 
|  297     } |  381     } | 
|  298   } |  382   } | 
|  299   if (create) { |  383   if (create) { | 
|  300     if (extract) { |  384     if (extract) { | 
|  301       usage(argv[0]); |  385       usage(argv[0]); | 
|  302     } |  386     } | 
|  303     // Create a zip |  387     // Create a zip | 
|  304     return devtools_ijar::create(argv[2], argv + 3, flatten, verbose, compress); |  388     char **filelist = argv + 3; | 
 |  389     if (argc == 4 && argv[3][0] == '@') { | 
 |  390       // We never free that list because it needs to be allocated during the | 
 |  391       // whole execution, the system will reclaim memory. | 
 |  392       filelist = devtools_ijar::read_filelist(argv[3] + 1); | 
 |  393       if (filelist == NULL) { | 
 |  394         return -1; | 
 |  395       } | 
 |  396     } | 
 |  397     return devtools_ijar::create(argv[2], filelist, flatten, verbose, compress); | 
|  305   } else { |  398   } else { | 
|  306     if (flatten) { |  399     if (flatten) { | 
|  307       usage(argv[0]); |  400       usage(argv[0]); | 
|  308     } |  401     } | 
|  309     // Extraction / list mode |  402     // Extraction / list mode | 
|  310     return devtools_ijar::extract(argv[2], verbose, extract); |  403     return devtools_ijar::extract(argv[2], verbose, extract); | 
|  311   } |  404   } | 
|  312 } |  405 } | 
| OLD | NEW |