hurd: Avoid PLTs for longjmp & siglongjmp
[glibc.git] / posix / tst-glob_lstat_compat.c
blob22cd1f02f96d5d118c3750cae96932b9f127daeb
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.
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.
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.
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/>. */
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>
29 #include <stdio.h>
31 #include <shlib-compat.h>
32 #include <support/check.h>
33 #include <support/temp_file.h>
35 #if TEST_COMPAT (libc, GLIBC_2_0, GLIBC_2_27)
37 __typeof (glob) glob;
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__
42 compat_symbol_reference (libc, glob, glob, GLIBC_2_1);
43 # else
44 compat_symbol_reference (libc, glob, glob, GLIBC_2_0);
45 # endif
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. */
50 static bool stat_called;
51 static bool lstat_called;
53 static struct
55 const char *name;
56 int level;
57 int type;
58 } filesystem[] =
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 },
68 static const size_t nfiles = sizeof (filesystem) / sizeof (filesystem [0]);
70 typedef struct
72 int level;
73 int idx;
74 struct dirent d;
75 char room_for_dirent[NAME_MAX];
76 } my_DIR;
78 static long int
79 find_file (const char *s)
81 int level = 1;
82 long int idx = 0;
84 while (s[0] == '/')
86 if (s[1] == '\0')
88 s = ".";
89 break;
91 ++s;
94 if (strcmp (s, ".") == 0)
95 return 0;
97 if (s[0] == '.' && s[1] == '/')
98 s += 2;
100 while (*s != '\0')
102 char *endp = strchrnul (s, '/');
104 while (idx < nfiles && filesystem[idx].level >= level)
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;
113 if (idx == nfiles || filesystem[idx].level < level)
115 errno = ENOENT;
116 return -1;
119 if (*endp == '\0')
120 return idx + 1;
122 if (filesystem[idx].type != DT_DIR
123 && (idx + 1 >= nfiles
124 || filesystem[idx].level >= filesystem[idx + 1].level))
126 errno = ENOTDIR;
127 return -1;
130 ++idx;
132 s = endp + 1;
133 ++level;
136 errno = ENOENT;
137 return -1;
140 static void *
141 my_opendir (const char *s)
143 long int idx = find_file (s);
144 if (idx == -1 || filesystem[idx].type != DT_DIR)
145 return NULL;
147 my_DIR *dir = malloc (sizeof (my_DIR));
148 if (dir == NULL)
149 FAIL_EXIT1 ("cannot allocate directory handle");
151 dir->level = filesystem[idx].level;
152 dir->idx = idx;
154 return dir;
157 static struct dirent *
158 my_readdir (void *gdir)
160 my_DIR *dir = gdir;
162 if (dir->idx == -1)
163 return NULL;
165 while (dir->idx < nfiles && filesystem[dir->idx].level > dir->level)
166 ++dir->idx;
168 if (dir->idx == nfiles || filesystem[dir->idx].level < dir->level)
170 dir->idx = -1;
171 return NULL;
174 dir->d.d_ino = 1; /* glob should not skip this entry. */
176 dir->d.d_type = filesystem[dir->idx].type;
178 strcpy (dir->d.d_name, filesystem[dir->idx].name);
180 ++dir->idx;
182 return &dir->d;
185 static void
186 my_closedir (void *dir)
188 free (dir);
191 static int
192 my_stat (const char *name, struct stat *st)
194 stat_called = true;
196 long int idx = find_file (name);
197 if (idx == -1)
198 return -1;
200 memset (st, '\0', sizeof (*st));
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;
211 static int
212 my_lstat (const char *name, struct stat *st)
214 lstat_called = true;
216 long int idx = find_file (name);
217 if (idx == -1)
218 return -1;
220 memset (st, '\0', sizeof (*st));
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;
231 static int
232 do_test (void)
234 glob_t gl;
236 memset (&gl, '\0', sizeof (gl));
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;
244 int flags = GLOB_ALTDIRFUNC;
246 stat_called = false;
247 lstat_called = false;
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);
253 TEST_VERIFY_EXIT (stat_called == true);
254 TEST_VERIFY_EXIT (lstat_called == false);
256 return 0;
259 #else /* TEST_COMPAT (libc, GLIBC_2_0, GLIBC_2_27) */
261 static int
262 do_test (void)
264 return 77;
266 #endif
268 #include <support/test-driver.c>