Deleted Added
full compact
fs.c (240120) fs.c (273929)
1/*
2 * Automated Testing Framework (atf)
3 *
4 * Copyright (c) 2007 The NetBSD Foundation, Inc.
1/* 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
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
27 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
24 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
29
25
26#include "atf-c/detail/fs.h"
27
30#if defined(HAVE_CONFIG_H)
28#if defined(HAVE_CONFIG_H)
31#include "bconfig.h"
29#include "config.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"
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"
50#include "atf-c/error.h"
51
51#include "atf-c/error.h"
52
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
61static bool check_umask(const mode_t, const mode_t);
62static atf_error_t copy_contents(const atf_fs_path_t *, char **);
63static mode_t current_umask(void);
64static atf_error_t do_mkdtemp(char *);
65static atf_error_t normalize(atf_dynstr_t *, char *);
66static atf_error_t normalize_ap(atf_dynstr_t *, const char *, va_list);
67static void replace_contents(atf_fs_path_t *, const char *);
68static const char *stat_type_to_string(const int);
69
70/* ---------------------------------------------------------------------
71 * The "invalid_umask" error type.
72 * --------------------------------------------------------------------- */
73
74struct 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};
88typedef struct invalid_umask_error_data invalid_umask_error_data_t;
89
90static
91void
92invalid_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
105static
106atf_error_t
107invalid_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
130struct unknown_type_error_data {
131 const char *m_path;
132 int m_type;
133};
134typedef struct unknown_type_error_data unknown_type_error_data_t;
135
136static
137void
138unknown_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
149static
150atf_error_t
151unknown_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
169static
170bool
171check_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
177static
178atf_error_t
179copy_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
196static
197mode_t
198current_umask(void)
199{
200 const mode_t current = umask(0);
201 (void)umask(current);
202 return current;
203}
204
205static
206atf_error_t
207do_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
222static
223atf_error_t
224do_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
241static
242atf_error_t
243normalize(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
273static
274atf_error_t
275normalize_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
295out:
296 return err;
297}
298
299static
300void
301replace_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
313static
314const char *
315stat_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
351atf_error_t
352atf_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
364atf_error_t
365atf_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
377atf_error_t
378atf_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
383void
384atf_fs_path_fini(atf_fs_path_t *p)
385{
386 atf_dynstr_fini(&p->m_data);
387}
388
389/*
390 * Getters.
391 */
392
393atf_error_t
394atf_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
414const char *
415atf_fs_path_cstring(const atf_fs_path_t *p)
416{
417 return atf_dynstr_cstring(&p->m_data);
418}
419
420atf_error_t
421atf_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
441bool
442atf_fs_path_is_absolute(const atf_fs_path_t *p)
443{
444 return atf_dynstr_cstring(&p->m_data)[0] == '/';
445}
446
447bool
448atf_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
457atf_error_t
458atf_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
480atf_error_t
481atf_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
493atf_error_t
494atf_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
499atf_error_t
500atf_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
514out:
515 return err;
516}
517
518/*
519 * Operators.
520 */
521
522bool 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
536const int atf_fs_stat_blk_type = 1;
537const int atf_fs_stat_chr_type = 2;
538const int atf_fs_stat_dir_type = 3;
539const int atf_fs_stat_fifo_type = 4;
540const int atf_fs_stat_lnk_type = 5;
541const int atf_fs_stat_reg_type = 6;
542const int atf_fs_stat_sock_type = 7;
543const int atf_fs_stat_wht_type = 8;
544
545/*
546 * Constructors/destructors.
547 */
548
549atf_error_t
550atf_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
580void
581atf_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
587void
588atf_fs_stat_fini(atf_fs_stat_t *st ATF_DEFS_ATTRIBUTE_UNUSED)
589{
590}
591
592/*
593 * Getters.
594 */
595
596dev_t
597atf_fs_stat_get_device(const atf_fs_stat_t *st)
598{
599 return st->m_sb.st_dev;
600}
601
602ino_t
603atf_fs_stat_get_inode(const atf_fs_stat_t *st)
604{
605 return st->m_sb.st_ino;
606}
607
608mode_t
609atf_fs_stat_get_mode(const atf_fs_stat_t *st)
610{
611 return st->m_sb.st_mode & ~S_IFMT;
612}
613
614off_t
615atf_fs_stat_get_size(const atf_fs_stat_t *st)
616{
617 return st->m_sb.st_size;
618}
619
620int
621atf_fs_stat_get_type(const atf_fs_stat_t *st)
622{
623 return st->m_type;
624}
625
626bool
627atf_fs_stat_is_owner_readable(const atf_fs_stat_t *st)
628{
629 return st->m_sb.st_mode & S_IRUSR;
630}
631
632bool
633atf_fs_stat_is_owner_writable(const atf_fs_stat_t *st)
634{
635 return st->m_sb.st_mode & S_IWUSR;
636}
637
638bool
639atf_fs_stat_is_owner_executable(const atf_fs_stat_t *st)
640{
641 return st->m_sb.st_mode & S_IXUSR;
642}
643
644bool
645atf_fs_stat_is_group_readable(const atf_fs_stat_t *st)
646{
647 return st->m_sb.st_mode & S_IRGRP;
648}
649
650bool
651atf_fs_stat_is_group_writable(const atf_fs_stat_t *st)
652{
653 return st->m_sb.st_mode & S_IWGRP;
654}
655
656bool
657atf_fs_stat_is_group_executable(const atf_fs_stat_t *st)
658{
659 return st->m_sb.st_mode & S_IXGRP;
660}
661
662bool
663atf_fs_stat_is_other_readable(const atf_fs_stat_t *st)
664{
665 return st->m_sb.st_mode & S_IROTH;
666}
667
668bool
669atf_fs_stat_is_other_writable(const atf_fs_stat_t *st)
670{
671 return st->m_sb.st_mode & S_IWOTH;
672}
673
674bool
675atf_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
684const int atf_fs_access_f = 1 << 0;
685const int atf_fs_access_r = 1 << 1;
686const int atf_fs_access_w = 1 << 2;
687const 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 */
694atf_error_t
695atf_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
751out:
752 return err;
753}
754
755atf_error_t
756atf_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
773atf_error_t
774atf_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
792out:
793 return err;
794}
795
796atf_error_t
797atf_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));
818out_buf:
819 free(buf);
820out:
821 return err;
822}
823
824atf_error_t
825atf_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));
848out_buf:
849 free(buf);
850out:
851 return err;
852}
853
854atf_error_t
855atf_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
874atf_error_t
875atf_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}
53/* ---------------------------------------------------------------------
54 * Prototypes for auxiliary functions.
55 * --------------------------------------------------------------------- */
56
57static bool check_umask(const mode_t, const mode_t);
58static atf_error_t copy_contents(const atf_fs_path_t *, char **);
59static mode_t current_umask(void);
60static atf_error_t do_mkdtemp(char *);
61static atf_error_t normalize(atf_dynstr_t *, char *);
62static atf_error_t normalize_ap(atf_dynstr_t *, const char *, va_list);
63static void replace_contents(atf_fs_path_t *, const char *);
64static const char *stat_type_to_string(const int);
65
66/* ---------------------------------------------------------------------
67 * The "invalid_umask" error type.
68 * --------------------------------------------------------------------- */
69
70struct 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};
84typedef struct invalid_umask_error_data invalid_umask_error_data_t;
85
86static
87void
88invalid_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
101static
102atf_error_t
103invalid_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
126struct unknown_type_error_data {
127 const char *m_path;
128 int m_type;
129};
130typedef struct unknown_type_error_data unknown_type_error_data_t;
131
132static
133void
134unknown_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
145static
146atf_error_t
147unknown_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
165static
166bool
167check_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
173static
174atf_error_t
175copy_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
192static
193mode_t
194current_umask(void)
195{
196 const mode_t current = umask(0);
197 (void)umask(current);
198 return current;
199}
200
201static
202atf_error_t
203do_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
218static
219atf_error_t
220do_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
237static
238atf_error_t
239normalize(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
269static
270atf_error_t
271normalize_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
291out:
292 return err;
293}
294
295static
296void
297replace_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
309static
310const char *
311stat_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
347atf_error_t
348atf_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
360atf_error_t
361atf_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
373atf_error_t
374atf_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
379void
380atf_fs_path_fini(atf_fs_path_t *p)
381{
382 atf_dynstr_fini(&p->m_data);
383}
384
385/*
386 * Getters.
387 */
388
389atf_error_t
390atf_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
410const char *
411atf_fs_path_cstring(const atf_fs_path_t *p)
412{
413 return atf_dynstr_cstring(&p->m_data);
414}
415
416atf_error_t
417atf_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
437bool
438atf_fs_path_is_absolute(const atf_fs_path_t *p)
439{
440 return atf_dynstr_cstring(&p->m_data)[0] == '/';
441}
442
443bool
444atf_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
453atf_error_t
454atf_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
476atf_error_t
477atf_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
489atf_error_t
490atf_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
495atf_error_t
496atf_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
510out:
511 return err;
512}
513
514/*
515 * Operators.
516 */
517
518bool 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
532const int atf_fs_stat_blk_type = 1;
533const int atf_fs_stat_chr_type = 2;
534const int atf_fs_stat_dir_type = 3;
535const int atf_fs_stat_fifo_type = 4;
536const int atf_fs_stat_lnk_type = 5;
537const int atf_fs_stat_reg_type = 6;
538const int atf_fs_stat_sock_type = 7;
539const int atf_fs_stat_wht_type = 8;
540
541/*
542 * Constructors/destructors.
543 */
544
545atf_error_t
546atf_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
576void
577atf_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
583void
584atf_fs_stat_fini(atf_fs_stat_t *st ATF_DEFS_ATTRIBUTE_UNUSED)
585{
586}
587
588/*
589 * Getters.
590 */
591
592dev_t
593atf_fs_stat_get_device(const atf_fs_stat_t *st)
594{
595 return st->m_sb.st_dev;
596}
597
598ino_t
599atf_fs_stat_get_inode(const atf_fs_stat_t *st)
600{
601 return st->m_sb.st_ino;
602}
603
604mode_t
605atf_fs_stat_get_mode(const atf_fs_stat_t *st)
606{
607 return st->m_sb.st_mode & ~S_IFMT;
608}
609
610off_t
611atf_fs_stat_get_size(const atf_fs_stat_t *st)
612{
613 return st->m_sb.st_size;
614}
615
616int
617atf_fs_stat_get_type(const atf_fs_stat_t *st)
618{
619 return st->m_type;
620}
621
622bool
623atf_fs_stat_is_owner_readable(const atf_fs_stat_t *st)
624{
625 return st->m_sb.st_mode & S_IRUSR;
626}
627
628bool
629atf_fs_stat_is_owner_writable(const atf_fs_stat_t *st)
630{
631 return st->m_sb.st_mode & S_IWUSR;
632}
633
634bool
635atf_fs_stat_is_owner_executable(const atf_fs_stat_t *st)
636{
637 return st->m_sb.st_mode & S_IXUSR;
638}
639
640bool
641atf_fs_stat_is_group_readable(const atf_fs_stat_t *st)
642{
643 return st->m_sb.st_mode & S_IRGRP;
644}
645
646bool
647atf_fs_stat_is_group_writable(const atf_fs_stat_t *st)
648{
649 return st->m_sb.st_mode & S_IWGRP;
650}
651
652bool
653atf_fs_stat_is_group_executable(const atf_fs_stat_t *st)
654{
655 return st->m_sb.st_mode & S_IXGRP;
656}
657
658bool
659atf_fs_stat_is_other_readable(const atf_fs_stat_t *st)
660{
661 return st->m_sb.st_mode & S_IROTH;
662}
663
664bool
665atf_fs_stat_is_other_writable(const atf_fs_stat_t *st)
666{
667 return st->m_sb.st_mode & S_IWOTH;
668}
669
670bool
671atf_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
680const int atf_fs_access_f = 1 << 0;
681const int atf_fs_access_r = 1 << 1;
682const int atf_fs_access_w = 1 << 2;
683const 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 */
690atf_error_t
691atf_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
747out:
748 return err;
749}
750
751atf_error_t
752atf_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
769atf_error_t
770atf_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
788out:
789 return err;
790}
791
792atf_error_t
793atf_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));
814out_buf:
815 free(buf);
816out:
817 return err;
818}
819
820atf_error_t
821atf_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));
844out_buf:
845 free(buf);
846out:
847 return err;
848}
849
850atf_error_t
851atf_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
870atf_error_t
871atf_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}