]> granicus.if.org Git - php/commitdiff
virtual_chdir:
authorSascha Schumann <sas@php.net>
Thu, 16 Mar 2000 18:25:47 +0000 (18:25 +0000)
committerSascha Schumann <sas@php.net>
Thu, 16 Mar 2000 18:25:47 +0000 (18:25 +0000)
* 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)

main/php_virtual_cwd.c

index 168067d8ef8cfbd1b57de07d8d2b07c51c98de9a..3e7b99c2b3e4342f21210b5134ce911face35a2b 100644 (file)
@@ -1,25 +1,86 @@
+#include <sys/types.h>
+#include <sys/stat.h>
 #include <string.h>
 #include <stdio.h>
+#include <unistd.h>
+#include <limits.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <ctype.h>
 
 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"));