From 38124a40e480c1717326b7bc27bcbca758de908e Mon Sep 17 00:00:00 2001 From: Brandon Williams Date: Tue, 25 Apr 2017 16:46:59 -0700 Subject: run-command: expose is_executable function Move the logic for 'is_executable()' from help.c to run_command.c and expose it so that callers from outside help.c can access the function. This is to enable run-command to be able to query if a file is executable in a future patch. Signed-off-by: Brandon Williams Reviewed-by: Jonathan Nieder Signed-off-by: Junio C Hamano --- run-command.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) (limited to 'run-command.c') diff --git a/run-command.c b/run-command.c index a97d7bf9f..2ffbd7e67 100644 --- a/run-command.c +++ b/run-command.c @@ -117,6 +117,48 @@ 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; +} + static char *locate_in_PATH(const char *file) { const char *p = getenv("PATH"); -- cgit v1.2.3