Message ID | xnee1zjkta.fsf@greed.delorie.com |
---|---|
State | New |
Headers | show |
Series | [v3] posix/glob.c: update from gnulib | expand |
On 4/14/22 19:40, DJ Delorie wrote: > > [v3: Added sysdeps/unix/sysv/linux/glob64-time64.c to fix i686 build] > > Copied from gnulib/lib/glob.c in order to fix rhbz 1982608 > Also fixes swbz 25659 Passes CI/CD. Passes without regression on x86_64. Minor difference from upstream gnulib. LGTM. Thank you! Reviewed-by: Carlos O'Donell <carlos@redhat.com> Tested-by: Carlos O'Donell <carlos@redhat.com> > diff --git a/posix/glob.c b/posix/glob.c > index a2b5aabada..f6993a3706 100644 > --- a/posix/glob.c > +++ b/posix/glob.c > @@ -21,13 +21,14 @@ > 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> > @@ -56,6 +57,8 @@ > # 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) > @@ -69,11 +72,8 @@ > # ifndef GLOB_LSTAT > # define GLOB_LSTAT gl_lstat > # endif > -# ifndef GLOB_STAT64 > -# define GLOB_STAT64 __stat64 > -# endif > -# ifndef GLOB_LSTAT64 > -# define GLOB_LSTAT64 __lstat64 > +# ifndef GLOB_FSTATAT64 > +# define GLOB_FSTATAT64 __fstatat64 > # endif > # include <shlib-compat.h> > #else /* !_LIBC */ > @@ -88,8 +88,7 @@ > # define struct_stat struct stat > # define struct_stat64 struct stat > # define GLOB_LSTAT gl_lstat > -# define GLOB_STAT64 stat > -# define GLOB_LSTAT64 lstat > +# define GLOB_FSTATAT64 fstatat > #endif /* _LIBC */ > > #include <fnmatch.h> > @@ -215,7 +214,8 @@ glob_lstat (glob_t *pglob, int flags, const char *fullname) > } ust; > return (__glibc_unlikely (flags & GLOB_ALTDIRFUNC) > ? pglob->GLOB_LSTAT (fullname, &ust.st) > - : GLOB_LSTAT64 (fullname, &ust.st64)); > + : GLOB_FSTATAT64 (AT_FDCWD, fullname, &ust.st64, > + AT_SYMLINK_NOFOLLOW)); > } > > /* Set *R = A + B. Return true if the answer is mathematically > @@ -257,7 +257,8 @@ is_dir (char const *filename, int flags, glob_t const *pglob) > struct_stat64 st64; > return (__glibc_unlikely (flags & GLOB_ALTDIRFUNC) > ? pglob->gl_stat (filename, &st) == 0 && S_ISDIR (st.st_mode) > - : GLOB_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. */ > @@ -747,6 +748,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; > @@ -885,7 +888,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 */ > } > } > > @@ -1266,6 +1284,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) }; > @@ -1337,6 +1357,7 @@ glob_in_dir (const char *pattern, const char *directory, int flags, > } > else > { > + int dfd = dirfd (stream); > int fnm_flags = ((!(flags & GLOB_PERIOD) ? FNM_PERIOD : 0) > | ((flags & GLOB_NOESCAPE) ? FNM_NOESCAPE : 0)); > flags |= GLOB_MAGCHAR; > @@ -1364,8 +1385,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) > @@ -1497,5 +1542,6 @@ glob_in_dir (const char *pattern, const char *directory, int flags, > __set_errno (save); > } > > + scratch_buffer_free (&s); > return result; > } > diff --git a/sysdeps/unix/sysv/linux/glob64-time64.c b/sysdeps/unix/sysv/linux/glob64-time64.c > index 32b4929a1b..1d485dc806 100644 > --- a/sysdeps/unix/sysv/linux/glob64-time64.c > +++ b/sysdeps/unix/sysv/linux/glob64-time64.c > @@ -37,6 +37,7 @@ > # define GLOB_LSTAT gl_lstat > # define GLOB_STAT64 __stat64_time64 > # define GLOB_LSTAT64 __lstat64_time64 > +# define GLOB_FSTATAT64 __fstatat64_time64 > > # define COMPILE_GLOB64 1 > >
Thanks! Pushed - and with attribution this time!
diff --git a/posix/glob.c b/posix/glob.c index a2b5aabada..f6993a3706 100644 --- a/posix/glob.c +++ b/posix/glob.c @@ -21,13 +21,14 @@ 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> @@ -56,6 +57,8 @@ # 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) @@ -69,11 +72,8 @@ # ifndef GLOB_LSTAT # define GLOB_LSTAT gl_lstat # endif -# ifndef GLOB_STAT64 -# define GLOB_STAT64 __stat64 -# endif -# ifndef GLOB_LSTAT64 -# define GLOB_LSTAT64 __lstat64 +# ifndef GLOB_FSTATAT64 +# define GLOB_FSTATAT64 __fstatat64 # endif # include <shlib-compat.h> #else /* !_LIBC */ @@ -88,8 +88,7 @@ # define struct_stat struct stat # define struct_stat64 struct stat # define GLOB_LSTAT gl_lstat -# define GLOB_STAT64 stat -# define GLOB_LSTAT64 lstat +# define GLOB_FSTATAT64 fstatat #endif /* _LIBC */ #include <fnmatch.h> @@ -215,7 +214,8 @@ glob_lstat (glob_t *pglob, int flags, const char *fullname) } ust; return (__glibc_unlikely (flags & GLOB_ALTDIRFUNC) ? pglob->GLOB_LSTAT (fullname, &ust.st) - : GLOB_LSTAT64 (fullname, &ust.st64)); + : GLOB_FSTATAT64 (AT_FDCWD, fullname, &ust.st64, + AT_SYMLINK_NOFOLLOW)); } /* Set *R = A + B. Return true if the answer is mathematically @@ -257,7 +257,8 @@ is_dir (char const *filename, int flags, glob_t const *pglob) struct_stat64 st64; return (__glibc_unlikely (flags & GLOB_ALTDIRFUNC) ? pglob->gl_stat (filename, &st) == 0 && S_ISDIR (st.st_mode) - : GLOB_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. */ @@ -747,6 +748,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; @@ -885,7 +888,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 */ } } @@ -1266,6 +1284,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) }; @@ -1337,6 +1357,7 @@ glob_in_dir (const char *pattern, const char *directory, int flags, } else { + int dfd = dirfd (stream); int fnm_flags = ((!(flags & GLOB_PERIOD) ? FNM_PERIOD : 0) | ((flags & GLOB_NOESCAPE) ? FNM_NOESCAPE : 0)); flags |= GLOB_MAGCHAR; @@ -1364,8 +1385,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) @@ -1497,5 +1542,6 @@ glob_in_dir (const char *pattern, const char *directory, int flags, __set_errno (save); } + scratch_buffer_free (&s); return result; } diff --git a/sysdeps/unix/sysv/linux/glob64-time64.c b/sysdeps/unix/sysv/linux/glob64-time64.c index 32b4929a1b..1d485dc806 100644 --- a/sysdeps/unix/sysv/linux/glob64-time64.c +++ b/sysdeps/unix/sysv/linux/glob64-time64.c @@ -37,6 +37,7 @@ # define GLOB_LSTAT gl_lstat # define GLOB_STAT64 __stat64_time64 # define GLOB_LSTAT64 __lstat64_time64 +# define GLOB_FSTATAT64 __fstatat64_time64 # define COMPILE_GLOB64 1