1314817Sngie/*	$NetBSD: t_glob.c,v 1.5 2017/01/14 20:47:41 christos Exp $	*/
2272343Sngie/*-
3272343Sngie * Copyright (c) 2010 The NetBSD Foundation, Inc.
4272343Sngie * All rights reserved.
5272343Sngie *
6272343Sngie * This code is derived from software contributed to The NetBSD Foundation
7272343Sngie * by Christos Zoulas
8272343Sngie *
9272343Sngie * Redistribution and use in source and binary forms, with or without
10272343Sngie * modification, are permitted provided that the following conditions
11272343Sngie * are met:
12272343Sngie *
13272343Sngie * 1. Redistributions of source code must retain the above copyright
14272343Sngie *    notice, this list of conditions and the following disclaimer.
15272343Sngie * 2. Redistributions in binary form must reproduce the above copyright
16272343Sngie *    notice, this list of conditions and the following disclaimer in
17272343Sngie *    the documentation and/or other materials provided with the
18272343Sngie *    distribution.
19272343Sngie *
20272343Sngie * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21272343Sngie * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22272343Sngie * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23272343Sngie * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
24272343Sngie * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25272343Sngie * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
26272343Sngie * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27272343Sngie * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28272343Sngie * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29272343Sngie * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
30272343Sngie * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31272343Sngie * SUCH DAMAGE.
32272343Sngie */
33272343Sngie
34272343Sngie#include <sys/cdefs.h>
35314817Sngie__RCSID("$NetBSD: t_glob.c,v 1.5 2017/01/14 20:47:41 christos Exp $");
36272343Sngie
37272343Sngie#include <atf-c.h>
38272343Sngie
39272343Sngie#include <sys/param.h>
40272343Sngie#include <sys/stat.h>
41272343Sngie
42272343Sngie#include <dirent.h>
43272343Sngie#include <glob.h>
44272343Sngie#include <stdio.h>
45272343Sngie#include <stdlib.h>
46272343Sngie#include <string.h>
47272343Sngie#include <errno.h>
48272343Sngie
49276478Sngie#include "h_macros.h"
50272343Sngie
51272343Sngie
52272343Sngie#ifdef DEBUG
53272343Sngie#define DPRINTF(a) printf a
54272343Sngie#else
55272343Sngie#define DPRINTF(a)
56272343Sngie#endif
57272343Sngie
58272343Sngiestruct gl_file {
59272343Sngie	const char *name;
60272343Sngie	int dir;
61272343Sngie};
62272343Sngie
63272343Sngiestatic struct gl_file a[] = {
64272343Sngie	{ "1", 0 },
65272343Sngie	{ "b", 1 },
66272343Sngie	{ "3", 0 },
67272343Sngie	{ "4", 0 },
68272343Sngie};
69272343Sngie
70272343Sngiestatic struct gl_file b[] = {
71272343Sngie	{ "x", 0 },
72272343Sngie	{ "y", 0 },
73272343Sngie	{ "z", 0 },
74272343Sngie	{ "w", 0 },
75272343Sngie};
76272343Sngie
77272343Sngiestruct gl_dir {
78272343Sngie	const char *name;	/* directory name */
79272343Sngie	const struct gl_file *dir;
80272343Sngie	size_t len, pos;
81272343Sngie};
82272343Sngie
83272343Sngiestatic struct gl_dir d[] = {
84272343Sngie	{ "a", a, __arraycount(a), 0 },
85272343Sngie	{ "a/b", b, __arraycount(b), 0 },
86272343Sngie};
87272343Sngie
88314817Sngie#ifdef GLOB_STAR
89272343Sngiestatic const char *glob_star[] = {
90272343Sngie    "a/1", "a/3", "a/4", "a/b", "a/b/w", "a/b/x", "a/b/y", "a/b/z",
91272343Sngie};
92291044Sngie#endif
93272343Sngie
94272343Sngiestatic const char *glob_star_not[] = {
95272343Sngie	"a/1", "a/3", "a/4", "a/b",
96272343Sngie};
97272343Sngie
98272343Sngiestatic void
99272343Sngietrim(char *buf, size_t len, const char *name)
100272343Sngie{
101272343Sngie	char *path = buf, *epath = buf + len;
102272343Sngie	while (path < epath && (*path++ = *name++) != '\0')
103272343Sngie		continue;
104272343Sngie	path--;
105272343Sngie	while (path > buf && *--path == '/')
106272343Sngie		*path = '\0';
107272343Sngie}
108272343Sngie
109272343Sngiestatic void *
110272343Sngiegl_opendir(const char *dir)
111272343Sngie{
112272343Sngie	size_t i;
113272343Sngie	char buf[MAXPATHLEN];
114272343Sngie	trim(buf, sizeof(buf), dir);
115272343Sngie
116272343Sngie	for (i = 0; i < __arraycount(d); i++)
117272343Sngie		if (strcmp(buf, d[i].name) == 0) {
118272343Sngie			DPRINTF(("opendir %s %zu\n", buf, i));
119272343Sngie			return &d[i];
120272343Sngie		}
121272343Sngie	errno = ENOENT;
122272343Sngie	return NULL;
123272343Sngie}
124272343Sngie
125272343Sngiestatic struct dirent *
126272343Sngiegl_readdir(void *v)
127272343Sngie{
128272343Sngie	static struct dirent dir;
129272343Sngie	struct gl_dir *dd = v;
130272343Sngie	if (dd->pos < dd->len) {
131272343Sngie		const struct gl_file *f = &dd->dir[dd->pos++];
132272343Sngie		strcpy(dir.d_name, f->name);
133272343Sngie		dir.d_namlen = strlen(f->name);
134272343Sngie		dir.d_ino = dd->pos;
135272343Sngie		dir.d_type = f->dir ? DT_DIR : DT_REG;
136272343Sngie		DPRINTF(("readdir %s %d\n", dir.d_name, dir.d_type));
137276478Sngie#ifdef __FreeBSD__
138276478Sngie		dir.d_reclen = -1; /* Does not have _DIRENT_RECLEN */
139276478Sngie#else
140272343Sngie		dir.d_reclen = _DIRENT_RECLEN(&dir, dir.d_namlen);
141276478Sngie#endif
142272343Sngie		return &dir;
143272343Sngie	}
144272343Sngie	return NULL;
145272343Sngie}
146272343Sngie
147272343Sngiestatic int
148272343Sngiegl_stat(const char *name , __gl_stat_t *st)
149272343Sngie{
150272343Sngie	char buf[MAXPATHLEN];
151272343Sngie	trim(buf, sizeof(buf), name);
152272343Sngie	memset(st, 0, sizeof(*st));
153272343Sngie
154272343Sngie	if (strcmp(buf, "a") == 0 || strcmp(buf, "a/b") == 0) {
155314817Sngie		st->st_mode |= S_IFDIR;
156272343Sngie		return 0;
157272343Sngie	}
158272343Sngie
159272343Sngie	if (buf[0] == 'a' && buf[1] == '/') {
160272343Sngie		struct gl_file *f;
161272343Sngie		size_t offs, count;
162272343Sngie
163272343Sngie		if (buf[2] == 'b' && buf[3] == '/') {
164272343Sngie			offs = 4;
165272343Sngie			count = __arraycount(b);
166272343Sngie			f = b;
167272343Sngie		} else {
168272343Sngie			offs = 2;
169272343Sngie			count = __arraycount(a);
170272343Sngie			f = a;
171272343Sngie		}
172272343Sngie
173272343Sngie		for (size_t i = 0; i < count; i++)
174272343Sngie			if (strcmp(f[i].name, buf + offs) == 0)
175272343Sngie				return 0;
176272343Sngie	}
177272343Sngie	DPRINTF(("stat %s %d\n", buf, st->st_mode));
178272343Sngie	errno = ENOENT;
179272343Sngie	return -1;
180272343Sngie}
181272343Sngie
182272343Sngiestatic int
183272343Sngiegl_lstat(const char *name , __gl_stat_t *st)
184272343Sngie{
185272343Sngie	return gl_stat(name, st);
186272343Sngie}
187272343Sngie
188272343Sngiestatic void
189272343Sngiegl_closedir(void *v)
190272343Sngie{
191272343Sngie	struct gl_dir *dd = v;
192272343Sngie	dd->pos = 0;
193272343Sngie	DPRINTF(("closedir %p\n", dd));
194272343Sngie}
195272343Sngie
196272343Sngiestatic void
197272343Sngierun(const char *p, int flags, const char **res, size_t len)
198272343Sngie{
199272343Sngie	glob_t gl;
200272343Sngie	size_t i;
201272343Sngie
202272343Sngie	memset(&gl, 0, sizeof(gl));
203272343Sngie	gl.gl_opendir = gl_opendir;
204272343Sngie	gl.gl_readdir = gl_readdir;
205272343Sngie	gl.gl_closedir = gl_closedir;
206272343Sngie	gl.gl_stat = gl_stat;
207272343Sngie	gl.gl_lstat = gl_lstat;
208272343Sngie
209272343Sngie	RZ(glob(p, GLOB_ALTDIRFUNC | flags, NULL, &gl));
210272343Sngie
211272343Sngie	for (i = 0; i < gl.gl_pathc; i++)
212272343Sngie		DPRINTF(("%s\n", gl.gl_pathv[i]));
213272343Sngie
214272343Sngie	ATF_CHECK(len == gl.gl_pathc);
215272343Sngie	for (i = 0; i < gl.gl_pathc; i++)
216272343Sngie		ATF_CHECK_STREQ(gl.gl_pathv[i], res[i]);
217272343Sngie
218272343Sngie	globfree(&gl);
219272343Sngie}
220272343Sngie
221272343Sngie
222314817Sngie#ifdef GLOB_STAR
223272343SngieATF_TC(glob_star);
224272343SngieATF_TC_HEAD(glob_star, tc)
225272343Sngie{
226272343Sngie	atf_tc_set_md_var(tc, "descr",
227272343Sngie	    "Test glob(3) ** with GLOB_STAR");
228272343Sngie}
229272343Sngie
230272343SngieATF_TC_BODY(glob_star, tc)
231272343Sngie{
232272343Sngie	run("a/**", GLOB_STAR, glob_star, __arraycount(glob_star));
233272343Sngie}
234276478Sngie#endif
235272343Sngie
236272343SngieATF_TC(glob_star_not);
237272343SngieATF_TC_HEAD(glob_star_not, tc)
238272343Sngie{
239272343Sngie	atf_tc_set_md_var(tc, "descr",
240272343Sngie	    "Test glob(3) ** without GLOB_STAR");
241272343Sngie}
242272343Sngie
243272343Sngie
244272343SngieATF_TC_BODY(glob_star_not, tc)
245272343Sngie{
246272343Sngie	run("a/**", 0, glob_star_not, __arraycount(glob_star_not));
247272343Sngie}
248272343Sngie
249272343Sngie#if 0
250272343SngieATF_TC(glob_nocheck);
251272343SngieATF_TC_HEAD(glob_nocheck, tc)
252272343Sngie{
253272343Sngie	atf_tc_set_md_var(tc, "descr",
254272343Sngie	    "Test glob(3) pattern with backslash and GLOB_NOCHECK");
255272343Sngie}
256272343Sngie
257272343Sngie
258272343SngieATF_TC_BODY(glob_nocheck, tc)
259272343Sngie{
260272343Sngie	static const char pattern[] = { 'f', 'o', 'o', '\\', ';', 'b', 'a',
261272343Sngie	    'r', '\0' };
262272343Sngie	static const char *glob_nocheck[] = {
263272343Sngie	    pattern
264272343Sngie	};
265272343Sngie	run(pattern, GLOB_NOCHECK, glob_nocheck, __arraycount(glob_nocheck));
266272343Sngie}
267272343Sngie#endif
268272343Sngie
269272343SngieATF_TP_ADD_TCS(tp)
270272343Sngie{
271314817Sngie#ifdef GLOB_STAR
272272343Sngie	ATF_TP_ADD_TC(tp, glob_star);
273276478Sngie#endif
274272343Sngie	ATF_TP_ADD_TC(tp, glob_star_not);
275272343Sngie/*
276272343Sngie * Remove this test for now - the GLOB_NOCHECK return value has been
277272343Sngie * re-defined to return a modified pattern in revision 1.33 of glob.c
278272343Sngie *
279272343Sngie *	ATF_TP_ADD_TC(tp, glob_nocheck);
280272343Sngie */
281272343Sngie
282272343Sngie	return atf_no_error();
283272343Sngie}
284