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