Windows: avoid the "dup dance" when spawning a child process
[gitweb.git] / setup.c
diff --git a/setup.c b/setup.c
index 029371e5844a1069d62456c6bb51028efbb671c4..3a07aa4df710f5d9584d4ddf412e3debc0e64db4 100644 (file)
--- a/setup.c
+++ b/setup.c
@@ -18,9 +18,12 @@ const char *prefix_path(const char *prefix, int len, const char *path)
        if (normalize_path_copy(sanitized, sanitized))
                goto error_out;
        if (is_absolute_path(orig)) {
+               size_t len, total;
                const char *work_tree = get_git_work_tree();
-               size_t len = strlen(work_tree);
-               size_t total = strlen(sanitized) + 1;
+               if (!work_tree)
+                       goto error_out;
+               len = strlen(work_tree);
+               total = strlen(sanitized) + 1;
                if (strncmp(sanitized, work_tree, len) ||
                    (sanitized[len] != '\0' && sanitized[len] != '/')) {
                error_out:
@@ -61,6 +64,31 @@ const char *prefix_filename(const char *pfx, int pfx_len, const char *arg)
        return path;
 }
 
+int check_filename(const char *prefix, const char *arg)
+{
+       const char *name;
+       struct stat st;
+
+       name = prefix ? prefix_filename(prefix, strlen(prefix), arg) : arg;
+       if (!lstat(name, &st))
+               return 1; /* file exists */
+       if (errno == ENOENT || errno == ENOTDIR)
+               return 0; /* file does not exist */
+       die_errno("failed to stat '%s'", arg);
+}
+
+static void NORETURN die_verify_filename(const char *prefix, const char *arg)
+{
+       unsigned char sha1[20];
+       unsigned mode;
+       /* try a detailed diagnostic ... */
+       get_sha1_with_mode_1(arg, sha1, &mode, 0, 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);
+
+}
+
 /*
  * Verify a filename that we got as an argument for a pathspec
  * entry. Note that a filename that begins with "-" never verifies
@@ -70,18 +98,11 @@ const char *prefix_filename(const char *pfx, int pfx_len, const char *arg)
  */
 void verify_filename(const char *prefix, const char *arg)
 {
-       const char *name;
-       struct stat st;
-
        if (*arg == '-')
                die("bad flag '%s' used after filename", arg);
-       name = prefix ? prefix_filename(prefix, strlen(prefix), arg) : arg;
-       if (!lstat(name, &st))
+       if (check_filename(prefix, arg))
                return;
-       if (errno == ENOENT)
-               die("ambiguous argument '%s': unknown revision or path not in the working tree.\n"
-                   "Use '--' to separate paths from revisions", arg);
-       die_errno("failed to stat '%s'", arg);
+       die_verify_filename(prefix, arg);
 }
 
 /*
@@ -91,19 +112,14 @@ void verify_filename(const char *prefix, const char *arg)
  */
 void verify_non_filename(const char *prefix, const char *arg)
 {
-       const char *name;
-       struct stat st;
-
        if (!is_inside_work_tree() || is_inside_git_dir())
                return;
        if (*arg == '-')
                return; /* flag */
-       name = prefix ? prefix_filename(prefix, strlen(prefix), arg) : arg;
-       if (!lstat(name, &st))
-               die("ambiguous argument '%s': both revision and filename\n"
-                   "Use '--' to separate filenames from revisions", arg);
-       if (errno != ENOENT && errno != ENOTDIR)
-               die_errno("failed to stat '%s'", arg);
+       if (!check_filename(prefix, arg))
+               return;
+       die("ambiguous argument '%s': both revision and filename\n"
+           "Use '--' to separate filenames from revisions", arg);
 }
 
 const char **get_pathspec(const char *prefix, const char **pathspec)