Damien Martin-Guillerez | bf6281d | 2015-11-19 16:41:33 +0000 | [diff] [blame] | 1 | // Copyright 2015 The Bazel Authors. All rights reserved. |
Damien Martin-Guillerez | 0844112 | 2015-05-28 11:12:31 +0000 | [diff] [blame] | 2 | // |
| 3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | // you may not use this file except in compliance with the License. |
| 5 | // You may obtain a copy of the License at |
| 6 | // |
| 7 | // http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | // |
| 9 | // Unless required by applicable law or agreed to in writing, software |
| 10 | // distributed under the License is distributed on an "AS IS" BASIS, |
| 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | // See the License for the specific language governing permissions and |
| 13 | // limitations under the License. |
| 14 | |
| 15 | // |
| 16 | // Zip / Unzip file using ijar zip implementation. |
| 17 | // |
| 18 | // Note that this Zip implementation intentionally don't compute CRC-32 |
| 19 | // because it is useless computation for jar because Java doesn't care. |
| 20 | // CRC-32 of all files in the zip file will be set to 0. |
| 21 | // |
| 22 | |
Damien Martin-Guillerez | 0844112 | 2015-05-28 11:12:31 +0000 | [diff] [blame] | 23 | #include <errno.h> |
Damien Martin-Guillerez | c88508c | 2016-01-21 14:19:07 +0000 | [diff] [blame] | 24 | #include <limits.h> |
| 25 | #include <stdint.h> |
| 26 | #include <stdio.h> |
| 27 | #include <stdlib.h> |
| 28 | #include <string.h> |
Laszlo Csomor | d2ed069 | 2016-12-01 14:04:35 +0000 | [diff] [blame] | 29 | |
Damien Martin-Guillerez | 0844112 | 2015-05-28 11:12:31 +0000 | [diff] [blame] | 30 | #include <memory> |
Rumou Duan | 7942bdc | 2016-05-12 15:31:07 +0000 | [diff] [blame] | 31 | #include <set> |
| 32 | #include <string> |
Damien Martin-Guillerez | 0844112 | 2015-05-28 11:12:31 +0000 | [diff] [blame] | 33 | |
Laszlo Csomor | 645dbc4 | 2016-12-01 12:56:43 +0000 | [diff] [blame] | 34 | #include "third_party/ijar/platform_utils.h" |
Damien Martin-Guillerez | 0844112 | 2015-05-28 11:12:31 +0000 | [diff] [blame] | 35 | #include "third_party/ijar/zip.h" |
| 36 | |
| 37 | namespace devtools_ijar { |
| 38 | |
Damien Martin-Guillerez | 0844112 | 2015-05-28 11:12:31 +0000 | [diff] [blame] | 39 | // |
Rumou Duan | 7942bdc | 2016-05-12 15:31:07 +0000 | [diff] [blame] | 40 | // A ZipExtractorProcessor that extract files in the ZIP file. |
Damien Martin-Guillerez | 0844112 | 2015-05-28 11:12:31 +0000 | [diff] [blame] | 41 | // |
| 42 | class UnzipProcessor : public ZipExtractorProcessor { |
| 43 | public: |
Rumou Duan | 7942bdc | 2016-05-12 15:31:07 +0000 | [diff] [blame] | 44 | // Create a processor who will extract the given files (or all files if NULL) |
| 45 | // into output_root if "extract" is set to true and will print the list of |
| 46 | // files and their unix modes if "verbose" is set to true. |
Laszlo Csomor | 9f3f6de | 2016-10-04 10:55:43 +0000 | [diff] [blame] | 47 | UnzipProcessor(const char *output_root, char **files, bool verbose, |
Laszlo Csomor | 8742568 | 2016-10-04 10:28:54 +0000 | [diff] [blame] | 48 | bool extract) : output_root_(output_root), |
| 49 | verbose_(verbose), |
| 50 | extract_(extract) { |
Rumou Duan | 7942bdc | 2016-05-12 15:31:07 +0000 | [diff] [blame] | 51 | if (files != NULL) { |
| 52 | for (int i = 0; files[i] != NULL; i++) { |
| 53 | file_names.insert(std::string(files[i])); |
| 54 | } |
| 55 | } |
| 56 | } |
| 57 | |
Damien Martin-Guillerez | 0844112 | 2015-05-28 11:12:31 +0000 | [diff] [blame] | 58 | virtual ~UnzipProcessor() {} |
| 59 | |
| 60 | virtual void Process(const char* filename, const u4 attr, |
| 61 | const u1* data, const size_t size); |
| 62 | virtual bool Accept(const char* filename, const u4 attr) { |
Rumou Duan | 7942bdc | 2016-05-12 15:31:07 +0000 | [diff] [blame] | 63 | // All entry files are accepted by default. |
| 64 | if (file_names.empty()) { |
| 65 | return true; |
| 66 | } else { |
| 67 | // If users have specified file entries, only accept those files. |
| 68 | return file_names.count(std::string(filename)) == 1; |
| 69 | } |
Damien Martin-Guillerez | 0844112 | 2015-05-28 11:12:31 +0000 | [diff] [blame] | 70 | } |
| 71 | |
| 72 | private: |
Laszlo Csomor | 9f3f6de | 2016-10-04 10:55:43 +0000 | [diff] [blame] | 73 | const char *output_root_; |
Damien Martin-Guillerez | 0844112 | 2015-05-28 11:12:31 +0000 | [diff] [blame] | 74 | const bool verbose_; |
| 75 | const bool extract_; |
Rumou Duan | 7942bdc | 2016-05-12 15:31:07 +0000 | [diff] [blame] | 76 | std::set<std::string> file_names; |
Damien Martin-Guillerez | 0844112 | 2015-05-28 11:12:31 +0000 | [diff] [blame] | 77 | }; |
| 78 | |
Laszlo Csomor | 9f3f6de | 2016-10-04 10:55:43 +0000 | [diff] [blame] | 79 | // Concatene 2 path, path1 and path2, using / as a directory separator and |
| 80 | // puting the result in "out". "size" specify the size of the output buffer |
| 81 | void concat_path(char* out, const size_t size, |
| 82 | const char *path1, const char *path2) { |
| 83 | int len1 = strlen(path1); |
| 84 | size_t l = len1; |
| 85 | strncpy(out, path1, size - 1); |
| 86 | out[size-1] = 0; |
| 87 | if (l < size - 1 && path1[len1] != '/' && path2[0] != '/') { |
| 88 | out[l] = '/'; |
| 89 | l++; |
| 90 | out[l] = 0; |
| 91 | } |
| 92 | if (l < size - 1) { |
| 93 | strncat(out, path2, size - 1 - l); |
| 94 | } |
| 95 | } |
| 96 | |
Damien Martin-Guillerez | 0844112 | 2015-05-28 11:12:31 +0000 | [diff] [blame] | 97 | void UnzipProcessor::Process(const char* filename, const u4 attr, |
| 98 | const u1* data, const size_t size) { |
Laszlo Csomor | 479e18d | 2016-12-02 15:11:08 +0000 | [diff] [blame] | 99 | mode_t perm = zipattr_to_perm(attr); |
| 100 | bool isdir = zipattr_is_dir(attr); |
Damien Martin-Guillerez | 0cd6dfb | 2015-06-29 11:06:50 +0000 | [diff] [blame] | 101 | if (attr == 0) { |
| 102 | // Fallback when the external attribute is not set. |
| 103 | isdir = filename[strlen(filename)-1] == '/'; |
| 104 | perm = 0777; |
| 105 | } |
Damien Martin-Guillerez | 0844112 | 2015-05-28 11:12:31 +0000 | [diff] [blame] | 106 | if (verbose_) { |
Damien Martin-Guillerez | a1c73f9 | 2015-05-29 12:27:25 +0000 | [diff] [blame] | 107 | printf("%c %o %s\n", isdir ? 'd' : 'f', perm, filename); |
Damien Martin-Guillerez | 0844112 | 2015-05-28 11:12:31 +0000 | [diff] [blame] | 108 | } |
| 109 | if (extract_) { |
Laszlo Csomor | 9f3f6de | 2016-10-04 10:55:43 +0000 | [diff] [blame] | 110 | char path[PATH_MAX]; |
Laszlo Csomor | 9f3f6de | 2016-10-04 10:55:43 +0000 | [diff] [blame] | 111 | concat_path(path, PATH_MAX, output_root_, filename); |
Laszlo Csomor | b8caca0 | 2016-12-01 14:37:46 +0000 | [diff] [blame] | 112 | if (!make_dirs(path, perm) || |
| 113 | (!isdir && !write_file(path, perm, data, size))) { |
Laszlo Csomor | 8d6da00 | 2016-12-01 13:16:13 +0000 | [diff] [blame] | 114 | abort(); |
Damien Martin-Guillerez | 0844112 | 2015-05-28 11:12:31 +0000 | [diff] [blame] | 115 | } |
| 116 | } |
| 117 | } |
| 118 | |
Laszlo Csomor | 8742568 | 2016-10-04 10:28:54 +0000 | [diff] [blame] | 119 | // Get the basename of path and store it in output. output_size |
| 120 | // is the size of the output buffer. |
| 121 | void basename(const char *path, char *output, size_t output_size) { |
| 122 | const char *pointer = strrchr(path, '/'); |
| 123 | if (pointer == NULL) { |
| 124 | pointer = path; |
| 125 | } else { |
| 126 | pointer++; // Skip the leading slash. |
| 127 | } |
| 128 | strncpy(output, pointer, output_size); |
| 129 | output[output_size-1] = 0; |
| 130 | } |
| 131 | |
Damien Martin-Guillerez | 0844112 | 2015-05-28 11:12:31 +0000 | [diff] [blame] | 132 | // Execute the extraction (or just listing if just v is provided) |
Rumou Duan | 7942bdc | 2016-05-12 15:31:07 +0000 | [diff] [blame] | 133 | int extract(char *zipfile, char* exdir, char **files, bool verbose, |
| 134 | bool extract) { |
Laszlo Csomor | 8457f3f | 2016-12-01 14:25:18 +0000 | [diff] [blame] | 135 | std::string cwd = get_cwd(); |
| 136 | if (cwd.empty()) { |
Thiago Farina | 74d179a | 2016-04-05 09:30:51 +0000 | [diff] [blame] | 137 | return -1; |
| 138 | } |
Damien Martin-Guillerez | 0844112 | 2015-05-28 11:12:31 +0000 | [diff] [blame] | 139 | |
Laszlo Csomor | 9f3f6de | 2016-10-04 10:55:43 +0000 | [diff] [blame] | 140 | char output_root[PATH_MAX]; |
Rumou Duan | 7942bdc | 2016-05-12 15:31:07 +0000 | [diff] [blame] | 141 | if (exdir != NULL) { |
Laszlo Csomor | 8457f3f | 2016-12-01 14:25:18 +0000 | [diff] [blame] | 142 | concat_path(output_root, PATH_MAX, cwd.c_str(), exdir); |
Rumou Duan | 7942bdc | 2016-05-12 15:31:07 +0000 | [diff] [blame] | 143 | } else { |
Laszlo Csomor | 8457f3f | 2016-12-01 14:25:18 +0000 | [diff] [blame] | 144 | strncpy(output_root, cwd.c_str(), PATH_MAX); |
Rumou Duan | 7942bdc | 2016-05-12 15:31:07 +0000 | [diff] [blame] | 145 | } |
| 146 | |
| 147 | UnzipProcessor processor(output_root, files, verbose, extract); |
Damien Martin-Guillerez | 0844112 | 2015-05-28 11:12:31 +0000 | [diff] [blame] | 148 | std::unique_ptr<ZipExtractor> extractor(ZipExtractor::Create(zipfile, |
| 149 | &processor)); |
| 150 | if (extractor.get() == NULL) { |
| 151 | fprintf(stderr, "Unable to open zip file %s: %s.\n", zipfile, |
| 152 | strerror(errno)); |
| 153 | return -1; |
| 154 | } |
| 155 | |
| 156 | if (extractor->ProcessAll() < 0) { |
| 157 | fprintf(stderr, "%s.\n", extractor->GetError()); |
| 158 | return -1; |
| 159 | } |
| 160 | return 0; |
| 161 | } |
| 162 | |
Damien Martin-Guillerez | c88508c | 2016-01-21 14:19:07 +0000 | [diff] [blame] | 163 | // add a file to the zip |
| 164 | int add_file(std::unique_ptr<ZipBuilder> const &builder, char *file, |
Yun Peng | 43302f4 | 2016-08-04 13:48:02 +0000 | [diff] [blame] | 165 | char *zip_path, bool flatten, bool verbose, bool compress) { |
Laszlo Csomor | 479e18d | 2016-12-02 15:11:08 +0000 | [diff] [blame] | 166 | Stat file_stat = {0, 0666, false}; |
Yun Peng | 43302f4 | 2016-08-04 13:48:02 +0000 | [diff] [blame] | 167 | if (file != NULL) { |
Laszlo Csomor | 645dbc4 | 2016-12-01 12:56:43 +0000 | [diff] [blame] | 168 | if (!stat_file(file, &file_stat)) { |
László Csomor | 9a4dffe | 2016-12-12 09:59:38 +0000 | [diff] [blame] | 169 | fprintf(stderr, "Cannot stat file %s: %s\n", file, strerror(errno)); |
Yun Peng | 43302f4 | 2016-08-04 13:48:02 +0000 | [diff] [blame] | 170 | return -1; |
| 171 | } |
Damien Martin-Guillerez | c88508c | 2016-01-21 14:19:07 +0000 | [diff] [blame] | 172 | } |
Yun Peng | 3070266 | 2016-08-05 11:16:05 +0000 | [diff] [blame] | 173 | char *final_path = zip_path != NULL ? zip_path : file; |
Yun Peng | 43302f4 | 2016-08-04 13:48:02 +0000 | [diff] [blame] | 174 | |
Laszlo Csomor | 645dbc4 | 2016-12-01 12:56:43 +0000 | [diff] [blame] | 175 | bool isdir = file_stat.is_directory; |
Damien Martin-Guillerez | c88508c | 2016-01-21 14:19:07 +0000 | [diff] [blame] | 176 | |
| 177 | if (flatten && isdir) { |
| 178 | return 0; |
| 179 | } |
| 180 | |
| 181 | // Compute the path, flattening it if requested |
Laszlo Csomor | 8742568 | 2016-10-04 10:28:54 +0000 | [diff] [blame] | 182 | char path[PATH_MAX]; |
Yun Peng | 43302f4 | 2016-08-04 13:48:02 +0000 | [diff] [blame] | 183 | size_t len = strlen(final_path); |
Damien Martin-Guillerez | c88508c | 2016-01-21 14:19:07 +0000 | [diff] [blame] | 184 | if (len > PATH_MAX) { |
Yun Peng | 43302f4 | 2016-08-04 13:48:02 +0000 | [diff] [blame] | 185 | fprintf(stderr, "Path too long: %s.\n", final_path); |
Damien Martin-Guillerez | c88508c | 2016-01-21 14:19:07 +0000 | [diff] [blame] | 186 | return -1; |
| 187 | } |
| 188 | if (flatten) { |
Laszlo Csomor | 8742568 | 2016-10-04 10:28:54 +0000 | [diff] [blame] | 189 | basename(final_path, path, PATH_MAX); |
Damien Martin-Guillerez | c88508c | 2016-01-21 14:19:07 +0000 | [diff] [blame] | 190 | } else { |
Laszlo Csomor | 8742568 | 2016-10-04 10:28:54 +0000 | [diff] [blame] | 191 | strncpy(path, final_path, PATH_MAX); |
| 192 | path[PATH_MAX - 1] = 0; |
| 193 | if (isdir && len < PATH_MAX - 1) { |
Damien Martin-Guillerez | c88508c | 2016-01-21 14:19:07 +0000 | [diff] [blame] | 194 | // Add the trailing slash for folders |
Laszlo Csomor | 8742568 | 2016-10-04 10:28:54 +0000 | [diff] [blame] | 195 | path[len] = '/'; |
| 196 | path[len + 1] = 0; |
Damien Martin-Guillerez | c88508c | 2016-01-21 14:19:07 +0000 | [diff] [blame] | 197 | } |
| 198 | } |
| 199 | |
| 200 | if (verbose) { |
Laszlo Csomor | 645dbc4 | 2016-12-01 12:56:43 +0000 | [diff] [blame] | 201 | mode_t perm = file_stat.file_mode & 0777; |
Laszlo Csomor | 8742568 | 2016-10-04 10:28:54 +0000 | [diff] [blame] | 202 | printf("%c %o %s\n", isdir ? 'd' : 'f', perm, path); |
Damien Martin-Guillerez | c88508c | 2016-01-21 14:19:07 +0000 | [diff] [blame] | 203 | } |
| 204 | |
Laszlo Csomor | 479e18d | 2016-12-02 15:11:08 +0000 | [diff] [blame] | 205 | u1 *buffer = builder->NewFile(path, stat_to_zipattr(file_stat)); |
Laszlo Csomor | 645dbc4 | 2016-12-01 12:56:43 +0000 | [diff] [blame] | 206 | if (isdir || file_stat.total_size == 0) { |
Damien Martin-Guillerez | c88508c | 2016-01-21 14:19:07 +0000 | [diff] [blame] | 207 | builder->FinishFile(0); |
| 208 | } else { |
Laszlo Csomor | d2ed069 | 2016-12-01 14:04:35 +0000 | [diff] [blame] | 209 | if (!read_file(file, buffer, file_stat.total_size)) { |
Damien Martin-Guillerez | c88508c | 2016-01-21 14:19:07 +0000 | [diff] [blame] | 210 | return -1; |
| 211 | } |
Laszlo Csomor | 645dbc4 | 2016-12-01 12:56:43 +0000 | [diff] [blame] | 212 | builder->FinishFile(file_stat.total_size, compress, true); |
Damien Martin-Guillerez | c88508c | 2016-01-21 14:19:07 +0000 | [diff] [blame] | 213 | } |
| 214 | return 0; |
| 215 | } |
| 216 | |
| 217 | // Read a list of files separated by newlines. The resulting array can be |
| 218 | // freed using the free method. |
| 219 | char **read_filelist(char *filename) { |
Laszlo Csomor | 645dbc4 | 2016-12-01 12:56:43 +0000 | [diff] [blame] | 220 | Stat file_stat; |
| 221 | if (!stat_file(filename, &file_stat)) { |
László Csomor | 9a4dffe | 2016-12-12 09:59:38 +0000 | [diff] [blame] | 222 | fprintf(stderr, "Cannot stat file %s: %s\n", filename, strerror(errno)); |
Laszlo Csomor | 645dbc4 | 2016-12-01 12:56:43 +0000 | [diff] [blame] | 223 | return NULL; |
| 224 | } |
| 225 | |
Laszlo Csomor | 645dbc4 | 2016-12-01 12:56:43 +0000 | [diff] [blame] | 226 | char *data = static_cast<char *>(malloc(file_stat.total_size)); |
Laszlo Csomor | d2ed069 | 2016-12-01 14:04:35 +0000 | [diff] [blame] | 227 | if (!read_file(filename, data, file_stat.total_size)) { |
Damien Martin-Guillerez | c88508c | 2016-01-21 14:19:07 +0000 | [diff] [blame] | 228 | return NULL; |
| 229 | } |
Damien Martin-Guillerez | c88508c | 2016-01-21 14:19:07 +0000 | [diff] [blame] | 230 | |
| 231 | int nb_entries = 1; |
Laszlo Csomor | 645dbc4 | 2016-12-01 12:56:43 +0000 | [diff] [blame] | 232 | for (int i = 0; i < file_stat.total_size; i++) { |
Damien Martin-Guillerez | c88508c | 2016-01-21 14:19:07 +0000 | [diff] [blame] | 233 | if (data[i] == '\n') { |
| 234 | nb_entries++; |
| 235 | } |
| 236 | } |
| 237 | |
| 238 | size_t sizeof_array = sizeof(char *) * (nb_entries + 1); |
Laszlo Csomor | 645dbc4 | 2016-12-01 12:56:43 +0000 | [diff] [blame] | 239 | void *result = malloc(sizeof_array + file_stat.total_size); |
Damien Martin-Guillerez | c88508c | 2016-01-21 14:19:07 +0000 | [diff] [blame] | 240 | // copy the content |
| 241 | char **filelist = static_cast<char **>(result); |
| 242 | char *content = static_cast<char *>(result) + sizeof_array; |
Laszlo Csomor | 645dbc4 | 2016-12-01 12:56:43 +0000 | [diff] [blame] | 243 | memcpy(content, data, file_stat.total_size); |
Damien Martin-Guillerez | c88508c | 2016-01-21 14:19:07 +0000 | [diff] [blame] | 244 | free(data); |
| 245 | // Create the corresponding array |
| 246 | int j = 1; |
| 247 | filelist[0] = content; |
Laszlo Csomor | 645dbc4 | 2016-12-01 12:56:43 +0000 | [diff] [blame] | 248 | for (int i = 0; i < file_stat.total_size; i++) { |
Damien Martin-Guillerez | c88508c | 2016-01-21 14:19:07 +0000 | [diff] [blame] | 249 | if (content[i] == '\n') { |
| 250 | content[i] = 0; |
Laszlo Csomor | 645dbc4 | 2016-12-01 12:56:43 +0000 | [diff] [blame] | 251 | if (i + 1 < file_stat.total_size) { |
Damien Martin-Guillerez | c88508c | 2016-01-21 14:19:07 +0000 | [diff] [blame] | 252 | filelist[j] = content + i + 1; |
| 253 | j++; |
| 254 | } |
| 255 | } |
| 256 | } |
| 257 | filelist[j] = NULL; |
| 258 | return filelist; |
| 259 | } |
| 260 | |
Yun Peng | 43302f4 | 2016-08-04 13:48:02 +0000 | [diff] [blame] | 261 | // return real paths of the files |
| 262 | char **parse_filelist(char *zipfile, char **file_entries, int nb_entries, |
| 263 | bool flatten) { |
| 264 | // no need to free since the path lists should live until the end of the |
| 265 | // program |
| 266 | char **files = static_cast<char **>(malloc(sizeof(char *) * nb_entries)); |
| 267 | char **zip_paths = file_entries; |
| 268 | for (int i = 0; i < nb_entries; i++) { |
| 269 | char *p_eq = strchr(file_entries[i], '='); |
| 270 | if (p_eq != NULL) { |
| 271 | if (flatten) { |
| 272 | fprintf(stderr, "Unable to create zip file %s: %s.\n", zipfile, |
| 273 | "= can't be used with flatten"); |
| 274 | free(files); |
| 275 | return NULL; |
| 276 | } |
| 277 | if (p_eq == file_entries[i]) { |
| 278 | fprintf(stderr, "Unable to create zip file %s: %s.\n", zipfile, |
| 279 | "A zip path should be given before ="); |
| 280 | free(files); |
| 281 | return NULL; |
| 282 | } |
| 283 | *p_eq = '\0'; |
| 284 | files[i] = p_eq + 1; |
| 285 | if (files[i][0] == '\0') { |
| 286 | files[i] = NULL; |
| 287 | } |
| 288 | } else { |
| 289 | files[i] = file_entries[i]; |
| 290 | zip_paths[i] = NULL; |
| 291 | } |
| 292 | } |
| 293 | return files; |
| 294 | } |
| 295 | |
Damien Martin-Guillerez | 0844112 | 2015-05-28 11:12:31 +0000 | [diff] [blame] | 296 | // Execute the create operation |
Yun Peng | 43302f4 | 2016-08-04 13:48:02 +0000 | [diff] [blame] | 297 | int create(char *zipfile, char **file_entries, bool flatten, bool verbose, |
Damien Martin-Guillerez | 3a160e7 | 2015-08-31 12:22:14 +0000 | [diff] [blame] | 298 | bool compress) { |
Yun Peng | 43302f4 | 2016-08-04 13:48:02 +0000 | [diff] [blame] | 299 | int nb_entries = 0; |
| 300 | while (file_entries[nb_entries] != NULL) { |
| 301 | nb_entries++; |
| 302 | } |
| 303 | char **zip_paths = file_entries; |
| 304 | char **files = parse_filelist(zipfile, file_entries, nb_entries, flatten); |
| 305 | if (files == NULL) { |
| 306 | return -1; |
| 307 | } |
| 308 | |
| 309 | u8 size = ZipBuilder::EstimateSize(files, zip_paths, nb_entries); |
Damien Martin-Guillerez | 0844112 | 2015-05-28 11:12:31 +0000 | [diff] [blame] | 310 | if (size == 0) { |
| 311 | return -1; |
| 312 | } |
| 313 | std::unique_ptr<ZipBuilder> builder(ZipBuilder::Create(zipfile, size)); |
| 314 | if (builder.get() == NULL) { |
| 315 | fprintf(stderr, "Unable to create zip file %s: %s.\n", |
| 316 | zipfile, strerror(errno)); |
| 317 | return -1; |
| 318 | } |
Yun Peng | 43302f4 | 2016-08-04 13:48:02 +0000 | [diff] [blame] | 319 | |
| 320 | for (int i = 0; i < nb_entries; i++) { |
| 321 | if (add_file(builder, files[i], zip_paths[i], flatten, verbose, compress) < |
| 322 | 0) { |
Damien Martin-Guillerez | c88508c | 2016-01-21 14:19:07 +0000 | [diff] [blame] | 323 | return -1; |
Damien Martin-Guillerez | 0844112 | 2015-05-28 11:12:31 +0000 | [diff] [blame] | 324 | } |
| 325 | } |
| 326 | if (builder->Finish() < 0) { |
| 327 | fprintf(stderr, "%s\n", builder->GetError()); |
| 328 | return -1; |
| 329 | } |
| 330 | return 0; |
| 331 | } |
| 332 | |
| 333 | } // namespace devtools_ijar |
| 334 | |
| 335 | // |
| 336 | // main method |
| 337 | // |
| 338 | static void usage(char *progname) { |
Yun Peng | 43302f4 | 2016-08-04 13:48:02 +0000 | [diff] [blame] | 339 | fprintf(stderr, |
Yun Peng | 3070266 | 2016-08-05 11:16:05 +0000 | [diff] [blame] | 340 | "Usage: %s [vxc[fC]] x.zip [-d exdir] [[zip_path1=]file1 ... " |
| 341 | "[zip_pathn=]filen]\n", |
Rumou Duan | 7942bdc | 2016-05-12 15:31:07 +0000 | [diff] [blame] | 342 | progname); |
Damien Martin-Guillerez | 0844112 | 2015-05-28 11:12:31 +0000 | [diff] [blame] | 343 | fprintf(stderr, " v verbose - list all file in x.zip\n"); |
Rumou Duan | 7942bdc | 2016-05-12 15:31:07 +0000 | [diff] [blame] | 344 | fprintf(stderr, |
| 345 | " x extract - extract files in x.zip to current directory, or " |
| 346 | " an optional directory relative to the current directory " |
| 347 | " specified through -d option\n"); |
Damien Martin-Guillerez | 0844112 | 2015-05-28 11:12:31 +0000 | [diff] [blame] | 348 | fprintf(stderr, " c create - add files to x.zip\n"); |
| 349 | fprintf(stderr, " f flatten - flatten files to use with create operation\n"); |
Damien Martin-Guillerez | 3a160e7 | 2015-08-31 12:22:14 +0000 | [diff] [blame] | 350 | fprintf(stderr, |
| 351 | " C compress - compress files when using the create operation\n"); |
Damien Martin-Guillerez | 0844112 | 2015-05-28 11:12:31 +0000 | [diff] [blame] | 352 | fprintf(stderr, "x and c cannot be used in the same command-line.\n"); |
Yun Peng | 3070266 | 2016-08-05 11:16:05 +0000 | [diff] [blame] | 353 | fprintf(stderr, |
| 354 | "\nFor every file, a path in the zip can be specified. Examples:\n"); |
Yun Peng | 43302f4 | 2016-08-04 13:48:02 +0000 | [diff] [blame] | 355 | fprintf(stderr, |
| 356 | " zipper c x.zip a/b/__init__.py= # Add an empty file at " |
| 357 | "a/b/__init__.py\n"); |
| 358 | fprintf(stderr, |
| 359 | " zipper c x.zip a/b/main.py=foo/bar/bin.py # Add file " |
| 360 | "foo/bar/bin.py at a/b/main.py\n"); |
Yun Peng | 3070266 | 2016-08-05 11:16:05 +0000 | [diff] [blame] | 361 | fprintf(stderr, |
| 362 | "\nIf the zip path is not specified, it is assumed to be the file " |
| 363 | "path.\n"); |
Damien Martin-Guillerez | 0844112 | 2015-05-28 11:12:31 +0000 | [diff] [blame] | 364 | exit(1); |
| 365 | } |
| 366 | |
| 367 | int main(int argc, char **argv) { |
| 368 | bool extract = false; |
| 369 | bool verbose = false; |
| 370 | bool create = false; |
Damien Martin-Guillerez | 3a160e7 | 2015-08-31 12:22:14 +0000 | [diff] [blame] | 371 | bool compress = false; |
Damien Martin-Guillerez | 0844112 | 2015-05-28 11:12:31 +0000 | [diff] [blame] | 372 | bool flatten = false; |
| 373 | |
| 374 | if (argc < 3) { |
| 375 | usage(argv[0]); |
| 376 | } |
| 377 | |
| 378 | for (int i = 0; argv[1][i] != 0; i++) { |
| 379 | switch (argv[1][i]) { |
| 380 | case 'x': |
| 381 | extract = true; |
| 382 | break; |
| 383 | case 'v': |
| 384 | verbose = true; |
| 385 | break; |
| 386 | case 'c': |
| 387 | create = true; |
| 388 | break; |
| 389 | case 'f': |
| 390 | flatten = true; |
| 391 | break; |
Damien Martin-Guillerez | 3a160e7 | 2015-08-31 12:22:14 +0000 | [diff] [blame] | 392 | case 'C': |
| 393 | compress = true; |
| 394 | break; |
Damien Martin-Guillerez | 0844112 | 2015-05-28 11:12:31 +0000 | [diff] [blame] | 395 | default: |
| 396 | usage(argv[0]); |
| 397 | } |
| 398 | } |
Rumou Duan | 7942bdc | 2016-05-12 15:31:07 +0000 | [diff] [blame] | 399 | |
| 400 | // x and c cannot be used in the same command-line. |
| 401 | if (create && extract) { |
| 402 | usage(argv[0]); |
| 403 | } |
| 404 | |
| 405 | // Calculate the argument index of the first entry file. |
| 406 | int filelist_start_index; |
| 407 | if (argc > 3 && strcmp(argv[3], "-d") == 0) { |
| 408 | filelist_start_index = 5; |
| 409 | } else { |
| 410 | filelist_start_index = 3; |
| 411 | } |
| 412 | |
| 413 | char** filelist = NULL; |
| 414 | |
| 415 | // We have one option file. Read and extract the content. |
| 416 | if (argc == filelist_start_index + 1 && |
| 417 | argv[filelist_start_index][0] == '@') { |
| 418 | char* filelist_name = argv[filelist_start_index]; |
| 419 | filelist = devtools_ijar::read_filelist(filelist_name + 1); |
| 420 | if (filelist == NULL) { |
| 421 | fprintf(stderr, "Can't read file list %s: %s.\n", filelist_name, |
| 422 | strerror(errno)); |
| 423 | return -1; |
| 424 | } |
| 425 | // We have more than one files. Assume that they are all file entries. |
| 426 | } else if (argc >= filelist_start_index + 1) { |
| 427 | filelist = argv + filelist_start_index; |
| 428 | } else { |
| 429 | // There are no entry files specified. This is forbidden if we are creating |
| 430 | // a zip file. |
| 431 | if (create) { |
| 432 | fprintf(stderr, "Can't create zip without input files specified."); |
| 433 | return -1; |
| 434 | } |
| 435 | } |
| 436 | |
Damien Martin-Guillerez | 0844112 | 2015-05-28 11:12:31 +0000 | [diff] [blame] | 437 | if (create) { |
Damien Martin-Guillerez | 0844112 | 2015-05-28 11:12:31 +0000 | [diff] [blame] | 438 | // Create a zip |
Damien Martin-Guillerez | c88508c | 2016-01-21 14:19:07 +0000 | [diff] [blame] | 439 | return devtools_ijar::create(argv[2], filelist, flatten, verbose, compress); |
Damien Martin-Guillerez | 0844112 | 2015-05-28 11:12:31 +0000 | [diff] [blame] | 440 | } else { |
| 441 | if (flatten) { |
| 442 | usage(argv[0]); |
| 443 | } |
Rumou Duan | 7942bdc | 2016-05-12 15:31:07 +0000 | [diff] [blame] | 444 | |
| 445 | char* exdir = NULL; |
| 446 | if (argc > 3 && strcmp(argv[3], "-d") == 0) { |
| 447 | exdir = argv[4]; |
| 448 | } |
| 449 | |
Damien Martin-Guillerez | 0844112 | 2015-05-28 11:12:31 +0000 | [diff] [blame] | 450 | // Extraction / list mode |
Rumou Duan | 7942bdc | 2016-05-12 15:31:07 +0000 | [diff] [blame] | 451 | return devtools_ijar::extract(argv[2], exdir, filelist, verbose, extract); |
Damien Martin-Guillerez | 0844112 | 2015-05-28 11:12:31 +0000 | [diff] [blame] | 452 | } |
| 453 | } |