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