fs: improve path-in-executable location

* Do not search `PATH` for fully- or partially-qualified filenames
  (eg, `foo/bar`)
* Ensure that a file in the `PATH` is executable before returning it
This commit is contained in:
Edward Thomson
2025-10-30 21:44:04 +00:00
parent d8b452f953
commit 47dfe7fa37
2 changed files with 39 additions and 4 deletions

View File

@@ -611,6 +611,18 @@ bool git_fs_path_isfile(const char *path)
return S_ISREG(st.st_mode) != 0;
}
bool git_fs_path_isexecutable(const char *path)
{
struct stat st;
GIT_ASSERT_ARG_WITH_RETVAL(path, false);
if (p_stat(path, &st) < 0)
return false;
return S_ISREG(st.st_mode) != 0 &&
((st.st_mode & S_IXUSR) != 0);
}
bool git_fs_path_islink(const char *path)
{
struct stat st;
@@ -2038,8 +2050,17 @@ int git_fs_path_find_executable(git_str *fullpath, const char *executable)
#else
git_str path = GIT_STR_INIT;
const char *current_dir, *term;
size_t current_dirlen;
bool found = false;
/* For qualified paths we do not look in PATH */
if (strchr(executable, '/') != NULL) {
if (!git_fs_path_isexecutable(executable))
return GIT_ENOTFOUND;
return git_str_puts(fullpath, executable);
}
if (git__getenv(&path, "PATH") < 0)
return -1;
@@ -2049,20 +2070,28 @@ int git_fs_path_find_executable(git_str *fullpath, const char *executable)
if (! (term = strchr(current_dir, GIT_PATH_LIST_SEPARATOR)))
term = strchr(current_dir, '\0');
current_dirlen = term - current_dir;
git_str_clear(fullpath);
if (git_str_put(fullpath, current_dir, (term - current_dir)) < 0 ||
git_str_putc(fullpath, '/') < 0 ||
/* An empty path segment is treated as '.' */
if (current_dirlen == 0 && git_str_putc(fullpath, '.'))
return -1;
else if (current_dirlen != 0 &&
git_str_put(fullpath, current_dir, current_dirlen) < 0)
return -1;
if (git_str_putc(fullpath, '/') < 0 ||
git_str_puts(fullpath, executable) < 0)
return -1;
if (git_fs_path_isfile(fullpath->ptr)) {
if (git_fs_path_isexecutable(fullpath->ptr)) {
found = true;
break;
}
current_dir = term;
while (*current_dir == GIT_PATH_LIST_SEPARATOR)
if (*current_dir == GIT_PATH_LIST_SEPARATOR)
current_dir++;
}

View File

@@ -204,6 +204,12 @@ extern bool git_fs_path_isdir(const char *path);
*/
extern bool git_fs_path_isfile(const char *path);
/**
* Check if the given path points to an executable.
* @return true or false
*/
extern bool git_fs_path_isexecutable(const char *path);
/**
* Check if the given path points to a symbolic link.
* @return true or false