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>