"phar stream",
NULL, /* seek */
NULL, /* cast */
- NULL, /* stat */
+ phar_stat, /* stat */
NULL, /* set option */
};
static void phar_dostat(phar_manifest_entry *data, php_stream_statbuf *ssb, zend_bool is_dir TSRMLS_DC)
{
memset(ssb, 0, sizeof(php_stream_statbuf));
+ /* read-only across the board */
ssb->sb.st_mode = 0444;
if (!is_dir) {
ssb->sb.st_size = data->uncompressed_filesize;
- ssb->sb.st_mode |= S_IFREG;
+ ssb->sb.st_mode |= S_IFREG; /* regular file */
+ /* timestamp is just the timestamp when this was added to the phar */
#ifdef NETWARE
ssb->sb.st_mtime.tv_sec = data->timestamp;
ssb->sb.st_atime.tv_sec = data->timestamp;
#endif
} else {
ssb->sb.st_size = 0;
- ssb->sb.st_mode |= S_IFDIR;
+ ssb->sb.st_mode |= S_IFDIR; /* regular directory */
#ifdef NETWARE
ssb->sb.st_mtime.tv_sec = 0;
ssb->sb.st_atime.tv_sec = 0;
}
internal_file = resource->path + 1; /* strip leading "/" */
+ /* find the phar in our trusty global hash indexed by alias (host of phar://blah.phar/file.whatever) */
if (SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_data), resource->host, strlen(resource->host), (void **) &data)) {
if (*internal_file == '\0') {
/* root directory requested */
php_url_free(resource);
return 0;
}
+ /* search through the manifest of files, and if we have an exact match, it's a file */
if (SUCCESS == zend_hash_find(data->manifest, internal_file, strlen(internal_file), (void **) &file_data)) {
phar_dostat(file_data, ssb, 0 TSRMLS_CC);
} else {
- /* search for directory */
+ /* search for directory (partial match of a file) */
zend_hash_internal_pointer_reset(data->manifest);
- while (zend_hash_has_more_elements(data->manifest)) {
+ while (HASH_KEY_NON_EXISTANT != zend_hash_has_more_elements(data->manifest)) {
if (HASH_KEY_NON_EXISTANT !=
zend_hash_get_current_key_ex(
data->manifest, &key, &keylen, &unused, 0, NULL)) {
- if (0 == memcmp(key, internal_file, keylen)) {
- /* directory found */
+ if (0 == memcmp(internal_file, key, strlen(internal_file))) {
+ /* directory found, all dirs have the same stat */
phar_dostat(NULL, ssb, 1 TSRMLS_CC);
break;
}
}
- zend_hash_move_forward(data->manifest);
+ if (SUCCESS != zend_hash_move_forward(data->manifest)) {
+ break;
+ }
}
}
}
return 0;
}
+/* add an empty element with a char * key to a hash table, avoiding duplicates */
static int phar_add_empty(HashTable *ht, char *arKey, uint nKeyLength)
{
void *dummy = (void *) 1;
phar_manifest_entry *file_data;
resource = php_url_parse(filename);
- /* we must have at the very least phar://alias.phar/internalfile.php */
+ /* we must have at the very least phar://alias.phar/ */
if (!resource || !resource->scheme || !resource->host || !resource->path) {
+ if (resource->host && !resource->path) {
+ php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: no directory in \"%s\", must have at least phar://%s/ for root directory", filename, resource->host);
+ php_url_free(resource);
+ return NULL;
+ }
php_url_free(resource);
- php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: invalid url \"%s\"", filename);
+ php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: invalid url \"%s\", must have at least phar://%s/", filename, filename);
return NULL;
}
--- /dev/null
+--TEST--
+opendir test - no dir specified at all
+--SKIPIF--
+<?php if (!extension_loaded("phar")) print "skip"; ?>
+--FILE--
+<?php
+function cleanup() { unlink(dirname(__FILE__) . '/008_phar.php'); }
+register_shutdown_function('cleanup');
+$file = "<?php
+PHP_Archive::mapPhar(5, 'hio', true);
+__HALT_COMPILER(); ?>";
+// file length is too short
+$manifest = pack('V', 1) . 'a' . pack('VVVV', 1, time(), 0, 9);
+$file .= pack('VV', strlen($manifest) + 4, 1) . $manifest . pack('VV', crc32('a'), 1) . 'a';
+file_put_contents(dirname(__FILE__) . '/008_phar.php', $file);
+include dirname(__FILE__) . '/008_phar.php';
+$dir = opendir('phar://hio');
+?>
+--EXPECTF--
+Warning: opendir(phar://hio): failed to open dir: phar error: no directory in "phar://hio", must have at least phar://hio/ for root directory in %s on line %d
\ No newline at end of file
--- /dev/null
+--TEST--
+opendir test, root directory
+--SKIPIF--
+<?php if (!extension_loaded("phar")) print "skip"; ?>
+--FILE--
+<?php
+function cleanup() { unlink(dirname(__FILE__) . '/008_phar.php'); }
+register_shutdown_function('cleanup');
+$file = "<?php
+PHP_Archive::mapPhar(5, 'hio', true);
+__HALT_COMPILER(); ?>";
+$manifest = '';
+$manifest .= pack('V', 1) . 'a' . pack('VVVV', 1, time(), 0, 9);
+$manifest .= pack('V', 3) . 'b/a' . pack('VVVV', 1, time(), 0, 9);
+$file .= pack('VV', strlen($manifest) + 4, 2) .
+ $manifest .
+ pack('VV', crc32('a'), 1) . 'a' .
+ pack('VV', crc32('b'), 1) . 'b';
+file_put_contents(dirname(__FILE__) . '/008_phar.php', $file);
+include dirname(__FILE__) . '/008_phar.php';
+$dir = opendir('phar://hio/');
+while (false !== ($a = readdir($dir))) {
+ var_dump($a);
+ var_dump(is_dir('phar://hio/' . $a));
+}
+?>
+--EXPECT--
+string(1) "a"
+bool(false)
+string(1) "b"
+bool(true)
\ No newline at end of file