From: Sascha Schumann Date: Thu, 16 Mar 2000 18:25:47 +0000 (+0000) Subject: virtual_chdir: X-Git-Tag: PHP-4.0-RC1~112 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=3cb7cf43defe7e063e951b437d7427337b461eca;p=php virtual_chdir: * added error handling * fixed the special case where there were more DIRECTORY_UPs than directory parts (i.e. cwd is d:\foo and path is ../..) * no spaces between # and preprocessor directive - breaks some compilers # added directory-existence check (not activated) --- diff --git a/main/php_virtual_cwd.c b/main/php_virtual_cwd.c index 168067d8ef..3e7b99c2b3 100644 --- a/main/php_virtual_cwd.c +++ b/main/php_virtual_cwd.c @@ -1,25 +1,86 @@ +#include +#include #include #include +#include +#include +#include +#include +#include typedef unsigned int uint; #if WINDOWS -# define IS_SLASH(c) ((c) == '/' || (c) == '\\') -# define DEFAULT_SLASH '\\' -# define TOKENIZER_STRING "/\\" +#define IS_SLASH(c) ((c) == '/' || (c) == '\\') +#define DEFAULT_SLASH '\\' +#define TOKENIZER_STRING "/\\" + +#define IS_ABSOLUTE_PATH(path, len) \ + (len >= 2 && isalpha(path[0]) && path[1] == ':') + +static int php_check_dots(char *element, uint len) +{ + uint n = len; + + while (n-- > 0) if (element[n] != '.') break; + + return (n != -1); +} + +#define IS_DIRECTORY_UP(element, len) \ + (len >= 2 && !php_check_dots(element, len)) + +#define IS_DIRECTORY_CURRENT(element, len) \ + (len == 1 && ptr[0] == '.') + + #else -# define IS_SLASH(c) ((c) == '/') -# define DEFAULT_SLASH '/' -# define TOKENIZER_STRING "/" +#define IS_SLASH(c) ((c) == '/') +#define DEFAULT_SLASH '/' +#define TOKENIZER_STRING "/" +#endif + + +/* default macros */ + +#ifndef IS_ABSOLUTE_PATH +#define IS_ABSOLUTE_PATH(path, len) \ + (IS_SLASH(path[0])) #endif +#ifndef IS_DIRECTORY_UP +#define IS_DIRECTORY_UP(element, len) \ + (len == 2 && memcmp(element, "..", 2) == 0) +#endif +#ifndef IS_DIRECTORY_CURRENT +#define IS_DIRECTORY_CURRENT(element, len) \ + (len == 1 && ptr[0] == '.') +#endif +/* for now */ +#define IS_DIR_OK(s) (1) + +#ifndef IS_DIR_OK +#define IS_DIR_OK(state) (php_is_dir_ok(state) == 0) +#endif + typedef struct _cwd_state { char *cwd; uint cwd_length; } cwd_state; +static int php_is_dir_ok(const cwd_state *state) +{ + struct stat buf; + + if (stat(state->cwd, &buf) == 0 && S_ISDIR(buf.st_mode)) + return (0); + + return (1); +} + + char *virtual_getcwd(cwd_state *state, uint *length) { if (state->cwd_length == 0) { @@ -49,60 +110,110 @@ char *virtual_getcwd(cwd_state *state, uint *length) return strdup(state->cwd); } -void virtual_chdir(cwd_state *state, char *path) +/* returns 0 for ok, 1 for error */ +int virtual_chdir(cwd_state *state, char *path) { uint path_length = strlen(path); char *ptr = path; + char *tok = NULL; uint ptr_length; + cwd_state *old_state; - if (path_length == 0) { - return; - } -#if WINDOWS - /* Full path includes anything starting with C: */ - if (IS_SLASH(*ptr) || (path_length >= 2 && path[1] == ':')) -#else - if (IS_SLASH(*ptr)) -#endif - { - state->cwd = (char *) realloc(state->cwd, 1); + if (path_length == 0) + return (0); + + old_state = (cwd_state *) malloc(sizeof(*old_state)); + old_state->cwd = strdup(state->cwd); + old_state->cwd_length = state->cwd_length; + + if (IS_ABSOLUTE_PATH(path, path_length)) { + state->cwd = (char *) malloc(1); state->cwd[0] = '\0'; state->cwd_length = 0; - } - - ptr = strtok(path, TOKENIZER_STRING); - while(ptr) { - ptr_length = strlen(ptr); - if (ptr_length == 2 && !memcmp(ptr, "..", 2)) { - while (!IS_SLASH(state->cwd[state->cwd_length-1])) { - state->cwd[--(state->cwd_length)] = '\0'; +#if WINDOWS + } else if(IS_SLASH(path[0])) { + state->cwd = (char *) malloc(3); + memcpy(state->cwd, old_state->cwd, 2); + state->cwd[2] = '\0'; + state->cwd_length = 2; +#endif + } + + + ptr = strtok_r(path, TOKENIZER_STRING, &tok); + while (ptr) { + ptr_length = strlen(ptr); + + + if (IS_DIRECTORY_UP(ptr, ptr_length)) { + char save; + + save = '\0'; + +#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--; } - state->cwd[--(state->cwd_length)] = '\0'; - } else if (ptr_length == 1 && *ptr == '.') { - /* Do nothing */ - } else { + } else if (!IS_DIRECTORY_CURRENT(ptr, ptr_length)) { state->cwd = (char *) realloc(state->cwd, state->cwd_length+ptr_length+1+1); state->cwd[state->cwd_length] = DEFAULT_SLASH; memcpy(&state->cwd[state->cwd_length+1], ptr, ptr_length+1); state->cwd_length += (ptr_length+1); } - ptr = strtok(NULL, TOKENIZER_STRING); + ptr = strtok_r(NULL, TOKENIZER_STRING, &tok); } + + if (!IS_DIR_OK(state)) { + free(state->cwd); + + state->cwd = old_state->cwd; + state->cwd_length = state->cwd_length; + + free(old_state); + + return (1); + } + + return (0); } -main() +void main(void) { cwd_state state; uint length; - - state.cwd = strdup(""); - state.cwd_length = 0; + +#if !WINDOWS + state.cwd = malloc(PATH_MAX + 1); + state.cwd_length = PATH_MAX; + + while (getcwd(state.cwd, state.cwd_length) == NULL && errno == ERANGE) { + state.cwd_length <<= 1; + state.cwd = realloc(state.cwd, state.cwd_length + 1); + } +#else + state.cwd = strdup("d:\\foo\\bar"); + state.cwd_length = strlen(state.cwd); +#endif printf("%s\n", virtual_getcwd(&state, &length)); virtual_chdir(&state, strdup("/foo/barbara")); printf("%s\n", virtual_getcwd(&state, &length)); virtual_chdir(&state, strdup("../andi")); printf("%s\n", virtual_getcwd(&state, &length)); + virtual_chdir(&state, strdup("../../..../.././.../foo/...../")); + printf("%s\n", virtual_getcwd(&state, &length)); virtual_chdir(&state, strdup("/////andi")); printf("%s\n", virtual_getcwd(&state, &length)); virtual_chdir(&state, strdup("andi/././././././////bar"));