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