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

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

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