1 /*	$NetBSD: fs_test.c,v 1.3 2014/12/10 04:38:03 christos Exp $	*/
2 
3 /*
4  * Automated Testing Framework (atf)
5  *
6  * Copyright (c) 2007 The NetBSD Foundation, Inc.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
19  * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
20  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22  * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
23  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
25  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
27  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
29  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include <sys/types.h>
33 #include <sys/stat.h>
34 
35 #include <errno.h>
36 #include <fcntl.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <unistd.h>
41 
42 #include <atf-c.h>
43 
44 #include "fs.h"
45 #include "test_helpers.h"
46 #include "user.h"
47 
48 /* ---------------------------------------------------------------------
49  * Auxiliary functions.
50  * --------------------------------------------------------------------- */
51 
52 static
53 void
54 create_dir(const char *p, int mode)
55 {
56     int ret;
57 
58     ret = mkdir(p, mode);
59     if (ret == -1)
60         atf_tc_fail("Could not create helper directory %s", p);
61 }
62 
63 static
64 void
65 create_file(const char *p, int mode)
66 {
67     int fd;
68 
69     fd = open(p, O_CREAT | O_WRONLY | O_TRUNC, mode);
70     if (fd == -1)
71         atf_tc_fail("Could not create helper file %s", p);
72     close(fd);
73 }
74 
75 static
76 bool
77 exists(const atf_fs_path_t *p)
78 {
79     return access(atf_fs_path_cstring(p), F_OK) == 0;
80 }
81 
82 static
83 atf_error_t
84 mkstemp_discard_fd(atf_fs_path_t *p)
85 {
86     int fd;
87     atf_error_t err = atf_fs_mkstemp(p, &fd);
88     if (!atf_is_error(err))
89         close(fd);
90     return err;
91 }
92 
93 /* ---------------------------------------------------------------------
94  * Test cases for the "atf_fs_path" type.
95  * --------------------------------------------------------------------- */
96 
97 ATF_TC(path_normalize);
98 ATF_TC_HEAD(path_normalize, tc)
99 {
100     atf_tc_set_md_var(tc, "descr", "Tests the path's normalization");
101 }
102 ATF_TC_BODY(path_normalize, tc)
103 {
104     struct test {
105         const char *in;
106         const char *out;
107     } tests[] = {
108         { ".", ".", },
109         { "..", "..", },
110 
111         { "/", "/", },
112         { "//", "/", }, /* NO_CHECK_STYLE */
113         { "///", "/", }, /* NO_CHECK_STYLE */
114 
115         { "foo", "foo", },
116         { "foo/", "foo", },
117         { "foo/bar", "foo/bar", },
118         { "foo/bar/", "foo/bar", },
119 
120         { "/foo", "/foo", },
121         { "/foo/bar", "/foo/bar", },
122         { "/foo/bar/", "/foo/bar", },
123 
124         { "///foo", "/foo", }, /* NO_CHECK_STYLE */
125         { "///foo///bar", "/foo/bar", }, /* NO_CHECK_STYLE */
126         { "///foo///bar///", "/foo/bar", }, /* NO_CHECK_STYLE */
127 
128         { NULL, NULL }
129     };
130     struct test *t;
131 
132     for (t = &tests[0]; t->in != NULL; t++) {
133         atf_fs_path_t p;
134 
135         printf("Input          : >%s<\n", t->in);
136         printf("Expected output: >%s<\n", t->out);
137 
138         RE(atf_fs_path_init_fmt(&p, "%s", t->in));
139         printf("Output         : >%s<\n", atf_fs_path_cstring(&p));
140         ATF_REQUIRE(strcmp(atf_fs_path_cstring(&p), t->out) == 0);
141         atf_fs_path_fini(&p);
142 
143         printf("\n");
144     }
145 }
146 
147 ATF_TC(path_copy);
148 ATF_TC_HEAD(path_copy, tc)
149 {
150     atf_tc_set_md_var(tc, "descr", "Tests the atf_fs_path_copy constructor");
151 }
152 ATF_TC_BODY(path_copy, tc)
153 {
154     atf_fs_path_t str, str2;
155 
156     RE(atf_fs_path_init_fmt(&str, "foo"));
157     RE(atf_fs_path_copy(&str2, &str));
158 
159     ATF_REQUIRE(atf_equal_fs_path_fs_path(&str, &str2));
160 
161     RE(atf_fs_path_append_fmt(&str2, "bar"));
162 
163     ATF_REQUIRE(!atf_equal_fs_path_fs_path(&str, &str2));
164 
165     atf_fs_path_fini(&str2);
166     atf_fs_path_fini(&str);
167 }
168 
169 ATF_TC(path_is_absolute);
170 ATF_TC_HEAD(path_is_absolute, tc)
171 {
172     atf_tc_set_md_var(tc, "descr", "Tests the path::is_absolute function");
173 }
174 ATF_TC_BODY(path_is_absolute, tc)
175 {
176     struct test {
177         const char *in;
178         bool abs;
179     } tests[] = {
180         { "/", true },
181         { "////", true }, /* NO_CHECK_STYLE */
182         { "////a", true }, /* NO_CHECK_STYLE */
183         { "//a//", true }, /* NO_CHECK_STYLE */
184         { "a////", false }, /* NO_CHECK_STYLE */
185         { "../foo", false },
186         { NULL, false },
187     };
188     struct test *t;
189 
190     for (t = &tests[0]; t->in != NULL; t++) {
191         atf_fs_path_t p;
192 
193         printf("Input          : %s\n", t->in);
194         printf("Expected result: %s\n", t->abs ? "true" : "false");
195 
196         RE(atf_fs_path_init_fmt(&p, "%s", t->in));
197         printf("Result         : %s\n",
198                atf_fs_path_is_absolute(&p) ? "true" : "false");
199         if (t->abs)
200             ATF_REQUIRE(atf_fs_path_is_absolute(&p));
201         else
202             ATF_REQUIRE(!atf_fs_path_is_absolute(&p));
203         atf_fs_path_fini(&p);
204 
205         printf("\n");
206     }
207 }
208 
209 ATF_TC(path_is_root);
210 ATF_TC_HEAD(path_is_root, tc)
211 {
212     atf_tc_set_md_var(tc, "descr", "Tests the path::is_root function");
213 }
214 ATF_TC_BODY(path_is_root, tc)
215 {
216     struct test {
217         const char *in;
218         bool root;
219     } tests[] = {
220         { "/", true },
221         { "////", true }, /* NO_CHECK_STYLE */
222         { "////a", false }, /* NO_CHECK_STYLE */
223         { "//a//", false }, /* NO_CHECK_STYLE */
224         { "a////", false }, /* NO_CHECK_STYLE */
225         { "../foo", false },
226         { NULL, false },
227     };
228     struct test *t;
229 
230     for (t = &tests[0]; t->in != NULL; t++) {
231         atf_fs_path_t p;
232 
233         printf("Input          : %s\n", t->in);
234         printf("Expected result: %s\n", t->root ? "true" : "false");
235 
236         RE(atf_fs_path_init_fmt(&p, "%s", t->in));
237         printf("Result         : %s\n",
238                atf_fs_path_is_root(&p) ? "true" : "false");
239         if (t->root)
240             ATF_REQUIRE(atf_fs_path_is_root(&p));
241         else
242             ATF_REQUIRE(!atf_fs_path_is_root(&p));
243         atf_fs_path_fini(&p);
244 
245         printf("\n");
246     }
247 }
248 
249 ATF_TC(path_branch_path);
250 ATF_TC_HEAD(path_branch_path, tc)
251 {
252     atf_tc_set_md_var(tc, "descr", "Tests the atf_fs_path_branch_path "
253                       "function");
254 }
255 ATF_TC_BODY(path_branch_path, tc)
256 {
257     struct test {
258         const char *in;
259         const char *branch;
260     } tests[] = {
261         { ".", "." },
262         { "foo", "." },
263         { "foo/bar", "foo" },
264         { "/foo", "/" },
265         { "/foo/bar", "/foo" },
266         { NULL, NULL },
267     };
268     struct test *t;
269 
270     for (t = &tests[0]; t->in != NULL; t++) {
271         atf_fs_path_t p, bp;
272 
273         printf("Input          : %s\n", t->in);
274         printf("Expected output: %s\n", t->branch);
275 
276         RE(atf_fs_path_init_fmt(&p, "%s", t->in));
277         RE(atf_fs_path_branch_path(&p, &bp));
278         printf("Output         : %s\n", atf_fs_path_cstring(&bp));
279         ATF_REQUIRE(strcmp(atf_fs_path_cstring(&bp), t->branch) == 0);
280         atf_fs_path_fini(&bp);
281         atf_fs_path_fini(&p);
282 
283         printf("\n");
284     }
285 }
286 
287 ATF_TC(path_leaf_name);
288 ATF_TC_HEAD(path_leaf_name, tc)
289 {
290     atf_tc_set_md_var(tc, "descr", "Tests the atf_fs_path_leaf_name "
291                       "function");
292 }
293 ATF_TC_BODY(path_leaf_name, tc)
294 {
295     struct test {
296         const char *in;
297         const char *leaf;
298     } tests[] = {
299         { ".", "." },
300         { "foo", "foo" },
301         { "foo/bar", "bar" },
302         { "/foo", "foo" },
303         { "/foo/bar", "bar" },
304         { NULL, NULL },
305     };
306     struct test *t;
307 
308     for (t = &tests[0]; t->in != NULL; t++) {
309         atf_fs_path_t p;
310         atf_dynstr_t ln;
311 
312         printf("Input          : %s\n", t->in);
313         printf("Expected output: %s\n", t->leaf);
314 
315         RE(atf_fs_path_init_fmt(&p, "%s", t->in));
316         RE(atf_fs_path_leaf_name(&p, &ln));
317         printf("Output         : %s\n", atf_dynstr_cstring(&ln));
318         ATF_REQUIRE(atf_equal_dynstr_cstring(&ln, t->leaf));
319         atf_dynstr_fini(&ln);
320         atf_fs_path_fini(&p);
321 
322         printf("\n");
323     }
324 }
325 
326 ATF_TC(path_append);
327 ATF_TC_HEAD(path_append, tc)
328 {
329     atf_tc_set_md_var(tc, "descr", "Tests the concatenation of multiple "
330                       "paths");
331 }
332 ATF_TC_BODY(path_append, tc)
333 {
334     struct test {
335         const char *in;
336         const char *ap;
337         const char *out;
338     } tests[] = {
339         { "foo", "bar", "foo/bar" },
340         { "foo/", "/bar", "foo/bar" },
341         { "foo/", "/bar/baz", "foo/bar/baz" },
342         { "foo/", "///bar///baz", "foo/bar/baz" }, /* NO_CHECK_STYLE */
343 
344         { NULL, NULL, NULL }
345     };
346     struct test *t;
347 
348     for (t = &tests[0]; t->in != NULL; t++) {
349         atf_fs_path_t p;
350 
351         printf("Input          : >%s<\n", t->in);
352         printf("Append         : >%s<\n", t->ap);
353         printf("Expected output: >%s<\n", t->out);
354 
355         RE(atf_fs_path_init_fmt(&p, "%s", t->in));
356 
357         RE(atf_fs_path_append_fmt(&p, "%s", t->ap));
358 
359         printf("Output         : >%s<\n", atf_fs_path_cstring(&p));
360         ATF_REQUIRE(strcmp(atf_fs_path_cstring(&p), t->out) == 0);
361 
362         atf_fs_path_fini(&p);
363 
364         printf("\n");
365     }
366 }
367 
368 ATF_TC(path_to_absolute);
369 ATF_TC_HEAD(path_to_absolute, tc)
370 {
371     atf_tc_set_md_var(tc, "descr", "Tests the atf_fs_path_to_absolute "
372                       "function");
373 }
374 ATF_TC_BODY(path_to_absolute, tc)
375 {
376     const char *names[] = { ".", "dir", NULL };
377     const char **n;
378 
379     ATF_REQUIRE(mkdir("dir", 0755) != -1);
380 
381     for (n = names; *n != NULL; n++) {
382         atf_fs_path_t p, p2;
383         atf_fs_stat_t st1, st2;
384 
385         RE(atf_fs_path_init_fmt(&p, "%s", *n));
386         RE(atf_fs_stat_init(&st1, &p));
387         printf("Relative path: %s\n", atf_fs_path_cstring(&p));
388 
389         RE(atf_fs_path_to_absolute(&p, &p2));
390         printf("Absolute path: %s\n", atf_fs_path_cstring(&p2));
391 
392         ATF_REQUIRE(atf_fs_path_is_absolute(&p2));
393         RE(atf_fs_stat_init(&st2, &p2));
394 
395         ATF_REQUIRE_EQ(atf_fs_stat_get_device(&st1),
396                         atf_fs_stat_get_device(&st2));
397         ATF_REQUIRE_EQ(atf_fs_stat_get_inode(&st1),
398                         atf_fs_stat_get_inode(&st2));
399 
400         atf_fs_stat_fini(&st2);
401         atf_fs_stat_fini(&st1);
402         atf_fs_path_fini(&p2);
403         atf_fs_path_fini(&p);
404 
405         printf("\n");
406     }
407 }
408 
409 ATF_TC(path_equal);
410 ATF_TC_HEAD(path_equal, tc)
411 {
412     atf_tc_set_md_var(tc, "descr", "Tests the equality operators for paths");
413 }
414 ATF_TC_BODY(path_equal, tc)
415 {
416     atf_fs_path_t p1, p2;
417 
418     RE(atf_fs_path_init_fmt(&p1, "foo"));
419 
420     RE(atf_fs_path_init_fmt(&p2, "foo"));
421     ATF_REQUIRE(atf_equal_fs_path_fs_path(&p1, &p2));
422     atf_fs_path_fini(&p2);
423 
424     RE(atf_fs_path_init_fmt(&p2, "bar"));
425     ATF_REQUIRE(!atf_equal_fs_path_fs_path(&p1, &p2));
426     atf_fs_path_fini(&p2);
427 
428     atf_fs_path_fini(&p1);
429 }
430 
431 /* ---------------------------------------------------------------------
432  * Test cases for the "atf_fs_stat" type.
433  * --------------------------------------------------------------------- */
434 
435 ATF_TC(stat_mode);
436 ATF_TC_HEAD(stat_mode, tc)
437 {
438     atf_tc_set_md_var(tc, "descr", "Tests the atf_fs_stat_get_mode function "
439                       "and, indirectly, the constructor");
440 }
441 ATF_TC_BODY(stat_mode, tc)
442 {
443     atf_fs_path_t p;
444     atf_fs_stat_t st;
445 
446     create_file("f1", 0400);
447     create_file("f2", 0644);
448 
449     RE(atf_fs_path_init_fmt(&p, "f1"));
450     RE(atf_fs_stat_init(&st, &p));
451     ATF_CHECK_EQ(0400, atf_fs_stat_get_mode(&st));
452     atf_fs_stat_fini(&st);
453     atf_fs_path_fini(&p);
454 
455     RE(atf_fs_path_init_fmt(&p, "f2"));
456     RE(atf_fs_stat_init(&st, &p));
457     ATF_CHECK_EQ(0644, atf_fs_stat_get_mode(&st));
458     atf_fs_stat_fini(&st);
459     atf_fs_path_fini(&p);
460 }
461 
462 ATF_TC(stat_type);
463 ATF_TC_HEAD(stat_type, tc)
464 {
465     atf_tc_set_md_var(tc, "descr", "Tests the atf_fs_stat_get_type function "
466                       "and, indirectly, the constructor");
467 }
468 ATF_TC_BODY(stat_type, tc)
469 {
470     atf_fs_path_t p;
471     atf_fs_stat_t st;
472 
473     create_dir("dir", 0755);
474     create_file("reg", 0644);
475 
476     RE(atf_fs_path_init_fmt(&p, "dir"));
477     RE(atf_fs_stat_init(&st, &p));
478     ATF_REQUIRE_EQ(atf_fs_stat_get_type(&st), atf_fs_stat_dir_type);
479     atf_fs_stat_fini(&st);
480     atf_fs_path_fini(&p);
481 
482     RE(atf_fs_path_init_fmt(&p, "reg"));
483     RE(atf_fs_stat_init(&st, &p));
484     ATF_REQUIRE_EQ(atf_fs_stat_get_type(&st), atf_fs_stat_reg_type);
485     atf_fs_stat_fini(&st);
486     atf_fs_path_fini(&p);
487 }
488 
489 ATF_TC(stat_perms);
490 ATF_TC_HEAD(stat_perms, tc)
491 {
492     atf_tc_set_md_var(tc, "descr", "Tests the atf_fs_stat_is_* functions");
493 }
494 ATF_TC_BODY(stat_perms, tc)
495 {
496     atf_fs_path_t p;
497     atf_fs_stat_t st;
498 
499     create_file("reg", 0);
500 
501     RE(atf_fs_path_init_fmt(&p, "reg"));
502 
503 #define perms(ur, uw, ux, gr, gw, gx, othr, othw, othx) \
504     { \
505         RE(atf_fs_stat_init(&st, &p)); \
506         ATF_REQUIRE(atf_fs_stat_is_owner_readable(&st) == ur); \
507         ATF_REQUIRE(atf_fs_stat_is_owner_writable(&st) == uw); \
508         ATF_REQUIRE(atf_fs_stat_is_owner_executable(&st) == ux); \
509         ATF_REQUIRE(atf_fs_stat_is_group_readable(&st) == gr); \
510         ATF_REQUIRE(atf_fs_stat_is_group_writable(&st) == gw); \
511         ATF_REQUIRE(atf_fs_stat_is_group_executable(&st) == gx); \
512         ATF_REQUIRE(atf_fs_stat_is_other_readable(&st) == othr); \
513         ATF_REQUIRE(atf_fs_stat_is_other_writable(&st) == othw); \
514         ATF_REQUIRE(atf_fs_stat_is_other_executable(&st) == othx); \
515         atf_fs_stat_fini(&st); \
516     }
517 
518     chmod("reg", 0000);
519     perms(false, false, false, false, false, false, false, false, false);
520 
521     chmod("reg", 0001);
522     perms(false, false, false, false, false, false, false, false, true);
523 
524     chmod("reg", 0010);
525     perms(false, false, false, false, false, true, false, false, false);
526 
527     chmod("reg", 0100);
528     perms(false, false, true, false, false, false, false, false, false);
529 
530     chmod("reg", 0002);
531     perms(false, false, false, false, false, false, false, true, false);
532 
533     chmod("reg", 0020);
534     perms(false, false, false, false, true, false, false, false, false);
535 
536     chmod("reg", 0200);
537     perms(false, true, false, false, false, false, false, false, false);
538 
539     chmod("reg", 0004);
540     perms(false, false, false, false, false, false, true, false, false);
541 
542     chmod("reg", 0040);
543     perms(false, false, false, true, false, false, false, false, false);
544 
545     chmod("reg", 0400);
546     perms(true, false, false, false, false, false, false, false, false);
547 
548     chmod("reg", 0644);
549     perms(true, true, false, true, false, false, true, false, false);
550 
551     chmod("reg", 0755);
552     perms(true, true, true, true, false, true, true, false, true);
553 
554     chmod("reg", 0777);
555     perms(true, true, true, true, true, true, true, true, true);
556 
557 #undef perms
558 
559     atf_fs_path_fini(&p);
560 }
561 
562 /* ---------------------------------------------------------------------
563  * Test cases for the free functions.
564  * --------------------------------------------------------------------- */
565 
566 ATF_TC(exists);
567 ATF_TC_HEAD(exists, tc)
568 {
569     atf_tc_set_md_var(tc, "descr", "Tests the atf_fs_exists function");
570 }
571 ATF_TC_BODY(exists, tc)
572 {
573     atf_error_t err;
574     atf_fs_path_t pdir, pfile;
575     bool b;
576 
577     RE(atf_fs_path_init_fmt(&pdir, "dir"));
578     RE(atf_fs_path_init_fmt(&pfile, "dir/file"));
579 
580     create_dir(atf_fs_path_cstring(&pdir), 0755);
581     create_file(atf_fs_path_cstring(&pfile), 0644);
582 
583     printf("Checking existence of a directory\n");
584     RE(atf_fs_exists(&pdir, &b));
585     ATF_REQUIRE(b);
586 
587     printf("Checking existence of a file\n");
588     RE(atf_fs_exists(&pfile, &b));
589     ATF_REQUIRE(b);
590 
591     /* XXX: This should probably be a separate test case to let the user
592      * be aware that some tests were skipped because privileges were not
593      * correct. */
594     if (!atf_user_is_root()) {
595         printf("Checking existence of a file inside a directory without "
596                "permissions\n");
597         ATF_REQUIRE(chmod(atf_fs_path_cstring(&pdir), 0000) != -1);
598         err = atf_fs_exists(&pfile, &b);
599         ATF_REQUIRE(atf_is_error(err));
600         ATF_REQUIRE(atf_error_is(err, "libc"));
601         ATF_REQUIRE(chmod(atf_fs_path_cstring(&pdir), 0755) != -1);
602         atf_error_free(err);
603     }
604 
605     printf("Checking existence of a non-existent file\n");
606     ATF_REQUIRE(unlink(atf_fs_path_cstring(&pfile)) != -1);
607     RE(atf_fs_exists(&pfile, &b));
608     ATF_REQUIRE(!b);
609 
610     atf_fs_path_fini(&pfile);
611     atf_fs_path_fini(&pdir);
612 }
613 
614 ATF_TC(eaccess);
615 ATF_TC_HEAD(eaccess, tc)
616 {
617     atf_tc_set_md_var(tc, "descr", "Tests the atf_fs_eaccess function");
618 }
619 ATF_TC_BODY(eaccess, tc)
620 {
621     const int modes[] = { atf_fs_access_f, atf_fs_access_r, atf_fs_access_w,
622                           atf_fs_access_x, 0 };
623     const int *m;
624     struct tests {
625         mode_t fmode;
626         int amode;
627         int uerror;
628         int rerror;
629     } tests[] = {
630         { 0000, atf_fs_access_r, EACCES, 0 },
631         { 0000, atf_fs_access_w, EACCES, 0 },
632         { 0000, atf_fs_access_x, EACCES, EACCES },
633 
634         { 0001, atf_fs_access_r, EACCES, 0 },
635         { 0001, atf_fs_access_w, EACCES, 0 },
636         { 0001, atf_fs_access_x, EACCES, 0 },
637         { 0002, atf_fs_access_r, EACCES, 0 },
638         { 0002, atf_fs_access_w, EACCES, 0 },
639         { 0002, atf_fs_access_x, EACCES, EACCES },
640         { 0004, atf_fs_access_r, EACCES, 0 },
641         { 0004, atf_fs_access_w, EACCES, 0 },
642         { 0004, atf_fs_access_x, EACCES, EACCES },
643 
644         { 0010, atf_fs_access_r, EACCES, 0 },
645         { 0010, atf_fs_access_w, EACCES, 0 },
646         { 0010, atf_fs_access_x, 0,      0 },
647         { 0020, atf_fs_access_r, EACCES, 0 },
648         { 0020, atf_fs_access_w, 0,      0 },
649         { 0020, atf_fs_access_x, EACCES, EACCES },
650         { 0040, atf_fs_access_r, 0,      0 },
651         { 0040, atf_fs_access_w, EACCES, 0 },
652         { 0040, atf_fs_access_x, EACCES, EACCES },
653 
654         { 0100, atf_fs_access_r, EACCES, 0 },
655         { 0100, atf_fs_access_w, EACCES, 0 },
656         { 0100, atf_fs_access_x, 0,      0 },
657         { 0200, atf_fs_access_r, EACCES, 0 },
658         { 0200, atf_fs_access_w, 0,      0 },
659         { 0200, atf_fs_access_x, EACCES, EACCES },
660         { 0400, atf_fs_access_r, 0,      0 },
661         { 0400, atf_fs_access_w, EACCES, 0 },
662         { 0400, atf_fs_access_x, EACCES, EACCES },
663 
664         { 0, 0, 0, 0 }
665     };
666     struct tests *t;
667     atf_fs_path_t p;
668     atf_error_t err;
669 
670     RE(atf_fs_path_init_fmt(&p, "the-file"));
671 
672     printf("Non-existent file checks\n");
673     for (m = &modes[0]; *m != 0; m++) {
674         err = atf_fs_eaccess(&p, *m);
675         ATF_REQUIRE(atf_is_error(err));
676         ATF_REQUIRE(atf_error_is(err, "libc"));
677         ATF_REQUIRE_EQ(atf_libc_error_code(err), ENOENT);
678         atf_error_free(err);
679     }
680 
681     create_file(atf_fs_path_cstring(&p), 0000);
682     ATF_REQUIRE(chown(atf_fs_path_cstring(&p), geteuid(), getegid()) != -1);
683 
684     for (t = &tests[0]; t->amode != 0; t++) {
685         const int experr = atf_user_is_root() ? t->rerror : t->uerror;
686 
687         printf("\n");
688         printf("File mode     : %04o\n", (unsigned int)t->fmode);
689         printf("Access mode   : 0x%02x\n", t->amode);
690 
691         ATF_REQUIRE(chmod(atf_fs_path_cstring(&p), t->fmode) != -1);
692 
693         /* First, existence check. */
694         err = atf_fs_eaccess(&p, atf_fs_access_f);
695         ATF_REQUIRE(!atf_is_error(err));
696 
697         /* Now do the specific test case. */
698         printf("Expected error: %d\n", experr);
699         err = atf_fs_eaccess(&p, t->amode);
700         if (atf_is_error(err)) {
701             if (atf_error_is(err, "libc"))
702                 printf("Error         : %d\n", atf_libc_error_code(err));
703             else
704                 printf("Error         : Non-libc error\n");
705         } else
706                 printf("Error         : None\n");
707         if (experr == 0) {
708             ATF_REQUIRE(!atf_is_error(err));
709         } else {
710             ATF_REQUIRE(atf_is_error(err));
711             ATF_REQUIRE(atf_error_is(err, "libc"));
712             ATF_REQUIRE_EQ(atf_libc_error_code(err), experr);
713             atf_error_free(err);
714         }
715     }
716 
717     atf_fs_path_fini(&p);
718 }
719 
720 ATF_TC(getcwd);
721 ATF_TC_HEAD(getcwd, tc)
722 {
723     atf_tc_set_md_var(tc, "descr", "Tests the atf_fs_getcwd function");
724 }
725 ATF_TC_BODY(getcwd, tc)
726 {
727     atf_fs_path_t cwd1, cwd2;
728 
729     create_dir ("root", 0755);
730 
731     RE(atf_fs_getcwd(&cwd1));
732     ATF_REQUIRE(chdir("root") != -1);
733     RE(atf_fs_getcwd(&cwd2));
734 
735     RE(atf_fs_path_append_fmt(&cwd1, "root"));
736 
737     ATF_REQUIRE(atf_equal_fs_path_fs_path(&cwd1, &cwd2));
738 
739     atf_fs_path_fini(&cwd2);
740     atf_fs_path_fini(&cwd1);
741 }
742 
743 ATF_TC(rmdir_empty);
744 ATF_TC_HEAD(rmdir_empty, tc)
745 {
746     atf_tc_set_md_var(tc, "descr", "Tests the atf_fs_rmdir function");
747 }
748 ATF_TC_BODY(rmdir_empty, tc)
749 {
750     atf_fs_path_t p;
751 
752     RE(atf_fs_path_init_fmt(&p, "test-dir"));
753 
754     ATF_REQUIRE(mkdir("test-dir", 0755) != -1);
755     ATF_REQUIRE(exists(&p));
756     RE(atf_fs_rmdir(&p));
757     ATF_REQUIRE(!exists(&p));
758 
759     atf_fs_path_fini(&p);
760 }
761 
762 ATF_TC(rmdir_enotempty);
763 ATF_TC_HEAD(rmdir_enotempty, tc)
764 {
765     atf_tc_set_md_var(tc, "descr", "Tests the atf_fs_rmdir function");
766 }
767 ATF_TC_BODY(rmdir_enotempty, tc)
768 {
769     atf_fs_path_t p;
770     atf_error_t err;
771 
772     RE(atf_fs_path_init_fmt(&p, "test-dir"));
773 
774     ATF_REQUIRE(mkdir("test-dir", 0755) != -1);
775     ATF_REQUIRE(exists(&p));
776     create_file("test-dir/foo", 0644);
777 
778     err = atf_fs_rmdir(&p);
779     ATF_REQUIRE(atf_is_error(err));
780     ATF_REQUIRE(atf_error_is(err, "libc"));
781     ATF_REQUIRE_EQ(atf_libc_error_code(err), ENOTEMPTY);
782     atf_error_free(err);
783 
784     atf_fs_path_fini(&p);
785 }
786 
787 ATF_TC(rmdir_eperm);
788 ATF_TC_HEAD(rmdir_eperm, tc)
789 {
790     atf_tc_set_md_var(tc, "descr", "Tests the atf_fs_rmdir function");
791 }
792 ATF_TC_BODY(rmdir_eperm, tc)
793 {
794     atf_fs_path_t p;
795     atf_error_t err;
796 
797     RE(atf_fs_path_init_fmt(&p, "test-dir/foo"));
798 
799     ATF_REQUIRE(mkdir("test-dir", 0755) != -1);
800     ATF_REQUIRE(mkdir("test-dir/foo", 0755) != -1);
801     ATF_REQUIRE(chmod("test-dir", 0555) != -1);
802     ATF_REQUIRE(exists(&p));
803 
804     err = atf_fs_rmdir(&p);
805     if (atf_user_is_root()) {
806         ATF_REQUIRE(!atf_is_error(err));
807     } else {
808         ATF_REQUIRE(atf_is_error(err));
809         ATF_REQUIRE(atf_error_is(err, "libc"));
810         ATF_REQUIRE_EQ(atf_libc_error_code(err), EACCES);
811         atf_error_free(err);
812     }
813 
814     atf_fs_path_fini(&p);
815 }
816 
817 ATF_TC(mkdtemp_ok);
818 ATF_TC_HEAD(mkdtemp_ok, tc)
819 {
820     atf_tc_set_md_var(tc, "descr", "Tests the atf_fs_mkdtemp function, "
821                       "successful execution");
822 }
823 ATF_TC_BODY(mkdtemp_ok, tc)
824 {
825     atf_fs_path_t p1, p2;
826     atf_fs_stat_t s1, s2;
827 
828     RE(atf_fs_path_init_fmt(&p1, "testdir.XXXXXX"));
829     RE(atf_fs_path_init_fmt(&p2, "testdir.XXXXXX"));
830     RE(atf_fs_mkdtemp(&p1));
831     RE(atf_fs_mkdtemp(&p2));
832     ATF_REQUIRE(!atf_equal_fs_path_fs_path(&p1, &p2));
833     ATF_REQUIRE(exists(&p1));
834     ATF_REQUIRE(exists(&p2));
835 
836     RE(atf_fs_stat_init(&s1, &p1));
837     ATF_REQUIRE_EQ(atf_fs_stat_get_type(&s1), atf_fs_stat_dir_type);
838     ATF_REQUIRE( atf_fs_stat_is_owner_readable(&s1));
839     ATF_REQUIRE( atf_fs_stat_is_owner_writable(&s1));
840     ATF_REQUIRE( atf_fs_stat_is_owner_executable(&s1));
841     ATF_REQUIRE(!atf_fs_stat_is_group_readable(&s1));
842     ATF_REQUIRE(!atf_fs_stat_is_group_writable(&s1));
843     ATF_REQUIRE(!atf_fs_stat_is_group_executable(&s1));
844     ATF_REQUIRE(!atf_fs_stat_is_other_readable(&s1));
845     ATF_REQUIRE(!atf_fs_stat_is_other_writable(&s1));
846     ATF_REQUIRE(!atf_fs_stat_is_other_executable(&s1));
847 
848     RE(atf_fs_stat_init(&s2, &p2));
849     ATF_REQUIRE_EQ(atf_fs_stat_get_type(&s2), atf_fs_stat_dir_type);
850     ATF_REQUIRE( atf_fs_stat_is_owner_readable(&s2));
851     ATF_REQUIRE( atf_fs_stat_is_owner_writable(&s2));
852     ATF_REQUIRE( atf_fs_stat_is_owner_executable(&s2));
853     ATF_REQUIRE(!atf_fs_stat_is_group_readable(&s2));
854     ATF_REQUIRE(!atf_fs_stat_is_group_writable(&s2));
855     ATF_REQUIRE(!atf_fs_stat_is_group_executable(&s2));
856     ATF_REQUIRE(!atf_fs_stat_is_other_readable(&s2));
857     ATF_REQUIRE(!atf_fs_stat_is_other_writable(&s2));
858     ATF_REQUIRE(!atf_fs_stat_is_other_executable(&s2));
859 
860     atf_fs_stat_fini(&s2);
861     atf_fs_stat_fini(&s1);
862     atf_fs_path_fini(&p2);
863     atf_fs_path_fini(&p1);
864 }
865 
866 ATF_TC(mkdtemp_err);
867 ATF_TC_HEAD(mkdtemp_err, tc)
868 {
869     atf_tc_set_md_var(tc, "descr", "Tests the atf_fs_mkdtemp function, "
870                       "error conditions");
871     atf_tc_set_md_var(tc, "require.user", "unprivileged");
872 }
873 ATF_TC_BODY(mkdtemp_err, tc)
874 {
875     atf_error_t err;
876     atf_fs_path_t p;
877 
878     ATF_REQUIRE(mkdir("dir", 0555) != -1);
879 
880     RE(atf_fs_path_init_fmt(&p, "dir/testdir.XXXXXX"));
881 
882     err = atf_fs_mkdtemp(&p);
883     ATF_REQUIRE(atf_is_error(err));
884     ATF_REQUIRE(atf_error_is(err, "libc"));
885     ATF_CHECK_EQ(atf_libc_error_code(err), EACCES);
886     atf_error_free(err);
887 
888     ATF_CHECK(!exists(&p));
889     ATF_CHECK(strcmp(atf_fs_path_cstring(&p), "dir/testdir.XXXXXX") == 0);
890 
891     atf_fs_path_fini(&p);
892 }
893 
894 static
895 void
896 do_umask_check(atf_error_t (*const mk_func)(atf_fs_path_t *),
897                atf_fs_path_t *path, const mode_t test_mask,
898                const char *str_mask, const char *exp_name)
899 {
900     char buf[1024];
901     int old_umask;
902     atf_error_t err;
903 
904     printf("Creating temporary %s with umask %s\n", exp_name, str_mask);
905 
906     old_umask = umask(test_mask);
907     err = mk_func(path);
908     (void)umask(old_umask);
909 
910     ATF_REQUIRE(atf_is_error(err));
911     ATF_REQUIRE(atf_error_is(err, "invalid_umask"));
912     atf_error_format(err, buf, sizeof(buf));
913     ATF_CHECK(strstr(buf, exp_name) != NULL);
914     ATF_CHECK(strstr(buf, str_mask) != NULL);
915     atf_error_free(err);
916 }
917 
918 ATF_TC(mkdtemp_umask);
919 ATF_TC_HEAD(mkdtemp_umask, tc)
920 {
921     atf_tc_set_md_var(tc, "descr", "Tests the atf_fs_mkdtemp function "
922                       "causing an error due to a too strict umask");
923 }
924 ATF_TC_BODY(mkdtemp_umask, tc)
925 {
926     atf_fs_path_t p;
927 
928     RE(atf_fs_path_init_fmt(&p, "testdir.XXXXXX"));
929 
930     do_umask_check(atf_fs_mkdtemp, &p, 00100, "00100", "directory");
931     do_umask_check(atf_fs_mkdtemp, &p, 00200, "00200", "directory");
932     do_umask_check(atf_fs_mkdtemp, &p, 00400, "00400", "directory");
933     do_umask_check(atf_fs_mkdtemp, &p, 00500, "00500", "directory");
934     do_umask_check(atf_fs_mkdtemp, &p, 00600, "00600", "directory");
935 
936     atf_fs_path_fini(&p);
937 }
938 
939 ATF_TC(mkstemp_ok);
940 ATF_TC_HEAD(mkstemp_ok, tc)
941 {
942     atf_tc_set_md_var(tc, "descr", "Tests the atf_fs_mkstemp function, "
943                       "successful execution");
944 }
945 ATF_TC_BODY(mkstemp_ok, tc)
946 {
947     int fd1, fd2;
948     atf_fs_path_t p1, p2;
949     atf_fs_stat_t s1, s2;
950 
951     RE(atf_fs_path_init_fmt(&p1, "testfile.XXXXXX"));
952     RE(atf_fs_path_init_fmt(&p2, "testfile.XXXXXX"));
953     fd1 = fd2 = -1;
954     RE(atf_fs_mkstemp(&p1, &fd1));
955     RE(atf_fs_mkstemp(&p2, &fd2));
956     ATF_REQUIRE(!atf_equal_fs_path_fs_path(&p1, &p2));
957     ATF_REQUIRE(exists(&p1));
958     ATF_REQUIRE(exists(&p2));
959 
960     ATF_CHECK(fd1 != -1);
961     ATF_CHECK(fd2 != -1);
962     ATF_CHECK(write(fd1, "foo", 3) == 3);
963     ATF_CHECK(write(fd2, "bar", 3) == 3);
964     close(fd1);
965     close(fd2);
966 
967     RE(atf_fs_stat_init(&s1, &p1));
968     ATF_CHECK_EQ(atf_fs_stat_get_type(&s1), atf_fs_stat_reg_type);
969     ATF_CHECK( atf_fs_stat_is_owner_readable(&s1));
970     ATF_CHECK( atf_fs_stat_is_owner_writable(&s1));
971     ATF_CHECK(!atf_fs_stat_is_owner_executable(&s1));
972     ATF_CHECK(!atf_fs_stat_is_group_readable(&s1));
973     ATF_CHECK(!atf_fs_stat_is_group_writable(&s1));
974     ATF_CHECK(!atf_fs_stat_is_group_executable(&s1));
975     ATF_CHECK(!atf_fs_stat_is_other_readable(&s1));
976     ATF_CHECK(!atf_fs_stat_is_other_writable(&s1));
977     ATF_CHECK(!atf_fs_stat_is_other_executable(&s1));
978 
979     RE(atf_fs_stat_init(&s2, &p2));
980     ATF_CHECK_EQ(atf_fs_stat_get_type(&s2), atf_fs_stat_reg_type);
981     ATF_CHECK( atf_fs_stat_is_owner_readable(&s2));
982     ATF_CHECK( atf_fs_stat_is_owner_writable(&s2));
983     ATF_CHECK(!atf_fs_stat_is_owner_executable(&s2));
984     ATF_CHECK(!atf_fs_stat_is_group_readable(&s2));
985     ATF_CHECK(!atf_fs_stat_is_group_writable(&s2));
986     ATF_CHECK(!atf_fs_stat_is_group_executable(&s2));
987     ATF_CHECK(!atf_fs_stat_is_other_readable(&s2));
988     ATF_CHECK(!atf_fs_stat_is_other_writable(&s2));
989     ATF_CHECK(!atf_fs_stat_is_other_executable(&s2));
990 
991     atf_fs_stat_fini(&s2);
992     atf_fs_stat_fini(&s1);
993     atf_fs_path_fini(&p2);
994     atf_fs_path_fini(&p1);
995 }
996 
997 ATF_TC(mkstemp_err);
998 ATF_TC_HEAD(mkstemp_err, tc)
999 {
1000     atf_tc_set_md_var(tc, "descr", "Tests the atf_fs_mkstemp function, "
1001                       "error conditions");
1002     atf_tc_set_md_var(tc, "require.user", "unprivileged");
1003 }
1004 ATF_TC_BODY(mkstemp_err, tc)
1005 {
1006     int fd;
1007     atf_error_t err;
1008     atf_fs_path_t p;
1009 
1010     ATF_REQUIRE(mkdir("dir", 0555) != -1);
1011 
1012     RE(atf_fs_path_init_fmt(&p, "dir/testfile.XXXXXX"));
1013     fd = 1234;
1014 
1015     err = atf_fs_mkstemp(&p, &fd);
1016     ATF_REQUIRE(atf_is_error(err));
1017     ATF_REQUIRE(atf_error_is(err, "libc"));
1018     ATF_CHECK_EQ(atf_libc_error_code(err), EACCES);
1019     atf_error_free(err);
1020 
1021     ATF_CHECK(!exists(&p));
1022     ATF_CHECK(strcmp(atf_fs_path_cstring(&p), "dir/testfile.XXXXXX") == 0);
1023     ATF_CHECK_EQ(fd, 1234);
1024 
1025     atf_fs_path_fini(&p);
1026 }
1027 
1028 ATF_TC(mkstemp_umask);
1029 ATF_TC_HEAD(mkstemp_umask, tc)
1030 {
1031     atf_tc_set_md_var(tc, "descr", "Tests the atf_fs_mkstemp function "
1032                       "causing an error due to a too strict umask");
1033 }
1034 ATF_TC_BODY(mkstemp_umask, tc)
1035 {
1036     atf_fs_path_t p;
1037 
1038     RE(atf_fs_path_init_fmt(&p, "testfile.XXXXXX"));
1039 
1040     do_umask_check(mkstemp_discard_fd, &p, 00100, "00100", "regular file");
1041     do_umask_check(mkstemp_discard_fd, &p, 00200, "00200", "regular file");
1042     do_umask_check(mkstemp_discard_fd, &p, 00400, "00400", "regular file");
1043 
1044     atf_fs_path_fini(&p);
1045 }
1046 
1047 /* ---------------------------------------------------------------------
1048  * Main.
1049  * --------------------------------------------------------------------- */
1050 
1051 ATF_TP_ADD_TCS(tp)
1052 {
1053     /* Add the tests for the "atf_fs_path" type. */
1054     ATF_TP_ADD_TC(tp, path_normalize);
1055     ATF_TP_ADD_TC(tp, path_copy);
1056     ATF_TP_ADD_TC(tp, path_is_absolute);
1057     ATF_TP_ADD_TC(tp, path_is_root);
1058     ATF_TP_ADD_TC(tp, path_branch_path);
1059     ATF_TP_ADD_TC(tp, path_leaf_name);
1060     ATF_TP_ADD_TC(tp, path_append);
1061     ATF_TP_ADD_TC(tp, path_to_absolute);
1062     ATF_TP_ADD_TC(tp, path_equal);
1063 
1064     /* Add the tests for the "atf_fs_stat" type. */
1065     ATF_TP_ADD_TC(tp, stat_mode);
1066     ATF_TP_ADD_TC(tp, stat_type);
1067     ATF_TP_ADD_TC(tp, stat_perms);
1068 
1069     /* Add the tests for the free functions. */
1070     ATF_TP_ADD_TC(tp, eaccess);
1071     ATF_TP_ADD_TC(tp, exists);
1072     ATF_TP_ADD_TC(tp, getcwd);
1073     ATF_TP_ADD_TC(tp, rmdir_empty);
1074     ATF_TP_ADD_TC(tp, rmdir_enotempty);
1075     ATF_TP_ADD_TC(tp, rmdir_eperm);
1076     ATF_TP_ADD_TC(tp, mkdtemp_ok);
1077     ATF_TP_ADD_TC(tp, mkdtemp_err);
1078     ATF_TP_ADD_TC(tp, mkdtemp_umask);
1079     ATF_TP_ADD_TC(tp, mkstemp_ok);
1080     ATF_TP_ADD_TC(tp, mkstemp_err);
1081     ATF_TP_ADD_TC(tp, mkstemp_umask);
1082 
1083     return atf_no_error();
1084 }
1085