2 ziptool.c -- tool for modifying zip archive in multiple ways
3 Copyright (C) 2012-2016 Dieter Baron and Thomas Klausner
5 This file is part of libzip, a library to manipulate ZIP archives.
6 The authors can be contacted at <libzip@nih.at>
8 Redistribution and use in source and binary forms, with or without
9 modification, are permitted provided that the following conditions
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
17 3. The names of the authors may not be used to endorse or promote
18 products derived from this software without specific prior
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.
44 /* WIN32 needs <fcntl.h> for _O_BINARY */
47 #define STDIN_FILENO _fileno(stdin)
59 zip_source_t *source_hole_create(const char *, int flags, zip_error_t *);
63 SOURCE_TYPE_IN_MEMORY,
67 typedef struct dispatch_table_s {
68 const char *cmdline_name;
70 const char *arg_names;
71 const char *description;
72 int (*function)(int argc, char *argv[]);
75 static zip_flags_t get_flags(const char *arg);
76 static zip_int32_t get_compression_method(const char *arg);
77 static zip_uint16_t get_encryption_method(const char *arg);
78 static void hexdump(const zip_uint8_t *data, zip_uint16_t len);
79 static zip_t *read_to_memory(const char *archive, int flags, zip_error_t *error, zip_source_t **srcp);
80 static zip_source_t *source_nul(zip_t *za, zip_uint64_t length);
83 unsigned int z_in_count;
84 zip_flags_t stat_flags;
87 add(int argc, char *argv[]) {
90 if ((zs=zip_source_buffer(za, argv[1], strlen(argv[1]), 0)) == NULL) {
91 fprintf(stderr, "can't create zip_source from buffer: %s\n", zip_strerror(za));
95 if (zip_add(za, argv[0], zs) == -1) {
97 fprintf(stderr, "can't add file '%s': %s\n", argv[0], zip_strerror(za));
104 add_dir(int argc, char *argv[]) {
106 if (zip_add_dir(za, argv[0]) < 0) {
107 fprintf(stderr, "can't add directory '%s': %s\n", argv[0], zip_strerror(za));
114 add_file(int argc, char *argv[]) {
116 zip_uint64_t start = strtoull(argv[2], NULL, 10);
117 zip_int64_t len = strtoll(argv[3], NULL, 10);
119 if (strcmp(argv[1], "/dev/stdin") == 0) {
120 if ((zs=zip_source_filep(za, stdin, start, len)) == NULL) {
121 fprintf(stderr, "can't create zip_source from stdin: %s\n", zip_strerror(za));
125 if ((zs=zip_source_file(za, argv[1], start, len)) == NULL) {
126 fprintf(stderr, "can't create zip_source from file: %s\n", zip_strerror(za));
131 if (zip_add(za, argv[0], zs) == -1) {
133 fprintf(stderr, "can't add file '%s': %s\n", argv[0], zip_strerror(za));
140 add_from_zip(int argc, char *argv[]) {
141 zip_uint64_t idx, start;
145 /* add from another zip file */
146 idx = strtoull(argv[2], NULL, 10);
147 start = strtoull(argv[3], NULL, 10);
148 len = strtoll(argv[4], NULL, 10);
149 if ((z_in[z_in_count]=zip_open(argv[1], ZIP_CHECKCONS, &err)) == NULL) {
151 zip_error_init_with_code(&error, err);
152 fprintf(stderr, "can't open zip archive '%s': %s\n", argv[1], zip_error_strerror(&error));
153 zip_error_fini(&error);
156 if ((zs=zip_source_zip(za, z_in[z_in_count], idx, 0, start, len)) == NULL) {
157 fprintf(stderr, "error creating file source from '%s' index '%" PRIu64 "': %s\n", argv[1], idx, zip_strerror(za));
158 zip_close(z_in[z_in_count]);
161 if (zip_add(za, argv[0], zs) == -1) {
162 fprintf(stderr, "can't add file '%s': %s\n", argv[0], zip_strerror(za));
164 zip_close(z_in[z_in_count]);
172 add_nul(int argc, char *argv[]) {
174 zip_uint64_t length = strtoull(argv[1], NULL, 10);
176 if ((zs=source_nul(za, length)) == NULL) {
177 fprintf(stderr, "can't create zip_source for length: %s\n", zip_strerror(za));
181 if (zip_add(za, argv[0], zs) == -1) {
183 fprintf(stderr, "can't add file '%s': %s\n", argv[0], zip_strerror(za));
190 cat(int argc, char *argv[]) {
191 /* output file contents to stdout */
197 idx = strtoull(argv[0], NULL, 10);
200 /* Need to set stdout to binary mode for Windows */
201 setmode(fileno(stdout), _O_BINARY);
203 if ((zf=zip_fopen_index(za, idx, 0)) == NULL) {
204 fprintf(stderr, "can't open file at index '%" PRIu64 "': %s\n", idx, zip_strerror(za));
207 while ((n=zip_fread(zf, buf, sizeof(buf))) > 0) {
208 if (fwrite(buf, (size_t)n, 1, stdout) != 1) {
210 fprintf(stderr, "can't write file contents to stdout: %s\n", strerror(errno));
215 fprintf(stderr, "can't read file at index '%" PRIu64 "': %s\n", idx, zip_file_strerror(zf));
219 if ((err = zip_fclose(zf)) != 0) {
222 zip_error_init_with_code(&error, err);
223 fprintf(stderr, "can't close file at index '%" PRIu64 "': %s\n", idx, zip_error_strerror(&error));
231 count_extra(int argc, char *argv[]) {
234 zip_flags_t ceflags = 0;
235 idx = strtoull(argv[0], NULL, 10);
236 ceflags = get_flags(argv[1]);
237 if ((count=zip_file_extra_fields_count(za, idx, ceflags)) < 0) {
238 fprintf(stderr, "can't get extra field count for file at index '%" PRIu64 "': %s\n", idx, zip_strerror(za));
241 printf("Extra field count: %d\n", count);
247 count_extra_by_id(int argc, char *argv[]) {
250 zip_flags_t ceflags = 0;
252 idx = strtoull(argv[0], NULL, 10);
253 eid = (zip_uint16_t)strtoull(argv[1], NULL, 10);
254 ceflags = get_flags(argv[2]);
255 if ((count=zip_file_extra_fields_count_by_id(za, idx, eid, ceflags)) < 0) {
256 fprintf(stderr, "can't get extra field count for file at index '%" PRIu64 "' and for id '%d': %s\n", idx, eid, zip_strerror(za));
259 printf("Extra field count: %d\n", count);
265 delete(int argc, char *argv[]) {
267 idx = strtoull(argv[0], NULL, 10);
268 if (zip_delete(za, idx) < 0) {
269 fprintf(stderr, "can't delete file at index '%" PRIu64 "': %s\n", idx, zip_strerror(za));
276 delete_extra(int argc, char *argv[]) {
280 idx = strtoull(argv[0], NULL, 10);
281 eid = (zip_uint16_t)strtoull(argv[1], NULL, 10);
282 geflags = get_flags(argv[2]);
283 if ((zip_file_extra_field_delete(za, idx, eid, geflags)) < 0) {
284 fprintf(stderr, "can't delete extra field data for file at index '%" PRIu64 "', extra field id '%d': %s\n", idx, eid, zip_strerror(za));
291 delete_extra_by_id(int argc, char *argv[]) {
293 zip_uint16_t eid, eidx;
295 idx = strtoull(argv[0], NULL, 10);
296 eid = (zip_uint16_t)strtoull(argv[1], NULL, 10);
297 eidx = (zip_uint16_t)strtoull(argv[2], NULL, 10);
298 geflags = get_flags(argv[3]);
299 if ((zip_file_extra_field_delete_by_id(za, idx, eid, eidx, geflags)) < 0) {
300 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));
307 get_archive_comment(int argc, char *argv[]) {
310 /* get archive comment */
311 if ((comment=zip_get_archive_comment(za, &len, 0)) == NULL)
312 printf("No archive comment\n");
314 printf("Archive comment: %.*s\n", len, comment);
319 get_extra(int argc, char *argv[]) {
321 zip_uint16_t id, eidx, eflen;
322 const zip_uint8_t *efdata;
324 /* get extra field data */
325 idx = strtoull(argv[0], NULL, 10);
326 eidx = (zip_uint16_t)strtoull(argv[1], NULL, 10);
327 geflags = get_flags(argv[2]);
328 if ((efdata=zip_file_extra_field_get(za, idx, eidx, &id, &eflen, geflags)) == NULL) {
329 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));
332 printf("Extra field 0x%04x: len %d", id, eflen);
335 hexdump(efdata, eflen);
342 get_extra_by_id(int argc, char *argv[]) {
344 zip_uint16_t eid, eidx, eflen;
345 const zip_uint8_t *efdata;
347 idx = strtoull(argv[0], NULL, 10);
348 eid = (zip_uint16_t)strtoull(argv[1], NULL, 10);
349 eidx = (zip_uint16_t)strtoull(argv[2], NULL, 10);
350 geflags = get_flags(argv[3]);
351 if ((efdata=zip_file_extra_field_get_by_id(za, idx, eid, eidx, &eflen, geflags)) == NULL) {
352 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));
355 printf("Extra field 0x%04x: len %d", eid, eflen);
358 hexdump(efdata, eflen);
365 get_file_comment(int argc, char *argv[]) {
369 /* get file comment */
370 idx = strtoull(argv[0], NULL, 10);
371 if ((comment=zip_get_file_comment(za, idx, &len, 0)) == NULL) {
372 fprintf(stderr, "can't get comment for '%s': %s\n", zip_get_name(za, idx, 0), zip_strerror(za));
375 printf("No comment for '%s'\n", zip_get_name(za, idx, 0));
377 printf("File comment for '%s': %.*s\n", zip_get_name(za, idx, 0), len, comment);
382 get_num_entries(int argc, char *argv[]) {
385 /* get number of entries in archive */
386 flags = get_flags(argv[0]);
387 count = zip_get_num_entries(za, flags);
388 printf("%" PRId64 " entr%s in archive\n", count, count == 1 ? "y" : "ies");
393 name_locate(int argc, char *argv[]) {
396 flags = get_flags(argv[1]);
398 if ((idx=zip_name_locate(za, argv[0], flags)) < 0) {
399 fprintf(stderr, "can't find entry with name '%s' using flags '%s'\n", argv[0], argv[1]);
401 printf("name '%s' using flags '%s' found at index %" PRId64 "\n", argv[0], argv[1], idx);
408 progress_callback(zip_t *za, double percentage, void *ud) {
409 printf("%.1lf%% done\n", percentage*100);
413 print_progress(int argc, char *argv[]) {
414 zip_register_progress_callback_with_state(za, 0.001, progress_callback, NULL, NULL);
419 zrename(int argc, char *argv[]) {
421 idx = strtoull(argv[0], NULL, 10);
422 if (zip_rename(za, idx, argv[1]) < 0) {
423 fprintf(stderr, "can't rename file at index '%" PRIu64 "' to '%s': %s\n", idx, argv[1], zip_strerror(za));
430 replace_file_contents(int argc, char *argv[]) {
431 /* replace file contents with data from command line */
435 idx = strtoull(argv[0], NULL, 10);
437 if ((s=zip_source_buffer(za, content, strlen(content), 0)) == NULL ||
438 zip_file_replace(za, idx, s, 0) < 0) {
440 fprintf(stderr, "error replacing file data: %s\n", zip_strerror(za));
447 set_extra(int argc, char *argv[]) {
449 zip_uint16_t eid, eidx;
450 const zip_uint8_t *efdata;
452 idx = strtoull(argv[0], NULL, 10);
453 eid = (zip_uint16_t)strtoull(argv[1], NULL, 10);
454 eidx = (zip_uint16_t)strtoull(argv[2], NULL, 10);
455 geflags = get_flags(argv[3]);
456 efdata = (zip_uint8_t *)argv[4];
457 if ((zip_file_extra_field_set(za, idx, eid, eidx, efdata, (zip_uint16_t)strlen((const char *)efdata), geflags)) < 0) {
458 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));
465 set_archive_comment(int argc, char *argv[]) {
466 if (zip_set_archive_comment(za, argv[0], (zip_uint16_t)strlen(argv[0])) < 0) {
467 fprintf(stderr, "can't set archive comment to '%s': %s\n", argv[0], zip_strerror(za));
474 set_file_comment(int argc, char *argv[]) {
476 idx = strtoull(argv[0], NULL, 10);
477 if (zip_file_set_comment(za, idx, argv[1], (zip_uint16_t)strlen(argv[1]), 0) < 0) {
478 fprintf(stderr, "can't set file comment at index '%" PRIu64 "' to '%s': %s\n", idx, argv[1], zip_strerror(za));
485 set_file_compression(int argc, char *argv[]) {
489 idx = strtoull(argv[0], NULL, 10);
490 method = get_compression_method(argv[1]);
491 flags = (zip_uint32_t)strtoull(argv[2], NULL, 10);
492 if (zip_set_file_compression(za, idx, method, flags) < 0) {
493 fprintf(stderr, "can't set file compression method at index '%" PRIu64 "' to '%s', flags '%d': %s\n", idx, argv[1], flags, zip_strerror(za));
500 set_file_encryption(int argc, char *argv[]) {
504 idx = strtoull(argv[0], NULL, 10);
505 method = get_encryption_method(argv[1]);
507 if (strlen(password) == 0) {
510 if (zip_file_set_encryption(za, idx, method, password) < 0) {
511 fprintf(stderr, "can't set file encryption method at index '%" PRIu64 "' to '%s': %s\n", idx, argv[1], zip_strerror(za));
518 set_file_mtime(int argc, char *argv[]) {
519 /* set file last modification time (mtime) */
522 idx = strtoull(argv[0], NULL, 10);
523 mtime = (time_t)strtoull(argv[1], NULL, 10);
524 if (zip_file_set_mtime(za, idx, mtime, 0) < 0) {
525 fprintf(stderr, "can't set file mtime at index '%" PRIu64 "' to '%ld': %s\n", idx, mtime, zip_strerror(za));
532 set_file_mtime_all(int argc, char *argv[]) {
533 /* set last modification time (mtime) for all files */
535 zip_int64_t num_entries;
537 mtime = (time_t)strtoull(argv[0], NULL, 10);
539 if ((num_entries = zip_get_num_entries(za, 0)) < 0) {
540 fprintf(stderr, "can't get number of entries: %s\n", zip_strerror(za));
543 for (idx = 0; idx < (zip_uint64_t)num_entries; idx++) {
544 if (zip_file_set_mtime(za, idx, mtime, 0) < 0) {
545 fprintf(stderr, "can't set file mtime at index '%" PRIu64 "' to '%ld': %s\n", idx, mtime, zip_strerror(za));
553 set_password(int argc, char *argv[]) {
554 /* set default password */
555 if (zip_set_default_password(za, argv[0]) < 0) {
556 fprintf(stderr, "can't set default password to '%s'\n", argv[0]);
563 zstat(int argc, char *argv[]) {
567 idx = strtoull(argv[0], NULL, 10);
569 if (zip_stat_index(za, idx, stat_flags, &sb) < 0) {
570 fprintf(stderr, "zip_stat_index failed on '%" PRIu64 "' failed: %s\n", idx, zip_strerror(za));
574 if (sb.valid & ZIP_STAT_NAME)
575 printf("name: '%s'\n", sb.name);
576 if (sb.valid & ZIP_STAT_INDEX)
577 printf("index: '%"PRIu64"'\n", sb.index);
578 if (sb.valid & ZIP_STAT_SIZE)
579 printf("size: '%"PRIu64"'\n", sb.size);
580 if (sb.valid & ZIP_STAT_COMP_SIZE)
581 printf("compressed size: '%"PRIu64"'\n", sb.comp_size);
582 if (sb.valid & ZIP_STAT_MTIME) {
584 tpm = localtime(&sb.mtime);
585 strftime(buf, sizeof(buf), "%a %b %d %Y %H:%M:%S", tpm);
586 printf("mtime: '%s'\n", buf);
588 if (sb.valid & ZIP_STAT_CRC)
589 printf("crc: '%0x'\n", sb.crc);
590 if (sb.valid & ZIP_STAT_COMP_METHOD)
591 printf("compression method: '%d'\n", sb.comp_method);
592 if (sb.valid & ZIP_STAT_ENCRYPTION_METHOD)
593 printf("encryption method: '%d'\n", sb.encryption_method);
594 if (sb.valid & ZIP_STAT_FLAGS)
595 printf("flags: '%ld'\n", (long)sb.flags);
602 unchange_all(int argc, char *argv[]) {
603 if (zip_unchange_all(za) < 0) {
604 fprintf(stderr, "can't revert changes to archive: %s\n", zip_strerror(za));
611 zin_close(int argc, char *argv[]) {
614 idx = strtoull(argv[0], NULL, 10);
615 if (idx >= z_in_count) {
616 fprintf(stderr, "invalid argument '%" PRIu64 "', only %d zip sources open\n", idx, z_in_count);
619 if (zip_close(z_in[idx]) < 0) {
620 fprintf(stderr, "can't close source archive: %s\n", zip_strerror(z_in[idx]));
623 z_in[idx] = z_in[z_in_count];
630 get_flags(const char *arg)
632 zip_flags_t flags = 0;
633 if (strchr(arg, 'C') != NULL)
634 flags |= ZIP_FL_NOCASE;
635 if (strchr(arg, 'c') != NULL)
636 flags |= ZIP_FL_CENTRAL;
637 if (strchr(arg, 'd') != NULL)
638 flags |= ZIP_FL_NODIR;
639 if (strchr(arg, 'l') != NULL)
640 flags |= ZIP_FL_LOCAL;
641 if (strchr(arg, 'u') != NULL)
642 flags |= ZIP_FL_UNCHANGED;
647 get_compression_method(const char *arg)
649 if (strcmp(arg, "default") == 0)
650 return ZIP_CM_DEFAULT;
651 else if (strcmp(arg, "store") == 0)
653 else if (strcmp(arg, "deflate") == 0)
654 return ZIP_CM_DEFLATE;
655 #if defined(HAVE_LIBBZ2)
656 else if (strcmp(arg, "bzip2") == 0)
659 else if (strcmp(arg, "unknown") == 0)
661 return 0; /* TODO: error handling */
665 get_encryption_method(const char *arg)
667 if (strcmp(arg, "none") == 0)
669 else if (strcmp(arg, "AES-128") == 0)
670 return ZIP_EM_AES_128;
671 else if (strcmp(arg, "AES-192") == 0)
672 return ZIP_EM_AES_192;
673 else if (strcmp(arg, "AES-256") == 0)
674 return ZIP_EM_AES_256;
675 else if (strcmp(arg, "unknown") == 0)
677 return (zip_uint16_t)-1; /* TODO: error handling */
681 hexdump(const zip_uint8_t *data, zip_uint16_t len)
690 for (i=0; i<len; i++)
691 printf("%02x", data[i]);
698 read_from_file(const char *archive, int flags, zip_error_t *error, zip_uint64_t offset, zip_uint64_t length)
701 zip_source_t *source;
704 if (offset == 0 && length == 0) {
705 if (strcmp(archive, "/dev/stdin") == 0) {
706 zaa = zip_fdopen(STDIN_FILENO, flags & ~ZIP_CREATE, &err);
709 zaa = zip_open(archive, flags, &err);
712 zip_error_set(error, err, errno);
717 if (length > ZIP_INT64_MAX) {
718 zip_error_set(error, ZIP_ER_INVAL, 0);
721 if ((source = zip_source_file_create(archive, offset, (zip_int64_t)length, error)) == NULL
722 || (zaa = zip_open_from_source(source, flags, error)) == NULL) {
723 zip_source_free(source);
733 read_hole(const char *archive, int flags, zip_error_t *error)
735 zip_source_t *src = NULL;
738 if (strcmp(archive, "/dev/stdin") == 0) {
739 zip_error_set(error, ZIP_ER_OPNOTSUPP, 0);
743 if ((src = source_hole_create(archive, flags, error)) == NULL
744 || (zs = zip_open_from_source(src, flags, error)) == NULL) {
745 zip_source_free(src);
753 read_to_memory(const char *archive, int flags, zip_error_t *error, zip_source_t **srcp)
759 if (strcmp(archive, "/dev/stdin") == 0) {
760 zip_error_set(error, ZIP_ER_OPNOTSUPP, 0);
764 if (stat(archive, &st) < 0) {
765 if (errno == ENOENT) {
766 src = zip_source_buffer_create(NULL, 0, 0, error);
769 zip_error_set(error, ZIP_ER_OPEN, errno);
776 if ((buf=malloc((size_t)st.st_size)) == NULL) {
777 zip_error_set(error, ZIP_ER_MEMORY, 0);
780 if ((fp=fopen(archive, "r")) == NULL) {
782 zip_error_set(error, ZIP_ER_READ, errno);
785 if (fread(buf, (size_t)st.st_size, 1, fp) < 1) {
788 zip_error_set(error, ZIP_ER_READ, errno);
792 src = zip_source_buffer_create(buf, (zip_uint64_t)st.st_size, 1, error);
800 zb = zip_open_from_source(src, flags, error);
802 zip_source_free(src);
805 zip_source_keep(src);
811 typedef struct source_nul {
818 source_nul_cb(void *ud, void *data, zip_uint64_t length, zip_source_cmd_t command)
820 source_nul_t *ctx = (source_nul_t *)ud;
823 case ZIP_SOURCE_CLOSE:
826 case ZIP_SOURCE_ERROR:
827 return zip_error_to_data(&ctx->error, data, length);
829 case ZIP_SOURCE_FREE:
833 case ZIP_SOURCE_OPEN:
837 case ZIP_SOURCE_READ:
838 if (length > ZIP_INT64_MAX) {
839 zip_error_set(&ctx->error, ZIP_ER_INVAL, 0);
843 if (length > ctx->length - ctx->offset) {
844 length =ctx->length - ctx->offset;
847 memset(data, 0, length);
848 ctx->offset += length;
849 return (zip_int64_t)length;
851 case ZIP_SOURCE_STAT: {
852 zip_stat_t *st = ZIP_SOURCE_GET_ARGS(zip_stat_t, data, length, &ctx->error);
858 st->valid |= ZIP_STAT_SIZE;
859 st->size = ctx->length;
864 case ZIP_SOURCE_SUPPORTS:
865 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);
868 zip_error_set(&ctx->error, ZIP_ER_OPNOTSUPP, 0);
873 static zip_source_t *
874 source_nul(zip_t *zs, zip_uint64_t length)
879 if ((ctx = (source_nul_t *)malloc(sizeof(*ctx))) == NULL) {
880 zip_error_set(zip_get_error(zs), ZIP_ER_MEMORY, 0);
884 zip_error_init(&ctx->error);
885 ctx->length = length;
888 if ((src = zip_source_function(zs, source_nul_cb, ctx)) == NULL) {
898 write_memory_src_to_file(const char *archive, zip_source_t *src)
904 if (zip_source_stat(src, &zst) < 0) {
905 fprintf(stderr, "zip_source_stat on buffer failed: %s\n", zip_error_strerror(zip_source_error(src)));
908 if (zip_source_open(src) < 0) {
909 if (zip_error_code_zip(zip_source_error(src)) == ZIP_ER_DELETED) {
910 if (unlink(archive) < 0 && errno != ENOENT) {
911 fprintf(stderr, "unlink failed: %s\n", strerror(errno));
916 fprintf(stderr, "zip_source_open on buffer failed: %s\n", zip_error_strerror(zip_source_error(src)));
919 if ((buf=malloc(zst.size)) == NULL) {
920 fprintf(stderr, "malloc failed: %s\n", strerror(errno));
921 zip_source_close(src);
924 if (zip_source_read(src, buf, zst.size) < (zip_int64_t)zst.size) {
925 fprintf(stderr, "zip_source_read on buffer failed: %s\n", zip_error_strerror(zip_source_error(src)));
926 zip_source_close(src);
930 zip_source_close(src);
931 if ((fp=fopen(archive, "wb")) == NULL) {
932 fprintf(stderr, "fopen failed: %s\n", strerror(errno));
936 if (fwrite(buf, zst.size, 1, fp) < 1) {
937 fprintf(stderr, "fwrite failed: %s\n", strerror(errno));
943 if (fclose(fp) != 0) {
944 fprintf(stderr, "fclose failed: %s\n", strerror(errno));
950 dispatch_table_t dispatch_table[] = {
951 { "add", 2, "name content", "add file called name using content", add },
952 { "add_dir", 1, "name", "add directory", add_dir },
953 { "add_file", 4, "name file_to_add offset len", "add file to archive, len bytes starting from offset", add_file },
954 { "add_from_zip", 5, "name archivename index offset len", "add file from another archive, len bytes starting from offset", add_from_zip },
955 { "add_nul", 2, "name length", "add NUL bytes", add_nul },
956 { "cat", 1, "index", "output file contents to stdout", cat },
957 { "count_extra", 2, "index flags", "show number of extra fields for archive entry", count_extra },
958 { "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 },
959 { "delete", 1, "index", "remove entry", delete },
960 { "delete_extra", 3, "index extra_idx flags", "remove extra field", delete_extra },
961 { "delete_extra_by_id", 4, "index extra_id extra_index flags", "remove extra field of type extra_id", delete_extra_by_id },
962 { "get_archive_comment", 0, "", "show archive comment", get_archive_comment },
963 { "get_extra", 3, "index extra_index flags", "show extra field", get_extra },
964 { "get_extra_by_id", 4, "index extra_id extra_index flags", "show extra field of type extra_id", get_extra_by_id },
965 { "get_file_comment", 1, "index", "get file comment", get_file_comment },
966 { "get_num_entries", 1, "flags", "get number of entries in archive", get_num_entries },
967 { "name_locate", 2, "name flags", "find entry in archive", name_locate },
968 { "print_progress", 0, "", "print progress during zip_close()", print_progress },
969 { "rename", 2, "index name", "rename entry", zrename },
970 { "replace_file_contents", 2, "index data", "replace entry with data", replace_file_contents },
971 { "set_archive_comment", 1, "comment", "set archive comment", set_archive_comment },
972 { "set_extra", 5, "index extra_id extra_index flags value", "set extra field", set_extra },
973 { "set_file_comment", 2, "index comment", "set file comment", set_file_comment },
974 { "set_file_compression", 3, "index method compression_flags", "set file compression method", set_file_compression },
975 { "set_file_encryption", 3, "index method password", "set file encryption method", set_file_encryption },
976 { "set_file_mtime", 2, "index timestamp", "set file modification time", set_file_mtime },
977 { "set_file_mtime_all", 1, "timestamp", "set file modification time for all files", set_file_mtime_all },
978 { "set_password", 1, "password", "set default password for encryption", set_password },
979 { "stat", 1, "index", "print information about entry", zstat },
980 { "unchange_all", 0, "", "revert all changes", unchange_all },
981 { "zin_close", 1, "index", "close input zip_source (for internal tests)", zin_close }
985 dispatch(int argc, char *argv[])
988 for (i=0; i<sizeof(dispatch_table)/sizeof(dispatch_table_t); i++) {
989 if (strcmp(dispatch_table[i].cmdline_name, argv[0]) == 0) {
992 /* 1 for the command, argument_count for the arguments */
993 if (argc < dispatch_table[i].argument_count) {
994 fprintf(stderr, "not enough arguments for command '%s': %d available, %d needed\n", dispatch_table[i].cmdline_name, argc, dispatch_table[i].argument_count);
997 if (dispatch_table[i].function(argc, argv) == 0)
998 return 1 + dispatch_table[i].argument_count;
1003 fprintf(stderr, "unknown command '%s'\n", argv[0]);
1009 usage(const char *progname, const char *reason)
1017 fprintf(out, "usage: %s [-cegHhmnrst] [-l len] [-o offset] archive command1 [args] [command2 [args] ...]\n", progname);
1018 if (reason != NULL) {
1019 fprintf(out, "%s\n", reason);
1023 fprintf(out, "\nSupported options are:\n"
1024 "\t-c\t\tcheck consistency\n"
1025 "\t-e\t\terror if archive already exists (only useful with -n)\n"
1026 "\t-g\t\tguess file name encoding (for stat)\n"
1027 "\t-H\t\twrite files with holes compactly\n"
1028 "\t-h\t\tdisplay this usage\n"
1029 "\t-l len\t\tonly use len bytes of file\n"
1030 "\t-m\t\tread archive into memory, and modify there; write out at end\n"
1031 "\t-n\t\tcreate archive if it doesn't exist\n"
1032 "\t-o offset\tstart reading file at offset\n"
1033 "\t-r\t\tprint raw file name encoding without translation (for stat)\n"
1034 "\t-s\t\tfollow file name convention strictly (for stat)\n"
1035 "\t-t\t\tdisregard current archive contents, if any\n");
1036 fprintf(out, "\nSupported commands and arguments are:\n");
1037 for (i=0; i<sizeof(dispatch_table)/sizeof(dispatch_table_t); i++) {
1038 fprintf(out, "\t%s %s\n\t %s\n\n", dispatch_table[i].cmdline_name, dispatch_table[i].arg_names, dispatch_table[i].description);
1040 fprintf(out, "\nSupported flags are:\n"
1042 "\tC\tZIP_FL_NOCASE\n"
1043 "\tc\tZIP_FL_CENTRAL\n"
1044 "\td\tZIP_FL_NODIR\n"
1045 "\tl\tZIP_FL_LOCAL\n"
1046 "\tu\tZIP_FL_UNCHANGED\n");
1047 fprintf(out, "\nSupported compression methods are:\n"
1049 #if defined(HAVE_LIBBZ2)
1054 fprintf(out, "\nSupported compression methods are:\n"
1059 fprintf(out, "\nThe index is zero-based.\n");
1064 main(int argc, char *argv[])
1066 const char *archive;
1067 zip_source_t *memory_src = NULL;
1069 int c, arg, err, flags;
1071 source_type_t source_type = SOURCE_TYPE_NONE;
1072 zip_uint64_t len = 0, offset = 0;
1078 while ((c=getopt(argc, argv, "cegHhl:mno:rst")) != -1) {
1081 flags |= ZIP_CHECKCONS;
1087 stat_flags = ZIP_FL_ENC_GUESS;
1090 source_type = SOURCE_TYPE_HOLE;
1096 len = strtoull(optarg, NULL, 10);
1099 source_type = SOURCE_TYPE_IN_MEMORY;
1102 flags |= ZIP_CREATE;
1105 offset = strtoull(optarg, NULL, 10);
1108 stat_flags = ZIP_FL_ENC_RAW;
1111 stat_flags = ZIP_FL_ENC_STRICT;
1114 flags |= ZIP_TRUNCATE;
1120 snprintf(reason, sizeof(reason), "invalid option -%c", optopt);
1126 if (optind >= argc-1)
1127 usage(prg, "too few arguments");
1131 archive = argv[arg++];
1136 zip_error_init(&error);
1137 switch (source_type) {
1138 case SOURCE_TYPE_NONE:
1139 za = read_from_file(archive, flags, &error, offset, len);
1142 case SOURCE_TYPE_IN_MEMORY:
1143 za = read_to_memory(archive, flags, &error, &memory_src);
1146 case SOURCE_TYPE_HOLE:
1147 za = read_hole(archive, flags, &error);
1151 fprintf(stderr, "can't open zip archive '%s': %s\n", archive, zip_error_strerror(&error));
1152 zip_error_fini(&error);
1155 zip_error_fini(&error);
1158 while (arg < argc) {
1160 ret = dispatch(argc-arg, argv+arg);
1169 if (zip_close(za) == -1) {
1170 fprintf(stderr, "can't close zip archive '%s': %s\n", archive, zip_strerror(za));
1173 if (source_type == SOURCE_TYPE_IN_MEMORY) {
1174 if (write_memory_src_to_file(archive, memory_src) < 0) {
1177 zip_source_free(memory_src);
1180 for (i=0; i<z_in_count; i++) {
1181 if (zip_close(z_in[i]) < 0) {