1 /* 2 * Copyright 2005-2011, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include <BeOSBuildCompatibility.h> 8 9 #include "fs_impl.h" 10 11 #include <dirent.h> 12 #include <errno.h> 13 #include <fcntl.h> 14 #include <stdio.h> 15 #include <stdlib.h> 16 #include <unistd.h> 17 #include <utime.h> 18 #include <sys/stat.h> 19 #include <sys/time.h> 20 21 #include <map> 22 #include <string> 23 24 #include <fs_attr.h> 25 #include <NodeMonitor.h> // for B_STAT_* flags 26 #include <syscalls.h> 27 28 #include "fs_descriptors.h" 29 #include "NodeRef.h" 30 #include "remapped_functions.h" 31 32 #if defined(HAIKU_HOST_PLATFORM_FREEBSD) 33 # include "fs_freebsd.h" 34 #endif 35 36 37 using namespace std; 38 using namespace BPrivate; 39 40 41 #if defined(HAIKU_HOST_PLATFORM_FREEBSD) 42 # define haiku_host_platform_read haiku_freebsd_read 43 # define haiku_host_platform_write haiku_freebsd_write 44 # define haiku_host_platform_readv haiku_freebsd_readv 45 # define haiku_host_platform_writev haiku_freebsd_writev 46 # define HAIKU_HOST_STAT_ATIM(x) ((x).st_atimespec) 47 # define HAIKU_HOST_STAT_MTIM(x) ((x).st_mtimespec) 48 #else 49 # define haiku_host_platform_read read 50 # define haiku_host_platform_write write 51 # define haiku_host_platform_readv readv 52 # define haiku_host_platform_writev writev 53 # define HAIKU_HOST_STAT_ATIM(x) ((x).st_atim) 54 # define HAIKU_HOST_STAT_MTIM(x) ((x).st_mtim) 55 #endif 56 57 #define RETURN_AND_SET_ERRNO(err) \ 58 do { \ 59 __typeof(err) __result = (err); \ 60 if (__result < 0) { \ 61 errno = __result; \ 62 return -1; \ 63 } \ 64 return __result; \ 65 } while (0) 66 67 68 static status_t get_path(dev_t device, ino_t node, const char *name, 69 string &path); 70 71 72 // find_dir_entry 73 static status_t 74 find_dir_entry(DIR *dir, const char *path, NodeRef ref, string &name, 75 bool skipDot) 76 { 77 // find the entry 78 bool found = false; 79 while (dirent *entry = readdir(dir)) { 80 if ((!skipDot && strcmp(entry->d_name, ".") == 0) 81 || strcmp(entry->d_name, "..") == 0) { 82 // skip "." and ".." 83 } else /*if (entry->d_ino == ref.node)*/ { 84 // Note: Linux doesn't seem to translate dirent::d_ino of 85 // mount points. Thus we always have to lstat(). 86 // We also need to compare the device, which is generally not 87 // included in the dirent structure. Hence we lstat(). 88 string entryPath(path); 89 entryPath += '/'; 90 entryPath += entry->d_name; 91 struct stat st; 92 if (lstat(entryPath.c_str(), &st) == 0) { 93 if (NodeRef(st) == ref) { 94 name = entry->d_name; 95 found = true; 96 break; 97 } 98 } 99 } 100 } 101 102 if (!found) 103 return B_ENTRY_NOT_FOUND; 104 105 return B_OK; 106 } 107 108 // find_dir_entry 109 static status_t 110 find_dir_entry(const char *path, NodeRef ref, string &name, bool skipDot) 111 { 112 // open dir 113 DIR *dir = opendir(path); 114 if (!dir) 115 return errno; 116 117 status_t error = find_dir_entry(dir, path, ref, name, skipDot); 118 119 // close dir 120 closedir(dir); 121 122 return error; 123 } 124 125 // normalize_dir_path 126 static status_t 127 normalize_dir_path(string path, NodeRef ref, string &normalizedPath) 128 { 129 // get parent path 130 path += "/.."; 131 132 // stat the parent dir 133 struct stat st; 134 if (lstat(path.c_str(), &st) < 0) 135 return errno; 136 137 // root dir? 138 NodeRef parentRef(st); 139 if (parentRef == ref) { 140 normalizedPath = "/"; 141 return 0; 142 } 143 144 // find the entry 145 string name; 146 status_t error = find_dir_entry(path.c_str(), ref, name, true) ; 147 if (error != B_OK) 148 return error; 149 150 // recurse to get the parent dir path, if found 151 error = normalize_dir_path(path, parentRef, normalizedPath); 152 if (error != 0) 153 return error; 154 155 // construct the normalizedPath 156 if (normalizedPath.length() > 1) // don't append "/", if parent is root 157 normalizedPath += '/'; 158 normalizedPath += name; 159 160 return 0; 161 } 162 163 // normalize_dir_path 164 static status_t 165 normalize_dir_path(const char *path, string &normalizedPath) 166 { 167 // stat() the dir 168 struct stat st; 169 if (stat(path, &st) < 0) 170 return errno; 171 172 return normalize_dir_path(path, NodeRef(st), normalizedPath); 173 } 174 175 // normalize_entry_path 176 static status_t 177 normalize_entry_path(const char *path, string &normalizedPath) 178 { 179 const char *dirPath = NULL; 180 const char *leafName = NULL; 181 182 string dirPathString; 183 if (const char *lastSlash = strrchr(path, '/')) { 184 // found a slash: decompose into dir path and leaf name 185 leafName = lastSlash + 1; 186 if (leafName[0] == '\0') { 187 // slash is at the end: the whole path is a dir name 188 leafName = NULL; 189 } else { 190 dirPathString = string(path, leafName - path); 191 dirPath = dirPathString.c_str(); 192 } 193 194 } else { 195 // path contains no slash, so it is a path relative to the current dir 196 dirPath = "."; 197 leafName = path; 198 } 199 200 // catch special case: no leaf, or leaf is a directory 201 if (!leafName || strcmp(leafName, ".") == 0 || strcmp(leafName, "..") == 0) 202 return normalize_dir_path(path, normalizedPath); 203 204 // normalize the dir path 205 status_t error = normalize_dir_path(dirPath, normalizedPath); 206 if (error != B_OK) 207 return error; 208 209 // append the leaf name 210 if (normalizedPath.length() > 1) // don't append "/", if parent is root 211 normalizedPath += '/'; 212 normalizedPath += leafName; 213 214 return B_OK; 215 } 216 217 218 // #pragma mark - 219 220 typedef map<NodeRef, string> DirPathMap; 221 static DirPathMap sDirPathMap; 222 223 // get_path 224 static status_t 225 get_path(const NodeRef *ref, const char *name, string &path) 226 { 227 if (!ref && !name) 228 return B_BAD_VALUE; 229 230 // no ref or absolute path 231 if (!ref || (name && name[0] == '/')) { 232 path = name; 233 return B_OK; 234 } 235 236 // get the dir path 237 if (ref) { 238 DirPathMap::iterator it = sDirPathMap.find(*ref); 239 if (it == sDirPathMap.end()) 240 return B_ENTRY_NOT_FOUND; 241 242 path = it->second; 243 244 // stat the path to check, if it is still valid 245 struct stat st; 246 if (lstat(path.c_str(), &st) < 0) { 247 sDirPathMap.erase(it); 248 return errno; 249 } 250 251 // compare the NodeRef 252 if (NodeRef(st) != *ref) { 253 sDirPathMap.erase(it); 254 return B_ENTRY_NOT_FOUND; 255 } 256 257 // still a directory? 258 if (!S_ISDIR(st.st_mode)) { 259 sDirPathMap.erase(it); 260 return B_NOT_A_DIRECTORY; 261 } 262 } 263 264 // if there's a name, append it 265 if (name) { 266 path += '/'; 267 path += name; 268 } 269 270 return B_OK; 271 } 272 273 // get_path 274 status_t 275 BPrivate::get_path(int fd, const char *name, string &path) 276 { 277 // get the node ref for the fd, if any, and the path part is not absolute 278 if (fd >= 0 && !(name && name[0] == '/')) { 279 // get descriptor 280 Descriptor *descriptor = get_descriptor(fd); 281 if (!descriptor) 282 return B_FILE_ERROR; 283 284 // get node ref for the descriptor 285 NodeRef ref; 286 status_t error = descriptor->GetNodeRef(ref); 287 if (error != B_OK) 288 return error; 289 290 return ::get_path(&ref, name, path); 291 292 } else // no descriptor or absolute path 293 return ::get_path((NodeRef*)NULL, name, path); 294 } 295 296 // get_path 297 static status_t 298 get_path(dev_t device, ino_t directory, const char *name, string &path) 299 { 300 NodeRef ref; 301 ref.device = device; 302 ref.node = directory; 303 304 return get_path(&ref, name, path); 305 } 306 307 // add_dir_path 308 static void 309 add_dir_path(const char *path, const NodeRef &ref) 310 { 311 // add the normalized path 312 string normalizedPath; 313 if (normalize_dir_path(path, normalizedPath) == B_OK) 314 sDirPathMap[ref] = normalizedPath; 315 } 316 317 318 // #pragma mark - 319 320 // _kern_entry_ref_to_path 321 status_t 322 _kern_entry_ref_to_path(dev_t device, ino_t node, const char *leaf, 323 char *userPath, size_t pathLength) 324 { 325 // get the path 326 string path; 327 status_t error = get_path(device, node, leaf, path); 328 if (error != B_OK) 329 return error; 330 331 // copy it back to the user buffer 332 if (strlcpy(userPath, path.c_str(), pathLength) >= pathLength) 333 return B_BUFFER_OVERFLOW; 334 335 return B_OK; 336 } 337 338 339 // #pragma mark - 340 341 // _kern_create_dir 342 status_t 343 _kern_create_dir(int fd, const char *path, int perms) 344 { 345 // get a usable path 346 string realPath; 347 status_t error = get_path(fd, path, realPath); 348 if (error != B_OK) 349 return error; 350 351 // mkdir 352 if (mkdir(realPath.c_str(), perms) < 0) 353 return errno; 354 355 return B_OK; 356 } 357 358 // _kern_create_dir_entry_ref 359 status_t 360 _kern_create_dir_entry_ref(dev_t device, ino_t node, const char *name, 361 int perms) 362 { 363 // get a usable path 364 string realPath; 365 status_t error = get_path(device, node, name, realPath); 366 if (error != B_OK) 367 return error; 368 369 // mkdir 370 if (mkdir(realPath.c_str(), perms) < 0) 371 return errno; 372 373 return B_OK; 374 } 375 376 // open_dir 377 static int 378 open_dir(const char *path) 379 { 380 // open the dir 381 DIR *dir = opendir(path); 382 if (!dir) 383 return errno; 384 385 // stat the entry 386 struct stat st; 387 if (stat(path, &st) < 0) { 388 closedir(dir); 389 return errno; 390 } 391 392 if (!S_ISDIR(st.st_mode)) { 393 closedir(dir); 394 return B_NOT_A_DIRECTORY; 395 } 396 397 // cache dir path 398 NodeRef ref(st); 399 add_dir_path(path, ref); 400 401 // create descriptor 402 DirectoryDescriptor *descriptor = new DirectoryDescriptor(dir, ref); 403 return add_descriptor(descriptor); 404 } 405 406 // _kern_open_dir 407 int 408 _kern_open_dir(int fd, const char *path) 409 { 410 // get a usable path 411 string realPath; 412 status_t error = get_path(fd, path, realPath); 413 if (error != B_OK) 414 return error; 415 416 return open_dir(realPath.c_str()); 417 } 418 419 // _kern_open_dir_entry_ref 420 int 421 _kern_open_dir_entry_ref(dev_t device, ino_t node, const char *name) 422 { 423 // get a usable path 424 string realPath; 425 status_t error = get_path(device, node, name, realPath); 426 if (error != B_OK) 427 return error; 428 429 return open_dir(realPath.c_str()); 430 } 431 432 // _kern_open_parent_dir 433 int 434 _kern_open_parent_dir(int fd, char *name, size_t nameLength) 435 { 436 // get a usable path 437 string realPath; 438 status_t error = get_path(fd, NULL, realPath); 439 if (error != B_OK) 440 return error; 441 442 // stat the entry 443 struct stat st; 444 if (stat(realPath.c_str(), &st) < 0) 445 return errno; 446 447 if (!S_ISDIR(st.st_mode)) 448 return B_NOT_A_DIRECTORY; 449 450 // get the entry name 451 realPath += "/.."; 452 string entryName; 453 error = find_dir_entry(realPath.c_str(), NodeRef(st), 454 entryName, false); 455 if (error != B_OK) 456 return error; 457 458 if (strlcpy(name, entryName.c_str(), nameLength) >= nameLength) 459 return B_BUFFER_OVERFLOW; 460 461 // open the parent directory 462 463 return open_dir(realPath.c_str()); 464 } 465 466 // _kern_read_dir 467 ssize_t 468 _kern_read_dir(int fd, struct dirent *buffer, size_t bufferSize, 469 uint32 maxCount) 470 { 471 if (maxCount <= 0) 472 return B_BAD_VALUE; 473 474 // get the descriptor 475 DirectoryDescriptor *descriptor 476 = dynamic_cast<DirectoryDescriptor*>(get_descriptor(fd)); 477 if (!descriptor) 478 return B_FILE_ERROR; 479 480 // get the next entry 481 dirent *entry; 482 if (dynamic_cast<AttrDirDescriptor*>(descriptor)) 483 entry = fs_read_attr_dir(descriptor->dir); 484 else 485 entry = readdir(descriptor->dir); 486 if (!entry) 487 return errno; 488 489 // copy the entry 490 int entryLen = &entry->d_name[strlen(entry->d_name) + 1] - (char*)entry; 491 if (entryLen > (int)bufferSize) 492 return B_BUFFER_OVERFLOW; 493 494 memcpy(buffer, entry, entryLen); 495 496 return 1; 497 } 498 499 // _kern_rewind_dir 500 status_t 501 _kern_rewind_dir(int fd) 502 { 503 // get the descriptor 504 DirectoryDescriptor *descriptor 505 = dynamic_cast<DirectoryDescriptor*>(get_descriptor(fd)); 506 if (!descriptor) 507 return B_FILE_ERROR; 508 509 // rewind 510 if (dynamic_cast<AttrDirDescriptor*>(descriptor)) 511 fs_rewind_attr_dir(descriptor->dir); 512 else 513 rewinddir(descriptor->dir); 514 515 return B_OK; 516 } 517 518 519 // #pragma mark - 520 521 // open_file 522 static int 523 open_file(const char *path, int openMode, int perms) 524 { 525 // stat the node 526 bool exists = true; 527 struct stat st; 528 if (lstat(path, &st) < 0) { 529 exists = false; 530 if (!(openMode & O_CREAT)) 531 return errno; 532 } 533 534 Descriptor *descriptor; 535 if (exists && S_ISLNK(st.st_mode) && (openMode & O_NOTRAVERSE) != 0) { 536 // a symlink not to be followed: create a special descriptor 537 // normalize path first 538 string normalizedPath; 539 status_t error = normalize_entry_path(path, normalizedPath); 540 if (error != B_OK) 541 return error; 542 543 descriptor = new SymlinkDescriptor(normalizedPath.c_str()); 544 } else { 545 // open the file 546 openMode &= ~O_NOTRAVERSE; 547 int newFD = open(path, openMode, perms); 548 if (newFD < 0) 549 return errno; 550 551 descriptor = new FileDescriptor(newFD); 552 } 553 554 // cache path, if this is a directory 555 if (exists && S_ISDIR(st.st_mode)) 556 add_dir_path(path, NodeRef(st)); 557 558 return add_descriptor(descriptor); 559 } 560 561 // _kern_open 562 int 563 _kern_open(int fd, const char *path, int openMode, int perms) 564 { 565 // get a usable path 566 string realPath; 567 status_t error = get_path(fd, path, realPath); 568 if (error != B_OK) 569 return error; 570 571 return open_file(realPath.c_str(), openMode, perms); 572 } 573 574 // _kern_open_entry_ref 575 int 576 _kern_open_entry_ref(dev_t device, ino_t node, const char *name, 577 int openMode, int perms) 578 { 579 // get a usable path 580 string realPath; 581 status_t error = get_path(device, node, name, realPath); 582 if (error != B_OK) 583 return error; 584 585 return open_file(realPath.c_str(), openMode, perms); 586 } 587 588 // _kern_seek 589 off_t 590 _kern_seek(int fd, off_t pos, int seekType) 591 { 592 // get the descriptor 593 FileDescriptor *descriptor 594 = dynamic_cast<FileDescriptor*>(get_descriptor(fd)); 595 if (!descriptor) 596 return B_FILE_ERROR; 597 598 // seek 599 off_t result = lseek(descriptor->fd, pos, seekType); 600 if (result < 0) 601 return errno; 602 603 return result; 604 } 605 606 // _kern_read 607 ssize_t 608 _kern_read(int fd, off_t pos, void *buffer, size_t bufferSize) 609 { 610 // get the descriptor 611 FileDescriptor *descriptor 612 = dynamic_cast<FileDescriptor*>(get_descriptor(fd)); 613 if (!descriptor) 614 return B_FILE_ERROR; 615 616 // seek 617 if (pos != -1) { 618 off_t result = lseek(descriptor->fd, pos, SEEK_SET); 619 if (result < 0) 620 return errno; 621 } 622 623 // read 624 ssize_t bytesRead = haiku_host_platform_read(descriptor->fd, buffer, 625 bufferSize); 626 if (bytesRead < 0) 627 return errno; 628 629 return bytesRead; 630 } 631 632 // _kern_write 633 ssize_t 634 _kern_write(int fd, off_t pos, const void *buffer, size_t bufferSize) 635 { 636 // get the descriptor 637 FileDescriptor *descriptor 638 = dynamic_cast<FileDescriptor*>(get_descriptor(fd)); 639 if (!descriptor) 640 return B_FILE_ERROR; 641 642 // seek 643 if (pos != -1) { 644 off_t result = lseek(descriptor->fd, pos, SEEK_SET); 645 if (result < 0) 646 return errno; 647 } 648 649 // read 650 ssize_t bytesWritten = haiku_host_platform_write(descriptor->fd, buffer, 651 bufferSize); 652 if (bytesWritten < 0) 653 return errno; 654 655 return bytesWritten; 656 } 657 658 // _kern_close 659 status_t 660 _kern_close(int fd) 661 { 662 return delete_descriptor(fd); 663 } 664 665 // _kern_dup 666 int 667 _kern_dup(int fd) 668 { 669 // get the descriptor 670 Descriptor *descriptor = get_descriptor(fd); 671 if (!descriptor) 672 return B_FILE_ERROR; 673 674 // clone it 675 Descriptor *clone; 676 status_t error = descriptor->Dup(clone); 677 if (error != B_OK) 678 return error; 679 680 return add_descriptor(clone); 681 } 682 683 // _kern_fsync 684 status_t 685 _kern_fsync(int fd) 686 { 687 // get the descriptor 688 FileDescriptor *descriptor 689 = dynamic_cast<FileDescriptor*>(get_descriptor(fd)); 690 if (!descriptor) 691 return B_FILE_ERROR; 692 693 // sync 694 if (fsync(descriptor->fd) < 0) 695 return errno; 696 697 return B_OK; 698 } 699 700 // _kern_read_stat 701 status_t 702 _kern_read_stat(int fd, const char *path, bool traverseLink, 703 struct stat *st, size_t statSize) 704 { 705 if (path) { 706 // get a usable path 707 string realPath; 708 status_t error = get_path(fd, path, realPath); 709 if (error != B_OK) 710 return error; 711 712 // stat 713 int result; 714 if (traverseLink) 715 result = stat(realPath.c_str(), st); 716 else 717 result = lstat(realPath.c_str(), st); 718 719 if (result < 0) 720 return errno; 721 } else { 722 Descriptor *descriptor = get_descriptor(fd); 723 if (!descriptor) 724 return B_FILE_ERROR; 725 726 return descriptor->GetStat(traverseLink, st); 727 } 728 729 return B_OK; 730 } 731 732 // _kern_write_stat 733 status_t 734 _kern_write_stat(int fd, const char *path, bool traverseLink, 735 const struct stat *st, size_t statSize, int statMask) 736 { 737 // get a usable path 738 int realFD = -1; 739 string realPath; 740 status_t error; 741 bool isSymlink = false; 742 if (path) { 743 error = get_path(fd, path, realPath); 744 if (error != B_OK) 745 return error; 746 747 // stat it to see, if it is a symlink 748 struct stat tmpStat; 749 if (lstat(realPath.c_str(), &tmpStat) < 0) 750 return errno; 751 752 isSymlink = S_ISLNK(tmpStat.st_mode); 753 754 } else { 755 Descriptor *descriptor = get_descriptor(fd); 756 if (!descriptor) 757 return B_FILE_ERROR; 758 759 if (FileDescriptor *fileFD 760 = dynamic_cast<FileDescriptor*>(descriptor)) { 761 realFD = fileFD->fd; 762 763 } else if (dynamic_cast<DirectoryDescriptor*>(descriptor)) { 764 error = get_path(fd, NULL, realPath); 765 if (error != B_OK) 766 return error; 767 768 } else if (SymlinkDescriptor *linkFD 769 = dynamic_cast<SymlinkDescriptor*>(descriptor)) { 770 realPath = linkFD->path; 771 isSymlink = true; 772 773 } else 774 return B_FILE_ERROR; 775 } 776 777 // We're screwed, if the node to manipulate is a symlink. All the 778 // available functions traverse symlinks. 779 if (isSymlink && !traverseLink) 780 return B_ERROR; 781 782 if (realFD >= 0) { 783 if (statMask & B_STAT_MODE) { 784 if (fchmod(realFD, st->st_mode) < 0) 785 return errno; 786 } 787 788 if (statMask & B_STAT_UID) { 789 if (fchown(realFD, st->st_uid, (gid_t)-1) < 0) 790 return errno; 791 } 792 793 if (statMask & B_STAT_GID) { 794 if (fchown(realFD, (uid_t)-1, st->st_gid) < 0) 795 return errno; 796 } 797 798 if (statMask & B_STAT_SIZE) { 799 if (ftruncate(realFD, st->st_size) < 0) 800 return errno; 801 } 802 803 // The timestamps can only be set via utime(), but that requires a 804 // path we don't have. 805 if (statMask & (B_STAT_ACCESS_TIME | B_STAT_MODIFICATION_TIME 806 | B_STAT_CREATION_TIME | B_STAT_CHANGE_TIME)) { 807 return B_ERROR; 808 } 809 810 return 0; 811 812 } else { 813 if (statMask & B_STAT_MODE) { 814 if (chmod(realPath.c_str(), st->st_mode) < 0) 815 return errno; 816 } 817 818 if (statMask & B_STAT_UID) { 819 if (chown(realPath.c_str(), st->st_uid, (gid_t)-1) < 0) 820 return errno; 821 } 822 823 if (statMask & B_STAT_GID) { 824 if (chown(realPath.c_str(), (uid_t)-1, st->st_gid) < 0) 825 return errno; 826 } 827 828 if (statMask & B_STAT_SIZE) { 829 if (truncate(realPath.c_str(), st->st_size) < 0) 830 return errno; 831 } 832 833 if (statMask & (B_STAT_ACCESS_TIME | B_STAT_MODIFICATION_TIME)) { 834 // Grab the previous mod and access times so we only overwrite 835 // the specified time and not both 836 struct stat oldStat; 837 if (~statMask & (B_STAT_ACCESS_TIME | B_STAT_MODIFICATION_TIME)) { 838 if (stat(realPath.c_str(), &oldStat) < 0) 839 return errno; 840 } 841 842 utimbuf buffer; 843 buffer.actime = (statMask & B_STAT_ACCESS_TIME) ? st->st_atime : oldStat.st_atime; 844 buffer.modtime = (statMask & B_STAT_MODIFICATION_TIME) ? st->st_mtime : oldStat.st_mtime; 845 if (utime(realPath.c_str(), &buffer) < 0) 846 return errno; 847 } 848 849 // not supported 850 if (statMask & (B_STAT_CREATION_TIME | B_STAT_CHANGE_TIME)) 851 return B_ERROR; 852 } 853 854 return B_OK; 855 } 856 857 858 // #pragma mark - 859 860 // _kern_create_symlink 861 status_t 862 _kern_create_symlink(int fd, const char *path, const char *toPath, int mode) 863 { 864 // Note: path must not be NULL, so this will always work. 865 // get a usable path 866 string realPath; 867 status_t error = get_path(fd, path, realPath); 868 if (error != B_OK) 869 return error; 870 871 // symlink 872 if (symlink(toPath, realPath.c_str()) < 0) 873 return errno; 874 875 return B_OK; 876 } 877 878 // _kern_read_link 879 status_t 880 _kern_read_link(int fd, const char *path, char *buffer, size_t *_bufferSize) 881 { 882 // get the path 883 string realPath; 884 status_t error = get_path(fd, path, realPath); 885 if (error != B_OK) 886 return error; 887 888 // readlink 889 ssize_t bytesRead = readlink(realPath.c_str(), buffer, *_bufferSize); 890 if (bytesRead < 0) 891 return errno; 892 893 if (*_bufferSize > 0) { 894 if ((size_t)bytesRead == *_bufferSize) 895 bytesRead--; 896 897 buffer[bytesRead] = '\0'; 898 } 899 900 *_bufferSize = bytesRead; 901 902 return B_OK; 903 } 904 905 // _kern_unlink 906 status_t 907 _kern_unlink(int fd, const char *path) 908 { 909 // get a usable path 910 string realPath; 911 status_t error = get_path(fd, path, realPath); 912 if (error != B_OK) 913 return error; 914 915 // unlink 916 if (unlink(realPath.c_str()) < 0) 917 return errno; 918 919 return B_OK; 920 } 921 922 // _kern_rename 923 status_t 924 _kern_rename(int oldDir, const char *oldPath, int newDir, const char *newPath) 925 { 926 // get usable paths 927 string realOldPath; 928 status_t error = get_path(oldDir, oldPath, realOldPath); 929 if (error != B_OK) 930 return error; 931 932 string realNewPath; 933 error = get_path(newDir, newPath, realNewPath); 934 if (error != B_OK) 935 return error; 936 937 // rename 938 if (rename(realOldPath.c_str(), realNewPath.c_str()) < 0) 939 return errno; 940 941 return B_OK; 942 } 943 944 945 // #pragma mark - 946 947 // _kern_lock_node 948 status_t 949 _kern_lock_node(int fd) 950 { 951 return B_ERROR; 952 } 953 954 // _kern_unlock_node 955 status_t 956 _kern_unlock_node(int fd) 957 { 958 return B_ERROR; 959 } 960 961 962 // #pragma mark - 963 964 // read_pos 965 ssize_t 966 read_pos(int fd, off_t pos, void *buffer, size_t bufferSize) 967 { 968 // seek 969 off_t result = lseek(fd, pos, SEEK_SET); 970 if (result < 0) 971 return errno; 972 973 // read 974 ssize_t bytesRead = haiku_host_platform_read(fd, buffer, bufferSize); 975 if (bytesRead < 0) { 976 errno = bytesRead; 977 return -1; 978 } 979 980 return bytesRead; 981 } 982 983 // write_pos 984 ssize_t 985 write_pos(int fd, off_t pos, const void *buffer, size_t bufferSize) 986 { 987 // If this is an attribute descriptor, let it do the job. 988 AttributeDescriptor* descriptor 989 = dynamic_cast<AttributeDescriptor*>(get_descriptor(fd)); 990 if (descriptor != NULL) { 991 status_t error = descriptor->Write(pos, buffer, bufferSize); 992 if (error != B_OK) { 993 errno = error; 994 return -1; 995 } 996 997 return bufferSize; 998 } 999 1000 // seek 1001 off_t result = lseek(fd, pos, SEEK_SET); 1002 if (result < 0) 1003 return errno; 1004 1005 // write 1006 ssize_t bytesWritten = haiku_host_platform_write(fd, buffer, bufferSize); 1007 if (bytesWritten < 0) { 1008 errno = bytesWritten; 1009 return -1; 1010 } 1011 1012 return bytesWritten; 1013 } 1014 1015 // readv_pos 1016 ssize_t 1017 readv_pos(int fd, off_t pos, const struct iovec *vec, size_t count) 1018 { 1019 // seek 1020 off_t result = lseek(fd, pos, SEEK_SET); 1021 if (result < 0) 1022 return errno; 1023 1024 // read 1025 ssize_t bytesRead = haiku_host_platform_readv(fd, vec, count); 1026 if (bytesRead < 0) { 1027 errno = bytesRead; 1028 return -1; 1029 } 1030 1031 return bytesRead; 1032 } 1033 1034 // writev_pos 1035 ssize_t 1036 writev_pos(int fd, off_t pos, const struct iovec *vec, size_t count) 1037 { 1038 // seek 1039 off_t result = lseek(fd, pos, SEEK_SET); 1040 if (result < 0) 1041 return errno; 1042 1043 // read 1044 ssize_t bytesWritten = haiku_host_platform_writev(fd, vec, count); 1045 if (bytesWritten < 0) { 1046 errno = bytesWritten; 1047 return -1; 1048 } 1049 1050 return bytesWritten; 1051 } 1052 1053 1054 // #pragma mark - 1055 1056 1057 int 1058 _haiku_build_fchmod(int fd, mode_t mode) 1059 { 1060 return _haiku_build_fchmodat(fd, NULL, mode, AT_SYMLINK_NOFOLLOW); 1061 } 1062 1063 1064 int 1065 _haiku_build_fchmodat(int fd, const char* path, mode_t mode, int flag) 1066 { 1067 if (fd >= 0 && fd != AT_FDCWD && get_descriptor(fd) == NULL) 1068 return fchmodat(fd, path, mode, flag); 1069 1070 struct stat st; 1071 st.st_mode = mode; 1072 1073 RETURN_AND_SET_ERRNO(_kern_write_stat(fd, path, 1074 (flag & AT_SYMLINK_NOFOLLOW) == 0, &st, sizeof(st), B_STAT_MODE)); 1075 } 1076 1077 1078 int 1079 _haiku_build_fstat(int fd, struct stat* st) 1080 { 1081 return _haiku_build_fstatat(fd, NULL, st, AT_SYMLINK_NOFOLLOW); 1082 } 1083 1084 1085 int 1086 _haiku_build_fstatat(int fd, const char* path, struct stat* st, int flag) 1087 { 1088 if (fd >= 0 && fd != AT_FDCWD && get_descriptor(fd) == NULL) 1089 return fstatat(fd, path, st, flag); 1090 1091 RETURN_AND_SET_ERRNO(_kern_read_stat(fd, path, 1092 (flag & AT_SYMLINK_NOFOLLOW) == 0, st, sizeof(*st))); 1093 } 1094 1095 1096 int 1097 _haiku_build_mkdirat(int fd, const char* path, mode_t mode) 1098 { 1099 if (fd >= 0 && fd != AT_FDCWD && get_descriptor(fd) == NULL) 1100 return mkdirat(fd, path, mode); 1101 1102 RETURN_AND_SET_ERRNO(_kern_create_dir(fd, path, mode)); 1103 } 1104 1105 1106 int 1107 _haiku_build_mkfifoat(int fd, const char* path, mode_t mode) 1108 { 1109 return mkfifoat(fd, path, mode); 1110 1111 // TODO: Handle non-system FDs. 1112 } 1113 1114 1115 int 1116 _haiku_build_utimensat(int fd, const char* path, const struct timespec times[2], 1117 int flag) 1118 { 1119 if (fd >= 0 && fd != AT_FDCWD && get_descriptor(fd) == NULL) 1120 return utimensat(fd, path, times, flag); 1121 1122 struct stat stat; 1123 status_t status; 1124 uint32 mask = 0; 1125 1126 // Init the stat time fields to the current time, if at least one time is 1127 // supposed to be set to it. 1128 if (times == NULL || times[0].tv_nsec == UTIME_NOW 1129 || times[1].tv_nsec == UTIME_NOW) { 1130 timeval now; 1131 gettimeofday(&now, NULL); 1132 HAIKU_HOST_STAT_ATIM(stat).tv_sec 1133 = HAIKU_HOST_STAT_MTIM(stat).tv_sec = now.tv_sec; 1134 HAIKU_HOST_STAT_ATIM(stat).tv_nsec 1135 = HAIKU_HOST_STAT_MTIM(stat).tv_nsec = now.tv_usec * 1000; 1136 } 1137 1138 if (times != NULL) { 1139 // access time 1140 if (times[0].tv_nsec != UTIME_OMIT) { 1141 mask |= B_STAT_ACCESS_TIME; 1142 1143 if (times[0].tv_nsec != UTIME_NOW) { 1144 if (times[0].tv_nsec < 0 || times[0].tv_nsec > 999999999) 1145 RETURN_AND_SET_ERRNO(EINVAL); 1146 } 1147 1148 HAIKU_HOST_STAT_ATIM(stat) = times[0]; 1149 } 1150 1151 // modified time 1152 if (times[1].tv_nsec != UTIME_OMIT) { 1153 mask |= B_STAT_MODIFICATION_TIME; 1154 1155 if (times[1].tv_nsec != UTIME_NOW) { 1156 if (times[1].tv_nsec < 0 || times[1].tv_nsec > 999999999) 1157 RETURN_AND_SET_ERRNO(EINVAL); 1158 } 1159 1160 HAIKU_HOST_STAT_MTIM(stat) = times[1]; 1161 } 1162 } else 1163 mask |= B_STAT_ACCESS_TIME | B_STAT_MODIFICATION_TIME; 1164 1165 // set the times -- as per spec we even need to do this, if both have 1166 // UTIME_OMIT set 1167 status = _kern_write_stat(fd, path, (flag & AT_SYMLINK_NOFOLLOW) == 0, 1168 &stat, sizeof(struct stat), mask); 1169 1170 RETURN_AND_SET_ERRNO(status); 1171 } 1172 1173 1174 int 1175 _haiku_build_futimens(int fd, const struct timespec times[2]) 1176 { 1177 return _haiku_build_utimensat(fd, NULL, times, AT_SYMLINK_NOFOLLOW); 1178 } 1179 1180 1181 int 1182 _haiku_build_faccessat(int fd, const char* path, int accessMode, int flag) 1183 { 1184 if (fd >= 0 && fd != AT_FDCWD && get_descriptor(fd) == NULL) 1185 return faccessat(fd, path, accessMode, flag); 1186 1187 // stat the file 1188 struct stat st; 1189 status_t error = _kern_read_stat(fd, path, false, &st, sizeof(st)); 1190 if (error != B_OK) 1191 RETURN_AND_SET_ERRNO(error); 1192 1193 // get the current user 1194 uid_t uid = (flag & AT_EACCESS) != 0 ? geteuid() : getuid(); 1195 1196 int fileMode = 0; 1197 1198 if (uid == 0) { 1199 // user is root 1200 // root has always read/write permission, but at least one of the 1201 // X bits must be set for execute permission 1202 fileMode = R_OK | W_OK; 1203 if ((st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0) 1204 fileMode |= X_OK; 1205 } else if (st.st_uid == uid) { 1206 // user is node owner 1207 if ((st.st_mode & S_IRUSR) != 0) 1208 fileMode |= R_OK; 1209 if ((st.st_mode & S_IWUSR) != 0) 1210 fileMode |= W_OK; 1211 if ((st.st_mode & S_IXUSR) != 0) 1212 fileMode |= X_OK; 1213 } else if (st.st_gid == ((flag & AT_EACCESS) != 0 ? getegid() : getgid())) { 1214 // user is in owning group 1215 if ((st.st_mode & S_IRGRP) != 0) 1216 fileMode |= R_OK; 1217 if ((st.st_mode & S_IWGRP) != 0) 1218 fileMode |= W_OK; 1219 if ((st.st_mode & S_IXGRP) != 0) 1220 fileMode |= X_OK; 1221 } else { 1222 // user is one of the others 1223 if ((st.st_mode & S_IROTH) != 0) 1224 fileMode |= R_OK; 1225 if ((st.st_mode & S_IWOTH) != 0) 1226 fileMode |= W_OK; 1227 if ((st.st_mode & S_IXOTH) != 0) 1228 fileMode |= X_OK; 1229 } 1230 1231 if ((accessMode & ~fileMode) != 0) 1232 RETURN_AND_SET_ERRNO(EACCES); 1233 1234 return 0; 1235 } 1236 1237 1238 int 1239 _haiku_build_fchdir(int fd) 1240 { 1241 if (is_unknown_or_system_descriptor(fd)) 1242 return fchdir(fd); 1243 1244 RETURN_AND_SET_ERRNO(B_FILE_ERROR); 1245 } 1246 1247 1248 int 1249 _haiku_build_close(int fd) 1250 { 1251 if (get_descriptor(fd) == NULL) 1252 return close(fd); 1253 1254 RETURN_AND_SET_ERRNO(_kern_close(fd)); 1255 } 1256 1257 1258 int 1259 _haiku_build_dup(int fd) 1260 { 1261 if (get_descriptor(fd) == NULL) 1262 return close(fd); 1263 1264 RETURN_AND_SET_ERRNO(_kern_dup(fd)); 1265 } 1266 1267 1268 int 1269 _haiku_build_dup2(int fd1, int fd2) 1270 { 1271 if (is_unknown_or_system_descriptor(fd1)) 1272 return dup2(fd1, fd2); 1273 1274 // TODO: Handle non-system FDs. 1275 RETURN_AND_SET_ERRNO(B_NOT_SUPPORTED); 1276 } 1277 1278 1279 int 1280 _haiku_build_linkat(int toFD, const char* toPath, int pathFD, const char* path, 1281 int flag) 1282 { 1283 return linkat(toFD, toPath, pathFD, path, flag); 1284 1285 // TODO: Handle non-system FDs. 1286 } 1287 1288 1289 int 1290 _haiku_build_unlinkat(int fd, const char* path, int flag) 1291 { 1292 if (fd >= 0 && fd != AT_FDCWD && get_descriptor(fd) == NULL) 1293 return unlinkat(fd, path, flag); 1294 1295 RETURN_AND_SET_ERRNO(_kern_unlink(fd, path)); 1296 } 1297 1298 1299 ssize_t 1300 _haiku_build_readlinkat(int fd, const char* path, char* buffer, 1301 size_t bufferSize) 1302 { 1303 if (fd >= 0 && fd != AT_FDCWD && get_descriptor(fd) == NULL) 1304 return readlinkat(fd, path, buffer, bufferSize); 1305 1306 status_t error = _kern_read_link(fd, path, buffer, &bufferSize); 1307 if (error != B_OK) 1308 RETURN_AND_SET_ERRNO(error); 1309 1310 return bufferSize; 1311 } 1312 1313 1314 int 1315 _haiku_build_symlinkat(const char* toPath, int fd, const char* symlinkPath) 1316 { 1317 if (fd >= 0 && fd != AT_FDCWD && get_descriptor(fd) == NULL) 1318 return symlinkat(toPath, fd, symlinkPath); 1319 1320 RETURN_AND_SET_ERRNO(_kern_create_symlink(fd, symlinkPath, toPath, 1321 S_IRWXU | S_IRWXG | S_IRWXO)); 1322 } 1323 1324 1325 int 1326 _haiku_build_ftruncate(int fd, off_t newSize) 1327 { 1328 if (fd >= 0 && fd != AT_FDCWD && get_descriptor(fd) == NULL) 1329 return ftruncate(fd, newSize); 1330 1331 struct stat st; 1332 st.st_size = newSize; 1333 1334 RETURN_AND_SET_ERRNO(_kern_write_stat(fd, NULL, false, &st, sizeof(st), 1335 B_STAT_SIZE)); 1336 } 1337 1338 1339 int 1340 _haiku_build_fchown(int fd, uid_t owner, gid_t group) 1341 { 1342 return _haiku_build_fchownat(fd, NULL, owner, group, AT_SYMLINK_NOFOLLOW); 1343 } 1344 1345 1346 int 1347 _haiku_build_fchownat(int fd, const char* path, uid_t owner, gid_t group, 1348 int flag) 1349 { 1350 if (fd >= 0 && fd != AT_FDCWD && get_descriptor(fd) == NULL) 1351 return fchownat(fd, path, owner, group, flag); 1352 1353 struct stat st; 1354 st.st_uid = owner; 1355 st.st_gid = group; 1356 1357 RETURN_AND_SET_ERRNO(_kern_write_stat(fd, path, 1358 (flag & AT_SYMLINK_NOFOLLOW) == 0, &st, sizeof(st), 1359 B_STAT_UID | B_STAT_GID)); 1360 } 1361 1362 1363 int 1364 _haiku_build_mknodat(int fd, const char* name, mode_t mode, dev_t dev) 1365 { 1366 return mknodat(fd, name, mode, dev); 1367 1368 // TODO: Handle non-system FDs. 1369 } 1370 1371 1372 int 1373 _haiku_build_creat(const char* path, mode_t mode) 1374 { 1375 return _haiku_build_open(path, O_WRONLY | O_CREAT | O_TRUNC, mode); 1376 } 1377 1378 1379 int 1380 _haiku_build_open(const char* path, int openMode, mode_t permissions) 1381 { 1382 return _haiku_build_openat(AT_FDCWD, path, openMode, permissions); 1383 } 1384 1385 1386 int 1387 _haiku_build_openat(int fd, const char* path, int openMode, mode_t permissions) 1388 { 1389 // adapt the permissions as required by POSIX 1390 mode_t mask = umask(0); 1391 umask(mask); 1392 permissions &= ~mask; 1393 1394 RETURN_AND_SET_ERRNO(_kern_open(fd, path, openMode, permissions)); 1395 } 1396 1397 1398 int 1399 _haiku_build_fcntl(int fd, int op, int argument) 1400 { 1401 if (is_unknown_or_system_descriptor(fd)) 1402 return fcntl(fd, op, argument); 1403 1404 RETURN_AND_SET_ERRNO(B_NOT_SUPPORTED); 1405 } 1406 1407 1408 int 1409 _haiku_build_renameat(int fromFD, const char* from, int toFD, const char* to) 1410 { 1411 if ((fromFD >= 0 && fromFD != AT_FDCWD && get_descriptor(fromFD) == NULL) 1412 || (toFD >= 0 && toFD != AT_FDCWD && get_descriptor(toFD) == NULL)) { 1413 return renameat(fromFD, from, toFD, to); 1414 } 1415 1416 RETURN_AND_SET_ERRNO(_kern_rename(fromFD, from, toFD, to)); 1417 } 1418