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