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