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 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} 889