Skip to content

Commit 47dfe7f

Browse files
committed
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
1 parent d8b452f commit 47dfe7f

File tree

2 files changed

+39
-4
lines changed

2 files changed

+39
-4
lines changed

src/util/fs_path.c

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -611,6 +611,18 @@ bool git_fs_path_isfile(const char *path)
611611
return S_ISREG(st.st_mode) != 0;
612612
}
613613

614+
bool git_fs_path_isexecutable(const char *path)
615+
{
616+
struct stat st;
617+
618+
GIT_ASSERT_ARG_WITH_RETVAL(path, false);
619+
if (p_stat(path, &st) < 0)
620+
return false;
621+
622+
return S_ISREG(st.st_mode) != 0 &&
623+
((st.st_mode & S_IXUSR) != 0);
624+
}
625+
614626
bool git_fs_path_islink(const char *path)
615627
{
616628
struct stat st;
@@ -2038,8 +2050,17 @@ int git_fs_path_find_executable(git_str *fullpath, const char *executable)
20382050
#else
20392051
git_str path = GIT_STR_INIT;
20402052
const char *current_dir, *term;
2053+
size_t current_dirlen;
20412054
bool found = false;
20422055

2056+
/* For qualified paths we do not look in PATH */
2057+
if (strchr(executable, '/') != NULL) {
2058+
if (!git_fs_path_isexecutable(executable))
2059+
return GIT_ENOTFOUND;
2060+
2061+
return git_str_puts(fullpath, executable);
2062+
}
2063+
20432064
if (git__getenv(&path, "PATH") < 0)
20442065
return -1;
20452066

@@ -2049,20 +2070,28 @@ int git_fs_path_find_executable(git_str *fullpath, const char *executable)
20492070
if (! (term = strchr(current_dir, GIT_PATH_LIST_SEPARATOR)))
20502071
term = strchr(current_dir, '\0');
20512072

2073+
current_dirlen = term - current_dir;
20522074
git_str_clear(fullpath);
2053-
if (git_str_put(fullpath, current_dir, (term - current_dir)) < 0 ||
2054-
git_str_putc(fullpath, '/') < 0 ||
2075+
2076+
/* An empty path segment is treated as '.' */
2077+
if (current_dirlen == 0 && git_str_putc(fullpath, '.'))
2078+
return -1;
2079+
else if (current_dirlen != 0 &&
2080+
git_str_put(fullpath, current_dir, current_dirlen) < 0)
2081+
return -1;
2082+
2083+
if (git_str_putc(fullpath, '/') < 0 ||
20552084
git_str_puts(fullpath, executable) < 0)
20562085
return -1;
20572086

2058-
if (git_fs_path_isfile(fullpath->ptr)) {
2087+
if (git_fs_path_isexecutable(fullpath->ptr)) {
20592088
found = true;
20602089
break;
20612090
}
20622091

20632092
current_dir = term;
20642093

2065-
while (*current_dir == GIT_PATH_LIST_SEPARATOR)
2094+
if (*current_dir == GIT_PATH_LIST_SEPARATOR)
20662095
current_dir++;
20672096
}
20682097

src/util/fs_path.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,12 @@ extern bool git_fs_path_isdir(const char *path);
204204
*/
205205
extern bool git_fs_path_isfile(const char *path);
206206

207+
/**
208+
* Check if the given path points to an executable.
209+
* @return true or false
210+
*/
211+
extern bool git_fs_path_isexecutable(const char *path);
212+
207213
/**
208214
* Check if the given path points to a symbolic link.
209215
* @return true or false

0 commit comments

Comments
 (0)