mirror of
git://git.code.sf.net/p/cdesktopenv/code
synced 2025-03-09 15:50:02 +00:00
Fixes for -G/--globstar (re: 5312a59d
)
The fix for '.' and '..' in regular globbing broke '.' and '..' in globstar. No globstar pattern that contains '.' or '..' as any pathname component still matched. This commit fixes that. This commit also makes symlink/** mostly work, which it never has done in any ksh93 version. It is correct and expected that symlinks found by patterns are not resolved, but symlinks were not resolved even when specified as explicit non-pattern pathname components. For example, /tmp/** breaks if /tmp is a symlink (e.g. on macOS), which looks like a bug. src/lib/libast/include/glob.h, src/lib/libast/misc/glob.c: glob_dir(): - Make symlink/** work. we can check if the string pointed to by pat is exactly equal to *. If so, we are doing regular globbing for that particular pathname element, and it's okay to resolve symlinks. If not (if it's **), we're doing globstar and we should not be matching symlinks. - Let's also introduce proper identification of symlinks (GLOB_SYM) and not lump them in with other special files (GLOB_DEV). - Fix the bug with literal '.' and '..' components in globstar patterns. In preceding code, the matchdir pointer gets set to the complete glob pattern if we're doing globstar for the current pathname element, null if not. The pat pointer gets set to the elements of the pattern that are still left to be processed; already-done elements are trimmed from it by increasing the pointer. So, to do the right thing, we need to make sure that '.' or '..' is skipped if, and only if, it is the final element in the pattern (i.e., if pat does not contain a slash) and is not specified literally as '.' or '..', i.e., only if '.' or '..' was actually resolved from a glob pattern. After this change, '**/.*', '**/../.*', etc. do the right thing, showing all your hidden files and directories without undesirable '.' and '..' results; '.' and '..' are skipped as final elements, unless you literally specify '**/.', '**/..', '**/foo/bar/..', etc. src/cmd/ksh93/COMPATIBILITY: - Note the symlink/** globstar change. src/cmd/ksh93/sh.1: - Try to document the current globstar behaviour more exhausively. src/cmd/ksh93/tests/glob.sh: - Add tests. Try to cover all the corner cases. src/cmd/ksh93/tests/shtests: - Since tests in glob.sh do not use err_exit, they were not counted. Special-case glob.sh for counting the tests: count the lines starting with a test_* function call. Resolves: https://github.com/ksh93/ksh/issues/146
This commit is contained in:
parent
89c69b076d
commit
aad74597f7
8 changed files with 108 additions and 15 deletions
|
@ -121,10 +121,11 @@ struct _glob_
|
|||
|
||||
/* gl_type return */
|
||||
#define GLOB_NOTFOUND 0 /* does not exist */
|
||||
#define GLOB_DEV 1 /* exists but not DIR EXE REG */
|
||||
#define GLOB_DIR 2 /* directory */
|
||||
#define GLOB_EXE 3 /* executable regular file */
|
||||
#define GLOB_REG 4 /* regular file */
|
||||
#define GLOB_SYM 5 /* symbolic link */
|
||||
#define GLOB_DEV 1 /* exists but none of the above */
|
||||
|
||||
/* error return values */
|
||||
#define GLOB_ABORTED 1
|
||||
|
|
|
@ -125,6 +125,8 @@ gl_type(glob_t* gp, const char* path, int flags)
|
|||
type = 0;
|
||||
else if (S_ISDIR(st.st_mode))
|
||||
type = GLOB_DIR;
|
||||
else if (S_ISLNK(st.st_mode))
|
||||
type = GLOB_SYM;
|
||||
else if (!S_ISREG(st.st_mode))
|
||||
type = GLOB_DEV;
|
||||
else if (st.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH))
|
||||
|
@ -479,7 +481,9 @@ skip:
|
|||
break;
|
||||
prefix = streq(dirname, ".") ? (char*)0 : dirname;
|
||||
}
|
||||
if ((!starstar && !gp->gl_starstar || (*gp->gl_type)(gp, dirname, GLOB_STARSTAR) == GLOB_DIR) && (dirf = (*gp->gl_diropen)(gp, dirname)))
|
||||
if ((!starstar && !gp->gl_starstar || (t1 = (*gp->gl_type)(gp, dirname, GLOB_STARSTAR)) == GLOB_DIR
|
||||
|| t1 == GLOB_SYM && pat[0]=='*' && pat[1]=='\0') /* follow symlinks to dirs for non-globstar components */
|
||||
&& (dirf = (*gp->gl_diropen)(gp, dirname)))
|
||||
{
|
||||
if (!(gp->re_flags & REG_ICASE) && ((*gp->gl_attr)(gp, dirname, 0) & GLOB_ICASE))
|
||||
{
|
||||
|
@ -528,13 +532,14 @@ skip:
|
|||
*restore2 = gp->gl_delim;
|
||||
while ((name = (*gp->gl_dirnext)(gp, dirf)) && !*gp->gl_intr)
|
||||
{
|
||||
if (name[0] == '.' && (!name[1] || name[1] == '.' && !name[2]))
|
||||
continue; /* do not ever match '.' or '..' */
|
||||
if (!(matchdir && (pat[0] == '.' && (!pat[1] || pat[1] == '.' && !pat[2]) || strchr(pat,'/')))
|
||||
&& name[0] == '.' && (!name[1] || name[1] == '.' && !name[2]))
|
||||
continue; /* never match '.' or '..' as final element unless specified literally */
|
||||
if (notdir = (gp->gl_status & GLOB_NOTDIR))
|
||||
gp->gl_status &= ~GLOB_NOTDIR;
|
||||
if (ire && !regexec(ire, name, 0, NiL, 0))
|
||||
continue;
|
||||
if (matchdir && !notdir)
|
||||
if (matchdir && (name[0] != '.' || name[1] && (name[1] != '.' || name[2])) && !notdir)
|
||||
addmatch(gp, prefix, name, matchdir, NiL, anymeta);
|
||||
if (!regexec(pre, name, 0, NiL, 0))
|
||||
{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue