From 9906faf2dff6fd9033cb711619528501cae11721 Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Thu, 6 Dec 2018 15:16:49 +0000 Subject: win32: rework adding of extensions to filenames Previously there was one function to handle adding extensions to executable filenames, add_win32_extension(). Refactor this into three functions: add_win32_extension() appends the suffix to the argument string in-place. The argument must be long enough to cope with this, as is the case in ash where path_advance() adds 4 bytes to each filename for just this reason. alloc_win32_extension() is equivalent to the old add_win32_extension(). It allocates a string to hold the new filename then calls the new add_win32_extension() function. The caller is responsible for managing the returned string. auto_win32_extension() calls alloc_win32_extension() and saves the resulting string using auto_string(). It's used where the new filename is consumed immediately or the actual value isn't needed. Rewrite code to use the most appropriate function. Also reorder some code in find_executable() and find_command(). --- debianutils/which.c | 3 +-- include/mingw.h | 11 +++++++++- libbb/executable.c | 32 ++++++++++------------------ shell/ash.c | 60 +++++++---------------------------------------------- win32/mingw.c | 52 ++++++++++++++++++++++++++++------------------ win32/process.c | 4 ++-- 6 files changed, 64 insertions(+), 98 deletions(-) diff --git a/debianutils/which.c b/debianutils/which.c index 0b0a6a645..9b10b62f9 100644 --- a/debianutils/which.c +++ b/debianutils/which.c @@ -67,10 +67,9 @@ int which_main(int argc UNUSED_PARAM, char **argv) /* If file contains a slash don't use PATH */ if (strchr(*argv, '/') || (ENABLE_PLATFORM_MINGW32 && strchr(*argv, '\\'))) { #if ENABLE_PLATFORM_MINGW32 - if ((p=add_win32_extension(*argv)) != NULL) { + if ((p=auto_win32_extension(*argv)) != NULL) { missing = 0; puts(p); - free(p); } else #endif diff --git a/include/mingw.h b/include/mingw.h index 025c4e22b..543172075 100644 --- a/include/mingw.h +++ b/include/mingw.h @@ -457,7 +457,16 @@ void init_winsock(void); int has_bat_suffix(const char *p); int has_exe_suffix(const char *p); int has_exe_suffix_or_dot(const char *name); -char *add_win32_extension(const char *p); +char *alloc_win32_extension(const char *p); +int add_win32_extension(char *p); + +static inline char *auto_win32_extension(const char *p) +{ + extern char *auto_string(char *str) FAST_FUNC; + char *s = alloc_win32_extension(p); + return s ? auto_string(s) : NULL; +} + void FAST_FUNC convert_slashes(char *p); int err_win_to_posix(DWORD winerr); diff --git a/libbb/executable.c b/libbb/executable.c index aec829945..835341ed9 100644 --- a/libbb/executable.c +++ b/libbb/executable.c @@ -28,10 +28,6 @@ int FAST_FUNC file_is_executable(const char *name) * in all cases (*PATHp) contents are temporarily modified * but are restored on return (s/:/NUL/ and back). */ -#if !ENABLE_PLATFORM_MINGW32 -#define next_path_sep(s) strchr(s, ':') -#endif - char* FAST_FUNC find_executable(const char *filename, char **PATHp) { /* About empty components in $PATH: @@ -44,38 +40,32 @@ char* FAST_FUNC find_executable(const char *filename, char **PATHp) */ char *p, *n; #if ENABLE_PLATFORM_MINGW32 - char *w; + char sep, *w; #endif p = *PATHp; while (p) { int ex; -#if ENABLE_PLATFORM_MINGW32 - char sep; - n = (char*)next_path_sep(p); - if (n) { - sep = *n; - *n = '\0'; - } -#else +#if !ENABLE_PLATFORM_MINGW32 n = strchr(p, ':'); if (n) *n = '\0'; +#else + n = (char*)next_path_sep(p); + if (n) { sep = *n; *n = '\0'; } #endif p = concat_path_file( p[0] ? p : ".", /* handle "::" case */ filename ); -#if ENABLE_PLATFORM_MINGW32 - if (n) *n++ = sep; -#else +#if !ENABLE_PLATFORM_MINGW32 if (n) *n++ = ':'; -#endif -#if ENABLE_PLATFORM_MINGW32 - if ((w=add_win32_extension(p))) { - *PATHp = n; +#else + if (n) *n++ = sep; + if ((w=alloc_win32_extension(p))) { free(p); - return w; + p = w; + /* following test will succeed */ } #endif ex = file_is_executable(p); diff --git a/shell/ash.c b/shell/ash.c index cbe30a78b..587cf2abb 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -8405,7 +8405,7 @@ tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) const char *cmd, char **argv, c #if ENABLE_PLATFORM_MINGW32 { - char *new_cmd = add_win32_extension(cmd); + char *new_cmd = alloc_win32_extension(cmd); execve(new_cmd ? new_cmd : cmd, argv, envp); free(new_cmd); } @@ -8516,9 +8516,6 @@ printentry(struct tblentry *cmdp) int idx; const char *path; char *name; -#if ENABLE_PLATFORM_MINGW32 - char *n; -#endif idx = cmdp->param.index; path = pathval(); @@ -8527,13 +8524,9 @@ printentry(struct tblentry *cmdp) stunalloc(name); } while (--idx >= 0); #if ENABLE_PLATFORM_MINGW32 - if ((n=add_win32_extension(name)) != NULL) - name = n; + add_win32_extension(name); #endif out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr)); -#if ENABLE_PLATFORM_MINGW32 - free(n); -#endif } /* @@ -8921,9 +8914,6 @@ describe_command(char *command, const char *path, int describe_command_verbose) case CMDNORMAL: { int j = entry.u.index; char *p; -#if ENABLE_PLATFORM_MINGW32 - char *q; -#endif if (j < 0) { p = command; } else { @@ -8933,17 +8923,13 @@ describe_command(char *command, const char *path, int describe_command_verbose) } while (--j >= 0); } #if ENABLE_PLATFORM_MINGW32 - if ((q=add_win32_extension(p)) != NULL) - p = q; + add_win32_extension(p); #endif if (describe_command_verbose) { out1fmt(" is %s", p); } else { out1str(p); } -#if ENABLE_PLATFORM_MINGW32 - free(q); -#endif break; } @@ -13826,36 +13812,28 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path) struct tblentry *cmdp; int idx; int prev; - char *fullname IF_PLATFORM_MINGW32(= NULL); + char *fullname; struct stat statb; int e; int updatetbl; struct builtincmd *bcmd; -#if ENABLE_PLATFORM_MINGW32 - extern const char win_suffix[4][4]; - int i, len; -#endif /* If name contains a slash, don't use PATH or hash table */ if (strchr(name, '/') || (ENABLE_PLATFORM_MINGW32 && strchr(name, '\\'))) { entry->u.index = -1; if (act & DO_ABS) { #if ENABLE_PLATFORM_MINGW32 - while ((fullname=add_win32_extension(name)) == NULL && - stat(name, &statb) < 0 ) { + if (auto_win32_extension(name) == NULL && stat(name, &statb) < 0) { #else while (stat(name, &statb) < 0) { -#endif #ifdef SYSV if (errno == EINTR) continue; +#endif #endif entry->cmdtype = CMDUNKNOWN; return; } -#if ENABLE_PLATFORM_MINGW32 - free(fullname); -#endif } entry->cmdtype = CMDNORMAL; return; @@ -13959,29 +13937,8 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path) goto success; } #if ENABLE_PLATFORM_MINGW32 - /* first try appending suffixes (unless there's one already) */ - i = 4; - len = strlen(fullname); - if (!has_exe_suffix_or_dot(fullname)) { - /* path_advance() has reserved space for suffix */ - fullname[len] = '.'; - for (i=0; i<4; ++i) { - memcpy(fullname+len+1, win_suffix[i], 4); - if (stat(fullname, &statb) == 0) - break; - } - } - - if (i == 4) { - /* adding a suffix failed (or wasn't tried), try original */ - fullname[len] = '\0'; - if (stat(fullname, &statb) < 0) { - if (errno != ENOENT && errno != ENOTDIR) - e = errno; - goto loop; - } - } -#else + add_win32_extension(fullname); +#endif while (stat(fullname, &statb) < 0) { #ifdef SYSV if (errno == EINTR) @@ -13991,7 +13948,6 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path) e = errno; goto loop; } -#endif e = EACCES; /* if we fail, this will be the error */ if (!S_ISREG(statb.st_mode)) continue; diff --git a/win32/mingw.c b/win32/mingw.c index 707e6a3d2..08d955527 100644 --- a/win32/mingw.c +++ b/win32/mingw.c @@ -1160,7 +1160,7 @@ int mingw_rmdir(const char *path) return rmdir(path); } -const char win_suffix[4][4] = { "com", "exe", "bat", "cmd" }; +static const char win_suffix[4][4] = { "com", "exe", "bat", "cmd" }; static int has_win_suffix(const char *name, int start) { @@ -1191,33 +1191,45 @@ int has_exe_suffix_or_dot(const char *name) return last_char_is(name, '.') || has_win_suffix(name, 0); } -/* check if path can be made into an executable by adding a suffix; - * return an allocated string containing the path if it can; - * return NULL if not. +/* Check if path can be made into an executable by adding a suffix. + * The suffix is added to the end of the argument which must be + * long enough to allow this. * - * if path already has a suffix don't even bother trying + * If the return value is TRUE the argument contains the new path, + * if FALSE the argument is unchanged. */ -char *add_win32_extension(const char *p) +int add_win32_extension(char *p) { - char *path; - int i, len; - - if (has_exe_suffix_or_dot(p)) { - return NULL; + if (!has_exe_suffix_or_dot(p)) { + int i, len = strlen(p); + + p[len] = '.'; + for (i=0; i<4; ++i) { + memcpy(p+len+1, win_suffix[i], 4); + if (file_is_executable(p)) + return TRUE; + } + p[len] = '\0'; } + return FALSE; +} - len = strlen(p); - path = xasprintf("%s.com", p); +/* Check if path can be made into an executable by adding a suffix. + * Return an allocated string containing the path if it can; + * return NULL if not. + * + * If path already has a suffix don't even bother trying. + */ +char *alloc_win32_extension(const char *p) +{ + if (!has_exe_suffix_or_dot(p)) { + int len = strlen(p); + char *path = strcpy(xmalloc(len+5), p); - for (i=0; i<4; ++i) { - memcpy(path+len+1, win_suffix[i], 4); - if (file_is_executable(path)) { + if (add_win32_extension(path)) return path; - } + free(path); } - - free(path); - return NULL; } diff --git a/win32/process.c b/win32/process.c index e9b34b56d..b7f02e431 100644 --- a/win32/process.c +++ b/win32/process.c @@ -240,7 +240,7 @@ spawnveq(int mode, const char *path, char *const *argv, char *const *env) p = strdup(new_argv[0]); } else { - p = add_win32_extension(new_argv[0]); + p = alloc_win32_extension(new_argv[0]); } if (p != NULL && has_bat_suffix(p)) { @@ -307,7 +307,7 @@ mingw_spawn_interpreter(int mode, const char *prog, char *const *argv, char *con new_argv[nopts+1] = (char *)prog; /* pass absolute path */ memcpy(new_argv+nopts+2, argv+1, sizeof(*argv)*argc); - if ((fullpath=add_win32_extension(interp.path)) != NULL || + if ((fullpath=alloc_win32_extension(interp.path)) != NULL || file_is_executable(interp.path)) { new_argv[0] = fullpath ? fullpath : interp.path; ret = spawnveq(mode, new_argv[0], new_argv, envp); -- cgit v1.2.3-55-g6feb