1 // ClientConnection.cpp 2 3 #include "ClientConnection.h" 4 5 #include <new> 6 #include <typeinfo> 7 8 #include <dirent.h> 9 #include <fcntl.h> 10 #include <errno.h> 11 #include <stdlib.h> 12 #include <unistd.h> 13 #include <utime.h> 14 15 #include <AutoDeleter.h> 16 #include <AutoLocker.h> 17 #include <Entry.h> 18 #include <fs_query.h> 19 #include <GraphicsDefs.h> 20 #include <HashMap.h> 21 #include <NodeMonitor.h> 22 #include <Path.h> 23 #include <Rect.h> 24 #include <Mime.h> 25 26 #include <fsproto.h> 27 28 #include "Compatibility.h" 29 #include "Connection.h" 30 #include "DebugSupport.h" 31 #include "Directory.h" 32 #include "Entry.h" 33 #include "FDManager.h" 34 #include "NodeHandle.h" 35 #include "NodeHandleMap.h" 36 #include "NodeMonitoringEvent.h" 37 #include "Path.h" 38 #include "RequestBufferReplacer.h" 39 #include "RequestChannel.h" 40 #include "RequestConnection.h" 41 #include "RequestDumper.h" 42 #include "RequestFlattener.h" 43 #include "Requests.h" 44 #include "SecurityContext.h" 45 #include "ServerNodeID.h" 46 #include "UserSecurityContext.h" 47 #include "Utils.h" 48 #include "Volume.h" 49 #include "VolumeManager.h" 50 51 static const int32 kMaxSaneReadLinkSize = 10240; // 10 KB 52 static const int32 kMaxReadBufferSize = 10240; // 10 KB 53 static const int32 kMaxReadDirBufferSize = 10240; 54 55 // Locking: 56 // 57 // fLock: Guards fReferenceCount and fClosed. 58 // fSecurityContextLock: Guards fSecurityContext. 59 // fVolumes: Guards the map itself. 60 61 62 // #pragma mark - 63 // #pragma mark ----- ClientConnection ----- 64 65 // ConnectionReference 66 class ClientConnection::ConnectionReference { 67 public: 68 ConnectionReference(ClientConnection* connection) 69 : fConnection(connection) 70 { 71 if (!fConnection || !fConnection->GetReference()) 72 fConnection = NULL; 73 } 74 75 ~ConnectionReference() 76 { 77 if (fConnection) 78 fConnection->PutReference(); 79 } 80 81 bool IsValid() const 82 { 83 return fConnection; 84 } 85 86 private: 87 ClientConnection* fConnection; 88 }; 89 90 // VolumeMap 91 struct ClientConnection::VolumeMap 92 : public SynchronizedHashMap<HashKey32<int32>, ClientVolume*> { 93 }; 94 95 // ClientVolumePutter 96 class ClientConnection::ClientVolumePutter { 97 public: 98 ClientVolumePutter(ClientConnection* connection, ClientVolume* volume) 99 : fConnection(connection), 100 fVolume(volume) 101 { 102 } 103 104 ~ClientVolumePutter() 105 { 106 if (fConnection && fVolume) 107 fConnection->_PutVolume(fVolume); 108 } 109 110 void Detach() 111 { 112 fConnection = NULL; 113 fVolume = NULL; 114 } 115 116 private: 117 ClientConnection* fConnection; 118 ClientVolume* fVolume; 119 }; 120 121 // VolumeNodeMonitoringEvent 122 struct ClientConnection::VolumeNodeMonitoringEvent { 123 VolumeNodeMonitoringEvent(int32 volumeID, NodeMonitoringEvent* event) 124 : volumeID(volumeID), 125 event(event) 126 { 127 if (event) 128 event->AcquireReference(); 129 } 130 131 ~VolumeNodeMonitoringEvent() 132 { 133 if (event) 134 event->ReleaseReference(); 135 } 136 137 int32 volumeID; 138 NodeMonitoringEvent* event; 139 }; 140 141 // NodeMonitoringEventQueue 142 struct ClientConnection::NodeMonitoringEventQueue 143 : BlockingQueue<NodeMonitoringRequest> { 144 NodeMonitoringEventQueue() 145 : BlockingQueue<NodeMonitoringRequest>("client NM requests") 146 { 147 } 148 }; 149 150 // QueryHandleUnlocker 151 struct ClientConnection::QueryHandleUnlocker { 152 QueryHandleUnlocker(ClientConnection* connection, NodeHandle* nodeHandle) 153 : fConnection(connection), 154 fHandle(nodeHandle) 155 { 156 } 157 158 ~QueryHandleUnlocker() 159 { 160 if (fConnection && fHandle) { 161 fConnection->_UnlockQueryHandle(fHandle); 162 fConnection = NULL; 163 fHandle = NULL; 164 } 165 } 166 167 private: 168 ClientConnection* fConnection; 169 NodeHandle* fHandle; 170 }; 171 172 // ClientVolumeFilter 173 struct ClientConnection::ClientVolumeFilter { 174 virtual ~ClientVolumeFilter() {} 175 176 virtual bool FilterVolume(ClientConnection* connection, 177 ClientVolume* volume) = 0; 178 }; 179 180 // HasQueryPermissionClientVolumeFilter 181 struct ClientConnection::HasQueryPermissionClientVolumeFilter 182 : ClientConnection::ClientVolumeFilter { 183 virtual bool FilterVolume(ClientConnection* connection, 184 ClientVolume* volume) 185 { 186 return volume->GetSharePermissions().ImpliesQuerySharePermission(); 187 } 188 }; 189 190 191 // #pragma mark - 192 193 // constructor 194 ClientConnection::ClientConnection(Connection* connection, 195 SecurityContext* securityContext, User* user, 196 ClientConnectionListener* listener) 197 : RequestHandler(), 198 ClientVolume::NodeMonitoringProcessor(), 199 fConnection(NULL), 200 fSecurityContext(securityContext), 201 fSecurityContextLock("security context lock"), 202 fUser(user), 203 fVolumes(NULL), 204 fQueryHandles(NULL), 205 fListener(listener), 206 fNodeMonitoringEvents(NULL), 207 fNodeMonitoringProcessor(-1), 208 fLock("client connection locker"), 209 fReferenceCount(0), 210 fInitialized(0), 211 fClosed(false), 212 fError(false), 213 fInverseClientEndianess(false) 214 { 215 fConnection = new(std::nothrow) RequestConnection(connection, this); 216 if (!fConnection) 217 delete connection; 218 } 219 220 // destructor 221 ClientConnection::~ClientConnection() 222 { 223 _Close(); 224 delete fConnection; 225 226 // delete all volumes 227 for (VolumeMap::Iterator it = fVolumes->GetIterator(); it.HasNext();) 228 delete it.Next().value; 229 delete fVolumes; 230 231 delete fQueryHandles; 232 delete fNodeMonitoringEvents; 233 } 234 235 // Init 236 status_t 237 ClientConnection::Init() 238 { 239 // create a client volume map 240 fVolumes = new(std::nothrow) VolumeMap; 241 if (!fVolumes) 242 return B_NO_MEMORY; 243 status_t error = fVolumes->InitCheck(); 244 if (error != B_OK) 245 return error; 246 247 // create the query handle map 248 fQueryHandles = new(std::nothrow) NodeHandleMap("query handles"); 249 if (!fQueryHandles) 250 return B_NO_MEMORY; 251 error = fQueryHandles->Init(); 252 if (error != B_OK) 253 return error; 254 255 // create the node monitoring event queue 256 fNodeMonitoringEvents = new(std::nothrow) NodeMonitoringEventQueue; 257 if (!fNodeMonitoringEvents) 258 return B_NO_MEMORY; 259 error = fNodeMonitoringEvents->InitCheck(); 260 if (error != B_OK) 261 return error; 262 263 // initialize the connection 264 error = fConnection->Init(); 265 if (error != B_OK) 266 return error; 267 268 // start the node monitoring processor 269 fNodeMonitoringProcessor = spawn_thread(_NodeMonitoringProcessorEntry, 270 "client connection NM processor", B_NORMAL_PRIORITY, this); 271 if (fNodeMonitoringProcessor < 0) { 272 _Close(); 273 return fNodeMonitoringProcessor; 274 } 275 resume_thread(fNodeMonitoringProcessor); 276 return B_OK; 277 } 278 279 // Close 280 /*! 281 Called by the NetFSServer. Not for internal use. Waits for the connection 282 to be closed (at least for the node monitoring thread to be gone). 283 */ 284 void 285 ClientConnection::Close() 286 { 287 { 288 ConnectionReference connectionReference(this); 289 if (connectionReference.IsValid()) 290 _MarkClosed(false); 291 fListener = NULL; 292 } 293 294 // Wait at least for the node monitoring processor; this is not perfect, 295 // but not too bad either. 296 if (fNodeMonitoringProcessor >= 0 297 && find_thread(NULL) != fNodeMonitoringProcessor) { 298 int32 result; 299 wait_for_thread(fNodeMonitoringProcessor, &result); 300 } 301 } 302 303 // GetReference 304 bool 305 ClientConnection::GetReference() 306 { 307 AutoLocker<Locker> _(fLock); 308 if (fClosed || !atomic_or(&fInitialized, 0)) 309 return false; 310 fReferenceCount++; 311 return true; 312 } 313 314 // PutReference 315 void 316 ClientConnection::PutReference() 317 { 318 bool close = false; 319 { 320 AutoLocker<Locker> _(fLock); 321 --fReferenceCount; 322 if (fClosed) 323 close = (fReferenceCount == 0); 324 } 325 if (close) 326 _Close(); 327 } 328 329 // UserRemoved 330 void 331 ClientConnection::UserRemoved(User* user) 332 { 333 // get all volumes 334 ClientVolume** volumes = NULL; 335 int32 volumeCount = 0; 336 AutoLocker<VolumeMap> volumesLocker(fVolumes); 337 volumes = new(std::nothrow) ClientVolume*[fVolumes->Size()]; 338 if (!volumes) { 339 ERROR(("ClientConnection::UserRemoved(): ERROR: Failed to " 340 "allocate memory for volume array.\n")); 341 volumesLocker.Unlock(); 342 _UnmountAllVolumes(); 343 return; 344 } 345 for (VolumeMap::Iterator it = fVolumes->GetIterator(); it.HasNext();) { 346 if (ClientVolume* volume = _GetVolume(it.Next().value->GetID())) 347 volumes[volumeCount++] = volume; 348 } 349 volumesLocker.Unlock(); 350 351 // unmount the concerned volumes 352 for (int32 i = 0; i < volumeCount; i++) { 353 ClientVolume* volume = volumes[i]; 354 355 fSecurityContextLock.Lock(); 356 bool unmount = (volume->GetSecurityContext()->GetUser() == user); 357 fSecurityContextLock.Unlock(); 358 359 if (unmount) 360 _UnmountVolume(volume); 361 } 362 363 // put the volumes 364 for (int32 i = 0; i < volumeCount; i++) 365 _PutVolume(volumes[i]); 366 delete[] volumes; 367 } 368 369 // ShareRemoved 370 void 371 ClientConnection::ShareRemoved(Share* share) 372 { 373 // get all volumes 374 ClientVolume** volumes = NULL; 375 int32 volumeCount = 0; 376 AutoLocker<VolumeMap> volumesLocker(fVolumes); 377 volumes = new(std::nothrow) ClientVolume*[fVolumes->Size()]; 378 if (!volumes) { 379 ERROR(("ClientConnection::ShareRemoved(): ERROR: Failed to " 380 "allocate memory for volume array.\n")); 381 volumesLocker.Unlock(); 382 _UnmountAllVolumes(); 383 return; 384 } 385 for (VolumeMap::Iterator it = fVolumes->GetIterator(); it.HasNext();) { 386 if (ClientVolume* volume = _GetVolume(it.Next().value->GetID())) 387 volumes[volumeCount++] = volume; 388 } 389 volumesLocker.Unlock(); 390 391 // unmount the concerned volumes 392 for (int32 i = 0; i < volumeCount; i++) { 393 ClientVolume* volume = volumes[i]; 394 395 fSecurityContextLock.Lock(); 396 bool unmount = (volume->GetShare() == share); 397 fSecurityContextLock.Unlock(); 398 399 if (unmount) 400 _UnmountVolume(volume); 401 } 402 403 // put the volumes 404 for (int32 i = 0; i < volumeCount; i++) 405 _PutVolume(volumes[i]); 406 delete[] volumes; 407 } 408 409 // UserPermissionsChanged 410 void 411 ClientConnection::UserPermissionsChanged(Share* share, User* user, 412 Permissions permissions) 413 { 414 bool unmountAll = (!permissions.ImpliesMountSharePermission()); 415 416 // get all volumes 417 ClientVolume** volumes = NULL; 418 int32 volumeCount = 0; 419 AutoLocker<VolumeMap> volumesLocker(fVolumes); 420 volumes = new(std::nothrow) ClientVolume*[fVolumes->Size()]; 421 if (!volumes) { 422 ERROR(("ClientConnection::ShareRemoved(): ERROR: Failed to " 423 "allocate memory for volume array.\n")); 424 volumesLocker.Unlock(); 425 _UnmountAllVolumes(); 426 return; 427 } 428 for (VolumeMap::Iterator it = fVolumes->GetIterator(); it.HasNext();) { 429 if (ClientVolume* volume = _GetVolume(it.Next().value->GetID())) 430 volumes[volumeCount++] = volume; 431 } 432 volumesLocker.Unlock(); 433 434 // update the concerned volumes 435 for (int32 i = 0; i < volumeCount; i++) { 436 ClientVolume* volume = volumes[i]; 437 438 fSecurityContextLock.Lock(); 439 bool concerned = (volume->GetShare() == share 440 && volume->GetSecurityContext()->GetUser() == user); 441 fSecurityContextLock.Unlock(); 442 443 if (concerned) { 444 // create a new user security context for the volume 445 status_t error = B_OK; 446 447 if (unmountAll) { 448 _UnmountVolume(volume); 449 } else { 450 // create a new user security context 451 AutoLocker<Locker> securityContextLocker(fSecurityContextLock); 452 UserSecurityContext* userSecurityContext 453 = new(std::nothrow) UserSecurityContext; 454 455 // init it 456 if (userSecurityContext) { 457 error = fSecurityContext->GetUserSecurityContext(user, 458 userSecurityContext); 459 } else 460 error = B_NO_MEMORY; 461 if (error != B_OK) { 462 delete userSecurityContext; 463 securityContextLocker.Unlock(); 464 _UnmountVolume(volume); 465 continue; 466 } 467 468 // set the volume's new user security context 469 securityContextLocker.Unlock(); 470 volume->SetSecurityContext(userSecurityContext); 471 } 472 } 473 } 474 475 // put the volumes 476 for (int32 i = 0; i < volumeCount; i++) 477 _PutVolume(volumes[i]); 478 delete[] volumes; 479 } 480 481 482 // #pragma mark - 483 484 // VisitConnectionBrokenRequest 485 status_t 486 ClientConnection::VisitConnectionBrokenRequest(ConnectionBrokenRequest* request) 487 { 488 ConnectionReference connectionReference(this); 489 if (!connectionReference.IsValid()) 490 return B_OK; 491 492 _MarkClosed(true); 493 return B_OK; 494 } 495 496 // VisitInitConnectionRequest 497 status_t 498 ClientConnection::VisitInitConnectionRequest(InitConnectionRequest* request) 499 { 500 bool alreadyInitialized = atomic_or(&fInitialized, ~0); 501 502 ConnectionReference connectionReference(this); 503 if (!connectionReference.IsValid()) 504 return B_OK; 505 506 if (!alreadyInitialized) 507 fInverseClientEndianess = (request->bigEndian != B_HOST_IS_BENDIAN); 508 509 // prepare the reply 510 InitConnectionReply reply; 511 512 // send the reply 513 reply.error = (alreadyInitialized ? B_BAD_VALUE : B_OK); 514 status_t error = GetChannel()->SendRequest(&reply); 515 516 // on error just close 517 if (error != B_OK) 518 _MarkClosed(true); 519 return B_OK; 520 } 521 522 // VisitMountRequest 523 status_t 524 ClientConnection::VisitMountRequest(MountRequest* request) 525 { 526 ConnectionReference connectionReference(this); 527 if (!connectionReference.IsValid()) 528 return B_OK; 529 530 status_t result = B_OK; 531 const char* shareName = request->share.GetString(); 532 if (!shareName) 533 SET_ERROR(result, B_BAD_DATA); 534 535 // create a volume 536 ClientVolume* volume = NULL; 537 if (result == B_OK) 538 result = _CreateVolume(&volume); 539 ClientVolumePutter volumePutter(this, volume); 540 541 // if we haven't been supplied with a user yet, use the info from the 542 // mount request for authentication 543 VolumeManagerLocker managerLocker; 544 AutoLocker<Locker> securityContextLocker(fSecurityContextLock); 545 const char* userName = request->user.GetString(); 546 User* user = fUser; 547 BReference<User> userReference(user); 548 bool noPermission = false; 549 if (result == B_OK && !user) { 550 if (userName) { 551 SET_ERROR(result, fSecurityContext->AuthenticateUser(userName, 552 request->password.GetString(), &user)); 553 if (result == B_OK) 554 userReference.SetTo(user, true); 555 } else 556 result = B_PERMISSION_DENIED; 557 if (result == B_PERMISSION_DENIED) 558 noPermission = true; 559 } 560 561 // create a user security context 562 UserSecurityContext* securityContext = NULL; 563 if (result == B_OK) { 564 securityContext = new(std::nothrow) UserSecurityContext; 565 if (securityContext) { 566 SET_ERROR(result, fSecurityContext->GetUserSecurityContext(user, 567 securityContext)); 568 } else 569 SET_ERROR(result, B_NO_MEMORY); 570 } 571 ObjectDeleter<UserSecurityContext> securityContextDeleter(securityContext); 572 573 // get the share 574 Share* share = NULL; 575 Permissions sharePermissions; 576 node_ref mountPoint; 577 if (result == B_OK) { 578 AutoLocker<SecurityContext> _(fSecurityContext); 579 share = fSecurityContext->FindShare(shareName); 580 if (share) { 581 mountPoint = share->GetNodeRef(); 582 sharePermissions = securityContext->GetNodePermissions( 583 mountPoint); 584 if (!sharePermissions.ImpliesMountSharePermission()) { 585 SET_ERROR(result, B_PERMISSION_DENIED); 586 noPermission = true; 587 } 588 } else 589 SET_ERROR(result, B_ENTRY_NOT_FOUND); 590 } 591 BReference<Share> shareReference(share, true); 592 593 // mount the volume 594 MountReply reply; 595 if (result == B_OK) { 596 SET_ERROR(result, volume->Mount(securityContext, share)); 597 securityContextDeleter.Detach(); 598 } 599 if (result == B_OK) { 600 _GetNodeInfo(volume->GetRootDirectory(), &reply.nodeInfo); 601 reply.sharePermissions = sharePermissions.GetPermissions(); 602 reply.volumeID = volume->GetID(); 603 } 604 605 // make sure, the volume is removed on error 606 if (result != B_OK && volume) { 607 AutoLocker<VolumeMap> volumeMapLocker(fVolumes); 608 volume->MarkRemoved(); 609 } 610 611 securityContextLocker.Unlock(); 612 managerLocker.Unlock(); 613 614 // send the reply 615 reply.error = result; 616 reply.noPermission = noPermission; 617 return GetChannel()->SendRequest(&reply); 618 } 619 620 // VisitUnmountRequest 621 status_t 622 ClientConnection::VisitUnmountRequest(UnmountRequest* request) 623 { 624 ConnectionReference connectionReference(this); 625 if (!connectionReference.IsValid()) 626 return B_OK; 627 628 if (ClientVolume* volume = _GetVolume(request->volumeID)) { 629 _UnmountVolume(volume); 630 _PutVolume(volume); 631 } 632 633 return B_OK; 634 } 635 636 // VisitReadVNodeRequest 637 status_t 638 ClientConnection::VisitReadVNodeRequest(ReadVNodeRequest* request) 639 { 640 ConnectionReference connectionReference(this); 641 if (!connectionReference.IsValid()) 642 return B_OK; 643 644 // get the volume 645 status_t result = B_OK; 646 ClientVolume* volume = _GetVolume(request->volumeID); 647 if (!volume) 648 result = B_BAD_VALUE; 649 ClientVolumePutter volumePutter(this, volume); 650 651 VolumeManagerLocker managerLocker; 652 653 // get the node 654 Node* node = NULL; 655 if (result == B_OK) { 656 node = volume->GetNode(request->nodeID); 657 if (!node) 658 result = B_ENTRY_NOT_FOUND; 659 } 660 661 // prepare the reply 662 ReadVNodeReply reply; 663 if (result == B_OK) 664 _GetNodeInfo(node, &reply.nodeInfo); 665 666 managerLocker.Unlock(); 667 668 // send the reply 669 reply.error = result; 670 return GetChannel()->SendRequest(&reply); 671 } 672 673 // VisitWriteStatRequest 674 status_t 675 ClientConnection::VisitWriteStatRequest(WriteStatRequest* request) 676 { 677 ConnectionReference connectionReference(this); 678 if (!connectionReference.IsValid()) 679 return B_OK; 680 681 // get the volume 682 status_t result = B_OK; 683 ClientVolume* volume = _GetVolume(request->volumeID); 684 if (!volume) 685 result = B_BAD_VALUE; 686 ClientVolumePutter volumePutter(this, volume); 687 688 VolumeManagerLocker managerLocker; 689 690 // get the node 691 Node* node = NULL; 692 if (result == B_OK) { 693 node = volume->GetNode(request->nodeID); 694 if (!node) 695 result = B_ENTRY_NOT_FOUND; 696 } 697 698 // check permissions 699 if (result == B_OK) { 700 if (!volume->GetNodePermissions(node).ImpliesWritePermission()) 701 result = B_PERMISSION_DENIED; 702 } 703 704 // get the path 705 Path path; 706 if (result == B_OK) 707 result = node->GetPath(&path); 708 709 // write the stat 710 uint32 mask = request->mask; 711 // size 712 if (result == B_OK && (mask & WSTAT_SIZE)) { 713 if (truncate(path.GetPath(), request->nodeInfo.st.st_size) < 0) 714 result = errno; 715 } 716 // mode 717 if (result == B_OK && (mask & WSTAT_MODE)) { 718 if (chmod(path.GetPath(), request->nodeInfo.st.st_mode) < 0) 719 result = errno; 720 } 721 // mtime 722 if (result == B_OK && (mask & (WSTAT_ATIME | WSTAT_MTIME))) { 723 utimbuf buffer; 724 buffer.actime = (mask & WSTAT_ATIME) 725 ? request->nodeInfo.st.st_atime 726 : node->GetStat().st_atime; 727 buffer.modtime = (mask & WSTAT_MTIME) 728 ? request->nodeInfo.st.st_mtime 729 : node->GetStat().st_mtime; 730 if (utime(path.GetPath(), &buffer) < 0) 731 result = errno; 732 } 733 // ignore WSTAT_CRTIME, WSTAT_UID, WSTAT_GID for the time being 734 735 // prepare the reply 736 WriteStatReply reply; 737 // update the node stat 738 reply.nodeInfoValid = false; 739 if (node) { 740 if (node->UpdateStat() == B_OK) { 741 _GetNodeInfo(node, &reply.nodeInfo); 742 reply.nodeInfoValid = true; 743 } 744 } 745 746 managerLocker.Unlock(); 747 748 // send the reply 749 reply.error = result; 750 return GetChannel()->SendRequest(&reply); 751 } 752 753 // VisitCreateFileRequest 754 status_t 755 ClientConnection::VisitCreateFileRequest(CreateFileRequest* request) 756 { 757 ConnectionReference connectionReference(this); 758 if (!connectionReference.IsValid()) 759 return B_OK; 760 761 // get the volume 762 status_t result = B_OK; 763 ClientVolume* volume = _GetVolume(request->volumeID); 764 if (!volume) 765 result = B_BAD_VALUE; 766 ClientVolumePutter volumePutter(this, volume); 767 768 VolumeManagerLocker managerLocker; 769 770 // get the directory 771 Directory* directory = NULL; 772 if (result == B_OK) { 773 Node* node = volume->GetNode(request->directoryID); 774 if (node) { 775 directory = dynamic_cast<Directory*>(node); 776 if (!directory) 777 result = B_NOT_A_DIRECTORY; 778 } else 779 result = B_ENTRY_NOT_FOUND; 780 } 781 782 // check permissions 783 int openMode = request->openMode; 784 if (result == B_OK) { 785 if (!volume->GetNodePermissions(directory).ImpliesWritePermission()) 786 result = B_PERMISSION_DENIED; 787 } 788 789 // get the path 790 Path path; 791 if (result == B_OK) { 792 result = directory->GetPath(&path); 793 if (result == B_OK) 794 result = path.Append(request->name.GetString()); 795 } 796 797 // create the file 798 if (result == B_OK) { 799 int fd = -1; 800 result = FDManager::Open(path.GetPath(), 801 openMode | O_CREAT | O_NOTRAVERSE, request->mode, fd); 802 if (result == B_OK) 803 close(fd); 804 } 805 806 // load the new entry 807 Entry* entry = NULL; 808 if (result == B_OK) { 809 VolumeManager* volumeManager = VolumeManager::GetDefault(); 810 811 // if there existed an entry before, we need to delete it, to avoid that 812 // we open the wrong node 813 entry = volumeManager->GetEntry(directory->GetVolumeID(), 814 directory->GetID(), request->name.GetString()); 815 if (entry) 816 volumeManager->DeleteEntry(entry, false); 817 818 // load the new entry 819 entry = NULL; 820 result = volume->LoadEntry(directory, request->name.GetString(), 821 &entry); 822 } 823 824 // open the node 825 FileHandle* handle = NULL; 826 if (result == B_OK) { 827 openMode &= ~(O_CREAT | O_EXCL | O_TRUNC); 828 result = volume->Open(entry->GetNode(), openMode, &handle); 829 } 830 NodeHandleUnlocker handleUnlocker(volume, handle); 831 832 // prepare the reply 833 CreateFileReply reply; 834 if (result == B_OK) { 835 _GetEntryInfo(entry, &reply.entryInfo); 836 reply.cookie = handle->GetCookie(); 837 } 838 839 managerLocker.Unlock(); 840 841 // send the reply 842 reply.error = result; 843 status_t error = GetChannel()->SendRequest(&reply); 844 845 // close the handle, if a send error occurred 846 if (error != B_OK && result == B_OK) 847 volume->Close(handle); 848 849 return error; 850 } 851 852 // VisitOpenRequest 853 status_t 854 ClientConnection::VisitOpenRequest(OpenRequest* request) 855 { 856 ConnectionReference connectionReference(this); 857 if (!connectionReference.IsValid()) 858 return B_OK; 859 860 // get the volume 861 status_t result = B_OK; 862 ClientVolume* volume = _GetVolume(request->volumeID); 863 if (!volume) 864 result = B_BAD_VALUE; 865 ClientVolumePutter volumePutter(this, volume); 866 867 VolumeManagerLocker managerLocker; 868 869 // get the node 870 Node* node = NULL; 871 if (result == B_OK) { 872 node = volume->GetNode(request->nodeID); 873 if (!node) 874 result = B_ENTRY_NOT_FOUND; 875 } 876 877 // check permissions 878 int openMode = request->openMode; 879 if (result == B_OK) { 880 Permissions permissions = volume->GetNodePermissions(node); 881 if ((openMode & O_RWMASK) == O_RDWR) { 882 // read+write: fall back to read/write only, if the other permission 883 // is missing 884 if (!permissions.ImpliesReadPermission()) 885 openMode = (openMode & ~O_RWMASK) | O_WRONLY; 886 else if (!permissions.ImpliesWritePermission()) 887 openMode = (openMode & ~O_RWMASK) | O_RDONLY; 888 } 889 if ((openMode & O_RWMASK) == O_RDONLY) { 890 if (!permissions.ImpliesReadPermission()) 891 result = B_PERMISSION_DENIED; 892 } else if ((openMode & O_RWMASK) == O_WRONLY) { 893 if (!permissions.ImpliesWritePermission()) 894 result = B_PERMISSION_DENIED; 895 } 896 } 897 898 // open the node 899 FileHandle* handle = NULL; 900 if (result == B_OK) 901 result = volume->Open(node, openMode, &handle); 902 NodeHandleUnlocker handleUnlocker(volume, handle); 903 904 // prepare the reply 905 OpenReply reply; 906 if (result == B_OK) { 907 _GetNodeInfo(node, &reply.nodeInfo); 908 reply.cookie = handle->GetCookie(); 909 } 910 911 managerLocker.Unlock(); 912 913 // send the reply 914 reply.error = result; 915 status_t error = GetChannel()->SendRequest(&reply); 916 917 // close the handle, if a send error occurred 918 if (error != B_OK && result == B_OK) 919 volume->Close(handle); 920 921 return error; 922 } 923 924 // VisitCloseRequest 925 status_t 926 ClientConnection::VisitCloseRequest(CloseRequest* request) 927 { 928 ConnectionReference connectionReference(this); 929 if (!connectionReference.IsValid()) 930 return B_OK; 931 932 status_t result = B_OK; 933 934 if (request->volumeID >= 0) { 935 // get the volume 936 ClientVolume* volume = _GetVolume(request->volumeID); 937 if (!volume) 938 SET_ERROR(result, B_BAD_VALUE); 939 ClientVolumePutter volumePutter(this, volume); 940 941 // get the node handle 942 NodeHandle* handle = NULL; 943 if (result == B_OK) 944 SET_ERROR(result, volume->LockNodeHandle(request->cookie, &handle)); 945 NodeHandleUnlocker handleUnlocker(volume, handle); 946 947 VolumeManagerLocker managerLocker; 948 949 // close it 950 if (result == B_OK) 951 SET_ERROR(result, volume->Close(handle)); 952 953 managerLocker.Unlock(); 954 } else { 955 // no volume ID given, so this is a query handle 956 // lock the handle 957 QueryHandle* handle = NULL; 958 if (result == B_OK) 959 SET_ERROR(result, _LockQueryHandle(request->cookie, &handle)); 960 QueryHandleUnlocker handleUnlocker(this, handle); 961 962 // close it 963 if (result == B_OK) 964 SET_ERROR(result, _CloseQuery(handle)); 965 } 966 967 // send the reply 968 CloseReply reply; 969 reply.error = result; 970 return GetChannel()->SendRequest(&reply); 971 } 972 973 // VisitReadRequest 974 status_t 975 ClientConnection::VisitReadRequest(ReadRequest* request) 976 { 977 ConnectionReference connectionReference(this); 978 if (!connectionReference.IsValid()) 979 return B_OK; 980 981 // get the volume 982 status_t result = B_OK; 983 ClientVolume* volume = _GetVolume(request->volumeID); 984 if (!volume) 985 result = B_BAD_VALUE; 986 ClientVolumePutter volumePutter(this, volume); 987 988 // get the node handle 989 NodeHandle* handle = NULL; 990 if (result == B_OK) 991 result = volume->LockNodeHandle(request->cookie, &handle); 992 NodeHandleUnlocker handleUnlocker(volume, handle); 993 994 // check if it is a file handle 995 FileHandle* fileHandle = NULL; 996 if (result == B_OK) { 997 fileHandle = dynamic_cast<FileHandle*>(handle); 998 if (!fileHandle) 999 result = B_BAD_VALUE; 1000 } 1001 1002 VolumeManagerLocker managerLocker; 1003 1004 // check read permission 1005 if (result == B_OK) { 1006 Node* node = volume->GetNode(fileHandle->GetNodeRef()); 1007 if (!node || !volume->GetNodePermissions(node).ImpliesReadPermission()) 1008 result = B_PERMISSION_DENIED; 1009 } 1010 1011 managerLocker.Unlock(); 1012 1013 off_t pos = request->pos; 1014 int32 size = request->size; 1015 int32 bufferSize = min(size, kMaxReadBufferSize); 1016 // allocate a buffer 1017 uint8* buffer = NULL; 1018 if (result == B_OK) { 1019 buffer = (uint8*)malloc(bufferSize); 1020 if (!buffer) 1021 result = B_NO_MEMORY; 1022 } 1023 MemoryDeleter bufferDeleter(buffer); 1024 1025 // read as long as there are bytes left to read or an error occurs 1026 bool moreToRead = true; 1027 do { 1028 int32 bytesToRead = min(size, bufferSize); 1029 size_t bytesRead = 0; 1030 if (result == B_OK) 1031 result = fileHandle->Read(pos, buffer, bytesToRead, &bytesRead); 1032 moreToRead = (result == B_OK && bytesRead > 0 1033 && (int32)bytesRead < size); 1034 1035 // prepare the reply 1036 ReadReply reply; 1037 if (result == B_OK) { 1038 reply.pos = pos; 1039 reply.data.SetTo(buffer, bytesRead); 1040 reply.moreToCome = moreToRead; 1041 pos += bytesRead; 1042 size -= bytesRead; 1043 } 1044 1045 // send the reply 1046 reply.error = result; 1047 status_t error = GetChannel()->SendRequest(&reply); 1048 if (error != B_OK) 1049 return error; 1050 } while (moreToRead); 1051 1052 return B_OK; 1053 } 1054 1055 // VisitWriteRequest 1056 status_t 1057 ClientConnection::VisitWriteRequest(WriteRequest* request) 1058 { 1059 ConnectionReference connectionReference(this); 1060 if (!connectionReference.IsValid()) 1061 return B_OK; 1062 1063 // get the volume 1064 status_t result = B_OK; 1065 ClientVolume* volume = _GetVolume(request->volumeID); 1066 if (!volume) 1067 result = B_BAD_VALUE; 1068 ClientVolumePutter volumePutter(this, volume); 1069 1070 // get the node handle 1071 NodeHandle* handle = NULL; 1072 if (result == B_OK) 1073 result = volume->LockNodeHandle(request->cookie, &handle); 1074 NodeHandleUnlocker handleUnlocker(volume, handle); 1075 1076 // check if it is a file handle 1077 FileHandle* fileHandle = NULL; 1078 if (result == B_OK) { 1079 fileHandle = dynamic_cast<FileHandle*>(handle); 1080 if (!fileHandle) 1081 result = B_BAD_VALUE; 1082 } 1083 1084 VolumeManagerLocker managerLocker; 1085 1086 // check read permission 1087 if (result == B_OK) { 1088 Node* node = volume->GetNode(fileHandle->GetNodeRef()); 1089 if (!node || !volume->GetNodePermissions(node).ImpliesWritePermission()) 1090 result = B_PERMISSION_DENIED; 1091 } 1092 1093 managerLocker.Unlock(); 1094 1095 // write until all has been written or an error occurs 1096 off_t pos = request->pos; 1097 int32 size = request->data.GetSize(); 1098 const char* buffer = (const char*)request->data.GetData(); 1099 while (result == B_OK && size > 0) { 1100 size_t bytesWritten; 1101 result = fileHandle->Write(pos, buffer, size, &bytesWritten); 1102 if (result == B_OK) { 1103 pos += bytesWritten; 1104 buffer += bytesWritten; 1105 size -= bytesWritten; 1106 } 1107 } 1108 1109 // prepare the reply 1110 WriteReply reply; 1111 // send the reply 1112 reply.error = result; 1113 return GetChannel()->SendRequest(&reply); 1114 } 1115 1116 // VisitCreateLinkRequest 1117 status_t 1118 ClientConnection::VisitCreateLinkRequest(CreateLinkRequest* request) 1119 { 1120 ConnectionReference connectionReference(this); 1121 if (!connectionReference.IsValid()) 1122 return B_OK; 1123 1124 // get the volume 1125 status_t result = B_OK; 1126 ClientVolume* volume = _GetVolume(request->volumeID); 1127 if (!volume) 1128 result = B_BAD_VALUE; 1129 ClientVolumePutter volumePutter(this, volume); 1130 1131 VolumeManagerLocker managerLocker; 1132 1133 // get the target node 1134 Node* node = NULL; 1135 if (result == B_OK) { 1136 node = volume->GetNode(request->nodeID); 1137 if (!node) 1138 result = B_ENTRY_NOT_FOUND; 1139 } 1140 1141 // get the target node path 1142 Path targetPath; 1143 if (result == B_OK) 1144 result = node->GetPath(&targetPath); 1145 1146 // get the directory 1147 Directory* directory = NULL; 1148 if (result == B_OK) { 1149 Node* node = volume->GetNode(request->directoryID); 1150 if (node) { 1151 directory = dynamic_cast<Directory*>(node); 1152 if (!directory) 1153 result = B_NOT_A_DIRECTORY; 1154 } else 1155 result = B_ENTRY_NOT_FOUND; 1156 } 1157 1158 // check permissions 1159 if (result == B_OK) { 1160 if (!volume->GetNodePermissions(directory).ImpliesWritePermission()) 1161 result = B_PERMISSION_DENIED; 1162 } 1163 1164 // get the new entry's path 1165 Path path; 1166 if (result == B_OK) { 1167 result = directory->GetPath(&path); 1168 if (result == B_OK) 1169 result = path.Append(request->name.GetString()); 1170 } 1171 1172 managerLocker.Unlock(); 1173 1174 // create the link 1175 if (result == B_OK) { 1176 if (link(targetPath.GetPath(), path.GetPath()) < 0) 1177 result = errno; 1178 } 1179 1180 // prepare the reply 1181 CreateSymlinkReply reply; 1182 // send the reply 1183 reply.error = result; 1184 return GetChannel()->SendRequest(&reply); 1185 } 1186 1187 // VisitUnlinkRequest 1188 status_t 1189 ClientConnection::VisitUnlinkRequest(UnlinkRequest* request) 1190 { 1191 ConnectionReference connectionReference(this); 1192 if (!connectionReference.IsValid()) 1193 return B_OK; 1194 1195 // get the volume 1196 status_t result = B_OK; 1197 ClientVolume* volume = _GetVolume(request->volumeID); 1198 if (!volume) 1199 result = B_BAD_VALUE; 1200 ClientVolumePutter volumePutter(this, volume); 1201 1202 VolumeManagerLocker managerLocker; 1203 1204 // get the directory 1205 Directory* directory = NULL; 1206 if (result == B_OK) { 1207 Node* node = volume->GetNode(request->directoryID); 1208 if (node) { 1209 directory = dynamic_cast<Directory*>(node); 1210 if (!directory) 1211 result = B_NOT_A_DIRECTORY; 1212 } else 1213 result = B_ENTRY_NOT_FOUND; 1214 } 1215 1216 // check permissions 1217 if (result == B_OK) { 1218 if (!volume->GetNodePermissions(directory).ImpliesWritePermission()) 1219 result = B_PERMISSION_DENIED; 1220 } 1221 1222 // get the entry's path 1223 Path path; 1224 if (result == B_OK) { 1225 result = directory->GetPath(&path); 1226 if (result == B_OK) 1227 result = path.Append(request->name.GetString()); 1228 } 1229 1230 managerLocker.Unlock(); 1231 1232 // remove the entry 1233 if (result == B_OK) { 1234 if (unlink(path.GetPath()) < 0) 1235 result = errno; 1236 } 1237 1238 // prepare the reply 1239 UnlinkReply reply; 1240 // send the reply 1241 reply.error = result; 1242 return GetChannel()->SendRequest(&reply); 1243 } 1244 1245 // VisitCreateSymlinkRequest 1246 status_t 1247 ClientConnection::VisitCreateSymlinkRequest(CreateSymlinkRequest* request) 1248 { 1249 ConnectionReference connectionReference(this); 1250 if (!connectionReference.IsValid()) 1251 return B_OK; 1252 1253 // get the volume 1254 status_t result = B_OK; 1255 ClientVolume* volume = _GetVolume(request->volumeID); 1256 if (!volume) 1257 result = B_BAD_VALUE; 1258 ClientVolumePutter volumePutter(this, volume); 1259 1260 VolumeManagerLocker managerLocker; 1261 1262 // get the directory 1263 Directory* directory = NULL; 1264 if (result == B_OK) { 1265 Node* node = volume->GetNode(request->directoryID); 1266 if (node) { 1267 directory = dynamic_cast<Directory*>(node); 1268 if (!directory) 1269 result = B_NOT_A_DIRECTORY; 1270 } else 1271 result = B_ENTRY_NOT_FOUND; 1272 } 1273 1274 // check permissions 1275 if (result == B_OK) { 1276 if (!volume->GetNodePermissions(directory).ImpliesWritePermission()) 1277 result = B_PERMISSION_DENIED; 1278 } 1279 1280 // get the new entry's path 1281 Path path; 1282 if (result == B_OK) { 1283 result = directory->GetPath(&path); 1284 if (result == B_OK) 1285 result = path.Append(request->name.GetString()); 1286 } 1287 1288 managerLocker.Unlock(); 1289 1290 // create the symlink 1291 if (result == B_OK) { 1292 if (symlink(request->target.GetString(), path.GetPath()) < 0) 1293 result = errno; 1294 } 1295 1296 // prepare the reply 1297 CreateSymlinkReply reply; 1298 // send the reply 1299 reply.error = result; 1300 return GetChannel()->SendRequest(&reply); 1301 } 1302 1303 // VisitReadLinkRequest 1304 status_t 1305 ClientConnection::VisitReadLinkRequest(ReadLinkRequest* request) 1306 { 1307 ConnectionReference connectionReference(this); 1308 if (!connectionReference.IsValid()) 1309 return B_OK; 1310 1311 // get the volume 1312 status_t result = B_OK; 1313 ClientVolume* volume = _GetVolume(request->volumeID); 1314 if (!volume) 1315 result = B_BAD_VALUE; 1316 ClientVolumePutter volumePutter(this, volume); 1317 1318 VolumeManagerLocker managerLocker; 1319 1320 // get the node 1321 Node* node = NULL; 1322 if (result == B_OK) { 1323 node = volume->GetNode(request->nodeID); 1324 if (!node) 1325 result = B_ENTRY_NOT_FOUND; 1326 } 1327 1328 int32 bufferSize = request->maxSize; 1329 1330 // check read permission 1331 if (result == B_OK) { 1332 if (!volume->GetNodePermissions(node).ImpliesReadPermission()) 1333 result = B_PERMISSION_DENIED; 1334 } 1335 1336 // allocate a buffer 1337 void* buffer = NULL; 1338 if (result == B_OK) { 1339 if (bufferSize < 0 || bufferSize > kMaxSaneReadLinkSize) 1340 result = B_BAD_DATA; 1341 } 1342 if (result == B_OK) { 1343 buffer = malloc(bufferSize); 1344 if (!buffer) 1345 result = B_NO_MEMORY; 1346 } 1347 MemoryDeleter bufferDeleter(buffer); 1348 1349 // read the link and prepare the reply 1350 ReadLinkReply reply; 1351 int32 bytesRead = 0; 1352 if (result == B_OK) 1353 result = node->ReadSymlink((char*)buffer, bufferSize, &bytesRead); 1354 if (result == B_OK) { 1355 reply.data.SetTo(buffer, bytesRead); 1356 _GetNodeInfo(node, &reply.nodeInfo); 1357 } 1358 1359 managerLocker.Unlock(); 1360 1361 // send the reply 1362 reply.error = result; 1363 return GetChannel()->SendRequest(&reply); 1364 } 1365 1366 // VisitRenameRequest 1367 status_t 1368 ClientConnection::VisitRenameRequest(RenameRequest* request) 1369 { 1370 ConnectionReference connectionReference(this); 1371 if (!connectionReference.IsValid()) 1372 return B_OK; 1373 1374 // get the volume 1375 status_t result = B_OK; 1376 ClientVolume* volume = _GetVolume(request->volumeID); 1377 if (!volume) 1378 result = B_BAD_VALUE; 1379 ClientVolumePutter volumePutter(this, volume); 1380 1381 VolumeManagerLocker managerLocker; 1382 1383 // get the new directory 1384 Directory* newDirectory = NULL; 1385 if (result == B_OK) { 1386 Node* node = volume->GetNode(request->newDirectoryID); 1387 if (node) { 1388 newDirectory = dynamic_cast<Directory*>(node); 1389 if (!newDirectory) 1390 result = B_NOT_A_DIRECTORY; 1391 } else 1392 result = B_ENTRY_NOT_FOUND; 1393 } 1394 1395 // check permissions 1396 if (result == B_OK) { 1397 if (!volume->GetNodePermissions(newDirectory).ImpliesWritePermission()) 1398 result = B_PERMISSION_DENIED; 1399 } 1400 1401 // get the new path 1402 Path newPath; 1403 if (result == B_OK) { 1404 result = newDirectory->GetPath(&newPath); 1405 if (result == B_OK) 1406 result = newPath.Append(request->newName.GetString()); 1407 } 1408 1409 // get the old directory 1410 Directory* oldDirectory = NULL; 1411 if (result == B_OK) { 1412 Node* node = volume->GetNode(request->oldDirectoryID); 1413 if (node) { 1414 oldDirectory = dynamic_cast<Directory*>(node); 1415 if (!oldDirectory) 1416 result = B_NOT_A_DIRECTORY; 1417 } else 1418 result = B_ENTRY_NOT_FOUND; 1419 } 1420 1421 // check permissions 1422 if (result == B_OK) { 1423 if (!volume->GetNodePermissions(oldDirectory).ImpliesWritePermission()) 1424 result = B_PERMISSION_DENIED; 1425 } 1426 1427 // get the new path 1428 Path oldPath; 1429 if (result == B_OK) { 1430 result = oldDirectory->GetPath(&oldPath); 1431 if (result == B_OK) 1432 result = oldPath.Append(request->oldName.GetString()); 1433 } 1434 1435 managerLocker.Unlock(); 1436 1437 // rename the entry 1438 if (result == B_OK) { 1439 if (rename(oldPath.GetPath(), newPath.GetPath()) < 0) 1440 result = errno; 1441 } 1442 1443 // prepare the reply 1444 RenameReply reply; 1445 // send the reply 1446 reply.error = result; 1447 return GetChannel()->SendRequest(&reply); 1448 } 1449 1450 // VisitMakeDirRequest 1451 status_t 1452 ClientConnection::VisitMakeDirRequest(MakeDirRequest* request) 1453 { 1454 ConnectionReference connectionReference(this); 1455 if (!connectionReference.IsValid()) 1456 return B_OK; 1457 1458 // get the volume 1459 status_t result = B_OK; 1460 ClientVolume* volume = _GetVolume(request->volumeID); 1461 if (!volume) 1462 result = B_BAD_VALUE; 1463 ClientVolumePutter volumePutter(this, volume); 1464 1465 VolumeManagerLocker managerLocker; 1466 1467 // get the directory 1468 Directory* directory = NULL; 1469 if (result == B_OK) { 1470 Node* node = volume->GetNode(request->directoryID); 1471 if (node) { 1472 directory = dynamic_cast<Directory*>(node); 1473 if (!directory) 1474 result = B_NOT_A_DIRECTORY; 1475 } else 1476 result = B_ENTRY_NOT_FOUND; 1477 } 1478 1479 // check permissions 1480 if (result == B_OK) { 1481 if (!volume->GetNodePermissions(directory).ImpliesWritePermission()) 1482 result = B_PERMISSION_DENIED; 1483 } 1484 1485 // get the path 1486 Path path; 1487 if (result == B_OK) { 1488 result = directory->GetPath(&path); 1489 if (result == B_OK) 1490 result = path.Append(request->name.GetString()); 1491 } 1492 1493 managerLocker.Unlock(); 1494 1495 // create the directory 1496 if (result == B_OK) { 1497 if (mkdir(path.GetPath(), request->mode) < 0) 1498 result = errno; 1499 } 1500 1501 // prepare the reply 1502 MakeDirReply reply; 1503 // send the reply 1504 reply.error = result; 1505 return GetChannel()->SendRequest(&reply); 1506 } 1507 1508 // VisitRemoveDirRequest 1509 status_t 1510 ClientConnection::VisitRemoveDirRequest(RemoveDirRequest* request) 1511 { 1512 ConnectionReference connectionReference(this); 1513 if (!connectionReference.IsValid()) 1514 return B_OK; 1515 1516 // get the volume 1517 status_t result = B_OK; 1518 ClientVolume* volume = _GetVolume(request->volumeID); 1519 if (!volume) 1520 result = B_BAD_VALUE; 1521 ClientVolumePutter volumePutter(this, volume); 1522 1523 VolumeManagerLocker managerLocker; 1524 1525 // get the directory 1526 Directory* directory = NULL; 1527 if (result == B_OK) { 1528 Node* node = volume->GetNode(request->directoryID); 1529 if (node) { 1530 directory = dynamic_cast<Directory*>(node); 1531 if (!directory) 1532 result = B_NOT_A_DIRECTORY; 1533 } else 1534 result = B_ENTRY_NOT_FOUND; 1535 } 1536 1537 // check permissions 1538 if (result == B_OK) { 1539 if (!volume->GetNodePermissions(directory).ImpliesWritePermission()) 1540 result = B_PERMISSION_DENIED; 1541 } 1542 1543 // get the path 1544 Path path; 1545 if (result == B_OK) { 1546 result = directory->GetPath(&path); 1547 if (result == B_OK) 1548 result = path.Append(request->name.GetString()); 1549 } 1550 1551 managerLocker.Unlock(); 1552 1553 // remove the directory 1554 if (result == B_OK) { 1555 if (rmdir(path.GetPath()) < 0) 1556 result = errno; 1557 } 1558 1559 // prepare the reply 1560 RemoveDirReply reply; 1561 // send the reply 1562 reply.error = result; 1563 return GetChannel()->SendRequest(&reply); 1564 } 1565 1566 // VisitOpenDirRequest 1567 status_t 1568 ClientConnection::VisitOpenDirRequest(OpenDirRequest* request) 1569 { 1570 ConnectionReference connectionReference(this); 1571 if (!connectionReference.IsValid()) 1572 return B_OK; 1573 1574 // get the volume 1575 status_t result = B_OK; 1576 ClientVolume* volume = _GetVolume(request->volumeID); 1577 if (!volume) 1578 result = B_BAD_VALUE; 1579 ClientVolumePutter volumePutter(this, volume); 1580 1581 VolumeManagerLocker managerLocker; 1582 1583 // get the directory 1584 Directory* directory = NULL; 1585 if (result == B_OK) { 1586 Node* node = volume->GetNode(request->nodeID); 1587 if (node) { 1588 directory = dynamic_cast<Directory*>(node); 1589 if (!directory) 1590 result = B_NOT_A_DIRECTORY; 1591 } else 1592 result = B_ENTRY_NOT_FOUND; 1593 } 1594 1595 // check permission 1596 if (result == B_OK) { 1597 if (!volume->GetNodePermissions(directory).ImpliesReadDirPermission()) 1598 result = B_PERMISSION_DENIED; 1599 } 1600 1601 // open the directory 1602 DirIterator* handle = NULL; 1603 if (result == B_OK) 1604 result = volume->OpenDir(directory, &handle); 1605 NodeHandleUnlocker handleUnlocker(volume, handle); 1606 1607 // prepare the reply 1608 OpenDirReply reply; 1609 if (result == B_OK) { 1610 _GetNodeInfo(directory, &reply.nodeInfo); 1611 reply.cookie = handle->GetCookie(); 1612 } 1613 else { 1614 if (directory) 1615 PRINT("OpenDir() failed: client volume: %ld, node: (%ld, %lld)\n", 1616 volume->GetID(), directory->GetVolumeID(), directory->GetID()); 1617 } 1618 1619 managerLocker.Unlock(); 1620 1621 // send the reply 1622 reply.error = result; 1623 status_t error = GetChannel()->SendRequest(&reply); 1624 1625 // close the handle, if a send error occurred 1626 if (error != B_OK && result == B_OK) 1627 volume->Close(handle); 1628 1629 return error; 1630 } 1631 1632 // VisitReadDirRequest 1633 status_t 1634 ClientConnection::VisitReadDirRequest(ReadDirRequest* request) 1635 { 1636 ConnectionReference connectionReference(this); 1637 if (!connectionReference.IsValid()) 1638 return B_OK; 1639 1640 // get the volume 1641 status_t result = B_OK; 1642 ClientVolume* volume = _GetVolume(request->volumeID); 1643 if (!volume) 1644 result = B_BAD_VALUE; 1645 ClientVolumePutter volumePutter(this, volume); 1646 1647 // get the node handle 1648 NodeHandle* handle = NULL; 1649 if (result == B_OK) 1650 result = volume->LockNodeHandle(request->cookie, &handle); 1651 NodeHandleUnlocker handleUnlocker(volume, handle); 1652 1653 // check if it is a directory iterator 1654 DirIterator* iterator = NULL; 1655 if (result == B_OK) { 1656 iterator = dynamic_cast<DirIterator*>(handle); 1657 if (!iterator) 1658 result = B_BAD_VALUE; 1659 } 1660 1661 VolumeManagerLocker managerLocker; 1662 1663 // get the directory 1664 Directory* directory = NULL; 1665 if (result == B_OK) { 1666 Node* node = volume->GetNode(iterator->GetNodeRef()); 1667 if (node) { 1668 directory = dynamic_cast<Directory*>(node); 1669 if (!directory) 1670 result = B_NOT_A_DIRECTORY; 1671 } else 1672 result = B_ENTRY_NOT_FOUND; 1673 } 1674 1675 // check read permission 1676 if (result == B_OK) { 1677 if (!volume->GetNodePermissions(directory).ImpliesReadDirPermission()) 1678 result = B_PERMISSION_DENIED; 1679 } 1680 1681 if (result == B_OK) { 1682 PRINT("ReadDir: (%ld, %lld)\n", request->volumeID, directory->GetID()); 1683 } 1684 1685 // rewind, if requested 1686 if (result == B_OK && request->rewind) 1687 iterator->Rewind(); 1688 1689 // read the directory 1690 bool done = false; 1691 ReadDirReply reply; 1692 int32 toRead = request->count; 1693 while (result == B_OK && toRead > 0) { 1694 // get the next entry 1695 Entry* entry = iterator->NextEntry(); 1696 if (!entry) { 1697 done = true; 1698 break; 1699 } 1700 1701 // get and add an entry info 1702 EntryInfo entryInfo; 1703 _GetEntryInfo(entry, &entryInfo); 1704 result = reply.entryInfos.Append(entryInfo); 1705 1706 toRead--; 1707 } 1708 1709 reply.revision = VolumeManager::GetDefault()->GetRevision(); 1710 1711 //PRINT(("ReadDir: (%lld) -> (%lx, %ld, dir: %lld, node: %lld, `%s')\n", 1712 //directoryID, reply.error, reply.entryInfos.CountElements(), 1713 //reply.entryInfo.directoryID, 1714 //reply.entryInfo.nodeID, reply.entryInfo.name.GetString())); 1715 if (directory) { 1716 PRINT("ReadDir done: volume: %ld, (%ld, %lld) -> (%lx, %ld)\n", 1717 volume->GetID(), directory->GetVolumeID(), directory->GetID(), result, 1718 reply.entryInfos.CountElements()); 1719 } 1720 1721 managerLocker.Unlock(); 1722 1723 // send the reply 1724 reply.error = result; 1725 reply.done = (result != B_OK || done); 1726 return GetChannel()->SendRequest(&reply); 1727 } 1728 1729 // VisitWalkRequest 1730 status_t 1731 ClientConnection::VisitWalkRequest(WalkRequest* request) 1732 { 1733 ConnectionReference connectionReference(this); 1734 if (!connectionReference.IsValid()) 1735 return B_OK; 1736 1737 // get the volume 1738 status_t result = B_OK; 1739 ClientVolume* volume = _GetVolume(request->volumeID); 1740 if (!volume) 1741 result = B_BAD_VALUE; 1742 ClientVolumePutter volumePutter(this, volume); 1743 1744 VolumeManagerLocker managerLocker; 1745 1746 // get the directory 1747 Directory* directory = NULL; 1748 if (result == B_OK) { 1749 Node* node = volume->GetNode(request->nodeID); 1750 if (node) { 1751 directory = dynamic_cast<Directory*>(node); 1752 if (!directory) 1753 result = B_NOT_A_DIRECTORY; 1754 } else 1755 result = B_ENTRY_NOT_FOUND; 1756 } 1757 1758 // check permission 1759 if (result == B_OK) { 1760 if (!volume->GetNodePermissions(directory) 1761 .ImpliesResolveDirEntryPermission()) { 1762 result = B_PERMISSION_DENIED; 1763 } 1764 } 1765 1766 WalkReply reply; 1767 char linkPath[B_PATH_NAME_LENGTH]; 1768 if (result == B_OK) { 1769 // load the entry 1770 Entry* entry; 1771 result = volume->LoadEntry(directory, request->name.GetString(), 1772 &entry); 1773 1774 // fill in the reply 1775 if (result == B_OK) { 1776 _GetEntryInfo(entry, &reply.entryInfo); 1777 1778 // resolve a symlink, if desired 1779 Node* node = entry->GetNode(); 1780 if (request->resolveLink && node->IsSymlink()) { 1781 result = node->ReadSymlink(linkPath, B_PATH_NAME_LENGTH); 1782 if (result == B_OK) 1783 reply.linkPath.SetTo(linkPath); 1784 } 1785 } 1786 } 1787 1788 managerLocker.Unlock(); 1789 1790 // send the reply 1791 reply.error = result; 1792 PRINT("Walk: (%ld, %lld, `%s') -> (%lx, (%ld, %lld), `%s')\n", 1793 request->nodeID.volumeID, request->nodeID.nodeID, 1794 request->name.GetString(), result, 1795 reply.entryInfo.nodeInfo.st.st_dev, 1796 reply.entryInfo.nodeInfo.st.st_ino, reply.linkPath.GetString()); 1797 return GetChannel()->SendRequest(&reply); 1798 } 1799 1800 // VisitMultiWalkRequest 1801 status_t 1802 ClientConnection::VisitMultiWalkRequest(MultiWalkRequest* request) 1803 { 1804 ConnectionReference connectionReference(this); 1805 if (!connectionReference.IsValid()) 1806 return B_OK; 1807 1808 // get the volume 1809 status_t result = B_OK; 1810 ClientVolume* volume = _GetVolume(request->volumeID); 1811 if (!volume) 1812 result = B_BAD_VALUE; 1813 ClientVolumePutter volumePutter(this, volume); 1814 1815 VolumeManagerLocker managerLocker; 1816 1817 // get the directory 1818 Directory* directory = NULL; 1819 if (result == B_OK) { 1820 Node* node = volume->GetNode(request->nodeID); 1821 if (node) { 1822 directory = dynamic_cast<Directory*>(node); 1823 if (!directory) 1824 result = B_NOT_A_DIRECTORY; 1825 } else 1826 result = B_ENTRY_NOT_FOUND; 1827 } 1828 1829 // check permission 1830 if (result == B_OK) { 1831 if (!volume->GetNodePermissions(directory) 1832 .ImpliesResolveDirEntryPermission()) { 1833 result = B_PERMISSION_DENIED; 1834 } 1835 } 1836 1837 MultiWalkReply reply; 1838 StringData* names = request->names.GetElements(); 1839 int32 count = request->names.CountElements(); 1840 for (int32 i = 0; result == B_OK && i < count; i++) { 1841 // load the entry 1842 Entry* entry; 1843 if (volume->LoadEntry(directory, names[i].GetString(), &entry) 1844 == B_OK) { 1845 // add an entry info 1846 EntryInfo entryInfo; 1847 _GetEntryInfo(entry, &entryInfo); 1848 1849 // append the info 1850 result = reply.entryInfos.Append(entryInfo); 1851 } 1852 } 1853 1854 managerLocker.Unlock(); 1855 1856 // send the reply 1857 reply.error = result; 1858 PRINT("MultiWalk: (%ld, %lld, %ld) -> (%lx, %ld)\n", 1859 request->nodeID.volumeID, request->nodeID.nodeID, count, 1860 result, reply.entryInfos.CountElements()); 1861 return GetChannel()->SendRequest(&reply); 1862 } 1863 1864 // VisitOpenAttrDirRequest 1865 status_t 1866 ClientConnection::VisitOpenAttrDirRequest(OpenAttrDirRequest* request) 1867 { 1868 ConnectionReference connectionReference(this); 1869 if (!connectionReference.IsValid()) 1870 return B_OK; 1871 1872 // get the volume 1873 status_t result = B_OK; 1874 ClientVolume* volume = _GetVolume(request->volumeID); 1875 if (!volume) 1876 result = B_BAD_VALUE; 1877 ClientVolumePutter volumePutter(this, volume); 1878 1879 VolumeManagerLocker managerLocker; 1880 1881 // get the node 1882 Node* node = NULL; 1883 if (result == B_OK) { 1884 node = volume->GetNode(request->nodeID); 1885 if (!node) 1886 result = B_ENTRY_NOT_FOUND; 1887 } 1888 1889 // check permission 1890 if (result == B_OK) { 1891 if (!volume->GetNodePermissions(node).ImpliesReadPermission()) 1892 result = B_PERMISSION_DENIED; 1893 } 1894 1895 // load/cache the attribute directory 1896 bool attrDirCached = (node->LoadAttrDir() == B_OK); 1897 1898 // open the attribute directory, if caching it failed 1899 AttrDirIterator* handle = NULL; 1900 if (result == B_OK && !attrDirCached) 1901 result = volume->OpenAttrDir(node, &handle); 1902 NodeHandleUnlocker handleUnlocker(volume, handle); 1903 1904 // prepare the reply 1905 OpenAttrDirReply reply; 1906 if (result == B_OK) { 1907 if (handle) { 1908 reply.cookie = handle->GetCookie(); 1909 } else { 1910 // the attribute directory is cached 1911 reply.cookie = -1; 1912 result = _GetAttrDirInfo(request, node, &reply.attrDirInfo); 1913 } 1914 } 1915 1916 managerLocker.Unlock(); 1917 1918 // send the reply 1919 reply.error = result; 1920 status_t error = GetChannel()->SendRequest(&reply); 1921 1922 // close the handle, if a send error occurred 1923 if (error != B_OK && result == B_OK && handle) 1924 volume->Close(handle); 1925 1926 return error; 1927 } 1928 1929 // VisitReadAttrDirRequest 1930 status_t 1931 ClientConnection::VisitReadAttrDirRequest(ReadAttrDirRequest* request) 1932 { 1933 ConnectionReference connectionReference(this); 1934 if (!connectionReference.IsValid()) 1935 return B_OK; 1936 1937 // get the volume 1938 status_t result = B_OK; 1939 ClientVolume* volume = _GetVolume(request->volumeID); 1940 if (!volume) 1941 result = B_BAD_VALUE; 1942 ClientVolumePutter volumePutter(this, volume); 1943 1944 // get the node handle 1945 NodeHandle* handle = NULL; 1946 if (result == B_OK) 1947 result = volume->LockNodeHandle(request->cookie, &handle); 1948 NodeHandleUnlocker handleUnlocker(volume, handle); 1949 1950 // check if it is a attribute directory iterator 1951 AttrDirIterator* iterator = NULL; 1952 if (result == B_OK) { 1953 iterator = dynamic_cast<AttrDirIterator*>(handle); 1954 if (!iterator) 1955 result = B_BAD_VALUE; 1956 } 1957 1958 VolumeManagerLocker managerLocker; 1959 1960 // get the node 1961 Node* node = NULL; 1962 if (result == B_OK) { 1963 node = volume->GetNode(iterator->GetNodeRef()); 1964 if (!node) 1965 result = B_ENTRY_NOT_FOUND; 1966 } 1967 1968 // check read permission (we already checked when opening, but anyway...) 1969 if (result == B_OK) { 1970 if (!volume->GetNodePermissions(node).ImpliesReadPermission()) 1971 result = B_PERMISSION_DENIED; 1972 } 1973 1974 managerLocker.Unlock(); 1975 1976 // read the attribute directory 1977 uint8 buffer[sizeof(struct dirent) + B_FILE_NAME_LENGTH]; 1978 struct dirent* dirEntry = (struct dirent*)buffer; 1979 int32 countRead = 0; 1980 bool done = true; 1981 if (result == B_OK) { 1982 if (request->rewind) 1983 result = iterator->RewindDir(); 1984 if (result == B_OK) { 1985 result = iterator->ReadDir(dirEntry, sizeof(buffer), 1, 1986 &countRead, &done); 1987 } 1988 } 1989 1990 // prepare the reply 1991 ReadAttrDirReply reply; 1992 reply.name.SetTo(dirEntry->d_name); 1993 1994 // send the reply 1995 reply.error = result; 1996 reply.count = countRead; 1997 return GetChannel()->SendRequest(&reply); 1998 } 1999 2000 // VisitReadAttrRequest 2001 status_t 2002 ClientConnection::VisitReadAttrRequest(ReadAttrRequest* request) 2003 { 2004 ConnectionReference connectionReference(this); 2005 if (!connectionReference.IsValid()) 2006 return B_OK; 2007 2008 // get the volume 2009 status_t result = B_OK; 2010 ClientVolume* volume = _GetVolume(request->volumeID); 2011 if (!volume) 2012 result = B_BAD_VALUE; 2013 ClientVolumePutter volumePutter(this, volume); 2014 2015 VolumeManagerLocker managerLocker; 2016 2017 // get the node 2018 Node* node = NULL; 2019 if (result == B_OK) { 2020 node = volume->GetNode(request->nodeID); 2021 if (!node) 2022 result = B_ENTRY_NOT_FOUND; 2023 } 2024 2025 // check read permission 2026 if (result == B_OK) { 2027 if (!volume->GetNodePermissions(node).ImpliesReadPermission()) 2028 result = B_PERMISSION_DENIED; 2029 } 2030 2031 // open the node 2032 FileHandle* handle = NULL; 2033 if (result == B_OK) 2034 result = volume->Open(node, O_RDONLY, &handle); 2035 NodeHandleUnlocker handleUnlocker(volume, handle); 2036 2037 managerLocker.Unlock(); 2038 2039 // read the attribute 2040 if (result == B_OK) { 2041 // Due to a bug in BFS the `pos' is ignored. This means that the loop 2042 // below won't work if the attribute is non-empty and the buffer is 2043 // larger than the attribute, because the we would again and again 2044 // read the beginning of the attribute until the buffer is full. 2045 // Hence we first get an attr_info and don't try to read more than 2046 // the size of the attribute. 2047 attr_info info; 2048 result = handle->StatAttr(request->name.GetString(), &info); 2049 off_t originalPos = max(request->pos, 0LL); 2050 int32 originalSize = max(request->size, 0L); 2051 off_t pos = originalPos; 2052 int32 size = originalSize; 2053 type_code type = B_SWAP_INT32(request->type); 2054 bool convert = false; 2055 2056 if (result == B_OK) { 2057 originalSize = min((off_t)originalSize, max(0LL, info.size - pos)); 2058 size = originalSize; 2059 2060 // deal with inverse endianess clients 2061 if (fInverseClientEndianess) { 2062 convert = _KnownAttributeType(info.type); 2063 if (convert) { 2064 // read the whole attribute 2065 pos = 0; 2066 size = info.size; 2067 } else 2068 type = B_SWAP_INT32(request->type); 2069 } 2070 } 2071 int32 bufferSize = min(size, kMaxReadBufferSize); 2072 2073 // allocate a buffer 2074 uint8* buffer = NULL; 2075 if (result == B_OK) { 2076 buffer = (uint8*)malloc(bufferSize); 2077 if (!buffer) 2078 result = B_NO_MEMORY; 2079 } 2080 MemoryDeleter bufferDeleter(buffer); 2081 2082 if (convert) { 2083 // read the whole attribute and convert it 2084 if (result == B_OK) { 2085 // read 2086 size_t bytesRead = 0; 2087 result = handle->ReadAttr(request->name.GetString(), 2088 type, 0, buffer, size, &bytesRead); 2089 if (result == B_OK && (int32)bytesRead != size) 2090 result = B_ERROR; 2091 2092 // convert 2093 if (result == B_OK) 2094 _ConvertAttribute(info, buffer); 2095 } 2096 2097 // prepare the reply 2098 ReadAttrReply reply; 2099 if (result == B_OK) { 2100 reply.pos = originalPos; 2101 reply.data.SetTo(buffer + originalPos, originalSize); 2102 reply.moreToCome = false; 2103 } 2104 2105 // send the reply 2106 reply.error = result; 2107 status_t error = GetChannel()->SendRequest(&reply); 2108 if (error != B_OK) 2109 return error; 2110 } else { 2111 // read as long as there are bytes left to read or an error occurs 2112 bool moreToRead = true; 2113 do { 2114 int32 bytesToRead = min(size, bufferSize); 2115 size_t bytesRead = 0; 2116 if (result == B_OK) { 2117 result = handle->ReadAttr(request->name.GetString(), 2118 request->type, pos, buffer, bytesToRead, &bytesRead); 2119 } 2120 moreToRead = (result == B_OK && bytesRead > 0 2121 && (int32)bytesRead < size); 2122 2123 // prepare the reply 2124 ReadAttrReply reply; 2125 if (result == B_OK) { 2126 reply.pos = pos; 2127 reply.data.SetTo(buffer, bytesRead); 2128 reply.moreToCome = moreToRead; 2129 pos += bytesRead; 2130 size -= bytesRead; 2131 } 2132 2133 // send the reply 2134 reply.error = result; 2135 status_t error = GetChannel()->SendRequest(&reply); 2136 if (error != B_OK) 2137 return error; 2138 } while (moreToRead); 2139 } 2140 2141 // close the handle 2142 volume->Close(handle); 2143 } else { 2144 // opening the node failed (or something even earlier): send an error 2145 // reply 2146 ReadAttrReply reply; 2147 reply.error = result; 2148 status_t error = GetChannel()->SendRequest(&reply); 2149 if (error != B_OK) 2150 return error; 2151 } 2152 2153 return B_OK; 2154 } 2155 2156 // VisitWriteAttrRequest 2157 status_t 2158 ClientConnection::VisitWriteAttrRequest(WriteAttrRequest* request) 2159 { 2160 ConnectionReference connectionReference(this); 2161 if (!connectionReference.IsValid()) 2162 return B_OK; 2163 2164 // get the volume 2165 status_t result = B_OK; 2166 ClientVolume* volume = _GetVolume(request->volumeID); 2167 if (!volume) 2168 result = B_BAD_VALUE; 2169 ClientVolumePutter volumePutter(this, volume); 2170 2171 VolumeManagerLocker managerLocker; 2172 2173 // get the node 2174 Node* node = NULL; 2175 if (result == B_OK) { 2176 node = volume->GetNode(request->nodeID); 2177 if (!node) 2178 result = B_ENTRY_NOT_FOUND; 2179 } 2180 2181 // check read permission 2182 if (result == B_OK) { 2183 if (!volume->GetNodePermissions(node).ImpliesWritePermission()) 2184 result = B_PERMISSION_DENIED; 2185 } 2186 2187 // open the node 2188 FileHandle* handle = NULL; 2189 if (result == B_OK) 2190 result = volume->Open(node, O_RDWR, &handle); 2191 NodeHandleUnlocker handleUnlocker(volume, handle); 2192 2193 managerLocker.Unlock(); 2194 2195 if (result == B_OK) { 2196 off_t pos = max(request->pos, 0LL); 2197 int32 size = request->data.GetSize(); 2198 type_code type = request->type; 2199 char* buffer = (char*)request->data.GetData(); 2200 2201 // convert the data, if necessary 2202 if (fInverseClientEndianess) { 2203 if (_KnownAttributeType(type)) { 2204 if (pos != 0) { 2205 WARN("WriteAttr(): WARNING: Need to convert attribute " 2206 "endianess, but position is not 0: attribute: %s, " 2207 "pos: %lld, size: %ld\n", request->name.GetString(), 2208 pos, size); 2209 } 2210 swap_data(type, buffer, size, B_SWAP_ALWAYS); 2211 } else 2212 type = B_SWAP_INT32(type); 2213 } 2214 2215 // write the data 2216 while (result == B_OK && size > 0) { 2217 size_t bytesWritten; 2218 result = handle->WriteAttr(request->name.GetString(), 2219 type, pos, buffer, size, &bytesWritten); 2220 if (result == B_OK) { 2221 pos += bytesWritten; 2222 buffer += bytesWritten; 2223 size -= bytesWritten; 2224 } 2225 } 2226 2227 // close the handle 2228 volume->Close(handle); 2229 } 2230 2231 // prepare the reply 2232 WriteAttrReply reply; 2233 // send the reply 2234 reply.error = result; 2235 return GetChannel()->SendRequest(&reply); 2236 } 2237 2238 // VisitRemoveAttrRequest 2239 status_t 2240 ClientConnection::VisitRemoveAttrRequest(RemoveAttrRequest* request) 2241 { 2242 ConnectionReference connectionReference(this); 2243 if (!connectionReference.IsValid()) 2244 return B_OK; 2245 2246 // get the volume 2247 status_t result = B_OK; 2248 ClientVolume* volume = _GetVolume(request->volumeID); 2249 if (!volume) 2250 result = B_BAD_VALUE; 2251 ClientVolumePutter volumePutter(this, volume); 2252 2253 VolumeManagerLocker managerLocker; 2254 2255 // get the node 2256 Node* node = NULL; 2257 if (result == B_OK) { 2258 node = volume->GetNode(request->nodeID); 2259 if (!node) 2260 result = B_ENTRY_NOT_FOUND; 2261 } 2262 2263 // check read permission 2264 if (result == B_OK) { 2265 if (!volume->GetNodePermissions(node).ImpliesWritePermission()) 2266 result = B_PERMISSION_DENIED; 2267 } 2268 2269 // open the node 2270 FileHandle* handle = NULL; 2271 if (result == B_OK) 2272 result = volume->Open(node, O_RDWR, &handle); 2273 NodeHandleUnlocker handleUnlocker(volume, handle); 2274 2275 managerLocker.Unlock(); 2276 2277 // remove the attribute and close the node 2278 if (result == B_OK) { 2279 result = handle->RemoveAttr(request->name.GetString()); 2280 volume->Close(handle); 2281 } 2282 2283 // send the reply 2284 RemoveAttrReply reply; 2285 reply.error = result; 2286 return GetChannel()->SendRequest(&reply); 2287 } 2288 2289 // VisitRenameAttrRequest 2290 status_t 2291 ClientConnection::VisitRenameAttrRequest(RenameAttrRequest* request) 2292 { 2293 // Not supported, since there's no API function to rename an attribute. 2294 // send the reply 2295 RemoveAttrReply reply; 2296 reply.error = B_UNSUPPORTED; 2297 return GetChannel()->SendRequest(&reply); 2298 } 2299 2300 // VisitStatAttrRequest 2301 status_t 2302 ClientConnection::VisitStatAttrRequest(StatAttrRequest* request) 2303 { 2304 ConnectionReference connectionReference(this); 2305 if (!connectionReference.IsValid()) 2306 return B_OK; 2307 2308 // get the volume 2309 status_t result = B_OK; 2310 ClientVolume* volume = _GetVolume(request->volumeID); 2311 if (!volume) 2312 result = B_BAD_VALUE; 2313 ClientVolumePutter volumePutter(this, volume); 2314 2315 VolumeManagerLocker managerLocker; 2316 2317 // get the node 2318 Node* node = NULL; 2319 if (result == B_OK) { 2320 node = volume->GetNode(request->nodeID); 2321 if (!node) 2322 result = B_ENTRY_NOT_FOUND; 2323 } 2324 2325 // check read permission 2326 if (result == B_OK) { 2327 if (!volume->GetNodePermissions(node).ImpliesReadPermission()) 2328 result = B_PERMISSION_DENIED; 2329 } 2330 2331 // open the node 2332 FileHandle* handle = NULL; 2333 if (result == B_OK) 2334 result = volume->Open(node, O_RDONLY, &handle); 2335 NodeHandleUnlocker handleUnlocker(volume, handle); 2336 2337 managerLocker.Unlock(); 2338 2339 // stat the attribute and close the node 2340 attr_info attrInfo; 2341 StatAttrReply reply; 2342 if (result == B_OK) { 2343 result = handle->StatAttr(request->name.GetString(), &attrInfo); 2344 volume->Close(handle); 2345 } 2346 2347 // set the attribute info 2348 if (result == B_OK) { 2349 result = _GetAttrInfo(request, request->name.GetString(), attrInfo, 2350 NULL, &reply.attrInfo); 2351 } 2352 2353 // send the reply 2354 reply.error = result; 2355 return GetChannel()->SendRequest(&reply); 2356 } 2357 2358 // VisitOpenQueryRequest 2359 status_t 2360 ClientConnection::VisitOpenQueryRequest(OpenQueryRequest* request) 2361 { 2362 ConnectionReference connectionReference(this); 2363 if (!connectionReference.IsValid()) 2364 return B_OK; 2365 2366 VolumeManagerLocker managerLocker; 2367 2368 // open the query 2369 status_t result = B_OK; 2370 QueryHandle* handle = NULL; 2371 if (result == B_OK) { 2372 result = _OpenQuery(request->queryString.GetString(), 2373 request->flags, request->port, request->token, &handle); 2374 } 2375 QueryHandleUnlocker handleUnlocker(this, handle); 2376 2377 // prepare the reply 2378 OpenQueryReply reply; 2379 if (result == B_OK) 2380 reply.cookie = handle->GetCookie(); 2381 2382 managerLocker.Unlock(); 2383 2384 // send the reply 2385 reply.error = result; 2386 status_t error = GetChannel()->SendRequest(&reply); 2387 2388 // close the handle, if a send error occurred 2389 if (error != B_OK && result == B_OK) 2390 _CloseQuery(handle); 2391 2392 return error; 2393 } 2394 2395 // VisitReadQueryRequest 2396 status_t 2397 ClientConnection::VisitReadQueryRequest(ReadQueryRequest* request) 2398 { 2399 ConnectionReference connectionReference(this); 2400 if (!connectionReference.IsValid()) 2401 return B_OK; 2402 2403 // create an array for the IDs of the client volumes a found entry may 2404 // reside on 2405 status_t result = B_OK; 2406 int32 volumeCount = fVolumes->Size(); 2407 int32* volumeIDs = new(std::nothrow) int32[volumeCount]; 2408 if (!volumeIDs) 2409 result = B_NO_MEMORY; 2410 ArrayDeleter<int32> volumeIDsDeleter(volumeIDs); 2411 2412 // get the query handle 2413 QueryHandle* handle = NULL; 2414 if (result == B_OK) 2415 result = _LockQueryHandle(request->cookie, &handle); 2416 QueryHandleUnlocker handleUnlocker(this, handle); 2417 2418 // check if it is a query handle 2419 QueryHandle* queryHandle = NULL; 2420 if (result == B_OK) { 2421 queryHandle = dynamic_cast<QueryHandle*>(handle); 2422 if (!queryHandle) 2423 result = B_BAD_VALUE; 2424 } 2425 2426 // read the query 2427 ReadQueryReply reply; 2428 int32 countRead = 0; 2429 while (result == B_OK) { 2430 uint8 buffer[sizeof(struct dirent) + B_FILE_NAME_LENGTH]; 2431 struct dirent* dirEntry = (struct dirent*)buffer; 2432 2433 result = queryHandle->ReadDir(dirEntry, 1, &countRead); 2434 if (result != B_OK) 2435 break; 2436 if (countRead == 0) 2437 break; 2438 PRINT(" query entry: %ld, %lld, \"%s\"\n", 2439 dirEntry->d_pdev, dirEntry->d_pino, dirEntry->d_name); 2440 2441 VolumeManagerLocker managerLocker; 2442 VolumeManager* volumeManager = VolumeManager::GetDefault(); 2443 2444 // load the entry 2445 Entry* entry = NULL; 2446 result = volumeManager->LoadEntry(dirEntry->d_pdev, 2447 dirEntry->d_pino, dirEntry->d_name, true, &entry); 2448 2449 // if at least one client volume contains the entry, get an entry info 2450 if (result == B_OK) { 2451 HasQueryPermissionClientVolumeFilter filter; 2452 int32 entryVolumeCount = _GetContainingClientVolumes( 2453 entry->GetDirectory(), volumeIDs, volumeCount, &filter); 2454 if (entryVolumeCount > 0) { 2455 // store all the client volume IDs in the reply 2456 for (int32 i = 0; i < entryVolumeCount; i++) { 2457 result = reply.clientVolumeIDs.Append(volumeIDs[i]); 2458 if (result != B_OK) 2459 break; 2460 } 2461 2462 // get an entry info 2463 _GetNodeInfo(entry->GetDirectory(), &reply.dirInfo); 2464 _GetEntryInfo(entry, &reply.entryInfo); 2465 break; 2466 } 2467 else 2468 PRINT((" -> no client volumes\n")); 2469 } 2470 2471 // entry is not in the volume: next round... 2472 result = B_OK; 2473 } 2474 2475 // send the reply 2476 reply.error = result; 2477 reply.count = countRead; 2478 PRINT("ReadQuery: (%lx, %ld, dir: (%ld, %lld), node: (%ld, %lld, `%s')" 2479 "\n", reply.error, reply.count, 2480 reply.entryInfo.directoryID.volumeID, 2481 reply.entryInfo.directoryID.nodeID, 2482 reply.entryInfo.nodeInfo.st.st_dev, 2483 reply.entryInfo.nodeInfo.st.st_ino, 2484 reply.entryInfo.name.GetString()); 2485 return GetChannel()->SendRequest(&reply); 2486 } 2487 2488 2489 // #pragma mark - 2490 2491 // ProcessNodeMonitoringEvent 2492 void 2493 ClientConnection::ProcessNodeMonitoringEvent(int32 volumeID, 2494 NodeMonitoringEvent* event) 2495 { 2496 // get a connection reference 2497 ConnectionReference connectionReference(this); 2498 if (!connectionReference.IsValid()) 2499 return; 2500 2501 _PushNodeMonitoringEvent(volumeID, event); 2502 } 2503 2504 // CloseNodeMonitoringEventQueue 2505 void 2506 ClientConnection::CloseNodeMonitoringEventQueue() 2507 { 2508 typedef Vector<NodeMonitoringRequest*> RequestVector; 2509 const RequestVector* requests = NULL; 2510 if (fNodeMonitoringEvents->Close(false, &requests) == B_OK) { 2511 for (RequestVector::ConstIterator it = requests->Begin(); 2512 it != requests->End(); 2513 it++) { 2514 delete *it; 2515 } 2516 } 2517 } 2518 2519 2520 // #pragma mark - 2521 2522 // QueryDomainIntersectsWith 2523 bool 2524 ClientConnection::QueryDomainIntersectsWith(Volume* volume) 2525 { 2526 // Iterate through the the client volumes and check whether any one contains 2527 // the supplied volume or its root dir is on the volume. We don't check 2528 // directory inclusion for the latter, since we don't need to query the 2529 // volume, if the client volume is located on a volume mounted somewhere 2530 // under the supplied volume (e.g. the root FS contains everything, but does 2531 // seldomly need to be queried). 2532 VolumeManager* volumeManager = VolumeManager::GetDefault(); 2533 AutoLocker<VolumeMap> volumesLocker(fVolumes); 2534 for (VolumeMap::Iterator it = fVolumes->GetIterator(); it.HasNext();) { 2535 ClientVolume* clientVolume = it.Next().value; 2536 Directory* volumeRoot = volume->GetRootDirectory(); 2537 Directory* clientVolumeRoot = clientVolume->GetRootDirectory(); 2538 if (volumeManager->DirectoryContains(clientVolumeRoot, volumeRoot, true) 2539 || volumeRoot->GetVolumeID() == clientVolumeRoot->GetVolumeID()) { 2540 return true; 2541 } 2542 } 2543 2544 return false; 2545 } 2546 2547 // ProcessQueryEvent 2548 void 2549 ClientConnection::ProcessQueryEvent(NodeMonitoringEvent* event) 2550 { 2551 dev_t volumeID; 2552 ino_t directoryID; 2553 if (event->opcode == B_ENTRY_CREATED) { 2554 // "entry created" event 2555 EntryCreatedEvent* createdEvent 2556 = dynamic_cast<EntryCreatedEvent*>(event); 2557 if (!createdEvent) 2558 return; 2559 volumeID = createdEvent->volumeID; 2560 directoryID = createdEvent->directoryID; 2561 2562 } else if (event->opcode == B_ENTRY_REMOVED) { 2563 // "entry removed" event 2564 EntryRemovedEvent* removedEvent 2565 = dynamic_cast<EntryRemovedEvent*>(event); 2566 if (!removedEvent) 2567 return; 2568 volumeID = removedEvent->volumeID; 2569 directoryID = removedEvent->directoryID; 2570 2571 } else { 2572 // We only support "entry created" and "entry removed" query events. 2573 // "entry moved" is split by the volume manager into those. 2574 ERROR("Ignoring unexpected query event: opcode: 0x%lx\n", 2575 event->opcode); 2576 return; 2577 } 2578 PRINT("ClientConnection::ProcessQueryEvent(): event: %p, type: %s:" 2579 " directory: (%ld, %lld)\n", event, typeid(event).name(), 2580 volumeID, directoryID); 2581 2582 // create an array for the IDs of the client volumes a found entry may 2583 // reside on 2584 status_t result = B_OK; 2585 int32 volumeCount = fVolumes->Size(); 2586 int32* volumeIDs = new(std::nothrow) int32[volumeCount]; 2587 if (!volumeIDs) 2588 result = B_NO_MEMORY; 2589 ArrayDeleter<int32> volumeIDsDeleter(volumeIDs); 2590 2591 HasQueryPermissionClientVolumeFilter filter; 2592 2593 // load the directory the concerned entry belongs/belonged to 2594 Directory* directory; 2595 int32 concernedVolumes = 0; 2596 if (VolumeManager::GetDefault()->LoadDirectory(volumeID, directoryID, 2597 &directory) == B_OK) { 2598 // find out, which client volumes the directory is located in 2599 concernedVolumes = _GetContainingClientVolumes(directory, volumeIDs, 2600 volumeCount, &filter); 2601 } else { 2602 // Failed to load the directory, so maybe it has already been 2603 // deleted. For "entry removed" events, we consider all client 2604 // volumes to be notified -- those that don't know the entry will 2605 // ignore the event. 2606 if (event->opcode == B_ENTRY_REMOVED) { 2607 concernedVolumes = _GetAllClientVolumeIDs(volumeIDs, volumeCount, 2608 &filter); 2609 } 2610 } 2611 2612 // now push the event for each concerned client volume 2613 for (int32 i = 0; i < concernedVolumes; i++) 2614 _PushNodeMonitoringEvent(volumeIDs[i], event); 2615 // TODO: More than one volume will usually only be concerned in case of 2616 // nested client volumes. We could optimize the case by having an array of 2617 // volume IDs in the respective requests sent over the net (just as in the 2618 // ReadQueryReply). 2619 } 2620 2621 2622 // #pragma mark - 2623 2624 // _Close 2625 void 2626 ClientConnection::_Close() 2627 { 2628 // terminate node monitoring processor 2629 CloseNodeMonitoringEventQueue(); 2630 if (fNodeMonitoringProcessor >= 0 2631 && find_thread(NULL) != fNodeMonitoringProcessor) { 2632 int32 result; 2633 wait_for_thread(fNodeMonitoringProcessor, &result); 2634 // The variable is not unset, when this is the node monitoring 2635 // processor thread -- which is good, since the destructor will 2636 // wait for the thread in this case. 2637 fNodeMonitoringProcessor = -1; 2638 } 2639 if (fConnection) 2640 fConnection->Close(); 2641 // notify the listener 2642 ClientConnectionListener* listener = fListener; 2643 fListener = NULL; 2644 if (listener) 2645 listener->ClientConnectionClosed(this, fError); 2646 } 2647 2648 // _MarkClosed 2649 void 2650 ClientConnection::_MarkClosed(bool error) 2651 { 2652 AutoLocker<Locker> _(fLock); 2653 if (!fClosed) { 2654 fClosed = true; 2655 fError = error; 2656 } 2657 } 2658 2659 // _GetNodeInfo 2660 void 2661 ClientConnection::_GetNodeInfo(Node* node, NodeInfo* info) 2662 { 2663 if (node && info) { 2664 info->st = node->GetStat(); 2665 info->revision = VolumeManager::GetDefault()->GetRevision(); 2666 } 2667 } 2668 2669 // _GetEntryInfo 2670 void 2671 ClientConnection::_GetEntryInfo(Entry* entry, EntryInfo* info) 2672 { 2673 if (entry && info) { 2674 info->directoryID.volumeID = entry->GetVolumeID(); 2675 info->directoryID.nodeID = entry->GetDirectoryID(); 2676 info->name.SetTo(entry->GetName()); 2677 _GetNodeInfo(entry->GetNode(), &info->nodeInfo); 2678 } 2679 } 2680 2681 // _GetAttrInfo 2682 status_t 2683 ClientConnection::_GetAttrInfo(Request* request, const char* name, 2684 const attr_info& attrInfo, const void* data, AttributeInfo* info) 2685 { 2686 if (!request || !name || !info) 2687 return B_BAD_VALUE; 2688 2689 info->name.SetTo(name); 2690 info->info = attrInfo; 2691 data = (attrInfo.size > 0 ? data : NULL); 2692 int32 dataSize = (data ? attrInfo.size : 0); 2693 info->data.SetTo(data, dataSize); 2694 2695 // if the client has inverse endianess, swap the type, if we don't know it 2696 if (fInverseClientEndianess) { 2697 if (_KnownAttributeType(info->info.type)) { 2698 // we need to convert the data, if supplied 2699 if (data) { 2700 // allocate a buffer 2701 RequestBuffer* requestBuffer = RequestBuffer::Create(dataSize); 2702 if (!requestBuffer) 2703 return B_NO_MEMORY; 2704 2705 // convert the data 2706 memcpy(requestBuffer->GetData(), data, dataSize); 2707 _ConvertAttribute(info->info, requestBuffer->GetData()); 2708 } 2709 } else 2710 info->info.type = B_SWAP_INT32(info->info.type); 2711 } 2712 2713 return B_OK; 2714 } 2715 2716 // _GetAttrDirInfo 2717 status_t 2718 ClientConnection::_GetAttrDirInfo(Request* request, AttributeDirectory* attrDir, 2719 AttrDirInfo* info) 2720 { 2721 if (!request || !attrDir || !info || !attrDir->IsAttrDirValid()) 2722 return B_BAD_VALUE; 2723 2724 // add the attribute infos 2725 for (Attribute* attribute = attrDir->GetFirstAttribute(); 2726 attribute; 2727 attribute = attrDir->GetNextAttribute(attribute)) { 2728 // get the attribute info 2729 AttributeInfo attrInfo; 2730 attr_info bAttrInfo; 2731 attribute->GetInfo(&bAttrInfo); 2732 status_t error = _GetAttrInfo(request, attribute->GetName(), bAttrInfo, 2733 attribute->GetData(), &attrInfo); 2734 2735 // append it 2736 if (error == B_OK) 2737 error = info->attributeInfos.Append(attrInfo); 2738 if (error != B_OK) 2739 return error; 2740 } 2741 2742 info->revision = VolumeManager::GetDefault()->GetRevision(); 2743 info->isValid = true; 2744 2745 return B_OK; 2746 } 2747 2748 // _CreateVolume 2749 status_t 2750 ClientConnection::_CreateVolume(ClientVolume** _volume) 2751 { 2752 // create and init the volume 2753 ClientVolume* volume = new(std::nothrow) ClientVolume(fSecurityContextLock, 2754 this); 2755 if (!volume) 2756 return B_NO_MEMORY; 2757 status_t error = volume->Init(); 2758 if (error != B_OK) { 2759 delete volume; 2760 return error; 2761 } 2762 2763 // add it to the volume map 2764 AutoLocker<VolumeMap> locker(fVolumes); 2765 error = fVolumes->Put(volume->GetID(), volume); 2766 locker.Unlock(); 2767 2768 if (error == B_OK) 2769 *_volume = volume; 2770 else 2771 delete volume; 2772 2773 return error; 2774 } 2775 2776 // _GetVolume 2777 ClientVolume* 2778 ClientConnection::_GetVolume(int32 id) 2779 { 2780 AutoLocker<VolumeMap> _(fVolumes); 2781 ClientVolume* volume = fVolumes->Get(id); 2782 if (!volume || volume->IsRemoved()) 2783 return NULL; 2784 volume->AcquireReference(); 2785 return volume; 2786 } 2787 2788 // _PutVolume 2789 // 2790 // The VolumeManager may be locked, but no other lock must be held. 2791 void 2792 ClientConnection::_PutVolume(ClientVolume* volume) 2793 { 2794 if (!volume) 2795 return; 2796 2797 // decrement reference counter and remove the volume, if 0 2798 AutoLocker<VolumeMap> locker(fVolumes); 2799 bool removed = (volume->ReleaseReference() == 1 && volume->IsRemoved()); 2800 if (removed) 2801 fVolumes->Remove(volume->GetID()); 2802 locker.Unlock(); 2803 2804 if (removed) { 2805 VolumeManagerLocker managerLocker; 2806 delete volume; 2807 } 2808 } 2809 2810 // _UnmountVolume 2811 // 2812 // The caller must have a reference to the volume. 2813 void 2814 ClientConnection::_UnmountVolume(ClientVolume* volume) 2815 { 2816 if (!volume) 2817 return; 2818 AutoLocker<VolumeMap> locker(fVolumes); 2819 volume->MarkRemoved(); 2820 locker.Unlock(); 2821 2822 // push a notification event 2823 if (VolumeUnmountedEvent* event = new(std::nothrow) VolumeUnmountedEvent) { 2824 VolumeManagerLocker managerLocker; 2825 2826 event->opcode = B_DEVICE_UNMOUNTED; 2827 _PushNodeMonitoringEvent(volume->GetID(), event); 2828 event->ReleaseReference(); 2829 } 2830 } 2831 2832 // _UnmountAllVolumes 2833 void 2834 ClientConnection::_UnmountAllVolumes() 2835 { 2836 while (true) { 2837 // To avoid heap allocation (which can fail) we unmount the volumes 2838 // chunkwise. 2839 // get the volumes 2840 const int32 volumeChunkSize = 32; 2841 ClientVolume* volumes[volumeChunkSize]; 2842 int32 volumeCount = 0; 2843 AutoLocker<VolumeMap> volumesLocker(fVolumes); 2844 for (VolumeMap::Iterator it = fVolumes->GetIterator(); it.HasNext();) { 2845 if (ClientVolume* volume = _GetVolume(it.Next().value->GetID())) { 2846 volumes[volumeCount++] = volume; 2847 } 2848 if (volumeCount == volumeChunkSize) 2849 break; 2850 } 2851 volumesLocker.Unlock(); 2852 2853 // unmount and put the volumes 2854 for (int32 i = 0; i < volumeCount; i++) { 2855 ClientVolume* volume = volumes[i]; 2856 _UnmountVolume(volume); 2857 _PutVolume(volume); 2858 } 2859 2860 if (volumeCount < volumeChunkSize) 2861 break; 2862 } 2863 } 2864 2865 // _NodeMonitoringProcessorEntry 2866 int32 2867 ClientConnection::_NodeMonitoringProcessorEntry(void* data) 2868 { 2869 return ((ClientConnection*)data)->_NodeMonitoringProcessor(); 2870 } 2871 2872 2873 // _NodeMonitoringProcessor 2874 int32 2875 ClientConnection::_NodeMonitoringProcessor() 2876 { 2877 while (!fClosed) { 2878 // get the next request 2879 NodeMonitoringRequest* request = NULL; 2880 status_t error = fNodeMonitoringEvents->Pop(&request); 2881 2882 // get a client connection reference 2883 ConnectionReference connectionReference(this); 2884 if (!connectionReference.IsValid()) 2885 return B_OK; 2886 2887 // No request? Next round... 2888 if (error != B_OK) 2889 continue; 2890 ObjectDeleter<NodeMonitoringRequest> requestDeleter(request); 2891 2892 // send the request 2893 if (error == B_OK) { 2894 error = fConnection->SendRequest(request); 2895 if (error != B_OK) { 2896 ERROR(("ClientConnection::_NodeMonitoringProcessor(): " 2897 "Failed to send request.\n")); 2898 } 2899 } 2900 } 2901 return 0; 2902 } 2903 2904 2905 // _PushNodeMonitoringEvent 2906 // 2907 // The caller must have a connection reference. Moreover the VolumeManager 2908 // must be locked. 2909 status_t 2910 ClientConnection::_PushNodeMonitoringEvent(int32 volumeID, 2911 NodeMonitoringEvent* event) 2912 { 2913 if (!event) 2914 return B_BAD_VALUE; 2915 2916 // get the volume 2917 ClientVolume* volume = _GetVolume(volumeID); 2918 if (!volume && event->opcode != B_DEVICE_UNMOUNTED) 2919 return B_BAD_VALUE; 2920 ClientVolumePutter volumePutter(this, volume); 2921 2922 // create a node monitoring request 2923 NodeMonitoringRequest* request = NULL; 2924 status_t error = B_ERROR; 2925 switch (event->opcode) { 2926 case B_ENTRY_CREATED: 2927 error = _EntryCreated(volume, 2928 dynamic_cast<EntryCreatedEvent*>(event), request); 2929 break; 2930 case B_ENTRY_REMOVED: 2931 error = _EntryRemoved(volume, 2932 dynamic_cast<EntryRemovedEvent*>(event), request); 2933 break; 2934 case B_ENTRY_MOVED: 2935 error = _EntryMoved(volume, 2936 dynamic_cast<EntryMovedEvent*>(event), request); 2937 break; 2938 case B_STAT_CHANGED: 2939 error = _NodeStatChanged(volume, 2940 dynamic_cast<StatChangedEvent*>(event), request); 2941 break; 2942 case B_ATTR_CHANGED: 2943 error = _NodeAttributeChanged(volume, 2944 dynamic_cast<AttributeChangedEvent*>(event), request); 2945 break; 2946 case B_DEVICE_UNMOUNTED: 2947 error = B_OK; 2948 break; 2949 } 2950 2951 // replace all data buffers -- when the request is actually sent, they 2952 // might no longer exist 2953 if (error == B_OK) 2954 error = RequestBufferReplacer().ReplaceBuffer(request); 2955 2956 if (error == B_OK) { 2957 // common initialization 2958 request->volumeID = volumeID; 2959 request->opcode = event->opcode; 2960 request->revision = VolumeManager::GetDefault()->GetRevision(); 2961 2962 // push the request 2963 error = fNodeMonitoringEvents->Push(request); 2964 if (error != B_OK) 2965 delete request; 2966 } 2967 2968 return error; 2969 } 2970 2971 // _EntryCreated 2972 status_t 2973 ClientConnection::_EntryCreated(ClientVolume* volume, EntryCreatedEvent* event, 2974 NodeMonitoringRequest*& _request) 2975 { 2976 // allocate the request 2977 EntryCreatedRequest* request = new(std::nothrow) EntryCreatedRequest; 2978 if (!request) 2979 return B_NO_MEMORY; 2980 ObjectDeleter<NodeMonitoringRequest> requestDeleter(request); 2981 2982 // get the name 2983 const char* name = event->name.GetString(); 2984 2985 // set the request fields 2986 request->directoryID = NodeID(event->volumeID, event->directoryID); 2987 request->nodeID = NodeID(event->volumeID, event->nodeID); 2988 request->name.SetTo(name); 2989 if (event->queryHandler) { 2990 request->port = event->remotePort; 2991 request->token = event->remoteToken; 2992 request->queryUpdate = true; 2993 } else 2994 request->queryUpdate = false; 2995 2996 // try to get an entry info 2997 Entry* entry; 2998 if (VolumeManager::GetDefault()->LoadEntry(event->volumeID, 2999 event->directoryID, name, true, &entry) == B_OK 3000 && entry->GetNode()->GetVolumeID() == event->volumeID 3001 && entry->GetNode()->GetID() == event->nodeID) { 3002 _GetEntryInfo(entry, &request->entryInfo); 3003 request->entryInfoValid = true; 3004 } else 3005 request->entryInfoValid = false; 3006 3007 requestDeleter.Detach(); 3008 _request = request; 3009 return B_OK; 3010 } 3011 3012 // _EntryRemoved 3013 status_t 3014 ClientConnection::_EntryRemoved(ClientVolume* volume, EntryRemovedEvent* event, 3015 NodeMonitoringRequest*& _request) 3016 { 3017 // special handling, if it is the root node of the client volume that has 3018 // been removed 3019 if (!event->queryHandler 3020 && NodeRef(event->nodeVolumeID, event->nodeID) 3021 == volume->GetRootNodeRef()) { 3022 NoAllocEntryRef ref(event->nodeVolumeID, event->nodeID, "."); 3023 BEntry entry; 3024 if (FDManager::SetEntry(&entry, &ref) != B_OK || !entry.Exists()) 3025 _UnmountVolume(volume); 3026 3027 // don't send the "entry removed" event 3028 return B_ERROR; 3029 } 3030 3031 // allocate the request 3032 EntryRemovedRequest* request = new(std::nothrow) EntryRemovedRequest; 3033 if (!request) 3034 return B_NO_MEMORY; 3035 ObjectDeleter<NodeMonitoringRequest> requestDeleter(request); 3036 3037 // get the name 3038 const char* name = event->name.GetString(); 3039 3040 // set the request fields 3041 request->directoryID = NodeID(event->volumeID, event->directoryID); 3042 request->nodeID = NodeID(event->nodeVolumeID, event->nodeID); 3043 request->name.SetTo(name); 3044 if (event->queryHandler) { 3045 request->port = event->remotePort; 3046 request->token = event->remoteToken; 3047 request->queryUpdate = true; 3048 } else 3049 request->queryUpdate = false; 3050 3051 requestDeleter.Detach(); 3052 _request = request; 3053 return B_OK; 3054 } 3055 3056 // _EntryMoved 3057 status_t 3058 ClientConnection::_EntryMoved(ClientVolume* volume, EntryMovedEvent* event, 3059 NodeMonitoringRequest*& _request) 3060 { 3061 // allocate the request 3062 EntryMovedRequest* request = new(std::nothrow) EntryMovedRequest; 3063 if (!request) 3064 return B_NO_MEMORY; 3065 ObjectDeleter<NodeMonitoringRequest> requestDeleter(request); 3066 3067 // allocate memory for the names 3068 int32 fromNameLen = event->fromName.GetLength(); 3069 const char* fromName 3070 = (fromNameLen > 0 ? event->fromName.GetString() : NULL); 3071 const char* toName = event->toName.GetString(); 3072 3073 // set the request fields 3074 request->fromDirectoryID = NodeID(event->volumeID, event->fromDirectoryID); 3075 request->toDirectoryID = NodeID(event->volumeID, event->toDirectoryID); 3076 request->nodeID = NodeID(event->nodeVolumeID, event->nodeID); 3077 request->fromName.SetTo(fromName); 3078 request->toName.SetTo(toName); 3079 request->queryUpdate = false; 3080 3081 // try to get an entry info 3082 Entry* entry; 3083 if (VolumeManager::GetDefault()->LoadEntry(event->volumeID, 3084 event->toDirectoryID, toName, true, &entry) == B_OK 3085 && entry->GetNode()->GetVolumeID() == event->nodeVolumeID 3086 && entry->GetNode()->GetID() == event->nodeID) { 3087 _GetEntryInfo(entry, &request->entryInfo); 3088 request->entryInfoValid = true; 3089 } else 3090 request->entryInfoValid = false; 3091 3092 requestDeleter.Detach(); 3093 _request = request; 3094 return B_OK; 3095 } 3096 3097 // _NodeStatChanged 3098 status_t 3099 ClientConnection::_NodeStatChanged(ClientVolume* volume, 3100 StatChangedEvent* event, NodeMonitoringRequest*& _request) 3101 { 3102 // get the node 3103 Node* node = volume->GetNode(event->volumeID, event->nodeID); 3104 if (!node) 3105 return B_ENTRY_NOT_FOUND; 3106 3107 // allocate the request 3108 StatChangedRequest* request = new(std::nothrow) StatChangedRequest; 3109 if (!request) 3110 return B_NO_MEMORY; 3111 ObjectDeleter<NodeMonitoringRequest> requestDeleter(request); 3112 3113 // set the request fields 3114 request->nodeID = NodeID(event->volumeID, event->nodeID); 3115 _GetNodeInfo(node, &request->nodeInfo); 3116 request->queryUpdate = false; 3117 3118 requestDeleter.Detach(); 3119 _request = request; 3120 return B_OK; 3121 } 3122 3123 // _NodeAttributeChanged 3124 status_t 3125 ClientConnection::_NodeAttributeChanged(ClientVolume* volume, 3126 AttributeChangedEvent* event, NodeMonitoringRequest*& _request) 3127 { 3128 // get the node 3129 Node* node = volume->GetNode(event->volumeID, event->nodeID); 3130 if (!node) 3131 return B_ENTRY_NOT_FOUND; 3132 3133 // update the attribute directory 3134 bool removed = false; 3135 bool valid = false; 3136 attr_info info; 3137 const void* data = NULL; 3138 status_t error = node->UpdateAttribute(event->attribute.GetString(), 3139 &removed, &info, &data); 3140 valid = (error == B_OK); 3141 3142 // allocate the request 3143 AttributeChangedRequest* request = new(std::nothrow) AttributeChangedRequest; 3144 if (!request) 3145 return B_NO_MEMORY; 3146 ObjectDeleter<NodeMonitoringRequest> requestDeleter(request); 3147 3148 // get an attr dir info, if the directory is valid 3149 if (node->IsAttrDirValid()) { 3150 status_t error = _GetAttrDirInfo(request, node, &request->attrDirInfo); 3151 if (error != B_OK) 3152 return error; 3153 } 3154 3155 // get name and the data size 3156 int32 dataSize = (data ? info.size : 0); 3157 const char* name = event->attribute.GetString(); 3158 3159 // set the request fields 3160 request->nodeID = NodeID(event->volumeID, event->nodeID); 3161 request->attrInfo.name.SetTo(name); 3162 request->valid = valid; 3163 request->removed = removed; 3164 if (!removed && valid) { 3165 request->attrInfo.info = info; 3166 request->attrInfo.data.SetTo(data, dataSize); 3167 } 3168 request->queryUpdate = false; 3169 3170 requestDeleter.Detach(); 3171 _request = request; 3172 return B_OK; 3173 } 3174 3175 // _KnownAttributeType 3176 bool 3177 ClientConnection::_KnownAttributeType(type_code type) 3178 { 3179 if (!fInverseClientEndianess) 3180 return false; 3181 3182 switch (type) { 3183 case B_BOOL_TYPE: 3184 case B_CHAR_TYPE: 3185 case B_COLOR_8_BIT_TYPE: 3186 case B_DOUBLE_TYPE: 3187 case B_FLOAT_TYPE: 3188 case B_GRAYSCALE_8_BIT_TYPE: 3189 case B_INT64_TYPE: 3190 case B_INT32_TYPE: 3191 case B_INT16_TYPE: 3192 case B_INT8_TYPE: 3193 case B_MESSAGE_TYPE: 3194 case B_MESSENGER_TYPE: 3195 case B_MIME_TYPE: 3196 case B_MONOCHROME_1_BIT_TYPE: 3197 case B_OFF_T_TYPE: 3198 case B_POINTER_TYPE: 3199 case B_POINT_TYPE: 3200 case B_RECT_TYPE: 3201 case B_REF_TYPE: 3202 case B_RGB_COLOR_TYPE: 3203 case B_SIZE_T_TYPE: 3204 case B_SSIZE_T_TYPE: 3205 case B_STRING_TYPE: 3206 case B_TIME_TYPE: 3207 case B_UINT64_TYPE: 3208 case B_UINT32_TYPE: 3209 case B_UINT16_TYPE: 3210 case B_UINT8_TYPE: 3211 case B_ASCII_TYPE: 3212 case B_MIME_STRING_TYPE: 3213 return true; 3214 3215 //B_RGB_32_BIT_TYPE: We could translate it, but it's heavy... 3216 } 3217 3218 return false; 3219 } 3220 3221 // _ConvertAttribute 3222 void 3223 ClientConnection::_ConvertAttribute(const attr_info& info, void* buffer) 3224 { 3225 swap_data(info.type, buffer, info.size, B_SWAP_ALWAYS); 3226 } 3227 3228 3229 // #pragma mark - 3230 3231 // _OpenQuery 3232 status_t 3233 ClientConnection::_OpenQuery(const char* queryString, uint32 flags, 3234 port_id remotePort, int32 remoteToken, QueryHandle** _handle) 3235 { 3236 if (!queryString || !_handle) 3237 return B_BAD_VALUE; 3238 3239 // open query 3240 QueryHandle* queryHandle; 3241 status_t error = VolumeManager::GetDefault()->OpenQuery(this, queryString, 3242 flags, remotePort, remoteToken, &queryHandle); 3243 if (error != B_OK) 3244 return error; 3245 BReference<QueryHandle> handleReference(queryHandle, true); 3246 3247 // lock the handle 3248 queryHandle->Lock(); 3249 3250 // add the handle 3251 error = fQueryHandles->AddNodeHandle(queryHandle); 3252 if (error != B_OK) 3253 return error; 3254 3255 handleReference.Detach(); 3256 *_handle = queryHandle; 3257 return B_OK; 3258 } 3259 3260 // _CloseQuery 3261 status_t 3262 ClientConnection::_CloseQuery(QueryHandle* handle) 3263 { 3264 if (!handle || !fQueryHandles->RemoveNodeHandle(handle)) 3265 return B_BAD_VALUE; 3266 3267 return B_OK; 3268 } 3269 3270 // _LockQueryHandle 3271 // 3272 // VolumeManager must NOT be locked. 3273 status_t 3274 ClientConnection::_LockQueryHandle(int32 cookie, QueryHandle** _handle) 3275 { 3276 NodeHandle* handle; 3277 status_t error = fQueryHandles->LockNodeHandle(cookie, &handle); 3278 if (error == B_OK) 3279 *_handle = static_cast<QueryHandle*>(handle); 3280 return error; 3281 } 3282 3283 // _UnlockQueryHandle 3284 // 3285 // VolumeManager may or may not be locked. 3286 void 3287 ClientConnection::_UnlockQueryHandle(NodeHandle* nodeHandle) 3288 { 3289 fQueryHandles->UnlockNodeHandle(nodeHandle); 3290 } 3291 3292 3293 // #pragma mark - 3294 3295 // _GetAllClientVolumeIDs 3296 int32 3297 ClientConnection::_GetAllClientVolumeIDs(int32* volumeIDs, int32 arraySize, 3298 ClientVolumeFilter* filter) 3299 { 3300 int32 count = 0; 3301 AutoLocker<VolumeMap> volumesLocker(fVolumes); 3302 for (VolumeMap::Iterator it = fVolumes->GetIterator(); 3303 it.HasNext() && arraySize > count;) { 3304 ClientVolume* clientVolume = it.Next().value; 3305 if (!filter || filter->FilterVolume(this, clientVolume)) 3306 volumeIDs[count++] = clientVolume->GetID(); 3307 } 3308 3309 return count; 3310 } 3311 3312 // _GetContainingClientVolumes 3313 int32 3314 ClientConnection::_GetContainingClientVolumes(Directory* directory, 3315 int32* volumeIDs, int32 arraySize, ClientVolumeFilter* filter) 3316 { 3317 int32 count = 0; 3318 VolumeManager* volumeManager = VolumeManager::GetDefault(); 3319 AutoLocker<VolumeMap> volumesLocker(fVolumes); 3320 for (VolumeMap::Iterator it = fVolumes->GetIterator(); 3321 it.HasNext() && arraySize > count;) { 3322 ClientVolume* clientVolume = it.Next().value; 3323 Directory* clientVolumeRoot = clientVolume->GetRootDirectory(); 3324 if (volumeManager->DirectoryContains(clientVolumeRoot, directory, true) 3325 && (!filter || filter->FilterVolume(this, clientVolume))) { 3326 volumeIDs[count++] = clientVolume->GetID(); 3327 } 3328 } 3329 3330 return count; 3331 } 3332 3333 3334 // #pragma mark - 3335 // #pragma mark ----- ClientConnectionListener ----- 3336 3337 // constructor 3338 ClientConnectionListener::ClientConnectionListener() 3339 { 3340 } 3341 3342 // destructor 3343 ClientConnectionListener::~ClientConnectionListener() 3344 { 3345 } 3346 3347