xref: /PHP-7.0/ext/zip/lib/zip_close.c (revision 0d57c06b)
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
zip_close(zip_t * za)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
add_data(zip_t * za,zip_source_t * src,zip_dirent_t * de)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
copy_data(zip_t * za,zip_uint64_t len)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
copy_source(zip_t * za,zip_source_t * src)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
write_cdir(zip_t * za,const zip_filelist_t * filelist,zip_uint64_t survivors)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
_zip_changed(const zip_t * za,zip_uint64_t * survivorsp)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 }
493