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