1 /*	$NetBSD: dirent-test.c,v 1.1.1.2 2014/04/24 12:45:52 pettai 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