mirror of
https://github.com/php/php-src.git
synced 2026-03-26 09:12:14 +01:00
- Windows ACL cache support, update existing tests and add a new one
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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);
|
||||
|
||||
64
ext/standard/tests/file/windows_acls/bug44859_4.phpt
Normal file
64
ext/standard/tests/file/windows_acls/bug44859_4.phpt
Normal file
@@ -0,0 +1,64 @@
|
||||
--TEST--
|
||||
bug #44859 (incorrect result with NTFS ACL permissions, is_readable)
|
||||
--CREDIT--
|
||||
Venkat Raman Don
|
||||
--SKIPIF--
|
||||
<?php
|
||||
include_once __DIR__ . '/common.inc';
|
||||
skipif();
|
||||
?>
|
||||
--FILE--
|
||||
<?php
|
||||
include_once __DIR__ . '/common.inc';
|
||||
|
||||
$iteration = array(
|
||||
PHPT_ACL_READ => 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.
|
||||
@@ -123,7 +123,6 @@ function create_file($name, $perms) {
|
||||
}
|
||||
|
||||
touch($name);
|
||||
$dst = realpath($name);
|
||||
icacls_set($name, PHPT_ACL_GRANT, $perms);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user