From 6059723900f2af1fbd394c457d1feae342e344f6 Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Thu, 13 Aug 2020 13:56:17 +0100 Subject: win32: handle Unix-style absolute paths for executables As noted in commit 548ec7045 (win32: interpret absolute paths as relative to %SYSTEMDRIVE%) a path starting with a '/' in the Unix world is treated as relative to the current drive by Windows. To avoid ambiguity that commit considered certain such paths to be relative to %SYSTEMDRIVE%. Extend this to paths representing executables. Add the functions need_system_drive() and auto_add_system_drive() to detect the need for a system drive prefix and to add it if necessary. Use these functions in: - the 'which' applet - the find_executable() function - tab-completion code - PATH look-up, shellexec(), describe_command() and find_command() in ash - parse_interpreter() and mingw_spawn_1() With these changes executable paths starting with a slash are handled consistently, whatever the current drive. --- debianutils/which.c | 1 + include/mingw.h | 2 ++ libbb/executable.c | 3 +++ libbb/lineedit.c | 10 +++++++++- shell/ash.c | 30 ++++++++++++++++++++++++++++-- win32/mingw.c | 15 +++++++++++++++ win32/process.c | 11 ++++++++++- 7 files changed, 68 insertions(+), 4 deletions(-) diff --git a/debianutils/which.c b/debianutils/which.c index 1f8c1a538..c8e99acda 100644 --- a/debianutils/which.c +++ b/debianutils/which.c @@ -71,6 +71,7 @@ int which_main(int argc UNUSED_PARAM, char **argv) if (strchr(*argv, '/')) { #else if (has_path(*argv)) { + *argv = auto_add_system_drive(*argv); if ((p=auto_win32_extension(*argv)) != NULL) { missing = 0; puts(bs_to_slash(p)); diff --git a/include/mingw.h b/include/mingw.h index 91e4dc1a5..434f3a474 100644 --- a/include/mingw.h +++ b/include/mingw.h @@ -547,6 +547,8 @@ void hide_console(void); int unc_root_len(const char *dir); int root_len(const char *path); const char *get_system_drive(void); +const char *need_system_drive(const char *path); +char *auto_add_system_drive(const char *path); int chdir_system_drive(void); char *xabsolute_path(char *path); char *get_drive_cwd(const char *path, char *buffer, int size); diff --git a/libbb/executable.c b/libbb/executable.c index 87a40eeda..0a0769ef3 100644 --- a/libbb/executable.c +++ b/libbb/executable.c @@ -49,6 +49,9 @@ char* FAST_FUNC find_executable(const char *filename, char **PATHp) n = strchr(p, PATH_SEP); if (n) *n = '\0'; +#if ENABLE_PLATFORM_MINGW32 + p = auto_add_system_drive(p); +#endif p = concat_path_file( p[0] ? p : ".", /* handle "::" case */ filename diff --git a/libbb/lineedit.c b/libbb/lineedit.c index a36a1647d..f6577e372 100644 --- a/libbb/lineedit.c +++ b/libbb/lineedit.c @@ -913,8 +913,12 @@ static NOINLINE unsigned complete_cmd_dir_file(const char *command, int type) struct dirent *next; struct stat st; char *found; - +#if ENABLE_PLATFORM_MINGW32 + char *lpath = auto_add_system_drive(paths[i]); + dir = opendir(lpath); +#else dir = opendir(paths[i]); +#endif if (!dir) continue; /* don't print an error */ @@ -929,7 +933,11 @@ static NOINLINE unsigned complete_cmd_dir_file(const char *command, int type) if (!is_prefixed_with(name_found, pfind)) continue; /* no */ +#if ENABLE_PLATFORM_MINGW32 + found = concat_path_file(lpath, name_found); +#else found = concat_path_file(paths[i], name_found); +#endif /* NB: stat() first so that we see is it a directory; * but if that fails, use lstat() so that * we still match dangling links */ diff --git a/shell/ash.c b/shell/ash.c index 7a2d0ab68..0a638b1df 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -2828,6 +2828,10 @@ padvance_magic(const char **path, const char *name, int magic) const char *start; size_t qlen; size_t len; +#if ENABLE_PLATFORM_MINGW32 + size_t sdlen = 0; + const char *sd; +#endif if (*path == NULL) return -1; @@ -2859,11 +2863,20 @@ padvance_magic(const char **path, const char *name, int magic) *path = *p == PATH_SEP ? p + 1 : NULL; /* "2" is for '/' and '\0' */ - /* reserve space for suffix on WIN32 */ - qlen = len + strlen(name) + 2 IF_PLATFORM_MINGW32(+ 4); + qlen = len + strlen(name) + 2; +#if ENABLE_PLATFORM_MINGW32 + /* reserve space for system drive prefix and extension */ + sd = need_system_drive(start); + if (sd != NULL) + sdlen = strlen(sd); + qlen += 4 + sdlen; +#endif q = growstackto(qlen); if (len) { +#if ENABLE_PLATFORM_MINGW32 + q = mempcpy(q, sd, sdlen); +#endif q = mempcpy(q, start, len); #if ENABLE_PLATFORM_MINGW32 if (q[-1] != '/' && q[-1] != '\\') @@ -8740,6 +8753,9 @@ static void shellexec(char *prog, char **argv, const char *path, int idx) || (applet_no = find_applet_by_name(prog)) >= 0 #endif ) { +#if ENABLE_PLATFORM_MINGW32 + prog = auto_add_system_drive(prog); +#endif tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) prog, argv, envp); if (applet_no >= 0) { /* We tried execing ourself, but it didn't work. @@ -9176,7 +9192,16 @@ describe_command(char *command, const char *path, int describe_command_verbose) int j = entry.u.index; char *p; if (j < 0) { +#if ENABLE_PLATFORM_MINGW32 + /* can't use auto_add_system_drive, need space for extension */ + const char *sd = need_system_drive(command); + size_t len = strlen(command) + 5 + (sd ? strlen(sd) : 0); + + p = auto_string(xmalloc(len)); + sprintf(p, "%s%s", sd ? sd : "", command); +#else p = command; +#endif } else { do { padvance(&path, command); @@ -14246,6 +14271,7 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path) /* If name contains a slash, don't use PATH or hash table */ #if ENABLE_PLATFORM_MINGW32 if (has_path(name)) { + name = auto_add_system_drive(name); #else if (strchr(name, '/') != NULL) { #endif diff --git a/win32/mingw.c b/win32/mingw.c index 8501ecdd4..e63ffa0ac 100644 --- a/win32/mingw.c +++ b/win32/mingw.c @@ -1698,6 +1698,21 @@ const char *get_system_drive(void) return drive; } +/* Return pointer to system drive if path is of form '/file', else NULL */ +const char *need_system_drive(const char *path) +{ + if (root_len(path) == 0 && (path[0] == '/' || path[0] == '\\')) + return get_system_drive(); + return NULL; +} + +/* Add a system drive prefix to 'path' if necessary, else return 'path' */ +char *auto_add_system_drive(const char *path) +{ + const char *sd = need_system_drive(path); + return sd ? auto_string(concat_path_file(sd, path)) : (char *)path; +} + int chdir_system_drive(void) { const char *sd = get_system_drive(); diff --git a/win32/process.c b/win32/process.c index 1118eb18a..cd164e0ed 100644 --- a/win32/process.c +++ b/win32/process.c @@ -63,6 +63,7 @@ static int parse_interpreter(const char *cmd, interp_t *interp) { char *path, *t; + const char *sd; int n; while (TRUE) { @@ -88,6 +89,12 @@ parse_interpreter(const char *cmd, interp_t *interp) if (*t == '\0') break; + sd = need_system_drive(path); + if (sd && strlen(sd) == 2) { + path -= 2; + memcpy(path, sd, 2); + } + interp->path = path; interp->name = t; interp->opts = strtok(NULL, "\r\n"); @@ -342,6 +349,7 @@ static intptr_t mingw_spawn_1(int mode, const char *cmd, char *const *argv, char *const *envp) { char *prog; + const char *path; #if ENABLE_FEATURE_PREFER_APPLETS || ENABLE_FEATURE_SH_STANDALONE if (find_applet_by_name(cmd) >= 0) @@ -349,7 +357,8 @@ mingw_spawn_1(int mode, const char *cmd, char *const *argv, char *const *envp) else #endif if (has_path(cmd)) { - const char *path = auto_win32_extension(cmd); + cmd = auto_add_system_drive(cmd); + path = auto_win32_extension(cmd); return mingw_spawn_interpreter(mode, path ? path : cmd, argv, envp, 0); } else if ((prog=find_first_executable(cmd)) != NULL) { -- cgit v1.2.3-55-g6feb