Update miscellaneous files from upstream sources.
[glibc.git] / posix / tst-glob_lstat_compat.c
blobc46bc9e57834863d04ef74da495bdfe6bf2b149c
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 compat_symbol_reference (libc, glob, glob, GLIBC_2_0);
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;
46 static struct
48 const char *name;
49 int level;
50 int type;
51 } filesystem[] =
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 },
61 static const size_t nfiles = sizeof (filesystem) / sizeof (filesystem [0]);
63 typedef struct
65 int level;
66 int idx;
67 struct dirent d;
68 char room_for_dirent[NAME_MAX];
69 } my_DIR;
71 static long int
72 find_file (const char *s)
74 int level = 1;
75 long int idx = 0;
77 while (s[0] == '/')
79 if (s[1] == '\0')
81 s = ".";
82 break;
84 ++s;
87 if (strcmp (s, ".") == 0)
88 return 0;
90 if (s[0] == '.' && s[1] == '/')
91 s += 2;
93 while (*s != '\0')
95 char *endp = strchrnul (s, '/');
97 while (idx < nfiles && filesystem[idx].level >= level)
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;
106 if (idx == nfiles || filesystem[idx].level < level)
108 errno = ENOENT;
109 return -1;
112 if (*endp == '\0')
113 return idx + 1;
115 if (filesystem[idx].type != DT_DIR
116 && (idx + 1 >= nfiles
117 || filesystem[idx].level >= filesystem[idx + 1].level))
119 errno = ENOTDIR;
120 return -1;
123 ++idx;
125 s = endp + 1;
126 ++level;
129 errno = ENOENT;
130 return -1;
133 static void *
134 my_opendir (const char *s)
136 long int idx = find_file (s);
137 if (idx == -1 || filesystem[idx].type != DT_DIR)
138 return NULL;
140 my_DIR *dir = malloc (sizeof (my_DIR));
141 if (dir == NULL)
142 FAIL_EXIT1 ("cannot allocate directory handle");
144 dir->level = filesystem[idx].level;
145 dir->idx = idx;
147 return dir;
150 static struct dirent *
151 my_readdir (void *gdir)
153 my_DIR *dir = gdir;
155 if (dir->idx == -1)
156 return NULL;
158 while (dir->idx < nfiles && filesystem[dir->idx].level > dir->level)
159 ++dir->idx;
161 if (dir->idx == nfiles || filesystem[dir->idx].level < dir->level)
163 dir->idx = -1;
164 return NULL;
167 dir->d.d_ino = 1; /* glob should not skip this entry. */
169 dir->d.d_type = filesystem[dir->idx].type;
171 strcpy (dir->d.d_name, filesystem[dir->idx].name);
173 ++dir->idx;
175 return &dir->d;
178 static void
179 my_closedir (void *dir)
181 free (dir);
184 static int
185 my_stat (const char *name, struct stat *st)
187 stat_called = true;
189 long int idx = find_file (name);
190 if (idx == -1)
191 return -1;
193 memset (st, '\0', sizeof (*st));
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;
204 static int
205 my_lstat (const char *name, struct stat *st)
207 lstat_called = true;
209 long int idx = find_file (name);
210 if (idx == -1)
211 return -1;
213 memset (st, '\0', sizeof (*st));
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;
224 static int
225 do_test (void)
227 glob_t gl;
229 memset (&gl, '\0', sizeof (gl));
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;
237 int flags = GLOB_ALTDIRFUNC;
239 stat_called = false;
240 lstat_called = false;
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);
246 TEST_VERIFY_EXIT (stat_called == true);
247 TEST_VERIFY_EXIT (lstat_called == false);
249 return 0;
252 #else /* TEST_COMPAT (libc, GLIBC_2_0, GLIBC_2_27) */
254 static int
255 do_test (void)
257 return 77;
259 #endif
261 #include <support/test-driver.c>