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