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