summaryrefslogtreecommitdiff
path: root/lib/glob.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/glob.c')
-rw-r--r--lib/glob.c143
1 files changed, 90 insertions, 53 deletions
diff --git a/lib/glob.c b/lib/glob.c
index 32c88e5d15..dc1a915c05 100644
--- a/lib/glob.c
+++ b/lib/glob.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1991-2021 Free Software Foundation, Inc.
+/* Copyright (C) 1991-2024 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@@ -21,16 +21,17 @@
optimizes away the pattern == NULL test below. */
# define _GL_ARG_NONNULL(params)
-# include <config.h>
+# include <libc-config.h>
#endif
#include <glob.h>
#include <errno.h>
+#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
-#include <stdbool.h>
+#include <stdckdint.h>
#include <stddef.h>
#include <stdint.h>
#include <assert.h>
@@ -56,28 +57,38 @@
# define sysconf(id) __sysconf (id)
# define closedir(dir) __closedir (dir)
# define opendir(name) __opendir (name)
+# undef dirfd
+# define dirfd(str) __dirfd (str)
# define readdir(str) __readdir64 (str)
# define getpwnam_r(name, bufp, buf, len, res) \
__getpwnam_r (name, bufp, buf, len, res)
-# define struct_stat64 struct stat64
# define FLEXIBLE_ARRAY_MEMBER
+# ifndef struct_stat
+# define struct_stat struct stat
+# endif
+# ifndef struct_stat64
+# define struct_stat64 struct stat64
+# endif
+# ifndef GLOB_LSTAT
+# define GLOB_LSTAT gl_lstat
+# endif
+# ifndef GLOB_FSTATAT64
+# define GLOB_FSTATAT64 __fstatat64
+# endif
# include <shlib-compat.h>
#else /* !_LIBC */
# define __glob glob
# define __getlogin_r(buf, len) getlogin_r (buf, len)
-# define __lstat64(fname, buf) lstat (fname, buf)
-# if defined _WIN32 && !defined __CYGWIN__
- /* Avoid GCC or clang warning. The original __stat64 macro is unused. */
-# undef __stat64
-# endif
-# define __stat64(fname, buf) stat (fname, buf)
# define __fxstatat64(_, d, f, st, flag) fstatat (d, f, st, flag)
-# define struct_stat64 struct stat
# ifndef __MVS__
# define __alloca alloca
# endif
# define __readdir readdir
# define COMPILE_GLOB64
+# define struct_stat struct stat
+# define struct_stat64 struct stat
+# define GLOB_LSTAT gl_lstat
+# define GLOB_FSTATAT64 fstatat
#endif /* _LIBC */
#include <fnmatch.h>
@@ -172,16 +183,17 @@ convert_dirent64 (const struct dirent64 *source)
#endif
#ifndef _LIBC
-/* The results of opendir() in this file are not used with dirfd and fchdir,
- and we do not leak fds to any single-threaded code that could use stdio,
- therefore save some unnecessary recursion in fchdir.c and opendir_safer.c.
- FIXME - if the kernel ever adds support for multi-thread safety for
- avoiding standard fds, then we should use opendir_safer. */
-# ifdef GNULIB_defined_opendir
-# undef opendir
-# endif
-# ifdef GNULIB_defined_closedir
-# undef closedir
+/* The results of opendir() in this file are used with dirfd. But they are
+ not used with fchdir, and we do not leak fds to any single-threaded code
+ that could use stdio, therefore save some unnecessary recursion in
+ fchdir.c and opendir_safer.c. */
+# ifndef GNULIB_defined_DIR
+# ifdef GNULIB_defined_opendir
+# undef opendir
+# endif
+# ifdef GNULIB_defined_closedir
+# undef closedir
+# endif
# endif
/* Just use malloc. */
@@ -196,44 +208,22 @@ glob_lstat (glob_t *pglob, int flags, const char *fullname)
{
/* Use on glob-lstat-compat.c to provide a compat symbol which does not
use lstat / gl_lstat. */
-#ifdef GLOB_NO_LSTAT
-# define GL_LSTAT gl_stat
-# define LSTAT64 __stat64
-#else
-# define GL_LSTAT gl_lstat
-# define LSTAT64 __lstat64
-#endif
-
union
{
- struct stat st;
+ struct_stat st;
struct_stat64 st64;
} ust;
return (__glibc_unlikely (flags & GLOB_ALTDIRFUNC)
- ? pglob->GL_LSTAT (fullname, &ust.st)
- : LSTAT64 (fullname, &ust.st64));
-}
-
-/* Set *R = A + B. Return true if the answer is mathematically
- incorrect due to overflow; in this case, *R is the low order
- bits of the correct answer. */
-
-static bool
-size_add_wrapv (size_t a, size_t b, size_t *r)
-{
-#if 7 <= __GNUC__ && !defined __ICC
- return __builtin_add_overflow (a, b, r);
-#else
- *r = a + b;
- return *r < a;
-#endif
+ ? pglob->GLOB_LSTAT (fullname, &ust.st)
+ : GLOB_FSTATAT64 (AT_FDCWD, fullname, &ust.st64,
+ AT_SYMLINK_NOFOLLOW));
}
static bool
glob_use_alloca (size_t alloca_used, size_t len)
{
size_t size;
- return (!size_add_wrapv (alloca_used, len, &size)
+ return (!ckd_add (&size, alloca_used, len)
&& __libc_use_alloca (size));
}
@@ -249,11 +239,12 @@ static int collated_compare (const void *, const void *) __THROWNL;
static bool
is_dir (char const *filename, int flags, glob_t const *pglob)
{
- struct stat st;
+ struct_stat st;
struct_stat64 st64;
return (__glibc_unlikely (flags & GLOB_ALTDIRFUNC)
? pglob->gl_stat (filename, &st) == 0 && S_ISDIR (st.st_mode)
- : __stat64 (filename, &st64) == 0 && S_ISDIR (st64.st_mode));
+ : (GLOB_FSTATAT64 (AT_FDCWD, filename, &st64, 0) == 0
+ && S_ISDIR (st64.st_mode)));
}
/* Find the end of the sub-pattern in a brace expression. */
@@ -743,6 +734,8 @@ __glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
else
{
#ifndef WINDOWS32
+ /* Recognize ~user as a shorthand for the specified user's home
+ directory. */
char *end_name = strchr (dirname, '/');
char *user_name;
int malloc_user_name = 0;
@@ -881,7 +874,22 @@ __glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
}
scratch_buffer_free (&pwtmpbuf);
}
-#endif /* !WINDOWS32 */
+#else /* WINDOWS32 */
+ /* On native Windows, access to a user's home directory
+ (via GetUserProfileDirectory) or to a user's environment
+ variables (via ExpandEnvironmentStringsForUser) requires
+ the credentials of the user. Therefore we cannot support
+ the ~user syntax on this platform.
+ Handling ~user specially (and treat it like plain ~) if
+ user is getenv ("USERNAME") would not be a good idea,
+ since it would make people think that ~user is supported
+ in general. */
+ if (flags & GLOB_TILDE_CHECK)
+ {
+ retval = GLOB_NOMATCH;
+ goto out;
+ }
+#endif /* WINDOWS32 */
}
}
@@ -1262,6 +1270,8 @@ glob_in_dir (const char *pattern, const char *directory, int flags,
{
size_t dirlen = strlen (directory);
void *stream = NULL;
+ struct scratch_buffer s;
+ scratch_buffer_init (&s);
# define GLOBNAMES_MEMBERS(nnames) \
struct globnames *next; size_t count; char *name[nnames];
struct globnames { GLOBNAMES_MEMBERS (FLEXIBLE_ARRAY_MEMBER) };
@@ -1295,7 +1305,7 @@ glob_in_dir (const char *pattern, const char *directory, int flags,
size_t patlen = strlen (pattern);
size_t fullsize;
bool alloca_fullname
- = (! size_add_wrapv (dirlen + 1, patlen + 1, &fullsize)
+ = (!ckd_add (&fullsize, dirlen + 1, patlen + 1)
&& glob_use_alloca (alloca_used, fullsize));
char *fullname;
if (alloca_fullname)
@@ -1333,6 +1343,8 @@ glob_in_dir (const char *pattern, const char *directory, int flags,
}
else
{
+ DIR *dirp = stream;
+ int dfd = dirfd (dirp);
int fnm_flags = ((!(flags & GLOB_PERIOD) ? FNM_PERIOD : 0)
| ((flags & GLOB_NOESCAPE) ? FNM_NOESCAPE : 0));
flags |= GLOB_MAGCHAR;
@@ -1360,8 +1372,32 @@ glob_in_dir (const char *pattern, const char *directory, int flags,
if (flags & GLOB_ONLYDIR)
switch (readdir_result_type (d))
{
- case DT_DIR: case DT_LNK: case DT_UNKNOWN: break;
default: continue;
+ case DT_DIR: break;
+ case DT_LNK: case DT_UNKNOWN:
+ /* The filesystem was too lazy to give us a hint,
+ so we have to do it the hard way. */
+ if (__glibc_unlikely (dfd < 0 || flags & GLOB_ALTDIRFUNC))
+ {
+ size_t namelen = strlen (d.name);
+ size_t need = dirlen + 1 + namelen + 1;
+ if (s.length < need
+ && !scratch_buffer_set_array_size (&s, need, 1))
+ goto memory_error;
+ char *p = mempcpy (s.data, directory, dirlen);
+ *p = '/';
+ p += p[-1] != '/';
+ memcpy (p, d.name, namelen + 1);
+ if (! is_dir (s.data, flags, pglob))
+ continue;
+ }
+ else
+ {
+ struct_stat64 st64;
+ if (! (GLOB_FSTATAT64 (dfd, d.name, &st64, 0) == 0
+ && S_ISDIR (st64.st_mode)))
+ continue;
+ }
}
if (fnmatch (pattern, d.name, fnm_flags) == 0)
@@ -1493,5 +1529,6 @@ glob_in_dir (const char *pattern, const char *directory, int flags,
__set_errno (save);
}
+ scratch_buffer_free (&s);
return result;
}

Return to:

Send suggestions and report system problems to the System administrator.