This source file includes following definitions.
- phar_write_32
- phar_write_16
- phar_zip_process_extra
- phar_zip_d2u_time
- phar_zip_u2d_time
- phar_parse_zipfile
- phar_open_or_create_zip
- phar_zip_changed_apply_int
- phar_zip_changed_apply
- phar_zip_applysignature
- phar_zip_flush
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 #include "phar_internal.h"
20
21 #define PHAR_GET_16(var) ((php_uint16)((((php_uint16)var[0]) & 0xff) | \
22 (((php_uint16)var[1]) & 0xff) << 8))
23 #define PHAR_GET_32(var) ((php_uint32)((((php_uint32)var[0]) & 0xff) | \
24 (((php_uint32)var[1]) & 0xff) << 8 | \
25 (((php_uint32)var[2]) & 0xff) << 16 | \
26 (((php_uint32)var[3]) & 0xff) << 24))
27 static inline void phar_write_32(char buffer[4], php_uint32 value)
28 {
29 buffer[3] = (unsigned char) ((value & 0xff000000) >> 24);
30 buffer[2] = (unsigned char) ((value & 0xff0000) >> 16);
31 buffer[1] = (unsigned char) ((value & 0xff00) >> 8);
32 buffer[0] = (unsigned char) (value & 0xff);
33 }
34 static inline void phar_write_16(char buffer[2], php_uint32 value)
35 {
36 buffer[1] = (unsigned char) ((value & 0xff00) >> 8);
37 buffer[0] = (unsigned char) (value & 0xff);
38 }
39 # define PHAR_SET_32(var, value) phar_write_32(var, (php_uint32) (value));
40 # define PHAR_SET_16(var, value) phar_write_16(var, (php_uint16) (value));
41
42 static int phar_zip_process_extra(php_stream *fp, phar_entry_info *entry, php_uint16 len)
43 {
44 union {
45 phar_zip_extra_field_header header;
46 phar_zip_unix3 unix3;
47 } h;
48 int read;
49
50 do {
51 if (sizeof(h.header) != php_stream_read(fp, (char *) &h.header, sizeof(h.header))) {
52 return FAILURE;
53 }
54
55 if (h.header.tag[0] != 'n' || h.header.tag[1] != 'u') {
56
57 php_stream_seek(fp, PHAR_GET_16(h.header.size), SEEK_CUR);
58 len -= PHAR_GET_16(h.header.size) + 4;
59 continue;
60 }
61
62
63 read = php_stream_read(fp, (char *) &(h.unix3.crc32), sizeof(h.unix3) - sizeof(h.header));
64 len -= read + 4;
65
66 if (sizeof(h.unix3) - sizeof(h.header) != read) {
67 return FAILURE;
68 }
69
70 if (PHAR_GET_16(h.unix3.size) > sizeof(h.unix3) - 4) {
71
72 php_stream_seek(fp, PHAR_GET_16(h.unix3.size) - sizeof(h.unix3.size), SEEK_CUR);
73 }
74
75
76 entry->flags &= PHAR_ENT_COMPRESSION_MASK;
77
78 if (entry->is_dir) {
79 entry->flags |= PHAR_GET_16(h.unix3.perms) & PHAR_ENT_PERM_MASK;
80 } else {
81 entry->flags |= PHAR_GET_16(h.unix3.perms) & PHAR_ENT_PERM_MASK;
82 }
83
84 } while (len);
85
86 return SUCCESS;
87 }
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123 static time_t phar_zip_d2u_time(char *cdtime, char *cddate)
124 {
125 int dtime = PHAR_GET_16(cdtime), ddate = PHAR_GET_16(cddate);
126 struct tm *tm, tmbuf;
127 time_t now;
128
129 now = time(NULL);
130 tm = php_localtime_r(&now, &tmbuf);
131
132 tm->tm_year = ((ddate>>9)&127) + 1980 - 1900;
133 tm->tm_mon = ((ddate>>5)&15) - 1;
134 tm->tm_mday = ddate&31;
135
136 tm->tm_hour = (dtime>>11)&31;
137 tm->tm_min = (dtime>>5)&63;
138 tm->tm_sec = (dtime<<1)&62;
139
140 return mktime(tm);
141 }
142
143
144 static void phar_zip_u2d_time(time_t time, char *dtime, char *ddate)
145 {
146 php_uint16 ctime, cdate;
147 struct tm *tm, tmbuf;
148
149 tm = php_localtime_r(&time, &tmbuf);
150 cdate = ((tm->tm_year+1900-1980)<<9) + ((tm->tm_mon+1)<<5) + tm->tm_mday;
151 ctime = ((tm->tm_hour)<<11) + ((tm->tm_min)<<5) + ((tm->tm_sec)>>1);
152 PHAR_SET_16(dtime, ctime);
153 PHAR_SET_16(ddate, cdate);
154 }
155
156
157
158
159
160
161
162
163
164
165
166 int phar_parse_zipfile(php_stream *fp, char *fname, int fname_len, char *alias, int alias_len, phar_archive_data** pphar, char **error)
167 {
168 phar_zip_dir_end locator;
169 char buf[sizeof(locator) + 65536];
170 zend_long size;
171 php_uint16 i;
172 phar_archive_data *mydata = NULL;
173 phar_entry_info entry = {0};
174 char *p = buf, *ext, *actual_alias = NULL;
175 char *metadata = NULL;
176
177 size = php_stream_tell(fp);
178
179 if (size > sizeof(locator) + 65536) {
180
181 size = sizeof(locator) + 65536;
182 if (FAILURE == php_stream_seek(fp, -size, SEEK_END)) {
183 php_stream_close(fp);
184 if (error) {
185 spprintf(error, 4096, "phar error: unable to search for end of central directory in zip-based phar \"%s\"", fname);
186 }
187 return FAILURE;
188 }
189 } else {
190 php_stream_seek(fp, 0, SEEK_SET);
191 }
192
193 if (!php_stream_read(fp, buf, size)) {
194 php_stream_close(fp);
195 if (error) {
196 spprintf(error, 4096, "phar error: unable to read in data to search for end of central directory in zip-based phar \"%s\"", fname);
197 }
198 return FAILURE;
199 }
200
201 while ((p=(char *) memchr(p + 1, 'P', (size_t) (size - (p + 1 - buf)))) != NULL) {
202 if ((p - buf) + sizeof(locator) <= size && !memcmp(p + 1, "K\5\6", 3)) {
203 memcpy((void *)&locator, (void *) p, sizeof(locator));
204 if (PHAR_GET_16(locator.centraldisk) != 0 || PHAR_GET_16(locator.disknumber) != 0) {
205
206 php_stream_close(fp);
207 if (error) {
208 spprintf(error, 4096, "phar error: split archives spanning multiple zips cannot be processed in zip-based phar \"%s\"", fname);
209 }
210 return FAILURE;
211 }
212
213 if (PHAR_GET_16(locator.counthere) != PHAR_GET_16(locator.count)) {
214 if (error) {
215 spprintf(error, 4096, "phar error: corrupt zip archive, conflicting file count in end of central directory record in zip-based phar \"%s\"", fname);
216 }
217 php_stream_close(fp);
218 return FAILURE;
219 }
220
221 mydata = pecalloc(1, sizeof(phar_archive_data), PHAR_G(persist));
222 mydata->is_persistent = PHAR_G(persist);
223
224
225 if (PHAR_GET_16(locator.comment_len)) {
226
227 metadata = p + sizeof(locator);
228
229 if (PHAR_GET_16(locator.comment_len) != size - (metadata - buf)) {
230 if (error) {
231 spprintf(error, 4096, "phar error: corrupt zip archive, zip file comment truncated in zip-based phar \"%s\"", fname);
232 }
233 php_stream_close(fp);
234 pefree(mydata, mydata->is_persistent);
235 return FAILURE;
236 }
237
238 mydata->metadata_len = PHAR_GET_16(locator.comment_len);
239
240 if (phar_parse_metadata(&metadata, &mydata->metadata, PHAR_GET_16(locator.comment_len)) == FAILURE) {
241 mydata->metadata_len = 0;
242
243
244 ZVAL_NEW_STR(&mydata->metadata, zend_string_init(metadata, PHAR_GET_16(locator.comment_len), mydata->is_persistent));
245 }
246 } else {
247 ZVAL_UNDEF(&mydata->metadata);
248 }
249
250 goto foundit;
251 }
252 }
253
254 php_stream_close(fp);
255
256 if (error) {
257 spprintf(error, 4096, "phar error: end of central directory not found in zip-based phar \"%s\"", fname);
258 }
259
260 return FAILURE;
261 foundit:
262 mydata->fname = pestrndup(fname, fname_len, mydata->is_persistent);
263 #ifdef PHP_WIN32
264 phar_unixify_path_separators(mydata->fname, fname_len);
265 #endif
266 mydata->is_zip = 1;
267 mydata->fname_len = fname_len;
268 ext = strrchr(mydata->fname, '/');
269
270 if (ext) {
271 mydata->ext = memchr(ext, '.', (mydata->fname + fname_len) - ext);
272 if (mydata->ext == ext) {
273 mydata->ext = memchr(ext + 1, '.', (mydata->fname + fname_len) - ext - 1);
274 }
275 if (mydata->ext) {
276 mydata->ext_len = (mydata->fname + fname_len) - mydata->ext;
277 }
278 }
279
280
281
282 php_stream_seek(fp, PHAR_GET_32(locator.cdir_offset), SEEK_SET);
283
284 zend_hash_init(&mydata->manifest, PHAR_GET_16(locator.count),
285 zend_get_hash_value, destroy_phar_manifest_entry, (zend_bool)mydata->is_persistent);
286 zend_hash_init(&mydata->mounted_dirs, 5,
287 zend_get_hash_value, NULL, (zend_bool)mydata->is_persistent);
288 zend_hash_init(&mydata->virtual_dirs, PHAR_GET_16(locator.count) * 2,
289 zend_get_hash_value, NULL, (zend_bool)mydata->is_persistent);
290 entry.phar = mydata;
291 entry.is_zip = 1;
292 entry.fp_type = PHAR_FP;
293 entry.is_persistent = mydata->is_persistent;
294 #define PHAR_ZIP_FAIL_FREE(errmsg, save) \
295 zend_hash_destroy(&mydata->manifest); \
296 mydata->manifest.u.flags = 0; \
297 zend_hash_destroy(&mydata->mounted_dirs); \
298 mydata->mounted_dirs.u.flags = 0; \
299 zend_hash_destroy(&mydata->virtual_dirs); \
300 mydata->virtual_dirs.u.flags = 0; \
301 php_stream_close(fp); \
302 zval_dtor(&mydata->metadata); \
303 if (mydata->signature) { \
304 efree(mydata->signature); \
305 } \
306 if (error) { \
307 spprintf(error, 4096, "phar error: %s in zip-based phar \"%s\"", errmsg, mydata->fname); \
308 } \
309 pefree(mydata->fname, mydata->is_persistent); \
310 if (mydata->alias) { \
311 pefree(mydata->alias, mydata->is_persistent); \
312 } \
313 pefree(mydata, mydata->is_persistent); \
314 efree(save); \
315 return FAILURE;
316 #define PHAR_ZIP_FAIL(errmsg) \
317 zend_hash_destroy(&mydata->manifest); \
318 mydata->manifest.u.flags = 0; \
319 zend_hash_destroy(&mydata->mounted_dirs); \
320 mydata->mounted_dirs.u.flags = 0; \
321 zend_hash_destroy(&mydata->virtual_dirs); \
322 mydata->virtual_dirs.u.flags = 0; \
323 php_stream_close(fp); \
324 zval_dtor(&mydata->metadata); \
325 if (mydata->signature) { \
326 efree(mydata->signature); \
327 } \
328 if (error) { \
329 spprintf(error, 4096, "phar error: %s in zip-based phar \"%s\"", errmsg, mydata->fname); \
330 } \
331 pefree(mydata->fname, mydata->is_persistent); \
332 if (mydata->alias) { \
333 pefree(mydata->alias, mydata->is_persistent); \
334 } \
335 pefree(mydata, mydata->is_persistent); \
336 return FAILURE;
337
338
339 for (i = 0; i < PHAR_GET_16(locator.count); ++i) {
340 phar_zip_central_dir_file zipentry;
341 zend_off_t beforeus = php_stream_tell(fp);
342
343 if (sizeof(zipentry) != php_stream_read(fp, (char *) &zipentry, sizeof(zipentry))) {
344 PHAR_ZIP_FAIL("unable to read central directory entry, truncated");
345 }
346
347
348 if (memcmp("PK\1\2", zipentry.signature, 4)) {
349
350 PHAR_ZIP_FAIL("corrupted central directory entry, no magic signature");
351 }
352
353 if (entry.is_persistent) {
354 entry.manifest_pos = i;
355 }
356
357 entry.compressed_filesize = PHAR_GET_32(zipentry.compsize);
358 entry.uncompressed_filesize = PHAR_GET_32(zipentry.uncompsize);
359 entry.crc32 = PHAR_GET_32(zipentry.crc32);
360
361 entry.timestamp = phar_zip_d2u_time(zipentry.timestamp, zipentry.datestamp);
362 entry.flags = PHAR_ENT_PERM_DEF_FILE;
363 entry.header_offset = PHAR_GET_32(zipentry.offset);
364 entry.offset = entry.offset_abs = PHAR_GET_32(zipentry.offset) + sizeof(phar_zip_file_header) + PHAR_GET_16(zipentry.filename_len) +
365 PHAR_GET_16(zipentry.extra_len);
366
367 if (PHAR_GET_16(zipentry.flags) & PHAR_ZIP_FLAG_ENCRYPTED) {
368 PHAR_ZIP_FAIL("Cannot process encrypted zip files");
369 }
370
371 if (!PHAR_GET_16(zipentry.filename_len)) {
372 PHAR_ZIP_FAIL("Cannot process zips created from stdin (zero-length filename)");
373 }
374
375 entry.filename_len = PHAR_GET_16(zipentry.filename_len);
376 entry.filename = (char *) pemalloc(entry.filename_len + 1, entry.is_persistent);
377
378 if (entry.filename_len != php_stream_read(fp, entry.filename, entry.filename_len)) {
379 pefree(entry.filename, entry.is_persistent);
380 PHAR_ZIP_FAIL("unable to read in filename from central directory, truncated");
381 }
382
383 entry.filename[entry.filename_len] = '\0';
384
385 if (entry.filename[entry.filename_len - 1] == '/') {
386 entry.is_dir = 1;
387 if(entry.filename_len > 1) {
388 entry.filename_len--;
389 }
390 entry.flags |= PHAR_ENT_PERM_DEF_DIR;
391 } else {
392 entry.is_dir = 0;
393 }
394
395 if (entry.filename_len == sizeof(".phar/signature.bin")-1 && !strncmp(entry.filename, ".phar/signature.bin", sizeof(".phar/signature.bin")-1)) {
396 size_t read;
397 php_stream *sigfile;
398 zend_off_t now;
399 char *sig;
400
401 now = php_stream_tell(fp);
402 pefree(entry.filename, entry.is_persistent);
403 sigfile = php_stream_fopen_tmpfile();
404 if (!sigfile) {
405 PHAR_ZIP_FAIL("couldn't open temporary file");
406 }
407
408 php_stream_seek(fp, 0, SEEK_SET);
409
410 php_stream_copy_to_stream_ex(fp, sigfile, entry.header_offset, NULL);
411
412 php_stream_seek(fp, PHAR_GET_32(locator.cdir_offset), SEEK_SET);
413
414 php_stream_copy_to_stream_ex(fp, sigfile, beforeus - PHAR_GET_32(locator.cdir_offset), NULL);
415 if (metadata) {
416 php_stream_write(sigfile, metadata, PHAR_GET_16(locator.comment_len));
417 }
418 php_stream_seek(fp, sizeof(phar_zip_file_header) + entry.header_offset + entry.filename_len + PHAR_GET_16(zipentry.extra_len), SEEK_SET);
419 sig = (char *) emalloc(entry.uncompressed_filesize);
420 read = php_stream_read(fp, sig, entry.uncompressed_filesize);
421 if (read != entry.uncompressed_filesize) {
422 php_stream_close(sigfile);
423 efree(sig);
424 PHAR_ZIP_FAIL("signature cannot be read");
425 }
426 mydata->sig_flags = PHAR_GET_32(sig);
427 if (FAILURE == phar_verify_signature(sigfile, php_stream_tell(sigfile), mydata->sig_flags, sig + 8, entry.uncompressed_filesize - 8, fname, &mydata->signature, &mydata->sig_len, error)) {
428 efree(sig);
429 if (error) {
430 char *save;
431 php_stream_close(sigfile);
432 spprintf(&save, 4096, "signature cannot be verified: %s", *error);
433 efree(*error);
434 PHAR_ZIP_FAIL_FREE(save, save);
435 } else {
436 php_stream_close(sigfile);
437 PHAR_ZIP_FAIL("signature cannot be verified");
438 }
439 }
440 php_stream_close(sigfile);
441 efree(sig);
442
443 if (i != PHAR_GET_16(locator.count) - 1) {
444 PHAR_ZIP_FAIL("entries exist after signature, invalid phar");
445 }
446
447 continue;
448 }
449
450 phar_add_virtual_dirs(mydata, entry.filename, entry.filename_len);
451
452 if (PHAR_GET_16(zipentry.extra_len)) {
453 zend_off_t loc = php_stream_tell(fp);
454 if (FAILURE == phar_zip_process_extra(fp, &entry, PHAR_GET_16(zipentry.extra_len))) {
455 pefree(entry.filename, entry.is_persistent);
456 PHAR_ZIP_FAIL("Unable to process extra field header for file in central directory");
457 }
458 php_stream_seek(fp, loc + PHAR_GET_16(zipentry.extra_len), SEEK_SET);
459 }
460
461 switch (PHAR_GET_16(zipentry.compressed)) {
462 case PHAR_ZIP_COMP_NONE :
463
464 break;
465 case PHAR_ZIP_COMP_DEFLATE :
466 entry.flags |= PHAR_ENT_COMPRESSED_GZ;
467 if (!PHAR_G(has_zlib)) {
468 pefree(entry.filename, entry.is_persistent);
469 PHAR_ZIP_FAIL("zlib extension is required");
470 }
471 break;
472 case PHAR_ZIP_COMP_BZIP2 :
473 entry.flags |= PHAR_ENT_COMPRESSED_BZ2;
474 if (!PHAR_G(has_bz2)) {
475 pefree(entry.filename, entry.is_persistent);
476 PHAR_ZIP_FAIL("bzip2 extension is required");
477 }
478 break;
479 case 1 :
480 pefree(entry.filename, entry.is_persistent);
481 PHAR_ZIP_FAIL("unsupported compression method (Shrunk) used in this zip");
482 case 2 :
483 case 3 :
484 case 4 :
485 case 5 :
486 pefree(entry.filename, entry.is_persistent);
487 PHAR_ZIP_FAIL("unsupported compression method (Reduce) used in this zip");
488 case 6 :
489 pefree(entry.filename, entry.is_persistent);
490 PHAR_ZIP_FAIL("unsupported compression method (Implode) used in this zip");
491 case 7 :
492 pefree(entry.filename, entry.is_persistent);
493 PHAR_ZIP_FAIL("unsupported compression method (Tokenize) used in this zip");
494 case 9 :
495 pefree(entry.filename, entry.is_persistent);
496 PHAR_ZIP_FAIL("unsupported compression method (Deflate64) used in this zip");
497 case 10 :
498 pefree(entry.filename, entry.is_persistent);
499 PHAR_ZIP_FAIL("unsupported compression method (PKWare Implode/old IBM TERSE) used in this zip");
500 case 14 :
501 pefree(entry.filename, entry.is_persistent);
502 PHAR_ZIP_FAIL("unsupported compression method (LZMA) used in this zip");
503 case 18 :
504 pefree(entry.filename, entry.is_persistent);
505 PHAR_ZIP_FAIL("unsupported compression method (IBM TERSE) used in this zip");
506 case 19 :
507 pefree(entry.filename, entry.is_persistent);
508 PHAR_ZIP_FAIL("unsupported compression method (IBM LZ77) used in this zip");
509 case 97 :
510 pefree(entry.filename, entry.is_persistent);
511 PHAR_ZIP_FAIL("unsupported compression method (WavPack) used in this zip");
512 case 98 :
513 pefree(entry.filename, entry.is_persistent);
514 PHAR_ZIP_FAIL("unsupported compression method (PPMd) used in this zip");
515 default :
516 pefree(entry.filename, entry.is_persistent);
517 PHAR_ZIP_FAIL("unsupported compression method (unknown) used in this zip");
518 }
519
520
521 if (PHAR_GET_16(zipentry.comment_len)) {
522 if (PHAR_GET_16(zipentry.comment_len) != php_stream_read(fp, buf, PHAR_GET_16(zipentry.comment_len))) {
523 pefree(entry.filename, entry.is_persistent);
524 PHAR_ZIP_FAIL("unable to read in file comment, truncated");
525 }
526
527 p = buf;
528 entry.metadata_len = PHAR_GET_16(zipentry.comment_len);
529
530 if (phar_parse_metadata(&p, &(entry.metadata), PHAR_GET_16(zipentry.comment_len)) == FAILURE) {
531 entry.metadata_len = 0;
532
533
534 ZVAL_NEW_STR(&entry.metadata, zend_string_init(buf, PHAR_GET_16(zipentry.comment_len), entry.is_persistent));
535 }
536 } else {
537 ZVAL_UNDEF(&entry.metadata);
538 }
539
540 if (!actual_alias && entry.filename_len == sizeof(".phar/alias.txt")-1 && !strncmp(entry.filename, ".phar/alias.txt", sizeof(".phar/alias.txt")-1)) {
541 php_stream_filter *filter;
542 zend_off_t saveloc;
543
544 phar_zip_file_header local;
545
546
547 saveloc = php_stream_tell(fp);
548 php_stream_seek(fp, PHAR_GET_32(zipentry.offset), SEEK_SET);
549
550 if (sizeof(local) != php_stream_read(fp, (char *) &local, sizeof(local))) {
551 pefree(entry.filename, entry.is_persistent);
552 PHAR_ZIP_FAIL("phar error: internal corruption of zip-based phar (cannot read local file header for alias)");
553 }
554
555
556 if (entry.filename_len != PHAR_GET_16(local.filename_len) || entry.crc32 != PHAR_GET_32(local.crc32) || entry.uncompressed_filesize != PHAR_GET_32(local.uncompsize) || entry.compressed_filesize != PHAR_GET_32(local.compsize)) {
557 pefree(entry.filename, entry.is_persistent);
558 PHAR_ZIP_FAIL("phar error: internal corruption of zip-based phar (local header of alias does not match central directory)");
559 }
560
561
562 entry.offset = entry.offset_abs =
563 sizeof(local) + entry.header_offset + PHAR_GET_16(local.filename_len) + PHAR_GET_16(local.extra_len);
564 php_stream_seek(fp, entry.offset, SEEK_SET);
565
566 fp->writepos = 0;
567 fp->readpos = 0;
568 php_stream_seek(fp, entry.offset, SEEK_SET);
569 fp->writepos = 0;
570 fp->readpos = 0;
571
572
573 mydata->alias_len = entry.uncompressed_filesize;
574 if (entry.flags & PHAR_ENT_COMPRESSED_GZ) {
575 filter = php_stream_filter_create("zlib.inflate", NULL, php_stream_is_persistent(fp));
576
577 if (!filter) {
578 pefree(entry.filename, entry.is_persistent);
579 PHAR_ZIP_FAIL("unable to decompress alias, zlib filter creation failed");
580 }
581
582 php_stream_filter_append(&fp->readfilters, filter);
583
584
585
586 {
587 zend_string *str = php_stream_copy_to_mem(fp, entry.uncompressed_filesize, 0);
588 if (str) {
589 entry.uncompressed_filesize = ZSTR_LEN(str);
590 actual_alias = estrndup(ZSTR_VAL(str), ZSTR_LEN(str));
591 zend_string_release(str);
592 } else {
593 actual_alias = NULL;
594 entry.uncompressed_filesize = 0;
595 }
596 }
597
598 if (!entry.uncompressed_filesize || !actual_alias) {
599 pefree(entry.filename, entry.is_persistent);
600 PHAR_ZIP_FAIL("unable to read in alias, truncated");
601 }
602
603 php_stream_filter_flush(filter, 1);
604 php_stream_filter_remove(filter, 1);
605
606 } else if (entry.flags & PHAR_ENT_COMPRESSED_BZ2) {
607 filter = php_stream_filter_create("bzip2.decompress", NULL, php_stream_is_persistent(fp));
608
609 if (!filter) {
610 pefree(entry.filename, entry.is_persistent);
611 PHAR_ZIP_FAIL("unable to read in alias, bzip2 filter creation failed");
612 }
613
614 php_stream_filter_append(&fp->readfilters, filter);
615
616
617
618 {
619 zend_string *str = php_stream_copy_to_mem(fp, entry.uncompressed_filesize, 0);
620 if (str) {
621 entry.uncompressed_filesize = ZSTR_LEN(str);
622 actual_alias = estrndup(ZSTR_VAL(str), ZSTR_LEN(str));
623 zend_string_release(str);
624 } else {
625 actual_alias = NULL;
626 entry.uncompressed_filesize = 0;
627 }
628 }
629
630 if (!entry.uncompressed_filesize || !actual_alias) {
631 pefree(entry.filename, entry.is_persistent);
632 PHAR_ZIP_FAIL("unable to read in alias, truncated");
633 }
634
635 php_stream_filter_flush(filter, 1);
636 php_stream_filter_remove(filter, 1);
637 } else {
638
639
640 {
641 zend_string *str = php_stream_copy_to_mem(fp, entry.uncompressed_filesize, 0);
642 if (str) {
643 entry.uncompressed_filesize = ZSTR_LEN(str);
644 actual_alias = estrndup(ZSTR_VAL(str), ZSTR_LEN(str));
645 zend_string_release(str);
646 } else {
647 actual_alias = NULL;
648 entry.uncompressed_filesize = 0;
649 }
650 }
651
652 if (!entry.uncompressed_filesize || !actual_alias) {
653 pefree(entry.filename, entry.is_persistent);
654 PHAR_ZIP_FAIL("unable to read in alias, truncated");
655 }
656 }
657
658
659 php_stream_seek(fp, saveloc, SEEK_SET);
660 }
661
662 phar_set_inode(&entry);
663 zend_hash_str_add_mem(&mydata->manifest, entry.filename, entry.filename_len, (void *)&entry, sizeof(phar_entry_info));
664 }
665
666 mydata->fp = fp;
667
668 if (zend_hash_str_exists(&(mydata->manifest), ".phar/stub.php", sizeof(".phar/stub.php")-1)) {
669 mydata->is_data = 0;
670 } else {
671 mydata->is_data = 1;
672 }
673
674 zend_hash_str_add_ptr(&(PHAR_G(phar_fname_map)), mydata->fname, fname_len, mydata);
675
676 if (actual_alias) {
677 phar_archive_data *fd_ptr;
678
679 if (!phar_validate_alias(actual_alias, mydata->alias_len)) {
680 if (error) {
681 spprintf(error, 4096, "phar error: invalid alias \"%s\" in zip-based phar \"%s\"", actual_alias, fname);
682 }
683 efree(actual_alias);
684 zend_hash_str_del(&(PHAR_G(phar_fname_map)), mydata->fname, fname_len);
685 return FAILURE;
686 }
687
688 mydata->is_temporary_alias = 0;
689
690 if (NULL != (fd_ptr = zend_hash_str_find_ptr(&(PHAR_G(phar_alias_map)), actual_alias, mydata->alias_len))) {
691 if (SUCCESS != phar_free_alias(fd_ptr, actual_alias, mydata->alias_len)) {
692 if (error) {
693 spprintf(error, 4096, "phar error: Unable to add zip-based phar \"%s\" with implicit alias, alias is already in use", fname);
694 }
695 efree(actual_alias);
696 zend_hash_str_del(&(PHAR_G(phar_fname_map)), mydata->fname, fname_len);
697 return FAILURE;
698 }
699 }
700
701 mydata->alias = entry.is_persistent ? pestrndup(actual_alias, mydata->alias_len, 1) : actual_alias;
702
703 if (entry.is_persistent) {
704 efree(actual_alias);
705 }
706
707 zend_hash_str_add_ptr(&(PHAR_G(phar_alias_map)), actual_alias, mydata->alias_len, mydata);
708 } else {
709 phar_archive_data *fd_ptr;
710
711 if (alias_len) {
712 if (NULL != (fd_ptr = zend_hash_str_find_ptr(&(PHAR_G(phar_alias_map)), alias, alias_len))) {
713 if (SUCCESS != phar_free_alias(fd_ptr, alias, alias_len)) {
714 if (error) {
715 spprintf(error, 4096, "phar error: Unable to add zip-based phar \"%s\" with explicit alias, alias is already in use", fname);
716 }
717 zend_hash_str_del(&(PHAR_G(phar_fname_map)), mydata->fname, fname_len);
718 return FAILURE;
719 }
720 }
721
722 zend_hash_str_add_ptr(&(PHAR_G(phar_alias_map)), actual_alias, mydata->alias_len, mydata);
723 mydata->alias = pestrndup(alias, alias_len, mydata->is_persistent);
724 mydata->alias_len = alias_len;
725 } else {
726 mydata->alias = pestrndup(mydata->fname, fname_len, mydata->is_persistent);
727 mydata->alias_len = fname_len;
728 }
729
730 mydata->is_temporary_alias = 1;
731 }
732
733 if (pphar) {
734 *pphar = mydata;
735 }
736
737 return SUCCESS;
738 }
739
740
741
742
743
744 int phar_open_or_create_zip(char *fname, int fname_len, char *alias, int alias_len, int is_data, int options, phar_archive_data** pphar, char **error)
745 {
746 phar_archive_data *phar;
747 int ret = phar_create_or_parse_filename(fname, fname_len, alias, alias_len, is_data, options, &phar, error);
748
749 if (FAILURE == ret) {
750 return FAILURE;
751 }
752
753 if (pphar) {
754 *pphar = phar;
755 }
756
757 phar->is_data = is_data;
758
759 if (phar->is_zip) {
760 return ret;
761 }
762
763 if (phar->is_brandnew) {
764 phar->internal_file_start = 0;
765 phar->is_zip = 1;
766 phar->is_tar = 0;
767 return SUCCESS;
768 }
769
770
771 if (error) {
772 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);
773 }
774
775 return FAILURE;
776 }
777
778
779 struct _phar_zip_pass {
780 php_stream *filefp;
781 php_stream *centralfp;
782 php_stream *old;
783 int free_fp;
784 int free_ufp;
785 char **error;
786 };
787
788 static int phar_zip_changed_apply_int(phar_entry_info *entry, void *arg)
789 {
790 phar_zip_file_header local;
791 phar_zip_unix3 perms;
792 phar_zip_central_dir_file central;
793 struct _phar_zip_pass *p;
794 php_uint32 newcrc32;
795 zend_off_t offset;
796 int not_really_modified = 0;
797 p = (struct _phar_zip_pass*) arg;
798
799 if (entry->is_mounted) {
800 return ZEND_HASH_APPLY_KEEP;
801 }
802
803 if (entry->is_deleted) {
804 if (entry->fp_refcount <= 0) {
805 return ZEND_HASH_APPLY_REMOVE;
806 } else {
807
808 return ZEND_HASH_APPLY_KEEP;
809 }
810 }
811
812 phar_add_virtual_dirs(entry->phar, entry->filename, entry->filename_len);
813 memset(&local, 0, sizeof(local));
814 memset(¢ral, 0, sizeof(central));
815 memset(&perms, 0, sizeof(perms));
816 strncpy(local.signature, "PK\3\4", 4);
817 strncpy(central.signature, "PK\1\2", 4);
818 PHAR_SET_16(central.extra_len, sizeof(perms));
819 PHAR_SET_16(local.extra_len, sizeof(perms));
820 perms.tag[0] = 'n';
821 perms.tag[1] = 'u';
822 PHAR_SET_16(perms.size, sizeof(perms) - 4);
823 PHAR_SET_16(perms.perms, entry->flags & PHAR_ENT_PERM_MASK);
824 {
825 php_uint32 crc = (php_uint32) ~0;
826 CRC32(crc, perms.perms[0]);
827 CRC32(crc, perms.perms[1]);
828 PHAR_SET_32(perms.crc32, ~crc);
829 }
830
831 if (entry->flags & PHAR_ENT_COMPRESSED_GZ) {
832 PHAR_SET_16(central.compressed, PHAR_ZIP_COMP_DEFLATE);
833 PHAR_SET_16(local.compressed, PHAR_ZIP_COMP_DEFLATE);
834 }
835
836 if (entry->flags & PHAR_ENT_COMPRESSED_BZ2) {
837 PHAR_SET_16(central.compressed, PHAR_ZIP_COMP_BZIP2);
838 PHAR_SET_16(local.compressed, PHAR_ZIP_COMP_BZIP2);
839 }
840
841
842 phar_zip_u2d_time(entry->timestamp, local.timestamp, local.datestamp);
843 memcpy(central.timestamp, local.timestamp, sizeof(local.timestamp));
844 memcpy(central.datestamp, local.datestamp, sizeof(local.datestamp));
845 PHAR_SET_16(central.filename_len, entry->filename_len + (entry->is_dir ? 1 : 0));
846 PHAR_SET_16(local.filename_len, entry->filename_len + (entry->is_dir ? 1 : 0));
847 PHAR_SET_32(central.offset, php_stream_tell(p->filefp));
848
849
850 if (entry->is_modified) {
851 php_uint32 loc;
852 php_stream_filter *filter;
853 php_stream *efp;
854
855 if (entry->is_dir) {
856 entry->is_modified = 0;
857 if (entry->fp_type == PHAR_MOD && entry->fp != entry->phar->fp && entry->fp != entry->phar->ufp) {
858 php_stream_close(entry->fp);
859 entry->fp = NULL;
860 entry->fp_type = PHAR_FP;
861 }
862 goto continue_dir;
863 }
864
865 if (FAILURE == phar_open_entry_fp(entry, p->error, 0)) {
866 spprintf(p->error, 0, "unable to open file contents of file \"%s\" in zip-based phar \"%s\"", entry->filename, entry->phar->fname);
867 return ZEND_HASH_APPLY_STOP;
868 }
869
870
871 if (entry->flags & PHAR_ENT_COMPRESSION_MASK && (entry->old_flags == entry->flags || !entry->old_flags)) {
872 not_really_modified = 1;
873 goto is_compressed;
874 }
875
876 if (-1 == phar_seek_efp(entry, 0, SEEK_SET, 0, 0)) {
877 spprintf(p->error, 0, "unable to seek to start of file \"%s\" to zip-based phar \"%s\"", entry->filename, entry->phar->fname);
878 return ZEND_HASH_APPLY_STOP;
879 }
880
881 efp = phar_get_efp(entry, 0);
882 newcrc32 = ~0;
883
884 for (loc = 0;loc < entry->uncompressed_filesize; ++loc) {
885 CRC32(newcrc32, php_stream_getc(efp));
886 }
887
888 entry->crc32 = ~newcrc32;
889 PHAR_SET_32(central.uncompsize, entry->uncompressed_filesize);
890 PHAR_SET_32(local.uncompsize, entry->uncompressed_filesize);
891
892 if (!(entry->flags & PHAR_ENT_COMPRESSION_MASK)) {
893
894 entry->compressed_filesize = entry->uncompressed_filesize;
895 PHAR_SET_32(central.compsize, entry->uncompressed_filesize);
896 PHAR_SET_32(local.compsize, entry->uncompressed_filesize);
897 goto not_compressed;
898 }
899
900 filter = php_stream_filter_create(phar_compress_filter(entry, 0), NULL, 0);
901
902 if (!filter) {
903 if (entry->flags & PHAR_ENT_COMPRESSED_GZ) {
904 spprintf(p->error, 0, "unable to gzip compress file \"%s\" to zip-based phar \"%s\"", entry->filename, entry->phar->fname);
905 } else {
906 spprintf(p->error, 0, "unable to bzip2 compress file \"%s\" to zip-based phar \"%s\"", entry->filename, entry->phar->fname);
907 }
908 return ZEND_HASH_APPLY_STOP;
909 }
910
911
912
913
914 entry->cfp = php_stream_fopen_tmpfile();
915
916 if (!entry->cfp) {
917 spprintf(p->error, 0, "unable to create temporary file for file \"%s\" while creating zip-based phar \"%s\"", entry->filename, entry->phar->fname);
918 return ZEND_HASH_APPLY_STOP;
919 }
920
921 php_stream_flush(efp);
922
923 if (-1 == phar_seek_efp(entry, 0, SEEK_SET, 0, 0)) {
924 spprintf(p->error, 0, "unable to seek to start of file \"%s\" to zip-based phar \"%s\"", entry->filename, entry->phar->fname);
925 return ZEND_HASH_APPLY_STOP;
926 }
927
928 php_stream_filter_append((&entry->cfp->writefilters), filter);
929
930 if (SUCCESS != php_stream_copy_to_stream_ex(efp, entry->cfp, entry->uncompressed_filesize, NULL)) {
931 spprintf(p->error, 0, "unable to copy compressed file contents of file \"%s\" while creating new phar \"%s\"", entry->filename, entry->phar->fname);
932 return ZEND_HASH_APPLY_STOP;
933 }
934
935 php_stream_filter_flush(filter, 1);
936 php_stream_flush(entry->cfp);
937 php_stream_filter_remove(filter, 1);
938 php_stream_seek(entry->cfp, 0, SEEK_END);
939 entry->compressed_filesize = (php_uint32) php_stream_tell(entry->cfp);
940 PHAR_SET_32(central.compsize, entry->compressed_filesize);
941 PHAR_SET_32(local.compsize, entry->compressed_filesize);
942
943 php_stream_rewind(entry->cfp);
944 entry->old_flags = entry->flags;
945 entry->is_modified = 1;
946 } else {
947 is_compressed:
948 PHAR_SET_32(central.uncompsize, entry->uncompressed_filesize);
949 PHAR_SET_32(local.uncompsize, entry->uncompressed_filesize);
950 PHAR_SET_32(central.compsize, entry->compressed_filesize);
951 PHAR_SET_32(local.compsize, entry->compressed_filesize);
952 if (p->old) {
953 if (-1 == php_stream_seek(p->old, entry->offset_abs, SEEK_SET)) {
954 spprintf(p->error, 0, "unable to seek to start of file \"%s\" while creating zip-based phar \"%s\"", entry->filename, entry->phar->fname);
955 return ZEND_HASH_APPLY_STOP;
956 }
957 }
958 }
959 not_compressed:
960 PHAR_SET_32(central.crc32, entry->crc32);
961 PHAR_SET_32(local.crc32, entry->crc32);
962 continue_dir:
963
964 if (Z_TYPE(entry->metadata) != IS_UNDEF) {
965 php_serialize_data_t metadata_hash;
966
967 if (entry->metadata_str.s) {
968 smart_str_free(&entry->metadata_str);
969 }
970 entry->metadata_str.s = NULL;
971 PHP_VAR_SERIALIZE_INIT(metadata_hash);
972 php_var_serialize(&entry->metadata_str, &entry->metadata, &metadata_hash);
973 PHP_VAR_SERIALIZE_DESTROY(metadata_hash);
974 PHAR_SET_16(central.comment_len, ZSTR_LEN(entry->metadata_str.s));
975 }
976
977 entry->header_offset = php_stream_tell(p->filefp);
978 offset = entry->header_offset + sizeof(local) + entry->filename_len + (entry->is_dir ? 1 : 0) + sizeof(perms);
979
980 if (sizeof(local) != php_stream_write(p->filefp, (char *)&local, sizeof(local))) {
981 spprintf(p->error, 0, "unable to write local file header of file \"%s\" to zip-based phar \"%s\"", entry->filename, entry->phar->fname);
982 return ZEND_HASH_APPLY_STOP;
983 }
984
985 if (sizeof(central) != php_stream_write(p->centralfp, (char *)¢ral, sizeof(central))) {
986 spprintf(p->error, 0, "unable to write central directory entry for file \"%s\" while creating zip-based phar \"%s\"", entry->filename, entry->phar->fname);
987 return ZEND_HASH_APPLY_STOP;
988 }
989
990 if (entry->is_dir) {
991 if (entry->filename_len != php_stream_write(p->filefp, entry->filename, entry->filename_len)) {
992 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);
993 return ZEND_HASH_APPLY_STOP;
994 }
995
996 if (1 != php_stream_write(p->filefp, "/", 1)) {
997 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);
998 return ZEND_HASH_APPLY_STOP;
999 }
1000
1001 if (entry->filename_len != php_stream_write(p->centralfp, entry->filename, entry->filename_len)) {
1002 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);
1003 return ZEND_HASH_APPLY_STOP;
1004 }
1005
1006 if (1 != php_stream_write(p->centralfp, "/", 1)) {
1007 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);
1008 return ZEND_HASH_APPLY_STOP;
1009 }
1010 } else {
1011 if (entry->filename_len != php_stream_write(p->filefp, entry->filename, entry->filename_len)) {
1012 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);
1013 return ZEND_HASH_APPLY_STOP;
1014 }
1015
1016 if (entry->filename_len != php_stream_write(p->centralfp, entry->filename, entry->filename_len)) {
1017 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);
1018 return ZEND_HASH_APPLY_STOP;
1019 }
1020 }
1021
1022 if (sizeof(perms) != php_stream_write(p->filefp, (char *)&perms, sizeof(perms))) {
1023 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);
1024 return ZEND_HASH_APPLY_STOP;
1025 }
1026
1027 if (sizeof(perms) != php_stream_write(p->centralfp, (char *)&perms, sizeof(perms))) {
1028 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);
1029 return ZEND_HASH_APPLY_STOP;
1030 }
1031
1032 if (!not_really_modified && entry->is_modified) {
1033 if (entry->cfp) {
1034 if (SUCCESS != php_stream_copy_to_stream_ex(entry->cfp, p->filefp, entry->compressed_filesize, NULL)) {
1035 spprintf(p->error, 0, "unable to write compressed contents of file \"%s\" in zip-based phar \"%s\"", entry->filename, entry->phar->fname);
1036 return ZEND_HASH_APPLY_STOP;
1037 }
1038
1039 php_stream_close(entry->cfp);
1040 entry->cfp = NULL;
1041 } else {
1042 if (FAILURE == phar_open_entry_fp(entry, p->error, 0)) {
1043 return ZEND_HASH_APPLY_STOP;
1044 }
1045
1046 phar_seek_efp(entry, 0, SEEK_SET, 0, 0);
1047
1048 if (SUCCESS != php_stream_copy_to_stream_ex(phar_get_efp(entry, 0), p->filefp, entry->uncompressed_filesize, NULL)) {
1049 spprintf(p->error, 0, "unable to write contents of file \"%s\" in zip-based phar \"%s\"", entry->filename, entry->phar->fname);
1050 return ZEND_HASH_APPLY_STOP;
1051 }
1052 }
1053
1054 if (entry->fp_type == PHAR_MOD && entry->fp != entry->phar->fp && entry->fp != entry->phar->ufp && entry->fp_refcount == 0) {
1055 php_stream_close(entry->fp);
1056 }
1057
1058 entry->is_modified = 0;
1059 } else {
1060 entry->is_modified = 0;
1061 if (entry->fp_refcount) {
1062
1063 switch (entry->fp_type) {
1064 case PHAR_FP:
1065 p->free_fp = 0;
1066 break;
1067 case PHAR_UFP:
1068 p->free_ufp = 0;
1069 default:
1070 break;
1071 }
1072 }
1073
1074 if (!entry->is_dir && entry->compressed_filesize && SUCCESS != php_stream_copy_to_stream_ex(p->old, p->filefp, entry->compressed_filesize, NULL)) {
1075 spprintf(p->error, 0, "unable to copy contents of file \"%s\" while creating zip-based phar \"%s\"", entry->filename, entry->phar->fname);
1076 return ZEND_HASH_APPLY_STOP;
1077 }
1078 }
1079
1080 entry->fp = NULL;
1081 entry->offset = entry->offset_abs = offset;
1082 entry->fp_type = PHAR_FP;
1083
1084 if (entry->metadata_str.s) {
1085 if (ZSTR_LEN(entry->metadata_str.s) != php_stream_write(p->centralfp, ZSTR_VAL(entry->metadata_str.s), ZSTR_LEN(entry->metadata_str.s))) {
1086 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);
1087 smart_str_free(&entry->metadata_str);
1088 return ZEND_HASH_APPLY_STOP;
1089 }
1090
1091 smart_str_free(&entry->metadata_str);
1092 }
1093
1094 return ZEND_HASH_APPLY_KEEP;
1095 }
1096
1097
1098 static int phar_zip_changed_apply(zval *zv, void *arg)
1099 {
1100 return phar_zip_changed_apply_int(Z_PTR_P(zv), arg);
1101 }
1102
1103
1104 static int phar_zip_applysignature(phar_archive_data *phar, struct _phar_zip_pass *pass,
1105 smart_str *metadata)
1106 {
1107
1108 if (!phar->is_data || phar->sig_flags) {
1109 int signature_length;
1110 char *signature, sigbuf[8];
1111 phar_entry_info entry = {0};
1112 php_stream *newfile;
1113 zend_off_t tell, st;
1114
1115 newfile = php_stream_fopen_tmpfile();
1116 if (newfile == NULL) {
1117 spprintf(pass->error, 0, "phar error: unable to create temporary file for the signature file");
1118 return FAILURE;
1119 }
1120 st = tell = php_stream_tell(pass->filefp);
1121
1122 php_stream_seek(pass->filefp, 0, SEEK_SET);
1123 php_stream_copy_to_stream_ex(pass->filefp, newfile, tell, NULL);
1124 tell = php_stream_tell(pass->centralfp);
1125 php_stream_seek(pass->centralfp, 0, SEEK_SET);
1126 php_stream_copy_to_stream_ex(pass->centralfp, newfile, tell, NULL);
1127 if (metadata->s) {
1128 php_stream_write(newfile, ZSTR_VAL(metadata->s), ZSTR_LEN(metadata->s));
1129 }
1130
1131 if (FAILURE == phar_create_signature(phar, newfile, &signature, &signature_length, pass->error)) {
1132 if (pass->error) {
1133 char *save = *(pass->error);
1134 spprintf(pass->error, 0, "phar error: unable to write signature to zip-based phar: %s", save);
1135 efree(save);
1136 }
1137
1138 php_stream_close(newfile);
1139 return FAILURE;
1140 }
1141
1142 entry.filename = ".phar/signature.bin";
1143 entry.filename_len = sizeof(".phar/signature.bin")-1;
1144 entry.fp = php_stream_fopen_tmpfile();
1145 entry.fp_type = PHAR_MOD;
1146 entry.is_modified = 1;
1147 if (entry.fp == NULL) {
1148 spprintf(pass->error, 0, "phar error: unable to create temporary file for signature");
1149 return FAILURE;
1150 }
1151
1152 PHAR_SET_32(sigbuf, phar->sig_flags);
1153 PHAR_SET_32(sigbuf + 4, signature_length);
1154
1155 if (8 != (int)php_stream_write(entry.fp, sigbuf, 8) || signature_length != (int)php_stream_write(entry.fp, signature, signature_length)) {
1156 efree(signature);
1157 if (pass->error) {
1158 spprintf(pass->error, 0, "phar error: unable to write signature to zip-based phar %s", phar->fname);
1159 }
1160
1161 php_stream_close(newfile);
1162 return FAILURE;
1163 }
1164
1165 efree(signature);
1166 entry.uncompressed_filesize = entry.compressed_filesize = signature_length + 8;
1167 entry.phar = phar;
1168
1169 phar_zip_changed_apply_int(&entry, (void *)pass);
1170 php_stream_close(newfile);
1171
1172 if (pass->error && *(pass->error)) {
1173
1174 php_stream_close(newfile);
1175 return FAILURE;
1176 }
1177 }
1178 return SUCCESS;
1179 }
1180
1181
1182 int phar_zip_flush(phar_archive_data *phar, char *user_stub, zend_long len, int defaultstub, char **error)
1183 {
1184 char *pos;
1185 smart_str main_metadata_str = {0};
1186 static const char newstub[] = "<?php // zip-based phar archive stub file\n__HALT_COMPILER();";
1187 char halt_stub[] = "__HALT_COMPILER();";
1188 char *tmp;
1189
1190 php_stream *stubfile, *oldfile;
1191 php_serialize_data_t metadata_hash;
1192 int free_user_stub, closeoldfile = 0;
1193 phar_entry_info entry = {0};
1194 char *temperr = NULL;
1195 struct _phar_zip_pass pass;
1196 phar_zip_dir_end eocd;
1197 php_uint32 cdir_size, cdir_offset;
1198
1199 pass.error = &temperr;
1200 entry.flags = PHAR_ENT_PERM_DEF_FILE;
1201 entry.timestamp = time(NULL);
1202 entry.is_modified = 1;
1203 entry.is_zip = 1;
1204 entry.phar = phar;
1205 entry.fp_type = PHAR_MOD;
1206
1207 if (phar->is_persistent) {
1208 if (error) {
1209 spprintf(error, 0, "internal error: attempt to flush cached zip-based phar \"%s\"", phar->fname);
1210 }
1211 return EOF;
1212 }
1213
1214 if (phar->is_data) {
1215 goto nostub;
1216 }
1217
1218
1219 if (!phar->is_temporary_alias && phar->alias_len) {
1220 entry.fp = php_stream_fopen_tmpfile();
1221 if (entry.fp == NULL) {
1222 spprintf(error, 0, "phar error: unable to create temporary file");
1223 return EOF;
1224 }
1225 if (phar->alias_len != (int)php_stream_write(entry.fp, phar->alias, phar->alias_len)) {
1226 if (error) {
1227 spprintf(error, 0, "unable to set alias in zip-based phar \"%s\"", phar->fname);
1228 }
1229 return EOF;
1230 }
1231
1232 entry.uncompressed_filesize = entry.compressed_filesize = phar->alias_len;
1233 entry.filename = estrndup(".phar/alias.txt", sizeof(".phar/alias.txt")-1);
1234 entry.filename_len = sizeof(".phar/alias.txt")-1;
1235
1236 if (NULL == zend_hash_str_update_mem(&phar->manifest, entry.filename, entry.filename_len, (void*)&entry, sizeof(phar_entry_info))) {
1237 if (error) {
1238 spprintf(error, 0, "unable to set alias in zip-based phar \"%s\"", phar->fname);
1239 }
1240 return EOF;
1241 }
1242 } else {
1243 zend_hash_str_del(&phar->manifest, ".phar/alias.txt", sizeof(".phar/alias.txt")-1);
1244 }
1245
1246
1247 if (phar->alias_len) {
1248 if (FAILURE == phar_get_archive(&phar, phar->fname, phar->fname_len, phar->alias, phar->alias_len, error)) {
1249 return EOF;
1250 }
1251 }
1252
1253
1254 if (user_stub && !defaultstub) {
1255 if (len < 0) {
1256
1257 if (!(php_stream_from_zval_no_verify(stubfile, (zval *)user_stub))) {
1258 if (error) {
1259 spprintf(error, 0, "unable to access resource to copy stub to new zip-based phar \"%s\"", phar->fname);
1260 }
1261 return EOF;
1262 }
1263
1264 if (len == -1) {
1265 len = PHP_STREAM_COPY_ALL;
1266 } else {
1267 len = -len;
1268 }
1269
1270 user_stub = 0;
1271
1272
1273
1274 {
1275 zend_string *str = php_stream_copy_to_mem(stubfile, len, 0);
1276 if (str) {
1277 len = ZSTR_LEN(str);
1278 user_stub = estrndup(ZSTR_VAL(str), ZSTR_LEN(str));
1279 zend_string_release(str);
1280 } else {
1281 user_stub = NULL;
1282 len = 0;
1283 }
1284 }
1285
1286 if (!len || !user_stub) {
1287 if (error) {
1288 spprintf(error, 0, "unable to read resource to copy stub to new zip-based phar \"%s\"", phar->fname);
1289 }
1290 return EOF;
1291 }
1292 free_user_stub = 1;
1293 } else {
1294 free_user_stub = 0;
1295 }
1296
1297 tmp = estrndup(user_stub, len);
1298 if ((pos = php_stristr(tmp, halt_stub, len, sizeof(halt_stub) - 1)) == NULL) {
1299 efree(tmp);
1300 if (error) {
1301 spprintf(error, 0, "illegal stub for zip-based phar \"%s\"", phar->fname);
1302 }
1303 if (free_user_stub) {
1304 efree(user_stub);
1305 }
1306 return EOF;
1307 }
1308 pos = user_stub + (pos - tmp);
1309 efree(tmp);
1310
1311 len = pos - user_stub + 18;
1312 entry.fp = php_stream_fopen_tmpfile();
1313 if (entry.fp == NULL) {
1314 spprintf(error, 0, "phar error: unable to create temporary file");
1315 return EOF;
1316 }
1317 entry.uncompressed_filesize = len + 5;
1318
1319 if ((size_t)len != php_stream_write(entry.fp, user_stub, len)
1320 || 5 != php_stream_write(entry.fp, " ?>\r\n", 5)) {
1321 if (error) {
1322 spprintf(error, 0, "unable to create stub from string in new zip-based phar \"%s\"", phar->fname);
1323 }
1324 if (free_user_stub) {
1325 efree(user_stub);
1326 }
1327 php_stream_close(entry.fp);
1328 return EOF;
1329 }
1330
1331 entry.filename = estrndup(".phar/stub.php", sizeof(".phar/stub.php")-1);
1332 entry.filename_len = sizeof(".phar/stub.php")-1;
1333
1334 if (NULL == zend_hash_str_update_mem(&phar->manifest, entry.filename, entry.filename_len, (void*)&entry, sizeof(phar_entry_info))) {
1335 if (free_user_stub) {
1336 efree(user_stub);
1337 }
1338 if (error) {
1339 spprintf(error, 0, "unable to set stub in zip-based phar \"%s\"", phar->fname);
1340 }
1341 return EOF;
1342 }
1343
1344 if (free_user_stub) {
1345 efree(user_stub);
1346 }
1347 } else {
1348
1349 entry.fp = php_stream_fopen_tmpfile();
1350 if (entry.fp == NULL) {
1351 spprintf(error, 0, "phar error: unable to create temporary file");
1352 return EOF;
1353 }
1354 if (sizeof(newstub)-1 != php_stream_write(entry.fp, newstub, sizeof(newstub)-1)) {
1355 php_stream_close(entry.fp);
1356 if (error) {
1357 spprintf(error, 0, "unable to %s stub in%szip-based phar \"%s\", failed", user_stub ? "overwrite" : "create", user_stub ? " " : " new ", phar->fname);
1358 }
1359 return EOF;
1360 }
1361
1362 entry.uncompressed_filesize = entry.compressed_filesize = sizeof(newstub) - 1;
1363 entry.filename = estrndup(".phar/stub.php", sizeof(".phar/stub.php")-1);
1364 entry.filename_len = sizeof(".phar/stub.php")-1;
1365
1366 if (!defaultstub) {
1367 if (!zend_hash_str_exists(&phar->manifest, ".phar/stub.php", sizeof(".phar/stub.php")-1)) {
1368 if (NULL == zend_hash_str_add_mem(&phar->manifest, entry.filename, entry.filename_len, (void*)&entry, sizeof(phar_entry_info))) {
1369 php_stream_close(entry.fp);
1370 efree(entry.filename);
1371 if (error) {
1372 spprintf(error, 0, "unable to create stub in zip-based phar \"%s\"", phar->fname);
1373 }
1374 return EOF;
1375 }
1376 } else {
1377 php_stream_close(entry.fp);
1378 efree(entry.filename);
1379 }
1380 } else {
1381 if (NULL == zend_hash_str_update_mem(&phar->manifest, entry.filename, entry.filename_len, (void*)&entry, sizeof(phar_entry_info))) {
1382 php_stream_close(entry.fp);
1383 efree(entry.filename);
1384 if (error) {
1385 spprintf(error, 0, "unable to overwrite stub in zip-based phar \"%s\"", phar->fname);
1386 }
1387 return EOF;
1388 }
1389 }
1390 }
1391 nostub:
1392 if (phar->fp && !phar->is_brandnew) {
1393 oldfile = phar->fp;
1394 closeoldfile = 0;
1395 php_stream_rewind(oldfile);
1396 } else {
1397 oldfile = php_stream_open_wrapper(phar->fname, "rb", 0, NULL);
1398 closeoldfile = oldfile != NULL;
1399 }
1400
1401
1402 pass.old = oldfile;
1403 pass.filefp = php_stream_fopen_tmpfile();
1404
1405 if (!pass.filefp) {
1406 fperror:
1407 if (closeoldfile) {
1408 php_stream_close(oldfile);
1409 }
1410 if (error) {
1411 spprintf(error, 4096, "phar zip flush of \"%s\" failed: unable to open temporary file", phar->fname);
1412 }
1413 return EOF;
1414 }
1415
1416 pass.centralfp = php_stream_fopen_tmpfile();
1417
1418 if (!pass.centralfp) {
1419 goto fperror;
1420 }
1421
1422 pass.free_fp = pass.free_ufp = 1;
1423 memset(&eocd, 0, sizeof(eocd));
1424
1425 strncpy(eocd.signature, "PK\5\6", 4);
1426 if (!phar->is_data && !phar->sig_flags) {
1427 phar->sig_flags = PHAR_SIG_SHA1;
1428 }
1429 if (phar->sig_flags) {
1430 PHAR_SET_16(eocd.counthere, zend_hash_num_elements(&phar->manifest) + 1);
1431 PHAR_SET_16(eocd.count, zend_hash_num_elements(&phar->manifest) + 1);
1432 } else {
1433 PHAR_SET_16(eocd.counthere, zend_hash_num_elements(&phar->manifest));
1434 PHAR_SET_16(eocd.count, zend_hash_num_elements(&phar->manifest));
1435 }
1436 zend_hash_apply_with_argument(&phar->manifest, phar_zip_changed_apply, (void *) &pass);
1437
1438 if (Z_TYPE(phar->metadata) != IS_UNDEF) {
1439
1440 PHP_VAR_SERIALIZE_INIT(metadata_hash);
1441 php_var_serialize(&main_metadata_str, &phar->metadata, &metadata_hash);
1442 PHP_VAR_SERIALIZE_DESTROY(metadata_hash);
1443 }
1444 if (temperr) {
1445 if (error) {
1446 spprintf(error, 4096, "phar zip flush of \"%s\" failed: %s", phar->fname, temperr);
1447 }
1448 efree(temperr);
1449 temperror:
1450 php_stream_close(pass.centralfp);
1451 nocentralerror:
1452 if (Z_TYPE(phar->metadata) != IS_UNDEF) {
1453 smart_str_free(&main_metadata_str);
1454 }
1455 php_stream_close(pass.filefp);
1456 if (closeoldfile) {
1457 php_stream_close(oldfile);
1458 }
1459 return EOF;
1460 }
1461
1462 if (FAILURE == phar_zip_applysignature(phar, &pass, &main_metadata_str)) {
1463 goto temperror;
1464 }
1465
1466
1467 cdir_size = php_stream_tell(pass.centralfp);
1468 cdir_offset = php_stream_tell(pass.filefp);
1469 PHAR_SET_32(eocd.cdir_size, cdir_size);
1470 PHAR_SET_32(eocd.cdir_offset, cdir_offset);
1471 php_stream_seek(pass.centralfp, 0, SEEK_SET);
1472
1473 {
1474 size_t clen;
1475 int ret = php_stream_copy_to_stream_ex(pass.centralfp, pass.filefp, PHP_STREAM_COPY_ALL, &clen);
1476 if (SUCCESS != ret || clen != cdir_size) {
1477 if (error) {
1478 spprintf(error, 4096, "phar zip flush of \"%s\" failed: unable to write central-directory", phar->fname);
1479 }
1480 goto temperror;
1481 }
1482 }
1483
1484 php_stream_close(pass.centralfp);
1485
1486 if (Z_TYPE(phar->metadata) != IS_UNDEF) {
1487
1488 PHAR_SET_16(eocd.comment_len, ZSTR_LEN(main_metadata_str.s));
1489
1490 if (sizeof(eocd) != php_stream_write(pass.filefp, (char *)&eocd, sizeof(eocd))) {
1491 if (error) {
1492 spprintf(error, 4096, "phar zip flush of \"%s\" failed: unable to write end of central-directory", phar->fname);
1493 }
1494 goto nocentralerror;
1495 }
1496
1497 if (ZSTR_LEN(main_metadata_str.s) != php_stream_write(pass.filefp, ZSTR_VAL(main_metadata_str.s), ZSTR_LEN(main_metadata_str.s))) {
1498 if (error) {
1499 spprintf(error, 4096, "phar zip flush of \"%s\" failed: unable to write metadata to zip comment", phar->fname);
1500 }
1501 goto nocentralerror;
1502 }
1503
1504 smart_str_free(&main_metadata_str);
1505
1506 } else {
1507 if (sizeof(eocd) != php_stream_write(pass.filefp, (char *)&eocd, sizeof(eocd))) {
1508 if (error) {
1509 spprintf(error, 4096, "phar zip flush of \"%s\" failed: unable to write end of central-directory", phar->fname);
1510 }
1511 goto nocentralerror;
1512 }
1513 }
1514
1515 if (phar->fp && pass.free_fp) {
1516 php_stream_close(phar->fp);
1517 }
1518
1519 if (phar->ufp) {
1520 if (pass.free_ufp) {
1521 php_stream_close(phar->ufp);
1522 }
1523 phar->ufp = NULL;
1524 }
1525
1526
1527 phar->is_brandnew = 0;
1528
1529 if (phar->donotflush) {
1530
1531 phar->fp = pass.filefp;
1532 } else {
1533 phar->fp = php_stream_open_wrapper(phar->fname, "w+b", IGNORE_URL|STREAM_MUST_SEEK|REPORT_ERRORS, NULL);
1534 if (!phar->fp) {
1535 if (closeoldfile) {
1536 php_stream_close(oldfile);
1537 }
1538 phar->fp = pass.filefp;
1539 if (error) {
1540 spprintf(error, 4096, "unable to open new phar \"%s\" for writing", phar->fname);
1541 }
1542 return EOF;
1543 }
1544 php_stream_rewind(pass.filefp);
1545 php_stream_copy_to_stream_ex(pass.filefp, phar->fp, PHP_STREAM_COPY_ALL, NULL);
1546
1547 php_stream_close(pass.filefp);
1548 }
1549
1550 if (closeoldfile) {
1551 php_stream_close(oldfile);
1552 }
1553 return EOF;
1554 }
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564