From 3d43f717720545f123b5a208f0d448e8018cc694 Mon Sep 17 00:00:00 2001 From: foobar Date: Thu, 10 Feb 2005 22:50:47 +0000 Subject: [PATCH] MFH: - Multiple fixes for nasty leaks in ZTS mode --- TSRM/TSRM.c | 99 ++++++++++-- TSRM/TSRM.h | 16 ++ TSRM/tsrm_config.nw.h | 6 +- TSRM/tsrm_config_common.h | 2 + TSRM/tsrm_nw.c | 326 ++++++++++++++++++-------------------- TSRM/tsrm_nw.h | 11 +- TSRM/tsrm_virtual_cwd.c | 260 ++++++++++++++++++++++-------- TSRM/tsrm_virtual_cwd.h | 69 ++++++-- TSRM/tsrm_win32.c | 29 +++- TSRM/tsrm_win32.h | 13 +- 10 files changed, 544 insertions(+), 287 deletions(-) diff --git a/TSRM/TSRM.c b/TSRM/TSRM.c index ac2cca9321..db47adfb1c 100644 --- a/TSRM/TSRM.c +++ b/TSRM/TSRM.c @@ -34,6 +34,7 @@ typedef struct { size_t size; ts_allocate_ctor ctor; ts_allocate_dtor dtor; + int done; } tsrm_resource_type; @@ -158,16 +159,12 @@ TSRM_API void tsrm_shutdown(void) next_p = p->next; for (j=0; jcount; j++) { - /* Disabled - calling dtors in tsrm_shutdown makes - modules registering TSRM ids to crash, if they have - dtors, since the module is unloaded before tsrm_shutdown - is called. Can be re-enabled after tsrm_free_id is - implemented. - if (resource_types_table && resource_types_table[j].dtor) { - resource_types_table[j].dtor(p->storage[j], &p->storage); + if (p->storage[j]) { + if (resource_types_table && !resource_types_table[j].done && resource_types_table[j].dtor) { + resource_types_table[j].dtor(p->storage[j], &p->storage); + } + free(p->storage[j]); } - */ - free(p->storage[j]); } free(p->storage); free(p); @@ -225,6 +222,7 @@ TSRM_API ts_rsrc_id ts_allocate_id(ts_rsrc_id *rsrc_id, size_t size, ts_allocate resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].size = size; resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].ctor = ctor; resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].dtor = dtor; + resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].done = 0; /* enlarge the arrays for the already active threads */ for (i=0; istorage)); } for (i=0; istorage[i] = (void *) malloc(resource_types_table[i].size); - if (resource_types_table[i].ctor) { - resource_types_table[i].ctor((*thread_resources_ptr)->storage[i], &(*thread_resources_ptr)->storage); + if (resource_types_table[i].done) { + (*thread_resources_ptr)->storage[i] = NULL; + } else + { + (*thread_resources_ptr)->storage[i] = (void *) malloc(resource_types_table[i].size); + if (resource_types_table[i].ctor) { + resource_types_table[i].ctor((*thread_resources_ptr)->storage[i], &(*thread_resources_ptr)->storage); + } } } @@ -300,6 +303,15 @@ TSRM_API void *ts_resource_ex(ts_rsrc_id id, THREAD_T *th_id) int hash_value; tsrm_tls_entry *thread_resources; +#ifdef NETWARE + /* The below if loop is added for NetWare to fix an abend while unloading PHP + * when an Apache unload command is issued on the system console. + * While exiting from PHP, at the end for some reason, this function is called + * with tsrm_tls_table = NULL. When this happened, the server abends when + * tsrm_tls_table is accessed since it is NULL. + */ + if(tsrm_tls_table) { +#endif if (!th_id) { #if defined(PTHREADS) /* Fast path for looking up the resources for the current @@ -362,6 +374,9 @@ TSRM_API void *ts_resource_ex(ts_rsrc_id id, THREAD_T *th_id) * changes to the structure as we read it. */ TSRM_SAFE_RETURN_RSRC(thread_resources->storage, id, thread_resources->count); +#ifdef NETWARE + } /* if(tsrm_tls_table) */ +#endif } @@ -414,6 +429,34 @@ void ts_free_thread(void) /* deallocates all occurrences of a given id */ void ts_free_id(ts_rsrc_id id) { + int i; + int j = TSRM_UNSHUFFLE_RSRC_ID(id); + + tsrm_mutex_lock(tsmm_mutex); + + TSRM_ERROR((TSRM_ERROR_LEVEL_CORE, "Freeing resource id %d", id)); + + if (tsrm_tls_table) { + for (i=0; icount > j && p->storage[j]) { + if (resource_types_table && resource_types_table[j].dtor) { + resource_types_table[j].dtor(p->storage[j], &p->storage); + } + free(p->storage[j]); + p->storage[j] = NULL; + } + p = p->next; + } + } + } + resource_types_table[j].done = 1; + + tsrm_mutex_unlock(tsmm_mutex); + + TSRM_ERROR((TSRM_ERROR_LEVEL_CORE, "Successfully freed resource id %d", id)); } @@ -429,7 +472,12 @@ TSRM_API THREAD_T tsrm_thread_id(void) #ifdef TSRM_WIN32 return GetCurrentThreadId(); #elif defined(NETWARE) - return NXThreadGetId(); + /* There seems to be some problem with the LibC call: NXThreadGetId(). + * Due to this, the PHPMyAdmin application is abending in PHP calls. + * Used the call, kCurrentThread instead and it works fine. + */ +/* return NXThreadGetId(); */ + return kCurrentThread(); #elif defined(GNUPTH) return pth_self(); #elif defined(PTHREADS) @@ -451,16 +499,23 @@ TSRM_API MUTEX_T tsrm_mutex_alloc(void) { MUTEX_T mutexp; #ifdef NETWARE - long flags = 0; /* Don't require NX_MUTEX_RECURSIVE, I guess */ +#ifndef USE_MPK + /* To use the Recursive Mutex Locking of LibC */ + long flags = NX_MUTEX_RECURSIVE; NXHierarchy_t order = 0; NX_LOCK_INFO_ALLOC (lockInfo, "PHP-TSRM", 0); -#endif +#endif +#endif #ifdef TSRM_WIN32 mutexp = malloc(sizeof(CRITICAL_SECTION)); InitializeCriticalSection(mutexp); #elif defined(NETWARE) - mutexp = NXMutexAlloc(flags, order, &lockInfo); /* return value ignored for now */ +#ifdef USE_MPK + mutexp = kMutexAlloc((BYTE*)"PHP-TSRM"); +#else + mutexp = NXMutexAlloc(flags, order, &lockInfo); +#endif #elif defined(GNUPTH) mutexp = (MUTEX_T) malloc(sizeof(*mutexp)); pth_mutex_init(mutexp); @@ -493,7 +548,11 @@ TSRM_API void tsrm_mutex_free(MUTEX_T mutexp) DeleteCriticalSection(mutexp); free(mutexp); #elif defined(NETWARE) +#ifdef USE_MPK + kMutexFree(mutexp); +#else NXMutexFree(mutexp); +#endif #elif defined(GNUPTH) free(mutexp); #elif defined(PTHREADS) @@ -524,7 +583,11 @@ TSRM_API int tsrm_mutex_lock(MUTEX_T mutexp) EnterCriticalSection(mutexp); return 1; #elif defined(NETWARE) +#ifdef USE_MPK + return kMutexLock(mutexp); +#else return NXLock(mutexp); +#endif #elif defined(GNUPTH) return pth_mutex_acquire(mutexp, 0, NULL); #elif defined(PTHREADS) @@ -551,7 +614,11 @@ TSRM_API int tsrm_mutex_unlock(MUTEX_T mutexp) LeaveCriticalSection(mutexp); return 1; #elif defined(NETWARE) +#ifdef USE_MPK + return kMutexUnlock(mutexp); +#else return NXUnlock(mutexp); +#endif #elif defined(GNUPTH) return pth_mutex_release(mutexp); #elif defined(PTHREADS) diff --git a/TSRM/TSRM.h b/TSRM/TSRM.h index 46f9702bd2..d33240fa1e 100644 --- a/TSRM/TSRM.h +++ b/TSRM/TSRM.h @@ -37,10 +37,18 @@ #ifdef ZTS #ifdef TSRM_WIN32 +# ifndef TSRM_INCLUDE_FULL_WINDOWS_HEADERS +# define WIN32_LEAN_AND_MEAN +# endif # include +# include #elif defined(NETWARE) # include +#ifdef USE_MPK +# include +#else # include +#endif #elif defined(GNUPTH) # include #elif defined(PTHREADS) @@ -60,7 +68,11 @@ typedef int ts_rsrc_id; # define MUTEX_T CRITICAL_SECTION * #elif defined(NETWARE) # define THREAD_T NXThreadId_t +#ifdef USE_MPK +# define MUTEX_T MUTEX +#else # define MUTEX_T NXMutex_t * +#endif #elif defined(GNUPTH) # define THREAD_T pth_t # define MUTEX_T pth_mutex_t * @@ -138,6 +150,8 @@ TSRM_API void *tsrm_set_new_thread_end_handler(tsrm_thread_end_func_t new_thread #define TSRM_UNSHUFFLE_RSRC_ID(rsrc_id) ((rsrc_id)-1) #define TSRMLS_FETCH() void ***tsrm_ls = (void ***) ts_resource_ex(0, NULL) +#define TSRMLS_FETCH_FROM_CTX(ctx) void ***tsrm_ls = (void ***) ctx +#define TSRMLS_SET_CTX(ctx) (void ***) ctx = tsrm_ls #define TSRMG(id, type, element) (((type) (*((void ***) tsrm_ls))[TSRM_UNSHUFFLE_RSRC_ID(id)])->element) #define TSRMLS_D void ***tsrm_ls #define TSRMLS_DC , TSRMLS_D @@ -151,6 +165,8 @@ TSRM_API void *tsrm_set_new_thread_end_handler(tsrm_thread_end_func_t new_thread #else /* non ZTS */ #define TSRMLS_FETCH() +#define TSRMLS_FETCH_FROM_CTX(ctx) +#define TSRMLS_SET_CTX(ctx) #define TSRMLS_D void #define TSRMLS_DC #define TSRMLS_C diff --git a/TSRM/tsrm_config.nw.h b/TSRM/tsrm_config.nw.h index 0681852c7d..14fcc19ab2 100644 --- a/TSRM/tsrm_config.nw.h +++ b/TSRM/tsrm_config.nw.h @@ -3,7 +3,9 @@ #define HAVE_UTIME 1 -/* Though we have alloca(), this seems to be causing some problem with the stack pointer -- hence not using it */ -/* #define HAVE_ALLOCA 1 */ +/* Though we have alloca(), this seems to be causing some problem + * with the stack pointer. Hence not using it + */ +/*#define HAVE_ALLOCA 1*/ #endif diff --git a/TSRM/tsrm_config_common.h b/TSRM/tsrm_config_common.h index 23dc9bfd79..a029bfaa96 100644 --- a/TSRM/tsrm_config_common.h +++ b/TSRM/tsrm_config_common.h @@ -25,7 +25,9 @@ #pragma alloca # else # ifndef alloca /* predefined by HP cc +Olibcalls */ +# ifndef NETWARE char *alloca (); +# endif # endif # endif # endif diff --git a/TSRM/tsrm_nw.c b/TSRM/tsrm_nw.c index 3559b783a8..442e096b23 100644 --- a/TSRM/tsrm_nw.c +++ b/TSRM/tsrm_nw.c @@ -1,18 +1,19 @@ /* +----------------------------------------------------------------------+ - | PHP Version 4 | + | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2003 The PHP Group | + | Copyright (c) 1997-2004 The PHP Group | +----------------------------------------------------------------------+ - | This source file is subject to version 2.02 of the PHP license, | + | This source file is subject to version 3.0 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | - | available at through the world-wide-web at | - | http://www.php.net/license/2_02.txt. | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_0.txt. | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Authors: Venkat Raghavan S | + | Anantha Kesari H Y | +----------------------------------------------------------------------+ */ @@ -39,8 +40,9 @@ #include "mktemp.h" -/* strtok() call in LibC is abending when used in a different address space -- hence using - PHP's version itself for now : Venkat (30/4/02) */ +/* strtok() call in LibC is abending when used in a different address space + * -- hence using PHP's version itself for now + */ #include "tsrm_strtok_r.h" #define tsrm_strtok_r(a,b,c) strtok((a),(b)) @@ -50,211 +52,189 @@ TSRM_API FILE* popen(const char *commandline, const char *type) { - char *command = NULL, *argv[MAX_ARGS] = {'\0'}, **env = NULL; + char *command = NULL, *argv[MAX_ARGS] = {'\0'}, **env = NULL; char *tempName = "sys:/php/temp/phpXXXXXX.tmp"; - char *filePath = NULL; - char *ptr = NULL; - int ptrLen = 0, argc = 0, i = 0, envCount = 0, err = 0; + char *filePath = NULL; + char *ptr = NULL; + int ptrLen = 0, argc = 0, i = 0, envCount = 0, err = 0; FILE *stream = NULL; #if defined(USE_PIPE_OPEN) || defined(USE_MKFIFO) - int pipe_handle; - int mode = O_RDONLY; + int pipe_handle; + int mode = O_RDONLY; #else - NXHandle_t pipe_handle; - NXMode_t mode = NX_O_RDONLY; + NXHandle_t pipe_handle; + NXMode_t mode = NX_O_RDONLY; #endif - NXExecEnvSpec_t envSpec; - NXNameSpec_t nameSpec; - NXVmId_t newVM = 0; + NXExecEnvSpec_t envSpec; + NXNameSpec_t nameSpec; + NXVmId_t newVM = 0; - /* Check for validity of input parameters */ - if (!commandline || !type) - return NULL; + /* Check for validity of input parameters */ + if (!commandline || !type) + return NULL; - /* Get temporary file name */ - filePath = mktemp(tempName); -/*consoleprintf ("PHP | popen: file path = %s, mode = %s\n", filePath, type);*/ + /* Get temporary file name */ + filePath = mktemp(tempName); if (!filePath) return NULL; - /* Set pipe mode according to type -- for now allow only "r" or "w" */ - if (strcmp(type, "r") == 0) + /* Set pipe mode according to type -- for now allow only "r" or "w" */ + if (strcmp(type, "r") == 0) #if defined(USE_PIPE_OPEN) || defined(USE_MKFIFO) - mode = O_RDONLY; + mode = O_RDONLY; #else - mode = NX_O_RDONLY; + mode = NX_O_RDONLY; #endif - else if (strcmp(type, "w") == 0) + else if (strcmp(type, "w") == 0) #if defined(USE_PIPE_OPEN) || defined(USE_MKFIFO) - mode = O_WRONLY; + mode = O_WRONLY; #else - mode = NX_O_WRONLY; + mode = NX_O_WRONLY; #endif - else - return NULL; + else + return NULL; #ifdef USE_PIPE_OPEN - pipe_handle = pipe_open(filePath, mode); -/*consoleprintf ("PHP | popen: pipe_open() returned %d\n", pipe_handle);*/ - if (pipe_handle == -1) - return NULL; + pipe_handle = pipe_open(filePath, mode); + if (pipe_handle == -1) + return NULL; #elif defined(USE_MKFIFO) - pipe_handle = mkfifo(filePath, mode); -consoleprintf ("PHP | popen: mkfifo() returned %d\n", pipe_handle); - if (pipe_handle == -1) - return NULL; + pipe_handle = mkfifo(filePath, mode); + if (pipe_handle == -1) + return NULL; #else - /* - - NetWare doesn't require first parameter - - Allowing LibC to choose the buffer size for now - */ - err = NXFifoOpen(0, filePath, mode, 0, &pipe_handle); -/*consoleprintf ("PHP | popen: NXFifoOpen() returned %d\n", err);*/ - if (err) - return NULL; + /* - NetWare doesn't require first parameter + * - Allowing LibC to choose the buffer size for now + */ + err = NXFifoOpen(0, filePath, mode, 0, &pipe_handle); + if (err) + return NULL; #endif - /* Copy the environment variables in preparation for the spawn call */ - - envCount = NXGetEnvCount() + 1; /* add one for NULL */ - env = (char**)NXMemAlloc(sizeof(char*) * envCount, 0); - if (!env) - return NULL; - - err = NXCopyEnv(env, envCount); -consoleprintf ("PHP | popen: NXCopyEnv() returned %d\n", err); - if (err) - { - NXMemFree (env); - return NULL; - } - - /* Separate commandline string into words */ -consoleprintf ("PHP | popen: commandline = %s\n", commandline); - ptr = tsrm_strtok_r((char*)commandline, WHITESPACE, NULL); - ptrLen = strlen(ptr); - - command = (char*)malloc(ptrLen + 1); - if (!command) - { - NXMemFree (env); - return NULL; - } - - strcpy (command, ptr); - - ptr = tsrm_strtok_r(NULL, WHITESPACE, NULL); - while (ptr && (argc < MAX_ARGS)) - { - ptrLen = strlen(ptr); - - argv[argc] = (char*)malloc(ptrLen + 1); - if (!argv[argc]) - { - NXMemFree (env); - - if (command) - free (command); - - for (i = 0; i < argc; i++) - { - if (argv[i]) - free (argv[i]); - } - - return NULL; - } - - strcpy (argv[argc], ptr); - - argc++; - - ptr = tsrm_strtok_r(NULL, WHITESPACE, NULL); - } -consoleprintf ("PHP | popen: commandline string parsed into tokens\n"); - /* Setup the execution environment and spawn new process */ - - envSpec.esFlags = 0; /* Not used */ - envSpec.esArgc = argc; - envSpec.esArgv = (void**)argv; - envSpec.esEnv = (void**)env; - - envSpec.esStdin.ssType = - envSpec.esStdout.ssType = NX_OBJ_FIFO; - envSpec.esStderr.ssType = NX_OBJ_FILE; + /* Copy the environment variables in preparation for the spawn call */ + envCount = NXGetEnvCount() + 1; /* add one for NULL */ + env = (char **) NXMemAlloc(sizeof(char *) * envCount, 0); + if (!env) + return NULL; + + err = NXCopyEnv(env, envCount); + if (err) { + NXMemFree (env); + return NULL; + } + + /* Separate commandline string into words */ + ptr = tsrm_strtok_r((char*)commandline, WHITESPACE, NULL); + ptrLen = strlen(ptr); + + command = (char*)malloc(ptrLen + 1); + if (!command) { + NXMemFree (env); + return NULL; + } + + strcpy (command, ptr); + + ptr = tsrm_strtok_r(NULL, WHITESPACE, NULL); + while (ptr && (argc < MAX_ARGS)) { + ptrLen = strlen(ptr); + + argv[argc] = (char*)malloc(ptrLen + 1); + if (!argv[argc]) { + NXMemFree (env); + if (command) + free (command); + + for (i = 0; i < argc; i++) { + if (argv[i]) + free (argv[i]); + } + + return NULL; + } + + strcpy (argv[argc], ptr); + argc++; + ptr = tsrm_strtok_r(NULL, WHITESPACE, NULL); + } + + /* Setup the execution environment and spawn new process */ + envSpec.esFlags = 0; /* Not used */ + envSpec.esArgc = argc; + envSpec.esArgv = (void **) argv; + envSpec.esEnv = (void **) env; + +/* envSpec.esStdin.ssType = */ + envSpec.esStdout.ssType = NX_OBJ_FIFO; + envSpec.esStderr.ssType = NX_OBJ_FILE; + + /* 'ssHandle' is not a struct/union/class member */ /* - envSpec.esStdin.ssHandle = - envSpec.esStdout.ssHandle = - envSpec.esStderr.ssHandle = -1; + envSpec.esStdin.ssHandle = + envSpec.esStdout.ssHandle = + envSpec.esStderr.ssHandle = -1; */ - envSpec.esStdin.ssPathCtx = - envSpec.esStdout.ssPathCtx = - envSpec.esStderr.ssPathCtx = NULL; + envSpec.esStdin.ssPathCtx = NULL; + envSpec.esStdout.ssPathCtx = NULL; + envSpec.esStderr.ssPathCtx = NULL; #if defined(USE_PIPE_OPEN) || defined(USE_MKFIFO) - if (mode == O_RDONLY) + if (mode == O_RDONLY) { #else - if (mode == NX_O_RDONLY) + if (mode == NX_O_RDONLY) { #endif - { - envSpec.esStdin.ssPath = filePath; - envSpec.esStdout.ssPath = stdout; - } - else /* Write Only */ - { - envSpec.esStdin.ssPath = stdin; - envSpec.esStdout.ssPath = filePath; - } - - envSpec.esStderr.ssPath = stdout; - - nameSpec.ssType = NX_OBJ_FIFO; -/* nameSpec.ssHandle = 0; */ /* Not used */ - nameSpec.ssPathCtx = NULL; /* Not used */ - nameSpec.ssPath = argv[0]; -consoleprintf ("PHP | popen: environment setup\n"); - err = NXVmSpawn(&nameSpec, &envSpec, 0, &newVM); -consoleprintf ("PHP | popen: NXVmSpawn() returned %d\n", err); - if (!err) - /* Get file pointer corresponding to the pipe (file) opened */ - stream = fdopen(pipe_handle, type); - - /* Clean-up */ - - if (env) - NXMemFree (env); - - if (pipe_handle) + envSpec.esStdin.ssPath = filePath; + envSpec.esStdout.ssPath = stdout; + } else { /* Write Only */ + envSpec.esStdin.ssPath = stdin; + envSpec.esStdout.ssPath = filePath; + } + + envSpec.esStderr.ssPath = stdout; + + nameSpec.ssType = NX_OBJ_FIFO; +/* nameSpec.ssHandle = 0; */ /* 'ssHandle' is not a struct/union/class member */ + nameSpec.ssPathCtx = NULL; /* Not used */ + nameSpec.ssPath = argv[0]; + err = NXVmSpawn(&nameSpec, &envSpec, 0, &newVM); + if (!err) + /* Get file pointer corresponding to the pipe (file) opened */ + stream = fdopen(pipe_handle, type); + + /* Clean-up */ + if (env) + NXMemFree (env); + + if (pipe_handle) #if defined(USE_PIPE_OPEN) || defined(USE_MKFIFO) - close(pipe_handle); + close(pipe_handle); #else - NXClose(pipe_handle); + NXClose(pipe_handle); #endif - if (command) - free (command); + if (command) + free (command); - for (i = 0; i < argc; i++) - { - if (argv[i]) - free (argv[i]); - } -consoleprintf ("PHP | popen: all clean-up done, returning...\n"); - return stream; + for (i = 0; i < argc; i++) { + if (argv[i]) + free (argv[i]); + } + + return stream; } TSRM_API int pclose(FILE* stream) { - int err = 0; - NXHandle_t fd = 0; + int err = 0; + NXHandle_t fd = 0; - /* Get the process associated with this pipe (file) handle and terminate it */ - fd = fileno(stream); - NXClose (fd); + /* Get the process associated with this pipe (file) handle and terminate it */ + fd = fileno(stream); + NXClose (fd); - err = fclose(stream); + err = fclose(stream); - return err; + return err; } -#endif +#endif /* NETWARE */ diff --git a/TSRM/tsrm_nw.h b/TSRM/tsrm_nw.h index e5ba62b8aa..24188d56a7 100644 --- a/TSRM/tsrm_nw.h +++ b/TSRM/tsrm_nw.h @@ -1,18 +1,19 @@ /* +----------------------------------------------------------------------+ - | PHP Version 4 | + | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2003 The PHP Group | + | Copyright (c) 1997-2004 The PHP Group | +----------------------------------------------------------------------+ - | This source file is subject to version 2.02 of the PHP license, | + | This source file is subject to version 3.0 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | - | available at through the world-wide-web at | - | http://www.php.net/license/2_02.txt. | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_0.txt. | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Authors: Venkat Raghavan S | + | Anantha Kesari H Y | +----------------------------------------------------------------------+ */ diff --git a/TSRM/tsrm_virtual_cwd.c b/TSRM/tsrm_virtual_cwd.c index 3c8ba90d37..6ad810113f 100644 --- a/TSRM/tsrm_virtual_cwd.c +++ b/TSRM/tsrm_virtual_cwd.c @@ -1,13 +1,13 @@ /* +----------------------------------------------------------------------+ - | PHP Version 4 | + | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2003 The PHP Group | + | Copyright (c) 1997-2004 The PHP Group | +----------------------------------------------------------------------+ - | This source file is subject to version 2.02 of the PHP license, | + | This source file is subject to version 3.0 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | - | available at through the world-wide-web at | - | http://www.php.net/license/2_02.txt. | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_0.txt. | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | @@ -27,6 +27,7 @@ #include #include #include +#include #include "tsrm_virtual_cwd.h" #include "tsrm_strtok_r.h" @@ -34,11 +35,11 @@ #ifdef TSRM_WIN32 #include #include "tsrm_win32.h" -#endif - -#ifdef NETWARE -/*#include "pipe.h"*/ -#include "tsrm_nw.h" +# if HAVE_NEWAPIS_H +# define WANT_GETLONGPATHNAME_WRAPPER +# define COMPILE_NEWAPIS_STUBS +# include +# endif #endif #ifndef HAVE_REALPATH @@ -49,15 +50,15 @@ #include "TSRM.h" -/* Only need mutex for popen() in Windows and NetWare, because it doesn't chdir() on UNIX */ +/* Only need mutex for popen() in Windows and NetWare because it doesn't chdir() on UNIX */ #if (defined(TSRM_WIN32) || defined(NETWARE)) && defined(ZTS) 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 */ @@ -137,15 +138,9 @@ static int php_check_dots(const char *element, int n) static int php_is_dir_ok(const cwd_state *state) { -#if !(defined(NETWARE) && defined(CLIB_STAT_PATCH)) struct stat buf; if (stat(state->cwd, &buf) == 0 && S_ISDIR(buf.st_mode)) -#else - struct stat_libc buf; - - if (stat(state->cwd, (struct stat*)(&buf)) == 0 && S_ISDIR(buf.st_mode)) -#endif return (0); return (1); @@ -153,15 +148,9 @@ static int php_is_dir_ok(const cwd_state *state) static int php_is_file_ok(const cwd_state *state) { -#if !(defined(NETWARE) && defined(CLIB_STAT_PATCH)) struct stat buf; if (stat(state->cwd, &buf) == 0 && S_ISREG(buf.st_mode)) -#else - struct stat_libc buf; - - if (stat(state->cwd, (struct stat*)(&buf)) == 0 && S_ISREG(buf.st_mode)) -#endif return (0); return (1); @@ -170,11 +159,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) @@ -210,7 +219,7 @@ CWD_API void virtual_cwd_startup(void) cwd_globals_ctor(&cwd_globals TSRMLS_CC); #endif -#if defined(TSRM_WIN32) && defined(ZTS) +#if (defined(TSRM_WIN32) || defined(NETWARE)) && defined(ZTS) cwd_mutex = tsrm_mutex_alloc(); #endif } @@ -220,7 +229,7 @@ CWD_API void virtual_cwd_shutdown(void) #ifndef ZTS cwd_globals_dtor(&cwd_globals TSRMLS_CC); #endif -#if defined(TSRM_WIN32) && defined(ZTS) +#if (defined(TSRM_WIN32) || defined(NETWARE)) && defined(ZTS) tsrm_mutex_free(cwd_mutex); #endif @@ -282,6 +291,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) @@ -290,13 +358,22 @@ 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; unsigned char is_absolute = 0; #ifndef TSRM_WIN32 char resolved_path[MAXPATHLEN]; +#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) @@ -304,6 +381,39 @@ CWD_API int virtual_file_ex(cwd_state *state, const char *path, verify_path_func if (path_length >= MAXPATHLEN) return (1); +#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 >= 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 @@ -341,18 +451,40 @@ CWD_API int virtual_file_ex(cwd_state *state, const char *path, verify_path_func path = resolved_path; path_length = strlen(path); } else { - /* disable for now + /* disable for now free(tmp); return 1; */ } } free(tmp); } +#endif +#if defined(TSRM_WIN32) + { + char *dummy = NULL; + int new_path_length; + + new_path_length = GetLongPathName(path, dummy, 0) + 1; + if (new_path_length == 0) { + return 1; + } + new_path = (char *) malloc(new_path_length); + if (!new_path) { + return 1; + } + + if (GetLongPathName(path, new_path, new_path_length) != 0) { + path = new_path; + path_length = new_path_length; + } else { + free(new_path); + new_path = NULL; + } + } #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 @@ -360,9 +492,6 @@ CWD_API int virtual_file_ex(cwd_state *state, const char *path, verify_path_func copy_amount = COPY_WHEN_ABSOLUTE(path_copy); is_absolute = 1; #ifdef TSRM_WIN32 - } else if (IS_UNC_PATH(path_copy, path_length)) { - copy_amount = 2; - is_absolute = 1; } else if (IS_SLASH(path_copy[0])) { copy_amount = 2; #endif @@ -375,7 +504,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'; @@ -418,8 +547,19 @@ CWD_API int virtual_file_ex(cwd_state *state, const char *path, verify_path_func state->cwd[state->cwd_length++] = DEFAULT_SLASH; } #elif defined(NETWARE) - /* If the token is a volume name, it will have colon at the end -- so, no slash before it */ - if (ptr[ptr_length-1] != ':') { + /* + Below code keeps appending to state->cwd a File system seperator + cases where this appending should not happen is given below, + a) sys: should just be left as it is + b) sys:system should just be left as it is, + Colon is allowed only in the first token as volume names alone can have the : in their names. + Files and Directories cannot have : in their names + So the check goes like this, + For second token and above simply append the DEFAULT_SLASH to the state->cwd. + For first token check for the existence of : + if it exists don't append the DEFAULT_SLASH to the state->cwd. + */ + if(((state->cwd_length == 0) && (strchr(ptr, ':') == NULL)) || (state->cwd_length > 0)) { state->cwd[state->cwd_length++] = DEFAULT_SLASH; } #else @@ -443,20 +583,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 (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); - - free(free_path); #if VIRTUAL_CWD_DEBUG fprintf (stderr, "virtual_file_ex() = %s\n",state->cwd); #endif @@ -559,7 +707,6 @@ CWD_API FILE *virtual_fopen(const char *path, const char *mode TSRMLS_DC) return f; } -#if !defined(TSRM_WIN32) CWD_API int virtual_access(const char *pathname, int mode TSRMLS_DC) { cwd_state new_state; @@ -568,13 +715,16 @@ CWD_API int virtual_access(const char *pathname, int mode TSRMLS_DC) CWD_STATE_COPY(&new_state, &CWDG(cwd)); virtual_file_ex(&new_state, pathname, NULL, 1); +#if defined(TSRM_WIN32) + ret = tsrm_win32_access(new_state.cwd, mode); +#else ret = access(new_state.cwd, mode); +#endif CWD_STATE_FREE(&new_state); return ret; } -#endif #if HAVE_UTIME @@ -683,7 +833,6 @@ CWD_API int virtual_rename(char *oldname, char *newname TSRMLS_DC) return retval; } -#if !(defined(NETWARE) && defined(CLIB_STAT_PATCH)) CWD_API int virtual_stat(const char *path, struct stat *buf TSRMLS_DC) { cwd_state new_state; @@ -697,21 +846,6 @@ CWD_API int virtual_stat(const char *path, struct stat *buf TSRMLS_DC) CWD_STATE_FREE(&new_state); return retval; } -#else -CWD_API int virtual_stat(const char *path, struct stat_libc *buf TSRMLS_DC) -{ - cwd_state new_state; - int retval; - - CWD_STATE_COPY(&new_state, &CWDG(cwd)); - virtual_file_ex(&new_state, path, NULL, 1); - - retval = stat(new_state.cwd, (struct stat*)buf); - - CWD_STATE_FREE(&new_state); - return retval; -} -#endif #if !defined(TSRM_WIN32) && !defined(NETWARE) CWD_API int virtual_lstat(const char *path, struct stat *buf TSRMLS_DC) @@ -852,7 +986,7 @@ CWD_API FILE *virtual_popen(const char *command, const char *type TSRMLS_DC) dir_length = CWDG(cwd).cwd_length; dir = CWDG(cwd).cwd; - ptr = command_line = (char *) malloc(command_length + sizeof("cd '' ; ") + dir_length +extra+1+1); + ptr = command_line = (char *) malloc(command_length + sizeof("cd '' ; ") + dir_length + extra+1+1); if (!command_line) { return NULL; } diff --git a/TSRM/tsrm_virtual_cwd.h b/TSRM/tsrm_virtual_cwd.h index 0a05cf8016..bc06a21c64 100644 --- a/TSRM/tsrm_virtual_cwd.h +++ b/TSRM/tsrm_virtual_cwd.h @@ -1,13 +1,13 @@ /* +----------------------------------------------------------------------+ - | PHP Version 4 | + | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2003 The PHP Group | + | Copyright (c) 1997-2004 The PHP Group | +----------------------------------------------------------------------+ - | This source file is subject to version 2.02 of the PHP license, | + | This source file is subject to version 3.0 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | - | available at through the world-wide-web at | - | http://www.php.net/license/2_02.txt. | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_0.txt. | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | @@ -57,9 +57,8 @@ typedef unsigned short mode_t; #define IS_SLASH_P(c) (*(c) == '/' || \ (*(c) == '\\' && !IsDBCSLeadByte(*(c-1)))) -/* COPY_WHEN_ABSOLUTE also takes path as argument because netware needs it - * to account for volume name that is unique to NetWare absolute paths - */ +/* COPY_WHEN_ABSOLUTE is 2 under Win32 because by chance both regular absolute paths + in the file system and UNC paths need copying of two characters */ #define COPY_WHEN_ABSOLUTE(path) 2 #define IS_UNC_PATH(path, len) \ (len >= 2 && IS_SLASH(path[0]) && IS_SLASH(path[1])) @@ -71,13 +70,15 @@ typedef unsigned short mode_t; #include #endif -#define DEFAULT_SLASH '/' +#define DEFAULT_SLASH '\\' #define DEFAULT_DIR_SEPARATOR ';' #define IS_SLASH(c) ((c) == '/' || (c) == '\\') +#define IS_SLASH_P(c) IS_SLASH(*(c)) #define COPY_WHEN_ABSOLUTE(path) \ (strchr(path, ':') - path + 1) /* Take the volume name which ends with a colon */ +/* Colon indicates volume name, either first character should be forward slash or backward slash */ #define IS_ABSOLUTE_PATH(path, len) \ - (strchr(path, ':') != NULL) /* Colon indicates volume name */ + ((strchr(path, ':') != NULL) || ((len >= 1) && ((path[0] == '/') || (path[0] == '\\')))) #else #ifdef HAVE_DIRENT_H @@ -141,11 +142,7 @@ CWD_API FILE *virtual_fopen(const char *path, const char *mode TSRMLS_DC); CWD_API int virtual_open(const char *path TSRMLS_DC, int flags, ...); CWD_API int virtual_creat(const char *path, mode_t mode TSRMLS_DC); CWD_API int virtual_rename(char *oldname, char *newname TSRMLS_DC); -#if !(defined(NETWARE) && defined(CLIB_STAT_PATCH)) CWD_API int virtual_stat(const char *path, struct stat *buf TSRMLS_DC); -#else -CWD_API int virtual_stat(const char *path, struct stat_libc *buf TSRMLS_DC); -#endif #if !defined(TSRM_WIN32) && !defined(NETWARE) CWD_API int virtual_lstat(const char *path, struct stat *buf TSRMLS_DC); #endif @@ -154,9 +151,21 @@ CWD_API int virtual_mkdir(const char *pathname, mode_t mode TSRMLS_DC); CWD_API int virtual_rmdir(const char *pathname TSRMLS_DC); CWD_API DIR *virtual_opendir(const char *pathname TSRMLS_DC); CWD_API FILE *virtual_popen(const char *command, const char *type TSRMLS_DC); - -#if !defined(TSRM_WIN32) CWD_API int virtual_access(const char *pathname, int mode TSRMLS_DC); +#if defined(TSRM_WIN32) +/* these are not defined in win32 headers */ +#ifndef W_OK +#define W_OK 0x02 +#endif +#ifndef R_OK +#define R_OK 0x04 +#endif +#ifndef X_OK +#define X_OK 0x01 +#endif +#ifndef F_OK +#define F_OK 0x00 +#endif #endif /* On AIX & Tru64 when a file does not exist realpath() returns @@ -188,13 +197,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 @@ -252,7 +285,11 @@ typedef struct _virtual_cwd_globals { #define VCWD_RMDIR(pathname) rmdir(pathname) #define VCWD_OPENDIR(pathname) opendir(pathname) #define VCWD_POPEN(command, type) popen(command, type) +#if defined(TSRM_WIN32) +#define VCWD_ACCESS(pathname, mode) tsrm_win32_access(pathname, mode) +#else #define VCWD_ACCESS(pathname, mode) access(pathname, mode) +#endif #ifdef HAVE_REALPATH #if defined(__osf__) || defined(_AIX) diff --git a/TSRM/tsrm_win32.c b/TSRM/tsrm_win32.c index 8a4946d5c8..124b91f9d4 100644 --- a/TSRM/tsrm_win32.c +++ b/TSRM/tsrm_win32.c @@ -1,13 +1,13 @@ /* +----------------------------------------------------------------------+ - | PHP Version 4 | + | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2003 The PHP Group | + | Copyright (c) 1997-2004 The PHP Group | +----------------------------------------------------------------------+ - | This source file is subject to version 2.02 of the PHP license, | + | This source file is subject to version 3.0 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | - | available at through the world-wide-web at | - | http://www.php.net/license/2_02.txt. | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_0.txt. | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | @@ -24,9 +24,12 @@ #include #include +#define TSRM_INCLUDE_FULL_WINDOWS_HEADERS + #include "TSRM.h" #ifdef TSRM_WIN32 + #include "tsrm_win32.h" #ifdef ZTS @@ -81,6 +84,19 @@ TSRM_API void tsrm_win32_shutdown(void) #endif } +TSRM_API int tsrm_win32_access(const char *pathname, int mode) +{ + SHFILEINFO sfi; + + if (mode == 1 /*X_OK*/) { + return access(pathname, 0) == 0 && + SHGetFileInfo(pathname, 0, &sfi, sizeof(SHFILEINFO), SHGFI_EXETYPE) != 0 ? 0 : -1; + } else { + return access(pathname, mode); + } +} + + static process_pair *process_get(FILE *stream TSRMLS_DC) { process_pair *ptr; @@ -368,4 +384,5 @@ TSRM_API char *realpath(char *orig_path, char *buffer) } return buffer; } -#endif \ No newline at end of file + +#endif diff --git a/TSRM/tsrm_win32.h b/TSRM/tsrm_win32.h index f2b76d33e1..f2a8e73746 100644 --- a/TSRM/tsrm_win32.h +++ b/TSRM/tsrm_win32.h @@ -1,13 +1,13 @@ /* +----------------------------------------------------------------------+ - | PHP Version 4 | + | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2003 The PHP Group | + | Copyright (c) 1997-2004 The PHP Group | +----------------------------------------------------------------------+ - | This source file is subject to version 2.02 of the PHP license, | + | This source file is subject to version 3.0 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | - | available at through the world-wide-web at | - | http://www.php.net/license/2_02.txt. | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_0.txt. | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | @@ -95,6 +95,7 @@ TSRM_API void tsrm_win32_shutdown(void); TSRM_API FILE *popen_ex(const char *command, const char *type, const char *cwd, char *env); TSRM_API FILE *popen(const char *command, const char *type); TSRM_API int pclose(FILE *stream); +TSRM_API int tsrm_win32_access(const char *pathname, int mode); TSRM_API int shmget(int key, int size, int flags); TSRM_API void *shmat(int key, const void *shmaddr, int flags); @@ -102,4 +103,4 @@ TSRM_API int shmdt(const void *shmaddr); TSRM_API int shmctl(int key, int cmd, struct shmid_ds *buf); TSRM_API char *realpath(char *orig_path, char *buffer); -#endif \ No newline at end of file +#endif -- 2.40.0