Merge branch 'mv/commit-tree'
[gitweb.git] / setup.c
diff --git a/setup.c b/setup.c
index 5fc89fd7da6a7035e7c187e17074073b8d51e6a7..2e3248a0c4958f31001213470a88d1154b5947fc 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 != '/')
-                       *dst++ = c;
-               if (c == '/') {
+               while ((c = *src++) != '\0' && !is_dir_sep(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;
 }
 
@@ -289,9 +308,10 @@ void setup_work_tree(void)
        work_tree = get_git_work_tree();
        git_dir = get_git_dir();
        if (!is_absolute_path(git_dir))
-               set_git_dir(make_absolute_path(git_dir));
+               git_dir = make_absolute_path(git_dir);
        if (!work_tree || chdir(work_tree))
                die("This operation must be run in a work tree");
+       set_git_dir(make_relative_path(git_dir, work_tree));
        initialized = 1;
 }
 
@@ -356,10 +376,11 @@ const char *read_gitfile_gently(const char *path)
 const char *setup_git_directory_gently(int *nongit_ok)
 {
        const char *work_tree_env = getenv(GIT_WORK_TREE_ENVIRONMENT);
+       const char *env_ceiling_dirs = getenv(CEILING_DIRECTORIES_ENVIRONMENT);
        static char cwd[PATH_MAX+1];
        const char *gitdirenv;
        const char *gitfile_dir;
-       int len, offset;
+       int len, offset, ceil_offset;
 
        /*
         * Let's assume that we are in a git repository.
@@ -411,6 +432,10 @@ const char *setup_git_directory_gently(int *nongit_ok)
        if (!getcwd(cwd, sizeof(cwd)-1))
                die("Unable to read current working directory");
 
+       ceil_offset = longest_ancestor_length(cwd, env_ceiling_dirs);
+       if (ceil_offset < 0 && has_dos_drive_prefix(cwd))
+               ceil_offset = 1;
+
        /*
         * Test in the following order (relative to the cwd):
         * - .git (file containing "gitdir: <path>")
@@ -440,18 +465,17 @@ const char *setup_git_directory_gently(int *nongit_ok)
                        check_repository_format_gently(nongit_ok);
                        return NULL;
                }
-               chdir("..");
-               do {
-                       if (!offset) {
-                               if (nongit_ok) {
-                                       if (chdir(cwd))
-                                               die("Cannot come back to cwd");
-                                       *nongit_ok = 1;
-                                       return NULL;
-                               }
-                               die("Not a git repository");
+               while (--offset > ceil_offset && cwd[offset] != '/');
+               if (offset <= ceil_offset) {
+                       if (nongit_ok) {
+                               if (chdir(cwd))
+                                       die("Cannot come back to cwd");
+                               *nongit_ok = 1;
+                               return NULL;
                        }
-               } while (cwd[--offset] != '/');
+                       die("Not a git repository");
+               }
+               chdir("..");
        }
 
        inside_git_dir = 0;
@@ -557,6 +581,8 @@ const char *setup_git_directory(void)
                if (retval && chdir(retval))
                        die ("Could not jump back into original cwd");
                rel = get_relative_cwd(buffer, PATH_MAX, get_git_work_tree());
+               if (rel && *rel && chdir(get_git_work_tree()))
+                       die ("Could not jump to working directory");
                return rel && *rel ? strcat(rel, "/") : NULL;
        }