/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- startup
- killdir
- finish
- test1
- test2
- test3
- test4
- test5
- test6
- test7
- main
1 /*
2 * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
3 * The President and Fellows of Harvard College.
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 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the University nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30 /*
31 * rmdirtest.c
32 *
33 * Tests file system synchronization and directory implementation by
34 * removing the current directory under itself and then trying to do
35 * things. It's ok for most of those things to fail, but the system
36 * shouldn't crash.
37 */
38
39 #include <sys/types.h>
40 #include <sys/stat.h>
41 #include <stdio.h>
42 #include <string.h>
43 #include <unistd.h>
44 #include <fcntl.h>
45 #include <errno.h>
46 #include <limits.h>
47 #include <err.h>
48
49
50 static const char testdir[] = "testdir";
51 static char startpoint[PATH_MAX - sizeof(testdir)];
52
53 /*
54 * Create the test directory, and change into it, remembering
55 * where we came from.
56 */
57
58 static
59 void
60 startup(void)
61 {
62 if (getcwd(startpoint, sizeof(startpoint))==NULL) {
63 err(1, "getcwd (not in test dir)");
64 }
65
66 if (mkdir(testdir, 0775) < 0) {
67 err(1, "%s: mkdir", testdir);
68 }
69
70 if (chdir(testdir) < 0) {
71 err(1, "%s: chdir", testdir);
72 }
73 }
74
75 /*
76 * Remove the test directory.
77 *
78 * Note that even though it's the current directory, we can't do it
79 * with rmdir(".") - what that would try to do is remove the "." entry
80 * from the current directory, which is justifiably prohibited.
81 */
82
83 static
84 void
85 killdir(void)
86 {
87 char tmp[PATH_MAX];
88
89 snprintf(tmp, sizeof(tmp), "%s/%s", startpoint, testdir);
90 if (rmdir(tmp)<0) {
91 err(1, "%s: rmdir", tmp);
92 }
93 }
94
95 /*
96 * Leave the test directory and go back to where we came from, so we
97 * can try again.
98 */
99
100 static
101 void
102 finish(void)
103 {
104 if (chdir(startpoint)<0) {
105 err(1, "%s: chdir", startpoint);
106 }
107 }
108
109 /*************************************************************/
110
111 /*
112 * Basic test - just try removing the directory without doing anything
113 * evil.
114 */
115 static
116 void
117 test1(void)
118 {
119 printf("Making %s\n", testdir);
120 startup();
121
122 printf("Removing %s while in it\n", testdir);
123 killdir();
124
125 printf("Leaving the test directory\n");
126 finish();
127 }
128
129 /*
130 * Now do it while we also have the directory open.
131 */
132
133 static
134 void
135 test2(void)
136 {
137 int fd;
138
139 printf("Now trying with the directory open...\n");
140 startup();
141 fd = open(".", O_RDONLY);
142 if (fd<0) {
143 err(1, ".: open");
144 }
145 killdir();
146 finish();
147
148 /* close *after* leaving, just for excitement */
149 if (close(fd)<0) {
150 err(1, "removed %s: close", testdir);
151 }
152 }
153
154 /*
155 * Now see if . and .. work after rmdir.
156 */
157
158 static
159 void
160 test3(void)
161 {
162 char buf[PATH_MAX];
163 int fd;
164
165 printf("Checking if . exists after rmdir\n");
166 startup();
167 killdir();
168
169 fd = open(".", O_RDONLY);
170 if (fd<0) {
171 switch (errno) {
172 case EINVAL:
173 case EIO:
174 case ENOENT:
175 break;
176 default:
177 err(1, ".");
178 break;
179 }
180 }
181 else {
182 close(fd);
183 }
184
185 fd = open("..", O_RDONLY);
186 if (fd<0) {
187 switch (errno) {
188 case EINVAL:
189 case EIO:
190 case ENOENT:
191 break;
192 default:
193 err(1, "..");
194 break;
195 }
196 }
197 else {
198 warnx("..: openable after rmdir - might be bad");
199 close(fd);
200 }
201
202 snprintf(buf, sizeof(buf), "../%s", testdir);
203 fd = open(buf, O_RDONLY);
204 if (fd<0) {
205 switch (errno) {
206 case EINVAL:
207 case EIO:
208 case ENOENT:
209 break;
210 default:
211 err(1, "%s", buf);
212 break;
213 }
214 }
215 else {
216 errx(1, "%s: works after rmdir", buf);
217 }
218
219 finish();
220 }
221
222 /*
223 * Now try to create files.
224 */
225
226 static
227 void
228 test4(void)
229 {
230 char buf[4096];
231 int fd;
232
233 printf("Checking if creating files works after rmdir...\n");
234 startup();
235 killdir();
236
237 fd = open("newfile", O_WRONLY|O_CREAT|O_TRUNC, 0664);
238 if (fd<0) {
239 switch (errno) {
240 case EINVAL:
241 case EIO:
242 case ENOENT:
243 break;
244 default:
245 err(1, "%s", buf);
246 break;
247 }
248 }
249 else {
250 warnx("newfile: creating files after rmdir works");
251 warnx("(this is only ok if the space gets reclaimed)");
252
253 /*
254 * Waste a bunch of space so we'll be able to tell
255 */
256 memset(buf, 'J', sizeof(buf));
257 write(fd, buf, sizeof(buf));
258 write(fd, buf, sizeof(buf));
259 write(fd, buf, sizeof(buf));
260 write(fd, buf, sizeof(buf));
261 close(fd);
262 }
263
264 finish();
265 }
266
267 /*
268 * Now try to create directories.
269 */
270
271 static
272 void
273 test5(void)
274 {
275 printf("Checking if creating subdirs works after rmdir...\n");
276 startup();
277 killdir();
278
279 if (mkdir("newdir", 0775)<0) {
280 switch (errno) {
281 case EINVAL:
282 case EIO:
283 case ENOENT:
284 break;
285 default:
286 err(1, "mkdir in removed dir");
287 break;
288 }
289 }
290 else {
291 warnx("newfile: creating directories after rmdir works");
292 warnx("(this is only ok if the space gets reclaimed)");
293
294 /*
295 * Waste a bunch of space so we'll be able to tell
296 */
297 mkdir("newdir/t0", 0775);
298 mkdir("newdir/t1", 0775);
299 mkdir("newdir/t2", 0775);
300 mkdir("newdir/t3", 0775);
301 mkdir("newdir/t4", 0775);
302 mkdir("newdir/t5", 0775);
303 }
304
305 finish();
306 }
307
308 /*
309 * Now try listing the directory.
310 */
311 static
312 void
313 test6(void)
314 {
315 char buf[PATH_MAX];
316 int fd, len;
317
318 printf("Now trying to list the directory...\n");
319 startup();
320 fd = open(".", O_RDONLY);
321 if (fd<0) {
322 err(1, ".: open");
323 }
324 killdir();
325
326 while ((len = getdirentry(fd, buf, sizeof(buf)-1))>0) {
327 if ((unsigned)len >= sizeof(buf)-1) {
328 errx(1, ".: getdirentry: returned invalid length");
329 }
330 buf[len] = 0;
331 if (!strcmp(buf, ".") || !strcmp(buf, "..")) {
332 /* these are allowed to appear */
333 continue;
334 }
335 errx(1, ".: getdirentry: returned unexpected name %s", buf);
336 }
337 if (len==0) {
338 /* EOF - ok */
339 }
340 else { /* len < 0 */
341 switch (errno) {
342 case EINVAL:
343 case EIO:
344 break;
345 default:
346 err(1, ".: getdirentry");
347 break;
348 }
349 }
350
351 finish();
352
353 /* close *after* leaving, just for excitement */
354 if (close(fd)<0) {
355 err(1, "removed %s: close", testdir);
356 }
357 }
358
359 /*
360 * Try getcwd.
361 */
362 static
363 void
364 test7(void)
365 {
366 char buf[PATH_MAX];
367
368 startup();
369 killdir();
370 if (getcwd(buf, sizeof(buf))==NULL) {
371 switch (errno) {
372 case EINVAL:
373 case EIO:
374 case ENOENT:
375 break;
376 default:
377 err(1, "getcwd after removing %s", testdir);
378 break;
379 }
380 }
381 else {
382 errx(1, "getcwd after removing %s: succeeded (got %s)",
383 testdir, buf);
384 }
385
386 finish();
387 }
388
389 /**************************************************************/
390
391 int
392 main(void)
393 {
394 test1();
395 test2();
396 test3();
397 test4();
398 test5();
399 test6();
400 test7();
401
402 printf("Whew... survived.\n");
403 return 0;
404 }