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
50 const 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
61 const char * entries_begin_with_C[] = {
62 "C",
63 "CAA",
64 "CAAA",
65 "CABBBB",
66 "CAABBB.txt"
67 };
68
69 const char * entries_end_with_A[] = {
70 "A",
71 "CAA",
72 "CAAA"
73 };
74
75 const int n_dir_entries = sizeof(dir_entries)/sizeof(dir_entries[0]);
76
77 int teardown_test(void);
78
fail_test(const char * reason,...)79 void 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
fail_test_nf(const char * format,...)92 void 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
touch(const char * filename)105 int 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
setup_test(void)117 int 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
teardown_test(void)139 int 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
check_list(const char * filespec,const char ** list,int n,int expect_dot_and_dotdot)198 int 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
run_tests()257 int 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
main(int argc,char ** argv)270 int 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