From 1ff6eb52032bb52501ef3bd8b49010ac19efa268 Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Wed, 20 Sep 2023 10:06:19 +0100 Subject: ash: add options to control globbing of hidden files Add shell options: - 'nohiddenglob' excludes files with the hidden attribute from globbing - 'nohidsysglob' excludes files with the hidden and system attributes from globbing If both options are enabled 'nohiddenglob' takes precedence. These options also affect tab completion. Files that are hidden because they start with a period aren't affected (unless they also have the hidden attribute). Costs 160-208 bytes. (GitHub issue #367) --- configs/make32_defconfig | 4 ++-- configs/make64_defconfig | 4 ++-- configs/mingw32_defconfig | 4 ++-- configs/mingw64_defconfig | 4 ++-- configs/mingw64u_defconfig | 4 ++-- include/libbb.h | 4 ++++ libbb/lineedit.c | 4 ++++ shell/ash.c | 49 ++++++++++++++++++++++++++++++++++++++-------- 8 files changed, 59 insertions(+), 18 deletions(-) diff --git a/configs/make32_defconfig b/configs/make32_defconfig index be793be52..428c16a4e 100644 --- a/configs/make32_defconfig +++ b/configs/make32_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit # Busybox version: 1.37.0.git -# Fri Sep 15 08:35:20 2023 +# Wed Sep 20 08:30:38 2023 # CONFIG_HAVE_DOT_CONFIG=y # CONFIG_PLATFORM_POSIX is not set @@ -1165,7 +1165,7 @@ CONFIG_ASH_HELP=y CONFIG_ASH_GETOPTS=y CONFIG_ASH_CMDCMD=y CONFIG_ASH_NOCONSOLE=y -CONFIG_ASH_NOCASEGLOB=y +CONFIG_ASH_GLOB_OPTIONS=y # CONFIG_CTTYHACK is not set # CONFIG_HUSH is not set # CONFIG_SHELL_HUSH is not set diff --git a/configs/make64_defconfig b/configs/make64_defconfig index 71f08c502..c69f1e5fb 100644 --- a/configs/make64_defconfig +++ b/configs/make64_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit # Busybox version: 1.37.0.git -# Fri Sep 15 08:35:20 2023 +# Wed Sep 20 08:30:38 2023 # CONFIG_HAVE_DOT_CONFIG=y # CONFIG_PLATFORM_POSIX is not set @@ -1165,7 +1165,7 @@ CONFIG_ASH_HELP=y CONFIG_ASH_GETOPTS=y CONFIG_ASH_CMDCMD=y CONFIG_ASH_NOCONSOLE=y -CONFIG_ASH_NOCASEGLOB=y +CONFIG_ASH_GLOB_OPTIONS=y # CONFIG_CTTYHACK is not set # CONFIG_HUSH is not set # CONFIG_SHELL_HUSH is not set diff --git a/configs/mingw32_defconfig b/configs/mingw32_defconfig index 12e432500..3a21dfae6 100644 --- a/configs/mingw32_defconfig +++ b/configs/mingw32_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit # Busybox version: 1.37.0.git -# Fri Sep 15 08:35:20 2023 +# Wed Sep 20 08:30:38 2023 # CONFIG_HAVE_DOT_CONFIG=y # CONFIG_PLATFORM_POSIX is not set @@ -1177,7 +1177,7 @@ CONFIG_ASH_HELP=y CONFIG_ASH_GETOPTS=y CONFIG_ASH_CMDCMD=y CONFIG_ASH_NOCONSOLE=y -CONFIG_ASH_NOCASEGLOB=y +CONFIG_ASH_GLOB_OPTIONS=y # CONFIG_CTTYHACK is not set # CONFIG_HUSH is not set # CONFIG_SHELL_HUSH is not set diff --git a/configs/mingw64_defconfig b/configs/mingw64_defconfig index dd5a9b068..8b993460f 100644 --- a/configs/mingw64_defconfig +++ b/configs/mingw64_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit # Busybox version: 1.37.0.git -# Fri Sep 15 08:35:20 2023 +# Wed Sep 20 08:30:38 2023 # CONFIG_HAVE_DOT_CONFIG=y # CONFIG_PLATFORM_POSIX is not set @@ -1177,7 +1177,7 @@ CONFIG_ASH_HELP=y CONFIG_ASH_GETOPTS=y CONFIG_ASH_CMDCMD=y CONFIG_ASH_NOCONSOLE=y -CONFIG_ASH_NOCASEGLOB=y +CONFIG_ASH_GLOB_OPTIONS=y # CONFIG_CTTYHACK is not set # CONFIG_HUSH is not set # CONFIG_SHELL_HUSH is not set diff --git a/configs/mingw64u_defconfig b/configs/mingw64u_defconfig index 159f409d9..a7428d1d2 100644 --- a/configs/mingw64u_defconfig +++ b/configs/mingw64u_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit # Busybox version: 1.37.0.git -# Fri Sep 15 08:35:20 2023 +# Wed Sep 20 08:30:38 2023 # CONFIG_HAVE_DOT_CONFIG=y # CONFIG_PLATFORM_POSIX is not set @@ -1177,7 +1177,7 @@ CONFIG_ASH_HELP=y CONFIG_ASH_GETOPTS=y CONFIG_ASH_CMDCMD=y CONFIG_ASH_NOCONSOLE=y -CONFIG_ASH_NOCASEGLOB=y +CONFIG_ASH_GLOB_OPTIONS=y # CONFIG_CTTYHACK is not set # CONFIG_HUSH is not set # CONFIG_SHELL_HUSH is not set diff --git a/include/libbb.h b/include/libbb.h index 2cdfac639..bbb3108a9 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -2011,6 +2011,7 @@ unsigned size_from_HISTFILESIZE(const char *hp) FAST_FUNC; # endif typedef const char *get_exe_name_t(int i) FAST_FUNC; typedef const char *sh_get_var_t(const char *name) FAST_FUNC; +typedef int sh_accept_glob_t(const char *name) FAST_FUNC; typedef struct line_input_t { int flags; int timeout; @@ -2024,6 +2025,9 @@ typedef struct line_input_t { # if ENABLE_SHELL_ASH || ENABLE_SHELL_HUSH /* function to fetch additional application-specific names to match */ get_exe_name_t *get_exe_name; +# if ENABLE_ASH_GLOB_OPTIONS + sh_accept_glob_t *sh_accept_glob; +# endif # endif # endif # if (ENABLE_FEATURE_USERNAME_COMPLETION || ENABLE_FEATURE_EDITING_FANCY_PROMPT) \ diff --git a/libbb/lineedit.c b/libbb/lineedit.c index 316c53f64..e7729996f 100644 --- a/libbb/lineedit.c +++ b/libbb/lineedit.c @@ -1032,6 +1032,10 @@ static NOINLINE unsigned complete_cmd_dir_file(const char *command, int type) goto cont; /* hmm, remove in progress? */ # if ENABLE_PLATFORM_MINGW32 +# if ENABLE_ASH_GLOB_OPTIONS + if (state->sh_accept_glob && !state->sh_accept_glob(found)) + goto cont; +# endif if (type == FIND_EXE_ONLY && S_ISREG(st.st_mode) && !(st.st_mode & S_IXUSR)) goto cont; diff --git a/shell/ash.c b/shell/ash.c index f0480f723..95bf81db3 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -196,13 +196,15 @@ //config: application. This may be useful when running a shell script //config: from a GUI application. //config: -//config:config ASH_NOCASEGLOB -//config: bool "'nocaseglob' option" +//config:config ASH_GLOB_OPTIONS +//config: bool "Globbing options" //config: default y //config: depends on (ASH || SH_IS_ASH || BASH_IS_ASH) && PLATFORM_MINGW32 //config: help -//config: Enable support for the 'nocaseglob' option, which allows -//config: case-insensitive filename globbing. +//config: Enable support for options to control globbing: +//config: - 'nocaseglob' allows case-insensitive filename globbing +//config: - 'nohiddenglob' allows hidden files to be omitted from globbing +//config: - 'nohidsysglob' allows hidden system files to be omitted //config: //config:endif # ash options @@ -545,8 +547,10 @@ static const char *const optletters_optnames[] ALIGN_PTR = { #if ENABLE_ASH_NOCONSOLE ,"\0" "noconsole" #endif -#if ENABLE_ASH_NOCASEGLOB +#if ENABLE_ASH_GLOB_OPTIONS ,"\0" "nocaseglob" + ,"\0" "nohiddenglob" + ,"\0" "nohidsysglob" #endif }; //bash 4.4.23 also has these opts (with these defaults): @@ -673,8 +677,10 @@ struct globals_misc { # if ENABLE_ASH_NOCONSOLE # define noconsole optlist[17 + BASH_PIPEFAIL + 2*(DEBUG != 0)] # endif -# if ENABLE_ASH_NOCASEGLOB +# if ENABLE_ASH_GLOB_OPTIONS # define nocaseglob optlist[17 + BASH_PIPEFAIL + 2*(DEBUG != 0) + ENABLE_ASH_NOCONSOLE] +# define nohiddenglob optlist[18 + BASH_PIPEFAIL + 2*(DEBUG != 0) + ENABLE_ASH_NOCONSOLE] +# define nohidsysglob optlist[19 + BASH_PIPEFAIL + 2*(DEBUG != 0) + ENABLE_ASH_NOCONSOLE] # endif #endif @@ -8678,6 +8684,26 @@ expandmeta(struct strlist *str /*, int flag*/) #else /* ENABLE_ASH_INTERNAL_GLOB: Homegrown globbing code. (dash also has both, uses homegrown one.) */ +#if ENABLE_ASH_GLOB_OPTIONS +static int FAST_FUNC +ash_accept_glob(const char *name) +{ + struct stat st; + + if (nohiddenglob || nohidsysglob) { + if (!lstat(name, &st)) { + if ((st.st_attr & FILE_ATTRIBUTE_HIDDEN)) { + if (nohiddenglob || + (st.st_attr & FILE_ATTRIBUTE_SYSTEM)) { + return FALSE; + } + } + } + } + return TRUE; +} +#endif + /* * Do metacharacter (i.e. *, ?, [...]) expansion. */ @@ -8783,12 +8809,16 @@ expmeta(exp_t *exp, char *name, unsigned name_len, unsigned expdir_len) while (!pending_int && (dp = readdir(dirp)) != NULL) { if (dp->d_name[0] == '.' && !matchdot) continue; -#if ENABLE_ASH_NOCASEGLOB +#if ENABLE_ASH_GLOB_OPTIONS # undef pmatch # define pmatch(a, b) !fnmatch((a), (b), nocaseglob ? FNM_CASEFOLD : 0) #endif if (pmatch(start, dp->d_name)) { if (atend) { +#if ENABLE_ASH_GLOB_OPTIONS + if (!ash_accept_glob(dp->d_name)) + continue; +#endif strcpy(enddir, dp->d_name); addfname(expdir); } else { @@ -8816,7 +8846,7 @@ expmeta(exp_t *exp, char *name, unsigned name_len, unsigned expdir_len) endname[-esc - 1] = esc ? '\\' : '/'; #undef expdir #undef expdir_max -#if ENABLE_ASH_NOCASEGLOB +#if ENABLE_ASH_GLOB_OPTIONS # undef pmatch # define pmatch(a, b) !fnmatch((a), (b), 0) #endif @@ -10865,6 +10895,9 @@ setinteractive(int on) line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP); # if ENABLE_FEATURE_TAB_COMPLETION line_input_state->get_exe_name = ash_command_name; +# if ENABLE_ASH_GLOB_OPTIONS + line_input_state->sh_accept_glob = ash_accept_glob; +# endif # endif # if EDITING_HAS_sh_get_var line_input_state->sh_get_var = lookupvar; -- cgit v1.2.3-55-g6feb