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