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