1 : /*
2 : +----------------------------------------------------------------------+
3 : | PHP Version 5 |
4 : +----------------------------------------------------------------------+
5 : | Copyright (c) 1997-2009 The PHP Group |
6 : +----------------------------------------------------------------------+
7 : | This source file is subject to version 3.01 of the PHP license, |
8 : | that is bundled with this package in the file LICENSE, and is |
9 : | available through the world-wide-web at the following url: |
10 : | http://www.php.net/license/3_01.txt |
11 : | If you did not receive a copy of the PHP license and are unable to |
12 : | obtain it through the world-wide-web, please send a note to |
13 : | license@php.net so we can mail you a copy immediately. |
14 : +----------------------------------------------------------------------+
15 : | Authors: Andi Gutmans <andi@zend.com> |
16 : | Sascha Schumann <sascha@schumann.cx> |
17 : +----------------------------------------------------------------------+
18 : */
19 :
20 : /* $Id: tsrm_virtual_cwd.c 272374 2008-12-31 11:17:49Z sebastian $ */
21 :
22 : #include <sys/types.h>
23 : #include <sys/stat.h>
24 : #include <string.h>
25 : #include <stdio.h>
26 : #include <limits.h>
27 : #include <errno.h>
28 : #include <stdlib.h>
29 : #include <fcntl.h>
30 : #include <time.h>
31 :
32 : #include "tsrm_virtual_cwd.h"
33 : #include "tsrm_strtok_r.h"
34 :
35 : #ifdef TSRM_WIN32
36 : #include <io.h>
37 : #include "tsrm_win32.h"
38 : #endif
39 :
40 : #ifdef NETWARE
41 : #include <fsio.h>
42 : #endif
43 :
44 : #ifndef HAVE_REALPATH
45 : #define realpath(x,y) strcpy(y,x)
46 : #endif
47 :
48 : #define VIRTUAL_CWD_DEBUG 0
49 :
50 : #include "TSRM.h"
51 :
52 : /* Only need mutex for popen() in Windows and NetWare because it doesn't chdir() on UNIX */
53 : #if (defined(TSRM_WIN32) || defined(NETWARE)) && defined(ZTS)
54 : MUTEX_T cwd_mutex;
55 : #endif
56 :
57 : #ifdef ZTS
58 : ts_rsrc_id cwd_globals_id;
59 : #else
60 : virtual_cwd_globals cwd_globals;
61 : #endif
62 :
63 : cwd_state main_cwd_state; /* True global */
64 :
65 : #ifndef TSRM_WIN32
66 : #include <unistd.h>
67 : #else
68 : #include <direct.h>
69 : #endif
70 :
71 : #ifndef S_ISDIR
72 : #define S_ISDIR(mode) ((mode) & _S_IFDIR)
73 : #endif
74 :
75 : #ifndef S_ISREG
76 : #define S_ISREG(mode) ((mode) & _S_IFREG)
77 : #endif
78 :
79 : #ifdef TSRM_WIN32
80 : #include <tchar.h>
81 : #define tsrm_strtok_r(a,b,c) _tcstok((a),(b))
82 : #define TOKENIZER_STRING "/\\"
83 :
84 : static int php_check_dots(const char *element, int n)
85 : {
86 : while (n-- > 0) if (element[n] != '.') break;
87 :
88 : return (n != -1);
89 : }
90 :
91 : #define IS_DIRECTORY_UP(element, len) \
92 : (len >= 2 && !php_check_dots(element, len))
93 :
94 : #define IS_DIRECTORY_CURRENT(element, len) \
95 : (len == 1 && element[0] == '.')
96 :
97 : #elif defined(NETWARE)
98 : /* NetWare has strtok() (in LibC) and allows both slashes in paths, like Windows --
99 : but rest of the stuff is like Unix */
100 : /* strtok() call in LibC is abending when used in a different address space -- hence using
101 : PHP's version itself for now */
102 : /*#define tsrm_strtok_r(a,b,c) strtok((a),(b))*/
103 : #define TOKENIZER_STRING "/\\"
104 :
105 : #else
106 : #define TOKENIZER_STRING "/"
107 : #endif
108 :
109 :
110 : /* default macros */
111 :
112 : #ifndef IS_DIRECTORY_UP
113 : #define IS_DIRECTORY_UP(element, len) \
114 : (len == 2 && element[0] == '.' && element[1] == '.')
115 : #endif
116 :
117 : #ifndef IS_DIRECTORY_CURRENT
118 : #define IS_DIRECTORY_CURRENT(element, len) \
119 : (len == 1 && element[0] == '.')
120 : #endif
121 :
122 : /* define this to check semantics */
123 : #define IS_DIR_OK(s) (1)
124 :
125 : #ifndef IS_DIR_OK
126 : #define IS_DIR_OK(state) (php_is_dir_ok(state) == 0)
127 : #endif
128 :
129 :
130 : #define CWD_STATE_COPY(d, s) \
131 : (d)->cwd_length = (s)->cwd_length; \
132 : (d)->cwd = (char *) malloc((s)->cwd_length+1); \
133 : memcpy((d)->cwd, (s)->cwd, (s)->cwd_length+1);
134 :
135 : #define CWD_STATE_FREE(s) \
136 : free((s)->cwd);
137 :
138 : #ifdef TSRM_WIN32
139 : CWD_API int php_sys_stat(const char *path, struct stat *buf) /* {{{ */
140 : {
141 : WIN32_FILE_ATTRIBUTE_DATA data;
142 : __int64 t;
143 :
144 : if (!GetFileAttributesEx(path, GetFileExInfoStandard, &data)) {
145 : return stat(path, buf);
146 : }
147 :
148 : if (path[1] == ':') {
149 : if (path[0] >= 'A' && path[0] <= 'Z') {
150 : buf->st_dev = buf->st_rdev = path[0] - 'A';
151 : } else {
152 : buf->st_dev = buf->st_rdev = path[0] - 'a';
153 : }
154 : } else {
155 : char cur_path[MAXPATHLEN+1];
156 : DWORD len = sizeof(cur_path);
157 : char *tmp = cur_path;
158 :
159 : while(1) {
160 : DWORD r = GetCurrentDirectory(len, tmp);
161 : if (r < len) {
162 : if (tmp[1] == ':') {
163 : if (path[0] >= 'A' && path[0] <= 'Z') {
164 : buf->st_dev = buf->st_rdev = path[0] - 'A';
165 : } else {
166 : buf->st_dev = buf->st_rdev = path[0] - 'a';
167 : }
168 : } else {
169 : buf->st_dev = buf->st_rdev = -1;
170 : }
171 : break;
172 : } else if (!r) {
173 : buf->st_dev = buf->st_rdev = -1;
174 : break;
175 : } else {
176 : len = r+1;
177 : tmp = (char*)malloc(len);
178 : }
179 : }
180 : if (tmp != cur_path) {
181 : free(tmp);
182 : }
183 : }
184 : buf->st_uid = buf->st_gid = buf->st_ino = 0;
185 : buf->st_mode = (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? (S_IFDIR|S_IEXEC|(S_IEXEC>>3)|(S_IEXEC>>6)) : S_IFREG;
186 : 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));
187 : if ((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) {
188 : int len = strlen(path);
189 :
190 : if (path[len-4] == '.') {
191 : if (_memicmp(path+len-3, "exe", 3) == 0 ||
192 : _memicmp(path+len-3, "com", 3) == 0 ||
193 : _memicmp(path+len-3, "bat", 3) == 0 ||
194 : _memicmp(path+len-3, "cmd", 3) == 0) {
195 : buf->st_mode |= (S_IEXEC|(S_IEXEC>>3)|(S_IEXEC>>6));
196 : }
197 : }
198 : }
199 : buf->st_nlink = 1;
200 : t = data.nFileSizeHigh;
201 : t = t << 32;
202 : t |= data.nFileSizeLow;
203 : buf->st_size = t;
204 : t = data.ftLastAccessTime.dwHighDateTime;
205 : t = t << 32;
206 : t |= data.ftLastAccessTime.dwLowDateTime;
207 : buf->st_atime = (unsigned long)((t / 10000000) - 11644473600);
208 : t = data.ftCreationTime.dwHighDateTime;
209 : t = t << 32;
210 : t |= data.ftCreationTime.dwLowDateTime;
211 : buf->st_ctime = (unsigned long)((t / 10000000) - 11644473600);
212 : t = data.ftLastWriteTime.dwHighDateTime;
213 : t = t << 32;
214 : t |= data.ftLastWriteTime.dwLowDateTime;
215 : buf->st_mtime = (unsigned long)((t / 10000000) - 11644473600);
216 : return 0;
217 : }
218 : /* }}} */
219 : #endif
220 :
221 : static int php_is_dir_ok(const cwd_state *state) /* {{{ */
222 0 : {
223 : struct stat buf;
224 :
225 0 : if (php_sys_stat(state->cwd, &buf) == 0 && S_ISDIR(buf.st_mode))
226 0 : return (0);
227 :
228 0 : return (1);
229 : }
230 : /* }}} */
231 :
232 : static int php_is_file_ok(const cwd_state *state) /* {{{ */
233 0 : {
234 : struct stat buf;
235 :
236 0 : if (php_sys_stat(state->cwd, &buf) == 0 && S_ISREG(buf.st_mode))
237 0 : return (0);
238 :
239 0 : return (1);
240 : }
241 : /* }}} */
242 :
243 : static void cwd_globals_ctor(virtual_cwd_globals *cwd_globals TSRMLS_DC) /* {{{ */
244 13565 : {
245 13565 : CWD_STATE_COPY(&cwd_globals->cwd, &main_cwd_state);
246 13565 : cwd_globals->realpath_cache_size = 0;
247 13565 : cwd_globals->realpath_cache_size_limit = REALPATH_CACHE_SIZE;
248 13565 : cwd_globals->realpath_cache_ttl = REALPATH_CACHE_TTL;
249 13565 : memset(cwd_globals->realpath_cache, 0, sizeof(cwd_globals->realpath_cache));
250 13565 : }
251 : /* }}} */
252 :
253 : static void cwd_globals_dtor(virtual_cwd_globals *cwd_globals TSRMLS_DC) /* {{{ */
254 13597 : {
255 13597 : CWD_STATE_FREE(&cwd_globals->cwd);
256 13597 : realpath_cache_clean(TSRMLS_C);
257 13597 : }
258 : /* }}} */
259 :
260 : static char *tsrm_strndup(const char *s, size_t length) /* {{{ */
261 27186 : {
262 : char *p;
263 :
264 27186 : p = (char *) malloc(length+1);
265 27186 : if (!p) {
266 0 : return (char *)NULL;
267 : }
268 27186 : if (length) {
269 27186 : memcpy(p,s,length);
270 : }
271 27186 : p[length]=0;
272 27186 : return p;
273 : }
274 : /* }}} */
275 :
276 : CWD_API void virtual_cwd_startup(void) /* {{{ */
277 13565 : {
278 : char cwd[MAXPATHLEN];
279 : char *result;
280 :
281 : #ifdef NETWARE
282 : result = getcwdpath(cwd, NULL, 1);
283 : if(result)
284 : {
285 : char *c=cwd;
286 : while(c = strchr(c, '\\'))
287 : {
288 : *c='/';
289 : ++c;
290 : }
291 : }
292 : #else
293 13565 : result = getcwd(cwd, sizeof(cwd));
294 : #endif
295 13565 : if (!result) {
296 0 : cwd[0] = '\0';
297 : }
298 13565 : main_cwd_state.cwd = strdup(cwd);
299 13565 : main_cwd_state.cwd_length = strlen(cwd);
300 :
301 : #ifdef ZTS
302 : ts_allocate_id(&cwd_globals_id, sizeof(virtual_cwd_globals), (ts_allocate_ctor) cwd_globals_ctor, (ts_allocate_dtor) cwd_globals_dtor);
303 : #else
304 13565 : cwd_globals_ctor(&cwd_globals TSRMLS_CC);
305 : #endif
306 :
307 : #if (defined(TSRM_WIN32) || defined(NETWARE)) && defined(ZTS)
308 : cwd_mutex = tsrm_mutex_alloc();
309 : #endif
310 13565 : }
311 : /* }}} */
312 :
313 : CWD_API void virtual_cwd_shutdown(void) /* {{{ */
314 13597 : {
315 : #ifndef ZTS
316 13597 : cwd_globals_dtor(&cwd_globals TSRMLS_CC);
317 : #endif
318 : #if (defined(TSRM_WIN32) || defined(NETWARE)) && defined(ZTS)
319 : tsrm_mutex_free(cwd_mutex);
320 : #endif
321 :
322 13597 : free(main_cwd_state.cwd); /* Don't use CWD_STATE_FREE because the non global states will probably use emalloc()/efree() */
323 13597 : }
324 : /* }}} */
325 :
326 : CWD_API char *virtual_getcwd_ex(size_t *length TSRMLS_DC) /* {{{ */
327 0 : {
328 : cwd_state *state;
329 :
330 0 : state = &CWDG(cwd);
331 :
332 0 : if (state->cwd_length == 0) {
333 : char *retval;
334 :
335 0 : *length = 1;
336 0 : retval = (char *) malloc(2);
337 0 : retval[0] = DEFAULT_SLASH;
338 0 : retval[1] = '\0';
339 0 : return retval;
340 : }
341 :
342 : #ifdef TSRM_WIN32
343 : /* If we have something like C: */
344 : if (state->cwd_length == 2 && state->cwd[state->cwd_length-1] == ':') {
345 : char *retval;
346 :
347 : *length = state->cwd_length+1;
348 : retval = (char *) malloc(*length+1);
349 : memcpy(retval, state->cwd, *length);
350 : retval[*length-1] = DEFAULT_SLASH;
351 : retval[*length] = '\0';
352 : return retval;
353 : }
354 : #endif
355 0 : *length = state->cwd_length;
356 0 : return strdup(state->cwd);
357 : }
358 : /* }}} */
359 :
360 : /* Same semantics as UNIX getcwd() */
361 : CWD_API char *virtual_getcwd(char *buf, size_t size TSRMLS_DC) /* {{{ */
362 0 : {
363 : size_t length;
364 : char *cwd;
365 :
366 0 : cwd = virtual_getcwd_ex(&length TSRMLS_CC);
367 :
368 0 : if (buf == NULL) {
369 0 : return cwd;
370 : }
371 0 : if (length > size-1) {
372 0 : free(cwd);
373 0 : errno = ERANGE; /* Is this OK? */
374 0 : return NULL;
375 : }
376 0 : memcpy(buf, cwd, length+1);
377 0 : free(cwd);
378 0 : return buf;
379 : }
380 : /* }}} */
381 :
382 : static inline unsigned long realpath_cache_key(const char *path, int path_len) /* {{{ */
383 123276 : {
384 : register unsigned long h;
385 123276 : const char *e = path + path_len;
386 :
387 7353952 : for (h = 2166136261U; path < e;) {
388 7107400 : h *= 16777619;
389 7107400 : h ^= *path++;
390 : }
391 :
392 123276 : return h;
393 : }
394 : /* }}} */
395 :
396 : CWD_API void realpath_cache_clean(TSRMLS_D) /* {{{ */
397 40437 : {
398 : int i;
399 :
400 41447925 : for (i = 0; i < sizeof(CWDG(realpath_cache))/sizeof(CWDG(realpath_cache)[0]); i++) {
401 41407488 : realpath_cache_bucket *p = CWDG(realpath_cache)[i];
402 82856395 : while (p != NULL) {
403 41419 : realpath_cache_bucket *r = p;
404 41419 : p = p->next;
405 41419 : free(r);
406 : }
407 41407488 : CWDG(realpath_cache)[i] = NULL;
408 : }
409 40437 : CWDG(realpath_cache_size) = 0;
410 40437 : }
411 : /* }}} */
412 :
413 : CWD_API void realpath_cache_del(const char *path, int path_len TSRMLS_DC) /* {{{ */
414 0 : {
415 0 : unsigned long key = realpath_cache_key(path, path_len);
416 0 : unsigned long n = key % (sizeof(CWDG(realpath_cache)) / sizeof(CWDG(realpath_cache)[0]));
417 0 : realpath_cache_bucket **bucket = &CWDG(realpath_cache)[n];
418 :
419 0 : while (*bucket != NULL) {
420 0 : if (key == (*bucket)->key && path_len == (*bucket)->path_len &&
421 : memcmp(path, (*bucket)->path, path_len) == 0) {
422 0 : realpath_cache_bucket *r = *bucket;
423 0 : *bucket = (*bucket)->next;
424 0 : CWDG(realpath_cache_size) -= sizeof(realpath_cache_bucket) + r->path_len + 1 + r->realpath_len + 1;
425 0 : free(r);
426 0 : return;
427 : } else {
428 0 : bucket = &(*bucket)->next;
429 : }
430 : }
431 : }
432 : /* }}} */
433 :
434 : static inline void realpath_cache_add(const char *path, int path_len, const char *realpath, int realpath_len, time_t t TSRMLS_DC) /* {{{ */
435 50169 : {
436 50169 : long size = sizeof(realpath_cache_bucket) + path_len + 1 + realpath_len + 1;
437 50169 : if (CWDG(realpath_cache_size) + size <= CWDG(realpath_cache_size_limit)) {
438 41360 : realpath_cache_bucket *bucket = malloc(size);
439 : unsigned long n;
440 :
441 41360 : bucket->key = realpath_cache_key(path, path_len);
442 41360 : bucket->path = (char*)bucket + sizeof(realpath_cache_bucket);
443 41360 : memcpy(bucket->path, path, path_len+1);
444 41360 : bucket->path_len = path_len;
445 41360 : bucket->realpath = bucket->path + (path_len + 1);
446 41360 : memcpy(bucket->realpath, realpath, realpath_len+1);
447 41360 : bucket->realpath_len = realpath_len;
448 41360 : bucket->expires = t + CWDG(realpath_cache_ttl);
449 41360 : n = bucket->key % (sizeof(CWDG(realpath_cache)) / sizeof(CWDG(realpath_cache)[0]));
450 41360 : bucket->next = CWDG(realpath_cache)[n];
451 41360 : CWDG(realpath_cache)[n] = bucket;
452 41360 : CWDG(realpath_cache_size) += size;
453 : }
454 50169 : }
455 : /* }}} */
456 :
457 : static inline realpath_cache_bucket* realpath_cache_find(const char *path, int path_len, time_t t TSRMLS_DC) /* {{{ */
458 81916 : {
459 81916 : unsigned long key = realpath_cache_key(path, path_len);
460 81916 : unsigned long n = key % (sizeof(CWDG(realpath_cache)) / sizeof(CWDG(realpath_cache)[0]));
461 81916 : realpath_cache_bucket **bucket = &CWDG(realpath_cache)[n];
462 :
463 165046 : while (*bucket != NULL) {
464 6309 : if (CWDG(realpath_cache_ttl) && (*bucket)->expires < t) {
465 0 : realpath_cache_bucket *r = *bucket;
466 0 : *bucket = (*bucket)->next;
467 0 : CWDG(realpath_cache_size) -= sizeof(realpath_cache_bucket) + r->path_len + 1 + r->realpath_len + 1;
468 0 : free(r);
469 6309 : } else if (key == (*bucket)->key && path_len == (*bucket)->path_len &&
470 : memcmp(path, (*bucket)->path, path_len) == 0) {
471 5095 : return *bucket;
472 : } else {
473 1214 : bucket = &(*bucket)->next;
474 : }
475 : }
476 76821 : return NULL;
477 : }
478 : /* }}} */
479 :
480 : /* Resolve path relatively to state and put the real path into state */
481 : /* returns 0 for ok, 1 for error */
482 : CWD_API int virtual_file_ex(cwd_state *state, const char *path, verify_path_func verify_path, int use_realpath) /* {{{ */
483 113039 : {
484 113039 : int path_length = strlen(path);
485 : cwd_state old_state;
486 : char orig_path[MAXPATHLEN];
487 : realpath_cache_bucket *bucket;
488 113039 : time_t t = 0;
489 : int ret;
490 : int use_cache;
491 113039 : int use_relative_path = 0;
492 : #ifdef TSRM_WIN32
493 : int is_unc;
494 : int exists;
495 : #endif
496 : TSRMLS_FETCH();
497 :
498 113039 : use_cache = ((use_realpath != CWD_EXPAND) && CWDG(realpath_cache_size_limit));
499 :
500 113039 : if (path_length == 0)
501 0 : return (1);
502 113039 : if (path_length >= MAXPATHLEN)
503 3 : return (1);
504 :
505 : #if VIRTUAL_CWD_DEBUG
506 : fprintf(stderr,"cwd = %s path = %s\n", state->cwd, path);
507 : #endif
508 :
509 : /* cwd_length can be 0 when getcwd() fails.
510 : * This can happen under solaris when a dir does not have read permissions
511 : * but *does* have execute permissions */
512 113036 : if (!IS_ABSOLUTE_PATH(path, path_length)) {
513 3997 : if (state->cwd_length == 0) {
514 0 : use_cache = 0;
515 0 : use_relative_path = 1;
516 : } else {
517 : int orig_path_len;
518 3997 : int state_cwd_length = state->cwd_length;
519 :
520 : #ifdef TSRM_WIN32
521 : if (IS_SLASH(path[0])) {
522 : state_cwd_length = 2;
523 : }
524 : #endif
525 3997 : orig_path_len = path_length + state_cwd_length + 1;
526 3997 : if (orig_path_len >= MAXPATHLEN) {
527 0 : return 1;
528 : }
529 3997 : memcpy(orig_path, state->cwd, state_cwd_length);
530 3997 : orig_path[state_cwd_length] = DEFAULT_SLASH;
531 3997 : memcpy(orig_path + state_cwd_length + 1, path, path_length + 1);
532 3997 : path = orig_path;
533 3997 : path_length = orig_path_len;
534 : }
535 : }
536 :
537 113036 : if (use_cache) {
538 81916 : t = CWDG(realpath_cache_ttl)?time(0):0;
539 81916 : if ((bucket = realpath_cache_find(path, path_length, t TSRMLS_CC)) != NULL) {
540 5095 : int len = bucket->realpath_len;
541 :
542 5095 : CWD_STATE_COPY(&old_state, state);
543 5095 : state->cwd = (char *) realloc(state->cwd, len+1);
544 5095 : memcpy(state->cwd, bucket->realpath, len+1);
545 5095 : state->cwd_length = len;
546 5095 : if (verify_path && verify_path(state)) {
547 0 : CWD_STATE_FREE(state);
548 0 : *state = old_state;
549 0 : return 1;
550 : } else {
551 5095 : CWD_STATE_FREE(&old_state);
552 5095 : return 0;
553 : }
554 : }
555 : }
556 :
557 107941 : if (use_realpath != CWD_EXPAND) {
558 : #if !defined(TSRM_WIN32) && !defined(NETWARE)
559 : char resolved_path[MAXPATHLEN];
560 :
561 107941 : if (!realpath(path, resolved_path)) { /* Note: Not threadsafe on older *BSD's */
562 27654 : if (use_realpath == CWD_REALPATH) {
563 468 : return 1;
564 : }
565 27186 : goto no_realpath;
566 : }
567 80287 : use_realpath = CWD_REALPATH;
568 80287 : CWD_STATE_COPY(&old_state, state);
569 :
570 80287 : state->cwd_length = strlen(resolved_path);
571 80287 : state->cwd = (char *) realloc(state->cwd, state->cwd_length+1);
572 80287 : memcpy(state->cwd, resolved_path, state->cwd_length+1);
573 : #else
574 : goto no_realpath;
575 : #endif
576 : } else {
577 : char *ptr, *path_copy, *free_path;
578 : char *tok;
579 : int ptr_length;
580 27186 : no_realpath:
581 :
582 : #ifdef TSRM_WIN32
583 : if (memchr(path, '*', path_length) ||
584 : memchr(path, '?', path_length)) {
585 : return 1;
586 : }
587 : #endif
588 :
589 27186 : free_path = path_copy = tsrm_strndup(path, path_length);
590 27186 : CWD_STATE_COPY(&old_state, state);
591 :
592 : #ifdef TSRM_WIN32
593 : exists = (use_realpath != CWD_EXPAND);
594 : ret = 0;
595 : is_unc = 0;
596 : if (path_length >= 2 && path[1] == ':') {
597 : state->cwd = (char *) realloc(state->cwd, 2 + 1);
598 : state->cwd[0] = toupper(path[0]);
599 : state->cwd[1] = ':';
600 : state->cwd[2] = '\0';
601 : state->cwd_length = 2;
602 : path_copy += 2;
603 : } else if (IS_UNC_PATH(path, path_length)) {
604 : state->cwd = (char *) realloc(state->cwd, 1 + 1);
605 : state->cwd[0] = DEFAULT_SLASH;
606 : state->cwd[1] = '\0';
607 : state->cwd_length = 1;
608 : path_copy += 2;
609 : is_unc = 2;
610 : } else {
611 : #endif
612 27186 : state->cwd = (char *) realloc(state->cwd, 1);
613 27186 : state->cwd[0] = '\0';
614 27186 : state->cwd_length = 0;
615 : #ifdef TSRM_WIN32
616 : }
617 : #endif
618 :
619 27186 : tok = NULL;
620 27186 : ptr = tsrm_strtok_r(path_copy, TOKENIZER_STRING, &tok);
621 244695 : while (ptr) {
622 190323 : ptr_length = strlen(ptr);
623 :
624 190454 : if (IS_DIRECTORY_UP(ptr, ptr_length)) {
625 : char save;
626 :
627 131 : if (use_relative_path) {
628 0 : CWD_STATE_FREE(state);
629 0 : *state = old_state;
630 0 : return 1;
631 : }
632 :
633 131 : save = DEFAULT_SLASH;
634 :
635 : #define PREVIOUS state->cwd[state->cwd_length - 1]
636 :
637 1778 : while (IS_ABSOLUTE_PATH(state->cwd, state->cwd_length) &&
638 : !IS_SLASH(PREVIOUS)) {
639 1516 : save = PREVIOUS;
640 1516 : PREVIOUS = '\0';
641 1516 : state->cwd_length--;
642 : }
643 :
644 131 : if (!IS_ABSOLUTE_PATH(state->cwd, state->cwd_length)) {
645 0 : state->cwd[state->cwd_length++] = save;
646 0 : state->cwd[state->cwd_length] = '\0';
647 : } else {
648 131 : PREVIOUS = '\0';
649 131 : state->cwd_length--;
650 : }
651 190192 : } else if (!IS_DIRECTORY_CURRENT(ptr, ptr_length)) {
652 187506 : if (use_relative_path) {
653 0 : state->cwd = (char *) realloc(state->cwd, state->cwd_length+ptr_length+1);
654 0 : use_relative_path = 0;
655 : } else {
656 187506 : state->cwd = (char *) realloc(state->cwd, state->cwd_length+ptr_length+1+1);
657 : #ifdef TSRM_WIN32
658 : /* Windows 9x will consider C:\\Foo as a network path. Avoid it. */
659 : if (state->cwd_length < 2 ||
660 : (state->cwd[state->cwd_length-1]!='\\' && state->cwd[state->cwd_length-1]!='/') ||
661 : IsDBCSLeadByte(state->cwd[state->cwd_length-2])) {
662 : state->cwd[state->cwd_length++] = DEFAULT_SLASH;
663 : }
664 : #elif defined(NETWARE)
665 : /*
666 : Below code keeps appending to state->cwd a File system seperator
667 : cases where this appending should not happen is given below,
668 : a) sys: should just be left as it is
669 : b) sys:system should just be left as it is,
670 : Colon is allowed only in the first token as volume names alone can have the : in their names.
671 : Files and Directories cannot have : in their names
672 : So the check goes like this,
673 : For second token and above simply append the DEFAULT_SLASH to the state->cwd.
674 : For first token check for the existence of :
675 : if it exists don't append the DEFAULT_SLASH to the state->cwd.
676 : */
677 : if(((state->cwd_length == 0) && (strchr(ptr, ':') == NULL)) || (state->cwd_length > 0)) {
678 : state->cwd[state->cwd_length++] = DEFAULT_SLASH;
679 : }
680 : #else
681 187506 : state->cwd[state->cwd_length++] = DEFAULT_SLASH;
682 : #endif
683 : }
684 187506 : memcpy(&state->cwd[state->cwd_length], ptr, ptr_length+1);
685 :
686 : #ifdef TSRM_WIN32
687 : if (use_realpath != CWD_EXPAND) {
688 : WIN32_FIND_DATA data;
689 : HANDLE hFind;
690 :
691 : if ((hFind = FindFirstFile(state->cwd, &data)) != INVALID_HANDLE_VALUE) {
692 : int length = strlen(data.cFileName);
693 :
694 : if (length != ptr_length) {
695 : state->cwd = (char *) realloc(state->cwd, state->cwd_length+length+1);
696 : }
697 : memcpy(&state->cwd[state->cwd_length], data.cFileName, length+1);
698 : ptr_length = length;
699 : FindClose(hFind);
700 : ret = 0;
701 : } else {
702 : if (is_unc) {
703 : /* skip share name */
704 : is_unc--;
705 : ret = 0;
706 : } else {
707 : exists = 0;
708 : if (use_realpath == CWD_REALPATH) {
709 : ret = 1;
710 : }
711 : }
712 : }
713 : }
714 : #endif
715 :
716 187506 : state->cwd_length += ptr_length;
717 : }
718 190323 : ptr = tsrm_strtok_r(NULL, TOKENIZER_STRING, &tok);
719 : }
720 27186 : free(free_path);
721 :
722 27186 : if (use_realpath == CWD_REALPATH) {
723 0 : if (ret) {
724 0 : CWD_STATE_FREE(state);
725 0 : *state = old_state;
726 0 : return 1;
727 : }
728 : } else {
729 : #if defined(TSRM_WIN32) || defined(NETWARE)
730 : if (path[path_length-1] == '\\' || path[path_length-1] == '/') {
731 : #else
732 27186 : if (path[path_length-1] == '/') {
733 : #endif
734 4 : state->cwd = (char*)realloc(state->cwd, state->cwd_length + 2);
735 4 : state->cwd[state->cwd_length++] = DEFAULT_SLASH;
736 4 : state->cwd[state->cwd_length] = 0;
737 : }
738 : }
739 :
740 27186 : if (state->cwd_length == COPY_WHEN_ABSOLUTE(state->cwd)) {
741 0 : state->cwd = (char *) realloc(state->cwd, state->cwd_length+1+1);
742 0 : state->cwd[state->cwd_length] = DEFAULT_SLASH;
743 0 : state->cwd[state->cwd_length+1] = '\0';
744 0 : state->cwd_length++;
745 : }
746 : }
747 :
748 : /* Store existent file in realpath cache. */
749 : #ifdef TSRM_WIN32
750 : if (use_cache && !is_unc && exists) {
751 : #else
752 107473 : if (use_cache && (use_realpath == CWD_REALPATH)) {
753 : #endif
754 50169 : realpath_cache_add(path, path_length, state->cwd, state->cwd_length, t TSRMLS_CC);
755 : }
756 :
757 107473 : if (verify_path && verify_path(state)) {
758 0 : CWD_STATE_FREE(state);
759 0 : *state = old_state;
760 0 : ret = 1;
761 : } else {
762 107473 : CWD_STATE_FREE(&old_state);
763 107473 : ret = 0;
764 : }
765 :
766 : #if VIRTUAL_CWD_DEBUG
767 : fprintf (stderr, "virtual_file_ex() = %s\n",state->cwd);
768 : #endif
769 107473 : return (ret);
770 : }
771 : /* }}} */
772 :
773 : CWD_API int virtual_chdir(const char *path TSRMLS_DC) /* {{{ */
774 0 : {
775 0 : return virtual_file_ex(&CWDG(cwd), path, php_is_dir_ok, CWD_REALPATH)?-1:0;
776 : }
777 : /* }}} */
778 :
779 : CWD_API int virtual_chdir_file(const char *path, int (*p_chdir)(const char *path TSRMLS_DC) TSRMLS_DC) /* {{{ */
780 68 : {
781 68 : int length = strlen(path);
782 : char *temp;
783 : int retval;
784 :
785 68 : if (length == 0) {
786 0 : return 1; /* Can't cd to empty string */
787 : }
788 823 : while(--length >= 0 && !IS_SLASH(path[length])) {
789 : }
790 :
791 68 : if (length == -1) {
792 : /* No directory only file name */
793 0 : errno = ENOENT;
794 0 : return -1;
795 : }
796 :
797 68 : if (length == COPY_WHEN_ABSOLUTE(path) && IS_ABSOLUTE_PATH(path, length+1)) { /* Also use trailing slash if this is absolute */
798 0 : length++;
799 : }
800 68 : temp = (char *) tsrm_do_alloca(length+1);
801 68 : memcpy(temp, path, length);
802 68 : temp[length] = 0;
803 : #if VIRTUAL_CWD_DEBUG
804 : fprintf (stderr, "Changing directory to %s\n", temp);
805 : #endif
806 68 : retval = p_chdir(temp TSRMLS_CC);
807 : tsrm_free_alloca(temp);
808 68 : return retval;
809 : }
810 : /* }}} */
811 :
812 : CWD_API char *virtual_realpath(const char *path, char *real_path TSRMLS_DC) /* {{{ */
813 0 : {
814 : cwd_state new_state;
815 : char *retval;
816 : char cwd[MAXPATHLEN];
817 :
818 : /* realpath("") returns CWD */
819 0 : if (!*path) {
820 0 : new_state.cwd = (char*)malloc(1);
821 0 : new_state.cwd[0] = '\0';
822 0 : new_state.cwd_length = 0;
823 0 : if (VCWD_GETCWD(cwd, MAXPATHLEN)) {
824 0 : path = cwd;
825 : }
826 0 : } else if (!IS_ABSOLUTE_PATH(path, strlen(path))) {
827 0 : CWD_STATE_COPY(&new_state, &CWDG(cwd));
828 : } else {
829 0 : new_state.cwd = (char*)malloc(1);
830 0 : new_state.cwd[0] = '\0';
831 0 : new_state.cwd_length = 0;
832 : }
833 :
834 0 : if (virtual_file_ex(&new_state, path, NULL, CWD_REALPATH)==0) {
835 0 : int len = new_state.cwd_length>MAXPATHLEN-1?MAXPATHLEN-1:new_state.cwd_length;
836 :
837 0 : memcpy(real_path, new_state.cwd, len);
838 0 : real_path[len] = '\0';
839 0 : retval = real_path;
840 : } else {
841 0 : retval = NULL;
842 : }
843 :
844 0 : CWD_STATE_FREE(&new_state);
845 :
846 0 : return retval;
847 : }
848 : /* }}} */
849 :
850 : CWD_API int virtual_filepath_ex(const char *path, char **filepath, verify_path_func verify_path TSRMLS_DC) /* {{{ */
851 0 : {
852 : cwd_state new_state;
853 : int retval;
854 :
855 0 : CWD_STATE_COPY(&new_state, &CWDG(cwd));
856 0 : retval = virtual_file_ex(&new_state, path, verify_path, CWD_FILEPATH);
857 :
858 0 : *filepath = new_state.cwd;
859 :
860 0 : return retval;
861 :
862 : }
863 : /* }}} */
864 :
865 : CWD_API int virtual_filepath(const char *path, char **filepath TSRMLS_DC) /* {{{ */
866 0 : {
867 0 : return virtual_filepath_ex(path, filepath, php_is_file_ok TSRMLS_CC);
868 : }
869 : /* }}} */
870 :
871 : CWD_API FILE *virtual_fopen(const char *path, const char *mode TSRMLS_DC) /* {{{ */
872 0 : {
873 : cwd_state new_state;
874 : FILE *f;
875 :
876 0 : if (path[0] == '\0') { /* Fail to open empty path */
877 0 : return NULL;
878 : }
879 :
880 0 : CWD_STATE_COPY(&new_state, &CWDG(cwd));
881 0 : if (virtual_file_ex(&new_state, path, NULL, CWD_FILEPATH)) {
882 0 : CWD_STATE_FREE(&new_state);
883 0 : return NULL;
884 : }
885 :
886 0 : f = fopen(new_state.cwd, mode);
887 :
888 0 : CWD_STATE_FREE(&new_state);
889 0 : return f;
890 : }
891 : /* }}} */
892 :
893 : CWD_API int virtual_access(const char *pathname, int mode TSRMLS_DC) /* {{{ */
894 0 : {
895 : cwd_state new_state;
896 : int ret;
897 :
898 0 : CWD_STATE_COPY(&new_state, &CWDG(cwd));
899 0 : if (virtual_file_ex(&new_state, pathname, NULL, CWD_REALPATH)) {
900 0 : CWD_STATE_FREE(&new_state);
901 0 : return -1;
902 : }
903 :
904 : #if defined(TSRM_WIN32)
905 : ret = tsrm_win32_access(new_state.cwd, mode);
906 : #else
907 0 : ret = access(new_state.cwd, mode);
908 : #endif
909 :
910 0 : CWD_STATE_FREE(&new_state);
911 :
912 0 : return ret;
913 : }
914 : /* }}} */
915 :
916 : #if HAVE_UTIME
917 : CWD_API int virtual_utime(const char *filename, struct utimbuf *buf TSRMLS_DC) /* {{{ */
918 0 : {
919 : cwd_state new_state;
920 : int ret;
921 :
922 0 : CWD_STATE_COPY(&new_state, &CWDG(cwd));
923 0 : if (virtual_file_ex(&new_state, filename, NULL, CWD_REALPATH)) {
924 0 : CWD_STATE_FREE(&new_state);
925 0 : return -1;
926 : }
927 :
928 0 : ret = utime(new_state.cwd, buf);
929 :
930 0 : CWD_STATE_FREE(&new_state);
931 0 : return ret;
932 : }
933 : /* }}} */
934 : #endif
935 :
936 : CWD_API int virtual_chmod(const char *filename, mode_t mode TSRMLS_DC) /* {{{ */
937 0 : {
938 : cwd_state new_state;
939 : int ret;
940 :
941 0 : CWD_STATE_COPY(&new_state, &CWDG(cwd));
942 0 : if (virtual_file_ex(&new_state, filename, NULL, CWD_REALPATH)) {
943 0 : CWD_STATE_FREE(&new_state);
944 0 : return -1;
945 : }
946 :
947 0 : ret = chmod(new_state.cwd, mode);
948 :
949 0 : CWD_STATE_FREE(&new_state);
950 0 : return ret;
951 : }
952 : /* }}} */
953 :
954 : #if !defined(TSRM_WIN32) && !defined(NETWARE)
955 : CWD_API int virtual_chown(const char *filename, uid_t owner, gid_t group, int link TSRMLS_DC) /* {{{ */
956 0 : {
957 : cwd_state new_state;
958 : int ret;
959 :
960 0 : CWD_STATE_COPY(&new_state, &CWDG(cwd));
961 0 : if (virtual_file_ex(&new_state, filename, NULL, CWD_REALPATH)) {
962 0 : CWD_STATE_FREE(&new_state);
963 0 : return -1;
964 : }
965 :
966 0 : if (link) {
967 : #if HAVE_LCHOWN
968 0 : ret = lchown(new_state.cwd, owner, group);
969 : #else
970 : ret = -1;
971 : #endif
972 : } else {
973 0 : ret = chown(new_state.cwd, owner, group);
974 : }
975 :
976 0 : CWD_STATE_FREE(&new_state);
977 0 : return ret;
978 : }
979 : /* }}} */
980 : #endif
981 :
982 : CWD_API int virtual_open(const char *path TSRMLS_DC, int flags, ...) /* {{{ */
983 0 : {
984 : cwd_state new_state;
985 : int f;
986 :
987 0 : CWD_STATE_COPY(&new_state, &CWDG(cwd));
988 0 : if (virtual_file_ex(&new_state, path, NULL, CWD_FILEPATH)) {
989 0 : CWD_STATE_FREE(&new_state);
990 0 : return -1;
991 : }
992 :
993 0 : if (flags & O_CREAT) {
994 : mode_t mode;
995 : va_list arg;
996 :
997 0 : va_start(arg, flags);
998 0 : mode = (mode_t) va_arg(arg, int);
999 0 : va_end(arg);
1000 :
1001 0 : f = open(new_state.cwd, flags, mode);
1002 : } else {
1003 0 : f = open(new_state.cwd, flags);
1004 : }
1005 0 : CWD_STATE_FREE(&new_state);
1006 0 : return f;
1007 : }
1008 : /* }}} */
1009 :
1010 : CWD_API int virtual_creat(const char *path, mode_t mode TSRMLS_DC) /* {{{ */
1011 0 : {
1012 : cwd_state new_state;
1013 : int f;
1014 :
1015 0 : CWD_STATE_COPY(&new_state, &CWDG(cwd));
1016 0 : if (virtual_file_ex(&new_state, path, NULL, CWD_FILEPATH)) {
1017 0 : CWD_STATE_FREE(&new_state);
1018 0 : return -1;
1019 : }
1020 :
1021 0 : f = creat(new_state.cwd, mode);
1022 :
1023 0 : CWD_STATE_FREE(&new_state);
1024 0 : return f;
1025 : }
1026 : /* }}} */
1027 :
1028 : CWD_API int virtual_rename(char *oldname, char *newname TSRMLS_DC) /* {{{ */
1029 0 : {
1030 : cwd_state old_state;
1031 : cwd_state new_state;
1032 : int retval;
1033 :
1034 0 : CWD_STATE_COPY(&old_state, &CWDG(cwd));
1035 0 : if (virtual_file_ex(&old_state, oldname, NULL, CWD_EXPAND)) {
1036 0 : CWD_STATE_FREE(&old_state);
1037 0 : return -1;
1038 : }
1039 0 : oldname = old_state.cwd;
1040 :
1041 0 : CWD_STATE_COPY(&new_state, &CWDG(cwd));
1042 0 : if (virtual_file_ex(&new_state, newname, NULL, CWD_EXPAND)) {
1043 0 : CWD_STATE_FREE(&old_state);
1044 0 : CWD_STATE_FREE(&new_state);
1045 0 : return -1;
1046 : }
1047 0 : newname = new_state.cwd;
1048 :
1049 0 : retval = rename(oldname, newname);
1050 :
1051 0 : CWD_STATE_FREE(&old_state);
1052 0 : CWD_STATE_FREE(&new_state);
1053 :
1054 0 : return retval;
1055 : }
1056 : /* }}} */
1057 :
1058 : CWD_API int virtual_stat(const char *path, struct stat *buf TSRMLS_DC) /* {{{ */
1059 0 : {
1060 : cwd_state new_state;
1061 : int retval;
1062 :
1063 0 : CWD_STATE_COPY(&new_state, &CWDG(cwd));
1064 0 : if (virtual_file_ex(&new_state, path, NULL, CWD_REALPATH)) {
1065 0 : CWD_STATE_FREE(&new_state);
1066 0 : return -1;
1067 : }
1068 :
1069 0 : retval = php_sys_stat(new_state.cwd, buf);
1070 :
1071 0 : CWD_STATE_FREE(&new_state);
1072 0 : return retval;
1073 : }
1074 : /* }}} */
1075 :
1076 : #if !defined(TSRM_WIN32)
1077 : CWD_API int virtual_lstat(const char *path, struct stat *buf TSRMLS_DC) /* {{{ */
1078 0 : {
1079 : cwd_state new_state;
1080 : int retval;
1081 :
1082 0 : CWD_STATE_COPY(&new_state, &CWDG(cwd));
1083 0 : if (virtual_file_ex(&new_state, path, NULL, CWD_EXPAND)) {
1084 0 : CWD_STATE_FREE(&new_state);
1085 0 : return -1;
1086 : }
1087 :
1088 0 : retval = lstat(new_state.cwd, buf);
1089 :
1090 0 : CWD_STATE_FREE(&new_state);
1091 0 : return retval;
1092 : }
1093 : /* }}} */
1094 : #endif
1095 :
1096 : CWD_API int virtual_unlink(const char *path TSRMLS_DC) /* {{{ */
1097 0 : {
1098 : cwd_state new_state;
1099 : int retval;
1100 :
1101 0 : CWD_STATE_COPY(&new_state, &CWDG(cwd));
1102 0 : if (virtual_file_ex(&new_state, path, NULL, CWD_EXPAND)) {
1103 0 : CWD_STATE_FREE(&new_state);
1104 0 : return -1;
1105 : }
1106 :
1107 0 : retval = unlink(new_state.cwd);
1108 :
1109 0 : CWD_STATE_FREE(&new_state);
1110 0 : return retval;
1111 : }
1112 : /* }}} */
1113 :
1114 : CWD_API int virtual_mkdir(const char *pathname, mode_t mode TSRMLS_DC) /* {{{ */
1115 0 : {
1116 : cwd_state new_state;
1117 : int retval;
1118 :
1119 0 : CWD_STATE_COPY(&new_state, &CWDG(cwd));
1120 0 : if (virtual_file_ex(&new_state, pathname, NULL, CWD_FILEPATH)) {
1121 0 : CWD_STATE_FREE(&new_state);
1122 0 : return -1;
1123 : }
1124 :
1125 : #ifdef TSRM_WIN32
1126 : retval = mkdir(new_state.cwd);
1127 : #else
1128 0 : retval = mkdir(new_state.cwd, mode);
1129 : #endif
1130 0 : CWD_STATE_FREE(&new_state);
1131 0 : return retval;
1132 : }
1133 : /* }}} */
1134 :
1135 : CWD_API int virtual_rmdir(const char *pathname TSRMLS_DC) /* {{{ */
1136 0 : {
1137 : cwd_state new_state;
1138 : int retval;
1139 :
1140 0 : CWD_STATE_COPY(&new_state, &CWDG(cwd));
1141 0 : if (virtual_file_ex(&new_state, pathname, NULL, CWD_EXPAND)) {
1142 0 : CWD_STATE_FREE(&new_state);
1143 0 : return -1;
1144 : }
1145 :
1146 0 : retval = rmdir(new_state.cwd);
1147 :
1148 0 : CWD_STATE_FREE(&new_state);
1149 0 : return retval;
1150 : }
1151 : /* }}} */
1152 :
1153 : #ifdef TSRM_WIN32
1154 : DIR *opendir(const char *name);
1155 : #endif
1156 :
1157 : CWD_API DIR *virtual_opendir(const char *pathname TSRMLS_DC) /* {{{ */
1158 0 : {
1159 : cwd_state new_state;
1160 : DIR *retval;
1161 :
1162 0 : CWD_STATE_COPY(&new_state, &CWDG(cwd));
1163 0 : if (virtual_file_ex(&new_state, pathname, NULL, CWD_REALPATH)) {
1164 0 : CWD_STATE_FREE(&new_state);
1165 0 : return NULL;
1166 : }
1167 :
1168 0 : retval = opendir(new_state.cwd);
1169 :
1170 0 : CWD_STATE_FREE(&new_state);
1171 0 : return retval;
1172 : }
1173 : /* }}} */
1174 :
1175 : #ifdef TSRM_WIN32
1176 : CWD_API FILE *virtual_popen(const char *command, const char *type TSRMLS_DC) /* {{{ */
1177 : {
1178 : return popen_ex(command, type, CWDG(cwd).cwd, NULL);
1179 : }
1180 : /* }}} */
1181 : #elif defined(NETWARE)
1182 : /* On NetWare, the trick of prepending "cd cwd; " doesn't work so we need to perform
1183 : a VCWD_CHDIR() and mutex it
1184 : */
1185 : CWD_API FILE *virtual_popen(const char *command, const char *type TSRMLS_DC) /* {{{ */
1186 : {
1187 : char prev_cwd[MAXPATHLEN];
1188 : char *getcwd_result;
1189 : FILE *retval;
1190 :
1191 : getcwd_result = VCWD_GETCWD(prev_cwd, MAXPATHLEN);
1192 : if (!getcwd_result) {
1193 : return NULL;
1194 : }
1195 :
1196 : #ifdef ZTS
1197 : tsrm_mutex_lock(cwd_mutex);
1198 : #endif
1199 :
1200 : VCWD_CHDIR(CWDG(cwd).cwd);
1201 : retval = popen(command, type);
1202 : VCWD_CHDIR(prev_cwd);
1203 :
1204 : #ifdef ZTS
1205 : tsrm_mutex_unlock(cwd_mutex);
1206 : #endif
1207 :
1208 : return retval;
1209 : }
1210 : /* }}} */
1211 : #else /* Unix */
1212 : CWD_API FILE *virtual_popen(const char *command, const char *type TSRMLS_DC) /* {{{ */
1213 0 : {
1214 : int command_length;
1215 0 : int dir_length, extra = 0;
1216 : char *command_line;
1217 : char *ptr, *dir;
1218 : FILE *retval;
1219 :
1220 0 : command_length = strlen(command);
1221 :
1222 0 : dir_length = CWDG(cwd).cwd_length;
1223 0 : dir = CWDG(cwd).cwd;
1224 0 : while (dir_length > 0) {
1225 0 : if (*dir == '\'') extra+=3;
1226 0 : dir++;
1227 0 : dir_length--;
1228 : }
1229 0 : dir_length = CWDG(cwd).cwd_length;
1230 0 : dir = CWDG(cwd).cwd;
1231 :
1232 0 : ptr = command_line = (char *) malloc(command_length + sizeof("cd '' ; ") + dir_length + extra+1+1);
1233 0 : if (!command_line) {
1234 0 : return NULL;
1235 : }
1236 0 : memcpy(ptr, "cd ", sizeof("cd ")-1);
1237 0 : ptr += sizeof("cd ")-1;
1238 :
1239 0 : if (CWDG(cwd).cwd_length == 0) {
1240 0 : *ptr++ = DEFAULT_SLASH;
1241 : } else {
1242 0 : *ptr++ = '\'';
1243 0 : while (dir_length > 0) {
1244 0 : switch (*dir) {
1245 : case '\'':
1246 0 : *ptr++ = '\'';
1247 0 : *ptr++ = '\\';
1248 0 : *ptr++ = '\'';
1249 : /* fall-through */
1250 : default:
1251 0 : *ptr++ = *dir;
1252 : }
1253 0 : dir++;
1254 0 : dir_length--;
1255 : }
1256 0 : *ptr++ = '\'';
1257 : }
1258 :
1259 0 : *ptr++ = ' ';
1260 0 : *ptr++ = ';';
1261 0 : *ptr++ = ' ';
1262 :
1263 0 : memcpy(ptr, command, command_length+1);
1264 0 : retval = popen(command_line, type);
1265 :
1266 0 : free(command_line);
1267 0 : return retval;
1268 : }
1269 : /* }}} */
1270 : #endif
1271 :
1272 : CWD_API char *tsrm_realpath(const char *path, char *real_path TSRMLS_DC) /* {{{ */
1273 34375 : {
1274 : cwd_state new_state;
1275 : char cwd[MAXPATHLEN];
1276 :
1277 : /* realpath("") returns CWD */
1278 34375 : if (!*path) {
1279 4 : new_state.cwd = (char*)malloc(1);
1280 4 : new_state.cwd[0] = '\0';
1281 4 : new_state.cwd_length = 0;
1282 4 : if (VCWD_GETCWD(cwd, MAXPATHLEN)) {
1283 4 : path = cwd;
1284 : }
1285 34688 : } else if (!IS_ABSOLUTE_PATH(path, strlen(path)) &&
1286 : VCWD_GETCWD(cwd, MAXPATHLEN)) {
1287 317 : new_state.cwd = strdup(cwd);
1288 317 : new_state.cwd_length = strlen(cwd);
1289 : } else {
1290 34054 : new_state.cwd = (char*)malloc(1);
1291 34054 : new_state.cwd[0] = '\0';
1292 34054 : new_state.cwd_length = 0;
1293 : }
1294 :
1295 34375 : if (virtual_file_ex(&new_state, path, NULL, CWD_REALPATH)) {
1296 459 : free(new_state.cwd);
1297 459 : return NULL;
1298 : }
1299 :
1300 33916 : if (real_path) {
1301 33861 : int copy_len = new_state.cwd_length>MAXPATHLEN-1 ? MAXPATHLEN-1 : new_state.cwd_length;
1302 33861 : memcpy(real_path, new_state.cwd, copy_len);
1303 33861 : real_path[copy_len] = '\0';
1304 33861 : free(new_state.cwd);
1305 33861 : return real_path;
1306 : } else {
1307 55 : return new_state.cwd;
1308 : }
1309 : }
1310 : /* }}} */
1311 :
1312 : /*
1313 : * Local variables:
1314 : * tab-width: 4
1315 : * c-basic-offset: 4
1316 : * End:
1317 : */
|