1 /* 2 * Copyright 2005-2008, 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 20 #include <map> 21 #include <string> 22 23 #include <fs_attr.h> 24 #include <NodeMonitor.h> // for B_STAT_* flags 25 #include <syscalls.h> 26 27 #include "fs_descriptors.h" 28 #include "NodeRef.h" 29 30 #if defined(HAIKU_HOST_PLATFORM_FREEBSD) 31 # include "fs_freebsd.h" 32 #endif 33 34 35 using namespace std; 36 using namespace BPrivate; 37 38 39 #if defined(HAIKU_HOST_PLATFORM_FREEBSD) 40 # define haiku_host_platform_read haiku_freebsd_read 41 # define haiku_host_platform_write haiku_freebsd_write 42 # define haiku_host_platform_readv haiku_freebsd_readv 43 # define haiku_host_platform_writev haiku_freebsd_writev 44 #else 45 # define haiku_host_platform_read read 46 # define haiku_host_platform_write write 47 # define haiku_host_platform_readv readv 48 # define haiku_host_platform_writev writev 49 #endif 50 51 52 static status_t get_path(dev_t device, ino_t node, const char *name, 53 string &path); 54 55 56 // find_dir_entry 57 static status_t 58 find_dir_entry(DIR *dir, const char *path, NodeRef ref, string &name, 59 bool skipDot) 60 { 61 // find the entry 62 bool found = false; 63 while (dirent *entry = readdir(dir)) { 64 if ((!skipDot && strcmp(entry->d_name, ".") == 0) 65 || strcmp(entry->d_name, "..") == 0) { 66 // skip "." and ".." 67 } else /*if (entry->d_ino == ref.node)*/ { 68 // Note: Linux doesn't seem to translate dirent::d_ino of 69 // mount points. Thus we always have to lstat(). 70 // We also need to compare the device, which is generally not 71 // included in the dirent structure. Hence we lstat(). 72 string entryPath(path); 73 entryPath += '/'; 74 entryPath += entry->d_name; 75 struct stat st; 76 if (lstat(entryPath.c_str(), &st) == 0) { 77 if (NodeRef(st) == ref) { 78 name = entry->d_name; 79 found = true; 80 break; 81 } 82 } 83 } 84 } 85 86 if (!found) 87 return B_ENTRY_NOT_FOUND; 88 89 return B_OK; 90 } 91 92 // find_dir_entry 93 static status_t 94 find_dir_entry(const char *path, NodeRef ref, string &name, bool skipDot) 95 { 96 // open dir 97 DIR *dir = opendir(path); 98 if (!dir) 99 return errno; 100 101 status_t error = find_dir_entry(dir, path, ref, name, skipDot); 102 103 // close dir 104 closedir(dir); 105 106 return error; 107 } 108 109 // normalize_dir_path 110 static status_t 111 normalize_dir_path(string path, NodeRef ref, string &normalizedPath) 112 { 113 // get parent path 114 path += "/.."; 115 116 // stat the parent dir 117 struct stat st; 118 if (lstat(path.c_str(), &st) < 0) 119 return errno; 120 121 // root dir? 122 NodeRef parentRef(st); 123 if (parentRef == ref) { 124 normalizedPath = "/"; 125 return 0; 126 } 127 128 // find the entry 129 string name; 130 status_t error = find_dir_entry(path.c_str(), ref, name, true) ; 131 if (error != B_OK) 132 return error; 133 134 // recurse to get the parent dir path, if found 135 error = normalize_dir_path(path, parentRef, normalizedPath); 136 if (error != 0) 137 return error; 138 139 // construct the normalizedPath 140 if (normalizedPath.length() > 1) // don't append "/", if parent is root 141 normalizedPath += '/'; 142 normalizedPath += name; 143 144 return 0; 145 } 146 147 // normalize_dir_path 148 static status_t 149 normalize_dir_path(const char *path, string &normalizedPath) 150 { 151 // stat() the dir 152 struct stat st; 153 if (stat(path, &st) < 0) 154 return errno; 155 156 return normalize_dir_path(path, NodeRef(st), normalizedPath); 157 } 158 159 // normalize_entry_path 160 static status_t 161 normalize_entry_path(const char *path, string &normalizedPath) 162 { 163 const char *dirPath = NULL; 164 const char *leafName = NULL; 165 166 string dirPathString; 167 if (const char *lastSlash = strrchr(path, '/')) { 168 // found a slash: decompose into dir path and leaf name 169 leafName = lastSlash + 1; 170 if (leafName[0] == '\0') { 171 // slash is at the end: the whole path is a dir name 172 leafName = NULL; 173 } else { 174 dirPathString = string(path, leafName - path); 175 dirPath = dirPathString.c_str(); 176 } 177 178 } else { 179 // path contains no slash, so it is a path relative to the current dir 180 dirPath = "."; 181 leafName = path; 182 } 183 184 // catch special case: no leaf, or leaf is a directory 185 if (!leafName || strcmp(leafName, ".") == 0 || strcmp(leafName, "..") == 0) 186 return normalize_dir_path(path, normalizedPath); 187 188 // normalize the dir path 189 status_t error = normalize_dir_path(dirPath, normalizedPath); 190 if (error != B_OK) 191 return error; 192 193 // append the leaf name 194 if (normalizedPath.length() > 1) // don't append "/", if parent is root 195 normalizedPath += '/'; 196 normalizedPath += leafName; 197 198 return B_OK; 199 } 200 201 202 // #pragma mark - 203 204 typedef map<NodeRef, string> DirPathMap; 205 static DirPathMap sDirPathMap; 206 207 // get_path 208 static status_t 209 get_path(const NodeRef *ref, const char *name, string &path) 210 { 211 if (!ref && !name) 212 return B_BAD_VALUE; 213 214 // no ref or absolute path 215 if (!ref || (name && name[0] == '/')) { 216 path = name; 217 return B_OK; 218 } 219 220 // get the dir path 221 if (ref) { 222 DirPathMap::iterator it = sDirPathMap.find(*ref); 223 if (it == sDirPathMap.end()) 224 return B_ENTRY_NOT_FOUND; 225 226 path = it->second; 227 228 // stat the path to check, if it is still valid 229 struct stat st; 230 if (lstat(path.c_str(), &st) < 0) { 231 sDirPathMap.erase(it); 232 return errno; 233 } 234 235 // compare the NodeRef 236 if (NodeRef(st) != *ref) { 237 sDirPathMap.erase(it); 238 return B_ENTRY_NOT_FOUND; 239 } 240 241 // still a directory? 242 if (!S_ISDIR(st.st_mode)) { 243 sDirPathMap.erase(it); 244 return B_NOT_A_DIRECTORY; 245 } 246 } 247 248 // if there's a name, append it 249 if (name) { 250 path += '/'; 251 path += name; 252 } 253 254 return B_OK; 255 } 256 257 // get_path 258 status_t 259 BPrivate::get_path(int fd, const char *name, string &path) 260 { 261 // get the node ref for the fd, if any, and the path part is not absolute 262 if (fd >= 0 && !(name && name[0] == '/')) { 263 // get descriptor 264 Descriptor *descriptor = get_descriptor(fd); 265 if (!descriptor) 266 return B_FILE_ERROR; 267 268 // get node ref for the descriptor 269 NodeRef ref; 270 status_t error = descriptor->GetNodeRef(ref); 271 if (error != B_OK) 272 return error; 273 274 return ::get_path(&ref, name, path); 275 276 } else // no descriptor or absolute path 277 return ::get_path((NodeRef*)NULL, name, path); 278 } 279 280 // get_path 281 static status_t 282 get_path(dev_t device, ino_t directory, const char *name, string &path) 283 { 284 NodeRef ref; 285 ref.device = device; 286 ref.node = directory; 287 288 return get_path(&ref, name, path); 289 } 290 291 // add_dir_path 292 static void 293 add_dir_path(const char *path, const NodeRef &ref) 294 { 295 // add the normalized path 296 string normalizedPath; 297 if (normalize_dir_path(path, normalizedPath) == B_OK) 298 sDirPathMap[ref] = normalizedPath; 299 } 300 301 302 // #pragma mark - 303 304 // _kern_entry_ref_to_path 305 status_t 306 _kern_entry_ref_to_path(dev_t device, ino_t node, const char *leaf, 307 char *userPath, size_t pathLength) 308 { 309 // get the path 310 string path; 311 status_t error = get_path(device, node, leaf, path); 312 if (error != B_OK) 313 return error; 314 315 // copy it back to the user buffer 316 if (strlcpy(userPath, path.c_str(), pathLength) >= pathLength) 317 return B_BUFFER_OVERFLOW; 318 319 return B_OK; 320 } 321 322 323 // #pragma mark - 324 325 // _kern_create_dir 326 status_t 327 _kern_create_dir(int fd, const char *path, int perms) 328 { 329 // get a usable path 330 string realPath; 331 status_t error = get_path(fd, path, realPath); 332 if (error != B_OK) 333 return error; 334 335 // mkdir 336 if (mkdir(realPath.c_str(), perms) < 0) 337 return errno; 338 339 return B_OK; 340 } 341 342 // _kern_create_dir_entry_ref 343 status_t 344 _kern_create_dir_entry_ref(dev_t device, ino_t node, const char *name, 345 int perms) 346 { 347 // get a usable path 348 string realPath; 349 status_t error = get_path(device, node, name, realPath); 350 if (error != B_OK) 351 return error; 352 353 // mkdir 354 if (mkdir(realPath.c_str(), perms) < 0) 355 return errno; 356 357 return B_OK; 358 } 359 360 // open_dir 361 static int 362 open_dir(const char *path) 363 { 364 // open the dir 365 DIR *dir = opendir(path); 366 if (!dir) 367 return errno; 368 369 // stat the entry 370 struct stat st; 371 if (stat(path, &st) < 0) { 372 closedir(dir); 373 return errno; 374 } 375 376 if (!S_ISDIR(st.st_mode)) { 377 closedir(dir); 378 return B_NOT_A_DIRECTORY; 379 } 380 381 // cache dir path 382 NodeRef ref(st); 383 add_dir_path(path, ref); 384 385 // create descriptor 386 DirectoryDescriptor *descriptor = new DirectoryDescriptor(dir, ref); 387 return add_descriptor(descriptor); 388 } 389 390 // _kern_open_dir 391 int 392 _kern_open_dir(int fd, const char *path) 393 { 394 // get a usable path 395 string realPath; 396 status_t error = get_path(fd, path, realPath); 397 if (error != B_OK) 398 return error; 399 400 return open_dir(realPath.c_str()); 401 } 402 403 // _kern_open_dir_entry_ref 404 int 405 _kern_open_dir_entry_ref(dev_t device, ino_t node, const char *name) 406 { 407 // get a usable path 408 string realPath; 409 status_t error = get_path(device, node, name, realPath); 410 if (error != B_OK) 411 return error; 412 413 return open_dir(realPath.c_str()); 414 } 415 416 // _kern_open_parent_dir 417 int 418 _kern_open_parent_dir(int fd, char *name, size_t nameLength) 419 { 420 // get a usable path 421 string realPath; 422 status_t error = get_path(fd, NULL, realPath); 423 if (error != B_OK) 424 return error; 425 426 // stat the entry 427 struct stat st; 428 if (stat(realPath.c_str(), &st) < 0) 429 return errno; 430 431 if (!S_ISDIR(st.st_mode)) 432 return B_NOT_A_DIRECTORY; 433 434 // get the entry name 435 realPath += "/.."; 436 string entryName; 437 error = find_dir_entry(realPath.c_str(), NodeRef(st), 438 entryName, false); 439 if (error != B_OK) 440 return error; 441 442 if (strlcpy(name, entryName.c_str(), nameLength) >= nameLength) 443 return B_BUFFER_OVERFLOW; 444 445 // open the parent directory 446 447 return open_dir(realPath.c_str()); 448 } 449 450 // _kern_read_dir 451 ssize_t 452 _kern_read_dir(int fd, struct dirent *buffer, size_t bufferSize, 453 uint32 maxCount) 454 { 455 if (maxCount <= 0) 456 return B_BAD_VALUE; 457 458 // get the descriptor 459 DirectoryDescriptor *descriptor 460 = dynamic_cast<DirectoryDescriptor*>(get_descriptor(fd)); 461 if (!descriptor) 462 return B_FILE_ERROR; 463 464 // get the next entry 465 dirent *entry; 466 if (dynamic_cast<AttrDirDescriptor*>(descriptor)) 467 entry = fs_read_attr_dir(descriptor->dir); 468 else 469 entry = readdir(descriptor->dir); 470 if (!entry) 471 return errno; 472 473 // copy the entry 474 int entryLen = &entry->d_name[strlen(entry->d_name) + 1] - (char*)entry; 475 if (entryLen > (int)bufferSize) 476 return B_BUFFER_OVERFLOW; 477 478 memcpy(buffer, entry, entryLen); 479 480 return 1; 481 } 482 483 // _kern_rewind_dir 484 status_t 485 _kern_rewind_dir(int fd) 486 { 487 // get the descriptor 488 DirectoryDescriptor *descriptor 489 = dynamic_cast<DirectoryDescriptor*>(get_descriptor(fd)); 490 if (!descriptor) 491 return B_FILE_ERROR; 492 493 // rewind 494 if (dynamic_cast<AttrDirDescriptor*>(descriptor)) 495 fs_rewind_attr_dir(descriptor->dir); 496 else 497 rewinddir(descriptor->dir); 498 499 return B_OK; 500 } 501 502 503 // #pragma mark - 504 505 // open_file 506 static int 507 open_file(const char *path, int openMode, int perms) 508 { 509 // stat the node 510 bool exists = true; 511 struct stat st; 512 if (lstat(path, &st) < 0) { 513 exists = false; 514 if (!(openMode & O_CREAT)) 515 return errno; 516 } 517 518 Descriptor *descriptor; 519 if (exists && S_ISLNK(st.st_mode) && (openMode & O_NOTRAVERSE) != 0) { 520 // a symlink not to be followed: create a special descriptor 521 // normalize path first 522 string normalizedPath; 523 status_t error = normalize_entry_path(path, normalizedPath); 524 if (error != B_OK) 525 return error; 526 527 descriptor = new SymlinkDescriptor(normalizedPath.c_str()); 528 } else { 529 // open the file 530 openMode &= ~O_NOTRAVERSE; 531 int newFD = open(path, openMode, perms); 532 if (newFD < 0) 533 return errno; 534 535 descriptor = new FileDescriptor(newFD); 536 } 537 538 // cache path, if this is a directory 539 if (exists && S_ISDIR(st.st_mode)) 540 add_dir_path(path, NodeRef(st)); 541 542 return add_descriptor(descriptor); 543 } 544 545 // _kern_open 546 int 547 _kern_open(int fd, const char *path, int openMode, int perms) 548 { 549 // get a usable path 550 string realPath; 551 status_t error = get_path(fd, path, realPath); 552 if (error != B_OK) 553 return error; 554 555 return open_file(realPath.c_str(), openMode, perms); 556 } 557 558 // _kern_open_entry_ref 559 int 560 _kern_open_entry_ref(dev_t device, ino_t node, const char *name, 561 int openMode, int perms) 562 { 563 // get a usable path 564 string realPath; 565 status_t error = get_path(device, node, name, realPath); 566 if (error != B_OK) 567 return error; 568 569 return open_file(realPath.c_str(), openMode, perms); 570 } 571 572 // _kern_seek 573 off_t 574 _kern_seek(int fd, off_t pos, int seekType) 575 { 576 // get the descriptor 577 FileDescriptor *descriptor 578 = dynamic_cast<FileDescriptor*>(get_descriptor(fd)); 579 if (!descriptor) 580 return B_FILE_ERROR; 581 582 // seek 583 off_t result = lseek(descriptor->fd, pos, seekType); 584 if (result < 0) 585 return errno; 586 587 return result; 588 } 589 590 // _kern_read 591 ssize_t 592 _kern_read(int fd, off_t pos, void *buffer, size_t bufferSize) 593 { 594 // get the descriptor 595 FileDescriptor *descriptor 596 = dynamic_cast<FileDescriptor*>(get_descriptor(fd)); 597 if (!descriptor) 598 return B_FILE_ERROR; 599 600 // seek 601 if (pos != -1) { 602 off_t result = lseek(descriptor->fd, pos, SEEK_SET); 603 if (result < 0) 604 return errno; 605 } 606 607 // read 608 ssize_t bytesRead = haiku_host_platform_read(descriptor->fd, buffer, 609 bufferSize); 610 if (bytesRead < 0) 611 return errno; 612 613 return bytesRead; 614 } 615 616 // _kern_write 617 ssize_t 618 _kern_write(int fd, off_t pos, const void *buffer, size_t bufferSize) 619 { 620 // get the descriptor 621 FileDescriptor *descriptor 622 = dynamic_cast<FileDescriptor*>(get_descriptor(fd)); 623 if (!descriptor) 624 return B_FILE_ERROR; 625 626 // seek 627 if (pos != -1) { 628 off_t result = lseek(descriptor->fd, pos, SEEK_SET); 629 if (result < 0) 630 return errno; 631 } 632 633 // read 634 ssize_t bytesWritten = haiku_host_platform_write(descriptor->fd, buffer, 635 bufferSize); 636 if (bytesWritten < 0) 637 return errno; 638 639 return bytesWritten; 640 } 641 642 // _kern_close 643 status_t 644 _kern_close(int fd) 645 { 646 return delete_descriptor(fd); 647 } 648 649 // _kern_dup 650 int 651 _kern_dup(int fd) 652 { 653 // get the descriptor 654 Descriptor *descriptor = get_descriptor(fd); 655 if (!descriptor) 656 return B_FILE_ERROR; 657 658 // clone it 659 Descriptor *clone; 660 status_t error = descriptor->Dup(clone); 661 if (error != B_OK) 662 return error; 663 664 return add_descriptor(clone); 665 } 666 667 // _kern_fsync 668 status_t 669 _kern_fsync(int fd) 670 { 671 // get the descriptor 672 FileDescriptor *descriptor 673 = dynamic_cast<FileDescriptor*>(get_descriptor(fd)); 674 if (!descriptor) 675 return B_FILE_ERROR; 676 677 // sync 678 if (fsync(descriptor->fd) < 0) 679 return errno; 680 681 return B_OK; 682 } 683 684 // _kern_read_stat 685 status_t 686 _kern_read_stat(int fd, const char *path, bool traverseLink, 687 struct stat *st, size_t statSize) 688 { 689 if (path) { 690 // get a usable path 691 string realPath; 692 status_t error = get_path(fd, path, realPath); 693 if (error != B_OK) 694 return error; 695 696 // stat 697 int result; 698 if (traverseLink) 699 result = stat(realPath.c_str(), st); 700 else 701 result = lstat(realPath.c_str(), st); 702 703 if (result < 0) 704 return errno; 705 } else { 706 Descriptor *descriptor = get_descriptor(fd); 707 if (!descriptor) 708 return B_FILE_ERROR; 709 710 return descriptor->GetStat(traverseLink, st); 711 } 712 713 return B_OK; 714 } 715 716 // _kern_write_stat 717 status_t 718 _kern_write_stat(int fd, const char *path, bool traverseLink, 719 const struct stat *st, size_t statSize, int statMask) 720 { 721 // get a usable path 722 int realFD = -1; 723 string realPath; 724 status_t error; 725 bool isSymlink = false; 726 if (path) { 727 error = get_path(fd, path, realPath); 728 if (error != B_OK) 729 return error; 730 731 // stat it to see, if it is a symlink 732 struct stat tmpStat; 733 if (lstat(realPath.c_str(), &tmpStat) < 0) 734 return errno; 735 736 isSymlink = S_ISLNK(tmpStat.st_mode); 737 738 } else { 739 Descriptor *descriptor = get_descriptor(fd); 740 if (!descriptor) 741 return B_FILE_ERROR; 742 743 if (FileDescriptor *fileFD 744 = dynamic_cast<FileDescriptor*>(descriptor)) { 745 realFD = fileFD->fd; 746 747 } else if (dynamic_cast<DirectoryDescriptor*>(descriptor)) { 748 error = get_path(fd, NULL, realPath); 749 if (error != B_OK) 750 return error; 751 752 } else if (SymlinkDescriptor *linkFD 753 = dynamic_cast<SymlinkDescriptor*>(descriptor)) { 754 realPath = linkFD->path; 755 isSymlink = true; 756 757 } else 758 return B_FILE_ERROR; 759 } 760 761 // We're screwed, if the node to manipulate is a symlink. All the 762 // available functions traverse symlinks. 763 if (isSymlink && !traverseLink) 764 return B_ERROR; 765 766 if (realFD >= 0) { 767 if (statMask & B_STAT_MODE) { 768 if (fchmod(realFD, st->st_mode) < 0) 769 return errno; 770 } 771 772 if (statMask & B_STAT_UID) { 773 if (fchown(realFD, st->st_uid, (gid_t)-1) < 0) 774 return errno; 775 } 776 777 if (statMask & B_STAT_GID) { 778 if (fchown(realFD, (uid_t)-1, st->st_gid) < 0) 779 return errno; 780 } 781 782 if (statMask & B_STAT_SIZE) { 783 if (ftruncate(realFD, st->st_size) < 0) 784 return errno; 785 } 786 787 // The timestamps can only be set via utime(), but that requires a 788 // path we don't have. 789 if (statMask & (B_STAT_ACCESS_TIME | B_STAT_MODIFICATION_TIME 790 | B_STAT_CREATION_TIME | B_STAT_CHANGE_TIME)) { 791 return B_ERROR; 792 } 793 794 return 0; 795 796 } else { 797 if (statMask & B_STAT_MODE) { 798 if (chmod(realPath.c_str(), st->st_mode) < 0) 799 return errno; 800 } 801 802 if (statMask & B_STAT_UID) { 803 if (chown(realPath.c_str(), st->st_uid, (gid_t)-1) < 0) 804 return errno; 805 } 806 807 if (statMask & B_STAT_GID) { 808 if (chown(realPath.c_str(), (uid_t)-1, st->st_gid) < 0) 809 return errno; 810 } 811 812 if (statMask & B_STAT_SIZE) { 813 if (truncate(realPath.c_str(), st->st_size) < 0) 814 return errno; 815 } 816 817 if (statMask & (B_STAT_ACCESS_TIME | B_STAT_MODIFICATION_TIME)) { 818 // Grab the previous mod and access times so we only overwrite 819 // the specified time and not both 820 struct stat oldStat; 821 if (~statMask & (B_STAT_ACCESS_TIME | B_STAT_MODIFICATION_TIME)) { 822 if (stat(realPath.c_str(), &oldStat) < 0) 823 return errno; 824 } 825 826 utimbuf buffer; 827 buffer.actime = (statMask & B_STAT_ACCESS_TIME) ? st->st_atime : oldStat.st_atime; 828 buffer.modtime = (statMask & B_STAT_MODIFICATION_TIME) ? st->st_mtime : oldStat.st_mtime; 829 if (utime(realPath.c_str(), &buffer) < 0) 830 return errno; 831 } 832 833 // not supported 834 if (statMask & (B_STAT_CREATION_TIME | B_STAT_CHANGE_TIME)) 835 return B_ERROR; 836 } 837 838 return B_OK; 839 } 840 841 842 // #pragma mark - 843 844 // _kern_create_symlink 845 status_t 846 _kern_create_symlink(int fd, const char *path, const char *toPath, int mode) 847 { 848 // Note: path must not be NULL, so this will always work. 849 // get a usable path 850 string realPath; 851 status_t error = get_path(fd, path, realPath); 852 if (error != B_OK) 853 return error; 854 855 // symlink 856 if (symlink(toPath, realPath.c_str()) < 0) 857 return errno; 858 859 return B_OK; 860 } 861 862 // _kern_read_link 863 status_t 864 _kern_read_link(int fd, const char *path, char *buffer, size_t *_bufferSize) 865 { 866 // get the descriptor 867 SymlinkDescriptor *descriptor 868 = dynamic_cast<SymlinkDescriptor*>(get_descriptor(fd)); 869 if (!descriptor) 870 return B_FILE_ERROR; 871 872 // readlink 873 ssize_t bytesRead = readlink(descriptor->path.c_str(), buffer, 874 *_bufferSize); 875 if (bytesRead < 0) 876 return errno; 877 878 if (*_bufferSize > 0) { 879 if ((size_t)bytesRead == *_bufferSize) 880 bytesRead--; 881 882 buffer[bytesRead] = '\0'; 883 } 884 885 *_bufferSize = bytesRead; 886 887 return B_OK; 888 } 889 890 // _kern_unlink 891 status_t 892 _kern_unlink(int fd, const char *path) 893 { 894 // get a usable path 895 string realPath; 896 status_t error = get_path(fd, path, realPath); 897 if (error != B_OK) 898 return error; 899 900 // unlink 901 if (unlink(realPath.c_str()) < 0) 902 return errno; 903 904 return B_OK; 905 } 906 907 // _kern_rename 908 status_t 909 _kern_rename(int oldDir, const char *oldPath, int newDir, const char *newPath) 910 { 911 // get usable paths 912 string realOldPath; 913 status_t error = get_path(oldDir, oldPath, realOldPath); 914 if (error != B_OK) 915 return error; 916 917 string realNewPath; 918 error = get_path(newDir, newPath, realNewPath); 919 if (error != B_OK) 920 return error; 921 922 // rename 923 if (rename(realOldPath.c_str(), realNewPath.c_str()) < 0) 924 return errno; 925 926 return B_OK; 927 } 928 929 930 // #pragma mark - 931 932 // _kern_lock_node 933 status_t 934 _kern_lock_node(int fd) 935 { 936 return B_ERROR; 937 } 938 939 // _kern_unlock_node 940 status_t 941 _kern_unlock_node(int fd) 942 { 943 return B_ERROR; 944 } 945 946 947 // #pragma mark - 948 949 // read_pos 950 ssize_t 951 read_pos(int fd, off_t pos, void *buffer, size_t bufferSize) 952 { 953 // seek 954 off_t result = lseek(fd, pos, SEEK_SET); 955 if (result < 0) 956 return errno; 957 958 // read 959 ssize_t bytesRead = haiku_host_platform_read(fd, buffer, bufferSize); 960 if (bytesRead < 0) { 961 errno = bytesRead; 962 return -1; 963 } 964 965 return bytesRead; 966 } 967 968 // write_pos 969 ssize_t 970 write_pos(int fd, off_t pos, const void *buffer, size_t bufferSize) 971 { 972 // seek 973 off_t result = lseek(fd, pos, SEEK_SET); 974 if (result < 0) 975 return errno; 976 977 // read 978 ssize_t bytesWritten = haiku_host_platform_write(fd, buffer, bufferSize); 979 if (bytesWritten < 0) { 980 errno = bytesWritten; 981 return -1; 982 } 983 984 return bytesWritten; 985 } 986 987 // readv_pos 988 ssize_t 989 readv_pos(int fd, off_t pos, const struct iovec *vec, size_t count) 990 { 991 // seek 992 off_t result = lseek(fd, pos, SEEK_SET); 993 if (result < 0) 994 return errno; 995 996 // read 997 ssize_t bytesRead = haiku_host_platform_readv(fd, vec, count); 998 if (bytesRead < 0) { 999 errno = bytesRead; 1000 return -1; 1001 } 1002 1003 return bytesRead; 1004 } 1005 1006 // writev_pos 1007 ssize_t 1008 writev_pos(int fd, off_t pos, const struct iovec *vec, size_t count) 1009 { 1010 // seek 1011 off_t result = lseek(fd, pos, SEEK_SET); 1012 if (result < 0) 1013 return errno; 1014 1015 // read 1016 ssize_t bytesWritten = haiku_host_platform_writev(fd, vec, count); 1017 if (bytesWritten < 0) { 1018 errno = bytesWritten; 1019 return -1; 1020 } 1021 1022 return bytesWritten; 1023 } 1024