mirror of
https://github.com/php/php-src.git
synced 2024-09-21 18:07:23 +00:00
- Added system independent realpath() implementation which caches intermediate directories in realpath-cache
- Fixed bug #45044 (relative paths not resolved correctly) - Fixed bug #43817 (opendir() fails on Windows directories with parent directory unaccessible). [DOC] The semantic of realpath() on BSD and Windows is changed. Now it should work exactly in the same way as on Linux (POSIX.1-2001)
This commit is contained in:
parent
a12b6846e5
commit
3fadad3160
5
NEWS
5
NEWS
@ -5,6 +5,8 @@ PHP NEWS
|
||||
|
||||
- Changed session_start() to return false when session startup fails. (Jani)
|
||||
|
||||
- Added system independent realpath() implementation which caches intermediate
|
||||
directories in realpath-cache (Dmitry)
|
||||
- Added optional clear_realpath_cache and filename parameters to
|
||||
clearstatcache(). (Jani, Arnaud)
|
||||
- Added litespeed SAPI module. (George Wang)
|
||||
@ -22,8 +24,11 @@ PHP NEWS
|
||||
- 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)
|
||||
|
||||
|
@ -257,22 +257,6 @@ static void cwd_globals_dtor(virtual_cwd_globals *cwd_globals TSRMLS_DC) /* {{{
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
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 char *path, int path_len TSRMLS_DC) /* {{{
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
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(const char *path, int path_len, const char
|
||||
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,33 +474,231 @@ static inline realpath_cache_bucket* realpath_cache_find(const char *path, int p
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
#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 i, j, save;
|
||||
int directory = 0;
|
||||
#ifdef TSRM_WIN32
|
||||
WIN32_FIND_DATA data;
|
||||
HANDLE hFind;
|
||||
#else
|
||||
struct stat st;
|
||||
#endif
|
||||
realpath_cache_bucket *bucket;
|
||||
char *tmp;
|
||||
TSRM_ALLOCA_FLAG(use_heap);
|
||||
|
||||
while (1) {
|
||||
if (len <= start) {
|
||||
return start;
|
||||
}
|
||||
|
||||
i = len;
|
||||
while (i > start && !IS_SLASH(path[i-1])) {
|
||||
i--;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
return j;
|
||||
}
|
||||
|
||||
path[len] = 0;
|
||||
|
||||
save = (use_realpath != CWD_EXPAND);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef TSRM_WIN32
|
||||
if (save && (hFind = FindFirstFile(path, &data)) == INVALID_HANDLE_VALUE) {
|
||||
if (use_realpath == CWD_REALPATH) {
|
||||
/* file not found */
|
||||
return -1;
|
||||
}
|
||||
/* continue resolution anyway but don't save result in the cache */
|
||||
save = 0;
|
||||
}
|
||||
if (save) {
|
||||
directory = (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
|
||||
if (is_dir && !directory) {
|
||||
/* not a directory */
|
||||
FindClose(hFind);
|
||||
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
|
||||
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;
|
||||
}
|
||||
|
||||
tmp = tsrm_do_alloca(len+1, use_heap);
|
||||
memcpy(tmp, path, len+1);
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
tsrm_free_alloca(tmp, use_heap);
|
||||
return j;
|
||||
}
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* 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);
|
||||
cwd_state old_state;
|
||||
char orig_path[MAXPATHLEN];
|
||||
realpath_cache_bucket *bucket;
|
||||
time_t t = 0;
|
||||
char resolved_path[MAXPATHLEN];
|
||||
int start = 1;
|
||||
int ll = 0;
|
||||
time_t t;
|
||||
int ret;
|
||||
int use_cache;
|
||||
int use_relative_path = 0;
|
||||
#ifdef TSRM_WIN32
|
||||
int is_unc;
|
||||
int exists;
|
||||
#endif
|
||||
int add_slash;
|
||||
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);
|
||||
if (path_length == 0 || path_length >= MAXPATHLEN-1) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if VIRTUAL_CWD_DEBUG
|
||||
fprintf(stderr,"cwd = %s path = %s\n", state->cwd, path);
|
||||
fprintf(stderr,"cwd = %s path = %s\n", state->cwd, path);
|
||||
#endif
|
||||
|
||||
/* cwd_length can be 0 when getcwd() fails.
|
||||
@ -511,10 +706,10 @@ CWD_API int virtual_file_ex(cwd_state *state, const char *path, verify_path_func
|
||||
* but *does* have execute permissions */
|
||||
if (!IS_ABSOLUTE_PATH(path, path_length)) {
|
||||
if (state->cwd_length == 0) {
|
||||
use_cache = 0;
|
||||
use_relative_path = 1;
|
||||
/* resolve relative path */
|
||||
start = 0;
|
||||
memcpy(resolved_path , path, path_length + 1);
|
||||
} else {
|
||||
int orig_path_len;
|
||||
int state_cwd_length = state->cwd_length;
|
||||
|
||||
#ifdef TSRM_WIN32
|
||||
@ -522,245 +717,109 @@ CWD_API int virtual_file_ex(cwd_state *state, const char *path, verify_path_func
|
||||
state_cwd_length = 2;
|
||||
}
|
||||
#endif
|
||||
orig_path_len = path_length + state_cwd_length + 1;
|
||||
if (orig_path_len >= MAXPATHLEN) {
|
||||
if (path_length + state_cwd_length + 1 >= MAXPATHLEN-1) {
|
||||
return 1;
|
||||
}
|
||||
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;
|
||||
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);
|
||||
}
|
||||
|
||||
#ifdef TSRM_WIN32
|
||||
if (memchr(resolved_path, '*', path_length) ||
|
||||
memchr(resolved_path, '?', path_length)) {
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
#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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
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 */
|
||||
if (use_realpath == CWD_REALPATH) {
|
||||
return 1;
|
||||
}
|
||||
goto no_realpath;
|
||||
#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++;
|
||||
}
|
||||
use_realpath = CWD_REALPATH;
|
||||
start++;
|
||||
if (!IS_SLASH(resolved_path[start])) return -1;
|
||||
resolved_path[start++] = DEFAULT_SLASH;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
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;
|
||||
|
||||
#ifdef TSRM_WIN32
|
||||
verify:
|
||||
#endif
|
||||
if (verify_path) {
|
||||
cwd_state old_state;
|
||||
|
||||
CWD_STATE_COPY(&old_state, state);
|
||||
|
||||
state->cwd_length = strlen(resolved_path);
|
||||
state->cwd_length = path_length;
|
||||
state->cwd = (char *) realloc(state->cwd, state->cwd_length+1);
|
||||
memcpy(state->cwd, resolved_path, state->cwd_length+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;
|
||||
}
|
||||
#endif
|
||||
|
||||
free_path = path_copy = tsrm_strndup(path, path_length);
|
||||
CWD_STATE_COPY(&old_state, state);
|
||||
|
||||
#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 (verify_path(state)) {
|
||||
CWD_STATE_FREE(state);
|
||||
*state = old_state;
|
||||
ret = 1;
|
||||
} else {
|
||||
#endif
|
||||
state->cwd = (char *) realloc(state->cwd, 1);
|
||||
state->cwd[0] = '\0';
|
||||
state->cwd_length = 0;
|
||||
#ifdef TSRM_WIN32
|
||||
CWD_STATE_FREE(&old_state);
|
||||
ret = 0;
|
||||
}
|
||||
#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;
|
||||
}
|
||||
|
||||
save = DEFAULT_SLASH;
|
||||
|
||||
#define PREVIOUS state->cwd[state->cwd_length - 1]
|
||||
|
||||
while (IS_ABSOLUTE_PATH(state->cwd, state->cwd_length) &&
|
||||
!IS_SLASH(PREVIOUS)) {
|
||||
save = PREVIOUS;
|
||||
PREVIOUS = '\0';
|
||||
state->cwd_length--;
|
||||
}
|
||||
|
||||
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;
|
||||
#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);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
state->cwd_length += ptr_length;
|
||||
}
|
||||
ptr = tsrm_strtok_r(NULL, TOKENIZER_STRING, &tok);
|
||||
}
|
||||
|
||||
free(free_path);
|
||||
|
||||
if (use_realpath == CWD_REALPATH) {
|
||||
if (ret) {
|
||||
CWD_STATE_FREE(state);
|
||||
*state = old_state;
|
||||
return 1;
|
||||
}
|
||||
} 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;
|
||||
}
|
||||
}
|
||||
|
||||
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++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Store existent file in realpath cache. */
|
||||
#ifdef TSRM_WIN32
|
||||
if (use_cache && !is_unc && exists) {
|
||||
#else
|
||||
if (use_cache && (use_realpath == CWD_REALPATH)) {
|
||||
#endif
|
||||
realpath_cache_add(path, path_length, state->cwd, state->cwd_length, t TSRMLS_CC);
|
||||
}
|
||||
|
||||
if (verify_path && verify_path(state)) {
|
||||
CWD_STATE_FREE(state);
|
||||
*state = old_state;
|
||||
ret = 1;
|
||||
} 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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user