Merge branch 'dr/ceiling'
[gitweb.git] / help.c
diff --git a/help.c b/help.c
index 5d1a773ad7f3ed811c35a6b9fa8afe1697615cc8..ca9632b6c58267776086f48e87e2236ff1f6053f 100644 (file)
--- a/help.c
+++ b/help.c
@@ -391,6 +391,32 @@ static void pretty_print_string_list(struct cmdnames *cmds, int longest)
        }
 }
 
+static int is_executable(const char *name)
+{
+       struct stat st;
+
+       if (stat(name, &st) || /* stat, not lstat */
+           !S_ISREG(st.st_mode))
+               return 0;
+
+#ifdef __MINGW32__
+       /* cannot trust the executable bit, 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)
+                       /* DOS executables start with "MZ" */
+                       if (!strcmp(buf, "#!") || !strcmp(buf, "MZ"))
+                               st.st_mode |= S_IXUSR;
+               close(fd);
+       }
+#endif
+       return st.st_mode & S_IXUSR;
+}
+
 static unsigned int list_commands_in_dir(struct cmdnames *cmds,
                                         const char *path)
 {
@@ -404,15 +430,12 @@ static unsigned int list_commands_in_dir(struct cmdnames *cmds,
                return 0;
 
        while ((de = readdir(dir)) != NULL) {
-               struct stat st;
                int entlen;
 
                if (prefixcmp(de->d_name, prefix))
                        continue;
 
-               if (stat(de->d_name, &st) || /* stat, not lstat */
-                   !S_ISREG(st.st_mode) ||
-                   !(st.st_mode & S_IXUSR))
+               if (!is_executable(de->d_name))
                        continue;
 
                entlen = strlen(de->d_name) - prefix_len;
@@ -447,7 +470,7 @@ static unsigned int load_command_list(void)
 
        path = paths = xstrdup(env_path);
        while (1) {
-               if ((colon = strchr(path, ':')))
+               if ((colon = strchr(path, PATH_SEP)))
                        *colon = 0;
 
                len = list_commands_in_dir(&other_cmds, path);