1 /* 2 * Copyright 2009-2011, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Copyright 2002-2018, Axel Dörfler, axeld@pinc-software.de. 4 * Distributed under the terms of the MIT License. 5 */ 6 7 8 //! Operations on file descriptors 9 10 11 #include <fd.h> 12 13 #include <stdlib.h> 14 #include <string.h> 15 16 #include <OS.h> 17 18 #include <AutoDeleter.h> 19 #include <AutoDeleterDrivers.h> 20 #include <BytePointer.h> 21 22 #include <syscalls.h> 23 #include <syscall_restart.h> 24 #include <slab/Slab.h> 25 #include <util/AutoLock.h> 26 #include <util/iovec_support.h> 27 #include <vfs.h> 28 #include <wait_for_objects.h> 29 30 #include "vfs_tracing.h" 31 32 33 //#define TRACE_FD 34 #ifdef TRACE_FD 35 # define TRACE(x) dprintf x 36 #else 37 # define TRACE(x) 38 #endif 39 40 41 static const size_t kMaxReadDirBufferSize = 64 * 1024; 42 43 extern object_cache* sFileDescriptorCache; 44 45 46 static struct file_descriptor* get_fd_locked(struct io_context* context, 47 int fd); 48 static struct file_descriptor* remove_fd(struct io_context* context, int fd); 49 static void deselect_select_infos(file_descriptor* descriptor, 50 select_info* infos, bool putSyncObjects); 51 52 53 struct FDGetterLocking { 54 inline bool Lock(file_descriptor* /*lockable*/) 55 { 56 return false; 57 } 58 59 inline void Unlock(file_descriptor* lockable) 60 { 61 put_fd(lockable); 62 } 63 }; 64 65 class FDGetter : public AutoLocker<file_descriptor, FDGetterLocking> { 66 public: 67 inline FDGetter() 68 : AutoLocker<file_descriptor, FDGetterLocking>() 69 { 70 } 71 72 inline FDGetter(io_context* context, int fd, bool contextLocked = false) 73 : AutoLocker<file_descriptor, FDGetterLocking>( 74 contextLocked ? get_fd_locked(context, fd) : get_fd(context, fd)) 75 { 76 } 77 78 inline file_descriptor* SetTo(io_context* context, int fd, 79 bool contextLocked = false) 80 { 81 file_descriptor* descriptor 82 = contextLocked ? get_fd_locked(context, fd) : get_fd(context, fd); 83 AutoLocker<file_descriptor, FDGetterLocking>::SetTo(descriptor, true); 84 return descriptor; 85 } 86 87 inline file_descriptor* SetTo(int fd, bool kernel, 88 bool contextLocked = false) 89 { 90 return SetTo(get_current_io_context(kernel), fd, contextLocked); 91 } 92 93 inline file_descriptor* FD() const 94 { 95 return fLockable; 96 } 97 }; 98 99 100 // #pragma mark - General fd routines 101 102 103 #ifdef DEBUG 104 void dump_fd(int fd, struct file_descriptor* descriptor); 105 106 void 107 dump_fd(int fd,struct file_descriptor* descriptor) 108 { 109 dprintf("fd[%d] = %p: type = %" B_PRId32 ", ref_count = %" B_PRId32 ", ops " 110 "= %p, u.vnode = %p, u.mount = %p, cookie = %p, open_mode = %" B_PRIx32 111 ", pos = %" B_PRId64 "\n", 112 fd, descriptor, descriptor->type, descriptor->ref_count, 113 descriptor->ops, descriptor->u.vnode, descriptor->u.mount, 114 descriptor->cookie, descriptor->open_mode, descriptor->pos); 115 } 116 #endif 117 118 119 /*! Allocates and initializes a new file_descriptor. 120 */ 121 struct file_descriptor* 122 alloc_fd(void) 123 { 124 file_descriptor* descriptor 125 = (file_descriptor*)object_cache_alloc(sFileDescriptorCache, 0); 126 if (descriptor == NULL) 127 return NULL; 128 129 descriptor->u.vnode = NULL; 130 descriptor->cookie = NULL; 131 descriptor->ref_count = 1; 132 descriptor->open_count = 0; 133 descriptor->open_mode = 0; 134 descriptor->pos = 0; 135 136 return descriptor; 137 } 138 139 140 bool 141 fd_close_on_exec(struct io_context* context, int fd) 142 { 143 return CHECK_BIT(context->fds_close_on_exec[fd / 8], fd & 7) ? true : false; 144 } 145 146 147 void 148 fd_set_close_on_exec(struct io_context* context, int fd, bool closeFD) 149 { 150 if (closeFD) 151 context->fds_close_on_exec[fd / 8] |= (1 << (fd & 7)); 152 else 153 context->fds_close_on_exec[fd / 8] &= ~(1 << (fd & 7)); 154 } 155 156 157 /*! Searches a free slot in the FD table of the provided I/O context, and 158 inserts the specified descriptor into it. 159 */ 160 int 161 new_fd_etc(struct io_context* context, struct file_descriptor* descriptor, 162 int firstIndex) 163 { 164 int fd = -1; 165 uint32 i; 166 167 if (firstIndex < 0 || (uint32)firstIndex >= context->table_size) 168 return B_BAD_VALUE; 169 170 mutex_lock(&context->io_mutex); 171 172 for (i = firstIndex; i < context->table_size; i++) { 173 if (!context->fds[i]) { 174 fd = i; 175 break; 176 } 177 } 178 if (fd < 0) { 179 fd = B_NO_MORE_FDS; 180 goto err; 181 } 182 183 TFD(NewFD(context, fd, descriptor)); 184 185 context->fds[fd] = descriptor; 186 context->num_used_fds++; 187 atomic_add(&descriptor->open_count, 1); 188 189 err: 190 mutex_unlock(&context->io_mutex); 191 192 return fd; 193 } 194 195 196 int 197 new_fd(struct io_context* context, struct file_descriptor* descriptor) 198 { 199 return new_fd_etc(context, descriptor, 0); 200 } 201 202 203 /*! Reduces the descriptor's reference counter, and frees all resources 204 when it's no longer used. 205 */ 206 void 207 put_fd(struct file_descriptor* descriptor) 208 { 209 int32 previous = atomic_add(&descriptor->ref_count, -1); 210 211 TFD(PutFD(descriptor)); 212 213 TRACE(("put_fd(descriptor = %p [ref = %ld, cookie = %p])\n", 214 descriptor, descriptor->ref_count, descriptor->cookie)); 215 216 // free the descriptor if we don't need it anymore 217 if (previous == 1) { 218 // free the underlying object 219 if (descriptor->ops != NULL && descriptor->ops->fd_free != NULL) 220 descriptor->ops->fd_free(descriptor); 221 222 object_cache_free(sFileDescriptorCache, descriptor, 0); 223 } else if ((descriptor->open_mode & O_DISCONNECTED) != 0 224 && previous - 1 == descriptor->open_count 225 && descriptor->ops != NULL) { 226 // the descriptor has been disconnected - it cannot 227 // be accessed anymore, let's close it (no one is 228 // currently accessing this descriptor) 229 230 if (descriptor->ops->fd_close) 231 descriptor->ops->fd_close(descriptor); 232 if (descriptor->ops->fd_free) 233 descriptor->ops->fd_free(descriptor); 234 235 // prevent this descriptor from being closed/freed again 236 descriptor->ops = NULL; 237 descriptor->u.vnode = NULL; 238 239 // the file descriptor is kept intact, so that it's not 240 // reused until someone explicitly closes it 241 } 242 } 243 244 245 /*! Decrements the open counter of the file descriptor and invokes 246 its close hook when appropriate. 247 */ 248 void 249 close_fd(struct io_context* context, struct file_descriptor* descriptor) 250 { 251 // POSIX advisory locks need to be released when any file descriptor closes 252 if (descriptor->type == FDTYPE_FILE) 253 vfs_release_posix_lock(context, descriptor); 254 255 if (atomic_add(&descriptor->open_count, -1) == 1) { 256 vfs_unlock_vnode_if_locked(descriptor); 257 258 if (descriptor->ops != NULL && descriptor->ops->fd_close != NULL) 259 descriptor->ops->fd_close(descriptor); 260 } 261 } 262 263 264 status_t 265 close_fd_index(struct io_context* context, int fd) 266 { 267 struct file_descriptor* descriptor = remove_fd(context, fd); 268 269 if (descriptor == NULL) 270 return B_FILE_ERROR; 271 272 close_fd(context, descriptor); 273 put_fd(descriptor); 274 // the reference associated with the slot 275 276 return B_OK; 277 } 278 279 280 /*! This descriptor's underlying object will be closed and freed as soon as 281 possible (in one of the next calls to put_fd() - get_fd() will no longer 282 succeed on this descriptor). 283 This is useful if the underlying object is gone, for instance when a 284 (mounted) volume got removed unexpectedly. 285 */ 286 void 287 disconnect_fd(struct file_descriptor* descriptor) 288 { 289 descriptor->open_mode |= O_DISCONNECTED; 290 } 291 292 293 void 294 inc_fd_ref_count(struct file_descriptor* descriptor) 295 { 296 atomic_add(&descriptor->ref_count, 1); 297 } 298 299 300 static struct file_descriptor* 301 get_fd_locked(struct io_context* context, int fd) 302 { 303 if (fd < 0 || (uint32)fd >= context->table_size) 304 return NULL; 305 306 struct file_descriptor* descriptor = context->fds[fd]; 307 308 if (descriptor != NULL) { 309 // disconnected descriptors cannot be accessed anymore 310 if (descriptor->open_mode & O_DISCONNECTED) 311 return NULL; 312 313 TFD(GetFD(context, fd, descriptor)); 314 inc_fd_ref_count(descriptor); 315 } 316 317 return descriptor; 318 } 319 320 321 struct file_descriptor* 322 get_fd(struct io_context* context, int fd) 323 { 324 MutexLocker _(context->io_mutex); 325 326 return get_fd_locked(context, fd); 327 } 328 329 330 struct file_descriptor* 331 get_open_fd(struct io_context* context, int fd) 332 { 333 MutexLocker _(context->io_mutex); 334 335 file_descriptor* descriptor = get_fd_locked(context, fd); 336 if (descriptor == NULL) 337 return NULL; 338 339 atomic_add(&descriptor->open_count, 1); 340 341 return descriptor; 342 } 343 344 345 /*! Removes the file descriptor from the specified slot. 346 */ 347 static struct file_descriptor* 348 remove_fd(struct io_context* context, int fd) 349 { 350 struct file_descriptor* descriptor = NULL; 351 352 if (fd < 0) 353 return NULL; 354 355 mutex_lock(&context->io_mutex); 356 357 if ((uint32)fd < context->table_size) 358 descriptor = context->fds[fd]; 359 360 select_info* selectInfos = NULL; 361 bool disconnected = false; 362 363 if (descriptor != NULL) { 364 // fd is valid 365 TFD(RemoveFD(context, fd, descriptor)); 366 367 context->fds[fd] = NULL; 368 fd_set_close_on_exec(context, fd, false); 369 context->num_used_fds--; 370 371 selectInfos = context->select_infos[fd]; 372 context->select_infos[fd] = NULL; 373 374 disconnected = (descriptor->open_mode & O_DISCONNECTED); 375 } 376 377 mutex_unlock(&context->io_mutex); 378 379 if (selectInfos != NULL) 380 deselect_select_infos(descriptor, selectInfos, true); 381 382 return disconnected ? NULL : descriptor; 383 } 384 385 386 static int 387 dup_fd(int fd, bool kernel) 388 { 389 struct io_context* context = get_current_io_context(kernel); 390 struct file_descriptor* descriptor; 391 int status; 392 393 TRACE(("dup_fd: fd = %d\n", fd)); 394 395 // Try to get the fd structure 396 descriptor = get_fd(context, fd); 397 if (descriptor == NULL) 398 return B_FILE_ERROR; 399 400 // now put the fd in place 401 status = new_fd(context, descriptor); 402 if (status < 0) 403 put_fd(descriptor); 404 else { 405 mutex_lock(&context->io_mutex); 406 fd_set_close_on_exec(context, status, false); 407 mutex_unlock(&context->io_mutex); 408 } 409 410 return status; 411 } 412 413 414 /*! POSIX says this should be the same as: 415 close(newfd); 416 fcntl(oldfd, F_DUPFD, newfd); 417 418 We do dup2() directly to be thread-safe. 419 */ 420 static int 421 dup2_fd(int oldfd, int newfd, bool kernel) 422 { 423 struct file_descriptor* evicted = NULL; 424 struct io_context* context; 425 426 TRACE(("dup2_fd: ofd = %d, nfd = %d\n", oldfd, newfd)); 427 428 // quick check 429 if (oldfd < 0 || newfd < 0) 430 return B_FILE_ERROR; 431 432 // Get current I/O context and lock it 433 context = get_current_io_context(kernel); 434 mutex_lock(&context->io_mutex); 435 436 // Check if the fds are valid (mutex must be locked because 437 // the table size could be changed) 438 if ((uint32)oldfd >= context->table_size 439 || (uint32)newfd >= context->table_size 440 || context->fds[oldfd] == NULL 441 || (context->fds[oldfd]->open_mode & O_DISCONNECTED) != 0) { 442 mutex_unlock(&context->io_mutex); 443 return B_FILE_ERROR; 444 } 445 446 // Check for identity, note that it cannot be made above 447 // because we always want to return an error on invalid 448 // handles 449 select_info* selectInfos = NULL; 450 if (oldfd != newfd) { 451 // Now do the work 452 TFD(Dup2FD(context, oldfd, newfd)); 453 454 evicted = context->fds[newfd]; 455 selectInfos = context->select_infos[newfd]; 456 context->select_infos[newfd] = NULL; 457 atomic_add(&context->fds[oldfd]->ref_count, 1); 458 atomic_add(&context->fds[oldfd]->open_count, 1); 459 context->fds[newfd] = context->fds[oldfd]; 460 461 if (evicted == NULL) 462 context->num_used_fds++; 463 } 464 465 fd_set_close_on_exec(context, newfd, false); 466 467 mutex_unlock(&context->io_mutex); 468 469 // Say bye bye to the evicted fd 470 if (evicted) { 471 deselect_select_infos(evicted, selectInfos, true); 472 close_fd(context, evicted); 473 put_fd(evicted); 474 } 475 476 return newfd; 477 } 478 479 480 /*! Duplicates an FD from another team to this/the kernel team. 481 \param fromTeam The team which owns the FD. 482 \param fd The FD to duplicate. 483 \param kernel If \c true, the new FD will be created in the kernel team, 484 the current userland team otherwise. 485 \return The newly created FD or an error code, if something went wrong. 486 */ 487 int 488 dup_foreign_fd(team_id fromTeam, int fd, bool kernel) 489 { 490 // get the I/O context for the team in question 491 Team* team = Team::Get(fromTeam); 492 if (team == NULL) 493 return B_BAD_TEAM_ID; 494 BReference<Team> teamReference(team, true); 495 496 io_context* fromContext = team->io_context; 497 498 // get the file descriptor 499 file_descriptor* descriptor = get_fd(fromContext, fd); 500 if (descriptor == NULL) 501 return B_FILE_ERROR; 502 DescriptorPutter descriptorPutter(descriptor); 503 504 // create a new FD in the target I/O context 505 int result = new_fd(get_current_io_context(kernel), descriptor); 506 if (result >= 0) { 507 // the descriptor reference belongs to the slot, now 508 descriptorPutter.Detach(); 509 } 510 511 return result; 512 } 513 514 515 static status_t 516 fd_ioctl(bool kernelFD, int fd, uint32 op, void* buffer, size_t length) 517 { 518 struct file_descriptor* descriptor; 519 int status; 520 521 descriptor = get_fd(get_current_io_context(kernelFD), fd); 522 if (descriptor == NULL) 523 return B_FILE_ERROR; 524 525 if (descriptor->ops->fd_ioctl) 526 status = descriptor->ops->fd_ioctl(descriptor, op, buffer, length); 527 else 528 status = B_DEV_INVALID_IOCTL; 529 530 if (status == B_DEV_INVALID_IOCTL) 531 status = ENOTTY; 532 533 put_fd(descriptor); 534 return status; 535 } 536 537 538 static void 539 deselect_select_infos(file_descriptor* descriptor, select_info* infos, 540 bool putSyncObjects) 541 { 542 TRACE(("deselect_select_infos(%p, %p)\n", descriptor, infos)); 543 544 select_info* info = infos; 545 while (info != NULL) { 546 select_sync* sync = info->sync; 547 548 // deselect the selected events 549 uint16 eventsToDeselect = info->selected_events & ~B_EVENT_INVALID; 550 if (descriptor->ops->fd_deselect != NULL && eventsToDeselect != 0) { 551 for (uint16 event = 1; event < 16; event++) { 552 if ((eventsToDeselect & SELECT_FLAG(event)) != 0) { 553 descriptor->ops->fd_deselect(descriptor, event, 554 (selectsync*)info); 555 } 556 } 557 } 558 559 notify_select_events(info, B_EVENT_INVALID); 560 info = info->next; 561 562 if (putSyncObjects) 563 put_select_sync(sync); 564 } 565 } 566 567 568 status_t 569 select_fd(int32 fd, struct select_info* info, bool kernel) 570 { 571 TRACE(("select_fd(fd = %ld, info = %p (%p), 0x%x)\n", fd, info, 572 info->sync, info->selected_events)); 573 574 FDGetter fdGetter; 575 // define before the context locker, so it will be destroyed after it 576 577 io_context* context = get_current_io_context(kernel); 578 MutexLocker locker(context->io_mutex); 579 580 struct file_descriptor* descriptor = fdGetter.SetTo(context, fd, true); 581 if (descriptor == NULL) 582 return B_FILE_ERROR; 583 584 uint16 eventsToSelect = info->selected_events & ~B_EVENT_INVALID; 585 586 if (descriptor->ops->fd_select == NULL) { 587 // if the I/O subsystem doesn't support select(), we will 588 // immediately notify the select call 589 eventsToSelect &= ~SELECT_OUTPUT_ONLY_FLAGS; 590 if (eventsToSelect != 0) 591 return notify_select_events(info, eventsToSelect); 592 else 593 return B_OK; 594 } 595 596 // We need the FD to stay open while we're doing this, so no select()/ 597 // deselect() will be called on it after it is closed. 598 atomic_add(&descriptor->open_count, 1); 599 600 locker.Unlock(); 601 602 // select any events asked for 603 uint32 selectedEvents = 0; 604 605 for (uint16 event = 1; event < 16; event++) { 606 if ((eventsToSelect & SELECT_FLAG(event)) != 0 607 && descriptor->ops->fd_select(descriptor, event, 608 (selectsync*)info) == B_OK) { 609 selectedEvents |= SELECT_FLAG(event); 610 } 611 } 612 info->selected_events = selectedEvents 613 | (info->selected_events & B_EVENT_INVALID); 614 615 // Add the info to the IO context. Even if nothing has been selected -- we 616 // always support B_EVENT_INVALID. 617 locker.Lock(); 618 if (context->fds[fd] != descriptor) { 619 // Someone close()d the index in the meantime. deselect() all 620 // events. 621 info->next = NULL; 622 deselect_select_infos(descriptor, info, false); 623 624 // Release our open reference of the descriptor. 625 close_fd(context, descriptor); 626 return B_FILE_ERROR; 627 } 628 629 // The FD index hasn't changed, so we add the select info to the table. 630 631 info->next = context->select_infos[fd]; 632 context->select_infos[fd] = info; 633 634 // As long as the info is in the list, we keep a reference to the sync 635 // object. 636 atomic_add(&info->sync->ref_count, 1); 637 638 // Finally release our open reference. It is safe just to decrement, 639 // since as long as the descriptor is associated with the slot, 640 // someone else still has it open. 641 atomic_add(&descriptor->open_count, -1); 642 643 return B_OK; 644 } 645 646 647 status_t 648 deselect_fd(int32 fd, struct select_info* info, bool kernel) 649 { 650 TRACE(("deselect_fd(fd = %ld, info = %p (%p), 0x%x)\n", fd, info, 651 info->sync, info->selected_events)); 652 653 FDGetter fdGetter; 654 // define before the context locker, so it will be destroyed after it 655 656 io_context* context = get_current_io_context(kernel); 657 MutexLocker locker(context->io_mutex); 658 659 struct file_descriptor* descriptor = fdGetter.SetTo(context, fd, true); 660 if (descriptor == NULL) 661 return B_FILE_ERROR; 662 663 // remove the info from the IO context 664 665 select_info** infoLocation = &context->select_infos[fd]; 666 while (*infoLocation != NULL && *infoLocation != info) 667 infoLocation = &(*infoLocation)->next; 668 669 // If not found, someone else beat us to it. 670 if (*infoLocation != info) 671 return B_OK; 672 673 *infoLocation = info->next; 674 675 locker.Unlock(); 676 677 // deselect the selected events 678 uint16 eventsToDeselect = info->selected_events & ~B_EVENT_INVALID; 679 if (descriptor->ops->fd_deselect != NULL && eventsToDeselect != 0) { 680 for (uint16 event = 1; event < 16; event++) { 681 if ((eventsToDeselect & SELECT_FLAG(event)) != 0) { 682 descriptor->ops->fd_deselect(descriptor, event, 683 (selectsync*)info); 684 } 685 } 686 } 687 688 put_select_sync(info->sync); 689 690 return B_OK; 691 } 692 693 694 /*! This function checks if the specified fd is valid in the current 695 context. It can be used for a quick check; the fd is not locked 696 so it could become invalid immediately after this check. 697 */ 698 bool 699 fd_is_valid(int fd, bool kernel) 700 { 701 struct file_descriptor* descriptor 702 = get_fd(get_current_io_context(kernel), fd); 703 if (descriptor == NULL) 704 return false; 705 706 put_fd(descriptor); 707 return true; 708 } 709 710 711 struct vnode* 712 fd_vnode(struct file_descriptor* descriptor) 713 { 714 switch (descriptor->type) { 715 case FDTYPE_FILE: 716 case FDTYPE_DIR: 717 case FDTYPE_ATTR_DIR: 718 case FDTYPE_ATTR: 719 return descriptor->u.vnode; 720 } 721 722 return NULL; 723 } 724 725 726 static status_t 727 common_close(int fd, bool kernel) 728 { 729 return close_fd_index(get_current_io_context(kernel), fd); 730 } 731 732 733 static ssize_t 734 common_user_io(int fd, off_t pos, void* buffer, size_t length, bool write) 735 { 736 if (pos < -1) 737 return B_BAD_VALUE; 738 739 FDGetter fdGetter; 740 struct file_descriptor* descriptor = fdGetter.SetTo(fd, false); 741 if (!descriptor) 742 return B_FILE_ERROR; 743 744 if (write ? (descriptor->open_mode & O_RWMASK) == O_RDONLY 745 : (descriptor->open_mode & O_RWMASK) == O_WRONLY) { 746 return B_FILE_ERROR; 747 } 748 749 bool movePosition = false; 750 if (pos == -1) { 751 pos = descriptor->pos; 752 movePosition = true; 753 } 754 755 if (write ? descriptor->ops->fd_write == NULL 756 : descriptor->ops->fd_read == NULL) { 757 return B_BAD_VALUE; 758 } 759 760 if (length == 0) 761 return 0; 762 763 if (!is_user_address_range(buffer, length)) 764 return B_BAD_ADDRESS; 765 766 SyscallRestartWrapper<status_t> status; 767 768 if (write) 769 status = descriptor->ops->fd_write(descriptor, pos, buffer, &length); 770 else 771 status = descriptor->ops->fd_read(descriptor, pos, buffer, &length); 772 773 if (status != B_OK) 774 return status; 775 776 if (movePosition) { 777 descriptor->pos = write && (descriptor->open_mode & O_APPEND) != 0 778 ? descriptor->ops->fd_seek(descriptor, 0, SEEK_END) : pos + length; 779 } 780 781 return length <= SSIZE_MAX ? (ssize_t)length : SSIZE_MAX; 782 } 783 784 785 static ssize_t 786 common_user_vector_io(int fd, off_t pos, const iovec* userVecs, size_t count, 787 bool write) 788 { 789 if (pos < -1) 790 return B_BAD_VALUE; 791 792 iovec* vecs; 793 status_t error = get_iovecs_from_user(userVecs, count, vecs, true); 794 if (error != B_OK) 795 return error; 796 MemoryDeleter _(vecs); 797 798 FDGetter fdGetter; 799 struct file_descriptor* descriptor = fdGetter.SetTo(fd, false); 800 if (!descriptor) 801 return B_FILE_ERROR; 802 803 if (write ? (descriptor->open_mode & O_RWMASK) == O_RDONLY 804 : (descriptor->open_mode & O_RWMASK) == O_WRONLY) { 805 return B_FILE_ERROR; 806 } 807 808 bool movePosition = false; 809 if (pos == -1) { 810 pos = descriptor->pos; 811 movePosition = true; 812 } 813 814 if (write ? descriptor->ops->fd_write == NULL 815 : descriptor->ops->fd_read == NULL) { 816 return B_BAD_VALUE; 817 } 818 819 SyscallRestartWrapper<status_t> status; 820 821 ssize_t bytesTransferred = 0; 822 for (uint32 i = 0; i < count; i++) { 823 if (vecs[i].iov_base == NULL) 824 continue; 825 826 size_t length = vecs[i].iov_len; 827 if (write) { 828 status = descriptor->ops->fd_write(descriptor, pos, 829 vecs[i].iov_base, &length); 830 } else { 831 status = descriptor->ops->fd_read(descriptor, pos, vecs[i].iov_base, 832 &length); 833 } 834 835 if (status != B_OK) { 836 if (bytesTransferred == 0) 837 return status; 838 status = B_OK; 839 break; 840 } 841 842 if ((uint64)bytesTransferred + length > SSIZE_MAX) 843 bytesTransferred = SSIZE_MAX; 844 else 845 bytesTransferred += (ssize_t)length; 846 847 pos += length; 848 849 if (length < vecs[i].iov_len) 850 break; 851 } 852 853 if (movePosition) { 854 descriptor->pos = write && (descriptor->open_mode & O_APPEND) != 0 855 ? descriptor->ops->fd_seek(descriptor, 0, SEEK_END) : pos; 856 } 857 858 return bytesTransferred; 859 } 860 861 862 status_t 863 user_fd_kernel_ioctl(int fd, uint32 op, void* buffer, size_t length) 864 { 865 TRACE(("user_fd_kernel_ioctl: fd %d\n", fd)); 866 867 return fd_ioctl(false, fd, op, buffer, length); 868 } 869 870 871 // #pragma mark - User syscalls 872 873 874 ssize_t 875 _user_read(int fd, off_t pos, void* buffer, size_t length) 876 { 877 return common_user_io(fd, pos, buffer, length, false); 878 } 879 880 881 ssize_t 882 _user_readv(int fd, off_t pos, const iovec* userVecs, size_t count) 883 { 884 return common_user_vector_io(fd, pos, userVecs, count, false); 885 } 886 887 888 ssize_t 889 _user_write(int fd, off_t pos, const void* buffer, size_t length) 890 { 891 return common_user_io(fd, pos, (void*)buffer, length, true); 892 } 893 894 895 ssize_t 896 _user_writev(int fd, off_t pos, const iovec* userVecs, size_t count) 897 { 898 return common_user_vector_io(fd, pos, userVecs, count, true); 899 } 900 901 902 off_t 903 _user_seek(int fd, off_t pos, int seekType) 904 { 905 syscall_64_bit_return_value(); 906 907 struct file_descriptor* descriptor; 908 909 descriptor = get_fd(get_current_io_context(false), fd); 910 if (!descriptor) 911 return B_FILE_ERROR; 912 913 TRACE(("user_seek(descriptor = %p)\n", descriptor)); 914 915 if (descriptor->ops->fd_seek) 916 pos = descriptor->ops->fd_seek(descriptor, pos, seekType); 917 else 918 pos = ESPIPE; 919 920 put_fd(descriptor); 921 return pos; 922 } 923 924 925 status_t 926 _user_ioctl(int fd, uint32 op, void* buffer, size_t length) 927 { 928 TRACE(("user_ioctl: fd %d\n", fd)); 929 930 // "buffer" is not always a pointer depending on "op", so we cannot 931 // check that it is a userland buffer here. Instead we check that 932 // it is at least not within the bounds of kernel memory; as in 933 // the cases where it is a numeric constant it is usually a low one. 934 if (IS_KERNEL_ADDRESS(buffer)) 935 return B_BAD_ADDRESS; 936 937 SyscallRestartWrapper<status_t> status; 938 939 return status = fd_ioctl(false, fd, op, buffer, length); 940 } 941 942 943 ssize_t 944 _user_read_dir(int fd, struct dirent* userBuffer, size_t bufferSize, 945 uint32 maxCount) 946 { 947 TRACE(("user_read_dir(fd = %d, userBuffer = %p, bufferSize = %ld, count = " 948 "%lu)\n", fd, userBuffer, bufferSize, maxCount)); 949 950 if (maxCount == 0) 951 return 0; 952 953 if (userBuffer == NULL || !IS_USER_ADDRESS(userBuffer)) 954 return B_BAD_ADDRESS; 955 956 // get I/O context and FD 957 io_context* ioContext = get_current_io_context(false); 958 FDGetter fdGetter; 959 struct file_descriptor* descriptor = fdGetter.SetTo(ioContext, fd, false); 960 if (descriptor == NULL) 961 return B_FILE_ERROR; 962 963 if (descriptor->ops->fd_read_dir == NULL) 964 return B_UNSUPPORTED; 965 966 // restrict buffer size and allocate a heap buffer 967 if (bufferSize > kMaxReadDirBufferSize) 968 bufferSize = kMaxReadDirBufferSize; 969 struct dirent* buffer = (struct dirent*)malloc(bufferSize); 970 if (buffer == NULL) 971 return B_NO_MEMORY; 972 MemoryDeleter bufferDeleter(buffer); 973 974 // read the directory 975 uint32 count = maxCount; 976 status_t status = descriptor->ops->fd_read_dir(ioContext, descriptor, 977 buffer, bufferSize, &count); 978 if (status != B_OK) 979 return status; 980 981 ASSERT(count <= maxCount); 982 983 // copy the buffer back -- determine the total buffer size first 984 size_t sizeToCopy = 0; 985 BytePointer<struct dirent> entry = buffer; 986 for (uint32 i = 0; i < count; i++) { 987 size_t length = entry->d_reclen; 988 sizeToCopy += length; 989 entry += length; 990 } 991 992 ASSERT(sizeToCopy <= bufferSize); 993 994 if (user_memcpy(userBuffer, buffer, sizeToCopy) != B_OK) 995 return B_BAD_ADDRESS; 996 997 return count; 998 } 999 1000 1001 status_t 1002 _user_rewind_dir(int fd) 1003 { 1004 struct file_descriptor* descriptor; 1005 status_t status; 1006 1007 TRACE(("user_rewind_dir(fd = %d)\n", fd)); 1008 1009 descriptor = get_fd(get_current_io_context(false), fd); 1010 if (descriptor == NULL) 1011 return B_FILE_ERROR; 1012 1013 if (descriptor->ops->fd_rewind_dir) 1014 status = descriptor->ops->fd_rewind_dir(descriptor); 1015 else 1016 status = B_UNSUPPORTED; 1017 1018 put_fd(descriptor); 1019 return status; 1020 } 1021 1022 1023 status_t 1024 _user_close(int fd) 1025 { 1026 return common_close(fd, false); 1027 } 1028 1029 1030 int 1031 _user_dup(int fd) 1032 { 1033 return dup_fd(fd, false); 1034 } 1035 1036 1037 int 1038 _user_dup2(int ofd, int nfd) 1039 { 1040 return dup2_fd(ofd, nfd, false); 1041 } 1042 1043 1044 // #pragma mark - Kernel calls 1045 1046 1047 ssize_t 1048 _kern_read(int fd, off_t pos, void* buffer, size_t length) 1049 { 1050 if (pos < -1) 1051 return B_BAD_VALUE; 1052 1053 FDGetter fdGetter; 1054 struct file_descriptor* descriptor = fdGetter.SetTo(fd, true); 1055 1056 if (!descriptor) 1057 return B_FILE_ERROR; 1058 if ((descriptor->open_mode & O_RWMASK) == O_WRONLY) 1059 return B_FILE_ERROR; 1060 1061 bool movePosition = false; 1062 if (pos == -1) { 1063 pos = descriptor->pos; 1064 movePosition = true; 1065 } 1066 1067 SyscallFlagUnsetter _; 1068 1069 if (descriptor->ops->fd_read == NULL) 1070 return B_BAD_VALUE; 1071 1072 ssize_t bytesRead = descriptor->ops->fd_read(descriptor, pos, buffer, 1073 &length); 1074 if (bytesRead >= B_OK) { 1075 if (length > SSIZE_MAX) 1076 bytesRead = SSIZE_MAX; 1077 else 1078 bytesRead = (ssize_t)length; 1079 1080 if (movePosition) 1081 descriptor->pos = pos + length; 1082 } 1083 1084 return bytesRead; 1085 } 1086 1087 1088 ssize_t 1089 _kern_readv(int fd, off_t pos, const iovec* vecs, size_t count) 1090 { 1091 bool movePosition = false; 1092 status_t status; 1093 uint32 i; 1094 1095 if (pos < -1) 1096 return B_BAD_VALUE; 1097 1098 FDGetter fdGetter; 1099 struct file_descriptor* descriptor = fdGetter.SetTo(fd, true); 1100 1101 if (!descriptor) 1102 return B_FILE_ERROR; 1103 if ((descriptor->open_mode & O_RWMASK) == O_WRONLY) 1104 return B_FILE_ERROR; 1105 1106 if (pos == -1) { 1107 pos = descriptor->pos; 1108 movePosition = true; 1109 } 1110 1111 if (descriptor->ops->fd_read == NULL) 1112 return B_BAD_VALUE; 1113 1114 SyscallFlagUnsetter _; 1115 1116 ssize_t bytesRead = 0; 1117 1118 for (i = 0; i < count; i++) { 1119 size_t length = vecs[i].iov_len; 1120 status = descriptor->ops->fd_read(descriptor, pos, vecs[i].iov_base, 1121 &length); 1122 if (status != B_OK) { 1123 bytesRead = status; 1124 break; 1125 } 1126 1127 if ((uint64)bytesRead + length > SSIZE_MAX) 1128 bytesRead = SSIZE_MAX; 1129 else 1130 bytesRead += (ssize_t)length; 1131 1132 pos += vecs[i].iov_len; 1133 } 1134 1135 if (movePosition) 1136 descriptor->pos = pos; 1137 1138 return bytesRead; 1139 } 1140 1141 1142 ssize_t 1143 _kern_write(int fd, off_t pos, const void* buffer, size_t length) 1144 { 1145 if (pos < -1) 1146 return B_BAD_VALUE; 1147 1148 FDGetter fdGetter; 1149 struct file_descriptor* descriptor = fdGetter.SetTo(fd, true); 1150 1151 if (descriptor == NULL) 1152 return B_FILE_ERROR; 1153 if ((descriptor->open_mode & O_RWMASK) == O_RDONLY) 1154 return B_FILE_ERROR; 1155 1156 bool movePosition = false; 1157 if (pos == -1) { 1158 pos = descriptor->pos; 1159 movePosition = true; 1160 } 1161 1162 if (descriptor->ops->fd_write == NULL) 1163 return B_BAD_VALUE; 1164 1165 SyscallFlagUnsetter _; 1166 1167 ssize_t bytesWritten = descriptor->ops->fd_write(descriptor, pos, buffer, 1168 &length); 1169 if (bytesWritten >= B_OK) { 1170 if (length > SSIZE_MAX) 1171 bytesWritten = SSIZE_MAX; 1172 else 1173 bytesWritten = (ssize_t)length; 1174 1175 if (movePosition) 1176 descriptor->pos = pos + length; 1177 } 1178 1179 return bytesWritten; 1180 } 1181 1182 1183 ssize_t 1184 _kern_writev(int fd, off_t pos, const iovec* vecs, size_t count) 1185 { 1186 bool movePosition = false; 1187 status_t status; 1188 uint32 i; 1189 1190 if (pos < -1) 1191 return B_BAD_VALUE; 1192 1193 FDGetter fdGetter; 1194 struct file_descriptor* descriptor = fdGetter.SetTo(fd, true); 1195 1196 if (!descriptor) 1197 return B_FILE_ERROR; 1198 if ((descriptor->open_mode & O_RWMASK) == O_RDONLY) 1199 return B_FILE_ERROR; 1200 1201 if (pos == -1) { 1202 pos = descriptor->pos; 1203 movePosition = true; 1204 } 1205 1206 if (descriptor->ops->fd_write == NULL) 1207 return B_BAD_VALUE; 1208 1209 SyscallFlagUnsetter _; 1210 1211 ssize_t bytesWritten = 0; 1212 1213 for (i = 0; i < count; i++) { 1214 size_t length = vecs[i].iov_len; 1215 status = descriptor->ops->fd_write(descriptor, pos, 1216 vecs[i].iov_base, &length); 1217 if (status != B_OK) { 1218 bytesWritten = status; 1219 break; 1220 } 1221 1222 if ((uint64)bytesWritten + length > SSIZE_MAX) 1223 bytesWritten = SSIZE_MAX; 1224 else 1225 bytesWritten += (ssize_t)length; 1226 1227 pos += vecs[i].iov_len; 1228 } 1229 1230 if (movePosition) 1231 descriptor->pos = pos; 1232 1233 return bytesWritten; 1234 } 1235 1236 1237 off_t 1238 _kern_seek(int fd, off_t pos, int seekType) 1239 { 1240 struct file_descriptor* descriptor; 1241 1242 descriptor = get_fd(get_current_io_context(true), fd); 1243 if (!descriptor) 1244 return B_FILE_ERROR; 1245 1246 if (descriptor->ops->fd_seek) 1247 pos = descriptor->ops->fd_seek(descriptor, pos, seekType); 1248 else 1249 pos = ESPIPE; 1250 1251 put_fd(descriptor); 1252 return pos; 1253 } 1254 1255 1256 status_t 1257 _kern_ioctl(int fd, uint32 op, void* buffer, size_t length) 1258 { 1259 TRACE(("kern_ioctl: fd %d\n", fd)); 1260 1261 SyscallFlagUnsetter _; 1262 1263 return fd_ioctl(true, fd, op, buffer, length); 1264 } 1265 1266 1267 ssize_t 1268 _kern_read_dir(int fd, struct dirent* buffer, size_t bufferSize, 1269 uint32 maxCount) 1270 { 1271 struct file_descriptor* descriptor; 1272 ssize_t retval; 1273 1274 TRACE(("sys_read_dir(fd = %d, buffer = %p, bufferSize = %ld, count = " 1275 "%lu)\n",fd, buffer, bufferSize, maxCount)); 1276 1277 struct io_context* ioContext = get_current_io_context(true); 1278 descriptor = get_fd(ioContext, fd); 1279 if (descriptor == NULL) 1280 return B_FILE_ERROR; 1281 1282 if (descriptor->ops->fd_read_dir) { 1283 uint32 count = maxCount; 1284 retval = descriptor->ops->fd_read_dir(ioContext, descriptor, buffer, 1285 bufferSize, &count); 1286 if (retval >= 0) 1287 retval = count; 1288 } else 1289 retval = B_UNSUPPORTED; 1290 1291 put_fd(descriptor); 1292 return retval; 1293 } 1294 1295 1296 status_t 1297 _kern_rewind_dir(int fd) 1298 { 1299 struct file_descriptor* descriptor; 1300 status_t status; 1301 1302 TRACE(("sys_rewind_dir(fd = %d)\n",fd)); 1303 1304 descriptor = get_fd(get_current_io_context(true), fd); 1305 if (descriptor == NULL) 1306 return B_FILE_ERROR; 1307 1308 if (descriptor->ops->fd_rewind_dir) 1309 status = descriptor->ops->fd_rewind_dir(descriptor); 1310 else 1311 status = B_UNSUPPORTED; 1312 1313 put_fd(descriptor); 1314 return status; 1315 } 1316 1317 1318 status_t 1319 _kern_close(int fd) 1320 { 1321 return common_close(fd, true); 1322 } 1323 1324 1325 int 1326 _kern_dup(int fd) 1327 { 1328 return dup_fd(fd, true); 1329 } 1330 1331 1332 int 1333 _kern_dup2(int ofd, int nfd) 1334 { 1335 return dup2_fd(ofd, nfd, true); 1336 } 1337 1338