xref: /netbsd-src/tests/lib/libc/gen/t_glob.c (revision cf957f51cbf4427c207359713a6508c6f00f90f7)
1*cf957f51Srillig /*	$NetBSD: t_glob.c,v 1.10 2020/03/13 23:27:54 rillig Exp $	*/
2cc004164Sjruoho /*-
3cc004164Sjruoho  * Copyright (c) 2010 The NetBSD Foundation, Inc.
4cc004164Sjruoho  * All rights reserved.
5cc004164Sjruoho  *
6cc004164Sjruoho  * This code is derived from software contributed to The NetBSD Foundation
7cc004164Sjruoho  * by Christos Zoulas
8cc004164Sjruoho  *
9cc004164Sjruoho  * Redistribution and use in source and binary forms, with or without
10cc004164Sjruoho  * modification, are permitted provided that the following conditions
11cc004164Sjruoho  * are met:
12cc004164Sjruoho  *
13cc004164Sjruoho  * 1. Redistributions of source code must retain the above copyright
14cc004164Sjruoho  *    notice, this list of conditions and the following disclaimer.
15cc004164Sjruoho  * 2. Redistributions in binary form must reproduce the above copyright
16cc004164Sjruoho  *    notice, this list of conditions and the following disclaimer in
17cc004164Sjruoho  *    the documentation and/or other materials provided with the
18cc004164Sjruoho  *    distribution.
19cc004164Sjruoho  *
20cc004164Sjruoho  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21cc004164Sjruoho  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22cc004164Sjruoho  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23cc004164Sjruoho  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
24cc004164Sjruoho  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25cc004164Sjruoho  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
26cc004164Sjruoho  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27cc004164Sjruoho  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28cc004164Sjruoho  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29cc004164Sjruoho  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
30cc004164Sjruoho  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31cc004164Sjruoho  * SUCH DAMAGE.
32cc004164Sjruoho  */
33cc004164Sjruoho 
34cc004164Sjruoho #include <sys/cdefs.h>
35*cf957f51Srillig __RCSID("$NetBSD: t_glob.c,v 1.10 2020/03/13 23:27:54 rillig Exp $");
36cc004164Sjruoho 
37cc004164Sjruoho #include <atf-c.h>
38cc004164Sjruoho 
39cc004164Sjruoho #include <sys/param.h>
40cc004164Sjruoho #include <sys/stat.h>
41cc004164Sjruoho 
42cc004164Sjruoho #include <dirent.h>
43cc004164Sjruoho #include <glob.h>
447bf96131Srillig #include <stdarg.h>
45cc004164Sjruoho #include <stdio.h>
46cc004164Sjruoho #include <stdlib.h>
47cc004164Sjruoho #include <string.h>
48cc004164Sjruoho #include <errno.h>
49cc004164Sjruoho 
50c54cb811Schristos #include "h_macros.h"
51cc004164Sjruoho 
52cc004164Sjruoho 
53cc004164Sjruoho #ifdef DEBUG
54cc004164Sjruoho #define DPRINTF(a) printf a
55cc004164Sjruoho #else
56cc004164Sjruoho #define DPRINTF(a)
57cc004164Sjruoho #endif
58cc004164Sjruoho 
59518b6daeSrillig struct vfs_file {
60*cf957f51Srillig 	char type;		/* 'd' or '-', like in ls(1) */
61cc004164Sjruoho 	const char *name;
62cc004164Sjruoho };
63cc004164Sjruoho 
64518b6daeSrillig static struct vfs_file a[] = {
65*cf957f51Srillig 	{ '-', "1" },
66*cf957f51Srillig 	{ 'd', "b" },
67*cf957f51Srillig 	{ '-', "3" },
68*cf957f51Srillig 	{ '-', "4" },
69cc004164Sjruoho };
70cc004164Sjruoho 
71518b6daeSrillig static struct vfs_file b[] = {
72*cf957f51Srillig 	{ '-', "x" },
73*cf957f51Srillig 	{ '-', "y" },
74*cf957f51Srillig 	{ '-', "z" },
75*cf957f51Srillig 	{ '-', "w" },
76cc004164Sjruoho };
77cc004164Sjruoho 
78afe826aaSrillig static struct vfs_file hidden_dir[] = {
79*cf957f51Srillig 	{ '-', "visible-file" },
80*cf957f51Srillig 	{ '-', ".hidden-file" },
81afe826aaSrillig };
82afe826aaSrillig 
83afe826aaSrillig static struct vfs_file dot[] = {
84*cf957f51Srillig 	{ 'd', "a" },
85*cf957f51Srillig 	{ 'd', ".hidden-dir" },
86afe826aaSrillig };
87afe826aaSrillig 
88518b6daeSrillig struct vfs_dir {
89*cf957f51Srillig 	const char *name;	/* full directory name */
90*cf957f51Srillig 	const struct vfs_file *entries;
91*cf957f51Srillig 	size_t entries_len;
92*cf957f51Srillig 	size_t pos;		/* only between opendir/closedir */
93cc004164Sjruoho };
94cc004164Sjruoho 
95afe826aaSrillig #define VFS_DIR_INIT(name, entries) \
96afe826aaSrillig     { name, entries, __arraycount(entries), 0 }
97afe826aaSrillig 
98518b6daeSrillig static struct vfs_dir d[] = {
99afe826aaSrillig 	VFS_DIR_INIT("a", a),
100afe826aaSrillig 	VFS_DIR_INIT("a/b", b),
101afe826aaSrillig 	VFS_DIR_INIT(".", dot),
102afe826aaSrillig 	VFS_DIR_INIT(".hidden-dir", hidden_dir),
103cc004164Sjruoho };
104cc004164Sjruoho 
105cc004164Sjruoho static void
trim(char * buf,size_t len,const char * name)106cc004164Sjruoho trim(char *buf, size_t len, const char *name)
107cc004164Sjruoho {
108cc004164Sjruoho 	char *path = buf, *epath = buf + len;
109cc004164Sjruoho 	while (path < epath && (*path++ = *name++) != '\0')
110cc004164Sjruoho 		continue;
111cc004164Sjruoho 	path--;
112cc004164Sjruoho 	while (path > buf && *--path == '/')
113cc004164Sjruoho 		*path = '\0';
114cc004164Sjruoho }
115cc004164Sjruoho 
116cc004164Sjruoho static void *
vfs_opendir(const char * dir)117518b6daeSrillig vfs_opendir(const char *dir)
118cc004164Sjruoho {
119cc004164Sjruoho 	size_t i;
120cc004164Sjruoho 	char buf[MAXPATHLEN];
121cc004164Sjruoho 	trim(buf, sizeof(buf), dir);
122cc004164Sjruoho 
123cc004164Sjruoho 	for (i = 0; i < __arraycount(d); i++)
124cc004164Sjruoho 		if (strcmp(buf, d[i].name) == 0) {
125afe826aaSrillig 			DPRINTF(("opendir %s %p\n", buf, &d[i]));
126cc004164Sjruoho 			return &d[i];
127cc004164Sjruoho 		}
128afe826aaSrillig 	DPRINTF(("opendir %s ENOENT\n", buf));
129cc004164Sjruoho 	errno = ENOENT;
130cc004164Sjruoho 	return NULL;
131cc004164Sjruoho }
132cc004164Sjruoho 
133cc004164Sjruoho static struct dirent *
vfs_readdir(void * v)134518b6daeSrillig vfs_readdir(void *v)
135cc004164Sjruoho {
136cc004164Sjruoho 	static struct dirent dir;
137518b6daeSrillig 	struct vfs_dir *dd = v;
138*cf957f51Srillig 	if (dd->pos < dd->entries_len) {
139*cf957f51Srillig 		const struct vfs_file *f = &dd->entries[dd->pos++];
140cc004164Sjruoho 		strcpy(dir.d_name, f->name);
141cc004164Sjruoho 		dir.d_namlen = strlen(f->name);
142cc004164Sjruoho 		dir.d_ino = dd->pos;
143*cf957f51Srillig 		dir.d_type = f->type == 'd' ? DT_DIR : DT_REG;
144cc004164Sjruoho 		DPRINTF(("readdir %s %d\n", dir.d_name, dir.d_type));
145cc004164Sjruoho 		dir.d_reclen = _DIRENT_RECLEN(&dir, dir.d_namlen);
146cc004164Sjruoho 		return &dir;
147cc004164Sjruoho 	}
148cc004164Sjruoho 	return NULL;
149cc004164Sjruoho }
150cc004164Sjruoho 
151cc004164Sjruoho static int
vfs_stat(const char * name,__gl_stat_t * st)152518b6daeSrillig vfs_stat(const char *name , __gl_stat_t *st)
153cc004164Sjruoho {
154cc004164Sjruoho 	char buf[MAXPATHLEN];
155cc004164Sjruoho 	trim(buf, sizeof(buf), name);
156cc004164Sjruoho 	memset(st, 0, sizeof(*st));
1573f1c66c5Schristos 
158afe826aaSrillig 	for (size_t i = 0; i < __arraycount(d); i++)
159afe826aaSrillig 		if (strcmp(buf, d[i].name) == 0) {
160afe826aaSrillig 			st->st_mode = S_IFDIR | 0755;
161afe826aaSrillig 			goto out;
162cc004164Sjruoho 		}
163cc004164Sjruoho 
164afe826aaSrillig 	for (size_t i = 0; i < __arraycount(d); i++) {
165afe826aaSrillig 		size_t dir_len = strlen(d[i].name);
166afe826aaSrillig 		if (strncmp(buf, d[i].name, dir_len) != 0)
167afe826aaSrillig 			continue;
168afe826aaSrillig 		if (buf[dir_len] != '/')
169afe826aaSrillig 			continue;
170afe826aaSrillig 		const char *base = buf + dir_len + 1;
1713f1c66c5Schristos 
172*cf957f51Srillig 		for (size_t j = 0; j < d[i].entries_len; j++) {
173*cf957f51Srillig 			const struct vfs_file *f = &d[i].entries[j];
174*cf957f51Srillig 			if (strcmp(f->name, base) != 0)
175*cf957f51Srillig 				continue;
176*cf957f51Srillig 			ATF_CHECK(f->type != 'd'); // handled above
177*cf957f51Srillig 			st->st_mode = S_IFREG | 0644;
178afe826aaSrillig 			goto out;
1793f1c66c5Schristos 		}
1803f1c66c5Schristos 	}
181afe826aaSrillig 	DPRINTF(("stat %s ENOENT\n", buf));
1823f1c66c5Schristos 	errno = ENOENT;
1833f1c66c5Schristos 	return -1;
184afe826aaSrillig out:
185afe826aaSrillig 	DPRINTF(("stat %s %06o\n", buf, st->st_mode));
186afe826aaSrillig 	return 0;
1873f1c66c5Schristos }
1883f1c66c5Schristos 
189cc004164Sjruoho static int
vfs_lstat(const char * name,__gl_stat_t * st)190518b6daeSrillig vfs_lstat(const char *name , __gl_stat_t *st)
191cc004164Sjruoho {
192518b6daeSrillig 	return vfs_stat(name, st);
193cc004164Sjruoho }
194cc004164Sjruoho 
195cc004164Sjruoho static void
vfs_closedir(void * v)196518b6daeSrillig vfs_closedir(void *v)
197cc004164Sjruoho {
198518b6daeSrillig 	struct vfs_dir *dd = v;
199cc004164Sjruoho 	dd->pos = 0;
200cc004164Sjruoho 	DPRINTF(("closedir %p\n", dd));
201cc004164Sjruoho }
202cc004164Sjruoho 
203cc004164Sjruoho static void
run(const char * p,int flags,...)2047bf96131Srillig run(const char *p, int flags, /* const char *res */ ...)
205cc004164Sjruoho {
206cc004164Sjruoho 	glob_t gl;
207cc004164Sjruoho 	size_t i;
208d30a2b5fSchristos 	int e;
209cc004164Sjruoho 
210d30a2b5fSchristos 	DPRINTF(("pattern %s\n", p));
211cc004164Sjruoho 	memset(&gl, 0, sizeof(gl));
212518b6daeSrillig 	gl.gl_opendir = vfs_opendir;
213518b6daeSrillig 	gl.gl_readdir = vfs_readdir;
214518b6daeSrillig 	gl.gl_closedir = vfs_closedir;
215518b6daeSrillig 	gl.gl_stat = vfs_stat;
216518b6daeSrillig 	gl.gl_lstat = vfs_lstat;
217cc004164Sjruoho 
218d30a2b5fSchristos 	switch ((e = glob(p, GLOB_ALTDIRFUNC | flags, NULL, &gl))) {
219d30a2b5fSchristos 	case 0:
220d30a2b5fSchristos 		break;
221d30a2b5fSchristos 	case GLOB_NOSPACE:
222d30a2b5fSchristos 		fprintf(stderr, "Malloc call failed.\n");
223d30a2b5fSchristos 		goto bad;
224d30a2b5fSchristos 	case GLOB_ABORTED:
225d30a2b5fSchristos 		fprintf(stderr, "Unignored error.\n");
226d30a2b5fSchristos 		goto bad;
227d30a2b5fSchristos 	case GLOB_NOMATCH:
228d30a2b5fSchristos 		fprintf(stderr, "No match, and GLOB_NOCHECK was not set.\n");
229d30a2b5fSchristos 		goto bad;
230d30a2b5fSchristos 	case GLOB_NOSYS:
231d30a2b5fSchristos 		fprintf(stderr, "Implementation does not support function.\n");
232d30a2b5fSchristos 		goto bad;
233d30a2b5fSchristos 	default:
234d30a2b5fSchristos 		fprintf(stderr, "Unknown error %d.\n", e);
235d30a2b5fSchristos 		goto bad;
236d30a2b5fSchristos 	}
237cc004164Sjruoho 
238cc004164Sjruoho 	for (i = 0; i < gl.gl_pathc; i++)
239afe826aaSrillig 		DPRINTF(("glob result %zu: %s\n", i, gl.gl_pathv[i]));
240cc004164Sjruoho 
2417bf96131Srillig 	va_list res;
2427bf96131Srillig 	va_start(res, flags);
243afe826aaSrillig 	i = 0;
244afe826aaSrillig 	const char *name;
245afe826aaSrillig 	while ((name = va_arg(res, const char *)) != NULL && i < gl.gl_pathc) {
246afe826aaSrillig 		ATF_CHECK_STREQ(gl.gl_pathv[i], name);
247afe826aaSrillig 		i++;
248afe826aaSrillig 	}
2497bf96131Srillig 	va_end(res);
250afe826aaSrillig 	ATF_CHECK_EQ_MSG(i, gl.gl_pathc,
251afe826aaSrillig 	    "expected %zu results, got %zu", i, gl.gl_pathc);
252afe826aaSrillig 	ATF_CHECK_EQ_MSG(name, NULL,
253afe826aaSrillig 	    "\"%s\" should have been found, but wasn't", name);
254cc004164Sjruoho 
255cc004164Sjruoho 	globfree(&gl);
256d30a2b5fSchristos 	return;
257d30a2b5fSchristos bad:
258d30a2b5fSchristos 	ATF_REQUIRE_MSG(e == 0, "No match for `%s'", p);
259cc004164Sjruoho }
260cc004164Sjruoho 
2617bf96131Srillig #define run(p, flags, ...) (run)(p, flags, __VA_ARGS__, (const char *) 0)
262cc004164Sjruoho 
263d30a2b5fSchristos ATF_TC(glob_range);
ATF_TC_HEAD(glob_range,tc)264d30a2b5fSchristos ATF_TC_HEAD(glob_range, tc)
265d30a2b5fSchristos {
266d30a2b5fSchristos 	atf_tc_set_md_var(tc, "descr",
267d30a2b5fSchristos 	    "Test glob(3) range");
268d30a2b5fSchristos }
269d30a2b5fSchristos 
ATF_TC_BODY(glob_range,tc)270d30a2b5fSchristos ATF_TC_BODY(glob_range, tc)
271d30a2b5fSchristos {
2727bf96131Srillig 	run("a/b/[x-z]", 0,
2737bf96131Srillig 	    "a/b/x", "a/b/y", "a/b/z");
274d30a2b5fSchristos }
275d30a2b5fSchristos 
276d30a2b5fSchristos ATF_TC(glob_range_not);
ATF_TC_HEAD(glob_range_not,tc)277d30a2b5fSchristos ATF_TC_HEAD(glob_range_not, tc)
278d30a2b5fSchristos {
279d30a2b5fSchristos 	atf_tc_set_md_var(tc, "descr",
280d30a2b5fSchristos 	    "Test glob(3) ! range");
281d30a2b5fSchristos }
282d30a2b5fSchristos 
ATF_TC_BODY(glob_range_not,tc)283d30a2b5fSchristos ATF_TC_BODY(glob_range_not, tc)
284d30a2b5fSchristos {
2857bf96131Srillig 	run("a/b/[!x-z]", 0,
2867bf96131Srillig 	    "a/b/w");
287d30a2b5fSchristos }
288d30a2b5fSchristos 
289cc004164Sjruoho ATF_TC(glob_star);
ATF_TC_HEAD(glob_star,tc)290cc004164Sjruoho ATF_TC_HEAD(glob_star, tc)
291cc004164Sjruoho {
292cc004164Sjruoho 	atf_tc_set_md_var(tc, "descr",
293cc004164Sjruoho 	    "Test glob(3) ** with GLOB_STAR");
294cc004164Sjruoho }
295cc004164Sjruoho 
ATF_TC_BODY(glob_star,tc)296cc004164Sjruoho ATF_TC_BODY(glob_star, tc)
297cc004164Sjruoho {
2987bf96131Srillig 	run("a/**", GLOB_STAR,
2997bf96131Srillig 	    "a/1", "a/3", "a/4", "a/b", "a/b/w", "a/b/x", "a/b/y", "a/b/z");
300cc004164Sjruoho }
301cc004164Sjruoho 
302cc004164Sjruoho ATF_TC(glob_star_not);
ATF_TC_HEAD(glob_star_not,tc)303cc004164Sjruoho ATF_TC_HEAD(glob_star_not, tc)
304cc004164Sjruoho {
305cc004164Sjruoho 	atf_tc_set_md_var(tc, "descr",
306cc004164Sjruoho 	    "Test glob(3) ** without GLOB_STAR");
307cc004164Sjruoho }
308cc004164Sjruoho 
ATF_TC_BODY(glob_star_not,tc)309cc004164Sjruoho ATF_TC_BODY(glob_star_not, tc)
310cc004164Sjruoho {
3117bf96131Srillig 	run("a/**", 0,
3127bf96131Srillig 	    "a/1", "a/3", "a/4", "a/b");
313cc004164Sjruoho }
314cc004164Sjruoho 
315afe826aaSrillig ATF_TC(glob_star_star);
ATF_TC_HEAD(glob_star_star,tc)316afe826aaSrillig ATF_TC_HEAD(glob_star_star, tc)
317afe826aaSrillig {
318afe826aaSrillig 	atf_tc_set_md_var(tc, "descr",
319afe826aaSrillig 	    "Test glob(3) with star-star");
320afe826aaSrillig }
321afe826aaSrillig 
ATF_TC_BODY(glob_star_star,tc)322afe826aaSrillig ATF_TC_BODY(glob_star_star, tc)
323afe826aaSrillig {
324afe826aaSrillig 	run("**", GLOB_STAR,
325afe826aaSrillig 	    "a",
326afe826aaSrillig 	    "a/1", "a/3", "a/4", "a/b",
327afe826aaSrillig 	    "a/b/w", "a/b/x", "a/b/y", "a/b/z");
328afe826aaSrillig }
329afe826aaSrillig 
330afe826aaSrillig ATF_TC(glob_hidden);
ATF_TC_HEAD(glob_hidden,tc)331afe826aaSrillig ATF_TC_HEAD(glob_hidden, tc)
332afe826aaSrillig {
333afe826aaSrillig 	atf_tc_set_md_var(tc, "descr",
334afe826aaSrillig 	    "Test glob(3) with hidden directory");
335afe826aaSrillig }
336afe826aaSrillig 
ATF_TC_BODY(glob_hidden,tc)337afe826aaSrillig ATF_TC_BODY(glob_hidden, tc)
338afe826aaSrillig {
339afe826aaSrillig 	run(".**", GLOB_STAR,
340afe826aaSrillig 	    ".hidden-dir",
341afe826aaSrillig 	    ".hidden-dir/visible-file");
342afe826aaSrillig }
343afe826aaSrillig 
344236eac06Smartin #if 0
3453f1c66c5Schristos ATF_TC(glob_nocheck);
3463f1c66c5Schristos ATF_TC_HEAD(glob_nocheck, tc)
3473f1c66c5Schristos {
3483f1c66c5Schristos 	atf_tc_set_md_var(tc, "descr",
3493f1c66c5Schristos 	    "Test glob(3) pattern with backslash and GLOB_NOCHECK");
3503f1c66c5Schristos }
3513f1c66c5Schristos 
3523f1c66c5Schristos 
3533f1c66c5Schristos ATF_TC_BODY(glob_nocheck, tc)
3543f1c66c5Schristos {
3553f1c66c5Schristos 	static const char pattern[] = { 'f', 'o', 'o', '\\', ';', 'b', 'a',
3563f1c66c5Schristos 	    'r', '\0' };
3573f1c66c5Schristos 	static const char *glob_nocheck[] = {
3583f1c66c5Schristos 	    pattern
3593f1c66c5Schristos 	};
3603f1c66c5Schristos 	run(pattern, GLOB_NOCHECK, glob_nocheck, __arraycount(glob_nocheck));
3613f1c66c5Schristos }
362236eac06Smartin #endif
3633f1c66c5Schristos 
ATF_TP_ADD_TCS(tp)364cc004164Sjruoho ATF_TP_ADD_TCS(tp)
365cc004164Sjruoho {
366cc004164Sjruoho 	ATF_TP_ADD_TC(tp, glob_star);
367cc004164Sjruoho 	ATF_TP_ADD_TC(tp, glob_star_not);
368d30a2b5fSchristos 	ATF_TP_ADD_TC(tp, glob_range);
369d30a2b5fSchristos 	ATF_TP_ADD_TC(tp, glob_range_not);
370afe826aaSrillig 	ATF_TP_ADD_TC(tp, glob_star_star);
371afe826aaSrillig 	ATF_TP_ADD_TC(tp, glob_hidden);
372236eac06Smartin /*
373236eac06Smartin  * Remove this test for now - the GLOB_NOCHECK return value has been
374236eac06Smartin  * re-defined to return a modified pattern in revision 1.33 of glob.c
375236eac06Smartin  *
376236eac06Smartin  *	ATF_TP_ADD_TC(tp, glob_nocheck);
377236eac06Smartin  */
378cc004164Sjruoho 
379cc004164Sjruoho 	return atf_no_error();
380cc004164Sjruoho }
381