The improved patch fixes all the issues I found during testing.
However I wasn't able to test it on NETWARE and on Solaris with relative paths.

Please test it as much as possible.
I'm going to commit it on Tuesday in case of no objections.

Thanks. Dmitry.

Rasmus Lerdorf wrote:
Rasmus Lerdorf wrote:
Dmitry Stogov wrote:
Hi,

The attached patch is going to fix the problem.
It implements its own realpath() function, so we won't depend on system
anymore. It also improve realpath cache usage by caching intermediate
results.

Very nice. The intermediate caching is going to drastically reduce the
amount of memory we need for the cache. I have seen a number of cases
where sites had to increase the realpath cache size by quite a bit.

Oh, and on top of that we also get a big performance improvement for include_path misses since we no longer have to re-stat every component of the docroot on every miss.

-Rasmus
? TSRM/autom4te.cache
? TSRM/stamp-h1
? TSRM/tsrm_virtual_cwd-0.c
? TSRM/tsrm_virtual_cwd-1.c
? TSRM/tsrm_virtual_cwd-2.c
Index: NEWS
===================================================================
RCS file: /repository/php-src/NEWS,v
retrieving revision 1.2027.2.547.2.965.2.259
diff -u -p -d -r1.2027.2.547.2.965.2.259 NEWS
--- NEWS        8 Aug 2008 18:46:20 -0000       1.2027.2.547.2.965.2.259
+++ NEWS        9 Aug 2008 14:52:58 -0000
@@ -5,6 +5,8 @@ PHP                                     
 
 - Changed session_start() to return false when session startup fails. (Jani)
 
+- Added system independent realpth() implementation which caches intermediate
+  results in realpath-cache (Dmitry)
 - Added optional clear_realpath_cache and filename parameters to
   clearstatcache(). (Jani, Arnaud)
 - Added litespeed SAPI module. (George Wang)
@@ -21,8 +23,11 @@ PHP                                     
 - Fixed bug #45636 (fileinfo ext duplicate strndup). (Derick)
 - Fixed bug #45545 (DateInterval has 4 char limitation for ISO durations).
   (Derick)
+- Fixed bug #45044 (relative paths not resolved correctly). (Dmitry)
 - Fixed bug #44100 (Inconsistent handling of static array declarations with
   duplicate keys). (Dmitry)
+- Fixed bug #43817 (opendir() fails on Windows directories with parent
+  directory unaccessible). (Dmitry)
 - Fixed bug #43008 (php://filter uris ignore url encoded filternames and can't
   handle slashes). (Arnaud)
 
Index: TSRM/tsrm_virtual_cwd.c
===================================================================
RCS file: /repository/TSRM/tsrm_virtual_cwd.c,v
retrieving revision 1.74.2.9.2.35.2.7
diff -u -p -d -r1.74.2.9.2.35.2.7 tsrm_virtual_cwd.c
--- TSRM/tsrm_virtual_cwd.c     20 May 2008 07:41:35 -0000      
1.74.2.9.2.35.2.7
+++ TSRM/tsrm_virtual_cwd.c     9 Aug 2008 14:52:59 -0000
@@ -257,22 +257,6 @@ static void cwd_globals_dtor(virtual_cwd
 }
 /* }}} */
 
-static char *tsrm_strndup(const char *s, size_t length) /* {{{ */
-{
-    char *p;
-
-    p = (char *) malloc(length+1);
-    if (!p) {
-        return (char *)NULL;
-    }
-    if (length) {
-        memcpy(p,s,length);
-    }
-    p[length]=0;
-    return p;
-}
-/* }}} */
-
 CWD_API void virtual_cwd_startup(void) /* {{{ */
 {
        char cwd[MAXPATHLEN];
@@ -431,9 +415,17 @@ CWD_API void realpath_cache_del(const ch
 }
 /* }}} */
 
-static inline void realpath_cache_add(const char *path, int path_len, const 
char *realpath, int realpath_len, time_t t TSRMLS_DC) /* {{{ */
+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) /* {{{ */
 {
-       long size = sizeof(realpath_cache_bucket) + path_len + 1 + realpath_len 
+ 1;
+       long size = sizeof(realpath_cache_bucket) + path_len + 1;
+       int same = 1;
+       
+       if (realpath_len != path_len ||
+           memcmp(path, realpath, path_len) != 0) {
+               size += realpath_len + 1;
+               same = 0;
+       }
+
        if (CWDG(realpath_cache_size) + size <= 
CWDG(realpath_cache_size_limit)) {
                realpath_cache_bucket *bucket = malloc(size);
                unsigned long n;
@@ -442,9 +434,14 @@ static inline void realpath_cache_add(co
                bucket->path = (char*)bucket + sizeof(realpath_cache_bucket);
                memcpy(bucket->path, path, path_len+1);
                bucket->path_len = path_len;
-               bucket->realpath = bucket->path + (path_len + 1);
-               memcpy(bucket->realpath, realpath, realpath_len+1);
+               if (same) {
+                       bucket->realpath = bucket->path;
+               } else {
+                       bucket->realpath = bucket->path + (path_len + 1);
+                       memcpy(bucket->realpath, realpath, realpath_len+1);
+               }
                bucket->realpath_len = realpath_len;
+               bucket->is_dir = is_dir;
                bucket->expires = t + CWDG(realpath_cache_ttl);
                n = bucket->key % (sizeof(CWDG(realpath_cache)) / 
sizeof(CWDG(realpath_cache)[0]));
                bucket->next = CWDG(realpath_cache)[n];
@@ -477,290 +474,351 @@ static inline realpath_cache_bucket* rea
 }
 /* }}} */
 
-/* Resolve path relatively to state and put the real path into state */
-/* returns 0 for ok, 1 for error */
-CWD_API int virtual_file_ex(cwd_state *state, const char *path, 
verify_path_func verify_path, int use_realpath) /* {{{ */
+#define LINK_MAX 32
+
+static int tsrm_realpath_r(char *path, int start, int len, int *ll, time_t *t, 
int use_realpath, int is_dir TSRMLS_DC) /* {{{ */
 {
-       int path_length = strlen(path);
-       cwd_state old_state;
-       char orig_path[MAXPATHLEN];
-       realpath_cache_bucket *bucket;
-       time_t t = 0;
-       int ret;
-       int use_cache;
-       int use_relative_path = 0;
+       int i, j, save;
+       int directory = 0;
 #ifdef TSRM_WIN32
-       int is_unc;
-       int exists;
+       WIN32_FIND_DATA data;
+       HANDLE hFind;
+#else
+       struct stat st;
 #endif
-       TSRMLS_FETCH();
-
-       use_cache = ((use_realpath != CWD_EXPAND) && 
CWDG(realpath_cache_size_limit));
-
-       if (path_length == 0) 
-               return (1);
-       if (path_length >= MAXPATHLEN)
-               return (1);
+       realpath_cache_bucket *bucket;
+       char *tmp;
+       TSRM_ALLOCA_FLAG(use_heap);
 
-#if VIRTUAL_CWD_DEBUG
-               fprintf(stderr,"cwd = %s path = %s\n", state->cwd, path);
-#endif
+       while (1) {
+               if (len <= start) {
+                       return start;
+               }
 
-       /* cwd_length can be 0 when getcwd() fails.
-        * This can happen under solaris when a dir does not have read 
permissions
-        * but *does* have execute permissions */
-       if (!IS_ABSOLUTE_PATH(path, path_length)) {
-               if (state->cwd_length == 0) {
-                       use_cache = 0;
-                       use_relative_path = 1;
-               } else {
-                       int orig_path_len;
-                       int state_cwd_length = state->cwd_length;
+               i = len;
+               while (i > start && !IS_SLASH(path[i-1])) {
+                       i--;
+               }
 
-#ifdef TSRM_WIN32
-                       if (IS_SLASH(path[0])) {
-                               state_cwd_length = 2;
+               if (i == len ||
+                       (i == len - 1 && path[i] == '.')) {
+                       /* remove double slashes and '.' */
+                       len = i - 1;
+                       is_dir = 1;
+                       continue;
+               } else if (i == len - 2 && path[i] == '.' && path[i+1] == '.') {
+                       /* remove '..' and previous directory */
+                       if (i - 1 <= start) {
+                               return start ? start : len;
                        }
-#endif
-                       orig_path_len = path_length + state_cwd_length + 1;
-                       if (orig_path_len >= MAXPATHLEN) {
-                               return 1;
+                       j = tsrm_realpath_r(path, start, i-1, ll, t, 
use_realpath, 1 TSRMLS_CC);
+                       if (j > start) {
+                               j--;
+                               while (j > start && !IS_SLASH(path[j])) {
+                                       j--;
+                               }
+                               if (!start) {
+                                       /* leading '..' must not be removed in 
case of relative path */
+                                       if (j == 0 && path[0] == '.' && path[1] 
== '.' &&
+                                           IS_SLASH(path[2])) {
+                                               path[3] = '.';
+                                               path[4] = '.';
+                                               path[5] = DEFAULT_SLASH;
+                                               j = 5;
+                                       } else if (j > 0 && 
+                                              path[j+1] == '.' && path[j+2] == 
'.' &&
+                                              IS_SLASH(path[j+3])) {
+                                               j += 4;
+                                               path[j++] = '.';
+                                               path[j++] = '.';
+                                               path[j] = DEFAULT_SLASH;
+                                       }
+                               }
+                       } else if (!start && !j) {
+                               /* leading '..' must not be removed in case of 
relative path */
+                               path[0] = '.';
+                               path[1] = '.';
+                               path[2] = DEFAULT_SLASH;
+                               j = 2;
                        }
-                       memcpy(orig_path, state->cwd, state_cwd_length);
-                       orig_path[state_cwd_length] = DEFAULT_SLASH;
-                       memcpy(orig_path + state_cwd_length + 1, path, 
path_length + 1);
-                       path = orig_path;
-                       path_length = orig_path_len; 
+                       return j;
                }
-       }
+       
+               path[len] = 0;
 
-       if (use_cache) {
-               t = CWDG(realpath_cache_ttl)?time(0):0;
-               if ((bucket = realpath_cache_find(path, path_length, t 
TSRMLS_CC)) != NULL) {           
-                       int len = bucket->realpath_len;
+               save = (use_realpath != CWD_EXPAND);
 
-                       CWD_STATE_COPY(&old_state, state);
-                       state->cwd = (char *) realloc(state->cwd, len+1);
-                       memcpy(state->cwd, bucket->realpath, len+1);
-                       state->cwd_length = len;
-                       if (verify_path && verify_path(state)) {
-                               CWD_STATE_FREE(state);
-                               *state = old_state;
-                               return 1;
-                       } else {
-                               CWD_STATE_FREE(&old_state);
-                               return 0;
+               if (start && save && CWDG(realpath_cache_size_limit)) {
+                       /* cache lookup for absolute path */
+                       if (!*t) {
+                               *t = time(0);
                        }
+                   if ((bucket = realpath_cache_find(path, len, *t TSRMLS_CC)) 
!= NULL) {
+                       if (is_dir && !bucket->is_dir) {
+                                       /* not a directory */
+                                       return -1;
+                       } else {
+                                       memcpy(path, bucket->realpath, 
bucket->realpath_len + 1);
+                                   return bucket->realpath_len;
+                               }
+               }
                }
-       }
 
-       if (use_realpath != CWD_EXPAND) {
-#if !defined(TSRM_WIN32) && !defined(NETWARE)
-               char resolved_path[MAXPATHLEN];
-
-               if (!realpath(path, resolved_path)) {  /* Note: Not threadsafe 
on older *BSD's */
+#ifdef TSRM_WIN32
+               if (save && (hFind = FindFirstFile(path, &data)) == 
INVALID_HANDLE_VALUE) {
                        if (use_realpath == CWD_REALPATH) {
-                               return 1;
+                               /* file not found */
+                               return -1;
                        }
-                       goto no_realpath;
+                       /* continue resolution anyway but don't save result in 
the cache */
+                       save = 0;
                }
-               use_realpath = CWD_REALPATH;
-               CWD_STATE_COPY(&old_state, state);
-
-               state->cwd_length = strlen(resolved_path);
-               state->cwd = (char *) realloc(state->cwd, state->cwd_length+1);
-               memcpy(state->cwd, resolved_path, state->cwd_length+1);
+               if (save) {
+                       directory = (data.dwFileAttributes & 
FILE_ATTRIBUTE_DIRECTORY) != 0;
+                       if (is_dir && !directory) {
+                               /* not a directory */
+                               return -1;
+                       }
+               }
+               tmp = tsrm_do_alloca(len+1, use_heap);
+               memcpy(tmp, path, len+1);
+#elif defined(NETWARE)
+               save = 0;
+               tmp = tsrm_do_alloca(len+1, use_heap);
+               memcpy(tmp, path, len+1);
 #else
-               goto no_realpath;
-#endif
-       } else {
-               char *ptr, *path_copy, *free_path;
-               char *tok;
-               int ptr_length;
-no_realpath:
-
-#ifdef TSRM_WIN32
-               if (memchr(path, '*', path_length) ||
-                   memchr(path, '?', path_length)) {
-                       return 1;
+               if (save && lstat(path, &st) < 0) {
+                       if (use_realpath == CWD_REALPATH) {
+                               /* file not found */
+                               return -1;
+                       }
+                       /* continue resolution anyway but don't save result in 
the cache */
+                       save = 0;
                }
-#endif
 
-               free_path = path_copy = tsrm_strndup(path, path_length);
-               CWD_STATE_COPY(&old_state, state);
+               tmp = tsrm_do_alloca(len+1, use_heap);
+               memcpy(tmp, path, len+1);
 
-#ifdef TSRM_WIN32
-               exists = (use_realpath != CWD_EXPAND);
-               ret = 0;
-               is_unc = 0;
-               if (path_length >= 2 && path[1] == ':') {                       
-                       state->cwd = (char *) realloc(state->cwd, 2 + 1);
-                       state->cwd[0] = toupper(path[0]);
-                       state->cwd[1] = ':';
-                       state->cwd[2] = '\0';
-                       state->cwd_length = 2;
-                       path_copy += 2;
-               } else if (IS_UNC_PATH(path, path_length)) {
-                       state->cwd = (char *) realloc(state->cwd, 1 + 1);
-                       state->cwd[0] = DEFAULT_SLASH;
-                       state->cwd[1] = '\0';
-                       state->cwd_length = 1;
-                       path_copy += 2;
-                       is_unc = 2;
+               if (save && S_ISLNK(st.st_mode)) {
+                       if (++(*ll) > LINK_MAX || (j = readlink(tmp, path, 
MAXPATHLEN)) < 0) {
+                           /* too many links or broken symlinks */
+                               tsrm_free_alloca(tmp, use_heap);
+                               return -1;
+                       }
+                       path[j] = 0;
+                       if (IS_ABSOLUTE_PATH(path, j)) {
+                               j = tsrm_realpath_r(path, 1, j, ll, t, 
use_realpath, is_dir TSRMLS_CC);
+                               if (j < 0) {
+                                       tsrm_free_alloca(tmp, use_heap);
+                                       return -1;
+                               }
+                       } else {
+                           if (i + j >= MAXPATHLEN-1) {
+                                       tsrm_free_alloca(tmp, use_heap);
+                                       return -1; /* buffer overflow */
+                           }
+                               memmove(path+i, path, j+1);
+                               memcpy(path, tmp, i-1);
+                               path[i-1] = DEFAULT_SLASH;
+                               j = tsrm_realpath_r(path, start, i + j, ll, t, 
use_realpath, is_dir TSRMLS_CC);
+                               if (j < 0) {
+                                       tsrm_free_alloca(tmp, use_heap);
+                                       return -1;
+                               }
+                       }
                } else {
+                       if (save) {
+                               directory = S_ISDIR(st.st_mode);
+                               if (is_dir && !directory) {
+                                       /* not a directory */
+                                       return -1;
+                               }
+                       }
 #endif
-                       state->cwd = (char *) realloc(state->cwd, 1);
-                       state->cwd[0] = '\0';
-                       state->cwd_length = 0;
+                       if (i - 1 <= start) {
+                               j = start;
+                       } else {
+                               /* some leading directories may be unaccessable 
*/
+                               j = tsrm_realpath_r(path, start, i-1, ll, t, 
save ? CWD_FILEPATH : use_realpath, 1 TSRMLS_CC);
+                               if (j > start) {
+                                       path[j++] = DEFAULT_SLASH;
+                               }
+                       }
 #ifdef TSRM_WIN32
+                       if (j < 0 || j + len - i >= MAXPATHLEN-1) {
+                               tsrm_free_alloca(tmp, use_heap);
+                               if (save) FindClose(hFind);
+                               return -1;
+                       }
+                       if (save) {
+                               memcpy(path+j, data.cFileName, len-i+1);
+                               FindClose(hFind);
+                       } else {
+                               /* use the original file or directory name as 
it wasn't found */
+                               memcpy(path+j, tmp+i, len-i+1);
+                       }
+                       j += (len-i);
+#else
+                       if (j < 0 || j + len - i >= MAXPATHLEN-1) {
+                               tsrm_free_alloca(tmp, use_heap);
+                               return -1;
+                       }
+                       memcpy(path+j, tmp+i, len-i+1);
+                       j += (len-i);
                }
 #endif
-               
-               tok = NULL;
-               ptr = tsrm_strtok_r(path_copy, TOKENIZER_STRING, &tok);
-               while (ptr) {
-                       ptr_length = strlen(ptr);
-
-                       if (IS_DIRECTORY_UP(ptr, ptr_length)) {
-                               char save;
 
-                               if (use_relative_path) {
-                                       CWD_STATE_FREE(state);
-                                       *state = old_state;
-                                       return 1;
-                               }
+               if (save && start && CWDG(realpath_cache_size_limit)) {
+                       /* save absolute path in the cache */
+                       realpath_cache_add(tmp, len, path, j, directory, *t 
TSRMLS_CC);
+               }
 
-                               save = DEFAULT_SLASH;
+               tsrm_free_alloca(tmp, use_heap);
+               return j;
+       }
+}
+/* }}} */
 
-#define PREVIOUS state->cwd[state->cwd_length - 1]
+/* Resolve path relatively to state and put the real path into state */
+/* returns 0 for ok, 1 for error */
+CWD_API int virtual_file_ex(cwd_state *state, const char *path, 
verify_path_func verify_path, int use_realpath) /* {{{ */
+{
+       int path_length = strlen(path);
+       char resolved_path[MAXPATHLEN];
+       int start = 1;
+       int ll = 0;
+       time_t t;
+       int ret;
+       int add_slash;
+       TSRMLS_FETCH();
 
-                               while (IS_ABSOLUTE_PATH(state->cwd, 
state->cwd_length) &&
-                                               !IS_SLASH(PREVIOUS)) {
-                                       save = PREVIOUS;
-                                       PREVIOUS = '\0';
-                                       state->cwd_length--;
-                               }
+       if (path_length == 0 || path_length >= MAXPATHLEN-1) {
+               return 1;
+       }
 
-                               if (!IS_ABSOLUTE_PATH(state->cwd, 
state->cwd_length)) {
-                                       state->cwd[state->cwd_length++] = save;
-                                       state->cwd[state->cwd_length] = '\0';
-                               } else {
-                                       PREVIOUS = '\0';
-                                       state->cwd_length--;
-                               }
-                       } else if (!IS_DIRECTORY_CURRENT(ptr, ptr_length)) {
-                               if (use_relative_path) {
-                                       state->cwd = (char *) 
realloc(state->cwd, state->cwd_length+ptr_length+1);
-                                       use_relative_path = 0;
-                               } else {
-                                       state->cwd = (char *) 
realloc(state->cwd, state->cwd_length+ptr_length+1+1);
-#ifdef TSRM_WIN32
-                                       /* Windows 9x will consider C:\\Foo as 
a network path. Avoid it. */
-                                       if (state->cwd_length < 2 ||
-                                           
(state->cwd[state->cwd_length-1]!='\\' && state->cwd[state->cwd_length-1]!='/') 
||
-                                                       
IsDBCSLeadByte(state->cwd[state->cwd_length-2])) {
-                                               state->cwd[state->cwd_length++] 
= DEFAULT_SLASH;
-                                       }
-#elif defined(NETWARE)
-                                       /* 
-                                       Below code keeps appending to 
state->cwd a File system seperator
-                                       cases where this appending should not 
happen is given below,
-                                       a) sys: should just be left as it is
-                                       b) sys:system should just be left as it 
is,
-                                               Colon is allowed only in the 
first token as volume names alone can have the : in their names.
-                                               Files and Directories cannot 
have : in their names
-                                               So the check goes like this,
-                                               For second token and above 
simply append the DEFAULT_SLASH to the state->cwd.
-                                               For first token check for the 
existence of : 
-                                               if it exists don't append the 
DEFAULT_SLASH to the state->cwd.
-                                       */
-                                       if(((state->cwd_length == 0) && 
(strchr(ptr, ':') == NULL)) || (state->cwd_length > 0)) {
-                                               state->cwd[state->cwd_length++] 
= DEFAULT_SLASH;
-                                       }
-#else
-                                       state->cwd[state->cwd_length++] = 
DEFAULT_SLASH;
+#if VIRTUAL_CWD_DEBUG
+       fprintf(stderr,"cwd = %s path = %s\n", state->cwd, path);
 #endif
-                               }
-                               memcpy(&state->cwd[state->cwd_length], ptr, 
ptr_length+1);
-
-#ifdef TSRM_WIN32
-                               if (use_realpath != CWD_EXPAND) {
-                                       WIN32_FIND_DATA data;
-                                       HANDLE hFind;
 
-                                       if ((hFind = FindFirstFile(state->cwd, 
&data)) != INVALID_HANDLE_VALUE) {
-                                               int length = 
strlen(data.cFileName);
+       /* cwd_length can be 0 when getcwd() fails.
+        * This can happen under solaris when a dir does not have read 
permissions
+        * but *does* have execute permissions */
+       if (!IS_ABSOLUTE_PATH(path, path_length)) {
+               if (state->cwd_length == 0) {
+                       /* resolve relative path */
+                       start = 0;
+                       memcpy(resolved_path , path, path_length + 1);
+               } else {
+                       int state_cwd_length = state->cwd_length;
 
-                                               if (length != ptr_length) {
-                                                       state->cwd = (char *) 
realloc(state->cwd, state->cwd_length+length+1);
-                                               }
-                                               
memcpy(&state->cwd[state->cwd_length], data.cFileName, length+1);
-                                               ptr_length = length;
-                                               FindClose(hFind);
-                                               ret = 0;
-                                       } else {
-                                               if (is_unc) {
-                                                       /* skip share name */
-                                                       is_unc--;
-                                                       ret = 0;
-                                               } else {
-                                                       exists = 0;
-                                                       if (use_realpath == 
CWD_REALPATH) {
-                                                               ret = 1;
-                                                       }
-                                               }
-                                       }
-                               }
+#ifdef TSRM_WIN32
+                       if (IS_SLASH(path[0])) {
+                               state_cwd_length = 2;
+                       }
 #endif
-
-                               state->cwd_length += ptr_length;
+                       if (path_length + state_cwd_length + 1 >= MAXPATHLEN-1) 
{
+                               return 1;
                        }
-                       ptr = tsrm_strtok_r(NULL, TOKENIZER_STRING, &tok);
+                       memcpy(resolved_path, state->cwd, state_cwd_length);
+                       resolved_path[state_cwd_length] = DEFAULT_SLASH;
+                       memcpy(resolved_path + state_cwd_length + 1, path, 
path_length + 1);
+                       path_length += state_cwd_length + 1;
                }
+       } else {                
+               memcpy(resolved_path , path, path_length + 1);
+       } 
 
-               free(free_path);
+#ifdef TSRM_WIN32
+       if (memchr(resolved_path, '*', path_length) ||
+           memchr(resolved_path, '?', path_length)) {
+               return 1;
+       }
+#endif
 
-               if (use_realpath == CWD_REALPATH) {
-                       if (ret) {
-                               CWD_STATE_FREE(state);
-                               *state = old_state;                             
        
-                               return 1;
+#ifdef TSRM_WIN32
+       if (IS_UNC_PATH(resolved_path, path_length)) {
+               /* skip UNC name */
+               resolved_path[0] = DEFAULT_SLASH;
+               resolved_path[1] = DEFAULT_SLASH;
+               start = 2;
+               while (!IS_SLASH(resolved_path[start])) {
+                       if (resolved_path[start] == 0) {
+                               goto verify;
                        }
-               } else {
-#if defined(TSRM_WIN32) || defined(NETWARE)
-                       if (path[path_length-1] == '\\' || path[path_length-1] 
== '/') {
-#else 
-                       if (path[path_length-1] == '/') {
-#endif
-                               state->cwd = (char*)realloc(state->cwd, 
state->cwd_length + 2);
-                               state->cwd[state->cwd_length++] = DEFAULT_SLASH;
-                               state->cwd[state->cwd_length] = 0;
+                       resolved_path[start] = toupper(resolved_path[start]);
+                       start++;
+               }
+               resolved_path[start++] = DEFAULT_SLASH;
+               while (!IS_SLASH(resolved_path[start])) {
+                       if (resolved_path[start] == 0) {
+                               goto verify;
                        }
+                       resolved_path[start] = toupper(resolved_path[start]);
+                       start++;
                }
+               resolved_path[start++] = DEFAULT_SLASH;
+       } else if (IS_ABSOLUTE_PATH(resolved_path, path_length)) {
+               /* skip DRIVE name */
+               resolved_path[0] = toupper(resolved_path[0]);
+               resolved_path[2] = DEFAULT_SLASH;
+               start = 3;
+       }
+#elif defined(NETWARE)
+       if (IS_ABSOLUTE_PATH(resolved_path, path_length)) {
+               /* skip VOLUME name */
+               start = 0;
+               while (start != ':') {
+                       if (resolved_path[start] == 0) return -1;
+                       start++;
+               }
+               start++;
+               if (!IS_SLASH(resolved_path[start])) return -1;
+               resolved_path[start++] = DEFAULT_SLASH;
+       }
+#endif
 
-               if (state->cwd_length == COPY_WHEN_ABSOLUTE(state->cwd)) {
-                       state->cwd = (char *) realloc(state->cwd, 
state->cwd_length+1+1);
-                       state->cwd[state->cwd_length] = DEFAULT_SLASH;
-                       state->cwd[state->cwd_length+1] = '\0';
-                       state->cwd_length++;
+
+       add_slash = (use_realpath != CWD_REALPATH) && path_length > 0 && 
IS_SLASH(resolved_path[path_length-1]);        
+       t = CWDG(realpath_cache_ttl) ? 0 : -1;
+       path_length = tsrm_realpath_r(resolved_path, start, path_length, &ll, 
&t, use_realpath, 0 TSRMLS_CC);
+       
+       if (path_length < 0) {
+               return 1;
+       }
+       
+       if (!start && !path_length) {
+               resolved_path[path_length++] = '.';
+       }
+       if (add_slash && path_length && 
!IS_SLASH(resolved_path[path_length-1])) {
+               if (path_length >= MAXPATHLEN-1) {
+                       return -1;
                }
+               resolved_path[path_length++] = DEFAULT_SLASH;
        }
+       resolved_path[path_length] = 0;
 
-       /* Store existent file in realpath cache. */
 #ifdef TSRM_WIN32
-       if (use_cache && !is_unc && exists) {
-#else
-       if (use_cache && (use_realpath == CWD_REALPATH)) {
+verify:
 #endif
-               realpath_cache_add(path, path_length, state->cwd, 
state->cwd_length, t TSRMLS_CC);
-       }
+       if (verify_path) {
+               cwd_state old_state;
 
-       if (verify_path && verify_path(state)) {
-               CWD_STATE_FREE(state);
-               *state = old_state;
-               ret = 1;
+               CWD_STATE_COPY(&old_state, state);
+               state->cwd_length = path_length;
+               state->cwd = (char *) realloc(state->cwd, state->cwd_length+1);
+               memcpy(state->cwd, resolved_path, state->cwd_length+1);
+               if (verify_path(state)) {
+                       CWD_STATE_FREE(state);
+                       *state = old_state;
+                       ret = 1;
+               } else {
+                       CWD_STATE_FREE(&old_state);
+                       ret = 0;
+               }
        } else {
-               CWD_STATE_FREE(&old_state);
+               state->cwd_length = path_length;
+               state->cwd = (char *) realloc(state->cwd, state->cwd_length+1);
+               memcpy(state->cwd, resolved_path, state->cwd_length+1);
                ret = 0;
        }
        
Index: TSRM/tsrm_virtual_cwd.h
===================================================================
RCS file: /repository/TSRM/tsrm_virtual_cwd.h,v
retrieving revision 1.48.2.5.2.8.2.4
diff -u -p -d -r1.48.2.5.2.8.2.4 tsrm_virtual_cwd.h
--- TSRM/tsrm_virtual_cwd.h     2 May 2008 14:07:26 -0000       1.48.2.5.2.8.2.4
+++ TSRM/tsrm_virtual_cwd.h     9 Aug 2008 14:52:59 -0000
@@ -208,6 +208,7 @@ typedef struct _realpath_cache_bucket {
        int                            path_len;
        char                          *realpath;
        int                            realpath_len;
+       int                            is_dir;
        time_t                         expires;
        struct _realpath_cache_bucket *next;    
 } realpath_cache_bucket;

-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to