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