]> git.ipfire.org Git - thirdparty/glibc.git/blob - posix/tst-glob_lstat_compat.c
Update copyright dates with scripts/update-copyrights.
[thirdparty/glibc.git] / posix / tst-glob_lstat_compat.c
1 /* Test glob compat symbol which avoid call GLOB_ALTDIRFUNC/gl_lstat.
2 Copyright (C) 2017-2018 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 <http://www.gnu.org/licenses/>. */
18
19 #include <glob.h>
20 #include <errno.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <sys/types.h>
24 #include <dirent.h>
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <unistd.h>
28
29 #include <stdio.h>
30
31 #include <shlib-compat.h>
32 #include <support/check.h>
33 #include <support/temp_file.h>
34
35 #if TEST_COMPAT (libc, GLIBC_2_0, GLIBC_2_27)
36
37 __typeof (glob) glob;
38 compat_symbol_reference (libc, glob, glob, GLIBC_2_0);
39
40 /* Compat glob should not call gl_lstat since for some old binaries it
41 might be unitialized (for instance GNUmake). Check if it is indeed
42 not called. */
43 static bool stat_called;
44 static bool lstat_called;
45
46 static struct
47 {
48 const char *name;
49 int level;
50 int type;
51 } filesystem[] =
52 {
53 { ".", 1, DT_DIR },
54 { "..", 1, DT_DIR },
55 { "dir1lev1", 1, DT_UNKNOWN },
56 { ".", 2, DT_DIR },
57 { "..", 2, DT_DIR },
58 { "file1lev2", 2, DT_REG },
59 { "file2lev2", 2, DT_REG },
60 };
61 static const size_t nfiles = sizeof (filesystem) / sizeof (filesystem [0]);
62
63 typedef struct
64 {
65 int level;
66 int idx;
67 struct dirent d;
68 char room_for_dirent[NAME_MAX];
69 } my_DIR;
70
71 static long int
72 find_file (const char *s)
73 {
74 int level = 1;
75 long int idx = 0;
76
77 while (s[0] == '/')
78 {
79 if (s[1] == '\0')
80 {
81 s = ".";
82 break;
83 }
84 ++s;
85 }
86
87 if (strcmp (s, ".") == 0)
88 return 0;
89
90 if (s[0] == '.' && s[1] == '/')
91 s += 2;
92
93 while (*s != '\0')
94 {
95 char *endp = strchrnul (s, '/');
96
97 while (idx < nfiles && filesystem[idx].level >= level)
98 {
99 if (filesystem[idx].level == level
100 && memcmp (s, filesystem[idx].name, endp - s) == 0
101 && filesystem[idx].name[endp - s] == '\0')
102 break;
103 ++idx;
104 }
105
106 if (idx == nfiles || filesystem[idx].level < level)
107 {
108 errno = ENOENT;
109 return -1;
110 }
111
112 if (*endp == '\0')
113 return idx + 1;
114
115 if (filesystem[idx].type != DT_DIR
116 && (idx + 1 >= nfiles
117 || filesystem[idx].level >= filesystem[idx + 1].level))
118 {
119 errno = ENOTDIR;
120 return -1;
121 }
122
123 ++idx;
124
125 s = endp + 1;
126 ++level;
127 }
128
129 errno = ENOENT;
130 return -1;
131 }
132
133 static void *
134 my_opendir (const char *s)
135 {
136 long int idx = find_file (s);
137 if (idx == -1 || filesystem[idx].type != DT_DIR)
138 return NULL;
139
140 my_DIR *dir = malloc (sizeof (my_DIR));
141 if (dir == NULL)
142 FAIL_EXIT1 ("cannot allocate directory handle");
143
144 dir->level = filesystem[idx].level;
145 dir->idx = idx;
146
147 return dir;
148 }
149
150 static struct dirent *
151 my_readdir (void *gdir)
152 {
153 my_DIR *dir = gdir;
154
155 if (dir->idx == -1)
156 return NULL;
157
158 while (dir->idx < nfiles && filesystem[dir->idx].level > dir->level)
159 ++dir->idx;
160
161 if (dir->idx == nfiles || filesystem[dir->idx].level < dir->level)
162 {
163 dir->idx = -1;
164 return NULL;
165 }
166
167 dir->d.d_ino = 1; /* glob should not skip this entry. */
168
169 dir->d.d_type = filesystem[dir->idx].type;
170
171 strcpy (dir->d.d_name, filesystem[dir->idx].name);
172
173 ++dir->idx;
174
175 return &dir->d;
176 }
177
178 static void
179 my_closedir (void *dir)
180 {
181 free (dir);
182 }
183
184 static int
185 my_stat (const char *name, struct stat *st)
186 {
187 stat_called = true;
188
189 long int idx = find_file (name);
190 if (idx == -1)
191 return -1;
192
193 memset (st, '\0', sizeof (*st));
194
195 if (filesystem[idx].type == DT_UNKNOWN)
196 st->st_mode = DTTOIF (idx + 1 < nfiles
197 && filesystem[idx].level < filesystem[idx + 1].level
198 ? DT_DIR : DT_REG) | 0777;
199 else
200 st->st_mode = DTTOIF (filesystem[idx].type) | 0777;
201 return 0;
202 }
203
204 static int
205 my_lstat (const char *name, struct stat *st)
206 {
207 lstat_called = true;
208
209 long int idx = find_file (name);
210 if (idx == -1)
211 return -1;
212
213 memset (st, '\0', sizeof (*st));
214
215 if (filesystem[idx].type == DT_UNKNOWN)
216 st->st_mode = DTTOIF (idx + 1 < nfiles
217 && filesystem[idx].level < filesystem[idx + 1].level
218 ? DT_DIR : DT_REG) | 0777;
219 else
220 st->st_mode = DTTOIF (filesystem[idx].type) | 0777;
221 return 0;
222 }
223
224 static int
225 do_test (void)
226 {
227 glob_t gl;
228
229 memset (&gl, '\0', sizeof (gl));
230
231 gl.gl_closedir = my_closedir;
232 gl.gl_readdir = my_readdir;
233 gl.gl_opendir = my_opendir;
234 gl.gl_lstat = my_lstat;
235 gl.gl_stat = my_stat;
236
237 int flags = GLOB_ALTDIRFUNC;
238
239 stat_called = false;
240 lstat_called = false;
241
242 TEST_VERIFY_EXIT (glob ("*/file1lev2", flags, NULL, &gl) == 0);
243 TEST_VERIFY_EXIT (gl.gl_pathc == 1);
244 TEST_VERIFY_EXIT (strcmp (gl.gl_pathv[0], "dir1lev1/file1lev2") == 0);
245
246 TEST_VERIFY_EXIT (stat_called == true);
247 TEST_VERIFY_EXIT (lstat_called == false);
248
249 return 0;
250 }
251
252 #else /* TEST_COMPAT (libc, GLIBC_2_0, GLIBC_2_27) */
253
254 static int
255 do_test (void)
256 {
257 return 77;
258 }
259 #endif
260
261 #include <support/test-driver.c>