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