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) /* {{{ */ { if (!filename_length) { RETURN_FALSE; } if (!IS_ABSOLUTE_PATH(filename, filename_length) && !strstr(filename, "://")) { char *arch, *entry, *fname; int arch_len, entry_len, fname_len; zend_stat_t sb = {0}; phar_entry_info *data = NULL; phar_archive_data *phar; fname = (char*)zend_get_executed_filename(); /* we are checking for existence of a file within the relative path. Chances are good that this is retrieving something from within the phar archive */ if (strncasecmp(fname, "phar://", 7)) { goto skip_phar; } fname_len = strlen(fname); 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))) { arch = estrndup(PHAR_G(last_phar_name), PHAR_G(last_phar_name_len)); arch_len = PHAR_G(last_phar_name_len); entry = estrndup(filename, filename_length); /* fopen within phar, if :// is not in the url, then prepend phar://<archive>/ */ entry_len = (int) filename_length; phar = PHAR_G(last_phar); goto splitted; } if (SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len, 2, 0)) { efree(entry); entry = estrndup(filename, filename_length); /* fopen within phar, if :// is not in the url, then prepend phar://<archive>/ */ entry_len = (int) filename_length; if (FAILURE == phar_get_archive(&phar, arch, arch_len, NULL, 0, NULL)) { efree(arch); efree(entry); goto skip_phar; } splitted: entry = phar_fix_filepath(entry, &entry_len, 1); if (entry[0] == '/') { if (NULL != (data = zend_hash_str_find_ptr(&(phar->manifest), entry + 1, entry_len - 1))) { efree(entry); goto stat_entry; } goto notfound; } if (NULL != (data = zend_hash_str_find_ptr(&(phar->manifest), entry, entry_len))) { efree(entry); goto stat_entry; } if (zend_hash_str_exists(&(phar->virtual_dirs), entry, entry_len)) { efree(entry); efree(arch); if (IS_EXISTS_CHECK(type)) { RETURN_TRUE; } sb.st_size = 0; sb.st_mode = 0777; sb.st_mode |= S_IFDIR; /* regular directory */ #ifdef NETWARE sb.st_mtime.tv_sec = phar->max_timestamp; sb.st_atime.tv_sec = phar->max_timestamp; sb.st_ctime.tv_sec = phar->max_timestamp; #else sb.st_mtime = phar->max_timestamp; sb.st_atime = phar->max_timestamp; sb.st_ctime = phar->max_timestamp; #endif goto statme_baby; } else { char *save; int save_len; notfound: efree(entry); save = PHAR_G(cwd); save_len = PHAR_G(cwd_len); /* this file is not in the current directory, use the original path */ entry = estrndup(filename, filename_length); entry_len = filename_length; PHAR_G(cwd) = "/"; PHAR_G(cwd_len) = 0; /* clean path without cwd */ entry = phar_fix_filepath(entry, &entry_len, 1); if (NULL != (data = zend_hash_str_find_ptr(&(phar->manifest), entry + 1, entry_len - 1))) { PHAR_G(cwd) = save; PHAR_G(cwd_len) = save_len; efree(entry); if (IS_EXISTS_CHECK(type)) { efree(arch); RETURN_TRUE; } goto stat_entry; } if (zend_hash_str_exists(&(phar->virtual_dirs), entry + 1, entry_len - 1)) { PHAR_G(cwd) = save; PHAR_G(cwd_len) = save_len; efree(entry); efree(arch); if (IS_EXISTS_CHECK(type)) { RETURN_TRUE; } sb.st_size = 0; sb.st_mode = 0777; sb.st_mode |= S_IFDIR; /* regular directory */ #ifdef NETWARE sb.st_mtime.tv_sec = phar->max_timestamp; sb.st_atime.tv_sec = phar->max_timestamp; sb.st_ctime.tv_sec = phar->max_timestamp; #else sb.st_mtime = phar->max_timestamp; sb.st_atime = phar->max_timestamp; sb.st_ctime = phar->max_timestamp; #endif goto statme_baby; } PHAR_G(cwd) = save; PHAR_G(cwd_len) = save_len; efree(entry); efree(arch); /* Error Occurred */ if (!IS_EXISTS_CHECK(type)) { php_error_docref(NULL, E_WARNING, "%sstat failed for %s", IS_LINK_OPERATION(type) ? "L" : "", filename); } RETURN_FALSE; } stat_entry: efree(arch); if (!data->is_dir) { sb.st_size = data->uncompressed_filesize; sb.st_mode = data->flags & PHAR_ENT_PERM_MASK; if (data->link) { sb.st_mode |= S_IFREG|S_IFLNK; /* regular file */ } else { sb.st_mode |= S_IFREG; /* regular file */ } /* timestamp is just the timestamp when this was added to the phar */ #ifdef NETWARE sb.st_mtime.tv_sec = data->timestamp; sb.st_atime.tv_sec = data->timestamp; sb.st_ctime.tv_sec = data->timestamp; #else sb.st_mtime = data->timestamp; sb.st_atime = data->timestamp; sb.st_ctime = data->timestamp; #endif } else { sb.st_size = 0; sb.st_mode = data->flags & PHAR_ENT_PERM_MASK; sb.st_mode |= S_IFDIR; /* regular directory */ if (data->link) { sb.st_mode |= S_IFLNK; } /* timestamp is just the timestamp when this was added to the phar */ #ifdef NETWARE sb.st_mtime.tv_sec = data->timestamp; sb.st_atime.tv_sec = data->timestamp; sb.st_ctime.tv_sec = data->timestamp; #else sb.st_mtime = data->timestamp; sb.st_atime = data->timestamp; sb.st_ctime = data->timestamp; #endif } statme_baby: if (!phar->is_writeable) { sb.st_mode = (sb.st_mode & 0555) | (sb.st_mode & ~0777); } sb.st_nlink = 1; sb.st_rdev = -1; /* this is only for APC, so use /dev/null device - no chance of conflict there! */ sb.st_dev = 0xc; /* generate unique inode number for alias/filename, so no phars will conflict */ if (data) { sb.st_ino = data->inode; } #ifndef PHP_WIN32 sb.st_blksize = -1; sb.st_blocks = -1; #endif phar_fancy_stat(&sb, type, return_value); return; } } skip_phar: orig_stat_func(INTERNAL_FUNCTION_PARAM_PASSTHRU); return; }
/** * Open a phar file for streams API */ php_url* phar_parse_url(php_stream_wrapper *wrapper, const char *filename, const char *mode, int options) /* {{{ */ { php_url *resource; char *arch = NULL, *entry = NULL, *error; int arch_len, entry_len; if (strlen(filename) < 7 || strncasecmp(filename, "phar://", 7)) { return NULL; } if (mode[0] == 'a') { if (!(options & PHP_STREAM_URL_STAT_QUIET)) { php_stream_wrapper_log_error(wrapper, options, "phar error: open mode append not supported"); } return NULL; } if (phar_split_fname(filename, strlen(filename), &arch, &arch_len, &entry, &entry_len, 2, (mode[0] == 'w' ? 2 : 0)) == FAILURE) { if (!(options & PHP_STREAM_URL_STAT_QUIET)) { if (arch && !entry) { php_stream_wrapper_log_error(wrapper, options, "phar error: no directory in \"%s\", must have at least phar://%s/ for root directory (always use full path to a new phar)", filename, arch); arch = NULL; } else { php_stream_wrapper_log_error(wrapper, options, "phar error: invalid url or non-existent phar \"%s\"", filename); } } return NULL; } resource = ecalloc(1, sizeof(php_url)); resource->scheme = estrndup("phar", 4); resource->host = arch; resource->path = entry; #if MBO_0 if (resource) { fprintf(stderr, "Alias: %s\n", alias); fprintf(stderr, "Scheme: %s\n", resource->scheme); /* fprintf(stderr, "User: %s\n", resource->user);*/ /* fprintf(stderr, "Pass: %s\n", resource->pass ? "***" : NULL);*/ fprintf(stderr, "Host: %s\n", resource->host); /* fprintf(stderr, "Port: %d\n", resource->port);*/ fprintf(stderr, "Path: %s\n", resource->path); /* fprintf(stderr, "Query: %s\n", resource->query);*/ /* fprintf(stderr, "Fragment: %s\n", resource->fragment);*/ } #endif if (mode[0] == 'w' || (mode[0] == 'r' && mode[1] == '+')) { phar_archive_data *pphar = NULL, *phar; if (PHAR_G(request_init) && PHAR_G(phar_fname_map.u.flags) && NULL == (pphar = zend_hash_str_find_ptr(&(PHAR_G(phar_fname_map)), arch, arch_len))) { pphar = NULL; } if (PHAR_G(readonly) && (!pphar || !pphar->is_data)) { if (!(options & PHP_STREAM_URL_STAT_QUIET)) { php_stream_wrapper_log_error(wrapper, options, "phar error: write operations disabled by the php.ini setting phar.readonly"); } php_url_free(resource); return NULL; } if (phar_open_or_create_filename(resource->host, arch_len, NULL, 0, 0, options, &phar, &error) == FAILURE) { if (error) { if (!(options & PHP_STREAM_URL_STAT_QUIET)) { php_stream_wrapper_log_error(wrapper, options, "%s", error); } efree(error); } php_url_free(resource); return NULL; } if (phar->is_persistent && FAILURE == phar_copy_on_write(&phar)) { if (error) { spprintf(&error, 0, "Cannot open cached phar '%s' as writeable, copy on write failed", resource->host); if (!(options & PHP_STREAM_URL_STAT_QUIET)) { php_stream_wrapper_log_error(wrapper, options, "%s", error); } efree(error); } php_url_free(resource); return NULL; } } else { if (phar_open_from_filename(resource->host, arch_len, NULL, 0, options, NULL, &error) == FAILURE) { if (error) { if (!(options & PHP_STREAM_URL_STAT_QUIET)) { php_stream_wrapper_log_error(wrapper, options, "%s", error); } efree(error); } php_url_free(resource); return NULL; } } return resource; }