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