@matheusbsbs / matheus-bagliano / commits / cc3b7a9732
Fork 0

Windows: Make 'git help -a' work.

git help -a scans the PATH for git commands. On Windows it failed for two reasons: - The PATH separator is ';', not ':' on Windows. - stat() does not set the executable bit. We now open the file and guess whether it is executable. The result of the guess is good enough for the list of git commands, but it is of no use for a general stat() implementation because (1) it is a guess, (2) the user has no way to influence the outcome (via chmod or similar), and (3) it would reduce stat() performance by an unacceptable amount. Therefore, this strategy is a special-case local to help.c. Signed-off-by: Johannes Sixt <johannes.sixt@telecom.at>

Johannes Sixt committed Jan 14, 2008 at 14:05 UTC cc3b7a9732f940cb0249a12cb3c02e3d83723eb0
1 file changed +28 -5
help.c
+28 -5
@@ -391,6 +391,32 @@ static void pretty_print_string_list(struct cmdnames *cmds, int longest)
391 }
392 }
393
394 +static int is_executable(const char *name)
395 +{
396 + struct stat st;
397 +
398 + if (stat(name, &st) || /* stat, not lstat */
399 + !S_ISREG(st.st_mode))
400 + return 0;
401 +
402 +#ifdef __MINGW32__
403 + /* cannot trust the executable bit, peek into the file instead */
404 + char buf[3] = { 0 };
405 + int n;
406 + int fd = open(name, O_RDONLY);
407 + st.st_mode &= ~S_IXUSR;
408 + if (fd >= 0) {
409 + n = read(fd, buf, 2);
410 + if (n == 2)
411 + /* DOS executables start with "MZ" */
412 + if (!strcmp(buf, "#!") || !strcmp(buf, "MZ"))
413 + st.st_mode |= S_IXUSR;
414 + close(fd);
415 + }
416 +#endif
417 + return st.st_mode & S_IXUSR;
418 +}
419 +
420 static unsigned int list_commands_in_dir(struct cmdnames *cmds,
421 const char *path)
422 {
@@ -404,15 +430,12 @@ static unsigned int list_commands_in_dir(struct cmdnames *cmds,
430 return 0;
431
432 while ((de = readdir(dir)) != NULL) {
407 - struct stat st;
433 int entlen;
434
435 if (prefixcmp(de->d_name, prefix))
436 continue;
437
413 - if (stat(de->d_name, &st) || /* stat, not lstat */
414 - !S_ISREG(st.st_mode) ||
415 - !(st.st_mode & S_IXUSR))
438 + if (!is_executable(de->d_name))
439 continue;
440
441 entlen = strlen(de->d_name) - prefix_len;
@@ -447,7 +470,7 @@ static unsigned int load_command_list(void)
470
471 path = paths = xstrdup(env_path);
472 while (1) {
450 - if ((colon = strchr(path, ':')))
473 + if ((colon = strchr(path, PATH_SEP)))
474 *colon = 0;
475
476 len = list_commands_in_dir(&other_cmds, path);