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