1 // Copyright 2015 Google Inc. All rights reserved.
3 // Author: Alan Donovan <adonovan@google.com>
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
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.
35 #include "third_party/ijar/zip.h"
37 namespace devtools_ijar
{
39 #define SYSCALL(expr) do { \
47 // A ZipExtractorProcessor that extract all files in the ZIP file.
49 class UnzipProcessor
: public ZipExtractorProcessor
{
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
) {
65 const char *output_root_
;
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
);
76 strncpy(out
, path1
, size
-1);
78 if (l
< size
- 1 && path1
[len1
] != '/' && path2
[0] != '/') {
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
) {
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
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
));
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;
119 // Fallback when the external attribute is not set.
120 isdir
= filename
[strlen(filename
)-1] == '/';
124 printf("%c %o %s\n", isdir
? 'd' : 'f', perm
, filename
);
129 concat_path(path
, PATH_MAX
, output_root_
, filename
);
132 fd
= open(path
, O_CREAT
| O_WRONLY
, perm
);
134 fprintf(stderr
, "Cannot open file %s for writing: %s\n",
135 path
, strerror(errno
));
138 SYSCALL(write(fd
, data
, size
));
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
) {
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
,
166 if (extractor
.get() == NULL
) {
167 fprintf(stderr
, "Unable to open zip file %s: %s.\n", zipfile
,
172 if (extractor
->ProcessAll() < 0) {
173 fprintf(stderr
, "%s.\n", extractor
->GetError());
179 // Execute the create operation
180 int create(char *zipfile
, char **files
, bool flatten
, bool verbose
,
183 u8 size
= ZipBuilder::EstimateSize(files
);
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
));
193 for (int i
= 0; files
[i
] != NULL
; i
++) {
194 stat(files
[i
], &statst
);
196 bool isdir
= (statst
.st_mode
& S_IFDIR
) != 0;
198 if (flatten
&& isdir
) {
202 // Compute the path, flattening it if requested
204 basename(files
[i
], path
, PATH_MAX
);
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
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);
225 // mmap the input file and memcpy
226 int fd
= open(files
[i
], O_RDONLY
);
228 fprintf(stderr
, "Can't open file %s for reading: %s.\n",
229 files
[i
], strerror(errno
));
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
));
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());
250 } // namespace devtools_ijar
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");
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");
267 int main(int argc
, char **argv
) {
268 bool extract
= false;
269 bool verbose
= false;
271 bool compress
= false;
272 bool flatten
= false;
278 for (int i
= 0; argv
[1][i
] != 0; i
++) {
279 switch (argv
[1][i
]) {
304 return devtools_ijar::create(argv
[2], argv
+ 3, flatten
, verbose
, compress
);
309 // Extraction / list mode
310 return devtools_ijar::extract(argv
[2], verbose
, extract
);