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