Add a Notification Settings Button to all web notifications behind the web platform...
[chromium-blink-merge.git] / third_party / ijar / zip_main.cc
blob6c2a97439734cd70020f5da3c0e67c5eb315c6de
1 // Copyright 2015 Google Inc. All rights reserved.
2 //
3 // Author: Alan Donovan <adonovan@google.com>
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 // http://www.apache.org/licenses/LICENSE-2.0
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
18 // Zip / Unzip file using ijar zip implementation.
20 // Note that this Zip implementation intentionally don't compute CRC-32
21 // 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.
25 #include <stdio.h>
26 #include <string.h>
27 #include <stdlib.h>
28 #include <limits.h>
29 #include <fcntl.h>
30 #include <unistd.h>
31 #include <sys/mman.h>
32 #include <errno.h>
33 #include <memory>
35 #include "third_party/ijar/zip.h"
37 namespace devtools_ijar {
39 #define SYSCALL(expr) do { \
40 if ((expr) < 0) { \
41 perror(#expr); \
42 abort(); \
43 } \
44 } while (0)
47 // A ZipExtractorProcessor that extract all files in the ZIP file.
49 class UnzipProcessor : public ZipExtractorProcessor {
50 public:
51 // Create a processor who will extract the files into output_root
52 // if "extract" is set to true and will print the list of files and
53 // their unix modes if "verbose" is set to true.
54 UnzipProcessor(const char *output_root, bool verbose, bool extract)
55 : output_root_(output_root), verbose_(verbose), extract_(extract) {}
56 virtual ~UnzipProcessor() {}
58 virtual void Process(const char* filename, const u4 attr,
59 const u1* data, const size_t size);
60 virtual bool Accept(const char* filename, const u4 attr) {
61 return true;
64 private:
65 const char *output_root_;
66 const bool verbose_;
67 const bool extract_;
70 // 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
72 void concat_path(char* out, const size_t size,
73 const char *path1, const char *path2) {
74 int len1 = strlen(path1);
75 int l = len1;
76 strncpy(out, path1, size-1);
77 out[size-1] = 0;
78 if (l < size - 1 && path1[len1] != '/' && path2[0] != '/') {
79 out[l] = '/';
80 l++;
81 out[l] = 0;
83 if (l < size - 1) {
84 strncat(out, path2, size - 1 - l);
88 // Do a recursive mkdir of all folders of path except the last path
89 // segment (if path ends with a / then the last path segment is empty).
90 // All folders are created using "mode" for creation mode.
91 void mkdirs(const char *path, mode_t mode) {
92 char path_[PATH_MAX];
93 struct stat statst;
94 strncpy(path_, path, PATH_MAX);
95 path_[PATH_MAX-1] = 0;
96 char *pointer = path_;
97 while ((pointer = strchr(pointer, '/')) != NULL) {
98 if (path_ != pointer) { // skip leading slash
99 *pointer = 0;
100 if (stat(path_, &statst) != 0) {
101 if (mkdir(path_, mode) < 0) {
102 fprintf(stderr, "Cannot create folder %s: %s\n",
103 path_, strerror(errno));
104 abort();
107 *pointer = '/';
109 pointer++;
113 void UnzipProcessor::Process(const char* filename, const u4 attr,
114 const u1* data, const size_t size) {
115 mode_t mode = zipattr_to_mode(attr);
116 mode_t perm = mode & 0777;
117 bool isdir = (mode & S_IFDIR) != 0;
118 if (attr == 0) {
119 // Fallback when the external attribute is not set.
120 isdir = filename[strlen(filename)-1] == '/';
121 perm = 0777;
123 if (verbose_) {
124 printf("%c %o %s\n", isdir ? 'd' : 'f', perm, filename);
126 if (extract_) {
127 char path[PATH_MAX];
128 int fd;
129 concat_path(path, PATH_MAX, output_root_, filename);
130 mkdirs(path, perm);
131 if (!isdir) {
132 fd = open(path, O_CREAT | O_WRONLY, perm);
133 if (fd < 0) {
134 fprintf(stderr, "Cannot open file %s for writing: %s\n",
135 path, strerror(errno));
136 abort();
138 SYSCALL(write(fd, data, size));
139 SYSCALL(close(fd));
144 // Get the basename of path and store it in output. output_size
145 // is the size of the output buffer.
146 void basename(const char *path, char *output, size_t output_size) {
147 const char *pointer = strrchr(path, '/');
148 if (pointer == NULL) {
149 pointer = path;
150 } else {
151 pointer++; // Skip the leading slash.
153 strncpy(output, pointer, output_size);
154 output[output_size-1] = 0;
158 // Execute the extraction (or just listing if just v is provided)
159 int extract(char *zipfile, bool verbose, bool extract) {
160 char output_root[PATH_MAX];
161 getcwd(output_root, PATH_MAX);
163 UnzipProcessor processor(output_root, verbose, extract);
164 std::unique_ptr<ZipExtractor> extractor(ZipExtractor::Create(zipfile,
165 &processor));
166 if (extractor.get() == NULL) {
167 fprintf(stderr, "Unable to open zip file %s: %s.\n", zipfile,
168 strerror(errno));
169 return -1;
172 if (extractor->ProcessAll() < 0) {
173 fprintf(stderr, "%s.\n", extractor->GetError());
174 return -1;
176 return 0;
179 // Execute the create operation
180 int create(char *zipfile, char **files, bool flatten, bool verbose,
181 bool compress) {
182 struct stat statst;
183 u8 size = ZipBuilder::EstimateSize(files);
184 if (size == 0) {
185 return -1;
187 std::unique_ptr<ZipBuilder> builder(ZipBuilder::Create(zipfile, size));
188 if (builder.get() == NULL) {
189 fprintf(stderr, "Unable to create zip file %s: %s.\n",
190 zipfile, strerror(errno));
191 return -1;
193 for (int i = 0; files[i] != NULL; i++) {
194 stat(files[i], &statst);
195 char path[PATH_MAX];
196 bool isdir = (statst.st_mode & S_IFDIR) != 0;
198 if (flatten && isdir) {
199 continue;
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;
216 if (verbose) {
217 mode_t perm = statst.st_mode & 0777;
218 printf("%c %o %s\n", isdir ? 'd' : 'f', perm, path);
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;
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;
238 memcpy(buffer, data, statst.st_size);
239 munmap(data, statst.st_size);
240 builder->FinishFile(statst.st_size, compress);
243 if (builder->Finish() < 0) {
244 fprintf(stderr, "%s\n", builder->GetError());
245 return -1;
247 return 0;
250 } // namespace devtools_ijar
253 // main method
255 static void usage(char *progname) {
256 fprintf(stderr, "Usage: %s [vxc[fC]] x.zip [file1...filen]\n", progname);
257 fprintf(stderr, " v verbose - list all file in x.zip\n");
258 fprintf(stderr, " x extract - extract file in x.zip in current directory\n");
259 fprintf(stderr, " c create - add files to x.zip\n");
260 fprintf(stderr, " f flatten - flatten files to use with create operation\n");
261 fprintf(stderr,
262 " C compress - compress files when using the create operation\n");
263 fprintf(stderr, "x and c cannot be used in the same command-line.\n");
264 exit(1);
267 int main(int argc, char **argv) {
268 bool extract = false;
269 bool verbose = false;
270 bool create = false;
271 bool compress = false;
272 bool flatten = false;
274 if (argc < 3) {
275 usage(argv[0]);
278 for (int i = 0; argv[1][i] != 0; i++) {
279 switch (argv[1][i]) {
280 case 'x':
281 extract = true;
282 break;
283 case 'v':
284 verbose = true;
285 break;
286 case 'c':
287 create = true;
288 break;
289 case 'f':
290 flatten = true;
291 break;
292 case 'C':
293 compress = true;
294 break;
295 default:
296 usage(argv[0]);
299 if (create) {
300 if (extract) {
301 usage(argv[0]);
303 // Create a zip
304 return devtools_ijar::create(argv[2], argv + 3, flatten, verbose, compress);
305 } else {
306 if (flatten) {
307 usage(argv[0]);
309 // Extraction / list mode
310 return devtools_ijar::extract(argv[2], verbose, extract);