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