]> granicus.if.org Git - php/commitdiff
- Apply realpath() cache patch. We don't use it if we're in safe_mode and
authorAndi Gutmans <andi@php.net>
Tue, 5 Oct 2004 00:42:25 +0000 (00:42 +0000)
committerAndi Gutmans <andi@php.net>
Tue, 5 Oct 2004 00:42:25 +0000 (00:42 +0000)
- friends (which are quite slow anyway).
- If it proves to be stable I'll remove the #ifdef's in a few weeks.

TSRM/tsrm_virtual_cwd.c
TSRM/tsrm_virtual_cwd.h
main/SAPI.c
main/main.c

index d0c741faaeb0afe5ce6a10ec0562dfbc406c90f3..0f65f32bcd4a57c0b28195b8c9b0840a0b93d003 100644 (file)
@@ -60,9 +60,9 @@ MUTEX_T cwd_mutex;
 #endif
 
 #ifdef ZTS
-static ts_rsrc_id cwd_globals_id;
+ts_rsrc_id cwd_globals_id;
 #else
-static virtual_cwd_globals cwd_globals;
+virtual_cwd_globals cwd_globals;
 #endif
 
 cwd_state main_cwd_state; /* True global */
@@ -175,11 +175,31 @@ static int php_is_file_ok(const cwd_state *state)
 static void cwd_globals_ctor(virtual_cwd_globals *cwd_globals TSRMLS_DC)
 {
        CWD_STATE_COPY(&cwd_globals->cwd, &main_cwd_state);
+#ifdef REALPATH_CACHE
+       cwd_globals->realpath_cache_size = 0;
+       cwd_globals->realpath_cache_size_limit = REALPATH_CACHE_SIZE;
+       cwd_globals->realpath_cache_ttl = REALPATH_CACHE_TTL;
+       memset(cwd_globals->realpath_cache, 0, sizeof(cwd_globals->realpath_cache));
+#endif
 }
 
 static void cwd_globals_dtor(virtual_cwd_globals *cwd_globals TSRMLS_DC)
 {
        CWD_STATE_FREE(&cwd_globals->cwd);
+#ifdef REALPATH_CACHE
+       {
+               int i;
+
+               for (i = 0; i < sizeof(cwd_globals->realpath_cache)/sizeof(cwd_globals->realpath_cache[0]); i++) {
+                       realpath_cache_bucket *p = cwd_globals->realpath_cache[i];
+                       while (p != NULL) {
+                               realpath_cache_bucket *r = p;
+                               p = p->next;
+                               free(r);
+                       }
+               }
+       }
+#endif
 }
 
 static char *tsrm_strndup(const char *s, size_t length)
@@ -287,6 +307,65 @@ CWD_API char *virtual_getcwd(char *buf, size_t size TSRMLS_DC)
        return buf;
 }
 
+#ifdef REALPATH_CACHE
+static inline unsigned long realpath_cache_key(const char *path, int path_len)
+{
+  register unsigned long h;
+
+  const char *e = path + path_len;
+  for (h = 2166136261U; path < e; ) {
+    h *= 16777619;
+    h ^= *path++;
+  }
+  return h;
+}
+
+static inline void realpath_cache_add(const char *path, int path_len, const char *realpath, int realpath_len, time_t t TSRMLS_DC)
+{
+       long size = sizeof(realpath_cache_bucket) + path_len + 1 + realpath_len + 1;
+       if (CWDG(realpath_cache_size) + size <= CWDG(realpath_cache_size_limit)) {
+               realpath_cache_bucket *bucket = malloc(size);
+               unsigned long n;
+       
+               bucket->key = realpath_cache_key(path, path_len);
+               bucket->path = (char*)bucket + sizeof(realpath_cache_bucket);
+               memcpy(bucket->path, path, path_len+1);
+               bucket->path_len = path_len;
+               bucket->realpath = bucket->path + (path_len + 1);
+               memcpy(bucket->realpath, realpath, realpath_len+1);
+               bucket->realpath_len = realpath_len;
+               bucket->expires = t + CWDG(realpath_cache_ttl);
+               n = bucket->key % (sizeof(CWDG(realpath_cache)) / sizeof(CWDG(realpath_cache)[0]));
+               bucket->next = CWDG(realpath_cache)[n];
+               CWDG(realpath_cache)[n] = bucket;
+         CWDG(realpath_cache_size) += size;
+       }
+}
+
+static inline realpath_cache_bucket* realpath_cache_find(const char *path, int path_len, time_t t TSRMLS_DC)
+{
+       unsigned long key = realpath_cache_key(path, path_len);
+       unsigned long n = key % (sizeof(CWDG(realpath_cache)) / sizeof(CWDG(realpath_cache)[0]));
+       realpath_cache_bucket **bucket = &CWDG(realpath_cache)[n];
+
+       while (*bucket != NULL) {
+               if (CWDG(realpath_cache_ttl) && (*bucket)->expires < t) {
+                       realpath_cache_bucket *r = *bucket;
+                 *bucket = (*bucket)->next;
+                 CWDG(realpath_cache_size) -= sizeof(realpath_cache_bucket) + r->path_len + 1 + r->realpath_len + 1;
+                 free(r);
+               } else if (key == (*bucket)->key && path_len == (*bucket)->path_len &&
+                          memcmp(path, (*bucket)->path, path_len) == 0) {
+                       return *bucket;
+               } else {
+                       *bucket = (*bucket)->next;
+               }
+       }
+       return NULL;
+}
+#endif
+
+
 /* Resolve path relatively to state and put the real path into state */
 /* returns 0 for ok, 1 for error */
 CWD_API int virtual_file_ex(cwd_state *state, const char *path, verify_path_func verify_path, int use_realpath)
@@ -295,7 +374,7 @@ CWD_API int virtual_file_ex(cwd_state *state, const char *path, verify_path_func
        char *ptr, *path_copy;
        char *tok = NULL;
        int ptr_length;
-       cwd_state *old_state;
+       cwd_state old_state;
        int ret = 0;
        int copy_amount = -1;
        char *free_path;
@@ -305,10 +384,50 @@ CWD_API int virtual_file_ex(cwd_state *state, const char *path, verify_path_func
 #else
        char *new_path;
 #endif
+#ifdef REALPATH_CACHE
+       char orig_path[MAXPATHLEN];
+       int orig_path_len;
+       realpath_cache_bucket *bucket;
+       time_t t;
+       TSRMLS_FETCH();
+#endif
 
        if (path_length == 0) 
                return (0);
 
+#ifdef REALPATH_CACHE
+       if (use_realpath && CWDG(realpath_cache_size_limit)) {
+               if (IS_ABSOLUTE_PATH(path, path_length) || (state->cwd_length < 1)) {
+                       memcpy(orig_path, path, path_length+1);
+                       orig_path_len = path_length;
+               } else {
+                       orig_path_len = path_length + state->cwd_length + 1;
+                       if (orig_path_len+1 > MAXPATHLEN) {
+                               return 1;
+                       }
+                       memcpy(orig_path, state->cwd, state->cwd_length);
+                       orig_path[state->cwd_length] = DEFAULT_SLASH;
+                       memcpy(orig_path + state->cwd_length + 1, path, path_length + 1);
+               }
+               t = CWDG(realpath_cache_ttl)?time(NULL):0;
+               if ((bucket = realpath_cache_find(orig_path, orig_path_len, t TSRMLS_CC)) != NULL) {            
+                       int len = bucket->realpath_len;
+
+                       CWD_STATE_COPY(&old_state, state);
+                       state->cwd = (char *) realloc(state->cwd, len+1);
+                       memcpy(state->cwd, bucket->realpath, len+1);
+                       state->cwd_length = len;
+                       if (verify_path && verify_path(state)) {
+                               CWD_STATE_FREE(state);
+                               *state = old_state;
+                               return 1;
+                       } else {
+                               CWD_STATE_FREE(&old_state);
+                               return 0;
+                       }
+               }
+       }
+#endif
 #if !defined(TSRM_WIN32) && !defined(NETWARE)
        /* cwd_length can be 0 when getcwd() fails.
         * This can happen under solaris when a dir does not have read permissions
@@ -364,8 +483,7 @@ CWD_API int virtual_file_ex(cwd_state *state, const char *path, verify_path_func
 #endif
        free_path = path_copy = tsrm_strndup(path, path_length);
 
-       old_state = (cwd_state *) malloc(sizeof(cwd_state));
-       CWD_STATE_COPY(old_state, state);
+       CWD_STATE_COPY(&old_state, state);
 #if VIRTUAL_CWD_DEBUG
        fprintf(stderr,"cwd = %s path = %s\n", state->cwd, path);
 #endif
@@ -385,7 +503,7 @@ CWD_API int virtual_file_ex(cwd_state *state, const char *path, verify_path_func
                                memcpy(state->cwd, path_copy, copy_amount);
                                path_copy += copy_amount;
                        } else {
-                               memcpy(state->cwd, old_state->cwd, copy_amount);
+                               memcpy(state->cwd, old_state.cwd, copy_amount);
                        }
                }
                state->cwd[copy_amount] = '\0';
@@ -453,24 +571,28 @@ CWD_API int virtual_file_ex(cwd_state *state, const char *path, verify_path_func
                state->cwd_length = path_length;
        }
 
-       if (verify_path && verify_path(state)) {
-               CWD_STATE_FREE(state);
+#ifdef TSRM_WIN32
+       if (new_path) {
+               free(new_path);
+       }
+#endif
+       free(free_path);
 
-               *state = *old_state;
+#ifdef REALPATH_CACHE
+       if (ret == 0 && use_realpath && CWDG(realpath_cache_size_limit)) {
+               realpath_cache_add(orig_path, orig_path_len, state->cwd, state->cwd_length, t TSRMLS_CC);
+       }
+#endif
 
+       if (verify_path && verify_path(state)) {
+               CWD_STATE_FREE(state);
+               *state = old_state;
                ret = 1;
        } else {
-               CWD_STATE_FREE(old_state);
+               CWD_STATE_FREE(&old_state);
                ret = 0;
        }
        
-       free(old_state);
-#ifdef TSRM_WIN32
-       if (new_path) {
-               free(new_path);
-       }
-#endif
-       free(free_path);
 #if VIRTUAL_CWD_DEBUG
        fprintf (stderr, "virtual_file_ex() = %s\n",state->cwd);
 #endif
index bcfb9a08a7c3b1d44bc8407067ed0eef16915c3a..00daf0bb777388228b944f53addc6742b79f2222 100644 (file)
@@ -200,13 +200,37 @@ CWD_API int virtual_chown(const char *filename, uid_t owner, gid_t group TSRMLS_
 
 CWD_API int virtual_file_ex(cwd_state *state, const char *path, verify_path_func verify_path, int use_realpath);
 
+#define REALPATH_CACHE
+#define REALPATH_CACHE_TTL  (2*60) /* 2 minutes */
+#define REALPATH_CACHE_SIZE 0      /* disabled while php.ini isn't loaded */
+
+#ifdef REALPATH_CACHE
+typedef struct _realpath_cache_bucket {
+       unsigned long                  key;
+       char                          *path;
+       int                            path_len;
+       char                          *realpath;
+       int                            realpath_len;
+       time_t                         expires;
+       struct _realpath_cache_bucket *next;    
+} realpath_cache_bucket;
+#endif
+
 typedef struct _virtual_cwd_globals {
        cwd_state cwd;
+#ifdef REALPATH_CACHE
+       long                   realpath_cache_size;
+       long                   realpath_cache_size_limit;
+       long                   realpath_cache_ttl;
+       realpath_cache_bucket *realpath_cache[1024];
+#endif
 } virtual_cwd_globals;
 
 #ifdef ZTS
+extern ts_rsrc_id cwd_globals_id;
 # define CWDG(v) TSRMG(cwd_globals_id, virtual_cwd_globals *, v)
 #else
+extern virtual_cwd_globals cwd_globals;
 # define CWDG(v) (cwd_globals.v)
 #endif
 
index 34e104cea6f92000971c135c665dcefd102b4c9a..5c1dfe4373d27c2a1d8836836b8ad8823bf2b4bf 100644 (file)
@@ -79,9 +79,7 @@ SAPI_API void sapi_startup(sapi_module_struct *sf)
        sapi_globals_ctor(&sapi_globals TSRMLS_CC);
 #endif
 
-#ifdef VIRTUAL_DIR
        virtual_cwd_startup(); /* Could use shutdown to free the main cwd but it would just slow it down for CGI */
-#endif
 
 #ifdef PHP_WIN32
        tsrm_win32_startup();
@@ -93,9 +91,8 @@ SAPI_API void sapi_startup(sapi_module_struct *sf)
 SAPI_API void sapi_shutdown(void)
 {
        reentrancy_shutdown();
-#ifdef VIRTUAL_DIR
+
        virtual_cwd_shutdown();
-#endif
 
 #ifdef PHP_WIN32
        tsrm_win32_shutdown();
index 9004c37ab499f09469b7e4d729aa60942ac418cd..eeb96e18c7b3058beec4f37f310637f9974f34cd 100644 (file)
@@ -322,7 +322,10 @@ PHP_INI_BEGIN()
 
        STD_PHP_INI_BOOLEAN("allow_url_fopen",          "1",            PHP_INI_SYSTEM,         OnUpdateBool,                   allow_url_fopen,                        php_core_globals,       core_globals)
        STD_PHP_INI_BOOLEAN("always_populate_raw_post_data",            "0",            PHP_INI_SYSTEM|PHP_INI_PERDIR,          OnUpdateBool,                   always_populate_raw_post_data,                  php_core_globals,       core_globals)
-
+#ifdef REALPATH_CACHE
+       STD_PHP_INI_ENTRY("realpath_cache_size", "16K", PHP_INI_SYSTEM, OnUpdateLong, realpath_cache_size_limit, virtual_cwd_globals, cwd_globals)
+       STD_PHP_INI_ENTRY("realpath_cache_ttl", "120", PHP_INI_SYSTEM, OnUpdateLong, realpath_cache_ttl, virtual_cwd_globals, cwd_globals)
+#endif
 PHP_INI_END()
 /* }}} */
 
@@ -1386,6 +1389,11 @@ int php_module_startup(sapi_module_struct *sf, zend_module_entry *additional_mod
        REGISTER_INI_ENTRIES();
        zend_register_standard_ini_entries(TSRMLS_C);
 
+       /* Disable realpath cache if safe_mode or open_basedir are set */
+       if (PG(safe_mode) || (PG(open_basedir) && *PG(open_basedir))) {
+               CWDG(realpath_cache_size_limit) = 0;
+       }
+
        /* initialize stream wrappers registry
         * (this uses configuration parameters from php.ini)
         */