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