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