1 // kernel_emu.cpp 2 3 #include "kernel_emu.h" 4 5 #include <stdarg.h> 6 #include <stdio.h> 7 #include <stdlib.h> 8 9 #include <algorithm> 10 11 #include "FileSystem.h" 12 #include "RequestPort.h" 13 #include "Requests.h" 14 #include "RequestThread.h" 15 #include "UserlandFSServer.h" 16 #include "UserlandRequestHandler.h" 17 #include "Volume.h" 18 19 20 // Taken from the Haiku Storage Kit (storage_support.cpp) 21 /*! The length of the first component is returned as well as the index at 22 which the next one starts. These values are only valid, if the function 23 returns \c B_OK. 24 \param path the path to be parsed 25 \param length the variable the length of the first component is written 26 into 27 \param nextComponent the variable the index of the next component is 28 written into. \c 0 is returned, if there is no next component. 29 \return \c B_OK, if \a path is not \c NULL, \c B_BAD_VALUE otherwise 30 */ 31 static status_t 32 parse_first_path_component(const char *path, int32& length, 33 int32& nextComponent) 34 { 35 status_t error = (path ? B_OK : B_BAD_VALUE); 36 if (error == B_OK) { 37 int32 i = 0; 38 // find first '/' or end of name 39 for (; path[i] != '/' && path[i] != '\0'; i++); 40 // handle special case "/..." (absolute path) 41 if (i == 0 && path[i] != '\0') 42 i = 1; 43 length = i; 44 // find last '/' or end of name 45 for (; path[i] == '/' && path[i] != '\0'; i++); 46 if (path[i] == '\0') // this covers "" as well 47 nextComponent = 0; 48 else 49 nextComponent = i; 50 } 51 return error; 52 } 53 54 // new_path 55 int 56 UserlandFS::KernelEmu::new_path(const char *path, char **copy) 57 { 58 // check errors and special cases 59 if (!copy) 60 return B_BAD_VALUE; 61 if (!path) { 62 *copy = NULL; 63 return B_OK; 64 } 65 int32 len = strlen(path); 66 if (len < 1) 67 return B_ENTRY_NOT_FOUND; 68 bool appendDot = (path[len - 1] == '/'); 69 if (appendDot) 70 len++; 71 if (len >= B_PATH_NAME_LENGTH) 72 return B_NAME_TOO_LONG; 73 // check the path components 74 const char *remainder = path; 75 int32 length, nextComponent; 76 do { 77 status_t error 78 = parse_first_path_component(remainder, length, nextComponent); 79 if (error != B_OK) 80 return error; 81 if (length >= B_FILE_NAME_LENGTH) 82 error = B_NAME_TOO_LONG; 83 remainder += nextComponent; 84 } while (nextComponent != 0); 85 // clone the path 86 char *copiedPath = (char*)malloc(len + 1); 87 if (!copiedPath) 88 return B_NO_MEMORY; 89 strcpy(copiedPath, path); 90 // append a dot, if desired 91 if (appendDot) { 92 copiedPath[len - 1] = '.'; 93 copiedPath[len] = '\0'; 94 } 95 *copy = copiedPath; 96 return B_OK; 97 } 98 99 // free_path 100 void 101 UserlandFS::KernelEmu::free_path(char *p) 102 { 103 free(p); 104 } 105 106 107 // #pragma mark - 108 109 110 // get_port_and_fs 111 static status_t 112 get_port_and_fs(RequestPort** port, FileSystem** fileSystem) 113 { 114 // get the request thread 115 RequestThread* thread = RequestThread::GetCurrentThread(); 116 if (thread) { 117 *port = thread->GetPort(); 118 *fileSystem = thread->GetFileSystem(); 119 } else { 120 *port = UserlandFSServer::GetNotificationRequestPort(); 121 *fileSystem = UserlandFSServer::GetFileSystem(); 122 if (!*port || !*fileSystem) 123 return B_BAD_VALUE; 124 } 125 return B_OK; 126 } 127 128 // notify_listener 129 status_t 130 UserlandFS::KernelEmu::notify_listener(int32 operation, uint32 details, 131 dev_t device, ino_t oldDirectory, ino_t directory, 132 ino_t node, const char* oldName, const char* name) 133 { 134 // get the request port and the file system 135 RequestPort* port; 136 FileSystem* fileSystem; 137 status_t error = get_port_and_fs(&port, &fileSystem); 138 if (error != B_OK) 139 return error; 140 141 // prepare the request 142 RequestAllocator allocator(port->GetPort()); 143 NotifyListenerRequest* request; 144 error = AllocateRequest(allocator, &request); 145 if (error != B_OK) 146 return error; 147 148 request->operation = operation; 149 request->details = details; 150 request->device = device; 151 request->oldDirectory = oldDirectory; 152 request->directory = directory; 153 request->node = node; 154 error = allocator.AllocateString(request->oldName, oldName); 155 if (error != B_OK) 156 return error; 157 error = allocator.AllocateString(request->name, name); 158 if (error != B_OK) 159 return error; 160 161 // send the request 162 UserlandRequestHandler handler(fileSystem, NOTIFY_LISTENER_REPLY); 163 NotifyListenerReply* reply; 164 error = port->SendRequest(&allocator, &handler, (Request**)&reply); 165 if (error != B_OK) 166 return error; 167 RequestReleaser requestReleaser(port, reply); 168 169 // process the reply 170 if (reply->error != B_OK) 171 return reply->error; 172 return error; 173 } 174 175 // notify_select_event 176 status_t 177 UserlandFS::KernelEmu::notify_select_event(selectsync *sync, uint8 event, 178 bool unspecifiedEvent) 179 { 180 // get the request port and the file system 181 RequestPort* port; 182 FileSystem* fileSystem; 183 status_t error = get_port_and_fs(&port, &fileSystem); 184 if (error != B_OK) 185 return error; 186 187 // prepare the request 188 RequestAllocator allocator(port->GetPort()); 189 NotifySelectEventRequest* request; 190 error = AllocateRequest(allocator, &request); 191 if (error != B_OK) 192 return error; 193 194 request->sync = sync; 195 request->event = event; 196 request->unspecifiedEvent = unspecifiedEvent; 197 198 // send the request 199 UserlandRequestHandler handler(fileSystem, NOTIFY_SELECT_EVENT_REPLY); 200 NotifySelectEventReply* reply; 201 error = port->SendRequest(&allocator, &handler, (Request**)&reply); 202 if (error != B_OK) 203 return error; 204 RequestReleaser requestReleaser(port, reply); 205 206 // process the reply 207 if (reply->error != B_OK) 208 return reply->error; 209 return error; 210 } 211 212 // send_notification 213 status_t 214 UserlandFS::KernelEmu::notify_query(port_id targetPort, int32 token, 215 int32 operation, dev_t device, ino_t directory, const char* name, 216 ino_t node) 217 { 218 // get the request port and the file system 219 RequestPort* port; 220 FileSystem* fileSystem; 221 status_t error = get_port_and_fs(&port, &fileSystem); 222 if (error != B_OK) 223 return error; 224 225 // prepare the request 226 RequestAllocator allocator(port->GetPort()); 227 NotifyQueryRequest* request; 228 error = AllocateRequest(allocator, &request); 229 if (error != B_OK) 230 return error; 231 232 request->port = targetPort; 233 request->token = token; 234 request->operation = operation; 235 request->device = device; 236 request->directory = directory; 237 request->node = node; 238 error = allocator.AllocateString(request->name, name); 239 if (error != B_OK) 240 return error; 241 242 // send the request 243 UserlandRequestHandler handler(fileSystem, NOTIFY_QUERY_REPLY); 244 NotifyQueryReply* reply; 245 error = port->SendRequest(&allocator, &handler, (Request**)&reply); 246 if (error != B_OK) 247 return error; 248 RequestReleaser requestReleaser(port, reply); 249 250 // process the reply 251 if (reply->error != B_OK) 252 return reply->error; 253 return error; 254 } 255 256 257 // #pragma mark - 258 259 260 // get_vnode 261 status_t 262 UserlandFS::KernelEmu::get_vnode(dev_t nsid, ino_t vnid, void** node) 263 { 264 // get the request port and the file system 265 RequestPort* port; 266 FileSystem* fileSystem; 267 status_t error = get_port_and_fs(&port, &fileSystem); 268 if (error != B_OK) 269 return error; 270 271 // prepare the request 272 RequestAllocator allocator(port->GetPort()); 273 GetVNodeRequest* request; 274 error = AllocateRequest(allocator, &request); 275 if (error != B_OK) 276 return error; 277 278 request->nsid = nsid; 279 request->vnid = vnid; 280 281 // send the request 282 UserlandRequestHandler handler(fileSystem, GET_VNODE_REPLY); 283 GetVNodeReply* reply; 284 error = port->SendRequest(&allocator, &handler, (Request**)&reply); 285 if (error != B_OK) 286 return error; 287 RequestReleaser requestReleaser(port, reply); 288 289 // process the reply 290 if (reply->error != B_OK) 291 return reply->error; 292 *node = reply->node; 293 return error; 294 } 295 296 // put_vnode 297 status_t 298 UserlandFS::KernelEmu::put_vnode(dev_t nsid, ino_t vnid) 299 { 300 // get the request port and the file system 301 RequestPort* port; 302 FileSystem* fileSystem; 303 status_t error = get_port_and_fs(&port, &fileSystem); 304 if (error != B_OK) 305 return error; 306 307 // prepare the request 308 RequestAllocator allocator(port->GetPort()); 309 PutVNodeRequest* request; 310 error = AllocateRequest(allocator, &request); 311 if (error != B_OK) 312 return error; 313 314 request->nsid = nsid; 315 request->vnid = vnid; 316 317 // send the request 318 UserlandRequestHandler handler(fileSystem, PUT_VNODE_REPLY); 319 PutVNodeReply* reply; 320 error = port->SendRequest(&allocator, &handler, (Request**)&reply); 321 if (error != B_OK) 322 return error; 323 RequestReleaser requestReleaser(port, reply); 324 325 // process the reply 326 if (reply->error != B_OK) 327 return reply->error; 328 return error; 329 } 330 331 // acquire_vnode 332 status_t 333 UserlandFS::KernelEmu::acquire_vnode(dev_t nsid, ino_t vnid) 334 { 335 // get the request port and the file system 336 RequestPort* port; 337 FileSystem* fileSystem; 338 status_t error = get_port_and_fs(&port, &fileSystem); 339 if (error != B_OK) 340 return error; 341 342 // prepare the request 343 RequestAllocator allocator(port->GetPort()); 344 AcquireVNodeRequest* request; 345 error = AllocateRequest(allocator, &request); 346 if (error != B_OK) 347 return error; 348 349 request->nsid = nsid; 350 request->vnid = vnid; 351 352 // send the request 353 UserlandRequestHandler handler(fileSystem, ACQUIRE_VNODE_REPLY); 354 AcquireVNodeReply* reply; 355 error = port->SendRequest(&allocator, &handler, (Request**)&reply); 356 if (error != B_OK) 357 return error; 358 RequestReleaser requestReleaser(port, reply); 359 360 // process the reply 361 if (reply->error != B_OK) 362 return reply->error; 363 return error; 364 } 365 366 // new_vnode 367 status_t 368 UserlandFS::KernelEmu::new_vnode(dev_t nsid, ino_t vnid, void* data, 369 const FSVNodeCapabilities& capabilities) 370 { 371 // get the request port and the file system 372 RequestPort* port; 373 FileSystem* fileSystem; 374 status_t error = get_port_and_fs(&port, &fileSystem); 375 if (error != B_OK) 376 return error; 377 378 // prepare the request 379 RequestAllocator allocator(port->GetPort()); 380 NewVNodeRequest* request; 381 error = AllocateRequest(allocator, &request); 382 if (error != B_OK) 383 return error; 384 385 request->nsid = nsid; 386 request->vnid = vnid; 387 request->node = data; 388 request->capabilities = capabilities; 389 390 // send the request 391 UserlandRequestHandler handler(fileSystem, NEW_VNODE_REPLY); 392 NewVNodeReply* reply; 393 error = port->SendRequest(&allocator, &handler, (Request**)&reply); 394 if (error != B_OK) 395 return error; 396 RequestReleaser requestReleaser(port, reply); 397 398 // process the reply 399 if (reply->error != B_OK) 400 return reply->error; 401 return error; 402 } 403 404 // publish_vnode 405 status_t 406 UserlandFS::KernelEmu::publish_vnode(dev_t nsid, ino_t vnid, void* data, 407 int type, uint32 flags, const FSVNodeCapabilities& capabilities) 408 { 409 // get the request port and the file system 410 RequestPort* port; 411 FileSystem* fileSystem; 412 status_t error = get_port_and_fs(&port, &fileSystem); 413 if (error != B_OK) 414 return error; 415 416 // prepare the request 417 RequestAllocator allocator(port->GetPort()); 418 PublishVNodeRequest* request; 419 error = AllocateRequest(allocator, &request); 420 if (error != B_OK) 421 return error; 422 423 request->nsid = nsid; 424 request->vnid = vnid; 425 request->node = data; 426 request->type = type; 427 request->flags = flags; 428 request->capabilities = capabilities; 429 430 // send the request 431 UserlandRequestHandler handler(fileSystem, PUBLISH_VNODE_REPLY); 432 PublishVNodeReply* reply; 433 error = port->SendRequest(&allocator, &handler, (Request**)&reply); 434 if (error != B_OK) 435 return error; 436 RequestReleaser requestReleaser(port, reply); 437 438 // process the reply 439 if (reply->error != B_OK) 440 return reply->error; 441 return error; 442 } 443 444 445 // publish_vnode 446 status_t 447 UserlandFS::KernelEmu::publish_vnode(dev_t nsid, ino_t vnid, void* data, 448 const FSVNodeCapabilities& capabilities) 449 { 450 // get the volume 451 Volume* volume = FileSystem::GetInstance()->VolumeWithID(nsid); 452 if (volume == NULL) 453 return B_BAD_VALUE; 454 455 // stat() the node to get its type 456 int type; 457 status_t error = volume->GetVNodeType(data, &type); 458 if (error != B_OK) 459 return error; 460 461 // publish the node 462 return UserlandFS::KernelEmu::publish_vnode(nsid, vnid, data, type, 0, 463 capabilities); 464 } 465 466 467 // remove_vnode 468 status_t 469 UserlandFS::KernelEmu::remove_vnode(dev_t nsid, ino_t vnid) 470 { 471 // get the request port and the file system 472 RequestPort* port; 473 FileSystem* fileSystem; 474 status_t error = get_port_and_fs(&port, &fileSystem); 475 if (error != B_OK) 476 return error; 477 478 // prepare the request 479 RequestAllocator allocator(port->GetPort()); 480 RemoveVNodeRequest* request; 481 error = AllocateRequest(allocator, &request); 482 if (error != B_OK) 483 return error; 484 485 request->nsid = nsid; 486 request->vnid = vnid; 487 488 // send the request 489 UserlandRequestHandler handler(fileSystem, REMOVE_VNODE_REPLY); 490 RemoveVNodeReply* reply; 491 error = port->SendRequest(&allocator, &handler, (Request**)&reply); 492 if (error != B_OK) 493 return error; 494 RequestReleaser requestReleaser(port, reply); 495 496 // process the reply 497 if (reply->error != B_OK) 498 return reply->error; 499 return error; 500 } 501 502 // unremove_vnode 503 status_t 504 UserlandFS::KernelEmu::unremove_vnode(dev_t nsid, ino_t vnid) 505 { 506 // get the request port and the file system 507 RequestPort* port; 508 FileSystem* fileSystem; 509 status_t error = get_port_and_fs(&port, &fileSystem); 510 if (error != B_OK) 511 return error; 512 513 // prepare the request 514 RequestAllocator allocator(port->GetPort()); 515 UnremoveVNodeRequest* request; 516 error = AllocateRequest(allocator, &request); 517 if (error != B_OK) 518 return error; 519 520 request->nsid = nsid; 521 request->vnid = vnid; 522 523 // send the request 524 UserlandRequestHandler handler(fileSystem, UNREMOVE_VNODE_REPLY); 525 UnremoveVNodeReply* reply; 526 error = port->SendRequest(&allocator, &handler, (Request**)&reply); 527 if (error != B_OK) 528 return error; 529 RequestReleaser requestReleaser(port, reply); 530 531 // process the reply 532 if (reply->error != B_OK) 533 return reply->error; 534 return error; 535 } 536 537 // get_vnode_removed 538 status_t 539 UserlandFS::KernelEmu::get_vnode_removed(dev_t nsid, ino_t vnid, 540 bool* removed) 541 { 542 // get the request port and the file system 543 RequestPort* port; 544 FileSystem* fileSystem; 545 status_t error = get_port_and_fs(&port, &fileSystem); 546 if (error != B_OK) 547 return error; 548 549 // prepare the request 550 RequestAllocator allocator(port->GetPort()); 551 GetVNodeRemovedRequest* request; 552 error = AllocateRequest(allocator, &request); 553 if (error != B_OK) 554 return error; 555 556 request->nsid = nsid; 557 request->vnid = vnid; 558 559 // send the request 560 UserlandRequestHandler handler(fileSystem, GET_VNODE_REMOVED_REPLY); 561 GetVNodeRemovedReply* reply; 562 error = port->SendRequest(&allocator, &handler, (Request**)&reply); 563 if (error != B_OK) 564 return error; 565 RequestReleaser requestReleaser(port, reply); 566 567 // process the reply 568 *removed = reply->removed; 569 return reply->error; 570 } 571 572 573 // #pragma mark - file cache 574 575 576 // file_cache_create 577 status_t 578 UserlandFS::KernelEmu::file_cache_create(dev_t mountID, ino_t vnodeID, 579 off_t size) 580 { 581 // get the request port and the file system 582 RequestPort* port; 583 FileSystem* fileSystem; 584 status_t error = get_port_and_fs(&port, &fileSystem); 585 if (error != B_OK) 586 RETURN_ERROR(error); 587 588 // prepare the request 589 RequestAllocator allocator(port->GetPort()); 590 FileCacheCreateRequest* request; 591 error = AllocateRequest(allocator, &request); 592 if (error != B_OK) 593 RETURN_ERROR(error); 594 595 request->nsid = mountID; 596 request->vnid = vnodeID; 597 request->size = size; 598 599 // send the request 600 UserlandRequestHandler handler(fileSystem, FILE_CACHE_CREATE_REPLY); 601 FileCacheCreateReply* reply; 602 error = port->SendRequest(&allocator, &handler, (Request**)&reply); 603 if (error != B_OK) 604 RETURN_ERROR(error); 605 RequestReleaser requestReleaser(port, reply); 606 607 // process the reply 608 RETURN_ERROR(reply->error); 609 } 610 611 612 // file_cache_delete 613 status_t 614 UserlandFS::KernelEmu::file_cache_delete(dev_t mountID, ino_t vnodeID) 615 { 616 // get the request port and the file system 617 RequestPort* port; 618 FileSystem* fileSystem; 619 status_t error = get_port_and_fs(&port, &fileSystem); 620 if (error != B_OK) 621 return error; 622 623 // prepare the request 624 RequestAllocator allocator(port->GetPort()); 625 FileCacheDeleteRequest* request; 626 error = AllocateRequest(allocator, &request); 627 if (error != B_OK) 628 return error; 629 630 request->nsid = mountID; 631 request->vnid = vnodeID; 632 633 // send the request 634 UserlandRequestHandler handler(fileSystem, FILE_CACHE_DELETE_REPLY); 635 FileCacheDeleteReply* reply; 636 error = port->SendRequest(&allocator, &handler, (Request**)&reply); 637 if (error != B_OK) 638 return error; 639 RequestReleaser requestReleaser(port, reply); 640 641 // process the reply 642 return reply->error; 643 } 644 645 646 // file_cache_set_enable 647 status_t 648 UserlandFS::KernelEmu::file_cache_set_enabled(dev_t mountID, ino_t vnodeID, 649 bool enabled) 650 { 651 // get the request port and the file system 652 RequestPort* port; 653 FileSystem* fileSystem; 654 status_t error = get_port_and_fs(&port, &fileSystem); 655 if (error != B_OK) 656 return error; 657 658 // prepare the request 659 RequestAllocator allocator(port->GetPort()); 660 FileCacheSetEnabledRequest* request; 661 error = AllocateRequest(allocator, &request); 662 if (error != B_OK) 663 return error; 664 665 request->nsid = mountID; 666 request->vnid = vnodeID; 667 request->enabled = enabled; 668 669 // send the request 670 UserlandRequestHandler handler(fileSystem, FILE_CACHE_SET_ENABLED_REPLY); 671 FileCacheSetEnabledReply* reply; 672 error = port->SendRequest(&allocator, &handler, (Request**)&reply); 673 if (error != B_OK) 674 return error; 675 RequestReleaser requestReleaser(port, reply); 676 677 // process the reply 678 return reply->error; 679 } 680 681 682 // file_cache_set_size 683 status_t 684 UserlandFS::KernelEmu::file_cache_set_size(dev_t mountID, ino_t vnodeID, 685 off_t size) 686 { 687 // get the request port and the file system 688 RequestPort* port; 689 FileSystem* fileSystem; 690 status_t error = get_port_and_fs(&port, &fileSystem); 691 if (error != B_OK) 692 return error; 693 694 // prepare the request 695 RequestAllocator allocator(port->GetPort()); 696 FileCacheSetSizeRequest* request; 697 error = AllocateRequest(allocator, &request); 698 if (error != B_OK) 699 return error; 700 701 request->nsid = mountID; 702 request->vnid = vnodeID; 703 request->size = size; 704 705 // send the request 706 UserlandRequestHandler handler(fileSystem, FILE_CACHE_SET_SIZE_REPLY); 707 FileCacheSetSizeReply* reply; 708 error = port->SendRequest(&allocator, &handler, (Request**)&reply); 709 if (error != B_OK) 710 return error; 711 RequestReleaser requestReleaser(port, reply); 712 713 // process the reply 714 return reply->error; 715 } 716 717 718 // file_cache_sync 719 status_t 720 UserlandFS::KernelEmu::file_cache_sync(dev_t mountID, ino_t vnodeID) 721 { 722 // get the request port and the file system 723 RequestPort* port; 724 FileSystem* fileSystem; 725 status_t error = get_port_and_fs(&port, &fileSystem); 726 if (error != B_OK) 727 return error; 728 729 // prepare the request 730 RequestAllocator allocator(port->GetPort()); 731 FileCacheSyncRequest* request; 732 error = AllocateRequest(allocator, &request); 733 if (error != B_OK) 734 return error; 735 736 request->nsid = mountID; 737 request->vnid = vnodeID; 738 739 // send the request 740 UserlandRequestHandler handler(fileSystem, FILE_CACHE_SYNC_REPLY); 741 FileCacheSyncReply* reply; 742 error = port->SendRequest(&allocator, &handler, (Request**)&reply); 743 if (error != B_OK) 744 return error; 745 RequestReleaser requestReleaser(port, reply); 746 747 // process the reply 748 return reply->error; 749 } 750 751 752 // file_cache_read 753 status_t 754 UserlandFS::KernelEmu::file_cache_read(dev_t mountID, ino_t vnodeID, 755 void *cookie, off_t offset, void *bufferBase, size_t *_size) 756 { 757 // get the request port and the file system 758 RequestPort* port; 759 FileSystem* fileSystem; 760 status_t error = get_port_and_fs(&port, &fileSystem); 761 if (error != B_OK) 762 return error; 763 764 // prepare the request 765 RequestAllocator allocator(port->GetPort()); 766 FileCacheReadRequest* request; 767 error = AllocateRequest(allocator, &request); 768 if (error != B_OK) 769 return error; 770 771 request->nsid = mountID; 772 request->vnid = vnodeID; 773 request->cookie = cookie; 774 request->pos = offset; 775 request->size = *_size; 776 777 // send the request 778 UserlandRequestHandler handler(fileSystem, FILE_CACHE_READ_REPLY); 779 FileCacheReadReply* reply; 780 error = port->SendRequest(&allocator, &handler, (Request**)&reply); 781 if (error != B_OK) 782 return error; 783 RequestReleaser requestReleaser(port, reply); 784 785 // process the reply 786 if (reply->error != B_OK) 787 return reply->error; 788 789 if (reply->bytesRead > 0) { 790 memcpy(bufferBase, reply->buffer.GetData(), reply->buffer.GetSize()); 791 792 // send receipt-ack 793 RequestAllocator receiptAckAllocator(port->GetPort()); 794 ReceiptAckReply* receiptAck; 795 if (AllocateRequest(receiptAckAllocator, &receiptAck) == B_OK) 796 port->SendRequest(&receiptAckAllocator); 797 } 798 799 *_size = reply->bytesRead; 800 801 return B_OK; 802 } 803 804 805 // file_cache_write 806 status_t 807 UserlandFS::KernelEmu::file_cache_write(dev_t mountID, ino_t vnodeID, 808 void *cookie, off_t offset, const void *buffer, size_t *_size) 809 { 810 // get the request port and the file system 811 RequestPort* port; 812 FileSystem* fileSystem; 813 status_t error = get_port_and_fs(&port, &fileSystem); 814 if (error != B_OK) 815 return error; 816 817 // prepare the request 818 RequestAllocator allocator(port->GetPort()); 819 FileCacheWriteRequest* request; 820 error = AllocateRequest(allocator, &request); 821 if (error != B_OK) 822 return error; 823 824 request->nsid = mountID; 825 request->vnid = vnodeID; 826 request->cookie = cookie; 827 request->size = *_size; 828 request->pos = offset; 829 830 if (buffer != NULL) { 831 error = allocator.AllocateData(request->buffer, buffer, *_size, 1, 832 false); 833 if (error != B_OK) 834 return error; 835 } 836 837 // send the request 838 UserlandRequestHandler handler(fileSystem, FILE_CACHE_WRITE_REPLY); 839 FileCacheWriteReply* reply; 840 error = port->SendRequest(&allocator, &handler, (Request**)&reply); 841 if (error != B_OK) 842 return error; 843 RequestReleaser requestReleaser(port, reply); 844 845 // process the reply 846 *_size = reply->bytesWritten; 847 return reply->error; 848 } 849 850 851 // #pragma mark - I/O 852 853 854 status_t 855 UserlandFS::KernelEmu::do_iterative_fd_io(dev_t volumeID, int fd, 856 int32 requestID, void* cookie, const file_io_vec* vecs, uint32 vecCount) 857 { 858 // get the request port and the file system 859 RequestPort* port; 860 FileSystem* fileSystem; 861 status_t error = get_port_and_fs(&port, &fileSystem); 862 if (error != B_OK) 863 return error; 864 865 // prepare the request 866 RequestAllocator allocator(port->GetPort()); 867 DoIterativeFDIORequest* request; 868 error = AllocateRequest(allocator, &request); 869 if (error != B_OK) 870 return error; 871 872 request->nsid = volumeID; 873 request->fd = fd; 874 request->request = requestID; 875 request->cookie = cookie; 876 877 if (vecCount > 0) { 878 vecCount = std::min(vecCount, (uint32)DoIterativeFDIORequest::MAX_VECS); 879 memcpy(request->vecs, vecs, sizeof(file_io_vec) * vecCount); 880 } 881 request->vecCount = vecCount; 882 883 // send the request 884 UserlandRequestHandler handler(fileSystem, DO_ITERATIVE_FD_IO_REPLY); 885 DoIterativeFDIOReply* reply; 886 error = port->SendRequest(&allocator, &handler, (Request**)&reply); 887 if (error != B_OK) 888 return error; 889 // TODO: Up to this point we should call the finished hook on error! 890 RequestReleaser requestReleaser(port, reply); 891 892 // process the reply 893 return reply->error; 894 } 895 896 897 status_t 898 UserlandFS::KernelEmu::read_from_io_request(dev_t volumeID, int32 requestID, 899 void* buffer, size_t size) 900 { 901 // get the request port and the file system 902 RequestPort* port; 903 FileSystem* fileSystem; 904 status_t error = get_port_and_fs(&port, &fileSystem); 905 if (error != B_OK) 906 return error; 907 908 // prepare the request 909 RequestAllocator allocator(port->GetPort()); 910 ReadFromIORequestRequest* request; 911 error = AllocateRequest(allocator, &request); 912 if (error != B_OK) 913 return error; 914 915 request->nsid = volumeID; 916 request->request = requestID; 917 request->size = size; 918 919 // send the request 920 UserlandRequestHandler handler(fileSystem, READ_FROM_IO_REQUEST_REPLY); 921 ReadFromIORequestReply* reply; 922 error = port->SendRequest(&allocator, &handler, (Request**)&reply); 923 if (error != B_OK) 924 return error; 925 RequestReleaser requestReleaser(port, reply); 926 927 // process the reply 928 if (reply->error != B_OK) 929 return reply->error; 930 931 memcpy(buffer, reply->buffer.GetData(), reply->buffer.GetSize()); 932 933 // send receipt-ack 934 RequestAllocator receiptAckAllocator(port->GetPort()); 935 ReceiptAckReply* receiptAck; 936 if (AllocateRequest(receiptAckAllocator, &receiptAck) == B_OK) 937 port->SendRequest(&receiptAckAllocator); 938 939 return B_OK; 940 } 941 942 943 status_t 944 UserlandFS::KernelEmu::write_to_io_request(dev_t volumeID, int32 requestID, 945 const void* buffer, size_t size) 946 { 947 // get the request port and the file system 948 RequestPort* port; 949 FileSystem* fileSystem; 950 status_t error = get_port_and_fs(&port, &fileSystem); 951 if (error != B_OK) 952 return error; 953 954 // prepare the request 955 RequestAllocator allocator(port->GetPort()); 956 WriteToIORequestRequest* request; 957 error = AllocateRequest(allocator, &request); 958 if (error != B_OK) 959 return error; 960 961 request->nsid = volumeID; 962 request->request = requestID; 963 964 error = allocator.AllocateData(request->buffer, buffer, size, 1, false); 965 if (error != B_OK) 966 return error; 967 968 // send the request 969 UserlandRequestHandler handler(fileSystem, WRITE_TO_IO_REQUEST_REPLY); 970 FileCacheWriteReply* reply; 971 error = port->SendRequest(&allocator, &handler, (Request**)&reply); 972 if (error != B_OK) 973 return error; 974 RequestReleaser requestReleaser(port, reply); 975 976 // process the reply 977 return reply->error; 978 } 979 980 981 status_t 982 UserlandFS::KernelEmu::notify_io_request(dev_t volumeID, int32 requestID, 983 status_t status) 984 { 985 // get the request port and the file system 986 RequestPort* port; 987 FileSystem* fileSystem; 988 status_t error = get_port_and_fs(&port, &fileSystem); 989 if (error != B_OK) 990 return error; 991 992 // prepare the request 993 RequestAllocator allocator(port->GetPort()); 994 NotifyIORequestRequest* request; 995 error = AllocateRequest(allocator, &request); 996 if (error != B_OK) 997 return error; 998 999 request->nsid = volumeID; 1000 request->request = requestID; 1001 request->status = status; 1002 1003 // send the request 1004 UserlandRequestHandler handler(fileSystem, NOTIFY_IO_REQUEST_REPLY); 1005 NotifyIORequestReply* reply; 1006 error = port->SendRequest(&allocator, &handler, (Request**)&reply); 1007 if (error != B_OK) 1008 return error; 1009 RequestReleaser requestReleaser(port, reply); 1010 1011 // process the reply 1012 return reply->error; 1013 } 1014 1015 1016 // #pragma mark - node monitoring 1017 1018 1019 status_t 1020 UserlandFS::KernelEmu::add_node_listener(dev_t device, ino_t node, uint32 flags, 1021 void* listener) 1022 { 1023 // get the request port and the file system 1024 RequestPort* port; 1025 FileSystem* fileSystem; 1026 status_t error = get_port_and_fs(&port, &fileSystem); 1027 if (error != B_OK) 1028 return error; 1029 1030 // prepare the request 1031 RequestAllocator allocator(port->GetPort()); 1032 AddNodeListenerRequest* request; 1033 error = AllocateRequest(allocator, &request); 1034 if (error != B_OK) 1035 return error; 1036 1037 request->device = device; 1038 request->node = node; 1039 request->flags = flags; 1040 request->listener = listener; 1041 1042 // send the request 1043 UserlandRequestHandler handler(fileSystem, ADD_NODE_LISTENER_REPLY); 1044 AddNodeListenerReply* reply; 1045 error = port->SendRequest(&allocator, &handler, (Request**)&reply); 1046 if (error != B_OK) 1047 return error; 1048 RequestReleaser requestReleaser(port, reply); 1049 1050 // process the reply 1051 return reply->error; 1052 } 1053 1054 1055 status_t 1056 UserlandFS::KernelEmu::remove_node_listener(dev_t device, ino_t node, 1057 void* listener) 1058 { 1059 // get the request port and the file system 1060 RequestPort* port; 1061 FileSystem* fileSystem; 1062 status_t error = get_port_and_fs(&port, &fileSystem); 1063 if (error != B_OK) 1064 return error; 1065 1066 // prepare the request 1067 RequestAllocator allocator(port->GetPort()); 1068 RemoveNodeListenerRequest* request; 1069 error = AllocateRequest(allocator, &request); 1070 if (error != B_OK) 1071 return error; 1072 1073 request->device = device; 1074 request->node = node; 1075 request->listener = listener; 1076 1077 // send the request 1078 UserlandRequestHandler handler(fileSystem, REMOVE_NODE_LISTENER_REPLY); 1079 RemoveNodeListenerReply* reply; 1080 error = port->SendRequest(&allocator, &handler, (Request**)&reply); 1081 if (error != B_OK) 1082 return error; 1083 RequestReleaser requestReleaser(port, reply); 1084 1085 // process the reply 1086 return reply->error; 1087 } 1088 1089 1090 // #pragma mark - 1091 1092 1093 // kernel_debugger 1094 void 1095 UserlandFS::KernelEmu::kernel_debugger(const char *message) 1096 { 1097 debugger(message); 1098 } 1099 1100 // vdprintf 1101 void 1102 UserlandFS::KernelEmu::vdprintf(const char *format, va_list args) 1103 { 1104 vprintf(format, args); 1105 } 1106 1107 // dprintf 1108 void 1109 UserlandFS::KernelEmu::dprintf(const char *format, ...) 1110 { 1111 va_list args; 1112 va_start(args, format); 1113 vdprintf(format, args); 1114 va_end(args); 1115 } 1116 1117 void 1118 UserlandFS::KernelEmu::dump_block(const char *buffer, int size, 1119 const char *prefix) 1120 { 1121 // TODO: Implement! 1122 } 1123 1124 // parse_expression 1125 //ulong 1126 //parse_expression(char *str) 1127 //{ 1128 // return 0; 1129 //} 1130 1131 // add_debugger_command 1132 int 1133 UserlandFS::KernelEmu::add_debugger_command(char *name, 1134 int (*func)(int argc, char **argv), char *help) 1135 { 1136 return B_OK; 1137 } 1138 1139 // remove_debugger_command 1140 int 1141 UserlandFS::KernelEmu::remove_debugger_command(char *name, 1142 int (*func)(int argc, char **argv)) 1143 { 1144 return B_OK; 1145 } 1146 1147 // parse_expression 1148 uint32 1149 UserlandFS::KernelEmu::parse_expression(const char *string) 1150 { 1151 return 0; 1152 } 1153 1154 1155 // kprintf 1156 //void 1157 //kprintf(const char *format, ...) 1158 //{ 1159 //} 1160 1161 // spawn_kernel_thread 1162 thread_id 1163 UserlandFS::KernelEmu::spawn_kernel_thread(thread_entry function, 1164 const char *threadName, long priority, void *arg) 1165 { 1166 return spawn_thread(function, threadName, priority, arg); 1167 } 1168