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