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