blob: 43932342d7859cd356a66816af1f2c742306e47a [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
51
Thomas Klausner89bb5fe2012-02-20 01:43:56 +010052#include "zip.h"
Thomas Klausner2bb30c72016-01-06 15:45:24 +010053#include "compat.h"
Thomas Klausner89bb5fe2012-02-20 01:43:56 +010054
Dieter Baron91374c72014-10-09 22:14:55 +020055zip_source_t *source_hole_create(const char *, int flags, zip_error_t *);
56
57typedef enum {
58 SOURCE_TYPE_NONE,
59 SOURCE_TYPE_IN_MEMORY,
60 SOURCE_TYPE_HOLE
61} source_type_t;
62
Thomas Klausnerea8ba492014-09-23 16:54:47 +020063typedef struct dispatch_table_s {
64 const char *cmdline_name;
65 int argument_count;
66 const char *arg_names;
67 const char *description;
68 int (*function)(int argc, char *argv[]);
69} dispatch_table_t;
Thomas Klausner89bb5fe2012-02-20 01:43:56 +010070
Thomas Klausnerea8ba492014-09-23 16:54:47 +020071static zip_flags_t get_flags(const char *arg);
72static zip_int32_t get_compression_method(const char *arg);
73static void hexdump(const zip_uint8_t *data, zip_uint16_t len);
Dieter Baron1d9dfeb2014-09-28 23:02:54 +020074static zip_t *read_to_memory(const char *archive, int flags, int *err, zip_source_t **srcp);
Dieter Baron273a1c92014-10-01 14:20:21 +020075static zip_source_t *source_nul(zip_t *za, zip_uint64_t length);
Thomas Klausnerea8ba492014-09-23 16:54:47 +020076
Thomas Klausner24030de2015-04-29 15:18:35 +020077zip_t *za, *z_in[16];
Thomas Klausnerb1e93a02015-07-08 16:27:38 +020078unsigned int z_in_count;
Thomas Klausnerea8ba492014-09-23 16:54:47 +020079zip_flags_t stat_flags;
80
81static int
82add(int argc, char *argv[]) {
Dieter Baron1d9dfeb2014-09-28 23:02:54 +020083 zip_source_t *zs;
Thomas Klausnerea8ba492014-09-23 16:54:47 +020084
85 if ((zs=zip_source_buffer(za, argv[1], strlen(argv[1]), 0)) == NULL) {
86 fprintf(stderr, "can't create zip_source from buffer: %s\n", zip_strerror(za));
87 return -1;
88 }
89
90 if (zip_add(za, argv[0], zs) == -1) {
91 zip_source_free(zs);
92 fprintf(stderr, "can't add file '%s': %s\n", argv[0], zip_strerror(za));
93 return -1;
94 }
95 return 0;
96}
97
98static int
99add_dir(int argc, char *argv[]) {
100 /* add directory */
101 if (zip_add_dir(za, argv[0]) < 0) {
102 fprintf(stderr, "can't add directory '%s': %s\n", argv[0], zip_strerror(za));
103 return -1;
104 }
105 return 0;
106}
107
108static int
109add_file(int argc, char *argv[]) {
Dieter Baron1d9dfeb2014-09-28 23:02:54 +0200110 zip_source_t *zs;
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200111 zip_uint64_t start = strtoull(argv[2], NULL, 10);
112 zip_int64_t len = strtoll(argv[3], NULL, 10);
113
114 if (strcmp(argv[1], "/dev/stdin") == 0) {
115 if ((zs=zip_source_filep(za, stdin, start, len)) == NULL) {
116 fprintf(stderr, "can't create zip_source from stdin: %s\n", zip_strerror(za));
117 return -1;
118 }
119 } else {
120 if ((zs=zip_source_file(za, argv[1], start, len)) == NULL) {
121 fprintf(stderr, "can't create zip_source from file: %s\n", zip_strerror(za));
122 return -1;
123 }
124 }
125
126 if (zip_add(za, argv[0], zs) == -1) {
127 zip_source_free(zs);
128 fprintf(stderr, "can't add file '%s': %s\n", argv[0], zip_strerror(za));
129 return -1;
130 }
131 return 0;
132}
133
134static int
135add_from_zip(int argc, char *argv[]) {
Thomas Klausnerb51f6132016-01-05 14:07:07 +0100136 zip_uint64_t idx, start;
137 zip_int64_t len;
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200138 int err;
Dieter Baron1d9dfeb2014-09-28 23:02:54 +0200139 zip_source_t *zs;
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200140 /* add from another zip file */
141 idx = strtoull(argv[2], NULL, 10);
Thomas Klausnerb51f6132016-01-05 14:07:07 +0100142 start = strtoull(argv[3], NULL, 10);
143 len = strtoll(argv[4], NULL, 10);
Thomas Klausner24030de2015-04-29 15:18:35 +0200144 if ((z_in[z_in_count]=zip_open(argv[1], ZIP_CHECKCONS, &err)) == NULL) {
Thomas Klausnerda1c2452014-12-02 16:01:26 +0100145 zip_error_t error;
146 zip_error_init_with_code(&error, err);
147 fprintf(stderr, "can't open zip archive '%s': %s\n", argv[1], zip_error_strerror(&error));
148 zip_error_fini(&error);
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200149 return -1;
150 }
Thomas Klausner24030de2015-04-29 15:18:35 +0200151 if ((zs=zip_source_zip(za, z_in[z_in_count], idx, 0, start, len)) == NULL) {
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200152 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 +0200153 zip_close(z_in[z_in_count]);
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200154 return -1;
155 }
156 if (zip_add(za, argv[0], zs) == -1) {
157 fprintf(stderr, "can't add file '%s': %s\n", argv[0], zip_strerror(za));
158 zip_source_free(zs);
Thomas Klausner24030de2015-04-29 15:18:35 +0200159 zip_close(z_in[z_in_count]);
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200160 return -1;
161 }
Thomas Klausner24030de2015-04-29 15:18:35 +0200162 z_in_count++;
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200163 return 0;
164}
165
Dieter Baron98bf11d2014-10-10 09:39:32 +0200166static int
Dieter Baron273a1c92014-10-01 14:20:21 +0200167add_nul(int argc, char *argv[]) {
168 zip_source_t *zs;
169 zip_uint64_t length = strtoull(argv[1], NULL, 10);
Thomas Klausner28c97922016-01-12 13:48:48 +0100170
Dieter Baron273a1c92014-10-01 14:20:21 +0200171 if ((zs=source_nul(za, length)) == NULL) {
172 fprintf(stderr, "can't create zip_source for length: %s\n", zip_strerror(za));
173 return -1;
174 }
Thomas Klausner28c97922016-01-12 13:48:48 +0100175
Dieter Baron273a1c92014-10-01 14:20:21 +0200176 if (zip_add(za, argv[0], zs) == -1) {
177 zip_source_free(zs);
178 fprintf(stderr, "can't add file '%s': %s\n", argv[0], zip_strerror(za));
179 return -1;
180 }
181 return 0;
182}
183
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200184static int
Thomas Klausner4a41da22014-12-02 11:23:23 +0100185cat(int argc, char *argv[]) {
186 /* output file contents to stdout */
187 zip_uint64_t idx;
188 zip_int64_t n;
189 zip_file_t *zf;
190 char buf[8192];
Thomas Klausnerda1c2452014-12-02 16:01:26 +0100191 int err;
Thomas Klausner4a41da22014-12-02 11:23:23 +0100192 idx = strtoull(argv[0], NULL, 10);
193
Thomas Klausnerbe146cb2015-09-15 14:12:08 +0200194#ifdef _WIN32
195 /* Need to set stdout to binary mode for Windows */
196 setmode(fileno(stdout), _O_BINARY);
197#endif
Thomas Klausner4a41da22014-12-02 11:23:23 +0100198 if ((zf=zip_fopen_index(za, idx, 0)) == NULL) {
199 fprintf(stderr, "can't open file at index '%" PRIu64 "': %s\n", idx, zip_strerror(za));
200 return -1;
201 }
202 while ((n=zip_fread(zf, buf, sizeof(buf))) > 0) {
203 if (fwrite(buf, (size_t)n, 1, stdout) != 1) {
204 zip_fclose(zf);
205 fprintf(stderr, "can't write file contents to stdout: %s\n", strerror(errno));
206 return -1;
207 }
208 }
209 if (n == -1) {
210 zip_fclose(zf);
211 fprintf(stderr, "can't read file at index '%" PRIu64 "': %s\n", idx, zip_file_strerror(zf));
212 return -1;
213 }
Thomas Klausnerda1c2452014-12-02 16:01:26 +0100214 if ((err = zip_fclose(zf)) != 0) {
215 zip_error_t error;
Thomas Klausner28c97922016-01-12 13:48:48 +0100216
Thomas Klausnerda1c2452014-12-02 16:01:26 +0100217 zip_error_init_with_code(&error, err);
218 fprintf(stderr, "can't close file at index '%" PRIu64 "': %s\n", idx, zip_error_strerror(&error));
Thomas Klausner4a41da22014-12-02 11:23:23 +0100219 return -1;
220 }
221
222 return 0;
223}
224
225static int
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200226count_extra(int argc, char *argv[]) {
227 zip_int16_t count;
228 zip_uint64_t idx;
229 zip_flags_t ceflags = 0;
230 idx = strtoull(argv[0], NULL, 10);
231 ceflags = get_flags(argv[1]);
232 if ((count=zip_file_extra_fields_count(za, idx, ceflags)) < 0) {
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200233 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 +0200234 return -1;
235 } else {
236 printf("Extra field count: %d\n", count);
237 }
238 return 0;
239}
240
241static int
242count_extra_by_id(int argc, char *argv[]) {
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200243 zip_int16_t count;
244 zip_uint16_t eid;
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200245 zip_flags_t ceflags = 0;
246 zip_uint64_t idx;
247 idx = strtoull(argv[0], NULL, 10);
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200248 eid = (zip_uint16_t)strtoull(argv[1], NULL, 10);
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200249 ceflags = get_flags(argv[2]);
250 if ((count=zip_file_extra_fields_count_by_id(za, idx, eid, ceflags)) < 0) {
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200251 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 +0200252 return -1;
253 } else {
254 printf("Extra field count: %d\n", count);
255 }
256 return 0;
257}
258
259static int
260delete(int argc, char *argv[]) {
261 zip_uint64_t idx;
262 idx = strtoull(argv[0], NULL, 10);
263 if (zip_delete(za, idx) < 0) {
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200264 fprintf(stderr, "can't delete file at index '%" PRIu64 "': %s\n", idx, zip_strerror(za));
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200265 return -1;
266 }
267 return 0;
268}
269
270static int
271delete_extra(int argc, char *argv[]) {
272 zip_flags_t geflags;
273 zip_uint16_t eid;
274 zip_uint64_t idx;
275 idx = strtoull(argv[0], NULL, 10);
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200276 eid = (zip_uint16_t)strtoull(argv[1], NULL, 10);
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200277 geflags = get_flags(argv[2]);
278 if ((zip_file_extra_field_delete(za, idx, eid, geflags)) < 0) {
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200279 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 +0200280 return -1;
281 }
282 return 0;
283}
284
285static int
286delete_extra_by_id(int argc, char *argv[]) {
287 zip_flags_t geflags;
288 zip_uint16_t eid, eidx;
289 zip_uint64_t idx;
290 idx = strtoull(argv[0], NULL, 10);
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200291 eid = (zip_uint16_t)strtoull(argv[1], NULL, 10);
292 eidx = (zip_uint16_t)strtoull(argv[2], NULL, 10);
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200293 geflags = get_flags(argv[3]);
294 if ((zip_file_extra_field_delete_by_id(za, idx, eid, eidx, geflags)) < 0) {
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200295 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 +0200296 return -1;
297 }
298 return 0;
299}
300
301static int
302get_archive_comment(int argc, char *argv[]) {
303 const char *comment;
304 int len;
305 /* get archive comment */
306 if ((comment=zip_get_archive_comment(za, &len, 0)) == NULL)
307 printf("No archive comment\n");
308 else
309 printf("Archive comment: %.*s\n", len, comment);
310 return 0;
311}
312
313static int
314get_extra(int argc, char *argv[]) {
315 zip_flags_t geflags;
316 zip_uint16_t id, eidx, eflen;
317 const zip_uint8_t *efdata;
318 zip_uint64_t idx;
319 /* get extra field data */
320 idx = strtoull(argv[0], NULL, 10);
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200321 eidx = (zip_uint16_t)strtoull(argv[1], NULL, 10);
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200322 geflags = get_flags(argv[2]);
323 if ((efdata=zip_file_extra_field_get(za, idx, eidx, &id, &eflen, geflags)) == NULL) {
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200324 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 +0200325 return -1;
326 }
327 printf("Extra field 0x%04x: len %d", id, eflen);
328 if (eflen > 0) {
329 printf(", data ");
330 hexdump(efdata, eflen);
331 }
332 printf("\n");
333 return 0;
334}
335
336static int
337get_extra_by_id(int argc, char *argv[]) {
338 zip_flags_t geflags;
339 zip_uint16_t eid, eidx, eflen;
340 const zip_uint8_t *efdata;
341 zip_uint64_t idx;
342 idx = strtoull(argv[0], NULL, 10);
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200343 eid = (zip_uint16_t)strtoull(argv[1], NULL, 10);
344 eidx = (zip_uint16_t)strtoull(argv[2], NULL, 10);
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200345 geflags = get_flags(argv[3]);
346 if ((efdata=zip_file_extra_field_get_by_id(za, idx, eid, eidx, &eflen, geflags)) == NULL) {
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200347 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 +0200348 return -1;
349 }
350 printf("Extra field 0x%04x: len %d", eid, eflen);
351 if (eflen > 0) {
352 printf(", data ");
353 hexdump(efdata, eflen);
354 }
355 printf("\n");
356 return 0;
357}
358
359static int
360get_file_comment(int argc, char *argv[]) {
361 const char *comment;
362 int len;
363 zip_uint64_t idx;
364 /* get file comment */
365 idx = strtoull(argv[0], NULL, 10);
366 if ((comment=zip_get_file_comment(za, idx, &len, 0)) == NULL) {
367 fprintf(stderr, "can't get comment for '%s': %s\n", zip_get_name(za, idx, 0), zip_strerror(za));
368 return -1;
369 } else if (len == 0)
370 printf("No comment for '%s'\n", zip_get_name(za, idx, 0));
371 else
372 printf("File comment for '%s': %.*s\n", zip_get_name(za, idx, 0), len, comment);
373 return 0;
374}
375
376static int
Thomas Klausner1f7908f2015-12-30 03:24:49 +0100377get_num_entries(int argc, char *argv[]) {
Thomas Klausner59a92aa2016-01-05 14:29:05 +0100378 zip_int64_t count;
Thomas Klausner1f7908f2015-12-30 03:24:49 +0100379 zip_flags_t flags;
380 /* get number of entries in archive */
381 flags = get_flags(argv[0]);
382 count = zip_get_num_entries(za, flags);
Thomas Klausner52113b82016-01-05 15:06:27 +0100383 printf("%" PRId64 " entr%s in archive\n", count, count == 1 ? "y" : "ies");
Thomas Klausner1f7908f2015-12-30 03:24:49 +0100384 return 0;
385}
386
387static int
Thomas Klausner27c4a222014-12-10 00:47:11 +0100388name_locate(int argc, char *argv[]) {
389 zip_flags_t flags;
390 zip_int64_t idx;
391 flags = get_flags(argv[1]);
392
393 if ((idx=zip_name_locate(za, argv[0], flags)) < 0) {
394 fprintf(stderr, "can't find entry with name '%s' using flags '%s'\n", argv[0], argv[1]);
395 } else {
396 printf("name '%s' using flags '%s' found at index %" PRId64 "\n", argv[0], argv[1], idx);
Thomas Klausner28c97922016-01-12 13:48:48 +0100397 }
Thomas Klausner27c4a222014-12-10 00:47:11 +0100398
399 return 0;
400}
401
402static int
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200403zrename(int argc, char *argv[]) {
404 zip_uint64_t idx;
405 idx = strtoull(argv[0], NULL, 10);
406 if (zip_rename(za, idx, argv[1]) < 0) {
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200407 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 +0200408 return -1;
409 }
410 return 0;
411}
412
413static int
414replace_file_contents(int argc, char *argv[]) {
415 /* replace file contents with data from command line */
416 const char *content;
Dieter Baron1d9dfeb2014-09-28 23:02:54 +0200417 zip_source_t *s;
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200418 zip_uint64_t idx;
419 idx = strtoull(argv[0], NULL, 10);
420 content = argv[1];
421 if ((s=zip_source_buffer(za, content, strlen(content), 0)) == NULL ||
422 zip_file_replace(za, idx, s, 0) < 0) {
423 zip_source_free(s);
424 fprintf(stderr, "error replacing file data: %s\n", zip_strerror(za));
425 return -1;
426 }
427 return 0;
428}
429
430static int
431set_extra(int argc, char *argv[]) {
432 zip_flags_t geflags;
433 zip_uint16_t eid, eidx;
434 const zip_uint8_t *efdata;
435 zip_uint64_t idx;
436 idx = strtoull(argv[0], NULL, 10);
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200437 eid = (zip_uint16_t)strtoull(argv[1], NULL, 10);
438 eidx = (zip_uint16_t)strtoull(argv[2], NULL, 10);
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200439 geflags = get_flags(argv[3]);
440 efdata = (zip_uint8_t *)argv[4];
441 if ((zip_file_extra_field_set(za, idx, eid, eidx, efdata, (zip_uint16_t)strlen((const char *)efdata), geflags)) < 0) {
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200442 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 +0200443 return -1;
444 }
445 return 0;
446}
447
448static int
Thomas Klausner8f76c552014-12-04 13:25:04 +0100449set_archive_comment(int argc, char *argv[]) {
450 if (zip_set_archive_comment(za, argv[0], (zip_uint16_t)strlen(argv[0])) < 0) {
451 fprintf(stderr, "can't set archive comment to `%s': %s\n", argv[0], zip_strerror(za));
452 return -1;
453 }
454 return 0;
455}
456
457static int
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200458set_file_comment(int argc, char *argv[]) {
459 zip_uint64_t idx;
460 idx = strtoull(argv[0], NULL, 10);
461 if (zip_file_set_comment(za, idx, argv[1], (zip_uint16_t)strlen(argv[1]), 0) < 0) {
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200462 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 +0200463 return -1;
464 }
465 return 0;
466}
467
468static int
469set_file_compression(int argc, char *argv[]) {
470 zip_int32_t method;
471 zip_uint32_t flags;
472 zip_uint64_t idx;
473 idx = strtoull(argv[0], NULL, 10);
474 method = get_compression_method(argv[1]);
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200475 flags = (zip_uint32_t)strtoull(argv[2], NULL, 10);
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200476 if (zip_set_file_compression(za, idx, method, flags) < 0) {
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200477 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 +0200478 return -1;
479 }
480 return 0;
481}
482
483static int
484set_file_mtime(int argc, char *argv[]) {
485 /* set file last modification time (mtime) */
486 time_t mtime;
487 zip_uint64_t idx;
488 idx = strtoull(argv[0], NULL, 10);
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200489 mtime = (time_t)strtoull(argv[1], NULL, 10);
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200490 if (zip_file_set_mtime(za, idx, mtime, 0) < 0) {
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200491 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 +0200492 return -1;
493 }
494 return 0;
495}
496
497static int
Thomas Klausner35bc3262016-01-12 15:10:42 +0100498set_file_mtime_all(int argc, char *argv[]) {
499 /* set last modification time (mtime) for all files */
500 time_t mtime;
Dieter Baronedc02482016-01-21 10:07:26 +0100501 zip_int64_t num_entries;
502 zip_uint64_t idx;
Thomas Klausner35bc3262016-01-12 15:10:42 +0100503 mtime = (time_t)strtoull(argv[0], NULL, 10);
Dieter Baronedc02482016-01-21 10:07:26 +0100504
505 if ((num_entries = zip_get_num_entries(za, 0)) < 0) {
506 fprintf(stderr, "can't get number of entries: %s\n", zip_strerror(za));
507 return -1;
508 }
509 for (idx = 0; idx < (zip_uint64_t)num_entries; idx++) {
Thomas Klausner35bc3262016-01-12 15:10:42 +0100510 if (zip_file_set_mtime(za, idx, mtime, 0) < 0) {
511 fprintf(stderr, "can't set file mtime at index '%" PRIu64 "' to `%ld': %s\n", idx, mtime, zip_strerror(za));
512 return -1;
513 }
514 }
515 return 0;
516}
517
518static int
Thomas Klausnera96b85f2015-05-05 12:19:14 +0200519set_password(int argc, char *argv[]) {
520 /* set default password */
521 if (zip_set_default_password(za, argv[0]) < 0) {
522 fprintf(stderr, "can't set default password to `%s'", argv[0]);
523 return -1;
524 }
525 return 0;
526}
527
528static int
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200529zstat(int argc, char *argv[]) {
Thomas Klausner85dc6a52014-09-24 01:10:05 +0200530 zip_uint64_t idx;
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200531 char buf[100];
532 struct zip_stat sb;
Thomas Klausner85dc6a52014-09-24 01:10:05 +0200533 idx = strtoull(argv[0], NULL, 10);
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200534
Thomas Klausner85dc6a52014-09-24 01:10:05 +0200535 if (zip_stat_index(za, idx, stat_flags, &sb) < 0) {
536 fprintf(stderr, "zip_stat_index failed on '%" PRIu64 "' failed: %s\n", idx, zip_strerror(za));
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200537 return -1;
538 }
539
540 if (sb.valid & ZIP_STAT_NAME)
541 printf("name: '%s'\n", sb.name);
542 if (sb.valid & ZIP_STAT_INDEX)
543 printf("index: '%"PRIu64"'\n", sb.index);
544 if (sb.valid & ZIP_STAT_SIZE)
545 printf("size: '%"PRIu64"'\n", sb.size);
546 if (sb.valid & ZIP_STAT_COMP_SIZE)
547 printf("compressed size: '%"PRIu64"'\n", sb.comp_size);
548 if (sb.valid & ZIP_STAT_MTIME) {
549 struct tm *tpm;
550 tpm = localtime(&sb.mtime);
551 strftime(buf, sizeof(buf), "%a %b %d %Y %H:%M:%S", tpm);
552 printf("mtime: '%s'\n", buf);
553 }
554 if (sb.valid & ZIP_STAT_CRC)
555 printf("crc: '%0x'\n", sb.crc);
556 if (sb.valid & ZIP_STAT_COMP_METHOD)
557 printf("compression method: '%d'\n", sb.comp_method);
558 if (sb.valid & ZIP_STAT_ENCRYPTION_METHOD)
559 printf("encryption method: '%d'\n", sb.encryption_method);
560 if (sb.valid & ZIP_STAT_FLAGS)
561 printf("flags: '%ld'\n", (long)sb.flags);
562 printf("\n");
563
564 return 0;
565}
566
567static int
Thomas Klausner935294a2014-12-04 16:52:34 +0100568unchange_all(int argc, char *argv[]) {
569 if (zip_unchange_all(za) < 0) {
570 fprintf(stderr, "can't revert changes to archive: %s\n", zip_strerror(za));
571 return -1;
572 }
573 return 0;
574}
575
576static int
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200577zin_close(int argc, char *argv[]) {
Thomas Klausner24030de2015-04-29 15:18:35 +0200578 zip_uint64_t idx;
579
580 idx = strtoull(argv[0], NULL, 10);
581 if (idx >= z_in_count) {
Thomas Klausner380f8352015-04-29 15:31:28 +0200582 fprintf(stderr, "invalid argument '%" PRIu64 "', only %d zip sources open\n", idx, z_in_count);
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200583 return -1;
584 }
Thomas Klausner24030de2015-04-29 15:18:35 +0200585 if (zip_close(z_in[idx]) < 0) {
586 fprintf(stderr, "can't close source archive: %s\n", zip_strerror(z_in[idx]));
587 return -1;
588 }
589 z_in[idx] = z_in[z_in_count];
590 z_in_count--;
591
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200592 return 0;
593}
Thomas Klausner8cd9f822012-04-27 16:02:29 +0200594
Thomas Klausnercbb79a72013-02-25 14:15:22 +0100595static zip_flags_t
Thomas Klausner0da98c92012-10-06 22:27:17 +0200596get_flags(const char *arg)
597{
598 zip_flags_t flags = 0;
Thomas Klausner27c4a222014-12-10 00:47:11 +0100599 if (strchr(arg, 'C') != NULL)
600 flags |= ZIP_FL_NOCASE;
Thomas Klausner0da98c92012-10-06 22:27:17 +0200601 if (strchr(arg, 'c') != NULL)
602 flags |= ZIP_FL_CENTRAL;
Thomas Klausner27c4a222014-12-10 00:47:11 +0100603 if (strchr(arg, 'd') != NULL)
604 flags |= ZIP_FL_NODIR;
Thomas Klausner0da98c92012-10-06 22:27:17 +0200605 if (strchr(arg, 'l') != NULL)
606 flags |= ZIP_FL_LOCAL;
607 if (strchr(arg, 'u') != NULL)
608 flags |= ZIP_FL_UNCHANGED;
609 return flags;
610}
611
Dieter Baron4abfd5a2013-04-15 20:25:23 +0200612static zip_int32_t
613get_compression_method(const char *arg)
614{
615 if (strcmp(arg, "default") == 0)
616 return ZIP_CM_DEFAULT;
617 else if (strcmp(arg, "store") == 0)
618 return ZIP_CM_STORE;
619 else if (strcmp(arg, "deflate") ==0)
620 return ZIP_CM_DEFLATE;
Thomas Klausnerac8ca362014-12-04 17:05:09 +0100621 else if (strcmp(arg, "unknown") ==0)
622 return 99;
Thomas Klausnerb52bda02013-11-28 18:01:40 +0100623 return 0; /* TODO: error handling */
Dieter Baron4abfd5a2013-04-15 20:25:23 +0200624}
625
Thomas Klausnercbb79a72013-02-25 14:15:22 +0100626static void
Thomas Klausner0da98c92012-10-06 22:27:17 +0200627hexdump(const zip_uint8_t *data, zip_uint16_t len)
628{
629 zip_uint16_t i;
630
631 if (len <= 0)
632 return;
633
634 printf("0x");
Thomas Klausner28c97922016-01-12 13:48:48 +0100635
Thomas Klausner0da98c92012-10-06 22:27:17 +0200636 for (i=0; i<len; i++)
637 printf("%02x", data[i]);
638
Thomas Klausner28c97922016-01-12 13:48:48 +0100639 return;
Thomas Klausner0da98c92012-10-06 22:27:17 +0200640}
641
Dieter Baron91374c72014-10-09 22:14:55 +0200642
643static zip_t *
644read_hole(const char *archive, int flags, int *err)
645{
646 zip_error_t error;
647 zip_source_t *src = NULL;
Dieter Baron98bf11d2014-10-10 09:39:32 +0200648 zip_t *zs = NULL;
Thomas Klausner28c97922016-01-12 13:48:48 +0100649
Dieter Baron91374c72014-10-09 22:14:55 +0200650 zip_error_init(&error);
Thomas Klausner28c97922016-01-12 13:48:48 +0100651
Dieter Baron91374c72014-10-09 22:14:55 +0200652 if ((src = source_hole_create(archive, flags, &error)) == NULL
Dieter Baron98bf11d2014-10-10 09:39:32 +0200653 || (zs = zip_open_from_source(src, flags, &error)) == NULL) {
Dieter Baron91374c72014-10-09 22:14:55 +0200654 zip_source_free(src);
655 *err = zip_error_code_zip(&error);
656 errno = zip_error_code_system(&error);
657 }
Thomas Klausner28c97922016-01-12 13:48:48 +0100658
Dieter Baron98bf11d2014-10-10 09:39:32 +0200659 return zs;
Dieter Baron91374c72014-10-09 22:14:55 +0200660}
661
662
Dieter Baron1d9dfeb2014-09-28 23:02:54 +0200663static zip_t *
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200664read_to_memory(const char *archive, int flags, int *err, zip_source_t **srcp)
665{
666 struct stat st;
667 zip_source_t *src;
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200668 zip_t *zb;
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200669 zip_error_t error;
670
671 if (stat(archive, &st) < 0) {
672 if (errno == ENOENT) {
673 src = zip_source_buffer_create(NULL, 0, 0, &error);
674 }
675 else {
676 *err = ZIP_ER_OPEN;
677 return NULL;
678 }
679 }
680 else {
681 char *buf;
682 FILE *fp;
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200683 if ((buf=malloc((size_t)st.st_size)) == NULL) {
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200684 *err = ZIP_ER_MEMORY;
685 return NULL;
686 }
687 if ((fp=fopen(archive, "r")) == NULL) {
688 free(buf);
689 *err = ZIP_ER_READ;
690 return NULL;
691 }
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200692 if (fread(buf, (size_t)st.st_size, 1, fp) < 1) {
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200693 free(buf);
Thomas Klausner96cc48d2015-04-22 21:48:44 +0200694 fclose(fp);
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200695 *err = ZIP_ER_READ;
696 return NULL;
697 }
698 fclose(fp);
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200699 src = zip_source_buffer_create(buf, (zip_uint64_t)st.st_size, 1, &error);
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200700 if (src == NULL) {
701 free(buf);
702 }
703 }
704 if (src == NULL) {
705 *err = zip_error_code_zip(&error);
706 errno = zip_error_code_system(&error);
707 return NULL;
708 }
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200709 zb = zip_open_from_source(src, flags, &error);
710 if (zb == NULL) {
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200711 *err = zip_error_code_zip(&error);
712 errno = zip_error_code_system(&error);
713 zip_source_free(src);
714 return NULL;
715 }
716 zip_source_keep(src);
717 *srcp = src;
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200718 return zb;
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200719}
720
Dieter Baron91374c72014-10-09 22:14:55 +0200721
Dieter Baron273a1c92014-10-01 14:20:21 +0200722typedef struct source_nul {
723 zip_error_t error;
724 zip_uint64_t length;
725 zip_uint64_t offset;
726} source_nul_t;
727
728static zip_int64_t
729source_nul_cb(void *ud, void *data, zip_uint64_t length, zip_source_cmd_t command)
730{
731 source_nul_t *ctx = (source_nul_t *)ud;
Thomas Klausner28c97922016-01-12 13:48:48 +0100732
Dieter Baron273a1c92014-10-01 14:20:21 +0200733 switch (command) {
734 case ZIP_SOURCE_CLOSE:
735 return 0;
736
737 case ZIP_SOURCE_ERROR:
738 return zip_error_to_data(&ctx->error, data, length);
Thomas Klausner28c97922016-01-12 13:48:48 +0100739
Dieter Baron273a1c92014-10-01 14:20:21 +0200740 case ZIP_SOURCE_FREE:
741 free(ctx);
742 return 0;
Thomas Klausner28c97922016-01-12 13:48:48 +0100743
Dieter Baron273a1c92014-10-01 14:20:21 +0200744 case ZIP_SOURCE_OPEN:
745 ctx->offset = 0;
746 return 0;
Thomas Klausner28c97922016-01-12 13:48:48 +0100747
Dieter Baron273a1c92014-10-01 14:20:21 +0200748 case ZIP_SOURCE_READ:
Thomas Klausnerd4472902014-10-01 15:41:14 +0200749 if (length > ZIP_INT64_MAX) {
750 zip_error_set(&ctx->error, ZIP_ER_INVAL, 0);
751 return -1;
752 }
753
Dieter Baron273a1c92014-10-01 14:20:21 +0200754 if (length > ctx->length - ctx->offset) {
755 length =ctx->length - ctx->offset;
756 }
Thomas Klausner28c97922016-01-12 13:48:48 +0100757
Dieter Baron273a1c92014-10-01 14:20:21 +0200758 memset(data, 0, length);
759 ctx->offset += length;
Thomas Klausnerd4472902014-10-01 15:41:14 +0200760 return (zip_int64_t)length;
Thomas Klausner28c97922016-01-12 13:48:48 +0100761
Dieter Baron273a1c92014-10-01 14:20:21 +0200762 case ZIP_SOURCE_STAT: {
763 zip_stat_t *st = ZIP_SOURCE_GET_ARGS(zip_stat_t, data, length, &ctx->error);
Thomas Klausner28c97922016-01-12 13:48:48 +0100764
Dieter Baron273a1c92014-10-01 14:20:21 +0200765 if (st == NULL) {
766 return -1;
767 }
Thomas Klausner28c97922016-01-12 13:48:48 +0100768
Dieter Baron273a1c92014-10-01 14:20:21 +0200769 st->valid |= ZIP_STAT_SIZE;
770 st->size = ctx->length;
Thomas Klausner28c97922016-01-12 13:48:48 +0100771
Dieter Baron273a1c92014-10-01 14:20:21 +0200772 return 0;
773 }
Thomas Klausner28c97922016-01-12 13:48:48 +0100774
Dieter Baron273a1c92014-10-01 14:20:21 +0200775 case ZIP_SOURCE_SUPPORTS:
776 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);
777
778 default:
779 zip_error_set(&ctx->error, ZIP_ER_OPNOTSUPP, 0);
780 return -1;
781 }
782}
783
784static zip_source_t *
Thomas Klausnerd4472902014-10-01 15:41:14 +0200785source_nul(zip_t *zs, zip_uint64_t length)
Dieter Baron273a1c92014-10-01 14:20:21 +0200786{
787 source_nul_t *ctx;
788 zip_source_t *src;
Thomas Klausner28c97922016-01-12 13:48:48 +0100789
Dieter Baron273a1c92014-10-01 14:20:21 +0200790 if ((ctx = (source_nul_t *)malloc(sizeof(*ctx))) == NULL) {
Thomas Klausnerd4472902014-10-01 15:41:14 +0200791 zip_error_set(zip_get_error(zs), ZIP_ER_MEMORY, 0);
Dieter Baron273a1c92014-10-01 14:20:21 +0200792 return NULL;
793 }
Thomas Klausner28c97922016-01-12 13:48:48 +0100794
Dieter Baron273a1c92014-10-01 14:20:21 +0200795 zip_error_init(&ctx->error);
796 ctx->length = length;
797 ctx->offset = 0;
Thomas Klausner28c97922016-01-12 13:48:48 +0100798
Thomas Klausnerd4472902014-10-01 15:41:14 +0200799 if ((src = zip_source_function(zs, source_nul_cb, ctx)) == NULL) {
Dieter Baron273a1c92014-10-01 14:20:21 +0200800 free(ctx);
801 return NULL;
802 }
Thomas Klausner28c97922016-01-12 13:48:48 +0100803
Dieter Baron273a1c92014-10-01 14:20:21 +0200804 return src;
805}
806
807
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200808static int
809write_memory_src_to_file(const char *archive, zip_source_t *src)
810{
811 zip_stat_t zst;
812 char *buf;
813 FILE *fp;
814
815 if (zip_source_stat(src, &zst) < 0) {
816 fprintf(stderr, "zip_source_stat on buffer failed: %s\n", zip_error_strerror(zip_source_error(src)));
817 return -1;
818 }
819 if (zip_source_open(src) < 0) {
820 if (zip_error_code_zip(zip_source_error(src)) == ZIP_ER_DELETED) {
821 if (remove(archive) < 0 && errno != ENOENT) {
822 fprintf(stderr, "remove failed: %s\n", strerror(errno));
823 return -1;
824 }
825 return 0;
826 }
827 fprintf(stderr, "zip_source_open on buffer failed: %s\n", zip_error_strerror(zip_source_error(src)));
828 return -1;
829 }
830 if ((buf=malloc(zst.size)) == NULL) {
831 fprintf(stderr, "malloc failed: %s\n", strerror(errno));
832 zip_source_close(src);
833 return -1;
834 }
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200835 if (zip_source_read(src, buf, zst.size) < (zip_int64_t)zst.size) {
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200836 fprintf(stderr, "zip_source_read on buffer failed: %s\n", zip_error_strerror(zip_source_error(src)));
837 zip_source_close(src);
838 free(buf);
839 return -1;
840 }
841 zip_source_close(src);
842 if ((fp=fopen(archive, "wb")) == NULL) {
843 fprintf(stderr, "fopen failed: %s\n", strerror(errno));
844 free(buf);
845 return -1;
846 }
847 if (fwrite(buf, zst.size, 1, fp) < 1) {
848 fprintf(stderr, "fwrite failed: %s\n", strerror(errno));
849 free(buf);
Thomas Klausnerdb9cb402015-04-22 21:45:33 +0200850 fclose(fp);
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200851 return -1;
852 }
853 free(buf);
854 if (fclose(fp) != 0) {
855 fprintf(stderr, "fclose failed: %s\n", strerror(errno));
856 return -1;
857 }
858 return 0;
859}
860
861dispatch_table_t dispatch_table[] = {
862 { "add", 2, "name content", "add file called name using content", add },
863 { "add_dir", 1, "name", "add directory", add_dir },
864 { "add_file", 4, "name file_to_add offset len", "add file to archive, len bytes starting from offset", add_file },
865 { "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 +0200866 { "add_nul", 2, "name length", "add NUL bytes", add_nul },
Thomas Klausner4a41da22014-12-02 11:23:23 +0100867 { "cat", 1, "index", "output file contents to stdout", cat },
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200868 { "count_extra", 2, "index flags", "show number of extra fields for archive entry", count_extra },
869 { "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 },
870 { "delete", 1, "index", "remove entry", delete },
871 { "delete_extra", 3, "index extra_idx flags", "remove extra field", delete_extra },
872 { "delete_extra_by_id", 4, "index extra_id extra_index flags", "remove extra field of type extra_id", delete_extra_by_id },
873 { "get_archive_comment", 0, "", "show archive comment", get_archive_comment },
874 { "get_extra", 3, "index extra_index flags", "show extra field", get_extra },
875 { "get_extra_by_id", 4, "index extra_id extra_index flags", "show extra field of type extra_id", get_extra_by_id },
876 { "get_file_comment", 1, "index", "get file comment", get_file_comment },
Thomas Klausner1f7908f2015-12-30 03:24:49 +0100877 { "get_num_entries", 1, "flags", "get number of entries in archive", get_num_entries },
Thomas Klausner27c4a222014-12-10 00:47:11 +0100878 { "name_locate", 2, "name flags", "find entry in archive", name_locate },
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200879 { "rename", 2, "index name", "rename entry", zrename },
880 { "replace_file_contents", 2, "index data", "replace entry with data", replace_file_contents },
Thomas Klausner8f76c552014-12-04 13:25:04 +0100881 { "set_archive_comment", 1, "comment", "set archive comment", set_archive_comment },
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200882 { "set_extra", 5, "index extra_id extra_index flags value", "set extra field", set_extra },
883 { "set_file_comment", 2, "index comment", "set file comment", set_file_comment },
Thomas Klausnerd389a492016-01-19 12:40:39 +0100884 { "set_file_compression", 3, "index method compression_flags", "set file compression method", set_file_compression },
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200885 { "set_file_mtime", 2, "index timestamp", "set file modification time", set_file_mtime },
Thomas Klausner35bc3262016-01-12 15:10:42 +0100886 { "set_file_mtime_all", 1, "timestamp", "set file modification time for all files", set_file_mtime_all },
Thomas Klausnerafa299f2016-01-12 14:48:40 +0100887 { "set_password", 1, "password", "set default password for encryption", set_password },
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200888 { "stat", 1, "index", "print information about entry", zstat },
Thomas Klausner935294a2014-12-04 16:52:34 +0100889 { "unchange_all", 0, "", "revert all changes", unchange_all },
Thomas Klausner24030de2015-04-29 15:18:35 +0200890 { "zin_close", 1, "index", "close input zip_source (for internal tests)", zin_close }
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200891};
892
Dieter Baron98bf11d2014-10-10 09:39:32 +0200893static int
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200894dispatch(int argc, char *argv[])
895{
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200896 unsigned int i;
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200897 for (i=0; i<sizeof(dispatch_table)/sizeof(dispatch_table_t); i++) {
898 if (strcmp(dispatch_table[i].cmdline_name, argv[0]) == 0) {
899 argc--;
900 argv++;
901 /* 1 for the command, argument_count for the arguments */
902 if (argc < dispatch_table[i].argument_count) {
903 fprintf(stderr, "not enough arguments for command '%s': %d available, %d needed\n", dispatch_table[i].cmdline_name, argc, dispatch_table[i].argument_count);
904 return -1;
905 }
906 if (dispatch_table[i].function(argc, argv) == 0)
907 return 1 + dispatch_table[i].argument_count;
908 return -1;
909 }
910 }
911
912 fprintf(stderr, "unknown command '%s'\n", argv[0]);
913 return -1;
914}
915
916
Dieter Baron98bf11d2014-10-10 09:39:32 +0200917static void
Thomas Klausner5781d2f2016-01-19 12:09:40 +0100918usage(const char *progname, const char *reason)
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200919{
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200920 unsigned int i;
Thomas Klausner72f023c2016-01-19 12:02:50 +0100921 FILE *out;
Thomas Klausner5781d2f2016-01-19 12:09:40 +0100922 if (reason == NULL)
Thomas Klausner72f023c2016-01-19 12:02:50 +0100923 out = stdout;
924 else
925 out = stderr;
Thomas Klausner5781d2f2016-01-19 12:09:40 +0100926 fprintf(out, "usage: %s [-cegHhmnrst] archive command1 [args] [command2 [args] ...]\n", progname);
927 if (reason != NULL) {
928 fprintf(out, "%s\n", reason);
929 exit(1);
930 }
931
932 fprintf(out, "\nSupported options are:\n"
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200933 "\t-c\tcheck consistency\n"
934 "\t-e\terror if archive already exists (only useful with -n)\n"
935 "\t-g\tguess file name encoding (for stat)\n"
Dieter Baron91374c72014-10-09 22:14:55 +0200936 "\t-H\twrite files with holes compactly\n"
Thomas Klausner72f023c2016-01-19 12:02:50 +0100937 "\t-h\tdisplay this usage\n"
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200938 "\t-m\tread archive into memory, and modify there; write out at end\n"
Thomas Klausnerd389a492016-01-19 12:40:39 +0100939 "\t-n\tcreate archive if it doesn't exist\n"
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200940 "\t-r\tprint raw file name encoding without translation (for stat)\n"
941 "\t-s\tfollow file name convention strictly (for stat)\n"
Thomas Klausner5781d2f2016-01-19 12:09:40 +0100942 "\t-t\tdisregard current archive contents, if any\n");
Thomas Klausner72f023c2016-01-19 12:02:50 +0100943 fprintf(out, "\nSupported commands and arguments are:\n");
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200944 for (i=0; i<sizeof(dispatch_table)/sizeof(dispatch_table_t); i++) {
Thomas Klausner72f023c2016-01-19 12:02:50 +0100945 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 +0200946 }
Thomas Klausner72f023c2016-01-19 12:02:50 +0100947 fprintf(out, "\nSupported flags are:\n"
Thomas Klausner27c4a222014-12-10 00:47:11 +0100948 "\tC\tZIP_FL_NOCASE\n"
949 "\tc\tZIP_FL_CENTRAL\n"
950 "\td\tZIP_FL_NODIR\n"
951 "\tl\tZIP_FL_LOCAL\n"
952 "\tu\tZIP_FL_UNCHANGED\n");
Thomas Klausner756b7c82016-01-19 12:12:09 +0100953 fprintf(out, "\nSupported compression methods are:\n"
954 "\tdefault\n"
955 "\tdeflate\n"
956 "\tstore\n");
Thomas Klausner72f023c2016-01-19 12:02:50 +0100957 fprintf(out, "\nThe index is zero-based.\n");
Thomas Klausner5781d2f2016-01-19 12:09:40 +0100958 exit(0);
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200959}
960
Thomas Klausner89bb5fe2012-02-20 01:43:56 +0100961int
962main(int argc, char *argv[])
963{
964 const char *archive;
Dieter Baron1d9dfeb2014-09-28 23:02:54 +0200965 zip_source_t *memory_src;
Thomas Klausnerb1e93a02015-07-08 16:27:38 +0200966 unsigned int i;
967 int c, arg, err, flags;
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200968 const char *prg;
Dieter Baron91374c72014-10-09 22:14:55 +0200969 source_type_t source_type = SOURCE_TYPE_NONE;
Thomas Klausner89bb5fe2012-02-20 01:43:56 +0100970
Dieter Baronc9d42c22012-07-30 21:48:51 +0200971 flags = 0;
972 prg = argv[0];
Thomas Klausner89bb5fe2012-02-20 01:43:56 +0100973
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200974 if (argc < 2)
Thomas Klausner5781d2f2016-01-19 12:09:40 +0100975 usage(prg, "too few arguments");
Thomas Klausner89bb5fe2012-02-20 01:43:56 +0100976
Thomas Klausner72f023c2016-01-19 12:02:50 +0100977 while ((c=getopt(argc, argv, "cegHhmnrst")) != -1) {
Thomas Klausner8cd9f822012-04-27 16:02:29 +0200978 switch (c) {
979 case 'c':
980 flags |= ZIP_CHECKCONS;
981 break;
982 case 'e':
983 flags |= ZIP_EXCL;
984 break;
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200985 case 'g':
986 stat_flags = ZIP_FL_ENC_GUESS;
987 break;
Dieter Baron91374c72014-10-09 22:14:55 +0200988 case 'H':
989 source_type = SOURCE_TYPE_HOLE;
990 break;
Thomas Klausner72f023c2016-01-19 12:02:50 +0100991 case 'h':
Thomas Klausner5781d2f2016-01-19 12:09:40 +0100992 usage(prg, NULL);
Thomas Klausner72f023c2016-01-19 12:02:50 +0100993 break;
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200994 case 'm':
Dieter Baron91374c72014-10-09 22:14:55 +0200995 source_type = SOURCE_TYPE_IN_MEMORY;
996 break;
Thomas Klausner8cd9f822012-04-27 16:02:29 +0200997 case 'n':
998 flags |= ZIP_CREATE;
999 break;
Thomas Klausnerea8ba492014-09-23 16:54:47 +02001000 case 'r':
1001 stat_flags = ZIP_FL_ENC_RAW;
1002 break;
1003 case 's':
1004 stat_flags = ZIP_FL_ENC_STRICT;
1005 break;
Thomas Klausner8cd9f822012-04-27 16:02:29 +02001006 case 't':
1007 flags |= ZIP_TRUNCATE;
1008 break;
1009
1010 default:
Thomas Klausner5781d2f2016-01-19 12:09:40 +01001011 {
1012 char reason[128];
1013 snprintf(reason, sizeof(reason), "invalid option -%c", optopt);
1014 usage(prg, reason);
1015 }
Thomas Klausner8cd9f822012-04-27 16:02:29 +02001016 }
1017 }
Thomas Klausner28c97922016-01-12 13:48:48 +01001018
Dieter Baronc9d42c22012-07-30 21:48:51 +02001019 arg = optind;
Thomas Klausner8cd9f822012-04-27 16:02:29 +02001020
Thomas Klausner89bb5fe2012-02-20 01:43:56 +01001021 archive = argv[arg++];
Thomas Klausner8cd9f822012-04-27 16:02:29 +02001022
1023 if (flags == 0)
1024 flags = ZIP_CREATE;
1025
Dieter Baron91374c72014-10-09 22:14:55 +02001026 switch (source_type) {
1027 case SOURCE_TYPE_NONE:
1028 za = zip_open(archive, flags, &err);
1029 break;
Thomas Klausner28c97922016-01-12 13:48:48 +01001030
Dieter Baron91374c72014-10-09 22:14:55 +02001031 case SOURCE_TYPE_IN_MEMORY:
1032 za = read_to_memory(archive, flags, &err, &memory_src);
1033 break;
Thomas Klausner28c97922016-01-12 13:48:48 +01001034
Dieter Baron91374c72014-10-09 22:14:55 +02001035 case SOURCE_TYPE_HOLE: {
1036 za = read_hole(archive, flags, &err);
1037 break;
1038 }
Thomas Klausnerea8ba492014-09-23 16:54:47 +02001039 }
1040 if (za == NULL) {
Thomas Klausnerda1c2452014-12-02 16:01:26 +01001041 zip_error_t error;
1042 zip_error_init_with_code(&error, err);
1043 fprintf(stderr, "can't open zip archive '%s': %s\n", archive, zip_error_strerror(&error));
1044 zip_error_fini(&error);
Thomas Klausner89bb5fe2012-02-20 01:43:56 +01001045 return 1;
1046 }
1047
Thomas Klausner9b6aff12012-04-27 15:24:07 +02001048 err = 0;
Thomas Klausner89bb5fe2012-02-20 01:43:56 +01001049 while (arg < argc) {
Thomas Klausnerea8ba492014-09-23 16:54:47 +02001050 int ret;
1051 ret = dispatch(argc-arg, argv+arg);
1052 if (ret > 0) {
1053 arg += ret;
Thomas Klausner89bb5fe2012-02-20 01:43:56 +01001054 } else {
Thomas Klausner9b6aff12012-04-27 15:24:07 +02001055 err = 1;
Thomas Klausner89bb5fe2012-02-20 01:43:56 +01001056 break;
1057 }
1058 }
1059
1060 if (zip_close(za) == -1) {
Thomas Klausner73716052013-11-28 18:15:14 +01001061 fprintf(stderr, "can't close zip archive '%s': %s\n", archive, zip_strerror(za));
Thomas Klausner89bb5fe2012-02-20 01:43:56 +01001062 return 1;
1063 }
Dieter Baron91374c72014-10-09 22:14:55 +02001064 if (source_type == SOURCE_TYPE_IN_MEMORY) {
Thomas Klausnerea8ba492014-09-23 16:54:47 +02001065 if (write_memory_src_to_file(archive, memory_src) < 0) {
1066 err = 1;
1067 }
1068 zip_source_free(memory_src);
1069 }
Thomas Klausner89bb5fe2012-02-20 01:43:56 +01001070
Thomas Klausner24030de2015-04-29 15:18:35 +02001071 for (i=0; i<z_in_count; i++) {
1072 if (zip_close(z_in[i]) < 0) {
1073 err = 1;
1074 }
1075 }
1076
Thomas Klausner9b6aff12012-04-27 15:24:07 +02001077 return err;
Thomas Klausner89bb5fe2012-02-20 01:43:56 +01001078}