Merge branch 'rr/precompose-utf8-cleanup'
[gitweb.git] / setup.c
diff --git a/setup.c b/setup.c
index d121b6ab77cb40afff69cb9003be62033a12802f..3a1b2fd45580cad7ecd55efa755872efc81075ad 100644 (file)
--- a/setup.c
+++ b/setup.c
@@ -4,7 +4,7 @@
 static int inside_git_dir = -1;
 static int inside_work_tree = -1;
 
-char *prefix_path(const char *prefix, int len, const char *path)
+static char *prefix_path_gently(const char *prefix, int len, const char *path)
 {
        const char *orig = path;
        char *sanitized;
@@ -31,7 +31,8 @@ char *prefix_path(const char *prefix, int len, const char *path)
                if (strncmp(sanitized, work_tree, len) ||
                    (len > root_len && sanitized[len] != '\0' && sanitized[len] != '/')) {
                error_out:
-                       die("'%s' is outside repository", orig);
+                       free(sanitized);
+                       return NULL;
                }
                if (sanitized[len] == '/')
                        len++;
@@ -40,6 +41,25 @@ char *prefix_path(const char *prefix, int len, const char *path)
        return sanitized;
 }
 
+char *prefix_path(const char *prefix, int len, const char *path)
+{
+       char *r = prefix_path_gently(prefix, len, path);
+       if (!r)
+               die("'%s' is outside repository", path);
+       return r;
+}
+
+int path_inside_repo(const char *prefix, const char *path)
+{
+       int len = prefix ? strlen(prefix) : 0;
+       char *r = prefix_path_gently(prefix, len, path);
+       if (r) {
+               free(r);
+               return 1;
+       }
+       return 0;
+}
+
 int check_filename(const char *prefix, const char *arg)
 {
        const char *name;
@@ -57,26 +77,23 @@ static void NORETURN die_verify_filename(const char *prefix,
                                         const char *arg,
                                         int diagnose_misspelt_rev)
 {
-       unsigned char sha1[20];
-       unsigned mode;
-
        if (!diagnose_misspelt_rev)
                die("%s: no such path in the working tree.\n"
-                   "Use '-- <path>...' to specify paths that do not exist locally.",
+                   "Use 'git <command> -- <path>...' to specify paths that do not exist locally.",
                    arg);
        /*
         * Saying "'(icase)foo' does not exist in the index" when the
         * user gave us ":(icase)foo" is just stupid.  A magic pathspec
         * begins with a colon and is followed by a non-alnum; do not
-        * let get_sha1_with_mode_1(only_to_die=1) to even trigger.
+        * let maybe_die_on_misspelt_object_name() even trigger.
         */
        if (!(arg[0] == ':' && !isalnum(arg[1])))
-               /* try a detailed diagnostic ... */
-               get_sha1_with_mode_1(arg, sha1, &mode, 1, prefix);
+               maybe_die_on_misspelt_object_name(arg, prefix);
 
        /* ... or fall back the most general message. */
        die("ambiguous argument '%s': unknown revision or path not in the working tree.\n"
-           "Use '--' to separate paths from revisions", arg);
+           "Use '--' to separate paths from revisions, like this:\n"
+           "'git <command> [<revision>...] -- [<file>...]'", arg);
 
 }
 
@@ -125,7 +142,8 @@ void verify_non_filename(const char *prefix, const char *arg)
        if (!check_filename(prefix, arg))
                return;
        die("ambiguous argument '%s': both revision and filename\n"
-           "Use '--' to separate filenames from revisions", arg);
+           "Use '--' to separate paths from revisions, like this:\n"
+           "'git <command> [<revision>...] -- [<file>...]'", arg);
 }
 
 /*
@@ -268,7 +286,7 @@ const char **get_pathspec(const char *prefix, const char **pathspec)
  *    a proper "ref:", or a regular file HEAD that has a properly
  *    formatted sha1 object name.
  */
-static int is_git_directory(const char *suspect)
+int is_git_directory(const char *suspect)
 {
        char path[PATH_MAX];
        size_t len = strlen(suspect);
@@ -590,13 +608,15 @@ static const char *setup_nongit(const char *cwd, int *nongit_ok)
        return NULL;
 }
 
-static dev_t get_device_or_die(const char *path, const char *prefix)
+static dev_t get_device_or_die(const char *path, const char *prefix, int prefix_len)
 {
        struct stat buf;
-       if (stat(path, &buf))
-               die_errno("failed to stat '%s%s%s'",
+       if (stat(path, &buf)) {
+               die_errno("failed to stat '%*s%s%s'",
+                               prefix_len,
                                prefix ? prefix : "",
                                prefix ? "/" : "", path);
+       }
        return buf.st_dev;
 }
 
@@ -610,7 +630,7 @@ static const char *setup_git_directory_gently_1(int *nongit_ok)
        static char cwd[PATH_MAX+1];
        const char *gitdirenv, *ret;
        char *gitfile;
-       int len, offset, ceil_offset;
+       int len, offset, offset_parent, ceil_offset;
        dev_t current_device = 0;
        int one_filesystem = 1;
 
@@ -652,7 +672,7 @@ static const char *setup_git_directory_gently_1(int *nongit_ok)
         */
        one_filesystem = !git_env_bool("GIT_DISCOVERY_ACROSS_FILESYSTEM", 0);
        if (one_filesystem)
-               current_device = get_device_or_die(".", NULL);
+               current_device = get_device_or_die(".", NULL, 0);
        for (;;) {
                gitfile = (char*)read_gitfile(DEFAULT_GIT_DIR_ENVIRONMENT);
                if (gitfile)
@@ -674,11 +694,12 @@ static const char *setup_git_directory_gently_1(int *nongit_ok)
                if (is_git_directory("."))
                        return setup_bare_git_dir(cwd, offset, len, nongit_ok);
 
-               while (--offset > ceil_offset && cwd[offset] != '/');
-               if (offset <= ceil_offset)
+               offset_parent = offset;
+               while (--offset_parent > ceil_offset && cwd[offset_parent] != '/');
+               if (offset_parent <= ceil_offset)
                        return setup_nongit(cwd, nongit_ok);
                if (one_filesystem) {
-                       dev_t parent_device = get_device_or_die("..", cwd);
+                       dev_t parent_device = get_device_or_die("..", cwd, offset);
                        if (parent_device != current_device) {
                                if (nongit_ok) {
                                        if (chdir(cwd))
@@ -687,7 +708,7 @@ static const char *setup_git_directory_gently_1(int *nongit_ok)
                                        return NULL;
                                }
                                cwd[offset] = '\0';
-                               die("Not a git repository (or any parent up to mount parent %s)\n"
+                               die("Not a git repository (or any parent up to mount point %s)\n"
                                "Stopping at filesystem boundary (GIT_DISCOVERY_ACROSS_FILESYSTEM not set).", cwd);
                        }
                }
@@ -695,6 +716,7 @@ static const char *setup_git_directory_gently_1(int *nongit_ok)
                        cwd[offset] = '\0';
                        die_errno("Cannot change to '%s/..'", cwd);
                }
+               offset = offset_parent;
        }
 }