mirror of
https://github.com/libgit2/libgit2.git
synced 2026-06-22 06:26:26 +00:00
fs: improve executable search on Windows
Ensure that when we look for an executable on Windows that we add executable suffixes (`.exe`, `.cmd`). Without this, we would not support looking for (eg) `ssh`, since we actually need to identify a file named `ssh.exe` (or `ssh.cmd`) in `PATH`.
This commit is contained in:
@@ -611,6 +611,23 @@ bool git_fs_path_isfile(const char *path)
|
||||
return S_ISREG(st.st_mode) != 0;
|
||||
}
|
||||
|
||||
#ifdef GIT_WIN32
|
||||
|
||||
bool git_fs_path_isexecutable(const char *path)
|
||||
{
|
||||
struct stat st;
|
||||
|
||||
GIT_ASSERT_ARG_WITH_RETVAL(path, false);
|
||||
|
||||
if (git__suffixcmp_icase(path, ".exe") != 0 &&
|
||||
git__suffixcmp_icase(path, ".cmd") != 0)
|
||||
return false;
|
||||
|
||||
return (p_stat(path, &st) == 0);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
bool git_fs_path_isexecutable(const char *path)
|
||||
{
|
||||
struct stat st;
|
||||
@@ -623,6 +640,8 @@ bool git_fs_path_isexecutable(const char *path)
|
||||
((st.st_mode & S_IXUSR) != 0);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
bool git_fs_path_islink(const char *path)
|
||||
{
|
||||
struct stat st;
|
||||
@@ -2032,9 +2051,10 @@ int git_fs_path_owner_is_system(bool *out, const char *path)
|
||||
return git_fs_path_owner_is(out, path, GIT_FS_PATH_OWNER_ADMINISTRATOR);
|
||||
}
|
||||
|
||||
int git_fs_path_find_executable(git_str *fullpath, const char *executable)
|
||||
{
|
||||
#ifdef GIT_WIN32
|
||||
|
||||
static int find_executable(git_str *fullpath, const char *executable)
|
||||
{
|
||||
git_win32_path fullpath_w, executable_w;
|
||||
int error;
|
||||
|
||||
@@ -2047,20 +2067,17 @@ int git_fs_path_find_executable(git_str *fullpath, const char *executable)
|
||||
error = git_str_put_w(fullpath, fullpath_w, wcslen(fullpath_w));
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static int find_executable(git_str *fullpath, const char *executable)
|
||||
{
|
||||
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;
|
||||
|
||||
@@ -2102,5 +2119,19 @@ int git_fs_path_find_executable(git_str *fullpath, const char *executable)
|
||||
|
||||
git_str_clear(fullpath);
|
||||
return GIT_ENOTFOUND;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int git_fs_path_find_executable(git_str *fullpath, const char *executable)
|
||||
{
|
||||
/* 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);
|
||||
}
|
||||
|
||||
return find_executable(fullpath, executable);
|
||||
}
|
||||
|
||||
@@ -253,26 +253,67 @@ static void win32_path_iter_dispose(struct win32_path_iter *iter)
|
||||
iter->current_dir = NULL;
|
||||
}
|
||||
|
||||
struct executable_suffix {
|
||||
const wchar_t *suffix;
|
||||
size_t len;
|
||||
};
|
||||
|
||||
int git_win32_path_find_executable(git_win32_path fullpath, wchar_t *exe)
|
||||
{
|
||||
struct win32_path_iter path_iter;
|
||||
const wchar_t *dir;
|
||||
size_t dir_len, exe_len = wcslen(exe);
|
||||
bool found = false;
|
||||
static struct executable_suffix suffixes[] = { { NULL, 0 }, { L".exe", 4 }, { L".cmd", 4 } };
|
||||
size_t skip_bare = 1, i;
|
||||
|
||||
if (win32_path_iter_init(&path_iter) < 0)
|
||||
return -1;
|
||||
|
||||
while (win32_path_iter_next(&dir, &dir_len, &path_iter) != GIT_ITEROVER) {
|
||||
if (git_win32_path_join(fullpath, dir, dir_len, exe, exe_len) < 0)
|
||||
/* see if the given executable has an executable suffix; if so we will
|
||||
* look for the explicit name directly, as well as with added suffixes.
|
||||
*/
|
||||
for (i = 0; i < ARRAY_SIZE(suffixes); i++) {
|
||||
struct executable_suffix *suffix = &suffixes[i];
|
||||
|
||||
if (!suffix->len)
|
||||
continue;
|
||||
|
||||
if (_waccess(fullpath, 0) == 0) {
|
||||
found = true;
|
||||
if (exe_len < suffix->len)
|
||||
continue;
|
||||
|
||||
if (memcmp(&exe[exe_len - suffix->len], suffix->suffix, suffix->len) == 0) {
|
||||
skip_bare = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
while (win32_path_iter_next(&dir, &dir_len, &path_iter) != GIT_ITEROVER && !found) {
|
||||
/*
|
||||
* if the given name has an executable suffix, then try looking for it
|
||||
* directly. in all cases, append executable extensions
|
||||
* (".exe", ".cmd"...)
|
||||
*/
|
||||
for (i = skip_bare; i < ARRAY_SIZE(suffixes); i++) {
|
||||
struct executable_suffix *suffix = &suffixes[i];
|
||||
|
||||
if (git_win32_path_join(fullpath, dir, dir_len, exe, exe_len) < 0)
|
||||
continue;
|
||||
|
||||
if (suffix->len) {
|
||||
if (dir_len + exe_len + 1 + suffix->len > MAX_PATH)
|
||||
continue;
|
||||
|
||||
wcscat(fullpath, suffix->suffix);
|
||||
}
|
||||
|
||||
if (_waccess(fullpath, 0) == 0) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
win32_path_iter_dispose(&path_iter);
|
||||
|
||||
if (found)
|
||||
|
||||
Reference in New Issue
Block a user