@@ -69,7 +69,7 @@ tests := test-errno tstgetopt testfnm runtests runptests \
tst-mmap tst-mmap-offset tst-getaddrinfo tst-truncate \
tst-truncate64 tst-fork tst-fnmatch tst-regexloc tst-dir \
tst-chmod bug-regex1 bug-regex2 bug-regex3 bug-regex4 \
- tst-gnuglob tst-regex bug-regex6 bug-regex7 \
+ tst-gnuglob tst-glob_symlinks tst-regex bug-regex6 bug-regex7 \
bug-regex8 bug-regex9 bug-regex10 bug-regex11 bug-regex12 \
bug-regex13 bug-regex14 bug-regex15 bug-regex16 \
bug-regex17 bug-regex18 bug-regex19 \
@@ -79,7 +79,7 @@ tests := test-errno tstgetopt testfnm runtests runptests \
tst-nice tst-nanosleep tst-regex2 \
transbug tst-rxspencer tst-pcre tst-boost \
bug-ga1 tst-vfork1 tst-vfork2 tst-vfork3 tst-waitid \
- tst-getaddrinfo2 bug-glob1 bug-glob2 bug-glob3 tst-sysconf \
+ tst-getaddrinfo2 bug-glob2 bug-glob3 tst-sysconf \
tst-execvp1 tst-execvp2 tst-execlp1 tst-execlp2 \
tst-execv1 tst-execv2 tst-execl1 tst-execl2 \
tst-execve1 tst-execve2 tst-execle1 tst-execle2 \
@@ -249,7 +249,6 @@ tst-rxspencer-ARGS = --utf8 rxspencer/tests
tst-rxspencer-no-utf8-ARGS = rxspencer/tests
tst-pcre-ARGS = PCRE.tests
tst-boost-ARGS = BOOST.tests
-bug-glob1-ARGS = "$(objpfx)"
tst-execvp3-ARGS = --test-dir=$(objpfx)
testcases.h: TESTS TESTS2C.sed
deleted file mode 100644
@@ -1,88 +0,0 @@
-/* Test case for globbing dangling symlink. By Ulrich Drepper. */
-#include <errno.h>
-#include <error.h>
-#include <glob.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-
-static void prepare (int argc, char *argv[]);
-#define PREPARE prepare
-static int do_test (void);
-#define TEST_FUNCTION do_test ()
-
-#include "../test-skeleton.c"
-
-
-static char *fname;
-
-static void
-prepare (int argc, char *argv[])
-{
- if (argc < 2)
- error (EXIT_FAILURE, 0, "missing argument");
-
- size_t len = strlen (argv[1]);
- static const char ext[] = "globXXXXXX";
- fname = malloc (len + sizeof (ext));
- if (fname == NULL)
- error (EXIT_FAILURE, errno, "cannot create temp file");
- again:
- strcpy (stpcpy (fname, argv[1]), ext);
- fname = mktemp (fname);
- if (fname == NULL || *fname == '\0')
- error (EXIT_FAILURE, errno, "cannot create temp file name");
- if (symlink ("bug-glob1-does-not-exist", fname) != 0)
- {
- if (errno == EEXIST)
- goto again;
-
- error (EXIT_FAILURE, errno, "cannot create symlink");
- }
- add_temp_file (fname);
-}
-
-
-static int
-do_test (void)
-{
- glob_t gl;
- int retval = 0;
- int e;
-
- e = glob (fname, 0, NULL, &gl);
- if (e == 0)
- {
- printf ("glob(\"%s\") succeeded\n", fname);
- retval = 1;
- }
- globfree (&gl);
-
- size_t fnamelen = strlen (fname);
- char buf[fnamelen + 2];
-
- strcpy (buf, fname);
- buf[fnamelen - 1] = '?';
- e = glob (buf, 0, NULL, &gl);
- if (e == 0)
- {
- printf ("glob(\"%s\") succeeded\n", buf);
- retval = 1;
- }
- globfree (&gl);
-
- strcpy (buf, fname);
- buf[fnamelen] = '*';
- buf[fnamelen + 1] = '\0';
- e = glob (buf, 0, NULL, &gl);
- if (e == 0)
- {
- printf ("glob(\"%s\") succeeded\n", buf);
- retval = 1;
- }
- globfree (&gl);
-
- return retval;
-}
@@ -71,8 +71,8 @@
# define readdir(str) __readdir64 (str)
# define getpwnam_r(name, bufp, buf, len, res) \
__getpwnam_r (name, bufp, buf, len, res)
-# ifndef __stat64
-# define __stat64(fname, buf) __xstat64 (_STAT_VER, fname, buf)
+# ifndef __lstat64
+# define __lstat64(fname, buf) __lxstat64 (_STAT_VER, fname, buf)
# endif
# define struct_stat64 struct stat64
#else /* !_LIBC */
@@ -1049,9 +1049,9 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
/* Return the directory if we don't check for error or if it exists. */
if ((flags & GLOB_NOCHECK)
|| (((__builtin_expect (flags & GLOB_ALTDIRFUNC, 0))
- ? ((*pglob->gl_stat) (dirname, &st) == 0
+ ? ((*pglob->gl_lstat) (dirname, &st) == 0
&& S_ISDIR (st.st_mode))
- : (__stat64 (dirname, &st64) == 0 && S_ISDIR (st64.st_mode)))))
+ : (__lstat64 (dirname, &st64) == 0 && S_ISDIR (st64.st_mode)))))
{
size_t newcount = pglob->gl_pathc + pglob->gl_offs;
char **new_gl_pathv;
@@ -1318,10 +1318,10 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
for (i = oldcount; i < pglob->gl_pathc + pglob->gl_offs; ++i)
if ((__builtin_expect (flags & GLOB_ALTDIRFUNC, 0)
- ? ((*pglob->gl_stat) (pglob->gl_pathv[i], &st) == 0
- && S_ISDIR (st.st_mode))
- : (__stat64 (pglob->gl_pathv[i], &st64) == 0
- && S_ISDIR (st64.st_mode))))
+ ? ((*pglob->gl_lstat) (pglob->gl_pathv[i], &st) == 0
+ && (S_ISDIR (st.st_mode) || S_ISLNK (st.st_mode)))
+ : (__lstat64 (pglob->gl_pathv[i], &st64) == 0
+ && (S_ISDIR (st64.st_mode) || S_ISLNK (st64.st_mode)))))
{
size_t len = strlen (pglob->gl_pathv[i]) + 2;
char *new = realloc (pglob->gl_pathv[i], len);
@@ -1500,54 +1500,6 @@ weak_alias (__glob_pattern_p, glob_pattern_p)
# endif
#endif
-
-/* We put this in a separate function mainly to allow the memory
- allocated with alloca to be recycled. */
-static int
-__attribute_noinline__
-link_exists2_p (const char *dir, size_t dirlen, const char *fname,
- glob_t *pglob
-# if !defined _LIBC && !HAVE_FSTATAT
- , int flags
-# endif
- )
-{
- size_t fnamelen = strlen (fname);
- char *fullname = __alloca (dirlen + 1 + fnamelen + 1);
- struct stat st;
-
- mempcpy (mempcpy (mempcpy (fullname, dir, dirlen), "/", 1),
- fname, fnamelen + 1);
-
-# if !defined _LIBC && !HAVE_FSTATAT
- if (__builtin_expect ((flags & GLOB_ALTDIRFUNC) == 0, 1))
- {
- struct_stat64 st64;
- return __stat64 (fullname, &st64) == 0;
- }
-# endif
- return (*pglob->gl_stat) (fullname, &st) == 0;
-}
-
-/* Return true if DIR/FNAME exists. */
-static int
-link_exists_p (int dfd, const char *dir, size_t dirlen, const char *fname,
- glob_t *pglob, int flags)
-{
-# if defined _LIBC || HAVE_FSTATAT
- if (__builtin_expect (flags & GLOB_ALTDIRFUNC, 0))
- return link_exists2_p (dir, dirlen, fname, pglob);
- else
- {
- /* dfd cannot be -1 here, because dirfd never returns -1 on
- glibc, or on hosts that have fstatat. */
- struct_stat64 st64;
- return __fxstatat64 (_STAT_VER, dfd, fname, &st64, 0) == 0;
- }
-# else
- return link_exists2_p (dir, dirlen, fname, pglob, flags);
-# endif
-}
#endif /* !defined GLOB_ONLY_P */
@@ -1619,8 +1571,8 @@ glob_in_dir (const char *pattern, const char *directory, int flags,
"/", 1),
pattern, patlen + 1);
if ((__builtin_expect (flags & GLOB_ALTDIRFUNC, 0)
- ? (*pglob->gl_stat) (fullname, &ust.st)
- : __stat64 (fullname, &ust.st64)) == 0)
+ ? (*pglob->gl_lstat) (fullname, &ust.st)
+ : __lstat64 (fullname, &ust.st64)) == 0)
/* We found this file to be existing. Now tell the rest
of the function to copy this name into the result. */
flags |= GLOB_NOCHECK;
@@ -1642,8 +1594,6 @@ glob_in_dir (const char *pattern, const char *directory, int flags,
}
else
{
- int dfd = (__builtin_expect (flags & GLOB_ALTDIRFUNC, 0)
- ? -1 : dirfd ((DIR *) stream));
int fnm_flags = ((!(flags & GLOB_PERIOD) ? FNM_PERIOD : 0)
| ((flags & GLOB_NOESCAPE) ? FNM_NOESCAPE : 0)
#if defined _AMIGA || defined VMS
@@ -1679,38 +1629,30 @@ glob_in_dir (const char *pattern, const char *directory, int flags,
if (fnmatch (pattern, d.name, fnm_flags) == 0)
{
- /* If the file we found is a symlink we have to
- make sure the target file exists. */
- if (!readdir_result_might_be_symlink (d)
- || link_exists_p (dfd, directory, dirlen, d.name,
- pglob, flags))
+ if (cur == names->count)
{
- if (cur == names->count)
- {
- struct globnames *newnames;
- size_t count = names->count * 2;
- size_t size = (sizeof (struct globnames)
- + ((count - INITIAL_COUNT)
- * sizeof (char *)));
- if (glob_use_alloca (alloca_used, size))
- newnames = names_alloca
- = alloca_account (size, alloca_used);
- else if ((newnames = malloc (size))
- == NULL)
- goto memory_error;
- newnames->count = count;
- newnames->next = names;
- names = newnames;
- cur = 0;
- }
- names->name[cur] = strdup (d.name);
- if (names->name[cur] == NULL)
- goto memory_error;
- ++cur;
- ++nfound;
- if (SIZE_MAX - pglob->gl_offs <= nfound)
+ struct globnames *newnames;
+ size_t count = names->count * 2;
+ size_t size = (sizeof (struct globnames)
+ + ((count - INITIAL_COUNT)
+ * sizeof (char *)));
+ if (glob_use_alloca (alloca_used, size))
+ newnames = names_alloca
+ = alloca_account (size, alloca_used);
+ else if ((newnames = malloc (size)) == NULL)
goto memory_error;
- }
+ newnames->count = count;
+ newnames->next = names;
+ names = newnames;
+ cur = 0;
+ }
+ names->name[cur] = strdup (d.name);
+ if (names->name[cur] == NULL)
+ goto memory_error;
+ ++cur;
+ ++nfound;
+ if (SIZE_MAX - pglob->gl_offs <= nfound)
+ goto memory_error;
}
}
}
new file mode 100644
@@ -0,0 +1,133 @@
+/* Test glob symlinks return (BZ #866).
+ for the filesystem access functions.
+ Copyright (C) 2017 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
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <limits.h>
+#include <stddef.h>
+#include <glob.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <support/check.h>
+#include <support/temp_file.h>
+
+static void do_prepare (int argc, char *argv[]);
+#define PREPARE do_prepare
+static int do_test (void);
+#include <support/test-driver.c>
+
+static void
+create_link (const char *base, const char *fname, char *linkname,
+ size_t linknamesize)
+{
+ int ntries = 0;
+ while (1)
+ {
+ snprintf (linkname, linknamesize, "%s/%s%02d", test_dir, base,
+ ntries);
+ if (symlink (fname, linkname) == 0)
+ break;
+ if (errno != EEXIST)
+ FAIL_EXIT1 ("symlink failed: %m");
+ if (ntries++ == 10)
+ FAIL_EXIT1 ("symlink failed with EEXIST too many times");
+ }
+ add_temp_file (linkname);
+}
+
+static char valid_link[PATH_MAX];
+static char dangling_link[PATH_MAX];
+static char dangling_dir[PATH_MAX];
+
+static void
+do_prepare (int argc, char *argv[])
+{
+ char *fname;
+
+ create_temp_file ("tst-glob_symlinks.", &fname);
+
+ /* Create a existing symlink. */
+ create_link ("valid-symlink-tst-glob_symlinks", fname, valid_link,
+ sizeof valid_link);
+
+ /* Create a dangling symlink to a file. */
+ int fd = create_temp_file ("dangling-tst-glob_file", &fname);
+ TEST_VERIFY_EXIT (close (fd) == 0);
+ /* It throws an warning at process end due 'add_temp_file' trying to
+ unlink it again. */
+ TEST_VERIFY_EXIT (unlink (fname) == 0);
+ create_link ("dangling-symlink-file-tst-glob", fname, dangling_link,
+ sizeof dangling_link);
+
+ /* Create a dangling symlink to a directory. */
+ char tmpdir[PATH_MAX];
+ snprintf (tmpdir, sizeof tmpdir, "%s/dangling-tst-glob_folder.XXXXXX",
+ test_dir);
+ TEST_VERIFY_EXIT (mkdtemp (tmpdir) != NULL);
+ create_link ("dangling-symlink-dir-tst-glob", tmpdir, dangling_dir,
+ sizeof dangling_dir);
+ TEST_VERIFY_EXIT (rmdir (tmpdir) == 0);
+}
+
+static int
+do_test (void)
+{
+ char buf[PATH_MAX];
+ glob_t gl;
+
+ TEST_VERIFY_EXIT (glob (valid_link, 0, NULL, &gl) == 0);
+ TEST_VERIFY_EXIT (gl.gl_pathc == 1);
+ TEST_VERIFY_EXIT (strcmp (gl.gl_pathv[0], valid_link) == 0);
+ globfree (&gl);
+
+ TEST_VERIFY_EXIT (glob (dangling_link, 0, NULL, &gl) == 0);
+ TEST_VERIFY_EXIT (gl.gl_pathc == 1);
+ TEST_VERIFY_EXIT (strcmp (gl.gl_pathv[0], dangling_link) == 0);
+ globfree (&gl);
+
+ TEST_VERIFY_EXIT (glob (dangling_dir, 0, NULL, &gl) == 0);
+ TEST_VERIFY_EXIT (gl.gl_pathc == 1);
+ TEST_VERIFY_EXIT (strcmp (gl.gl_pathv[0], dangling_dir) == 0);
+ globfree (&gl);
+
+ snprintf (buf, sizeof buf, "%s", dangling_link);
+ buf[strlen(buf) - 1] = '?';
+ TEST_VERIFY_EXIT (glob (buf, 0, NULL, &gl) == 0);
+ TEST_VERIFY_EXIT (gl.gl_pathc == 1);
+ TEST_VERIFY_EXIT (strcmp (gl.gl_pathv[0], dangling_link) == 0);
+ globfree (&gl);
+
+ /* glob should handle dangling symbol as normal file, so <file>? should
+ return an empty string. */
+ snprintf (buf, sizeof buf, "%s?", dangling_link);
+ TEST_VERIFY_EXIT (glob (buf, 0, NULL, &gl) != 0);
+ globfree (&gl);
+
+ snprintf (buf, sizeof buf, "%s*", dangling_link);
+ TEST_VERIFY_EXIT (glob (buf, 0, NULL, &gl) == 0);
+ TEST_VERIFY_EXIT (gl.gl_pathc == 1);
+ TEST_VERIFY_EXIT (strcmp (gl.gl_pathv[0], dangling_link) == 0);
+ globfree (&gl);
+
+ return 0;
+}
@@ -12,8 +12,8 @@
#undef stat
#define stat stat64
-#undef __stat
-#define __stat(file, buf) __xstat64 (_STAT_VER, file, buf)
+#undef __lstat
+#define __lstat(file, buf) __lxstat64 (_STAT_VER, file, buf)
#define NO_GLOB_PATTERN_P 1
@@ -30,8 +30,8 @@
#undef stat
#define stat stat64
-#undef __stat
-#define __stat(file, buf) __xstat64 (_STAT_VER, file, buf)
+#undef __lstat
+#define __lstat(file, buf) __lxstat64 (_STAT_VER, file, buf)
#define NO_GLOB_PATTERN_P 1