Code

Windows: Treat Windows style path names.
authorJohannes Sixt <johannes.sixt@telecom.at>
Wed, 5 Mar 2008 20:51:27 +0000 (21:51 +0100)
committerJohannes Sixt <johannes.sixt@telecom.at>
Mon, 23 Jun 2008 11:30:22 +0000 (13:30 +0200)
GIT's guts work with a forward slash as a path separators. We do not change
that. Rather we make sure that only "normalized" paths enter the depths
of the machinery.

We have to translate backslashes to forward slashes in the prefix and in
command line arguments. Fortunately, all of them are passed through
functions in setup.c.

A macro has_dos_drive_path() is defined that checks whether a path begins
with a drive letter+colon combination. This predicate is always false on
Unix. Another macro is_dir_sep() abstracts that a backslash is also a
directory separator on Windows.

Signed-off-by: Johannes Sixt <johannes.sixt@telecom.at>
cache.h
compat/mingw.c
compat/mingw.h
git-compat-util.h
setup.c

diff --git a/cache.h b/cache.h
index 81b7e17de26ae33249c60b101f5718cb5c5e5699..72544de4ce22c7b9b5cf6d0da786a243992ae5ce 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -521,7 +521,7 @@ int safe_create_leading_directories(char *path);
 char *enter_repo(char *path, int strict);
 static inline int is_absolute_path(const char *path)
 {
-       return path[0] == '/';
+       return path[0] == '/' || has_dos_drive_prefix(path);
 }
 const char *make_absolute_path(const char *path);
 const char *make_nonrelative_path(const char *path);
index 075448d2455f8237e867bd4ff82eec7867442b27..4e559bdc93dbee413fd574168fd382e4682a0092 100644 (file)
@@ -40,6 +40,19 @@ struct tm *localtime_r(const time_t *timep, struct tm *result)
        return result;
 }
 
+#undef getcwd
+char *mingw_getcwd(char *pointer, int len)
+{
+       int i;
+       char *ret = getcwd(pointer, len);
+       if (!ret)
+               return ret;
+       for (i = 0; pointer[i]; i++)
+               if (pointer[i] == '\\')
+                       pointer[i] = '/';
+       return ret;
+}
+
 struct passwd *getpwuid(int uid)
 {
        static struct passwd p;
index 22aae0077ef1a78fc54abdc1d0a04e3db23745a6..a954014ff2a815a931fcb968308aa11739b544c1 100644 (file)
@@ -133,8 +133,17 @@ struct passwd *getpwuid(int uid);
 int setitimer(int type, struct itimerval *in, struct itimerval *out);
 int sigaction(int sig, struct sigaction *in, struct sigaction *out);
 
+/*
+ * replacements of existing functions
+ */
+
+char *mingw_getcwd(char *pointer, int len);
+#define getcwd mingw_getcwd
+
 /*
  * git specific compatibility
  */
 
+#define has_dos_drive_prefix(path) (isalpha(*(path)) && (path)[1] == ':')
+#define is_dir_sep(c) ((c) == '/' || (c) == '\\')
 #define PATH_SEP ';'
index 9dc733e56ceb2c2e95dfc3b14c29e825b3c25615..ab762c79eedb6ba9f539f6679f0d1231d9206f3f 100644 (file)
 #define PATH_SEP ':'
 #endif
 
+#ifndef has_dos_drive_prefix
+#define has_dos_drive_prefix(path) 0
+#endif
+
+#ifndef is_dir_sep
+#define is_dir_sep(c) ((c) == '/')
+#endif
+
 #ifdef __GNUC__
 #define NORETURN __attribute__((__noreturn__))
 #else
diff --git a/setup.c b/setup.c
index 5fc89fd7da6a7035e7c187e17074073b8d51e6a7..8bb7b10174fdb24f2a028d6404224109c600b7ca 100644 (file)
--- a/setup.c
+++ b/setup.c
@@ -6,11 +6,17 @@ static int inside_work_tree = -1;
 
 static int sanitary_path_copy(char *dst, const char *src)
 {
-       char *dst0 = dst;
+       char *dst0;
 
-       if (*src == '/') {
+       if (has_dos_drive_prefix(src)) {
+               *dst++ = *src++;
+               *dst++ = *src++;
+       }
+       dst0 = dst;
+
+       if (is_dir_sep(*src)) {
                *dst++ = '/';
-               while (*src == '/')
+               while (is_dir_sep(*src))
                        src++;
        }
 
@@ -29,10 +35,10 @@ static int sanitary_path_copy(char *dst, const char *src)
                        if (!src[1]) {
                                /* (1) */
                                src++;
-                       } else if (src[1] == '/') {
+                       } else if (is_dir_sep(src[1])) {
                                /* (2) */
                                src += 2;
-                               while (*src == '/')
+                               while (is_dir_sep(*src))
                                        src++;
                                continue;
                        } else if (src[1] == '.') {
@@ -40,10 +46,10 @@ static int sanitary_path_copy(char *dst, const char *src)
                                        /* (3) */
                                        src += 2;
                                        goto up_one;
-                               } else if (src[2] == '/') {
+                               } else if (is_dir_sep(src[2])) {
                                        /* (4) */
                                        src += 3;
-                                       while (*src == '/')
+                                       while (is_dir_sep(*src))
                                                src++;
                                        goto up_one;
                                }
@@ -51,11 +57,11 @@ static int sanitary_path_copy(char *dst, const char *src)
                }
 
                /* copy up to the next '/', and eat all '/' */
-               while ((c = *src++) != '\0' && c != '/')
+               while ((c = *src++) != '\0' && !is_dir_sep(c))
                        *dst++ = c;
-               if (c == '/') {
-                       *dst++ = c;
-                       while (c == '/')
+               if (is_dir_sep(c)) {
+                       *dst++ = '/';
+                       while (is_dir_sep(c))
                                c = *src++;
                        src--;
                } else if (!c)
@@ -74,7 +80,7 @@ static int sanitary_path_copy(char *dst, const char *src)
                        if (dst <= dst0)
                                break;
                        c = *dst--;
-                       if (c == '/') {
+                       if (c == '/') { /* MinGW: cannot be '\\' anymore */
                                dst += 2;
                                break;
                        }
@@ -123,10 +129,23 @@ const char *prefix_path(const char *prefix, int len, const char *path)
 const char *prefix_filename(const char *pfx, int pfx_len, const char *arg)
 {
        static char path[PATH_MAX];
+#ifndef __MINGW32__
        if (!pfx || !*pfx || is_absolute_path(arg))
                return arg;
        memcpy(path, pfx, pfx_len);
        strcpy(path + pfx_len, arg);
+#else
+       char *p;
+       /* don't add prefix to absolute paths, but still replace '\' by '/' */
+       if (is_absolute_path(arg))
+               pfx_len = 0;
+       else
+               memcpy(path, pfx, pfx_len);
+       strcpy(path + pfx_len, arg);
+       for (p = path + pfx_len; *p; p++)
+               if (*p == '\\')
+                       *p = '/';
+#endif
        return path;
 }
 
@@ -360,6 +379,7 @@ const char *setup_git_directory_gently(int *nongit_ok)
        const char *gitdirenv;
        const char *gitfile_dir;
        int len, offset;
+       int minoffset = 0;
 
        /*
         * Let's assume that we are in a git repository.
@@ -410,6 +430,8 @@ const char *setup_git_directory_gently(int *nongit_ok)
 
        if (!getcwd(cwd, sizeof(cwd)-1))
                die("Unable to read current working directory");
+       if (has_dos_drive_prefix(cwd))
+               minoffset = 2;
 
        /*
         * Test in the following order (relative to the cwd):
@@ -442,7 +464,7 @@ const char *setup_git_directory_gently(int *nongit_ok)
                }
                chdir("..");
                do {
-                       if (!offset) {
+                       if (offset <= minoffset) {
                                if (nongit_ok) {
                                        if (chdir(cwd))
                                                die("Cannot come back to cwd");
@@ -451,7 +473,7 @@ const char *setup_git_directory_gently(int *nongit_ok)
                                }
                                die("Not a git repository");
                        }
-               } while (cwd[--offset] != '/');
+               } while (offset > minoffset && cwd[--offset] != '/');
        }
 
        inside_git_dir = 0;