Dieter Baron | 659721f | 2017-12-04 17:16:46 +0100 | [diff] [blame] | 1 | #include "zip.h" |
| 2 | |
Thomas Klausner | 00b3e34 | 2020-04-19 16:55:20 +0200 | [diff] [blame] | 3 | #include <sys/stat.h> |
| 4 | |
Thomas Klausner | 8eab1a2 | 2018-01-15 14:10:11 +0100 | [diff] [blame] | 5 | #define ZIP_MIN(a, b) ((a) < (b) ? (a) : (b)) |
Dieter Baron | 983d3a9 | 2017-12-10 13:21:07 +0100 | [diff] [blame] | 6 | |
Dieter Baron | 659721f | 2017-12-04 17:16:46 +0100 | [diff] [blame] | 7 | #define FOR_REGRESS |
| 8 | |
Thomas Klausner | 8eab1a2 | 2018-01-15 14:10:11 +0100 | [diff] [blame] | 9 | typedef enum { SOURCE_TYPE_NONE, SOURCE_TYPE_IN_MEMORY, SOURCE_TYPE_HOLE } source_type_t; |
Dieter Baron | 659721f | 2017-12-04 17:16:46 +0100 | [diff] [blame] | 10 | |
| 11 | source_type_t source_type = SOURCE_TYPE_NONE; |
Dieter Baron | 983d3a9 | 2017-12-10 13:21:07 +0100 | [diff] [blame] | 12 | zip_uint64_t fragment_size = 0; |
Dieter Baron | 659721f | 2017-12-04 17:16:46 +0100 | [diff] [blame] | 13 | |
| 14 | static int add_nul(int argc, char *argv[]); |
Thomas Klausner | a576122 | 2020-01-07 11:59:25 +0100 | [diff] [blame] | 15 | static int cancel(int argc, char *argv[]); |
Thomas Klausner | 1e51775 | 2020-12-21 00:11:31 +0100 | [diff] [blame] | 16 | static int unchange_one(int argc, char *argv[]); |
Dieter Baron | 659721f | 2017-12-04 17:16:46 +0100 | [diff] [blame] | 17 | static int unchange_all(int argc, char *argv[]); |
| 18 | static int zin_close(int argc, char *argv[]); |
| 19 | |
Dieter Baron | 983d3a9 | 2017-12-10 13:21:07 +0100 | [diff] [blame] | 20 | #define OPTIONS_REGRESS "F:Hm" |
Dieter Baron | 659721f | 2017-12-04 17:16:46 +0100 | [diff] [blame] | 21 | |
Dieter Baron | 983d3a9 | 2017-12-10 13:21:07 +0100 | [diff] [blame] | 22 | #define USAGE_REGRESS " [-Hm] [-F fragment-size]" |
Dieter Baron | 659721f | 2017-12-04 17:16:46 +0100 | [diff] [blame] | 23 | |
Thomas Klausner | 8eab1a2 | 2018-01-15 14:10:11 +0100 | [diff] [blame] | 24 | #define GETOPT_REGRESS \ |
| 25 | case 'H': \ |
Thomas Klausner | a14fded | 2020-07-21 16:07:23 +0200 | [diff] [blame] | 26 | source_type = SOURCE_TYPE_HOLE; \ |
| 27 | break; \ |
Thomas Klausner | 8eab1a2 | 2018-01-15 14:10:11 +0100 | [diff] [blame] | 28 | case 'm': \ |
Thomas Klausner | a14fded | 2020-07-21 16:07:23 +0200 | [diff] [blame] | 29 | source_type = SOURCE_TYPE_IN_MEMORY; \ |
| 30 | break; \ |
Thomas Klausner | 8eab1a2 | 2018-01-15 14:10:11 +0100 | [diff] [blame] | 31 | case 'F': \ |
Thomas Klausner | a14fded | 2020-07-21 16:07:23 +0200 | [diff] [blame] | 32 | fragment_size = strtoull(optarg, NULL, 10); \ |
| 33 | break; |
Dieter Baron | 659721f | 2017-12-04 17:16:46 +0100 | [diff] [blame] | 34 | |
Thomas Klausner | 47dc1fc | 2020-07-21 16:05:31 +0200 | [diff] [blame] | 35 | /* clang-format off */ |
| 36 | |
Dieter Baron | 659721f | 2017-12-04 17:16:46 +0100 | [diff] [blame] | 37 | #define DISPATCH_REGRESS \ |
Thomas Klausner | a576122 | 2020-01-07 11:59:25 +0100 | [diff] [blame] | 38 | {"add_nul", 2, "name length", "add NUL bytes", add_nul}, \ |
| 39 | {"cancel", 1, "limit", "cancel writing archive when limit% have been written (calls print_progress)", cancel}, \ |
Thomas Klausner | 1e51775 | 2020-12-21 00:11:31 +0100 | [diff] [blame] | 40 | {"unchange", 1, "index", "revert changes for entry", unchange_one}, \ |
Thomas Klausner | a576122 | 2020-01-07 11:59:25 +0100 | [diff] [blame] | 41 | {"unchange_all", 0, "", "revert all changes", unchange_all}, \ |
| 42 | { "zin_close", 1, "index", "close input zip_source (for internal tests)", zin_close } |
Dieter Baron | 659721f | 2017-12-04 17:16:46 +0100 | [diff] [blame] | 43 | |
Thomas Klausner | 47dc1fc | 2020-07-21 16:05:31 +0200 | [diff] [blame] | 44 | /* clang-format on */ |
| 45 | |
Dieter Baron | 659721f | 2017-12-04 17:16:46 +0100 | [diff] [blame] | 46 | |
| 47 | zip_t *ziptool_open(const char *archive, int flags, zip_error_t *error, zip_uint64_t offset, zip_uint64_t len); |
Dieter Baron | 659721f | 2017-12-04 17:16:46 +0100 | [diff] [blame] | 48 | |
| 49 | |
| 50 | #include "ziptool.c" |
| 51 | |
| 52 | |
| 53 | zip_source_t *memory_src = NULL; |
| 54 | |
| 55 | zip_source_t *source_hole_create(const char *, int flags, zip_error_t *); |
| 56 | |
| 57 | static zip_t *read_to_memory(const char *archive, int flags, zip_error_t *error, zip_source_t **srcp); |
| 58 | static zip_source_t *source_nul(zip_t *za, zip_uint64_t length); |
| 59 | |
| 60 | |
| 61 | static int |
| 62 | add_nul(int argc, char *argv[]) { |
| 63 | zip_source_t *zs; |
| 64 | zip_uint64_t length = strtoull(argv[1], NULL, 10); |
| 65 | |
Thomas Klausner | 8eab1a2 | 2018-01-15 14:10:11 +0100 | [diff] [blame] | 66 | if ((zs = source_nul(za, length)) == NULL) { |
Thomas Klausner | a14fded | 2020-07-21 16:07:23 +0200 | [diff] [blame] | 67 | fprintf(stderr, "can't create zip_source for length: %s\n", zip_strerror(za)); |
| 68 | return -1; |
Dieter Baron | 659721f | 2017-12-04 17:16:46 +0100 | [diff] [blame] | 69 | } |
| 70 | |
| 71 | if (zip_add(za, argv[0], zs) == -1) { |
Thomas Klausner | a14fded | 2020-07-21 16:07:23 +0200 | [diff] [blame] | 72 | zip_source_free(zs); |
| 73 | fprintf(stderr, "can't add file '%s': %s\n", argv[0], zip_strerror(za)); |
| 74 | return -1; |
Dieter Baron | 659721f | 2017-12-04 17:16:46 +0100 | [diff] [blame] | 75 | } |
| 76 | return 0; |
| 77 | } |
| 78 | |
| 79 | static int |
| 80 | unchange_all(int argc, char *argv[]) { |
| 81 | if (zip_unchange_all(za) < 0) { |
Thomas Klausner | a14fded | 2020-07-21 16:07:23 +0200 | [diff] [blame] | 82 | fprintf(stderr, "can't revert changes to archive: %s\n", zip_strerror(za)); |
| 83 | return -1; |
Dieter Baron | 659721f | 2017-12-04 17:16:46 +0100 | [diff] [blame] | 84 | } |
| 85 | return 0; |
| 86 | } |
| 87 | |
Thomas Klausner | 1e51775 | 2020-12-21 00:11:31 +0100 | [diff] [blame] | 88 | |
| 89 | static int |
| 90 | unchange_one(int argc, char *argv[]) { |
| 91 | zip_uint64_t idx; |
| 92 | |
| 93 | idx = strtoull(argv[0], NULL, 10); |
| 94 | |
| 95 | if (zip_unchange(za, idx) < 0) { |
| 96 | fprintf(stderr, "can't revert changes for entry %" PRIu64 ": %s", idx, zip_strerror(za)); |
| 97 | return -1; |
| 98 | } |
| 99 | |
| 100 | return 0; |
| 101 | } |
| 102 | |
| 103 | |
Dieter Baron | 659721f | 2017-12-04 17:16:46 +0100 | [diff] [blame] | 104 | static int |
Thomas Klausner | a576122 | 2020-01-07 11:59:25 +0100 | [diff] [blame] | 105 | cancel_callback(zip_t *archive, void *ud) { |
| 106 | if (progress_userdata.percentage >= progress_userdata.limit) { |
Thomas Klausner | a14fded | 2020-07-21 16:07:23 +0200 | [diff] [blame] | 107 | return -1; |
Thomas Klausner | a576122 | 2020-01-07 11:59:25 +0100 | [diff] [blame] | 108 | } |
| 109 | return 0; |
| 110 | } |
| 111 | |
| 112 | static int |
| 113 | cancel(int argc, char *argv[]) { |
| 114 | zip_int64_t percent; |
| 115 | percent = strtoll(argv[0], NULL, 10); |
| 116 | if (percent > 100 || percent < 0) { |
Thomas Klausner | a14fded | 2020-07-21 16:07:23 +0200 | [diff] [blame] | 117 | fprintf(stderr, "invalid percentage '%" PRId64 "' for cancel (valid: 0 <= x <= 100)\n", percent); |
| 118 | return -1; |
Thomas Klausner | a576122 | 2020-01-07 11:59:25 +0100 | [diff] [blame] | 119 | } |
Thomas Klausner | 29c6a39 | 2020-07-21 16:06:03 +0200 | [diff] [blame] | 120 | progress_userdata.limit = ((double)percent) / 100; |
Thomas Klausner | a576122 | 2020-01-07 11:59:25 +0100 | [diff] [blame] | 121 | |
| 122 | zip_register_cancel_callback_with_state(za, cancel_callback, NULL, NULL); |
| 123 | |
| 124 | /* needs the percentage updates from print_progress */ |
| 125 | print_progress(argc, argv); |
| 126 | return 0; |
| 127 | } |
| 128 | |
| 129 | static int |
Dieter Baron | 659721f | 2017-12-04 17:16:46 +0100 | [diff] [blame] | 130 | zin_close(int argc, char *argv[]) { |
| 131 | zip_uint64_t idx; |
| 132 | |
| 133 | idx = strtoull(argv[0], NULL, 10); |
| 134 | if (idx >= z_in_count) { |
Thomas Klausner | a14fded | 2020-07-21 16:07:23 +0200 | [diff] [blame] | 135 | fprintf(stderr, "invalid argument '%" PRIu64 "', only %u zip sources open\n", idx, z_in_count); |
| 136 | return -1; |
Dieter Baron | 659721f | 2017-12-04 17:16:46 +0100 | [diff] [blame] | 137 | } |
| 138 | if (zip_close(z_in[idx]) < 0) { |
Thomas Klausner | a14fded | 2020-07-21 16:07:23 +0200 | [diff] [blame] | 139 | fprintf(stderr, "can't close source archive: %s\n", zip_strerror(z_in[idx])); |
| 140 | return -1; |
Dieter Baron | 659721f | 2017-12-04 17:16:46 +0100 | [diff] [blame] | 141 | } |
| 142 | z_in[idx] = z_in[z_in_count]; |
| 143 | z_in_count--; |
| 144 | |
| 145 | return 0; |
| 146 | } |
| 147 | |
| 148 | |
| 149 | static zip_t * |
Thomas Klausner | 8eab1a2 | 2018-01-15 14:10:11 +0100 | [diff] [blame] | 150 | read_hole(const char *archive, int flags, zip_error_t *error) { |
Dieter Baron | 659721f | 2017-12-04 17:16:46 +0100 | [diff] [blame] | 151 | zip_source_t *src = NULL; |
| 152 | zip_t *zs = NULL; |
| 153 | |
| 154 | if (strcmp(archive, "/dev/stdin") == 0) { |
Thomas Klausner | a14fded | 2020-07-21 16:07:23 +0200 | [diff] [blame] | 155 | zip_error_set(error, ZIP_ER_OPNOTSUPP, 0); |
| 156 | return NULL; |
Dieter Baron | 659721f | 2017-12-04 17:16:46 +0100 | [diff] [blame] | 157 | } |
| 158 | |
Thomas Klausner | 8eab1a2 | 2018-01-15 14:10:11 +0100 | [diff] [blame] | 159 | if ((src = source_hole_create(archive, flags, error)) == NULL || (zs = zip_open_from_source(src, flags, error)) == NULL) { |
Thomas Klausner | a14fded | 2020-07-21 16:07:23 +0200 | [diff] [blame] | 160 | zip_source_free(src); |
Dieter Baron | 659721f | 2017-12-04 17:16:46 +0100 | [diff] [blame] | 161 | } |
| 162 | |
| 163 | return zs; |
| 164 | } |
| 165 | |
| 166 | |
| 167 | static zip_t * |
Thomas Klausner | 8eab1a2 | 2018-01-15 14:10:11 +0100 | [diff] [blame] | 168 | read_to_memory(const char *archive, int flags, zip_error_t *error, zip_source_t **srcp) { |
Dieter Baron | 659721f | 2017-12-04 17:16:46 +0100 | [diff] [blame] | 169 | zip_source_t *src; |
| 170 | zip_t *zb; |
Dieter Baron | 7955734 | 2017-12-22 16:00:11 +0100 | [diff] [blame] | 171 | FILE *fp; |
Dieter Baron | 659721f | 2017-12-04 17:16:46 +0100 | [diff] [blame] | 172 | |
| 173 | if (strcmp(archive, "/dev/stdin") == 0) { |
Thomas Klausner | a14fded | 2020-07-21 16:07:23 +0200 | [diff] [blame] | 174 | zip_error_set(error, ZIP_ER_OPNOTSUPP, 0); |
| 175 | return NULL; |
Dieter Baron | 659721f | 2017-12-04 17:16:46 +0100 | [diff] [blame] | 176 | } |
| 177 | |
Michał Janiszewski | a9bf616 | 2020-03-08 21:34:36 +0100 | [diff] [blame] | 178 | if ((fp = fopen(archive, "rb")) == NULL) { |
Thomas Klausner | a14fded | 2020-07-21 16:07:23 +0200 | [diff] [blame] | 179 | if (errno == ENOENT) { |
| 180 | src = zip_source_buffer_create(NULL, 0, 0, error); |
| 181 | } |
| 182 | else { |
| 183 | zip_error_set(error, ZIP_ER_OPEN, errno); |
| 184 | return NULL; |
| 185 | } |
Dieter Baron | 659721f | 2017-12-04 17:16:46 +0100 | [diff] [blame] | 186 | } |
| 187 | else { |
Thomas Klausner | a14fded | 2020-07-21 16:07:23 +0200 | [diff] [blame] | 188 | struct stat st; |
Dieter Baron | 983d3a9 | 2017-12-10 13:21:07 +0100 | [diff] [blame] | 189 | |
Thomas Klausner | a14fded | 2020-07-21 16:07:23 +0200 | [diff] [blame] | 190 | if (fstat(fileno(fp), &st) < 0) { |
| 191 | fclose(fp); |
| 192 | zip_error_set(error, ZIP_ER_OPEN, errno); |
| 193 | return NULL; |
| 194 | } |
| 195 | if (fragment_size == 0) { |
| 196 | char *buf; |
| 197 | if ((buf = malloc((size_t)st.st_size)) == NULL) { |
| 198 | fclose(fp); |
| 199 | zip_error_set(error, ZIP_ER_MEMORY, 0); |
| 200 | return NULL; |
| 201 | } |
| 202 | if (fread(buf, (size_t)st.st_size, 1, fp) < 1) { |
| 203 | free(buf); |
| 204 | fclose(fp); |
| 205 | zip_error_set(error, ZIP_ER_READ, errno); |
| 206 | return NULL; |
| 207 | } |
| 208 | src = zip_source_buffer_create(buf, (zip_uint64_t)st.st_size, 1, error); |
| 209 | if (src == NULL) { |
| 210 | free(buf); |
| 211 | } |
| 212 | } |
| 213 | else { |
| 214 | zip_uint64_t nfragments, i, left; |
| 215 | zip_buffer_fragment_t *fragments; |
Dieter Baron | 983d3a9 | 2017-12-10 13:21:07 +0100 | [diff] [blame] | 216 | |
Thomas Klausner | a14fded | 2020-07-21 16:07:23 +0200 | [diff] [blame] | 217 | nfragments = ((size_t)st.st_size + fragment_size - 1) / fragment_size; |
| 218 | if ((fragments = malloc(sizeof(fragments[0]) * nfragments)) == NULL) { |
| 219 | fclose(fp); |
| 220 | zip_error_set(error, ZIP_ER_MEMORY, 0); |
| 221 | return NULL; |
| 222 | } |
| 223 | for (i = 0; i < nfragments; i++) { |
| 224 | left = ZIP_MIN(fragment_size, (size_t)st.st_size - i * fragment_size); |
| 225 | if ((fragments[i].data = malloc(left)) == NULL) { |
Dieter Baron | da9477f | 2018-02-17 12:16:03 +0100 | [diff] [blame] | 226 | #ifndef __clang_analyzer__ |
Thomas Klausner | a14fded | 2020-07-21 16:07:23 +0200 | [diff] [blame] | 227 | /* fragments is initialized up to i - 1*/ |
| 228 | while (--i > 0) { |
| 229 | free(fragments[i].data); |
| 230 | } |
Dieter Baron | da9477f | 2018-02-17 12:16:03 +0100 | [diff] [blame] | 231 | #endif |
Thomas Klausner | a14fded | 2020-07-21 16:07:23 +0200 | [diff] [blame] | 232 | free(fragments); |
| 233 | fclose(fp); |
| 234 | zip_error_set(error, ZIP_ER_MEMORY, 0); |
| 235 | return NULL; |
| 236 | } |
| 237 | fragments[i].length = left; |
| 238 | if (fread(fragments[i].data, left, 1, fp) < 1) { |
Dieter Baron | da9477f | 2018-02-17 12:16:03 +0100 | [diff] [blame] | 239 | #ifndef __clang_analyzer__ |
Thomas Klausner | a14fded | 2020-07-21 16:07:23 +0200 | [diff] [blame] | 240 | /* fragments is initialized up to i - 1*/ |
| 241 | while (--i > 0) { |
| 242 | free(fragments[i].data); |
| 243 | } |
Dieter Baron | da9477f | 2018-02-17 12:16:03 +0100 | [diff] [blame] | 244 | #endif |
Thomas Klausner | a14fded | 2020-07-21 16:07:23 +0200 | [diff] [blame] | 245 | free(fragments); |
| 246 | fclose(fp); |
| 247 | zip_error_set(error, ZIP_ER_READ, errno); |
| 248 | return NULL; |
| 249 | } |
| 250 | } |
| 251 | src = zip_source_buffer_fragment_create(fragments, nfragments, 1, error); |
| 252 | if (src == NULL) { |
| 253 | for (i = 0; i < nfragments; i++) { |
| 254 | free(fragments[i].data); |
| 255 | } |
| 256 | free(fragments); |
| 257 | fclose(fp); |
| 258 | return NULL; |
| 259 | } |
| 260 | free(fragments); |
| 261 | } |
| 262 | fclose(fp); |
Dieter Baron | 659721f | 2017-12-04 17:16:46 +0100 | [diff] [blame] | 263 | } |
| 264 | if (src == NULL) { |
Thomas Klausner | a14fded | 2020-07-21 16:07:23 +0200 | [diff] [blame] | 265 | return NULL; |
Dieter Baron | 659721f | 2017-12-04 17:16:46 +0100 | [diff] [blame] | 266 | } |
| 267 | zb = zip_open_from_source(src, flags, error); |
| 268 | if (zb == NULL) { |
Thomas Klausner | a14fded | 2020-07-21 16:07:23 +0200 | [diff] [blame] | 269 | zip_source_free(src); |
| 270 | return NULL; |
Dieter Baron | 659721f | 2017-12-04 17:16:46 +0100 | [diff] [blame] | 271 | } |
| 272 | zip_source_keep(src); |
| 273 | *srcp = src; |
| 274 | return zb; |
| 275 | } |
| 276 | |
| 277 | |
| 278 | typedef struct source_nul { |
| 279 | zip_error_t error; |
| 280 | zip_uint64_t length; |
| 281 | zip_uint64_t offset; |
| 282 | } source_nul_t; |
| 283 | |
| 284 | static zip_int64_t |
Thomas Klausner | 8eab1a2 | 2018-01-15 14:10:11 +0100 | [diff] [blame] | 285 | source_nul_cb(void *ud, void *data, zip_uint64_t length, zip_source_cmd_t command) { |
Dieter Baron | 659721f | 2017-12-04 17:16:46 +0100 | [diff] [blame] | 286 | source_nul_t *ctx = (source_nul_t *)ud; |
| 287 | |
| 288 | switch (command) { |
Thomas Klausner | 8eab1a2 | 2018-01-15 14:10:11 +0100 | [diff] [blame] | 289 | case ZIP_SOURCE_CLOSE: |
Thomas Klausner | a14fded | 2020-07-21 16:07:23 +0200 | [diff] [blame] | 290 | return 0; |
Dieter Baron | 659721f | 2017-12-04 17:16:46 +0100 | [diff] [blame] | 291 | |
Thomas Klausner | 8eab1a2 | 2018-01-15 14:10:11 +0100 | [diff] [blame] | 292 | case ZIP_SOURCE_ERROR: |
Thomas Klausner | a14fded | 2020-07-21 16:07:23 +0200 | [diff] [blame] | 293 | return zip_error_to_data(&ctx->error, data, length); |
Dieter Baron | 659721f | 2017-12-04 17:16:46 +0100 | [diff] [blame] | 294 | |
Thomas Klausner | 8eab1a2 | 2018-01-15 14:10:11 +0100 | [diff] [blame] | 295 | case ZIP_SOURCE_FREE: |
Thomas Klausner | a14fded | 2020-07-21 16:07:23 +0200 | [diff] [blame] | 296 | free(ctx); |
| 297 | return 0; |
Dieter Baron | 659721f | 2017-12-04 17:16:46 +0100 | [diff] [blame] | 298 | |
Thomas Klausner | 8eab1a2 | 2018-01-15 14:10:11 +0100 | [diff] [blame] | 299 | case ZIP_SOURCE_OPEN: |
Thomas Klausner | a14fded | 2020-07-21 16:07:23 +0200 | [diff] [blame] | 300 | ctx->offset = 0; |
| 301 | return 0; |
Dieter Baron | 659721f | 2017-12-04 17:16:46 +0100 | [diff] [blame] | 302 | |
Thomas Klausner | 8eab1a2 | 2018-01-15 14:10:11 +0100 | [diff] [blame] | 303 | case ZIP_SOURCE_READ: |
Thomas Klausner | a14fded | 2020-07-21 16:07:23 +0200 | [diff] [blame] | 304 | if (length > ZIP_INT64_MAX) { |
| 305 | zip_error_set(&ctx->error, ZIP_ER_INVAL, 0); |
| 306 | return -1; |
| 307 | } |
Dieter Baron | 659721f | 2017-12-04 17:16:46 +0100 | [diff] [blame] | 308 | |
Thomas Klausner | a14fded | 2020-07-21 16:07:23 +0200 | [diff] [blame] | 309 | if (length > ctx->length - ctx->offset) { |
| 310 | length = ctx->length - ctx->offset; |
| 311 | } |
Dieter Baron | 659721f | 2017-12-04 17:16:46 +0100 | [diff] [blame] | 312 | |
Thomas Klausner | a14fded | 2020-07-21 16:07:23 +0200 | [diff] [blame] | 313 | memset(data, 0, length); |
| 314 | ctx->offset += length; |
| 315 | return (zip_int64_t)length; |
Dieter Baron | 659721f | 2017-12-04 17:16:46 +0100 | [diff] [blame] | 316 | |
Thomas Klausner | 8eab1a2 | 2018-01-15 14:10:11 +0100 | [diff] [blame] | 317 | case ZIP_SOURCE_STAT: { |
Thomas Klausner | a14fded | 2020-07-21 16:07:23 +0200 | [diff] [blame] | 318 | zip_stat_t *st = ZIP_SOURCE_GET_ARGS(zip_stat_t, data, length, &ctx->error); |
Dieter Baron | 659721f | 2017-12-04 17:16:46 +0100 | [diff] [blame] | 319 | |
Thomas Klausner | a14fded | 2020-07-21 16:07:23 +0200 | [diff] [blame] | 320 | if (st == NULL) { |
| 321 | return -1; |
| 322 | } |
Dieter Baron | 659721f | 2017-12-04 17:16:46 +0100 | [diff] [blame] | 323 | |
Thomas Klausner | a14fded | 2020-07-21 16:07:23 +0200 | [diff] [blame] | 324 | st->valid |= ZIP_STAT_SIZE; |
| 325 | st->size = ctx->length; |
Dieter Baron | 659721f | 2017-12-04 17:16:46 +0100 | [diff] [blame] | 326 | |
Thomas Klausner | a14fded | 2020-07-21 16:07:23 +0200 | [diff] [blame] | 327 | return 0; |
Thomas Klausner | 8eab1a2 | 2018-01-15 14:10:11 +0100 | [diff] [blame] | 328 | } |
Dieter Baron | 659721f | 2017-12-04 17:16:46 +0100 | [diff] [blame] | 329 | |
Thomas Klausner | 8eab1a2 | 2018-01-15 14:10:11 +0100 | [diff] [blame] | 330 | case ZIP_SOURCE_SUPPORTS: |
Thomas Klausner | a14fded | 2020-07-21 16:07:23 +0200 | [diff] [blame] | 331 | 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); |
Dieter Baron | 659721f | 2017-12-04 17:16:46 +0100 | [diff] [blame] | 332 | |
Thomas Klausner | 8eab1a2 | 2018-01-15 14:10:11 +0100 | [diff] [blame] | 333 | default: |
Thomas Klausner | a14fded | 2020-07-21 16:07:23 +0200 | [diff] [blame] | 334 | zip_error_set(&ctx->error, ZIP_ER_OPNOTSUPP, 0); |
| 335 | return -1; |
Dieter Baron | 659721f | 2017-12-04 17:16:46 +0100 | [diff] [blame] | 336 | } |
| 337 | } |
| 338 | |
| 339 | static zip_source_t * |
Thomas Klausner | 8eab1a2 | 2018-01-15 14:10:11 +0100 | [diff] [blame] | 340 | source_nul(zip_t *zs, zip_uint64_t length) { |
Dieter Baron | 659721f | 2017-12-04 17:16:46 +0100 | [diff] [blame] | 341 | source_nul_t *ctx; |
| 342 | zip_source_t *src; |
| 343 | |
| 344 | if ((ctx = (source_nul_t *)malloc(sizeof(*ctx))) == NULL) { |
Thomas Klausner | a14fded | 2020-07-21 16:07:23 +0200 | [diff] [blame] | 345 | zip_error_set(zip_get_error(zs), ZIP_ER_MEMORY, 0); |
| 346 | return NULL; |
Dieter Baron | 659721f | 2017-12-04 17:16:46 +0100 | [diff] [blame] | 347 | } |
| 348 | |
| 349 | zip_error_init(&ctx->error); |
| 350 | ctx->length = length; |
| 351 | ctx->offset = 0; |
| 352 | |
| 353 | if ((src = zip_source_function(zs, source_nul_cb, ctx)) == NULL) { |
Thomas Klausner | a14fded | 2020-07-21 16:07:23 +0200 | [diff] [blame] | 354 | free(ctx); |
| 355 | return NULL; |
Dieter Baron | 659721f | 2017-12-04 17:16:46 +0100 | [diff] [blame] | 356 | } |
| 357 | |
| 358 | return src; |
| 359 | } |
| 360 | |
| 361 | |
| 362 | static int |
Thomas Klausner | 8eab1a2 | 2018-01-15 14:10:11 +0100 | [diff] [blame] | 363 | write_memory_src_to_file(const char *archive, zip_source_t *src) { |
Dieter Baron | 659721f | 2017-12-04 17:16:46 +0100 | [diff] [blame] | 364 | zip_stat_t zst; |
| 365 | char *buf; |
| 366 | FILE *fp; |
| 367 | |
| 368 | if (zip_source_stat(src, &zst) < 0) { |
Thomas Klausner | a14fded | 2020-07-21 16:07:23 +0200 | [diff] [blame] | 369 | fprintf(stderr, "zip_source_stat on buffer failed: %s\n", zip_error_strerror(zip_source_error(src))); |
| 370 | return -1; |
Dieter Baron | 659721f | 2017-12-04 17:16:46 +0100 | [diff] [blame] | 371 | } |
| 372 | if (zip_source_open(src) < 0) { |
Thomas Klausner | a14fded | 2020-07-21 16:07:23 +0200 | [diff] [blame] | 373 | if (zip_error_code_zip(zip_source_error(src)) == ZIP_ER_DELETED) { |
| 374 | if (unlink(archive) < 0 && errno != ENOENT) { |
| 375 | fprintf(stderr, "unlink failed: %s\n", strerror(errno)); |
| 376 | return -1; |
| 377 | } |
| 378 | return 0; |
| 379 | } |
| 380 | fprintf(stderr, "zip_source_open on buffer failed: %s\n", zip_error_strerror(zip_source_error(src))); |
| 381 | return -1; |
Dieter Baron | 659721f | 2017-12-04 17:16:46 +0100 | [diff] [blame] | 382 | } |
Thomas Klausner | 8eab1a2 | 2018-01-15 14:10:11 +0100 | [diff] [blame] | 383 | if ((buf = malloc(zst.size)) == NULL) { |
Thomas Klausner | a14fded | 2020-07-21 16:07:23 +0200 | [diff] [blame] | 384 | fprintf(stderr, "malloc failed: %s\n", strerror(errno)); |
| 385 | zip_source_close(src); |
| 386 | return -1; |
Dieter Baron | 659721f | 2017-12-04 17:16:46 +0100 | [diff] [blame] | 387 | } |
| 388 | if (zip_source_read(src, buf, zst.size) < (zip_int64_t)zst.size) { |
Thomas Klausner | a14fded | 2020-07-21 16:07:23 +0200 | [diff] [blame] | 389 | fprintf(stderr, "zip_source_read on buffer failed: %s\n", zip_error_strerror(zip_source_error(src))); |
| 390 | zip_source_close(src); |
| 391 | free(buf); |
| 392 | return -1; |
Dieter Baron | 659721f | 2017-12-04 17:16:46 +0100 | [diff] [blame] | 393 | } |
| 394 | zip_source_close(src); |
Thomas Klausner | 8eab1a2 | 2018-01-15 14:10:11 +0100 | [diff] [blame] | 395 | if ((fp = fopen(archive, "wb")) == NULL) { |
Thomas Klausner | a14fded | 2020-07-21 16:07:23 +0200 | [diff] [blame] | 396 | fprintf(stderr, "fopen failed: %s\n", strerror(errno)); |
| 397 | free(buf); |
| 398 | return -1; |
Dieter Baron | 659721f | 2017-12-04 17:16:46 +0100 | [diff] [blame] | 399 | } |
| 400 | if (fwrite(buf, zst.size, 1, fp) < 1) { |
Thomas Klausner | a14fded | 2020-07-21 16:07:23 +0200 | [diff] [blame] | 401 | fprintf(stderr, "fwrite failed: %s\n", strerror(errno)); |
| 402 | free(buf); |
| 403 | fclose(fp); |
| 404 | return -1; |
Dieter Baron | 659721f | 2017-12-04 17:16:46 +0100 | [diff] [blame] | 405 | } |
| 406 | free(buf); |
| 407 | if (fclose(fp) != 0) { |
Thomas Klausner | a14fded | 2020-07-21 16:07:23 +0200 | [diff] [blame] | 408 | fprintf(stderr, "fclose failed: %s\n", strerror(errno)); |
| 409 | return -1; |
Dieter Baron | 659721f | 2017-12-04 17:16:46 +0100 | [diff] [blame] | 410 | } |
| 411 | return 0; |
| 412 | } |
| 413 | |
| 414 | |
| 415 | zip_t * |
| 416 | ziptool_open(const char *archive, int flags, zip_error_t *error, zip_uint64_t offset, zip_uint64_t len) { |
| 417 | switch (source_type) { |
Thomas Klausner | 8eab1a2 | 2018-01-15 14:10:11 +0100 | [diff] [blame] | 418 | case SOURCE_TYPE_NONE: |
Thomas Klausner | a14fded | 2020-07-21 16:07:23 +0200 | [diff] [blame] | 419 | za = read_from_file(archive, flags, error, offset, len); |
| 420 | break; |
Dieter Baron | 659721f | 2017-12-04 17:16:46 +0100 | [diff] [blame] | 421 | |
Thomas Klausner | 8eab1a2 | 2018-01-15 14:10:11 +0100 | [diff] [blame] | 422 | case SOURCE_TYPE_IN_MEMORY: |
Thomas Klausner | a14fded | 2020-07-21 16:07:23 +0200 | [diff] [blame] | 423 | za = read_to_memory(archive, flags, error, &memory_src); |
| 424 | break; |
Dieter Baron | 659721f | 2017-12-04 17:16:46 +0100 | [diff] [blame] | 425 | |
Thomas Klausner | 8eab1a2 | 2018-01-15 14:10:11 +0100 | [diff] [blame] | 426 | case SOURCE_TYPE_HOLE: |
Thomas Klausner | a14fded | 2020-07-21 16:07:23 +0200 | [diff] [blame] | 427 | za = read_hole(archive, flags, error); |
| 428 | break; |
Dieter Baron | 659721f | 2017-12-04 17:16:46 +0100 | [diff] [blame] | 429 | } |
| 430 | |
| 431 | return za; |
| 432 | } |
| 433 | |
| 434 | |
| 435 | int |
| 436 | ziptool_post_close(const char *archive) { |
| 437 | if (source_type == SOURCE_TYPE_IN_MEMORY) { |
Thomas Klausner | a14fded | 2020-07-21 16:07:23 +0200 | [diff] [blame] | 438 | if (write_memory_src_to_file(archive, memory_src) < 0) { |
| 439 | return -1; |
| 440 | } |
| 441 | zip_source_free(memory_src); |
Dieter Baron | 659721f | 2017-12-04 17:16:46 +0100 | [diff] [blame] | 442 | } |
| 443 | |
| 444 | return 0; |
| 445 | } |