Annotation of embedaddon/php/TSRM/tsrm_virtual_cwd.c, revision 1.1

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

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