File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / php / TSRM / tsrm_virtual_cwd.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue May 29 12:34:34 2012 UTC (12 years, 1 month ago) by misho
Branches: php, MAIN
CVS tags: v5_4_3elwix, v5_4_17p0, HEAD
php 5.4.3+patches

    1: /*
    2:    +----------------------------------------------------------------------+
    3:    | PHP Version 5                                                        |
    4:    +----------------------------------------------------------------------+
    5:    | Copyright (c) 1997-2012 The PHP Group                                |
    6:    +----------------------------------------------------------------------+
    7:    | This source file is subject to version 3.01 of the PHP license,      |
    8:    | that is bundled with this package in the file LICENSE, and is        |
    9:    | available through the world-wide-web at the following url:           |
   10:    | http://www.php.net/license/3_01.txt                                  |
   11:    | If you did not receive a copy of the PHP license and are unable to   |
   12:    | obtain it through the world-wide-web, please send a note to          |
   13:    | license@php.net so we can mail you a copy immediately.               |
   14:    +----------------------------------------------------------------------+
   15:    | Authors: Andi Gutmans <andi@zend.com>                                |
   16:    |          Sascha Schumann <sascha@schumann.cx>                        |
   17:    |          Pierre Joye <pierre@php.net>                                |
   18:    +----------------------------------------------------------------------+
   19: */
   20: 
   21: /* $Id: tsrm_virtual_cwd.c,v 1.1.1.2 2012/05/29 12:34:34 misho Exp $ */
   22: 
   23: #include <sys/types.h>
   24: #include <sys/stat.h>
   25: #include <string.h>
   26: #include <stdio.h>
   27: #include <limits.h>
   28: #include <errno.h>
   29: #include <stdlib.h>
   30: #include <fcntl.h>
   31: #include <time.h>
   32: 
   33: #include "tsrm_virtual_cwd.h"
   34: #include "tsrm_strtok_r.h"
   35: 
   36: #ifdef TSRM_WIN32
   37: #include <io.h>
   38: #include "tsrm_win32.h"
   39: # ifndef IO_REPARSE_TAG_SYMLINK
   40: #  define IO_REPARSE_TAG_SYMLINK 0xA000000C
   41: # endif
   42: 
   43: # ifndef VOLUME_NAME_NT
   44: #  define VOLUME_NAME_NT 0x2
   45: # endif
   46: 
   47: # ifndef VOLUME_NAME_DOS
   48: #  define VOLUME_NAME_DOS 0x0
   49: # endif
   50: #endif
   51: 
   52: #ifndef S_IFLNK
   53: # define S_IFLNK 0120000
   54: #endif
   55: 
   56: #ifdef NETWARE
   57: #include <fsio.h>
   58: #endif
   59: 
   60: #ifndef HAVE_REALPATH
   61: #define realpath(x,y) strcpy(y,x)
   62: #endif
   63: 
   64: #define VIRTUAL_CWD_DEBUG 0
   65: 
   66: #include "TSRM.h"
   67: 
   68: /* Only need mutex for popen() in Windows and NetWare because it doesn't chdir() on UNIX */
   69: #if (defined(TSRM_WIN32) || defined(NETWARE)) && defined(ZTS)
   70: MUTEX_T cwd_mutex;
   71: #endif
   72: 
   73: #ifdef ZTS
   74: ts_rsrc_id cwd_globals_id;
   75: #else
   76: virtual_cwd_globals cwd_globals;
   77: #endif
   78: 
   79: cwd_state main_cwd_state; /* True global */
   80: 
   81: #ifndef TSRM_WIN32
   82: #include <unistd.h>
   83: #else
   84: #include <direct.h>
   85: #endif
   86: 
   87: #ifndef S_ISDIR
   88: #define S_ISDIR(mode) ((mode) & _S_IFDIR)
   89: #endif
   90: 
   91: #ifndef S_ISREG
   92: #define S_ISREG(mode) ((mode) & _S_IFREG)
   93: #endif
   94: 
   95: #ifdef TSRM_WIN32
   96: #include <tchar.h>
   97: #define tsrm_strtok_r(a,b,c) _tcstok((a),(b))
   98: #define TOKENIZER_STRING "/\\"
   99: 
  100: static int php_check_dots(const char *element, int n)
  101: {
  102: 	while (n-- > 0) if (element[n] != '.') break;
  103: 
  104: 	return (n != -1);
  105: }
  106: 
  107: #define IS_DIRECTORY_UP(element, len) \
  108: 	(len >= 2 && !php_check_dots(element, len))
  109: 
  110: #define IS_DIRECTORY_CURRENT(element, len) \
  111: 	(len == 1 && element[0] == '.')
  112: 
  113: #elif defined(NETWARE)
  114: /* NetWare has strtok() (in LibC) and allows both slashes in paths, like Windows --
  115:    but rest of the stuff is like Unix */
  116: /* strtok() call in LibC is abending when used in a different address space -- hence using
  117:    PHP's version itself for now */
  118: /*#define tsrm_strtok_r(a,b,c) strtok((a),(b))*/
  119: #define TOKENIZER_STRING "/\\"
  120: 
  121: #else
  122: #define TOKENIZER_STRING "/"
  123: #endif
  124: 
  125: 
  126: /* default macros */
  127: 
  128: #ifndef IS_DIRECTORY_UP
  129: #define IS_DIRECTORY_UP(element, len) \
  130: 	(len == 2 && element[0] == '.' && element[1] == '.')
  131: #endif
  132: 
  133: #ifndef IS_DIRECTORY_CURRENT
  134: #define IS_DIRECTORY_CURRENT(element, len) \
  135: 	(len == 1 && element[0] == '.')
  136: #endif
  137: 
  138: /* define this to check semantics */
  139: #define IS_DIR_OK(s) (1)
  140: 
  141: #ifndef IS_DIR_OK
  142: #define IS_DIR_OK(state) (php_is_dir_ok(state) == 0)
  143: #endif
  144: 
  145: 
  146: #define CWD_STATE_COPY(d, s)				\
  147: 	(d)->cwd_length = (s)->cwd_length;		\
  148: 	(d)->cwd = (char *) malloc((s)->cwd_length+1);	\
  149: 	memcpy((d)->cwd, (s)->cwd, (s)->cwd_length+1);
  150: 
  151: #define CWD_STATE_FREE(s)			\
  152: 	free((s)->cwd);
  153: 
  154: #ifdef TSRM_WIN32
  155: 
  156: #ifdef CTL_CODE
  157: #undef CTL_CODE
  158: #endif
  159: #define CTL_CODE(DeviceType,Function,Method,Access) (((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method))
  160: #define FILE_DEVICE_FILE_SYSTEM 0x00000009
  161: #define METHOD_BUFFERED		0
  162: #define FILE_ANY_ACCESS 	0
  163: #define FSCTL_GET_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 42, METHOD_BUFFERED, FILE_ANY_ACCESS)
  164: #define MAXIMUM_REPARSE_DATA_BUFFER_SIZE  ( 16 * 1024 )
  165: 
  166: typedef struct {
  167: 	unsigned long  ReparseTag;
  168: 	unsigned short ReparseDataLength;
  169: 	unsigned short Reserved;
  170: 	union {
  171: 		struct {
  172: 			unsigned short SubstituteNameOffset;
  173: 			unsigned short SubstituteNameLength;
  174: 			unsigned short PrintNameOffset;
  175: 			unsigned short PrintNameLength;
  176: 			unsigned long  Flags;
  177: 			wchar_t        ReparseTarget[1];
  178: 		} SymbolicLinkReparseBuffer;
  179: 		struct {
  180: 			unsigned short SubstituteNameOffset;
  181: 			unsigned short SubstituteNameLength;
  182: 			unsigned short PrintNameOffset;
  183: 			unsigned short PrintNameLength;
  184: 			wchar_t        ReparseTarget[1];
  185: 		} MountPointReparseBuffer;
  186: 		struct {
  187: 			unsigned char  ReparseTarget[1];
  188: 		} GenericReparseBuffer;
  189: 	};
  190: } REPARSE_DATA_BUFFER;
  191: 
  192: #define SECS_BETWEEN_EPOCHS (__int64)11644473600
  193: #define SECS_TO_100NS (__int64)10000000
  194: static inline time_t FileTimeToUnixTime(const FILETIME FileTime)
  195: {
  196: 	__int64 UnixTime;
  197: 	long *nsec = NULL;
  198: 	SYSTEMTIME SystemTime;
  199: 	FileTimeToSystemTime(&FileTime, &SystemTime);
  200: 
  201: 	UnixTime = ((__int64)FileTime.dwHighDateTime << 32) +
  202: 	FileTime.dwLowDateTime;
  203: 
  204: 	UnixTime -= (SECS_BETWEEN_EPOCHS * SECS_TO_100NS);
  205: 
  206: 	if (nsec) {
  207: 		*nsec = (UnixTime % SECS_TO_100NS) * (__int64)100;
  208: 	}
  209: 
  210: 	UnixTime /= SECS_TO_100NS; /* now convert to seconds */
  211: 
  212: 	if ((time_t)UnixTime != UnixTime) {
  213: 		UnixTime = 0;
  214: 	}
  215: 	return (time_t)UnixTime;
  216: }
  217: 
  218: CWD_API int php_sys_readlink(const char *link, char *target, size_t target_len){ /* {{{ */
  219: 	HINSTANCE kernel32;
  220: 	HANDLE hFile;
  221: 	DWORD dwRet;
  222: 
  223: 	typedef BOOL (WINAPI *gfpnh_func)(HANDLE, LPTSTR, DWORD, DWORD);
  224: 	gfpnh_func pGetFinalPathNameByHandle;
  225: 
  226: 	kernel32 = LoadLibrary("kernel32.dll");
  227: 
  228: 	if (kernel32) {
  229: 		pGetFinalPathNameByHandle = (gfpnh_func)GetProcAddress(kernel32, "GetFinalPathNameByHandleA");
  230: 		if (pGetFinalPathNameByHandle == NULL) {
  231: 			return -1;
  232: 		}
  233: 	} else {
  234: 		return -1;
  235: 	}
  236: 
  237: 	hFile = CreateFile(link,            // file to open
  238: 				 GENERIC_READ,          // open for reading
  239: 				 FILE_SHARE_READ,       // share for reading
  240: 				 NULL,                  // default security
  241: 				 OPEN_EXISTING,         // existing file only
  242: 				 FILE_FLAG_BACKUP_SEMANTICS, // normal file
  243: 				 NULL);                 // no attr. template
  244: 
  245: 	if( hFile == INVALID_HANDLE_VALUE) {
  246: 			return -1;
  247: 	}
  248: 
  249: 	dwRet = pGetFinalPathNameByHandle(hFile, target, MAXPATHLEN, VOLUME_NAME_DOS);
  250: 	if(dwRet >= MAXPATHLEN) {
  251: 		return -1;
  252: 	}
  253: 
  254: 	CloseHandle(hFile);
  255: 
  256: 	if(dwRet > 4) {
  257: 		/* Skip first 4 characters if they are "\??\" */
  258: 		if(target[0] == '\\' && target[1] == '\\' && target[2] == '?' && target[3] ==  '\\') {
  259: 			char tmp[MAXPATHLEN];
  260: 			unsigned int offset = 4;
  261: 			dwRet -= 4;
  262: 
  263: 			/* \??\UNC\ */
  264: 			if (dwRet > 7 && target[4] == 'U' && target[5] == 'N' && target[6] == 'C') {
  265: 				offset += 2;
  266: 				dwRet -= 2;
  267: 				target[offset] = '\\';
  268: 			}
  269: 
  270: 			memcpy(tmp, target + offset, dwRet);
  271: 			memcpy(target, tmp, dwRet);
  272: 		}
  273: 	}
  274: 
  275: 	target[dwRet] = '\0';
  276: 	return dwRet;
  277: }
  278: /* }}} */
  279: 
  280: CWD_API int php_sys_stat_ex(const char *path, struct stat *buf, int lstat) /* {{{ */
  281: {
  282: 	WIN32_FILE_ATTRIBUTE_DATA data;
  283: 	__int64 t;
  284: 	const size_t path_len = strlen(path);
  285: 
  286: 	if (!GetFileAttributesEx(path, GetFileExInfoStandard, &data)) {
  287: 		return stat(path, buf);
  288: 	}
  289: 
  290: 	if (path_len >= 1 && path[1] == ':') {
  291: 		if (path[0] >= 'A' && path[0] <= 'Z') {
  292: 			buf->st_dev = buf->st_rdev = path[0] - 'A';
  293: 		} else {
  294: 			buf->st_dev = buf->st_rdev = path[0] - 'a';
  295: 		}
  296: 	} else if (IS_UNC_PATH(path, path_len)) {
  297: 		buf->st_dev = buf->st_rdev = 0;
  298: 	} else {
  299: 		char  cur_path[MAXPATHLEN+1];
  300: 		DWORD len = sizeof(cur_path);
  301: 		char *tmp = cur_path;
  302: 
  303: 		while(1) {
  304: 			DWORD r = GetCurrentDirectory(len, tmp);
  305: 			if (r < len) {
  306: 				if (tmp[1] == ':') {
  307: 					if (path[0] >= 'A' && path[0] <= 'Z') {
  308: 						buf->st_dev = buf->st_rdev = path[0] - 'A';
  309: 					} else {
  310: 						buf->st_dev = buf->st_rdev = path[0] - 'a';
  311: 					}
  312: 				} else {
  313: 					buf->st_dev = buf->st_rdev = -1;
  314: 				}
  315: 				break;
  316: 			} else if (!r) {
  317: 				buf->st_dev = buf->st_rdev = -1;
  318: 				break;
  319: 			} else {
  320: 				len = r+1;
  321: 				tmp = (char*)malloc(len);
  322: 			}
  323: 		}
  324: 		if (tmp != cur_path) {
  325: 			free(tmp);
  326: 		}
  327: 	}
  328: 
  329: 	buf->st_uid = buf->st_gid = buf->st_ino = 0;
  330: 
  331: 	if (lstat && data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
  332: 		/* File is a reparse point. Get the target */
  333: 		HANDLE hLink = NULL;
  334: 		REPARSE_DATA_BUFFER * pbuffer;
  335: 		unsigned int retlength = 0;
  336: 		TSRM_ALLOCA_FLAG(use_heap_large);
  337: 
  338: 		hLink = CreateFile(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT|FILE_FLAG_BACKUP_SEMANTICS, NULL);
  339: 		if(hLink == INVALID_HANDLE_VALUE) {
  340: 			return -1;
  341: 		}
  342: 
  343: 		pbuffer = (REPARSE_DATA_BUFFER *)tsrm_do_alloca(MAXIMUM_REPARSE_DATA_BUFFER_SIZE, use_heap_large);
  344: 		if(!DeviceIoControl(hLink, FSCTL_GET_REPARSE_POINT, NULL, 0, pbuffer,  MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &retlength, NULL)) {
  345: 			tsrm_free_alloca(pbuffer, use_heap_large);
  346: 			CloseHandle(hLink);
  347: 			return -1;
  348: 		}
  349: 
  350: 		CloseHandle(hLink);
  351: 
  352: 		if(pbuffer->ReparseTag == IO_REPARSE_TAG_SYMLINK) {
  353: 			buf->st_mode = S_IFLNK;
  354: 			buf->st_mode |= (data.dwFileAttributes & FILE_ATTRIBUTE_READONLY) ? (S_IREAD|(S_IREAD>>3)|(S_IREAD>>6)) : (S_IREAD|(S_IREAD>>3)|(S_IREAD>>6)|S_IWRITE|(S_IWRITE>>3)|(S_IWRITE>>6));
  355: 		}
  356: 
  357: #if 0 /* Not used yet */
  358: 		else if(pbuffer->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) {
  359: 			buf->st_mode |=;
  360: 		}
  361: #endif
  362: 		tsrm_free_alloca(pbuffer, use_heap_large);
  363: 	} else {
  364: 		buf->st_mode = (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? (S_IFDIR|S_IEXEC|(S_IEXEC>>3)|(S_IEXEC>>6)) : S_IFREG;
  365: 		buf->st_mode |= (data.dwFileAttributes & FILE_ATTRIBUTE_READONLY) ? (S_IREAD|(S_IREAD>>3)|(S_IREAD>>6)) : (S_IREAD|(S_IREAD>>3)|(S_IREAD>>6)|S_IWRITE|(S_IWRITE>>3)|(S_IWRITE>>6));
  366: 	}
  367: 
  368: 	if ((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) {
  369: 		int len = strlen(path);
  370: 
  371: 		if (path[len-4] == '.') {
  372: 			if (_memicmp(path+len-3, "exe", 3) == 0 ||
  373: 				_memicmp(path+len-3, "com", 3) == 0 ||
  374: 				_memicmp(path+len-3, "bat", 3) == 0 ||
  375: 				_memicmp(path+len-3, "cmd", 3) == 0) {
  376: 				buf->st_mode  |= (S_IEXEC|(S_IEXEC>>3)|(S_IEXEC>>6));
  377: 			}
  378: 		}
  379: 	}
  380: 
  381: 	buf->st_nlink = 1;
  382: 	t = data.nFileSizeHigh;
  383: 	t = t << 32;
  384: 	t |= data.nFileSizeLow;
  385: 	buf->st_size = t;
  386: 	buf->st_atime = FileTimeToUnixTime(data.ftLastAccessTime);
  387: 	buf->st_ctime = FileTimeToUnixTime(data.ftCreationTime);
  388: 	buf->st_mtime = FileTimeToUnixTime(data.ftLastWriteTime);
  389: 	return 0;
  390: }
  391: /* }}} */
  392: #endif
  393: 
  394: static int php_is_dir_ok(const cwd_state *state)  /* {{{ */
  395: {
  396: 	struct stat buf;
  397: 
  398: 	if (php_sys_stat(state->cwd, &buf) == 0 && S_ISDIR(buf.st_mode))
  399: 		return (0);
  400: 
  401: 	return (1);
  402: }
  403: /* }}} */
  404: 
  405: static int php_is_file_ok(const cwd_state *state)  /* {{{ */
  406: {
  407: 	struct stat buf;
  408: 
  409: 	if (php_sys_stat(state->cwd, &buf) == 0 && S_ISREG(buf.st_mode))
  410: 		return (0);
  411: 
  412: 	return (1);
  413: }
  414: /* }}} */
  415: 
  416: static void cwd_globals_ctor(virtual_cwd_globals *cwd_g TSRMLS_DC) /* {{{ */
  417: {
  418: 	CWD_STATE_COPY(&cwd_g->cwd, &main_cwd_state);
  419: 	cwd_g->realpath_cache_size = 0;
  420: 	cwd_g->realpath_cache_size_limit = REALPATH_CACHE_SIZE;
  421: 	cwd_g->realpath_cache_ttl = REALPATH_CACHE_TTL;
  422: 	memset(cwd_g->realpath_cache, 0, sizeof(cwd_g->realpath_cache));
  423: }
  424: /* }}} */
  425: 
  426: static void cwd_globals_dtor(virtual_cwd_globals *cwd_g TSRMLS_DC) /* {{{ */
  427: {
  428: 	CWD_STATE_FREE(&cwd_g->cwd);
  429: 	realpath_cache_clean(TSRMLS_C);
  430: }
  431: /* }}} */
  432: 
  433: CWD_API void virtual_cwd_startup(void) /* {{{ */
  434: {
  435: 	char cwd[MAXPATHLEN];
  436: 	char *result;
  437: 
  438: #ifdef NETWARE
  439: 	result = getcwdpath(cwd, NULL, 1);
  440: 	if(result)
  441: 	{
  442: 		char *c=cwd;
  443: 		while(c = strchr(c, '\\'))
  444: 		{
  445: 			*c='/';
  446: 			++c;
  447: 		}
  448: 	}
  449: #else
  450: 	result = getcwd(cwd, sizeof(cwd));
  451: #endif
  452: 	if (!result) {
  453: 		cwd[0] = '\0';
  454: 	}
  455: 
  456: 	main_cwd_state.cwd_length = strlen(cwd);
  457: #ifdef TSRM_WIN32
  458: 	if (main_cwd_state.cwd_length >= 2 && cwd[1] == ':') {
  459: 		cwd[0] = toupper(cwd[0]);
  460: 	}
  461: #endif
  462: 	main_cwd_state.cwd = strdup(cwd);
  463: 
  464: #ifdef ZTS
  465: 	ts_allocate_id(&cwd_globals_id, sizeof(virtual_cwd_globals), (ts_allocate_ctor) cwd_globals_ctor, (ts_allocate_dtor) cwd_globals_dtor);
  466: #else
  467: 	cwd_globals_ctor(&cwd_globals TSRMLS_CC);
  468: #endif
  469: 
  470: #if (defined(TSRM_WIN32) || defined(NETWARE)) && defined(ZTS)
  471: 	cwd_mutex = tsrm_mutex_alloc();
  472: #endif
  473: }
  474: /* }}} */
  475: 
  476: CWD_API void virtual_cwd_shutdown(void) /* {{{ */
  477: {
  478: #ifndef ZTS
  479: 	cwd_globals_dtor(&cwd_globals TSRMLS_CC);
  480: #endif
  481: #if (defined(TSRM_WIN32) || defined(NETWARE)) && defined(ZTS)
  482: 	tsrm_mutex_free(cwd_mutex);
  483: #endif
  484: 
  485: 	free(main_cwd_state.cwd); /* Don't use CWD_STATE_FREE because the non global states will probably use emalloc()/efree() */
  486: }
  487: /* }}} */
  488: 
  489: CWD_API char *virtual_getcwd_ex(size_t *length TSRMLS_DC) /* {{{ */
  490: {
  491: 	cwd_state *state;
  492: 
  493: 	state = &CWDG(cwd);
  494: 
  495: 	if (state->cwd_length == 0) {
  496: 		char *retval;
  497: 
  498: 		*length = 1;
  499: 		retval = (char *) malloc(2);
  500: 		if (retval == NULL) {
  501: 			return NULL;
  502: 		}
  503: 		retval[0] = DEFAULT_SLASH;
  504: 		retval[1] = '\0';
  505: 		return retval;
  506: 	}
  507: 
  508: #ifdef TSRM_WIN32
  509: 	/* If we have something like C: */
  510: 	if (state->cwd_length == 2 && state->cwd[state->cwd_length-1] == ':') {
  511: 		char *retval;
  512: 
  513: 		*length = state->cwd_length+1;
  514: 		retval = (char *) malloc(*length+1);
  515: 		if (retval == NULL) {
  516: 			return NULL;
  517: 		}
  518: 		memcpy(retval, state->cwd, *length);
  519: 		retval[0] = toupper(retval[0]);
  520: 		retval[*length-1] = DEFAULT_SLASH;
  521: 		retval[*length] = '\0';
  522: 		return retval;
  523: 	}
  524: #endif
  525: 	*length = state->cwd_length;
  526: 	return strdup(state->cwd);
  527: }
  528: /* }}} */
  529: 
  530: /* Same semantics as UNIX getcwd() */
  531: CWD_API char *virtual_getcwd(char *buf, size_t size TSRMLS_DC) /* {{{ */
  532: {
  533: 	size_t length;
  534: 	char *cwd;
  535: 
  536: 	cwd = virtual_getcwd_ex(&length TSRMLS_CC);
  537: 
  538: 	if (buf == NULL) {
  539: 		return cwd;
  540: 	}
  541: 	if (length > size-1) {
  542: 		free(cwd);
  543: 		errno = ERANGE; /* Is this OK? */
  544: 		return NULL;
  545: 	}
  546: 	memcpy(buf, cwd, length+1);
  547: 	free(cwd);
  548: 	return buf;
  549: }
  550: /* }}} */
  551: 
  552: #ifdef PHP_WIN32
  553: static inline unsigned long realpath_cache_key(const char *path, int path_len TSRMLS_DC) /* {{{ */
  554: {
  555: 	register unsigned long h;
  556: 	char *bucket_key_start = tsrm_win32_get_path_sid_key(path TSRMLS_CC);
  557: 	char *bucket_key = (char *)bucket_key_start;
  558: 	const char *e = bucket_key + strlen(bucket_key);
  559: 
  560: 	if (!bucket_key) {
  561: 		return 0;
  562: 	}
  563: 
  564: 	for (h = 2166136261U; bucket_key < e;) {
  565: 		h *= 16777619;
  566: 		h ^= *bucket_key++;
  567: 	}
  568: 	HeapFree(GetProcessHeap(), 0, (LPVOID)bucket_key_start);
  569: 	return h;
  570: }
  571: /* }}} */
  572: #else
  573: static inline unsigned long realpath_cache_key(const char *path, int path_len) /* {{{ */
  574: {
  575: 	register unsigned long h;
  576: 	const char *e = path + path_len;
  577: 
  578: 	for (h = 2166136261U; path < e;) {
  579: 		h *= 16777619;
  580: 		h ^= *path++;
  581: 	}
  582: 
  583: 	return h;
  584: }
  585: /* }}} */
  586: #endif /* defined(PHP_WIN32) */
  587: 
  588: CWD_API void realpath_cache_clean(TSRMLS_D) /* {{{ */
  589: {
  590: 	int i;
  591: 
  592: 	for (i = 0; i < sizeof(CWDG(realpath_cache))/sizeof(CWDG(realpath_cache)[0]); i++) {
  593: 		realpath_cache_bucket *p = CWDG(realpath_cache)[i];
  594: 		while (p != NULL) {
  595: 			realpath_cache_bucket *r = p;
  596: 			p = p->next;
  597: 			free(r);
  598: 		}
  599: 		CWDG(realpath_cache)[i] = NULL;
  600: 	}
  601: 	CWDG(realpath_cache_size) = 0;
  602: }
  603: /* }}} */
  604: 
  605: CWD_API void realpath_cache_del(const char *path, int path_len TSRMLS_DC) /* {{{ */
  606: {
  607: #ifdef PHP_WIN32
  608: 	unsigned long key = realpath_cache_key(path, path_len TSRMLS_CC);
  609: #else
  610: 	unsigned long key = realpath_cache_key(path, path_len);
  611: #endif
  612: 	unsigned long n = key % (sizeof(CWDG(realpath_cache)) / sizeof(CWDG(realpath_cache)[0]));
  613: 	realpath_cache_bucket **bucket = &CWDG(realpath_cache)[n];
  614: 
  615: 	while (*bucket != NULL) {
  616: 		if (key == (*bucket)->key && path_len == (*bucket)->path_len &&
  617: 					memcmp(path, (*bucket)->path, path_len) == 0) {
  618: 			realpath_cache_bucket *r = *bucket;
  619: 			*bucket = (*bucket)->next;
  620: 		   
  621: 			/* if the pointers match then only subtract the length of the path */
  622: 		   	if(r->path == r->realpath) {
  623: 				CWDG(realpath_cache_size) -= sizeof(realpath_cache_bucket) + r->path_len + 1;
  624: 			} else {
  625: 				CWDG(realpath_cache_size) -= sizeof(realpath_cache_bucket) + r->path_len + 1 + r->realpath_len + 1;
  626: 			}
  627: 		   
  628: 			free(r);
  629: 			return;
  630: 		} else {
  631: 			bucket = &(*bucket)->next;
  632: 		}
  633: 	}
  634: }
  635: /* }}} */
  636: 
  637: static inline void realpath_cache_add(const char *path, int path_len, const char *realpath, int realpath_len, int is_dir, time_t t TSRMLS_DC) /* {{{ */
  638: {
  639: 	long size = sizeof(realpath_cache_bucket) + path_len + 1;
  640: 	int same = 1;
  641: 
  642: 	if (realpath_len != path_len ||
  643: 		memcmp(path, realpath, path_len) != 0) {
  644: 		size += realpath_len + 1;
  645: 		same = 0;
  646: 	}
  647: 
  648: 	if (CWDG(realpath_cache_size) + size <= CWDG(realpath_cache_size_limit)) {
  649: 		realpath_cache_bucket *bucket = malloc(size);
  650: 		unsigned long n;
  651: 
  652: 		if (bucket == NULL) {
  653: 			return;
  654: 		}
  655: 
  656: #ifdef PHP_WIN32
  657: 		bucket->key = realpath_cache_key(path, path_len TSRMLS_CC);
  658: #else
  659: 		bucket->key = realpath_cache_key(path, path_len);
  660: #endif
  661: 		bucket->path = (char*)bucket + sizeof(realpath_cache_bucket);
  662: 		memcpy(bucket->path, path, path_len+1);
  663: 		bucket->path_len = path_len;
  664: 		if (same) {
  665: 			bucket->realpath = bucket->path;
  666: 		} else {
  667: 			bucket->realpath = bucket->path + (path_len + 1);
  668: 			memcpy(bucket->realpath, realpath, realpath_len+1);
  669: 		}
  670: 		bucket->realpath_len = realpath_len;
  671: 		bucket->is_dir = is_dir;
  672: #ifdef PHP_WIN32
  673: 		bucket->is_rvalid   = 0;
  674: 		bucket->is_readable = 0;
  675: 		bucket->is_wvalid   = 0;
  676: 		bucket->is_writable = 0;
  677: #endif
  678: 		bucket->expires = t + CWDG(realpath_cache_ttl);
  679: 		n = bucket->key % (sizeof(CWDG(realpath_cache)) / sizeof(CWDG(realpath_cache)[0]));
  680: 		bucket->next = CWDG(realpath_cache)[n];
  681: 		CWDG(realpath_cache)[n] = bucket;
  682: 		CWDG(realpath_cache_size) += size;
  683: 	}
  684: }
  685: /* }}} */
  686: 
  687: static inline realpath_cache_bucket* realpath_cache_find(const char *path, int path_len, time_t t TSRMLS_DC) /* {{{ */
  688: {
  689: #ifdef PHP_WIN32
  690: 	unsigned long key = realpath_cache_key(path, path_len TSRMLS_CC);
  691: #else
  692: 	unsigned long key = realpath_cache_key(path, path_len);
  693: #endif
  694: 
  695: 	unsigned long n = key % (sizeof(CWDG(realpath_cache)) / sizeof(CWDG(realpath_cache)[0]));
  696: 	realpath_cache_bucket **bucket = &CWDG(realpath_cache)[n];
  697: 
  698: 	while (*bucket != NULL) {
  699: 		if (CWDG(realpath_cache_ttl) && (*bucket)->expires < t) {
  700: 			realpath_cache_bucket *r = *bucket;
  701: 			*bucket = (*bucket)->next;
  702: 
  703: 			/* if the pointers match then only subtract the length of the path */		   
  704: 		   	if(r->path == r->realpath) {
  705: 				CWDG(realpath_cache_size) -= sizeof(realpath_cache_bucket) + r->path_len + 1;
  706: 			} else {
  707: 				CWDG(realpath_cache_size) -= sizeof(realpath_cache_bucket) + r->path_len + 1 + r->realpath_len + 1;
  708: 			}
  709: 			free(r);
  710: 		} else if (key == (*bucket)->key && path_len == (*bucket)->path_len &&
  711: 					memcmp(path, (*bucket)->path, path_len) == 0) {
  712: 			return *bucket;
  713: 		} else {
  714: 			bucket = &(*bucket)->next;
  715: 		}
  716: 	}
  717: 	return NULL;
  718: }
  719: /* }}} */
  720: 
  721: CWD_API realpath_cache_bucket* realpath_cache_lookup(const char *path, int path_len, time_t t TSRMLS_DC) /* {{{ */
  722: {
  723: 	return realpath_cache_find(path, path_len, t TSRMLS_CC);
  724: }
  725: /* }}} */
  726: 
  727: CWD_API int realpath_cache_size(TSRMLS_D)
  728: {
  729: 	return CWDG(realpath_cache_size);
  730: }
  731: 
  732: CWD_API int realpath_cache_max_buckets(TSRMLS_D)
  733: {
  734: 	return (sizeof(CWDG(realpath_cache)) / sizeof(CWDG(realpath_cache)[0]));
  735: }
  736: 
  737: CWD_API realpath_cache_bucket** realpath_cache_get_buckets(TSRMLS_D)
  738: {
  739: 	return CWDG(realpath_cache);
  740: }
  741: 
  742: 
  743: #undef LINK_MAX
  744: #define LINK_MAX 32
  745: 
  746: static int tsrm_realpath_r(char *path, int start, int len, int *ll, time_t *t, int use_realpath, int is_dir, int *link_is_dir TSRMLS_DC) /* {{{ */
  747: {
  748: 	int i, j, save;
  749: 	int directory = 0;
  750: #ifdef TSRM_WIN32
  751: 	WIN32_FIND_DATA data;
  752: 	HANDLE hFind;
  753: 	TSRM_ALLOCA_FLAG(use_heap_large)
  754: #else
  755: 	struct stat st;
  756: #endif
  757: 	realpath_cache_bucket *bucket;
  758: 	char *tmp;
  759: 	TSRM_ALLOCA_FLAG(use_heap)
  760: 
  761: 	while (1) {
  762: 		if (len <= start) {
  763: 			if (link_is_dir) {
  764: 				*link_is_dir = 1;
  765: 			}
  766: 			return start;
  767: 		}
  768: 
  769: 		i = len;
  770: 		while (i > start && !IS_SLASH(path[i-1])) {
  771: 			i--;
  772: 		}
  773: 
  774: 		if (i == len ||
  775: 			(i == len - 1 && path[i] == '.')) {
  776: 			/* remove double slashes and '.' */
  777: 			len = i - 1;
  778: 			is_dir = 1;
  779: 			continue;
  780: 		} else if (i == len - 2 && path[i] == '.' && path[i+1] == '.') {
  781: 			/* remove '..' and previous directory */
  782: 			is_dir = 1;
  783: 			if (link_is_dir) {
  784: 				*link_is_dir = 1;
  785: 			}
  786: 			if (i - 1 <= start) {
  787: 				return start ? start : len;
  788: 			}
  789: 			j = tsrm_realpath_r(path, start, i-1, ll, t, use_realpath, 1, NULL TSRMLS_CC);
  790: 			if (j > start) {
  791: 				j--;
  792: 				while (j > start && !IS_SLASH(path[j])) {
  793: 					j--;
  794: 				}
  795: 				if (!start) {
  796: 					/* leading '..' must not be removed in case of relative path */
  797: 					if (j == 0 && path[0] == '.' && path[1] == '.' &&
  798: 							IS_SLASH(path[2])) {
  799: 						path[3] = '.';
  800: 						path[4] = '.';
  801: 						path[5] = DEFAULT_SLASH;
  802: 						j = 5;
  803: 					} else if (j > 0 &&
  804: 							path[j+1] == '.' && path[j+2] == '.' &&
  805: 							IS_SLASH(path[j+3])) {
  806: 						j += 4;
  807: 						path[j++] = '.';
  808: 						path[j++] = '.';
  809: 						path[j] = DEFAULT_SLASH;
  810: 					}
  811: 				}
  812: 			} else if (!start && !j) {
  813: 				/* leading '..' must not be removed in case of relative path */
  814: 				path[0] = '.';
  815: 				path[1] = '.';
  816: 				path[2] = DEFAULT_SLASH;
  817: 				j = 2;
  818: 			}
  819: 			return j;
  820: 		}
  821: 
  822: 		path[len] = 0;
  823: 
  824: 		save = (use_realpath != CWD_EXPAND);
  825: 
  826: 		if (start && save && CWDG(realpath_cache_size_limit)) {
  827: 			/* cache lookup for absolute path */
  828: 			if (!*t) {
  829: 				*t = time(0);
  830: 			}
  831: 			if ((bucket = realpath_cache_find(path, len, *t TSRMLS_CC)) != NULL) {
  832: 				if (is_dir && !bucket->is_dir) {
  833: 					/* not a directory */
  834: 					return -1;
  835: 				} else {
  836: 					if (link_is_dir) {
  837: 						*link_is_dir = bucket->is_dir;
  838: 					}
  839: 					memcpy(path, bucket->realpath, bucket->realpath_len + 1);
  840: 					return bucket->realpath_len;
  841: 				}
  842: 			}
  843: 		}
  844: 
  845: #ifdef TSRM_WIN32
  846: 		if (save && (hFind = FindFirstFile(path, &data)) == INVALID_HANDLE_VALUE) {
  847: 			if (use_realpath == CWD_REALPATH) {
  848: 				/* file not found */
  849: 				return -1;
  850: 			}
  851: 			/* continue resolution anyway but don't save result in the cache */
  852: 			save = 0;
  853: 		}
  854: 
  855: 		if (save) {
  856: 			FindClose(hFind);
  857: 		}
  858: 
  859: 		tmp = tsrm_do_alloca(len+1, use_heap);
  860: 		memcpy(tmp, path, len+1);
  861: 
  862: 		if(save &&
  863: 				!(IS_UNC_PATH(path, len) && len >= 3 && path[2] != '?') &&
  864: 				(data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) {
  865: 			/* File is a reparse point. Get the target */
  866: 			HANDLE hLink = NULL;
  867: 			REPARSE_DATA_BUFFER * pbuffer;
  868: 			unsigned int retlength = 0;
  869: 			int bufindex = 0, isabsolute = 0;
  870: 			wchar_t * reparsetarget;
  871: 			BOOL isVolume = FALSE;
  872: 			char printname[MAX_PATH];
  873: 			char substitutename[MAX_PATH];
  874: 			int printname_len, substitutename_len;
  875: 			int substitutename_off = 0;
  876: 
  877: 			if(++(*ll) > LINK_MAX) {
  878: 				return -1;
  879: 			}
  880: 
  881: 			hLink = CreateFile(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT|FILE_FLAG_BACKUP_SEMANTICS, NULL);
  882: 			if(hLink == INVALID_HANDLE_VALUE) {
  883: 				return -1;
  884: 			}
  885: 
  886: 			pbuffer = (REPARSE_DATA_BUFFER *)tsrm_do_alloca(MAXIMUM_REPARSE_DATA_BUFFER_SIZE, use_heap_large);
  887: 			if (pbuffer == NULL) {
  888: 				return -1;
  889: 			}
  890: 			if(!DeviceIoControl(hLink, FSCTL_GET_REPARSE_POINT, NULL, 0, pbuffer,  MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &retlength, NULL)) {
  891: 				tsrm_free_alloca(pbuffer, use_heap_large);
  892: 				CloseHandle(hLink);
  893: 				return -1;
  894: 			}
  895: 
  896: 			CloseHandle(hLink);
  897: 
  898: 			if(pbuffer->ReparseTag == IO_REPARSE_TAG_SYMLINK) {
  899: 				reparsetarget = pbuffer->SymbolicLinkReparseBuffer.ReparseTarget;
  900: 				printname_len = pbuffer->MountPointReparseBuffer.PrintNameLength / sizeof(WCHAR);
  901: 				isabsolute = (pbuffer->SymbolicLinkReparseBuffer.Flags == 0) ? 1 : 0;
  902: 				if (!WideCharToMultiByte(CP_THREAD_ACP, 0,
  903: 					reparsetarget + pbuffer->MountPointReparseBuffer.PrintNameOffset  / sizeof(WCHAR),
  904: 					printname_len + 1,
  905: 					printname, MAX_PATH, NULL, NULL
  906: 				)) {
  907: 					tsrm_free_alloca(pbuffer, use_heap_large);
  908: 					return -1;
  909: 				};
  910: 				printname_len = pbuffer->MountPointReparseBuffer.PrintNameLength / sizeof(WCHAR);
  911: 				printname[printname_len] = 0;
  912: 
  913: 				substitutename_len = pbuffer->MountPointReparseBuffer.SubstituteNameLength / sizeof(WCHAR);
  914: 				if (!WideCharToMultiByte(CP_THREAD_ACP, 0,
  915: 					reparsetarget + pbuffer->MountPointReparseBuffer.SubstituteNameOffset / sizeof(WCHAR),
  916: 					substitutename_len + 1,
  917: 					substitutename, MAX_PATH, NULL, NULL
  918: 				)) {
  919: 					tsrm_free_alloca(pbuffer, use_heap_large);
  920: 					return -1;
  921: 				};
  922: 				substitutename[substitutename_len] = 0;
  923: 			}
  924: 			else if(pbuffer->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) {
  925: 				isabsolute = 1;
  926: 				reparsetarget = pbuffer->MountPointReparseBuffer.ReparseTarget;
  927: 				printname_len = pbuffer->MountPointReparseBuffer.PrintNameLength / sizeof(WCHAR);
  928: 				if (!WideCharToMultiByte(CP_THREAD_ACP, 0,
  929: 					reparsetarget + pbuffer->MountPointReparseBuffer.PrintNameOffset  / sizeof(WCHAR),
  930: 					printname_len + 1,
  931: 					printname, MAX_PATH, NULL, NULL
  932: 				)) {
  933: 					tsrm_free_alloca(pbuffer, use_heap_large);
  934: 					return -1;
  935: 				};
  936: 				printname[pbuffer->MountPointReparseBuffer.PrintNameLength / sizeof(WCHAR)] = 0;
  937: 
  938: 				substitutename_len = pbuffer->MountPointReparseBuffer.SubstituteNameLength / sizeof(WCHAR);
  939: 				if (!WideCharToMultiByte(CP_THREAD_ACP, 0,
  940: 					reparsetarget + pbuffer->MountPointReparseBuffer.SubstituteNameOffset / sizeof(WCHAR),
  941: 					substitutename_len + 1,
  942: 					substitutename, MAX_PATH, NULL, NULL
  943: 				)) {
  944: 					tsrm_free_alloca(pbuffer, use_heap_large);
  945: 					return -1;
  946: 				};
  947: 				substitutename[substitutename_len] = 0;
  948: 			} else {
  949: 				tsrm_free_alloca(pbuffer, use_heap_large);
  950: 				return -1;
  951: 			}
  952: 
  953: 			if(isabsolute && substitutename_len > 4) {
  954: 				/* Do not resolve volumes (for now). A mounted point can
  955: 				   target a volume without a drive, it is not certain that
  956: 				   all IO functions we use in php and its deps support
  957: 				   path with volume GUID instead of the DOS way, like:
  958: 				   d:\test\mnt\foo
  959: 				   \\?\Volume{62d1c3f8-83b9-11de-b108-806e6f6e6963}\foo
  960: 				*/
  961: 				if (strncmp(substitutename, "\\??\\Volume{",11) == 0
  962: 					|| strncmp(substitutename, "\\\\?\\Volume{",11) == 0
  963: 					|| strncmp(substitutename, "\\??\\UNC\\", 8) == 0
  964: 					) {
  965: 					isVolume = TRUE;
  966: 					substitutename_off = 0;
  967: 				} else
  968: 					/* do not use the \??\ and \\?\ prefix*/
  969: 					if (strncmp(substitutename, "\\??\\", 4) == 0
  970: 						|| strncmp(substitutename, "\\\\?\\", 4) == 0) {
  971: 					substitutename_off = 4;
  972: 				}
  973: 			}
  974: 
  975: 			if (!isVolume) {
  976: 				char * tmp2 = substitutename + substitutename_off;
  977: 				for(bufindex = 0; bufindex < (substitutename_len - substitutename_off); bufindex++) {
  978: 					*(path + bufindex) = *(tmp2 + bufindex);
  979: 				}
  980: 
  981: 				*(path + bufindex) = 0;
  982: 				j = bufindex;
  983: 			} else {
  984: 				j = len;
  985: 			}
  986: 
  987: 
  988: #if VIRTUAL_CWD_DEBUG
  989: 			fprintf(stderr, "reparse: print: %s ", printname);
  990: 			fprintf(stderr, "sub: %s ", substitutename);
  991: 			fprintf(stderr, "resolved: %s ", path);
  992: #endif
  993: 			tsrm_free_alloca(pbuffer, use_heap_large);
  994: 
  995: 			if(isabsolute == 1) {
  996: 				if (!((j == 3) && (path[1] == ':') && (path[2] == '\\'))) {
  997: 					/* use_realpath is 0 in the call below coz path is absolute*/
  998: 					j = tsrm_realpath_r(path, 0, j, ll, t, 0, is_dir, &directory TSRMLS_CC);
  999: 					if(j < 0) {
 1000: 						tsrm_free_alloca(tmp, use_heap);
 1001: 						return -1;
 1002: 					}
 1003: 				}
 1004: 			}
 1005: 			else {
 1006: 				if(i + j >= MAXPATHLEN - 1) {
 1007: 					tsrm_free_alloca(tmp, use_heap);
 1008: 					return -1;
 1009: 				}
 1010: 
 1011: 				memmove(path+i, path, j+1);
 1012: 				memcpy(path, tmp, i-1);
 1013: 				path[i-1] = DEFAULT_SLASH;
 1014: 				j  = tsrm_realpath_r(path, start, i + j, ll, t, use_realpath, is_dir, &directory TSRMLS_CC);
 1015: 				if(j < 0) {
 1016: 					tsrm_free_alloca(tmp, use_heap);
 1017: 					return -1;
 1018: 				}
 1019: 			}
 1020: 			directory = (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
 1021: 
 1022: 			if(link_is_dir) {
 1023: 				*link_is_dir = directory;
 1024: 			}
 1025: 		}
 1026: 		else {
 1027: 			if (save) {
 1028: 				directory = (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
 1029: 				if (is_dir && !directory) {
 1030: 					/* not a directory */
 1031: 					return -1;
 1032: 				}
 1033: 			}
 1034: 
 1035: #elif defined(NETWARE)
 1036: 		save = 0;
 1037: 		tmp = tsrm_do_alloca(len+1, use_heap);
 1038: 		memcpy(tmp, path, len+1);
 1039: #else
 1040: 		if (save && php_sys_lstat(path, &st) < 0) {
 1041: 			if (use_realpath == CWD_REALPATH) {
 1042: 				/* file not found */
 1043: 				return -1;
 1044: 			}
 1045: 			/* continue resolution anyway but don't save result in the cache */
 1046: 			save = 0;
 1047: 		}
 1048: 
 1049: 		tmp = tsrm_do_alloca(len+1, use_heap);
 1050: 		memcpy(tmp, path, len+1);
 1051: 
 1052: 		if (save && S_ISLNK(st.st_mode)) {
 1053: 			if (++(*ll) > LINK_MAX || (j = php_sys_readlink(tmp, path, MAXPATHLEN)) < 0) {
 1054: 				/* too many links or broken symlinks */
 1055: 				tsrm_free_alloca(tmp, use_heap);
 1056: 				return -1;
 1057: 			}
 1058: 			path[j] = 0;
 1059: 			if (IS_ABSOLUTE_PATH(path, j)) {
 1060: 				j = tsrm_realpath_r(path, 1, j, ll, t, use_realpath, is_dir, &directory TSRMLS_CC);
 1061: 				if (j < 0) {
 1062: 					tsrm_free_alloca(tmp, use_heap);
 1063: 					return -1;
 1064: 				}
 1065: 			} else {
 1066: 				if (i + j >= MAXPATHLEN-1) {
 1067: 					tsrm_free_alloca(tmp, use_heap);
 1068: 					return -1; /* buffer overflow */
 1069: 				}
 1070: 				memmove(path+i, path, j+1);
 1071: 				memcpy(path, tmp, i-1);
 1072: 				path[i-1] = DEFAULT_SLASH;
 1073: 				j = tsrm_realpath_r(path, start, i + j, ll, t, use_realpath, is_dir, &directory TSRMLS_CC);
 1074: 				if (j < 0) {
 1075: 					tsrm_free_alloca(tmp, use_heap);
 1076: 					return -1;
 1077: 				}
 1078: 			}
 1079: 			if (link_is_dir) {
 1080: 				*link_is_dir = directory;
 1081: 			}
 1082: 		} else {
 1083: 			if (save) {
 1084: 				directory = S_ISDIR(st.st_mode);
 1085: 				if (link_is_dir) {
 1086: 					*link_is_dir = directory;
 1087: 				}
 1088: 				if (is_dir && !directory) {
 1089: 					/* not a directory */
 1090: 					tsrm_free_alloca(tmp, use_heap);
 1091: 					return -1;
 1092: 				}
 1093: 			}
 1094: #endif
 1095: 			if (i - 1 <= start) {
 1096: 				j = start;
 1097: 			} else {
 1098: 				/* some leading directories may be unaccessable */
 1099: 				j = tsrm_realpath_r(path, start, i-1, ll, t, save ? CWD_FILEPATH : use_realpath, 1, NULL TSRMLS_CC);
 1100: 				if (j > start) {
 1101: 					path[j++] = DEFAULT_SLASH;
 1102: 				}
 1103: 			}
 1104: #ifdef TSRM_WIN32
 1105: 			if (j < 0 || j + len - i >= MAXPATHLEN-1) {
 1106: 				tsrm_free_alloca(tmp, use_heap);
 1107: 				return -1;
 1108: 			}
 1109: 			if (save) {
 1110: 				i = strlen(data.cFileName);
 1111: 				memcpy(path+j, data.cFileName, i+1);
 1112: 				j += i;
 1113: 			} else {
 1114: 				/* use the original file or directory name as it wasn't found */
 1115: 				memcpy(path+j, tmp+i, len-i+1);
 1116: 				j += (len-i);
 1117: 			}
 1118: 		}
 1119: #else
 1120: 			if (j < 0 || j + len - i >= MAXPATHLEN-1) {
 1121: 				tsrm_free_alloca(tmp, use_heap);
 1122: 				return -1;
 1123: 			}
 1124: 			memcpy(path+j, tmp+i, len-i+1);
 1125: 			j += (len-i);
 1126: 		}
 1127: #endif
 1128: 
 1129: 		if (save && start && CWDG(realpath_cache_size_limit)) {
 1130: 			/* save absolute path in the cache */
 1131: 			realpath_cache_add(tmp, len, path, j, directory, *t TSRMLS_CC);
 1132: 		}
 1133: 
 1134: 		tsrm_free_alloca(tmp, use_heap);
 1135: 		return j;
 1136: 	}
 1137: }
 1138: /* }}} */
 1139: 
 1140: /* Resolve path relatively to state and put the real path into state */
 1141: /* returns 0 for ok, 1 for error */
 1142: CWD_API int virtual_file_ex(cwd_state *state, const char *path, verify_path_func verify_path, int use_realpath TSRMLS_DC) /* {{{ */
 1143: {
 1144: 	int path_length = strlen(path);
 1145: 	char resolved_path[MAXPATHLEN];
 1146: 	int start = 1;
 1147: 	int ll = 0;
 1148: 	time_t t;
 1149: 	int ret;
 1150: 	int add_slash;
 1151: 	void *tmp;
 1152: 
 1153: 	if (path_length == 0 || path_length >= MAXPATHLEN-1) {
 1154: #ifdef TSRM_WIN32
 1155: # if _MSC_VER < 1300
 1156: 		errno = EINVAL;
 1157: # else
 1158: 		_set_errno(EINVAL);
 1159: # endif
 1160: #else
 1161: 		errno = EINVAL;
 1162: #endif
 1163: 		return 1;
 1164: 	}
 1165: 
 1166: #if VIRTUAL_CWD_DEBUG
 1167: 	fprintf(stderr,"cwd = %s path = %s\n", state->cwd, path);
 1168: #endif
 1169: 
 1170: 	/* cwd_length can be 0 when getcwd() fails.
 1171: 	 * This can happen under solaris when a dir does not have read permissions
 1172: 	 * but *does* have execute permissions */
 1173: 	if (!IS_ABSOLUTE_PATH(path, path_length)) {
 1174: 		if (state->cwd_length == 0) {
 1175: 			/* resolve relative path */
 1176: 			start = 0;
 1177: 			memcpy(resolved_path , path, path_length + 1);
 1178: 		} else {
 1179: 			int state_cwd_length = state->cwd_length;
 1180: 
 1181: #ifdef TSRM_WIN32
 1182: 			if (IS_SLASH(path[0])) {
 1183: 				if (state->cwd[1] == ':') {
 1184: 					/* Copy only the drive name */
 1185: 					state_cwd_length = 2;
 1186: 				} else if (IS_UNC_PATH(state->cwd, state->cwd_length)) {
 1187: 					/* Copy only the share name */
 1188: 					state_cwd_length = 2;
 1189: 					while (IS_SLASH(state->cwd[state_cwd_length])) {
 1190: 						state_cwd_length++;
 1191: 					}
 1192: 					while (state->cwd[state_cwd_length] &&
 1193: 							!IS_SLASH(state->cwd[state_cwd_length])) {
 1194: 						state_cwd_length++;
 1195: 					}
 1196: 					while (IS_SLASH(state->cwd[state_cwd_length])) {
 1197: 						state_cwd_length++;
 1198: 					}
 1199: 					while (state->cwd[state_cwd_length] &&
 1200: 							!IS_SLASH(state->cwd[state_cwd_length])) {
 1201: 						state_cwd_length++;
 1202: 					}
 1203: 				}
 1204: 			}
 1205: #endif
 1206: 			if (path_length + state_cwd_length + 1 >= MAXPATHLEN-1) {
 1207: 				return 1;
 1208: 			}
 1209: 			memcpy(resolved_path, state->cwd, state_cwd_length);
 1210: 			if (resolved_path[state_cwd_length-1] == DEFAULT_SLASH) {
 1211: 				memcpy(resolved_path + state_cwd_length, path, path_length + 1);
 1212: 				path_length += state_cwd_length;
 1213: 			} else {
 1214: 				resolved_path[state_cwd_length] = DEFAULT_SLASH;
 1215: 				memcpy(resolved_path + state_cwd_length + 1, path, path_length + 1);
 1216: 				path_length += state_cwd_length + 1;
 1217: 			}
 1218: 		}
 1219: 	} else {
 1220: #ifdef TSRM_WIN32
 1221: 		if (path_length > 2 && path[1] == ':' && !IS_SLASH(path[2])) {
 1222: 			resolved_path[0] = path[0];
 1223: 			resolved_path[1] = ':';
 1224: 			resolved_path[2] = DEFAULT_SLASH;
 1225: 			memcpy(resolved_path + 3, path + 2, path_length - 1);
 1226: 			path_length++;
 1227: 		} else
 1228: #endif
 1229: 		memcpy(resolved_path, path, path_length + 1);
 1230: 	}
 1231: 
 1232: #ifdef TSRM_WIN32
 1233: 	if (memchr(resolved_path, '*', path_length) ||
 1234: 		memchr(resolved_path, '?', path_length)) {
 1235: 		return 1;
 1236: 	}
 1237: #endif
 1238: 
 1239: #ifdef TSRM_WIN32
 1240: 	if (IS_UNC_PATH(resolved_path, path_length)) {
 1241: 		/* skip UNC name */
 1242: 		resolved_path[0] = DEFAULT_SLASH;
 1243: 		resolved_path[1] = DEFAULT_SLASH;
 1244: 		start = 2;
 1245: 		while (!IS_SLASH(resolved_path[start])) {
 1246: 			if (resolved_path[start] == 0) {
 1247: 				goto verify;
 1248: 			}
 1249: 			resolved_path[start] = toupper(resolved_path[start]);
 1250: 			start++;
 1251: 		}
 1252: 		resolved_path[start++] = DEFAULT_SLASH;
 1253: 		while (!IS_SLASH(resolved_path[start])) {
 1254: 			if (resolved_path[start] == 0) {
 1255: 				goto verify;
 1256: 			}
 1257: 			resolved_path[start] = toupper(resolved_path[start]);
 1258: 			start++;
 1259: 		}
 1260: 		resolved_path[start++] = DEFAULT_SLASH;
 1261: 	} else if (IS_ABSOLUTE_PATH(resolved_path, path_length)) {
 1262: 		/* skip DRIVE name */
 1263: 		resolved_path[0] = toupper(resolved_path[0]);
 1264: 		resolved_path[2] = DEFAULT_SLASH;
 1265: 		start = 3;
 1266: 	}
 1267: #elif defined(NETWARE)
 1268: 	if (IS_ABSOLUTE_PATH(resolved_path, path_length)) {
 1269: 		/* skip VOLUME name */
 1270: 		start = 0;
 1271: 		while (start != ':') {
 1272: 			if (resolved_path[start] == 0) return -1;
 1273: 			start++;
 1274: 		}
 1275: 		start++;
 1276: 		if (!IS_SLASH(resolved_path[start])) return -1;
 1277: 		resolved_path[start++] = DEFAULT_SLASH;
 1278: 	}
 1279: #endif
 1280: 
 1281: 	add_slash = (use_realpath != CWD_REALPATH) && path_length > 0 && IS_SLASH(resolved_path[path_length-1]);
 1282: 	t = CWDG(realpath_cache_ttl) ? 0 : -1;
 1283: 	path_length = tsrm_realpath_r(resolved_path, start, path_length, &ll, &t, use_realpath, 0, NULL TSRMLS_CC);
 1284: 
 1285: 	if (path_length < 0) {
 1286: 		errno = ENOENT;
 1287: 		return 1;
 1288: 	}
 1289: 
 1290: 	if (!start && !path_length) {
 1291: 		resolved_path[path_length++] = '.';
 1292: 	}
 1293: 	if (add_slash && path_length && !IS_SLASH(resolved_path[path_length-1])) {
 1294: 		if (path_length >= MAXPATHLEN-1) {
 1295: 			return -1;
 1296: 		}
 1297: 		resolved_path[path_length++] = DEFAULT_SLASH;
 1298: 	}
 1299: 	resolved_path[path_length] = 0;
 1300: 
 1301: #ifdef TSRM_WIN32
 1302: verify:
 1303: #endif
 1304: 	if (verify_path) {
 1305: 		cwd_state old_state;
 1306: 
 1307: 		CWD_STATE_COPY(&old_state, state);
 1308: 		state->cwd_length = path_length;
 1309: 
 1310: 		tmp = realloc(state->cwd, state->cwd_length+1);
 1311: 		if (tmp == NULL) {
 1312: #if VIRTUAL_CWD_DEBUG
 1313: 			fprintf (stderr, "Out of memory\n");
 1314: #endif
 1315: 			return 1;
 1316: 		}
 1317: 		state->cwd = (char *) tmp;
 1318: 
 1319: 		memcpy(state->cwd, resolved_path, state->cwd_length+1);
 1320: 		if (verify_path(state)) {
 1321: 			CWD_STATE_FREE(state);
 1322: 			*state = old_state;
 1323: 			ret = 1;
 1324: 		} else {
 1325: 			CWD_STATE_FREE(&old_state);
 1326: 			ret = 0;
 1327: 		}
 1328: 	} else {
 1329: 		state->cwd_length = path_length;
 1330: 		tmp = realloc(state->cwd, state->cwd_length+1);
 1331: 		if (tmp == NULL) {
 1332: #if VIRTUAL_CWD_DEBUG
 1333: 			fprintf (stderr, "Out of memory\n");
 1334: #endif
 1335: 			return 1;
 1336: 		}
 1337: 		state->cwd = (char *) tmp;
 1338: 
 1339: 		memcpy(state->cwd, resolved_path, state->cwd_length+1);
 1340: 		ret = 0;
 1341: 	}
 1342: 
 1343: #if VIRTUAL_CWD_DEBUG
 1344: 	fprintf (stderr, "virtual_file_ex() = %s\n",state->cwd);
 1345: #endif
 1346: 	return (ret);
 1347: }
 1348: /* }}} */
 1349: 
 1350: CWD_API int virtual_chdir(const char *path TSRMLS_DC) /* {{{ */
 1351: {
 1352: 	return virtual_file_ex(&CWDG(cwd), path, php_is_dir_ok, CWD_REALPATH TSRMLS_CC)?-1:0;
 1353: }
 1354: /* }}} */
 1355: 
 1356: CWD_API int virtual_chdir_file(const char *path, int (*p_chdir)(const char *path TSRMLS_DC) TSRMLS_DC) /* {{{ */
 1357: {
 1358: 	int length = strlen(path);
 1359: 	char *temp;
 1360: 	int retval;
 1361: 	TSRM_ALLOCA_FLAG(use_heap)
 1362: 
 1363: 	if (length == 0) {
 1364: 		return 1; /* Can't cd to empty string */
 1365: 	}
 1366: 	while(--length >= 0 && !IS_SLASH(path[length])) {
 1367: 	}
 1368: 
 1369: 	if (length == -1) {
 1370: 		/* No directory only file name */
 1371: 		errno = ENOENT;
 1372: 		return -1;
 1373: 	}
 1374: 
 1375: 	if (length == COPY_WHEN_ABSOLUTE(path) && IS_ABSOLUTE_PATH(path, length+1)) { /* Also use trailing slash if this is absolute */
 1376: 		length++;
 1377: 	}
 1378: 	temp = (char *) tsrm_do_alloca(length+1, use_heap);
 1379: 	memcpy(temp, path, length);
 1380: 	temp[length] = 0;
 1381: #if VIRTUAL_CWD_DEBUG
 1382: 	fprintf (stderr, "Changing directory to %s\n", temp);
 1383: #endif
 1384: 	retval = p_chdir(temp TSRMLS_CC);
 1385: 	tsrm_free_alloca(temp, use_heap);
 1386: 	return retval;
 1387: }
 1388: /* }}} */
 1389: 
 1390: CWD_API char *virtual_realpath(const char *path, char *real_path TSRMLS_DC) /* {{{ */
 1391: {
 1392: 	cwd_state new_state;
 1393: 	char *retval;
 1394: 	char cwd[MAXPATHLEN];
 1395: 
 1396: 	/* realpath("") returns CWD */
 1397: 	if (!*path) {
 1398: 		new_state.cwd = (char*)malloc(1);
 1399: 		if (new_state.cwd == NULL) {
 1400: 			retval = NULL;
 1401: 			goto end;
 1402: 		}
 1403: 		new_state.cwd[0] = '\0';
 1404: 		new_state.cwd_length = 0;
 1405: 		if (VCWD_GETCWD(cwd, MAXPATHLEN)) {
 1406: 			path = cwd;
 1407: 		}
 1408: 	} else if (!IS_ABSOLUTE_PATH(path, strlen(path))) {
 1409: 		CWD_STATE_COPY(&new_state, &CWDG(cwd));
 1410: 	} else {
 1411: 		new_state.cwd = (char*)malloc(1);
 1412: 		if (new_state.cwd == NULL) {
 1413: 			retval = NULL;
 1414: 			goto end;
 1415: 		}
 1416: 		new_state.cwd[0] = '\0';
 1417: 		new_state.cwd_length = 0;
 1418: 	}
 1419: 
 1420: 	if (virtual_file_ex(&new_state, path, NULL, CWD_REALPATH TSRMLS_CC)==0) {
 1421: 		int len = new_state.cwd_length>MAXPATHLEN-1?MAXPATHLEN-1:new_state.cwd_length;
 1422: 
 1423: 		memcpy(real_path, new_state.cwd, len);
 1424: 		real_path[len] = '\0';
 1425: 		retval = real_path;
 1426: 	} else {
 1427: 		retval = NULL;
 1428: 	}
 1429: 
 1430: 	CWD_STATE_FREE(&new_state);
 1431: end:
 1432: 	return retval;
 1433: }
 1434: /* }}} */
 1435: 
 1436: CWD_API int virtual_filepath_ex(const char *path, char **filepath, verify_path_func verify_path TSRMLS_DC) /* {{{ */
 1437: {
 1438: 	cwd_state new_state;
 1439: 	int retval;
 1440: 
 1441: 	CWD_STATE_COPY(&new_state, &CWDG(cwd));
 1442: 	retval = virtual_file_ex(&new_state, path, verify_path, CWD_FILEPATH TSRMLS_CC);
 1443: 
 1444: 	*filepath = new_state.cwd;
 1445: 
 1446: 	return retval;
 1447: 
 1448: }
 1449: /* }}} */
 1450: 
 1451: CWD_API int virtual_filepath(const char *path, char **filepath TSRMLS_DC) /* {{{ */
 1452: {
 1453: 	return virtual_filepath_ex(path, filepath, php_is_file_ok TSRMLS_CC);
 1454: }
 1455: /* }}} */
 1456: 
 1457: CWD_API FILE *virtual_fopen(const char *path, const char *mode TSRMLS_DC) /* {{{ */
 1458: {
 1459: 	cwd_state new_state;
 1460: 	FILE *f;
 1461: 
 1462: 	if (path[0] == '\0') { /* Fail to open empty path */
 1463: 		return NULL;
 1464: 	}
 1465: 
 1466: 	CWD_STATE_COPY(&new_state, &CWDG(cwd));
 1467: 	if (virtual_file_ex(&new_state, path, NULL, CWD_EXPAND TSRMLS_CC)) {
 1468: 		CWD_STATE_FREE(&new_state);
 1469: 		return NULL;
 1470: 	}
 1471: 
 1472: 	f = fopen(new_state.cwd, mode);
 1473: 
 1474: 	CWD_STATE_FREE(&new_state);
 1475: 	return f;
 1476: }
 1477: /* }}} */
 1478: 
 1479: CWD_API int virtual_access(const char *pathname, int mode TSRMLS_DC) /* {{{ */
 1480: {
 1481: 	cwd_state new_state;
 1482: 	int ret;
 1483: 
 1484: 	CWD_STATE_COPY(&new_state, &CWDG(cwd));
 1485: 	if (virtual_file_ex(&new_state, pathname, NULL, CWD_REALPATH TSRMLS_CC)) {
 1486: 		CWD_STATE_FREE(&new_state);
 1487: 		return -1;
 1488: 	}
 1489: 
 1490: #if defined(TSRM_WIN32)
 1491: 	ret = tsrm_win32_access(new_state.cwd, mode TSRMLS_CC);
 1492: #else
 1493: 	ret = access(new_state.cwd, mode);
 1494: #endif
 1495: 
 1496: 	CWD_STATE_FREE(&new_state);
 1497: 
 1498: 	return ret;
 1499: }
 1500: /* }}} */
 1501: 
 1502: #if HAVE_UTIME
 1503: #ifdef TSRM_WIN32
 1504: static void UnixTimeToFileTime(time_t t, LPFILETIME pft) /* {{{ */
 1505: {
 1506: 	// Note that LONGLONG is a 64-bit value
 1507: 	LONGLONG ll;
 1508: 
 1509: 	ll = Int32x32To64(t, 10000000) + 116444736000000000;
 1510: 	pft->dwLowDateTime = (DWORD)ll;
 1511: 	pft->dwHighDateTime = ll >> 32;
 1512: }
 1513: /* }}} */
 1514: 
 1515: TSRM_API int win32_utime(const char *filename, struct utimbuf *buf) /* {{{ */
 1516: {
 1517: 	FILETIME mtime, atime;
 1518: 	HANDLE hFile;
 1519: 
 1520: 	hFile = CreateFile(filename, GENERIC_WRITE, FILE_SHARE_WRITE|FILE_SHARE_READ, NULL,
 1521: 				 OPEN_ALWAYS, FILE_FLAG_BACKUP_SEMANTICS, NULL);
 1522: 
 1523: 	/* OPEN_ALWAYS mode sets the last error to ERROR_ALREADY_EXISTS but
 1524: 	   the CreateFile operation succeeds */
 1525: 	if (GetLastError() == ERROR_ALREADY_EXISTS) {
 1526: 		SetLastError(0);
 1527: 	}
 1528: 
 1529: 	if ( hFile == INVALID_HANDLE_VALUE ) {
 1530: 		return -1;
 1531: 	}
 1532: 
 1533: 	if (!buf) {
 1534: 		SYSTEMTIME st;
 1535: 		GetSystemTime(&st);
 1536: 		SystemTimeToFileTime(&st, &mtime);
 1537: 		atime = mtime;
 1538: 	} else {
 1539: 		UnixTimeToFileTime(buf->modtime, &mtime);
 1540: 		UnixTimeToFileTime(buf->actime, &atime);
 1541: 	}
 1542: 	if (!SetFileTime(hFile, NULL, &atime, &mtime)) {
 1543: 		CloseHandle(hFile);
 1544: 		return -1;
 1545: 	}
 1546: 	CloseHandle(hFile);
 1547: 	return 1;
 1548: }
 1549: /* }}} */
 1550: #endif
 1551: 
 1552: CWD_API int virtual_utime(const char *filename, struct utimbuf *buf TSRMLS_DC) /* {{{ */
 1553: {
 1554: 	cwd_state new_state;
 1555: 	int ret;
 1556: 
 1557: 	CWD_STATE_COPY(&new_state, &CWDG(cwd));
 1558: 	if (virtual_file_ex(&new_state, filename, NULL, CWD_REALPATH TSRMLS_CC)) {
 1559: 		CWD_STATE_FREE(&new_state);
 1560: 		return -1;
 1561: 	}
 1562: 
 1563: #ifdef TSRM_WIN32
 1564: 	ret = win32_utime(new_state.cwd, buf);
 1565: #else
 1566: 	ret = utime(new_state.cwd, buf);
 1567: #endif
 1568: 
 1569: 	CWD_STATE_FREE(&new_state);
 1570: 	return ret;
 1571: }
 1572: /* }}} */
 1573: #endif
 1574: 
 1575: CWD_API int virtual_chmod(const char *filename, mode_t mode TSRMLS_DC) /* {{{ */
 1576: {
 1577: 	cwd_state new_state;
 1578: 	int ret;
 1579: 
 1580: 	CWD_STATE_COPY(&new_state, &CWDG(cwd));
 1581: 	if (virtual_file_ex(&new_state, filename, NULL, CWD_REALPATH TSRMLS_CC)) {
 1582: 		CWD_STATE_FREE(&new_state);
 1583: 		return -1;
 1584: 	}
 1585: 
 1586: 	ret = chmod(new_state.cwd, mode);
 1587: 
 1588: 	CWD_STATE_FREE(&new_state);
 1589: 	return ret;
 1590: }
 1591: /* }}} */
 1592: 
 1593: #if !defined(TSRM_WIN32) && !defined(NETWARE)
 1594: CWD_API int virtual_chown(const char *filename, uid_t owner, gid_t group, int link TSRMLS_DC) /* {{{ */
 1595: {
 1596: 	cwd_state new_state;
 1597: 	int ret;
 1598: 
 1599: 	CWD_STATE_COPY(&new_state, &CWDG(cwd));
 1600: 	if (virtual_file_ex(&new_state, filename, NULL, CWD_REALPATH TSRMLS_CC)) {
 1601: 		CWD_STATE_FREE(&new_state);
 1602: 		return -1;
 1603: 	}
 1604: 
 1605: 	if (link) {
 1606: #if HAVE_LCHOWN
 1607: 		ret = lchown(new_state.cwd, owner, group);
 1608: #else
 1609: 		ret = -1;
 1610: #endif
 1611: 	} else {
 1612: 		ret = chown(new_state.cwd, owner, group);
 1613: 	}
 1614: 
 1615: 	CWD_STATE_FREE(&new_state);
 1616: 	return ret;
 1617: }
 1618: /* }}} */
 1619: #endif
 1620: 
 1621: CWD_API int virtual_open(const char *path TSRMLS_DC, int flags, ...) /* {{{ */
 1622: {
 1623: 	cwd_state new_state;
 1624: 	int f;
 1625: 
 1626: 	CWD_STATE_COPY(&new_state, &CWDG(cwd));
 1627: 	if (virtual_file_ex(&new_state, path, NULL, CWD_FILEPATH TSRMLS_CC)) {
 1628: 		CWD_STATE_FREE(&new_state);
 1629: 		return -1;
 1630: 	}
 1631: 
 1632: 	if (flags & O_CREAT) {
 1633: 		mode_t mode;
 1634: 		va_list arg;
 1635: 
 1636: 		va_start(arg, flags);
 1637: 		mode = (mode_t) va_arg(arg, int);
 1638: 		va_end(arg);
 1639: 
 1640: 		f = open(new_state.cwd, flags, mode);
 1641: 	} else {
 1642: 		f = open(new_state.cwd, flags);
 1643: 	}
 1644: 	CWD_STATE_FREE(&new_state);
 1645: 	return f;
 1646: }
 1647: /* }}} */
 1648: 
 1649: CWD_API int virtual_creat(const char *path, mode_t mode TSRMLS_DC) /* {{{ */
 1650: {
 1651: 	cwd_state new_state;
 1652: 	int f;
 1653: 
 1654: 	CWD_STATE_COPY(&new_state, &CWDG(cwd));
 1655: 	if (virtual_file_ex(&new_state, path, NULL, CWD_FILEPATH TSRMLS_CC)) {
 1656: 		CWD_STATE_FREE(&new_state);
 1657: 		return -1;
 1658: 	}
 1659: 
 1660: 	f = creat(new_state.cwd,  mode);
 1661: 
 1662: 	CWD_STATE_FREE(&new_state);
 1663: 	return f;
 1664: }
 1665: /* }}} */
 1666: 
 1667: CWD_API int virtual_rename(char *oldname, char *newname TSRMLS_DC) /* {{{ */
 1668: {
 1669: 	cwd_state old_state;
 1670: 	cwd_state new_state;
 1671: 	int retval;
 1672: 
 1673: 	CWD_STATE_COPY(&old_state, &CWDG(cwd));
 1674: 	if (virtual_file_ex(&old_state, oldname, NULL, CWD_EXPAND TSRMLS_CC)) {
 1675: 		CWD_STATE_FREE(&old_state);
 1676: 		return -1;
 1677: 	}
 1678: 	oldname = old_state.cwd;
 1679: 
 1680: 	CWD_STATE_COPY(&new_state, &CWDG(cwd));
 1681: 	if (virtual_file_ex(&new_state, newname, NULL, CWD_EXPAND TSRMLS_CC)) {
 1682: 		CWD_STATE_FREE(&old_state);
 1683: 		CWD_STATE_FREE(&new_state);
 1684: 		return -1;
 1685: 	}
 1686: 	newname = new_state.cwd;
 1687: 
 1688: 	/* rename on windows will fail if newname already exists.
 1689: 	   MoveFileEx has to be used */
 1690: #ifdef TSRM_WIN32
 1691: 	/* MoveFileEx returns 0 on failure, other way 'round for this function */
 1692: 	retval = (MoveFileEx(oldname, newname, MOVEFILE_REPLACE_EXISTING|MOVEFILE_COPY_ALLOWED) == 0) ? -1 : 0;
 1693: #else
 1694: 	retval = rename(oldname, newname);
 1695: #endif
 1696: 
 1697: 	CWD_STATE_FREE(&old_state);
 1698: 	CWD_STATE_FREE(&new_state);
 1699: 
 1700: 	return retval;
 1701: }
 1702: /* }}} */
 1703: 
 1704: CWD_API int virtual_stat(const char *path, struct stat *buf TSRMLS_DC) /* {{{ */
 1705: {
 1706: 	cwd_state new_state;
 1707: 	int retval;
 1708: 
 1709: 	CWD_STATE_COPY(&new_state, &CWDG(cwd));
 1710: 	if (virtual_file_ex(&new_state, path, NULL, CWD_REALPATH TSRMLS_CC)) {
 1711: 		CWD_STATE_FREE(&new_state);
 1712: 		return -1;
 1713: 	}
 1714: 
 1715: 	retval = php_sys_stat(new_state.cwd, buf);
 1716: 
 1717: 	CWD_STATE_FREE(&new_state);
 1718: 	return retval;
 1719: }
 1720: /* }}} */
 1721: 
 1722: CWD_API int virtual_lstat(const char *path, struct stat *buf TSRMLS_DC) /* {{{ */
 1723: {
 1724: 	cwd_state new_state;
 1725: 	int retval;
 1726: 
 1727: 	CWD_STATE_COPY(&new_state, &CWDG(cwd));
 1728: 	if (virtual_file_ex(&new_state, path, NULL, CWD_EXPAND TSRMLS_CC)) {
 1729: 		CWD_STATE_FREE(&new_state);
 1730: 		return -1;
 1731: 	}
 1732: 
 1733: 	retval = php_sys_lstat(new_state.cwd, buf);
 1734: 
 1735: 	CWD_STATE_FREE(&new_state);
 1736: 	return retval;
 1737: }
 1738: /* }}} */
 1739: 
 1740: CWD_API int virtual_unlink(const char *path TSRMLS_DC) /* {{{ */
 1741: {
 1742: 	cwd_state new_state;
 1743: 	int retval;
 1744: 
 1745: 	CWD_STATE_COPY(&new_state, &CWDG(cwd));
 1746: 	if (virtual_file_ex(&new_state, path, NULL, CWD_EXPAND TSRMLS_CC)) {
 1747: 		CWD_STATE_FREE(&new_state);
 1748: 		return -1;
 1749: 	}
 1750: 
 1751: 	retval = unlink(new_state.cwd);
 1752: 
 1753: 	CWD_STATE_FREE(&new_state);
 1754: 	return retval;
 1755: }
 1756: /* }}} */
 1757: 
 1758: CWD_API int virtual_mkdir(const char *pathname, mode_t mode TSRMLS_DC) /* {{{ */
 1759: {
 1760: 	cwd_state new_state;
 1761: 	int retval;
 1762: 
 1763: 	CWD_STATE_COPY(&new_state, &CWDG(cwd));
 1764: 	if (virtual_file_ex(&new_state, pathname, NULL, CWD_FILEPATH TSRMLS_CC)) {
 1765: 		CWD_STATE_FREE(&new_state);
 1766: 		return -1;
 1767: 	}
 1768: 
 1769: #ifdef TSRM_WIN32
 1770: 	retval = mkdir(new_state.cwd);
 1771: #else
 1772: 	retval = mkdir(new_state.cwd, mode);
 1773: #endif
 1774: 	CWD_STATE_FREE(&new_state);
 1775: 	return retval;
 1776: }
 1777: /* }}} */
 1778: 
 1779: CWD_API int virtual_rmdir(const char *pathname TSRMLS_DC) /* {{{ */
 1780: {
 1781: 	cwd_state new_state;
 1782: 	int retval;
 1783: 
 1784: 	CWD_STATE_COPY(&new_state, &CWDG(cwd));
 1785: 	if (virtual_file_ex(&new_state, pathname, NULL, CWD_EXPAND TSRMLS_CC)) {
 1786: 		CWD_STATE_FREE(&new_state);
 1787: 		return -1;
 1788: 	}
 1789: 
 1790: 	retval = rmdir(new_state.cwd);
 1791: 
 1792: 	CWD_STATE_FREE(&new_state);
 1793: 	return retval;
 1794: }
 1795: /* }}} */
 1796: 
 1797: #ifdef TSRM_WIN32
 1798: DIR *opendir(const char *name);
 1799: #endif
 1800: 
 1801: CWD_API DIR *virtual_opendir(const char *pathname TSRMLS_DC) /* {{{ */
 1802: {
 1803: 	cwd_state new_state;
 1804: 	DIR *retval;
 1805: 
 1806: 	CWD_STATE_COPY(&new_state, &CWDG(cwd));
 1807: 	if (virtual_file_ex(&new_state, pathname, NULL, CWD_REALPATH TSRMLS_CC)) {
 1808: 		CWD_STATE_FREE(&new_state);
 1809: 		return NULL;
 1810: 	}
 1811: 
 1812: 	retval = opendir(new_state.cwd);
 1813: 
 1814: 	CWD_STATE_FREE(&new_state);
 1815: 	return retval;
 1816: }
 1817: /* }}} */
 1818: 
 1819: #ifdef TSRM_WIN32
 1820: CWD_API FILE *virtual_popen(const char *command, const char *type TSRMLS_DC) /* {{{ */
 1821: {
 1822: 	return popen_ex(command, type, CWDG(cwd).cwd, NULL TSRMLS_CC);
 1823: }
 1824: /* }}} */
 1825: #elif defined(NETWARE)
 1826: /* On NetWare, the trick of prepending "cd cwd; " doesn't work so we need to perform
 1827:    a VCWD_CHDIR() and mutex it
 1828:  */
 1829: CWD_API FILE *virtual_popen(const char *command, const char *type TSRMLS_DC) /* {{{ */
 1830: {
 1831: 	char prev_cwd[MAXPATHLEN];
 1832: 	char *getcwd_result;
 1833: 	FILE *retval;
 1834: 
 1835: 	getcwd_result = VCWD_GETCWD(prev_cwd, MAXPATHLEN);
 1836: 	if (!getcwd_result) {
 1837: 		return NULL;
 1838: 	}
 1839: 
 1840: #ifdef ZTS
 1841: 	tsrm_mutex_lock(cwd_mutex);
 1842: #endif
 1843: 
 1844: 	VCWD_CHDIR(CWDG(cwd).cwd);
 1845: 	retval = popen(command, type);
 1846: 	VCWD_CHDIR(prev_cwd);
 1847: 
 1848: #ifdef ZTS
 1849: 	tsrm_mutex_unlock(cwd_mutex);
 1850: #endif
 1851: 
 1852: 	return retval;
 1853: }
 1854: /* }}} */
 1855: #else /* Unix */
 1856: CWD_API FILE *virtual_popen(const char *command, const char *type TSRMLS_DC) /* {{{ */
 1857: {
 1858: 	int command_length;
 1859: 	int dir_length, extra = 0;
 1860: 	char *command_line;
 1861: 	char *ptr, *dir;
 1862: 	FILE *retval;
 1863: 
 1864: 	command_length = strlen(command);
 1865: 
 1866: 	dir_length = CWDG(cwd).cwd_length;
 1867: 	dir = CWDG(cwd).cwd;
 1868: 	while (dir_length > 0) {
 1869: 		if (*dir == '\'') extra+=3;
 1870: 		dir++;
 1871: 		dir_length--;
 1872: 	}
 1873: 	dir_length = CWDG(cwd).cwd_length;
 1874: 	dir = CWDG(cwd).cwd;
 1875: 
 1876: 	ptr = command_line = (char *) malloc(command_length + sizeof("cd '' ; ") + dir_length + extra+1+1);
 1877: 	if (!command_line) {
 1878: 		return NULL;
 1879: 	}
 1880: 	memcpy(ptr, "cd ", sizeof("cd ")-1);
 1881: 	ptr += sizeof("cd ")-1;
 1882: 
 1883: 	if (CWDG(cwd).cwd_length == 0) {
 1884: 		*ptr++ = DEFAULT_SLASH;
 1885: 	} else {
 1886: 		*ptr++ = '\'';
 1887: 		while (dir_length > 0) {
 1888: 			switch (*dir) {
 1889: 			case '\'':
 1890: 				*ptr++ = '\'';
 1891: 				*ptr++ = '\\';
 1892: 				*ptr++ = '\'';
 1893: 				/* fall-through */
 1894: 			default:
 1895: 				*ptr++ = *dir;
 1896: 			}
 1897: 			dir++;
 1898: 			dir_length--;
 1899: 		}
 1900: 		*ptr++ = '\'';
 1901: 	}
 1902: 
 1903: 	*ptr++ = ' ';
 1904: 	*ptr++ = ';';
 1905: 	*ptr++ = ' ';
 1906: 
 1907: 	memcpy(ptr, command, command_length+1);
 1908: 	retval = popen(command_line, type);
 1909: 
 1910: 	free(command_line);
 1911: 	return retval;
 1912: }
 1913: /* }}} */
 1914: #endif
 1915: 
 1916: CWD_API char *tsrm_realpath(const char *path, char *real_path TSRMLS_DC) /* {{{ */
 1917: {
 1918: 	cwd_state new_state;
 1919: 	char cwd[MAXPATHLEN];
 1920: 
 1921: 	/* realpath("") returns CWD */
 1922: 	if (!*path) {
 1923: 		new_state.cwd = (char*)malloc(1);
 1924: 		if (new_state.cwd == NULL) {
 1925: 			return NULL;
 1926: 		}
 1927: 		new_state.cwd[0] = '\0';
 1928: 		new_state.cwd_length = 0;
 1929: 		if (VCWD_GETCWD(cwd, MAXPATHLEN)) {
 1930: 			path = cwd;
 1931: 		}
 1932: 	} else if (!IS_ABSOLUTE_PATH(path, strlen(path)) &&
 1933: 					VCWD_GETCWD(cwd, MAXPATHLEN)) {
 1934: 		new_state.cwd = strdup(cwd);
 1935: 		new_state.cwd_length = strlen(cwd);
 1936: 	} else {
 1937: 		new_state.cwd = (char*)malloc(1);
 1938: 		if (new_state.cwd == NULL) {
 1939: 			return NULL;
 1940: 		}
 1941: 		new_state.cwd[0] = '\0';
 1942: 		new_state.cwd_length = 0;
 1943: 	}
 1944: 
 1945: 	if (virtual_file_ex(&new_state, path, NULL, CWD_REALPATH TSRMLS_CC)) {
 1946: 		free(new_state.cwd);
 1947: 		return NULL;
 1948: 	}
 1949: 
 1950: 	if (real_path) {
 1951: 		int copy_len = new_state.cwd_length>MAXPATHLEN-1 ? MAXPATHLEN-1 : new_state.cwd_length;
 1952: 		memcpy(real_path, new_state.cwd, copy_len);
 1953: 		real_path[copy_len] = '\0';
 1954: 		free(new_state.cwd);
 1955: 		return real_path;
 1956: 	} else {
 1957: 		return new_state.cwd;
 1958: 	}
 1959: }
 1960: /* }}} */
 1961: 
 1962: /*
 1963:  * Local variables:
 1964:  * tab-width: 4
 1965:  * c-basic-offset: 4
 1966:  * End:
 1967:  */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>