Home | History | Annotate | Line # | Download | only in detail
      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 #if defined(HAVE_CONFIG_H)
     31 #include "bconfig.h"
     32 #endif
     33 
     34 #include <sys/types.h>
     35 #include <sys/param.h>
     36 #include <sys/mount.h>
     37 #include <sys/stat.h>
     38 #include <sys/wait.h>
     39 
     40 #include <dirent.h>
     41 #include <errno.h>
     42 #include <libgen.h>
     43 #include <stdarg.h>
     44 #include <stdio.h>
     45 #include <stdlib.h>
     46 #include <string.h>
     47 #include <unistd.h>
     48 
     49 #include "atf-c/defs.h"
     50 #include "atf-c/error.h"
     51 
     52 #include "fs.h"
     53 #include "sanity.h"
     54 #include "text.h"
     55 #include "user.h"
     56 
     57 /* ---------------------------------------------------------------------
     58  * Prototypes for auxiliary functions.
     59  * --------------------------------------------------------------------- */
     60 
     61 static bool check_umask(const mode_t, const mode_t);
     62 static atf_error_t copy_contents(const atf_fs_path_t *, char **);
     63 static mode_t current_umask(void);
     64 static atf_error_t do_mkdtemp(char *);
     65 static atf_error_t normalize(atf_dynstr_t *, char *);
     66 static atf_error_t normalize_ap(atf_dynstr_t *, const char *, va_list)
     67     ATF_DEFS_ATTRIBUTE_FORMAT_PRINTF(2, 0);
     68 static void replace_contents(atf_fs_path_t *, const char *);
     69 static const char *stat_type_to_string(const int);
     70 
     71 /* ---------------------------------------------------------------------
     72  * The "invalid_umask" error type.
     73  * --------------------------------------------------------------------- */
     74 
     75 struct invalid_umask_error_data {
     76     /* One of atf_fs_stat_*_type. */
     77     int m_type;
     78 
     79     /* The original path causing the error. */
     80     /* XXX: Ideally this would be an atf_fs_path_t, but if we create it
     81      * from the error constructor, we cannot delete the path later on.
     82      * Can't remember why atf_error_new does not take a hook for
     83      * deletion. */
     84     char m_path[1024];
     85 
     86     /* The umask that caused the error. */
     87     mode_t m_umask;
     88 };
     89 typedef struct invalid_umask_error_data invalid_umask_error_data_t;
     90 
     91 static
     92 void
     93 invalid_umask_format(const atf_error_t err, char *buf, size_t buflen)
     94 {
     95     const invalid_umask_error_data_t *data;
     96 
     97     PRE(atf_error_is(err, "invalid_umask"));
     98 
     99     data = atf_error_data(err);
    100     snprintf(buf, buflen, "Could not create the temporary %s %s because "
    101              "it will not have enough access rights due to the current "
    102              "umask %05o", stat_type_to_string(data->m_type),
    103              data->m_path, (unsigned int)data->m_umask);
    104 }
    105 
    106 static
    107 atf_error_t
    108 invalid_umask_error(const atf_fs_path_t *path, const int type,
    109                     const mode_t failing_mask)
    110 {
    111     atf_error_t err;
    112     invalid_umask_error_data_t data;
    113 
    114     data.m_type = type;
    115 
    116     strncpy(data.m_path, atf_fs_path_cstring(path), sizeof(data.m_path));
    117     data.m_path[sizeof(data.m_path) - 1] = '\0';
    118 
    119     data.m_umask = failing_mask;
    120 
    121     err = atf_error_new("invalid_umask", &data, sizeof(data),
    122                         invalid_umask_format);
    123 
    124     return err;
    125 }
    126 
    127 /* ---------------------------------------------------------------------
    128  * The "unknown_file_type" error type.
    129  * --------------------------------------------------------------------- */
    130 
    131 struct unknown_type_error_data {
    132     const char *m_path;
    133     int m_type;
    134 };
    135 typedef struct unknown_type_error_data unknown_type_error_data_t;
    136 
    137 static
    138 void
    139 unknown_type_format(const atf_error_t err, char *buf, size_t buflen)
    140 {
    141     const unknown_type_error_data_t *data;
    142 
    143     PRE(atf_error_is(err, "unknown_type"));
    144 
    145     data = atf_error_data(err);
    146     snprintf(buf, buflen, "Unknown file type %d of %s", data->m_type,
    147              data->m_path);
    148 }
    149 
    150 static
    151 atf_error_t
    152 unknown_type_error(const char *path, int type)
    153 {
    154     atf_error_t err;
    155     unknown_type_error_data_t data;
    156 
    157     data.m_path = path;
    158     data.m_type = type;
    159 
    160     err = atf_error_new("unknown_type", &data, sizeof(data),
    161                         unknown_type_format);
    162 
    163     return err;
    164 }
    165 
    166 /* ---------------------------------------------------------------------
    167  * Auxiliary functions.
    168  * --------------------------------------------------------------------- */
    169 
    170 static
    171 bool
    172 check_umask(const mode_t exp_mode, const mode_t min_mode)
    173 {
    174     const mode_t actual_mode = (~current_umask() & exp_mode);
    175     return (actual_mode & min_mode) == min_mode;
    176 }
    177 
    178 static
    179 atf_error_t
    180 copy_contents(const atf_fs_path_t *p, char **buf)
    181 {
    182     atf_error_t err;
    183     char *str;
    184 
    185     str = (char *)malloc(atf_dynstr_length(&p->m_data) + 1);
    186     if (str == NULL)
    187         err = atf_no_memory_error();
    188     else {
    189         strcpy(str, atf_dynstr_cstring(&p->m_data));
    190         *buf = str;
    191         err = atf_no_error();
    192     }
    193 
    194     return err;
    195 }
    196 
    197 static
    198 mode_t
    199 current_umask(void)
    200 {
    201     const mode_t current = umask(0);
    202     (void)umask(current);
    203     return current;
    204 }
    205 
    206 static
    207 atf_error_t
    208 do_mkdtemp(char *tmpl)
    209 {
    210     atf_error_t err;
    211 
    212     PRE(strstr(tmpl, "XXXXXX") != NULL);
    213 
    214     if (mkdtemp(tmpl) == NULL)
    215         err = atf_libc_error(errno, "Cannot create temporary directory "
    216                              "with template '%s'", tmpl);
    217     else
    218         err = atf_no_error();
    219 
    220     return err;
    221 }
    222 
    223 static
    224 atf_error_t
    225 do_mkstemp(char *tmpl, int *fdout)
    226 {
    227     atf_error_t err;
    228 
    229     PRE(strstr(tmpl, "XXXXXX") != NULL);
    230 
    231     *fdout = mkstemp(tmpl);
    232     if (*fdout == -1)
    233         err = atf_libc_error(errno, "Cannot create temporary file "
    234                              "with template '%s'", tmpl);
    235 
    236     else
    237         err = atf_no_error();
    238 
    239     return err;
    240 }
    241 
    242 static
    243 atf_error_t
    244 normalize(atf_dynstr_t *d, char *p)
    245 {
    246     const char *ptr;
    247     char *last;
    248     atf_error_t err;
    249     bool first;
    250 
    251     PRE(strlen(p) > 0);
    252     PRE(atf_dynstr_length(d) == 0);
    253 
    254     if (p[0] == '/')
    255         err = atf_dynstr_append_fmt(d, "/");
    256     else
    257         err = atf_no_error();
    258 
    259     first = true;
    260     last = NULL; /* Silence GCC warning. */
    261     ptr = strtok_r(p, "/", &last);
    262     while (!atf_is_error(err) && ptr != NULL) {
    263         if (strlen(ptr) > 0) {
    264             err = atf_dynstr_append_fmt(d, "%s%s", first ? "" : "/", ptr);
    265             first = false;
    266         }
    267 
    268         ptr = strtok_r(NULL, "/", &last);
    269     }
    270 
    271     return err;
    272 }
    273 
    274 static
    275 atf_error_t
    276 normalize_ap(atf_dynstr_t *d, const char *p, va_list ap)
    277 {
    278     char *str;
    279     atf_error_t err;
    280     va_list ap2;
    281 
    282     err = atf_dynstr_init(d);
    283     if (atf_is_error(err))
    284         goto out;
    285 
    286     va_copy(ap2, ap);
    287     err = atf_text_format_ap(&str, p, ap2);
    288     va_end(ap2);
    289     if (atf_is_error(err))
    290         atf_dynstr_fini(d);
    291     else {
    292         err = normalize(d, str);
    293         free(str);
    294     }
    295 
    296 out:
    297     return err;
    298 }
    299 
    300 static
    301 void
    302 replace_contents(atf_fs_path_t *p, const char *buf)
    303 {
    304     atf_error_t err;
    305 
    306     PRE(atf_dynstr_length(&p->m_data) == strlen(buf));
    307 
    308     atf_dynstr_clear(&p->m_data);
    309     err = atf_dynstr_append_fmt(&p->m_data, "%s", buf);
    310 
    311     INV(!atf_is_error(err));
    312 }
    313 
    314 static
    315 const char *
    316 stat_type_to_string(const int type)
    317 {
    318     const char *str;
    319 
    320     if (type == atf_fs_stat_blk_type)
    321         str = "block device";
    322     else if (type == atf_fs_stat_chr_type)
    323         str = "character device";
    324     else if (type == atf_fs_stat_dir_type)
    325         str = "directory";
    326     else if (type == atf_fs_stat_fifo_type)
    327         str = "named pipe";
    328     else if (type == atf_fs_stat_lnk_type)
    329         str = "symbolic link";
    330     else if (type == atf_fs_stat_reg_type)
    331         str = "regular file";
    332     else if (type == atf_fs_stat_sock_type)
    333         str = "socket";
    334     else if (type == atf_fs_stat_wht_type)
    335         str = "whiteout";
    336     else {
    337         UNREACHABLE;
    338         str = NULL;
    339     }
    340 
    341     return str;
    342 }
    343 
    344 /* ---------------------------------------------------------------------
    345  * The "atf_fs_path" type.
    346  * --------------------------------------------------------------------- */
    347 
    348 /*
    349  * Constructors/destructors.
    350  */
    351 
    352 atf_error_t
    353 atf_fs_path_init_ap(atf_fs_path_t *p, const char *fmt, va_list ap)
    354 {
    355     atf_error_t err;
    356     va_list ap2;
    357 
    358     va_copy(ap2, ap);
    359     err = normalize_ap(&p->m_data, fmt, ap2);
    360     va_end(ap2);
    361 
    362     return err;
    363 }
    364 
    365 atf_error_t
    366 atf_fs_path_init_fmt(atf_fs_path_t *p, const char *fmt, ...)
    367 {
    368     va_list ap;
    369     atf_error_t err;
    370 
    371     va_start(ap, fmt);
    372     err = atf_fs_path_init_ap(p, fmt, ap);
    373     va_end(ap);
    374 
    375     return err;
    376 }
    377 
    378 atf_error_t
    379 atf_fs_path_copy(atf_fs_path_t *dest, const atf_fs_path_t *src)
    380 {
    381     return atf_dynstr_copy(&dest->m_data, &src->m_data);
    382 }
    383 
    384 void
    385 atf_fs_path_fini(atf_fs_path_t *p)
    386 {
    387     atf_dynstr_fini(&p->m_data);
    388 }
    389 
    390 /*
    391  * Getters.
    392  */
    393 
    394 atf_error_t
    395 atf_fs_path_branch_path(const atf_fs_path_t *p, atf_fs_path_t *bp)
    396 {
    397     const size_t endpos = atf_dynstr_rfind_ch(&p->m_data, '/');
    398     atf_error_t err;
    399 
    400     if (endpos == atf_dynstr_npos)
    401         err = atf_fs_path_init_fmt(bp, ".");
    402     else if (endpos == 0)
    403         err = atf_fs_path_init_fmt(bp, "/");
    404     else
    405         err = atf_dynstr_init_substr(&bp->m_data, &p->m_data, 0, endpos);
    406 
    407 #if defined(HAVE_CONST_DIRNAME)
    408     INV(atf_equal_dynstr_cstring(&bp->m_data,
    409                                  dirname(atf_dynstr_cstring(&p->m_data))));
    410 #endif /* defined(HAVE_CONST_DIRNAME) */
    411 
    412     return err;
    413 }
    414 
    415 const char *
    416 atf_fs_path_cstring(const atf_fs_path_t *p)
    417 {
    418     return atf_dynstr_cstring(&p->m_data);
    419 }
    420 
    421 atf_error_t
    422 atf_fs_path_leaf_name(const atf_fs_path_t *p, atf_dynstr_t *ln)
    423 {
    424     size_t begpos = atf_dynstr_rfind_ch(&p->m_data, '/');
    425     atf_error_t err;
    426 
    427     if (begpos == atf_dynstr_npos)
    428         begpos = 0;
    429     else
    430         begpos++;
    431 
    432     err = atf_dynstr_init_substr(ln, &p->m_data, begpos, atf_dynstr_npos);
    433 
    434 #if defined(HAVE_CONST_BASENAME)
    435     INV(atf_equal_dynstr_cstring(ln,
    436                                  basename(atf_dynstr_cstring(&p->m_data))));
    437 #endif /* defined(HAVE_CONST_BASENAME) */
    438 
    439     return err;
    440 }
    441 
    442 bool
    443 atf_fs_path_is_absolute(const atf_fs_path_t *p)
    444 {
    445     return atf_dynstr_cstring(&p->m_data)[0] == '/';
    446 }
    447 
    448 bool
    449 atf_fs_path_is_root(const atf_fs_path_t *p)
    450 {
    451     return atf_equal_dynstr_cstring(&p->m_data, "/");
    452 }
    453 
    454 /*
    455  * Modifiers.
    456  */
    457 
    458 atf_error_t
    459 atf_fs_path_append_ap(atf_fs_path_t *p, const char *fmt, va_list ap)
    460 {
    461     atf_dynstr_t aux;
    462     atf_error_t err;
    463     va_list ap2;
    464 
    465     va_copy(ap2, ap);
    466     err = normalize_ap(&aux, fmt, ap2);
    467     va_end(ap2);
    468     if (!atf_is_error(err)) {
    469         const char *auxstr = atf_dynstr_cstring(&aux);
    470         const bool needslash = auxstr[0] != '/';
    471 
    472         err = atf_dynstr_append_fmt(&p->m_data, "%s%s",
    473                                     needslash ? "/" : "", auxstr);
    474 
    475         atf_dynstr_fini(&aux);
    476     }
    477 
    478     return err;
    479 }
    480 
    481 atf_error_t
    482 atf_fs_path_append_fmt(atf_fs_path_t *p, const char *fmt, ...)
    483 {
    484     va_list ap;
    485     atf_error_t err;
    486 
    487     va_start(ap, fmt);
    488     err = atf_fs_path_append_ap(p, fmt, ap);
    489     va_end(ap);
    490 
    491     return err;
    492 }
    493 
    494 atf_error_t
    495 atf_fs_path_append_path(atf_fs_path_t *p, const atf_fs_path_t *p2)
    496 {
    497     return atf_fs_path_append_fmt(p, "%s", atf_dynstr_cstring(&p2->m_data));
    498 }
    499 
    500 atf_error_t
    501 atf_fs_path_to_absolute(const atf_fs_path_t *p, atf_fs_path_t *pa)
    502 {
    503     atf_error_t err;
    504 
    505     PRE(!atf_fs_path_is_absolute(p));
    506 
    507     err = atf_fs_getcwd(pa);
    508     if (atf_is_error(err))
    509         goto out;
    510 
    511     err = atf_fs_path_append_path(pa, p);
    512     if (atf_is_error(err))
    513         atf_fs_path_fini(pa);
    514 
    515 out:
    516     return err;
    517 }
    518 
    519 /*
    520  * Operators.
    521  */
    522 
    523 bool atf_equal_fs_path_fs_path(const atf_fs_path_t *p1,
    524                                const atf_fs_path_t *p2)
    525 {
    526     return atf_equal_dynstr_dynstr(&p1->m_data, &p2->m_data);
    527 }
    528 
    529 /* ---------------------------------------------------------------------
    530  * The "atf_fs_path" type.
    531  * --------------------------------------------------------------------- */
    532 
    533 /*
    534  * Constants.
    535  */
    536 
    537 const int atf_fs_stat_blk_type  = 1;
    538 const int atf_fs_stat_chr_type  = 2;
    539 const int atf_fs_stat_dir_type  = 3;
    540 const int atf_fs_stat_fifo_type = 4;
    541 const int atf_fs_stat_lnk_type  = 5;
    542 const int atf_fs_stat_reg_type  = 6;
    543 const int atf_fs_stat_sock_type = 7;
    544 const int atf_fs_stat_wht_type  = 8;
    545 
    546 /*
    547  * Constructors/destructors.
    548  */
    549 
    550 atf_error_t
    551 atf_fs_stat_init(atf_fs_stat_t *st, const atf_fs_path_t *p)
    552 {
    553     atf_error_t err;
    554     const char *pstr = atf_fs_path_cstring(p);
    555 
    556     if (lstat(pstr, &st->m_sb) == -1) {
    557         err = atf_libc_error(errno, "Cannot get information of %s; "
    558                              "lstat(2) failed", pstr);
    559     } else {
    560         int type = st->m_sb.st_mode & S_IFMT;
    561         err = atf_no_error();
    562         switch (type) {
    563             case S_IFBLK:  st->m_type = atf_fs_stat_blk_type;  break;
    564             case S_IFCHR:  st->m_type = atf_fs_stat_chr_type;  break;
    565             case S_IFDIR:  st->m_type = atf_fs_stat_dir_type;  break;
    566             case S_IFIFO:  st->m_type = atf_fs_stat_fifo_type; break;
    567             case S_IFLNK:  st->m_type = atf_fs_stat_lnk_type;  break;
    568             case S_IFREG:  st->m_type = atf_fs_stat_reg_type;  break;
    569             case S_IFSOCK: st->m_type = atf_fs_stat_sock_type; break;
    570 #if defined(S_IFWHT)
    571             case S_IFWHT:  st->m_type = atf_fs_stat_wht_type;  break;
    572 #endif
    573             default:
    574                 err = unknown_type_error(pstr, type);
    575         }
    576     }
    577 
    578     return err;
    579 }
    580 
    581 void
    582 atf_fs_stat_copy(atf_fs_stat_t *dest, const atf_fs_stat_t *src)
    583 {
    584     dest->m_type = src->m_type;
    585     dest->m_sb = src->m_sb;
    586 }
    587 
    588 void
    589 atf_fs_stat_fini(atf_fs_stat_t *st ATF_DEFS_ATTRIBUTE_UNUSED)
    590 {
    591 }
    592 
    593 /*
    594  * Getters.
    595  */
    596 
    597 dev_t
    598 atf_fs_stat_get_device(const atf_fs_stat_t *st)
    599 {
    600     return st->m_sb.st_dev;
    601 }
    602 
    603 ino_t
    604 atf_fs_stat_get_inode(const atf_fs_stat_t *st)
    605 {
    606     return st->m_sb.st_ino;
    607 }
    608 
    609 mode_t
    610 atf_fs_stat_get_mode(const atf_fs_stat_t *st)
    611 {
    612     return st->m_sb.st_mode & ~S_IFMT;
    613 }
    614 
    615 off_t
    616 atf_fs_stat_get_size(const atf_fs_stat_t *st)
    617 {
    618     return st->m_sb.st_size;
    619 }
    620 
    621 int
    622 atf_fs_stat_get_type(const atf_fs_stat_t *st)
    623 {
    624     return st->m_type;
    625 }
    626 
    627 bool
    628 atf_fs_stat_is_owner_readable(const atf_fs_stat_t *st)
    629 {
    630     return st->m_sb.st_mode & S_IRUSR;
    631 }
    632 
    633 bool
    634 atf_fs_stat_is_owner_writable(const atf_fs_stat_t *st)
    635 {
    636     return st->m_sb.st_mode & S_IWUSR;
    637 }
    638 
    639 bool
    640 atf_fs_stat_is_owner_executable(const atf_fs_stat_t *st)
    641 {
    642     return st->m_sb.st_mode & S_IXUSR;
    643 }
    644 
    645 bool
    646 atf_fs_stat_is_group_readable(const atf_fs_stat_t *st)
    647 {
    648     return st->m_sb.st_mode & S_IRGRP;
    649 }
    650 
    651 bool
    652 atf_fs_stat_is_group_writable(const atf_fs_stat_t *st)
    653 {
    654     return st->m_sb.st_mode & S_IWGRP;
    655 }
    656 
    657 bool
    658 atf_fs_stat_is_group_executable(const atf_fs_stat_t *st)
    659 {
    660     return st->m_sb.st_mode & S_IXGRP;
    661 }
    662 
    663 bool
    664 atf_fs_stat_is_other_readable(const atf_fs_stat_t *st)
    665 {
    666     return st->m_sb.st_mode & S_IROTH;
    667 }
    668 
    669 bool
    670 atf_fs_stat_is_other_writable(const atf_fs_stat_t *st)
    671 {
    672     return st->m_sb.st_mode & S_IWOTH;
    673 }
    674 
    675 bool
    676 atf_fs_stat_is_other_executable(const atf_fs_stat_t *st)
    677 {
    678     return st->m_sb.st_mode & S_IXOTH;
    679 }
    680 
    681 /* ---------------------------------------------------------------------
    682  * Free functions.
    683  * --------------------------------------------------------------------- */
    684 
    685 const int atf_fs_access_f = 1 << 0;
    686 const int atf_fs_access_r = 1 << 1;
    687 const int atf_fs_access_w = 1 << 2;
    688 const int atf_fs_access_x = 1 << 3;
    689 
    690 /*
    691  * An implementation of access(2) but using the effective user value
    692  * instead of the real one.  Also avoids false positives for root when
    693  * asking for execute permissions, which appear in SunOS.
    694  */
    695 atf_error_t
    696 atf_fs_eaccess(const atf_fs_path_t *p, int mode)
    697 {
    698     atf_error_t err;
    699     struct stat st;
    700     bool ok;
    701 
    702     PRE(mode & atf_fs_access_f || mode & atf_fs_access_r ||
    703         mode & atf_fs_access_w || mode & atf_fs_access_x);
    704 
    705     if (lstat(atf_fs_path_cstring(p), &st) == -1) {
    706         err = atf_libc_error(errno, "Cannot get information from file %s",
    707                              atf_fs_path_cstring(p));
    708         goto out;
    709     }
    710 
    711     err = atf_no_error();
    712 
    713     /* Early return if we are only checking for existence and the file
    714      * exists (stat call returned). */
    715     if (mode & atf_fs_access_f)
    716         goto out;
    717 
    718     ok = false;
    719     if (atf_user_is_root()) {
    720         if (!ok && !(mode & atf_fs_access_x)) {
    721             /* Allow root to read/write any file. */
    722             ok = true;
    723         }
    724 
    725         if (!ok && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) {
    726             /* Allow root to execute the file if any of its execution bits
    727              * are set. */
    728             ok = true;
    729         }
    730     } else {
    731         if (!ok && (atf_user_euid() == st.st_uid)) {
    732             ok = ((mode & atf_fs_access_r) && (st.st_mode & S_IRUSR)) ||
    733                  ((mode & atf_fs_access_w) && (st.st_mode & S_IWUSR)) ||
    734                  ((mode & atf_fs_access_x) && (st.st_mode & S_IXUSR));
    735         }
    736         if (!ok && atf_user_is_member_of_group(st.st_gid)) {
    737             ok = ((mode & atf_fs_access_r) && (st.st_mode & S_IRGRP)) ||
    738                  ((mode & atf_fs_access_w) && (st.st_mode & S_IWGRP)) ||
    739                  ((mode & atf_fs_access_x) && (st.st_mode & S_IXGRP));
    740         }
    741         if (!ok && ((atf_user_euid() != st.st_uid) &&
    742                     !atf_user_is_member_of_group(st.st_gid))) {
    743             ok = ((mode & atf_fs_access_r) && (st.st_mode & S_IROTH)) ||
    744                  ((mode & atf_fs_access_w) && (st.st_mode & S_IWOTH)) ||
    745                  ((mode & atf_fs_access_x) && (st.st_mode & S_IXOTH));
    746         }
    747     }
    748 
    749     if (!ok)
    750         err = atf_libc_error(EACCES, "Access check failed");
    751 
    752 out:
    753     return err;
    754 }
    755 
    756 atf_error_t
    757 atf_fs_exists(const atf_fs_path_t *p, bool *b)
    758 {
    759     atf_error_t err;
    760 
    761     err = atf_fs_eaccess(p, atf_fs_access_f);
    762     if (atf_is_error(err)) {
    763         if (atf_error_is(err, "libc") && atf_libc_error_code(err) == ENOENT) {
    764             atf_error_free(err);
    765             err = atf_no_error();
    766             *b = false;
    767         }
    768     } else
    769         *b = true;
    770 
    771     return err;
    772 }
    773 
    774 atf_error_t
    775 atf_fs_getcwd(atf_fs_path_t *p)
    776 {
    777     atf_error_t err;
    778     char *cwd;
    779 
    780 #if defined(HAVE_GETCWD_DYN)
    781     cwd = getcwd(NULL, 0);
    782 #else
    783     cwd = getcwd(NULL, MAXPATHLEN);
    784 #endif
    785     if (cwd == NULL) {
    786         err = atf_libc_error(errno, "Cannot determine current directory");
    787         goto out;
    788     }
    789 
    790     err = atf_fs_path_init_fmt(p, "%s", cwd);
    791     free(cwd);
    792 
    793 out:
    794     return err;
    795 }
    796 
    797 atf_error_t
    798 atf_fs_mkdtemp(atf_fs_path_t *p)
    799 {
    800     atf_error_t err;
    801     char *buf;
    802 
    803     if (!check_umask(S_IRWXU, S_IRWXU)) {
    804         err = invalid_umask_error(p, atf_fs_stat_dir_type, current_umask());
    805         goto out;
    806     }
    807 
    808     err = copy_contents(p, &buf);
    809     if (atf_is_error(err))
    810         goto out;
    811 
    812     err = do_mkdtemp(buf);
    813     if (atf_is_error(err))
    814         goto out_buf;
    815 
    816     replace_contents(p, buf);
    817 
    818     INV(!atf_is_error(err));
    819 out_buf:
    820     free(buf);
    821 out:
    822     return err;
    823 }
    824 
    825 atf_error_t
    826 atf_fs_mkstemp(atf_fs_path_t *p, int *fdout)
    827 {
    828     atf_error_t err;
    829     char *buf;
    830     int fd;
    831 
    832     if (!check_umask(S_IRWXU, S_IRWXU)) {
    833         err = invalid_umask_error(p, atf_fs_stat_reg_type, current_umask());
    834         goto out;
    835     }
    836 
    837     err = copy_contents(p, &buf);
    838     if (atf_is_error(err))
    839         goto out;
    840 
    841     err = do_mkstemp(buf, &fd);
    842     if (atf_is_error(err))
    843         goto out_buf;
    844 
    845     replace_contents(p, buf);
    846     *fdout = fd;
    847 
    848     INV(!atf_is_error(err));
    849 out_buf:
    850     free(buf);
    851 out:
    852     return err;
    853 }
    854 
    855 atf_error_t
    856 atf_fs_rmdir(const atf_fs_path_t *p)
    857 {
    858     atf_error_t err;
    859 
    860     if (rmdir(atf_fs_path_cstring(p))) {
    861         if (errno == EEXIST) {
    862             /* Some operating systems (e.g. OpenSolaris 200906) return
    863              * EEXIST instead of ENOTEMPTY for non-empty directories.
    864              * Homogenize the return value so that callers don't need
    865              * to bother about differences in operating systems. */
    866             errno = ENOTEMPTY;
    867         }
    868         err = atf_libc_error(errno, "Cannot remove directory");
    869     } else
    870         err = atf_no_error();
    871 
    872     return err;
    873 }
    874 
    875 atf_error_t
    876 atf_fs_unlink(const atf_fs_path_t *p)
    877 {
    878     atf_error_t err;
    879     const char *path;
    880 
    881     path = atf_fs_path_cstring(p);
    882 
    883     if (unlink(path) != 0)
    884         err = atf_libc_error(errno, "Cannot unlink file: '%s'", path);
    885     else
    886         err = atf_no_error();
    887 
    888     return err;
    889 }
    890