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, request->name.GetString(), 1794 result, reply.entryInfo.nodeInfo.st.st_dev, reply.entryInfo.nodeInfo.st.st_ino, 1795 reply.linkPath.GetString())); 1796 return GetChannel()->SendRequest(&reply); 1797 } 1798 1799 // VisitMultiWalkRequest 1800 status_t 1801 ClientConnection::VisitMultiWalkRequest(MultiWalkRequest* request) 1802 { 1803 ConnectionReference connectionReference(this); 1804 if (!connectionReference.IsValid()) 1805 return B_OK; 1806 1807 // get the volume 1808 status_t result = B_OK; 1809 ClientVolume* volume = _GetVolume(request->volumeID); 1810 if (!volume) 1811 result = B_BAD_VALUE; 1812 ClientVolumePutter volumePutter(this, volume); 1813 1814 VolumeManagerLocker managerLocker; 1815 1816 // get the directory 1817 Directory* directory = NULL; 1818 if (result == B_OK) { 1819 Node* node = volume->GetNode(request->nodeID); 1820 if (node) { 1821 directory = dynamic_cast<Directory*>(node); 1822 if (!directory) 1823 result = B_NOT_A_DIRECTORY; 1824 } else 1825 result = B_ENTRY_NOT_FOUND; 1826 } 1827 1828 // check permission 1829 if (result == B_OK) { 1830 if (!volume->GetNodePermissions(directory) 1831 .ImpliesResolveDirEntryPermission()) { 1832 result = B_PERMISSION_DENIED; 1833 } 1834 } 1835 1836 MultiWalkReply reply; 1837 StringData* names = request->names.GetElements(); 1838 int32 count = request->names.CountElements(); 1839 for (int32 i = 0; result == B_OK && i < count; i++) { 1840 // load the entry 1841 Entry* entry; 1842 if (volume->LoadEntry(directory, names[i].GetString(), &entry) 1843 == B_OK) { 1844 // add an entry info 1845 EntryInfo entryInfo; 1846 _GetEntryInfo(entry, &entryInfo); 1847 1848 // append the info 1849 result = reply.entryInfos.Append(entryInfo); 1850 } 1851 } 1852 1853 managerLocker.Unlock(); 1854 1855 // send the reply 1856 reply.error = result; 1857 PRINT(("MultiWalk: (%ld, %lld, %ld) -> (%lx, %ld)\n", 1858 request->nodeID.volumeID, request->nodeID.nodeID, count, 1859 result, reply.entryInfos.CountElements())); 1860 return GetChannel()->SendRequest(&reply); 1861 } 1862 1863 // VisitOpenAttrDirRequest 1864 status_t 1865 ClientConnection::VisitOpenAttrDirRequest(OpenAttrDirRequest* request) 1866 { 1867 ConnectionReference connectionReference(this); 1868 if (!connectionReference.IsValid()) 1869 return B_OK; 1870 1871 // get the volume 1872 status_t result = B_OK; 1873 ClientVolume* volume = _GetVolume(request->volumeID); 1874 if (!volume) 1875 result = B_BAD_VALUE; 1876 ClientVolumePutter volumePutter(this, volume); 1877 1878 VolumeManagerLocker managerLocker; 1879 1880 // get the node 1881 Node* node = NULL; 1882 if (result == B_OK) { 1883 node = volume->GetNode(request->nodeID); 1884 if (!node) 1885 result = B_ENTRY_NOT_FOUND; 1886 } 1887 1888 // check permission 1889 if (result == B_OK) { 1890 if (!volume->GetNodePermissions(node).ImpliesReadPermission()) 1891 result = B_PERMISSION_DENIED; 1892 } 1893 1894 // load/cache the attribute directory 1895 bool attrDirCached = (node->LoadAttrDir() == B_OK); 1896 1897 // open the attribute directory, if caching it failed 1898 AttrDirIterator* handle = NULL; 1899 if (result == B_OK && !attrDirCached) 1900 result = volume->OpenAttrDir(node, &handle); 1901 NodeHandleUnlocker handleUnlocker(volume, handle); 1902 1903 // prepare the reply 1904 OpenAttrDirReply reply; 1905 if (result == B_OK) { 1906 if (handle) { 1907 reply.cookie = handle->GetCookie(); 1908 } else { 1909 // the attribute directory is cached 1910 reply.cookie = -1; 1911 result = _GetAttrDirInfo(request, node, &reply.attrDirInfo); 1912 } 1913 } 1914 1915 managerLocker.Unlock(); 1916 1917 // send the reply 1918 reply.error = result; 1919 status_t error = GetChannel()->SendRequest(&reply); 1920 1921 // close the handle, if a send error occurred 1922 if (error != B_OK && result == B_OK && handle) 1923 volume->Close(handle); 1924 1925 return error; 1926 } 1927 1928 // VisitReadAttrDirRequest 1929 status_t 1930 ClientConnection::VisitReadAttrDirRequest(ReadAttrDirRequest* request) 1931 { 1932 ConnectionReference connectionReference(this); 1933 if (!connectionReference.IsValid()) 1934 return B_OK; 1935 1936 // get the volume 1937 status_t result = B_OK; 1938 ClientVolume* volume = _GetVolume(request->volumeID); 1939 if (!volume) 1940 result = B_BAD_VALUE; 1941 ClientVolumePutter volumePutter(this, volume); 1942 1943 // get the node handle 1944 NodeHandle* handle = NULL; 1945 if (result == B_OK) 1946 result = volume->LockNodeHandle(request->cookie, &handle); 1947 NodeHandleUnlocker handleUnlocker(volume, handle); 1948 1949 // check if it is a attribute directory iterator 1950 AttrDirIterator* iterator = NULL; 1951 if (result == B_OK) { 1952 iterator = dynamic_cast<AttrDirIterator*>(handle); 1953 if (!iterator) 1954 result = B_BAD_VALUE; 1955 } 1956 1957 VolumeManagerLocker managerLocker; 1958 1959 // get the node 1960 Node* node = NULL; 1961 if (result == B_OK) { 1962 node = volume->GetNode(iterator->GetNodeRef()); 1963 if (!node) 1964 result = B_ENTRY_NOT_FOUND; 1965 } 1966 1967 // check read permission (we already checked when opening, but anyway...) 1968 if (result == B_OK) { 1969 if (!volume->GetNodePermissions(node).ImpliesReadPermission()) 1970 result = B_PERMISSION_DENIED; 1971 } 1972 1973 managerLocker.Unlock(); 1974 1975 // read the attribute directory 1976 uint8 buffer[sizeof(struct dirent) + B_FILE_NAME_LENGTH]; 1977 struct dirent* dirEntry = (struct dirent*)buffer; 1978 int32 countRead = 0; 1979 bool done = true; 1980 if (result == B_OK) { 1981 if (request->rewind) 1982 result = iterator->RewindDir(); 1983 if (result == B_OK) { 1984 result = iterator->ReadDir(dirEntry, sizeof(buffer), 1, 1985 &countRead, &done); 1986 } 1987 } 1988 1989 // prepare the reply 1990 ReadAttrDirReply reply; 1991 reply.name.SetTo(dirEntry->d_name); 1992 1993 // send the reply 1994 reply.error = result; 1995 reply.count = countRead; 1996 return GetChannel()->SendRequest(&reply); 1997 } 1998 1999 // VisitReadAttrRequest 2000 status_t 2001 ClientConnection::VisitReadAttrRequest(ReadAttrRequest* request) 2002 { 2003 ConnectionReference connectionReference(this); 2004 if (!connectionReference.IsValid()) 2005 return B_OK; 2006 2007 // get the volume 2008 status_t result = B_OK; 2009 ClientVolume* volume = _GetVolume(request->volumeID); 2010 if (!volume) 2011 result = B_BAD_VALUE; 2012 ClientVolumePutter volumePutter(this, volume); 2013 2014 VolumeManagerLocker managerLocker; 2015 2016 // get the node 2017 Node* node = NULL; 2018 if (result == B_OK) { 2019 node = volume->GetNode(request->nodeID); 2020 if (!node) 2021 result = B_ENTRY_NOT_FOUND; 2022 } 2023 2024 // check read permission 2025 if (result == B_OK) { 2026 if (!volume->GetNodePermissions(node).ImpliesReadPermission()) 2027 result = B_PERMISSION_DENIED; 2028 } 2029 2030 // open the node 2031 FileHandle* handle = NULL; 2032 if (result == B_OK) 2033 result = volume->Open(node, O_RDONLY, &handle); 2034 NodeHandleUnlocker handleUnlocker(volume, handle); 2035 2036 managerLocker.Unlock(); 2037 2038 // read the attribute 2039 if (result == B_OK) { 2040 // Due to a bug in BFS the `pos' is ignored. This means that the loop 2041 // below won't work if the attribute is non-empty and the buffer is 2042 // larger than the attribute, because the we would again and again 2043 // read the beginning of the attribute until the buffer is full. 2044 // Hence we first get an attr_info and don't try to read more than 2045 // the size of the attribute. 2046 attr_info info; 2047 result = handle->StatAttr(request->name.GetString(), &info); 2048 off_t originalPos = max(request->pos, 0LL); 2049 int32 originalSize = max(request->size, 0L); 2050 off_t pos = originalPos; 2051 int32 size = originalSize; 2052 type_code type = B_SWAP_INT32(request->type); 2053 bool convert = false; 2054 2055 if (result == B_OK) { 2056 originalSize = min((off_t)originalSize, max(0LL, info.size - pos)); 2057 size = originalSize; 2058 2059 // deal with inverse endianess clients 2060 if (fInverseClientEndianess) { 2061 convert = _KnownAttributeType(info.type); 2062 if (convert) { 2063 // read the whole attribute 2064 pos = 0; 2065 size = info.size; 2066 } else 2067 type = B_SWAP_INT32(request->type); 2068 } 2069 } 2070 int32 bufferSize = min(size, kMaxReadBufferSize); 2071 2072 // allocate a buffer 2073 uint8* buffer = NULL; 2074 if (result == B_OK) { 2075 buffer = (uint8*)malloc(bufferSize); 2076 if (!buffer) 2077 result = B_NO_MEMORY; 2078 } 2079 MemoryDeleter bufferDeleter(buffer); 2080 2081 if (convert) { 2082 // read the whole attribute and convert it 2083 if (result == B_OK) { 2084 // read 2085 size_t bytesRead = 0; 2086 result = handle->ReadAttr(request->name.GetString(), 2087 type, 0, buffer, size, &bytesRead); 2088 if (result == B_OK && (int32)bytesRead != size) 2089 result = B_ERROR; 2090 2091 // convert 2092 if (result == B_OK) 2093 _ConvertAttribute(info, buffer); 2094 } 2095 2096 // prepare the reply 2097 ReadAttrReply reply; 2098 if (result == B_OK) { 2099 reply.pos = originalPos; 2100 reply.data.SetTo(buffer + originalPos, originalSize); 2101 reply.moreToCome = false; 2102 } 2103 2104 // send the reply 2105 reply.error = result; 2106 status_t error = GetChannel()->SendRequest(&reply); 2107 if (error != B_OK) 2108 return error; 2109 } else { 2110 // read as long as there are bytes left to read or an error occurs 2111 bool moreToRead = true; 2112 do { 2113 int32 bytesToRead = min(size, bufferSize); 2114 size_t bytesRead = 0; 2115 if (result == B_OK) { 2116 result = handle->ReadAttr(request->name.GetString(), 2117 request->type, pos, buffer, bytesToRead, &bytesRead); 2118 } 2119 moreToRead = (result == B_OK && bytesRead > 0 2120 && (int32)bytesRead < size); 2121 2122 // prepare the reply 2123 ReadAttrReply reply; 2124 if (result == B_OK) { 2125 reply.pos = pos; 2126 reply.data.SetTo(buffer, bytesRead); 2127 reply.moreToCome = moreToRead; 2128 pos += bytesRead; 2129 size -= bytesRead; 2130 } 2131 2132 // send the reply 2133 reply.error = result; 2134 status_t error = GetChannel()->SendRequest(&reply); 2135 if (error != B_OK) 2136 return error; 2137 } while (moreToRead); 2138 } 2139 2140 // close the handle 2141 volume->Close(handle); 2142 } else { 2143 // opening the node failed (or something even earlier): send an error 2144 // reply 2145 ReadAttrReply reply; 2146 reply.error = result; 2147 status_t error = GetChannel()->SendRequest(&reply); 2148 if (error != B_OK) 2149 return error; 2150 } 2151 2152 return B_OK; 2153 } 2154 2155 // VisitWriteAttrRequest 2156 status_t 2157 ClientConnection::VisitWriteAttrRequest(WriteAttrRequest* request) 2158 { 2159 ConnectionReference connectionReference(this); 2160 if (!connectionReference.IsValid()) 2161 return B_OK; 2162 2163 // get the volume 2164 status_t result = B_OK; 2165 ClientVolume* volume = _GetVolume(request->volumeID); 2166 if (!volume) 2167 result = B_BAD_VALUE; 2168 ClientVolumePutter volumePutter(this, volume); 2169 2170 VolumeManagerLocker managerLocker; 2171 2172 // get the node 2173 Node* node = NULL; 2174 if (result == B_OK) { 2175 node = volume->GetNode(request->nodeID); 2176 if (!node) 2177 result = B_ENTRY_NOT_FOUND; 2178 } 2179 2180 // check read permission 2181 if (result == B_OK) { 2182 if (!volume->GetNodePermissions(node).ImpliesWritePermission()) 2183 result = B_PERMISSION_DENIED; 2184 } 2185 2186 // open the node 2187 FileHandle* handle = NULL; 2188 if (result == B_OK) 2189 result = volume->Open(node, O_RDWR, &handle); 2190 NodeHandleUnlocker handleUnlocker(volume, handle); 2191 2192 managerLocker.Unlock(); 2193 2194 if (result == B_OK) { 2195 off_t pos = max(request->pos, 0LL); 2196 int32 size = request->data.GetSize(); 2197 type_code type = request->type; 2198 char* buffer = (char*)request->data.GetData(); 2199 2200 // convert the data, if necessary 2201 if (fInverseClientEndianess) { 2202 if (_KnownAttributeType(type)) { 2203 if (pos != 0) { 2204 WARN("WriteAttr(): WARNING: Need to convert attribute " 2205 "endianess, but position is not 0: attribute: %s, " 2206 "pos: %lld, size: %ld\n", request->name.GetString(), 2207 pos, size); 2208 } 2209 swap_data(type, buffer, size, B_SWAP_ALWAYS); 2210 } else 2211 type = B_SWAP_INT32(type); 2212 } 2213 2214 // write the data 2215 while (result == B_OK && size > 0) { 2216 size_t bytesWritten; 2217 result = handle->WriteAttr(request->name.GetString(), 2218 type, pos, buffer, size, &bytesWritten); 2219 if (result == B_OK) { 2220 pos += bytesWritten; 2221 buffer += bytesWritten; 2222 size -= bytesWritten; 2223 } 2224 } 2225 2226 // close the handle 2227 volume->Close(handle); 2228 } 2229 2230 // prepare the reply 2231 WriteAttrReply reply; 2232 // send the reply 2233 reply.error = result; 2234 return GetChannel()->SendRequest(&reply); 2235 } 2236 2237 // VisitRemoveAttrRequest 2238 status_t 2239 ClientConnection::VisitRemoveAttrRequest(RemoveAttrRequest* request) 2240 { 2241 ConnectionReference connectionReference(this); 2242 if (!connectionReference.IsValid()) 2243 return B_OK; 2244 2245 // get the volume 2246 status_t result = B_OK; 2247 ClientVolume* volume = _GetVolume(request->volumeID); 2248 if (!volume) 2249 result = B_BAD_VALUE; 2250 ClientVolumePutter volumePutter(this, volume); 2251 2252 VolumeManagerLocker managerLocker; 2253 2254 // get the node 2255 Node* node = NULL; 2256 if (result == B_OK) { 2257 node = volume->GetNode(request->nodeID); 2258 if (!node) 2259 result = B_ENTRY_NOT_FOUND; 2260 } 2261 2262 // check read permission 2263 if (result == B_OK) { 2264 if (!volume->GetNodePermissions(node).ImpliesWritePermission()) 2265 result = B_PERMISSION_DENIED; 2266 } 2267 2268 // open the node 2269 FileHandle* handle = NULL; 2270 if (result == B_OK) 2271 result = volume->Open(node, O_RDWR, &handle); 2272 NodeHandleUnlocker handleUnlocker(volume, handle); 2273 2274 managerLocker.Unlock(); 2275 2276 // remove the attribute and close the node 2277 if (result == B_OK) { 2278 result = handle->RemoveAttr(request->name.GetString()); 2279 volume->Close(handle); 2280 } 2281 2282 // send the reply 2283 RemoveAttrReply reply; 2284 reply.error = result; 2285 return GetChannel()->SendRequest(&reply); 2286 } 2287 2288 // VisitRenameAttrRequest 2289 status_t 2290 ClientConnection::VisitRenameAttrRequest(RenameAttrRequest* request) 2291 { 2292 // Not supported, since there's no API function to rename an attribute. 2293 // send the reply 2294 RemoveAttrReply reply; 2295 reply.error = B_UNSUPPORTED; 2296 return GetChannel()->SendRequest(&reply); 2297 } 2298 2299 // VisitStatAttrRequest 2300 status_t 2301 ClientConnection::VisitStatAttrRequest(StatAttrRequest* request) 2302 { 2303 ConnectionReference connectionReference(this); 2304 if (!connectionReference.IsValid()) 2305 return B_OK; 2306 2307 // get the volume 2308 status_t result = B_OK; 2309 ClientVolume* volume = _GetVolume(request->volumeID); 2310 if (!volume) 2311 result = B_BAD_VALUE; 2312 ClientVolumePutter volumePutter(this, volume); 2313 2314 VolumeManagerLocker managerLocker; 2315 2316 // get the node 2317 Node* node = NULL; 2318 if (result == B_OK) { 2319 node = volume->GetNode(request->nodeID); 2320 if (!node) 2321 result = B_ENTRY_NOT_FOUND; 2322 } 2323 2324 // check read permission 2325 if (result == B_OK) { 2326 if (!volume->GetNodePermissions(node).ImpliesReadPermission()) 2327 result = B_PERMISSION_DENIED; 2328 } 2329 2330 // open the node 2331 FileHandle* handle = NULL; 2332 if (result == B_OK) 2333 result = volume->Open(node, O_RDONLY, &handle); 2334 NodeHandleUnlocker handleUnlocker(volume, handle); 2335 2336 managerLocker.Unlock(); 2337 2338 // stat the attribute and close the node 2339 attr_info attrInfo; 2340 StatAttrReply reply; 2341 if (result == B_OK) { 2342 result = handle->StatAttr(request->name.GetString(), &attrInfo); 2343 volume->Close(handle); 2344 } 2345 2346 // set the attribute info 2347 if (result == B_OK) { 2348 result = _GetAttrInfo(request, request->name.GetString(), attrInfo, 2349 NULL, &reply.attrInfo); 2350 } 2351 2352 // send the reply 2353 reply.error = result; 2354 return GetChannel()->SendRequest(&reply); 2355 } 2356 2357 // VisitOpenQueryRequest 2358 status_t 2359 ClientConnection::VisitOpenQueryRequest(OpenQueryRequest* request) 2360 { 2361 ConnectionReference connectionReference(this); 2362 if (!connectionReference.IsValid()) 2363 return B_OK; 2364 2365 VolumeManagerLocker managerLocker; 2366 2367 // open the query 2368 status_t result = B_OK; 2369 QueryHandle* handle = NULL; 2370 if (result == B_OK) { 2371 result = _OpenQuery(request->queryString.GetString(), 2372 request->flags, request->port, request->token, &handle); 2373 } 2374 QueryHandleUnlocker handleUnlocker(this, handle); 2375 2376 // prepare the reply 2377 OpenQueryReply reply; 2378 if (result == B_OK) 2379 reply.cookie = handle->GetCookie(); 2380 2381 managerLocker.Unlock(); 2382 2383 // send the reply 2384 reply.error = result; 2385 status_t error = GetChannel()->SendRequest(&reply); 2386 2387 // close the handle, if a send error occurred 2388 if (error != B_OK && result == B_OK) 2389 _CloseQuery(handle); 2390 2391 return error; 2392 } 2393 2394 // VisitReadQueryRequest 2395 status_t 2396 ClientConnection::VisitReadQueryRequest(ReadQueryRequest* request) 2397 { 2398 ConnectionReference connectionReference(this); 2399 if (!connectionReference.IsValid()) 2400 return B_OK; 2401 2402 // create an array for the IDs of the client volumes a found entry may 2403 // reside on 2404 status_t result = B_OK; 2405 int32 volumeCount = fVolumes->Size(); 2406 int32* volumeIDs = new(std::nothrow) int32[volumeCount]; 2407 if (!volumeIDs) 2408 result = B_NO_MEMORY; 2409 ArrayDeleter<int32> volumeIDsDeleter(volumeIDs); 2410 2411 // get the query handle 2412 QueryHandle* handle = NULL; 2413 if (result == B_OK) 2414 result = _LockQueryHandle(request->cookie, &handle); 2415 QueryHandleUnlocker handleUnlocker(this, handle); 2416 2417 // check if it is a query handle 2418 QueryHandle* queryHandle = NULL; 2419 if (result == B_OK) { 2420 queryHandle = dynamic_cast<QueryHandle*>(handle); 2421 if (!queryHandle) 2422 result = B_BAD_VALUE; 2423 } 2424 2425 // read the query 2426 ReadQueryReply reply; 2427 int32 countRead = 0; 2428 while (result == B_OK) { 2429 uint8 buffer[sizeof(struct dirent) + B_FILE_NAME_LENGTH]; 2430 struct dirent* dirEntry = (struct dirent*)buffer; 2431 2432 result = queryHandle->ReadDir(dirEntry, 1, &countRead); 2433 if (result != B_OK) 2434 break; 2435 if (countRead == 0) 2436 break; 2437 PRINT((" query entry: %ld, %lld, \"%s\"\n", dirEntry->d_pdev, dirEntry->d_pino, dirEntry->d_name)); 2438 2439 VolumeManagerLocker managerLocker; 2440 VolumeManager* volumeManager = VolumeManager::GetDefault(); 2441 2442 // load the entry 2443 Entry* entry = NULL; 2444 result = volumeManager->LoadEntry(dirEntry->d_pdev, 2445 dirEntry->d_pino, dirEntry->d_name, true, &entry); 2446 2447 // if at least one client volume contains the entry, get an entry info 2448 if (result == B_OK) { 2449 HasQueryPermissionClientVolumeFilter filter; 2450 int32 entryVolumeCount = _GetContainingClientVolumes( 2451 entry->GetDirectory(), volumeIDs, volumeCount, &filter); 2452 if (entryVolumeCount > 0) { 2453 // store all the client volume IDs in the reply 2454 for (int32 i = 0; i < entryVolumeCount; i++) { 2455 result = reply.clientVolumeIDs.Append(volumeIDs[i]); 2456 if (result != B_OK) 2457 break; 2458 } 2459 2460 // get an entry info 2461 _GetNodeInfo(entry->GetDirectory(), &reply.dirInfo); 2462 _GetEntryInfo(entry, &reply.entryInfo); 2463 break; 2464 } 2465 else 2466 PRINT((" -> no client volumes\n")); 2467 } 2468 2469 // entry is not in the volume: next round... 2470 result = B_OK; 2471 } 2472 2473 // send the reply 2474 reply.error = result; 2475 reply.count = countRead; 2476 PRINT(("ReadQuery: (%lx, %ld, dir: (%ld, %lld), node: (%ld, %lld, `%s')\n", 2477 reply.error, reply.count, reply.entryInfo.directoryID.volumeID, 2478 reply.entryInfo.directoryID.nodeID, reply.entryInfo.nodeInfo.st.st_dev, 2479 reply.entryInfo.nodeInfo.st.st_ino, reply.entryInfo.name.GetString())); 2480 return GetChannel()->SendRequest(&reply); 2481 } 2482 2483 2484 // #pragma mark - 2485 2486 // ProcessNodeMonitoringEvent 2487 void 2488 ClientConnection::ProcessNodeMonitoringEvent(int32 volumeID, 2489 NodeMonitoringEvent* event) 2490 { 2491 // get a connection reference 2492 ConnectionReference connectionReference(this); 2493 if (!connectionReference.IsValid()) 2494 return; 2495 2496 _PushNodeMonitoringEvent(volumeID, event); 2497 } 2498 2499 // CloseNodeMonitoringEventQueue 2500 void 2501 ClientConnection::CloseNodeMonitoringEventQueue() 2502 { 2503 typedef Vector<NodeMonitoringRequest*> RequestVector; 2504 const RequestVector* requests; 2505 if (fNodeMonitoringEvents->Close(false, &requests) == B_OK) { 2506 for (RequestVector::ConstIterator it = requests->Begin(); 2507 it != requests->End(); 2508 it++) { 2509 delete *it; 2510 } 2511 } 2512 } 2513 2514 2515 // #pragma mark - 2516 2517 // QueryDomainIntersectsWith 2518 bool 2519 ClientConnection::QueryDomainIntersectsWith(Volume* volume) 2520 { 2521 // Iterate through the the client volumes and check whether any one contains 2522 // the supplied volume or its root dir is on the volume. We don't check 2523 // directory inclusion for the latter, since we don't need to query the 2524 // volume, if the client volume is located on a volume mounted somewhere 2525 // under the supplied volume (e.g. the root FS contains everything, but does 2526 // seldomly need to be queried). 2527 VolumeManager* volumeManager = VolumeManager::GetDefault(); 2528 AutoLocker<VolumeMap> volumesLocker(fVolumes); 2529 for (VolumeMap::Iterator it = fVolumes->GetIterator(); it.HasNext();) { 2530 ClientVolume* clientVolume = it.Next().value; 2531 Directory* volumeRoot = volume->GetRootDirectory(); 2532 Directory* clientVolumeRoot = clientVolume->GetRootDirectory(); 2533 if (volumeManager->DirectoryContains(clientVolumeRoot, volumeRoot, true) 2534 || volumeRoot->GetVolumeID() == clientVolumeRoot->GetVolumeID()) { 2535 return true; 2536 } 2537 } 2538 2539 return false; 2540 } 2541 2542 // ProcessQueryEvent 2543 void 2544 ClientConnection::ProcessQueryEvent(NodeMonitoringEvent* event) 2545 { 2546 dev_t volumeID; 2547 ino_t directoryID; 2548 if (event->opcode == B_ENTRY_CREATED) { 2549 // "entry created" event 2550 EntryCreatedEvent* createdEvent 2551 = dynamic_cast<EntryCreatedEvent*>(event); 2552 if (!createdEvent) 2553 return; 2554 volumeID = createdEvent->volumeID; 2555 directoryID = createdEvent->directoryID; 2556 2557 } else if (event->opcode == B_ENTRY_REMOVED) { 2558 // "entry removed" event 2559 EntryRemovedEvent* removedEvent 2560 = dynamic_cast<EntryRemovedEvent*>(event); 2561 if (!removedEvent) 2562 return; 2563 volumeID = removedEvent->volumeID; 2564 directoryID = removedEvent->directoryID; 2565 2566 } else { 2567 // We only support "entry created" and "entry removed" query events. 2568 // "entry moved" is split by the volume manager into those. 2569 ERROR("Ignoring unexpected query event: opcode: 0x%lx\n", 2570 event->opcode); 2571 return; 2572 } 2573 PRINT(("ClientConnection::ProcessQueryEvent(): event: %p, type: %s: directory: (%ld, %lld)\n", event, typeid(event).name(), volumeID, directoryID)); 2574 2575 // create an array for the IDs of the client volumes a found entry may 2576 // reside on 2577 status_t result = B_OK; 2578 int32 volumeCount = fVolumes->Size(); 2579 int32* volumeIDs = new(std::nothrow) int32[volumeCount]; 2580 if (!volumeIDs) 2581 result = B_NO_MEMORY; 2582 ArrayDeleter<int32> volumeIDsDeleter(volumeIDs); 2583 2584 HasQueryPermissionClientVolumeFilter filter; 2585 2586 // load the directory the concerned entry belongs/belonged to 2587 Directory* directory; 2588 int32 concernedVolumes = 0; 2589 if (VolumeManager::GetDefault()->LoadDirectory(volumeID, directoryID, 2590 &directory) == B_OK) { 2591 // find out, which client volumes the directory is located in 2592 concernedVolumes = _GetContainingClientVolumes(directory, volumeIDs, 2593 volumeCount, &filter); 2594 } else { 2595 // Failed to load the directory, so maybe it has already been 2596 // deleted. For "entry removed" events, we consider all client 2597 // volumes to be notified -- those that don't know the entry will 2598 // ignore the event. 2599 if (event->opcode == B_ENTRY_REMOVED) { 2600 concernedVolumes = _GetAllClientVolumeIDs(volumeIDs, volumeCount, 2601 &filter); 2602 } 2603 } 2604 2605 // now push the event for each concerned client volume 2606 for (int32 i = 0; i < concernedVolumes; i++) 2607 _PushNodeMonitoringEvent(volumeIDs[i], event); 2608 // TODO: More than one volume will usually only be concerned in case of 2609 // nested client volumes. We could optimize the case by having an array of 2610 // volume IDs in the respective requests sent over the net (just as in the 2611 // ReadQueryReply). 2612 } 2613 2614 2615 // #pragma mark - 2616 2617 // _Close 2618 void 2619 ClientConnection::_Close() 2620 { 2621 // terminate node monitoring processor 2622 CloseNodeMonitoringEventQueue(); 2623 if (fNodeMonitoringProcessor >= 0 2624 && find_thread(NULL) != fNodeMonitoringProcessor) { 2625 int32 result; 2626 wait_for_thread(fNodeMonitoringProcessor, &result); 2627 // The variable is not unset, when this is the node monitoring 2628 // processor thread -- which is good, since the destructor will 2629 // wait for the thread in this case. 2630 fNodeMonitoringProcessor = -1; 2631 } 2632 if (fConnection) 2633 fConnection->Close(); 2634 // notify the listener 2635 ClientConnectionListener* listener = fListener; 2636 fListener = NULL; 2637 if (listener) 2638 listener->ClientConnectionClosed(this, fError); 2639 } 2640 2641 // _MarkClosed 2642 void 2643 ClientConnection::_MarkClosed(bool error) 2644 { 2645 AutoLocker<Locker> _(fLock); 2646 if (!fClosed) { 2647 fClosed = true; 2648 fError = error; 2649 } 2650 } 2651 2652 // _GetNodeInfo 2653 void 2654 ClientConnection::_GetNodeInfo(Node* node, NodeInfo* info) 2655 { 2656 if (node && info) { 2657 info->st = node->GetStat(); 2658 info->revision = VolumeManager::GetDefault()->GetRevision(); 2659 } 2660 } 2661 2662 // _GetEntryInfo 2663 void 2664 ClientConnection::_GetEntryInfo(Entry* entry, EntryInfo* info) 2665 { 2666 if (entry && info) { 2667 info->directoryID.volumeID = entry->GetVolumeID(); 2668 info->directoryID.nodeID = entry->GetDirectoryID(); 2669 info->name.SetTo(entry->GetName()); 2670 _GetNodeInfo(entry->GetNode(), &info->nodeInfo); 2671 } 2672 } 2673 2674 // _GetAttrInfo 2675 status_t 2676 ClientConnection::_GetAttrInfo(Request* request, const char* name, 2677 const attr_info& attrInfo, const void* data, AttributeInfo* info) 2678 { 2679 if (!request || !name || !info) 2680 return B_BAD_VALUE; 2681 2682 info->name.SetTo(name); 2683 info->info = attrInfo; 2684 data = (attrInfo.size > 0 ? data : NULL); 2685 int32 dataSize = (data ? attrInfo.size : 0); 2686 info->data.SetTo(data, dataSize); 2687 2688 // if the client has inverse endianess, swap the type, if we don't know it 2689 if (fInverseClientEndianess) { 2690 if (_KnownAttributeType(info->info.type)) { 2691 // we need to convert the data, if supplied 2692 if (data) { 2693 // allocate a buffer 2694 RequestBuffer* requestBuffer = RequestBuffer::Create(dataSize); 2695 if (!requestBuffer) 2696 return B_NO_MEMORY; 2697 2698 // convert the data 2699 memcpy(requestBuffer->GetData(), data, dataSize); 2700 _ConvertAttribute(info->info, requestBuffer->GetData()); 2701 } 2702 } else 2703 info->info.type = B_SWAP_INT32(info->info.type); 2704 } 2705 2706 return B_OK; 2707 } 2708 2709 // _GetAttrDirInfo 2710 status_t 2711 ClientConnection::_GetAttrDirInfo(Request* request, AttributeDirectory* attrDir, 2712 AttrDirInfo* info) 2713 { 2714 if (!request || !attrDir || !info || !attrDir->IsAttrDirValid()) 2715 return B_BAD_VALUE; 2716 2717 // add the attribute infos 2718 for (Attribute* attribute = attrDir->GetFirstAttribute(); 2719 attribute; 2720 attribute = attrDir->GetNextAttribute(attribute)) { 2721 // get the attribute info 2722 AttributeInfo attrInfo; 2723 attr_info bAttrInfo; 2724 attribute->GetInfo(&bAttrInfo); 2725 status_t error = _GetAttrInfo(request, attribute->GetName(), bAttrInfo, 2726 attribute->GetData(), &attrInfo); 2727 2728 // append it 2729 if (error == B_OK) 2730 error = info->attributeInfos.Append(attrInfo); 2731 if (error != B_OK) 2732 return error; 2733 } 2734 2735 info->revision = VolumeManager::GetDefault()->GetRevision(); 2736 info->isValid = true; 2737 2738 return B_OK; 2739 } 2740 2741 // _CreateVolume 2742 status_t 2743 ClientConnection::_CreateVolume(ClientVolume** _volume) 2744 { 2745 // create and init the volume 2746 ClientVolume* volume = new(std::nothrow) ClientVolume(fSecurityContextLock, 2747 this); 2748 if (!volume) 2749 return B_NO_MEMORY; 2750 status_t error = volume->Init(); 2751 if (error != B_OK) { 2752 delete volume; 2753 return error; 2754 } 2755 2756 // add it to the volume map 2757 AutoLocker<VolumeMap> locker(fVolumes); 2758 error = fVolumes->Put(volume->GetID(), volume); 2759 locker.Unlock(); 2760 2761 if (error == B_OK) 2762 *_volume = volume; 2763 else 2764 delete volume; 2765 2766 return error; 2767 } 2768 2769 // _GetVolume 2770 ClientVolume* 2771 ClientConnection::_GetVolume(int32 id) 2772 { 2773 AutoLocker<VolumeMap> _(fVolumes); 2774 ClientVolume* volume = fVolumes->Get(id); 2775 if (!volume || volume->IsRemoved()) 2776 return NULL; 2777 volume->AcquireReference(); 2778 return volume; 2779 } 2780 2781 // _PutVolume 2782 // 2783 // The VolumeManager may be locked, but no other lock must be held. 2784 void 2785 ClientConnection::_PutVolume(ClientVolume* volume) 2786 { 2787 if (!volume) 2788 return; 2789 2790 // decrement reference counter and remove the volume, if 0 2791 AutoLocker<VolumeMap> locker(fVolumes); 2792 bool removed = (volume->ReleaseReference() == 1 && volume->IsRemoved()); 2793 if (removed) 2794 fVolumes->Remove(volume->GetID()); 2795 locker.Unlock(); 2796 2797 if (removed) { 2798 VolumeManagerLocker managerLocker; 2799 delete volume; 2800 } 2801 } 2802 2803 // _UnmountVolume 2804 // 2805 // The caller must have a reference to the volume. 2806 void 2807 ClientConnection::_UnmountVolume(ClientVolume* volume) 2808 { 2809 if (!volume) 2810 return; 2811 AutoLocker<VolumeMap> locker(fVolumes); 2812 volume->MarkRemoved(); 2813 locker.Unlock(); 2814 2815 // push a notification event 2816 if (VolumeUnmountedEvent* event = new(std::nothrow) VolumeUnmountedEvent) { 2817 VolumeManagerLocker managerLocker; 2818 2819 event->opcode = B_DEVICE_UNMOUNTED; 2820 _PushNodeMonitoringEvent(volume->GetID(), event); 2821 event->ReleaseReference(); 2822 } 2823 } 2824 2825 // _UnmountAllVolumes 2826 void 2827 ClientConnection::_UnmountAllVolumes() 2828 { 2829 while (true) { 2830 // To avoid heap allocation (which can fail) we unmount the volumes 2831 // chunkwise. 2832 // get the volumes 2833 const int32 volumeChunkSize = 32; 2834 ClientVolume* volumes[volumeChunkSize]; 2835 int32 volumeCount = 0; 2836 AutoLocker<VolumeMap> volumesLocker(fVolumes); 2837 for (VolumeMap::Iterator it = fVolumes->GetIterator(); it.HasNext();) { 2838 if (ClientVolume* volume = _GetVolume(it.Next().value->GetID())) { 2839 volumes[volumeCount++] = volume; 2840 } 2841 if (volumeCount == volumeChunkSize) 2842 break; 2843 } 2844 volumesLocker.Unlock(); 2845 2846 // unmount and put the volumes 2847 for (int32 i = 0; i < volumeCount; i++) { 2848 ClientVolume* volume = volumes[i]; 2849 _UnmountVolume(volume); 2850 _PutVolume(volume); 2851 } 2852 2853 if (volumeCount < volumeChunkSize) 2854 break; 2855 } 2856 } 2857 2858 // _NodeMonitoringProcessorEntry 2859 int32 2860 ClientConnection::_NodeMonitoringProcessorEntry(void* data) 2861 { 2862 return ((ClientConnection*)data)->_NodeMonitoringProcessor(); 2863 } 2864 2865 // _NodeMonitoringProcessor 2866 int32 2867 ClientConnection::_NodeMonitoringProcessor() 2868 { 2869 while (!fClosed) { 2870 // get the next request 2871 NodeMonitoringRequest* request; 2872 status_t error = fNodeMonitoringEvents->Pop(&request); 2873 2874 // get a client connection reference 2875 ConnectionReference connectionReference(this); 2876 if (!connectionReference.IsValid()) 2877 return B_OK; 2878 2879 // No request? Next round... 2880 if (error != B_OK) 2881 continue; 2882 ObjectDeleter<NodeMonitoringRequest> requestDeleter(request); 2883 2884 // send the request 2885 if (error == B_OK) { 2886 error = fConnection->SendRequest(request); 2887 if (error != B_OK) { 2888 ERROR(("ClientConnection::_NodeMonitoringProcessor(): " 2889 "Failed to send request.\n")); 2890 } 2891 } 2892 } 2893 return 0; 2894 } 2895 2896 // _PushNodeMonitoringEvent 2897 // 2898 // The caller must have a connection reference. Moreover the VolumeManager 2899 // must be locked. 2900 status_t 2901 ClientConnection::_PushNodeMonitoringEvent(int32 volumeID, 2902 NodeMonitoringEvent* event) 2903 { 2904 if (!event) 2905 return B_BAD_VALUE; 2906 2907 // get the volume 2908 ClientVolume* volume = _GetVolume(volumeID); 2909 if (!volume && event->opcode != B_DEVICE_UNMOUNTED) 2910 return B_BAD_VALUE; 2911 ClientVolumePutter volumePutter(this, volume); 2912 2913 // create a node monitoring request 2914 NodeMonitoringRequest* request = NULL; 2915 status_t error = B_ERROR; 2916 switch (event->opcode) { 2917 case B_ENTRY_CREATED: 2918 error = _EntryCreated(volume, 2919 dynamic_cast<EntryCreatedEvent*>(event), request); 2920 break; 2921 case B_ENTRY_REMOVED: 2922 error = _EntryRemoved(volume, 2923 dynamic_cast<EntryRemovedEvent*>(event), request); 2924 break; 2925 case B_ENTRY_MOVED: 2926 error = _EntryMoved(volume, 2927 dynamic_cast<EntryMovedEvent*>(event), request); 2928 break; 2929 case B_STAT_CHANGED: 2930 error = _NodeStatChanged(volume, 2931 dynamic_cast<StatChangedEvent*>(event), request); 2932 break; 2933 case B_ATTR_CHANGED: 2934 error = _NodeAttributeChanged(volume, 2935 dynamic_cast<AttributeChangedEvent*>(event), request); 2936 break; 2937 case B_DEVICE_UNMOUNTED: 2938 error = B_OK; 2939 break; 2940 } 2941 2942 // replace all data buffers -- when the request is actually sent, they 2943 // might no longer exist 2944 if (error == B_OK) 2945 error = RequestBufferReplacer().ReplaceBuffer(request); 2946 2947 if (error == B_OK) { 2948 // common initialization 2949 request->volumeID = volumeID; 2950 request->opcode = event->opcode; 2951 request->revision = VolumeManager::GetDefault()->GetRevision(); 2952 2953 // push the request 2954 error = fNodeMonitoringEvents->Push(request); 2955 if (error != B_OK) 2956 delete request; 2957 } 2958 2959 return error; 2960 } 2961 2962 // _EntryCreated 2963 status_t 2964 ClientConnection::_EntryCreated(ClientVolume* volume, EntryCreatedEvent* event, 2965 NodeMonitoringRequest*& _request) 2966 { 2967 // allocate the request 2968 EntryCreatedRequest* request = new(std::nothrow) EntryCreatedRequest; 2969 if (!request) 2970 return B_NO_MEMORY; 2971 ObjectDeleter<NodeMonitoringRequest> requestDeleter(request); 2972 2973 // get the name 2974 const char* name = event->name.GetString(); 2975 2976 // set the request fields 2977 request->directoryID = NodeID(event->volumeID, event->directoryID); 2978 request->nodeID = NodeID(event->volumeID, event->nodeID); 2979 request->name.SetTo(name); 2980 if (event->queryHandler) { 2981 request->port = event->remotePort; 2982 request->token = event->remoteToken; 2983 request->queryUpdate = true; 2984 } else 2985 request->queryUpdate = false; 2986 2987 // try to get an entry info 2988 Entry* entry; 2989 if (VolumeManager::GetDefault()->LoadEntry(event->volumeID, 2990 event->directoryID, name, true, &entry) == B_OK 2991 && entry->GetNode()->GetVolumeID() == event->volumeID 2992 && entry->GetNode()->GetID() == event->nodeID) { 2993 _GetEntryInfo(entry, &request->entryInfo); 2994 request->entryInfoValid = true; 2995 } else 2996 request->entryInfoValid = false; 2997 2998 requestDeleter.Detach(); 2999 _request = request; 3000 return B_OK; 3001 } 3002 3003 // _EntryRemoved 3004 status_t 3005 ClientConnection::_EntryRemoved(ClientVolume* volume, EntryRemovedEvent* event, 3006 NodeMonitoringRequest*& _request) 3007 { 3008 // special handling, if it is the root node of the client volume that has 3009 // been removed 3010 if (!event->queryHandler 3011 && NodeRef(event->nodeVolumeID, event->nodeID) 3012 == volume->GetRootNodeRef()) { 3013 NoAllocEntryRef ref(event->nodeVolumeID, event->nodeID, "."); 3014 BEntry entry; 3015 if (FDManager::SetEntry(&entry, &ref) != B_OK || !entry.Exists()) 3016 _UnmountVolume(volume); 3017 3018 // don't send the "entry removed" event 3019 return B_ERROR; 3020 } 3021 3022 // allocate the request 3023 EntryRemovedRequest* request = new(std::nothrow) EntryRemovedRequest; 3024 if (!request) 3025 return B_NO_MEMORY; 3026 ObjectDeleter<NodeMonitoringRequest> requestDeleter(request); 3027 3028 // get the name 3029 const char* name = event->name.GetString(); 3030 3031 // set the request fields 3032 request->directoryID = NodeID(event->volumeID, event->directoryID); 3033 request->nodeID = NodeID(event->nodeVolumeID, event->nodeID); 3034 request->name.SetTo(name); 3035 if (event->queryHandler) { 3036 request->port = event->remotePort; 3037 request->token = event->remoteToken; 3038 request->queryUpdate = true; 3039 } else 3040 request->queryUpdate = false; 3041 3042 requestDeleter.Detach(); 3043 _request = request; 3044 return B_OK; 3045 } 3046 3047 // _EntryMoved 3048 status_t 3049 ClientConnection::_EntryMoved(ClientVolume* volume, EntryMovedEvent* event, 3050 NodeMonitoringRequest*& _request) 3051 { 3052 // allocate the request 3053 EntryMovedRequest* request = new(std::nothrow) EntryMovedRequest; 3054 if (!request) 3055 return B_NO_MEMORY; 3056 ObjectDeleter<NodeMonitoringRequest> requestDeleter(request); 3057 3058 // allocate memory for the names 3059 int32 fromNameLen = event->fromName.GetLength(); 3060 const char* fromName 3061 = (fromNameLen > 0 ? event->fromName.GetString() : NULL); 3062 const char* toName = event->toName.GetString(); 3063 3064 // set the request fields 3065 request->fromDirectoryID = NodeID(event->volumeID, event->fromDirectoryID); 3066 request->toDirectoryID = NodeID(event->volumeID, event->toDirectoryID); 3067 request->nodeID = NodeID(event->nodeVolumeID, event->nodeID); 3068 request->fromName.SetTo(fromName); 3069 request->toName.SetTo(toName); 3070 request->queryUpdate = false; 3071 3072 // try to get an entry info 3073 Entry* entry; 3074 if (VolumeManager::GetDefault()->LoadEntry(event->volumeID, 3075 event->toDirectoryID, toName, true, &entry) == B_OK 3076 && entry->GetNode()->GetVolumeID() == event->nodeVolumeID 3077 && entry->GetNode()->GetID() == event->nodeID) { 3078 _GetEntryInfo(entry, &request->entryInfo); 3079 request->entryInfoValid = true; 3080 } else 3081 request->entryInfoValid = false; 3082 3083 requestDeleter.Detach(); 3084 _request = request; 3085 return B_OK; 3086 } 3087 3088 // _NodeStatChanged 3089 status_t 3090 ClientConnection::_NodeStatChanged(ClientVolume* volume, 3091 StatChangedEvent* event, NodeMonitoringRequest*& _request) 3092 { 3093 // get the node 3094 Node* node = volume->GetNode(event->volumeID, event->nodeID); 3095 if (!node) 3096 return B_ENTRY_NOT_FOUND; 3097 3098 // allocate the request 3099 StatChangedRequest* request = new(std::nothrow) StatChangedRequest; 3100 if (!request) 3101 return B_NO_MEMORY; 3102 ObjectDeleter<NodeMonitoringRequest> requestDeleter(request); 3103 3104 // set the request fields 3105 request->nodeID = NodeID(event->volumeID, event->nodeID); 3106 _GetNodeInfo(node, &request->nodeInfo); 3107 request->queryUpdate = false; 3108 3109 requestDeleter.Detach(); 3110 _request = request; 3111 return B_OK; 3112 } 3113 3114 // _NodeAttributeChanged 3115 status_t 3116 ClientConnection::_NodeAttributeChanged(ClientVolume* volume, 3117 AttributeChangedEvent* event, NodeMonitoringRequest*& _request) 3118 { 3119 // get the node 3120 Node* node = volume->GetNode(event->volumeID, event->nodeID); 3121 if (!node) 3122 return B_ENTRY_NOT_FOUND; 3123 3124 // update the attribute directory 3125 bool removed = false; 3126 bool valid = false; 3127 attr_info info; 3128 const void* data = NULL; 3129 status_t error = node->UpdateAttribute(event->attribute.GetString(), 3130 &removed, &info, &data); 3131 valid = (error == B_OK); 3132 3133 // allocate the request 3134 AttributeChangedRequest* request = new(std::nothrow) AttributeChangedRequest; 3135 if (!request) 3136 return B_NO_MEMORY; 3137 ObjectDeleter<NodeMonitoringRequest> requestDeleter(request); 3138 3139 // get an attr dir info, if the directory is valid 3140 if (node->IsAttrDirValid()) { 3141 status_t error = _GetAttrDirInfo(request, node, &request->attrDirInfo); 3142 if (error != B_OK) 3143 return error; 3144 } 3145 3146 // get name and the data size 3147 int32 dataSize = (data ? info.size : 0); 3148 const char* name = event->attribute.GetString(); 3149 3150 // set the request fields 3151 request->nodeID = NodeID(event->volumeID, event->nodeID); 3152 request->attrInfo.name.SetTo(name); 3153 request->valid = valid; 3154 request->removed = removed; 3155 if (!removed && valid) { 3156 request->attrInfo.info = info; 3157 request->attrInfo.data.SetTo(data, dataSize); 3158 } 3159 request->queryUpdate = false; 3160 3161 requestDeleter.Detach(); 3162 _request = request; 3163 return B_OK; 3164 } 3165 3166 // _KnownAttributeType 3167 bool 3168 ClientConnection::_KnownAttributeType(type_code type) 3169 { 3170 if (!fInverseClientEndianess) 3171 return false; 3172 3173 switch (type) { 3174 case B_BOOL_TYPE: 3175 case B_CHAR_TYPE: 3176 case B_COLOR_8_BIT_TYPE: 3177 case B_DOUBLE_TYPE: 3178 case B_FLOAT_TYPE: 3179 case B_GRAYSCALE_8_BIT_TYPE: 3180 case B_INT64_TYPE: 3181 case B_INT32_TYPE: 3182 case B_INT16_TYPE: 3183 case B_INT8_TYPE: 3184 case B_MESSAGE_TYPE: 3185 case B_MESSENGER_TYPE: 3186 case B_MIME_TYPE: 3187 case B_MONOCHROME_1_BIT_TYPE: 3188 case B_OFF_T_TYPE: 3189 case B_POINTER_TYPE: 3190 case B_POINT_TYPE: 3191 case B_RECT_TYPE: 3192 case B_REF_TYPE: 3193 case B_RGB_COLOR_TYPE: 3194 case B_SIZE_T_TYPE: 3195 case B_SSIZE_T_TYPE: 3196 case B_STRING_TYPE: 3197 case B_TIME_TYPE: 3198 case B_UINT64_TYPE: 3199 case B_UINT32_TYPE: 3200 case B_UINT16_TYPE: 3201 case B_UINT8_TYPE: 3202 case B_ASCII_TYPE: 3203 case B_MIME_STRING_TYPE: 3204 return true; 3205 3206 //B_RGB_32_BIT_TYPE: We could translate it, but it's heavy... 3207 } 3208 3209 return false; 3210 } 3211 3212 // _ConvertAttribute 3213 void 3214 ClientConnection::_ConvertAttribute(const attr_info& info, void* buffer) 3215 { 3216 swap_data(info.type, buffer, info.size, B_SWAP_ALWAYS); 3217 } 3218 3219 3220 // #pragma mark - 3221 3222 // _OpenQuery 3223 status_t 3224 ClientConnection::_OpenQuery(const char* queryString, uint32 flags, 3225 port_id remotePort, int32 remoteToken, QueryHandle** _handle) 3226 { 3227 if (!queryString || !_handle) 3228 return B_BAD_VALUE; 3229 3230 // open query 3231 QueryHandle* queryHandle; 3232 status_t error = VolumeManager::GetDefault()->OpenQuery(this, queryString, 3233 flags, remotePort, remoteToken, &queryHandle); 3234 if (error != B_OK) 3235 return error; 3236 BReference<QueryHandle> handleReference(queryHandle, true); 3237 3238 // lock the handle 3239 queryHandle->Lock(); 3240 3241 // add the handle 3242 error = fQueryHandles->AddNodeHandle(queryHandle); 3243 if (error != B_OK) 3244 return error; 3245 3246 handleReference.Detach(); 3247 *_handle = queryHandle; 3248 return B_OK; 3249 } 3250 3251 // _CloseQuery 3252 status_t 3253 ClientConnection::_CloseQuery(QueryHandle* handle) 3254 { 3255 if (!handle || !fQueryHandles->RemoveNodeHandle(handle)) 3256 return B_BAD_VALUE; 3257 3258 return B_OK; 3259 } 3260 3261 // _LockQueryHandle 3262 // 3263 // VolumeManager must NOT be locked. 3264 status_t 3265 ClientConnection::_LockQueryHandle(int32 cookie, QueryHandle** _handle) 3266 { 3267 NodeHandle* handle; 3268 status_t error = fQueryHandles->LockNodeHandle(cookie, &handle); 3269 if (error == B_OK) 3270 *_handle = static_cast<QueryHandle*>(handle); 3271 return error; 3272 } 3273 3274 // _UnlockQueryHandle 3275 // 3276 // VolumeManager may or may not be locked. 3277 void 3278 ClientConnection::_UnlockQueryHandle(NodeHandle* nodeHandle) 3279 { 3280 fQueryHandles->UnlockNodeHandle(nodeHandle); 3281 } 3282 3283 3284 // #pragma mark - 3285 3286 // _GetAllClientVolumeIDs 3287 int32 3288 ClientConnection::_GetAllClientVolumeIDs(int32* volumeIDs, int32 arraySize, 3289 ClientVolumeFilter* filter) 3290 { 3291 int32 count = 0; 3292 AutoLocker<VolumeMap> volumesLocker(fVolumes); 3293 for (VolumeMap::Iterator it = fVolumes->GetIterator(); 3294 it.HasNext() && arraySize > count;) { 3295 ClientVolume* clientVolume = it.Next().value; 3296 if (!filter || filter->FilterVolume(this, clientVolume)) 3297 volumeIDs[count++] = clientVolume->GetID(); 3298 } 3299 3300 return count; 3301 } 3302 3303 // _GetContainingClientVolumes 3304 int32 3305 ClientConnection::_GetContainingClientVolumes(Directory* directory, 3306 int32* volumeIDs, int32 arraySize, ClientVolumeFilter* filter) 3307 { 3308 int32 count = 0; 3309 VolumeManager* volumeManager = VolumeManager::GetDefault(); 3310 AutoLocker<VolumeMap> volumesLocker(fVolumes); 3311 for (VolumeMap::Iterator it = fVolumes->GetIterator(); 3312 it.HasNext() && arraySize > count;) { 3313 ClientVolume* clientVolume = it.Next().value; 3314 Directory* clientVolumeRoot = clientVolume->GetRootDirectory(); 3315 if (volumeManager->DirectoryContains(clientVolumeRoot, directory, true) 3316 && (!filter || filter->FilterVolume(this, clientVolume))) { 3317 volumeIDs[count++] = clientVolume->GetID(); 3318 } 3319 } 3320 3321 return count; 3322 } 3323 3324 3325 // #pragma mark - 3326 // #pragma mark ----- ClientConnectionListener ----- 3327 3328 // constructor 3329 ClientConnectionListener::ClientConnectionListener() 3330 { 3331 } 3332 3333 // destructor 3334 ClientConnectionListener::~ClientConnectionListener() 3335 { 3336 } 3337 3338