5 #define ZIP_MIN(a, b) ((a) < (b) ? (a) : (b))
9 typedef enum { SOURCE_TYPE_NONE, SOURCE_TYPE_IN_MEMORY, SOURCE_TYPE_HOLE } source_type_t;
11 source_type_t source_type = SOURCE_TYPE_NONE;
12 zip_uint64_t fragment_size = 0;
14 static int add_nul(char *argv[]);
15 static int cancel(char *argv[]);
16 static int unchange_one(char *argv[]);
17 static int unchange_all(char *argv[]);
18 static int zin_close(char *argv[]);
20 #define OPTIONS_REGRESS "F:Hm"
22 #define USAGE_REGRESS " [-Hm] [-F fragment-size]"
24 #define GETOPT_REGRESS \
26 source_type = SOURCE_TYPE_HOLE; \
29 source_type = SOURCE_TYPE_IN_MEMORY; \
32 fragment_size = strtoull(optarg, NULL, 10); \
35 /* clang-format off */
37 #define DISPATCH_REGRESS \
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}, \
40 {"unchange", 1, "index", "revert changes for entry", unchange_one}, \
41 {"unchange_all", 0, "", "revert all changes", unchange_all}, \
42 { "zin_close", 1, "index", "close input zip_source (for internal tests)", zin_close }
47 zip_t *ziptool_open(const char *archive, int flags, zip_error_t *error, zip_uint64_t offset, zip_uint64_t len);
53 zip_source_t *memory_src = NULL;
55 zip_source_t *source_hole_create(const char *, int flags, zip_error_t *);
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);
62 add_nul(char *argv[]) {
64 zip_uint64_t length = strtoull(argv[1], NULL, 10);
66 if ((zs = source_nul(za, length)) == NULL) {
67 fprintf(stderr, "can't create zip_source for length: %s\n", zip_strerror(za));
71 if (zip_add(za, argv[0], zs) == -1) {
73 fprintf(stderr, "can't add file '%s': %s\n", argv[0], zip_strerror(za));
80 unchange_all(char *argv[]) {
81 if (zip_unchange_all(za) < 0) {
82 fprintf(stderr, "can't revert changes to archive: %s\n", zip_strerror(za));
90 unchange_one(char *argv[]) {
93 idx = strtoull(argv[0], NULL, 10);
95 if (zip_unchange(za, idx) < 0) {
96 fprintf(stderr, "can't revert changes for entry %" PRIu64 ": %s", idx, zip_strerror(za));
105 cancel_callback(zip_t *archive, void *ud) {
106 if (progress_userdata.percentage >= progress_userdata.limit) {
113 cancel(char *argv[]) {
115 percent = strtoll(argv[0], NULL, 10);
116 if (percent > 100 || percent < 0) {
117 fprintf(stderr, "invalid percentage '%" PRId64 "' for cancel (valid: 0 <= x <= 100)\n", percent);
120 progress_userdata.limit = ((double)percent) / 100;
122 zip_register_cancel_callback_with_state(za, cancel_callback, NULL, NULL);
124 /* needs the percentage updates from print_progress */
125 print_progress(argv);
130 zin_close(char *argv[]) {
133 idx = strtoull(argv[0], NULL, 10);
134 if (idx >= z_in_count) {
135 fprintf(stderr, "invalid argument '%" PRIu64 "', only %u zip sources open\n", idx, z_in_count);
138 if (zip_close(z_in[idx]) < 0) {
139 fprintf(stderr, "can't close source archive: %s\n", zip_strerror(z_in[idx]));
142 z_in[idx] = z_in[z_in_count];
150 read_hole(const char *archive, int flags, zip_error_t *error) {
151 zip_source_t *src = NULL;
154 if (strcmp(archive, "/dev/stdin") == 0) {
155 zip_error_set(error, ZIP_ER_OPNOTSUPP, 0);
159 if ((src = source_hole_create(archive, flags, error)) == NULL || (zs = zip_open_from_source(src, flags, error)) == NULL) {
160 zip_source_free(src);
168 read_to_memory(const char *archive, int flags, zip_error_t *error, zip_source_t **srcp) {
173 if (strcmp(archive, "/dev/stdin") == 0) {
174 zip_error_set(error, ZIP_ER_OPNOTSUPP, 0);
178 if ((fp = fopen(archive, "rb")) == NULL) {
179 if (errno == ENOENT) {
180 src = zip_source_buffer_create(NULL, 0, 0, error);
183 zip_error_set(error, ZIP_ER_OPEN, errno);
190 if (fstat(fileno(fp), &st) < 0) {
192 zip_error_set(error, ZIP_ER_OPEN, errno);
195 if (fragment_size == 0) {
197 if ((buf = malloc((size_t)st.st_size)) == NULL) {
199 zip_error_set(error, ZIP_ER_MEMORY, 0);
202 if (fread(buf, (size_t)st.st_size, 1, fp) < 1) {
205 zip_error_set(error, ZIP_ER_READ, errno);
208 src = zip_source_buffer_create(buf, (zip_uint64_t)st.st_size, 1, error);
214 zip_uint64_t nfragments, i, left;
215 zip_buffer_fragment_t *fragments;
217 nfragments = ((size_t)st.st_size + fragment_size - 1) / fragment_size;
218 if ((fragments = malloc(sizeof(fragments[0]) * nfragments)) == NULL) {
220 zip_error_set(error, ZIP_ER_MEMORY, 0);
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) {
226 #ifndef __clang_analyzer__
227 /* fragments is initialized up to i - 1*/
229 free(fragments[i].data);
234 zip_error_set(error, ZIP_ER_MEMORY, 0);
237 fragments[i].length = left;
238 if (fread(fragments[i].data, left, 1, fp) < 1) {
239 #ifndef __clang_analyzer__
240 /* fragments is initialized up to i - 1*/
242 free(fragments[i].data);
247 zip_error_set(error, ZIP_ER_READ, errno);
251 src = zip_source_buffer_fragment_create(fragments, nfragments, 1, error);
253 for (i = 0; i < nfragments; i++) {
254 free(fragments[i].data);
267 zb = zip_open_from_source(src, flags, error);
269 zip_source_free(src);
272 zip_source_keep(src);
278 typedef struct source_nul {
285 source_nul_cb(void *ud, void *data, zip_uint64_t length, zip_source_cmd_t command) {
286 source_nul_t *ctx = (source_nul_t *)ud;
289 case ZIP_SOURCE_CLOSE:
292 case ZIP_SOURCE_ERROR:
293 return zip_error_to_data(&ctx->error, data, length);
295 case ZIP_SOURCE_FREE:
299 case ZIP_SOURCE_OPEN:
303 case ZIP_SOURCE_READ:
304 if (length > ZIP_INT64_MAX) {
305 zip_error_set(&ctx->error, ZIP_ER_INVAL, 0);
309 if (length > ctx->length - ctx->offset) {
310 length = ctx->length - ctx->offset;
313 memset(data, 0, length);
314 ctx->offset += length;
315 return (zip_int64_t)length;
317 case ZIP_SOURCE_STAT: {
318 zip_stat_t *st = ZIP_SOURCE_GET_ARGS(zip_stat_t, data, length, &ctx->error);
324 st->valid |= ZIP_STAT_SIZE;
325 st->size = ctx->length;
330 case ZIP_SOURCE_SUPPORTS:
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);
334 zip_error_set(&ctx->error, ZIP_ER_OPNOTSUPP, 0);
339 static zip_source_t *
340 source_nul(zip_t *zs, zip_uint64_t length) {
344 if ((ctx = (source_nul_t *)malloc(sizeof(*ctx))) == NULL) {
345 zip_error_set(zip_get_error(zs), ZIP_ER_MEMORY, 0);
349 zip_error_init(&ctx->error);
350 ctx->length = length;
353 if ((src = zip_source_function(zs, source_nul_cb, ctx)) == NULL) {
363 write_memory_src_to_file(const char *archive, zip_source_t *src) {
368 if (zip_source_stat(src, &zst) < 0) {
369 fprintf(stderr, "zip_source_stat on buffer failed: %s\n", zip_error_strerror(zip_source_error(src)));
372 if (zip_source_open(src) < 0) {
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));
380 fprintf(stderr, "zip_source_open on buffer failed: %s\n", zip_error_strerror(zip_source_error(src)));
383 if ((buf = malloc(zst.size)) == NULL) {
384 fprintf(stderr, "malloc failed: %s\n", strerror(errno));
385 zip_source_close(src);
388 if (zip_source_read(src, buf, zst.size) < (zip_int64_t)zst.size) {
389 fprintf(stderr, "zip_source_read on buffer failed: %s\n", zip_error_strerror(zip_source_error(src)));
390 zip_source_close(src);
394 zip_source_close(src);
395 if ((fp = fopen(archive, "wb")) == NULL) {
396 fprintf(stderr, "fopen failed: %s\n", strerror(errno));
400 if (fwrite(buf, zst.size, 1, fp) < 1) {
401 fprintf(stderr, "fwrite failed: %s\n", strerror(errno));
407 if (fclose(fp) != 0) {
408 fprintf(stderr, "fclose failed: %s\n", strerror(errno));
416 ziptool_open(const char *archive, int flags, zip_error_t *error, zip_uint64_t offset, zip_uint64_t len) {
417 switch (source_type) {
418 case SOURCE_TYPE_NONE:
419 za = read_from_file(archive, flags, error, offset, len);
422 case SOURCE_TYPE_IN_MEMORY:
423 za = read_to_memory(archive, flags, error, &memory_src);
426 case SOURCE_TYPE_HOLE:
427 za = read_hole(archive, flags, error);
436 ziptool_post_close(const char *archive) {
437 if (source_type == SOURCE_TYPE_IN_MEMORY) {
438 if (write_memory_src_to_file(archive, memory_src) < 0) {
441 zip_source_free(memory_src);