cvs: TSRM / tsrm_virtual_cwd.c tsrm_virtual_cwd.h tsrm_win32.c

[email protected] ("Pierre-Alain Joye") Fri, 26 Jun 2009 07:44:57 -0000
Newsgroups php.zend-engine.cvs
Message-ID <cvspajoye1246002297@cvsserver>
--pajoye1246002297
Content-Type: text/plain

pajoye		Fri Jun 26 07:44:57 2009 UTC

  Modified files:              
    /TSRM	tsrm_virtual_cwd.c tsrm_virtual_cwd.h tsrm_win32.c 
  Log:
  - MF53:
   - Windows ACL cache support, update existing tests and add a new one
   - #48535,  file_exists returns false when impersonate is used
  
--pajoye1246002297
Content-Type: text/plain
Content-Disposition: attachment; filename="pajoye-20090626074457.txt"

http://cvs.php.net/viewvc.cgi/TSRM/tsrm_virtual_cwd.c?r1=1.135&r2=1.136&diff_format=u
Index: TSRM/tsrm_virtual_cwd.c
diff -u TSRM/tsrm_virtual_cwd.c:1.135 TSRM/tsrm_virtual_cwd.c:1.136
--- TSRM/tsrm_virtual_cwd.c:1.135	Sat Apr  4 11:37:23 2009
+++ TSRM/tsrm_virtual_cwd.c	Fri Jun 26 07:44:57 2009
@@ -17,7 +17,7 @@
    +----------------------------------------------------------------------+
 */
 
-/* $Id: tsrm_virtual_cwd.c,v 1.135 2009/04/04 11:37:23 pajoye Exp $ */
+/* $Id: tsrm_virtual_cwd.c,v 1.136 2009/06/26 07:44:57 pajoye Exp $ */
 
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -35,6 +35,9 @@
 #ifdef TSRM_WIN32
 #include <io.h>
 #include "tsrm_win32.h"
+# ifndef IO_REPARSE_TAG_SYMLINK
+#  define IO_REPARSE_TAG_SYMLINK 0xA000000C
+# endif
 #endif
 
 #ifdef NETWARE
@@ -137,6 +140,42 @@
 	
 #ifdef TSRM_WIN32
 
+#ifdef CTL_CODE
+#undef CTL_CODE
+#endif
+#define CTL_CODE(DeviceType,Function,Method,Access) (((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method))
+#define FILE_DEVICE_FILE_SYSTEM 0x00000009
+#define METHOD_BUFFERED		0
+#define FILE_ANY_ACCESS 	0
+#define FSCTL_GET_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 42, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define MAXIMUM_REPARSE_DATA_BUFFER_SIZE  ( 16 * 1024 )
+
+typedef struct {
+	unsigned long  ReparseTag;
+	unsigned short ReparseDataLength;
+	unsigned short Reserved;
+	union {
+		struct {
+			unsigned short SubstituteNameOffset;
+			unsigned short SubstituteNameLength;
+			unsigned short PrintNameOffset;
+			unsigned short PrintNameLength;
+			unsigned long  Flags;
+			wchar_t        ReparseTarget[1];
+		} SymbolicLinkReparseBuffer;
+		struct {
+			unsigned short SubstituteNameOffset;
+			unsigned short SubstituteNameLength;
+			unsigned short PrintNameOffset;
+			unsigned short PrintNameLength;
+			wchar_t        ReparseTarget[1];
+		} MountPointReparseBuffer;
+		struct {
+			unsigned char  ReparseTarget[1];
+		} GenericReparseBuffer;
+	};
+} REPARSE_DATA_BUFFER;
+
 #define SECS_BETWEEN_EPOCHS (__int64)11644473600
 #define SECS_TO_100NS (__int64)10000000
 static inline time_t FileTimeToUnixTime(const FILETIME FileTime)
@@ -471,6 +510,12 @@
 		}
 		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 +548,12 @@
 }
 /* }}} */
 
+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
 
@@ -518,7 +569,8 @@
 #endif
 	realpath_cache_bucket *bucket;
 	char *tmp;
-	TSRM_ALLOCA_FLAG(use_heap);
+	TSRM_ALLOCA_FLAG(use_heap)
+	TSRM_ALLOCA_FLAG(use_heap_large)
 
 	while (1) {
 		if (len <= start) {
@@ -606,16 +658,103 @@
 			/* continue resolution anyway but don't save result in the cache */
 			save = 0;
 		}
+		
 		if (save) {
-			directory = (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
-			if (is_dir && !directory) {
-				/* not a directory */
-				FindClose(hFind);
-				return -1;
-			}
+			FindClose(hFind);
 		}
+
 		tmp = tsrm_do_alloca(len+1, use_heap);
 		memcpy(tmp, path, len+1);
+
+		if(save && (data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) {
+			/* File is a reparse point. Get the target */
+			HANDLE hLink = NULL;
+			REPARSE_DATA_BUFFER * pbuffer;
+			unsigned int retlength = 0, rname_off = 0;
+			int bufindex = 0, rname_len = 0, isabsolute = 0;
+			wchar_t * reparsetarget;
+
+			if(++(*ll) > LINK_MAX) {
+				return -1;
+			}
+
+			hLink = CreateFile(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT|FILE_FLAG_BACKUP_SEMANTICS, NULL);
+			if(hLink == INVALID_HANDLE_VALUE) {
+				return -1;
+			}
+
+			pbuffer = (REPARSE_DATA_BUFFER *)tsrm_do_alloca(MAXIMUM_REPARSE_DATA_BUFFER_SIZE, use_heap_large);
+			if(!DeviceIoControl(hLink, FSCTL_GET_REPARSE_POINT, NULL, 0, pbuffer,  MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &retlength, NULL)) {
+				tsrm_free_alloca(pbuffer, use_heap_large);
+				CloseHandle(hLink);
+				return -1;
+			}
+
+			CloseHandle(hLink);
+
+			if(pbuffer->ReparseTag == IO_REPARSE_TAG_SYMLINK) {
+				rname_len = pbuffer->SymbolicLinkReparseBuffer.PrintNameLength/2;
+				rname_off = pbuffer->SymbolicLinkReparseBuffer.PrintNameOffset/2;
+				reparsetarget = pbuffer->SymbolicLinkReparseBuffer.ReparseTarget;
+				isabsolute = (pbuffer->SymbolicLinkReparseBuffer.Flags == 0) ? 1 : 0;
+			}
+			else if(pbuffer->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) {
+				rname_len = pbuffer->MountPointReparseBuffer.PrintNameLength/2;
+				rname_off = pbuffer->MountPointReparseBuffer.PrintNameOffset/2;
+				reparsetarget = pbuffer->MountPointReparseBuffer.ReparseTarget;
+				isabsolute = 1;
+			}
+			else {
+				tsrm_free_alloca(pbuffer, use_heap_large);
+				return -1;
+			}
+
+			/* Convert wide string to narrow string */
+			for(bufindex = 0; bufindex < rname_len; bufindex++) {
+				*(path + bufindex) = (char)(reparsetarget[rname_off + bufindex]);
+			}
+
+			*(path + bufindex) = 0;
+			tsrm_free_alloca(pbuffer, use_heap_large);
+			j = bufindex;
+
+			if(isabsolute == 1) {
+				/* use_realpath is 0 in the call below coz path is absolute*/
+				j = tsrm_realpath_r(path, 0, j, ll, t, 0, is_dir, &directory TSRMLS_CC);
+				if(j < 0) {
+					tsrm_free_alloca(tmp, use_heap);
+					return -1;
+				}
+			}
+			else {
+				if(i + j >= MAXPATHLEN - 1) {
+					tsrm_free_alloca(tmp, use_heap);
+					return -1;
+				}
+
+				memmove(path+i, path, j+1);
+				memcpy(path, tmp, i-1);
+				path[i-1] = DEFAULT_SLASH;
+				j  = tsrm_realpath_r(path, start, i + j, ll, t, use_realpath, is_dir, &directory TSRMLS_CC);
+				if(j < 0) {
+					tsrm_free_alloca(tmp, use_heap);
+					return -1;
+				}
+			}
+
+			if(link_is_dir) {
+				*link_is_dir = directory;
+			}
+		}
+		else {
+			if (save) {
+				directory = (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
+				if (is_dir && !directory) {
+					/* not a directory */
+					return -1;
+				}
+			}
+
 #elif defined(NETWARE)
 		save = 0;
 		tmp = tsrm_do_alloca(len+1, use_heap);
@@ -687,19 +826,18 @@
 #ifdef TSRM_WIN32
 			if (j < 0 || j + len - i >= MAXPATHLEN-1) {
 				tsrm_free_alloca(tmp, use_heap);
-				if (save) FindClose(hFind);
 				return -1;
 			}
 			if (save) {
 				i = strlen(data.cFileName);
 				memcpy(path+j, data.cFileName, i+1);
 				j += i;
-				FindClose(hFind);
 			} else {
 				/* use the original file or directory name as it wasn't found */
 				memcpy(path+j, tmp+i, len-i+1);
 				j += (len-i);
 			}
+		}
 #else
 			if (j < 0 || j + len - i >= MAXPATHLEN-1) {
 				tsrm_free_alloca(tmp, use_heap);
http://cvs.php.net/viewvc.cgi/TSRM/tsrm_virtual_cwd.h?r1=1.71&r2=1.72&diff_format=u
Index: TSRM/tsrm_virtual_cwd.h
diff -u TSRM/tsrm_virtual_cwd.h:1.71 TSRM/tsrm_virtual_cwd.h:1.72
--- TSRM/tsrm_virtual_cwd.h:1.71	Tue Mar 10 23:39:10 2009
+++ TSRM/tsrm_virtual_cwd.h	Fri Jun 26 07:44:57 2009
@@ -17,7 +17,7 @@
    +----------------------------------------------------------------------+
 */
 
-/* $Id: tsrm_virtual_cwd.h,v 1.71 2009/03/10 23:39:10 helly Exp $ */
+/* $Id: tsrm_virtual_cwd.h,v 1.72 2009/06/26 07:44:57 pajoye Exp $ */
 
 #ifndef VIRTUAL_CWD_H
 #define VIRTUAL_CWD_H
@@ -227,6 +227,12 @@
 	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;
 
@@ -248,6 +254,7 @@
 
 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
http://cvs.php.net/viewvc.cgi/TSRM/tsrm_win32.c?r1=1.41&r2=1.42&diff_format=u
Index: TSRM/tsrm_win32.c
diff -u TSRM/tsrm_win32.c:1.41 TSRM/tsrm_win32.c:1.42
--- TSRM/tsrm_win32.c:1.41	Tue Jun  9 14:05:44 2009
+++ TSRM/tsrm_win32.c	Fri Jun 26 07:44:57 2009
@@ -16,7 +16,7 @@
    +----------------------------------------------------------------------+
 */
 
-/* $Id: tsrm_win32.c,v 1.41 2009/06/09 14:05:44 pajoye Exp $ */
+/* $Id: tsrm_win32.c,v 1.42 2009/06/26 07:44:57 pajoye Exp $ */
 
 #include <stdio.h>
 #include <fcntl.h>
@@ -33,6 +33,7 @@
 #ifdef TSRM_WIN32
 
 #include "tsrm_win32.h"
+#include "tsrm_virtual_cwd.h"
 
 #ifdef ZTS
 static ts_rsrc_id win32_globals_id;
@@ -42,12 +43,25 @@
 
 static void tsrm_win32_ctor(tsrm_win32_globals *globals TSRMLS_DC)
 {
+	HANDLE process_token = NULL;
+
 	globals->process = NULL;
 	globals->shm	 = NULL;
 	globals->process_size = 0;
 	globals->shm_size	  = 0;
 	globals->comspec = _strdup((GetVersion()<0x80000000)?"cmd.exe":"command.com");
 	globals->impersonation_token = NULL;
+
+	/* Access check requires impersonation token. Create a duplicate token. */
+	if(OpenProcessToken(GetCurrentProcess(), TOKEN_DUPLICATE | TOKEN_QUERY, &process_token)) {
+		DuplicateToken(process_token, SecurityImpersonation, &globals->impersonation_token);
+	}
+
+	/* impersonation_token will be closed when the process dies */
+	if(process_token != NULL) {
+		CloseHandle(process_token);
+		process_token = NULL;
+	}
 }
 
 static void tsrm_win32_dtor(tsrm_win32_globals *globals TSRMLS_DC)
@@ -102,6 +116,11 @@
 	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*/) {
@@ -109,18 +128,60 @@
 		return GetBinaryType(pathname, &type) ? 0 : -1;
 	} else {
 		if(access(pathname, mode)) {
-				return errno;
+			return errno;
 		}
 
-		/* Do a full access check because access() will only check read-only attribute */
-		if(mode == 0 || mode > 6) {
+		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 <= 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;
+ 		} 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;
 		}
 
 		/* Get size of security buffer. Call is expected to fail */
@@ -134,35 +195,33 @@
 			goto Finished;
 		}
 
-		if(TWG(impersonation_token) == NULL) {
-
-			if(!OpenProcessToken(GetCurrentProcess(), TOKEN_DUPLICATE | TOKEN_QUERY, &process_token)) {
-				goto Finished;
-			}
-
-			/* Access check requires impersonation token. Create a duplicate token. */
-			if(!DuplicateToken(process_token, SecurityImpersonation, &TWG(impersonation_token))) {
-				goto Finished;
-			}
-		}
-
 		if(!AccessCheck((PSECURITY_DESCRIPTOR)psec_desc, TWG(impersonation_token), desired_access, &gen_map, &privilege_set, &priv_set_length, &granted_access, &fAccess)) {
 				goto Finished;
 		}
 
-Finished:
-
-		/* impersonation_token will be closed when the process dies */
-		if(process_token != NULL) {
-			CloseHandle(process_token);
-			process_token = NULL;
+		/* 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;
@@ -326,7 +385,7 @@
 	}
 
 	fflush(process->stream);
-    fclose(process->stream);
+	fclose(process->stream);
 
 	WaitForSingleObject(process->prochnd, INFINITE);
 	GetExitCodeProcess(process->prochnd, &termstat);

--pajoye1246002297--