1 /* 2 * Copyright 2005-2008, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 #include <BeOSBuildCompatibility.h> 7 8 #include "fs_impl.h" 9 10 #include <dirent.h> 11 #include <errno.h> 12 #include <fcntl.h> 13 #include <stdio.h> 14 #include <stdlib.h> 15 #include <unistd.h> 16 #include <utime.h> 17 #include <sys/stat.h> 18 19 #include <map> 20 #include <string> 21 22 #include <fs_attr.h> 23 #include <NodeMonitor.h> // for B_STAT_* flags 24 #include <syscalls.h> 25 26 #include "fs_descriptors.h" 27 #include "NodeRef.h" 28 29 #if defined(HAIKU_HOST_PLATFORM_FREEBSD) 30 # include "fs_freebsd.h" 31 #endif 32 33 34 using namespace std; 35 using namespace BPrivate; 36 37 38 #if defined(HAIKU_HOST_PLATFORM_FREEBSD) 39 # define haiku_host_platform_read haiku_freebsd_read 40 # define haiku_host_platform_write haiku_freebsd_write 41 # define haiku_host_platform_readv haiku_freebsd_readv 42 # define haiku_host_platform_writev haiku_freebsd_writev 43 #else 44 # define haiku_host_platform_read read 45 # define haiku_host_platform_write write 46 # define haiku_host_platform_readv readv 47 # define haiku_host_platform_writev writev 48 #endif 49 50 51 static status_t get_path(dev_t device, ino_t node, const char *name, 52 string &path); 53 54 55 // find_dir_entry 56 static status_t 57 find_dir_entry(DIR *dir, const char *path, NodeRef ref, string &name, 58 bool skipDot) 59 { 60 // find the entry 61 bool found = false; 62 while (dirent *entry = readdir(dir)) { 63 if ((!skipDot && strcmp(entry->d_name, ".") == 0) 64 || strcmp(entry->d_name, "..") == 0) { 65 // skip "." and ".." 66 } else /*if (entry->d_ino == ref.node)*/ { 67 // Note: Linux doesn't seem to translate dirent::d_ino of 68 // mount points. Thus we always have to lstat(). 69 // We also need to compare the device, which is generally not 70 // included in the dirent structure. Hence we lstat(). 71 string entryPath(path); 72 entryPath += '/'; 73 entryPath += entry->d_name; 74 struct stat st; 75 if (lstat(entryPath.c_str(), &st) == 0) { 76 if (NodeRef(st) == ref) { 77 name = entry->d_name; 78 found = true; 79 break; 80 } 81 } 82 } 83 } 84 85 if (!found) 86 return B_ENTRY_NOT_FOUND; 87 88 return B_OK; 89 } 90 91 // find_dir_entry 92 static status_t 93 find_dir_entry(const char *path, NodeRef ref, string &name, bool skipDot) 94 { 95 // open dir 96 DIR *dir = opendir(path); 97 if (!dir) 98 return errno; 99 100 status_t error = find_dir_entry(dir, path, ref, name, skipDot); 101 102 // close dir 103 closedir(dir); 104 105 return error; 106 } 107 108 // normalize_dir_path 109 static status_t 110 normalize_dir_path(string path, NodeRef ref, string &normalizedPath) 111 { 112 // get parent path 113 path += "/.."; 114 115 // stat the parent dir 116 struct stat st; 117 if (lstat(path.c_str(), &st) < 0) 118 return errno; 119 120 // root dir? 121 NodeRef parentRef(st); 122 if (parentRef == ref) { 123 normalizedPath = "/"; 124 return 0; 125 } 126 127 // find the entry 128 string name; 129 status_t error = find_dir_entry(path.c_str(), ref, name, true) ; 130 if (error != B_OK) 131 return error; 132 133 // recurse to get the parent dir path, if found 134 error = normalize_dir_path(path, parentRef, normalizedPath); 135 if (error != 0) 136 return error; 137 138 // construct the normalizedPath 139 if (normalizedPath.length() > 1) // don't append "/", if parent is root 140 normalizedPath += '/'; 141 normalizedPath += name; 142 143 return 0; 144 } 145 146 // normalize_dir_path 147 static status_t 148 normalize_dir_path(const char *path, string &normalizedPath) 149 { 150 // stat() the dir 151 struct stat st; 152 if (stat(path, &st) < 0) 153 return errno; 154 155 return normalize_dir_path(path, NodeRef(st), normalizedPath); 156 } 157 158 // normalize_entry_path 159 static status_t 160 normalize_entry_path(const char *path, string &normalizedPath) 161 { 162 const char *dirPath = NULL; 163 const char *leafName = NULL; 164 165 string dirPathString; 166 if (const char *lastSlash = strrchr(path, '/')) { 167 // found a slash: decompose into dir path and leaf name 168 leafName = lastSlash + 1; 169 if (leafName[0] == '\0') { 170 // slash is at the end: the whole path is a dir name 171 leafName = NULL; 172 } else { 173 dirPathString = string(path, leafName - path); 174 dirPath = dirPathString.c_str(); 175 } 176 177 } else { 178 // path contains no slash, so it is a path relative to the current dir 179 dirPath = "."; 180 leafName = path; 181 } 182 183 // catch special case: no leaf, or leaf is a directory 184 if (!leafName || strcmp(leafName, ".") == 0 || strcmp(leafName, "..") == 0) 185 return normalize_dir_path(path, normalizedPath); 186 187 // normalize the dir path 188 status_t error = normalize_dir_path(dirPath, normalizedPath); 189 if (error != B_OK) 190 return error; 191 192 // append the leaf name 193 if (normalizedPath.length() > 1) // don't append "/", if parent is root 194 normalizedPath += '/'; 195 normalizedPath += leafName; 196 197 return B_OK; 198 } 199 200 201 // #pragma mark - 202 203 typedef map<NodeRef, string> DirPathMap; 204 static DirPathMap sDirPathMap; 205 206 // get_path 207 static status_t 208 get_path(const NodeRef *ref, const char *name, string &path) 209 { 210 if (!ref && !name) 211 return B_BAD_VALUE; 212 213 // no ref or absolute path 214 if (!ref || (name && name[0] == '/')) { 215 path = name; 216 return B_OK; 217 } 218 219 // get the dir path 220 if (ref) { 221 DirPathMap::iterator it = sDirPathMap.find(*ref); 222 if (it == sDirPathMap.end()) 223 return B_ENTRY_NOT_FOUND; 224 225 path = it->second; 226 227 // stat the path to check, if it is still valid 228 struct stat st; 229 if (lstat(path.c_str(), &st) < 0) { 230 sDirPathMap.erase(it); 231 return errno; 232 } 233 234 // compare the NodeRef 235 if (NodeRef(st) != *ref) { 236 sDirPathMap.erase(it); 237 return B_ENTRY_NOT_FOUND; 238 } 239 240 // still a directory? 241 if (!S_ISDIR(st.st_mode)) { 242 sDirPathMap.erase(it); 243 return B_NOT_A_DIRECTORY; 244 } 245 } 246 247 // if there's a name, append it 248 if (name) { 249 path += '/'; 250 path += name; 251 } 252 253 return B_OK; 254 } 255 256 // get_path 257 status_t 258 BPrivate::get_path(int fd, const char *name, string &path) 259 { 260 // get the node ref for the fd, if any, and the path part is not absolute 261 if (fd >= 0 && !(name && name[0] == '/')) { 262 // get descriptor 263 Descriptor *descriptor = get_descriptor(fd); 264 if (!descriptor) 265 return B_FILE_ERROR; 266 267 // get node ref for the descriptor 268 NodeRef ref; 269 status_t error = descriptor->GetNodeRef(ref); 270 if (error != B_OK) 271 return error; 272 273 return ::get_path(&ref, name, path); 274 275 } else // no descriptor or absolute path 276 return ::get_path((NodeRef*)NULL, name, path); 277 } 278 279 // get_path 280 static status_t 281 get_path(dev_t device, ino_t directory, const char *name, string &path) 282 { 283 NodeRef ref; 284 ref.device = device; 285 ref.node = directory; 286 287 return get_path(&ref, name, path); 288 } 289 290 // add_dir_path 291 static void 292 add_dir_path(const char *path, const NodeRef &ref) 293 { 294 // add the normalized path 295 string normalizedPath; 296 if (normalize_dir_path(path, normalizedPath) == B_OK) 297 sDirPathMap[ref] = normalizedPath; 298 } 299 300 301 // #pragma mark - 302 303 // _kern_entry_ref_to_path 304 status_t 305 _kern_entry_ref_to_path(dev_t device, ino_t node, const char *leaf, 306 char *userPath, size_t pathLength) 307 { 308 // get the path 309 string path; 310 status_t error = get_path(device, node, leaf, path); 311 if (error != B_OK) 312 return error; 313 314 // copy it back to the user buffer 315 if (strlcpy(userPath, path.c_str(), pathLength) >= pathLength) 316 return B_BUFFER_OVERFLOW; 317 318 return B_OK; 319 } 320 321 322 // #pragma mark - 323 324 // _kern_create_dir 325 status_t 326 _kern_create_dir(int fd, const char *path, int perms) 327 { 328 // get a usable path 329 string realPath; 330 status_t error = get_path(fd, path, realPath); 331 if (error != B_OK) 332 return error; 333 334 // mkdir 335 if (mkdir(realPath.c_str(), perms) < 0) 336 return errno; 337 338 return B_OK; 339 } 340 341 // _kern_create_dir_entry_ref 342 status_t 343 _kern_create_dir_entry_ref(dev_t device, ino_t node, const char *name, 344 int perms) 345 { 346 // get a usable path 347 string realPath; 348 status_t error = get_path(device, node, name, realPath); 349 if (error != B_OK) 350 return error; 351 352 // mkdir 353 if (mkdir(realPath.c_str(), perms) < 0) 354 return errno; 355 356 return B_OK; 357 } 358 359 // open_dir 360 static int 361 open_dir(const char *path) 362 { 363 // open the dir 364 DIR *dir = opendir(path); 365 if (!dir) 366 return errno; 367 368 // stat the entry 369 struct stat st; 370 if (stat(path, &st) < 0) { 371 closedir(dir); 372 return errno; 373 } 374 375 if (!S_ISDIR(st.st_mode)) { 376 closedir(dir); 377 return B_NOT_A_DIRECTORY; 378 } 379 380 // cache dir path 381 NodeRef ref(st); 382 add_dir_path(path, ref); 383 384 // create descriptor 385 DirectoryDescriptor *descriptor = new DirectoryDescriptor(dir, ref); 386 return add_descriptor(descriptor); 387 } 388 389 // _kern_open_dir 390 int 391 _kern_open_dir(int fd, const char *path) 392 { 393 // get a usable path 394 string realPath; 395 status_t error = get_path(fd, path, realPath); 396 if (error != B_OK) 397 return error; 398 399 return open_dir(realPath.c_str()); 400 } 401 402 // _kern_open_dir_entry_ref 403 int 404 _kern_open_dir_entry_ref(dev_t device, ino_t node, const char *name) 405 { 406 // get a usable path 407 string realPath; 408 status_t error = get_path(device, node, name, realPath); 409 if (error != B_OK) 410 return error; 411 412 return open_dir(realPath.c_str()); 413 } 414 415 // _kern_open_parent_dir 416 int 417 _kern_open_parent_dir(int fd, char *name, size_t nameLength) 418 { 419 // get a usable path 420 string realPath; 421 status_t error = get_path(fd, NULL, realPath); 422 if (error != B_OK) 423 return error; 424 425 // stat the entry 426 struct stat st; 427 if (stat(realPath.c_str(), &st) < 0) 428 return errno; 429 430 if (!S_ISDIR(st.st_mode)) 431 return B_NOT_A_DIRECTORY; 432 433 // get the entry name 434 realPath += "/.."; 435 string entryName; 436 error = find_dir_entry(realPath.c_str(), NodeRef(st), 437 entryName, false); 438 if (error != B_OK) 439 return error; 440 441 if (strlcpy(name, entryName.c_str(), nameLength) >= nameLength) 442 return B_BUFFER_OVERFLOW; 443 444 // open the parent directory 445 446 return open_dir(realPath.c_str()); 447 } 448 449 // _kern_read_dir 450 ssize_t 451 _kern_read_dir(int fd, struct dirent *buffer, size_t bufferSize, 452 uint32 maxCount) 453 { 454 if (maxCount <= 0) 455 return B_BAD_VALUE; 456 457 // get the descriptor 458 DirectoryDescriptor *descriptor 459 = dynamic_cast<DirectoryDescriptor*>(get_descriptor(fd)); 460 if (!descriptor) 461 return B_FILE_ERROR; 462 463 // get the next entry 464 dirent *entry; 465 if (dynamic_cast<AttrDirDescriptor*>(descriptor)) 466 entry = fs_read_attr_dir(descriptor->dir); 467 else 468 entry = readdir(descriptor->dir); 469 if (!entry) 470 return errno; 471 472 // copy the entry 473 int entryLen = &entry->d_name[strlen(entry->d_name) + 1] - (char*)entry; 474 if (entryLen > (int)bufferSize) 475 return B_BUFFER_OVERFLOW; 476 477 memcpy(buffer, entry, entryLen); 478 479 return 1; 480 } 481 482 // _kern_rewind_dir 483 status_t 484 _kern_rewind_dir(int fd) 485 { 486 // get the descriptor 487 DirectoryDescriptor *descriptor 488 = dynamic_cast<DirectoryDescriptor*>(get_descriptor(fd)); 489 if (!descriptor) 490 return B_FILE_ERROR; 491 492 // rewind 493 if (dynamic_cast<AttrDirDescriptor*>(descriptor)) 494 fs_rewind_attr_dir(descriptor->dir); 495 else 496 rewinddir(descriptor->dir); 497 498 return B_OK; 499 } 500 501 502 // #pragma mark - 503 504 // open_file 505 static int 506 open_file(const char *path, int openMode, int perms) 507 { 508 // stat the node 509 bool exists = true; 510 struct stat st; 511 if (lstat(path, &st) < 0) { 512 exists = false; 513 if (!(openMode & O_CREAT)) 514 return errno; 515 } 516 517 Descriptor *descriptor; 518 if (exists && S_ISLNK(st.st_mode) && (openMode & O_NOTRAVERSE)) { 519 // a symlink not to be followed: create a special descriptor 520 // normalize path first 521 string normalizedPath; 522 status_t error = normalize_entry_path(path, normalizedPath); 523 if (error != B_OK) 524 return error; 525 526 descriptor = new SymlinkDescriptor(normalizedPath.c_str()); 527 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