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