Simplify C99 isgreater macros
[glibc.git] / posix / tst-glob_lstat_compat.c
blobccfda4bb742fe5df70d6e26ad86af3ae7510bb0f
1 /* Test glob compat symbol which avoid call GLOB_ALTDIRFUNC/gl_lstat.
2 Copyright (C) 2017 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 #ifdef _DIRENT_HAVE_D_TYPE
170 dir->d.d_type = filesystem[dir->idx].type;
171 #endif
173 strcpy (dir->d.d_name, filesystem[dir->idx].name);
175 ++dir->idx;
177 return &dir->d;
180 static void
181 my_closedir (void *dir)
183 free (dir);
186 static int
187 my_stat (const char *name, struct stat *st)
189 stat_called = true;
191 long int idx = find_file (name);
192 if (idx == -1)
193 return -1;
195 memset (st, '\0', sizeof (*st));
197 if (filesystem[idx].type == DT_UNKNOWN)
198 st->st_mode = DTTOIF (idx + 1 < nfiles
199 && filesystem[idx].level < filesystem[idx + 1].level
200 ? DT_DIR : DT_REG) | 0777;
201 else
202 st->st_mode = DTTOIF (filesystem[idx].type) | 0777;
203 return 0;
206 static int
207 my_lstat (const char *name, struct stat *st)
209 lstat_called = true;
211 long int idx = find_file (name);
212 if (idx == -1)
213 return -1;
215 memset (st, '\0', sizeof (*st));
217 if (filesystem[idx].type == DT_UNKNOWN)
218 st->st_mode = DTTOIF (idx + 1 < nfiles
219 && filesystem[idx].level < filesystem[idx + 1].level
220 ? DT_DIR : DT_REG) | 0777;
221 else
222 st->st_mode = DTTOIF (filesystem[idx].type) | 0777;
223 return 0;
226 static int
227 do_test (void)
229 glob_t gl;
231 memset (&gl, '\0', sizeof (gl));
233 gl.gl_closedir = my_closedir;
234 gl.gl_readdir = my_readdir;
235 gl.gl_opendir = my_opendir;
236 gl.gl_lstat = my_lstat;
237 gl.gl_stat = my_stat;
239 int flags = GLOB_ALTDIRFUNC;
241 stat_called = false;
242 lstat_called = false;
244 TEST_VERIFY_EXIT (glob ("*/file1lev2", flags, NULL, &gl) == 0);
245 TEST_VERIFY_EXIT (gl.gl_pathc == 1);
246 TEST_VERIFY_EXIT (strcmp (gl.gl_pathv[0], "dir1lev1/file1lev2") == 0);
248 TEST_VERIFY_EXIT (stat_called == true);
249 TEST_VERIFY_EXIT (lstat_called == false);
251 return 0;
254 #else /* TEST_COMPAT (libc, GLIBC_2_0, GLIBC_2_27) */
256 static int
257 do_test (void)
259 return 77;
261 #endif
263 #include <support/test-driver.c>