1 /*
2 +----------------------------------------------------------------------+
3 | phar php single-file executable PHP extension |
4 | utility functions |
5 +----------------------------------------------------------------------+
6 | Copyright (c) 2005-2018 The PHP Group |
7 +----------------------------------------------------------------------+
8 | This source file is subject to version 3.01 of the PHP license, |
9 | that is bundled with this package in the file LICENSE, and is |
10 | available through the world-wide-web at the following url: |
11 | http://www.php.net/license/3_01.txt. |
12 | If you did not receive a copy of the PHP license and are unable to |
13 | obtain it through the world-wide-web, please send a note to |
14 | license@php.net so we can mail you a copy immediately. |
15 +----------------------------------------------------------------------+
16 | Authors: Gregory Beaver <cellog@php.net> |
17 | Marcus Boerger <helly@php.net> |
18 +----------------------------------------------------------------------+
19 */
20
21 #include "phar_internal.h"
22 #ifdef PHAR_HASH_OK
23 #include "ext/hash/php_hash_sha.h"
24 #endif
25
26 #ifdef PHAR_HAVE_OPENSSL
27 /* OpenSSL includes */
28 #include <openssl/evp.h>
29 #include <openssl/x509.h>
30 #include <openssl/x509v3.h>
31 #include <openssl/crypto.h>
32 #include <openssl/pem.h>
33 #include <openssl/err.h>
34 #include <openssl/conf.h>
35 #include <openssl/rand.h>
36 #include <openssl/ssl.h>
37 #include <openssl/pkcs12.h>
38 #else
39 static int phar_call_openssl_signverify(int is_sign, php_stream *fp, zend_off_t end, char *key, size_t key_len, char **signature, size_t *signature_len);
40 #endif
41
42 /* for links to relative location, prepend cwd of the entry */
phar_get_link_location(phar_entry_info * entry)43 static char *phar_get_link_location(phar_entry_info *entry) /* {{{ */
44 {
45 char *p, *ret = NULL;
46 if (!entry->link) {
47 return NULL;
48 }
49 if (entry->link[0] == '/') {
50 return estrdup(entry->link + 1);
51 }
52 p = strrchr(entry->filename, '/');
53 if (p) {
54 *p = '\0';
55 spprintf(&ret, 0, "%s/%s", entry->filename, entry->link);
56 return ret;
57 }
58 return entry->link;
59 }
60 /* }}} */
61
phar_get_link_source(phar_entry_info * entry)62 phar_entry_info *phar_get_link_source(phar_entry_info *entry) /* {{{ */
63 {
64 phar_entry_info *link_entry;
65 char *link;
66
67 if (!entry->link) {
68 return entry;
69 }
70
71 link = phar_get_link_location(entry);
72 if (NULL != (link_entry = zend_hash_str_find_ptr(&(entry->phar->manifest), entry->link, strlen(entry->link))) ||
73 NULL != (link_entry = zend_hash_str_find_ptr(&(entry->phar->manifest), link, strlen(link)))) {
74 if (link != entry->link) {
75 efree(link);
76 }
77 return phar_get_link_source(link_entry);
78 } else {
79 if (link != entry->link) {
80 efree(link);
81 }
82 return NULL;
83 }
84 }
85 /* }}} */
86
87 /* retrieve a phar_entry_info's current file pointer for reading contents */
phar_get_efp(phar_entry_info * entry,int follow_links)88 php_stream *phar_get_efp(phar_entry_info *entry, int follow_links) /* {{{ */
89 {
90 if (follow_links && entry->link) {
91 phar_entry_info *link_entry = phar_get_link_source(entry);
92
93 if (link_entry && link_entry != entry) {
94 return phar_get_efp(link_entry, 1);
95 }
96 }
97
98 if (phar_get_fp_type(entry) == PHAR_FP) {
99 if (!phar_get_entrypfp(entry)) {
100 /* re-open just in time for cases where our refcount reached 0 on the phar archive */
101 phar_open_archive_fp(entry->phar);
102 }
103 return phar_get_entrypfp(entry);
104 } else if (phar_get_fp_type(entry) == PHAR_UFP) {
105 return phar_get_entrypufp(entry);
106 } else if (entry->fp_type == PHAR_MOD) {
107 return entry->fp;
108 } else {
109 /* temporary manifest entry */
110 if (!entry->fp) {
111 entry->fp = php_stream_open_wrapper(entry->tmp, "rb", STREAM_MUST_SEEK|0, NULL);
112 }
113 return entry->fp;
114 }
115 }
116 /* }}} */
117
phar_seek_efp(phar_entry_info * entry,zend_off_t offset,int whence,zend_off_t position,int follow_links)118 int phar_seek_efp(phar_entry_info *entry, zend_off_t offset, int whence, zend_off_t position, int follow_links) /* {{{ */
119 {
120 php_stream *fp = phar_get_efp(entry, follow_links);
121 zend_off_t temp, eoffset;
122
123 if (!fp) {
124 return -1;
125 }
126
127 if (follow_links) {
128 phar_entry_info *t;
129 t = phar_get_link_source(entry);
130 if (t) {
131 entry = t;
132 }
133 }
134
135 if (entry->is_dir) {
136 return 0;
137 }
138
139 eoffset = phar_get_fp_offset(entry);
140
141 switch (whence) {
142 case SEEK_END:
143 temp = eoffset + entry->uncompressed_filesize + offset;
144 break;
145 case SEEK_CUR:
146 temp = eoffset + position + offset;
147 break;
148 case SEEK_SET:
149 temp = eoffset + offset;
150 break;
151 default:
152 temp = 0;
153 }
154
155 if (temp > eoffset + (zend_off_t) entry->uncompressed_filesize) {
156 return -1;
157 }
158
159 if (temp < eoffset) {
160 return -1;
161 }
162
163 return php_stream_seek(fp, temp, SEEK_SET);
164 }
165 /* }}} */
166
167 /* mount an absolute path or uri to a path internal to the phar archive */
phar_mount_entry(phar_archive_data * phar,char * filename,size_t filename_len,char * path,size_t path_len)168 int phar_mount_entry(phar_archive_data *phar, char *filename, size_t filename_len, char *path, size_t path_len) /* {{{ */
169 {
170 phar_entry_info entry = {0};
171 php_stream_statbuf ssb;
172 int is_phar;
173 const char *err;
174
175 if (phar_path_check(&path, &path_len, &err) > pcr_is_ok) {
176 return FAILURE;
177 }
178
179 if (path_len >= sizeof(".phar")-1 && !memcmp(path, ".phar", sizeof(".phar")-1)) {
180 /* no creating magic phar files by mounting them */
181 return FAILURE;
182 }
183
184 is_phar = (filename_len > 7 && !memcmp(filename, "phar://", 7));
185
186 entry.phar = phar;
187 entry.filename = estrndup(path, path_len);
188 #ifdef PHP_WIN32
189 phar_unixify_path_separators(entry.filename, path_len);
190 #endif
191 entry.filename_len = path_len;
192 if (is_phar) {
193 entry.tmp = estrndup(filename, filename_len);
194 } else {
195 entry.tmp = expand_filepath(filename, NULL);
196 if (!entry.tmp) {
197 entry.tmp = estrndup(filename, filename_len);
198 }
199 }
200 filename = entry.tmp;
201
202 /* only check openbasedir for files, not for phar streams */
203 if (!is_phar && php_check_open_basedir(filename)) {
204 efree(entry.tmp);
205 efree(entry.filename);
206 return FAILURE;
207 }
208
209 entry.is_mounted = 1;
210 entry.is_crc_checked = 1;
211 entry.fp_type = PHAR_TMP;
212
213 if (SUCCESS != php_stream_stat_path(filename, &ssb)) {
214 efree(entry.tmp);
215 efree(entry.filename);
216 return FAILURE;
217 }
218
219 if (ssb.sb.st_mode & S_IFDIR) {
220 entry.is_dir = 1;
221 if (NULL == zend_hash_str_add_ptr(&phar->mounted_dirs, entry.filename, path_len, entry.filename)) {
222 /* directory already mounted */
223 efree(entry.tmp);
224 efree(entry.filename);
225 return FAILURE;
226 }
227 } else {
228 entry.is_dir = 0;
229 entry.uncompressed_filesize = entry.compressed_filesize = ssb.sb.st_size;
230 }
231
232 entry.flags = ssb.sb.st_mode;
233
234 if (NULL != zend_hash_str_add_mem(&phar->manifest, entry.filename, path_len, (void*)&entry, sizeof(phar_entry_info))) {
235 return SUCCESS;
236 }
237
238 efree(entry.tmp);
239 efree(entry.filename);
240 return FAILURE;
241 }
242 /* }}} */
243
phar_find_in_include_path(char * filename,size_t filename_len,phar_archive_data ** pphar)244 zend_string *phar_find_in_include_path(char *filename, size_t filename_len, phar_archive_data **pphar) /* {{{ */
245 {
246 zend_string *ret;
247 char *path, *fname, *arch, *entry, *test;
248 size_t arch_len, entry_len, fname_len;
249 phar_archive_data *phar;
250
251 if (pphar) {
252 *pphar = NULL;
253 } else {
254 pphar = &phar;
255 }
256
257 if (!zend_is_executing() || !PHAR_G(cwd)) {
258 return phar_save_resolve_path(filename, filename_len);
259 }
260
261 fname = (char*)zend_get_executed_filename();
262 fname_len = strlen(fname);
263
264 if (PHAR_G(last_phar) && !memcmp(fname, "phar://", 7) && fname_len - 7 >= PHAR_G(last_phar_name_len) && !memcmp(fname + 7, PHAR_G(last_phar_name), PHAR_G(last_phar_name_len))) {
265 arch = estrndup(PHAR_G(last_phar_name), PHAR_G(last_phar_name_len));
266 arch_len = PHAR_G(last_phar_name_len);
267 phar = PHAR_G(last_phar);
268 goto splitted;
269 }
270
271 if (fname_len < 7 || memcmp(fname, "phar://", 7) || SUCCESS != phar_split_fname(fname, strlen(fname), &arch, &arch_len, &entry, &entry_len, 1, 0)) {
272 return phar_save_resolve_path(filename, filename_len);
273 }
274
275 efree(entry);
276
277 if (*filename == '.') {
278 size_t try_len;
279
280 if (FAILURE == phar_get_archive(&phar, arch, arch_len, NULL, 0, NULL)) {
281 efree(arch);
282 return phar_save_resolve_path(filename, filename_len);
283 }
284 splitted:
285 if (pphar) {
286 *pphar = phar;
287 }
288
289 try_len = filename_len;
290 test = phar_fix_filepath(estrndup(filename, filename_len), &try_len, 1);
291
292 if (*test == '/') {
293 if (zend_hash_str_exists(&(phar->manifest), test + 1, try_len - 1)) {
294 ret = strpprintf(0, "phar://%s%s", arch, test);
295 efree(arch);
296 efree(test);
297 return ret;
298 }
299 } else {
300 if (zend_hash_str_exists(&(phar->manifest), test, try_len)) {
301 ret = strpprintf(0, "phar://%s/%s", arch, test);
302 efree(arch);
303 efree(test);
304 return ret;
305 }
306 }
307 efree(test);
308 }
309
310 spprintf(&path, MAXPATHLEN + 1 + strlen(PG(include_path)), "phar://%s/%s%c%s", arch, PHAR_G(cwd), DEFAULT_DIR_SEPARATOR, PG(include_path));
311 efree(arch);
312 ret = php_resolve_path(filename, filename_len, path);
313 efree(path);
314
315 if (ret && ZSTR_LEN(ret) > 8 && !strncmp(ZSTR_VAL(ret), "phar://", 7)) {
316 /* found phar:// */
317 if (SUCCESS != phar_split_fname(ZSTR_VAL(ret), ZSTR_LEN(ret), &arch, &arch_len, &entry, &entry_len, 1, 0)) {
318 return ret;
319 }
320
321 *pphar = zend_hash_str_find_ptr(&(PHAR_G(phar_fname_map)), arch, arch_len);
322
323 if (!*pphar && PHAR_G(manifest_cached)) {
324 *pphar = zend_hash_str_find_ptr(&cached_phars, arch, arch_len);
325 }
326
327 efree(arch);
328 efree(entry);
329 }
330
331 return ret;
332 }
333 /* }}} */
334
335 /**
336 * Retrieve a copy of the file information on a single file within a phar, or null.
337 * This also transfers the open file pointer, if any, to the entry.
338 *
339 * If the file does not already exist, this will fail. Pre-existing files can be
340 * appended, truncated, or read. For read, if the entry is marked unmodified, it is
341 * assumed that the file pointer, if present, is opened for reading
342 */
phar_get_entry_data(phar_entry_data ** ret,char * fname,size_t fname_len,char * path,size_t path_len,const char * mode,char allow_dir,char ** error,int security)343 int phar_get_entry_data(phar_entry_data **ret, char *fname, size_t fname_len, char *path, size_t path_len, const char *mode, char allow_dir, char **error, int security) /* {{{ */
344 {
345 phar_archive_data *phar;
346 phar_entry_info *entry;
347 int for_write = mode[0] != 'r' || mode[1] == '+';
348 int for_append = mode[0] == 'a';
349 int for_create = mode[0] != 'r';
350 int for_trunc = mode[0] == 'w';
351
352 if (!ret) {
353 return FAILURE;
354 }
355
356 *ret = NULL;
357
358 if (error) {
359 *error = NULL;
360 }
361
362 if (FAILURE == phar_get_archive(&phar, fname, fname_len, NULL, 0, error)) {
363 return FAILURE;
364 }
365
366 if (for_write && PHAR_G(readonly) && !phar->is_data) {
367 if (error) {
368 spprintf(error, 4096, "phar error: file \"%s\" in phar \"%s\" cannot be opened for writing, disabled by ini setting", path, fname);
369 }
370 return FAILURE;
371 }
372
373 if (!path_len) {
374 if (error) {
375 spprintf(error, 4096, "phar error: file \"\" in phar \"%s\" cannot be empty", fname);
376 }
377 return FAILURE;
378 }
379 really_get_entry:
380 if (allow_dir) {
381 if ((entry = phar_get_entry_info_dir(phar, path, path_len, allow_dir, for_create && !PHAR_G(readonly) && !phar->is_data ? NULL : error, security)) == NULL) {
382 if (for_create && (!PHAR_G(readonly) || phar->is_data)) {
383 return SUCCESS;
384 }
385 return FAILURE;
386 }
387 } else {
388 if ((entry = phar_get_entry_info(phar, path, path_len, for_create && !PHAR_G(readonly) && !phar->is_data ? NULL : error, security)) == NULL) {
389 if (for_create && (!PHAR_G(readonly) || phar->is_data)) {
390 return SUCCESS;
391 }
392 return FAILURE;
393 }
394 }
395
396 if (for_write && phar->is_persistent) {
397 if (FAILURE == phar_copy_on_write(&phar)) {
398 if (error) {
399 spprintf(error, 4096, "phar error: file \"%s\" in phar \"%s\" cannot be opened for writing, could not make cached phar writeable", path, fname);
400 }
401 return FAILURE;
402 } else {
403 goto really_get_entry;
404 }
405 }
406
407 if (entry->is_modified && !for_write) {
408 if (error) {
409 spprintf(error, 4096, "phar error: file \"%s\" in phar \"%s\" cannot be opened for reading, writable file pointers are open", path, fname);
410 }
411 return FAILURE;
412 }
413
414 if (entry->fp_refcount && for_write) {
415 if (error) {
416 spprintf(error, 4096, "phar error: file \"%s\" in phar \"%s\" cannot be opened for writing, readable file pointers are open", path, fname);
417 }
418 return FAILURE;
419 }
420
421 if (entry->is_deleted) {
422 if (!for_create) {
423 return FAILURE;
424 }
425 entry->is_deleted = 0;
426 }
427
428 if (entry->is_dir) {
429 *ret = (phar_entry_data *) emalloc(sizeof(phar_entry_data));
430 (*ret)->position = 0;
431 (*ret)->fp = NULL;
432 (*ret)->phar = phar;
433 (*ret)->for_write = for_write;
434 (*ret)->internal_file = entry;
435 (*ret)->is_zip = entry->is_zip;
436 (*ret)->is_tar = entry->is_tar;
437
438 if (!phar->is_persistent) {
439 ++(entry->phar->refcount);
440 ++(entry->fp_refcount);
441 }
442
443 return SUCCESS;
444 }
445
446 if (entry->fp_type == PHAR_MOD) {
447 if (for_trunc) {
448 if (FAILURE == phar_create_writeable_entry(phar, entry, error)) {
449 return FAILURE;
450 }
451 } else if (for_append) {
452 phar_seek_efp(entry, 0, SEEK_END, 0, 0);
453 }
454 } else {
455 if (for_write) {
456 if (entry->link) {
457 efree(entry->link);
458 entry->link = NULL;
459 entry->tar_type = (entry->is_tar ? TAR_FILE : '\0');
460 }
461
462 if (for_trunc) {
463 if (FAILURE == phar_create_writeable_entry(phar, entry, error)) {
464 return FAILURE;
465 }
466 } else {
467 if (FAILURE == phar_separate_entry_fp(entry, error)) {
468 return FAILURE;
469 }
470 }
471 } else {
472 if (FAILURE == phar_open_entry_fp(entry, error, 1)) {
473 return FAILURE;
474 }
475 }
476 }
477
478 *ret = (phar_entry_data *) emalloc(sizeof(phar_entry_data));
479 (*ret)->position = 0;
480 (*ret)->phar = phar;
481 (*ret)->for_write = for_write;
482 (*ret)->internal_file = entry;
483 (*ret)->is_zip = entry->is_zip;
484 (*ret)->is_tar = entry->is_tar;
485 (*ret)->fp = phar_get_efp(entry, 1);
486 if (entry->link) {
487 phar_entry_info *link = phar_get_link_source(entry);
488 if(!link) {
489 efree(*ret);
490 return FAILURE;
491 }
492 (*ret)->zero = phar_get_fp_offset(link);
493 } else {
494 (*ret)->zero = phar_get_fp_offset(entry);
495 }
496
497 if (!phar->is_persistent) {
498 ++(entry->fp_refcount);
499 ++(entry->phar->refcount);
500 }
501
502 return SUCCESS;
503 }
504 /* }}} */
505
506 /**
507 * Create a new dummy file slot within a writeable phar for a newly created file
508 */
phar_get_or_create_entry_data(char * fname,size_t fname_len,char * path,size_t path_len,const char * mode,char allow_dir,char ** error,int security)509 phar_entry_data *phar_get_or_create_entry_data(char *fname, size_t fname_len, char *path, size_t path_len, const char *mode, char allow_dir, char **error, int security) /* {{{ */
510 {
511 phar_archive_data *phar;
512 phar_entry_info *entry, etemp;
513 phar_entry_data *ret;
514 const char *pcr_error;
515 char is_dir;
516
517 #ifdef PHP_WIN32
518 phar_unixify_path_separators(path, path_len);
519 #endif
520
521 is_dir = (path_len && path[path_len - 1] == '/') ? 1 : 0;
522
523 if (FAILURE == phar_get_archive(&phar, fname, fname_len, NULL, 0, error)) {
524 return NULL;
525 }
526
527 if (FAILURE == phar_get_entry_data(&ret, fname, fname_len, path, path_len, mode, allow_dir, error, security)) {
528 return NULL;
529 } else if (ret) {
530 return ret;
531 }
532
533 if (phar_path_check(&path, &path_len, &pcr_error) > pcr_is_ok) {
534 if (error) {
535 spprintf(error, 0, "phar error: invalid path \"%s\" contains %s", path, pcr_error);
536 }
537 return NULL;
538 }
539
540 if (phar->is_persistent && FAILURE == phar_copy_on_write(&phar)) {
541 if (error) {
542 spprintf(error, 4096, "phar error: file \"%s\" in phar \"%s\" cannot be created, could not make cached phar writeable", path, fname);
543 }
544 return NULL;
545 }
546
547 /* create a new phar data holder */
548 ret = (phar_entry_data *) emalloc(sizeof(phar_entry_data));
549
550 /* create an entry, this is a new file */
551 memset(&etemp, 0, sizeof(phar_entry_info));
552 etemp.filename_len = path_len;
553 etemp.fp_type = PHAR_MOD;
554 etemp.fp = php_stream_fopen_tmpfile();
555
556 if (!etemp.fp) {
557 if (error) {
558 spprintf(error, 0, "phar error: unable to create temporary file");
559 }
560 efree(ret);
561 return NULL;
562 }
563
564 etemp.fp_refcount = 1;
565
566 if (allow_dir == 2) {
567 etemp.is_dir = 1;
568 etemp.flags = etemp.old_flags = PHAR_ENT_PERM_DEF_DIR;
569 } else {
570 etemp.flags = etemp.old_flags = PHAR_ENT_PERM_DEF_FILE;
571 }
572 if (is_dir) {
573 etemp.filename_len--; /* strip trailing / */
574 path_len--;
575 }
576
577 phar_add_virtual_dirs(phar, path, path_len);
578 etemp.is_modified = 1;
579 etemp.timestamp = time(0);
580 etemp.is_crc_checked = 1;
581 etemp.phar = phar;
582 etemp.filename = estrndup(path, path_len);
583 etemp.is_zip = phar->is_zip;
584
585 if (phar->is_tar) {
586 etemp.is_tar = phar->is_tar;
587 etemp.tar_type = etemp.is_dir ? TAR_DIR : TAR_FILE;
588 }
589
590 if (NULL == (entry = zend_hash_str_add_mem(&phar->manifest, etemp.filename, path_len, (void*)&etemp, sizeof(phar_entry_info)))) {
591 php_stream_close(etemp.fp);
592 if (error) {
593 spprintf(error, 0, "phar error: unable to add new entry \"%s\" to phar \"%s\"", etemp.filename, phar->fname);
594 }
595 efree(ret);
596 efree(etemp.filename);
597 return NULL;
598 }
599
600 if (!entry) {
601 php_stream_close(etemp.fp);
602 efree(etemp.filename);
603 efree(ret);
604 return NULL;
605 }
606
607 ++(phar->refcount);
608 ret->phar = phar;
609 ret->fp = entry->fp;
610 ret->position = ret->zero = 0;
611 ret->for_write = 1;
612 ret->is_zip = entry->is_zip;
613 ret->is_tar = entry->is_tar;
614 ret->internal_file = entry;
615
616 return ret;
617 }
618 /* }}} */
619
620 /* initialize a phar_archive_data's read-only fp for existing phar data */
phar_open_archive_fp(phar_archive_data * phar)621 int phar_open_archive_fp(phar_archive_data *phar) /* {{{ */
622 {
623 if (phar_get_pharfp(phar)) {
624 return SUCCESS;
625 }
626
627 if (php_check_open_basedir(phar->fname)) {
628 return FAILURE;
629 }
630
631 phar_set_pharfp(phar, php_stream_open_wrapper(phar->fname, "rb", IGNORE_URL|STREAM_MUST_SEEK|0, NULL));
632
633 if (!phar_get_pharfp(phar)) {
634 return FAILURE;
635 }
636
637 return SUCCESS;
638 }
639 /* }}} */
640
641 /* copy file data from an existing to a new phar_entry_info that is not in the manifest */
phar_copy_entry_fp(phar_entry_info * source,phar_entry_info * dest,char ** error)642 int phar_copy_entry_fp(phar_entry_info *source, phar_entry_info *dest, char **error) /* {{{ */
643 {
644 phar_entry_info *link;
645
646 if (FAILURE == phar_open_entry_fp(source, error, 1)) {
647 return FAILURE;
648 }
649
650 if (dest->link) {
651 efree(dest->link);
652 dest->link = NULL;
653 dest->tar_type = (dest->is_tar ? TAR_FILE : '\0');
654 }
655
656 dest->fp_type = PHAR_MOD;
657 dest->offset = 0;
658 dest->is_modified = 1;
659 dest->fp = php_stream_fopen_tmpfile();
660 if (dest->fp == NULL) {
661 spprintf(error, 0, "phar error: unable to create temporary file");
662 return EOF;
663 }
664 phar_seek_efp(source, 0, SEEK_SET, 0, 1);
665 link = phar_get_link_source(source);
666
667 if (!link) {
668 link = source;
669 }
670
671 if (SUCCESS != php_stream_copy_to_stream_ex(phar_get_efp(link, 0), dest->fp, link->uncompressed_filesize, NULL)) {
672 php_stream_close(dest->fp);
673 dest->fp_type = PHAR_FP;
674 if (error) {
675 spprintf(error, 4096, "phar error: unable to copy contents of file \"%s\" to \"%s\" in phar archive \"%s\"", source->filename, dest->filename, source->phar->fname);
676 }
677 return FAILURE;
678 }
679
680 return SUCCESS;
681 }
682 /* }}} */
683
684 /* open and decompress a compressed phar entry
685 */
phar_open_entry_fp(phar_entry_info * entry,char ** error,int follow_links)686 int phar_open_entry_fp(phar_entry_info *entry, char **error, int follow_links) /* {{{ */
687 {
688 php_stream_filter *filter;
689 phar_archive_data *phar = entry->phar;
690 char *filtername;
691 zend_off_t loc;
692 php_stream *ufp;
693 phar_entry_data dummy;
694
695 if (follow_links && entry->link) {
696 phar_entry_info *link_entry = phar_get_link_source(entry);
697 if (link_entry && link_entry != entry) {
698 return phar_open_entry_fp(link_entry, error, 1);
699 }
700 }
701
702 if (entry->is_modified) {
703 return SUCCESS;
704 }
705
706 if (entry->fp_type == PHAR_TMP) {
707 if (!entry->fp) {
708 entry->fp = php_stream_open_wrapper(entry->tmp, "rb", STREAM_MUST_SEEK|0, NULL);
709 }
710 return SUCCESS;
711 }
712
713 if (entry->fp_type != PHAR_FP) {
714 /* either newly created or already modified */
715 return SUCCESS;
716 }
717
718 if (!phar_get_pharfp(phar)) {
719 if (FAILURE == phar_open_archive_fp(phar)) {
720 spprintf(error, 4096, "phar error: Cannot open phar archive \"%s\" for reading", phar->fname);
721 return FAILURE;
722 }
723 }
724
725 if ((entry->old_flags && !(entry->old_flags & PHAR_ENT_COMPRESSION_MASK)) || !(entry->flags & PHAR_ENT_COMPRESSION_MASK)) {
726 dummy.internal_file = entry;
727 dummy.phar = phar;
728 dummy.zero = entry->offset;
729 dummy.fp = phar_get_pharfp(phar);
730 if (FAILURE == phar_postprocess_file(&dummy, entry->crc32, error, 1)) {
731 return FAILURE;
732 }
733 return SUCCESS;
734 }
735
736 if (!phar_get_entrypufp(entry)) {
737 phar_set_entrypufp(entry, php_stream_fopen_tmpfile());
738 if (!phar_get_entrypufp(entry)) {
739 spprintf(error, 4096, "phar error: Cannot open temporary file for decompressing phar archive \"%s\" file \"%s\"", phar->fname, entry->filename);
740 return FAILURE;
741 }
742 }
743
744 dummy.internal_file = entry;
745 dummy.phar = phar;
746 dummy.zero = entry->offset;
747 dummy.fp = phar_get_pharfp(phar);
748 if (FAILURE == phar_postprocess_file(&dummy, entry->crc32, error, 1)) {
749 return FAILURE;
750 }
751
752 ufp = phar_get_entrypufp(entry);
753
754 if ((filtername = phar_decompress_filter(entry, 0)) != NULL) {
755 filter = php_stream_filter_create(filtername, NULL, 0);
756 } else {
757 filter = NULL;
758 }
759
760 if (!filter) {
761 spprintf(error, 4096, "phar error: unable to read phar \"%s\" (cannot create %s filter while decompressing file \"%s\")", phar->fname, phar_decompress_filter(entry, 1), entry->filename);
762 return FAILURE;
763 }
764
765 /* now we can safely use proper decompression */
766 /* save the new offset location within ufp */
767 php_stream_seek(ufp, 0, SEEK_END);
768 loc = php_stream_tell(ufp);
769 php_stream_filter_append(&ufp->writefilters, filter);
770 php_stream_seek(phar_get_entrypfp(entry), phar_get_fp_offset(entry), SEEK_SET);
771
772 if (entry->uncompressed_filesize) {
773 if (SUCCESS != php_stream_copy_to_stream_ex(phar_get_entrypfp(entry), ufp, entry->compressed_filesize, NULL)) {
774 spprintf(error, 4096, "phar error: internal corruption of phar \"%s\" (actual filesize mismatch on file \"%s\")", phar->fname, entry->filename);
775 php_stream_filter_remove(filter, 1);
776 return FAILURE;
777 }
778 }
779
780 php_stream_filter_flush(filter, 1);
781 php_stream_flush(ufp);
782 php_stream_filter_remove(filter, 1);
783
784 if (php_stream_tell(ufp) - loc != (zend_off_t) entry->uncompressed_filesize) {
785 spprintf(error, 4096, "phar error: internal corruption of phar \"%s\" (actual filesize mismatch on file \"%s\")", phar->fname, entry->filename);
786 return FAILURE;
787 }
788
789 entry->old_flags = entry->flags;
790
791 /* this is now the new location of the file contents within this fp */
792 phar_set_fp_type(entry, PHAR_UFP, loc);
793 dummy.zero = entry->offset;
794 dummy.fp = ufp;
795 if (FAILURE == phar_postprocess_file(&dummy, entry->crc32, error, 0)) {
796 return FAILURE;
797 }
798 return SUCCESS;
799 }
800 /* }}} */
801
phar_create_writeable_entry(phar_archive_data * phar,phar_entry_info * entry,char ** error)802 int phar_create_writeable_entry(phar_archive_data *phar, phar_entry_info *entry, char **error) /* {{{ */
803 {
804 if (entry->fp_type == PHAR_MOD) {
805 /* already newly created, truncate */
806 php_stream_truncate_set_size(entry->fp, 0);
807
808 entry->old_flags = entry->flags;
809 entry->is_modified = 1;
810 phar->is_modified = 1;
811 /* reset file size */
812 entry->uncompressed_filesize = 0;
813 entry->compressed_filesize = 0;
814 entry->crc32 = 0;
815 entry->flags = PHAR_ENT_PERM_DEF_FILE;
816 entry->fp_type = PHAR_MOD;
817 entry->offset = 0;
818 return SUCCESS;
819 }
820
821 if (error) {
822 *error = NULL;
823 }
824
825 /* open a new temp file for writing */
826 if (entry->link) {
827 efree(entry->link);
828 entry->link = NULL;
829 entry->tar_type = (entry->is_tar ? TAR_FILE : '\0');
830 }
831
832 entry->fp = php_stream_fopen_tmpfile();
833
834 if (!entry->fp) {
835 if (error) {
836 spprintf(error, 0, "phar error: unable to create temporary file");
837 }
838 return FAILURE;
839 }
840
841 entry->old_flags = entry->flags;
842 entry->is_modified = 1;
843 phar->is_modified = 1;
844 /* reset file size */
845 entry->uncompressed_filesize = 0;
846 entry->compressed_filesize = 0;
847 entry->crc32 = 0;
848 entry->flags = PHAR_ENT_PERM_DEF_FILE;
849 entry->fp_type = PHAR_MOD;
850 entry->offset = 0;
851 return SUCCESS;
852 }
853 /* }}} */
854
phar_separate_entry_fp(phar_entry_info * entry,char ** error)855 int phar_separate_entry_fp(phar_entry_info *entry, char **error) /* {{{ */
856 {
857 php_stream *fp;
858 phar_entry_info *link;
859
860 if (FAILURE == phar_open_entry_fp(entry, error, 1)) {
861 return FAILURE;
862 }
863
864 if (entry->fp_type == PHAR_MOD) {
865 return SUCCESS;
866 }
867
868 fp = php_stream_fopen_tmpfile();
869 if (fp == NULL) {
870 spprintf(error, 0, "phar error: unable to create temporary file");
871 return FAILURE;
872 }
873 phar_seek_efp(entry, 0, SEEK_SET, 0, 1);
874 link = phar_get_link_source(entry);
875
876 if (!link) {
877 link = entry;
878 }
879
880 if (SUCCESS != php_stream_copy_to_stream_ex(phar_get_efp(link, 0), fp, link->uncompressed_filesize, NULL)) {
881 if (error) {
882 spprintf(error, 4096, "phar error: cannot separate entry file \"%s\" contents in phar archive \"%s\" for write access", entry->filename, entry->phar->fname);
883 }
884 return FAILURE;
885 }
886
887 if (entry->link) {
888 efree(entry->link);
889 entry->link = NULL;
890 entry->tar_type = (entry->is_tar ? TAR_FILE : '\0');
891 }
892
893 entry->offset = 0;
894 entry->fp = fp;
895 entry->fp_type = PHAR_MOD;
896 entry->is_modified = 1;
897 return SUCCESS;
898 }
899 /* }}} */
900
901 /**
902 * helper function to open an internal file's fp just-in-time
903 */
phar_open_jit(phar_archive_data * phar,phar_entry_info * entry,char ** error)904 phar_entry_info * phar_open_jit(phar_archive_data *phar, phar_entry_info *entry, char **error) /* {{{ */
905 {
906 if (error) {
907 *error = NULL;
908 }
909 /* seek to start of internal file and read it */
910 if (FAILURE == phar_open_entry_fp(entry, error, 1)) {
911 return NULL;
912 }
913 if (-1 == phar_seek_efp(entry, 0, SEEK_SET, 0, 1)) {
914 spprintf(error, 4096, "phar error: cannot seek to start of file \"%s\" in phar \"%s\"", entry->filename, phar->fname);
915 return NULL;
916 }
917 return entry;
918 }
919 /* }}} */
920
phar_resolve_alias(char * alias,size_t alias_len,char ** filename,size_t * filename_len)921 PHP_PHAR_API int phar_resolve_alias(char *alias, size_t alias_len, char **filename, size_t *filename_len) /* {{{ */ {
922 phar_archive_data *fd_ptr;
923 if (HT_FLAGS(&PHAR_G(phar_alias_map))
924 && NULL != (fd_ptr = zend_hash_str_find_ptr(&(PHAR_G(phar_alias_map)), alias, alias_len))) {
925 *filename = fd_ptr->fname;
926 *filename_len = fd_ptr->fname_len;
927 return SUCCESS;
928 }
929 return FAILURE;
930 }
931 /* }}} */
932
phar_free_alias(phar_archive_data * phar,char * alias,size_t alias_len)933 int phar_free_alias(phar_archive_data *phar, char *alias, size_t alias_len) /* {{{ */
934 {
935 if (phar->refcount || phar->is_persistent) {
936 return FAILURE;
937 }
938
939 /* this archive has no open references, so emit an E_STRICT and remove it */
940 if (zend_hash_str_del(&(PHAR_G(phar_fname_map)), phar->fname, phar->fname_len) != SUCCESS) {
941 return FAILURE;
942 }
943
944 /* invalidate phar cache */
945 PHAR_G(last_phar) = NULL;
946 PHAR_G(last_phar_name) = PHAR_G(last_alias) = NULL;
947
948 return SUCCESS;
949 }
950 /* }}} */
951
952 /**
953 * Looks up a phar archive in the filename map, connecting it to the alias
954 * (if any) or returns null
955 */
phar_get_archive(phar_archive_data ** archive,char * fname,size_t fname_len,char * alias,size_t alias_len,char ** error)956 int phar_get_archive(phar_archive_data **archive, char *fname, size_t fname_len, char *alias, size_t alias_len, char **error) /* {{{ */
957 {
958 phar_archive_data *fd, *fd_ptr;
959 char *my_realpath, *save;
960 size_t save_len;
961
962 phar_request_initialize();
963
964 if (error) {
965 *error = NULL;
966 }
967
968 *archive = NULL;
969
970 if (PHAR_G(last_phar) && fname_len == PHAR_G(last_phar_name_len) && !memcmp(fname, PHAR_G(last_phar_name), fname_len)) {
971 *archive = PHAR_G(last_phar);
972 if (alias && alias_len) {
973
974 if (!PHAR_G(last_phar)->is_temporary_alias && (alias_len != PHAR_G(last_phar)->alias_len || memcmp(PHAR_G(last_phar)->alias, alias, alias_len))) {
975 if (error) {
976 spprintf(error, 0, "alias \"%s\" is already used for archive \"%s\" cannot be overloaded with \"%s\"", alias, PHAR_G(last_phar)->fname, fname);
977 }
978 *archive = NULL;
979 return FAILURE;
980 }
981
982 if (PHAR_G(last_phar)->alias_len && NULL != (fd_ptr = zend_hash_str_find_ptr(&(PHAR_G(phar_alias_map)), PHAR_G(last_phar)->alias, PHAR_G(last_phar)->alias_len))) {
983 zend_hash_str_del(&(PHAR_G(phar_alias_map)), PHAR_G(last_phar)->alias, PHAR_G(last_phar)->alias_len);
984 }
985
986 zend_hash_str_add_ptr(&(PHAR_G(phar_alias_map)), alias, alias_len, *archive);
987 PHAR_G(last_alias) = alias;
988 PHAR_G(last_alias_len) = alias_len;
989 }
990
991 return SUCCESS;
992 }
993
994 if (alias && alias_len && PHAR_G(last_phar) && alias_len == PHAR_G(last_alias_len) && !memcmp(alias, PHAR_G(last_alias), alias_len)) {
995 fd = PHAR_G(last_phar);
996 fd_ptr = fd;
997 goto alias_success;
998 }
999
1000 if (alias && alias_len) {
1001 if (NULL != (fd_ptr = zend_hash_str_find_ptr(&(PHAR_G(phar_alias_map)), alias, alias_len))) {
1002 alias_success:
1003 if (fname && (fname_len != fd_ptr->fname_len || strncmp(fname, fd_ptr->fname, fname_len))) {
1004 if (error) {
1005 spprintf(error, 0, "alias \"%s\" is already used for archive \"%s\" cannot be overloaded with \"%s\"", alias, fd_ptr->fname, fname);
1006 }
1007 if (SUCCESS == phar_free_alias(fd_ptr, alias, alias_len)) {
1008 if (error) {
1009 efree(*error);
1010 *error = NULL;
1011 }
1012 }
1013 return FAILURE;
1014 }
1015
1016 *archive = fd_ptr;
1017 fd = fd_ptr;
1018 PHAR_G(last_phar) = fd;
1019 PHAR_G(last_phar_name) = fd->fname;
1020 PHAR_G(last_phar_name_len) = fd->fname_len;
1021 PHAR_G(last_alias) = alias;
1022 PHAR_G(last_alias_len) = alias_len;
1023
1024 return SUCCESS;
1025 }
1026
1027 if (PHAR_G(manifest_cached) && NULL != (fd_ptr = zend_hash_str_find_ptr(&cached_alias, alias, alias_len))) {
1028 goto alias_success;
1029 }
1030 }
1031
1032 my_realpath = NULL;
1033 save = fname;
1034 save_len = fname_len;
1035
1036 if (fname && fname_len) {
1037 if (NULL != (fd_ptr = zend_hash_str_find_ptr(&(PHAR_G(phar_fname_map)), fname, fname_len))) {
1038 *archive = fd_ptr;
1039 fd = fd_ptr;
1040
1041 if (alias && alias_len) {
1042 if (!fd->is_temporary_alias && (alias_len != fd->alias_len || memcmp(fd->alias, alias, alias_len))) {
1043 if (error) {
1044 spprintf(error, 0, "alias \"%s\" is already used for archive \"%s\" cannot be overloaded with \"%s\"", alias, fd_ptr->fname, fname);
1045 }
1046 return FAILURE;
1047 }
1048
1049 if (fd->alias_len && NULL != (fd_ptr = zend_hash_str_find_ptr(&(PHAR_G(phar_alias_map)), fd->alias, fd->alias_len))) {
1050 zend_hash_str_del(&(PHAR_G(phar_alias_map)), fd->alias, fd->alias_len);
1051 }
1052
1053 zend_hash_str_add_ptr(&(PHAR_G(phar_alias_map)), alias, alias_len, fd);
1054 }
1055
1056 PHAR_G(last_phar) = fd;
1057 PHAR_G(last_phar_name) = fd->fname;
1058 PHAR_G(last_phar_name_len) = fd->fname_len;
1059 PHAR_G(last_alias) = fd->alias;
1060 PHAR_G(last_alias_len) = fd->alias_len;
1061
1062 return SUCCESS;
1063 }
1064
1065 if (PHAR_G(manifest_cached) && NULL != (fd_ptr = zend_hash_str_find_ptr(&cached_phars, fname, fname_len))) {
1066 *archive = fd_ptr;
1067 fd = fd_ptr;
1068
1069 /* this could be problematic - alias should never be different from manifest alias
1070 for cached phars */
1071 if (!fd->is_temporary_alias && alias && alias_len) {
1072 if (alias_len != fd->alias_len || memcmp(fd->alias, alias, alias_len)) {
1073 if (error) {
1074 spprintf(error, 0, "alias \"%s\" is already used for archive \"%s\" cannot be overloaded with \"%s\"", alias, fd_ptr->fname, fname);
1075 }
1076 return FAILURE;
1077 }
1078 }
1079
1080 PHAR_G(last_phar) = fd;
1081 PHAR_G(last_phar_name) = fd->fname;
1082 PHAR_G(last_phar_name_len) = fd->fname_len;
1083 PHAR_G(last_alias) = fd->alias;
1084 PHAR_G(last_alias_len) = fd->alias_len;
1085
1086 return SUCCESS;
1087 }
1088
1089 if (NULL != (fd_ptr = zend_hash_str_find_ptr(&(PHAR_G(phar_alias_map)), save, save_len))) {
1090 fd = *archive = fd_ptr;
1091
1092 PHAR_G(last_phar) = fd;
1093 PHAR_G(last_phar_name) = fd->fname;
1094 PHAR_G(last_phar_name_len) = fd->fname_len;
1095 PHAR_G(last_alias) = fd->alias;
1096 PHAR_G(last_alias_len) = fd->alias_len;
1097
1098 return SUCCESS;
1099 }
1100
1101 if (PHAR_G(manifest_cached) && NULL != (fd_ptr = zend_hash_str_find_ptr(&cached_alias, save, save_len))) {
1102 fd = *archive = fd_ptr;
1103
1104 PHAR_G(last_phar) = fd;
1105 PHAR_G(last_phar_name) = fd->fname;
1106 PHAR_G(last_phar_name_len) = fd->fname_len;
1107 PHAR_G(last_alias) = fd->alias;
1108 PHAR_G(last_alias_len) = fd->alias_len;
1109
1110 return SUCCESS;
1111 }
1112
1113 /* not found, try converting \ to / */
1114 my_realpath = expand_filepath(fname, my_realpath);
1115
1116 if (my_realpath) {
1117 fname_len = strlen(my_realpath);
1118 fname = my_realpath;
1119 } else {
1120 return FAILURE;
1121 }
1122 #ifdef PHP_WIN32
1123 phar_unixify_path_separators(fname, fname_len);
1124 #endif
1125
1126 if (NULL != (fd_ptr = zend_hash_str_find_ptr(&(PHAR_G(phar_fname_map)), fname, fname_len))) {
1127 realpath_success:
1128 *archive = fd_ptr;
1129 fd = fd_ptr;
1130
1131 if (alias && alias_len) {
1132 zend_hash_str_add_ptr(&(PHAR_G(phar_alias_map)), alias, alias_len, fd);
1133 }
1134
1135 efree(my_realpath);
1136
1137 PHAR_G(last_phar) = fd;
1138 PHAR_G(last_phar_name) = fd->fname;
1139 PHAR_G(last_phar_name_len) = fd->fname_len;
1140 PHAR_G(last_alias) = fd->alias;
1141 PHAR_G(last_alias_len) = fd->alias_len;
1142
1143 return SUCCESS;
1144 }
1145
1146 if (PHAR_G(manifest_cached) && NULL != (fd_ptr = zend_hash_str_find_ptr(&cached_phars, fname, fname_len))) {
1147 goto realpath_success;
1148 }
1149
1150 efree(my_realpath);
1151 }
1152
1153 return FAILURE;
1154 }
1155 /* }}} */
1156
1157 /**
1158 * Determine which stream compression filter (if any) we need to read this file
1159 */
phar_compress_filter(phar_entry_info * entry,int return_unknown)1160 char * phar_compress_filter(phar_entry_info * entry, int return_unknown) /* {{{ */
1161 {
1162 switch (entry->flags & PHAR_ENT_COMPRESSION_MASK) {
1163 case PHAR_ENT_COMPRESSED_GZ:
1164 return "zlib.deflate";
1165 case PHAR_ENT_COMPRESSED_BZ2:
1166 return "bzip2.compress";
1167 default:
1168 return return_unknown ? "unknown" : NULL;
1169 }
1170 }
1171 /* }}} */
1172
1173 /**
1174 * Determine which stream decompression filter (if any) we need to read this file
1175 */
phar_decompress_filter(phar_entry_info * entry,int return_unknown)1176 char * phar_decompress_filter(phar_entry_info * entry, int return_unknown) /* {{{ */
1177 {
1178 uint32_t flags;
1179
1180 if (entry->is_modified) {
1181 flags = entry->old_flags;
1182 } else {
1183 flags = entry->flags;
1184 }
1185
1186 switch (flags & PHAR_ENT_COMPRESSION_MASK) {
1187 case PHAR_ENT_COMPRESSED_GZ:
1188 return "zlib.inflate";
1189 case PHAR_ENT_COMPRESSED_BZ2:
1190 return "bzip2.decompress";
1191 default:
1192 return return_unknown ? "unknown" : NULL;
1193 }
1194 }
1195 /* }}} */
1196
1197 /**
1198 * retrieve information on a file contained within a phar, or null if it ain't there
1199 */
phar_get_entry_info(phar_archive_data * phar,char * path,size_t path_len,char ** error,int security)1200 phar_entry_info *phar_get_entry_info(phar_archive_data *phar, char *path, size_t path_len, char **error, int security) /* {{{ */
1201 {
1202 return phar_get_entry_info_dir(phar, path, path_len, 0, error, security);
1203 }
1204 /* }}} */
1205 /**
1206 * retrieve information on a file or directory contained within a phar, or null if none found
1207 * allow_dir is 0 for none, 1 for both empty directories in the phar and temp directories, and 2 for only
1208 * valid pre-existing empty directory entries
1209 */
phar_get_entry_info_dir(phar_archive_data * phar,char * path,size_t path_len,char dir,char ** error,int security)1210 phar_entry_info *phar_get_entry_info_dir(phar_archive_data *phar, char *path, size_t path_len, char dir, char **error, int security) /* {{{ */
1211 {
1212 const char *pcr_error;
1213 phar_entry_info *entry;
1214 int is_dir;
1215
1216 #ifdef PHP_WIN32
1217 phar_unixify_path_separators(path, path_len);
1218 #endif
1219
1220 is_dir = (path_len && (path[path_len - 1] == '/')) ? 1 : 0;
1221
1222 if (error) {
1223 *error = NULL;
1224 }
1225
1226 if (security && path_len >= sizeof(".phar")-1 && !memcmp(path, ".phar", sizeof(".phar")-1)) {
1227 if (error) {
1228 spprintf(error, 4096, "phar error: cannot directly access magic \".phar\" directory or files within it");
1229 }
1230 return NULL;
1231 }
1232
1233 if (!path_len && !dir) {
1234 if (error) {
1235 spprintf(error, 4096, "phar error: invalid path \"%s\" must not be empty", path);
1236 }
1237 return NULL;
1238 }
1239
1240 if (phar_path_check(&path, &path_len, &pcr_error) > pcr_is_ok) {
1241 if (error) {
1242 spprintf(error, 4096, "phar error: invalid path \"%s\" contains %s", path, pcr_error);
1243 }
1244 return NULL;
1245 }
1246
1247 if (!HT_FLAGS(&phar->manifest)) {
1248 return NULL;
1249 }
1250
1251 if (is_dir) {
1252 if (!path_len || path_len == 1) {
1253 return NULL;
1254 }
1255 path_len--;
1256 }
1257
1258 if (NULL != (entry = zend_hash_str_find_ptr(&phar->manifest, path, path_len))) {
1259 if (entry->is_deleted) {
1260 /* entry is deleted, but has not been flushed to disk yet */
1261 return NULL;
1262 }
1263 if (entry->is_dir && !dir) {
1264 if (error) {
1265 spprintf(error, 4096, "phar error: path \"%s\" is a directory", path);
1266 }
1267 return NULL;
1268 }
1269 if (!entry->is_dir && dir == 2) {
1270 /* user requested a directory, we must return one */
1271 if (error) {
1272 spprintf(error, 4096, "phar error: path \"%s\" exists and is a not a directory", path);
1273 }
1274 return NULL;
1275 }
1276 return entry;
1277 }
1278
1279 if (dir) {
1280 if (zend_hash_str_exists(&phar->virtual_dirs, path, path_len)) {
1281 /* a file or directory exists in a sub-directory of this path */
1282 entry = (phar_entry_info *) ecalloc(1, sizeof(phar_entry_info));
1283 /* this next line tells PharFileInfo->__destruct() to efree the filename */
1284 entry->is_temp_dir = entry->is_dir = 1;
1285 entry->filename = (char *) estrndup(path, path_len + 1);
1286 entry->filename_len = path_len;
1287 entry->phar = phar;
1288 return entry;
1289 }
1290 }
1291
1292 if (HT_FLAGS(&phar->mounted_dirs) && zend_hash_num_elements(&phar->mounted_dirs)) {
1293 zend_string *str_key;
1294
1295 ZEND_HASH_FOREACH_STR_KEY(&phar->mounted_dirs, str_key) {
1296 if (ZSTR_LEN(str_key) >= path_len || strncmp(ZSTR_VAL(str_key), path, ZSTR_LEN(str_key))) {
1297 continue;
1298 } else {
1299 char *test;
1300 size_t test_len;
1301 php_stream_statbuf ssb;
1302
1303 if (NULL == (entry = zend_hash_find_ptr(&phar->manifest, str_key))) {
1304 if (error) {
1305 spprintf(error, 4096, "phar internal error: mounted path \"%s\" could not be retrieved from manifest", ZSTR_VAL(str_key));
1306 }
1307 return NULL;
1308 }
1309
1310 if (!entry->tmp || !entry->is_mounted) {
1311 if (error) {
1312 spprintf(error, 4096, "phar internal error: mounted path \"%s\" is not properly initialized as a mounted path", ZSTR_VAL(str_key));
1313 }
1314 return NULL;
1315 }
1316
1317 test_len = spprintf(&test, MAXPATHLEN, "%s%s", entry->tmp, path + ZSTR_LEN(str_key));
1318
1319 if (SUCCESS != php_stream_stat_path(test, &ssb)) {
1320 efree(test);
1321 return NULL;
1322 }
1323
1324 if (ssb.sb.st_mode & S_IFDIR && !dir) {
1325 efree(test);
1326 if (error) {
1327 spprintf(error, 4096, "phar error: path \"%s\" is a directory", path);
1328 }
1329 return NULL;
1330 }
1331
1332 if ((ssb.sb.st_mode & S_IFDIR) == 0 && dir) {
1333 efree(test);
1334 /* user requested a directory, we must return one */
1335 if (error) {
1336 spprintf(error, 4096, "phar error: path \"%s\" exists and is a not a directory", path);
1337 }
1338 return NULL;
1339 }
1340
1341 /* mount the file just in time */
1342 if (SUCCESS != phar_mount_entry(phar, test, test_len, path, path_len)) {
1343 efree(test);
1344 if (error) {
1345 spprintf(error, 4096, "phar error: path \"%s\" exists as file \"%s\" and could not be mounted", path, test);
1346 }
1347 return NULL;
1348 }
1349
1350 efree(test);
1351
1352 if (NULL == (entry = zend_hash_str_find_ptr(&phar->manifest, path, path_len))) {
1353 if (error) {
1354 spprintf(error, 4096, "phar error: path \"%s\" exists as file \"%s\" and could not be retrieved after being mounted", path, test);
1355 }
1356 return NULL;
1357 }
1358 return entry;
1359 }
1360 } ZEND_HASH_FOREACH_END();
1361 }
1362
1363 return NULL;
1364 }
1365 /* }}} */
1366
1367 static const char hexChars[] = "0123456789ABCDEF";
1368
phar_hex_str(const char * digest,size_t digest_len,char ** signature)1369 static int phar_hex_str(const char *digest, size_t digest_len, char **signature) /* {{{ */
1370 {
1371 int pos = -1;
1372 size_t len = 0;
1373
1374 *signature = (char*)safe_pemalloc(digest_len, 2, 1, PHAR_G(persist));
1375
1376 for (; len < digest_len; ++len) {
1377 (*signature)[++pos] = hexChars[((const unsigned char *)digest)[len] >> 4];
1378 (*signature)[++pos] = hexChars[((const unsigned char *)digest)[len] & 0x0F];
1379 }
1380 (*signature)[++pos] = '\0';
1381 return pos;
1382 }
1383 /* }}} */
1384
1385 #ifndef PHAR_HAVE_OPENSSL
phar_call_openssl_signverify(int is_sign,php_stream * fp,zend_off_t end,char * key,size_t key_len,char ** signature,size_t * signature_len)1386 static int phar_call_openssl_signverify(int is_sign, php_stream *fp, zend_off_t end, char *key, size_t key_len, char **signature, size_t *signature_len) /* {{{ */
1387 {
1388 zend_fcall_info fci;
1389 zend_fcall_info_cache fcc;
1390 zval retval, zp[3], openssl;
1391 zend_string *str;
1392
1393 ZVAL_STRINGL(&openssl, is_sign ? "openssl_sign" : "openssl_verify", is_sign ? sizeof("openssl_sign")-1 : sizeof("openssl_verify")-1);
1394 ZVAL_STRINGL(&zp[1], *signature, *signature_len);
1395 ZVAL_STRINGL(&zp[2], key, key_len);
1396 php_stream_rewind(fp);
1397 str = php_stream_copy_to_mem(fp, (size_t) end, 0);
1398 if (str) {
1399 ZVAL_STR(&zp[0], str);
1400 } else {
1401 ZVAL_EMPTY_STRING(&zp[0]);
1402 }
1403
1404 if ((size_t)end != Z_STRLEN(zp[0])) {
1405 zval_ptr_dtor_str(&zp[0]);
1406 zval_ptr_dtor_str(&zp[1]);
1407 zval_ptr_dtor_str(&zp[2]);
1408 zval_ptr_dtor_str(&openssl);
1409 return FAILURE;
1410 }
1411
1412 if (FAILURE == zend_fcall_info_init(&openssl, 0, &fci, &fcc, NULL, NULL)) {
1413 zval_ptr_dtor_str(&zp[0]);
1414 zval_ptr_dtor_str(&zp[1]);
1415 zval_ptr_dtor_str(&zp[2]);
1416 zval_ptr_dtor_str(&openssl);
1417 return FAILURE;
1418 }
1419
1420 fci.param_count = 3;
1421 fci.params = zp;
1422 Z_ADDREF(zp[0]);
1423 if (is_sign) {
1424 ZVAL_NEW_REF(&zp[1], &zp[1]);
1425 } else {
1426 Z_ADDREF(zp[1]);
1427 }
1428 Z_ADDREF(zp[2]);
1429
1430 fci.retval = &retval;
1431
1432 if (FAILURE == zend_call_function(&fci, &fcc)) {
1433 zval_ptr_dtor_str(&zp[0]);
1434 zval_ptr_dtor(&zp[1]);
1435 zval_ptr_dtor_str(&zp[2]);
1436 zval_ptr_dtor_str(&openssl);
1437 return FAILURE;
1438 }
1439
1440 zval_ptr_dtor_str(&openssl);
1441 Z_DELREF(zp[0]);
1442
1443 if (is_sign) {
1444 ZVAL_UNREF(&zp[1]);
1445 } else {
1446 Z_DELREF(zp[1]);
1447 }
1448 Z_DELREF(zp[2]);
1449
1450 zval_ptr_dtor_str(&zp[0]);
1451 zval_ptr_dtor_str(&zp[2]);
1452
1453 switch (Z_TYPE(retval)) {
1454 default:
1455 case IS_LONG:
1456 zval_ptr_dtor(&zp[1]);
1457 if (1 == Z_LVAL(retval)) {
1458 return SUCCESS;
1459 }
1460 return FAILURE;
1461 case IS_TRUE:
1462 *signature = estrndup(Z_STRVAL(zp[1]), Z_STRLEN(zp[1]));
1463 *signature_len = Z_STRLEN(zp[1]);
1464 zval_ptr_dtor(&zp[1]);
1465 return SUCCESS;
1466 case IS_FALSE:
1467 zval_ptr_dtor(&zp[1]);
1468 return FAILURE;
1469 }
1470 }
1471 /* }}} */
1472 #endif /* #ifndef PHAR_HAVE_OPENSSL */
1473
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)1474 int 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) /* {{{ */
1475 {
1476 size_t read_size, len;
1477 zend_off_t read_len;
1478 unsigned char buf[1024];
1479
1480 php_stream_rewind(fp);
1481
1482 switch (sig_type) {
1483 case PHAR_SIG_OPENSSL: {
1484 #ifdef PHAR_HAVE_OPENSSL
1485 BIO *in;
1486 EVP_PKEY *key;
1487 EVP_MD *mdtype = (EVP_MD *) EVP_sha1();
1488 EVP_MD_CTX *md_ctx;
1489 #else
1490 size_t tempsig;
1491 #endif
1492 zend_string *pubkey = NULL;
1493 char *pfile;
1494 php_stream *pfp;
1495 #ifndef PHAR_HAVE_OPENSSL
1496 if (!zend_hash_str_exists(&module_registry, "openssl", sizeof("openssl")-1)) {
1497 if (error) {
1498 spprintf(error, 0, "openssl not loaded");
1499 }
1500 return FAILURE;
1501 }
1502 #endif
1503 /* use __FILE__ . '.pubkey' for public key file */
1504 spprintf(&pfile, 0, "%s.pubkey", fname);
1505 pfp = php_stream_open_wrapper(pfile, "rb", 0, NULL);
1506 efree(pfile);
1507
1508 if (!pfp || !(pubkey = php_stream_copy_to_mem(pfp, PHP_STREAM_COPY_ALL, 0)) || !ZSTR_LEN(pubkey)) {
1509 if (pfp) {
1510 php_stream_close(pfp);
1511 }
1512 if (error) {
1513 spprintf(error, 0, "openssl public key could not be read");
1514 }
1515 return FAILURE;
1516 }
1517
1518 php_stream_close(pfp);
1519 #ifndef PHAR_HAVE_OPENSSL
1520 tempsig = sig_len;
1521
1522 if (FAILURE == phar_call_openssl_signverify(0, fp, end_of_phar, pubkey ? ZSTR_VAL(pubkey) : NULL, pubkey ? ZSTR_LEN(pubkey) : 0, &sig, &tempsig)) {
1523 if (pubkey) {
1524 zend_string_release_ex(pubkey, 0);
1525 }
1526
1527 if (error) {
1528 spprintf(error, 0, "openssl signature could not be verified");
1529 }
1530
1531 return FAILURE;
1532 }
1533
1534 if (pubkey) {
1535 zend_string_release_ex(pubkey, 0);
1536 }
1537
1538 sig_len = tempsig;
1539 #else
1540 in = BIO_new_mem_buf(pubkey ? ZSTR_VAL(pubkey) : NULL, pubkey ? ZSTR_LEN(pubkey) : 0);
1541
1542 if (NULL == in) {
1543 zend_string_release_ex(pubkey, 0);
1544 if (error) {
1545 spprintf(error, 0, "openssl signature could not be processed");
1546 }
1547 return FAILURE;
1548 }
1549
1550 key = PEM_read_bio_PUBKEY(in, NULL,NULL, NULL);
1551 BIO_free(in);
1552 zend_string_release_ex(pubkey, 0);
1553
1554 if (NULL == key) {
1555 if (error) {
1556 spprintf(error, 0, "openssl signature could not be processed");
1557 }
1558 return FAILURE;
1559 }
1560
1561 md_ctx = EVP_MD_CTX_create();
1562 EVP_VerifyInit(md_ctx, mdtype);
1563 read_len = end_of_phar;
1564
1565 if ((size_t)read_len > sizeof(buf)) {
1566 read_size = sizeof(buf);
1567 } else {
1568 read_size = (size_t)read_len;
1569 }
1570
1571 php_stream_seek(fp, 0, SEEK_SET);
1572
1573 while (read_size && (len = php_stream_read(fp, (char*)buf, read_size)) > 0) {
1574 EVP_VerifyUpdate (md_ctx, buf, len);
1575 read_len -= (zend_off_t)len;
1576
1577 if (read_len < read_size) {
1578 read_size = (size_t)read_len;
1579 }
1580 }
1581
1582 if (EVP_VerifyFinal(md_ctx, (unsigned char *)sig, sig_len, key) != 1) {
1583 /* 1: signature verified, 0: signature does not match, -1: failed signature operation */
1584 EVP_MD_CTX_destroy(md_ctx);
1585
1586 if (error) {
1587 spprintf(error, 0, "broken openssl signature");
1588 }
1589
1590 return FAILURE;
1591 }
1592
1593 EVP_MD_CTX_destroy(md_ctx);
1594 #endif
1595
1596 *signature_len = phar_hex_str((const char*)sig, sig_len, signature);
1597 }
1598 break;
1599 #ifdef PHAR_HASH_OK
1600 case PHAR_SIG_SHA512: {
1601 unsigned char digest[64];
1602 PHP_SHA512_CTX context;
1603
1604 if (sig_len < sizeof(digest)) {
1605 if (error) {
1606 spprintf(error, 0, "broken signature");
1607 }
1608 return FAILURE;
1609 }
1610
1611 PHP_SHA512Init(&context);
1612 read_len = end_of_phar;
1613
1614 if ((size_t)read_len > sizeof(buf)) {
1615 read_size = sizeof(buf);
1616 } else {
1617 read_size = (size_t)read_len;
1618 }
1619
1620 while ((len = php_stream_read(fp, (char*)buf, read_size)) > 0) {
1621 PHP_SHA512Update(&context, buf, len);
1622 read_len -= (zend_off_t)len;
1623 if ((size_t)read_len < read_size) {
1624 read_size = (size_t)read_len;
1625 }
1626 }
1627
1628 PHP_SHA512Final(digest, &context);
1629
1630 if (memcmp(digest, sig, sizeof(digest))) {
1631 if (error) {
1632 spprintf(error, 0, "broken signature");
1633 }
1634 return FAILURE;
1635 }
1636
1637 *signature_len = phar_hex_str((const char*)digest, sizeof(digest), signature);
1638 break;
1639 }
1640 case PHAR_SIG_SHA256: {
1641 unsigned char digest[32];
1642 PHP_SHA256_CTX context;
1643
1644 if (sig_len < sizeof(digest)) {
1645 if (error) {
1646 spprintf(error, 0, "broken signature");
1647 }
1648 return FAILURE;
1649 }
1650
1651 PHP_SHA256Init(&context);
1652 read_len = end_of_phar;
1653
1654 if ((size_t)read_len > sizeof(buf)) {
1655 read_size = sizeof(buf);
1656 } else {
1657 read_size = (size_t)read_len;
1658 }
1659
1660 while ((len = php_stream_read(fp, (char*)buf, read_size)) > 0) {
1661 PHP_SHA256Update(&context, buf, len);
1662 read_len -= (zend_off_t)len;
1663 if ((size_t)read_len < read_size) {
1664 read_size = (size_t)read_len;
1665 }
1666 }
1667
1668 PHP_SHA256Final(digest, &context);
1669
1670 if (memcmp(digest, sig, sizeof(digest))) {
1671 if (error) {
1672 spprintf(error, 0, "broken signature");
1673 }
1674 return FAILURE;
1675 }
1676
1677 *signature_len = phar_hex_str((const char*)digest, sizeof(digest), signature);
1678 break;
1679 }
1680 #else
1681 case PHAR_SIG_SHA512:
1682 case PHAR_SIG_SHA256:
1683 if (error) {
1684 spprintf(error, 0, "unsupported signature");
1685 }
1686 return FAILURE;
1687 #endif
1688 case PHAR_SIG_SHA1: {
1689 unsigned char digest[20];
1690 PHP_SHA1_CTX context;
1691
1692 if (sig_len < sizeof(digest)) {
1693 if (error) {
1694 spprintf(error, 0, "broken signature");
1695 }
1696 return FAILURE;
1697 }
1698
1699 PHP_SHA1Init(&context);
1700 read_len = end_of_phar;
1701
1702 if ((size_t)read_len > sizeof(buf)) {
1703 read_size = sizeof(buf);
1704 } else {
1705 read_size = (size_t)read_len;
1706 }
1707
1708 while ((len = php_stream_read(fp, (char*)buf, read_size)) > 0) {
1709 PHP_SHA1Update(&context, buf, len);
1710 read_len -= (zend_off_t)len;
1711 if ((size_t)read_len < read_size) {
1712 read_size = (size_t)read_len;
1713 }
1714 }
1715
1716 PHP_SHA1Final(digest, &context);
1717
1718 if (memcmp(digest, sig, sizeof(digest))) {
1719 if (error) {
1720 spprintf(error, 0, "broken signature");
1721 }
1722 return FAILURE;
1723 }
1724
1725 *signature_len = phar_hex_str((const char*)digest, sizeof(digest), signature);
1726 break;
1727 }
1728 case PHAR_SIG_MD5: {
1729 unsigned char digest[16];
1730 PHP_MD5_CTX context;
1731
1732 if (sig_len < sizeof(digest)) {
1733 if (error) {
1734 spprintf(error, 0, "broken signature");
1735 }
1736 return FAILURE;
1737 }
1738
1739 PHP_MD5Init(&context);
1740 read_len = end_of_phar;
1741
1742 if ((size_t)read_len > sizeof(buf)) {
1743 read_size = sizeof(buf);
1744 } else {
1745 read_size = (size_t)read_len;
1746 }
1747
1748 while ((len = php_stream_read(fp, (char*)buf, read_size)) > 0) {
1749 PHP_MD5Update(&context, buf, len);
1750 read_len -= (zend_off_t)len;
1751 if ((size_t)read_len < read_size) {
1752 read_size = (size_t)read_len;
1753 }
1754 }
1755
1756 PHP_MD5Final(digest, &context);
1757
1758 if (memcmp(digest, sig, sizeof(digest))) {
1759 if (error) {
1760 spprintf(error, 0, "broken signature");
1761 }
1762 return FAILURE;
1763 }
1764
1765 *signature_len = phar_hex_str((const char*)digest, sizeof(digest), signature);
1766 break;
1767 }
1768 default:
1769 if (error) {
1770 spprintf(error, 0, "broken or unsupported signature");
1771 }
1772 return FAILURE;
1773 }
1774 return SUCCESS;
1775 }
1776 /* }}} */
1777
phar_create_signature(phar_archive_data * phar,php_stream * fp,char ** signature,size_t * signature_length,char ** error)1778 int phar_create_signature(phar_archive_data *phar, php_stream *fp, char **signature, size_t *signature_length, char **error) /* {{{ */
1779 {
1780 unsigned char buf[1024];
1781 size_t sig_len;
1782
1783 php_stream_rewind(fp);
1784
1785 if (phar->signature) {
1786 efree(phar->signature);
1787 phar->signature = NULL;
1788 }
1789
1790 switch(phar->sig_flags) {
1791 #ifdef PHAR_HASH_OK
1792 case PHAR_SIG_SHA512: {
1793 unsigned char digest[64];
1794 PHP_SHA512_CTX context;
1795
1796 PHP_SHA512Init(&context);
1797
1798 while ((sig_len = php_stream_read(fp, (char*)buf, sizeof(buf))) > 0) {
1799 PHP_SHA512Update(&context, buf, sig_len);
1800 }
1801
1802 PHP_SHA512Final(digest, &context);
1803 *signature = estrndup((char *) digest, 64);
1804 *signature_length = 64;
1805 break;
1806 }
1807 case PHAR_SIG_SHA256: {
1808 unsigned char digest[32];
1809 PHP_SHA256_CTX context;
1810
1811 PHP_SHA256Init(&context);
1812
1813 while ((sig_len = php_stream_read(fp, (char*)buf, sizeof(buf))) > 0) {
1814 PHP_SHA256Update(&context, buf, sig_len);
1815 }
1816
1817 PHP_SHA256Final(digest, &context);
1818 *signature = estrndup((char *) digest, 32);
1819 *signature_length = 32;
1820 break;
1821 }
1822 #else
1823 case PHAR_SIG_SHA512:
1824 case PHAR_SIG_SHA256:
1825 if (error) {
1826 spprintf(error, 0, "unable to write to phar \"%s\" with requested hash type", phar->fname);
1827 }
1828
1829 return FAILURE;
1830 #endif
1831 case PHAR_SIG_OPENSSL: {
1832 unsigned char *sigbuf;
1833 #ifdef PHAR_HAVE_OPENSSL
1834 unsigned int siglen;
1835 BIO *in;
1836 EVP_PKEY *key;
1837 EVP_MD_CTX *md_ctx;
1838
1839 in = BIO_new_mem_buf(PHAR_G(openssl_privatekey), PHAR_G(openssl_privatekey_len));
1840
1841 if (in == NULL) {
1842 if (error) {
1843 spprintf(error, 0, "unable to write to phar \"%s\" with requested openssl signature", phar->fname);
1844 }
1845 return FAILURE;
1846 }
1847
1848 key = PEM_read_bio_PrivateKey(in, NULL,NULL, "");
1849 BIO_free(in);
1850
1851 if (!key) {
1852 if (error) {
1853 spprintf(error, 0, "unable to process private key");
1854 }
1855 return FAILURE;
1856 }
1857
1858 md_ctx = EVP_MD_CTX_create();
1859
1860 siglen = EVP_PKEY_size(key);
1861 sigbuf = emalloc(siglen + 1);
1862
1863 if (!EVP_SignInit(md_ctx, EVP_sha1())) {
1864 efree(sigbuf);
1865 if (error) {
1866 spprintf(error, 0, "unable to initialize openssl signature for phar \"%s\"", phar->fname);
1867 }
1868 return FAILURE;
1869 }
1870
1871 while ((sig_len = php_stream_read(fp, (char*)buf, sizeof(buf))) > 0) {
1872 if (!EVP_SignUpdate(md_ctx, buf, sig_len)) {
1873 efree(sigbuf);
1874 if (error) {
1875 spprintf(error, 0, "unable to update the openssl signature for phar \"%s\"", phar->fname);
1876 }
1877 return FAILURE;
1878 }
1879 }
1880
1881 if (!EVP_SignFinal (md_ctx, sigbuf, &siglen, key)) {
1882 efree(sigbuf);
1883 if (error) {
1884 spprintf(error, 0, "unable to write phar \"%s\" with requested openssl signature", phar->fname);
1885 }
1886 return FAILURE;
1887 }
1888
1889 sigbuf[siglen] = '\0';
1890 EVP_MD_CTX_destroy(md_ctx);
1891 #else
1892 size_t siglen;
1893 sigbuf = NULL;
1894 siglen = 0;
1895 php_stream_seek(fp, 0, SEEK_END);
1896
1897 if (FAILURE == phar_call_openssl_signverify(1, fp, php_stream_tell(fp), PHAR_G(openssl_privatekey), PHAR_G(openssl_privatekey_len), (char **)&sigbuf, &siglen)) {
1898 if (error) {
1899 spprintf(error, 0, "unable to write phar \"%s\" with requested openssl signature", phar->fname);
1900 }
1901 return FAILURE;
1902 }
1903 #endif
1904 *signature = (char *) sigbuf;
1905 *signature_length = siglen;
1906 }
1907 break;
1908 default:
1909 phar->sig_flags = PHAR_SIG_SHA1;
1910 case PHAR_SIG_SHA1: {
1911 unsigned char digest[20];
1912 PHP_SHA1_CTX context;
1913
1914 PHP_SHA1Init(&context);
1915
1916 while ((sig_len = php_stream_read(fp, (char*)buf, sizeof(buf))) > 0) {
1917 PHP_SHA1Update(&context, buf, sig_len);
1918 }
1919
1920 PHP_SHA1Final(digest, &context);
1921 *signature = estrndup((char *) digest, 20);
1922 *signature_length = 20;
1923 break;
1924 }
1925 case PHAR_SIG_MD5: {
1926 unsigned char digest[16];
1927 PHP_MD5_CTX context;
1928
1929 PHP_MD5Init(&context);
1930
1931 while ((sig_len = php_stream_read(fp, (char*)buf, sizeof(buf))) > 0) {
1932 PHP_MD5Update(&context, buf, sig_len);
1933 }
1934
1935 PHP_MD5Final(digest, &context);
1936 *signature = estrndup((char *) digest, 16);
1937 *signature_length = 16;
1938 break;
1939 }
1940 }
1941
1942 phar->sig_len = phar_hex_str((const char *)*signature, *signature_length, &phar->signature);
1943 return SUCCESS;
1944 }
1945 /* }}} */
1946
phar_add_virtual_dirs(phar_archive_data * phar,char * filename,size_t filename_len)1947 void phar_add_virtual_dirs(phar_archive_data *phar, char *filename, size_t filename_len) /* {{{ */
1948 {
1949 const char *s;
1950 zend_string *str;
1951 zval *ret;
1952
1953 while ((s = zend_memrchr(filename, '/', filename_len))) {
1954 filename_len = s - filename;
1955 if (!filename_len) {
1956 break;
1957 }
1958 if (GC_FLAGS(&phar->virtual_dirs) & GC_PERSISTENT) {
1959 str = zend_string_init_interned(filename, filename_len, 1);
1960 } else {
1961 str = zend_string_init(filename, filename_len, 0);
1962 }
1963 ret = zend_hash_add_empty_element(&phar->virtual_dirs, str);
1964 zend_string_release(str);
1965 if (ret == NULL) {
1966 break;
1967 }
1968 }
1969 }
1970 /* }}} */
1971
phar_update_cached_entry(zval * data,void * argument)1972 static int phar_update_cached_entry(zval *data, void *argument) /* {{{ */
1973 {
1974 phar_entry_info *entry = (phar_entry_info *)Z_PTR_P(data);
1975
1976 entry->phar = (phar_archive_data *)argument;
1977
1978 if (entry->link) {
1979 entry->link = estrdup(entry->link);
1980 }
1981
1982 if (entry->tmp) {
1983 entry->tmp = estrdup(entry->tmp);
1984 }
1985
1986 entry->metadata_str.s = NULL;
1987 entry->filename = estrndup(entry->filename, entry->filename_len);
1988 entry->is_persistent = 0;
1989
1990 if (Z_TYPE(entry->metadata) != IS_UNDEF) {
1991 if (entry->metadata_len) {
1992 char *buf = estrndup((char *) Z_PTR(entry->metadata), entry->metadata_len);
1993 /* assume success, we would have failed before */
1994 phar_parse_metadata((char **) &buf, &entry->metadata, entry->metadata_len);
1995 efree(buf);
1996 } else {
1997 zval_copy_ctor(&entry->metadata);
1998 entry->metadata_str.s = NULL;
1999 }
2000 }
2001 return ZEND_HASH_APPLY_KEEP;
2002 }
2003 /* }}} */
2004
phar_manifest_copy_ctor(zval * zv)2005 static void phar_manifest_copy_ctor(zval *zv) /* {{{ */
2006 {
2007 phar_entry_info *info = emalloc(sizeof(phar_entry_info));
2008 memcpy(info, Z_PTR_P(zv), sizeof(phar_entry_info));
2009 Z_PTR_P(zv) = info;
2010 }
2011 /* }}} */
2012
phar_copy_cached_phar(phar_archive_data ** pphar)2013 static void phar_copy_cached_phar(phar_archive_data **pphar) /* {{{ */
2014 {
2015 phar_archive_data *phar;
2016 HashTable newmanifest;
2017 char *fname;
2018 phar_archive_object *objphar;
2019
2020 phar = (phar_archive_data *) emalloc(sizeof(phar_archive_data));
2021 *phar = **pphar;
2022 phar->is_persistent = 0;
2023 fname = phar->fname;
2024 phar->fname = estrndup(phar->fname, phar->fname_len);
2025 phar->ext = phar->fname + (phar->ext - fname);
2026
2027 if (phar->alias) {
2028 phar->alias = estrndup(phar->alias, phar->alias_len);
2029 }
2030
2031 if (phar->signature) {
2032 phar->signature = estrdup(phar->signature);
2033 }
2034
2035 if (Z_TYPE(phar->metadata) != IS_UNDEF) {
2036 /* assume success, we would have failed before */
2037 if (phar->metadata_len) {
2038 char *buf = estrndup((char *) Z_PTR(phar->metadata), phar->metadata_len);
2039 phar_parse_metadata(&buf, &phar->metadata, phar->metadata_len);
2040 efree(buf);
2041 } else {
2042 zval_copy_ctor(&phar->metadata);
2043 }
2044 }
2045
2046 zend_hash_init(&newmanifest, sizeof(phar_entry_info),
2047 zend_get_hash_value, destroy_phar_manifest_entry, 0);
2048 zend_hash_copy(&newmanifest, &(*pphar)->manifest, phar_manifest_copy_ctor);
2049 zend_hash_apply_with_argument(&newmanifest, phar_update_cached_entry, (void *)phar);
2050 phar->manifest = newmanifest;
2051 zend_hash_init(&phar->mounted_dirs, sizeof(char *),
2052 zend_get_hash_value, NULL, 0);
2053 zend_hash_init(&phar->virtual_dirs, sizeof(char *),
2054 zend_get_hash_value, NULL, 0);
2055 zend_hash_copy(&phar->virtual_dirs, &(*pphar)->virtual_dirs, NULL);
2056 *pphar = phar;
2057
2058 /* now, scan the list of persistent Phar objects referencing this phar and update the pointers */
2059 ZEND_HASH_FOREACH_PTR(&PHAR_G(phar_persist_map), objphar) {
2060 if (objphar->archive->fname_len == phar->fname_len && !memcmp(objphar->archive->fname, phar->fname, phar->fname_len)) {
2061 objphar->archive = phar;
2062 }
2063 } ZEND_HASH_FOREACH_END();
2064 }
2065 /* }}} */
2066
phar_copy_on_write(phar_archive_data ** pphar)2067 int phar_copy_on_write(phar_archive_data **pphar) /* {{{ */
2068 {
2069 zval zv, *pzv;
2070 phar_archive_data *newpphar;
2071
2072 ZVAL_PTR(&zv, *pphar);
2073 if (NULL == (pzv = zend_hash_str_add(&(PHAR_G(phar_fname_map)), (*pphar)->fname, (*pphar)->fname_len, &zv))) {
2074 return FAILURE;
2075 }
2076
2077 phar_copy_cached_phar((phar_archive_data **)&Z_PTR_P(pzv));
2078 newpphar = Z_PTR_P(pzv);
2079 /* invalidate phar cache */
2080 PHAR_G(last_phar) = NULL;
2081 PHAR_G(last_phar_name) = PHAR_G(last_alias) = NULL;
2082
2083 if (newpphar->alias_len && NULL == zend_hash_str_add_ptr(&(PHAR_G(phar_alias_map)), newpphar->alias, newpphar->alias_len, newpphar)) {
2084 zend_hash_str_del(&(PHAR_G(phar_fname_map)), (*pphar)->fname, (*pphar)->fname_len);
2085 return FAILURE;
2086 }
2087
2088 *pphar = newpphar;
2089 return SUCCESS;
2090 }
2091 /* }}} */
2092
2093 /*
2094 * Local variables:
2095 * tab-width: 4
2096 * c-basic-offset: 4
2097 * End:
2098 * vim600: noet sw=4 ts=4 fdm=marker
2099 * vim<600: noet sw=4 ts=4
2100 */
2101