php-internal-docs 8.4.8
Unofficial docs for php/php-src
Loading...
Searching...
No Matches
zip.c
Go to the documentation of this file.
1/*
2 +----------------------------------------------------------------------+
3 | ZIP archive support for Phar |
4 +----------------------------------------------------------------------+
5 | Copyright (c) The PHP Group |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | https://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
15 | Authors: Gregory Beaver <cellog@php.net> |
16 +----------------------------------------------------------------------+
17*/
18
19#include "phar_internal.h"
20#include "ext/standard/crc32.h"
21#include "ext/standard/php_string.h" /* For php_stristr() */
22
23#define PHAR_GET_16(var) ((uint16_t)((((uint16_t)var[0]) & 0xff) | \
24 (((uint16_t)var[1]) & 0xff) << 8))
25#define PHAR_GET_32(var) ((uint32_t)((((uint32_t)var[0]) & 0xff) | \
26 (((uint32_t)var[1]) & 0xff) << 8 | \
27 (((uint32_t)var[2]) & 0xff) << 16 | \
28 (((uint32_t)var[3]) & 0xff) << 24))
29static inline void phar_write_32(char buffer[4], uint32_t value)
30{
31 buffer[3] = (unsigned char) ((value & 0xff000000) >> 24);
32 buffer[2] = (unsigned char) ((value & 0xff0000) >> 16);
33 buffer[1] = (unsigned char) ((value & 0xff00) >> 8);
34 buffer[0] = (unsigned char) (value & 0xff);
35}
36static inline void phar_write_16(char buffer[2], uint32_t value)
37{
38 buffer[1] = (unsigned char) ((value & 0xff00) >> 8);
39 buffer[0] = (unsigned char) (value & 0xff);
40}
41# define PHAR_SET_32(var, value) phar_write_32(var, (uint32_t) (value));
42# define PHAR_SET_16(var, value) phar_write_16(var, (uint16_t) (value));
43
44static int phar_zip_process_extra(php_stream *fp, phar_entry_info *entry, uint16_t len) /* {{{ */
45{
46 union {
48 phar_zip_unix3 unix3;
50 } h;
51 size_t read;
52
53 do {
54 if (sizeof(h.header) != php_stream_read(fp, (char *) &h.header, sizeof(h.header))) {
55 return FAILURE;
56 }
57
58 if (h.header.tag[0] == 'U' && h.header.tag[1] == 'T') {
59 /* Unix timestamp header found.
60 * The flags field indicates which timestamp fields are present.
61 * The size with a timestamp is at least 5 (== 9 - tag size) bytes, but may be larger.
62 * We only store the modification time in the entry, so only read that.
63 */
64 const size_t min_size = 5;
65 uint16_t header_size = PHAR_GET_16(h.header.size);
66 if (header_size >= min_size) {
67 read = php_stream_read(fp, &h.time.flags, min_size);
68 if (read != min_size) {
69 return FAILURE;
70 }
71 if (h.time.flags & (1 << 0)) {
72 /* Modification time set */
73 entry->timestamp = PHAR_GET_32(h.time.time);
74 }
75
76 len -= header_size + 4;
77
78 /* Consume remaining bytes */
79 if (header_size != read) {
80 php_stream_seek(fp, header_size - read, SEEK_CUR);
81 }
82 continue;
83 }
84 /* Fallthrough to next if to skip header */
85 }
86
87 if (h.header.tag[0] != 'n' || h.header.tag[1] != 'u') {
88 /* skip to next header */
89 php_stream_seek(fp, PHAR_GET_16(h.header.size), SEEK_CUR);
90 len -= PHAR_GET_16(h.header.size) + 4;
91 continue;
92 }
93
94 /* unix3 header found */
95 read = php_stream_read(fp, (char *) &(h.unix3.crc32), sizeof(h.unix3) - sizeof(h.header));
96 len -= read + 4;
97
98 if (sizeof(h.unix3) - sizeof(h.header) != read) {
99 return FAILURE;
100 }
101
102 if (PHAR_GET_16(h.unix3.size) > sizeof(h.unix3) - 4) {
103 /* skip symlink filename - we may add this support in later */
104 php_stream_seek(fp, PHAR_GET_16(h.unix3.size) - sizeof(h.unix3.size), SEEK_CUR);
105 }
106
107 /* set permissions */
109
110 if (entry->is_dir) {
111 entry->flags |= PHAR_GET_16(h.unix3.perms) & PHAR_ENT_PERM_MASK;
112 } else {
113 entry->flags |= PHAR_GET_16(h.unix3.perms) & PHAR_ENT_PERM_MASK;
114 }
115
116 } while (len);
117
118 return SUCCESS;
119}
120/* }}} */
121
122/*
123 extracted from libzip
124 zip_dirent.c -- read directory entry (local or central), clean dirent
125 Copyright (C) 1999, 2003, 2004, 2005 Dieter Baron and Thomas Klausner
126
127 This function is part of libzip, a library to manipulate ZIP archives.
128 The authors can be contacted at <nih@giga.or.at>
129
130 Redistribution and use in source and binary forms, with or without
131 modification, are permitted provided that the following conditions
132 are met:
133 1. Redistributions of source code must retain the above copyright
134 notice, this list of conditions and the following disclaimer.
135 2. Redistributions in binary form must reproduce the above copyright
136 notice, this list of conditions and the following disclaimer in
137 the documentation and/or other materials provided with the
138 distribution.
139 3. The names of the authors may not be used to endorse or promote
140 products derived from this software without specific prior
141 written permission.
142
143 THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
144 OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
145 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
146 ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
147 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
148 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
149 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
150 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
151 IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
152 OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
153 IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
154 */
155static time_t phar_zip_d2u_time(const char *cdtime, const char *cddate) /* {{{ */
156{
157 int dtime = PHAR_GET_16(cdtime), ddate = PHAR_GET_16(cddate);
158 struct tm *tm, tmbuf;
159 time_t now;
160
161 now = time(NULL);
162 tm = php_localtime_r(&now, &tmbuf);
163
164 tm->tm_year = ((ddate>>9)&127) + 1980 - 1900;
165 tm->tm_mon = ((ddate>>5)&15) - 1;
166 tm->tm_mday = ddate&31;
167
168 tm->tm_hour = (dtime>>11)&31;
169 tm->tm_min = (dtime>>5)&63;
170 tm->tm_sec = (dtime<<1)&62;
171
172 return mktime(tm);
173}
174/* }}} */
175
176static void phar_zip_u2d_time(time_t time, char *dtime, char *ddate) /* {{{ */
177{
178 uint16_t ctime, cdate;
179 struct tm *tm, tmbuf;
180
181 tm = php_localtime_r(&time, &tmbuf);
182 /* Note: tm_year is the year - 1900 */
183 if (tm->tm_year >= 80) {
184 cdate = ((tm->tm_year+1900-1980)<<9) + ((tm->tm_mon+1)<<5) + tm->tm_mday;
185 ctime = ((tm->tm_hour)<<11) + ((tm->tm_min)<<5) + ((tm->tm_sec)>>1);
186 } else {
187 /* This is the earliest date/time supported by zip. */
188 cdate = (1<<5) + 1; /* 1980-01-01 */
189 ctime = 0; /* 00:00:00 */
190 }
191
192 PHAR_SET_16(dtime, ctime);
193 PHAR_SET_16(ddate, cdate);
194}
195/* }}} */
196
197static char *phar_find_eocd(const char *s, size_t n)
198{
199 const char *end = s + n + sizeof("PK\5\6") - 1 - sizeof(phar_zip_dir_end);
200
201 /* search backwards for end of central directory signatures */
202 do {
203 uint16_t comment_len;
204 const char *eocd_start = zend_memnrstr(s, "PK\5\6", sizeof("PK\5\6") - 1, end);
205
206 if (eocd_start == NULL) {
207 return NULL;
208 }
209 ZEND_ASSERT(eocd_start + sizeof(phar_zip_dir_end) <= s + n);
210 comment_len = PHAR_GET_16(((phar_zip_dir_end *) eocd_start)->comment_len);
211 if (eocd_start + sizeof(phar_zip_dir_end) + comment_len == s + n) {
212 /* we can't be sure, but this looks like the proper EOCD signature */
213 return (char *) eocd_start;
214 }
215 end = eocd_start;
216 } while (end > s);
217 return NULL;
218}
219
229int phar_parse_zipfile(php_stream *fp, char *fname, size_t fname_len, char *alias, size_t alias_len, phar_archive_data** pphar, char **error) /* {{{ */
230{
231 phar_zip_dir_end locator;
232 char buf[sizeof(locator) + 65536];
234 uint16_t i;
235 phar_archive_data *mydata = NULL;
236 phar_entry_info entry = {0};
237 char *p = buf, *ext, *actual_alias = NULL;
238 char *metadata = NULL;
239
240 size = php_stream_tell(fp);
241
242 if (size > sizeof(locator) + 65536) {
243 /* seek to max comment length + end of central directory record */
244 size = sizeof(locator) + 65536;
245 if (FAILURE == php_stream_seek(fp, -size, SEEK_END)) {
247 if (error) {
248 spprintf(error, 4096, "phar error: unable to search for end of central directory in zip-based phar \"%s\"", fname);
249 }
250 return FAILURE;
251 }
252 } else {
254 }
255
256 if (!php_stream_read(fp, buf, size)) {
258 if (error) {
259 spprintf(error, 4096, "phar error: unable to read in data to search for end of central directory in zip-based phar \"%s\"", fname);
260 }
261 return FAILURE;
262 }
263
264 if ((p = phar_find_eocd(buf, size)) != NULL) {
265 memcpy((void *)&locator, (void *) p, sizeof(locator));
266 if (PHAR_GET_16(locator.centraldisk) != 0 || PHAR_GET_16(locator.disknumber) != 0) {
267 /* split archives not handled */
269 if (error) {
270 spprintf(error, 4096, "phar error: split archives spanning multiple zips cannot be processed in zip-based phar \"%s\"", fname);
271 }
272 return FAILURE;
273 }
274
275 if (PHAR_GET_16(locator.counthere) != PHAR_GET_16(locator.count)) {
276 if (error) {
277 spprintf(error, 4096, "phar error: corrupt zip archive, conflicting file count in end of central directory record in zip-based phar \"%s\"", fname);
278 }
280 return FAILURE;
281 }
282
283 mydata = pecalloc(1, sizeof(phar_archive_data), PHAR_G(persist));
284 mydata->is_persistent = PHAR_G(persist);
285
286 /* read in archive comment, if any */
287 if (PHAR_GET_16(locator.comment_len)) {
288
289 metadata = p + sizeof(locator);
290
291 if (PHAR_GET_16(locator.comment_len) != size - (metadata - buf)) {
292 if (error) {
293 spprintf(error, 4096, "phar error: corrupt zip archive, zip file comment truncated in zip-based phar \"%s\"", fname);
294 }
296 pefree(mydata, mydata->is_persistent);
297 return FAILURE;
298 }
299
300 phar_parse_metadata_lazy(metadata, &mydata->metadata_tracker, PHAR_GET_16(locator.comment_len), mydata->is_persistent);
301 } else {
303 }
304
305 goto foundit;
306 }
307
309
310 if (error) {
311 spprintf(error, 4096, "phar error: end of central directory not found in zip-based phar \"%s\"", fname);
312 }
313
314 return FAILURE;
315foundit:
316 mydata->fname = pestrndup(fname, fname_len, mydata->is_persistent);
317#ifdef PHP_WIN32
318 phar_unixify_path_separators(mydata->fname, fname_len);
319#endif
320 mydata->is_zip = 1;
321 mydata->fname_len = fname_len;
322 ext = strrchr(mydata->fname, '/');
323
324 if (ext) {
325 mydata->ext = memchr(ext, '.', (mydata->fname + fname_len) - ext);
326 if (mydata->ext == ext) {
327 mydata->ext = memchr(ext + 1, '.', (mydata->fname + fname_len) - ext - 1);
328 }
329 if (mydata->ext) {
330 mydata->ext_len = (mydata->fname + fname_len) - mydata->ext;
331 }
332 }
333
334 /* clean up on big-endian systems */
335 /* seek to central directory */
337 /* read in central directory */
338 zend_hash_init(&mydata->manifest, PHAR_GET_16(locator.count),
339 zend_get_hash_value, destroy_phar_manifest_entry, (bool)mydata->is_persistent);
340 zend_hash_init(&mydata->mounted_dirs, 5,
341 zend_get_hash_value, NULL, (bool)mydata->is_persistent);
342 zend_hash_init(&mydata->virtual_dirs, PHAR_GET_16(locator.count) * 2,
343 zend_get_hash_value, NULL, (bool)mydata->is_persistent);
344 entry.phar = mydata;
345 entry.is_zip = 1;
346 entry.fp_type = PHAR_FP;
347 entry.is_persistent = mydata->is_persistent;
348#define PHAR_ZIP_FAIL_FREE(errmsg, save) \
349 zend_hash_destroy(&mydata->manifest); \
350 HT_INVALIDATE(&mydata->manifest); \
351 zend_hash_destroy(&mydata->mounted_dirs); \
352 HT_INVALIDATE(&mydata->mounted_dirs); \
353 zend_hash_destroy(&mydata->virtual_dirs); \
354 HT_INVALIDATE(&mydata->virtual_dirs); \
355 php_stream_close(fp); \
356 phar_metadata_tracker_free(&mydata->metadata_tracker, mydata->is_persistent); \
357 if (mydata->signature) { \
358 efree(mydata->signature); \
359 } \
360 if (error) { \
361 spprintf(error, 4096, "phar error: %s in zip-based phar \"%s\"", errmsg, mydata->fname); \
362 } \
363 pefree(mydata->fname, mydata->is_persistent); \
364 if (mydata->alias) { \
365 pefree(mydata->alias, mydata->is_persistent); \
366 } \
367 pefree(mydata, mydata->is_persistent); \
368 efree(save); \
369 return FAILURE;
370#define PHAR_ZIP_FAIL(errmsg) \
371 zend_hash_destroy(&mydata->manifest); \
372 HT_INVALIDATE(&mydata->manifest); \
373 zend_hash_destroy(&mydata->mounted_dirs); \
374 HT_INVALIDATE(&mydata->mounted_dirs); \
375 zend_hash_destroy(&mydata->virtual_dirs); \
376 HT_INVALIDATE(&mydata->virtual_dirs); \
377 php_stream_close(fp); \
378 phar_metadata_tracker_free(&mydata->metadata_tracker, mydata->is_persistent); \
379 if (mydata->signature) { \
380 efree(mydata->signature); \
381 } \
382 if (error) { \
383 spprintf(error, 4096, "phar error: %s in zip-based phar \"%s\"", errmsg, mydata->fname); \
384 } \
385 pefree(mydata->fname, mydata->is_persistent); \
386 if (mydata->alias) { \
387 pefree(mydata->alias, mydata->is_persistent); \
388 } \
389 pefree(mydata, mydata->is_persistent); \
390 return FAILURE;
391
392 /* add each central directory item to the manifest */
393 for (i = 0; i < PHAR_GET_16(locator.count); ++i) {
395 zend_off_t beforeus = php_stream_tell(fp);
396
398 entry.metadata_tracker.str = NULL;
399
400 if (sizeof(zipentry) != php_stream_read(fp, (char *) &zipentry, sizeof(zipentry))) {
401 PHAR_ZIP_FAIL("unable to read central directory entry, truncated");
402 }
403
404 /* clean up for bigendian systems */
405 if (memcmp("PK\1\2", zipentry.signature, 4)) {
406 /* corrupted entry */
407 PHAR_ZIP_FAIL("corrupted central directory entry, no magic signature");
408 }
409
410 if (entry.is_persistent) {
411 entry.manifest_pos = i;
412 }
413
414 entry.compressed_filesize = PHAR_GET_32(zipentry.compsize);
416 entry.crc32 = PHAR_GET_32(zipentry.crc32);
417 /* do not PHAR_GET_16 either on the next line */
418 entry.timestamp = phar_zip_d2u_time(zipentry.timestamp, zipentry.datestamp);
420 entry.header_offset = PHAR_GET_32(zipentry.offset);
421
422 if (PHAR_GET_16(zipentry.flags) & PHAR_ZIP_FLAG_ENCRYPTED) {
423 PHAR_ZIP_FAIL("Cannot process encrypted zip files");
424 }
425
426 if (!PHAR_GET_16(zipentry.filename_len)) {
427 PHAR_ZIP_FAIL("Cannot process zips created from stdin (zero-length filename)");
428 }
429
430 entry.filename_len = PHAR_GET_16(zipentry.filename_len);
431 entry.filename = (char *) pemalloc(entry.filename_len + 1, entry.is_persistent);
432
433 if (entry.filename_len != php_stream_read(fp, entry.filename, entry.filename_len)) {
434 pefree(entry.filename, entry.is_persistent);
435 PHAR_ZIP_FAIL("unable to read in filename from central directory, truncated");
436 }
437
438 entry.filename[entry.filename_len] = '\0';
439
440 if (entry.filename[entry.filename_len - 1] == '/') {
441 entry.is_dir = 1;
442 if(entry.filename_len > 1) {
443 entry.filename_len--;
444 }
446 } else {
447 entry.is_dir = 0;
448 }
449
450 phar_zip_file_header local; /* Warning: only filled in when the entry is not a directory! */
451 if (!entry.is_dir) {
452 /* A file has a central directory entry, and a local file header. Both of these contain the filename
453 * and the extra field data. However, at least the extra field data does not have to match between the two!
454 * This happens for example for the "Extended Timestamp extra field" where the local header has 2 extra fields
455 * in comparison to the central header. So we have to use the local header to find the right offset to the file
456 * contents, otherwise we're reading some garbage bytes before reading the actual file contents. */
457 zend_off_t current_central_dir_pos = php_stream_tell(fp);
458
460 if (sizeof(local) != php_stream_read(fp, (char *) &local, sizeof(local))) {
461 pefree(entry.filename, entry.is_persistent);
462 PHAR_ZIP_FAIL("phar error: internal corruption (cannot read local file header)");
463 }
464 php_stream_seek(fp, current_central_dir_pos, SEEK_SET);
465
466 /* verify local header
467 * Note: normally I'd check the crc32, and file sizes too here, but that breaks tests zip/bug48791.phpt & zip/odt.phpt,
468 * suggesting that something may be wrong with those files or the assumption doesn't hold. Anyway, the other checks
469 * _are_ performed for the alias file as was done in the past too. */
470 if (entry.filename_len != PHAR_GET_16(local.filename_len)) {
471 pefree(entry.filename, entry.is_persistent);
472 PHAR_ZIP_FAIL("phar error: internal corruption (local file header does not match central directory)");
473 }
474
475 entry.offset = entry.offset_abs = entry.header_offset
476 + sizeof(phar_zip_file_header)
477 + entry.filename_len
478 + PHAR_GET_16(local.extra_len);
479 } else {
480 entry.offset = entry.offset_abs = entry.header_offset
481 + sizeof(phar_zip_file_header)
482 + entry.filename_len
483 + PHAR_GET_16(zipentry.extra_len);
484 }
485
486 if (entry.filename_len == sizeof(".phar/signature.bin")-1 && !strncmp(entry.filename, ".phar/signature.bin", sizeof(".phar/signature.bin")-1)) {
487 size_t read;
488 php_stream *sigfile;
489 char *sig;
490 size_t sig_len;
491
492 pefree(entry.filename, entry.is_persistent);
493
494 if (entry.uncompressed_filesize > 0x10000) {
495 PHAR_ZIP_FAIL("signatures larger than 64 KiB are not supported");
496 }
497
498 sigfile = php_stream_fopen_tmpfile();
499 if (!sigfile) {
500 PHAR_ZIP_FAIL("couldn't open temporary file");
501 }
502
504 /* copy file contents + local headers and zip comment, if any, to be hashed for signature */
506 /* seek to central directory */
508 /* copy central directory header */
509 php_stream_copy_to_stream_ex(fp, sigfile, beforeus - PHAR_GET_32(locator.cdir_offset), NULL);
510 if (metadata) {
511 php_stream_write(sigfile, metadata, PHAR_GET_16(locator.comment_len));
512 }
513 php_stream_seek(fp, entry.offset, SEEK_SET);
514 sig = (char *) emalloc(entry.uncompressed_filesize);
515 read = php_stream_read(fp, sig, entry.uncompressed_filesize);
516 if (read != entry.uncompressed_filesize || read <= 8) {
517 php_stream_close(sigfile);
518 efree(sig);
519 PHAR_ZIP_FAIL("signature cannot be read");
520 }
521 mydata->sig_flags = PHAR_GET_32(sig);
522 if (FAILURE == phar_verify_signature(sigfile, php_stream_tell(sigfile), mydata->sig_flags, sig + 8, entry.uncompressed_filesize - 8, fname, &mydata->signature, &sig_len, error)) {
523 efree(sig);
524 if (error) {
525 char *save;
526 php_stream_close(sigfile);
527 spprintf(&save, 4096, "signature cannot be verified: %s", *error);
528 efree(*error);
529 PHAR_ZIP_FAIL_FREE(save, save);
530 } else {
531 php_stream_close(sigfile);
532 PHAR_ZIP_FAIL("signature cannot be verified");
533 }
534 }
535 mydata->sig_len = sig_len;
536 php_stream_close(sigfile);
537 efree(sig);
538 /* signature checked out, let's ensure this is the last file in the phar */
539 if (i != PHAR_GET_16(locator.count) - 1) {
540 PHAR_ZIP_FAIL("entries exist after signature, invalid phar");
541 }
542
543 continue;
544 }
545
546 phar_add_virtual_dirs(mydata, entry.filename, entry.filename_len);
547
548 if (PHAR_GET_16(zipentry.extra_len)) {
549 zend_off_t loc = php_stream_tell(fp);
550 if (FAILURE == phar_zip_process_extra(fp, &entry, PHAR_GET_16(zipentry.extra_len))) {
551 pefree(entry.filename, entry.is_persistent);
552 PHAR_ZIP_FAIL("Unable to process extra field header for file in central directory");
553 }
554 php_stream_seek(fp, loc + PHAR_GET_16(zipentry.extra_len), SEEK_SET);
555 }
556
557 switch (PHAR_GET_16(zipentry.compressed)) {
558 case PHAR_ZIP_COMP_NONE :
559 /* compression flag already set */
560 break;
563 if (!PHAR_G(has_zlib)) {
564 pefree(entry.filename, entry.is_persistent);
565 PHAR_ZIP_FAIL("zlib extension is required");
566 }
567 break;
570 if (!PHAR_G(has_bz2)) {
571 pefree(entry.filename, entry.is_persistent);
572 PHAR_ZIP_FAIL("bzip2 extension is required");
573 }
574 break;
575 case 1 :
576 pefree(entry.filename, entry.is_persistent);
577 PHAR_ZIP_FAIL("unsupported compression method (Shrunk) used in this zip");
578 case 2 :
579 case 3 :
580 case 4 :
581 case 5 :
582 pefree(entry.filename, entry.is_persistent);
583 PHAR_ZIP_FAIL("unsupported compression method (Reduce) used in this zip");
584 case 6 :
585 pefree(entry.filename, entry.is_persistent);
586 PHAR_ZIP_FAIL("unsupported compression method (Implode) used in this zip");
587 case 7 :
588 pefree(entry.filename, entry.is_persistent);
589 PHAR_ZIP_FAIL("unsupported compression method (Tokenize) used in this zip");
590 case 9 :
591 pefree(entry.filename, entry.is_persistent);
592 PHAR_ZIP_FAIL("unsupported compression method (Deflate64) used in this zip");
593 case 10 :
594 pefree(entry.filename, entry.is_persistent);
595 PHAR_ZIP_FAIL("unsupported compression method (PKWare Implode/old IBM TERSE) used in this zip");
596 case 14 :
597 pefree(entry.filename, entry.is_persistent);
598 PHAR_ZIP_FAIL("unsupported compression method (LZMA) used in this zip");
599 case 18 :
600 pefree(entry.filename, entry.is_persistent);
601 PHAR_ZIP_FAIL("unsupported compression method (IBM TERSE) used in this zip");
602 case 19 :
603 pefree(entry.filename, entry.is_persistent);
604 PHAR_ZIP_FAIL("unsupported compression method (IBM LZ77) used in this zip");
605 case 97 :
606 pefree(entry.filename, entry.is_persistent);
607 PHAR_ZIP_FAIL("unsupported compression method (WavPack) used in this zip");
608 case 98 :
609 pefree(entry.filename, entry.is_persistent);
610 PHAR_ZIP_FAIL("unsupported compression method (PPMd) used in this zip");
611 default :
612 pefree(entry.filename, entry.is_persistent);
613 PHAR_ZIP_FAIL("unsupported compression method (unknown) used in this zip");
614 }
615
616 /* get file metadata */
617 if (PHAR_GET_16(zipentry.comment_len)) {
618 if (PHAR_GET_16(zipentry.comment_len) != php_stream_read(fp, buf, PHAR_GET_16(zipentry.comment_len))) {
619 pefree(entry.filename, entry.is_persistent);
620 PHAR_ZIP_FAIL("unable to read in file comment, truncated");
621 }
622
623 p = buf;
625 } else {
627 }
628
629 if (!actual_alias && entry.filename_len == sizeof(".phar/alias.txt")-1 && !strncmp(entry.filename, ".phar/alias.txt", sizeof(".phar/alias.txt")-1)) {
630 php_stream_filter *filter;
631
632 /* archive alias found */
633
634 /* verify local header */
635 ZEND_ASSERT(!entry.is_dir);
636 if (entry.crc32 != PHAR_GET_32(local.crc32) || entry.uncompressed_filesize != PHAR_GET_32(local.uncompsize) || entry.compressed_filesize != PHAR_GET_32(local.compsize)) {
637 pefree(entry.filename, entry.is_persistent);
638 PHAR_ZIP_FAIL("phar error: internal corruption of zip-based phar (local header of alias does not match central directory)");
639 }
640
641 zend_off_t restore_pos = php_stream_tell(fp);
642 php_stream_seek(fp, entry.offset, SEEK_SET);
643 /* these next lines should be for php < 5.2.6 after 5.3 filters are fixed */
644 fp->writepos = 0;
645 fp->readpos = 0;
646 php_stream_seek(fp, entry.offset, SEEK_SET);
647 fp->writepos = 0;
648 fp->readpos = 0;
649 /* the above lines should be for php < 5.2.6 after 5.3 filters are fixed */
650
651 mydata->alias_len = entry.uncompressed_filesize;
652 if (entry.flags & PHAR_ENT_COMPRESSED_GZ) {
653 filter = php_stream_filter_create("zlib.inflate", NULL, php_stream_is_persistent(fp));
654
655 if (!filter) {
656 pefree(entry.filename, entry.is_persistent);
657 PHAR_ZIP_FAIL("unable to decompress alias, zlib filter creation failed");
658 }
659
661
662 // TODO: refactor to avoid reallocation ???
663//??? entry.uncompressed_filesize = php_stream_copy_to_mem(fp, &actual_alias, entry.uncompressed_filesize, 0)
664 {
666 if (str) {
667 entry.uncompressed_filesize = ZSTR_LEN(str);
668 actual_alias = estrndup(ZSTR_VAL(str), ZSTR_LEN(str));
670 } else {
671 actual_alias = NULL;
672 entry.uncompressed_filesize = 0;
673 }
674 }
675
676 if (!entry.uncompressed_filesize || !actual_alias) {
677 pefree(entry.filename, entry.is_persistent);
678 PHAR_ZIP_FAIL("unable to read in alias, truncated");
679 }
680
681 php_stream_filter_flush(filter, 1);
682 php_stream_filter_remove(filter, 1);
683
684 } else if (entry.flags & PHAR_ENT_COMPRESSED_BZ2) {
685 filter = php_stream_filter_create("bzip2.decompress", NULL, php_stream_is_persistent(fp));
686
687 if (!filter) {
688 pefree(entry.filename, entry.is_persistent);
689 PHAR_ZIP_FAIL("unable to read in alias, bzip2 filter creation failed");
690 }
691
693
694 // TODO: refactor to avoid reallocation ???
695//??? entry.uncompressed_filesize = php_stream_copy_to_mem(fp, &actual_alias, entry.uncompressed_filesize, 0)
696 {
698 if (str) {
699 entry.uncompressed_filesize = ZSTR_LEN(str);
700 actual_alias = estrndup(ZSTR_VAL(str), ZSTR_LEN(str));
702 } else {
703 actual_alias = NULL;
704 entry.uncompressed_filesize = 0;
705 }
706 }
707
708 if (!entry.uncompressed_filesize || !actual_alias) {
709 pefree(entry.filename, entry.is_persistent);
710 PHAR_ZIP_FAIL("unable to read in alias, truncated");
711 }
712
713 php_stream_filter_flush(filter, 1);
714 php_stream_filter_remove(filter, 1);
715 } else {
716 // TODO: refactor to avoid reallocation ???
717//??? entry.uncompressed_filesize = php_stream_copy_to_mem(fp, &actual_alias, entry.uncompressed_filesize, 0)
718 {
720 if (str) {
721 entry.uncompressed_filesize = ZSTR_LEN(str);
722 actual_alias = estrndup(ZSTR_VAL(str), ZSTR_LEN(str));
724 } else {
725 actual_alias = NULL;
726 entry.uncompressed_filesize = 0;
727 }
728 }
729
730 if (!entry.uncompressed_filesize || !actual_alias) {
731 pefree(entry.filename, entry.is_persistent);
732 PHAR_ZIP_FAIL("unable to read in alias, truncated");
733 }
734 }
735
736 /* return to central directory parsing */
737 php_stream_seek(fp, restore_pos, SEEK_SET);
738 }
739
740 phar_set_inode(&entry);
741 zend_hash_str_add_mem(&mydata->manifest, entry.filename, entry.filename_len, (void *)&entry, sizeof(phar_entry_info));
742 }
743
744 if (zend_hash_str_exists(&(mydata->manifest), ".phar/stub.php", sizeof(".phar/stub.php")-1)) {
745 mydata->is_data = 0;
746 } else {
747 mydata->is_data = 1;
748 }
749
750 /* ensure signature set */
751 if (!mydata->is_data && PHAR_G(require_hash) && !mydata->signature) {
752 PHAR_ZIP_FAIL("signature is missing");
753 }
754
755 mydata->fp = fp;
756
757 zend_hash_str_add_ptr(&(PHAR_G(phar_fname_map)), mydata->fname, fname_len, mydata);
758
759 if (actual_alias) {
760 phar_archive_data *fd_ptr;
761
762 if (!phar_validate_alias(actual_alias, mydata->alias_len)) {
763 if (error) {
764 spprintf(error, 4096, "phar error: invalid alias \"%s\" in zip-based phar \"%s\"", actual_alias, fname);
765 }
766 efree(actual_alias);
767 zend_hash_str_del(&(PHAR_G(phar_fname_map)), mydata->fname, fname_len);
768 return FAILURE;
769 }
770
771 mydata->is_temporary_alias = 0;
772
773 if (NULL != (fd_ptr = zend_hash_str_find_ptr(&(PHAR_G(phar_alias_map)), actual_alias, mydata->alias_len))) {
774 if (SUCCESS != phar_free_alias(fd_ptr, actual_alias, mydata->alias_len)) {
775 if (error) {
776 spprintf(error, 4096, "phar error: Unable to add zip-based phar \"%s\" with implicit alias, alias is already in use", fname);
777 }
778 efree(actual_alias);
779 zend_hash_str_del(&(PHAR_G(phar_fname_map)), mydata->fname, fname_len);
780 return FAILURE;
781 }
782 }
783
784 mydata->alias = entry.is_persistent ? pestrndup(actual_alias, mydata->alias_len, 1) : actual_alias;
785
786 if (entry.is_persistent) {
787 efree(actual_alias);
788 }
789
790 zend_hash_str_add_ptr(&(PHAR_G(phar_alias_map)), mydata->alias, mydata->alias_len, mydata);
791 } else {
792 phar_archive_data *fd_ptr;
793
794 if (alias_len) {
795 if (NULL != (fd_ptr = zend_hash_str_find_ptr(&(PHAR_G(phar_alias_map)), alias, alias_len))) {
796 if (SUCCESS != phar_free_alias(fd_ptr, alias, alias_len)) {
797 if (error) {
798 spprintf(error, 4096, "phar error: Unable to add zip-based phar \"%s\" with explicit alias, alias is already in use", fname);
799 }
800 zend_hash_str_del(&(PHAR_G(phar_fname_map)), mydata->fname, fname_len);
801 return FAILURE;
802 }
803 }
804
805 zend_hash_str_add_ptr(&(PHAR_G(phar_alias_map)), alias, alias_len, mydata);
806 mydata->alias = pestrndup(alias, alias_len, mydata->is_persistent);
807 mydata->alias_len = alias_len;
808 } else {
809 mydata->alias = pestrndup(mydata->fname, fname_len, mydata->is_persistent);
810 mydata->alias_len = fname_len;
811 }
812
813 mydata->is_temporary_alias = 1;
814 }
815
816 if (pphar) {
817 *pphar = mydata;
818 }
819
820 return SUCCESS;
821}
822/* }}} */
823
827int phar_open_or_create_zip(char *fname, size_t fname_len, char *alias, size_t alias_len, int is_data, uint32_t options, phar_archive_data** pphar, char **error) /* {{{ */
828{
829 phar_archive_data *phar;
830 int ret = phar_create_or_parse_filename(fname, fname_len, alias, alias_len, is_data, options, &phar, error);
831
832 if (FAILURE == ret) {
833 return FAILURE;
834 }
835
836 if (pphar) {
837 *pphar = phar;
838 }
839
840 phar->is_data = is_data;
841
842 if (phar->is_zip) {
843 return ret;
844 }
845
846 if (phar->is_brandnew) {
847 phar->is_zip = 1;
848 phar->is_tar = 0;
849 return SUCCESS;
850 }
851
852 /* we've reached here - the phar exists and is a regular phar */
853 if (error) {
854 spprintf(error, 4096, "phar zip error: phar \"%s\" already exists as a regular phar and must be deleted from disk prior to creating as a zip-based phar", fname);
855 }
856
857 return FAILURE;
858}
859/* }}} */
860
869/* perform final modification of zip contents for each file in the manifest before saving */
870static int phar_zip_changed_apply_int(phar_entry_info *entry, void *arg) /* {{{ */
871{
873 phar_zip_unix3 perms;
875 struct _phar_zip_pass *p;
876 uint32_t newcrc32;
878 int not_really_modified = 0;
879 p = (struct _phar_zip_pass*) arg;
880 uint16_t general_purpose_flags;
881
882 if (entry->is_mounted) {
884 }
885
886 if (entry->is_deleted) {
887 if (entry->fp_refcount <= 0) {
889 } else {
890 /* we can't delete this in-memory until it is closed */
892 }
893 }
894
895 phar_add_virtual_dirs(entry->phar, entry->filename, entry->filename_len);
896 memset(&local, 0, sizeof(local));
897 memset(&central, 0, sizeof(central));
898 memset(&perms, 0, sizeof(perms));
899 memcpy(local.signature, "PK\3\4", 4);
900 memcpy(central.signature, "PK\1\2", 4);
901 PHAR_SET_16(central.extra_len, sizeof(perms));
902 PHAR_SET_16(local.extra_len, sizeof(perms));
903 perms.tag[0] = 'n';
904 perms.tag[1] = 'u';
905 PHAR_SET_16(perms.size, sizeof(perms) - 4);
906 PHAR_SET_16(perms.perms, entry->flags & PHAR_ENT_PERM_MASK);
907 {
908 uint32_t crc = (uint32_t) php_crc32_bulk_init();
909 CRC32(crc, perms.perms[0]);
910 CRC32(crc, perms.perms[1]);
912 }
913
914 if (entry->flags & PHAR_ENT_COMPRESSED_GZ) {
917 }
918
919 if (entry->flags & PHAR_ENT_COMPRESSED_BZ2) {
922 }
923
924 /* do not use PHAR_GET_16 on either field of the next line */
925 phar_zip_u2d_time(entry->timestamp, local.timestamp, local.datestamp);
926 memcpy(central.timestamp, local.timestamp, sizeof(local.timestamp));
927 memcpy(central.datestamp, local.datestamp, sizeof(local.datestamp));
928 PHAR_SET_16(central.filename_len, entry->filename_len + (entry->is_dir ? 1 : 0));
929 PHAR_SET_16(local.filename_len, entry->filename_len + (entry->is_dir ? 1 : 0));
930 // set language encoding flag (all filenames have to be UTF-8 anyway)
931 general_purpose_flags = PHAR_GET_16(central.flags);
932 PHAR_SET_16(central.flags, general_purpose_flags | (1 << 11));
933 general_purpose_flags = PHAR_GET_16(local.flags);
934 PHAR_SET_16(local.flags, general_purpose_flags | (1 << 11));
935 PHAR_SET_32(central.offset, php_stream_tell(p->filefp));
936
937 /* do extra field for perms later */
938 if (entry->is_modified) {
939 php_stream_filter *filter;
940 php_stream *efp;
941
942 if (entry->is_dir) {
943 entry->is_modified = 0;
944 if (entry->fp_type == PHAR_MOD && entry->fp != entry->phar->fp && entry->fp != entry->phar->ufp) {
945 php_stream_close(entry->fp);
946 entry->fp = NULL;
947 entry->fp_type = PHAR_FP;
948 }
949 goto continue_dir;
950 }
951
952 if (FAILURE == phar_open_entry_fp(entry, p->error, 0)) {
953 spprintf(p->error, 0, "unable to open file contents of file \"%s\" in zip-based phar \"%s\"", entry->filename, entry->phar->fname);
955 }
956
957 /* we can be modified and already be compressed, such as when chmod() is executed */
958 if (entry->flags & PHAR_ENT_COMPRESSION_MASK && (entry->old_flags == entry->flags || !entry->old_flags)) {
959 not_really_modified = 1;
960 goto is_compressed;
961 }
962
963 if (-1 == phar_seek_efp(entry, 0, SEEK_SET, 0, 0)) {
964 spprintf(p->error, 0, "unable to seek to start of file \"%s\" to zip-based phar \"%s\"", entry->filename, entry->phar->fname);
966 }
967
968 efp = phar_get_efp(entry, 0);
969 newcrc32 = php_crc32_bulk_init();
970
972
973 entry->crc32 = php_crc32_bulk_end(newcrc32);
976
977 if (!(entry->flags & PHAR_ENT_COMPRESSION_MASK)) {
978 /* not compressed */
982 goto not_compressed;
983 }
984
985 filter = php_stream_filter_create(phar_compress_filter(entry, 0), NULL, 0);
986
987 if (!filter) {
988 if (entry->flags & PHAR_ENT_COMPRESSED_GZ) {
989 spprintf(p->error, 0, "unable to gzip compress file \"%s\" to zip-based phar \"%s\"", entry->filename, entry->phar->fname);
990 } else {
991 spprintf(p->error, 0, "unable to bzip2 compress file \"%s\" to zip-based phar \"%s\"", entry->filename, entry->phar->fname);
992 }
994 }
995
996 /* create new file that holds the compressed version */
997 /* work around inability to specify freedom in write and strictness
998 in read count */
999 entry->cfp = php_stream_fopen_tmpfile();
1000
1001 if (!entry->cfp) {
1002 spprintf(p->error, 0, "unable to create temporary file for file \"%s\" while creating zip-based phar \"%s\"", entry->filename, entry->phar->fname);
1003 return ZEND_HASH_APPLY_STOP;
1004 }
1005
1006 php_stream_flush(efp);
1007
1008 if (-1 == phar_seek_efp(entry, 0, SEEK_SET, 0, 0)) {
1009 spprintf(p->error, 0, "unable to seek to start of file \"%s\" to zip-based phar \"%s\"", entry->filename, entry->phar->fname);
1010 return ZEND_HASH_APPLY_STOP;
1011 }
1012
1013 php_stream_filter_append((&entry->cfp->writefilters), filter);
1014
1015 if (SUCCESS != php_stream_copy_to_stream_ex(efp, entry->cfp, entry->uncompressed_filesize, NULL)) {
1016 spprintf(p->error, 0, "unable to copy compressed file contents of file \"%s\" while creating new phar \"%s\"", entry->filename, entry->phar->fname);
1017 return ZEND_HASH_APPLY_STOP;
1018 }
1019
1020 php_stream_filter_flush(filter, 1);
1021 php_stream_flush(entry->cfp);
1022 php_stream_filter_remove(filter, 1);
1023 php_stream_seek(entry->cfp, 0, SEEK_END);
1024 entry->compressed_filesize = (uint32_t) php_stream_tell(entry->cfp);
1025 PHAR_SET_32(central.compsize, entry->compressed_filesize);
1027 /* generate crc on compressed file */
1028 php_stream_rewind(entry->cfp);
1029 entry->old_flags = entry->flags;
1030 entry->is_modified = 1;
1031 } else {
1032is_compressed:
1035 PHAR_SET_32(central.compsize, entry->compressed_filesize);
1037 if (p->old) {
1038 if (-1 == php_stream_seek(p->old, entry->offset_abs, SEEK_SET)) {
1039 spprintf(p->error, 0, "unable to seek to start of file \"%s\" while creating zip-based phar \"%s\"", entry->filename, entry->phar->fname);
1040 return ZEND_HASH_APPLY_STOP;
1041 }
1042 }
1043 }
1044not_compressed:
1045 PHAR_SET_32(central.crc32, entry->crc32);
1046 PHAR_SET_32(local.crc32, entry->crc32);
1047continue_dir:
1048 /* set file metadata */
1052 }
1053
1054 entry->header_offset = php_stream_tell(p->filefp);
1055 offset = entry->header_offset + sizeof(local) + entry->filename_len + (entry->is_dir ? 1 : 0) + sizeof(perms);
1056
1057 if (sizeof(local) != php_stream_write(p->filefp, (char *)&local, sizeof(local))) {
1058 spprintf(p->error, 0, "unable to write local file header of file \"%s\" to zip-based phar \"%s\"", entry->filename, entry->phar->fname);
1059 return ZEND_HASH_APPLY_STOP;
1060 }
1061
1062 if (sizeof(central) != php_stream_write(p->centralfp, (char *)&central, sizeof(central))) {
1063 spprintf(p->error, 0, "unable to write central directory entry for file \"%s\" while creating zip-based phar \"%s\"", entry->filename, entry->phar->fname);
1064 return ZEND_HASH_APPLY_STOP;
1065 }
1066
1067 if (entry->is_dir) {
1068 if (entry->filename_len != php_stream_write(p->filefp, entry->filename, entry->filename_len)) {
1069 spprintf(p->error, 0, "unable to write filename to local directory entry for directory \"%s\" while creating zip-based phar \"%s\"", entry->filename, entry->phar->fname);
1070 return ZEND_HASH_APPLY_STOP;
1071 }
1072
1073 if (1 != php_stream_write(p->filefp, "/", 1)) {
1074 spprintf(p->error, 0, "unable to write filename to local directory entry for directory \"%s\" while creating zip-based phar \"%s\"", entry->filename, entry->phar->fname);
1075 return ZEND_HASH_APPLY_STOP;
1076 }
1077
1078 if (entry->filename_len != php_stream_write(p->centralfp, entry->filename, entry->filename_len)) {
1079 spprintf(p->error, 0, "unable to write filename to central directory entry for directory \"%s\" while creating zip-based phar \"%s\"", entry->filename, entry->phar->fname);
1080 return ZEND_HASH_APPLY_STOP;
1081 }
1082
1083 if (1 != php_stream_write(p->centralfp, "/", 1)) {
1084 spprintf(p->error, 0, "unable to write filename to central directory entry for directory \"%s\" while creating zip-based phar \"%s\"", entry->filename, entry->phar->fname);
1085 return ZEND_HASH_APPLY_STOP;
1086 }
1087 } else {
1088 if (entry->filename_len != php_stream_write(p->filefp, entry->filename, entry->filename_len)) {
1089 spprintf(p->error, 0, "unable to write filename to local directory entry for file \"%s\" while creating zip-based phar \"%s\"", entry->filename, entry->phar->fname);
1090 return ZEND_HASH_APPLY_STOP;
1091 }
1092
1093 if (entry->filename_len != php_stream_write(p->centralfp, entry->filename, entry->filename_len)) {
1094 spprintf(p->error, 0, "unable to write filename to central directory entry for file \"%s\" while creating zip-based phar \"%s\"", entry->filename, entry->phar->fname);
1095 return ZEND_HASH_APPLY_STOP;
1096 }
1097 }
1098
1099 if (sizeof(perms) != php_stream_write(p->filefp, (char *)&perms, sizeof(perms))) {
1100 spprintf(p->error, 0, "unable to write local extra permissions file header of file \"%s\" to zip-based phar \"%s\"", entry->filename, entry->phar->fname);
1101 return ZEND_HASH_APPLY_STOP;
1102 }
1103
1104 if (sizeof(perms) != php_stream_write(p->centralfp, (char *)&perms, sizeof(perms))) {
1105 spprintf(p->error, 0, "unable to write central extra permissions file header of file \"%s\" to zip-based phar \"%s\"", entry->filename, entry->phar->fname);
1106 return ZEND_HASH_APPLY_STOP;
1107 }
1108
1109 if (!not_really_modified && entry->is_modified) {
1110 if (entry->cfp) {
1111 if (SUCCESS != php_stream_copy_to_stream_ex(entry->cfp, p->filefp, entry->compressed_filesize, NULL)) {
1112 spprintf(p->error, 0, "unable to write compressed contents of file \"%s\" in zip-based phar \"%s\"", entry->filename, entry->phar->fname);
1113 return ZEND_HASH_APPLY_STOP;
1114 }
1115
1116 php_stream_close(entry->cfp);
1117 entry->cfp = NULL;
1118 } else {
1119 if (FAILURE == phar_open_entry_fp(entry, p->error, 0)) {
1120 return ZEND_HASH_APPLY_STOP;
1121 }
1122
1123 phar_seek_efp(entry, 0, SEEK_SET, 0, 0);
1124
1125 if (SUCCESS != php_stream_copy_to_stream_ex(phar_get_efp(entry, 0), p->filefp, entry->uncompressed_filesize, NULL)) {
1126 spprintf(p->error, 0, "unable to write contents of file \"%s\" in zip-based phar \"%s\"", entry->filename, entry->phar->fname);
1127 return ZEND_HASH_APPLY_STOP;
1128 }
1129 }
1130
1131 if (entry->fp_type == PHAR_MOD && entry->fp != entry->phar->fp && entry->fp != entry->phar->ufp && entry->fp_refcount == 0) {
1132 php_stream_close(entry->fp);
1133 }
1134
1135 entry->is_modified = 0;
1136 } else {
1137 entry->is_modified = 0;
1138 if (entry->fp_refcount) {
1139 /* open file pointers refer to this fp, do not free the stream */
1140 switch (entry->fp_type) {
1141 case PHAR_FP:
1142 p->free_fp = 0;
1143 break;
1144 case PHAR_UFP:
1145 p->free_ufp = 0;
1146 default:
1147 break;
1148 }
1149 }
1150
1151 if (!entry->is_dir && entry->compressed_filesize && SUCCESS != php_stream_copy_to_stream_ex(p->old, p->filefp, entry->compressed_filesize, NULL)) {
1152 spprintf(p->error, 0, "unable to copy contents of file \"%s\" while creating zip-based phar \"%s\"", entry->filename, entry->phar->fname);
1153 return ZEND_HASH_APPLY_STOP;
1154 }
1155 }
1156
1157 entry->fp = NULL;
1158 entry->offset = entry->offset_abs = offset;
1159 entry->fp_type = PHAR_FP;
1160
1161 if (entry->metadata_tracker.str) {
1163 spprintf(p->error, 0, "unable to write metadata as file comment for file \"%s\" while creating zip-based phar \"%s\"", entry->filename, entry->phar->fname);
1164 return ZEND_HASH_APPLY_STOP;
1165 }
1166 }
1167
1168 return ZEND_HASH_APPLY_KEEP;
1169}
1170/* }}} */
1171
1172static int phar_zip_changed_apply(zval *zv, void *arg) /* {{{ */
1173{
1174 return phar_zip_changed_apply_int(Z_PTR_P(zv), arg);
1175}
1176/* }}} */
1177
1178static int phar_zip_applysignature(phar_archive_data *phar, struct _phar_zip_pass *pass) /* {{{ */
1179{
1180 /* add signature for executable tars or tars explicitly set with setSignatureAlgorithm */
1181 if (!phar->is_data || phar->sig_flags) {
1182 size_t signature_length;
1183 char *signature, sigbuf[8];
1184 phar_entry_info entry = {0};
1185 php_stream *newfile;
1186 zend_off_t tell;
1187
1188 newfile = php_stream_fopen_tmpfile();
1189 if (newfile == NULL) {
1190 spprintf(pass->error, 0, "phar error: unable to create temporary file for the signature file");
1191 return FAILURE;
1192 }
1193 tell = php_stream_tell(pass->filefp);
1194 /* copy the local files, central directory, and the zip comment to generate the hash */
1195 php_stream_seek(pass->filefp, 0, SEEK_SET);
1196 php_stream_copy_to_stream_ex(pass->filefp, newfile, tell, NULL);
1197 tell = php_stream_tell(pass->centralfp);
1198 php_stream_seek(pass->centralfp, 0, SEEK_SET);
1199 php_stream_copy_to_stream_ex(pass->centralfp, newfile, tell, NULL);
1200 if (phar->metadata_tracker.str) {
1202 }
1203
1204 if (FAILURE == phar_create_signature(phar, newfile, &signature, &signature_length, pass->error)) {
1205 if (pass->error) {
1206 char *save = *(pass->error);
1207 spprintf(pass->error, 0, "phar error: unable to write signature to zip-based phar: %s", save);
1208 efree(save);
1209 }
1210
1211 php_stream_close(newfile);
1212 return FAILURE;
1213 }
1214
1215 entry.filename = ".phar/signature.bin";
1216 entry.filename_len = sizeof(".phar/signature.bin")-1;
1217 entry.fp = php_stream_fopen_tmpfile();
1218 entry.fp_type = PHAR_MOD;
1219 entry.is_modified = 1;
1220 if (entry.fp == NULL) {
1221 spprintf(pass->error, 0, "phar error: unable to create temporary file for signature");
1222 return FAILURE;
1223 }
1224
1225 PHAR_SET_32(sigbuf, phar->sig_flags);
1226 PHAR_SET_32(sigbuf + 4, signature_length);
1227
1228 if (Z_UL(8) != php_stream_write(entry.fp, sigbuf, 8) || signature_length != php_stream_write(entry.fp, signature, signature_length)) {
1229 efree(signature);
1230 if (pass->error) {
1231 spprintf(pass->error, 0, "phar error: unable to write signature to zip-based phar %s", phar->fname);
1232 }
1233
1234 php_stream_close(newfile);
1235 return FAILURE;
1236 }
1237
1238 efree(signature);
1239 entry.uncompressed_filesize = entry.compressed_filesize = signature_length + 8;
1240 entry.phar = phar;
1241 /* throw out return value and write the signature */
1242 phar_zip_changed_apply_int(&entry, (void *)pass);
1243 php_stream_close(newfile);
1244
1245 if (pass->error && *(pass->error)) {
1246 /* error is set by writeheaders */
1247 return FAILURE;
1248 }
1249 } /* signature */
1250 return SUCCESS;
1251}
1252/* }}} */
1253
1254void phar_zip_flush(phar_archive_data *phar, zend_string *user_stub, bool is_default_stub, char **error) /* {{{ */
1255{
1256 static const char newstub[] = "<?php // zip-based phar archive stub file\n__HALT_COMPILER();";
1257 static const char halt_stub[] = "__HALT_COMPILER();";
1258
1259 php_stream *oldfile;
1260 bool must_close_old_file = false;
1261 phar_entry_info entry = {0};
1262 char *temperr = NULL;
1263 struct _phar_zip_pass pass;
1264 phar_zip_dir_end eocd;
1265 uint32_t cdir_size, cdir_offset;
1266
1267 pass.error = &temperr;
1269 entry.timestamp = time(NULL);
1270 entry.is_modified = 1;
1271 entry.is_zip = true;
1272 entry.phar = phar;
1273 entry.fp_type = PHAR_MOD;
1274
1275 if (phar->is_persistent) {
1276 if (error) {
1277 spprintf(error, 0, "internal error: attempt to flush cached zip-based phar \"%s\"", phar->fname);
1278 }
1279 return;
1280 }
1281
1282 if (phar->is_data) {
1283 goto nostub;
1284 }
1285
1286 /* set alias */
1287 if (!phar->is_temporary_alias && phar->alias_len) {
1288 entry.fp = php_stream_fopen_tmpfile();
1289 if (entry.fp == NULL) {
1290 spprintf(error, 0, "phar error: unable to create temporary file");
1291 return;
1292 }
1293 if (phar->alias_len != php_stream_write(entry.fp, phar->alias, phar->alias_len)) {
1294 if (error) {
1295 spprintf(error, 0, "unable to set alias in zip-based phar \"%s\"", phar->fname);
1296 }
1297 return;
1298 }
1299
1301 entry.filename = estrndup(".phar/alias.txt", sizeof(".phar/alias.txt")-1);
1302 entry.filename_len = sizeof(".phar/alias.txt")-1;
1303
1304 zend_hash_str_update_mem(&phar->manifest, entry.filename, entry.filename_len, (void*)&entry, sizeof(phar_entry_info));
1305 } else {
1306 zend_hash_str_del(&phar->manifest, ".phar/alias.txt", sizeof(".phar/alias.txt")-1);
1307 }
1308
1309 /* register alias */
1310 if (phar->alias_len) {
1311 if (FAILURE == phar_get_archive(&phar, phar->fname, phar->fname_len, phar->alias, phar->alias_len, error)) {
1312 return;
1313 }
1314 }
1315
1316 /* set stub */
1317 if (user_stub && !is_default_stub) {
1318 char *pos = php_stristr(ZSTR_VAL(user_stub), halt_stub, ZSTR_LEN(user_stub), strlen(halt_stub));
1319
1320 if (pos == NULL) {
1321 if (error) {
1322 spprintf(error, 0, "illegal stub for zip-based phar \"%s\"", phar->fname);
1323 }
1324 return;
1325 }
1326
1327 size_t len = pos - ZSTR_VAL(user_stub) + strlen(halt_stub);
1328 const char end_sequence[] = " ?>\r\n";
1329 size_t end_sequence_len = strlen(end_sequence);
1330
1331 entry.fp = php_stream_fopen_tmpfile();
1332 if (entry.fp == NULL) {
1333 spprintf(error, 0, "phar error: unable to create temporary file");
1334 return;
1335 }
1336 entry.uncompressed_filesize = len + end_sequence_len;
1337
1338 if (
1339 len != php_stream_write(entry.fp, ZSTR_VAL(user_stub), len)
1340 || end_sequence_len != php_stream_write(entry.fp, end_sequence, end_sequence_len)
1341 ) {
1342 if (error) {
1343 spprintf(error, 0, "unable to create stub from string in new zip-based phar \"%s\"", phar->fname);
1344 }
1345 php_stream_close(entry.fp);
1346 return;
1347 }
1348
1349 entry.filename = estrndup(".phar/stub.php", sizeof(".phar/stub.php")-1);
1350 entry.filename_len = sizeof(".phar/stub.php")-1;
1351
1352 zend_hash_str_update_mem(&phar->manifest, entry.filename, entry.filename_len, (void*)&entry, sizeof(phar_entry_info));
1353 } else {
1354 /* Either this is a brand new phar (add the stub), or the default stub is required (overwrite the stub) */
1355 entry.fp = php_stream_fopen_tmpfile();
1356 if (entry.fp == NULL) {
1357 spprintf(error, 0, "phar error: unable to create temporary file");
1358 return;
1359 }
1360 if (sizeof(newstub)-1 != php_stream_write(entry.fp, newstub, sizeof(newstub)-1)) {
1361 php_stream_close(entry.fp);
1362 if (error) {
1363 spprintf(error, 0, "unable to %s stub in%szip-based phar \"%s\", failed", user_stub ? "overwrite" : "create", user_stub ? " " : " new ", phar->fname);
1364 }
1365 return;
1366 }
1367
1368 entry.uncompressed_filesize = entry.compressed_filesize = sizeof(newstub) - 1;
1369 entry.filename = estrndup(".phar/stub.php", sizeof(".phar/stub.php")-1);
1370 entry.filename_len = sizeof(".phar/stub.php")-1;
1371
1372 if (!is_default_stub) {
1373 if (!zend_hash_str_exists(&phar->manifest, ".phar/stub.php", sizeof(".phar/stub.php")-1)) {
1374 if (NULL == zend_hash_str_add_mem(&phar->manifest, entry.filename, entry.filename_len, (void*)&entry, sizeof(phar_entry_info))) {
1375 php_stream_close(entry.fp);
1376 efree(entry.filename);
1377 if (error) {
1378 spprintf(error, 0, "unable to create stub in zip-based phar \"%s\"", phar->fname);
1379 }
1380 return;
1381 }
1382 } else {
1383 php_stream_close(entry.fp);
1384 efree(entry.filename);
1385 }
1386 } else {
1387 zend_hash_str_update_mem(&phar->manifest, entry.filename, entry.filename_len, (void*)&entry, sizeof(phar_entry_info));
1388 }
1389 }
1390nostub:
1391 if (phar->fp && !phar->is_brandnew) {
1392 oldfile = phar->fp;
1393 must_close_old_file = false;
1394 php_stream_rewind(oldfile);
1395 } else {
1396 oldfile = php_stream_open_wrapper(phar->fname, "rb", 0, NULL);
1397 must_close_old_file = oldfile != NULL;
1398 }
1399
1400 /* save modified files to the zip */
1401 pass.old = oldfile;
1402 pass.filefp = php_stream_fopen_tmpfile();
1403
1404 if (!pass.filefp) {
1405fperror:
1406 if (must_close_old_file) {
1407 php_stream_close(oldfile);
1408 }
1409 if (error) {
1410 spprintf(error, 4096, "phar zip flush of \"%s\" failed: unable to open temporary file", phar->fname);
1411 }
1412 return;
1413 }
1414
1415 pass.centralfp = php_stream_fopen_tmpfile();
1416
1417 if (!pass.centralfp) {
1418 goto fperror;
1419 }
1420
1421 pass.free_fp = pass.free_ufp = 1;
1422 memset(&eocd, 0, sizeof(eocd));
1423
1424 memcpy(eocd.signature, "PK\5\6", 4);
1425 if (!phar->is_data && !phar->sig_flags) {
1426 phar->sig_flags = PHAR_SIG_SHA256;
1427 }
1428 if (phar->sig_flags) {
1429 PHAR_SET_16(eocd.counthere, zend_hash_num_elements(&phar->manifest) + 1);
1430 PHAR_SET_16(eocd.count, zend_hash_num_elements(&phar->manifest) + 1);
1431 } else {
1432 PHAR_SET_16(eocd.counthere, zend_hash_num_elements(&phar->manifest));
1433 PHAR_SET_16(eocd.count, zend_hash_num_elements(&phar->manifest));
1434 }
1435 zend_hash_apply_with_argument(&phar->manifest, phar_zip_changed_apply, (void *) &pass);
1436
1438 if (temperr) {
1439 if (error) {
1440 spprintf(error, 4096, "phar zip flush of \"%s\" failed: %s", phar->fname, temperr);
1441 }
1442 efree(temperr);
1443temperror:
1444 php_stream_close(pass.centralfp);
1445nocentralerror:
1446 php_stream_close(pass.filefp);
1447 if (must_close_old_file) {
1448 php_stream_close(oldfile);
1449 }
1450 return;
1451 }
1452
1453 if (FAILURE == phar_zip_applysignature(phar, &pass)) {
1454 goto temperror;
1455 }
1456
1457 /* save zip */
1458 cdir_size = php_stream_tell(pass.centralfp);
1459 cdir_offset = php_stream_tell(pass.filefp);
1460 PHAR_SET_32(eocd.cdir_size, cdir_size);
1461 PHAR_SET_32(eocd.cdir_offset, cdir_offset);
1462 php_stream_seek(pass.centralfp, 0, SEEK_SET);
1463
1464 {
1465 size_t clen;
1466 int ret = php_stream_copy_to_stream_ex(pass.centralfp, pass.filefp, PHP_STREAM_COPY_ALL, &clen);
1467 if (SUCCESS != ret || clen != cdir_size) {
1468 if (error) {
1469 spprintf(error, 4096, "phar zip flush of \"%s\" failed: unable to write central-directory", phar->fname);
1470 }
1471 goto temperror;
1472 }
1473 }
1474
1475 php_stream_close(pass.centralfp);
1476
1478 if (phar->metadata_tracker.str) {
1479 /* set phar metadata */
1480 PHAR_SET_16(eocd.comment_len, ZSTR_LEN(phar->metadata_tracker.str));
1481
1482 if (sizeof(eocd) != php_stream_write(pass.filefp, (char *)&eocd, sizeof(eocd))) {
1483 if (error) {
1484 spprintf(error, 4096, "phar zip flush of \"%s\" failed: unable to write end of central-directory", phar->fname);
1485 }
1486 goto nocentralerror;
1487 }
1488
1490 if (error) {
1491 spprintf(error, 4096, "phar zip flush of \"%s\" failed: unable to write metadata to zip comment", phar->fname);
1492 }
1493 goto nocentralerror;
1494 }
1495 } else {
1496 if (sizeof(eocd) != php_stream_write(pass.filefp, (char *)&eocd, sizeof(eocd))) {
1497 if (error) {
1498 spprintf(error, 4096, "phar zip flush of \"%s\" failed: unable to write end of central-directory", phar->fname);
1499 }
1500 goto nocentralerror;
1501 }
1502 }
1503
1504 if (phar->fp && pass.free_fp) {
1505 php_stream_close(phar->fp);
1506 }
1507
1508 if (phar->ufp) {
1509 if (pass.free_ufp) {
1510 php_stream_close(phar->ufp);
1511 }
1512 phar->ufp = NULL;
1513 }
1514
1515 /* re-open */
1516 phar->is_brandnew = 0;
1517
1518 if (phar->donotflush) {
1519 /* deferred flush */
1520 phar->fp = pass.filefp;
1521 } else {
1523 if (!phar->fp) {
1524 if (must_close_old_file) {
1525 php_stream_close(oldfile);
1526 }
1527 phar->fp = pass.filefp;
1528 if (error) {
1529 spprintf(error, 4096, "unable to open new phar \"%s\" for writing", phar->fname);
1530 }
1531 return;
1532 }
1533 php_stream_rewind(pass.filefp);
1535 /* we could also reopen the file in "rb" mode but there is no need for that */
1536 php_stream_close(pass.filefp);
1537 }
1538
1539 if (must_close_old_file) {
1540 php_stream_close(oldfile);
1541 }
1542}
1543/* }}} */
size_t len
Definition apprentice.c:174
file_private const char ext[]
strrchr(string $haystack, string $needle, bool $before_needle=false)
header(string $header, bool $replace=true, int $response_code=0)
char s[4]
Definition cdf.c:77
PHPAPI zend_result php_crc32_stream_bulk_update(uint32_t *crc, php_stream *fp, size_t nr)
Definition crc32.c:131
#define php_crc32_bulk_init()
Definition crc32.h:26
#define php_crc32_bulk_end(c)
Definition crc32.h:27
#define CRC32(crc, ch)
Definition crc32.h:24
error($message)
Definition ext_skel.php:22
zval * zv
Definition ffi.c:3975
zend_long n
Definition ffi.c:4979
new_type size
Definition ffi.c:4365
memcpy(ptr1, ptr2, size)
zval * arg
Definition ffi.c:3975
memset(ptr, 0, type->size)
zend_ffi_ctype_name_buf buf
Definition ffi.c:4685
const SEEK_CUR
Definition file.stub.php:16
const SEEK_END
Definition file.stub.php:21
zend_long offset
#define SEEK_SET
Definition gd_io_file.c:20
#define NULL
Definition gdcache.h:45
#define SUCCESS
Definition hash_sha3.c:261
#define pass(a, b, c, mul)
Definition hash_tiger.c:50
PHPAPI php_stream_filter * php_stream_filter_create(const char *filtername, zval *filterparams, uint8_t persistent)
Definition filter.c:220
PHPAPI php_stream_filter * php_stream_filter_remove(php_stream_filter *filter, int call_dtor)
Definition filter.c:483
bool phar_metadata_tracker_has_data(const phar_metadata_tracker *tracker, bool persistent)
Definition phar.c:634
#define PHAR_GET_16(buffer, var)
Definition phar.c:475
zend_result phar_create_or_parse_filename(char *fname, size_t fname_len, char *alias, size_t alias_len, bool is_data, uint32_t options, phar_archive_data **pphar, char **error)
Definition phar.c:1389
void phar_metadata_tracker_try_ensure_has_serialized_data(phar_metadata_tracker *tracker, bool persistent)
Definition phar.c:567
#define PHAR_GET_32(buffer, var)
Definition phar.c:472
void destroy_phar_manifest_entry(zval *zv)
Definition phar.c:384
void phar_parse_metadata_lazy(const char *buffer, phar_metadata_tracker *tracker, uint32_t zip_metadata_len, bool persistent)
Definition phar.c:702
void phar_add_virtual_dirs(phar_archive_data *phar, char *filename, size_t filename_len)
Definition util.c:2039
char * phar_compress_filter(phar_entry_info *entry, int return_unknown)
Definition util.c:1217
@ PHAR_MOD
@ PHAR_FP
@ PHAR_UFP
#define PHAR_ENT_COMPRESSED_GZ
bool has_zlib
int phar_seek_efp(phar_entry_info *entry, zend_off_t offset, int whence, zend_off_t position, int follow_links)
Definition util.c:140
HashTable phar_alias_map
#define PHAR_ENT_PERM_MASK
#define PHAR_ENT_PERM_DEF_DIR
bool require_hash
bool has_bz2
HashTable phar_fname_map
php_stream * phar_get_efp(phar_entry_info *entry, int follow_links)
Definition util.c:97
#define PHAR_ENT_PERM_DEF_FILE
#define PHAR_G(v)
struct _phar_archive_data phar_archive_data
#define PHAR_ENT_COMPRESSION_MASK
zend_result phar_create_signature(phar_archive_data *phar, php_stream *fp, char **signature, size_t *signature_length, char **error)
Definition util.c:1857
#define PHAR_ENT_COMPRESSED_BZ2
zend_result phar_free_alias(phar_archive_data *phar, char *alias, size_t alias_len)
Definition util.c:990
zend_result phar_verify_signature(php_stream *fp, size_t end_of_phar, uint32_t sig_type, char *sig, size_t sig_len, char *fname, char **signature, size_t *signature_len, char **error)
Definition util.c:1543
struct _phar_entry_info phar_entry_info
#define PHAR_SIG_SHA256
bool persist
zend_result phar_open_entry_fp(phar_entry_info *entry, char **error, int follow_links)
Definition util.c:842
zend_result phar_get_archive(phar_archive_data **archive, char *fname, size_t fname_len, char *alias, size_t alias_len, char **error)
Definition util.c:1013
struct _phar_zip_dir_end phar_zip_dir_end
struct _phar_zip_central_dir_file phar_zip_central_dir_file
struct _phar_zip_extra_field_header phar_zip_extra_field_header
struct _phar_zip_unix3 phar_zip_unix3
#define PHAR_ZIP_COMP_DEFLATE
Definition pharzip.h:94
struct _phar_zip_file_header phar_zip_file_header
struct _phar_zip_unix_time phar_zip_unix_time
#define PHAR_ZIP_COMP_NONE
Definition pharzip.h:93
#define PHAR_ZIP_FLAG_ENCRYPTED
Definition pharzip.h:64
#define PHAR_ZIP_COMP_BZIP2
Definition pharzip.h:95
mktime(int $hour, ?int $minute=null, ?int $second=null, ?int $month=null, ?int $day=null, ?int $year=null)
time()
unsigned const char * end
Definition php_ffi.h:51
unsigned const char * pos
Definition php_ffi.h:52
PHP_JSON_API size_t int options
Definition php_json.h:102
PHPAPI struct tm * php_localtime_r(const time_t *const timep, struct tm *p_tm)
Definition reentrancy.c:110
#define php_stream_filter_append(chain, filter)
#define php_stream_filter_flush(filter, finish)
#define php_stream_fopen_tmpfile()
struct _php_stream php_stream
Definition php_streams.h:96
#define REPORT_ERRORS
#define php_stream_read(stream, buf, count)
struct _php_stream_filter php_stream_filter
Definition php_streams.h:99
#define php_stream_rewind(stream)
#define PHP_STREAM_COPY_ALL
#define php_stream_seek(stream, offset, whence)
#define php_stream_flush(stream)
#define php_stream_close(stream)
#define php_stream_tell(stream)
#define php_stream_is_persistent(stream)
#define php_stream_copy_to_mem(src, maxlen, persistent)
#define php_stream_open_wrapper(path, mode, options, opened)
#define php_stream_copy_to_stream_ex(src, dest, maxlen, len)
#define STREAM_MUST_SEEK
#define IGNORE_URL
#define php_stream_write(stream, buf, count)
PHPAPI char * php_stristr(const char *s, const char *t, size_t s_len, size_t t_len)
Definition string.c:1672
p
Definition session.c:1105
time_t now
Definition session.c:1281
#define spprintf
Definition spprintf.h:29
phar_metadata_tracker metadata_tracker
uint32_t is_temporary_alias
uint32_t timestamp
zend_long header_offset
uint32_t is_modified
uint32_t flags
uint32_t is_deleted
uint32_t is_dir
char * filename
uint32_t manifest_pos
uint32_t compressed_filesize
php_stream * fp
int fp_refcount
uint32_t old_flags
uint32_t is_zip
phar_metadata_tracker metadata_tracker
uint32_t is_mounted
enum phar_fp_type fp_type
php_stream * cfp
uint32_t crc32
uint32_t uncompressed_filesize
phar_archive_data * phar
uint32_t is_persistent
uint32_t filename_len
zend_long offset
zend_long offset_abs
char comment_len[2]
Definition pharzip.h:238
char cdir_offset[4]
Definition pharzip.h:235
char ** error
Definition zip.c:865
php_stream * old
Definition zip.c:864
php_stream * centralfp
Definition zip.c:863
bool free_fp
Definition zip.c:866
php_stream * filefp
Definition zip.c:862
bool free_ufp
Definition zip.c:867
char size[2]
Definition pharzip.h:140
char perms[2]
Definition pharzip.h:142
char crc32[4]
Definition pharzip.h:141
char tag[2]
Definition pharzip.h:139
uint32_t flags
zend_off_t readpos
php_stream_filter_chain writefilters
php_stream_filter_chain readfilters
zend_off_t writepos
Definition file.h:177
#define estrndup(s, length)
Definition zend_alloc.h:165
#define pestrndup(s, length, persistent)
Definition zend_alloc.h:207
#define efree(ptr)
Definition zend_alloc.h:155
#define pefree(ptr, persistent)
Definition zend_alloc.h:191
#define pemalloc(size, persistent)
Definition zend_alloc.h:189
#define pecalloc(nmemb, size, persistent)
Definition zend_alloc.h:200
#define emalloc(size)
Definition zend_alloc.h:151
struct _zval_struct zval
strlen(string $string)
strncmp(string $string1, string $string2, int $length)
zend_string_release_ex(func->internal_function.function_name, 0)
ZEND_API void ZEND_FASTCALL zend_hash_apply_with_argument(HashTable *ht, apply_func_arg_t apply_func, void *argument)
Definition zend_hash.c:2099
ZEND_API zend_result ZEND_FASTCALL zend_hash_str_del(HashTable *ht, const char *str, size_t len)
Definition zend_hash.c:1661
#define zend_hash_init(ht, nSize, pHashFunction, pDestructor, persistent)
Definition zend_hash.h:108
#define ZEND_HASH_APPLY_STOP
Definition zend_hash.h:148
#define ZEND_HASH_APPLY_REMOVE
Definition zend_hash.h:147
#define ZEND_HASH_APPLY_KEEP
Definition zend_hash.h:146
int32_t zend_off_t
Definition zend_long.h:44
#define Z_UL(i)
Definition zend_long.h:49
struct _zend_string zend_string
#define ZEND_ASSERT(c)
#define ZSTR_VAL(zstr)
Definition zend_string.h:68
#define ZSTR_LEN(zstr)
Definition zend_string.h:69
#define ZVAL_UNDEF(z)
#define Z_PTR_P(zval_p)
@ FAILURE
Definition zend_types.h:61
zval * ret
value
#define PHAR_SET_32(var, value)
Definition zip.c:41
#define PHAR_ZIP_FAIL_FREE(errmsg, save)
int phar_parse_zipfile(php_stream *fp, char *fname, size_t fname_len, char *alias, size_t alias_len, phar_archive_data **pphar, char **error)
Definition zip.c:229
#define PHAR_SET_16(var, value)
Definition zip.c:42
#define PHAR_ZIP_FAIL(errmsg)
#define PHAR_GET_16(var)
Definition zip.c:23
int phar_open_or_create_zip(char *fname, size_t fname_len, char *alias, size_t alias_len, int is_data, uint32_t options, phar_archive_data **pphar, char **error)
Definition zip.c:827
#define PHAR_GET_32(var)
Definition zip.c:25
void phar_zip_flush(phar_archive_data *phar, zend_string *user_stub, bool is_default_stub, char **error)
Definition zip.c:1254