Mercurial > embed
annotate libzip/lib/zip_close.c @ 56:056ee6b5913e
libzip: update to 1.3.0, closes #654
author | David Demelier <markand@malikania.fr> |
---|---|
date | Tue, 10 Oct 2017 20:43:12 +0200 |
parents | 2306f4b04790 |
children |
rev | line source |
---|---|
4 | 1 /* |
2 zip_close.c -- close zip archive and update changes | |
56
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
3 Copyright (C) 1999-2016 Dieter Baron and Thomas Klausner |
4 | 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 static int add_data(zip_t *, zip_source_t *, zip_dirent_t *); | |
55 static int copy_data(zip_t *, zip_uint64_t); | |
56
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
56 static int copy_source(zip_t *, zip_source_t *, zip_int64_t); |
4 | 57 static int write_cdir(zip_t *, const zip_filelist_t *, zip_uint64_t); |
58 | |
59 ZIP_EXTERN int | |
60 zip_close(zip_t *za) | |
61 { | |
62 zip_uint64_t i, j, survivors; | |
63 zip_int64_t off; | |
64 int error; | |
65 zip_filelist_t *filelist; | |
66 int changed; | |
67 | |
68 if (za == NULL) | |
69 return -1; | |
70 | |
71 changed = _zip_changed(za, &survivors); | |
72 | |
73 /* don't create zip files with no entries */ | |
74 if (survivors == 0) { | |
75 if ((za->open_flags & ZIP_TRUNCATE) || changed) { | |
76 if (zip_source_remove(za->src) < 0) { | |
77 _zip_error_set_from_source(&za->error, za->src); | |
78 return -1; | |
79 } | |
80 } | |
81 zip_discard(za); | |
82 return 0; | |
83 } | |
84 | |
85 if (!changed) { | |
86 zip_discard(za); | |
87 return 0; | |
88 } | |
89 | |
90 if (survivors > za->nentry) { | |
91 zip_error_set(&za->error, ZIP_ER_INTERNAL, 0); | |
92 return -1; | |
93 } | |
94 | |
95 if ((filelist=(zip_filelist_t *)malloc(sizeof(filelist[0])*(size_t)survivors)) == NULL) | |
96 return -1; | |
97 | |
98 /* create list of files with index into original archive */ | |
99 for (i=j=0; i<za->nentry; i++) { | |
100 if (za->entry[i].deleted) | |
101 continue; | |
102 | |
103 if (j >= survivors) { | |
104 free(filelist); | |
105 zip_error_set(&za->error, ZIP_ER_INTERNAL, 0); | |
106 return -1; | |
107 } | |
108 | |
109 filelist[j].idx = i; | |
110 j++; | |
111 } | |
112 if (j < survivors) { | |
113 free(filelist); | |
114 zip_error_set(&za->error, ZIP_ER_INTERNAL, 0); | |
115 return -1; | |
116 } | |
117 | |
118 if (zip_source_begin_write(za->src) < 0) { | |
119 _zip_error_set_from_source(&za->error, za->src); | |
120 free(filelist); | |
121 return -1; | |
122 } | |
56
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
123 |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
124 _zip_progress_start(za->progress); |
4 | 125 error = 0; |
126 for (j=0; j<survivors; j++) { | |
127 int new_data; | |
128 zip_entry_t *entry; | |
129 zip_dirent_t *de; | |
130 | |
56
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
131 _zip_progress_subrange(za->progress, (double)j / (double)survivors, (double)(j+1) / (double)survivors); |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
132 |
4 | 133 i = filelist[j].idx; |
134 entry = za->entry+i; | |
135 | |
56
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
136 new_data = (ZIP_ENTRY_DATA_CHANGED(entry) || ZIP_ENTRY_CHANGED(entry, ZIP_DIRENT_COMP_METHOD) || ZIP_ENTRY_CHANGED(entry, ZIP_DIRENT_ENCRYPTION_METHOD)); |
4 | 137 |
138 /* create new local directory entry */ | |
139 if (entry->changes == NULL) { | |
140 if ((entry->changes=_zip_dirent_clone(entry->orig)) == NULL) { | |
141 zip_error_set(&za->error, ZIP_ER_MEMORY, 0); | |
142 error = 1; | |
143 break; | |
144 } | |
145 } | |
146 de = entry->changes; | |
147 | |
148 if (_zip_read_local_ef(za, i) < 0) { | |
149 error = 1; | |
150 break; | |
151 } | |
152 | |
153 if ((off = zip_source_tell_write(za->src)) < 0) { | |
154 error = 1; | |
155 break; | |
156 } | |
157 de->offset = (zip_uint64_t)off; | |
158 | |
159 if (new_data) { | |
160 zip_source_t *zs; | |
161 | |
162 zs = NULL; | |
163 if (!ZIP_ENTRY_DATA_CHANGED(entry)) { | |
164 if ((zs=_zip_source_zip_new(za, za, i, ZIP_FL_UNCHANGED, 0, 0, NULL)) == NULL) { | |
165 error = 1; | |
166 break; | |
167 } | |
168 } | |
169 | |
170 /* add_data writes dirent */ | |
171 if (add_data(za, zs ? zs : entry->source, de) < 0) { | |
172 error = 1; | |
173 if (zs) | |
174 zip_source_free(zs); | |
175 break; | |
176 } | |
177 if (zs) | |
178 zip_source_free(zs); | |
179 } | |
180 else { | |
181 zip_uint64_t offset; | |
182 | |
183 /* when copying data, all sizes are known -> no data descriptor needed */ | |
184 de->bitflags &= (zip_uint16_t)~ZIP_GPBF_DATA_DESCRIPTOR; | |
185 if (_zip_dirent_write(za, de, ZIP_FL_LOCAL) < 0) { | |
186 error = 1; | |
187 break; | |
188 } | |
189 if ((offset=_zip_file_get_offset(za, i, &za->error)) == 0) { | |
190 error = 1; | |
191 break; | |
192 } | |
193 if (zip_source_seek(za->src, (zip_int64_t)offset, SEEK_SET) < 0) { | |
194 _zip_error_set_from_source(&za->error, za->src); | |
195 error = 1; | |
196 break; | |
197 } | |
198 if (copy_data(za, de->comp_size) < 0) { | |
199 error = 1; | |
200 break; | |
201 } | |
202 } | |
203 } | |
204 | |
205 if (!error) { | |
206 if (write_cdir(za, filelist, survivors) < 0) | |
207 error = 1; | |
208 } | |
209 | |
210 free(filelist); | |
211 | |
212 if (!error) { | |
213 if (zip_source_commit_write(za->src) != 0) { | |
214 _zip_error_set_from_source(&za->error, za->src); | |
215 error = 1; | |
216 } | |
217 } | |
218 | |
219 if (error) { | |
220 zip_source_rollback_write(za->src); | |
221 return -1; | |
222 } | |
223 | |
56
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
224 _zip_progress_end(za->progress); |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
225 |
4 | 226 zip_discard(za); |
227 | |
228 return 0; | |
229 } | |
230 | |
231 | |
232 static int | |
233 add_data(zip_t *za, zip_source_t *src, zip_dirent_t *de) | |
234 { | |
56
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
235 zip_int64_t offstart, offdata, offend, data_length; |
4 | 236 struct zip_stat st; |
56
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
237 zip_source_t *src_final, *src_tmp; |
4 | 238 int ret; |
239 int is_zip64; | |
240 zip_flags_t flags; | |
56
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
241 zip_int8_t compression_flags; |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
242 bool needs_recompress, needs_decompress, needs_crc, needs_compress, needs_reencrypt, needs_decrypt, needs_encrypt; |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
243 |
4 | 244 if (zip_source_stat(src, &st) < 0) { |
245 _zip_error_set_from_source(&za->error, src); | |
246 return -1; | |
247 } | |
248 | |
249 if ((st.valid & ZIP_STAT_COMP_METHOD) == 0) { | |
250 st.valid |= ZIP_STAT_COMP_METHOD; | |
251 st.comp_method = ZIP_CM_STORE; | |
252 } | |
253 | |
254 if (ZIP_CM_IS_DEFAULT(de->comp_method) && st.comp_method != ZIP_CM_STORE) | |
255 de->comp_method = st.comp_method; | |
256 else if (de->comp_method == ZIP_CM_STORE && (st.valid & ZIP_STAT_SIZE)) { | |
257 st.valid |= ZIP_STAT_COMP_SIZE; | |
258 st.comp_size = st.size; | |
259 } | |
260 else { | |
261 /* we'll recompress */ | |
262 st.valid &= ~ZIP_STAT_COMP_SIZE; | |
263 } | |
264 | |
56
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
265 if ((st.valid & ZIP_STAT_ENCRYPTION_METHOD) == 0) { |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
266 st.valid |= ZIP_STAT_ENCRYPTION_METHOD; |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
267 st.encryption_method = ZIP_EM_NONE; |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
268 } |
4 | 269 |
270 flags = ZIP_EF_LOCAL; | |
271 | |
56
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
272 if ((st.valid & ZIP_STAT_SIZE) == 0) { |
4 | 273 flags |= ZIP_FL_FORCE_ZIP64; |
56
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
274 data_length = -1; |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
275 } |
4 | 276 else { |
277 de->uncomp_size = st.size; | |
56
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
278 /* this is technically incorrect (copy_source counts compressed data), but it's the best we have */ |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
279 data_length = (zip_int64_t)st.size; |
4 | 280 |
281 if ((st.valid & ZIP_STAT_COMP_SIZE) == 0) { | |
56
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
282 zip_uint64_t max_size; |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
283 |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
284 switch (ZIP_CM_ACTUAL(de->comp_method)) { |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
285 case ZIP_CM_BZIP2: |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
286 /* computed by looking at increase of 10 random files of size 1MB when |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
287 * compressed with bzip2, rounded up: 1.006 */ |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
288 max_size = 4269351188u; |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
289 break; |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
290 |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
291 case ZIP_CM_DEFLATE: |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
292 /* max deflate size increase: size + ceil(size/16k)*5+6 */ |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
293 max_size = 4293656963u; |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
294 break; |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
295 |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
296 case ZIP_CM_STORE: |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
297 max_size = 0xffffffffu; |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
298 break; |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
299 |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
300 default: |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
301 max_size = 0; |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
302 } |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
303 |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
304 if (st.size > max_size) { |
4 | 305 flags |= ZIP_FL_FORCE_ZIP64; |
56
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
306 } |
4 | 307 } |
308 else | |
309 de->comp_size = st.comp_size; | |
310 } | |
311 | |
312 if ((offstart = zip_source_tell_write(za->src)) < 0) { | |
56
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
313 _zip_error_set_from_source(&za->error, za->src); |
4 | 314 return -1; |
315 } | |
316 | |
317 /* as long as we don't support non-seekable output, clear data descriptor bit */ | |
318 de->bitflags &= (zip_uint16_t)~ZIP_GPBF_DATA_DESCRIPTOR; | |
56
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
319 if ((is_zip64=_zip_dirent_write(za, de, flags)) < 0) { |
4 | 320 return -1; |
56
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
321 } |
4 | 322 |
56
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
323 needs_recompress = st.comp_method != ZIP_CM_ACTUAL(de->comp_method); |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
324 needs_decompress = needs_recompress && (st.comp_method != ZIP_CM_STORE); |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
325 needs_crc = (st.comp_method == ZIP_CM_STORE) || needs_decompress; |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
326 needs_compress = needs_recompress && (de->comp_method != ZIP_CM_STORE); |
4 | 327 |
56
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
328 needs_reencrypt = needs_recompress || (de->changed & ZIP_DIRENT_PASSWORD) || (de->encryption_method != st.encryption_method); |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
329 needs_decrypt = needs_reencrypt && (st.encryption_method != ZIP_EM_NONE); |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
330 needs_encrypt = needs_reencrypt && (de->encryption_method != ZIP_EM_NONE); |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
331 |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
332 src_final = src; |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
333 zip_source_keep(src_final); |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
334 |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
335 if (needs_decrypt) { |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
336 zip_encryption_implementation impl; |
4 | 337 |
56
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
338 if ((impl = _zip_get_encryption_implementation(st.encryption_method, ZIP_CODEC_DECODE)) == NULL) { |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
339 zip_error_set(&za->error, ZIP_ER_ENCRNOTSUPP, 0); |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
340 zip_source_free(src_final); |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
341 return -1; |
4 | 342 } |
56
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
343 if ((src_tmp = impl(za, src_final, st.encryption_method, ZIP_CODEC_DECODE, za->default_password)) == NULL) { |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
344 /* error set by impl */ |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
345 zip_source_free(src_final); |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
346 return -1; |
4 | 347 } |
348 | |
56
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
349 zip_source_free(src_final); |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
350 src_final = src_tmp; |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
351 } |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
352 |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
353 if (needs_decompress) { |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
354 if ((src_tmp = zip_source_decompress(za, src_final, st.comp_method)) == NULL) { |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
355 zip_source_free(src_final); |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
356 return -1; |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
357 } |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
358 |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
359 zip_source_free(src_final); |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
360 src_final = src_tmp; |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
361 } |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
362 |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
363 if (needs_crc) { |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
364 if ((src_tmp = zip_source_crc(za, src_final, 0)) == NULL) { |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
365 zip_source_free(src_final); |
4 | 366 return -1; |
367 } | |
368 | |
56
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
369 zip_source_free(src_final); |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
370 src_final = src_tmp; |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
371 } |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
372 |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
373 if (needs_compress) { |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
374 if ((src_tmp = zip_source_compress(za, src_final, de->comp_method, de->compression_level)) == NULL) { |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
375 zip_source_free(src_final); |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
376 return -1; |
4 | 377 } |
56
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
378 |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
379 zip_source_free(src_final); |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
380 src_final = src_tmp; |
4 | 381 } |
382 | |
56
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
383 |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
384 if (needs_encrypt) { |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
385 zip_encryption_implementation impl; |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
386 const char *password = NULL; |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
387 |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
388 if (de->password) { |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
389 password = de->password; |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
390 } else if (za->default_password) { |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
391 password = za->default_password; |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
392 } |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
393 |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
394 if ((impl = _zip_get_encryption_implementation(de->encryption_method, ZIP_CODEC_ENCODE)) == NULL) { |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
395 zip_error_set(&za->error, ZIP_ER_ENCRNOTSUPP, 0); |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
396 zip_source_free(src_final); |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
397 return -1; |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
398 } |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
399 if ((src_tmp = impl(za, src_final, de->encryption_method, ZIP_CODEC_ENCODE, password)) == NULL) { |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
400 /* error set by impl */ |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
401 zip_source_free(src_final); |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
402 return -1; |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
403 } |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
404 |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
405 zip_source_free(src_final); |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
406 src_final = src_tmp; |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
407 } |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
408 |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
409 |
4 | 410 if ((offdata = zip_source_tell_write(za->src)) < 0) { |
56
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
411 _zip_error_set_from_source(&za->error, za->src); |
4 | 412 return -1; |
413 } | |
414 | |
56
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
415 ret = copy_source(za, src_final, data_length); |
4 | 416 |
56
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
417 if (zip_source_stat(src_final, &st) < 0) { |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
418 _zip_error_set_from_source(&za->error, src_final); |
4 | 419 ret = -1; |
56
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
420 } |
4 | 421 |
56
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
422 if ((compression_flags = zip_source_get_compression_flags(src_final)) < 0) { |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
423 _zip_error_set_from_source(&za->error, src_final); |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
424 ret = -1; |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
425 } |
4 | 426 |
56
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
427 zip_source_free(src_final); |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
428 |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
429 if (ret < 0) { |
4 | 430 return -1; |
56
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
431 } |
4 | 432 |
433 if ((offend = zip_source_tell_write(za->src)) < 0) { | |
56
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
434 _zip_error_set_from_source(&za->error, za->src); |
4 | 435 return -1; |
436 } | |
437 | |
438 if (zip_source_seek_write(za->src, offstart, SEEK_SET) < 0) { | |
439 _zip_error_set_from_source(&za->error, za->src); | |
440 return -1; | |
441 } | |
442 | |
443 if ((st.valid & (ZIP_STAT_COMP_METHOD|ZIP_STAT_CRC|ZIP_STAT_SIZE)) != (ZIP_STAT_COMP_METHOD|ZIP_STAT_CRC|ZIP_STAT_SIZE)) { | |
444 zip_error_set(&za->error, ZIP_ER_INTERNAL, 0); | |
445 return -1; | |
446 } | |
447 | |
448 if ((de->changed & ZIP_DIRENT_LAST_MOD) == 0) { | |
449 if (st.valid & ZIP_STAT_MTIME) | |
450 de->last_mod = st.mtime; | |
451 else | |
452 time(&de->last_mod); | |
453 } | |
454 de->comp_method = st.comp_method; | |
455 de->crc = st.crc; | |
456 de->uncomp_size = st.size; | |
457 de->comp_size = (zip_uint64_t)(offend - offdata); | |
56
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
458 de->bitflags = (zip_uint16_t)((de->bitflags & (zip_uint16_t)~6) | ((zip_uint8_t)compression_flags << 1)); |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
459 _zip_dirent_set_version_needed(de, (flags & ZIP_FL_FORCE_ZIP64) != 0); |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
460 |
4 | 461 if ((ret=_zip_dirent_write(za, de, flags)) < 0) |
462 return -1; | |
463 | |
464 if (is_zip64 != ret) { | |
465 /* Zip64 mismatch between preliminary file header written before data and final file header written afterwards */ | |
466 zip_error_set(&za->error, ZIP_ER_INTERNAL, 0); | |
467 return -1; | |
468 } | |
469 | |
470 if (zip_source_seek_write(za->src, offend, SEEK_SET) < 0) { | |
471 _zip_error_set_from_source(&za->error, za->src); | |
472 return -1; | |
473 } | |
474 | |
475 return 0; | |
476 } | |
477 | |
478 | |
479 static int | |
480 copy_data(zip_t *za, zip_uint64_t len) | |
481 { | |
482 zip_uint8_t buf[BUFSIZE]; | |
483 size_t n; | |
56
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
484 double total = (double)len; |
4 | 485 |
486 while (len > 0) { | |
487 n = len > sizeof(buf) ? sizeof(buf) : len; | |
488 if (_zip_read(za->src, buf, n, &za->error) < 0) { | |
489 return -1; | |
490 } | |
491 | |
492 if (_zip_write(za, buf, n) < 0) { | |
493 return -1; | |
494 } | |
495 | |
496 len -= n; | |
56
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
497 |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
498 _zip_progress_update(za->progress, (total - (double)len) / total); |
4 | 499 } |
500 | |
501 return 0; | |
502 } | |
503 | |
504 | |
505 static int | |
56
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
506 copy_source(zip_t *za, zip_source_t *src, zip_int64_t data_length) |
4 | 507 { |
508 zip_uint8_t buf[BUFSIZE]; | |
56
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
509 zip_int64_t n, current; |
4 | 510 int ret; |
511 | |
512 if (zip_source_open(src) < 0) { | |
513 _zip_error_set_from_source(&za->error, src); | |
514 return -1; | |
515 } | |
516 | |
517 ret = 0; | |
56
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
518 current = 0; |
4 | 519 while ((n=zip_source_read(src, buf, sizeof(buf))) > 0) { |
520 if (_zip_write(za, buf, (zip_uint64_t)n) < 0) { | |
521 ret = -1; | |
522 break; | |
523 } | |
56
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
524 if (n == sizeof(buf) && za->progress && data_length > 0) { |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
525 current += n; |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
526 _zip_progress_update(za->progress, (double)current/(double)data_length); |
056ee6b5913e
libzip: update to 1.3.0, closes #654
David Demelier <markand@malikania.fr>
parents:
4
diff
changeset
|
527 } |
4 | 528 } |
529 | |
530 if (n < 0) { | |
531 _zip_error_set_from_source(&za->error, src); | |
532 ret = -1; | |
533 } | |
534 | |
535 zip_source_close(src); | |
536 | |
537 return ret; | |
538 } | |
539 | |
540 static int | |
541 write_cdir(zip_t *za, const zip_filelist_t *filelist, zip_uint64_t survivors) | |
542 { | |
543 zip_int64_t cd_start, end, size; | |
544 | |
545 if ((cd_start = zip_source_tell_write(za->src)) < 0) { | |
546 return -1; | |
547 } | |
548 | |
549 if ((size=_zip_cdir_write(za, filelist, survivors)) < 0) { | |
550 return -1; | |
551 } | |
552 | |
553 if ((end = zip_source_tell_write(za->src)) < 0) { | |
554 return -1; | |
555 } | |
556 | |
557 return 0; | |
558 } | |
559 | |
560 | |
561 int | |
562 _zip_changed(const zip_t *za, zip_uint64_t *survivorsp) | |
563 { | |
564 int changed; | |
565 zip_uint64_t i, survivors; | |
566 | |
567 changed = 0; | |
568 survivors = 0; | |
569 | |
570 if (za->comment_changed || za->ch_flags != za->flags) | |
571 changed = 1; | |
572 | |
573 for (i=0; i<za->nentry; i++) { | |
574 if (za->entry[i].deleted || za->entry[i].source || (za->entry[i].changes && za->entry[i].changes->changed != 0)) | |
575 changed = 1; | |
576 if (!za->entry[i].deleted) | |
577 survivors++; | |
578 } | |
579 | |
580 if (survivorsp) | |
581 *survivorsp = survivors; | |
582 | |
583 return changed; | |
584 } |