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