diff options
author | Andi Gutmans <andi@php.net> | 2004-10-05 00:42:25 +0000 |
---|---|---|
committer | Andi Gutmans <andi@php.net> | 2004-10-05 00:42:25 +0000 |
commit | 216853c0dbd0fb46f25b2570bb575ff9df003c1c (patch) | |
tree | 8094084c61a33f6ec4db88484b2ffc665861513a /TSRM | |
parent | 01fda447c5ad0a233a74595d92de0f9822c32cac (diff) | |
download | php-git-216853c0dbd0fb46f25b2570bb575ff9df003c1c.tar.gz |
- Apply realpath() cache patch. We don't use it if we're in safe_mode and
- friends (which are quite slow anyway).
- If it proves to be stable I'll remove the #ifdef's in a few weeks.
Diffstat (limited to 'TSRM')
-rw-r--r-- | TSRM/tsrm_virtual_cwd.c | 156 | ||||
-rw-r--r-- | TSRM/tsrm_virtual_cwd.h | 24 |
2 files changed, 163 insertions, 17 deletions
diff --git a/TSRM/tsrm_virtual_cwd.c b/TSRM/tsrm_virtual_cwd.c index d0c741faae..0f65f32bcd 100644 --- a/TSRM/tsrm_virtual_cwd.c +++ b/TSRM/tsrm_virtual_cwd.c @@ -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 diff --git a/TSRM/tsrm_virtual_cwd.h b/TSRM/tsrm_virtual_cwd.h index bcfb9a08a7..00daf0bb77 100644 --- a/TSRM/tsrm_virtual_cwd.h +++ b/TSRM/tsrm_virtual_cwd.h @@ -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 |