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 (stat(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 (stat(path, &st) < 0) { 621 closedir(dir); 622 return errno; 623 } 624 625 if (!S_ISDIR(st.st_mode)) { 626 closedir(dir); 627 return B_NOT_A_DIRECTORY; 628 } 629 630 // cache dir path 631 NodeRef ref(st); 632 add_dir_path(path, ref); 633 634 // create descriptor 635 DirectoryDescriptor *descriptor = new DirectoryDescriptor(dir, ref); 636 return add_descriptor(descriptor); 637 } 638 639 // _kern_open_dir 640 int 641 _kern_open_dir(int fd, const char *path) 642 { 643 // get a usable path 644 string realPath; 645 status_t error = get_path(fd, path, realPath); 646 if (error != B_OK) 647 return error; 648 649 return open_dir(realPath.c_str()); 650 } 651 652 // _kern_open_dir_entry_ref 653 int 654 _kern_open_dir_entry_ref(dev_t device, ino_t node, const char *name) 655 { 656 // get a usable path 657 string realPath; 658 status_t error = get_path(device, node, name, realPath); 659 if (error != B_OK) 660 return error; 661 662 return open_dir(realPath.c_str()); 663 } 664 665 // _kern_open_parent_dir 666 int 667 _kern_open_parent_dir(int fd, char *name, size_t nameLength) 668 { 669 // get a usable path 670 string realPath; 671 status_t error = get_path(fd, name, realPath); 672 if (error != B_OK) 673 return error; 674 675 // stat the entry 676 struct stat st; 677 if (stat(realPath.c_str(), &st) < 0) 678 return errno; 679 680 if (!S_ISDIR(st.st_mode)) 681 return B_NOT_A_DIRECTORY; 682 683 // get the entry name 684 realPath += "/.."; 685 string entryName; 686 error = find_dir_entry(realPath.c_str(), NodeRef(st), 687 entryName, false); 688 if (error != B_OK) 689 return error; 690 691 if (strlcpy(name, entryName.c_str(), nameLength) >= nameLength) 692 return B_BUFFER_OVERFLOW; 693 694 // open the parent directory 695 696 return open_dir(realPath.c_str()); 697 } 698 699 // _kern_read_dir 700 ssize_t 701 _kern_read_dir(int fd, struct dirent *buffer, size_t bufferSize, 702 uint32 maxCount) 703 { 704 if (maxCount <= 0) 705 return B_BAD_VALUE; 706 707 // get the descriptor 708 DirectoryDescriptor *descriptor 709 = dynamic_cast<DirectoryDescriptor*>(get_descriptor(fd)); 710 if (!descriptor) 711 return B_FILE_ERROR; 712 713 // get the next entry 714 dirent *entry; 715 if (dynamic_cast<AttrDirDescriptor*>(descriptor)) 716 entry = fs_read_attr_dir(descriptor->dir); 717 else 718 entry = readdir(descriptor->dir); 719 if (!entry) 720 return errno; 721 722 // copy the entry 723 int entryLen = &entry->d_name[strlen(entry->d_name) + 1] - (char*)entry; 724 if (entryLen > (int)bufferSize) 725 return B_BUFFER_OVERFLOW; 726 727 memcpy(buffer, entry, entryLen); 728 729 return 1; 730 } 731 732 // _kern_rewind_dir 733 status_t 734 _kern_rewind_dir(int fd) 735 { 736 // get the descriptor 737 DirectoryDescriptor *descriptor 738 = dynamic_cast<DirectoryDescriptor*>(get_descriptor(fd)); 739 if (!descriptor) 740 return B_FILE_ERROR; 741 742 // rewind 743 if (dynamic_cast<AttrDirDescriptor*>(descriptor)) 744 fs_rewind_attr_dir(descriptor->dir); 745 else 746 rewinddir(descriptor->dir); 747 748 return B_OK; 749 } 750 751 752 // #pragma mark - 753 754 // open_file 755 static int 756 open_file(const char *path, int openMode, int perms) 757 { 758 // stat the node 759 bool exists = true; 760 struct stat st; 761 if (lstat(path, &st) < 0) { 762 exists = false; 763 if (!(openMode & O_CREAT)) 764 return errno; 765 } 766 767 Descriptor *descriptor; 768 if (exists && S_ISLNK(st.st_mode) && (openMode & O_NOTRAVERSE)) { 769 // a symlink not to be followed: create a special descriptor 770 // normalize path first 771 string normalizedPath; 772 status_t error = normalize_entry_path(path, normalizedPath); 773 if (error != B_OK) 774 return error; 775 776 descriptor = new SymlinkDescriptor(normalizedPath.c_str()); 777 778 } else { 779 // open the file 780 openMode &= ~O_NOTRAVERSE; 781 int newFD = open(path, openMode, perms); 782 if (newFD < 0) 783 return errno; 784 785 descriptor = new FileDescriptor(newFD); 786 } 787 788 // cache path, if this is a directory 789 if (S_ISDIR(st.st_mode)) 790 add_dir_path(path, NodeRef(st)); 791 792 return add_descriptor(descriptor); 793 } 794 795 // _kern_open 796 int 797 _kern_open(int fd, const char *path, int openMode, int perms) 798 { 799 // get a usable path 800 string realPath; 801 status_t error = get_path(fd, path, realPath); 802 if (error != B_OK) 803 return error; 804 805 return open_file(realPath.c_str(), openMode, perms); 806 } 807 808 // _kern_open_entry_ref 809 int 810 _kern_open_entry_ref(dev_t device, ino_t node, const char *name, 811 int openMode, int perms) 812 { 813 // get a usable path 814 string realPath; 815 status_t error = get_path(device, node, name, realPath); 816 if (error != B_OK) 817 return error; 818 819 return open_file(realPath.c_str(), openMode, perms); 820 } 821 822 // _kern_seek 823 off_t 824 _kern_seek(int fd, off_t pos, int seekType) 825 { 826 // get the descriptor 827 FileDescriptor *descriptor 828 = dynamic_cast<FileDescriptor*>(get_descriptor(fd)); 829 if (!descriptor) 830 return B_FILE_ERROR; 831 832 // seek 833 off_t result = lseek(descriptor->fd, pos, seekType); 834 if (result < 0) 835 return errno; 836 837 return result; 838 } 839 840 // _kern_read 841 ssize_t 842 _kern_read(int fd, off_t pos, void *buffer, size_t bufferSize) 843 { 844 // get the descriptor 845 FileDescriptor *descriptor 846 = dynamic_cast<FileDescriptor*>(get_descriptor(fd)); 847 if (!descriptor) 848 return B_FILE_ERROR; 849 850 // seek 851 if (pos != -1) { 852 off_t result = lseek(descriptor->fd, pos, SEEK_SET); 853 if (result < 0) 854 return errno; 855 } 856 857 // read 858 ssize_t bytesRead = read(descriptor->fd, buffer, bufferSize); 859 if (bytesRead < 0) 860 return errno; 861 862 return bytesRead; 863 } 864 865 // _kern_write 866 ssize_t 867 _kern_write(int fd, off_t pos, const void *buffer, size_t bufferSize) 868 { 869 // get the descriptor 870 FileDescriptor *descriptor 871 = dynamic_cast<FileDescriptor*>(get_descriptor(fd)); 872 if (!descriptor) 873 return B_FILE_ERROR; 874 875 // seek 876 if (pos != -1) { 877 off_t result = lseek(descriptor->fd, pos, SEEK_SET); 878 if (result < 0) 879 return errno; 880 } 881 882 // read 883 ssize_t bytesWritten = write(descriptor->fd, buffer, bufferSize); 884 if (bytesWritten < 0) 885 return errno; 886 887 return bytesWritten; 888 } 889 890 // _kern_close 891 status_t 892 _kern_close(int fd) 893 { 894 return delete_descriptor(fd); 895 } 896 897 // _kern_dup 898 int 899 _kern_dup(int fd) 900 { 901 // get the descriptor 902 Descriptor *descriptor = get_descriptor(fd); 903 if (!descriptor) 904 return B_FILE_ERROR; 905 906 // clone it 907 Descriptor *clone; 908 status_t error = descriptor->Dup(clone); 909 if (error != B_OK) 910 return error; 911 912 return add_descriptor(clone); 913 } 914 915 // _kern_fsync 916 status_t 917 _kern_fsync(int fd) 918 { 919 // get the descriptor 920 FileDescriptor *descriptor 921 = dynamic_cast<FileDescriptor*>(get_descriptor(fd)); 922 if (!descriptor) 923 return B_FILE_ERROR; 924 925 // sync 926 if (fsync(descriptor->fd) < 0) 927 return errno; 928 929 return B_OK; 930 } 931 932 // _kern_read_stat 933 status_t 934 _kern_read_stat(int fd, const char *path, bool traverseLink, 935 struct stat *st, size_t statSize) 936 { 937 if (path) { 938 // get a usable path 939 string realPath; 940 status_t error = get_path(fd, path, realPath); 941 if (error != B_OK) 942 return error; 943 944 // stat 945 int result; 946 if (traverseLink) 947 result = stat(realPath.c_str(), st); 948 else 949 result = lstat(realPath.c_str(), st); 950 951 if (result < 0) 952 return errno; 953 } else { 954 Descriptor *descriptor = get_descriptor(fd); 955 if (!descriptor) 956 return B_FILE_ERROR; 957 958 return descriptor->GetStat(traverseLink, st); 959 } 960 961 return B_OK; 962 } 963 964 // _kern_write_stat 965 status_t 966 _kern_write_stat(int fd, const char *path, bool traverseLink, 967 const struct stat *st, size_t statSize, int statMask) 968 { 969 // get a usable path 970 int realFD = -1; 971 string realPath; 972 status_t error; 973 bool isSymlink = false; 974 if (path) { 975 error = get_path(fd, path, realPath); 976 if (error != B_OK) 977 return error; 978 979 // stat it to see, if it is a symlink 980 struct stat tmpStat; 981 if (lstat(realPath.c_str(), &tmpStat) < 0) 982 return errno; 983 984 isSymlink = S_ISLNK(tmpStat.st_mode); 985 986 } else { 987 Descriptor *descriptor = get_descriptor(fd); 988 if (!descriptor) 989 return B_FILE_ERROR; 990 991 if (FileDescriptor *fileFD 992 = dynamic_cast<FileDescriptor*>(descriptor)) { 993 realFD = fileFD->fd; 994 995 } else if (dynamic_cast<DirectoryDescriptor*>(descriptor)) { 996 error = get_path(fd, NULL, realPath); 997 if (error != B_OK) 998 return error; 999 1000 } else if (SymlinkDescriptor *linkFD 1001 = dynamic_cast<SymlinkDescriptor*>(descriptor)) { 1002 realPath = linkFD->path; 1003 isSymlink = true; 1004 1005 } else 1006 return B_FILE_ERROR; 1007 } 1008 1009 // We're screwed, if the node to manipulate is a symlink. All the 1010 // available functions traverse symlinks. 1011 if (isSymlink && !traverseLink) 1012 return B_ERROR; 1013 1014 if (realFD >= 0) { 1015 if (statMask & B_STAT_MODE) { 1016 if (fchmod(realFD, st->st_mode) < 0) 1017 return errno; 1018 } 1019 1020 if (statMask & B_STAT_UID) { 1021 if (fchown(realFD, st->st_uid, (gid_t)-1) < 0) 1022 return errno; 1023 } 1024 1025 if (statMask & B_STAT_GID) { 1026 if (fchown(realFD, (uid_t)-1, st->st_gid) < 0) 1027 return errno; 1028 } 1029 1030 if (statMask & B_STAT_SIZE) { 1031 if (ftruncate(realFD, st->st_size) < 0) 1032 return errno; 1033 } 1034 1035 // The timestamps can only be set via utime(), but that requires a 1036 // path we don't have. 1037 if (statMask & (B_STAT_ACCESS_TIME | B_STAT_MODIFICATION_TIME 1038 | B_STAT_CREATION_TIME | B_STAT_CHANGE_TIME)) { 1039 return B_ERROR; 1040 } 1041 1042 return 0; 1043 1044 } else { 1045 if (statMask & B_STAT_MODE) { 1046 if (chmod(realPath.c_str(), st->st_mode) < 0) 1047 return errno; 1048 } 1049 1050 if (statMask & B_STAT_UID) { 1051 if (chown(realPath.c_str(), st->st_uid, (gid_t)-1) < 0) 1052 return errno; 1053 } 1054 1055 if (statMask & B_STAT_GID) { 1056 if (chown(realPath.c_str(), (uid_t)-1, st->st_gid) < 0) 1057 return errno; 1058 } 1059 1060 if (statMask & B_STAT_SIZE) { 1061 if (truncate(realPath.c_str(), st->st_size) < 0) 1062 return errno; 1063 } 1064 1065 if (statMask & (B_STAT_ACCESS_TIME | B_STAT_MODIFICATION_TIME)) { 1066 // Grab the previous mod and access times so we only overwrite 1067 // the specified time and not both 1068 struct stat oldStat; 1069 if (~statMask & (B_STAT_ACCESS_TIME | B_STAT_MODIFICATION_TIME)) { 1070 if (stat(realPath.c_str(), &oldStat) < 0) 1071 return errno; 1072 } 1073 1074 utimbuf buffer; 1075 buffer.actime = (statMask & B_STAT_ACCESS_TIME) ? st->st_atime : oldStat.st_atime; 1076 buffer.modtime = (statMask & B_STAT_MODIFICATION_TIME) ? st->st_mtime : oldStat.st_mtime; 1077 if (utime(realPath.c_str(), &buffer) < 0) 1078 return errno; 1079 } 1080 1081 // not supported 1082 if (statMask & (B_STAT_CREATION_TIME | B_STAT_CHANGE_TIME)) 1083 return B_ERROR; 1084 } 1085 1086 return B_OK; 1087 } 1088 1089 1090 // #pragma mark - 1091 1092 // _kern_create_symlink 1093 status_t 1094 _kern_create_symlink(int fd, const char *path, const char *toPath, int mode) 1095 { 1096 // Note: path must not be NULL, so this will always work. 1097 // get a usable path 1098 string realPath; 1099 status_t error = get_path(fd, path, realPath); 1100 if (error != B_OK) 1101 return error; 1102 1103 // symlink 1104 if (symlink(toPath, realPath.c_str()) < 0) 1105 return errno; 1106 1107 return B_OK; 1108 } 1109 1110 // _kern_read_link 1111 status_t 1112 _kern_read_link(int fd, const char *path, char *buffer, size_t *_bufferSize) 1113 { 1114 // get the descriptor 1115 SymlinkDescriptor *descriptor 1116 = dynamic_cast<SymlinkDescriptor*>(get_descriptor(fd)); 1117 if (!descriptor) 1118 return B_FILE_ERROR; 1119 1120 // readlink 1121 ssize_t bytesRead = readlink(descriptor->path.c_str(), buffer, 1122 *_bufferSize); 1123 if (bytesRead < 0) 1124 return errno; 1125 1126 if (*_bufferSize > 0) { 1127 if ((size_t)bytesRead == *_bufferSize) 1128 bytesRead--; 1129 1130 buffer[bytesRead] = '\0'; 1131 } 1132 1133 *_bufferSize = bytesRead; 1134 1135 return B_OK; 1136 } 1137 1138 // _kern_unlink 1139 status_t 1140 _kern_unlink(int fd, const char *path) 1141 { 1142 // get a usable path 1143 string realPath; 1144 status_t error = get_path(fd, path, realPath); 1145 if (error != B_OK) 1146 return error; 1147 1148 // unlink 1149 if (unlink(realPath.c_str()) < 0) 1150 return errno; 1151 1152 return B_OK; 1153 } 1154 1155 // _kern_rename 1156 status_t 1157 _kern_rename(int oldDir, const char *oldPath, int newDir, const char *newPath) 1158 { 1159 // get usable paths 1160 string realOldPath; 1161 status_t error = get_path(oldDir, oldPath, realOldPath); 1162 if (error != B_OK) 1163 return error; 1164 1165 string realNewPath; 1166 error = get_path(newDir, newPath, realNewPath); 1167 if (error != B_OK) 1168 return error; 1169 1170 // rename 1171 if (rename(realOldPath.c_str(), realNewPath.c_str()) < 0) 1172 return errno; 1173 1174 return B_OK; 1175 } 1176 1177 1178 // #pragma mark - 1179 1180 // _kern_lock_node 1181 status_t 1182 _kern_lock_node(int fd) 1183 { 1184 return B_ERROR; 1185 } 1186 1187 // _kern_unlock_node 1188 status_t 1189 _kern_unlock_node(int fd) 1190 { 1191 return B_ERROR; 1192 } 1193 1194 1195 // #pragma mark - 1196 1197 // _kern_open_attr_dir 1198 int 1199 _kern_open_attr_dir(int fd, const char *path) 1200 { 1201 // get node ref for the node 1202 struct stat st; 1203 status_t error = _kern_read_stat(fd, path, false, &st, 1204 sizeof(struct stat)); 1205 if (error != B_OK) { 1206 errno = error; 1207 return -1; 1208 } 1209 NodeRef ref(st); 1210 1211 // open the attr dir 1212 DIR *dir = open_attr_dir(ref); 1213 if (!dir) 1214 return errno; 1215 1216 // create descriptor 1217 AttrDirDescriptor *descriptor = new AttrDirDescriptor(dir, ref); 1218 return add_descriptor(descriptor); 1219 } 1220 1221 // get_attribute_path 1222 static status_t 1223 get_attribute_path(int fd, const char *attribute, string &attrPath, 1224 string &typePath) 1225 { 1226 // stat the file to get a NodeRef 1227 struct stat st; 1228 status_t error = _kern_read_stat(fd, NULL, false, &st, sizeof(st)); 1229 if (error != B_OK) 1230 return error; 1231 NodeRef ref(st); 1232 1233 // get the attribute path 1234 return get_attribute_path(ref, attribute, attrPath, typePath); 1235 } 1236 1237 // _kern_rename_attr 1238 status_t 1239 _kern_rename_attr(int fromFile, const char *fromName, int toFile, 1240 const char *toName) 1241 { 1242 if (!fromName || !toName) 1243 return B_BAD_VALUE; 1244 1245 // get the attribute paths 1246 string fromAttrPath; 1247 string fromTypePath; 1248 status_t error = get_attribute_path(fromFile, fromName, fromAttrPath, 1249 fromTypePath); 1250 if (error != B_OK) 1251 return error; 1252 1253 string toAttrPath; 1254 string toTypePath; 1255 error = get_attribute_path(toFile, toName, toAttrPath, toTypePath); 1256 if (error != B_OK) 1257 return error; 1258 1259 // rename the attribute and type files 1260 if (rename(fromAttrPath.c_str(), toAttrPath.c_str()) < 0) 1261 return errno; 1262 1263 if (rename(fromTypePath.c_str(), toTypePath.c_str()) < 0) { 1264 // renaming the type file failed: try to rename back the attribute file 1265 error = errno; 1266 1267 rename(toAttrPath.c_str(), fromAttrPath.c_str()); 1268 1269 return error; 1270 } 1271 1272 return B_OK; 1273 } 1274 1275 // _kern_remove_attr 1276 status_t 1277 _kern_remove_attr(int fd, const char *name) 1278 { 1279 if (!name) 1280 return B_BAD_VALUE; 1281 1282 // get the attribute path 1283 string attrPath; 1284 string typePath; 1285 status_t error = get_attribute_path(fd, name, attrPath, typePath); 1286 if (error != B_OK) 1287 return error; 1288 1289 // remove the attribute 1290 if (unlink(attrPath.c_str()) < 0) 1291 return errno; 1292 1293 unlink(typePath.c_str()); 1294 1295 return B_OK; 1296 } 1297 1298 1299 // #pragma mark - 1300 1301 // read_pos 1302 ssize_t 1303 read_pos(int fd, off_t pos, void *buffer, size_t bufferSize) 1304 { 1305 // seek 1306 off_t result = lseek(fd, pos, SEEK_SET); 1307 if (result < 0) 1308 return errno; 1309 1310 // read 1311 ssize_t bytesRead = read(fd, buffer, bufferSize); 1312 if (bytesRead < 0) { 1313 errno = bytesRead; 1314 return -1; 1315 } 1316 1317 return bytesRead; 1318 } 1319 1320 // write_pos 1321 ssize_t 1322 write_pos(int fd, off_t pos, const void *buffer, size_t bufferSize) 1323 { 1324 // seek 1325 off_t result = lseek(fd, pos, SEEK_SET); 1326 if (result < 0) 1327 return errno; 1328 1329 // read 1330 ssize_t bytesWritten = write(fd, buffer, bufferSize); 1331 if (bytesWritten < 0) { 1332 errno = bytesWritten; 1333 return -1; 1334 } 1335 1336 return bytesWritten; 1337 } 1338