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