submodule: don't use submodule_from_name
[gitweb.git] / run-command.c
index a97d7bf9f35328563675f9d71b1d81854ca03e9d..9e36151bf97d36945ca3464e719687718ee6d1c7 100644 (file)
@@ -117,6 +117,65 @@ static inline void close_pair(int fd[2])
        close(fd[1]);
 }
 
+int is_executable(const char *name)
+{
+       struct stat st;
+
+       if (stat(name, &st) || /* stat, not lstat */
+           !S_ISREG(st.st_mode))
+               return 0;
+
+#if defined(GIT_WINDOWS_NATIVE)
+       /*
+        * On Windows there is no executable bit. The file extension
+        * indicates whether it can be run as an executable, and Git
+        * has special-handling to detect scripts and launch them
+        * through the indicated script interpreter. We test for the
+        * file extension first because virus scanners may make
+        * it quite expensive to open many files.
+        */
+       if (ends_with(name, ".exe"))
+               return S_IXUSR;
+
+{
+       /*
+        * Now that we know it does not have an executable extension,
+        * peek into the file instead.
+        */
+       char buf[3] = { 0 };
+       int n;
+       int fd = open(name, O_RDONLY);
+       st.st_mode &= ~S_IXUSR;
+       if (fd >= 0) {
+               n = read(fd, buf, 2);
+               if (n == 2)
+                       /* look for a she-bang */
+                       if (!strcmp(buf, "#!"))
+                               st.st_mode |= S_IXUSR;
+               close(fd);
+       }
+}
+#endif
+       return st.st_mode & S_IXUSR;
+}
+
+/*
+ * Search $PATH for a command.  This emulates the path search that
+ * execvp would perform, without actually executing the command so it
+ * can be used before fork() to prepare to run a command using
+ * execve() or after execvp() to diagnose why it failed.
+ *
+ * The caller should ensure that file contains no directory
+ * separators.
+ *
+ * Returns the path to the command, as found in $PATH or NULL if the
+ * command could not be found.  The caller inherits ownership of the memory
+ * used to store the resultant path.
+ *
+ * This should not be used on Windows, where the $PATH search rules
+ * are more complicated (e.g., a search for "foo" should find
+ * "foo.exe").
+ */
 static char *locate_in_PATH(const char *file)
 {
        const char *p = getenv("PATH");
@@ -137,7 +196,7 @@ static char *locate_in_PATH(const char *file)
                }
                strbuf_addstr(&buf, file);
 
-               if (!access(buf.buf, F_OK))
+               if (is_executable(buf.buf))
                        return strbuf_detach(&buf, NULL);
 
                if (!*end)