"Fossies" - the Fresh Open Source Software Archive

Member "libzip-1.6.0/src/ziptool.c" (24 Jan 2020, 28954 Bytes) of package /linux/misc/libzip-1.6.0.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "ziptool.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.5.2_vs_1.6.0.

    1 /*
    2   ziptool.c -- tool for modifying zip archive in multiple ways
    3   Copyright (C) 2012-2020 Dieter Baron and Thomas Klausner
    4 
    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 
   34 #include "config.h"
   35 
   36 #include <errno.h>
   37 #include <stdlib.h>
   38 #include <string.h>
   39 #include <sys/stat.h>
   40 #include <time.h>
   41 #ifdef HAVE_UNISTD_H
   42 #include <unistd.h>
   43 #endif
   44 #ifdef _WIN32
   45 /* WIN32 needs <fcntl.h> for _O_BINARY */
   46 #include <fcntl.h>
   47 #ifndef STDIN_FILENO
   48 #define STDIN_FILENO _fileno(stdin)
   49 #endif
   50 #endif
   51 
   52 #ifndef HAVE_GETOPT
   53 #include "getopt.h"
   54 #endif
   55 extern int optopt;
   56 
   57 #include "compat.h"
   58 #include "zip.h"
   59 
   60 typedef struct dispatch_table_s {
   61     const char *cmdline_name;
   62     int argument_count;
   63     const char *arg_names;
   64     const char *description;
   65     int (*function)(int argc, char *argv[]);
   66 } dispatch_table_t;
   67 
   68 static zip_flags_t get_flags(const char *arg);
   69 static zip_int32_t get_compression_method(const char *arg);
   70 static zip_uint16_t get_encryption_method(const char *arg);
   71 static void hexdump(const zip_uint8_t *data, zip_uint16_t len);
   72 int ziptool_post_close(const char *archive);
   73 
   74 #ifndef FOR_REGRESS
   75 #define OPTIONS_REGRESS ""
   76 #define USAGE_REGRESS ""
   77 #endif
   78 
   79 zip_t *za, *z_in[16];
   80 unsigned int z_in_count;
   81 zip_flags_t stat_flags;
   82 
   83 static int
   84 add(int argc, char *argv[]) {
   85     zip_source_t *zs;
   86 
   87     if ((zs = zip_source_buffer(za, argv[1], strlen(argv[1]), 0)) == NULL) {
   88     fprintf(stderr, "can't create zip_source from buffer: %s\n", zip_strerror(za));
   89     return -1;
   90     }
   91 
   92     if (zip_add(za, argv[0], zs) == -1) {
   93     zip_source_free(zs);
   94     fprintf(stderr, "can't add file '%s': %s\n", argv[0], zip_strerror(za));
   95     return -1;
   96     }
   97     return 0;
   98 }
   99 
  100 static int
  101 add_dir(int argc, char *argv[]) {
  102     /* add directory */
  103     if (zip_add_dir(za, argv[0]) < 0) {
  104     fprintf(stderr, "can't add directory '%s': %s\n", argv[0], zip_strerror(za));
  105     return -1;
  106     }
  107     return 0;
  108 }
  109 
  110 static int
  111 add_file(int argc, char *argv[]) {
  112     zip_source_t *zs;
  113     zip_uint64_t start = strtoull(argv[2], NULL, 10);
  114     zip_int64_t len = strtoll(argv[3], NULL, 10);
  115 
  116     if (strcmp(argv[1], "/dev/stdin") == 0) {
  117     if ((zs = zip_source_filep(za, stdin, start, len)) == NULL) {
  118         fprintf(stderr, "can't create zip_source from stdin: %s\n", zip_strerror(za));
  119         return -1;
  120     }
  121     }
  122     else {
  123     if ((zs = zip_source_file(za, argv[1], start, len)) == NULL) {
  124         fprintf(stderr, "can't create zip_source from file: %s\n", zip_strerror(za));
  125         return -1;
  126     }
  127     }
  128 
  129     if (zip_add(za, argv[0], zs) == -1) {
  130     zip_source_free(zs);
  131     fprintf(stderr, "can't add file '%s': %s\n", argv[0], zip_strerror(za));
  132     return -1;
  133     }
  134     return 0;
  135 }
  136 
  137 static int
  138 add_from_zip(int argc, char *argv[]) {
  139     zip_uint64_t idx, start;
  140     zip_int64_t len;
  141     int err;
  142     zip_source_t *zs;
  143     /* add from another zip file */
  144     idx = strtoull(argv[2], NULL, 10);
  145     start = strtoull(argv[3], NULL, 10);
  146     len = strtoll(argv[4], NULL, 10);
  147     if ((z_in[z_in_count] = zip_open(argv[1], ZIP_CHECKCONS, &err)) == NULL) {
  148     zip_error_t error;
  149     zip_error_init_with_code(&error, err);
  150     fprintf(stderr, "can't open zip archive '%s': %s\n", argv[1], zip_error_strerror(&error));
  151     zip_error_fini(&error);
  152     return -1;
  153     }
  154     if ((zs = zip_source_zip(za, z_in[z_in_count], idx, 0, start, len)) == NULL) {
  155     fprintf(stderr, "error creating file source from '%s' index '%" PRIu64 "': %s\n", argv[1], idx, zip_strerror(za));
  156     zip_close(z_in[z_in_count]);
  157     return -1;
  158     }
  159     if (zip_add(za, argv[0], zs) == -1) {
  160     fprintf(stderr, "can't add file '%s': %s\n", argv[0], zip_strerror(za));
  161     zip_source_free(zs);
  162     zip_close(z_in[z_in_count]);
  163     return -1;
  164     }
  165     z_in_count++;
  166     return 0;
  167 }
  168 
  169 static int
  170 cat(int argc, char *argv[]) {
  171     /* output file contents to stdout */
  172     zip_uint64_t idx;
  173     zip_int64_t n;
  174     zip_file_t *zf;
  175     char buf[8192];
  176     int err;
  177     idx = strtoull(argv[0], NULL, 10);
  178 
  179 #ifdef _WIN32
  180     /* Need to set stdout to binary mode for Windows */
  181     setmode(fileno(stdout), _O_BINARY);
  182 #endif
  183     if ((zf = zip_fopen_index(za, idx, 0)) == NULL) {
  184     fprintf(stderr, "can't open file at index '%" PRIu64 "': %s\n", idx, zip_strerror(za));
  185     return -1;
  186     }
  187     while ((n = zip_fread(zf, buf, sizeof(buf))) > 0) {
  188     if (fwrite(buf, (size_t)n, 1, stdout) != 1) {
  189         zip_fclose(zf);
  190         fprintf(stderr, "can't write file contents to stdout: %s\n", strerror(errno));
  191         return -1;
  192     }
  193     }
  194     if (n == -1) {
  195     fprintf(stderr, "can't read file at index '%" PRIu64 "': %s\n", idx, zip_file_strerror(zf));
  196     zip_fclose(zf);
  197     return -1;
  198     }
  199     if ((err = zip_fclose(zf)) != 0) {
  200     zip_error_t error;
  201 
  202     zip_error_init_with_code(&error, err);
  203     fprintf(stderr, "can't close file at index '%" PRIu64 "': %s\n", idx, zip_error_strerror(&error));
  204     return -1;
  205     }
  206 
  207     return 0;
  208 }
  209 
  210 static int
  211 count_extra(int argc, char *argv[]) {
  212     zip_int16_t count;
  213     zip_uint64_t idx;
  214     zip_flags_t ceflags = 0;
  215     idx = strtoull(argv[0], NULL, 10);
  216     ceflags = get_flags(argv[1]);
  217     if ((count = zip_file_extra_fields_count(za, idx, ceflags)) < 0) {
  218     fprintf(stderr, "can't get extra field count for file at index '%" PRIu64 "': %s\n", idx, zip_strerror(za));
  219     return -1;
  220     }
  221     else {
  222     printf("Extra field count: %d\n", count);
  223     }
  224     return 0;
  225 }
  226 
  227 static int
  228 count_extra_by_id(int argc, char *argv[]) {
  229     zip_int16_t count;
  230     zip_uint16_t eid;
  231     zip_flags_t ceflags = 0;
  232     zip_uint64_t idx;
  233     idx = strtoull(argv[0], NULL, 10);
  234     eid = (zip_uint16_t)strtoull(argv[1], NULL, 10);
  235     ceflags = get_flags(argv[2]);
  236     if ((count = zip_file_extra_fields_count_by_id(za, idx, eid, ceflags)) < 0) {
  237     fprintf(stderr, "can't get extra field count for file at index '%" PRIu64 "' and for id '%d': %s\n", idx, eid, zip_strerror(za));
  238     return -1;
  239     }
  240     else {
  241     printf("Extra field count: %d\n", count);
  242     }
  243     return 0;
  244 }
  245 
  246 static int delete (int argc, char *argv[]) {
  247     zip_uint64_t idx;
  248     idx = strtoull(argv[0], NULL, 10);
  249     if (zip_delete(za, idx) < 0) {
  250     fprintf(stderr, "can't delete file at index '%" PRIu64 "': %s\n", idx, zip_strerror(za));
  251     return -1;
  252     }
  253     return 0;
  254 }
  255 
  256 static int
  257 delete_extra(int argc, char *argv[]) {
  258     zip_flags_t geflags;
  259     zip_uint16_t eid;
  260     zip_uint64_t idx;
  261     idx = strtoull(argv[0], NULL, 10);
  262     eid = (zip_uint16_t)strtoull(argv[1], NULL, 10);
  263     geflags = get_flags(argv[2]);
  264     if ((zip_file_extra_field_delete(za, idx, eid, geflags)) < 0) {
  265     fprintf(stderr, "can't delete extra field data for file at index '%" PRIu64 "', extra field id '%d': %s\n", idx, eid, zip_strerror(za));
  266     return -1;
  267     }
  268     return 0;
  269 }
  270 
  271 static int
  272 delete_extra_by_id(int argc, char *argv[]) {
  273     zip_flags_t geflags;
  274     zip_uint16_t eid, eidx;
  275     zip_uint64_t idx;
  276     idx = strtoull(argv[0], NULL, 10);
  277     eid = (zip_uint16_t)strtoull(argv[1], NULL, 10);
  278     eidx = (zip_uint16_t)strtoull(argv[2], NULL, 10);
  279     geflags = get_flags(argv[3]);
  280     if ((zip_file_extra_field_delete_by_id(za, idx, eid, eidx, geflags)) < 0) {
  281     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));
  282     return -1;
  283     }
  284     return 0;
  285 }
  286 
  287 static int
  288 get_archive_comment(int argc, char *argv[]) {
  289     const char *comment;
  290     int len;
  291     /* get archive comment */
  292     if ((comment = zip_get_archive_comment(za, &len, 0)) == NULL)
  293     printf("No archive comment\n");
  294     else
  295     printf("Archive comment: %.*s\n", len, comment);
  296     return 0;
  297 }
  298 
  299 static int
  300 get_extra(int argc, char *argv[]) {
  301     zip_flags_t geflags;
  302     zip_uint16_t id, eidx, eflen;
  303     const zip_uint8_t *efdata;
  304     zip_uint64_t idx;
  305     /* get extra field data */
  306     idx = strtoull(argv[0], NULL, 10);
  307     eidx = (zip_uint16_t)strtoull(argv[1], NULL, 10);
  308     geflags = get_flags(argv[2]);
  309     if ((efdata = zip_file_extra_field_get(za, idx, eidx, &id, &eflen, geflags)) == NULL) {
  310     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));
  311     return -1;
  312     }
  313     printf("Extra field 0x%04x: len %d", id, eflen);
  314     if (eflen > 0) {
  315     printf(", data ");
  316     hexdump(efdata, eflen);
  317     }
  318     printf("\n");
  319     return 0;
  320 }
  321 
  322 static int
  323 get_extra_by_id(int argc, char *argv[]) {
  324     zip_flags_t geflags;
  325     zip_uint16_t eid, eidx, eflen;
  326     const zip_uint8_t *efdata;
  327     zip_uint64_t idx;
  328     idx = strtoull(argv[0], NULL, 10);
  329     eid = (zip_uint16_t)strtoull(argv[1], NULL, 10);
  330     eidx = (zip_uint16_t)strtoull(argv[2], NULL, 10);
  331     geflags = get_flags(argv[3]);
  332     if ((efdata = zip_file_extra_field_get_by_id(za, idx, eid, eidx, &eflen, geflags)) == NULL) {
  333     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));
  334     return -1;
  335     }
  336     printf("Extra field 0x%04x: len %d", eid, eflen);
  337     if (eflen > 0) {
  338     printf(", data ");
  339     hexdump(efdata, eflen);
  340     }
  341     printf("\n");
  342     return 0;
  343 }
  344 
  345 static int
  346 get_file_comment(int argc, char *argv[]) {
  347     const char *comment;
  348     int len;
  349     zip_uint64_t idx;
  350     /* get file comment */
  351     idx = strtoull(argv[0], NULL, 10);
  352     if ((comment = zip_get_file_comment(za, idx, &len, 0)) == NULL) {
  353     fprintf(stderr, "can't get comment for '%s': %s\n", zip_get_name(za, idx, 0), zip_strerror(za));
  354     return -1;
  355     }
  356     else if (len == 0)
  357     printf("No comment for '%s'\n", zip_get_name(za, idx, 0));
  358     else
  359     printf("File comment for '%s': %.*s\n", zip_get_name(za, idx, 0), len, comment);
  360     return 0;
  361 }
  362 
  363 static int
  364 get_num_entries(int argc, char *argv[]) {
  365     zip_int64_t count;
  366     zip_flags_t flags;
  367     /* get number of entries in archive */
  368     flags = get_flags(argv[0]);
  369     count = zip_get_num_entries(za, flags);
  370     printf("%" PRId64 " entr%s in archive\n", count, count == 1 ? "y" : "ies");
  371     return 0;
  372 }
  373 
  374 static int
  375 name_locate(int argc, char *argv[]) {
  376     zip_flags_t flags;
  377     zip_int64_t idx;
  378     flags = get_flags(argv[1]);
  379 
  380     if ((idx = zip_name_locate(za, argv[0], flags)) < 0) {
  381     fprintf(stderr, "can't find entry with name '%s' using flags '%s'\n", argv[0], argv[1]);
  382     }
  383     else {
  384     printf("name '%s' using flags '%s' found at index %" PRId64 "\n", argv[0], argv[1], idx);
  385     }
  386 
  387     return 0;
  388 }
  389 
  390 struct progress_userdata_s {
  391   double percentage;
  392   double limit;
  393 };
  394 
  395 struct progress_userdata_s progress_userdata;
  396 
  397 static void
  398 progress_callback(zip_t *archive, double percentage, void *ud) {
  399     printf("%.1lf%% done\n", percentage * 100);
  400     progress_userdata.percentage = percentage;
  401 }
  402 
  403 static int
  404 print_progress(int argc, char *argv[]) {
  405     zip_register_progress_callback_with_state(za, 0.001, progress_callback, NULL, NULL);
  406     return 0;
  407 }
  408 
  409 static int
  410 zrename(int argc, char *argv[]) {
  411     zip_uint64_t idx;
  412     idx = strtoull(argv[0], NULL, 10);
  413     if (zip_rename(za, idx, argv[1]) < 0) {
  414     fprintf(stderr, "can't rename file at index '%" PRIu64 "' to '%s': %s\n", idx, argv[1], zip_strerror(za));
  415     return -1;
  416     }
  417     return 0;
  418 }
  419 
  420 static int
  421 replace_file_contents(int argc, char *argv[]) {
  422     /* replace file contents with data from command line */
  423     const char *content;
  424     zip_source_t *s;
  425     zip_uint64_t idx;
  426     idx = strtoull(argv[0], NULL, 10);
  427     content = argv[1];
  428     if ((s = zip_source_buffer(za, content, strlen(content), 0)) == NULL || zip_file_replace(za, idx, s, 0) < 0) {
  429     zip_source_free(s);
  430     fprintf(stderr, "error replacing file data: %s\n", zip_strerror(za));
  431     return -1;
  432     }
  433     return 0;
  434 }
  435 
  436 static int
  437 set_extra(int argc, char *argv[]) {
  438     zip_flags_t geflags;
  439     zip_uint16_t eid, eidx;
  440     const zip_uint8_t *efdata;
  441     zip_uint64_t idx;
  442     idx = strtoull(argv[0], NULL, 10);
  443     eid = (zip_uint16_t)strtoull(argv[1], NULL, 10);
  444     eidx = (zip_uint16_t)strtoull(argv[2], NULL, 10);
  445     geflags = get_flags(argv[3]);
  446     efdata = (zip_uint8_t *)argv[4];
  447     if ((zip_file_extra_field_set(za, idx, eid, eidx, efdata, (zip_uint16_t)strlen((const char *)efdata), geflags)) < 0) {
  448     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));
  449     return -1;
  450     }
  451     return 0;
  452 }
  453 
  454 static int
  455 set_archive_comment(int argc, char *argv[]) {
  456     if (zip_set_archive_comment(za, argv[0], (zip_uint16_t)strlen(argv[0])) < 0) {
  457     fprintf(stderr, "can't set archive comment to '%s': %s\n", argv[0], zip_strerror(za));
  458     return -1;
  459     }
  460     return 0;
  461 }
  462 
  463 static int
  464 set_file_comment(int argc, char *argv[]) {
  465     zip_uint64_t idx;
  466     idx = strtoull(argv[0], NULL, 10);
  467     if (zip_file_set_comment(za, idx, argv[1], (zip_uint16_t)strlen(argv[1]), 0) < 0) {
  468     fprintf(stderr, "can't set file comment at index '%" PRIu64 "' to '%s': %s\n", idx, argv[1], zip_strerror(za));
  469     return -1;
  470     }
  471     return 0;
  472 }
  473 
  474 static int
  475 set_file_compression(int argc, char *argv[]) {
  476     zip_int32_t method;
  477     zip_uint32_t flags;
  478     zip_uint64_t idx;
  479     idx = strtoull(argv[0], NULL, 10);
  480     method = get_compression_method(argv[1]);
  481     flags = (zip_uint32_t)strtoull(argv[2], NULL, 10);
  482     if (zip_set_file_compression(za, idx, method, flags) < 0) {
  483     fprintf(stderr, "can't set file compression method at index '%" PRIu64 "' to '%s', flags '%d': %s\n", idx, argv[1], flags, zip_strerror(za));
  484     return -1;
  485     }
  486     return 0;
  487 }
  488 
  489 static int
  490 set_file_encryption(int argc, char *argv[]) {
  491     zip_uint16_t method;
  492     zip_uint64_t idx;
  493     char *password;
  494     idx = strtoull(argv[0], NULL, 10);
  495     method = get_encryption_method(argv[1]);
  496     password = argv[2];
  497     if (strlen(password) == 0) {
  498     password = NULL;
  499     }
  500     if (zip_file_set_encryption(za, idx, method, password) < 0) {
  501     fprintf(stderr, "can't set file encryption method at index '%" PRIu64 "' to '%s': %s\n", idx, argv[1], zip_strerror(za));
  502     return -1;
  503     }
  504     return 0;
  505 }
  506 
  507 static int
  508 set_file_dostime(int argc, char *argv[]) {
  509     /* set file last modification time (mtime) directly */
  510     time_t mtime;
  511     zip_uint16_t dostime, dosdate;
  512     zip_uint64_t idx;
  513     idx = strtoull(argv[0], NULL, 10);
  514     dostime = (time_t)strtoull(argv[1], NULL, 10);
  515     dosdate = (time_t)strtoull(argv[2], NULL, 10);
  516     if (zip_file_set_dostime(za, idx, dostime, dosdate, 0) < 0) {
  517     fprintf(stderr, "can't set file dostime at index '%" PRIu64 "' to '%d'/'%d': %s\n", idx, (int)dostime, (int)dosdate, zip_strerror(za));
  518     return -1;
  519     }
  520     return 0;
  521 }
  522 
  523 static int
  524 set_file_mtime(int argc, char *argv[]) {
  525     /* set file last modification time (mtime) */
  526     time_t mtime;
  527     zip_uint64_t idx;
  528     idx = strtoull(argv[0], NULL, 10);
  529     mtime = (time_t)strtoull(argv[1], NULL, 10);
  530     if (zip_file_set_mtime(za, idx, mtime, 0) < 0) {
  531     fprintf(stderr, "can't set file mtime at index '%" PRIu64 "' to '%lld': %s\n", idx, (long long)mtime, zip_strerror(za));
  532     return -1;
  533     }
  534     return 0;
  535 }
  536 
  537 static int
  538 set_file_mtime_all(int argc, char *argv[]) {
  539     /* set last modification time (mtime) for all files */
  540     time_t mtime;
  541     zip_int64_t num_entries;
  542     zip_uint64_t idx;
  543     mtime = (time_t)strtoull(argv[0], NULL, 10);
  544 
  545     if ((num_entries = zip_get_num_entries(za, 0)) < 0) {
  546     fprintf(stderr, "can't get number of entries: %s\n", zip_strerror(za));
  547     return -1;
  548     }
  549     for (idx = 0; idx < (zip_uint64_t)num_entries; idx++) {
  550     if (zip_file_set_mtime(za, idx, mtime, 0) < 0) {
  551         fprintf(stderr, "can't set file mtime at index '%" PRIu64 "' to '%lld': %s\n", idx, (long long)mtime, zip_strerror(za));
  552         return -1;
  553     }
  554     }
  555     return 0;
  556 }
  557 
  558 static int
  559 set_password(int argc, char *argv[]) {
  560     /* set default password */
  561     if (zip_set_default_password(za, argv[0]) < 0) {
  562     fprintf(stderr, "can't set default password to '%s'\n", argv[0]);
  563     return -1;
  564     }
  565     return 0;
  566 }
  567 
  568 static int
  569 zstat(int argc, char *argv[]) {
  570     zip_uint64_t idx;
  571     char buf[100];
  572     struct zip_stat sb;
  573     idx = strtoull(argv[0], NULL, 10);
  574 
  575     if (zip_stat_index(za, idx, stat_flags, &sb) < 0) {
  576     fprintf(stderr, "zip_stat_index failed on '%" PRIu64 "' failed: %s\n", idx, zip_strerror(za));
  577     return -1;
  578     }
  579 
  580     if (sb.valid & ZIP_STAT_NAME)
  581     printf("name: '%s'\n", sb.name);
  582     if (sb.valid & ZIP_STAT_INDEX)
  583     printf("index: '%" PRIu64 "'\n", sb.index);
  584     if (sb.valid & ZIP_STAT_SIZE)
  585     printf("size: '%" PRIu64 "'\n", sb.size);
  586     if (sb.valid & ZIP_STAT_COMP_SIZE)
  587     printf("compressed size: '%" PRIu64 "'\n", sb.comp_size);
  588     if (sb.valid & ZIP_STAT_MTIME) {
  589     struct tm *tpm;
  590 #ifdef HAVE_LOCALTIME_R
  591     struct tm tm;
  592     tpm = localtime_r(&sb.mtime, &tm);
  593 #else
  594     tpm = localtime(&sb.mtime);
  595 #endif
  596     if (tpm == NULL) {
  597         printf("mtime: <not valid>\n");
  598     } else {
  599         strftime(buf, sizeof(buf), "%a %b %d %Y %H:%M:%S", tpm);
  600         printf("mtime: '%s'\n", buf);
  601     }
  602     }
  603     if (sb.valid & ZIP_STAT_CRC)
  604     printf("crc: '%0x'\n", sb.crc);
  605     if (sb.valid & ZIP_STAT_COMP_METHOD)
  606     printf("compression method: '%d'\n", sb.comp_method);
  607     if (sb.valid & ZIP_STAT_ENCRYPTION_METHOD)
  608     printf("encryption method: '%d'\n", sb.encryption_method);
  609     if (sb.valid & ZIP_STAT_FLAGS)
  610     printf("flags: '%ld'\n", (long)sb.flags);
  611     printf("\n");
  612 
  613     return 0;
  614 }
  615 
  616 static zip_flags_t
  617 get_flags(const char *arg) {
  618     zip_flags_t flags = 0;
  619     if (strchr(arg, 'C') != NULL)
  620     flags |= ZIP_FL_NOCASE;
  621     if (strchr(arg, 'c') != NULL)
  622     flags |= ZIP_FL_CENTRAL;
  623     if (strchr(arg, 'd') != NULL)
  624     flags |= ZIP_FL_NODIR;
  625     if (strchr(arg, 'l') != NULL)
  626     flags |= ZIP_FL_LOCAL;
  627     if (strchr(arg, 'u') != NULL)
  628     flags |= ZIP_FL_UNCHANGED;
  629     return flags;
  630 }
  631 
  632 static zip_int32_t
  633 get_compression_method(const char *arg) {
  634     if (strcmp(arg, "default") == 0)
  635     return ZIP_CM_DEFAULT;
  636     else if (strcmp(arg, "store") == 0)
  637     return ZIP_CM_STORE;
  638     else if (strcmp(arg, "deflate") == 0)
  639     return ZIP_CM_DEFLATE;
  640 #if defined(HAVE_LIBBZ2)
  641     else if (strcmp(arg, "bzip2") == 0)
  642     return ZIP_CM_BZIP2;
  643 #endif
  644 #if defined(HAVE_LIBLZMA)
  645 /*  Disabled - because 7z isn't able to unpack ZIP+LZMA ZIP+LZMA2
  646     archives made this way - and vice versa.
  647 
  648     else if (strcmp(arg, "lzma") == 0)
  649       return ZIP_CM_LZMA;
  650     else if (strcmp(arg, "lzma2") == 0)
  651       return ZIP_CM_LZMA2;
  652 */
  653     else if (strcmp(arg, "xz") == 0)
  654       return ZIP_CM_XZ;
  655 
  656 #endif
  657     else if (strcmp(arg, "unknown") == 0)
  658     return 100;
  659     return 0; /* TODO: error handling */
  660 }
  661 
  662 static zip_uint16_t
  663 get_encryption_method(const char *arg) {
  664     if (strcmp(arg, "none") == 0)
  665     return ZIP_EM_NONE;
  666     else if (strcmp(arg, "AES-128") == 0)
  667     return ZIP_EM_AES_128;
  668     else if (strcmp(arg, "AES-192") == 0)
  669     return ZIP_EM_AES_192;
  670     else if (strcmp(arg, "AES-256") == 0)
  671     return ZIP_EM_AES_256;
  672     else if (strcmp(arg, "unknown") == 0)
  673     return 100;
  674     return (zip_uint16_t)-1; /* TODO: error handling */
  675 }
  676 
  677 static void
  678 hexdump(const zip_uint8_t *data, zip_uint16_t len) {
  679     zip_uint16_t i;
  680 
  681     if (len <= 0)
  682     return;
  683 
  684     printf("0x");
  685 
  686     for (i = 0; i < len; i++)
  687     printf("%02x", data[i]);
  688 
  689     return;
  690 }
  691 
  692 
  693 static zip_t *
  694 read_from_file(const char *archive, int flags, zip_error_t *error, zip_uint64_t offset, zip_uint64_t length) {
  695     zip_t *zaa;
  696     zip_source_t *source;
  697     int err;
  698 
  699     if (offset == 0 && length == 0) {
  700     if (strcmp(archive, "/dev/stdin") == 0) {
  701         zaa = zip_fdopen(STDIN_FILENO, flags & ~ZIP_CREATE, &err);
  702     }
  703     else {
  704         zaa = zip_open(archive, flags, &err);
  705     }
  706     if (zaa == NULL) {
  707         zip_error_set(error, err, errno);
  708         return NULL;
  709     }
  710     }
  711     else {
  712     if (length > ZIP_INT64_MAX) {
  713         zip_error_set(error, ZIP_ER_INVAL, 0);
  714         return NULL;
  715     }
  716     if ((source = zip_source_file_create(archive, offset, (zip_int64_t)length, error)) == NULL || (zaa = zip_open_from_source(source, flags, error)) == NULL) {
  717         zip_source_free(source);
  718         return NULL;
  719     }
  720     }
  721 
  722     return zaa;
  723 }
  724 
  725 dispatch_table_t dispatch_table[] = {{"add", 2, "name content", "add file called name using content", add},
  726                      {"add_dir", 1, "name", "add directory", add_dir},
  727                      {"add_file", 4, "name file_to_add offset len", "add file to archive, len bytes starting from offset", add_file},
  728                      {"add_from_zip", 5, "name archivename index offset len", "add file from another archive, len bytes starting from offset", add_from_zip},
  729                      {"cat", 1, "index", "output file contents to stdout", cat},
  730                      {"count_extra", 2, "index flags", "show number of extra fields for archive entry", count_extra},
  731                      {"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},
  732                      {"delete", 1, "index", "remove entry", delete},
  733                      {"delete_extra", 3, "index extra_idx flags", "remove extra field", delete_extra},
  734                      {"delete_extra_by_id", 4, "index extra_id extra_index flags", "remove extra field of type extra_id", delete_extra_by_id},
  735                      {"get_archive_comment", 0, "", "show archive comment", get_archive_comment},
  736                      {"get_extra", 3, "index extra_index flags", "show extra field", get_extra},
  737                      {"get_extra_by_id", 4, "index extra_id extra_index flags", "show extra field of type extra_id", get_extra_by_id},
  738                      {"get_file_comment", 1, "index", "get file comment", get_file_comment},
  739                      {"get_num_entries", 1, "flags", "get number of entries in archive", get_num_entries},
  740                      {"name_locate", 2, "name flags", "find entry in archive", name_locate},
  741                      {"print_progress", 0, "", "print progress during zip_close()", print_progress},
  742                      {"rename", 2, "index name", "rename entry", zrename},
  743                      {"replace_file_contents", 2, "index data", "replace entry with data", replace_file_contents},
  744                      {"set_archive_comment", 1, "comment", "set archive comment", set_archive_comment},
  745                      {"set_extra", 5, "index extra_id extra_index flags value", "set extra field", set_extra},
  746                      {"set_file_comment", 2, "index comment", "set file comment", set_file_comment},
  747                      {"set_file_compression", 3, "index method compression_flags", "set file compression method", set_file_compression},
  748                      {"set_file_dostime", 3, "index time date", "set file modification time and date (DOS format)", set_file_dostime},
  749                      {"set_file_encryption", 3, "index method password", "set file encryption method", set_file_encryption},
  750                      {"set_file_mtime", 2, "index timestamp", "set file modification time", set_file_mtime},
  751                      {"set_file_mtime_all", 1, "timestamp", "set file modification time for all files", set_file_mtime_all},
  752                      {"set_password", 1, "password", "set default password for encryption", set_password},
  753                      {"stat", 1, "index", "print information about entry", zstat}
  754 #ifdef DISPATCH_REGRESS
  755                      ,
  756                      DISPATCH_REGRESS
  757 #endif
  758 };
  759 
  760 static int
  761 dispatch(int argc, char *argv[]) {
  762     unsigned int i;
  763     for (i = 0; i < sizeof(dispatch_table) / sizeof(dispatch_table_t); i++) {
  764     if (strcmp(dispatch_table[i].cmdline_name, argv[0]) == 0) {
  765         argc--;
  766         argv++;
  767         /* 1 for the command, argument_count for the arguments */
  768         if (argc < dispatch_table[i].argument_count) {
  769         fprintf(stderr, "not enough arguments for command '%s': %d available, %d needed\n", dispatch_table[i].cmdline_name, argc, dispatch_table[i].argument_count);
  770         return -1;
  771         }
  772         if (dispatch_table[i].function(argc, argv) == 0)
  773         return 1 + dispatch_table[i].argument_count;
  774         return -1;
  775     }
  776     }
  777 
  778     fprintf(stderr, "unknown command '%s'\n", argv[0]);
  779     return -1;
  780 }
  781 
  782 
  783 static void
  784 usage(const char *progname, const char *reason) {
  785     unsigned int i;
  786     FILE *out;
  787     if (reason == NULL)
  788     out = stdout;
  789     else
  790     out = stderr;
  791     fprintf(out, "usage: %s [-ceghnrst]" USAGE_REGRESS " [-l len] [-o offset] archive command1 [args] [command2 [args] ...]\n", progname);
  792     if (reason != NULL) {
  793     fprintf(out, "%s\n", reason);
  794     exit(1);
  795     }
  796 
  797     fprintf(out, "\nSupported options are:\n"
  798          "\t-c\t\tcheck consistency\n"
  799          "\t-e\t\terror if archive already exists (only useful with -n)\n"
  800 #ifdef FOR_REGRESS
  801          "\t-F size\t\tfragment size for in memory archive\n"
  802 #endif
  803          "\t-g\t\tguess file name encoding (for stat)\n"
  804 #ifdef FOR_REGRESS
  805          "\t-H\t\twrite files with holes compactly\n"
  806 #endif
  807          "\t-h\t\tdisplay this usage\n"
  808          "\t-l len\t\tonly use len bytes of file\n"
  809 #ifdef FOR_REGRESS
  810          "\t-m\t\tread archive into memory, and modify there; write out at end\n"
  811 #endif
  812          "\t-n\t\tcreate archive if it doesn't exist\n"
  813          "\t-o offset\tstart reading file at offset\n"
  814          "\t-r\t\tprint raw file name encoding without translation (for stat)\n"
  815          "\t-s\t\tfollow file name convention strictly (for stat)\n"
  816          "\t-t\t\tdisregard current archive contents, if any\n");
  817     fprintf(out, "\nSupported commands and arguments are:\n");
  818     for (i = 0; i < sizeof(dispatch_table) / sizeof(dispatch_table_t); i++) {
  819     fprintf(out, "\t%s %s\n\t    %s\n\n", dispatch_table[i].cmdline_name, dispatch_table[i].arg_names, dispatch_table[i].description);
  820     }
  821     fprintf(out, "\nSupported flags are:\n"
  822          "\t0\t(no flags)\n"
  823          "\tC\tZIP_FL_NOCASE\n"
  824          "\tc\tZIP_FL_CENTRAL\n"
  825          "\td\tZIP_FL_NODIR\n"
  826          "\tl\tZIP_FL_LOCAL\n"
  827          "\tu\tZIP_FL_UNCHANGED\n");
  828     fprintf(out, "\nSupported compression methods are:\n"
  829          "\tdefault\n"
  830 #if defined(HAVE_LIBBZ2)
  831          "\tbzip2\n"
  832 #endif
  833          "\tdeflate\n"
  834          "\tstore\n");
  835     fprintf(out, "\nSupported compression methods are:\n"
  836          "\tnone\n"
  837          "\tAES-128\n"
  838          "\tAES-192\n"
  839          "\tAES-256\n");
  840     fprintf(out, "\nThe index is zero-based.\n");
  841     exit(0);
  842 }
  843 
  844 #ifndef FOR_REGRESS
  845 #define ziptool_open read_from_file
  846 int
  847 ziptool_post_close(const char *archive) {
  848     return 0;
  849 }
  850 #endif
  851 
  852 int
  853 main(int argc, char *argv[]) {
  854     const char *archive;
  855     unsigned int i;
  856     int c, arg, err, flags;
  857     const char *prg;
  858     zip_uint64_t len = 0, offset = 0;
  859     zip_error_t error;
  860 
  861     flags = 0;
  862     prg = argv[0];
  863 
  864     while ((c = getopt(argc, argv, "ceghl:no:rst" OPTIONS_REGRESS)) != -1) {
  865     switch (c) {
  866     case 'c':
  867         flags |= ZIP_CHECKCONS;
  868         break;
  869     case 'e':
  870         flags |= ZIP_EXCL;
  871         break;
  872     case 'g':
  873         stat_flags = ZIP_FL_ENC_GUESS;
  874         break;
  875     case 'h':
  876         usage(prg, NULL);
  877         break;
  878     case 'l':
  879         len = strtoull(optarg, NULL, 10);
  880         break;
  881     case 'n':
  882         flags |= ZIP_CREATE;
  883         break;
  884     case 'o':
  885         offset = strtoull(optarg, NULL, 10);
  886         break;
  887     case 'r':
  888         stat_flags = ZIP_FL_ENC_RAW;
  889         break;
  890     case 's':
  891         stat_flags = ZIP_FL_ENC_STRICT;
  892         break;
  893     case 't':
  894         flags |= ZIP_TRUNCATE;
  895         break;
  896 #ifdef GETOPT_REGRESS
  897         GETOPT_REGRESS
  898 #endif
  899 
  900     default: {
  901         char reason[128];
  902         snprintf(reason, sizeof(reason), "invalid option -%c", optopt);
  903         usage(prg, reason);
  904     }
  905     }
  906     }
  907 
  908     if (optind >= argc - 1)
  909     usage(prg, "too few arguments");
  910 
  911     arg = optind;
  912 
  913     archive = argv[arg++];
  914 
  915     if (flags == 0)
  916     flags = ZIP_CREATE;
  917 
  918     zip_error_init(&error);
  919     za = ziptool_open(archive, flags, &error, offset, len);
  920     if (za == NULL) {
  921     fprintf(stderr, "can't open zip archive '%s': %s\n", archive, zip_error_strerror(&error));
  922     zip_error_fini(&error);
  923     return 1;
  924     }
  925     zip_error_fini(&error);
  926 
  927     err = 0;
  928     while (arg < argc) {
  929     int ret;
  930     ret = dispatch(argc - arg, argv + arg);
  931     if (ret > 0) {
  932         arg += ret;
  933     }
  934     else {
  935         err = 1;
  936         break;
  937     }
  938     }
  939 
  940     if (zip_close(za) == -1) {
  941     fprintf(stderr, "can't close zip archive '%s': %s\n", archive, zip_strerror(za));
  942     return 1;
  943     }
  944     if (ziptool_post_close(archive) < 0) {
  945     err = 1;
  946     }
  947 
  948     for (i = 0; i < z_in_count; i++) {
  949     if (zip_close(z_in[i]) < 0) {
  950         err = 1;
  951     }
  952     }
  953 
  954     return err;
  955 }