]> granicus.if.org Git - php/commitdiff
making progress - up to 42/phar vs. 48/disk with these optimizations
authorGreg Beaver <cellog@php.net>
Fri, 20 Jun 2008 05:42:58 +0000 (05:42 +0000)
committerGreg Beaver <cellog@php.net>
Fri, 20 Jun 2008 05:42:58 +0000 (05:42 +0000)
ext/phar/func_interceptors.c
ext/phar/phar.c
ext/phar/phar.phar
ext/phar/phar_internal.h
ext/phar/phar_object.c
ext/phar/util.c

index 0abc62396359209641afdbb93ff7f8cfad059152..026f88fd5d81efd0f517b636a60bff0899967804 100644 (file)
@@ -119,7 +119,7 @@ PHAR_FUNC(phar_file_get_contents) /* {{{ */
                fname_len = strlen(fname);
                if (SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len, 2, 0 TSRMLS_CC)) {
                        char *name;
-                       phar_archive_data **pphar;
+                       phar_archive_data *phar;
 
                        efree(entry);
                        entry = filename;
@@ -133,8 +133,7 @@ PHAR_FUNC(phar_file_get_contents) /* {{{ */
                        }
 
                        /* retrieving a file defaults to within the current directory, so use this if possible */
-                       if ((PHAR_GLOBALS->phar_fname_map.arBuckets && FAILURE == (zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar)))
-                               && (PHAR_G(manifest_cached) && FAILURE == (zend_hash_find(&cached_phars, arch, arch_len, (void **) &pphar)))) {
+                       if (FAILURE == phar_get_archive(&phar, arch, arch_len, NULL, 0, NULL TSRMLS_CC)) {
                                efree(arch);
                                goto skip_phar;
                        }
@@ -150,7 +149,7 @@ PHAR_FUNC(phar_file_get_contents) /* {{{ */
                        } else {
                                entry = phar_fix_filepath(estrndup(entry, entry_len), &entry_len, 1 TSRMLS_CC);
                                if (entry[0] == '/') {
-                                       if (!zend_hash_exists(&((*pphar)->manifest), entry + 1, entry_len - 1)) {
+                                       if (!zend_hash_exists(&(phar->manifest), entry + 1, entry_len - 1)) {
                                                /* this file is not in the phar, use the original path */
 notfound:
                                                efree(arch);
@@ -158,7 +157,7 @@ notfound:
                                                goto skip_phar;
                                        }
                                } else {
-                                       if (!zend_hash_exists(&((*pphar)->manifest), entry, entry_len)) {
+                                       if (!zend_hash_exists(&(phar->manifest), entry, entry_len)) {
                                                goto notfound;
                                        }
                                }
@@ -237,7 +236,7 @@ PHAR_FUNC(phar_readfile) /* {{{ */
                int arch_len, entry_len, fname_len;
                php_stream_context *context = NULL;
                char *name;
-               phar_archive_data **pphar;
+               phar_archive_data *phar;
                fname = zend_get_executed_filename(TSRMLS_C);
 
                if (strncasecmp(fname, "phar://", 7)) {
@@ -253,8 +252,7 @@ PHAR_FUNC(phar_readfile) /* {{{ */
                /* fopen within phar, if :// is not in the url, then prepend phar://<archive>/ */
                entry_len = filename_len;
                /* retrieving a file defaults to within the current directory, so use this if possible */
-               if ((PHAR_GLOBALS->phar_fname_map.arBuckets && FAILURE == (zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar)))
-                       && (PHAR_G(manifest_cached) && FAILURE == (zend_hash_find(&cached_phars, arch, arch_len, (void **) &pphar)))) {
+               if (FAILURE == phar_get_archive(&phar, arch, arch_len, NULL, 0, NULL TSRMLS_CC)) {
                        efree(arch);
                        goto skip_phar;
                }
@@ -269,7 +267,7 @@ PHAR_FUNC(phar_readfile) /* {{{ */
                } else {
                        entry = phar_fix_filepath(estrndup(entry, entry_len), &entry_len, 1 TSRMLS_CC);
                        if (entry[0] == '/') {
-                               if (!zend_hash_exists(&((*pphar)->manifest), entry + 1, entry_len - 1)) {
+                               if (!zend_hash_exists(&(phar->manifest), entry + 1, entry_len - 1)) {
                                        /* this file is not in the phar, use the original path */
 notfound:
                                        efree(entry);
@@ -277,7 +275,7 @@ notfound:
                                        goto skip_phar;
                                }
                        } else {
-                               if (!zend_hash_exists(&((*pphar)->manifest), entry, entry_len)) {
+                               if (!zend_hash_exists(&(phar->manifest), entry, entry_len)) {
                                        goto notfound;
                                }
                        }
@@ -330,7 +328,7 @@ PHAR_FUNC(phar_fopen) /* {{{ */
                int arch_len, entry_len, fname_len;
                php_stream_context *context = NULL;
                char *name;
-               phar_archive_data **pphar;
+               phar_archive_data *phar;
                fname = zend_get_executed_filename(TSRMLS_C);
 
                if (strncasecmp(fname, "phar://", 7)) {
@@ -346,8 +344,7 @@ PHAR_FUNC(phar_fopen) /* {{{ */
                /* fopen within phar, if :// is not in the url, then prepend phar://<archive>/ */
                entry_len = filename_len;
                /* retrieving a file defaults to within the current directory, so use this if possible */
-               if ((PHAR_GLOBALS->phar_fname_map.arBuckets && FAILURE == (zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar)))
-                       && (PHAR_G(manifest_cached) && FAILURE == (zend_hash_find(&cached_phars, arch, arch_len, (void **) &pphar)))) {
+               if (FAILURE == phar_get_archive(&phar, arch, arch_len, NULL, 0, NULL TSRMLS_CC)) {
                        efree(arch);
                        goto skip_phar;
                }
@@ -362,7 +359,7 @@ PHAR_FUNC(phar_fopen) /* {{{ */
                } else {
                        entry = phar_fix_filepath(estrndup(entry, entry_len), &entry_len, 1 TSRMLS_CC);
                        if (entry[0] == '/') {
-                               if (!zend_hash_exists(&((*pphar)->manifest), entry + 1, entry_len - 1)) {
+                               if (!zend_hash_exists(&(phar->manifest), entry + 1, entry_len - 1)) {
                                        /* this file is not in the phar, use the original path */
 notfound:
                                        efree(entry);
@@ -370,7 +367,7 @@ notfound:
                                        goto skip_phar;
                                }
                        } else {
-                               if (!zend_hash_exists(&((*pphar)->manifest), entry, entry_len)) {
+                               if (!zend_hash_exists(&(phar->manifest), entry, entry_len)) {
                                        /* this file is not in the phar, use the original path */
                                        goto notfound;
                                }
@@ -602,8 +599,7 @@ void phar_file_stat(const char *filename, php_stat_len filename_length, int type
                int arch_len, entry_len, fname_len;
                struct stat sb = {0};
                phar_entry_info *data = NULL;
-               char *tmp;
-               int tmp_len;
+               phar_archive_data *phar;
 
                fname = zend_get_executed_filename(TSRMLS_C);
 
@@ -614,31 +610,39 @@ void phar_file_stat(const char *filename, php_stat_len filename_length, int type
                        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 TSRMLS_CC)) {
-                       phar_archive_data **pphar;
 
                        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 ((PHAR_GLOBALS->phar_fname_map.arBuckets && FAILURE == (zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar)))
-                               && (PHAR_G(manifest_cached) && FAILURE == (zend_hash_find(&cached_phars, arch, arch_len, (void **) &pphar)))) {
+                       if (FAILURE == phar_get_archive(&phar, arch, arch_len, NULL, 0, NULL TSRMLS_CC)) {
                                efree(arch);
                                goto skip_phar;
                        }
+splitted:
                        entry = phar_fix_filepath(entry, &entry_len, 1 TSRMLS_CC);
                        if (entry[0] == '/') {
-                               if (SUCCESS == zend_hash_find(&((*pphar)->manifest), entry + 1, entry_len - 1, (void **) &data)) {
+                               if (SUCCESS == zend_hash_find(&(phar->manifest), entry + 1, entry_len - 1, (void **) &data)) {
                                        efree(entry);
                                        goto stat_entry;
                                }
                                goto notfound;
                        }
-                       if (SUCCESS == zend_hash_find(&((*pphar)->manifest), entry, entry_len, (void **) &data)) {
+                       if (SUCCESS == zend_hash_find(&(phar->manifest), entry, entry_len, (void **) &data)) {
                                efree(entry);
                                goto stat_entry;
                        }
-                       if (SUCCESS == zend_hash_find(&((*pphar)->virtual_dirs), entry, entry_len, (void **) &data)) {
+                       if (SUCCESS == zend_hash_find(&(phar->virtual_dirs), entry, entry_len, (void **) &data)) {
                                efree(entry);
                                efree(arch);
                                if (IS_EXISTS_CHECK(type)) {
@@ -648,13 +652,13 @@ void phar_file_stat(const char *filename, php_stat_len filename_length, int type
                                sb.st_mode = 0777;
                                sb.st_mode |= S_IFDIR; /* regular directory */
 #ifdef NETWARE
-                               sb.st_mtime.tv_sec = (*pphar)->max_timestamp;
-                               sb.st_atime.tv_sec = (*pphar)->max_timestamp;
-                               sb.st_ctime.tv_sec = (*pphar)->max_timestamp;
+                               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 = (*pphar)->max_timestamp;
-                               sb.st_atime = (*pphar)->max_timestamp;
-                               sb.st_ctime = (*pphar)->max_timestamp;
+                               sb.st_mtime = phar->max_timestamp;
+                               sb.st_atime = phar->max_timestamp;
+                               sb.st_ctime = phar->max_timestamp;
 #endif
                                goto statme_baby;
                        } else {
@@ -675,7 +679,7 @@ notfound:
                                PHAR_G(cwd_len) = 0;
                                /* clean path without cwd */
                                entry = phar_fix_filepath(entry, &entry_len, 1 TSRMLS_CC);
-                               if (SUCCESS == zend_hash_find(&((*pphar)->manifest), entry + 1, entry_len - 1, (void **) &data)) {
+                               if (SUCCESS == zend_hash_find(&(phar->manifest), entry + 1, entry_len - 1, (void **) &data)) {
                                        PHAR_G(cwd) = save;
                                        PHAR_G(cwd_len) = save_len;
                                        efree(entry);
@@ -685,7 +689,7 @@ notfound:
                                        }
                                        goto stat_entry;
                                }
-                               if (SUCCESS == zend_hash_find(&((*pphar)->virtual_dirs), entry + 1, entry_len - 1, (void **) &data)) {
+                               if (SUCCESS == zend_hash_find(&(phar->virtual_dirs), entry + 1, entry_len - 1, (void **) &data)) {
                                        PHAR_G(cwd) = save;
                                        PHAR_G(cwd_len) = save_len;
                                        efree(entry);
@@ -698,13 +702,13 @@ notfound:
                                        sb.st_mode = 0777;
                                        sb.st_mode |= S_IFDIR; /* regular directory */
 #ifdef NETWARE
-                                       sb.st_mtime.tv_sec = (*pphar)->max_timestamp;
-                                       sb.st_atime.tv_sec = (*pphar)->max_timestamp;
-                                       sb.st_ctime.tv_sec = (*pphar)->max_timestamp;
+                                       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 = (*pphar)->max_timestamp;
-                                       sb.st_atime = (*pphar)->max_timestamp;
-                                       sb.st_ctime = (*pphar)->max_timestamp;
+                                       sb.st_mtime = phar->max_timestamp;
+                                       sb.st_atime = phar->max_timestamp;
+                                       sb.st_ctime = phar->max_timestamp;
 #endif
                                        goto statme_baby;
                                }
@@ -759,29 +763,18 @@ stat_entry:
 
 statme_baby:
                        efree(arch);
-                       if (!(*pphar)->is_writeable) {
+                       if (!phar->is_writeable) {
                                sb.st_mode = (sb.st_mode & 0555) | (sb.st_mode & ~0777);
                        }
                
                        sb.st_nlink = 1;
                        sb.st_rdev = -1;
-                       if (data) {
-                               tmp_len = data->filename_len + (*pphar)->alias_len;
-                       } else {
-                               tmp_len = (*pphar)->alias_len + 1;
-                       }
-                       tmp = (char *) emalloc(tmp_len);
-                       memcpy(tmp, (*pphar)->alias, (*pphar)->alias_len);
-                       if (data) {
-                               memcpy(tmp + (*pphar)->alias_len, data->filename, data->filename_len);
-                       } else {
-                               *(tmp + (*pphar)->alias_len) = '/';
-                       }
                        /* 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 */
-                       sb.st_ino = (unsigned short)zend_get_hash_value(tmp, tmp_len);
-                       efree(tmp);
+                       if (data) {
+                               sb.st_ino = data->inode;
+                       }
 #ifndef PHP_WIN32
                        sb.st_blksize = -1;
                        sb.st_blocks = -1;
@@ -904,20 +897,19 @@ PHAR_FUNC(phar_is_file) /* {{{ */
                }
                fname_len = strlen(fname);
                if (SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len, 2, 0 TSRMLS_CC)) {
-                       phar_archive_data **pphar;
+                       phar_archive_data *phar;
 
                        efree(entry);
                        entry = filename;
                        /* fopen within phar, if :// is not in the url, then prepend phar://<archive>/ */
                        entry_len = filename_len;
                        /* retrieving a file within the current directory, so use this if possible */
-                       if ((PHAR_GLOBALS->phar_fname_map.arBuckets && SUCCESS == (zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar)))
-                               || (PHAR_G(manifest_cached) && SUCCESS == (zend_hash_find(&cached_phars, arch, arch_len, (void **) &pphar)))) {
+                       if (SUCCESS == phar_get_archive(&phar, arch, arch_len, NULL, 0, NULL TSRMLS_CC)) {
                                phar_entry_info *etemp;
 
                                entry = phar_fix_filepath(estrndup(entry, entry_len), &entry_len, 1 TSRMLS_CC);
                                if (entry[0] == '/') {
-                                       if (SUCCESS == zend_hash_find(&((*pphar)->manifest), entry + 1, entry_len - 1, (void **) &etemp)) {
+                                       if (SUCCESS == zend_hash_find(&(phar->manifest), entry + 1, entry_len - 1, (void **) &etemp)) {
                                                /* this file is not in the current directory, use the original path */
 found_it:
                                                efree(entry);
@@ -925,7 +917,7 @@ found_it:
                                                RETURN_BOOL(!etemp->is_dir);
                                        }
                                } else {
-                                       if (SUCCESS == zend_hash_find(&((*pphar)->manifest), entry, entry_len, (void **) &etemp)) {
+                                       if (SUCCESS == zend_hash_find(&(phar->manifest), entry, entry_len, (void **) &etemp)) {
                                                goto found_it;
                                        }
                                }
@@ -966,20 +958,19 @@ PHAR_FUNC(phar_is_link) /* {{{ */
                }
                fname_len = strlen(fname);
                if (SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len, 2, 0 TSRMLS_CC)) {
-                       phar_archive_data **pphar;
+                       phar_archive_data *phar;
 
                        efree(entry);
                        entry = filename;
                        /* fopen within phar, if :// is not in the url, then prepend phar://<archive>/ */
                        entry_len = filename_len;
                        /* retrieving a file within the current directory, so use this if possible */
-                       if ((PHAR_GLOBALS->phar_fname_map.arBuckets && SUCCESS == (zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar)))
-                               || (PHAR_G(manifest_cached) && SUCCESS == (zend_hash_find(&cached_phars, arch, arch_len, (void **) &pphar)))) {
+                       if (SUCCESS == phar_get_archive(&phar, arch, arch_len, NULL, 0, NULL TSRMLS_CC)) {
                                phar_entry_info *etemp;
 
                                entry = phar_fix_filepath(estrndup(entry, entry_len), &entry_len, 1 TSRMLS_CC);
                                if (entry[0] == '/') {
-                                       if (SUCCESS == zend_hash_find(&((*pphar)->manifest), entry + 1, entry_len - 1, (void **) &etemp)) {
+                                       if (SUCCESS == zend_hash_find(&(phar->manifest), entry + 1, entry_len - 1, (void **) &etemp)) {
                                                /* this file is not in the current directory, use the original path */
 found_it:
                                                efree(entry);
@@ -987,7 +978,7 @@ found_it:
                                                RETURN_BOOL(etemp->link);
                                        }
                                } else {
-                                       if (SUCCESS == zend_hash_find(&((*pphar)->manifest), entry, entry_len, (void **) &etemp)) {
+                                       if (SUCCESS == zend_hash_find(&(phar->manifest), entry, entry_len, (void **) &etemp)) {
                                                goto found_it;
                                        }
                                }
index 59bf81a4325403c0ab485d5c8bb67f71619011e2..ccec14f960f091df2686a837c3bfd2483236250f 100644 (file)
@@ -267,6 +267,9 @@ int phar_archive_delref(phar_archive_data *phar TSRMLS_DC) /* {{{ */
                }
                return 1;
        } else if (!phar->refcount) {
+               /* invalidate phar cache */
+               PHAR_G(last_phar) = NULL;
+               PHAR_G(last_phar_name) = PHAR_G(last_alias) = NULL;
                if (phar->fp && !(phar->flags & PHAR_FILE_COMPRESSION_MASK)) {
                        /* close open file handle - allows removal or rename of
                        the file on windows, which has greedy locking
@@ -1613,6 +1616,11 @@ static int phar_analyze_path(const char *fname, const char *ext, int ext_len, in
                        efree(realpath);
                        return SUCCESS;
                }
+               if (PHAR_G(manifest_cached) && zend_hash_exists(&cached_phars, realpath, strlen(realpath))) {
+                       *a = old;
+                       efree(realpath);
+                       return SUCCESS;
+               }
                efree(realpath);
        }
        if (SUCCESS == php_stream_stat_path((char *) fname, &ssb)) {
@@ -1746,9 +1754,14 @@ int phar_detect_phar_fname_ext(const char *filename, int filename_len, const cha
                        *ext_len = -1;
                        return FAILURE;
                }
+               if (PHAR_G(manifest_cached) && zend_hash_exists(&cached_alias, (char *) filename, pos - filename)) {
+                       *ext_str = pos;
+                       *ext_len = -1;
+                       return FAILURE;
+               }
        }
 
-       if (zend_hash_num_elements(&(PHAR_GLOBALS->phar_fname_map))) {
+       if (zend_hash_num_elements(&(PHAR_GLOBALS->phar_fname_map)) || PHAR_G(manifest_cached)) {
                phar_archive_data **pphar;
 
                if (is_complete) {
@@ -1767,6 +1780,10 @@ woohoo:
                                }
                                return FAILURE;
                        }
+                       if (PHAR_G(manifest_cached) && SUCCESS == zend_hash_find(&cached_phars, (char *) filename, filename_len, (void **)&pphar)) {
+                               *ext_str = filename + (filename_len - (*pphar)->ext_len);
+                               goto woohoo;
+                       }
                } else {
                        phar_zstr key;
                        char *str_key;
@@ -1795,6 +1812,30 @@ woohoo:
                                }
                                zend_hash_move_forward(&(PHAR_GLOBALS->phar_fname_map));
                        }
+                       if (PHAR_G(manifest_cached)) {
+                               zend_hash_internal_pointer_reset(&cached_phars);
+                               while (FAILURE != zend_hash_has_more_elements(&cached_phars)) {
+                                       if (HASH_KEY_NON_EXISTANT == zend_hash_get_current_key_ex(&cached_phars, &key, &keylen, &unused, 0, NULL)) {
+                                               break;
+                                       }
+       
+                                       PHAR_STR(key, str_key);
+       
+                                       if (keylen > (uint) filename_len) {
+                                               zend_hash_move_forward(&cached_phars);
+                                               continue;
+                                       }
+                                       if (!memcmp(filename, str_key, keylen) && ((uint)filename_len == keylen
+                                               || filename[keylen] == '/' || filename[keylen] == '\0')) {
+                                               if (FAILURE == zend_hash_get_current_data(&cached_phars, (void **) &pphar)) {
+                                                       break;
+                                               }
+                                               *ext_str = filename + (keylen - (*pphar)->ext_len);
+                                               goto woohoo;
+                                       }
+                                       zend_hash_move_forward(&cached_phars);
+                               }
+                       }
                }
        }
 
@@ -3205,6 +3246,9 @@ int phar_zend_open(const char *filename, zend_file_handle *handle TSRMLS_DC) /*
                if (fname_len > 7 && !strncasecmp(fname, "phar://", 7)) {
                        if (SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len, 1, 0 TSRMLS_CC)) {
                                zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar);
+                               if (!pphar && PHAR_G(manifest_cached)) {
+                                       zend_hash_find(&cached_phars, arch, arch_len, (void **) &pphar);
+                               }
                                efree(arch);
                                efree(entry);
                        }
@@ -3281,6 +3325,8 @@ void phar_request_initialize(TSRMLS_D) /* {{{ */
 {
        if (!PHAR_GLOBALS->request_init)
        {
+               PHAR_G(last_phar) = NULL;
+               PHAR_G(last_phar_name) = PHAR_G(last_alias) = NULL;
                PHAR_G(has_bz2) = zend_hash_exists(&module_registry, "bz2", sizeof("bz2"));
                PHAR_G(has_zlib) = zend_hash_exists(&module_registry, "zlib", sizeof("zlib"));
                PHAR_GLOBALS->request_init = 1;
index 336c929e64f2ff173a26ed660c47cdbdcd8f17da..70cdf8b9e2c176ced2b0e8681f01f6110b50af03 100755 (executable)
Binary files a/ext/phar/phar.phar and b/ext/phar/phar.phar differ
index f4f1f6e2a05cf5393176ba123bb08f9522a19fea..c80ac263d7ca8ac5cb9c2a228ab4d1172c4436cf 100755 (executable)
 #define TAR_NEW     '8'
 
 typedef struct _phar_entry_fp phar_entry_fp;
+typedef struct _phar_archive_data phar_archive_data;
 
 ZEND_BEGIN_MODULE_GLOBALS(phar)
        HashTable   phar_fname_map;
@@ -184,6 +185,12 @@ ZEND_BEGIN_MODULE_GLOBALS(phar)
        int         cwd_init;
        char        *openssl_privatekey;
        int         openssl_privatekey_len;
+       /* phar_get_archive cache */
+       char*       last_phar_name;
+       int         last_phar_name_len;
+       char*       last_alias;
+       int         last_alias_len;
+       phar_archive_data* last_phar;
 ZEND_END_MODULE_GLOBALS(phar)
 
 ZEND_EXTERN_MODULE_GLOBALS(phar)
@@ -226,8 +233,6 @@ enum phar_fp_type {
        PHAR_TMP
 };
 
-typedef struct _phar_archive_data phar_archive_data;
-
 /* entry for one file in a phar file */
 typedef struct _phar_entry_info {
        /* first bytes are exactly as in file */
index 2f5b1635dbc2c3a4f344b035588873ca34e0156b..06da714fcd62f0eee62c147144b7b86bc8fcea28 100755 (executable)
@@ -473,6 +473,11 @@ PHP_METHOD(Phar, mount)
                }
 carry_on2:
                if (SUCCESS != zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **)&pphar)) {
+                       if (PHAR_G(manifest_cached) && SUCCESS == zend_hash_find(&cached_phars, arch, arch_len, (void **)&pphar)) {
+                               if (SUCCESS == phar_copy_on_write(pphar)) {
+                                       goto carry_on;
+                               }
+                       }
                        zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "%s is not a phar archive, cannot mount", arch);
                        if (arch) {
                                efree(arch);
@@ -499,6 +504,11 @@ carry_on:
                return;
        } else if (SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), fname, fname_len, (void **)&pphar)) {
                goto carry_on;
+       } else if (PHAR_G(manifest_cached) && SUCCESS == zend_hash_find(&cached_phars, fname, fname_len, (void **)&pphar)) {
+               if (SUCCESS == phar_copy_on_write(pphar)) {
+                       goto carry_on;
+               }
+               goto carry_on;
        } else if (SUCCESS == phar_split_fname(path, path_len, &arch, &arch_len, &entry, &entry_len, 2, 0 TSRMLS_CC)) {
                path = entry;
                path_len = entry_len;
@@ -1334,6 +1344,10 @@ PHP_METHOD(Phar, unlinkArchive)
                return;
        }
        fname = estrndup(phar->fname, phar->fname_len);
+       /* invalidate phar cache */
+       PHAR_G(last_phar) = NULL;
+       PHAR_G(last_phar_name) = PHAR_G(last_alias) = NULL;
+
        phar_archive_delref(phar TSRMLS_CC);
        unlink(fname);
        efree(fname);
@@ -2042,6 +2056,10 @@ static zval *phar_convert_to_other(phar_archive_data *source, int convert, char
        phar_entry_info *entry, newentry;
        zval *ret;
 
+       /* invalidate phar cache */
+       PHAR_G(last_phar) = NULL;
+       PHAR_G(last_phar_name) = PHAR_G(last_alias) = NULL;
+
        phar = (phar_archive_data *) ecalloc(1, sizeof(phar_archive_data));
        /* set whole-archive compression and type from parameter */
        phar->flags = flags;
@@ -2468,6 +2486,9 @@ PHP_METHOD(Phar, setAlias)
                        "Cannot write out phar archive, phar is read-only");
                RETURN_FALSE;
        }
+       /* invalidate phar cache */
+       PHAR_G(last_phar) = NULL;
+       PHAR_G(last_phar_name) = PHAR_G(last_alias) = NULL;
 
        if (phar_obj->arc.archive->is_data) {
                zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
index 780e60533aa3ec2c393f0e6b6b25d7f00eab8e1e..30bb5a0d419e241b2fa2ddc4277603347ca0b660 100644 (file)
@@ -237,9 +237,12 @@ char *phar_find_in_include_path(char *filename, int filename_len, phar_archive_d
 #if PHP_VERSION_ID >= 50300
        char *path, *fname, *arch, *entry, *ret, *test;
        int arch_len, entry_len, fname_len;
+       phar_archive_data *phar;
 
        if (pphar) {
                *pphar = NULL;
+       } else {
+               pphar = &phar;
        }
 
        if (!zend_is_executing(TSRMLS_C) || !PHAR_G(cwd)) {
@@ -255,22 +258,24 @@ char *phar_find_in_include_path(char *filename, int filename_len, phar_archive_d
        if (*filename == '.') {
                int try_len;
 
-               if (SUCCESS != zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar) &&
-                       PHAR_G(manifest_cached) && SUCCESS != zend_hash_find(&cached_phars, arch, arch_len, (void **) &pphar)) {
+               if (FAILURE == phar_get_archive(&phar, arch, arch_len, NULL, 0, NULL TSRMLS_CC)) {
                        efree(arch);
                        return phar_save_resolve_path(filename, filename_len TSRMLS_CC);
                }
+               if (pphar) {
+                       *pphar = phar;
+               }
                try_len = filename_len;
                test = phar_fix_filepath(estrndup(filename, filename_len), &try_len, 1 TSRMLS_CC);
                if (*test == '/') {
-                       if (zend_hash_exists(&((*pphar)->manifest), test + 1, try_len - 1)) {
+                       if (zend_hash_exists(&(phar->manifest), test + 1, try_len - 1)) {
                                spprintf(&ret, 0, "phar://%s%s", arch, test);
                                efree(arch);
                                efree(test);
                                return ret;
                        }
                } else {
-                       if (zend_hash_exists(&((*pphar)->manifest), test, try_len)) {
+                       if (zend_hash_exists(&(phar->manifest), test, try_len)) {
                                spprintf(&ret, 0, "phar://%s/%s", arch, test);
                                efree(arch);
                                efree(test);
@@ -293,6 +298,9 @@ char *phar_find_in_include_path(char *filename, int filename_len, phar_archive_d
                        return ret;
                }
                zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar);
+               if (!pphar && PHAR_G(manifest_cached)) {
+                       zend_hash_find(&cached_phars, arch, arch_len, (void **) &pphar);
+               }
                efree(arch);
                efree(entry);
        }
@@ -324,7 +332,7 @@ char *phar_find_in_include_path(char *filename, int filename_len, phar_archive_d
                phar_archive_data **pphar;
                int try_len;
 
-               if (SUCCESS != (zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar))) {
+               if (FAILURE == phar_get_archive(pphar, arch, arch_len, NULL, 0, NULL TSRMLS_CC)) {
                        efree(arch);
                        goto doit;
                }
@@ -441,6 +449,9 @@ not_stream:
                                                                return estrndup(trypath, ret_len);
                                                        }
                                                        zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar);
+                                                       if (!pphar && PHAR_G(manifest_cached)) {
+                                                               zend_hash_find(&cached_phars, arch, arch_len, (void **) &pphar);
+                                                       }
                                                        efree(arch);
                                                        efree(entry);
                                                        return estrndup(trypath, ret_len);
@@ -1042,6 +1053,9 @@ int phar_free_alias(phar_archive_data *phar, char *alias, int alias_len TSRMLS_D
        if (zend_hash_del(&(PHAR_GLOBALS->phar_fname_map), phar->fname, phar->fname_len) != SUCCESS) {
                return FAILURE;
        }
+       /* invalidate phar cache */
+       PHAR_G(last_phar) = NULL;
+       PHAR_G(last_phar_name) = PHAR_G(last_alias) = NULL;
        return SUCCESS;
 }
 /* }}} */
@@ -1063,6 +1077,30 @@ int phar_get_archive(phar_archive_data **archive, char *fname, int fname_len, ch
                *error = NULL;
        }
        *archive = NULL;
+       if (PHAR_G(last_phar) && fname_len == PHAR_G(last_phar_name_len) && !memcmp(fname, PHAR_G(last_phar_name), fname_len)) {
+               *archive = PHAR_G(last_phar);
+               if (alias && alias_len) {
+                       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))) {
+                               if (error) {
+                                       spprintf(error, 0, "alias \"%s\" is already used for archive \"%s\" cannot be overloaded with \"%s\"", alias, PHAR_G(last_phar)->fname, fname);
+                               }
+                               *archive = NULL;
+                               return FAILURE;
+                       }
+                       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)) {
+                               zend_hash_del(&(PHAR_GLOBALS->phar_alias_map), PHAR_G(last_phar)->alias, PHAR_G(last_phar)->alias_len);
+                       }
+                       zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, (void*)&(*archive),   sizeof(phar_archive_data*), NULL);
+                       PHAR_G(last_alias) = alias;
+                       PHAR_G(last_alias_len) = alias_len;
+               }
+               return SUCCESS;
+       }
+       if (alias && alias_len && PHAR_G(last_phar) && alias_len == PHAR_G(last_alias_len) && !memcmp(alias, PHAR_G(last_alias), alias_len)) {
+               fd = PHAR_G(last_phar);
+               fd_ptr = &fd;
+               goto alias_success;
+       }
        if (alias && alias_len) {
                ahash = zend_inline_hash_func(alias, alias_len);
                if (SUCCESS == zend_hash_quick_find(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, ahash, (void**)&fd_ptr)) {
@@ -1078,6 +1116,12 @@ alias_success:
                                return FAILURE;
                        }
                        *archive = *fd_ptr;
+                       fd = *fd_ptr;
+                       PHAR_G(last_phar) = fd;
+                       PHAR_G(last_phar_name) = fd->fname;
+                       PHAR_G(last_phar_name_len) = fd->fname_len;
+                       PHAR_G(last_alias) = alias;
+                       PHAR_G(last_alias_len) = alias_len;
                        return SUCCESS;
                }
                if (PHAR_G(manifest_cached) && SUCCESS == zend_hash_quick_find(&cached_alias, alias, alias_len, ahash, (void **)&fd_ptr)) {
@@ -1104,6 +1148,11 @@ alias_success:
                                }
                                zend_hash_quick_add(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, ahash, (void*)&fd,   sizeof(phar_archive_data*), NULL);
                        }
+                       PHAR_G(last_phar) = fd;
+                       PHAR_G(last_phar_name) = fd->fname;
+                       PHAR_G(last_phar_name_len) = fd->fname_len;
+                       PHAR_G(last_alias) = fd->alias;
+                       PHAR_G(last_alias_len) = fd->alias_len;
                        return SUCCESS;
                }
                if (PHAR_G(manifest_cached) && SUCCESS == zend_hash_quick_find(&cached_phars, fname, fname_len, fhash, (void**)&fd_ptr)) {
@@ -1119,14 +1168,29 @@ alias_success:
                                        return FAILURE;
                                }
                        }
+                       PHAR_G(last_phar) = fd;
+                       PHAR_G(last_phar_name) = fd->fname;
+                       PHAR_G(last_phar_name_len) = fd->fname_len;
+                       PHAR_G(last_alias) = fd->alias;
+                       PHAR_G(last_alias_len) = fd->alias_len;
                        return SUCCESS;
                }
                if (SUCCESS == zend_hash_quick_find(&(PHAR_GLOBALS->phar_alias_map), save, save_len, fhash, (void**)&fd_ptr)) {
-                       *archive = *fd_ptr;
+                       fd = *archive = *fd_ptr;
+                       PHAR_G(last_phar) = fd;
+                       PHAR_G(last_phar_name) = fd->fname;
+                       PHAR_G(last_phar_name_len) = fd->fname_len;
+                       PHAR_G(last_alias) = fd->alias;
+                       PHAR_G(last_alias_len) = fd->alias_len;
                        return SUCCESS;
                }
                if (PHAR_G(manifest_cached) && SUCCESS == zend_hash_quick_find(&cached_alias, save, save_len, fhash, (void**)&fd_ptr)) {
-                       *archive = *fd_ptr;
+                       fd = *archive = *fd_ptr;
+                       PHAR_G(last_phar) = fd;
+                       PHAR_G(last_phar_name) = fd->fname;
+                       PHAR_G(last_phar_name_len) = fd->fname_len;
+                       PHAR_G(last_alias) = fd->alias;
+                       PHAR_G(last_alias_len) = fd->alias_len;
                        return SUCCESS;
                }
 
@@ -1150,6 +1214,11 @@ realpath_success:
                                zend_hash_quick_add(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, ahash, (void*)&fd,   sizeof(phar_archive_data*), NULL);
                        }
                        efree(my_realpath);
+                       PHAR_G(last_phar) = fd;
+                       PHAR_G(last_phar_name) = fd->fname;
+                       PHAR_G(last_phar_name_len) = fd->fname_len;
+                       PHAR_G(last_alias) = fd->alias;
+                       PHAR_G(last_alias_len) = fd->alias_len;
                        return SUCCESS;
                }
                if (PHAR_G(manifest_cached) && SUCCESS == zend_hash_quick_find(&cached_phars, fname, fname_len, fhash, (void**)&fd_ptr)) {
@@ -2025,6 +2094,9 @@ int phar_copy_on_write(phar_archive_data **pphar TSRMLS_DC) /* {{{ */
 
        *newpphar = *pphar;
        phar_copy_cached_phar(newpphar TSRMLS_CC);
+       /* invalidate phar cache */
+       PHAR_G(last_phar) = NULL;
+       PHAR_G(last_phar_name) = PHAR_G(last_alias) = NULL;
        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)) {
                zend_hash_del(&(PHAR_GLOBALS->phar_fname_map), (*pphar)->fname, (*pphar)->fname_len);
                return FAILURE;