summaryrefslogtreecommitdiff
path: root/TSRM
diff options
context:
space:
mode:
authorAndi Gutmans <andi@php.net>2004-10-05 00:42:25 +0000
committerAndi Gutmans <andi@php.net>2004-10-05 00:42:25 +0000
commit216853c0dbd0fb46f25b2570bb575ff9df003c1c (patch)
tree8094084c61a33f6ec4db88484b2ffc665861513a /TSRM
parent01fda447c5ad0a233a74595d92de0f9822c32cac (diff)
downloadphp-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.c156
-rw-r--r--TSRM/tsrm_virtual_cwd.h24
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