Imported Upstream version 1.2.0
[platform/upstream/libzip.git] / src / ziptool.c
index 062267e..2994cb2 100644 (file)
@@ -71,8 +71,9 @@ typedef struct dispatch_table_s {
 
 static zip_flags_t get_flags(const char *arg);
 static zip_int32_t get_compression_method(const char *arg);
+static zip_uint16_t get_encryption_method(const char *arg);
 static void hexdump(const zip_uint8_t *data, zip_uint16_t len);
-static zip_t *read_to_memory(const char *archive, int flags, int *err, zip_source_t **srcp);
+static zip_t *read_to_memory(const char *archive, int flags, zip_error_t *error, zip_source_t **srcp);
 static zip_source_t *source_nul(zip_t *za, zip_uint64_t length);
 
 zip_t *za, *z_in[16];
@@ -208,8 +209,8 @@ cat(int argc, char *argv[]) {
        }
     }
     if (n == -1) {
-       zip_fclose(zf);
        fprintf(stderr, "can't read file at index '%" PRIu64 "': %s\n", idx, zip_file_strerror(zf));
+       zip_fclose(zf);
        return -1;
     }
     if ((err = zip_fclose(zf)) != 0) {
@@ -249,7 +250,7 @@ count_extra_by_id(int argc, char *argv[]) {
     eid = (zip_uint16_t)strtoull(argv[1], NULL, 10);
     ceflags = get_flags(argv[2]);
     if ((count=zip_file_extra_fields_count_by_id(za, idx, eid, ceflags)) < 0) {
-       fprintf(stderr, "can't get extra field count for file at index '%" PRIu64 "' and for id `%d': %s\n", idx, eid, zip_strerror(za));
+       fprintf(stderr, "can't get extra field count for file at index '%" PRIu64 "' and for id '%d': %s\n", idx, eid, zip_strerror(za));
        return -1;
     } else {
        printf("Extra field count: %d\n", count);
@@ -277,7 +278,7 @@ delete_extra(int argc, char *argv[]) {
     eid = (zip_uint16_t)strtoull(argv[1], NULL, 10);
     geflags = get_flags(argv[2]);
     if ((zip_file_extra_field_delete(za, idx, eid, geflags)) < 0) {
-       fprintf(stderr, "can't delete extra field data for file at index '%" PRIu64 "', extra field id `%d': %s\n", idx, eid, zip_strerror(za));
+       fprintf(stderr, "can't delete extra field data for file at index '%" PRIu64 "', extra field id '%d': %s\n", idx, eid, zip_strerror(za));
        return -1;
     }
     return 0;
@@ -293,7 +294,7 @@ delete_extra_by_id(int argc, char *argv[]) {
     eidx = (zip_uint16_t)strtoull(argv[2], NULL, 10);
     geflags = get_flags(argv[3]);
     if ((zip_file_extra_field_delete_by_id(za, idx, eid, eidx, geflags)) < 0) {
-       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));
+       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));
        return -1;
     }
     return 0;
@@ -400,12 +401,23 @@ name_locate(int argc, char *argv[]) {
     return 0;
 }
 
+static void
+progress_callback(double percentage) {
+    printf("%.1lf%% done\n", percentage*100);
+}
+
+static int
+print_progress(int argc, char *argv[]) {
+    zip_register_progress_callback(za, progress_callback);
+    return 0;
+}
+
 static int
 zrename(int argc, char *argv[]) {
     zip_uint64_t idx;
     idx = strtoull(argv[0], NULL, 10);
     if (zip_rename(za, idx, argv[1]) < 0) {
-       fprintf(stderr, "can't rename file at index '%" PRIu64 "' to `%s': %s\n", idx, argv[1], zip_strerror(za));
+       fprintf(stderr, "can't rename file at index '%" PRIu64 "' to '%s': %s\n", idx, argv[1], zip_strerror(za));
        return -1;
     }
     return 0;
@@ -440,7 +452,7 @@ set_extra(int argc, char *argv[]) {
     geflags = get_flags(argv[3]);
     efdata = (zip_uint8_t *)argv[4];
     if ((zip_file_extra_field_set(za, idx, eid, eidx, efdata, (zip_uint16_t)strlen((const char *)efdata), geflags)) < 0) {
-       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));
+       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));
        return -1;
     }
     return 0;
@@ -449,7 +461,7 @@ set_extra(int argc, char *argv[]) {
 static int
 set_archive_comment(int argc, char *argv[]) {
     if (zip_set_archive_comment(za, argv[0], (zip_uint16_t)strlen(argv[0])) < 0) {
-       fprintf(stderr, "can't set archive comment to `%s': %s\n", argv[0], zip_strerror(za));
+       fprintf(stderr, "can't set archive comment to '%s': %s\n", argv[0], zip_strerror(za));
        return -1;
     }
     return 0;
@@ -460,7 +472,7 @@ set_file_comment(int argc, char *argv[]) {
     zip_uint64_t idx;
     idx = strtoull(argv[0], NULL, 10);
     if (zip_file_set_comment(za, idx, argv[1], (zip_uint16_t)strlen(argv[1]), 0) < 0) {
-       fprintf(stderr, "can't set file comment at index '%" PRIu64 "' to `%s': %s\n", idx, argv[1], zip_strerror(za));
+       fprintf(stderr, "can't set file comment at index '%" PRIu64 "' to '%s': %s\n", idx, argv[1], zip_strerror(za));
        return -1;
     }
     return 0;
@@ -475,7 +487,25 @@ set_file_compression(int argc, char *argv[]) {
     method = get_compression_method(argv[1]);
     flags = (zip_uint32_t)strtoull(argv[2], NULL, 10);
     if (zip_set_file_compression(za, idx, method, flags) < 0) {
-       fprintf(stderr, "can't set file compression method at index '%" PRIu64 "' to `%s', flags `%d': %s\n", idx, argv[1], flags, zip_strerror(za));
+       fprintf(stderr, "can't set file compression method at index '%" PRIu64 "' to '%s', flags '%d': %s\n", idx, argv[1], flags, zip_strerror(za));
+       return -1;
+    }
+    return 0;
+}
+
+static int
+set_file_encryption(int argc, char *argv[]) {
+    zip_int32_t method;
+    zip_uint64_t idx;
+    char *password;
+    idx = strtoull(argv[0], NULL, 10);
+    method = get_encryption_method(argv[1]);
+    password = argv[2];
+    if (strlen(password) == 0) {
+       password = NULL;
+    }
+    if (zip_file_set_encryption(za, idx, method, password) < 0) {
+       fprintf(stderr, "can't set file encryption method at index '%" PRIu64 "' to '%s': %s\n", idx, argv[1], zip_strerror(za));
        return -1;
     }
     return 0;
@@ -489,7 +519,7 @@ set_file_mtime(int argc, char *argv[]) {
     idx = strtoull(argv[0], NULL, 10);
     mtime = (time_t)strtoull(argv[1], NULL, 10);
     if (zip_file_set_mtime(za, idx, mtime, 0) < 0) {
-       fprintf(stderr, "can't set file mtime at index '%" PRIu64 "' to `%ld': %s\n", idx, mtime, zip_strerror(za));
+       fprintf(stderr, "can't set file mtime at index '%" PRIu64 "' to '%ld': %s\n", idx, mtime, zip_strerror(za));
        return -1;
     }
     return 0;
@@ -502,14 +532,14 @@ set_file_mtime_all(int argc, char *argv[]) {
     zip_int64_t num_entries;
     zip_uint64_t idx;
     mtime = (time_t)strtoull(argv[0], NULL, 10);
-    
+
     if ((num_entries = zip_get_num_entries(za, 0)) < 0) {
         fprintf(stderr, "can't get number of entries: %s\n", zip_strerror(za));
         return -1;
     }
     for (idx = 0; idx < (zip_uint64_t)num_entries; idx++) {
        if (zip_file_set_mtime(za, idx, mtime, 0) < 0) {
-           fprintf(stderr, "can't set file mtime at index '%" PRIu64 "' to `%ld': %s\n", idx, mtime, zip_strerror(za));
+           fprintf(stderr, "can't set file mtime at index '%" PRIu64 "' to '%ld': %s\n", idx, mtime, zip_strerror(za));
            return -1;
        }
     }
@@ -520,7 +550,7 @@ static int
 set_password(int argc, char *argv[]) {
     /* set default password */
     if (zip_set_default_password(za, argv[0]) < 0) {
-       fprintf(stderr, "can't set default password to `%s'", argv[0]);
+       fprintf(stderr, "can't set default password to '%s'\n", argv[0]);
        return -1;
     }
     return 0;
@@ -617,13 +647,29 @@ get_compression_method(const char *arg)
         return ZIP_CM_DEFAULT;
     else if (strcmp(arg, "store") == 0)
         return ZIP_CM_STORE;
-    else if (strcmp(arg, "deflate") ==0)
+    else if (strcmp(arg, "deflate") == 0)
         return ZIP_CM_DEFLATE;
-    else if (strcmp(arg, "unknown") ==0)
-        return 99;
+    else if (strcmp(arg, "unknown") == 0)
+        return 100;
     return 0; /* TODO: error handling */
 }
 
+static zip_uint16_t
+get_encryption_method(const char *arg)
+{
+    if (strcmp(arg, "none") == 0)
+        return ZIP_EM_NONE;
+    else if (strcmp(arg, "AES-128") == 0)
+        return ZIP_EM_AES_128;
+    else if (strcmp(arg, "AES-192") == 0)
+        return ZIP_EM_AES_192;
+    else if (strcmp(arg, "AES-256") == 0)
+        return ZIP_EM_AES_256;
+    else if (strcmp(arg, "unknown") == 0)
+        return 100;
+    return (zip_uint16_t)-1; /* TODO: error handling */
+}
+
 static void
 hexdump(const zip_uint8_t *data, zip_uint16_t len)
 {
@@ -642,19 +688,43 @@ hexdump(const zip_uint8_t *data, zip_uint16_t len)
 
 
 static zip_t *
-read_hole(const char *archive, int flags, int *err)
+read_from_file(const char *archive, int flags, zip_error_t *error, zip_uint64_t offset, zip_uint64_t length)
+{
+    zip_t *zaa;
+    zip_source_t *source;
+    int err;
+
+    if (offset == 0 && length == 0) {
+       if ((zaa = zip_open(archive, flags, &err)) == NULL) {
+           zip_error_set(error, err, errno);
+           return NULL;
+       }
+    }
+    else {
+        if (length > ZIP_INT64_MAX) {
+            zip_error_set(error, ZIP_ER_INVAL, 0);
+            return NULL;
+        }
+       if ((source = zip_source_file_create(archive, offset, (zip_int64_t)length, error)) == NULL
+           || (zaa = zip_open_from_source(source, flags, error)) == NULL) {
+           zip_source_free(source);
+           return NULL;
+       }
+    }
+
+    return zaa;
+}
+
+
+static zip_t *
+read_hole(const char *archive, int flags, zip_error_t *error)
 {
-    zip_error_t error;
     zip_source_t *src = NULL;
     zip_t *zs = NULL;
 
-    zip_error_init(&error);
-
-    if ((src = source_hole_create(archive, flags, &error)) == NULL
-        || (zs = zip_open_from_source(src, flags, &error)) == NULL) {
+    if ((src = source_hole_create(archive, flags, error)) == NULL
+        || (zs = zip_open_from_source(src, flags, error)) == NULL) {
         zip_source_free(src);
-        *err = zip_error_code_zip(&error);
-        errno = zip_error_code_system(&error);
     }
 
     return zs;
@@ -662,19 +732,18 @@ read_hole(const char *archive, int flags, int *err)
 
 
 static zip_t *
-read_to_memory(const char *archive, int flags, int *err, zip_source_t **srcp)
+read_to_memory(const char *archive, int flags, zip_error_t *error, zip_source_t **srcp)
 {
     struct stat st;
     zip_source_t *src;
     zip_t *zb;
-    zip_error_t error;
 
     if (stat(archive, &st) < 0) {
        if (errno == ENOENT) {
-           src = zip_source_buffer_create(NULL, 0, 0, &error);
+           src = zip_source_buffer_create(NULL, 0, 0, error);
        }
        else {
-           *err = ZIP_ER_OPEN;
+           zip_error_set(error, ZIP_ER_OPEN, errno);
            return NULL;
        }
     }
@@ -682,35 +751,31 @@ read_to_memory(const char *archive, int flags, int *err, zip_source_t **srcp)
        char *buf;
        FILE *fp;
        if ((buf=malloc((size_t)st.st_size)) == NULL) {
-           *err = ZIP_ER_MEMORY;
+           zip_error_set(error, ZIP_ER_MEMORY, 0);
            return NULL;
        }
        if ((fp=fopen(archive, "r")) == NULL) {
            free(buf);
-           *err = ZIP_ER_READ;
+           zip_error_set(error, ZIP_ER_READ, errno);
            return NULL;
        }
        if (fread(buf, (size_t)st.st_size, 1, fp) < 1) {
            free(buf);
            fclose(fp);
-           *err = ZIP_ER_READ;
+           zip_error_set(error, ZIP_ER_READ, errno);
            return NULL;
        }
        fclose(fp);
-       src = zip_source_buffer_create(buf, (zip_uint64_t)st.st_size, 1, &error);
+       src = zip_source_buffer_create(buf, (zip_uint64_t)st.st_size, 1, error);
        if (src == NULL) {
            free(buf);
        }
     }
     if (src == NULL) {
-       *err = zip_error_code_zip(&error);
-       errno = zip_error_code_system(&error);
        return NULL;
     }
-    zb = zip_open_from_source(src, flags, &error);
+    zb = zip_open_from_source(src, flags, error);
     if (zb == NULL) {
-       *err = zip_error_code_zip(&error);
-       errno = zip_error_code_system(&error);
        zip_source_free(src);
        return NULL;
     }
@@ -877,12 +942,14 @@ dispatch_table_t dispatch_table[] = {
     { "get_file_comment", 1, "index", "get file comment", get_file_comment },
     { "get_num_entries", 1, "flags", "get number of entries in archive", get_num_entries },
     { "name_locate", 2, "name flags", "find entry in archive", name_locate },
+    { "print_progress", 0, "", "print progress during zip_close()", print_progress },
     { "rename", 2, "index name", "rename entry", zrename },
     { "replace_file_contents", 2, "index data", "replace entry with data", replace_file_contents },
     { "set_archive_comment", 1, "comment", "set archive comment", set_archive_comment },
     { "set_extra", 5, "index extra_id extra_index flags value", "set extra field", set_extra },
     { "set_file_comment", 2, "index comment", "set file comment", set_file_comment },
     { "set_file_compression", 3, "index method compression_flags", "set file compression method", set_file_compression },
+    { "set_file_encryption", 3, "index method password", "set file encryption method", set_file_encryption },
     { "set_file_mtime", 2, "index timestamp", "set file modification time", set_file_mtime },
     { "set_file_mtime_all", 1, "timestamp", "set file modification time for all files", set_file_mtime_all },
     { "set_password", 1, "password", "set default password for encryption", set_password },
@@ -924,28 +991,31 @@ usage(const char *progname, const char *reason)
        out = stdout;
     else
        out = stderr;
-    fprintf(out, "usage: %s [-cegHhmnrst] archive command1 [args] [command2 [args] ...]\n", progname);
+    fprintf(out, "usage: %s [-cegHhmnrst] [-l len] [-o offset] archive command1 [args] [command2 [args] ...]\n", progname);
     if (reason != NULL) {
        fprintf(out, "%s\n", reason);
        exit(1);
     }
 
     fprintf(out, "\nSupported options are:\n"
-           "\t-c\tcheck consistency\n"
-           "\t-e\terror if archive already exists (only useful with -n)\n"
-           "\t-g\tguess file name encoding (for stat)\n"
-            "\t-H\twrite files with holes compactly\n"
-            "\t-h\tdisplay this usage\n"
-           "\t-m\tread archive into memory, and modify there; write out at end\n"
-           "\t-n\tcreate archive if it doesn't exist\n"
-           "\t-r\tprint raw file name encoding without translation (for stat)\n"
-           "\t-s\tfollow file name convention strictly (for stat)\n"
-           "\t-t\tdisregard current archive contents, if any\n");
+           "\t-c\t\tcheck consistency\n"
+           "\t-e\t\terror if archive already exists (only useful with -n)\n"
+           "\t-g\t\tguess file name encoding (for stat)\n"
+            "\t-H\t\twrite files with holes compactly\n"
+            "\t-h\t\tdisplay this usage\n"
+           "\t-l len\t\tonly use len bytes of file\n"
+           "\t-m\t\tread archive into memory, and modify there; write out at end\n"
+           "\t-n\t\tcreate archive if it doesn't exist\n"
+           "\t-o offset\tstart reading file at offset\n"
+           "\t-r\t\tprint raw file name encoding without translation (for stat)\n"
+           "\t-s\t\tfollow file name convention strictly (for stat)\n"
+           "\t-t\t\tdisregard current archive contents, if any\n");
     fprintf(out, "\nSupported commands and arguments are:\n");
     for (i=0; i<sizeof(dispatch_table)/sizeof(dispatch_table_t); i++) {
        fprintf(out, "\t%s %s\n\t    %s\n\n", dispatch_table[i].cmdline_name, dispatch_table[i].arg_names, dispatch_table[i].description);
     }
     fprintf(out, "\nSupported flags are:\n"
+           "\t0\t(no flags)\n"
            "\tC\tZIP_FL_NOCASE\n"
            "\tc\tZIP_FL_CENTRAL\n"
            "\td\tZIP_FL_NODIR\n"
@@ -955,6 +1025,11 @@ usage(const char *progname, const char *reason)
            "\tdefault\n"
            "\tdeflate\n"
            "\tstore\n");
+    fprintf(out, "\nSupported compression methods are:\n"
+           "\tnone\n"
+           "\tAES-128\n"
+           "\tAES-192\n"
+           "\tAES-256\n");
     fprintf(out, "\nThe index is zero-based.\n");
     exit(0);
 }
@@ -968,14 +1043,13 @@ main(int argc, char *argv[])
     int c, arg, err, flags;
     const char *prg;
     source_type_t source_type = SOURCE_TYPE_NONE;
+    zip_uint64_t len = 0, offset = 0;
+    zip_error_t error;
 
     flags = 0;
     prg = argv[0];
 
-    if (argc < 2)
-       usage(prg, "too few arguments");
-
-    while ((c=getopt(argc, argv, "cegHhmnrst")) != -1) {
+    while ((c=getopt(argc, argv, "cegHhl:mno:rst")) != -1) {
        switch (c) {
        case 'c':
            flags |= ZIP_CHECKCONS;
@@ -992,12 +1066,18 @@ main(int argc, char *argv[])
        case 'h':
            usage(prg, NULL);
            break;
+       case 'l':
+           len = strtoull(optarg, NULL, 10);
+           break;
        case 'm':
             source_type = SOURCE_TYPE_IN_MEMORY;
             break;
        case 'n':
            flags |= ZIP_CREATE;
            break;
+       case 'o':
+           offset = strtoull(optarg, NULL, 10);
+           break;
        case 'r':
            stat_flags = ZIP_FL_ENC_RAW;
            break;
@@ -1017,6 +1097,9 @@ main(int argc, char *argv[])
        }
     }
 
+    if (optind >= argc-1)
+       usage(prg, "too few arguments");
+
     arg = optind;
 
     archive = argv[arg++];
@@ -1024,27 +1107,26 @@ main(int argc, char *argv[])
     if (flags == 0)
        flags = ZIP_CREATE;
 
+    zip_error_init(&error);
     switch (source_type) {
-        case SOURCE_TYPE_NONE:
-            za = zip_open(archive, flags, &err);
-            break;
+       case SOURCE_TYPE_NONE:
+           za = read_from_file(archive, flags, &error, offset, len);
+           break;
 
         case SOURCE_TYPE_IN_MEMORY:
-            za = read_to_memory(archive, flags, &err, &memory_src);
+            za = read_to_memory(archive, flags, &error, &memory_src);
             break;
 
-        case SOURCE_TYPE_HOLE: {
-            za = read_hole(archive, flags, &err);
+       case SOURCE_TYPE_HOLE:
+           za = read_hole(archive, flags, &error);
             break;
-        }
     }
     if (za == NULL) {
-       zip_error_t error;
-       zip_error_init_with_code(&error, err);
        fprintf(stderr, "can't open zip archive '%s': %s\n", archive, zip_error_strerror(&error));
        zip_error_fini(&error);
        return 1;
     }
+    zip_error_fini(&error);
 
     err = 0;
     while (arg < argc) {