blob: 2994cb2361ad9adff1644a9f95128363fe65fbfe [file] [log] [blame]
Thomas Klausner89bb5fe2012-02-20 01:43:56 +01001/*
Thomas Klausner28c97922016-01-12 13:48:48 +01002 ziptool.c -- tool for modifying zip archive in multiple ways
Thomas Klausner00ff6bb2016-01-08 08:21:22 +01003 Copyright (C) 2012-2016 Dieter Baron and Thomas Klausner
Thomas Klausner89bb5fe2012-02-20 01:43:56 +01004
5 This file is part of libzip, a library to manipulate ZIP archives.
6 The authors can be contacted at <libzip@nih.at>
7
8 Redistribution and use in source and binary forms, with or without
9 modification, are permitted provided that the following conditions
10 are met:
11 1. Redistributions of source code must retain the above copyright
12 notice, this list of conditions and the following disclaimer.
13 2. Redistributions in binary form must reproduce the above copyright
14 notice, this list of conditions and the following disclaimer in
15 the documentation and/or other materials provided with the
16 distribution.
17 3. The names of the authors may not be used to endorse or promote
18 products derived from this software without specific prior
19 written permission.
Thomas Klausner28c97922016-01-12 13:48:48 +010020
Thomas Klausner89bb5fe2012-02-20 01:43:56 +010021 THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
22 OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
25 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
27 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
29 IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30 OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
31 IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32*/
33
Dieter Baronb5a0e3f2012-08-31 18:18:36 +020034#include "config.h"
Thomas Klausner89bb5fe2012-02-20 01:43:56 +010035
36#include <errno.h>
37#include <stdlib.h>
38#include <string.h>
Thomas Klausnerea8ba492014-09-23 16:54:47 +020039#include <sys/stat.h>
Dieter Baronb5a0e3f2012-08-31 18:18:36 +020040#ifdef HAVE_UNISTD_H
41#include <unistd.h>
42#endif
Thomas Klausnerbe146cb2015-09-15 14:12:08 +020043#ifdef _WIN32
44/* WIN32 needs <fcntl.h> for _O_BINARY */
45#include <fcntl.h>
46#endif
Thomas Klausner89bb5fe2012-02-20 01:43:56 +010047
Dieter Baronabc6fd72012-07-22 15:49:45 +020048#ifndef HAVE_GETOPT
49#include "getopt.h"
50#endif
Thomas Klausner4c8c5632016-01-28 14:21:35 +010051extern int optopt;
Dieter Baronabc6fd72012-07-22 15:49:45 +020052
Thomas Klausner89bb5fe2012-02-20 01:43:56 +010053#include "zip.h"
Thomas Klausner2bb30c72016-01-06 15:45:24 +010054#include "compat.h"
Thomas Klausner89bb5fe2012-02-20 01:43:56 +010055
Dieter Baron91374c72014-10-09 22:14:55 +020056zip_source_t *source_hole_create(const char *, int flags, zip_error_t *);
57
58typedef enum {
59 SOURCE_TYPE_NONE,
60 SOURCE_TYPE_IN_MEMORY,
61 SOURCE_TYPE_HOLE
62} source_type_t;
63
Thomas Klausnerea8ba492014-09-23 16:54:47 +020064typedef struct dispatch_table_s {
65 const char *cmdline_name;
66 int argument_count;
67 const char *arg_names;
68 const char *description;
69 int (*function)(int argc, char *argv[]);
70} dispatch_table_t;
Thomas Klausner89bb5fe2012-02-20 01:43:56 +010071
Thomas Klausnerea8ba492014-09-23 16:54:47 +020072static zip_flags_t get_flags(const char *arg);
73static zip_int32_t get_compression_method(const char *arg);
Thomas Klausner7ed6a922016-12-16 15:50:12 +010074static zip_uint16_t get_encryption_method(const char *arg);
Thomas Klausnerea8ba492014-09-23 16:54:47 +020075static void hexdump(const zip_uint8_t *data, zip_uint16_t len);
Dieter Barona5b4cb72016-08-25 17:11:07 +020076static zip_t *read_to_memory(const char *archive, int flags, zip_error_t *error, zip_source_t **srcp);
Dieter Baron273a1c92014-10-01 14:20:21 +020077static zip_source_t *source_nul(zip_t *za, zip_uint64_t length);
Thomas Klausnerea8ba492014-09-23 16:54:47 +020078
Thomas Klausner24030de2015-04-29 15:18:35 +020079zip_t *za, *z_in[16];
Thomas Klausnerb1e93a02015-07-08 16:27:38 +020080unsigned int z_in_count;
Thomas Klausnerea8ba492014-09-23 16:54:47 +020081zip_flags_t stat_flags;
82
83static int
84add(int argc, char *argv[]) {
Dieter Baron1d9dfeb2014-09-28 23:02:54 +020085 zip_source_t *zs;
Thomas Klausnerea8ba492014-09-23 16:54:47 +020086
87 if ((zs=zip_source_buffer(za, argv[1], strlen(argv[1]), 0)) == NULL) {
88 fprintf(stderr, "can't create zip_source from buffer: %s\n", zip_strerror(za));
89 return -1;
90 }
91
92 if (zip_add(za, argv[0], zs) == -1) {
93 zip_source_free(zs);
94 fprintf(stderr, "can't add file '%s': %s\n", argv[0], zip_strerror(za));
95 return -1;
96 }
97 return 0;
98}
99
100static int
101add_dir(int argc, char *argv[]) {
102 /* add directory */
103 if (zip_add_dir(za, argv[0]) < 0) {
104 fprintf(stderr, "can't add directory '%s': %s\n", argv[0], zip_strerror(za));
105 return -1;
106 }
107 return 0;
108}
109
110static int
111add_file(int argc, char *argv[]) {
Dieter Baron1d9dfeb2014-09-28 23:02:54 +0200112 zip_source_t *zs;
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200113 zip_uint64_t start = strtoull(argv[2], NULL, 10);
114 zip_int64_t len = strtoll(argv[3], NULL, 10);
115
116 if (strcmp(argv[1], "/dev/stdin") == 0) {
117 if ((zs=zip_source_filep(za, stdin, start, len)) == NULL) {
118 fprintf(stderr, "can't create zip_source from stdin: %s\n", zip_strerror(za));
119 return -1;
120 }
121 } else {
122 if ((zs=zip_source_file(za, argv[1], start, len)) == NULL) {
123 fprintf(stderr, "can't create zip_source from file: %s\n", zip_strerror(za));
124 return -1;
125 }
126 }
127
128 if (zip_add(za, argv[0], zs) == -1) {
129 zip_source_free(zs);
130 fprintf(stderr, "can't add file '%s': %s\n", argv[0], zip_strerror(za));
131 return -1;
132 }
133 return 0;
134}
135
136static int
137add_from_zip(int argc, char *argv[]) {
Thomas Klausnerb51f6132016-01-05 14:07:07 +0100138 zip_uint64_t idx, start;
139 zip_int64_t len;
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200140 int err;
Dieter Baron1d9dfeb2014-09-28 23:02:54 +0200141 zip_source_t *zs;
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200142 /* add from another zip file */
143 idx = strtoull(argv[2], NULL, 10);
Thomas Klausnerb51f6132016-01-05 14:07:07 +0100144 start = strtoull(argv[3], NULL, 10);
145 len = strtoll(argv[4], NULL, 10);
Thomas Klausner24030de2015-04-29 15:18:35 +0200146 if ((z_in[z_in_count]=zip_open(argv[1], ZIP_CHECKCONS, &err)) == NULL) {
Thomas Klausnerda1c2452014-12-02 16:01:26 +0100147 zip_error_t error;
148 zip_error_init_with_code(&error, err);
149 fprintf(stderr, "can't open zip archive '%s': %s\n", argv[1], zip_error_strerror(&error));
150 zip_error_fini(&error);
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200151 return -1;
152 }
Thomas Klausner24030de2015-04-29 15:18:35 +0200153 if ((zs=zip_source_zip(za, z_in[z_in_count], idx, 0, start, len)) == NULL) {
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200154 fprintf(stderr, "error creating file source from '%s' index '%" PRIu64 "': %s\n", argv[1], idx, zip_strerror(za));
Thomas Klausner24030de2015-04-29 15:18:35 +0200155 zip_close(z_in[z_in_count]);
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200156 return -1;
157 }
158 if (zip_add(za, argv[0], zs) == -1) {
159 fprintf(stderr, "can't add file '%s': %s\n", argv[0], zip_strerror(za));
160 zip_source_free(zs);
Thomas Klausner24030de2015-04-29 15:18:35 +0200161 zip_close(z_in[z_in_count]);
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200162 return -1;
163 }
Thomas Klausner24030de2015-04-29 15:18:35 +0200164 z_in_count++;
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200165 return 0;
166}
167
Dieter Baron98bf11d2014-10-10 09:39:32 +0200168static int
Dieter Baron273a1c92014-10-01 14:20:21 +0200169add_nul(int argc, char *argv[]) {
170 zip_source_t *zs;
171 zip_uint64_t length = strtoull(argv[1], NULL, 10);
Thomas Klausner28c97922016-01-12 13:48:48 +0100172
Dieter Baron273a1c92014-10-01 14:20:21 +0200173 if ((zs=source_nul(za, length)) == NULL) {
174 fprintf(stderr, "can't create zip_source for length: %s\n", zip_strerror(za));
175 return -1;
176 }
Thomas Klausner28c97922016-01-12 13:48:48 +0100177
Dieter Baron273a1c92014-10-01 14:20:21 +0200178 if (zip_add(za, argv[0], zs) == -1) {
179 zip_source_free(zs);
180 fprintf(stderr, "can't add file '%s': %s\n", argv[0], zip_strerror(za));
181 return -1;
182 }
183 return 0;
184}
185
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200186static int
Thomas Klausner4a41da22014-12-02 11:23:23 +0100187cat(int argc, char *argv[]) {
188 /* output file contents to stdout */
189 zip_uint64_t idx;
190 zip_int64_t n;
191 zip_file_t *zf;
192 char buf[8192];
Thomas Klausnerda1c2452014-12-02 16:01:26 +0100193 int err;
Thomas Klausner4a41da22014-12-02 11:23:23 +0100194 idx = strtoull(argv[0], NULL, 10);
195
Thomas Klausnerbe146cb2015-09-15 14:12:08 +0200196#ifdef _WIN32
197 /* Need to set stdout to binary mode for Windows */
198 setmode(fileno(stdout), _O_BINARY);
199#endif
Thomas Klausner4a41da22014-12-02 11:23:23 +0100200 if ((zf=zip_fopen_index(za, idx, 0)) == NULL) {
201 fprintf(stderr, "can't open file at index '%" PRIu64 "': %s\n", idx, zip_strerror(za));
202 return -1;
203 }
204 while ((n=zip_fread(zf, buf, sizeof(buf))) > 0) {
205 if (fwrite(buf, (size_t)n, 1, stdout) != 1) {
206 zip_fclose(zf);
207 fprintf(stderr, "can't write file contents to stdout: %s\n", strerror(errno));
208 return -1;
209 }
210 }
211 if (n == -1) {
Thomas Klausner4a41da22014-12-02 11:23:23 +0100212 fprintf(stderr, "can't read file at index '%" PRIu64 "': %s\n", idx, zip_file_strerror(zf));
Thomas Klausner7c745ea2016-10-18 13:31:07 +0200213 zip_fclose(zf);
Thomas Klausner4a41da22014-12-02 11:23:23 +0100214 return -1;
215 }
Thomas Klausnerda1c2452014-12-02 16:01:26 +0100216 if ((err = zip_fclose(zf)) != 0) {
217 zip_error_t error;
Thomas Klausner28c97922016-01-12 13:48:48 +0100218
Thomas Klausnerda1c2452014-12-02 16:01:26 +0100219 zip_error_init_with_code(&error, err);
220 fprintf(stderr, "can't close file at index '%" PRIu64 "': %s\n", idx, zip_error_strerror(&error));
Thomas Klausner4a41da22014-12-02 11:23:23 +0100221 return -1;
222 }
223
224 return 0;
225}
226
227static int
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200228count_extra(int argc, char *argv[]) {
229 zip_int16_t count;
230 zip_uint64_t idx;
231 zip_flags_t ceflags = 0;
232 idx = strtoull(argv[0], NULL, 10);
233 ceflags = get_flags(argv[1]);
234 if ((count=zip_file_extra_fields_count(za, idx, ceflags)) < 0) {
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200235 fprintf(stderr, "can't get extra field count for file at index '%" PRIu64 "': %s\n", idx, zip_strerror(za));
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200236 return -1;
237 } else {
238 printf("Extra field count: %d\n", count);
239 }
240 return 0;
241}
242
243static int
244count_extra_by_id(int argc, char *argv[]) {
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200245 zip_int16_t count;
246 zip_uint16_t eid;
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200247 zip_flags_t ceflags = 0;
248 zip_uint64_t idx;
249 idx = strtoull(argv[0], NULL, 10);
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200250 eid = (zip_uint16_t)strtoull(argv[1], NULL, 10);
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200251 ceflags = get_flags(argv[2]);
252 if ((count=zip_file_extra_fields_count_by_id(za, idx, eid, ceflags)) < 0) {
Thomas Klausner872f8932017-01-14 22:15:33 +0100253 fprintf(stderr, "can't get extra field count for file at index '%" PRIu64 "' and for id '%d': %s\n", idx, eid, zip_strerror(za));
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200254 return -1;
255 } else {
256 printf("Extra field count: %d\n", count);
257 }
258 return 0;
259}
260
261static int
262delete(int argc, char *argv[]) {
263 zip_uint64_t idx;
264 idx = strtoull(argv[0], NULL, 10);
265 if (zip_delete(za, idx) < 0) {
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200266 fprintf(stderr, "can't delete file at index '%" PRIu64 "': %s\n", idx, zip_strerror(za));
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200267 return -1;
268 }
269 return 0;
270}
271
272static int
273delete_extra(int argc, char *argv[]) {
274 zip_flags_t geflags;
275 zip_uint16_t eid;
276 zip_uint64_t idx;
277 idx = strtoull(argv[0], NULL, 10);
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200278 eid = (zip_uint16_t)strtoull(argv[1], NULL, 10);
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200279 geflags = get_flags(argv[2]);
280 if ((zip_file_extra_field_delete(za, idx, eid, geflags)) < 0) {
Thomas Klausner872f8932017-01-14 22:15:33 +0100281 fprintf(stderr, "can't delete extra field data for file at index '%" PRIu64 "', extra field id '%d': %s\n", idx, eid, zip_strerror(za));
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200282 return -1;
283 }
284 return 0;
285}
286
287static int
288delete_extra_by_id(int argc, char *argv[]) {
289 zip_flags_t geflags;
290 zip_uint16_t eid, eidx;
291 zip_uint64_t idx;
292 idx = strtoull(argv[0], NULL, 10);
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200293 eid = (zip_uint16_t)strtoull(argv[1], NULL, 10);
294 eidx = (zip_uint16_t)strtoull(argv[2], NULL, 10);
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200295 geflags = get_flags(argv[3]);
296 if ((zip_file_extra_field_delete_by_id(za, idx, eid, eidx, geflags)) < 0) {
Thomas Klausner872f8932017-01-14 22:15:33 +0100297 fprintf(stderr, "can't delete extra field data for file at index '%" PRIu64 "', extra field id '%d', extra field idx '%d': %s\n", idx, eid, eidx, zip_strerror(za));
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200298 return -1;
299 }
300 return 0;
301}
302
303static int
304get_archive_comment(int argc, char *argv[]) {
305 const char *comment;
306 int len;
307 /* get archive comment */
308 if ((comment=zip_get_archive_comment(za, &len, 0)) == NULL)
309 printf("No archive comment\n");
310 else
311 printf("Archive comment: %.*s\n", len, comment);
312 return 0;
313}
314
315static int
316get_extra(int argc, char *argv[]) {
317 zip_flags_t geflags;
318 zip_uint16_t id, eidx, eflen;
319 const zip_uint8_t *efdata;
320 zip_uint64_t idx;
321 /* get extra field data */
322 idx = strtoull(argv[0], NULL, 10);
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200323 eidx = (zip_uint16_t)strtoull(argv[1], NULL, 10);
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200324 geflags = get_flags(argv[2]);
325 if ((efdata=zip_file_extra_field_get(za, idx, eidx, &id, &eflen, geflags)) == NULL) {
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200326 fprintf(stderr, "can't get extra field data for file at index %" PRIu64 ", extra field %d, flags %u: %s\n", idx, eidx, geflags, zip_strerror(za));
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200327 return -1;
328 }
329 printf("Extra field 0x%04x: len %d", id, eflen);
330 if (eflen > 0) {
331 printf(", data ");
332 hexdump(efdata, eflen);
333 }
334 printf("\n");
335 return 0;
336}
337
338static int
339get_extra_by_id(int argc, char *argv[]) {
340 zip_flags_t geflags;
341 zip_uint16_t eid, eidx, eflen;
342 const zip_uint8_t *efdata;
343 zip_uint64_t idx;
344 idx = strtoull(argv[0], NULL, 10);
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200345 eid = (zip_uint16_t)strtoull(argv[1], NULL, 10);
346 eidx = (zip_uint16_t)strtoull(argv[2], NULL, 10);
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200347 geflags = get_flags(argv[3]);
348 if ((efdata=zip_file_extra_field_get_by_id(za, idx, eid, eidx, &eflen, geflags)) == NULL) {
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200349 fprintf(stderr, "can't get extra field data for file at index %" PRIu64 ", extra field id %d, ef index %d, flags %u: %s\n", idx, eid, eidx, geflags, zip_strerror(za));
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200350 return -1;
351 }
352 printf("Extra field 0x%04x: len %d", eid, eflen);
353 if (eflen > 0) {
354 printf(", data ");
355 hexdump(efdata, eflen);
356 }
357 printf("\n");
358 return 0;
359}
360
361static int
362get_file_comment(int argc, char *argv[]) {
363 const char *comment;
364 int len;
365 zip_uint64_t idx;
366 /* get file comment */
367 idx = strtoull(argv[0], NULL, 10);
368 if ((comment=zip_get_file_comment(za, idx, &len, 0)) == NULL) {
369 fprintf(stderr, "can't get comment for '%s': %s\n", zip_get_name(za, idx, 0), zip_strerror(za));
370 return -1;
371 } else if (len == 0)
372 printf("No comment for '%s'\n", zip_get_name(za, idx, 0));
373 else
374 printf("File comment for '%s': %.*s\n", zip_get_name(za, idx, 0), len, comment);
375 return 0;
376}
377
378static int
Thomas Klausner1f7908f2015-12-30 03:24:49 +0100379get_num_entries(int argc, char *argv[]) {
Thomas Klausner59a92aa2016-01-05 14:29:05 +0100380 zip_int64_t count;
Thomas Klausner1f7908f2015-12-30 03:24:49 +0100381 zip_flags_t flags;
382 /* get number of entries in archive */
383 flags = get_flags(argv[0]);
384 count = zip_get_num_entries(za, flags);
Thomas Klausner52113b82016-01-05 15:06:27 +0100385 printf("%" PRId64 " entr%s in archive\n", count, count == 1 ? "y" : "ies");
Thomas Klausner1f7908f2015-12-30 03:24:49 +0100386 return 0;
387}
388
389static int
Thomas Klausner27c4a222014-12-10 00:47:11 +0100390name_locate(int argc, char *argv[]) {
391 zip_flags_t flags;
392 zip_int64_t idx;
393 flags = get_flags(argv[1]);
394
395 if ((idx=zip_name_locate(za, argv[0], flags)) < 0) {
396 fprintf(stderr, "can't find entry with name '%s' using flags '%s'\n", argv[0], argv[1]);
397 } else {
398 printf("name '%s' using flags '%s' found at index %" PRId64 "\n", argv[0], argv[1], idx);
Thomas Klausner28c97922016-01-12 13:48:48 +0100399 }
Thomas Klausner27c4a222014-12-10 00:47:11 +0100400
401 return 0;
402}
403
Thomas Klausnerd6258af2016-12-18 11:55:06 +0100404static void
405progress_callback(double percentage) {
406 printf("%.1lf%% done\n", percentage*100);
407}
408
409static int
410print_progress(int argc, char *argv[]) {
411 zip_register_progress_callback(za, progress_callback);
412 return 0;
413}
414
Thomas Klausner27c4a222014-12-10 00:47:11 +0100415static int
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200416zrename(int argc, char *argv[]) {
417 zip_uint64_t idx;
418 idx = strtoull(argv[0], NULL, 10);
419 if (zip_rename(za, idx, argv[1]) < 0) {
Thomas Klausner872f8932017-01-14 22:15:33 +0100420 fprintf(stderr, "can't rename file at index '%" PRIu64 "' to '%s': %s\n", idx, argv[1], zip_strerror(za));
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200421 return -1;
422 }
423 return 0;
424}
425
426static int
427replace_file_contents(int argc, char *argv[]) {
428 /* replace file contents with data from command line */
429 const char *content;
Dieter Baron1d9dfeb2014-09-28 23:02:54 +0200430 zip_source_t *s;
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200431 zip_uint64_t idx;
432 idx = strtoull(argv[0], NULL, 10);
433 content = argv[1];
434 if ((s=zip_source_buffer(za, content, strlen(content), 0)) == NULL ||
435 zip_file_replace(za, idx, s, 0) < 0) {
436 zip_source_free(s);
437 fprintf(stderr, "error replacing file data: %s\n", zip_strerror(za));
438 return -1;
439 }
440 return 0;
441}
442
443static int
444set_extra(int argc, char *argv[]) {
445 zip_flags_t geflags;
446 zip_uint16_t eid, eidx;
447 const zip_uint8_t *efdata;
448 zip_uint64_t idx;
449 idx = strtoull(argv[0], NULL, 10);
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200450 eid = (zip_uint16_t)strtoull(argv[1], NULL, 10);
451 eidx = (zip_uint16_t)strtoull(argv[2], NULL, 10);
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200452 geflags = get_flags(argv[3]);
453 efdata = (zip_uint8_t *)argv[4];
454 if ((zip_file_extra_field_set(za, idx, eid, eidx, efdata, (zip_uint16_t)strlen((const char *)efdata), geflags)) < 0) {
Thomas Klausner872f8932017-01-14 22:15:33 +0100455 fprintf(stderr, "can't set extra field data for file at index '%" PRIu64 "', extra field id '%d', index '%d': %s\n", idx, eid, eidx, zip_strerror(za));
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200456 return -1;
457 }
458 return 0;
459}
460
461static int
Thomas Klausner8f76c552014-12-04 13:25:04 +0100462set_archive_comment(int argc, char *argv[]) {
463 if (zip_set_archive_comment(za, argv[0], (zip_uint16_t)strlen(argv[0])) < 0) {
Thomas Klausner872f8932017-01-14 22:15:33 +0100464 fprintf(stderr, "can't set archive comment to '%s': %s\n", argv[0], zip_strerror(za));
Thomas Klausner8f76c552014-12-04 13:25:04 +0100465 return -1;
466 }
467 return 0;
468}
469
470static int
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200471set_file_comment(int argc, char *argv[]) {
472 zip_uint64_t idx;
473 idx = strtoull(argv[0], NULL, 10);
474 if (zip_file_set_comment(za, idx, argv[1], (zip_uint16_t)strlen(argv[1]), 0) < 0) {
Thomas Klausner872f8932017-01-14 22:15:33 +0100475 fprintf(stderr, "can't set file comment at index '%" PRIu64 "' to '%s': %s\n", idx, argv[1], zip_strerror(za));
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200476 return -1;
477 }
478 return 0;
479}
480
481static int
482set_file_compression(int argc, char *argv[]) {
483 zip_int32_t method;
484 zip_uint32_t flags;
485 zip_uint64_t idx;
486 idx = strtoull(argv[0], NULL, 10);
487 method = get_compression_method(argv[1]);
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200488 flags = (zip_uint32_t)strtoull(argv[2], NULL, 10);
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200489 if (zip_set_file_compression(za, idx, method, flags) < 0) {
Thomas Klausner872f8932017-01-14 22:15:33 +0100490 fprintf(stderr, "can't set file compression method at index '%" PRIu64 "' to '%s', flags '%d': %s\n", idx, argv[1], flags, zip_strerror(za));
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200491 return -1;
492 }
493 return 0;
494}
495
496static int
Thomas Klausner7ed6a922016-12-16 15:50:12 +0100497set_file_encryption(int argc, char *argv[]) {
498 zip_int32_t method;
499 zip_uint64_t idx;
500 char *password;
501 idx = strtoull(argv[0], NULL, 10);
502 method = get_encryption_method(argv[1]);
503 password = argv[2];
504 if (strlen(password) == 0) {
505 password = NULL;
506 }
507 if (zip_file_set_encryption(za, idx, method, password) < 0) {
Thomas Klausner872f8932017-01-14 22:15:33 +0100508 fprintf(stderr, "can't set file encryption method at index '%" PRIu64 "' to '%s': %s\n", idx, argv[1], zip_strerror(za));
Thomas Klausner7ed6a922016-12-16 15:50:12 +0100509 return -1;
510 }
511 return 0;
512}
513
514static int
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200515set_file_mtime(int argc, char *argv[]) {
516 /* set file last modification time (mtime) */
517 time_t mtime;
518 zip_uint64_t idx;
519 idx = strtoull(argv[0], NULL, 10);
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200520 mtime = (time_t)strtoull(argv[1], NULL, 10);
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200521 if (zip_file_set_mtime(za, idx, mtime, 0) < 0) {
Thomas Klausner872f8932017-01-14 22:15:33 +0100522 fprintf(stderr, "can't set file mtime at index '%" PRIu64 "' to '%ld': %s\n", idx, mtime, zip_strerror(za));
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200523 return -1;
524 }
525 return 0;
526}
527
528static int
Thomas Klausner35bc3262016-01-12 15:10:42 +0100529set_file_mtime_all(int argc, char *argv[]) {
530 /* set last modification time (mtime) for all files */
531 time_t mtime;
Dieter Baronedc02482016-01-21 10:07:26 +0100532 zip_int64_t num_entries;
533 zip_uint64_t idx;
Thomas Klausner35bc3262016-01-12 15:10:42 +0100534 mtime = (time_t)strtoull(argv[0], NULL, 10);
Dieter Barona5b4cb72016-08-25 17:11:07 +0200535
Dieter Baronedc02482016-01-21 10:07:26 +0100536 if ((num_entries = zip_get_num_entries(za, 0)) < 0) {
537 fprintf(stderr, "can't get number of entries: %s\n", zip_strerror(za));
538 return -1;
539 }
540 for (idx = 0; idx < (zip_uint64_t)num_entries; idx++) {
Thomas Klausner35bc3262016-01-12 15:10:42 +0100541 if (zip_file_set_mtime(za, idx, mtime, 0) < 0) {
Thomas Klausner872f8932017-01-14 22:15:33 +0100542 fprintf(stderr, "can't set file mtime at index '%" PRIu64 "' to '%ld': %s\n", idx, mtime, zip_strerror(za));
Thomas Klausner35bc3262016-01-12 15:10:42 +0100543 return -1;
544 }
545 }
546 return 0;
547}
548
549static int
Thomas Klausnera96b85f2015-05-05 12:19:14 +0200550set_password(int argc, char *argv[]) {
551 /* set default password */
552 if (zip_set_default_password(za, argv[0]) < 0) {
Thomas Klausner872f8932017-01-14 22:15:33 +0100553 fprintf(stderr, "can't set default password to '%s'\n", argv[0]);
Thomas Klausnera96b85f2015-05-05 12:19:14 +0200554 return -1;
555 }
556 return 0;
557}
558
559static int
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200560zstat(int argc, char *argv[]) {
Thomas Klausner85dc6a52014-09-24 01:10:05 +0200561 zip_uint64_t idx;
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200562 char buf[100];
563 struct zip_stat sb;
Thomas Klausner85dc6a52014-09-24 01:10:05 +0200564 idx = strtoull(argv[0], NULL, 10);
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200565
Thomas Klausner85dc6a52014-09-24 01:10:05 +0200566 if (zip_stat_index(za, idx, stat_flags, &sb) < 0) {
567 fprintf(stderr, "zip_stat_index failed on '%" PRIu64 "' failed: %s\n", idx, zip_strerror(za));
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200568 return -1;
569 }
570
571 if (sb.valid & ZIP_STAT_NAME)
572 printf("name: '%s'\n", sb.name);
573 if (sb.valid & ZIP_STAT_INDEX)
574 printf("index: '%"PRIu64"'\n", sb.index);
575 if (sb.valid & ZIP_STAT_SIZE)
576 printf("size: '%"PRIu64"'\n", sb.size);
577 if (sb.valid & ZIP_STAT_COMP_SIZE)
578 printf("compressed size: '%"PRIu64"'\n", sb.comp_size);
579 if (sb.valid & ZIP_STAT_MTIME) {
580 struct tm *tpm;
581 tpm = localtime(&sb.mtime);
582 strftime(buf, sizeof(buf), "%a %b %d %Y %H:%M:%S", tpm);
583 printf("mtime: '%s'\n", buf);
584 }
585 if (sb.valid & ZIP_STAT_CRC)
586 printf("crc: '%0x'\n", sb.crc);
587 if (sb.valid & ZIP_STAT_COMP_METHOD)
588 printf("compression method: '%d'\n", sb.comp_method);
589 if (sb.valid & ZIP_STAT_ENCRYPTION_METHOD)
590 printf("encryption method: '%d'\n", sb.encryption_method);
591 if (sb.valid & ZIP_STAT_FLAGS)
592 printf("flags: '%ld'\n", (long)sb.flags);
593 printf("\n");
594
595 return 0;
596}
597
598static int
Thomas Klausner935294a2014-12-04 16:52:34 +0100599unchange_all(int argc, char *argv[]) {
600 if (zip_unchange_all(za) < 0) {
601 fprintf(stderr, "can't revert changes to archive: %s\n", zip_strerror(za));
602 return -1;
603 }
604 return 0;
605}
606
607static int
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200608zin_close(int argc, char *argv[]) {
Thomas Klausner24030de2015-04-29 15:18:35 +0200609 zip_uint64_t idx;
610
611 idx = strtoull(argv[0], NULL, 10);
612 if (idx >= z_in_count) {
Thomas Klausner380f8352015-04-29 15:31:28 +0200613 fprintf(stderr, "invalid argument '%" PRIu64 "', only %d zip sources open\n", idx, z_in_count);
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200614 return -1;
615 }
Thomas Klausner24030de2015-04-29 15:18:35 +0200616 if (zip_close(z_in[idx]) < 0) {
617 fprintf(stderr, "can't close source archive: %s\n", zip_strerror(z_in[idx]));
618 return -1;
619 }
620 z_in[idx] = z_in[z_in_count];
621 z_in_count--;
622
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200623 return 0;
624}
Thomas Klausner8cd9f822012-04-27 16:02:29 +0200625
Thomas Klausnercbb79a72013-02-25 14:15:22 +0100626static zip_flags_t
Thomas Klausner0da98c92012-10-06 22:27:17 +0200627get_flags(const char *arg)
628{
629 zip_flags_t flags = 0;
Thomas Klausner27c4a222014-12-10 00:47:11 +0100630 if (strchr(arg, 'C') != NULL)
631 flags |= ZIP_FL_NOCASE;
Thomas Klausner0da98c92012-10-06 22:27:17 +0200632 if (strchr(arg, 'c') != NULL)
633 flags |= ZIP_FL_CENTRAL;
Thomas Klausner27c4a222014-12-10 00:47:11 +0100634 if (strchr(arg, 'd') != NULL)
635 flags |= ZIP_FL_NODIR;
Thomas Klausner0da98c92012-10-06 22:27:17 +0200636 if (strchr(arg, 'l') != NULL)
637 flags |= ZIP_FL_LOCAL;
638 if (strchr(arg, 'u') != NULL)
639 flags |= ZIP_FL_UNCHANGED;
640 return flags;
641}
642
Dieter Baron4abfd5a2013-04-15 20:25:23 +0200643static zip_int32_t
644get_compression_method(const char *arg)
645{
646 if (strcmp(arg, "default") == 0)
647 return ZIP_CM_DEFAULT;
648 else if (strcmp(arg, "store") == 0)
649 return ZIP_CM_STORE;
Thomas Klausner7ed6a922016-12-16 15:50:12 +0100650 else if (strcmp(arg, "deflate") == 0)
Dieter Baron4abfd5a2013-04-15 20:25:23 +0200651 return ZIP_CM_DEFLATE;
Thomas Klausner7ed6a922016-12-16 15:50:12 +0100652 else if (strcmp(arg, "unknown") == 0)
653 return 100;
654 return 0; /* TODO: error handling */
655}
656
657static zip_uint16_t
658get_encryption_method(const char *arg)
659{
660 if (strcmp(arg, "none") == 0)
661 return ZIP_EM_NONE;
662 else if (strcmp(arg, "AES-128") == 0)
663 return ZIP_EM_AES_128;
664 else if (strcmp(arg, "AES-192") == 0)
665 return ZIP_EM_AES_192;
666 else if (strcmp(arg, "AES-256") == 0)
667 return ZIP_EM_AES_256;
668 else if (strcmp(arg, "unknown") == 0)
669 return 100;
Thomas Klausneradd18ea2017-01-18 20:11:48 +0100670 return (zip_uint16_t)-1; /* TODO: error handling */
Dieter Baron4abfd5a2013-04-15 20:25:23 +0200671}
672
Thomas Klausnercbb79a72013-02-25 14:15:22 +0100673static void
Thomas Klausner0da98c92012-10-06 22:27:17 +0200674hexdump(const zip_uint8_t *data, zip_uint16_t len)
675{
676 zip_uint16_t i;
677
678 if (len <= 0)
679 return;
680
681 printf("0x");
Thomas Klausner28c97922016-01-12 13:48:48 +0100682
Thomas Klausner0da98c92012-10-06 22:27:17 +0200683 for (i=0; i<len; i++)
684 printf("%02x", data[i]);
685
Thomas Klausner28c97922016-01-12 13:48:48 +0100686 return;
Thomas Klausner0da98c92012-10-06 22:27:17 +0200687}
688
Dieter Baron91374c72014-10-09 22:14:55 +0200689
690static zip_t *
Dieter Barona5b4cb72016-08-25 17:11:07 +0200691read_from_file(const char *archive, int flags, zip_error_t *error, zip_uint64_t offset, zip_uint64_t length)
Dieter Baron91374c72014-10-09 22:14:55 +0200692{
Dieter Baron1d7f6852016-12-08 11:56:44 +0100693 zip_t *zaa;
Dieter Barona5b4cb72016-08-25 17:11:07 +0200694 zip_source_t *source;
695 int err;
696
697 if (offset == 0 && length == 0) {
Dieter Baron1d7f6852016-12-08 11:56:44 +0100698 if ((zaa = zip_open(archive, flags, &err)) == NULL) {
Dieter Barona5b4cb72016-08-25 17:11:07 +0200699 zip_error_set(error, err, errno);
700 return NULL;
701 }
702 }
703 else {
Dieter Baron1d7f6852016-12-08 11:56:44 +0100704 if (length > ZIP_INT64_MAX) {
705 zip_error_set(error, ZIP_ER_INVAL, 0);
706 return NULL;
707 }
708 if ((source = zip_source_file_create(archive, offset, (zip_int64_t)length, error)) == NULL
709 || (zaa = zip_open_from_source(source, flags, error)) == NULL) {
Dieter Barona5b4cb72016-08-25 17:11:07 +0200710 zip_source_free(source);
711 return NULL;
712 }
713 }
714
Dieter Baron1d7f6852016-12-08 11:56:44 +0100715 return zaa;
Dieter Barona5b4cb72016-08-25 17:11:07 +0200716}
717
718
719static zip_t *
720read_hole(const char *archive, int flags, zip_error_t *error)
721{
Dieter Baron91374c72014-10-09 22:14:55 +0200722 zip_source_t *src = NULL;
Dieter Baron98bf11d2014-10-10 09:39:32 +0200723 zip_t *zs = NULL;
Thomas Klausner28c97922016-01-12 13:48:48 +0100724
Dieter Barona5b4cb72016-08-25 17:11:07 +0200725 if ((src = source_hole_create(archive, flags, error)) == NULL
726 || (zs = zip_open_from_source(src, flags, error)) == NULL) {
Dieter Baron91374c72014-10-09 22:14:55 +0200727 zip_source_free(src);
Dieter Baron91374c72014-10-09 22:14:55 +0200728 }
Thomas Klausner28c97922016-01-12 13:48:48 +0100729
Dieter Baron98bf11d2014-10-10 09:39:32 +0200730 return zs;
Dieter Baron91374c72014-10-09 22:14:55 +0200731}
732
733
Dieter Baron1d9dfeb2014-09-28 23:02:54 +0200734static zip_t *
Dieter Barona5b4cb72016-08-25 17:11:07 +0200735read_to_memory(const char *archive, int flags, zip_error_t *error, zip_source_t **srcp)
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200736{
737 struct stat st;
738 zip_source_t *src;
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200739 zip_t *zb;
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200740
741 if (stat(archive, &st) < 0) {
742 if (errno == ENOENT) {
Dieter Barona5b4cb72016-08-25 17:11:07 +0200743 src = zip_source_buffer_create(NULL, 0, 0, error);
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200744 }
745 else {
Dieter Barona5b4cb72016-08-25 17:11:07 +0200746 zip_error_set(error, ZIP_ER_OPEN, errno);
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200747 return NULL;
748 }
749 }
750 else {
751 char *buf;
752 FILE *fp;
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200753 if ((buf=malloc((size_t)st.st_size)) == NULL) {
Dieter Barona5b4cb72016-08-25 17:11:07 +0200754 zip_error_set(error, ZIP_ER_MEMORY, 0);
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200755 return NULL;
756 }
757 if ((fp=fopen(archive, "r")) == NULL) {
758 free(buf);
Dieter Barona5b4cb72016-08-25 17:11:07 +0200759 zip_error_set(error, ZIP_ER_READ, errno);
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200760 return NULL;
761 }
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200762 if (fread(buf, (size_t)st.st_size, 1, fp) < 1) {
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200763 free(buf);
Thomas Klausner96cc48d2015-04-22 21:48:44 +0200764 fclose(fp);
Dieter Barona5b4cb72016-08-25 17:11:07 +0200765 zip_error_set(error, ZIP_ER_READ, errno);
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200766 return NULL;
767 }
768 fclose(fp);
Dieter Barona5b4cb72016-08-25 17:11:07 +0200769 src = zip_source_buffer_create(buf, (zip_uint64_t)st.st_size, 1, error);
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200770 if (src == NULL) {
771 free(buf);
772 }
773 }
774 if (src == NULL) {
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200775 return NULL;
776 }
Dieter Barona5b4cb72016-08-25 17:11:07 +0200777 zb = zip_open_from_source(src, flags, error);
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200778 if (zb == NULL) {
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200779 zip_source_free(src);
780 return NULL;
781 }
782 zip_source_keep(src);
783 *srcp = src;
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200784 return zb;
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200785}
786
Dieter Baron91374c72014-10-09 22:14:55 +0200787
Dieter Baron273a1c92014-10-01 14:20:21 +0200788typedef struct source_nul {
789 zip_error_t error;
790 zip_uint64_t length;
791 zip_uint64_t offset;
792} source_nul_t;
793
794static zip_int64_t
795source_nul_cb(void *ud, void *data, zip_uint64_t length, zip_source_cmd_t command)
796{
797 source_nul_t *ctx = (source_nul_t *)ud;
Thomas Klausner28c97922016-01-12 13:48:48 +0100798
Dieter Baron273a1c92014-10-01 14:20:21 +0200799 switch (command) {
800 case ZIP_SOURCE_CLOSE:
801 return 0;
802
803 case ZIP_SOURCE_ERROR:
804 return zip_error_to_data(&ctx->error, data, length);
Thomas Klausner28c97922016-01-12 13:48:48 +0100805
Dieter Baron273a1c92014-10-01 14:20:21 +0200806 case ZIP_SOURCE_FREE:
807 free(ctx);
808 return 0;
Thomas Klausner28c97922016-01-12 13:48:48 +0100809
Dieter Baron273a1c92014-10-01 14:20:21 +0200810 case ZIP_SOURCE_OPEN:
811 ctx->offset = 0;
812 return 0;
Thomas Klausner28c97922016-01-12 13:48:48 +0100813
Dieter Baron273a1c92014-10-01 14:20:21 +0200814 case ZIP_SOURCE_READ:
Thomas Klausnerd4472902014-10-01 15:41:14 +0200815 if (length > ZIP_INT64_MAX) {
816 zip_error_set(&ctx->error, ZIP_ER_INVAL, 0);
817 return -1;
818 }
819
Dieter Baron273a1c92014-10-01 14:20:21 +0200820 if (length > ctx->length - ctx->offset) {
821 length =ctx->length - ctx->offset;
822 }
Thomas Klausner28c97922016-01-12 13:48:48 +0100823
Dieter Baron273a1c92014-10-01 14:20:21 +0200824 memset(data, 0, length);
825 ctx->offset += length;
Thomas Klausnerd4472902014-10-01 15:41:14 +0200826 return (zip_int64_t)length;
Thomas Klausner28c97922016-01-12 13:48:48 +0100827
Dieter Baron273a1c92014-10-01 14:20:21 +0200828 case ZIP_SOURCE_STAT: {
829 zip_stat_t *st = ZIP_SOURCE_GET_ARGS(zip_stat_t, data, length, &ctx->error);
Thomas Klausner28c97922016-01-12 13:48:48 +0100830
Dieter Baron273a1c92014-10-01 14:20:21 +0200831 if (st == NULL) {
832 return -1;
833 }
Thomas Klausner28c97922016-01-12 13:48:48 +0100834
Dieter Baron273a1c92014-10-01 14:20:21 +0200835 st->valid |= ZIP_STAT_SIZE;
836 st->size = ctx->length;
Thomas Klausner28c97922016-01-12 13:48:48 +0100837
Dieter Baron273a1c92014-10-01 14:20:21 +0200838 return 0;
839 }
Thomas Klausner28c97922016-01-12 13:48:48 +0100840
Dieter Baron273a1c92014-10-01 14:20:21 +0200841 case ZIP_SOURCE_SUPPORTS:
842 return zip_source_make_command_bitmap(ZIP_SOURCE_CLOSE, ZIP_SOURCE_ERROR, ZIP_SOURCE_FREE, ZIP_SOURCE_OPEN, ZIP_SOURCE_READ, ZIP_SOURCE_STAT, -1);
843
844 default:
845 zip_error_set(&ctx->error, ZIP_ER_OPNOTSUPP, 0);
846 return -1;
847 }
848}
849
850static zip_source_t *
Thomas Klausnerd4472902014-10-01 15:41:14 +0200851source_nul(zip_t *zs, zip_uint64_t length)
Dieter Baron273a1c92014-10-01 14:20:21 +0200852{
853 source_nul_t *ctx;
854 zip_source_t *src;
Thomas Klausner28c97922016-01-12 13:48:48 +0100855
Dieter Baron273a1c92014-10-01 14:20:21 +0200856 if ((ctx = (source_nul_t *)malloc(sizeof(*ctx))) == NULL) {
Thomas Klausnerd4472902014-10-01 15:41:14 +0200857 zip_error_set(zip_get_error(zs), ZIP_ER_MEMORY, 0);
Dieter Baron273a1c92014-10-01 14:20:21 +0200858 return NULL;
859 }
Thomas Klausner28c97922016-01-12 13:48:48 +0100860
Dieter Baron273a1c92014-10-01 14:20:21 +0200861 zip_error_init(&ctx->error);
862 ctx->length = length;
863 ctx->offset = 0;
Thomas Klausner28c97922016-01-12 13:48:48 +0100864
Thomas Klausnerd4472902014-10-01 15:41:14 +0200865 if ((src = zip_source_function(zs, source_nul_cb, ctx)) == NULL) {
Dieter Baron273a1c92014-10-01 14:20:21 +0200866 free(ctx);
867 return NULL;
868 }
Thomas Klausner28c97922016-01-12 13:48:48 +0100869
Dieter Baron273a1c92014-10-01 14:20:21 +0200870 return src;
871}
872
873
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200874static int
875write_memory_src_to_file(const char *archive, zip_source_t *src)
876{
877 zip_stat_t zst;
878 char *buf;
879 FILE *fp;
880
881 if (zip_source_stat(src, &zst) < 0) {
882 fprintf(stderr, "zip_source_stat on buffer failed: %s\n", zip_error_strerror(zip_source_error(src)));
883 return -1;
884 }
885 if (zip_source_open(src) < 0) {
886 if (zip_error_code_zip(zip_source_error(src)) == ZIP_ER_DELETED) {
Thomas Klausner471a67a2016-01-22 20:19:06 +0100887 if (unlink(archive) < 0 && errno != ENOENT) {
888 fprintf(stderr, "unlink failed: %s\n", strerror(errno));
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200889 return -1;
890 }
891 return 0;
892 }
893 fprintf(stderr, "zip_source_open on buffer failed: %s\n", zip_error_strerror(zip_source_error(src)));
894 return -1;
895 }
896 if ((buf=malloc(zst.size)) == NULL) {
897 fprintf(stderr, "malloc failed: %s\n", strerror(errno));
898 zip_source_close(src);
899 return -1;
900 }
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200901 if (zip_source_read(src, buf, zst.size) < (zip_int64_t)zst.size) {
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200902 fprintf(stderr, "zip_source_read on buffer failed: %s\n", zip_error_strerror(zip_source_error(src)));
903 zip_source_close(src);
904 free(buf);
905 return -1;
906 }
907 zip_source_close(src);
908 if ((fp=fopen(archive, "wb")) == NULL) {
909 fprintf(stderr, "fopen failed: %s\n", strerror(errno));
910 free(buf);
911 return -1;
912 }
913 if (fwrite(buf, zst.size, 1, fp) < 1) {
914 fprintf(stderr, "fwrite failed: %s\n", strerror(errno));
915 free(buf);
Thomas Klausnerdb9cb402015-04-22 21:45:33 +0200916 fclose(fp);
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200917 return -1;
918 }
919 free(buf);
920 if (fclose(fp) != 0) {
921 fprintf(stderr, "fclose failed: %s\n", strerror(errno));
922 return -1;
923 }
924 return 0;
925}
926
927dispatch_table_t dispatch_table[] = {
928 { "add", 2, "name content", "add file called name using content", add },
929 { "add_dir", 1, "name", "add directory", add_dir },
930 { "add_file", 4, "name file_to_add offset len", "add file to archive, len bytes starting from offset", add_file },
931 { "add_from_zip", 5, "name archivename index offset len", "add file from another archive, len bytes starting from offset", add_from_zip },
Dieter Baron273a1c92014-10-01 14:20:21 +0200932 { "add_nul", 2, "name length", "add NUL bytes", add_nul },
Thomas Klausner4a41da22014-12-02 11:23:23 +0100933 { "cat", 1, "index", "output file contents to stdout", cat },
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200934 { "count_extra", 2, "index flags", "show number of extra fields for archive entry", count_extra },
935 { "count_extra_by_id", 3, "index extra_id flags", "show number of extra fields of type extra_id for archive entry", count_extra_by_id },
936 { "delete", 1, "index", "remove entry", delete },
937 { "delete_extra", 3, "index extra_idx flags", "remove extra field", delete_extra },
938 { "delete_extra_by_id", 4, "index extra_id extra_index flags", "remove extra field of type extra_id", delete_extra_by_id },
939 { "get_archive_comment", 0, "", "show archive comment", get_archive_comment },
940 { "get_extra", 3, "index extra_index flags", "show extra field", get_extra },
941 { "get_extra_by_id", 4, "index extra_id extra_index flags", "show extra field of type extra_id", get_extra_by_id },
942 { "get_file_comment", 1, "index", "get file comment", get_file_comment },
Thomas Klausner1f7908f2015-12-30 03:24:49 +0100943 { "get_num_entries", 1, "flags", "get number of entries in archive", get_num_entries },
Thomas Klausner27c4a222014-12-10 00:47:11 +0100944 { "name_locate", 2, "name flags", "find entry in archive", name_locate },
Thomas Klausnerd6258af2016-12-18 11:55:06 +0100945 { "print_progress", 0, "", "print progress during zip_close()", print_progress },
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200946 { "rename", 2, "index name", "rename entry", zrename },
947 { "replace_file_contents", 2, "index data", "replace entry with data", replace_file_contents },
Thomas Klausner8f76c552014-12-04 13:25:04 +0100948 { "set_archive_comment", 1, "comment", "set archive comment", set_archive_comment },
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200949 { "set_extra", 5, "index extra_id extra_index flags value", "set extra field", set_extra },
950 { "set_file_comment", 2, "index comment", "set file comment", set_file_comment },
Thomas Klausnerd389a492016-01-19 12:40:39 +0100951 { "set_file_compression", 3, "index method compression_flags", "set file compression method", set_file_compression },
Thomas Klausner7ed6a922016-12-16 15:50:12 +0100952 { "set_file_encryption", 3, "index method password", "set file encryption method", set_file_encryption },
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200953 { "set_file_mtime", 2, "index timestamp", "set file modification time", set_file_mtime },
Thomas Klausner35bc3262016-01-12 15:10:42 +0100954 { "set_file_mtime_all", 1, "timestamp", "set file modification time for all files", set_file_mtime_all },
Thomas Klausnerafa299f2016-01-12 14:48:40 +0100955 { "set_password", 1, "password", "set default password for encryption", set_password },
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200956 { "stat", 1, "index", "print information about entry", zstat },
Thomas Klausner935294a2014-12-04 16:52:34 +0100957 { "unchange_all", 0, "", "revert all changes", unchange_all },
Thomas Klausner24030de2015-04-29 15:18:35 +0200958 { "zin_close", 1, "index", "close input zip_source (for internal tests)", zin_close }
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200959};
960
Dieter Baron98bf11d2014-10-10 09:39:32 +0200961static int
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200962dispatch(int argc, char *argv[])
963{
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200964 unsigned int i;
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200965 for (i=0; i<sizeof(dispatch_table)/sizeof(dispatch_table_t); i++) {
966 if (strcmp(dispatch_table[i].cmdline_name, argv[0]) == 0) {
967 argc--;
968 argv++;
969 /* 1 for the command, argument_count for the arguments */
970 if (argc < dispatch_table[i].argument_count) {
971 fprintf(stderr, "not enough arguments for command '%s': %d available, %d needed\n", dispatch_table[i].cmdline_name, argc, dispatch_table[i].argument_count);
972 return -1;
973 }
974 if (dispatch_table[i].function(argc, argv) == 0)
975 return 1 + dispatch_table[i].argument_count;
976 return -1;
977 }
978 }
979
980 fprintf(stderr, "unknown command '%s'\n", argv[0]);
981 return -1;
982}
983
984
Dieter Baron98bf11d2014-10-10 09:39:32 +0200985static void
Thomas Klausner5781d2f2016-01-19 12:09:40 +0100986usage(const char *progname, const char *reason)
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200987{
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200988 unsigned int i;
Thomas Klausner72f023c2016-01-19 12:02:50 +0100989 FILE *out;
Thomas Klausner5781d2f2016-01-19 12:09:40 +0100990 if (reason == NULL)
Thomas Klausner72f023c2016-01-19 12:02:50 +0100991 out = stdout;
992 else
993 out = stderr;
Dieter Barona5b4cb72016-08-25 17:11:07 +0200994 fprintf(out, "usage: %s [-cegHhmnrst] [-l len] [-o offset] archive command1 [args] [command2 [args] ...]\n", progname);
Thomas Klausner5781d2f2016-01-19 12:09:40 +0100995 if (reason != NULL) {
996 fprintf(out, "%s\n", reason);
997 exit(1);
998 }
999
1000 fprintf(out, "\nSupported options are:\n"
Dieter Barona5b4cb72016-08-25 17:11:07 +02001001 "\t-c\t\tcheck consistency\n"
1002 "\t-e\t\terror if archive already exists (only useful with -n)\n"
1003 "\t-g\t\tguess file name encoding (for stat)\n"
1004 "\t-H\t\twrite files with holes compactly\n"
1005 "\t-h\t\tdisplay this usage\n"
1006 "\t-l len\t\tonly use len bytes of file\n"
1007 "\t-m\t\tread archive into memory, and modify there; write out at end\n"
1008 "\t-n\t\tcreate archive if it doesn't exist\n"
1009 "\t-o offset\tstart reading file at offset\n"
1010 "\t-r\t\tprint raw file name encoding without translation (for stat)\n"
1011 "\t-s\t\tfollow file name convention strictly (for stat)\n"
1012 "\t-t\t\tdisregard current archive contents, if any\n");
Thomas Klausner72f023c2016-01-19 12:02:50 +01001013 fprintf(out, "\nSupported commands and arguments are:\n");
Thomas Klausnerea8ba492014-09-23 16:54:47 +02001014 for (i=0; i<sizeof(dispatch_table)/sizeof(dispatch_table_t); i++) {
Thomas Klausner72f023c2016-01-19 12:02:50 +01001015 fprintf(out, "\t%s %s\n\t %s\n\n", dispatch_table[i].cmdline_name, dispatch_table[i].arg_names, dispatch_table[i].description);
Thomas Klausnerea8ba492014-09-23 16:54:47 +02001016 }
Thomas Klausner72f023c2016-01-19 12:02:50 +01001017 fprintf(out, "\nSupported flags are:\n"
Thomas Klausnerc4385822016-08-25 13:56:57 +02001018 "\t0\t(no flags)\n"
Thomas Klausner27c4a222014-12-10 00:47:11 +01001019 "\tC\tZIP_FL_NOCASE\n"
1020 "\tc\tZIP_FL_CENTRAL\n"
1021 "\td\tZIP_FL_NODIR\n"
1022 "\tl\tZIP_FL_LOCAL\n"
1023 "\tu\tZIP_FL_UNCHANGED\n");
Thomas Klausner756b7c82016-01-19 12:12:09 +01001024 fprintf(out, "\nSupported compression methods are:\n"
1025 "\tdefault\n"
1026 "\tdeflate\n"
1027 "\tstore\n");
Thomas Klausner7ed6a922016-12-16 15:50:12 +01001028 fprintf(out, "\nSupported compression methods are:\n"
1029 "\tnone\n"
1030 "\tAES-128\n"
1031 "\tAES-192\n"
1032 "\tAES-256\n");
Thomas Klausner72f023c2016-01-19 12:02:50 +01001033 fprintf(out, "\nThe index is zero-based.\n");
Thomas Klausner5781d2f2016-01-19 12:09:40 +01001034 exit(0);
Thomas Klausnerea8ba492014-09-23 16:54:47 +02001035}
1036
Thomas Klausner89bb5fe2012-02-20 01:43:56 +01001037int
1038main(int argc, char *argv[])
1039{
1040 const char *archive;
Dieter Baron1d9dfeb2014-09-28 23:02:54 +02001041 zip_source_t *memory_src;
Thomas Klausnerb1e93a02015-07-08 16:27:38 +02001042 unsigned int i;
1043 int c, arg, err, flags;
Thomas Klausner03ca1c12014-09-24 01:02:15 +02001044 const char *prg;
Dieter Baron91374c72014-10-09 22:14:55 +02001045 source_type_t source_type = SOURCE_TYPE_NONE;
Dieter Barona5b4cb72016-08-25 17:11:07 +02001046 zip_uint64_t len = 0, offset = 0;
1047 zip_error_t error;
Thomas Klausner89bb5fe2012-02-20 01:43:56 +01001048
Dieter Baronc9d42c22012-07-30 21:48:51 +02001049 flags = 0;
1050 prg = argv[0];
Thomas Klausner89bb5fe2012-02-20 01:43:56 +01001051
Dieter Barona5b4cb72016-08-25 17:11:07 +02001052 while ((c=getopt(argc, argv, "cegHhl:mno:rst")) != -1) {
Thomas Klausner8cd9f822012-04-27 16:02:29 +02001053 switch (c) {
1054 case 'c':
1055 flags |= ZIP_CHECKCONS;
1056 break;
1057 case 'e':
1058 flags |= ZIP_EXCL;
1059 break;
Thomas Klausnerea8ba492014-09-23 16:54:47 +02001060 case 'g':
1061 stat_flags = ZIP_FL_ENC_GUESS;
1062 break;
Dieter Baron91374c72014-10-09 22:14:55 +02001063 case 'H':
1064 source_type = SOURCE_TYPE_HOLE;
1065 break;
Thomas Klausner72f023c2016-01-19 12:02:50 +01001066 case 'h':
Thomas Klausner5781d2f2016-01-19 12:09:40 +01001067 usage(prg, NULL);
Thomas Klausner72f023c2016-01-19 12:02:50 +01001068 break;
Dieter Barona5b4cb72016-08-25 17:11:07 +02001069 case 'l':
1070 len = strtoull(optarg, NULL, 10);
1071 break;
Thomas Klausnerea8ba492014-09-23 16:54:47 +02001072 case 'm':
Dieter Baron91374c72014-10-09 22:14:55 +02001073 source_type = SOURCE_TYPE_IN_MEMORY;
1074 break;
Thomas Klausner8cd9f822012-04-27 16:02:29 +02001075 case 'n':
1076 flags |= ZIP_CREATE;
1077 break;
Dieter Barona5b4cb72016-08-25 17:11:07 +02001078 case 'o':
1079 offset = strtoull(optarg, NULL, 10);
1080 break;
Thomas Klausnerea8ba492014-09-23 16:54:47 +02001081 case 'r':
1082 stat_flags = ZIP_FL_ENC_RAW;
1083 break;
1084 case 's':
1085 stat_flags = ZIP_FL_ENC_STRICT;
1086 break;
Thomas Klausner8cd9f822012-04-27 16:02:29 +02001087 case 't':
1088 flags |= ZIP_TRUNCATE;
1089 break;
1090
1091 default:
Thomas Klausner5781d2f2016-01-19 12:09:40 +01001092 {
1093 char reason[128];
1094 snprintf(reason, sizeof(reason), "invalid option -%c", optopt);
1095 usage(prg, reason);
1096 }
Thomas Klausner8cd9f822012-04-27 16:02:29 +02001097 }
1098 }
Thomas Klausner28c97922016-01-12 13:48:48 +01001099
Dieter Barona5b4cb72016-08-25 17:11:07 +02001100 if (optind >= argc-1)
1101 usage(prg, "too few arguments");
1102
Dieter Baronc9d42c22012-07-30 21:48:51 +02001103 arg = optind;
Thomas Klausner8cd9f822012-04-27 16:02:29 +02001104
Thomas Klausner89bb5fe2012-02-20 01:43:56 +01001105 archive = argv[arg++];
Thomas Klausner8cd9f822012-04-27 16:02:29 +02001106
1107 if (flags == 0)
1108 flags = ZIP_CREATE;
1109
Dieter Barona5b4cb72016-08-25 17:11:07 +02001110 zip_error_init(&error);
Dieter Baron91374c72014-10-09 22:14:55 +02001111 switch (source_type) {
Dieter Barona5b4cb72016-08-25 17:11:07 +02001112 case SOURCE_TYPE_NONE:
1113 za = read_from_file(archive, flags, &error, offset, len);
1114 break;
Thomas Klausner28c97922016-01-12 13:48:48 +01001115
Dieter Baron91374c72014-10-09 22:14:55 +02001116 case SOURCE_TYPE_IN_MEMORY:
Dieter Barona5b4cb72016-08-25 17:11:07 +02001117 za = read_to_memory(archive, flags, &error, &memory_src);
Dieter Baron91374c72014-10-09 22:14:55 +02001118 break;
Thomas Klausner28c97922016-01-12 13:48:48 +01001119
Dieter Barona5b4cb72016-08-25 17:11:07 +02001120 case SOURCE_TYPE_HOLE:
1121 za = read_hole(archive, flags, &error);
Dieter Baron91374c72014-10-09 22:14:55 +02001122 break;
Thomas Klausnerea8ba492014-09-23 16:54:47 +02001123 }
1124 if (za == NULL) {
Thomas Klausnerda1c2452014-12-02 16:01:26 +01001125 fprintf(stderr, "can't open zip archive '%s': %s\n", archive, zip_error_strerror(&error));
1126 zip_error_fini(&error);
Thomas Klausner89bb5fe2012-02-20 01:43:56 +01001127 return 1;
1128 }
Dieter Barona5b4cb72016-08-25 17:11:07 +02001129 zip_error_fini(&error);
Thomas Klausner89bb5fe2012-02-20 01:43:56 +01001130
Thomas Klausner9b6aff12012-04-27 15:24:07 +02001131 err = 0;
Thomas Klausner89bb5fe2012-02-20 01:43:56 +01001132 while (arg < argc) {
Thomas Klausnerea8ba492014-09-23 16:54:47 +02001133 int ret;
1134 ret = dispatch(argc-arg, argv+arg);
1135 if (ret > 0) {
1136 arg += ret;
Thomas Klausner89bb5fe2012-02-20 01:43:56 +01001137 } else {
Thomas Klausner9b6aff12012-04-27 15:24:07 +02001138 err = 1;
Thomas Klausner89bb5fe2012-02-20 01:43:56 +01001139 break;
1140 }
1141 }
1142
1143 if (zip_close(za) == -1) {
Thomas Klausner73716052013-11-28 18:15:14 +01001144 fprintf(stderr, "can't close zip archive '%s': %s\n", archive, zip_strerror(za));
Thomas Klausner89bb5fe2012-02-20 01:43:56 +01001145 return 1;
1146 }
Dieter Baron91374c72014-10-09 22:14:55 +02001147 if (source_type == SOURCE_TYPE_IN_MEMORY) {
Thomas Klausnerea8ba492014-09-23 16:54:47 +02001148 if (write_memory_src_to_file(archive, memory_src) < 0) {
1149 err = 1;
1150 }
1151 zip_source_free(memory_src);
1152 }
Thomas Klausner89bb5fe2012-02-20 01:43:56 +01001153
Thomas Klausner24030de2015-04-29 15:18:35 +02001154 for (i=0; i<z_in_count; i++) {
1155 if (zip_close(z_in[i]) < 0) {
1156 err = 1;
1157 }
1158 }
1159
Thomas Klausner9b6aff12012-04-27 15:24:07 +02001160 return err;
Thomas Klausner89bb5fe2012-02-20 01:43:56 +01001161}