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 bool check_umask(const mode_t, const mode_t); 58 static atf_error_t copy_contents(const atf_fs_path_t *, char **); 59 static mode_t current_umask(void); 60 static atf_error_t do_mkdtemp(char *); 61 static atf_error_t normalize(atf_dynstr_t *, char *); 62 static atf_error_t normalize_ap(atf_dynstr_t *, const char *, va_list); 63 static void replace_contents(atf_fs_path_t *, const char *); 64 static const char *stat_type_to_string(const int); 65 66 /* --------------------------------------------------------------------- 67 * The "invalid_umask" error type. 68 * --------------------------------------------------------------------- */ 69 70 struct 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 }; 84 typedef struct invalid_umask_error_data invalid_umask_error_data_t; 85 86 static 87 void 88 invalid_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 101 static 102 atf_error_t 103 invalid_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 126 struct unknown_type_error_data { 127 const char *m_path; 128 int m_type; 129 }; 130 typedef struct unknown_type_error_data unknown_type_error_data_t; 131 132 static 133 void 134 unknown_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 145 static 146 atf_error_t 147 unknown_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 165 static 166 bool 167 check_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 173 static 174 atf_error_t 175 copy_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 192 static 193 mode_t 194 current_umask(void) 195 { 196 const mode_t current = umask(0); 197 (void)umask(current); 198 return current; 199 } 200 201 static 202 atf_error_t 203 do_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 218 static 219 atf_error_t 220 do_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 237 static 238 atf_error_t 239 normalize(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 269 static 270 atf_error_t 271 normalize_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 291 out: 292 return err; 293 } 294 295 static 296 void 297 replace_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 309 static 310 const char * 311 stat_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 347 atf_error_t 348 atf_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 360 atf_error_t 361 atf_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 373 atf_error_t 374 atf_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 379 void 380 atf_fs_path_fini(atf_fs_path_t *p) 381 { 382 atf_dynstr_fini(&p->m_data); 383 } 384 385 /* 386 * Getters. 387 */ 388 389 atf_error_t 390 atf_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 410 const char * 411 atf_fs_path_cstring(const atf_fs_path_t *p) 412 { 413 return atf_dynstr_cstring(&p->m_data); 414 } 415 416 atf_error_t 417 atf_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 437 bool 438 atf_fs_path_is_absolute(const atf_fs_path_t *p) 439 { 440 return atf_dynstr_cstring(&p->m_data)[0] == '/'; 441 } 442 443 bool 444 atf_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 453 atf_error_t 454 atf_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 476 atf_error_t 477 atf_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 489 atf_error_t 490 atf_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 495 atf_error_t 496 atf_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 510 out: 511 return err; 512 } 513 514 /* 515 * Operators. 516 */ 517 518 bool 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 532 const int atf_fs_stat_blk_type = 1; 533 const int atf_fs_stat_chr_type = 2; 534 const int atf_fs_stat_dir_type = 3; 535 const int atf_fs_stat_fifo_type = 4; 536 const int atf_fs_stat_lnk_type = 5; 537 const int atf_fs_stat_reg_type = 6; 538 const int atf_fs_stat_sock_type = 7; 539 const int atf_fs_stat_wht_type = 8; 540 541 /* 542 * Constructors/destructors. 543 */ 544 545 atf_error_t 546 atf_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 576 void 577 atf_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 583 void 584 atf_fs_stat_fini(atf_fs_stat_t *st ATF_DEFS_ATTRIBUTE_UNUSED) 585 { 586 } 587 588 /* 589 * Getters. 590 */ 591 592 dev_t 593 atf_fs_stat_get_device(const atf_fs_stat_t *st) 594 { 595 return st->m_sb.st_dev; 596 } 597 598 ino_t 599 atf_fs_stat_get_inode(const atf_fs_stat_t *st) 600 { 601 return st->m_sb.st_ino; 602 } 603 604 mode_t 605 atf_fs_stat_get_mode(const atf_fs_stat_t *st) 606 { 607 return st->m_sb.st_mode & ~S_IFMT; 608 } 609 610 off_t 611 atf_fs_stat_get_size(const atf_fs_stat_t *st) 612 { 613 return st->m_sb.st_size; 614 } 615 616 int 617 atf_fs_stat_get_type(const atf_fs_stat_t *st) 618 { 619 return st->m_type; 620 } 621 622 bool 623 atf_fs_stat_is_owner_readable(const atf_fs_stat_t *st) 624 { 625 return st->m_sb.st_mode & S_IRUSR; 626 } 627 628 bool 629 atf_fs_stat_is_owner_writable(const atf_fs_stat_t *st) 630 { 631 return st->m_sb.st_mode & S_IWUSR; 632 } 633 634 bool 635 atf_fs_stat_is_owner_executable(const atf_fs_stat_t *st) 636 { 637 return st->m_sb.st_mode & S_IXUSR; 638 } 639 640 bool 641 atf_fs_stat_is_group_readable(const atf_fs_stat_t *st) 642 { 643 return st->m_sb.st_mode & S_IRGRP; 644 } 645 646 bool 647 atf_fs_stat_is_group_writable(const atf_fs_stat_t *st) 648 { 649 return st->m_sb.st_mode & S_IWGRP; 650 } 651 652 bool 653 atf_fs_stat_is_group_executable(const atf_fs_stat_t *st) 654 { 655 return st->m_sb.st_mode & S_IXGRP; 656 } 657 658 bool 659 atf_fs_stat_is_other_readable(const atf_fs_stat_t *st) 660 { 661 return st->m_sb.st_mode & S_IROTH; 662 } 663 664 bool 665 atf_fs_stat_is_other_writable(const atf_fs_stat_t *st) 666 { 667 return st->m_sb.st_mode & S_IWOTH; 668 } 669 670 bool 671 atf_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 680 const int atf_fs_access_f = 1 << 0; 681 const int atf_fs_access_r = 1 << 1; 682 const int atf_fs_access_w = 1 << 2; 683 const 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 */ 690 atf_error_t 691 atf_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 747 out: 748 return err; 749 } 750 751 atf_error_t 752 atf_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 769 atf_error_t 770 atf_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 788 out: 789 return err; 790 } 791 792 atf_error_t 793 atf_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)); 814 out_buf: 815 free(buf); 816 out: 817 return err; 818 } 819 820 atf_error_t 821 atf_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)); 844 out_buf: 845 free(buf); 846 out: 847 return err; 848 } 849 850 atf_error_t 851 atf_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 870 atf_error_t 871 atf_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 } 885