| 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 |