1 /* Test glob danglin symlink match (BZ #866).
2    Copyright (C) 2017-2022 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4 
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9 
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14 
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, see
17    <https://www.gnu.org/licenses/>.  */
18 
19 #include <stdio.h>
20 #include <string.h>
21 #include <stdlib.h>
22 #include <errno.h>
23 #include <unistd.h>
24 #include <limits.h>
25 #include <stddef.h>
26 #include <glob.h>
27 #include <sys/stat.h>
28 #include <sys/types.h>
29 
30 #include <support/check.h>
31 #include <support/temp_file.h>
32 
33 static void do_prepare (int argc, char *argv[]);
34 #define PREPARE do_prepare
35 static int do_test (void);
36 #include <support/test-driver.c>
37 
38 /* Maximum number of symlink calls for create_link function.  */
39 #define MAX_CREATE_LINK_TRIES 10
40 
41 static void
create_link(const char * base,const char * fname,char * linkname,size_t linknamesize)42 create_link (const char *base, const char *fname, char *linkname,
43 	     size_t linknamesize)
44 {
45   int ntries = 0;
46   while (1)
47     {
48       snprintf (linkname, linknamesize, "%s/%s%02d", test_dir, base,
49 		ntries);
50       if (symlink (fname, linkname) == 0)
51 	break;
52       if (errno != EEXIST)
53 	FAIL_EXIT1 ("symlink failed: %m");
54       if (ntries++ == MAX_CREATE_LINK_TRIES)
55 	FAIL_EXIT1 ("symlink failed with EEXIST too many times");
56     }
57   add_temp_file (linkname);
58 }
59 
60 #ifndef PATH_MAX
61 # define PATH_MAX 1024
62 #endif
63 static char valid_link[PATH_MAX];
64 static char dangling_link[PATH_MAX];
65 static char dangling_dir[PATH_MAX];
66 
67 static void
do_prepare(int argc,char * argv[])68 do_prepare (int argc, char *argv[])
69 {
70   char *fname;
71 
72   create_temp_file ("tst-glob_symlinks.", &fname);
73 
74   /* Create an existing symlink.  */
75   create_link ("valid-symlink-tst-glob_symlinks", fname, valid_link,
76 	       sizeof valid_link);
77 
78   /* Create a dangling symlink to a file.  */
79   int fd = create_temp_file ("dangling-tst-glob_file", &fname);
80   TEST_VERIFY_EXIT (close (fd) == 0);
81   /* It throws a warning at process end due 'add_temp_file' trying to
82      unlink it again.  */
83   TEST_VERIFY_EXIT (unlink (fname) == 0);
84   create_link ("dangling-symlink-file-tst-glob", fname, dangling_link,
85 	       sizeof dangling_link);
86 
87   /* Create a dangling symlink to a directory.  */
88   char tmpdir[PATH_MAX];
89   snprintf (tmpdir, sizeof tmpdir, "%s/dangling-tst-glob_folder.XXXXXX",
90 	    test_dir);
91   TEST_VERIFY_EXIT (mkdtemp (tmpdir) != NULL);
92   create_link ("dangling-symlink-dir-tst-glob", tmpdir, dangling_dir,
93 	       sizeof dangling_dir);
94   TEST_VERIFY_EXIT (rmdir (tmpdir) == 0);
95 }
96 
97 static int
do_test(void)98 do_test (void)
99 {
100   char buf[PATH_MAX + 1];
101   glob_t gl;
102 
103   TEST_VERIFY_EXIT (glob (valid_link, 0, NULL, &gl) == 0);
104   TEST_VERIFY_EXIT (gl.gl_pathc == 1);
105   TEST_VERIFY_EXIT (strcmp (gl.gl_pathv[0], valid_link) == 0);
106   globfree (&gl);
107 
108   TEST_VERIFY_EXIT (glob (dangling_link, 0, NULL, &gl) == 0);
109   TEST_VERIFY_EXIT (gl.gl_pathc == 1);
110   TEST_VERIFY_EXIT (strcmp (gl.gl_pathv[0], dangling_link) == 0);
111   globfree (&gl);
112 
113   TEST_VERIFY_EXIT (glob (dangling_dir, 0, NULL, &gl) == 0);
114   TEST_VERIFY_EXIT (gl.gl_pathc == 1);
115   TEST_VERIFY_EXIT (strcmp (gl.gl_pathv[0], dangling_dir) == 0);
116   globfree (&gl);
117 
118   snprintf (buf, sizeof buf, "%s", dangling_link);
119   buf[strlen(buf) - 1] = '?';
120   TEST_VERIFY_EXIT (glob (buf, 0, NULL, &gl) == 0);
121   TEST_VERIFY_EXIT (gl.gl_pathc == 1);
122   TEST_VERIFY_EXIT (strcmp (gl.gl_pathv[0], dangling_link) == 0);
123   globfree (&gl);
124 
125   /* glob should handle dangling symbol as normal file, so <file>? should
126      return an empty string.  */
127   snprintf (buf, sizeof buf, "%s?", dangling_link);
128   TEST_VERIFY_EXIT (glob (buf, 0, NULL, &gl) != 0);
129   globfree (&gl);
130 
131   snprintf (buf, sizeof buf, "%s*", dangling_link);
132   TEST_VERIFY_EXIT (glob (buf, 0, NULL, &gl) == 0);
133   TEST_VERIFY_EXIT (gl.gl_pathc == 1);
134   TEST_VERIFY_EXIT (strcmp (gl.gl_pathv[0], dangling_link) == 0);
135   globfree (&gl);
136 
137   return 0;
138 }
139