4
|
1 /* |
|
2 zip_close.c -- close zip archive and update changes |
|
3 Copyright (C) 1999-2015 Dieter Baron and Thomas Klausner |
|
4 |
|
5 This file is part of libzip, a library to manipulate ZIP archives. |
|
6 The authors can be contacted at <libzip@nih.at> |
|
7 |
|
8 Redistribution and use in source and binary forms, with or without |
|
9 modification, are permitted provided that the following conditions |
|
10 are met: |
|
11 1. Redistributions of source code must retain the above copyright |
|
12 notice, this list of conditions and the following disclaimer. |
|
13 2. Redistributions in binary form must reproduce the above copyright |
|
14 notice, this list of conditions and the following disclaimer in |
|
15 the documentation and/or other materials provided with the |
|
16 distribution. |
|
17 3. The names of the authors may not be used to endorse or promote |
|
18 products derived from this software without specific prior |
|
19 written permission. |
|
20 |
|
21 THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS |
|
22 OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
|
23 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
|
24 ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY |
|
25 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
|
26 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE |
|
27 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
|
28 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER |
|
29 IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR |
|
30 OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN |
|
31 IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
32 */ |
|
33 |
|
34 |
|
35 #include "zipint.h" |
|
36 |
|
37 #include <stdio.h> |
|
38 #include <stdlib.h> |
|
39 #include <string.h> |
|
40 #ifdef HAVE_STRINGS_H |
|
41 #include <strings.h> |
|
42 #endif |
|
43 #ifdef HAVE_UNISTD_H |
|
44 #include <unistd.h> |
|
45 #endif |
|
46 #include <sys/types.h> |
|
47 #include <sys/stat.h> |
|
48 #ifdef _WIN32 |
|
49 #include <io.h> |
|
50 #include <fcntl.h> |
|
51 #endif |
|
52 |
|
53 |
|
54 /* max deflate size increase: size + ceil(size/16k)*5+6 */ |
|
55 #define MAX_DEFLATE_SIZE_32 4293656963u |
|
56 |
|
57 static int add_data(zip_t *, zip_source_t *, zip_dirent_t *); |
|
58 static int copy_data(zip_t *, zip_uint64_t); |
|
59 static int copy_source(zip_t *, zip_source_t *); |
|
60 static int write_cdir(zip_t *, const zip_filelist_t *, zip_uint64_t); |
|
61 |
|
62 |
|
63 ZIP_EXTERN int |
|
64 zip_close(zip_t *za) |
|
65 { |
|
66 zip_uint64_t i, j, survivors; |
|
67 zip_int64_t off; |
|
68 int error; |
|
69 zip_filelist_t *filelist; |
|
70 int changed; |
|
71 |
|
72 if (za == NULL) |
|
73 return -1; |
|
74 |
|
75 changed = _zip_changed(za, &survivors); |
|
76 |
|
77 /* don't create zip files with no entries */ |
|
78 if (survivors == 0) { |
|
79 if ((za->open_flags & ZIP_TRUNCATE) || changed) { |
|
80 if (zip_source_remove(za->src) < 0) { |
|
81 _zip_error_set_from_source(&za->error, za->src); |
|
82 return -1; |
|
83 } |
|
84 } |
|
85 zip_discard(za); |
|
86 return 0; |
|
87 } |
|
88 |
|
89 if (!changed) { |
|
90 zip_discard(za); |
|
91 return 0; |
|
92 } |
|
93 |
|
94 if (survivors > za->nentry) { |
|
95 zip_error_set(&za->error, ZIP_ER_INTERNAL, 0); |
|
96 return -1; |
|
97 } |
|
98 |
|
99 if ((filelist=(zip_filelist_t *)malloc(sizeof(filelist[0])*(size_t)survivors)) == NULL) |
|
100 return -1; |
|
101 |
|
102 /* create list of files with index into original archive */ |
|
103 for (i=j=0; i<za->nentry; i++) { |
|
104 if (za->entry[i].deleted) |
|
105 continue; |
|
106 |
|
107 if (j >= survivors) { |
|
108 free(filelist); |
|
109 zip_error_set(&za->error, ZIP_ER_INTERNAL, 0); |
|
110 return -1; |
|
111 } |
|
112 |
|
113 filelist[j].idx = i; |
|
114 j++; |
|
115 } |
|
116 if (j < survivors) { |
|
117 free(filelist); |
|
118 zip_error_set(&za->error, ZIP_ER_INTERNAL, 0); |
|
119 return -1; |
|
120 } |
|
121 |
|
122 if (zip_source_begin_write(za->src) < 0) { |
|
123 _zip_error_set_from_source(&za->error, za->src); |
|
124 free(filelist); |
|
125 return -1; |
|
126 } |
|
127 |
|
128 error = 0; |
|
129 for (j=0; j<survivors; j++) { |
|
130 int new_data; |
|
131 zip_entry_t *entry; |
|
132 zip_dirent_t *de; |
|
133 |
|
134 i = filelist[j].idx; |
|
135 entry = za->entry+i; |
|
136 |
|
137 new_data = (ZIP_ENTRY_DATA_CHANGED(entry) || ZIP_ENTRY_CHANGED(entry, ZIP_DIRENT_COMP_METHOD)); |
|
138 |
|
139 /* create new local directory entry */ |
|
140 if (entry->changes == NULL) { |
|
141 if ((entry->changes=_zip_dirent_clone(entry->orig)) == NULL) { |
|
142 zip_error_set(&za->error, ZIP_ER_MEMORY, 0); |
|
143 error = 1; |
|
144 break; |
|
145 } |
|
146 } |
|
147 de = entry->changes; |
|
148 |
|
149 if (_zip_read_local_ef(za, i) < 0) { |
|
150 error = 1; |
|
151 break; |
|
152 } |
|
153 |
|
154 if ((off = zip_source_tell_write(za->src)) < 0) { |
|
155 error = 1; |
|
156 break; |
|
157 } |
|
158 de->offset = (zip_uint64_t)off; |
|
159 |
|
160 if (new_data) { |
|
161 zip_source_t *zs; |
|
162 |
|
163 zs = NULL; |
|
164 if (!ZIP_ENTRY_DATA_CHANGED(entry)) { |
|
165 if ((zs=_zip_source_zip_new(za, za, i, ZIP_FL_UNCHANGED, 0, 0, NULL)) == NULL) { |
|
166 error = 1; |
|
167 break; |
|
168 } |
|
169 } |
|
170 |
|
171 /* add_data writes dirent */ |
|
172 if (add_data(za, zs ? zs : entry->source, de) < 0) { |
|
173 error = 1; |
|
174 if (zs) |
|
175 zip_source_free(zs); |
|
176 break; |
|
177 } |
|
178 if (zs) |
|
179 zip_source_free(zs); |
|
180 } |
|
181 else { |
|
182 zip_uint64_t offset; |
|
183 |
|
184 /* when copying data, all sizes are known -> no data descriptor needed */ |
|
185 de->bitflags &= (zip_uint16_t)~ZIP_GPBF_DATA_DESCRIPTOR; |
|
186 if (_zip_dirent_write(za, de, ZIP_FL_LOCAL) < 0) { |
|
187 error = 1; |
|
188 break; |
|
189 } |
|
190 if ((offset=_zip_file_get_offset(za, i, &za->error)) == 0) { |
|
191 error = 1; |
|
192 break; |
|
193 } |
|
194 if (zip_source_seek(za->src, (zip_int64_t)offset, SEEK_SET) < 0) { |
|
195 _zip_error_set_from_source(&za->error, za->src); |
|
196 error = 1; |
|
197 break; |
|
198 } |
|
199 if (copy_data(za, de->comp_size) < 0) { |
|
200 error = 1; |
|
201 break; |
|
202 } |
|
203 } |
|
204 } |
|
205 |
|
206 if (!error) { |
|
207 if (write_cdir(za, filelist, survivors) < 0) |
|
208 error = 1; |
|
209 } |
|
210 |
|
211 free(filelist); |
|
212 |
|
213 if (!error) { |
|
214 if (zip_source_commit_write(za->src) != 0) { |
|
215 _zip_error_set_from_source(&za->error, za->src); |
|
216 error = 1; |
|
217 } |
|
218 } |
|
219 |
|
220 if (error) { |
|
221 zip_source_rollback_write(za->src); |
|
222 return -1; |
|
223 } |
|
224 |
|
225 zip_discard(za); |
|
226 |
|
227 return 0; |
|
228 } |
|
229 |
|
230 |
|
231 static int |
|
232 add_data(zip_t *za, zip_source_t *src, zip_dirent_t *de) |
|
233 { |
|
234 zip_int64_t offstart, offdata, offend; |
|
235 struct zip_stat st; |
|
236 zip_source_t *s2; |
|
237 int ret; |
|
238 int is_zip64; |
|
239 zip_flags_t flags; |
|
240 |
|
241 if (zip_source_stat(src, &st) < 0) { |
|
242 _zip_error_set_from_source(&za->error, src); |
|
243 return -1; |
|
244 } |
|
245 |
|
246 if ((st.valid & ZIP_STAT_COMP_METHOD) == 0) { |
|
247 st.valid |= ZIP_STAT_COMP_METHOD; |
|
248 st.comp_method = ZIP_CM_STORE; |
|
249 } |
|
250 |
|
251 if (ZIP_CM_IS_DEFAULT(de->comp_method) && st.comp_method != ZIP_CM_STORE) |
|
252 de->comp_method = st.comp_method; |
|
253 else if (de->comp_method == ZIP_CM_STORE && (st.valid & ZIP_STAT_SIZE)) { |
|
254 st.valid |= ZIP_STAT_COMP_SIZE; |
|
255 st.comp_size = st.size; |
|
256 } |
|
257 else { |
|
258 /* we'll recompress */ |
|
259 st.valid &= ~ZIP_STAT_COMP_SIZE; |
|
260 } |
|
261 |
|
262 |
|
263 flags = ZIP_EF_LOCAL; |
|
264 |
|
265 if ((st.valid & ZIP_STAT_SIZE) == 0) |
|
266 flags |= ZIP_FL_FORCE_ZIP64; |
|
267 else { |
|
268 de->uncomp_size = st.size; |
|
269 |
|
270 if ((st.valid & ZIP_STAT_COMP_SIZE) == 0) { |
|
271 if (( ((de->comp_method == ZIP_CM_DEFLATE || ZIP_CM_IS_DEFAULT(de->comp_method)) && st.size > MAX_DEFLATE_SIZE_32) |
|
272 || (de->comp_method != ZIP_CM_STORE && de->comp_method != ZIP_CM_DEFLATE && !ZIP_CM_IS_DEFAULT(de->comp_method)))) |
|
273 flags |= ZIP_FL_FORCE_ZIP64; |
|
274 } |
|
275 else |
|
276 de->comp_size = st.comp_size; |
|
277 } |
|
278 |
|
279 if ((offstart = zip_source_tell_write(za->src)) < 0) { |
|
280 return -1; |
|
281 } |
|
282 |
|
283 /* as long as we don't support non-seekable output, clear data descriptor bit */ |
|
284 de->bitflags &= (zip_uint16_t)~ZIP_GPBF_DATA_DESCRIPTOR; |
|
285 if ((is_zip64=_zip_dirent_write(za, de, flags)) < 0) |
|
286 return -1; |
|
287 |
|
288 |
|
289 if (st.comp_method == ZIP_CM_STORE || (ZIP_CM_IS_DEFAULT(de->comp_method) && st.comp_method != de->comp_method)) { |
|
290 zip_source_t *s_store, *s_crc; |
|
291 zip_compression_implementation comp_impl; |
|
292 |
|
293 if (st.comp_method != ZIP_CM_STORE) { |
|
294 if ((comp_impl=_zip_get_compression_implementation(st.comp_method)) == NULL) { |
|
295 zip_error_set(&za->error, ZIP_ER_COMPNOTSUPP, 0); |
|
296 return -1; |
|
297 } |
|
298 if ((s_store=comp_impl(za, src, st.comp_method, ZIP_CODEC_DECODE)) == NULL) { |
|
299 /* error set by comp_impl */ |
|
300 return -1; |
|
301 } |
|
302 } |
|
303 else { |
|
304 /* to have the same reference count to src as in the case where it's not stored */ |
|
305 zip_source_keep(src); |
|
306 s_store = src; |
|
307 } |
|
308 |
|
309 s_crc = zip_source_crc(za, s_store, 0); |
|
310 zip_source_free(s_store); |
|
311 if (s_crc == NULL) { |
|
312 return -1; |
|
313 } |
|
314 |
|
315 if (de->comp_method != ZIP_CM_STORE && ((st.valid & ZIP_STAT_SIZE) == 0 || st.size != 0)) { |
|
316 if ((comp_impl=_zip_get_compression_implementation(de->comp_method)) == NULL) { |
|
317 zip_error_set(&za->error, ZIP_ER_COMPNOTSUPP, 0); |
|
318 zip_source_free(s_crc); |
|
319 return -1; |
|
320 } |
|
321 s2 = comp_impl(za, s_crc, de->comp_method, ZIP_CODEC_ENCODE); |
|
322 zip_source_free(s_crc); |
|
323 if (s2 == NULL) { |
|
324 return -1; |
|
325 } |
|
326 } |
|
327 else { |
|
328 s2 = s_crc; |
|
329 } |
|
330 } |
|
331 else { |
|
332 zip_source_keep(src); |
|
333 s2 = src; |
|
334 } |
|
335 |
|
336 if ((offdata = zip_source_tell_write(za->src)) < 0) { |
|
337 return -1; |
|
338 } |
|
339 |
|
340 ret = copy_source(za, s2); |
|
341 |
|
342 if (zip_source_stat(s2, &st) < 0) |
|
343 ret = -1; |
|
344 |
|
345 zip_source_free(s2); |
|
346 |
|
347 if (ret < 0) |
|
348 return -1; |
|
349 |
|
350 if ((offend = zip_source_tell_write(za->src)) < 0) { |
|
351 return -1; |
|
352 } |
|
353 |
|
354 if (zip_source_seek_write(za->src, offstart, SEEK_SET) < 0) { |
|
355 _zip_error_set_from_source(&za->error, za->src); |
|
356 return -1; |
|
357 } |
|
358 |
|
359 if ((st.valid & (ZIP_STAT_COMP_METHOD|ZIP_STAT_CRC|ZIP_STAT_SIZE)) != (ZIP_STAT_COMP_METHOD|ZIP_STAT_CRC|ZIP_STAT_SIZE)) { |
|
360 zip_error_set(&za->error, ZIP_ER_INTERNAL, 0); |
|
361 return -1; |
|
362 } |
|
363 |
|
364 if ((de->changed & ZIP_DIRENT_LAST_MOD) == 0) { |
|
365 if (st.valid & ZIP_STAT_MTIME) |
|
366 de->last_mod = st.mtime; |
|
367 else |
|
368 time(&de->last_mod); |
|
369 } |
|
370 de->comp_method = st.comp_method; |
|
371 de->crc = st.crc; |
|
372 de->uncomp_size = st.size; |
|
373 de->comp_size = (zip_uint64_t)(offend - offdata); |
|
374 |
|
375 if ((ret=_zip_dirent_write(za, de, flags)) < 0) |
|
376 return -1; |
|
377 |
|
378 if (is_zip64 != ret) { |
|
379 /* Zip64 mismatch between preliminary file header written before data and final file header written afterwards */ |
|
380 zip_error_set(&za->error, ZIP_ER_INTERNAL, 0); |
|
381 return -1; |
|
382 } |
|
383 |
|
384 |
|
385 if (zip_source_seek_write(za->src, offend, SEEK_SET) < 0) { |
|
386 _zip_error_set_from_source(&za->error, za->src); |
|
387 return -1; |
|
388 } |
|
389 |
|
390 return 0; |
|
391 } |
|
392 |
|
393 |
|
394 static int |
|
395 copy_data(zip_t *za, zip_uint64_t len) |
|
396 { |
|
397 zip_uint8_t buf[BUFSIZE]; |
|
398 size_t n; |
|
399 |
|
400 while (len > 0) { |
|
401 n = len > sizeof(buf) ? sizeof(buf) : len; |
|
402 if (_zip_read(za->src, buf, n, &za->error) < 0) { |
|
403 return -1; |
|
404 } |
|
405 |
|
406 if (_zip_write(za, buf, n) < 0) { |
|
407 return -1; |
|
408 } |
|
409 |
|
410 len -= n; |
|
411 } |
|
412 |
|
413 return 0; |
|
414 } |
|
415 |
|
416 |
|
417 static int |
|
418 copy_source(zip_t *za, zip_source_t *src) |
|
419 { |
|
420 zip_uint8_t buf[BUFSIZE]; |
|
421 zip_int64_t n; |
|
422 int ret; |
|
423 |
|
424 if (zip_source_open(src) < 0) { |
|
425 _zip_error_set_from_source(&za->error, src); |
|
426 return -1; |
|
427 } |
|
428 |
|
429 ret = 0; |
|
430 while ((n=zip_source_read(src, buf, sizeof(buf))) > 0) { |
|
431 if (_zip_write(za, buf, (zip_uint64_t)n) < 0) { |
|
432 ret = -1; |
|
433 break; |
|
434 } |
|
435 } |
|
436 |
|
437 if (n < 0) { |
|
438 _zip_error_set_from_source(&za->error, src); |
|
439 ret = -1; |
|
440 } |
|
441 |
|
442 zip_source_close(src); |
|
443 |
|
444 return ret; |
|
445 } |
|
446 |
|
447 |
|
448 static int |
|
449 write_cdir(zip_t *za, const zip_filelist_t *filelist, zip_uint64_t survivors) |
|
450 { |
|
451 zip_int64_t cd_start, end, size; |
|
452 |
|
453 if ((cd_start = zip_source_tell_write(za->src)) < 0) { |
|
454 return -1; |
|
455 } |
|
456 |
|
457 if ((size=_zip_cdir_write(za, filelist, survivors)) < 0) { |
|
458 return -1; |
|
459 } |
|
460 |
|
461 if ((end = zip_source_tell_write(za->src)) < 0) { |
|
462 return -1; |
|
463 } |
|
464 |
|
465 return 0; |
|
466 } |
|
467 |
|
468 |
|
469 int |
|
470 _zip_changed(const zip_t *za, zip_uint64_t *survivorsp) |
|
471 { |
|
472 int changed; |
|
473 zip_uint64_t i, survivors; |
|
474 |
|
475 changed = 0; |
|
476 survivors = 0; |
|
477 |
|
478 if (za->comment_changed || za->ch_flags != za->flags) |
|
479 changed = 1; |
|
480 |
|
481 for (i=0; i<za->nentry; i++) { |
|
482 if (za->entry[i].deleted || za->entry[i].source || (za->entry[i].changes && za->entry[i].changes->changed != 0)) |
|
483 changed = 1; |
|
484 if (!za->entry[i].deleted) |
|
485 survivors++; |
|
486 } |
|
487 |
|
488 if (survivorsp) |
|
489 *survivorsp = survivors; |
|
490 |
|
491 return changed; |
|
492 } |