Annotation of embedaddon/php/TSRM/tsrm_virtual_cwd.c, revision 1.1.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>