blob: b4fde7e63e8493d3446f4768bf41de4b47604b4c [file] [log] [blame]
Thomas Klausner89bb5fe2012-02-20 01:43:56 +01001/*
Thomas Klausner0da98c92012-10-06 22:27:17 +02002 modify.c -- test tool for modifying zip archive in multiple ways
Thomas Klausnera1415de2015-04-29 15:36:30 +02003 Copyright (C) 2012-2015 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.
20
21 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 Klausner836e2892016-01-05 14:59:38 +010043#include <inttypes.h>
Thomas Klausnerbe146cb2015-09-15 14:12:08 +020044#ifdef _WIN32
45/* WIN32 needs <fcntl.h> for _O_BINARY */
46#include <fcntl.h>
47#endif
Thomas Klausner89bb5fe2012-02-20 01:43:56 +010048
Dieter Baronabc6fd72012-07-22 15:49:45 +020049#ifndef HAVE_GETOPT
50#include "getopt.h"
51#endif
52
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);
74static void hexdump(const zip_uint8_t *data, zip_uint16_t len);
Dieter Baron1d9dfeb2014-09-28 23:02:54 +020075static zip_t *read_to_memory(const char *archive, int flags, int *err, zip_source_t **srcp);
Dieter Baron273a1c92014-10-01 14:20:21 +020076static zip_source_t *source_nul(zip_t *za, zip_uint64_t length);
Thomas Klausnerea8ba492014-09-23 16:54:47 +020077
Thomas Klausner24030de2015-04-29 15:18:35 +020078zip_t *za, *z_in[16];
Thomas Klausnerb1e93a02015-07-08 16:27:38 +020079unsigned int z_in_count;
Thomas Klausnerea8ba492014-09-23 16:54:47 +020080zip_flags_t stat_flags;
81
82static int
83add(int argc, char *argv[]) {
Dieter Baron1d9dfeb2014-09-28 23:02:54 +020084 zip_source_t *zs;
Thomas Klausnerea8ba492014-09-23 16:54:47 +020085
86 if ((zs=zip_source_buffer(za, argv[1], strlen(argv[1]), 0)) == NULL) {
87 fprintf(stderr, "can't create zip_source from buffer: %s\n", zip_strerror(za));
88 return -1;
89 }
90
91 if (zip_add(za, argv[0], zs) == -1) {
92 zip_source_free(zs);
93 fprintf(stderr, "can't add file '%s': %s\n", argv[0], zip_strerror(za));
94 return -1;
95 }
96 return 0;
97}
98
99static int
100add_dir(int argc, char *argv[]) {
101 /* add directory */
102 if (zip_add_dir(za, argv[0]) < 0) {
103 fprintf(stderr, "can't add directory '%s': %s\n", argv[0], zip_strerror(za));
104 return -1;
105 }
106 return 0;
107}
108
109static int
110add_file(int argc, char *argv[]) {
Dieter Baron1d9dfeb2014-09-28 23:02:54 +0200111 zip_source_t *zs;
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200112 zip_uint64_t start = strtoull(argv[2], NULL, 10);
113 zip_int64_t len = strtoll(argv[3], NULL, 10);
114
115 if (strcmp(argv[1], "/dev/stdin") == 0) {
116 if ((zs=zip_source_filep(za, stdin, start, len)) == NULL) {
117 fprintf(stderr, "can't create zip_source from stdin: %s\n", zip_strerror(za));
118 return -1;
119 }
120 } else {
121 if ((zs=zip_source_file(za, argv[1], start, len)) == NULL) {
122 fprintf(stderr, "can't create zip_source from file: %s\n", zip_strerror(za));
123 return -1;
124 }
125 }
126
127 if (zip_add(za, argv[0], zs) == -1) {
128 zip_source_free(zs);
129 fprintf(stderr, "can't add file '%s': %s\n", argv[0], zip_strerror(za));
130 return -1;
131 }
132 return 0;
133}
134
135static int
136add_from_zip(int argc, char *argv[]) {
Thomas Klausnerb51f6132016-01-05 14:07:07 +0100137 zip_uint64_t idx, start;
138 zip_int64_t len;
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200139 int err;
Dieter Baron1d9dfeb2014-09-28 23:02:54 +0200140 zip_source_t *zs;
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200141 /* add from another zip file */
142 idx = strtoull(argv[2], NULL, 10);
Thomas Klausnerb51f6132016-01-05 14:07:07 +0100143 start = strtoull(argv[3], NULL, 10);
144 len = strtoll(argv[4], NULL, 10);
Thomas Klausner24030de2015-04-29 15:18:35 +0200145 if ((z_in[z_in_count]=zip_open(argv[1], ZIP_CHECKCONS, &err)) == NULL) {
Thomas Klausnerda1c2452014-12-02 16:01:26 +0100146 zip_error_t error;
147 zip_error_init_with_code(&error, err);
148 fprintf(stderr, "can't open zip archive '%s': %s\n", argv[1], zip_error_strerror(&error));
149 zip_error_fini(&error);
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200150 return -1;
151 }
Thomas Klausner24030de2015-04-29 15:18:35 +0200152 if ((zs=zip_source_zip(za, z_in[z_in_count], idx, 0, start, len)) == NULL) {
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200153 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 +0200154 zip_close(z_in[z_in_count]);
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200155 return -1;
156 }
157 if (zip_add(za, argv[0], zs) == -1) {
158 fprintf(stderr, "can't add file '%s': %s\n", argv[0], zip_strerror(za));
159 zip_source_free(zs);
Thomas Klausner24030de2015-04-29 15:18:35 +0200160 zip_close(z_in[z_in_count]);
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200161 return -1;
162 }
Thomas Klausner24030de2015-04-29 15:18:35 +0200163 z_in_count++;
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200164 return 0;
165}
166
Dieter Baron98bf11d2014-10-10 09:39:32 +0200167static int
Dieter Baron273a1c92014-10-01 14:20:21 +0200168add_nul(int argc, char *argv[]) {
169 zip_source_t *zs;
170 zip_uint64_t length = strtoull(argv[1], NULL, 10);
171
172 if ((zs=source_nul(za, length)) == NULL) {
173 fprintf(stderr, "can't create zip_source for length: %s\n", zip_strerror(za));
174 return -1;
175 }
176
177 if (zip_add(za, argv[0], zs) == -1) {
178 zip_source_free(zs);
179 fprintf(stderr, "can't add file '%s': %s\n", argv[0], zip_strerror(za));
180 return -1;
181 }
182 return 0;
183}
184
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200185static int
Thomas Klausner4a41da22014-12-02 11:23:23 +0100186cat(int argc, char *argv[]) {
187 /* output file contents to stdout */
188 zip_uint64_t idx;
189 zip_int64_t n;
190 zip_file_t *zf;
191 char buf[8192];
Thomas Klausnerda1c2452014-12-02 16:01:26 +0100192 int err;
Thomas Klausner4a41da22014-12-02 11:23:23 +0100193 idx = strtoull(argv[0], NULL, 10);
194
Thomas Klausnerbe146cb2015-09-15 14:12:08 +0200195#ifdef _WIN32
196 /* Need to set stdout to binary mode for Windows */
197 setmode(fileno(stdout), _O_BINARY);
198#endif
Thomas Klausner4a41da22014-12-02 11:23:23 +0100199 if ((zf=zip_fopen_index(za, idx, 0)) == NULL) {
200 fprintf(stderr, "can't open file at index '%" PRIu64 "': %s\n", idx, zip_strerror(za));
201 return -1;
202 }
203 while ((n=zip_fread(zf, buf, sizeof(buf))) > 0) {
204 if (fwrite(buf, (size_t)n, 1, stdout) != 1) {
205 zip_fclose(zf);
206 fprintf(stderr, "can't write file contents to stdout: %s\n", strerror(errno));
207 return -1;
208 }
209 }
210 if (n == -1) {
211 zip_fclose(zf);
212 fprintf(stderr, "can't read file at index '%" PRIu64 "': %s\n", idx, zip_file_strerror(zf));
213 return -1;
214 }
Thomas Klausnerda1c2452014-12-02 16:01:26 +0100215 if ((err = zip_fclose(zf)) != 0) {
216 zip_error_t error;
217
218 zip_error_init_with_code(&error, err);
219 fprintf(stderr, "can't close file at index '%" PRIu64 "': %s\n", idx, zip_error_strerror(&error));
Thomas Klausner4a41da22014-12-02 11:23:23 +0100220 return -1;
221 }
222
223 return 0;
224}
225
226static int
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200227count_extra(int argc, char *argv[]) {
228 zip_int16_t count;
229 zip_uint64_t idx;
230 zip_flags_t ceflags = 0;
231 idx = strtoull(argv[0], NULL, 10);
232 ceflags = get_flags(argv[1]);
233 if ((count=zip_file_extra_fields_count(za, idx, ceflags)) < 0) {
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200234 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 +0200235 return -1;
236 } else {
237 printf("Extra field count: %d\n", count);
238 }
239 return 0;
240}
241
242static int
243count_extra_by_id(int argc, char *argv[]) {
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200244 zip_int16_t count;
245 zip_uint16_t eid;
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200246 zip_flags_t ceflags = 0;
247 zip_uint64_t idx;
248 idx = strtoull(argv[0], NULL, 10);
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200249 eid = (zip_uint16_t)strtoull(argv[1], NULL, 10);
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200250 ceflags = get_flags(argv[2]);
251 if ((count=zip_file_extra_fields_count_by_id(za, idx, eid, ceflags)) < 0) {
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200252 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 +0200253 return -1;
254 } else {
255 printf("Extra field count: %d\n", count);
256 }
257 return 0;
258}
259
260static int
261delete(int argc, char *argv[]) {
262 zip_uint64_t idx;
263 idx = strtoull(argv[0], NULL, 10);
264 if (zip_delete(za, idx) < 0) {
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200265 fprintf(stderr, "can't delete file at index '%" PRIu64 "': %s\n", idx, zip_strerror(za));
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200266 return -1;
267 }
268 return 0;
269}
270
271static int
272delete_extra(int argc, char *argv[]) {
273 zip_flags_t geflags;
274 zip_uint16_t eid;
275 zip_uint64_t idx;
276 idx = strtoull(argv[0], NULL, 10);
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200277 eid = (zip_uint16_t)strtoull(argv[1], NULL, 10);
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200278 geflags = get_flags(argv[2]);
279 if ((zip_file_extra_field_delete(za, idx, eid, geflags)) < 0) {
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200280 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 +0200281 return -1;
282 }
283 return 0;
284}
285
286static int
287delete_extra_by_id(int argc, char *argv[]) {
288 zip_flags_t geflags;
289 zip_uint16_t eid, eidx;
290 zip_uint64_t idx;
291 idx = strtoull(argv[0], NULL, 10);
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200292 eid = (zip_uint16_t)strtoull(argv[1], NULL, 10);
293 eidx = (zip_uint16_t)strtoull(argv[2], NULL, 10);
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200294 geflags = get_flags(argv[3]);
295 if ((zip_file_extra_field_delete_by_id(za, idx, eid, eidx, geflags)) < 0) {
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200296 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 +0200297 return -1;
298 }
299 return 0;
300}
301
302static int
303get_archive_comment(int argc, char *argv[]) {
304 const char *comment;
305 int len;
306 /* get archive comment */
307 if ((comment=zip_get_archive_comment(za, &len, 0)) == NULL)
308 printf("No archive comment\n");
309 else
310 printf("Archive comment: %.*s\n", len, comment);
311 return 0;
312}
313
314static int
315get_extra(int argc, char *argv[]) {
316 zip_flags_t geflags;
317 zip_uint16_t id, eidx, eflen;
318 const zip_uint8_t *efdata;
319 zip_uint64_t idx;
320 /* get extra field data */
321 idx = strtoull(argv[0], NULL, 10);
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200322 eidx = (zip_uint16_t)strtoull(argv[1], NULL, 10);
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200323 geflags = get_flags(argv[2]);
324 if ((efdata=zip_file_extra_field_get(za, idx, eidx, &id, &eflen, geflags)) == NULL) {
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200325 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 +0200326 return -1;
327 }
328 printf("Extra field 0x%04x: len %d", id, eflen);
329 if (eflen > 0) {
330 printf(", data ");
331 hexdump(efdata, eflen);
332 }
333 printf("\n");
334 return 0;
335}
336
337static int
338get_extra_by_id(int argc, char *argv[]) {
339 zip_flags_t geflags;
340 zip_uint16_t eid, eidx, eflen;
341 const zip_uint8_t *efdata;
342 zip_uint64_t idx;
343 idx = strtoull(argv[0], NULL, 10);
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200344 eid = (zip_uint16_t)strtoull(argv[1], NULL, 10);
345 eidx = (zip_uint16_t)strtoull(argv[2], NULL, 10);
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200346 geflags = get_flags(argv[3]);
347 if ((efdata=zip_file_extra_field_get_by_id(za, idx, eid, eidx, &eflen, geflags)) == NULL) {
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200348 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 +0200349 return -1;
350 }
351 printf("Extra field 0x%04x: len %d", eid, eflen);
352 if (eflen > 0) {
353 printf(", data ");
354 hexdump(efdata, eflen);
355 }
356 printf("\n");
357 return 0;
358}
359
360static int
361get_file_comment(int argc, char *argv[]) {
362 const char *comment;
363 int len;
364 zip_uint64_t idx;
365 /* get file comment */
366 idx = strtoull(argv[0], NULL, 10);
367 if ((comment=zip_get_file_comment(za, idx, &len, 0)) == NULL) {
368 fprintf(stderr, "can't get comment for '%s': %s\n", zip_get_name(za, idx, 0), zip_strerror(za));
369 return -1;
370 } else if (len == 0)
371 printf("No comment for '%s'\n", zip_get_name(za, idx, 0));
372 else
373 printf("File comment for '%s': %.*s\n", zip_get_name(za, idx, 0), len, comment);
374 return 0;
375}
376
377static int
Thomas Klausner1f7908f2015-12-30 03:24:49 +0100378get_num_entries(int argc, char *argv[]) {
Thomas Klausner59a92aa2016-01-05 14:29:05 +0100379 zip_int64_t count;
Thomas Klausner1f7908f2015-12-30 03:24:49 +0100380 zip_flags_t flags;
381 /* get number of entries in archive */
382 flags = get_flags(argv[0]);
383 count = zip_get_num_entries(za, flags);
Thomas Klausner52113b82016-01-05 15:06:27 +0100384 printf("%" PRId64 " entr%s in archive\n", count, count == 1 ? "y" : "ies");
Thomas Klausner1f7908f2015-12-30 03:24:49 +0100385 return 0;
386}
387
388static int
Thomas Klausner27c4a222014-12-10 00:47:11 +0100389name_locate(int argc, char *argv[]) {
390 zip_flags_t flags;
391 zip_int64_t idx;
392 flags = get_flags(argv[1]);
393
394 if ((idx=zip_name_locate(za, argv[0], flags)) < 0) {
395 fprintf(stderr, "can't find entry with name '%s' using flags '%s'\n", argv[0], argv[1]);
396 } else {
397 printf("name '%s' using flags '%s' found at index %" PRId64 "\n", argv[0], argv[1], idx);
398 }
399
400 return 0;
401}
402
403static int
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200404zrename(int argc, char *argv[]) {
405 zip_uint64_t idx;
406 idx = strtoull(argv[0], NULL, 10);
407 if (zip_rename(za, idx, argv[1]) < 0) {
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200408 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 +0200409 return -1;
410 }
411 return 0;
412}
413
414static int
415replace_file_contents(int argc, char *argv[]) {
416 /* replace file contents with data from command line */
417 const char *content;
Dieter Baron1d9dfeb2014-09-28 23:02:54 +0200418 zip_source_t *s;
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200419 zip_uint64_t idx;
420 idx = strtoull(argv[0], NULL, 10);
421 content = argv[1];
422 if ((s=zip_source_buffer(za, content, strlen(content), 0)) == NULL ||
423 zip_file_replace(za, idx, s, 0) < 0) {
424 zip_source_free(s);
425 fprintf(stderr, "error replacing file data: %s\n", zip_strerror(za));
426 return -1;
427 }
428 return 0;
429}
430
431static int
432set_extra(int argc, char *argv[]) {
433 zip_flags_t geflags;
434 zip_uint16_t eid, eidx;
435 const zip_uint8_t *efdata;
436 zip_uint64_t idx;
437 idx = strtoull(argv[0], NULL, 10);
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200438 eid = (zip_uint16_t)strtoull(argv[1], NULL, 10);
439 eidx = (zip_uint16_t)strtoull(argv[2], NULL, 10);
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200440 geflags = get_flags(argv[3]);
441 efdata = (zip_uint8_t *)argv[4];
442 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 +0200443 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 +0200444 return -1;
445 }
446 return 0;
447}
448
449static int
Thomas Klausner8f76c552014-12-04 13:25:04 +0100450set_archive_comment(int argc, char *argv[]) {
451 if (zip_set_archive_comment(za, argv[0], (zip_uint16_t)strlen(argv[0])) < 0) {
452 fprintf(stderr, "can't set archive comment to `%s': %s\n", argv[0], zip_strerror(za));
453 return -1;
454 }
455 return 0;
456}
457
458static int
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200459set_file_comment(int argc, char *argv[]) {
460 zip_uint64_t idx;
461 idx = strtoull(argv[0], NULL, 10);
462 if (zip_file_set_comment(za, idx, argv[1], (zip_uint16_t)strlen(argv[1]), 0) < 0) {
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200463 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 +0200464 return -1;
465 }
466 return 0;
467}
468
469static int
470set_file_compression(int argc, char *argv[]) {
471 zip_int32_t method;
472 zip_uint32_t flags;
473 zip_uint64_t idx;
474 idx = strtoull(argv[0], NULL, 10);
475 method = get_compression_method(argv[1]);
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200476 flags = (zip_uint32_t)strtoull(argv[2], NULL, 10);
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200477 if (zip_set_file_compression(za, idx, method, flags) < 0) {
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200478 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 +0200479 return -1;
480 }
481 return 0;
482}
483
484static int
485set_file_mtime(int argc, char *argv[]) {
486 /* set file last modification time (mtime) */
487 time_t mtime;
488 zip_uint64_t idx;
489 idx = strtoull(argv[0], NULL, 10);
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200490 mtime = (time_t)strtoull(argv[1], NULL, 10);
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200491 if (zip_file_set_mtime(za, idx, mtime, 0) < 0) {
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200492 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 +0200493 return -1;
494 }
495 return 0;
496}
497
498static int
Thomas Klausnera96b85f2015-05-05 12:19:14 +0200499set_password(int argc, char *argv[]) {
500 /* set default password */
501 if (zip_set_default_password(za, argv[0]) < 0) {
502 fprintf(stderr, "can't set default password to `%s'", argv[0]);
503 return -1;
504 }
505 return 0;
506}
507
508static int
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200509zstat(int argc, char *argv[]) {
Thomas Klausner85dc6a52014-09-24 01:10:05 +0200510 zip_uint64_t idx;
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200511 char buf[100];
512 struct zip_stat sb;
Thomas Klausner85dc6a52014-09-24 01:10:05 +0200513 idx = strtoull(argv[0], NULL, 10);
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200514
Thomas Klausner85dc6a52014-09-24 01:10:05 +0200515 if (zip_stat_index(za, idx, stat_flags, &sb) < 0) {
516 fprintf(stderr, "zip_stat_index failed on '%" PRIu64 "' failed: %s\n", idx, zip_strerror(za));
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200517 return -1;
518 }
519
520 if (sb.valid & ZIP_STAT_NAME)
521 printf("name: '%s'\n", sb.name);
522 if (sb.valid & ZIP_STAT_INDEX)
523 printf("index: '%"PRIu64"'\n", sb.index);
524 if (sb.valid & ZIP_STAT_SIZE)
525 printf("size: '%"PRIu64"'\n", sb.size);
526 if (sb.valid & ZIP_STAT_COMP_SIZE)
527 printf("compressed size: '%"PRIu64"'\n", sb.comp_size);
528 if (sb.valid & ZIP_STAT_MTIME) {
529 struct tm *tpm;
530 tpm = localtime(&sb.mtime);
531 strftime(buf, sizeof(buf), "%a %b %d %Y %H:%M:%S", tpm);
532 printf("mtime: '%s'\n", buf);
533 }
534 if (sb.valid & ZIP_STAT_CRC)
535 printf("crc: '%0x'\n", sb.crc);
536 if (sb.valid & ZIP_STAT_COMP_METHOD)
537 printf("compression method: '%d'\n", sb.comp_method);
538 if (sb.valid & ZIP_STAT_ENCRYPTION_METHOD)
539 printf("encryption method: '%d'\n", sb.encryption_method);
540 if (sb.valid & ZIP_STAT_FLAGS)
541 printf("flags: '%ld'\n", (long)sb.flags);
542 printf("\n");
543
544 return 0;
545}
546
547static int
Thomas Klausner935294a2014-12-04 16:52:34 +0100548unchange_all(int argc, char *argv[]) {
549 if (zip_unchange_all(za) < 0) {
550 fprintf(stderr, "can't revert changes to archive: %s\n", zip_strerror(za));
551 return -1;
552 }
553 return 0;
554}
555
556static int
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200557zin_close(int argc, char *argv[]) {
Thomas Klausner24030de2015-04-29 15:18:35 +0200558 zip_uint64_t idx;
559
560 idx = strtoull(argv[0], NULL, 10);
561 if (idx >= z_in_count) {
Thomas Klausner380f8352015-04-29 15:31:28 +0200562 fprintf(stderr, "invalid argument '%" PRIu64 "', only %d zip sources open\n", idx, z_in_count);
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200563 return -1;
564 }
Thomas Klausner24030de2015-04-29 15:18:35 +0200565 if (zip_close(z_in[idx]) < 0) {
566 fprintf(stderr, "can't close source archive: %s\n", zip_strerror(z_in[idx]));
567 return -1;
568 }
569 z_in[idx] = z_in[z_in_count];
570 z_in_count--;
571
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200572 return 0;
573}
Thomas Klausner8cd9f822012-04-27 16:02:29 +0200574
Thomas Klausnercbb79a72013-02-25 14:15:22 +0100575static zip_flags_t
Thomas Klausner0da98c92012-10-06 22:27:17 +0200576get_flags(const char *arg)
577{
578 zip_flags_t flags = 0;
Thomas Klausner27c4a222014-12-10 00:47:11 +0100579 if (strchr(arg, 'C') != NULL)
580 flags |= ZIP_FL_NOCASE;
Thomas Klausner0da98c92012-10-06 22:27:17 +0200581 if (strchr(arg, 'c') != NULL)
582 flags |= ZIP_FL_CENTRAL;
Thomas Klausner27c4a222014-12-10 00:47:11 +0100583 if (strchr(arg, 'd') != NULL)
584 flags |= ZIP_FL_NODIR;
Thomas Klausner0da98c92012-10-06 22:27:17 +0200585 if (strchr(arg, 'l') != NULL)
586 flags |= ZIP_FL_LOCAL;
587 if (strchr(arg, 'u') != NULL)
588 flags |= ZIP_FL_UNCHANGED;
589 return flags;
590}
591
Dieter Baron4abfd5a2013-04-15 20:25:23 +0200592static zip_int32_t
593get_compression_method(const char *arg)
594{
595 if (strcmp(arg, "default") == 0)
596 return ZIP_CM_DEFAULT;
597 else if (strcmp(arg, "store") == 0)
598 return ZIP_CM_STORE;
599 else if (strcmp(arg, "deflate") ==0)
600 return ZIP_CM_DEFLATE;
Thomas Klausnerac8ca362014-12-04 17:05:09 +0100601 else if (strcmp(arg, "unknown") ==0)
602 return 99;
Thomas Klausnerb52bda02013-11-28 18:01:40 +0100603 return 0; /* TODO: error handling */
Dieter Baron4abfd5a2013-04-15 20:25:23 +0200604}
605
Thomas Klausnercbb79a72013-02-25 14:15:22 +0100606static void
Thomas Klausner0da98c92012-10-06 22:27:17 +0200607hexdump(const zip_uint8_t *data, zip_uint16_t len)
608{
609 zip_uint16_t i;
610
611 if (len <= 0)
612 return;
613
614 printf("0x");
615
616 for (i=0; i<len; i++)
617 printf("%02x", data[i]);
618
619 return;
620}
621
Dieter Baron91374c72014-10-09 22:14:55 +0200622
623static zip_t *
624read_hole(const char *archive, int flags, int *err)
625{
626 zip_error_t error;
627 zip_source_t *src = NULL;
Dieter Baron98bf11d2014-10-10 09:39:32 +0200628 zip_t *zs = NULL;
Dieter Baron91374c72014-10-09 22:14:55 +0200629
630 zip_error_init(&error);
631
632 if ((src = source_hole_create(archive, flags, &error)) == NULL
Dieter Baron98bf11d2014-10-10 09:39:32 +0200633 || (zs = zip_open_from_source(src, flags, &error)) == NULL) {
Dieter Baron91374c72014-10-09 22:14:55 +0200634 zip_source_free(src);
635 *err = zip_error_code_zip(&error);
636 errno = zip_error_code_system(&error);
637 }
638
Dieter Baron98bf11d2014-10-10 09:39:32 +0200639 return zs;
Dieter Baron91374c72014-10-09 22:14:55 +0200640}
641
642
Dieter Baron1d9dfeb2014-09-28 23:02:54 +0200643static zip_t *
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200644read_to_memory(const char *archive, int flags, int *err, zip_source_t **srcp)
645{
646 struct stat st;
647 zip_source_t *src;
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200648 zip_t *zb;
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200649 zip_error_t error;
650
651 if (stat(archive, &st) < 0) {
652 if (errno == ENOENT) {
653 src = zip_source_buffer_create(NULL, 0, 0, &error);
654 }
655 else {
656 *err = ZIP_ER_OPEN;
657 return NULL;
658 }
659 }
660 else {
661 char *buf;
662 FILE *fp;
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200663 if ((buf=malloc((size_t)st.st_size)) == NULL) {
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200664 *err = ZIP_ER_MEMORY;
665 return NULL;
666 }
667 if ((fp=fopen(archive, "r")) == NULL) {
668 free(buf);
669 *err = ZIP_ER_READ;
670 return NULL;
671 }
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200672 if (fread(buf, (size_t)st.st_size, 1, fp) < 1) {
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200673 free(buf);
Thomas Klausner96cc48d2015-04-22 21:48:44 +0200674 fclose(fp);
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200675 *err = ZIP_ER_READ;
676 return NULL;
677 }
678 fclose(fp);
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200679 src = zip_source_buffer_create(buf, (zip_uint64_t)st.st_size, 1, &error);
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200680 if (src == NULL) {
681 free(buf);
682 }
683 }
684 if (src == NULL) {
685 *err = zip_error_code_zip(&error);
686 errno = zip_error_code_system(&error);
687 return NULL;
688 }
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200689 zb = zip_open_from_source(src, flags, &error);
690 if (zb == NULL) {
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200691 *err = zip_error_code_zip(&error);
692 errno = zip_error_code_system(&error);
693 zip_source_free(src);
694 return NULL;
695 }
696 zip_source_keep(src);
697 *srcp = src;
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200698 return zb;
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200699}
700
Dieter Baron91374c72014-10-09 22:14:55 +0200701
Dieter Baron273a1c92014-10-01 14:20:21 +0200702typedef struct source_nul {
703 zip_error_t error;
704 zip_uint64_t length;
705 zip_uint64_t offset;
706} source_nul_t;
707
708static zip_int64_t
709source_nul_cb(void *ud, void *data, zip_uint64_t length, zip_source_cmd_t command)
710{
711 source_nul_t *ctx = (source_nul_t *)ud;
712
713 switch (command) {
714 case ZIP_SOURCE_CLOSE:
715 return 0;
716
717 case ZIP_SOURCE_ERROR:
718 return zip_error_to_data(&ctx->error, data, length);
719
720 case ZIP_SOURCE_FREE:
721 free(ctx);
722 return 0;
723
724 case ZIP_SOURCE_OPEN:
725 ctx->offset = 0;
726 return 0;
727
728 case ZIP_SOURCE_READ:
Thomas Klausnerd4472902014-10-01 15:41:14 +0200729 if (length > ZIP_INT64_MAX) {
730 zip_error_set(&ctx->error, ZIP_ER_INVAL, 0);
731 return -1;
732 }
733
Dieter Baron273a1c92014-10-01 14:20:21 +0200734 if (length > ctx->length - ctx->offset) {
735 length =ctx->length - ctx->offset;
736 }
737
738 memset(data, 0, length);
739 ctx->offset += length;
Thomas Klausnerd4472902014-10-01 15:41:14 +0200740 return (zip_int64_t)length;
Dieter Baron273a1c92014-10-01 14:20:21 +0200741
742 case ZIP_SOURCE_STAT: {
743 zip_stat_t *st = ZIP_SOURCE_GET_ARGS(zip_stat_t, data, length, &ctx->error);
744
745 if (st == NULL) {
746 return -1;
747 }
748
749 st->valid |= ZIP_STAT_SIZE;
750 st->size = ctx->length;
751
752 return 0;
753 }
754
755 case ZIP_SOURCE_SUPPORTS:
756 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);
757
758 default:
759 zip_error_set(&ctx->error, ZIP_ER_OPNOTSUPP, 0);
760 return -1;
761 }
762}
763
764static zip_source_t *
Thomas Klausnerd4472902014-10-01 15:41:14 +0200765source_nul(zip_t *zs, zip_uint64_t length)
Dieter Baron273a1c92014-10-01 14:20:21 +0200766{
767 source_nul_t *ctx;
768 zip_source_t *src;
769
770 if ((ctx = (source_nul_t *)malloc(sizeof(*ctx))) == NULL) {
Thomas Klausnerd4472902014-10-01 15:41:14 +0200771 zip_error_set(zip_get_error(zs), ZIP_ER_MEMORY, 0);
Dieter Baron273a1c92014-10-01 14:20:21 +0200772 return NULL;
773 }
774
775 zip_error_init(&ctx->error);
776 ctx->length = length;
777 ctx->offset = 0;
778
Thomas Klausnerd4472902014-10-01 15:41:14 +0200779 if ((src = zip_source_function(zs, source_nul_cb, ctx)) == NULL) {
Dieter Baron273a1c92014-10-01 14:20:21 +0200780 free(ctx);
781 return NULL;
782 }
783
784 return src;
785}
786
787
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200788static int
789write_memory_src_to_file(const char *archive, zip_source_t *src)
790{
791 zip_stat_t zst;
792 char *buf;
793 FILE *fp;
794
795 if (zip_source_stat(src, &zst) < 0) {
796 fprintf(stderr, "zip_source_stat on buffer failed: %s\n", zip_error_strerror(zip_source_error(src)));
797 return -1;
798 }
799 if (zip_source_open(src) < 0) {
800 if (zip_error_code_zip(zip_source_error(src)) == ZIP_ER_DELETED) {
801 if (remove(archive) < 0 && errno != ENOENT) {
802 fprintf(stderr, "remove failed: %s\n", strerror(errno));
803 return -1;
804 }
805 return 0;
806 }
807 fprintf(stderr, "zip_source_open on buffer failed: %s\n", zip_error_strerror(zip_source_error(src)));
808 return -1;
809 }
810 if ((buf=malloc(zst.size)) == NULL) {
811 fprintf(stderr, "malloc failed: %s\n", strerror(errno));
812 zip_source_close(src);
813 return -1;
814 }
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200815 if (zip_source_read(src, buf, zst.size) < (zip_int64_t)zst.size) {
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200816 fprintf(stderr, "zip_source_read on buffer failed: %s\n", zip_error_strerror(zip_source_error(src)));
817 zip_source_close(src);
818 free(buf);
819 return -1;
820 }
821 zip_source_close(src);
822 if ((fp=fopen(archive, "wb")) == NULL) {
823 fprintf(stderr, "fopen failed: %s\n", strerror(errno));
824 free(buf);
825 return -1;
826 }
827 if (fwrite(buf, zst.size, 1, fp) < 1) {
828 fprintf(stderr, "fwrite failed: %s\n", strerror(errno));
829 free(buf);
Thomas Klausnerdb9cb402015-04-22 21:45:33 +0200830 fclose(fp);
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200831 return -1;
832 }
833 free(buf);
834 if (fclose(fp) != 0) {
835 fprintf(stderr, "fclose failed: %s\n", strerror(errno));
836 return -1;
837 }
838 return 0;
839}
840
841dispatch_table_t dispatch_table[] = {
842 { "add", 2, "name content", "add file called name using content", add },
843 { "add_dir", 1, "name", "add directory", add_dir },
844 { "add_file", 4, "name file_to_add offset len", "add file to archive, len bytes starting from offset", add_file },
845 { "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 +0200846 { "add_nul", 2, "name length", "add NUL bytes", add_nul },
Thomas Klausner4a41da22014-12-02 11:23:23 +0100847 { "cat", 1, "index", "output file contents to stdout", cat },
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200848 { "count_extra", 2, "index flags", "show number of extra fields for archive entry", count_extra },
849 { "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 },
850 { "delete", 1, "index", "remove entry", delete },
851 { "delete_extra", 3, "index extra_idx flags", "remove extra field", delete_extra },
852 { "delete_extra_by_id", 4, "index extra_id extra_index flags", "remove extra field of type extra_id", delete_extra_by_id },
853 { "get_archive_comment", 0, "", "show archive comment", get_archive_comment },
854 { "get_extra", 3, "index extra_index flags", "show extra field", get_extra },
855 { "get_extra_by_id", 4, "index extra_id extra_index flags", "show extra field of type extra_id", get_extra_by_id },
856 { "get_file_comment", 1, "index", "get file comment", get_file_comment },
Thomas Klausner1f7908f2015-12-30 03:24:49 +0100857 { "get_num_entries", 1, "flags", "get number of entries in archive", get_num_entries },
Thomas Klausner27c4a222014-12-10 00:47:11 +0100858 { "name_locate", 2, "name flags", "find entry in archive", name_locate },
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200859 { "rename", 2, "index name", "rename entry", zrename },
860 { "replace_file_contents", 2, "index data", "replace entry with data", replace_file_contents },
Thomas Klausner8f76c552014-12-04 13:25:04 +0100861 { "set_archive_comment", 1, "comment", "set archive comment", set_archive_comment },
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200862 { "set_extra", 5, "index extra_id extra_index flags value", "set extra field", set_extra },
863 { "set_file_comment", 2, "index comment", "set file comment", set_file_comment },
864 { "set_file_compression", 3, "index method flags", "set file compression method", set_file_compression },
865 { "set_file_mtime", 2, "index timestamp", "set file modification time", set_file_mtime },
Thomas Klausnera96b85f2015-05-05 12:19:14 +0200866 { "set_password", 1, "set default password", "set default password for encryption", set_password },
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200867 { "stat", 1, "index", "print information about entry", zstat },
Thomas Klausner935294a2014-12-04 16:52:34 +0100868 { "unchange_all", 0, "", "revert all changes", unchange_all },
Thomas Klausner24030de2015-04-29 15:18:35 +0200869 { "zin_close", 1, "index", "close input zip_source (for internal tests)", zin_close }
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200870};
871
Dieter Baron98bf11d2014-10-10 09:39:32 +0200872static int
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200873dispatch(int argc, char *argv[])
874{
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200875 unsigned int i;
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200876 for (i=0; i<sizeof(dispatch_table)/sizeof(dispatch_table_t); i++) {
877 if (strcmp(dispatch_table[i].cmdline_name, argv[0]) == 0) {
878 argc--;
879 argv++;
880 /* 1 for the command, argument_count for the arguments */
881 if (argc < dispatch_table[i].argument_count) {
882 fprintf(stderr, "not enough arguments for command '%s': %d available, %d needed\n", dispatch_table[i].cmdline_name, argc, dispatch_table[i].argument_count);
883 return -1;
884 }
885 if (dispatch_table[i].function(argc, argv) == 0)
886 return 1 + dispatch_table[i].argument_count;
887 return -1;
888 }
889 }
890
891 fprintf(stderr, "unknown command '%s'\n", argv[0]);
892 return -1;
893}
894
895
Dieter Baron98bf11d2014-10-10 09:39:32 +0200896static void
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200897usage(const char *progname)
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200898{
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200899 unsigned int i;
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200900 fprintf(stderr, "usage: %s [-cemnt] archive command1 [args] [command2 [args] ...]\n\n"
901 "Supported options are:\n"
902 "\t-c\tcheck consistency\n"
903 "\t-e\terror if archive already exists (only useful with -n)\n"
904 "\t-g\tguess file name encoding (for stat)\n"
Dieter Baron91374c72014-10-09 22:14:55 +0200905 "\t-H\twrite files with holes compactly\n"
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200906 "\t-m\tread archive into memory, and modify there; write out at end\n"
907 "\t-n\tcreate archive if it doesn't exist (default)\n"
908 "\t-r\tprint raw file name encoding without translation (for stat)\n"
909 "\t-s\tfollow file name convention strictly (for stat)\n"
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200910 "\t-t\tdisregard current archive contents, if any\n", progname);
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200911 fprintf(stderr, "\nSupported commands and arguments are:\n");
912 for (i=0; i<sizeof(dispatch_table)/sizeof(dispatch_table_t); i++) {
913 fprintf(stderr, "\t%s %s -- %s\n", dispatch_table[i].cmdline_name, dispatch_table[i].arg_names, dispatch_table[i].description);
914 }
Thomas Klausner27c4a222014-12-10 00:47:11 +0100915 fprintf(stderr, "\nSupported flags are:\n"
916 "\tC\tZIP_FL_NOCASE\n"
917 "\tc\tZIP_FL_CENTRAL\n"
918 "\td\tZIP_FL_NODIR\n"
919 "\tl\tZIP_FL_LOCAL\n"
920 "\tu\tZIP_FL_UNCHANGED\n");
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200921 fprintf(stderr, "\nThe index is zero-based.\n");
922 exit(1);
923}
924
Thomas Klausner89bb5fe2012-02-20 01:43:56 +0100925int
926main(int argc, char *argv[])
927{
928 const char *archive;
Dieter Baron1d9dfeb2014-09-28 23:02:54 +0200929 zip_source_t *memory_src;
Thomas Klausnerb1e93a02015-07-08 16:27:38 +0200930 unsigned int i;
931 int c, arg, err, flags;
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200932 const char *prg;
Dieter Baron91374c72014-10-09 22:14:55 +0200933 source_type_t source_type = SOURCE_TYPE_NONE;
Thomas Klausner89bb5fe2012-02-20 01:43:56 +0100934
Dieter Baronc9d42c22012-07-30 21:48:51 +0200935 flags = 0;
936 prg = argv[0];
Thomas Klausner89bb5fe2012-02-20 01:43:56 +0100937
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200938 if (argc < 2)
939 usage(prg);
Thomas Klausner89bb5fe2012-02-20 01:43:56 +0100940
Dieter Baron91374c72014-10-09 22:14:55 +0200941 while ((c=getopt(argc, argv, "cegHmnrst")) != -1) {
Thomas Klausner8cd9f822012-04-27 16:02:29 +0200942 switch (c) {
943 case 'c':
944 flags |= ZIP_CHECKCONS;
945 break;
946 case 'e':
947 flags |= ZIP_EXCL;
948 break;
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200949 case 'g':
950 stat_flags = ZIP_FL_ENC_GUESS;
951 break;
Dieter Baron91374c72014-10-09 22:14:55 +0200952 case 'H':
953 source_type = SOURCE_TYPE_HOLE;
954 break;
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200955 case 'm':
Dieter Baron91374c72014-10-09 22:14:55 +0200956 source_type = SOURCE_TYPE_IN_MEMORY;
957 break;
Thomas Klausner8cd9f822012-04-27 16:02:29 +0200958 case 'n':
959 flags |= ZIP_CREATE;
960 break;
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200961 case 'r':
962 stat_flags = ZIP_FL_ENC_RAW;
963 break;
964 case 's':
965 stat_flags = ZIP_FL_ENC_STRICT;
966 break;
Thomas Klausner8cd9f822012-04-27 16:02:29 +0200967 case 't':
968 flags |= ZIP_TRUNCATE;
969 break;
970
971 default:
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200972 usage(prg);
Thomas Klausner8cd9f822012-04-27 16:02:29 +0200973 }
974 }
Dieter Baronc9d42c22012-07-30 21:48:51 +0200975
976 arg = optind;
Thomas Klausner8cd9f822012-04-27 16:02:29 +0200977
Thomas Klausner89bb5fe2012-02-20 01:43:56 +0100978 archive = argv[arg++];
Thomas Klausner8cd9f822012-04-27 16:02:29 +0200979
980 if (flags == 0)
981 flags = ZIP_CREATE;
982
Dieter Baron91374c72014-10-09 22:14:55 +0200983 switch (source_type) {
984 case SOURCE_TYPE_NONE:
985 za = zip_open(archive, flags, &err);
986 break;
987
988 case SOURCE_TYPE_IN_MEMORY:
989 za = read_to_memory(archive, flags, &err, &memory_src);
990 break;
991
992 case SOURCE_TYPE_HOLE: {
993 za = read_hole(archive, flags, &err);
994 break;
995 }
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200996 }
997 if (za == NULL) {
Thomas Klausnerda1c2452014-12-02 16:01:26 +0100998 zip_error_t error;
999 zip_error_init_with_code(&error, err);
1000 fprintf(stderr, "can't open zip archive '%s': %s\n", archive, zip_error_strerror(&error));
1001 zip_error_fini(&error);
Thomas Klausner89bb5fe2012-02-20 01:43:56 +01001002 return 1;
1003 }
1004
Thomas Klausner9b6aff12012-04-27 15:24:07 +02001005 err = 0;
Thomas Klausner89bb5fe2012-02-20 01:43:56 +01001006 while (arg < argc) {
Thomas Klausnerea8ba492014-09-23 16:54:47 +02001007 int ret;
1008 ret = dispatch(argc-arg, argv+arg);
1009 if (ret > 0) {
1010 arg += ret;
Thomas Klausner89bb5fe2012-02-20 01:43:56 +01001011 } else {
Thomas Klausner9b6aff12012-04-27 15:24:07 +02001012 err = 1;
Thomas Klausner89bb5fe2012-02-20 01:43:56 +01001013 break;
1014 }
1015 }
1016
1017 if (zip_close(za) == -1) {
Thomas Klausner73716052013-11-28 18:15:14 +01001018 fprintf(stderr, "can't close zip archive '%s': %s\n", archive, zip_strerror(za));
Thomas Klausner89bb5fe2012-02-20 01:43:56 +01001019 return 1;
1020 }
Dieter Baron91374c72014-10-09 22:14:55 +02001021 if (source_type == SOURCE_TYPE_IN_MEMORY) {
Thomas Klausnerea8ba492014-09-23 16:54:47 +02001022 if (write_memory_src_to_file(archive, memory_src) < 0) {
1023 err = 1;
1024 }
1025 zip_source_free(memory_src);
1026 }
Thomas Klausner89bb5fe2012-02-20 01:43:56 +01001027
Thomas Klausner24030de2015-04-29 15:18:35 +02001028 for (i=0; i<z_in_count; i++) {
1029 if (zip_close(z_in[i]) < 0) {
1030 err = 1;
1031 }
1032 }
1033
Thomas Klausner9b6aff12012-04-27 15:24:07 +02001034 return err;
Thomas Klausner89bb5fe2012-02-20 01:43:56 +01001035}