1272343Sngie/* $NetBSD: t_glob.c,v 1.3 2013/01/02 11:28:48 martin 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> 35272343Sngie__RCSID("$NetBSD: t_glob.c,v 1.3 2013/01/02 11:28:48 martin 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 49274626Sngie#ifdef __FreeBSD__ 50272915Sngie#include "h_macros.h" 51272915Sngie#define __gl_stat_t struct stat 52272915Sngie#define _S_IFDIR S_IFDIR 53272915Sngie#else 54272343Sngie#include "../../../h_macros.h" 55272915Sngie#endif 56272343Sngie 57272343Sngie 58272343Sngie#ifdef DEBUG 59272343Sngie#define DPRINTF(a) printf a 60272343Sngie#else 61272343Sngie#define DPRINTF(a) 62272343Sngie#endif 63272343Sngie 64272343Sngiestruct gl_file { 65272343Sngie const char *name; 66272343Sngie int dir; 67272343Sngie}; 68272343Sngie 69272343Sngiestatic struct gl_file a[] = { 70272343Sngie { "1", 0 }, 71272343Sngie { "b", 1 }, 72272343Sngie { "3", 0 }, 73272343Sngie { "4", 0 }, 74272343Sngie}; 75272343Sngie 76272343Sngiestatic struct gl_file b[] = { 77272343Sngie { "x", 0 }, 78272343Sngie { "y", 0 }, 79272343Sngie { "z", 0 }, 80272343Sngie { "w", 0 }, 81272343Sngie}; 82272343Sngie 83272343Sngiestruct gl_dir { 84272343Sngie const char *name; /* directory name */ 85272343Sngie const struct gl_file *dir; 86272343Sngie size_t len, pos; 87272343Sngie}; 88272343Sngie 89272343Sngiestatic struct gl_dir d[] = { 90272343Sngie { "a", a, __arraycount(a), 0 }, 91272343Sngie { "a/b", b, __arraycount(b), 0 }, 92272343Sngie}; 93272343Sngie 94290847Sngie#ifndef __FreeBSD__ 95272343Sngiestatic const char *glob_star[] = { 96272343Sngie "a/1", "a/3", "a/4", "a/b", "a/b/w", "a/b/x", "a/b/y", "a/b/z", 97272343Sngie}; 98290847Sngie#endif 99272343Sngie 100272343Sngiestatic const char *glob_star_not[] = { 101272343Sngie "a/1", "a/3", "a/4", "a/b", 102272343Sngie}; 103272343Sngie 104272343Sngiestatic void 105272343Sngietrim(char *buf, size_t len, const char *name) 106272343Sngie{ 107272343Sngie char *path = buf, *epath = buf + len; 108272343Sngie while (path < epath && (*path++ = *name++) != '\0') 109272343Sngie continue; 110272343Sngie path--; 111272343Sngie while (path > buf && *--path == '/') 112272343Sngie *path = '\0'; 113272343Sngie} 114272343Sngie 115272343Sngiestatic void * 116272343Sngiegl_opendir(const char *dir) 117272343Sngie{ 118272343Sngie size_t i; 119272343Sngie char buf[MAXPATHLEN]; 120272343Sngie trim(buf, sizeof(buf), dir); 121272343Sngie 122272343Sngie for (i = 0; i < __arraycount(d); i++) 123272343Sngie if (strcmp(buf, d[i].name) == 0) { 124272343Sngie DPRINTF(("opendir %s %zu\n", buf, i)); 125272343Sngie return &d[i]; 126272343Sngie } 127272343Sngie errno = ENOENT; 128272343Sngie return NULL; 129272343Sngie} 130272343Sngie 131272343Sngiestatic struct dirent * 132272343Sngiegl_readdir(void *v) 133272343Sngie{ 134272343Sngie static struct dirent dir; 135272343Sngie struct gl_dir *dd = v; 136272343Sngie if (dd->pos < dd->len) { 137272343Sngie const struct gl_file *f = &dd->dir[dd->pos++]; 138272343Sngie strcpy(dir.d_name, f->name); 139272343Sngie dir.d_namlen = strlen(f->name); 140272343Sngie dir.d_ino = dd->pos; 141272343Sngie dir.d_type = f->dir ? DT_DIR : DT_REG; 142272343Sngie DPRINTF(("readdir %s %d\n", dir.d_name, dir.d_type)); 143274626Sngie#ifdef __FreeBSD__ 144272915Sngie dir.d_reclen = -1; /* Does not have _DIRENT_RECLEN */ 145272915Sngie#else 146272343Sngie dir.d_reclen = _DIRENT_RECLEN(&dir, dir.d_namlen); 147272915Sngie#endif 148272343Sngie return &dir; 149272343Sngie } 150272343Sngie return NULL; 151272343Sngie} 152272343Sngie 153272343Sngiestatic int 154272343Sngiegl_stat(const char *name , __gl_stat_t *st) 155272343Sngie{ 156272343Sngie char buf[MAXPATHLEN]; 157272343Sngie trim(buf, sizeof(buf), name); 158272343Sngie memset(st, 0, sizeof(*st)); 159272343Sngie 160272343Sngie if (strcmp(buf, "a") == 0 || strcmp(buf, "a/b") == 0) { 161272343Sngie st->st_mode |= _S_IFDIR; 162272343Sngie return 0; 163272343Sngie } 164272343Sngie 165272343Sngie if (buf[0] == 'a' && buf[1] == '/') { 166272343Sngie struct gl_file *f; 167272343Sngie size_t offs, count; 168272343Sngie 169272343Sngie if (buf[2] == 'b' && buf[3] == '/') { 170272343Sngie offs = 4; 171272343Sngie count = __arraycount(b); 172272343Sngie f = b; 173272343Sngie } else { 174272343Sngie offs = 2; 175272343Sngie count = __arraycount(a); 176272343Sngie f = a; 177272343Sngie } 178272343Sngie 179272343Sngie for (size_t i = 0; i < count; i++) 180272343Sngie if (strcmp(f[i].name, buf + offs) == 0) 181272343Sngie return 0; 182272343Sngie } 183272343Sngie DPRINTF(("stat %s %d\n", buf, st->st_mode)); 184272343Sngie errno = ENOENT; 185272343Sngie return -1; 186272343Sngie} 187272343Sngie 188272343Sngiestatic int 189272343Sngiegl_lstat(const char *name , __gl_stat_t *st) 190272343Sngie{ 191272343Sngie return gl_stat(name, st); 192272343Sngie} 193272343Sngie 194272343Sngiestatic void 195272343Sngiegl_closedir(void *v) 196272343Sngie{ 197272343Sngie struct gl_dir *dd = v; 198272343Sngie dd->pos = 0; 199272343Sngie DPRINTF(("closedir %p\n", dd)); 200272343Sngie} 201272343Sngie 202272343Sngiestatic void 203272343Sngierun(const char *p, int flags, const char **res, size_t len) 204272343Sngie{ 205272343Sngie glob_t gl; 206272343Sngie size_t i; 207272343Sngie 208272343Sngie memset(&gl, 0, sizeof(gl)); 209272343Sngie gl.gl_opendir = gl_opendir; 210272343Sngie gl.gl_readdir = gl_readdir; 211272343Sngie gl.gl_closedir = gl_closedir; 212272343Sngie gl.gl_stat = gl_stat; 213272343Sngie gl.gl_lstat = gl_lstat; 214272343Sngie 215272343Sngie RZ(glob(p, GLOB_ALTDIRFUNC | flags, NULL, &gl)); 216272343Sngie 217272343Sngie for (i = 0; i < gl.gl_pathc; i++) 218272343Sngie DPRINTF(("%s\n", gl.gl_pathv[i])); 219272343Sngie 220272343Sngie ATF_CHECK(len == gl.gl_pathc); 221272343Sngie for (i = 0; i < gl.gl_pathc; i++) 222272343Sngie ATF_CHECK_STREQ(gl.gl_pathv[i], res[i]); 223272343Sngie 224272343Sngie globfree(&gl); 225272343Sngie} 226272343Sngie 227272343Sngie 228274626Sngie#ifndef __FreeBSD__ 229272343SngieATF_TC(glob_star); 230272343SngieATF_TC_HEAD(glob_star, tc) 231272343Sngie{ 232272343Sngie atf_tc_set_md_var(tc, "descr", 233272343Sngie "Test glob(3) ** with GLOB_STAR"); 234272343Sngie} 235272343Sngie 236272343SngieATF_TC_BODY(glob_star, tc) 237272343Sngie{ 238272343Sngie run("a/**", GLOB_STAR, glob_star, __arraycount(glob_star)); 239272343Sngie} 240272915Sngie#endif 241272343Sngie 242272343SngieATF_TC(glob_star_not); 243272343SngieATF_TC_HEAD(glob_star_not, tc) 244272343Sngie{ 245272343Sngie atf_tc_set_md_var(tc, "descr", 246272343Sngie "Test glob(3) ** without GLOB_STAR"); 247272343Sngie} 248272343Sngie 249272343Sngie 250272343SngieATF_TC_BODY(glob_star_not, tc) 251272343Sngie{ 252272343Sngie run("a/**", 0, glob_star_not, __arraycount(glob_star_not)); 253272343Sngie} 254272343Sngie 255272343Sngie#if 0 256272343SngieATF_TC(glob_nocheck); 257272343SngieATF_TC_HEAD(glob_nocheck, tc) 258272343Sngie{ 259272343Sngie atf_tc_set_md_var(tc, "descr", 260272343Sngie "Test glob(3) pattern with backslash and GLOB_NOCHECK"); 261272343Sngie} 262272343Sngie 263272343Sngie 264272343SngieATF_TC_BODY(glob_nocheck, tc) 265272343Sngie{ 266272343Sngie static const char pattern[] = { 'f', 'o', 'o', '\\', ';', 'b', 'a', 267272343Sngie 'r', '\0' }; 268272343Sngie static const char *glob_nocheck[] = { 269272343Sngie pattern 270272343Sngie }; 271272343Sngie run(pattern, GLOB_NOCHECK, glob_nocheck, __arraycount(glob_nocheck)); 272272343Sngie} 273272343Sngie#endif 274272343Sngie 275272343SngieATF_TP_ADD_TCS(tp) 276272343Sngie{ 277274626Sngie#ifndef __FreeBSD__ 278272343Sngie ATF_TP_ADD_TC(tp, glob_star); 279272915Sngie#endif 280272343Sngie ATF_TP_ADD_TC(tp, glob_star_not); 281272343Sngie/* 282272343Sngie * Remove this test for now - the GLOB_NOCHECK return value has been 283272343Sngie * re-defined to return a modified pattern in revision 1.33 of glob.c 284272343Sngie * 285272343Sngie * ATF_TP_ADD_TC(tp, glob_nocheck); 286272343Sngie */ 287272343Sngie 288272343Sngie return atf_no_error(); 289272343Sngie} 290