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