From: Pierre Joye Date: Tue, 16 Jun 2009 00:07:05 +0000 (+0000) Subject: - Windows ACL cache support, update existing tests and add a new one X-Git-Tag: php-5.3.0RC4~47 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=18d5751a9e8da170ca02ddbe06120c3993c9bf1e;p=php - Windows ACL cache support, update existing tests and add a new one --- diff --git a/TSRM/tsrm_virtual_cwd.c b/TSRM/tsrm_virtual_cwd.c index 206e31955d..41cd1ff754 100644 --- a/TSRM/tsrm_virtual_cwd.c +++ b/TSRM/tsrm_virtual_cwd.c @@ -471,6 +471,12 @@ static inline void realpath_cache_add(const char *path, int path_len, const char } bucket->realpath_len = realpath_len; bucket->is_dir = is_dir; +#ifdef PHP_WIN32 + bucket->is_rvalid = 0; + bucket->is_readable = 0; + bucket->is_wvalid = 0; + bucket->is_writable = 0; +#endif 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]; @@ -503,6 +509,12 @@ static inline realpath_cache_bucket* realpath_cache_find(const char *path, int p } /* }}} */ +CWD_API realpath_cache_bucket* realpath_cache_lookup(const char *path, int path_len, time_t t TSRMLS_DC) /* {{{ */ +{ + return realpath_cache_find(path, path_len, t TSRMLS_CC); +} +/* }}} */ + #undef LINK_MAX #define LINK_MAX 32 diff --git a/TSRM/tsrm_virtual_cwd.h b/TSRM/tsrm_virtual_cwd.h index 28e93fc7cc..8ddbee6f0f 100644 --- a/TSRM/tsrm_virtual_cwd.h +++ b/TSRM/tsrm_virtual_cwd.h @@ -210,6 +210,12 @@ typedef struct _realpath_cache_bucket { int realpath_len; int is_dir; time_t expires; +#ifdef PHP_WIN32 + unsigned char is_rvalid; + unsigned char is_readable; + unsigned char is_wvalid; + unsigned char is_writable; +#endif struct _realpath_cache_bucket *next; } realpath_cache_bucket; @@ -231,6 +237,7 @@ extern virtual_cwd_globals cwd_globals; CWD_API void realpath_cache_clean(TSRMLS_D); CWD_API void realpath_cache_del(const char *path, int path_len TSRMLS_DC); +CWD_API realpath_cache_bucket* realpath_cache_lookup(const char *path, int path_len, time_t t TSRMLS_DC); /* The actual macros to be used in programs using TSRM * If the program defines VIRTUAL_DIR it will use the diff --git a/TSRM/tsrm_win32.c b/TSRM/tsrm_win32.c index 69214d00d4..187f5e652e 100644 --- a/TSRM/tsrm_win32.c +++ b/TSRM/tsrm_win32.c @@ -32,6 +32,7 @@ #ifdef TSRM_WIN32 #include "tsrm_win32.h" +#include "tsrm_virtual_cwd.h" #ifdef ZTS static ts_rsrc_id win32_globals_id; @@ -114,6 +115,11 @@ TSRM_API int tsrm_win32_access(const char *pathname, int mode) BYTE * psec_desc = NULL; BOOL fAccess = FALSE; HANDLE process_token = NULL; + + realpath_cache_bucket * bucket = NULL; + char * real_path = NULL; + time_t t; + TSRMLS_FETCH(); if (mode == 1 /*X_OK*/) { @@ -121,24 +127,62 @@ TSRM_API int tsrm_win32_access(const char *pathname, int mode) return GetBinaryType(pathname, &type) ? 0 : -1; } else { if(access(pathname, mode)) { - return errno; + return errno; } + if(!IS_ABSOLUTE_PATH(pathname, strlen(pathname)+1)) { + real_path = (char *)malloc(MAX_PATH); + if(tsrm_realpath(pathname, real_path TSRMLS_CC) == NULL) { + goto Finished; + } + pathname = real_path; + } + + if (CWDG(realpath_cache_size_limit)) { + t = time(0); + bucket = realpath_cache_lookup(pathname, strlen(pathname), t TSRMLS_CC); + if(bucket == NULL && real_path == NULL) { + /* We used the pathname directly. Call tsrm_realpath */ + /* so that entry is created in realpath cache */ + real_path = (char *)malloc(MAX_PATH); + if(tsrm_realpath(pathname, real_path TSRMLS_CC) != NULL) { + pathname = real_path; + bucket = realpath_cache_lookup(pathname, strlen(pathname), t TSRMLS_CC); + } + } + } + + /* Do a full access check because access() will only check read-only attribute */ + if(mode == 0 || mode > 6) { + if(bucket != NULL && bucket->is_rvalid) { + fAccess = bucket->is_readable; + goto Finished; + } + desired_access = FILE_GENERIC_READ; + } else if(mode <= 2) { + if(bucket != NULL && bucket->is_wvalid) { + fAccess = bucket->is_writable; + goto Finished; + } + desired_access = FILE_GENERIC_WRITE; + } else if(mode <= 4) { + if(bucket != NULL && bucket->is_rvalid) { + fAccess = bucket->is_readable; + goto Finished; + } + desired_access = FILE_GENERIC_READ; + } else { // if(mode <= 6) + if(bucket != NULL && bucket->is_rvalid && bucket->is_wvalid) { + fAccess = bucket->is_readable & bucket->is_writable; + goto Finished; + } + desired_access = FILE_GENERIC_READ | FILE_GENERIC_WRITE; + } + if(TWG(impersonation_token) == NULL) { goto Finished; } - /* Do a full access check because access() will only check read-only attribute */ - if(mode == 0 || mode > 6) { - desired_access = FILE_GENERIC_READ; - } else if(mode <= 2) { - desired_access = FILE_GENERIC_WRITE; - } else if(mode <= 4) { - desired_access = FILE_GENERIC_READ; - } else { // if(mode <= 6) - desired_access = FILE_GENERIC_READ | FILE_GENERIC_WRITE; - } - /* Get size of security buffer. Call is expected to fail */ if(GetFileSecurity(pathname, sec_info, NULL, 0, &sec_desc_length)) { goto Finished; @@ -154,12 +198,29 @@ TSRM_API int tsrm_win32_access(const char *pathname, int mode) goto Finished; } + /* Keep the result in realpath_cache */ + if(bucket != NULL) { + if(desired_access == FILE_GENERIC_READ) { + bucket->is_rvalid = 1; + bucket->is_readable = fAccess; + } + else if(desired_access == FILE_GENERIC_WRITE) { + bucket->is_wvalid = 1; + bucket->is_writable = fAccess; + } + } + Finished: if(psec_desc != NULL) { free(psec_desc); psec_desc = NULL; } + if(real_path != NULL) { + free(real_path); + real_path = NULL; + } + if(fAccess == FALSE) { errno = EACCES; return errno; diff --git a/ext/standard/tests/file/windows_acls/bug44859.phpt b/ext/standard/tests/file/windows_acls/bug44859.phpt index 0716ee5ac4..bb22a5cd8e 100644 --- a/ext/standard/tests/file/windows_acls/bug44859.phpt +++ b/ext/standard/tests/file/windows_acls/bug44859.phpt @@ -21,6 +21,7 @@ $i = 1; $path = __DIR__ . '/a.txt'; foreach ($iteration as $perms => $exp) { create_file($path, $perms); + clearstatcache(true, $path); echo 'Iteration #' . $i++ . ': '; if (is_writable($path) == $exp) { echo "passed.\n"; @@ -36,6 +37,7 @@ $path = __DIR__ . '/adir'; $i = 1; foreach ($iteration as $perms => $exp) { create_file($path, $perms); + clearstatcache(true, $path); echo 'Iteration #' . $i++ . ': '; if (is_writable($path) == $exp) { echo "passed.\n"; diff --git a/ext/standard/tests/file/windows_acls/bug44859_2.phpt b/ext/standard/tests/file/windows_acls/bug44859_2.phpt index 8326eb473e..3cc4ed1ba1 100644 --- a/ext/standard/tests/file/windows_acls/bug44859_2.phpt +++ b/ext/standard/tests/file/windows_acls/bug44859_2.phpt @@ -21,11 +21,12 @@ $i = 1; $path = __DIR__ . '/a.txt'; foreach ($iteration as $perms => $exp) { create_file($path, $perms); + clearstatcache(true, $path); echo 'Iteration #' . $i++ . ': '; if (is_readable($path) == $exp) { echo "passed.\n"; } else { - var_dump(is_writable($path), $exp); + var_dump(is_readable($path), $exp); echo "failed.\n"; } delete_file($path); @@ -36,11 +37,12 @@ $path = __DIR__ . '/adir'; $i = 1; foreach ($iteration as $perms => $exp) { create_file($path, $perms); + clearstatcache(true, $path); echo 'Iteration #' . $i++ . ': '; if (is_readable($path) == $exp) { echo "passed.\n"; } else { - var_dump(is_writable($path), $exp); + var_dump(is_readable($path), $exp); echo "failed.\n"; } delete_file($path); diff --git a/ext/standard/tests/file/windows_acls/bug44859_4.phpt b/ext/standard/tests/file/windows_acls/bug44859_4.phpt new file mode 100644 index 0000000000..fff90662e8 --- /dev/null +++ b/ext/standard/tests/file/windows_acls/bug44859_4.phpt @@ -0,0 +1,64 @@ +--TEST-- +bug #44859 (incorrect result with NTFS ACL permissions, is_readable) +--CREDIT-- +Venkat Raman Don +--SKIPIF-- + +--FILE-- + true, + PHPT_ACL_NONE => false, + PHPT_ACL_WRITE => false, + PHPT_ACL_WRITE|PHPT_ACL_READ => true, +); + +echo "Testing file with relative path:\n"; +$i = 1; +$path = './a.txt'; +foreach ($iteration as $perms => $exp) { + create_file($path, $perms); + clearstatcache(true, $path); + echo 'Iteration #' . $i++ . ': '; + if (is_readable($path) == $exp) { + echo "passed.\n"; + } else { + var_dump(is_readable($path), $exp); + echo "failed.\n"; + } + delete_file($path); +} + +echo "Testing directory with relative path:\n"; +$path = 'adir'; +$i = 1; +foreach ($iteration as $perms => $exp) { + create_file($path, $perms); + clearstatcache(true, $path); + echo 'Iteration #' . $i++ . ': '; + if (is_readable($path) == $exp) { + echo "passed.\n"; + } else { + var_dump(is_readable($path), $exp); + echo "failed.\n"; + } + delete_file($path); +} + +?> +--EXPECT-- +Testing file with relative path: +Iteration #1: passed. +Iteration #2: passed. +Iteration #3: passed. +Iteration #4: passed. +Testing directory with relative path: +Iteration #1: passed. +Iteration #2: passed. +Iteration #3: passed. +Iteration #4: passed. diff --git a/ext/standard/tests/file/windows_acls/common.inc b/ext/standard/tests/file/windows_acls/common.inc index 6bcaf2b327..2a1adeb0a4 100644 --- a/ext/standard/tests/file/windows_acls/common.inc +++ b/ext/standard/tests/file/windows_acls/common.inc @@ -123,7 +123,6 @@ function create_file($name, $perms) { } touch($name); - $dst = realpath($name); icacls_set($name, PHPT_ACL_GRANT, $perms); }