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