xref: /minix3/external/bsd/atf/dist/atf-c/detail/fs.c (revision e1cdaee10649323af446eb1a74571984b2ab3181)
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
invalid_umask_format(const atf_error_t err,char * buf,size_t buflen)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
invalid_umask_error(const atf_fs_path_t * path,const int type,const mode_t failing_mask)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
unknown_type_format(const atf_error_t err,char * buf,size_t buflen)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
unknown_type_error(const char * path,int type)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
check_umask(const mode_t exp_mode,const mode_t min_mode)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
copy_contents(const atf_fs_path_t * p,char ** buf)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
current_umask(void)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
do_mkdtemp(char * tmpl)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
do_mkstemp(char * tmpl,int * fdout)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
normalize(atf_dynstr_t * d,char * p)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
normalize_ap(atf_dynstr_t * d,const char * p,va_list ap)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
replace_contents(atf_fs_path_t * p,const char * buf)302 replace_contents(atf_fs_path_t *p, const char *buf)
303 {
304 #if !defined(NDEBUG) && defined(__minix)
305     atf_error_t err;
306 
307     PRE(atf_dynstr_length(&p->m_data) == strlen(buf));
308 
309 #endif /* !defined(NDEBUG) && defined(__minix) */
310     atf_dynstr_clear(&p->m_data);
311 #if !defined(NDEBUG) && defined(__minix)
312     err =
313 #endif /* !defined(NDEBUG) && defined(__minix) */
314     	atf_dynstr_append_fmt(&p->m_data, "%s", buf);
315 
316 #if !defined(NDEBUG) && defined(__minix)
317     INV(!atf_is_error(err));
318 #endif /* !defined(NDEBUG) && defined(__minix) */
319 }
320 
321 static
322 const char *
stat_type_to_string(const int type)323 stat_type_to_string(const int type)
324 {
325     const char *str;
326 
327     if (type == atf_fs_stat_blk_type)
328         str = "block device";
329     else if (type == atf_fs_stat_chr_type)
330         str = "character device";
331     else if (type == atf_fs_stat_dir_type)
332         str = "directory";
333     else if (type == atf_fs_stat_fifo_type)
334         str = "named pipe";
335     else if (type == atf_fs_stat_lnk_type)
336         str = "symbolic link";
337     else if (type == atf_fs_stat_reg_type)
338         str = "regular file";
339     else if (type == atf_fs_stat_sock_type)
340         str = "socket";
341     else if (type == atf_fs_stat_wht_type)
342         str = "whiteout";
343     else {
344         UNREACHABLE;
345         str = NULL;
346     }
347 
348     return str;
349 }
350 
351 /* ---------------------------------------------------------------------
352  * The "atf_fs_path" type.
353  * --------------------------------------------------------------------- */
354 
355 /*
356  * Constructors/destructors.
357  */
358 
359 atf_error_t
atf_fs_path_init_ap(atf_fs_path_t * p,const char * fmt,va_list ap)360 atf_fs_path_init_ap(atf_fs_path_t *p, const char *fmt, va_list ap)
361 {
362     atf_error_t err;
363     va_list ap2;
364 
365     va_copy(ap2, ap);
366     err = normalize_ap(&p->m_data, fmt, ap2);
367     va_end(ap2);
368 
369     return err;
370 }
371 
372 atf_error_t
atf_fs_path_init_fmt(atf_fs_path_t * p,const char * fmt,...)373 atf_fs_path_init_fmt(atf_fs_path_t *p, const char *fmt, ...)
374 {
375     va_list ap;
376     atf_error_t err;
377 
378     va_start(ap, fmt);
379     err = atf_fs_path_init_ap(p, fmt, ap);
380     va_end(ap);
381 
382     return err;
383 }
384 
385 atf_error_t
atf_fs_path_copy(atf_fs_path_t * dest,const atf_fs_path_t * src)386 atf_fs_path_copy(atf_fs_path_t *dest, const atf_fs_path_t *src)
387 {
388     return atf_dynstr_copy(&dest->m_data, &src->m_data);
389 }
390 
391 void
atf_fs_path_fini(atf_fs_path_t * p)392 atf_fs_path_fini(atf_fs_path_t *p)
393 {
394     atf_dynstr_fini(&p->m_data);
395 }
396 
397 /*
398  * Getters.
399  */
400 
401 atf_error_t
atf_fs_path_branch_path(const atf_fs_path_t * p,atf_fs_path_t * bp)402 atf_fs_path_branch_path(const atf_fs_path_t *p, atf_fs_path_t *bp)
403 {
404     const size_t endpos = atf_dynstr_rfind_ch(&p->m_data, '/');
405     atf_error_t err;
406 
407     if (endpos == atf_dynstr_npos)
408         err = atf_fs_path_init_fmt(bp, ".");
409     else if (endpos == 0)
410         err = atf_fs_path_init_fmt(bp, "/");
411     else
412         err = atf_dynstr_init_substr(&bp->m_data, &p->m_data, 0, endpos);
413 
414 #if defined(HAVE_CONST_DIRNAME)
415     INV(atf_equal_dynstr_cstring(&bp->m_data,
416                                  dirname(atf_dynstr_cstring(&p->m_data))));
417 #endif /* defined(HAVE_CONST_DIRNAME) */
418 
419     return err;
420 }
421 
422 const char *
atf_fs_path_cstring(const atf_fs_path_t * p)423 atf_fs_path_cstring(const atf_fs_path_t *p)
424 {
425     return atf_dynstr_cstring(&p->m_data);
426 }
427 
428 atf_error_t
atf_fs_path_leaf_name(const atf_fs_path_t * p,atf_dynstr_t * ln)429 atf_fs_path_leaf_name(const atf_fs_path_t *p, atf_dynstr_t *ln)
430 {
431     size_t begpos = atf_dynstr_rfind_ch(&p->m_data, '/');
432     atf_error_t err;
433 
434     if (begpos == atf_dynstr_npos)
435         begpos = 0;
436     else
437         begpos++;
438 
439     err = atf_dynstr_init_substr(ln, &p->m_data, begpos, atf_dynstr_npos);
440 
441 #if defined(HAVE_CONST_BASENAME)
442     INV(atf_equal_dynstr_cstring(ln,
443                                  basename(atf_dynstr_cstring(&p->m_data))));
444 #endif /* defined(HAVE_CONST_BASENAME) */
445 
446     return err;
447 }
448 
449 bool
atf_fs_path_is_absolute(const atf_fs_path_t * p)450 atf_fs_path_is_absolute(const atf_fs_path_t *p)
451 {
452     return atf_dynstr_cstring(&p->m_data)[0] == '/';
453 }
454 
455 bool
atf_fs_path_is_root(const atf_fs_path_t * p)456 atf_fs_path_is_root(const atf_fs_path_t *p)
457 {
458     return atf_equal_dynstr_cstring(&p->m_data, "/");
459 }
460 
461 /*
462  * Modifiers.
463  */
464 
465 atf_error_t
atf_fs_path_append_ap(atf_fs_path_t * p,const char * fmt,va_list ap)466 atf_fs_path_append_ap(atf_fs_path_t *p, const char *fmt, va_list ap)
467 {
468     atf_dynstr_t aux;
469     atf_error_t err;
470     va_list ap2;
471 
472     va_copy(ap2, ap);
473     err = normalize_ap(&aux, fmt, ap2);
474     va_end(ap2);
475     if (!atf_is_error(err)) {
476         const char *auxstr = atf_dynstr_cstring(&aux);
477         const bool needslash = auxstr[0] != '/';
478 
479         err = atf_dynstr_append_fmt(&p->m_data, "%s%s",
480                                     needslash ? "/" : "", auxstr);
481 
482         atf_dynstr_fini(&aux);
483     }
484 
485     return err;
486 }
487 
488 atf_error_t
atf_fs_path_append_fmt(atf_fs_path_t * p,const char * fmt,...)489 atf_fs_path_append_fmt(atf_fs_path_t *p, const char *fmt, ...)
490 {
491     va_list ap;
492     atf_error_t err;
493 
494     va_start(ap, fmt);
495     err = atf_fs_path_append_ap(p, fmt, ap);
496     va_end(ap);
497 
498     return err;
499 }
500 
501 atf_error_t
atf_fs_path_append_path(atf_fs_path_t * p,const atf_fs_path_t * p2)502 atf_fs_path_append_path(atf_fs_path_t *p, const atf_fs_path_t *p2)
503 {
504     return atf_fs_path_append_fmt(p, "%s", atf_dynstr_cstring(&p2->m_data));
505 }
506 
507 atf_error_t
atf_fs_path_to_absolute(const atf_fs_path_t * p,atf_fs_path_t * pa)508 atf_fs_path_to_absolute(const atf_fs_path_t *p, atf_fs_path_t *pa)
509 {
510     atf_error_t err;
511 
512     PRE(!atf_fs_path_is_absolute(p));
513 
514     err = atf_fs_getcwd(pa);
515     if (atf_is_error(err))
516         goto out;
517 
518     err = atf_fs_path_append_path(pa, p);
519     if (atf_is_error(err))
520         atf_fs_path_fini(pa);
521 
522 out:
523     return err;
524 }
525 
526 /*
527  * Operators.
528  */
529 
atf_equal_fs_path_fs_path(const atf_fs_path_t * p1,const atf_fs_path_t * p2)530 bool atf_equal_fs_path_fs_path(const atf_fs_path_t *p1,
531                                const atf_fs_path_t *p2)
532 {
533     return atf_equal_dynstr_dynstr(&p1->m_data, &p2->m_data);
534 }
535 
536 /* ---------------------------------------------------------------------
537  * The "atf_fs_path" type.
538  * --------------------------------------------------------------------- */
539 
540 /*
541  * Constants.
542  */
543 
544 const int atf_fs_stat_blk_type  = 1;
545 const int atf_fs_stat_chr_type  = 2;
546 const int atf_fs_stat_dir_type  = 3;
547 const int atf_fs_stat_fifo_type = 4;
548 const int atf_fs_stat_lnk_type  = 5;
549 const int atf_fs_stat_reg_type  = 6;
550 const int atf_fs_stat_sock_type = 7;
551 const int atf_fs_stat_wht_type  = 8;
552 
553 /*
554  * Constructors/destructors.
555  */
556 
557 atf_error_t
atf_fs_stat_init(atf_fs_stat_t * st,const atf_fs_path_t * p)558 atf_fs_stat_init(atf_fs_stat_t *st, const atf_fs_path_t *p)
559 {
560     atf_error_t err;
561     const char *pstr = atf_fs_path_cstring(p);
562 
563     if (lstat(pstr, &st->m_sb) == -1) {
564         err = atf_libc_error(errno, "Cannot get information of %s; "
565                              "lstat(2) failed", pstr);
566     } else {
567         int type = st->m_sb.st_mode & S_IFMT;
568         err = atf_no_error();
569         switch (type) {
570             case S_IFBLK:  st->m_type = atf_fs_stat_blk_type;  break;
571             case S_IFCHR:  st->m_type = atf_fs_stat_chr_type;  break;
572             case S_IFDIR:  st->m_type = atf_fs_stat_dir_type;  break;
573             case S_IFIFO:  st->m_type = atf_fs_stat_fifo_type; break;
574             case S_IFLNK:  st->m_type = atf_fs_stat_lnk_type;  break;
575             case S_IFREG:  st->m_type = atf_fs_stat_reg_type;  break;
576             case S_IFSOCK: st->m_type = atf_fs_stat_sock_type; break;
577 #if defined(S_IFWHT)
578             case S_IFWHT:  st->m_type = atf_fs_stat_wht_type;  break;
579 #endif
580             default:
581                 err = unknown_type_error(pstr, type);
582         }
583     }
584 
585     return err;
586 }
587 
588 void
atf_fs_stat_copy(atf_fs_stat_t * dest,const atf_fs_stat_t * src)589 atf_fs_stat_copy(atf_fs_stat_t *dest, const atf_fs_stat_t *src)
590 {
591     dest->m_type = src->m_type;
592     dest->m_sb = src->m_sb;
593 }
594 
595 void
atf_fs_stat_fini(atf_fs_stat_t * st ATF_DEFS_ATTRIBUTE_UNUSED)596 atf_fs_stat_fini(atf_fs_stat_t *st ATF_DEFS_ATTRIBUTE_UNUSED)
597 {
598 }
599 
600 /*
601  * Getters.
602  */
603 
604 dev_t
atf_fs_stat_get_device(const atf_fs_stat_t * st)605 atf_fs_stat_get_device(const atf_fs_stat_t *st)
606 {
607     return st->m_sb.st_dev;
608 }
609 
610 ino_t
atf_fs_stat_get_inode(const atf_fs_stat_t * st)611 atf_fs_stat_get_inode(const atf_fs_stat_t *st)
612 {
613     return st->m_sb.st_ino;
614 }
615 
616 mode_t
atf_fs_stat_get_mode(const atf_fs_stat_t * st)617 atf_fs_stat_get_mode(const atf_fs_stat_t *st)
618 {
619     return st->m_sb.st_mode & ~S_IFMT;
620 }
621 
622 off_t
atf_fs_stat_get_size(const atf_fs_stat_t * st)623 atf_fs_stat_get_size(const atf_fs_stat_t *st)
624 {
625     return st->m_sb.st_size;
626 }
627 
628 int
atf_fs_stat_get_type(const atf_fs_stat_t * st)629 atf_fs_stat_get_type(const atf_fs_stat_t *st)
630 {
631     return st->m_type;
632 }
633 
634 bool
atf_fs_stat_is_owner_readable(const atf_fs_stat_t * st)635 atf_fs_stat_is_owner_readable(const atf_fs_stat_t *st)
636 {
637     return st->m_sb.st_mode & S_IRUSR;
638 }
639 
640 bool
atf_fs_stat_is_owner_writable(const atf_fs_stat_t * st)641 atf_fs_stat_is_owner_writable(const atf_fs_stat_t *st)
642 {
643     return st->m_sb.st_mode & S_IWUSR;
644 }
645 
646 bool
atf_fs_stat_is_owner_executable(const atf_fs_stat_t * st)647 atf_fs_stat_is_owner_executable(const atf_fs_stat_t *st)
648 {
649     return st->m_sb.st_mode & S_IXUSR;
650 }
651 
652 bool
atf_fs_stat_is_group_readable(const atf_fs_stat_t * st)653 atf_fs_stat_is_group_readable(const atf_fs_stat_t *st)
654 {
655     return st->m_sb.st_mode & S_IRGRP;
656 }
657 
658 bool
atf_fs_stat_is_group_writable(const atf_fs_stat_t * st)659 atf_fs_stat_is_group_writable(const atf_fs_stat_t *st)
660 {
661     return st->m_sb.st_mode & S_IWGRP;
662 }
663 
664 bool
atf_fs_stat_is_group_executable(const atf_fs_stat_t * st)665 atf_fs_stat_is_group_executable(const atf_fs_stat_t *st)
666 {
667     return st->m_sb.st_mode & S_IXGRP;
668 }
669 
670 bool
atf_fs_stat_is_other_readable(const atf_fs_stat_t * st)671 atf_fs_stat_is_other_readable(const atf_fs_stat_t *st)
672 {
673     return st->m_sb.st_mode & S_IROTH;
674 }
675 
676 bool
atf_fs_stat_is_other_writable(const atf_fs_stat_t * st)677 atf_fs_stat_is_other_writable(const atf_fs_stat_t *st)
678 {
679     return st->m_sb.st_mode & S_IWOTH;
680 }
681 
682 bool
atf_fs_stat_is_other_executable(const atf_fs_stat_t * st)683 atf_fs_stat_is_other_executable(const atf_fs_stat_t *st)
684 {
685     return st->m_sb.st_mode & S_IXOTH;
686 }
687 
688 /* ---------------------------------------------------------------------
689  * Free functions.
690  * --------------------------------------------------------------------- */
691 
692 const int atf_fs_access_f = 1 << 0;
693 const int atf_fs_access_r = 1 << 1;
694 const int atf_fs_access_w = 1 << 2;
695 const int atf_fs_access_x = 1 << 3;
696 
697 /*
698  * An implementation of access(2) but using the effective user value
699  * instead of the real one.  Also avoids false positives for root when
700  * asking for execute permissions, which appear in SunOS.
701  */
702 atf_error_t
atf_fs_eaccess(const atf_fs_path_t * p,int mode)703 atf_fs_eaccess(const atf_fs_path_t *p, int mode)
704 {
705     atf_error_t err;
706     struct stat st;
707     bool ok;
708 
709     PRE(mode & atf_fs_access_f || mode & atf_fs_access_r ||
710         mode & atf_fs_access_w || mode & atf_fs_access_x);
711 
712     if (lstat(atf_fs_path_cstring(p), &st) == -1) {
713         err = atf_libc_error(errno, "Cannot get information from file %s",
714                              atf_fs_path_cstring(p));
715         goto out;
716     }
717 
718     err = atf_no_error();
719 
720     /* Early return if we are only checking for existence and the file
721      * exists (stat call returned). */
722     if (mode & atf_fs_access_f)
723         goto out;
724 
725     ok = false;
726     if (atf_user_is_root()) {
727         if (!ok && !(mode & atf_fs_access_x)) {
728             /* Allow root to read/write any file. */
729             ok = true;
730         }
731 
732         if (!ok && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) {
733             /* Allow root to execute the file if any of its execution bits
734              * are set. */
735             ok = true;
736         }
737     } else {
738         if (!ok && (atf_user_euid() == st.st_uid)) {
739             ok = ((mode & atf_fs_access_r) && (st.st_mode & S_IRUSR)) ||
740                  ((mode & atf_fs_access_w) && (st.st_mode & S_IWUSR)) ||
741                  ((mode & atf_fs_access_x) && (st.st_mode & S_IXUSR));
742         }
743         if (!ok && atf_user_is_member_of_group(st.st_gid)) {
744             ok = ((mode & atf_fs_access_r) && (st.st_mode & S_IRGRP)) ||
745                  ((mode & atf_fs_access_w) && (st.st_mode & S_IWGRP)) ||
746                  ((mode & atf_fs_access_x) && (st.st_mode & S_IXGRP));
747         }
748         if (!ok && ((atf_user_euid() != st.st_uid) &&
749                     !atf_user_is_member_of_group(st.st_gid))) {
750             ok = ((mode & atf_fs_access_r) && (st.st_mode & S_IROTH)) ||
751                  ((mode & atf_fs_access_w) && (st.st_mode & S_IWOTH)) ||
752                  ((mode & atf_fs_access_x) && (st.st_mode & S_IXOTH));
753         }
754     }
755 
756     if (!ok)
757         err = atf_libc_error(EACCES, "Access check failed");
758 
759 out:
760     return err;
761 }
762 
763 atf_error_t
atf_fs_exists(const atf_fs_path_t * p,bool * b)764 atf_fs_exists(const atf_fs_path_t *p, bool *b)
765 {
766     atf_error_t err;
767 
768     err = atf_fs_eaccess(p, atf_fs_access_f);
769     if (atf_is_error(err)) {
770         if (atf_error_is(err, "libc") && atf_libc_error_code(err) == ENOENT) {
771             atf_error_free(err);
772             err = atf_no_error();
773             *b = false;
774         }
775     } else
776         *b = true;
777 
778     return err;
779 }
780 
781 atf_error_t
atf_fs_getcwd(atf_fs_path_t * p)782 atf_fs_getcwd(atf_fs_path_t *p)
783 {
784     atf_error_t err;
785     char *cwd;
786 
787 #if defined(HAVE_GETCWD_DYN)
788     cwd = getcwd(NULL, 0);
789 #else
790     cwd = getcwd(NULL, MAXPATHLEN);
791 #endif
792     if (cwd == NULL) {
793         err = atf_libc_error(errno, "Cannot determine current directory");
794         goto out;
795     }
796 
797     err = atf_fs_path_init_fmt(p, "%s", cwd);
798     free(cwd);
799 
800 out:
801     return err;
802 }
803 
804 atf_error_t
atf_fs_mkdtemp(atf_fs_path_t * p)805 atf_fs_mkdtemp(atf_fs_path_t *p)
806 {
807     atf_error_t err;
808     char *buf = NULL; /* MINIX: Complain in -O3 */
809 
810     if (!check_umask(S_IRWXU, S_IRWXU)) {
811         err = invalid_umask_error(p, atf_fs_stat_dir_type, current_umask());
812         goto out;
813     }
814 
815     err = copy_contents(p, &buf);
816     if (atf_is_error(err))
817         goto out;
818 
819     err = do_mkdtemp(buf);
820     if (atf_is_error(err))
821         goto out_buf;
822 
823     replace_contents(p, buf);
824 
825     INV(!atf_is_error(err));
826 out_buf:
827     free(buf);
828 out:
829     return err;
830 }
831 
832 atf_error_t
atf_fs_mkstemp(atf_fs_path_t * p,int * fdout)833 atf_fs_mkstemp(atf_fs_path_t *p, int *fdout)
834 {
835     atf_error_t err;
836     char *buf = NULL; /* MINIX: Complain in -O3 */
837     int fd;
838 
839     if (!check_umask(S_IRWXU, S_IRWXU)) {
840         err = invalid_umask_error(p, atf_fs_stat_reg_type, current_umask());
841         goto out;
842     }
843 
844     err = copy_contents(p, &buf);
845     if (atf_is_error(err))
846         goto out;
847 
848     err = do_mkstemp(buf, &fd);
849     if (atf_is_error(err))
850         goto out_buf;
851 
852     replace_contents(p, buf);
853     *fdout = fd;
854 
855     INV(!atf_is_error(err));
856 out_buf:
857     free(buf);
858 out:
859     return err;
860 }
861 
862 atf_error_t
atf_fs_rmdir(const atf_fs_path_t * p)863 atf_fs_rmdir(const atf_fs_path_t *p)
864 {
865     atf_error_t err;
866 
867     if (rmdir(atf_fs_path_cstring(p))) {
868         if (errno == EEXIST) {
869             /* Some operating systems (e.g. OpenSolaris 200906) return
870              * EEXIST instead of ENOTEMPTY for non-empty directories.
871              * Homogenize the return value so that callers don't need
872              * to bother about differences in operating systems. */
873             errno = ENOTEMPTY;
874         }
875         err = atf_libc_error(errno, "Cannot remove directory");
876     } else
877         err = atf_no_error();
878 
879     return err;
880 }
881 
882 atf_error_t
atf_fs_unlink(const atf_fs_path_t * p)883 atf_fs_unlink(const atf_fs_path_t *p)
884 {
885     atf_error_t err;
886     const char *path;
887 
888     path = atf_fs_path_cstring(p);
889 
890     if (unlink(path) != 0)
891         err = atf_libc_error(errno, "Cannot unlink file: '%s'", path);
892     else
893         err = atf_no_error();
894 
895     return err;
896 }
897