xref: /PHP-5.5/ext/phar/func_interceptors.c (revision 73c1be26)
1 /*
2   +----------------------------------------------------------------------+
3   | phar php single-file executable PHP extension                        |
4   +----------------------------------------------------------------------+
5   | Copyright (c) 2005-2015 The PHP Group                                |
6   +----------------------------------------------------------------------+
7   | This source file is subject to version 3.01 of the PHP license,      |
8   | that is bundled with this package in the file LICENSE, and is        |
9   | available through the world-wide-web at the following url:           |
10   | http://www.php.net/license/3_01.txt.                                 |
11   | If you did not receive a copy of the PHP license and are unable to   |
12   | obtain it through the world-wide-web, please send a note to          |
13   | license@php.net so we can mail you a copy immediately.               |
14   +----------------------------------------------------------------------+
15   | Authors: Gregory Beaver <cellog@php.net>                             |
16   +----------------------------------------------------------------------+
17 */
18 
19 /* $Id$ */
20 
21 #include "phar_internal.h"
22 
23 #define PHAR_FUNC(name) \
24 	static PHP_NAMED_FUNCTION(name)
25 
PHAR_FUNC(phar_opendir)26 PHAR_FUNC(phar_opendir) /* {{{ */
27 {
28 	char *filename;
29 	int filename_len;
30 	zval *zcontext = NULL;
31 
32 	if (!PHAR_G(intercepted)) {
33 		goto skip_phar;
34 	}
35 
36 	if ((PHAR_GLOBALS->phar_fname_map.arBuckets && !zend_hash_num_elements(&(PHAR_GLOBALS->phar_fname_map)))
37 		&& !cached_phars.arBuckets) {
38 		goto skip_phar;
39 	}
40 
41 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "p|z", &filename, &filename_len, &zcontext) == FAILURE) {
42 		return;
43 	}
44 
45 	if (!IS_ABSOLUTE_PATH(filename, filename_len) && !strstr(filename, "://")) {
46 		char *arch, *entry, *fname;
47 		int arch_len, entry_len, fname_len;
48 		fname = (char*)zend_get_executed_filename(TSRMLS_C);
49 
50 		/* we are checking for existence of a file within the relative path.  Chances are good that this is
51 		   retrieving something from within the phar archive */
52 
53 		if (strncasecmp(fname, "phar://", 7)) {
54 			goto skip_phar;
55 		}
56 		fname_len = strlen(fname);
57 		if (SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len, 2, 0 TSRMLS_CC)) {
58 			php_stream_context *context = NULL;
59 			php_stream *stream;
60 			char *name;
61 
62 			efree(entry);
63 			entry = estrndup(filename, filename_len);
64 			/* fopen within phar, if :// is not in the url, then prepend phar://<archive>/ */
65 			entry_len = filename_len;
66 			/* retrieving a file within the current directory, so use this if possible */
67 			entry = phar_fix_filepath(entry, &entry_len, 1 TSRMLS_CC);
68 
69 			if (entry[0] == '/') {
70 				spprintf(&name, 4096, "phar://%s%s", arch, entry);
71 			} else {
72 				spprintf(&name, 4096, "phar://%s/%s", arch, entry);
73 			}
74 			efree(entry);
75 			efree(arch);
76 			if (zcontext) {
77 				context = php_stream_context_from_zval(zcontext, 0);
78 			}
79 			stream = php_stream_opendir(name, REPORT_ERRORS, context);
80 			efree(name);
81 			if (!stream) {
82 				RETURN_FALSE;
83 			}
84 			php_stream_to_zval(stream, return_value);
85 			return;
86 		}
87 	}
88 skip_phar:
89 	PHAR_G(orig_opendir)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
90 	return;
91 }
92 /* }}} */
93 
PHAR_FUNC(phar_file_get_contents)94 PHAR_FUNC(phar_file_get_contents) /* {{{ */
95 {
96 	char *filename;
97 	int filename_len;
98 	char *contents;
99 	zend_bool use_include_path = 0;
100 	php_stream *stream;
101 	int len;
102 	long offset = -1;
103 	long maxlen = PHP_STREAM_COPY_ALL;
104 	zval *zcontext = NULL;
105 
106 	if (!PHAR_G(intercepted)) {
107 		goto skip_phar;
108 	}
109 
110 	if ((PHAR_GLOBALS->phar_fname_map.arBuckets && !zend_hash_num_elements(&(PHAR_GLOBALS->phar_fname_map)))
111 		&& !cached_phars.arBuckets) {
112 		goto skip_phar;
113 	}
114 
115 	/* Parse arguments */
116 	if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "p|br!ll", &filename, &filename_len, &use_include_path, &zcontext, &offset, &maxlen) == FAILURE) {
117 		goto skip_phar;
118 	}
119 
120 	if (use_include_path || (!IS_ABSOLUTE_PATH(filename, filename_len) && !strstr(filename, "://"))) {
121 		char *arch, *entry, *fname;
122 		int arch_len, entry_len, fname_len;
123 		php_stream_context *context = NULL;
124 
125 		fname = (char*)zend_get_executed_filename(TSRMLS_C);
126 
127 		if (strncasecmp(fname, "phar://", 7)) {
128 			goto skip_phar;
129 		}
130 		fname_len = strlen(fname);
131 		if (SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len, 2, 0 TSRMLS_CC)) {
132 			char *name;
133 			phar_archive_data *phar;
134 
135 			efree(entry);
136 			entry = filename;
137 			/* fopen within phar, if :// is not in the url, then prepend phar://<archive>/ */
138 			entry_len = filename_len;
139 
140 			if (ZEND_NUM_ARGS() == 5 && maxlen < 0) {
141 				efree(arch);
142 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "length must be greater than or equal to zero");
143 				RETURN_FALSE;
144 			}
145 
146 			/* retrieving a file defaults to within the current directory, so use this if possible */
147 			if (FAILURE == phar_get_archive(&phar, arch, arch_len, NULL, 0, NULL TSRMLS_CC)) {
148 				efree(arch);
149 				goto skip_phar;
150 			}
151 			if (use_include_path) {
152 				if ((entry = phar_find_in_include_path(entry, entry_len, NULL TSRMLS_CC))) {
153 					name = entry;
154 					goto phar_it;
155 				} else {
156 					/* this file is not in the phar, use the original path */
157 					efree(arch);
158 					goto skip_phar;
159 				}
160 			} else {
161 				entry = phar_fix_filepath(estrndup(entry, entry_len), &entry_len, 1 TSRMLS_CC);
162 				if (entry[0] == '/') {
163 					if (!zend_hash_exists(&(phar->manifest), entry + 1, entry_len - 1)) {
164 						/* this file is not in the phar, use the original path */
165 notfound:
166 						efree(arch);
167 						efree(entry);
168 						goto skip_phar;
169 					}
170 				} else {
171 					if (!zend_hash_exists(&(phar->manifest), entry, entry_len)) {
172 						goto notfound;
173 					}
174 				}
175 				/* auto-convert to phar:// */
176 				if (entry[0] == '/') {
177 					spprintf(&name, 4096, "phar://%s%s", arch, entry);
178 				} else {
179 					spprintf(&name, 4096, "phar://%s/%s", arch, entry);
180 				}
181 				if (entry != filename) {
182 					efree(entry);
183 				}
184 			}
185 
186 phar_it:
187 			efree(arch);
188 			if (zcontext) {
189 				context = php_stream_context_from_zval(zcontext, 0);
190 			}
191 			stream = php_stream_open_wrapper_ex(name, "rb", 0 | REPORT_ERRORS, NULL, context);
192 			efree(name);
193 
194 			if (!stream) {
195 				RETURN_FALSE;
196 			}
197 
198 			if (offset > 0 && php_stream_seek(stream, offset, SEEK_SET) < 0) {
199 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to seek to position %ld in the stream", offset);
200 				php_stream_close(stream);
201 				RETURN_FALSE;
202 			}
203 
204 			/* uses mmap if possible */
205 			if ((len = php_stream_copy_to_mem(stream, &contents, maxlen, 0)) > 0) {
206 #if PHP_API_VERSION < 20100412
207 				if (PG(magic_quotes_runtime)) {
208 					int newlen;
209 					contents = php_addslashes(contents, len, &newlen, 1 TSRMLS_CC); /* 1 = free source string */
210 					len = newlen;
211 				}
212 #endif
213 				RETVAL_STRINGL(contents, len, 0);
214 			} else if (len == 0) {
215 				RETVAL_EMPTY_STRING();
216 			} else {
217 				RETVAL_FALSE;
218 			}
219 
220 			php_stream_close(stream);
221 			return;
222 		}
223 	}
224 skip_phar:
225 	PHAR_G(orig_file_get_contents)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
226 	return;
227 }
228 /* }}} */
229 
PHAR_FUNC(phar_readfile)230 PHAR_FUNC(phar_readfile) /* {{{ */
231 {
232 	char *filename;
233 	int filename_len;
234 	int size = 0;
235 	zend_bool use_include_path = 0;
236 	zval *zcontext = NULL;
237 	php_stream *stream;
238 
239 	if (!PHAR_G(intercepted)) {
240 		goto skip_phar;
241 	}
242 
243 	if ((PHAR_GLOBALS->phar_fname_map.arBuckets && !zend_hash_num_elements(&(PHAR_GLOBALS->phar_fname_map)))
244 		&& !cached_phars.arBuckets) {
245 		goto skip_phar;
246 	}
247 	if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "p|br!", &filename, &filename_len, &use_include_path, &zcontext) == FAILURE) {
248 		goto skip_phar;
249 	}
250 	if (use_include_path || (!IS_ABSOLUTE_PATH(filename, filename_len) && !strstr(filename, "://"))) {
251 		char *arch, *entry, *fname;
252 		int arch_len, entry_len, fname_len;
253 		php_stream_context *context = NULL;
254 		char *name;
255 		phar_archive_data *phar;
256 		fname = (char*)zend_get_executed_filename(TSRMLS_C);
257 
258 		if (strncasecmp(fname, "phar://", 7)) {
259 			goto skip_phar;
260 		}
261 		fname_len = strlen(fname);
262 		if (FAILURE == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len, 2, 0 TSRMLS_CC)) {
263 			goto skip_phar;
264 		}
265 
266 		efree(entry);
267 		entry = filename;
268 		/* fopen within phar, if :// is not in the url, then prepend phar://<archive>/ */
269 		entry_len = filename_len;
270 		/* retrieving a file defaults to within the current directory, so use this if possible */
271 		if (FAILURE == phar_get_archive(&phar, arch, arch_len, NULL, 0, NULL TSRMLS_CC)) {
272 			efree(arch);
273 			goto skip_phar;
274 		}
275 		if (use_include_path) {
276 			if (!(entry = phar_find_in_include_path(entry, entry_len, NULL TSRMLS_CC))) {
277 				/* this file is not in the phar, use the original path */
278 				efree(arch);
279 				goto skip_phar;
280 			} else {
281 				name = entry;
282 			}
283 		} else {
284 			entry = phar_fix_filepath(estrndup(entry, entry_len), &entry_len, 1 TSRMLS_CC);
285 			if (entry[0] == '/') {
286 				if (!zend_hash_exists(&(phar->manifest), entry + 1, entry_len - 1)) {
287 					/* this file is not in the phar, use the original path */
288 notfound:
289 					efree(entry);
290 					efree(arch);
291 					goto skip_phar;
292 				}
293 			} else {
294 				if (!zend_hash_exists(&(phar->manifest), entry, entry_len)) {
295 					goto notfound;
296 				}
297 			}
298 			/* auto-convert to phar:// */
299 			if (entry[0] == '/') {
300 				spprintf(&name, 4096, "phar://%s%s", arch, entry);
301 			} else {
302 				spprintf(&name, 4096, "phar://%s/%s", arch, entry);
303 			}
304 			efree(entry);
305 		}
306 
307 		efree(arch);
308 		context = php_stream_context_from_zval(zcontext, 0);
309 		stream = php_stream_open_wrapper_ex(name, "rb", 0 | REPORT_ERRORS, NULL, context);
310 		efree(name);
311 		if (stream == NULL) {
312 			RETURN_FALSE;
313 		}
314 		size = php_stream_passthru(stream);
315 		php_stream_close(stream);
316 		RETURN_LONG(size);
317 	}
318 
319 skip_phar:
320 	PHAR_G(orig_readfile)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
321 	return;
322 
323 }
324 /* }}} */
325 
PHAR_FUNC(phar_fopen)326 PHAR_FUNC(phar_fopen) /* {{{ */
327 {
328 	char *filename, *mode;
329 	int filename_len, mode_len;
330 	zend_bool use_include_path = 0;
331 	zval *zcontext = NULL;
332 	php_stream *stream;
333 
334 	if (!PHAR_G(intercepted)) {
335 		goto skip_phar;
336 	}
337 
338 	if ((PHAR_GLOBALS->phar_fname_map.arBuckets && !zend_hash_num_elements(&(PHAR_GLOBALS->phar_fname_map)))
339 		&& !cached_phars.arBuckets) {
340 		/* no need to check, include_path not even specified in fopen/ no active phars */
341 		goto skip_phar;
342 	}
343 	if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "ps|br", &filename, &filename_len, &mode, &mode_len, &use_include_path, &zcontext) == FAILURE) {
344 		goto skip_phar;
345 	}
346 	if (use_include_path || (!IS_ABSOLUTE_PATH(filename, filename_len) && !strstr(filename, "://"))) {
347 		char *arch, *entry, *fname;
348 		int arch_len, entry_len, fname_len;
349 		php_stream_context *context = NULL;
350 		char *name;
351 		phar_archive_data *phar;
352 		fname = (char*)zend_get_executed_filename(TSRMLS_C);
353 
354 		if (strncasecmp(fname, "phar://", 7)) {
355 			goto skip_phar;
356 		}
357 		fname_len = strlen(fname);
358 		if (FAILURE == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len, 2, 0 TSRMLS_CC)) {
359 			goto skip_phar;
360 		}
361 
362 		efree(entry);
363 		entry = filename;
364 		/* fopen within phar, if :// is not in the url, then prepend phar://<archive>/ */
365 		entry_len = filename_len;
366 		/* retrieving a file defaults to within the current directory, so use this if possible */
367 		if (FAILURE == phar_get_archive(&phar, arch, arch_len, NULL, 0, NULL TSRMLS_CC)) {
368 			efree(arch);
369 			goto skip_phar;
370 		}
371 		if (use_include_path) {
372 			if (!(entry = phar_find_in_include_path(entry, entry_len, NULL TSRMLS_CC))) {
373 				/* this file is not in the phar, use the original path */
374 				efree(arch);
375 				goto skip_phar;
376 			} else {
377 				name = entry;
378 			}
379 		} else {
380 			entry = phar_fix_filepath(estrndup(entry, entry_len), &entry_len, 1 TSRMLS_CC);
381 			if (entry[0] == '/') {
382 				if (!zend_hash_exists(&(phar->manifest), entry + 1, entry_len - 1)) {
383 					/* this file is not in the phar, use the original path */
384 notfound:
385 					efree(entry);
386 					efree(arch);
387 					goto skip_phar;
388 				}
389 			} else {
390 				if (!zend_hash_exists(&(phar->manifest), entry, entry_len)) {
391 					/* this file is not in the phar, use the original path */
392 					goto notfound;
393 				}
394 			}
395 			/* auto-convert to phar:// */
396 			if (entry[0] == '/') {
397 				spprintf(&name, 4096, "phar://%s%s", arch, entry);
398 			} else {
399 				spprintf(&name, 4096, "phar://%s/%s", arch, entry);
400 			}
401 			efree(entry);
402 		}
403 
404 		efree(arch);
405 		context = php_stream_context_from_zval(zcontext, 0);
406 		stream = php_stream_open_wrapper_ex(name, mode, 0 | REPORT_ERRORS, NULL, context);
407 		efree(name);
408 		if (stream == NULL) {
409 			RETURN_FALSE;
410 		}
411 		php_stream_to_zval(stream, return_value);
412 		if (zcontext) {
413 			zend_list_addref(Z_RESVAL_P(zcontext));
414 		}
415 		return;
416 	}
417 skip_phar:
418 	PHAR_G(orig_fopen)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
419 	return;
420 }
421 /* }}} */
422 
423 #ifndef S_ISDIR
424 #define S_ISDIR(mode)	(((mode)&S_IFMT) == S_IFDIR)
425 #endif
426 #ifndef S_ISREG
427 #define S_ISREG(mode)	(((mode)&S_IFMT) == S_IFREG)
428 #endif
429 #ifndef S_ISLNK
430 #define S_ISLNK(mode)	(((mode)&S_IFMT) == S_IFLNK)
431 #endif
432 
433 #define S_IXROOT ( S_IXUSR | S_IXGRP | S_IXOTH )
434 
435 #define IS_LINK_OPERATION(__t) ((__t) == FS_TYPE || (__t) == FS_IS_LINK || (__t) == FS_LSTAT)
436 #define IS_EXISTS_CHECK(__t) ((__t) == FS_EXISTS  || (__t) == FS_IS_W || (__t) == FS_IS_R || (__t) == FS_IS_X || (__t) == FS_IS_FILE || (__t) == FS_IS_DIR || (__t) == FS_IS_LINK)
437 #define IS_ABLE_CHECK(__t) ((__t) == FS_IS_R || (__t) == FS_IS_W || (__t) == FS_IS_X)
438 #define IS_ACCESS_CHECK(__t) (IS_ABLE_CHECK(type) || (__t) == FS_EXISTS)
439 
440 /* {{{ php_stat
441  */
phar_fancy_stat(struct stat * stat_sb,int type,zval * return_value TSRMLS_DC)442 static void phar_fancy_stat(struct stat *stat_sb, int type, zval *return_value TSRMLS_DC)
443 {
444 	zval *stat_dev, *stat_ino, *stat_mode, *stat_nlink, *stat_uid, *stat_gid, *stat_rdev,
445 		 *stat_size, *stat_atime, *stat_mtime, *stat_ctime, *stat_blksize, *stat_blocks;
446 	int rmask=S_IROTH, wmask=S_IWOTH, xmask=S_IXOTH; /* access rights defaults to other */
447 	char *stat_sb_names[13] = {
448 		"dev", "ino", "mode", "nlink", "uid", "gid", "rdev",
449 		"size", "atime", "mtime", "ctime", "blksize", "blocks"
450 	};
451 
452 #ifndef NETWARE
453 	if (type >= FS_IS_W && type <= FS_IS_X) {
454 		if(stat_sb->st_uid==getuid()) {
455 			rmask=S_IRUSR;
456 			wmask=S_IWUSR;
457 			xmask=S_IXUSR;
458 		} else if(stat_sb->st_gid==getgid()) {
459 			rmask=S_IRGRP;
460 			wmask=S_IWGRP;
461 			xmask=S_IXGRP;
462 		} else {
463 			int   groups, n, i;
464 			gid_t *gids;
465 
466 			groups = getgroups(0, NULL);
467 			if(groups > 0) {
468 				gids=(gid_t *)safe_emalloc(groups, sizeof(gid_t), 0);
469 				n=getgroups(groups, gids);
470 				for(i=0;i<n;++i){
471 					if(stat_sb->st_gid==gids[i]) {
472 						rmask=S_IRGRP;
473 						wmask=S_IWGRP;
474 						xmask=S_IXGRP;
475 						break;
476 					}
477 				}
478 				efree(gids);
479 			}
480 		}
481 	}
482 #endif
483 
484 	switch (type) {
485 	case FS_PERMS:
486 		RETURN_LONG((long)stat_sb->st_mode);
487 	case FS_INODE:
488 		RETURN_LONG((long)stat_sb->st_ino);
489 	case FS_SIZE:
490 		RETURN_LONG((long)stat_sb->st_size);
491 	case FS_OWNER:
492 		RETURN_LONG((long)stat_sb->st_uid);
493 	case FS_GROUP:
494 		RETURN_LONG((long)stat_sb->st_gid);
495 	case FS_ATIME:
496 #ifdef NETWARE
497 		RETURN_LONG((long)stat_sb->st_atime.tv_sec);
498 #else
499 		RETURN_LONG((long)stat_sb->st_atime);
500 #endif
501 	case FS_MTIME:
502 #ifdef NETWARE
503 		RETURN_LONG((long)stat_sb->st_mtime.tv_sec);
504 #else
505 		RETURN_LONG((long)stat_sb->st_mtime);
506 #endif
507 	case FS_CTIME:
508 #ifdef NETWARE
509 		RETURN_LONG((long)stat_sb->st_ctime.tv_sec);
510 #else
511 		RETURN_LONG((long)stat_sb->st_ctime);
512 #endif
513 	case FS_TYPE:
514 		if (S_ISLNK(stat_sb->st_mode)) {
515 			RETURN_STRING("link", 1);
516 		}
517 		switch(stat_sb->st_mode & S_IFMT) {
518 		case S_IFDIR: RETURN_STRING("dir", 1);
519 		case S_IFREG: RETURN_STRING("file", 1);
520 		}
521 		php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Unknown file type (%u)", stat_sb->st_mode & S_IFMT);
522 		RETURN_STRING("unknown", 1);
523 	case FS_IS_W:
524 		RETURN_BOOL((stat_sb->st_mode & wmask) != 0);
525 	case FS_IS_R:
526 		RETURN_BOOL((stat_sb->st_mode&rmask)!=0);
527 	case FS_IS_X:
528 		RETURN_BOOL((stat_sb->st_mode&xmask)!=0 && !S_ISDIR(stat_sb->st_mode));
529 	case FS_IS_FILE:
530 		RETURN_BOOL(S_ISREG(stat_sb->st_mode));
531 	case FS_IS_DIR:
532 		RETURN_BOOL(S_ISDIR(stat_sb->st_mode));
533 	case FS_IS_LINK:
534 		RETURN_BOOL(S_ISLNK(stat_sb->st_mode));
535 	case FS_EXISTS:
536 		RETURN_TRUE; /* the false case was done earlier */
537 	case FS_LSTAT:
538 		/* FALLTHROUGH */
539 	case FS_STAT:
540 		array_init(return_value);
541 
542 		MAKE_LONG_ZVAL_INCREF(stat_dev, stat_sb->st_dev);
543 		MAKE_LONG_ZVAL_INCREF(stat_ino, stat_sb->st_ino);
544 		MAKE_LONG_ZVAL_INCREF(stat_mode, stat_sb->st_mode);
545 		MAKE_LONG_ZVAL_INCREF(stat_nlink, stat_sb->st_nlink);
546 		MAKE_LONG_ZVAL_INCREF(stat_uid, stat_sb->st_uid);
547 		MAKE_LONG_ZVAL_INCREF(stat_gid, stat_sb->st_gid);
548 #ifdef HAVE_ST_RDEV
549 		MAKE_LONG_ZVAL_INCREF(stat_rdev, stat_sb->st_rdev);
550 #else
551 		MAKE_LONG_ZVAL_INCREF(stat_rdev, -1);
552 #endif
553 		MAKE_LONG_ZVAL_INCREF(stat_size, stat_sb->st_size);
554 #ifdef NETWARE
555 		MAKE_LONG_ZVAL_INCREF(stat_atime, (stat_sb->st_atime).tv_sec);
556 		MAKE_LONG_ZVAL_INCREF(stat_mtime, (stat_sb->st_mtime).tv_sec);
557 		MAKE_LONG_ZVAL_INCREF(stat_ctime, (stat_sb->st_ctime).tv_sec);
558 #else
559 		MAKE_LONG_ZVAL_INCREF(stat_atime, stat_sb->st_atime);
560 		MAKE_LONG_ZVAL_INCREF(stat_mtime, stat_sb->st_mtime);
561 		MAKE_LONG_ZVAL_INCREF(stat_ctime, stat_sb->st_ctime);
562 #endif
563 #ifdef HAVE_ST_BLKSIZE
564 		MAKE_LONG_ZVAL_INCREF(stat_blksize, stat_sb->st_blksize);
565 #else
566 		MAKE_LONG_ZVAL_INCREF(stat_blksize,-1);
567 #endif
568 #ifdef HAVE_ST_BLOCKS
569 		MAKE_LONG_ZVAL_INCREF(stat_blocks, stat_sb->st_blocks);
570 #else
571 		MAKE_LONG_ZVAL_INCREF(stat_blocks,-1);
572 #endif
573 		/* Store numeric indexes in propper order */
574 		zend_hash_next_index_insert(HASH_OF(return_value), (void *)&stat_dev, sizeof(zval *), NULL);
575 		zend_hash_next_index_insert(HASH_OF(return_value), (void *)&stat_ino, sizeof(zval *), NULL);
576 		zend_hash_next_index_insert(HASH_OF(return_value), (void *)&stat_mode, sizeof(zval *), NULL);
577 		zend_hash_next_index_insert(HASH_OF(return_value), (void *)&stat_nlink, sizeof(zval *), NULL);
578 		zend_hash_next_index_insert(HASH_OF(return_value), (void *)&stat_uid, sizeof(zval *), NULL);
579 		zend_hash_next_index_insert(HASH_OF(return_value), (void *)&stat_gid, sizeof(zval *), NULL);
580 
581 		zend_hash_next_index_insert(HASH_OF(return_value), (void *)&stat_rdev, sizeof(zval *), NULL);
582 		zend_hash_next_index_insert(HASH_OF(return_value), (void *)&stat_size, sizeof(zval *), NULL);
583 		zend_hash_next_index_insert(HASH_OF(return_value), (void *)&stat_atime, sizeof(zval *), NULL);
584 		zend_hash_next_index_insert(HASH_OF(return_value), (void *)&stat_mtime, sizeof(zval *), NULL);
585 		zend_hash_next_index_insert(HASH_OF(return_value), (void *)&stat_ctime, sizeof(zval *), NULL);
586 		zend_hash_next_index_insert(HASH_OF(return_value), (void *)&stat_blksize, sizeof(zval *), NULL);
587 		zend_hash_next_index_insert(HASH_OF(return_value), (void *)&stat_blocks, sizeof(zval *), NULL);
588 
589 		/* Store string indexes referencing the same zval*/
590 		zend_hash_update(HASH_OF(return_value), stat_sb_names[0], strlen(stat_sb_names[0])+1, (void *) &stat_dev, sizeof(zval *), NULL);
591 		zend_hash_update(HASH_OF(return_value), stat_sb_names[1], strlen(stat_sb_names[1])+1, (void *) &stat_ino, sizeof(zval *), NULL);
592 		zend_hash_update(HASH_OF(return_value), stat_sb_names[2], strlen(stat_sb_names[2])+1, (void *) &stat_mode, sizeof(zval *), NULL);
593 		zend_hash_update(HASH_OF(return_value), stat_sb_names[3], strlen(stat_sb_names[3])+1, (void *) &stat_nlink, sizeof(zval *), NULL);
594 		zend_hash_update(HASH_OF(return_value), stat_sb_names[4], strlen(stat_sb_names[4])+1, (void *) &stat_uid, sizeof(zval *), NULL);
595 		zend_hash_update(HASH_OF(return_value), stat_sb_names[5], strlen(stat_sb_names[5])+1, (void *) &stat_gid, sizeof(zval *), NULL);
596 		zend_hash_update(HASH_OF(return_value), stat_sb_names[6], strlen(stat_sb_names[6])+1, (void *) &stat_rdev, sizeof(zval *), NULL);
597 		zend_hash_update(HASH_OF(return_value), stat_sb_names[7], strlen(stat_sb_names[7])+1, (void *) &stat_size, sizeof(zval *), NULL);
598 		zend_hash_update(HASH_OF(return_value), stat_sb_names[8], strlen(stat_sb_names[8])+1, (void *) &stat_atime, sizeof(zval *), NULL);
599 		zend_hash_update(HASH_OF(return_value), stat_sb_names[9], strlen(stat_sb_names[9])+1, (void *) &stat_mtime, sizeof(zval *), NULL);
600 		zend_hash_update(HASH_OF(return_value), stat_sb_names[10], strlen(stat_sb_names[10])+1, (void *) &stat_ctime, sizeof(zval *), NULL);
601 		zend_hash_update(HASH_OF(return_value), stat_sb_names[11], strlen(stat_sb_names[11])+1, (void *) &stat_blksize, sizeof(zval *), NULL);
602 		zend_hash_update(HASH_OF(return_value), stat_sb_names[12], strlen(stat_sb_names[12])+1, (void *) &stat_blocks, sizeof(zval *), NULL);
603 
604 		return;
605 	}
606 	php_error_docref(NULL TSRMLS_CC, E_WARNING, "Didn't understand stat call");
607 	RETURN_FALSE;
608 }
609 /* }}} */
610 
phar_file_stat(const char * filename,php_stat_len filename_length,int type,void (* orig_stat_func)(INTERNAL_FUNCTION_PARAMETERS),INTERNAL_FUNCTION_PARAMETERS)611 static void phar_file_stat(const char *filename, php_stat_len filename_length, int type, void (*orig_stat_func)(INTERNAL_FUNCTION_PARAMETERS), INTERNAL_FUNCTION_PARAMETERS) /* {{{ */
612 {
613 	if (!filename_length) {
614 		RETURN_FALSE;
615 	}
616 
617 	if (!IS_ABSOLUTE_PATH(filename, filename_length) && !strstr(filename, "://")) {
618 		char *arch, *entry, *fname;
619 		int arch_len, entry_len, fname_len;
620 		struct stat sb = {0};
621 		phar_entry_info *data = NULL;
622 		phar_archive_data *phar;
623 
624 		fname = (char*)zend_get_executed_filename(TSRMLS_C);
625 
626 		/* we are checking for existence of a file within the relative path.  Chances are good that this is
627 		   retrieving something from within the phar archive */
628 
629 		if (strncasecmp(fname, "phar://", 7)) {
630 			goto skip_phar;
631 		}
632 		fname_len = strlen(fname);
633 		if (PHAR_G(last_phar) && fname_len - 7 >= PHAR_G(last_phar_name_len) && !memcmp(fname + 7, PHAR_G(last_phar_name), PHAR_G(last_phar_name_len))) {
634 			arch = estrndup(PHAR_G(last_phar_name), PHAR_G(last_phar_name_len));
635 			arch_len = PHAR_G(last_phar_name_len);
636 			entry = estrndup(filename, filename_length);
637 			/* fopen within phar, if :// is not in the url, then prepend phar://<archive>/ */
638 			entry_len = (int) filename_length;
639 			phar = PHAR_G(last_phar);
640 			goto splitted;
641 		}
642 		if (SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len, 2, 0 TSRMLS_CC)) {
643 
644 			efree(entry);
645 			entry = estrndup(filename, filename_length);
646 			/* fopen within phar, if :// is not in the url, then prepend phar://<archive>/ */
647 			entry_len = (int) filename_length;
648 			if (FAILURE == phar_get_archive(&phar, arch, arch_len, NULL, 0, NULL TSRMLS_CC)) {
649 				efree(arch);
650 				efree(entry);
651 				goto skip_phar;
652 			}
653 splitted:
654 			entry = phar_fix_filepath(entry, &entry_len, 1 TSRMLS_CC);
655 			if (entry[0] == '/') {
656 				if (SUCCESS == zend_hash_find(&(phar->manifest), entry + 1, entry_len - 1, (void **) &data)) {
657 					efree(entry);
658 					goto stat_entry;
659 				}
660 				goto notfound;
661 			}
662 			if (SUCCESS == zend_hash_find(&(phar->manifest), entry, entry_len, (void **) &data)) {
663 				efree(entry);
664 				goto stat_entry;
665 			}
666 			if (zend_hash_exists(&(phar->virtual_dirs), entry, entry_len)) {
667 				efree(entry);
668 				efree(arch);
669 				if (IS_EXISTS_CHECK(type)) {
670 					RETURN_TRUE;
671 				}
672 				sb.st_size = 0;
673 				sb.st_mode = 0777;
674 				sb.st_mode |= S_IFDIR; /* regular directory */
675 #ifdef NETWARE
676 				sb.st_mtime.tv_sec = phar->max_timestamp;
677 				sb.st_atime.tv_sec = phar->max_timestamp;
678 				sb.st_ctime.tv_sec = phar->max_timestamp;
679 #else
680 				sb.st_mtime = phar->max_timestamp;
681 				sb.st_atime = phar->max_timestamp;
682 				sb.st_ctime = phar->max_timestamp;
683 #endif
684 				goto statme_baby;
685 			} else {
686 				char *save;
687 				int save_len;
688 
689 notfound:
690 				efree(entry);
691 				save = PHAR_G(cwd);
692 				save_len = PHAR_G(cwd_len);
693 				/* this file is not in the current directory, use the original path */
694 				entry = estrndup(filename, filename_length);
695 				entry_len = filename_length;
696 				PHAR_G(cwd) = "/";
697 				PHAR_G(cwd_len) = 0;
698 				/* clean path without cwd */
699 				entry = phar_fix_filepath(entry, &entry_len, 1 TSRMLS_CC);
700 				if (SUCCESS == zend_hash_find(&(phar->manifest), entry + 1, entry_len - 1, (void **) &data)) {
701 					PHAR_G(cwd) = save;
702 					PHAR_G(cwd_len) = save_len;
703 					efree(entry);
704 					if (IS_EXISTS_CHECK(type)) {
705 						efree(arch);
706 						RETURN_TRUE;
707 					}
708 					goto stat_entry;
709 				}
710 				if (zend_hash_exists(&(phar->virtual_dirs), entry + 1, entry_len - 1)) {
711 					PHAR_G(cwd) = save;
712 					PHAR_G(cwd_len) = save_len;
713 					efree(entry);
714 					efree(arch);
715 					if (IS_EXISTS_CHECK(type)) {
716 						RETURN_TRUE;
717 					}
718 					sb.st_size = 0;
719 					sb.st_mode = 0777;
720 					sb.st_mode |= S_IFDIR; /* regular directory */
721 #ifdef NETWARE
722 					sb.st_mtime.tv_sec = phar->max_timestamp;
723 					sb.st_atime.tv_sec = phar->max_timestamp;
724 					sb.st_ctime.tv_sec = phar->max_timestamp;
725 #else
726 					sb.st_mtime = phar->max_timestamp;
727 					sb.st_atime = phar->max_timestamp;
728 					sb.st_ctime = phar->max_timestamp;
729 #endif
730 					goto statme_baby;
731 				}
732 				PHAR_G(cwd) = save;
733 				PHAR_G(cwd_len) = save_len;
734 				efree(entry);
735 				efree(arch);
736 				/* Error Occurred */
737 				if (!IS_EXISTS_CHECK(type)) {
738 					php_error_docref(NULL TSRMLS_CC, E_WARNING, "%sstat failed for %s", IS_LINK_OPERATION(type) ? "L" : "", filename);
739 				}
740 				RETURN_FALSE;
741 			}
742 stat_entry:
743 			efree(arch);
744 			if (!data->is_dir) {
745 				sb.st_size = data->uncompressed_filesize;
746 				sb.st_mode = data->flags & PHAR_ENT_PERM_MASK;
747 				if (data->link) {
748 					sb.st_mode |= S_IFREG|S_IFLNK; /* regular file */
749 				} else {
750 					sb.st_mode |= S_IFREG; /* regular file */
751 				}
752 				/* timestamp is just the timestamp when this was added to the phar */
753 #ifdef NETWARE
754 				sb.st_mtime.tv_sec = data->timestamp;
755 				sb.st_atime.tv_sec = data->timestamp;
756 				sb.st_ctime.tv_sec = data->timestamp;
757 #else
758 				sb.st_mtime = data->timestamp;
759 				sb.st_atime = data->timestamp;
760 				sb.st_ctime = data->timestamp;
761 #endif
762 			} else {
763 				sb.st_size = 0;
764 				sb.st_mode = data->flags & PHAR_ENT_PERM_MASK;
765 				sb.st_mode |= S_IFDIR; /* regular directory */
766 				if (data->link) {
767 					sb.st_mode |= S_IFLNK;
768 				}
769 				/* timestamp is just the timestamp when this was added to the phar */
770 #ifdef NETWARE
771 				sb.st_mtime.tv_sec = data->timestamp;
772 				sb.st_atime.tv_sec = data->timestamp;
773 				sb.st_ctime.tv_sec = data->timestamp;
774 #else
775 				sb.st_mtime = data->timestamp;
776 				sb.st_atime = data->timestamp;
777 				sb.st_ctime = data->timestamp;
778 #endif
779 			}
780 
781 statme_baby:
782 			if (!phar->is_writeable) {
783 				sb.st_mode = (sb.st_mode & 0555) | (sb.st_mode & ~0777);
784 			}
785 
786 			sb.st_nlink = 1;
787 			sb.st_rdev = -1;
788 			/* this is only for APC, so use /dev/null device - no chance of conflict there! */
789 			sb.st_dev = 0xc;
790 			/* generate unique inode number for alias/filename, so no phars will conflict */
791 			if (data) {
792 				sb.st_ino = data->inode;
793 			}
794 #ifndef PHP_WIN32
795 			sb.st_blksize = -1;
796 			sb.st_blocks = -1;
797 #endif
798 			phar_fancy_stat(&sb, type, return_value TSRMLS_CC);
799 			return;
800 		}
801 	}
802 skip_phar:
803 	orig_stat_func(INTERNAL_FUNCTION_PARAM_PASSTHRU);
804 	return;
805 }
806 /* }}} */
807 
808 #define PharFileFunction(fname, funcnum, orig) \
809 void fname(INTERNAL_FUNCTION_PARAMETERS) { \
810 	if (!PHAR_G(intercepted)) { \
811 		PHAR_G(orig)(INTERNAL_FUNCTION_PARAM_PASSTHRU); \
812 	} else { \
813 		char *filename; \
814 		int filename_len; \
815 		\
816 		if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "p", &filename, &filename_len) == FAILURE) { \
817 			return; \
818 		} \
819 		\
820 		phar_file_stat(filename, (php_stat_len) filename_len, funcnum, PHAR_G(orig), INTERNAL_FUNCTION_PARAM_PASSTHRU); \
821 	} \
822 }
823 /* }}} */
824 
825 /* {{{ proto int fileperms(string filename)
826    Get file permissions */
PharFileFunction(phar_fileperms,FS_PERMS,orig_fileperms)827 PharFileFunction(phar_fileperms, FS_PERMS, orig_fileperms)
828 /* }}} */
829 
830 /* {{{ proto int fileinode(string filename)
831    Get file inode */
832 PharFileFunction(phar_fileinode, FS_INODE, orig_fileinode)
833 /* }}} */
834 
835 /* {{{ proto int filesize(string filename)
836    Get file size */
837 PharFileFunction(phar_filesize, FS_SIZE, orig_filesize)
838 /* }}} */
839 
840 /* {{{ proto int fileowner(string filename)
841    Get file owner */
842 PharFileFunction(phar_fileowner, FS_OWNER, orig_fileowner)
843 /* }}} */
844 
845 /* {{{ proto int filegroup(string filename)
846    Get file group */
847 PharFileFunction(phar_filegroup, FS_GROUP, orig_filegroup)
848 /* }}} */
849 
850 /* {{{ proto int fileatime(string filename)
851    Get last access time of file */
852 PharFileFunction(phar_fileatime, FS_ATIME, orig_fileatime)
853 /* }}} */
854 
855 /* {{{ proto int filemtime(string filename)
856    Get last modification time of file */
857 PharFileFunction(phar_filemtime, FS_MTIME, orig_filemtime)
858 /* }}} */
859 
860 /* {{{ proto int filectime(string filename)
861    Get inode modification time of file */
862 PharFileFunction(phar_filectime, FS_CTIME, orig_filectime)
863 /* }}} */
864 
865 /* {{{ proto string filetype(string filename)
866    Get file type */
867 PharFileFunction(phar_filetype, FS_TYPE, orig_filetype)
868 /* }}} */
869 
870 /* {{{ proto bool is_writable(string filename)
871    Returns true if file can be written */
872 PharFileFunction(phar_is_writable, FS_IS_W, orig_is_writable)
873 /* }}} */
874 
875 /* {{{ proto bool is_readable(string filename)
876    Returns true if file can be read */
877 PharFileFunction(phar_is_readable, FS_IS_R, orig_is_readable)
878 /* }}} */
879 
880 /* {{{ proto bool is_executable(string filename)
881    Returns true if file is executable */
882 PharFileFunction(phar_is_executable, FS_IS_X, orig_is_executable)
883 /* }}} */
884 
885 /* {{{ proto bool file_exists(string filename)
886    Returns true if filename exists */
887 PharFileFunction(phar_file_exists, FS_EXISTS, orig_file_exists)
888 /* }}} */
889 
890 /* {{{ proto bool is_dir(string filename)
891    Returns true if file is directory */
892 PharFileFunction(phar_is_dir, FS_IS_DIR, orig_is_dir)
893 /* }}} */
894 
895 PHAR_FUNC(phar_is_file) /* {{{ */
896 {
897 	char *filename;
898 	int filename_len;
899 
900 	if (!PHAR_G(intercepted)) {
901 		goto skip_phar;
902 	}
903 
904 	if ((PHAR_GLOBALS->phar_fname_map.arBuckets && !zend_hash_num_elements(&(PHAR_GLOBALS->phar_fname_map)))
905 		&& !cached_phars.arBuckets) {
906 		goto skip_phar;
907 	}
908 	if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "p", &filename, &filename_len) == FAILURE) {
909 		goto skip_phar;
910 	}
911 	if (!IS_ABSOLUTE_PATH(filename, filename_len) && !strstr(filename, "://")) {
912 		char *arch, *entry, *fname;
913 		int arch_len, entry_len, fname_len;
914 		fname = (char*)zend_get_executed_filename(TSRMLS_C);
915 
916 		/* we are checking for existence of a file within the relative path.  Chances are good that this is
917 		   retrieving something from within the phar archive */
918 
919 		if (strncasecmp(fname, "phar://", 7)) {
920 			goto skip_phar;
921 		}
922 		fname_len = strlen(fname);
923 		if (SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len, 2, 0 TSRMLS_CC)) {
924 			phar_archive_data *phar;
925 
926 			efree(entry);
927 			entry = filename;
928 			/* fopen within phar, if :// is not in the url, then prepend phar://<archive>/ */
929 			entry_len = filename_len;
930 			/* retrieving a file within the current directory, so use this if possible */
931 			if (SUCCESS == phar_get_archive(&phar, arch, arch_len, NULL, 0, NULL TSRMLS_CC)) {
932 				phar_entry_info *etemp;
933 
934 				entry = phar_fix_filepath(estrndup(entry, entry_len), &entry_len, 1 TSRMLS_CC);
935 				if (entry[0] == '/') {
936 					if (SUCCESS == zend_hash_find(&(phar->manifest), entry + 1, entry_len - 1, (void **) &etemp)) {
937 						/* this file is not in the current directory, use the original path */
938 found_it:
939 						efree(entry);
940 						efree(arch);
941 						RETURN_BOOL(!etemp->is_dir);
942 					}
943 				} else {
944 					if (SUCCESS == zend_hash_find(&(phar->manifest), entry, entry_len, (void **) &etemp)) {
945 						goto found_it;
946 					}
947 				}
948 			}
949 			if (entry != filename) {
950 				efree(entry);
951 			}
952 			efree(arch);
953 			RETURN_FALSE;
954 		}
955 	}
956 skip_phar:
957 	PHAR_G(orig_is_file)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
958 	return;
959 }
960 /* }}} */
961 
PHAR_FUNC(phar_is_link)962 PHAR_FUNC(phar_is_link) /* {{{ */
963 {
964 	char *filename;
965 	int filename_len;
966 
967 	if (!PHAR_G(intercepted)) {
968 		goto skip_phar;
969 	}
970 
971 	if ((PHAR_GLOBALS->phar_fname_map.arBuckets && !zend_hash_num_elements(&(PHAR_GLOBALS->phar_fname_map)))
972 		&& !cached_phars.arBuckets) {
973 		goto skip_phar;
974 	}
975 	if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "p", &filename, &filename_len) == FAILURE) {
976 		goto skip_phar;
977 	}
978 	if (!IS_ABSOLUTE_PATH(filename, filename_len) && !strstr(filename, "://")) {
979 		char *arch, *entry, *fname;
980 		int arch_len, entry_len, fname_len;
981 		fname = (char*)zend_get_executed_filename(TSRMLS_C);
982 
983 		/* we are checking for existence of a file within the relative path.  Chances are good that this is
984 		   retrieving something from within the phar archive */
985 
986 		if (strncasecmp(fname, "phar://", 7)) {
987 			goto skip_phar;
988 		}
989 		fname_len = strlen(fname);
990 		if (SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len, 2, 0 TSRMLS_CC)) {
991 			phar_archive_data *phar;
992 
993 			efree(entry);
994 			entry = filename;
995 			/* fopen within phar, if :// is not in the url, then prepend phar://<archive>/ */
996 			entry_len = filename_len;
997 			/* retrieving a file within the current directory, so use this if possible */
998 			if (SUCCESS == phar_get_archive(&phar, arch, arch_len, NULL, 0, NULL TSRMLS_CC)) {
999 				phar_entry_info *etemp;
1000 
1001 				entry = phar_fix_filepath(estrndup(entry, entry_len), &entry_len, 1 TSRMLS_CC);
1002 				if (entry[0] == '/') {
1003 					if (SUCCESS == zend_hash_find(&(phar->manifest), entry + 1, entry_len - 1, (void **) &etemp)) {
1004 						/* this file is not in the current directory, use the original path */
1005 found_it:
1006 						efree(entry);
1007 						efree(arch);
1008 						RETURN_BOOL(etemp->link);
1009 					}
1010 				} else {
1011 					if (SUCCESS == zend_hash_find(&(phar->manifest), entry, entry_len, (void **) &etemp)) {
1012 						goto found_it;
1013 					}
1014 				}
1015 			}
1016 			efree(entry);
1017 			efree(arch);
1018 			RETURN_FALSE;
1019 		}
1020 	}
1021 skip_phar:
1022 	PHAR_G(orig_is_link)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
1023 	return;
1024 }
1025 /* }}} */
1026 
1027 /* {{{ proto array lstat(string filename)
1028    Give information about a file or symbolic link */
PharFileFunction(phar_lstat,FS_LSTAT,orig_lstat)1029 PharFileFunction(phar_lstat, FS_LSTAT, orig_lstat)
1030 /* }}} */
1031 
1032 /* {{{ proto array stat(string filename)
1033    Give information about a file */
1034 PharFileFunction(phar_stat, FS_STAT, orig_stat)
1035 /* }}} */
1036 
1037 /* {{{ void phar_intercept_functions(TSRMLS_D) */
1038 void phar_intercept_functions(TSRMLS_D)
1039 {
1040 	if (!PHAR_G(request_init)) {
1041 		PHAR_G(cwd) = NULL;
1042 		PHAR_G(cwd_len) = 0;
1043 	}
1044 	PHAR_G(intercepted) = 1;
1045 }
1046 /* }}} */
1047 
1048 /* {{{ void phar_release_functions(TSRMLS_D) */
phar_release_functions(TSRMLS_D)1049 void phar_release_functions(TSRMLS_D)
1050 {
1051 	PHAR_G(intercepted) = 0;
1052 }
1053 /* }}} */
1054 
1055 /* {{{ void phar_intercept_functions_init(TSRMLS_D) */
1056 #define PHAR_INTERCEPT(func) \
1057 	PHAR_G(orig_##func) = NULL; \
1058 	if (SUCCESS == zend_hash_find(CG(function_table), #func, sizeof(#func), (void **)&orig)) { \
1059 		PHAR_G(orig_##func) = orig->internal_function.handler; \
1060 		orig->internal_function.handler = phar_##func; \
1061 	}
1062 
phar_intercept_functions_init(TSRMLS_D)1063 void phar_intercept_functions_init(TSRMLS_D)
1064 {
1065 	zend_function *orig;
1066 
1067 	PHAR_INTERCEPT(fopen);
1068 	PHAR_INTERCEPT(file_get_contents);
1069 	PHAR_INTERCEPT(is_file);
1070 	PHAR_INTERCEPT(is_link);
1071 	PHAR_INTERCEPT(is_dir);
1072 	PHAR_INTERCEPT(opendir);
1073 	PHAR_INTERCEPT(file_exists);
1074 	PHAR_INTERCEPT(fileperms);
1075 	PHAR_INTERCEPT(fileinode);
1076 	PHAR_INTERCEPT(filesize);
1077 	PHAR_INTERCEPT(fileowner);
1078 	PHAR_INTERCEPT(filegroup);
1079 	PHAR_INTERCEPT(fileatime);
1080 	PHAR_INTERCEPT(filemtime);
1081 	PHAR_INTERCEPT(filectime);
1082 	PHAR_INTERCEPT(filetype);
1083 	PHAR_INTERCEPT(is_writable);
1084 	PHAR_INTERCEPT(is_readable);
1085 	PHAR_INTERCEPT(is_executable);
1086 	PHAR_INTERCEPT(lstat);
1087 	PHAR_INTERCEPT(stat);
1088 	PHAR_INTERCEPT(readfile);
1089 	PHAR_G(intercepted) = 0;
1090 }
1091 /* }}} */
1092 
1093 /* {{{ void phar_intercept_functions_shutdown(TSRMLS_D) */
1094 #define PHAR_RELEASE(func) \
1095 	if (PHAR_G(orig_##func) && SUCCESS == zend_hash_find(CG(function_table), #func, sizeof(#func), (void **)&orig)) { \
1096 		orig->internal_function.handler = PHAR_G(orig_##func); \
1097 	} \
1098 	PHAR_G(orig_##func) = NULL;
1099 
phar_intercept_functions_shutdown(TSRMLS_D)1100 void phar_intercept_functions_shutdown(TSRMLS_D)
1101 {
1102 	zend_function *orig;
1103 
1104 	PHAR_RELEASE(fopen);
1105 	PHAR_RELEASE(file_get_contents);
1106 	PHAR_RELEASE(is_file);
1107 	PHAR_RELEASE(is_dir);
1108 	PHAR_RELEASE(opendir);
1109 	PHAR_RELEASE(file_exists);
1110 	PHAR_RELEASE(fileperms);
1111 	PHAR_RELEASE(fileinode);
1112 	PHAR_RELEASE(filesize);
1113 	PHAR_RELEASE(fileowner);
1114 	PHAR_RELEASE(filegroup);
1115 	PHAR_RELEASE(fileatime);
1116 	PHAR_RELEASE(filemtime);
1117 	PHAR_RELEASE(filectime);
1118 	PHAR_RELEASE(filetype);
1119 	PHAR_RELEASE(is_writable);
1120 	PHAR_RELEASE(is_readable);
1121 	PHAR_RELEASE(is_executable);
1122 	PHAR_RELEASE(lstat);
1123 	PHAR_RELEASE(stat);
1124 	PHAR_RELEASE(readfile);
1125 	PHAR_G(intercepted) = 0;
1126 }
1127 /* }}} */
1128 
1129 static struct _phar_orig_functions {
1130 	void        (*orig_fopen)(INTERNAL_FUNCTION_PARAMETERS);
1131 	void        (*orig_file_get_contents)(INTERNAL_FUNCTION_PARAMETERS);
1132 	void        (*orig_is_file)(INTERNAL_FUNCTION_PARAMETERS);
1133 	void        (*orig_is_link)(INTERNAL_FUNCTION_PARAMETERS);
1134 	void        (*orig_is_dir)(INTERNAL_FUNCTION_PARAMETERS);
1135 	void        (*orig_opendir)(INTERNAL_FUNCTION_PARAMETERS);
1136 	void        (*orig_file_exists)(INTERNAL_FUNCTION_PARAMETERS);
1137 	void        (*orig_fileperms)(INTERNAL_FUNCTION_PARAMETERS);
1138 	void        (*orig_fileinode)(INTERNAL_FUNCTION_PARAMETERS);
1139 	void        (*orig_filesize)(INTERNAL_FUNCTION_PARAMETERS);
1140 	void        (*orig_fileowner)(INTERNAL_FUNCTION_PARAMETERS);
1141 	void        (*orig_filegroup)(INTERNAL_FUNCTION_PARAMETERS);
1142 	void        (*orig_fileatime)(INTERNAL_FUNCTION_PARAMETERS);
1143 	void        (*orig_filemtime)(INTERNAL_FUNCTION_PARAMETERS);
1144 	void        (*orig_filectime)(INTERNAL_FUNCTION_PARAMETERS);
1145 	void        (*orig_filetype)(INTERNAL_FUNCTION_PARAMETERS);
1146 	void        (*orig_is_writable)(INTERNAL_FUNCTION_PARAMETERS);
1147 	void        (*orig_is_readable)(INTERNAL_FUNCTION_PARAMETERS);
1148 	void        (*orig_is_executable)(INTERNAL_FUNCTION_PARAMETERS);
1149 	void        (*orig_lstat)(INTERNAL_FUNCTION_PARAMETERS);
1150 	void        (*orig_readfile)(INTERNAL_FUNCTION_PARAMETERS);
1151 	void        (*orig_stat)(INTERNAL_FUNCTION_PARAMETERS);
1152 } phar_orig_functions = {NULL};
1153 
phar_save_orig_functions(TSRMLS_D)1154 void phar_save_orig_functions(TSRMLS_D) /* {{{ */
1155 {
1156 	phar_orig_functions.orig_fopen             = PHAR_G(orig_fopen);
1157 	phar_orig_functions.orig_file_get_contents = PHAR_G(orig_file_get_contents);
1158 	phar_orig_functions.orig_is_file           = PHAR_G(orig_is_file);
1159 	phar_orig_functions.orig_is_link           = PHAR_G(orig_is_link);
1160 	phar_orig_functions.orig_is_dir            = PHAR_G(orig_is_dir);
1161 	phar_orig_functions.orig_opendir           = PHAR_G(orig_opendir);
1162 	phar_orig_functions.orig_file_exists       = PHAR_G(orig_file_exists);
1163 	phar_orig_functions.orig_fileperms         = PHAR_G(orig_fileperms);
1164 	phar_orig_functions.orig_fileinode         = PHAR_G(orig_fileinode);
1165 	phar_orig_functions.orig_filesize          = PHAR_G(orig_filesize);
1166 	phar_orig_functions.orig_fileowner         = PHAR_G(orig_fileowner);
1167 	phar_orig_functions.orig_filegroup         = PHAR_G(orig_filegroup);
1168 	phar_orig_functions.orig_fileatime         = PHAR_G(orig_fileatime);
1169 	phar_orig_functions.orig_filemtime         = PHAR_G(orig_filemtime);
1170 	phar_orig_functions.orig_filectime         = PHAR_G(orig_filectime);
1171 	phar_orig_functions.orig_filetype          = PHAR_G(orig_filetype);
1172 	phar_orig_functions.orig_is_writable       = PHAR_G(orig_is_writable);
1173 	phar_orig_functions.orig_is_readable       = PHAR_G(orig_is_readable);
1174 	phar_orig_functions.orig_is_executable     = PHAR_G(orig_is_executable);
1175 	phar_orig_functions.orig_lstat             = PHAR_G(orig_lstat);
1176 	phar_orig_functions.orig_readfile          = PHAR_G(orig_readfile);
1177 	phar_orig_functions.orig_stat              = PHAR_G(orig_stat);
1178 }
1179 /* }}} */
1180 
phar_restore_orig_functions(TSRMLS_D)1181 void phar_restore_orig_functions(TSRMLS_D) /* {{{ */
1182 {
1183 	PHAR_G(orig_fopen)             = phar_orig_functions.orig_fopen;
1184 	PHAR_G(orig_file_get_contents) = phar_orig_functions.orig_file_get_contents;
1185 	PHAR_G(orig_is_file)           = phar_orig_functions.orig_is_file;
1186 	PHAR_G(orig_is_link)           = phar_orig_functions.orig_is_link;
1187 	PHAR_G(orig_is_dir)            = phar_orig_functions.orig_is_dir;
1188 	PHAR_G(orig_opendir)           = phar_orig_functions.orig_opendir;
1189 	PHAR_G(orig_file_exists)       = phar_orig_functions.orig_file_exists;
1190 	PHAR_G(orig_fileperms)         = phar_orig_functions.orig_fileperms;
1191 	PHAR_G(orig_fileinode)         = phar_orig_functions.orig_fileinode;
1192 	PHAR_G(orig_filesize)          = phar_orig_functions.orig_filesize;
1193 	PHAR_G(orig_fileowner)         = phar_orig_functions.orig_fileowner;
1194 	PHAR_G(orig_filegroup)         = phar_orig_functions.orig_filegroup;
1195 	PHAR_G(orig_fileatime)         = phar_orig_functions.orig_fileatime;
1196 	PHAR_G(orig_filemtime)         = phar_orig_functions.orig_filemtime;
1197 	PHAR_G(orig_filectime)         = phar_orig_functions.orig_filectime;
1198 	PHAR_G(orig_filetype)          = phar_orig_functions.orig_filetype;
1199 	PHAR_G(orig_is_writable)       = phar_orig_functions.orig_is_writable;
1200 	PHAR_G(orig_is_readable)       = phar_orig_functions.orig_is_readable;
1201 	PHAR_G(orig_is_executable)     = phar_orig_functions.orig_is_executable;
1202 	PHAR_G(orig_lstat)             = phar_orig_functions.orig_lstat;
1203 	PHAR_G(orig_readfile)          = phar_orig_functions.orig_readfile;
1204 	PHAR_G(orig_stat)              = phar_orig_functions.orig_stat;
1205 }
1206 /* }}} */
1207 
1208 /*
1209  * Local variables:
1210  * tab-width: 4
1211  * c-basic-offset: 4
1212  * End:
1213  * vim600: noet sw=4 ts=4 fdm=marker
1214  * vim<600: noet sw=4 ts=4
1215  */
1216 
1217