diff options
-rw-r--r-- | src/regex/glob.c | 17 |
1 files changed, 12 insertions, 5 deletions
diff --git a/src/regex/glob.c b/src/regex/glob.c index 58248675..9de080ed 100644 --- a/src/regex/glob.c +++ b/src/regex/glob.c @@ -92,16 +92,23 @@ static int do_glob(char *buf, size_t pos, int type, char *pat, int flags, int (* if (!*pat) { /* If we consumed any components above, or if GLOB_MARK is * requested and we don't yet know if the match is a dir, - * we must call stat to confirm the file exists and/or - * determine its type. */ + * we must confirm the file exists and/or determine its type. + * + * If marking dirs, symlink type is inconclusive; we need the + * type for the symlink target, and therefore must try stat + * first unless type is known not to be a symlink. Otherwise, + * or if that fails, use lstat for determining existence to + * avoid false negatives in the case of broken symlinks. */ struct stat st; - if ((flags & GLOB_MARK) && type==DT_LNK) type = 0; - if (!type && stat(buf, &st)) { + if ((flags & GLOB_MARK) && (!type||type==DT_LNK) && !stat(buf, &st)) { + if (S_ISDIR(st.st_mode)) type = DT_DIR; + else type = DT_REG; + } + if (!type && lstat(buf, &st)) { if (errno!=ENOENT && (errfunc(buf, errno) || (flags & GLOB_ERR))) return GLOB_ABORTED; return 0; } - if (!type && S_ISDIR(st.st_mode)) type = DT_DIR; if (append(tail, buf, pos, (flags & GLOB_MARK) && type==DT_DIR)) return GLOB_NOSPACE; return 0; |