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