1/* $NetBSD: dirent-test.c,v 1.2 2017/01/28 21:31:50 christos Exp $ */ 2 3/*********************************************************************** 4 * Copyright (c) 2009, Secure Endpoints Inc. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * - Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 14 * - Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in 16 * the documentation and/or other materials provided with the 17 * distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 22 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 23 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 24 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 25 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 28 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 30 * OF THE POSSIBILITY OF SUCH DAMAGE. 31 * 32 **********************************************************************/ 33 34#include <stdio.h> 35#include <stdlib.h> 36#include <stdarg.h> 37#include <direct.h> 38#include <errno.h> 39#include <io.h> 40#include <fcntl.h> 41#include <sys/stat.h> 42#include <string.h> 43#include "dirent.h" 44 45/* Note that we create a known directory structure in a subdirectory 46 of the current directory to run our tests. */ 47 48#define TESTDIR "dirent-test-dir" 49 50const char * dir_entries[] = { 51 "A", 52 "B", 53 "C", 54 "CAA", 55 "CAAA", 56 "CABBBB", 57 "CAABBB.txt", 58 "A filename with spaces" 59}; 60 61const char * entries_begin_with_C[] = { 62 "C", 63 "CAA", 64 "CAAA", 65 "CABBBB", 66 "CAABBB.txt" 67}; 68 69const char * entries_end_with_A[] = { 70 "A", 71 "CAA", 72 "CAAA" 73}; 74 75const int n_dir_entries = sizeof(dir_entries)/sizeof(dir_entries[0]); 76 77int teardown_test(void); 78 79void fail_test(const char * reason, ...) 80{ 81 va_list args; 82 83 va_start(args, reason); 84 vfprintf(stderr, reason, args); 85 va_end(args); 86 87 fprintf(stderr, " : errno = %d (%s)\n", errno, strerror(errno)); 88 teardown_test(); 89 abort(); 90} 91 92void fail_test_nf(const char * format, ...) 93{ 94 va_list args; 95 96 fprintf(stderr, "FAIL:"); 97 98 va_start(args, format); 99 vfprintf(stderr, format, args); 100 va_end(args); 101 102 fprintf(stderr, " : errno = %d (%s)\n", errno, strerror(errno)); 103} 104 105int touch(const char * filename) 106{ 107 int fd; 108 109 fd = _open(filename, _O_CREAT, _S_IREAD| _S_IWRITE); 110 111 if (fd == -1) 112 return -1; 113 114 return _close(fd); 115} 116 117int setup_test(void) 118{ 119 int i; 120 121 fprintf(stderr, "Creating test directory %s ...\n", TESTDIR); 122 123 if (_mkdir(TESTDIR)) 124 fail_test("Can't create test directory \"" TESTDIR "\""); 125 126 if (_chdir(TESTDIR)) 127 fail_test("Can't change to test directory"); 128 129 for (i=0; i < n_dir_entries; i++) { 130 if (touch(dir_entries[i])) 131 fail_test("Can't create test file '%s'", dir_entries[i]); 132 } 133 134 fprintf(stderr, "Done with test setup.\n"); 135 136 return 0; 137} 138 139int teardown_test(void) 140{ 141 char dirname[_MAX_PATH]; 142 size_t len; 143 int i; 144 145 printf ("Begin cleanup...\n"); 146 147 if (_getcwd(dirname, sizeof(dirname)/sizeof(char)) != NULL && 148 149 (len = strlen(dirname)) > sizeof(TESTDIR)/sizeof(char) && 150 151 !strcmp(dirname + len + 1 - sizeof(TESTDIR)/sizeof(char), TESTDIR)) { 152 153 /* fallthrough */ 154 155 } else { 156 /* did we create the directory? */ 157 158 if (!_rmdir( TESTDIR )) { 159 fprintf(stderr, "Removed test directory\n"); 160 return 0; 161 } else { 162 if (errno == ENOTEMPTY) { 163 if (_chdir(TESTDIR)) { 164 fprintf(stderr, "Can't change to test directory. Aborting cleanup.\n"); 165 return -1; 166 } else { 167 /* fallthrough */ 168 } 169 } else { 170 return -1; 171 } 172 } 173 } 174 175 fprintf(stderr, "Cleaning up test directory %s ...\n", TESTDIR); 176 177 for (i=0; i < n_dir_entries; i++) { 178 if (_unlink(dir_entries[i])) { 179 /* if the test setup failed, we expect this to happen for 180 at least some files */ 181 } 182 } 183 184 if (_chdir("..")) { 185 fprintf(stderr, "Can't escape test directory. Giving in.\n"); 186 return -1; 187 } 188 189 if (_rmdir( TESTDIR )) { 190 fprintf(stderr, "Can't remove test directory.\n"); 191 return -1; 192 } 193 194 printf("Cleaned up test directory\n"); 195 return 0; 196} 197 198int check_list(const char * filespec, const char ** list, int n, int expect_dot_and_dotdot) 199{ 200 DIR * d; 201 struct dirent * e; 202 int n_found = 0; 203 int i; 204 int rv = 0; 205 int retry = 1; 206 207 d = opendir(filespec); 208 if (d == NULL) { 209 fail_test_nf("opendir failed for [%s]", filespec); 210 return -1; 211 } 212 213 printf("Checking filespec [%s]... ", filespec); 214 215 retry: 216 while ((e = readdir(d)) != NULL) { 217 n_found ++; 218 219 if (expect_dot_and_dotdot && 220 (!strcmp(e->d_name, ".") || 221 !strcmp(e->d_name, ".."))) 222 continue; 223 224 for (i=0; i < n; i++) { 225 if (!strcmp(list[i], e->d_name)) 226 break; 227 } 228 229 if (i == n) { 230 fail_test_nf("Found unexpected entry [%s]", e->d_name); 231 rv = -1; 232 } 233 } 234 235 if (n_found != n) { 236 fail_test_nf("Unexpected number of entries [%d]. Expected %d", n_found, n); 237 rv = -1; 238 } 239 240 if (retry) { 241 retry = 0; 242 n_found = 0; 243 244 rewinddir(d); 245 goto retry; 246 } 247 248 if (closedir(d)) { 249 fail_test_nf("closedir() failed"); 250 } 251 252 printf("done\n"); 253 254 return rv; 255} 256 257int run_tests() 258{ 259 /* assumes that the test directory has been set up and we have 260 changed into the test directory. */ 261 262 check_list("*", dir_entries, n_dir_entries + 2, 1); 263 check_list("*.*", dir_entries, n_dir_entries + 2, 1); 264 check_list("C*", entries_begin_with_C, sizeof(entries_begin_with_C)/sizeof(entries_begin_with_C[0]), 0); 265 check_list("*A", entries_end_with_A, sizeof(entries_end_with_A)/sizeof(entries_end_with_A[0]), 0); 266 267 return 0; 268} 269 270int main(int argc, char ** argv) 271{ 272 if (setup_test()) 273 return 1; 274 275 run_tests(); 276 277 teardown_test(); 278 279 return 0; 280} 281