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 SET_ERROR(result, _LockQueryHandle(request->cookie, &handle)); 959 QueryHandleUnlocker handleUnlocker(this, handle); 960 961 // close it 962 if (result == B_OK) 963 SET_ERROR(result, _CloseQuery(handle)); 964 } 965 966 // send the reply 967 CloseReply reply; 968 reply.error = result; 969 return GetChannel()->SendRequest(&reply); 970 } 971 972 // VisitReadRequest 973 status_t 974 ClientConnection::VisitReadRequest(ReadRequest* request) 975 { 976 ConnectionReference connectionReference(this); 977 if (!connectionReference.IsValid()) 978 return B_OK; 979 980 // get the volume 981 status_t result = B_OK; 982 ClientVolume* volume = _GetVolume(request->volumeID); 983 if (!volume) 984 result = B_BAD_VALUE; 985 ClientVolumePutter volumePutter(this, volume); 986 987 // get the node handle 988 NodeHandle* handle = NULL; 989 if (result == B_OK) 990 result = volume->LockNodeHandle(request->cookie, &handle); 991 NodeHandleUnlocker handleUnlocker(volume, handle); 992 993 // check if it is a file handle 994 FileHandle* fileHandle = NULL; 995 if (result == B_OK) { 996 fileHandle = dynamic_cast<FileHandle*>(handle); 997 if (!fileHandle) 998 result = B_BAD_VALUE; 999 } 1000 1001 VolumeManagerLocker managerLocker; 1002 1003 // check read permission 1004 if (result == B_OK) { 1005 Node* node = volume->GetNode(fileHandle->GetNodeRef()); 1006 if (!node || !volume->GetNodePermissions(node).ImpliesReadPermission()) 1007 result = B_PERMISSION_DENIED; 1008 } 1009 1010 managerLocker.Unlock(); 1011 1012 off_t pos = request->pos; 1013 int32 size = request->size; 1014 int32 bufferSize = min(size, kMaxReadBufferSize); 1015 // allocate a buffer 1016 uint8* buffer = NULL; 1017 if (result == B_OK) { 1018 buffer = (uint8*)malloc(bufferSize); 1019 if (!buffer) 1020 result = B_NO_MEMORY; 1021 } 1022 MemoryDeleter bufferDeleter(buffer); 1023 1024 // read as long as there are bytes left to read or an error occurs 1025 bool moreToRead = true; 1026 do { 1027 int32 bytesToRead = min(size, bufferSize); 1028 size_t bytesRead = 0; 1029 if (result == B_OK) 1030 result = fileHandle->Read(pos, buffer, bytesToRead, &bytesRead); 1031 moreToRead = (result == B_OK && bytesRead > 0 1032 && (int32)bytesRead < size); 1033 1034 // prepare the reply 1035 ReadReply reply; 1036 if (result == B_OK) { 1037 reply.pos = pos; 1038 reply.data.SetTo(buffer, bytesRead); 1039 reply.moreToCome = moreToRead; 1040 pos += bytesRead; 1041 size -= bytesRead; 1042 } 1043 1044 // send the reply 1045 reply.error = result; 1046 status_t error = GetChannel()->SendRequest(&reply); 1047 if (error != B_OK) 1048 return error; 1049 } while (moreToRead); 1050 1051 return B_OK; 1052 } 1053 1054 // VisitWriteRequest 1055 status_t 1056 ClientConnection::VisitWriteRequest(WriteRequest* request) 1057 { 1058 ConnectionReference connectionReference(this); 1059 if (!connectionReference.IsValid()) 1060 return B_OK; 1061 1062 // get the volume 1063 status_t result = B_OK; 1064 ClientVolume* volume = _GetVolume(request->volumeID); 1065 if (!volume) 1066 result = B_BAD_VALUE; 1067 ClientVolumePutter volumePutter(this, volume); 1068 1069 // get the node handle 1070 NodeHandle* handle = NULL; 1071 if (result == B_OK) 1072 result = volume->LockNodeHandle(request->cookie, &handle); 1073 NodeHandleUnlocker handleUnlocker(volume, handle); 1074 1075 // check if it is a file handle 1076 FileHandle* fileHandle = NULL; 1077 if (result == B_OK) { 1078 fileHandle = dynamic_cast<FileHandle*>(handle); 1079 if (!fileHandle) 1080 result = B_BAD_VALUE; 1081 } 1082 1083 VolumeManagerLocker managerLocker; 1084 1085 // check read permission 1086 if (result == B_OK) { 1087 Node* node = volume->GetNode(fileHandle->GetNodeRef()); 1088 if (!node || !volume->GetNodePermissions(node).ImpliesWritePermission()) 1089 result = B_PERMISSION_DENIED; 1090 } 1091 1092 managerLocker.Unlock(); 1093 1094 // write until all has been written or an error occurs 1095 off_t pos = request->pos; 1096 int32 size = request->data.GetSize(); 1097 const char* buffer = (const char*)request->data.GetData(); 1098 while (result == B_OK && size > 0) { 1099 size_t bytesWritten; 1100 result = fileHandle->Write(pos, buffer, size, &bytesWritten); 1101 if (result == B_OK) { 1102 pos += bytesWritten; 1103 buffer += bytesWritten; 1104 size -= bytesWritten; 1105 } 1106 } 1107 1108 // prepare the reply 1109 WriteReply reply; 1110 // send the reply 1111 reply.error = result; 1112 return GetChannel()->SendRequest(&reply); 1113 } 1114 1115 // VisitCreateLinkRequest 1116 status_t 1117 ClientConnection::VisitCreateLinkRequest(CreateLinkRequest* request) 1118 { 1119 ConnectionReference connectionReference(this); 1120 if (!connectionReference.IsValid()) 1121 return B_OK; 1122 1123 // get the volume 1124 status_t result = B_OK; 1125 ClientVolume* volume = _GetVolume(request->volumeID); 1126 if (!volume) 1127 result = B_BAD_VALUE; 1128 ClientVolumePutter volumePutter(this, volume); 1129 1130 VolumeManagerLocker managerLocker; 1131 1132 // get the target node 1133 Node* node = NULL; 1134 if (result == B_OK) { 1135 node = volume->GetNode(request->nodeID); 1136 if (!node) 1137 result = B_ENTRY_NOT_FOUND; 1138 } 1139 1140 // get the target node path 1141 Path targetPath; 1142 if (result == B_OK) 1143 result = node->GetPath(&targetPath); 1144 1145 // get the directory 1146 Directory* directory = NULL; 1147 if (result == B_OK) { 1148 Node* node = volume->GetNode(request->directoryID); 1149 if (node) { 1150 directory = dynamic_cast<Directory*>(node); 1151 if (!directory) 1152 result = B_NOT_A_DIRECTORY; 1153 } else 1154 result = B_ENTRY_NOT_FOUND; 1155 } 1156 1157 // check permissions 1158 if (result == B_OK) { 1159 if (!volume->GetNodePermissions(directory).ImpliesWritePermission()) 1160 result = B_PERMISSION_DENIED; 1161 } 1162 1163 // get the new entry's path 1164 Path path; 1165 if (result == B_OK) { 1166 result = directory->GetPath(&path); 1167 if (result == B_OK) 1168 result = path.Append(request->name.GetString()); 1169 } 1170 1171 managerLocker.Unlock(); 1172 1173 // create the link 1174 if (result == B_OK) { 1175 if (link(targetPath.GetPath(), path.GetPath()) < 0) 1176 result = errno; 1177 } 1178 1179 // prepare the reply 1180 CreateSymlinkReply reply; 1181 // send the reply 1182 reply.error = result; 1183 return GetChannel()->SendRequest(&reply); 1184 } 1185 1186 // VisitUnlinkRequest 1187 status_t 1188 ClientConnection::VisitUnlinkRequest(UnlinkRequest* request) 1189 { 1190 ConnectionReference connectionReference(this); 1191 if (!connectionReference.IsValid()) 1192 return B_OK; 1193 1194 // get the volume 1195 status_t result = B_OK; 1196 ClientVolume* volume = _GetVolume(request->volumeID); 1197 if (!volume) 1198 result = B_BAD_VALUE; 1199 ClientVolumePutter volumePutter(this, volume); 1200 1201 VolumeManagerLocker managerLocker; 1202 1203 // get the directory 1204 Directory* directory = NULL; 1205 if (result == B_OK) { 1206 Node* node = volume->GetNode(request->directoryID); 1207 if (node) { 1208 directory = dynamic_cast<Directory*>(node); 1209 if (!directory) 1210 result = B_NOT_A_DIRECTORY; 1211 } else 1212 result = B_ENTRY_NOT_FOUND; 1213 } 1214 1215 // check permissions 1216 if (result == B_OK) { 1217 if (!volume->GetNodePermissions(directory).ImpliesWritePermission()) 1218 result = B_PERMISSION_DENIED; 1219 } 1220 1221 // get the entry's path 1222 Path path; 1223 if (result == B_OK) { 1224 result = directory->GetPath(&path); 1225 if (result == B_OK) 1226 result = path.Append(request->name.GetString()); 1227 } 1228 1229 managerLocker.Unlock(); 1230 1231 // remove the entry 1232 if (result == B_OK) { 1233 if (unlink(path.GetPath()) < 0) 1234 result = errno; 1235 } 1236 1237 // prepare the reply 1238 UnlinkReply reply; 1239 // send the reply 1240 reply.error = result; 1241 return GetChannel()->SendRequest(&reply); 1242 } 1243 1244 // VisitCreateSymlinkRequest 1245 status_t 1246 ClientConnection::VisitCreateSymlinkRequest(CreateSymlinkRequest* request) 1247 { 1248 ConnectionReference connectionReference(this); 1249 if (!connectionReference.IsValid()) 1250 return B_OK; 1251 1252 // get the volume 1253 status_t result = B_OK; 1254 ClientVolume* volume = _GetVolume(request->volumeID); 1255 if (!volume) 1256 result = B_BAD_VALUE; 1257 ClientVolumePutter volumePutter(this, volume); 1258 1259 VolumeManagerLocker managerLocker; 1260 1261 // get the directory 1262 Directory* directory = NULL; 1263 if (result == B_OK) { 1264 Node* node = volume->GetNode(request->directoryID); 1265 if (node) { 1266 directory = dynamic_cast<Directory*>(node); 1267 if (!directory) 1268 result = B_NOT_A_DIRECTORY; 1269 } else 1270 result = B_ENTRY_NOT_FOUND; 1271 } 1272 1273 // check permissions 1274 if (result == B_OK) { 1275 if (!volume->GetNodePermissions(directory).ImpliesWritePermission()) 1276 result = B_PERMISSION_DENIED; 1277 } 1278 1279 // get the new entry's path 1280 Path path; 1281 if (result == B_OK) { 1282 result = directory->GetPath(&path); 1283 if (result == B_OK) 1284 result = path.Append(request->name.GetString()); 1285 } 1286 1287 managerLocker.Unlock(); 1288 1289 // create the symlink 1290 if (result == B_OK) { 1291 if (symlink(request->target.GetString(), path.GetPath()) < 0) 1292 result = errno; 1293 } 1294 1295 // prepare the reply 1296 CreateSymlinkReply reply; 1297 // send the reply 1298 reply.error = result; 1299 return GetChannel()->SendRequest(&reply); 1300 } 1301 1302 // VisitReadLinkRequest 1303 status_t 1304 ClientConnection::VisitReadLinkRequest(ReadLinkRequest* request) 1305 { 1306 ConnectionReference connectionReference(this); 1307 if (!connectionReference.IsValid()) 1308 return B_OK; 1309 1310 // get the volume 1311 status_t result = B_OK; 1312 ClientVolume* volume = _GetVolume(request->volumeID); 1313 if (!volume) 1314 result = B_BAD_VALUE; 1315 ClientVolumePutter volumePutter(this, volume); 1316 1317 VolumeManagerLocker managerLocker; 1318 1319 // get the node 1320 Node* node = NULL; 1321 if (result == B_OK) { 1322 node = volume->GetNode(request->nodeID); 1323 if (!node) 1324 result = B_ENTRY_NOT_FOUND; 1325 } 1326 1327 int32 bufferSize = request->maxSize; 1328 1329 // check read permission 1330 if (result == B_OK) { 1331 if (!volume->GetNodePermissions(node).ImpliesReadPermission()) 1332 result = B_PERMISSION_DENIED; 1333 } 1334 1335 // allocate a buffer 1336 void* buffer = NULL; 1337 if (result == B_OK) { 1338 if (bufferSize < 0 || bufferSize > kMaxSaneReadLinkSize) 1339 result = B_BAD_DATA; 1340 } 1341 if (result == B_OK) { 1342 buffer = malloc(bufferSize); 1343 if (!buffer) 1344 result = B_NO_MEMORY; 1345 } 1346 MemoryDeleter bufferDeleter(buffer); 1347 1348 // read the link and prepare the reply 1349 ReadLinkReply reply; 1350 int32 bytesRead = 0; 1351 if (result == B_OK) 1352 result = node->ReadSymlink((char*)buffer, bufferSize, &bytesRead); 1353 if (result == B_OK) { 1354 reply.data.SetTo(buffer, bytesRead); 1355 _GetNodeInfo(node, &reply.nodeInfo); 1356 } 1357 1358 managerLocker.Unlock(); 1359 1360 // send the reply 1361 reply.error = result; 1362 return GetChannel()->SendRequest(&reply); 1363 } 1364 1365 // VisitRenameRequest 1366 status_t 1367 ClientConnection::VisitRenameRequest(RenameRequest* request) 1368 { 1369 ConnectionReference connectionReference(this); 1370 if (!connectionReference.IsValid()) 1371 return B_OK; 1372 1373 // get the volume 1374 status_t result = B_OK; 1375 ClientVolume* volume = _GetVolume(request->volumeID); 1376 if (!volume) 1377 result = B_BAD_VALUE; 1378 ClientVolumePutter volumePutter(this, volume); 1379 1380 VolumeManagerLocker managerLocker; 1381 1382 // get the new directory 1383 Directory* newDirectory = NULL; 1384 if (result == B_OK) { 1385 Node* node = volume->GetNode(request->newDirectoryID); 1386 if (node) { 1387 newDirectory = dynamic_cast<Directory*>(node); 1388 if (!newDirectory) 1389 result = B_NOT_A_DIRECTORY; 1390 } else 1391 result = B_ENTRY_NOT_FOUND; 1392 } 1393 1394 // check permissions 1395 if (result == B_OK) { 1396 if (!volume->GetNodePermissions(newDirectory).ImpliesWritePermission()) 1397 result = B_PERMISSION_DENIED; 1398 } 1399 1400 // get the new path 1401 Path newPath; 1402 if (result == B_OK) { 1403 result = newDirectory->GetPath(&newPath); 1404 if (result == B_OK) 1405 result = newPath.Append(request->newName.GetString()); 1406 } 1407 1408 // get the old directory 1409 Directory* oldDirectory = NULL; 1410 if (result == B_OK) { 1411 Node* node = volume->GetNode(request->oldDirectoryID); 1412 if (node) { 1413 oldDirectory = dynamic_cast<Directory*>(node); 1414 if (!oldDirectory) 1415 result = B_NOT_A_DIRECTORY; 1416 } else 1417 result = B_ENTRY_NOT_FOUND; 1418 } 1419 1420 // check permissions 1421 if (result == B_OK) { 1422 if (!volume->GetNodePermissions(oldDirectory).ImpliesWritePermission()) 1423 result = B_PERMISSION_DENIED; 1424 } 1425 1426 // get the new path 1427 Path oldPath; 1428 if (result == B_OK) { 1429 result = oldDirectory->GetPath(&oldPath); 1430 if (result == B_OK) 1431 result = oldPath.Append(request->oldName.GetString()); 1432 } 1433 1434 managerLocker.Unlock(); 1435 1436 // rename the entry 1437 if (result == B_OK) { 1438 if (rename(oldPath.GetPath(), newPath.GetPath()) < 0) 1439 result = errno; 1440 } 1441 1442 // prepare the reply 1443 RenameReply reply; 1444 // send the reply 1445 reply.error = result; 1446 return GetChannel()->SendRequest(&reply); 1447 } 1448 1449 // VisitMakeDirRequest 1450 status_t 1451 ClientConnection::VisitMakeDirRequest(MakeDirRequest* request) 1452 { 1453 ConnectionReference connectionReference(this); 1454 if (!connectionReference.IsValid()) 1455 return B_OK; 1456 1457 // get the volume 1458 status_t result = B_OK; 1459 ClientVolume* volume = _GetVolume(request->volumeID); 1460 if (!volume) 1461 result = B_BAD_VALUE; 1462 ClientVolumePutter volumePutter(this, volume); 1463 1464 VolumeManagerLocker managerLocker; 1465 1466 // get the directory 1467 Directory* directory = NULL; 1468 if (result == B_OK) { 1469 Node* node = volume->GetNode(request->directoryID); 1470 if (node) { 1471 directory = dynamic_cast<Directory*>(node); 1472 if (!directory) 1473 result = B_NOT_A_DIRECTORY; 1474 } else 1475 result = B_ENTRY_NOT_FOUND; 1476 } 1477 1478 // check permissions 1479 if (result == B_OK) { 1480 if (!volume->GetNodePermissions(directory).ImpliesWritePermission()) 1481 result = B_PERMISSION_DENIED; 1482 } 1483 1484 // get the path 1485 Path path; 1486 if (result == B_OK) { 1487 result = directory->GetPath(&path); 1488 if (result == B_OK) 1489 result = path.Append(request->name.GetString()); 1490 } 1491 1492 managerLocker.Unlock(); 1493 1494 // create the directory 1495 if (result == B_OK) { 1496 if (mkdir(path.GetPath(), request->mode) < 0) 1497 result = errno; 1498 } 1499 1500 // prepare the reply 1501 MakeDirReply reply; 1502 // send the reply 1503 reply.error = result; 1504 return GetChannel()->SendRequest(&reply); 1505 } 1506 1507 // VisitRemoveDirRequest 1508 status_t 1509 ClientConnection::VisitRemoveDirRequest(RemoveDirRequest* request) 1510 { 1511 ConnectionReference connectionReference(this); 1512 if (!connectionReference.IsValid()) 1513 return B_OK; 1514 1515 // get the volume 1516 status_t result = B_OK; 1517 ClientVolume* volume = _GetVolume(request->volumeID); 1518 if (!volume) 1519 result = B_BAD_VALUE; 1520 ClientVolumePutter volumePutter(this, volume); 1521 1522 VolumeManagerLocker managerLocker; 1523 1524 // get the directory 1525 Directory* directory = NULL; 1526 if (result == B_OK) { 1527 Node* node = volume->GetNode(request->directoryID); 1528 if (node) { 1529 directory = dynamic_cast<Directory*>(node); 1530 if (!directory) 1531 result = B_NOT_A_DIRECTORY; 1532 } else 1533 result = B_ENTRY_NOT_FOUND; 1534 } 1535 1536 // check permissions 1537 if (result == B_OK) { 1538 if (!volume->GetNodePermissions(directory).ImpliesWritePermission()) 1539 result = B_PERMISSION_DENIED; 1540 } 1541 1542 // get the path 1543 Path path; 1544 if (result == B_OK) { 1545 result = directory->GetPath(&path); 1546 if (result == B_OK) 1547 result = path.Append(request->name.GetString()); 1548 } 1549 1550 managerLocker.Unlock(); 1551 1552 // remove the directory 1553 if (result == B_OK) { 1554 if (rmdir(path.GetPath()) < 0) 1555 result = errno; 1556 } 1557 1558 // prepare the reply 1559 RemoveDirReply reply; 1560 // send the reply 1561 reply.error = result; 1562 return GetChannel()->SendRequest(&reply); 1563 } 1564 1565 // VisitOpenDirRequest 1566 status_t 1567 ClientConnection::VisitOpenDirRequest(OpenDirRequest* request) 1568 { 1569 ConnectionReference connectionReference(this); 1570 if (!connectionReference.IsValid()) 1571 return B_OK; 1572 1573 // get the volume 1574 status_t result = B_OK; 1575 ClientVolume* volume = _GetVolume(request->volumeID); 1576 if (!volume) 1577 result = B_BAD_VALUE; 1578 ClientVolumePutter volumePutter(this, volume); 1579 1580 VolumeManagerLocker managerLocker; 1581 1582 // get the directory 1583 Directory* directory = NULL; 1584 if (result == B_OK) { 1585 Node* node = volume->GetNode(request->nodeID); 1586 if (node) { 1587 directory = dynamic_cast<Directory*>(node); 1588 if (!directory) 1589 result = B_NOT_A_DIRECTORY; 1590 } else 1591 result = B_ENTRY_NOT_FOUND; 1592 } 1593 1594 // check permission 1595 if (result == B_OK) { 1596 if (!volume->GetNodePermissions(directory).ImpliesReadDirPermission()) 1597 result = B_PERMISSION_DENIED; 1598 } 1599 1600 // open the directory 1601 DirIterator* handle = NULL; 1602 if (result == B_OK) 1603 result = volume->OpenDir(directory, &handle); 1604 NodeHandleUnlocker handleUnlocker(volume, handle); 1605 1606 // prepare the reply 1607 OpenDirReply reply; 1608 if (result == B_OK) { 1609 _GetNodeInfo(directory, &reply.nodeInfo); 1610 reply.cookie = handle->GetCookie(); 1611 } 1612 else { 1613 if (directory) 1614 PRINT("OpenDir() failed: client volume: %ld, node: (%ld, %lld)\n", 1615 volume->GetID(), directory->GetVolumeID(), directory->GetID()); 1616 } 1617 1618 managerLocker.Unlock(); 1619 1620 // send the reply 1621 reply.error = result; 1622 status_t error = GetChannel()->SendRequest(&reply); 1623 1624 // close the handle, if a send error occurred 1625 if (error != B_OK && result == B_OK) 1626 volume->Close(handle); 1627 1628 return error; 1629 } 1630 1631 // VisitReadDirRequest 1632 status_t 1633 ClientConnection::VisitReadDirRequest(ReadDirRequest* request) 1634 { 1635 ConnectionReference connectionReference(this); 1636 if (!connectionReference.IsValid()) 1637 return B_OK; 1638 1639 // get the volume 1640 status_t result = B_OK; 1641 ClientVolume* volume = _GetVolume(request->volumeID); 1642 if (!volume) 1643 result = B_BAD_VALUE; 1644 ClientVolumePutter volumePutter(this, volume); 1645 1646 // get the node handle 1647 NodeHandle* handle = NULL; 1648 if (result == B_OK) 1649 result = volume->LockNodeHandle(request->cookie, &handle); 1650 NodeHandleUnlocker handleUnlocker(volume, handle); 1651 1652 // check if it is a directory iterator 1653 DirIterator* iterator = NULL; 1654 if (result == B_OK) { 1655 iterator = dynamic_cast<DirIterator*>(handle); 1656 if (!iterator) 1657 result = B_BAD_VALUE; 1658 } 1659 1660 VolumeManagerLocker managerLocker; 1661 1662 // get the directory 1663 Directory* directory = NULL; 1664 if (result == B_OK) { 1665 Node* node = volume->GetNode(iterator->GetNodeRef()); 1666 if (node) { 1667 directory = dynamic_cast<Directory*>(node); 1668 if (!directory) 1669 result = B_NOT_A_DIRECTORY; 1670 } else 1671 result = B_ENTRY_NOT_FOUND; 1672 } 1673 1674 // check read permission 1675 if (result == B_OK) { 1676 if (!volume->GetNodePermissions(directory).ImpliesReadDirPermission()) 1677 result = B_PERMISSION_DENIED; 1678 } 1679 1680 if (result == B_OK) { 1681 PRINT("ReadDir: (%ld, %lld)\n", request->volumeID, directory->GetID()); 1682 } 1683 1684 // rewind, if requested 1685 if (result == B_OK && request->rewind) 1686 iterator->Rewind(); 1687 1688 // read the directory 1689 bool done = false; 1690 ReadDirReply reply; 1691 int32 toRead = request->count; 1692 while (result == B_OK && toRead > 0) { 1693 // get the next entry 1694 Entry* entry = iterator->NextEntry(); 1695 if (!entry) { 1696 done = true; 1697 break; 1698 } 1699 1700 // get and add an entry info 1701 EntryInfo entryInfo; 1702 _GetEntryInfo(entry, &entryInfo); 1703 result = reply.entryInfos.Append(entryInfo); 1704 1705 toRead--; 1706 } 1707 1708 reply.revision = VolumeManager::GetDefault()->GetRevision(); 1709 1710 //PRINT(("ReadDir: (%lld) -> (%lx, %ld, dir: %lld, node: %lld, `%s')\n", 1711 //directoryID, reply.error, reply.entryInfos.CountElements(), 1712 //reply.entryInfo.directoryID, 1713 //reply.entryInfo.nodeID, reply.entryInfo.name.GetString())); 1714 if (directory) { 1715 PRINT("ReadDir done: volume: %ld, (%ld, %lld) -> (%lx, %ld)\n", 1716 volume->GetID(), directory->GetVolumeID(), directory->GetID(), result, 1717 reply.entryInfos.CountElements()); 1718 } 1719 1720 managerLocker.Unlock(); 1721 1722 // send the reply 1723 reply.error = result; 1724 reply.done = (result != B_OK || done); 1725 return GetChannel()->SendRequest(&reply); 1726 } 1727 1728 // VisitWalkRequest 1729 status_t 1730 ClientConnection::VisitWalkRequest(WalkRequest* request) 1731 { 1732 ConnectionReference connectionReference(this); 1733 if (!connectionReference.IsValid()) 1734 return B_OK; 1735 1736 // get the volume 1737 status_t result = B_OK; 1738 ClientVolume* volume = _GetVolume(request->volumeID); 1739 if (!volume) 1740 result = B_BAD_VALUE; 1741 ClientVolumePutter volumePutter(this, volume); 1742 1743 VolumeManagerLocker managerLocker; 1744 1745 // get the directory 1746 Directory* directory = NULL; 1747 if (result == B_OK) { 1748 Node* node = volume->GetNode(request->nodeID); 1749 if (node) { 1750 directory = dynamic_cast<Directory*>(node); 1751 if (!directory) 1752 result = B_NOT_A_DIRECTORY; 1753 } else 1754 result = B_ENTRY_NOT_FOUND; 1755 } 1756 1757 // check permission 1758 if (result == B_OK) { 1759 if (!volume->GetNodePermissions(directory) 1760 .ImpliesResolveDirEntryPermission()) { 1761 result = B_PERMISSION_DENIED; 1762 } 1763 } 1764 1765 WalkReply reply; 1766 char linkPath[B_PATH_NAME_LENGTH]; 1767 if (result == B_OK) { 1768 // load the entry 1769 Entry* entry; 1770 result = volume->LoadEntry(directory, request->name.GetString(), 1771 &entry); 1772 1773 // fill in the reply 1774 if (result == B_OK) { 1775 _GetEntryInfo(entry, &reply.entryInfo); 1776 1777 // resolve a symlink, if desired 1778 Node* node = entry->GetNode(); 1779 if (request->resolveLink && node->IsSymlink()) { 1780 result = node->ReadSymlink(linkPath, B_PATH_NAME_LENGTH); 1781 if (result == B_OK) 1782 reply.linkPath.SetTo(linkPath); 1783 } 1784 } 1785 } 1786 1787 managerLocker.Unlock(); 1788 1789 // send the reply 1790 reply.error = result; 1791 PRINT("Walk: (%ld, %lld, `%s') -> (%lx, (%ld, %lld), `%s')\n", 1792 request->nodeID.volumeID, request->nodeID.nodeID, 1793 request->name.GetString(), result, 1794 reply.entryInfo.nodeInfo.st.st_dev, 1795 reply.entryInfo.nodeInfo.st.st_ino, 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, (off_t)0); 2049 int32 originalSize = max(request->size, (int32)0); 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((off_t)0, 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, (off_t)0); 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: %" B_PRIdOFF ", size: %" B_PRId32 "\n", 2207 request->name.GetString(), 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; 2369 QueryHandle* handle = NULL; 2370 result = _OpenQuery(request->queryString.GetString(), 2371 request->flags, request->port, request->token, &handle); 2372 QueryHandleUnlocker handleUnlocker(this, handle); 2373 2374 // prepare the reply 2375 OpenQueryReply reply; 2376 if (result == B_OK) 2377 reply.cookie = handle->GetCookie(); 2378 2379 managerLocker.Unlock(); 2380 2381 // send the reply 2382 reply.error = result; 2383 status_t error = GetChannel()->SendRequest(&reply); 2384 2385 // close the handle, if a send error occurred 2386 if (error != B_OK && result == B_OK) 2387 _CloseQuery(handle); 2388 2389 return error; 2390 } 2391 2392 // VisitReadQueryRequest 2393 status_t 2394 ClientConnection::VisitReadQueryRequest(ReadQueryRequest* request) 2395 { 2396 ConnectionReference connectionReference(this); 2397 if (!connectionReference.IsValid()) 2398 return B_OK; 2399 2400 // create an array for the IDs of the client volumes a found entry may 2401 // reside on 2402 status_t result = B_OK; 2403 int32 volumeCount = fVolumes->Size(); 2404 int32* volumeIDs = new(std::nothrow) int32[volumeCount]; 2405 if (!volumeIDs) 2406 result = B_NO_MEMORY; 2407 ArrayDeleter<int32> volumeIDsDeleter(volumeIDs); 2408 2409 // get the query handle 2410 QueryHandle* handle = NULL; 2411 if (result == B_OK) 2412 result = _LockQueryHandle(request->cookie, &handle); 2413 QueryHandleUnlocker handleUnlocker(this, handle); 2414 2415 // check if it is a query handle 2416 QueryHandle* queryHandle = NULL; 2417 if (result == B_OK) { 2418 queryHandle = dynamic_cast<QueryHandle*>(handle); 2419 if (!queryHandle) 2420 result = B_BAD_VALUE; 2421 } 2422 2423 // read the query 2424 ReadQueryReply reply; 2425 int32 countRead = 0; 2426 while (result == B_OK) { 2427 uint8 buffer[sizeof(struct dirent) + B_FILE_NAME_LENGTH]; 2428 struct dirent* dirEntry = (struct dirent*)buffer; 2429 2430 result = queryHandle->ReadDir(dirEntry, 1, &countRead); 2431 if (result != B_OK) 2432 break; 2433 if (countRead == 0) 2434 break; 2435 PRINT(" query entry: %ld, %lld, \"%s\"\n", 2436 dirEntry->d_pdev, dirEntry->d_pino, dirEntry->d_name); 2437 2438 VolumeManagerLocker managerLocker; 2439 VolumeManager* volumeManager = VolumeManager::GetDefault(); 2440 2441 // load the entry 2442 Entry* entry = NULL; 2443 result = volumeManager->LoadEntry(dirEntry->d_pdev, 2444 dirEntry->d_pino, dirEntry->d_name, true, &entry); 2445 2446 // if at least one client volume contains the entry, get an entry info 2447 if (result == B_OK) { 2448 HasQueryPermissionClientVolumeFilter filter; 2449 int32 entryVolumeCount = _GetContainingClientVolumes( 2450 entry->GetDirectory(), volumeIDs, volumeCount, &filter); 2451 if (entryVolumeCount > 0) { 2452 // store all the client volume IDs in the reply 2453 for (int32 i = 0; i < entryVolumeCount; i++) { 2454 result = reply.clientVolumeIDs.Append(volumeIDs[i]); 2455 if (result != B_OK) 2456 break; 2457 } 2458 2459 // get an entry info 2460 _GetNodeInfo(entry->GetDirectory(), &reply.dirInfo); 2461 _GetEntryInfo(entry, &reply.entryInfo); 2462 break; 2463 } 2464 else 2465 PRINT((" -> no client volumes\n")); 2466 } 2467 2468 // entry is not in the volume: next round... 2469 result = B_OK; 2470 } 2471 2472 // send the reply 2473 reply.error = result; 2474 reply.count = countRead; 2475 PRINT("ReadQuery: (%lx, %ld, dir: (%ld, %lld), node: (%ld, %lld, `%s')" 2476 "\n", reply.error, reply.count, 2477 reply.entryInfo.directoryID.volumeID, 2478 reply.entryInfo.directoryID.nodeID, 2479 reply.entryInfo.nodeInfo.st.st_dev, 2480 reply.entryInfo.nodeInfo.st.st_ino, 2481 reply.entryInfo.name.GetString()); 2482 return GetChannel()->SendRequest(&reply); 2483 } 2484 2485 2486 // #pragma mark - 2487 2488 // ProcessNodeMonitoringEvent 2489 void 2490 ClientConnection::ProcessNodeMonitoringEvent(int32 volumeID, 2491 NodeMonitoringEvent* event) 2492 { 2493 // get a connection reference 2494 ConnectionReference connectionReference(this); 2495 if (!connectionReference.IsValid()) 2496 return; 2497 2498 _PushNodeMonitoringEvent(volumeID, event); 2499 } 2500 2501 // CloseNodeMonitoringEventQueue 2502 void 2503 ClientConnection::CloseNodeMonitoringEventQueue() 2504 { 2505 typedef Vector<NodeMonitoringRequest*> RequestVector; 2506 const RequestVector* requests = NULL; 2507 if (fNodeMonitoringEvents->Close(false, &requests) == B_OK) { 2508 for (RequestVector::ConstIterator it = requests->Begin(); 2509 it != requests->End(); 2510 it++) { 2511 delete *it; 2512 } 2513 } 2514 } 2515 2516 2517 // #pragma mark - 2518 2519 // QueryDomainIntersectsWith 2520 bool 2521 ClientConnection::QueryDomainIntersectsWith(Volume* volume) 2522 { 2523 // Iterate through the the client volumes and check whether any one contains 2524 // the supplied volume or its root dir is on the volume. We don't check 2525 // directory inclusion for the latter, since we don't need to query the 2526 // volume, if the client volume is located on a volume mounted somewhere 2527 // under the supplied volume (e.g. the root FS contains everything, but does 2528 // seldomly need to be queried). 2529 VolumeManager* volumeManager = VolumeManager::GetDefault(); 2530 AutoLocker<VolumeMap> volumesLocker(fVolumes); 2531 for (VolumeMap::Iterator it = fVolumes->GetIterator(); it.HasNext();) { 2532 ClientVolume* clientVolume = it.Next().value; 2533 Directory* volumeRoot = volume->GetRootDirectory(); 2534 Directory* clientVolumeRoot = clientVolume->GetRootDirectory(); 2535 if (volumeManager->DirectoryContains(clientVolumeRoot, volumeRoot, true) 2536 || volumeRoot->GetVolumeID() == clientVolumeRoot->GetVolumeID()) { 2537 return true; 2538 } 2539 } 2540 2541 return false; 2542 } 2543 2544 // ProcessQueryEvent 2545 void 2546 ClientConnection::ProcessQueryEvent(NodeMonitoringEvent* event) 2547 { 2548 dev_t volumeID; 2549 ino_t directoryID; 2550 if (event->opcode == B_ENTRY_CREATED) { 2551 // "entry created" event 2552 EntryCreatedEvent* createdEvent 2553 = dynamic_cast<EntryCreatedEvent*>(event); 2554 if (!createdEvent) 2555 return; 2556 volumeID = createdEvent->volumeID; 2557 directoryID = createdEvent->directoryID; 2558 2559 } else if (event->opcode == B_ENTRY_REMOVED) { 2560 // "entry removed" event 2561 EntryRemovedEvent* removedEvent 2562 = dynamic_cast<EntryRemovedEvent*>(event); 2563 if (!removedEvent) 2564 return; 2565 volumeID = removedEvent->volumeID; 2566 directoryID = removedEvent->directoryID; 2567 2568 } else { 2569 // We only support "entry created" and "entry removed" query events. 2570 // "entry moved" is split by the volume manager into those. 2571 ERROR("Ignoring unexpected query event: opcode: 0x%" B_PRIx32 "\n", 2572 event->opcode); 2573 return; 2574 } 2575 PRINT("ClientConnection::ProcessQueryEvent(): event: %p, type: %s:" 2576 " directory: (%ld, %lld)\n", event, typeid(event).name(), 2577 volumeID, directoryID); 2578 2579 // create an array for the IDs of the client volumes a found entry may 2580 // reside on 2581 status_t result = B_OK; 2582 int32 volumeCount = fVolumes->Size(); 2583 int32* volumeIDs = new(std::nothrow) int32[volumeCount]; 2584 if (!volumeIDs) 2585 result = B_NO_MEMORY; 2586 ArrayDeleter<int32> volumeIDsDeleter(volumeIDs); 2587 2588 HasQueryPermissionClientVolumeFilter filter; 2589 2590 // load the directory the concerned entry belongs/belonged to 2591 Directory* directory; 2592 int32 concernedVolumes = 0; 2593 if (VolumeManager::GetDefault()->LoadDirectory(volumeID, directoryID, 2594 &directory) == B_OK) { 2595 // find out, which client volumes the directory is located in 2596 concernedVolumes = _GetContainingClientVolumes(directory, volumeIDs, 2597 volumeCount, &filter); 2598 } else { 2599 // Failed to load the directory, so maybe it has already been 2600 // deleted. For "entry removed" events, we consider all client 2601 // volumes to be notified -- those that don't know the entry will 2602 // ignore the event. 2603 if (event->opcode == B_ENTRY_REMOVED) { 2604 concernedVolumes = _GetAllClientVolumeIDs(volumeIDs, volumeCount, 2605 &filter); 2606 } 2607 } 2608 2609 // now push the event for each concerned client volume 2610 for (int32 i = 0; i < concernedVolumes; i++) 2611 _PushNodeMonitoringEvent(volumeIDs[i], event); 2612 // TODO: More than one volume will usually only be concerned in case of 2613 // nested client volumes. We could optimize the case by having an array of 2614 // volume IDs in the respective requests sent over the net (just as in the 2615 // ReadQueryReply). 2616 } 2617 2618 2619 // #pragma mark - 2620 2621 // _Close 2622 void 2623 ClientConnection::_Close() 2624 { 2625 // terminate node monitoring processor 2626 CloseNodeMonitoringEventQueue(); 2627 if (fNodeMonitoringProcessor >= 0 2628 && find_thread(NULL) != fNodeMonitoringProcessor) { 2629 int32 result; 2630 wait_for_thread(fNodeMonitoringProcessor, &result); 2631 // The variable is not unset, when this is the node monitoring 2632 // processor thread -- which is good, since the destructor will 2633 // wait for the thread in this case. 2634 fNodeMonitoringProcessor = -1; 2635 } 2636 if (fConnection) 2637 fConnection->Close(); 2638 // notify the listener 2639 ClientConnectionListener* listener = fListener; 2640 fListener = NULL; 2641 if (listener) 2642 listener->ClientConnectionClosed(this, fError); 2643 } 2644 2645 // _MarkClosed 2646 void 2647 ClientConnection::_MarkClosed(bool error) 2648 { 2649 AutoLocker<Locker> _(fLock); 2650 if (!fClosed) { 2651 fClosed = true; 2652 fError = error; 2653 } 2654 } 2655 2656 // _GetNodeInfo 2657 void 2658 ClientConnection::_GetNodeInfo(Node* node, NodeInfo* info) 2659 { 2660 if (node && info) { 2661 info->st = node->GetStat(); 2662 info->revision = VolumeManager::GetDefault()->GetRevision(); 2663 } 2664 } 2665 2666 // _GetEntryInfo 2667 void 2668 ClientConnection::_GetEntryInfo(Entry* entry, EntryInfo* info) 2669 { 2670 if (entry && info) { 2671 info->directoryID.volumeID = entry->GetVolumeID(); 2672 info->directoryID.nodeID = entry->GetDirectoryID(); 2673 info->name.SetTo(entry->GetName()); 2674 _GetNodeInfo(entry->GetNode(), &info->nodeInfo); 2675 } 2676 } 2677 2678 // _GetAttrInfo 2679 status_t 2680 ClientConnection::_GetAttrInfo(Request* request, const char* name, 2681 const attr_info& attrInfo, const void* data, AttributeInfo* info) 2682 { 2683 if (!request || !name || !info) 2684 return B_BAD_VALUE; 2685 2686 info->name.SetTo(name); 2687 info->info = attrInfo; 2688 data = (attrInfo.size > 0 ? data : NULL); 2689 int32 dataSize = (data ? attrInfo.size : 0); 2690 info->data.SetTo(data, dataSize); 2691 2692 // if the client has inverse endianess, swap the type, if we don't know it 2693 if (fInverseClientEndianess) { 2694 if (_KnownAttributeType(info->info.type)) { 2695 // we need to convert the data, if supplied 2696 if (data) { 2697 // allocate a buffer 2698 RequestBuffer* requestBuffer = RequestBuffer::Create(dataSize); 2699 if (!requestBuffer) 2700 return B_NO_MEMORY; 2701 2702 // convert the data 2703 memcpy(requestBuffer->GetData(), data, dataSize); 2704 _ConvertAttribute(info->info, requestBuffer->GetData()); 2705 } 2706 } else 2707 info->info.type = B_SWAP_INT32(info->info.type); 2708 } 2709 2710 return B_OK; 2711 } 2712 2713 // _GetAttrDirInfo 2714 status_t 2715 ClientConnection::_GetAttrDirInfo(Request* request, AttributeDirectory* attrDir, 2716 AttrDirInfo* info) 2717 { 2718 if (!request || !attrDir || !info || !attrDir->IsAttrDirValid()) 2719 return B_BAD_VALUE; 2720 2721 // add the attribute infos 2722 for (Attribute* attribute = attrDir->GetFirstAttribute(); 2723 attribute; 2724 attribute = attrDir->GetNextAttribute(attribute)) { 2725 // get the attribute info 2726 AttributeInfo attrInfo; 2727 attr_info bAttrInfo; 2728 attribute->GetInfo(&bAttrInfo); 2729 status_t error = _GetAttrInfo(request, attribute->GetName(), bAttrInfo, 2730 attribute->GetData(), &attrInfo); 2731 2732 // append it 2733 if (error == B_OK) 2734 error = info->attributeInfos.Append(attrInfo); 2735 if (error != B_OK) 2736 return error; 2737 } 2738 2739 info->revision = VolumeManager::GetDefault()->GetRevision(); 2740 info->isValid = true; 2741 2742 return B_OK; 2743 } 2744 2745 // _CreateVolume 2746 status_t 2747 ClientConnection::_CreateVolume(ClientVolume** _volume) 2748 { 2749 // create and init the volume 2750 ClientVolume* volume = new(std::nothrow) ClientVolume(fSecurityContextLock, 2751 this); 2752 if (!volume) 2753 return B_NO_MEMORY; 2754 status_t error = volume->Init(); 2755 if (error != B_OK) { 2756 delete volume; 2757 return error; 2758 } 2759 2760 // add it to the volume map 2761 AutoLocker<VolumeMap> locker(fVolumes); 2762 error = fVolumes->Put(volume->GetID(), volume); 2763 locker.Unlock(); 2764 2765 if (error == B_OK) 2766 *_volume = volume; 2767 else 2768 delete volume; 2769 2770 return error; 2771 } 2772 2773 // _GetVolume 2774 ClientVolume* 2775 ClientConnection::_GetVolume(int32 id) 2776 { 2777 AutoLocker<VolumeMap> _(fVolumes); 2778 ClientVolume* volume = fVolumes->Get(id); 2779 if (!volume || volume->IsRemoved()) 2780 return NULL; 2781 volume->AcquireReference(); 2782 return volume; 2783 } 2784 2785 // _PutVolume 2786 // 2787 // The VolumeManager may be locked, but no other lock must be held. 2788 void 2789 ClientConnection::_PutVolume(ClientVolume* volume) 2790 { 2791 if (!volume) 2792 return; 2793 2794 // decrement reference counter and remove the volume, if 0 2795 AutoLocker<VolumeMap> locker(fVolumes); 2796 bool removed = (volume->ReleaseReference() == 1 && volume->IsRemoved()); 2797 if (removed) 2798 fVolumes->Remove(volume->GetID()); 2799 locker.Unlock(); 2800 2801 if (removed) { 2802 VolumeManagerLocker managerLocker; 2803 delete volume; 2804 } 2805 } 2806 2807 // _UnmountVolume 2808 // 2809 // The caller must have a reference to the volume. 2810 void 2811 ClientConnection::_UnmountVolume(ClientVolume* volume) 2812 { 2813 if (!volume) 2814 return; 2815 AutoLocker<VolumeMap> locker(fVolumes); 2816 volume->MarkRemoved(); 2817 locker.Unlock(); 2818 2819 // push a notification event 2820 if (VolumeUnmountedEvent* event = new(std::nothrow) VolumeUnmountedEvent) { 2821 VolumeManagerLocker managerLocker; 2822 2823 event->opcode = B_DEVICE_UNMOUNTED; 2824 _PushNodeMonitoringEvent(volume->GetID(), event); 2825 event->ReleaseReference(); 2826 } 2827 } 2828 2829 // _UnmountAllVolumes 2830 void 2831 ClientConnection::_UnmountAllVolumes() 2832 { 2833 while (true) { 2834 // To avoid heap allocation (which can fail) we unmount the volumes 2835 // chunkwise. 2836 // get the volumes 2837 const int32 volumeChunkSize = 32; 2838 ClientVolume* volumes[volumeChunkSize]; 2839 int32 volumeCount = 0; 2840 AutoLocker<VolumeMap> volumesLocker(fVolumes); 2841 for (VolumeMap::Iterator it = fVolumes->GetIterator(); it.HasNext();) { 2842 if (ClientVolume* volume = _GetVolume(it.Next().value->GetID())) { 2843 volumes[volumeCount++] = volume; 2844 } 2845 if (volumeCount == volumeChunkSize) 2846 break; 2847 } 2848 volumesLocker.Unlock(); 2849 2850 // unmount and put the volumes 2851 for (int32 i = 0; i < volumeCount; i++) { 2852 ClientVolume* volume = volumes[i]; 2853 _UnmountVolume(volume); 2854 _PutVolume(volume); 2855 } 2856 2857 if (volumeCount < volumeChunkSize) 2858 break; 2859 } 2860 } 2861 2862 // _NodeMonitoringProcessorEntry 2863 int32 2864 ClientConnection::_NodeMonitoringProcessorEntry(void* data) 2865 { 2866 return ((ClientConnection*)data)->_NodeMonitoringProcessor(); 2867 } 2868 2869 2870 // _NodeMonitoringProcessor 2871 int32 2872 ClientConnection::_NodeMonitoringProcessor() 2873 { 2874 while (!fClosed) { 2875 // get the next request 2876 NodeMonitoringRequest* request = NULL; 2877 status_t error = fNodeMonitoringEvents->Pop(&request); 2878 2879 // get a client connection reference 2880 ConnectionReference connectionReference(this); 2881 if (!connectionReference.IsValid()) 2882 return B_OK; 2883 2884 // No request? Next round... 2885 if (error != B_OK) 2886 continue; 2887 ObjectDeleter<NodeMonitoringRequest> requestDeleter(request); 2888 2889 // send the request 2890 error = fConnection->SendRequest(request); 2891 if (error != B_OK) { 2892 ERROR(("ClientConnection::_NodeMonitoringProcessor(): " 2893 "Failed to send request.\n")); 2894 } 2895 } 2896 return 0; 2897 } 2898 2899 2900 // _PushNodeMonitoringEvent 2901 // 2902 // The caller must have a connection reference. Moreover the VolumeManager 2903 // must be locked. 2904 status_t 2905 ClientConnection::_PushNodeMonitoringEvent(int32 volumeID, 2906 NodeMonitoringEvent* event) 2907 { 2908 if (!event) 2909 return B_BAD_VALUE; 2910 2911 // get the volume 2912 ClientVolume* volume = _GetVolume(volumeID); 2913 if (!volume && event->opcode != B_DEVICE_UNMOUNTED) 2914 return B_BAD_VALUE; 2915 ClientVolumePutter volumePutter(this, volume); 2916 2917 // create a node monitoring request 2918 NodeMonitoringRequest* request = NULL; 2919 status_t error = B_ERROR; 2920 switch (event->opcode) { 2921 case B_ENTRY_CREATED: 2922 error = _EntryCreated(volume, 2923 dynamic_cast<EntryCreatedEvent*>(event), request); 2924 break; 2925 case B_ENTRY_REMOVED: 2926 error = _EntryRemoved(volume, 2927 dynamic_cast<EntryRemovedEvent*>(event), request); 2928 break; 2929 case B_ENTRY_MOVED: 2930 error = _EntryMoved(volume, 2931 dynamic_cast<EntryMovedEvent*>(event), request); 2932 break; 2933 case B_STAT_CHANGED: 2934 error = _NodeStatChanged(volume, 2935 dynamic_cast<StatChangedEvent*>(event), request); 2936 break; 2937 case B_ATTR_CHANGED: 2938 error = _NodeAttributeChanged(volume, 2939 dynamic_cast<AttributeChangedEvent*>(event), request); 2940 break; 2941 case B_DEVICE_UNMOUNTED: 2942 error = B_OK; 2943 break; 2944 } 2945 2946 // replace all data buffers -- when the request is actually sent, they 2947 // might no longer exist 2948 if (error == B_OK) 2949 error = RequestBufferReplacer().ReplaceBuffer(request); 2950 2951 if (error == B_OK) { 2952 // common initialization 2953 request->volumeID = volumeID; 2954 request->opcode = event->opcode; 2955 request->revision = VolumeManager::GetDefault()->GetRevision(); 2956 2957 // push the request 2958 error = fNodeMonitoringEvents->Push(request); 2959 if (error != B_OK) 2960 delete request; 2961 } 2962 2963 return error; 2964 } 2965 2966 // _EntryCreated 2967 status_t 2968 ClientConnection::_EntryCreated(ClientVolume* volume, EntryCreatedEvent* event, 2969 NodeMonitoringRequest*& _request) 2970 { 2971 // allocate the request 2972 EntryCreatedRequest* request = new(std::nothrow) EntryCreatedRequest; 2973 if (!request) 2974 return B_NO_MEMORY; 2975 ObjectDeleter<NodeMonitoringRequest> requestDeleter(request); 2976 2977 // get the name 2978 const char* name = event->name.GetString(); 2979 2980 // set the request fields 2981 request->directoryID = NodeID(event->volumeID, event->directoryID); 2982 request->nodeID = NodeID(event->volumeID, event->nodeID); 2983 request->name.SetTo(name); 2984 if (event->queryHandler) { 2985 request->port = event->remotePort; 2986 request->token = event->remoteToken; 2987 request->queryUpdate = true; 2988 } else 2989 request->queryUpdate = false; 2990 2991 // try to get an entry info 2992 Entry* entry; 2993 if (VolumeManager::GetDefault()->LoadEntry(event->volumeID, 2994 event->directoryID, name, true, &entry) == B_OK 2995 && entry->GetNode()->GetVolumeID() == event->volumeID 2996 && entry->GetNode()->GetID() == event->nodeID) { 2997 _GetEntryInfo(entry, &request->entryInfo); 2998 request->entryInfoValid = true; 2999 } else 3000 request->entryInfoValid = false; 3001 3002 requestDeleter.Detach(); 3003 _request = request; 3004 return B_OK; 3005 } 3006 3007 // _EntryRemoved 3008 status_t 3009 ClientConnection::_EntryRemoved(ClientVolume* volume, EntryRemovedEvent* event, 3010 NodeMonitoringRequest*& _request) 3011 { 3012 // special handling, if it is the root node of the client volume that has 3013 // been removed 3014 if (!event->queryHandler 3015 && NodeRef(event->nodeVolumeID, event->nodeID) 3016 == volume->GetRootNodeRef()) { 3017 NoAllocEntryRef ref(event->nodeVolumeID, event->nodeID, "."); 3018 BEntry entry; 3019 if (FDManager::SetEntry(&entry, &ref) != B_OK || !entry.Exists()) 3020 _UnmountVolume(volume); 3021 3022 // don't send the "entry removed" event 3023 return B_ERROR; 3024 } 3025 3026 // allocate the request 3027 EntryRemovedRequest* request = new(std::nothrow) EntryRemovedRequest; 3028 if (!request) 3029 return B_NO_MEMORY; 3030 ObjectDeleter<NodeMonitoringRequest> requestDeleter(request); 3031 3032 // get the name 3033 const char* name = event->name.GetString(); 3034 3035 // set the request fields 3036 request->directoryID = NodeID(event->volumeID, event->directoryID); 3037 request->nodeID = NodeID(event->nodeVolumeID, event->nodeID); 3038 request->name.SetTo(name); 3039 if (event->queryHandler) { 3040 request->port = event->remotePort; 3041 request->token = event->remoteToken; 3042 request->queryUpdate = true; 3043 } else 3044 request->queryUpdate = false; 3045 3046 requestDeleter.Detach(); 3047 _request = request; 3048 return B_OK; 3049 } 3050 3051 // _EntryMoved 3052 status_t 3053 ClientConnection::_EntryMoved(ClientVolume* volume, EntryMovedEvent* event, 3054 NodeMonitoringRequest*& _request) 3055 { 3056 // allocate the request 3057 EntryMovedRequest* request = new(std::nothrow) EntryMovedRequest; 3058 if (!request) 3059 return B_NO_MEMORY; 3060 ObjectDeleter<NodeMonitoringRequest> requestDeleter(request); 3061 3062 // allocate memory for the names 3063 int32 fromNameLen = event->fromName.GetLength(); 3064 const char* fromName 3065 = (fromNameLen > 0 ? event->fromName.GetString() : NULL); 3066 const char* toName = event->toName.GetString(); 3067 3068 // set the request fields 3069 request->fromDirectoryID = NodeID(event->volumeID, event->fromDirectoryID); 3070 request->toDirectoryID = NodeID(event->volumeID, event->toDirectoryID); 3071 request->nodeID = NodeID(event->nodeVolumeID, event->nodeID); 3072 request->fromName.SetTo(fromName); 3073 request->toName.SetTo(toName); 3074 request->queryUpdate = false; 3075 3076 // try to get an entry info 3077 Entry* entry; 3078 if (VolumeManager::GetDefault()->LoadEntry(event->volumeID, 3079 event->toDirectoryID, toName, true, &entry) == B_OK 3080 && entry->GetNode()->GetVolumeID() == event->nodeVolumeID 3081 && entry->GetNode()->GetID() == event->nodeID) { 3082 _GetEntryInfo(entry, &request->entryInfo); 3083 request->entryInfoValid = true; 3084 } else 3085 request->entryInfoValid = false; 3086 3087 requestDeleter.Detach(); 3088 _request = request; 3089 return B_OK; 3090 } 3091 3092 // _NodeStatChanged 3093 status_t 3094 ClientConnection::_NodeStatChanged(ClientVolume* volume, 3095 StatChangedEvent* event, NodeMonitoringRequest*& _request) 3096 { 3097 // get the node 3098 Node* node = volume->GetNode(event->volumeID, event->nodeID); 3099 if (!node) 3100 return B_ENTRY_NOT_FOUND; 3101 3102 // allocate the request 3103 StatChangedRequest* request = new(std::nothrow) StatChangedRequest; 3104 if (!request) 3105 return B_NO_MEMORY; 3106 ObjectDeleter<NodeMonitoringRequest> requestDeleter(request); 3107 3108 // set the request fields 3109 request->nodeID = NodeID(event->volumeID, event->nodeID); 3110 _GetNodeInfo(node, &request->nodeInfo); 3111 request->queryUpdate = false; 3112 3113 requestDeleter.Detach(); 3114 _request = request; 3115 return B_OK; 3116 } 3117 3118 // _NodeAttributeChanged 3119 status_t 3120 ClientConnection::_NodeAttributeChanged(ClientVolume* volume, 3121 AttributeChangedEvent* event, NodeMonitoringRequest*& _request) 3122 { 3123 // get the node 3124 Node* node = volume->GetNode(event->volumeID, event->nodeID); 3125 if (!node) 3126 return B_ENTRY_NOT_FOUND; 3127 3128 // update the attribute directory 3129 bool removed = false; 3130 bool valid = false; 3131 attr_info info; 3132 const void* data = NULL; 3133 status_t error = node->UpdateAttribute(event->attribute.GetString(), 3134 &removed, &info, &data); 3135 valid = (error == B_OK); 3136 3137 // allocate the request 3138 AttributeChangedRequest* request = new(std::nothrow) AttributeChangedRequest; 3139 if (!request) 3140 return B_NO_MEMORY; 3141 ObjectDeleter<NodeMonitoringRequest> requestDeleter(request); 3142 3143 // get an attr dir info, if the directory is valid 3144 if (node->IsAttrDirValid()) { 3145 status_t error = _GetAttrDirInfo(request, node, &request->attrDirInfo); 3146 if (error != B_OK) 3147 return error; 3148 } 3149 3150 // get name and the data size 3151 int32 dataSize = (data ? info.size : 0); 3152 const char* name = event->attribute.GetString(); 3153 3154 // set the request fields 3155 request->nodeID = NodeID(event->volumeID, event->nodeID); 3156 request->attrInfo.name.SetTo(name); 3157 request->valid = valid; 3158 request->removed = removed; 3159 if (!removed && valid) { 3160 request->attrInfo.info = info; 3161 request->attrInfo.data.SetTo(data, dataSize); 3162 } 3163 request->queryUpdate = false; 3164 3165 requestDeleter.Detach(); 3166 _request = request; 3167 return B_OK; 3168 } 3169 3170 // _KnownAttributeType 3171 bool 3172 ClientConnection::_KnownAttributeType(type_code type) 3173 { 3174 if (!fInverseClientEndianess) 3175 return false; 3176 3177 switch (type) { 3178 case B_BOOL_TYPE: 3179 case B_CHAR_TYPE: 3180 case B_COLOR_8_BIT_TYPE: 3181 case B_DOUBLE_TYPE: 3182 case B_FLOAT_TYPE: 3183 case B_GRAYSCALE_8_BIT_TYPE: 3184 case B_INT64_TYPE: 3185 case B_INT32_TYPE: 3186 case B_INT16_TYPE: 3187 case B_INT8_TYPE: 3188 case B_MESSAGE_TYPE: 3189 case B_MESSENGER_TYPE: 3190 case B_MIME_TYPE: 3191 case B_MONOCHROME_1_BIT_TYPE: 3192 case B_OFF_T_TYPE: 3193 case B_POINTER_TYPE: 3194 case B_POINT_TYPE: 3195 case B_RECT_TYPE: 3196 case B_REF_TYPE: 3197 case B_RGB_COLOR_TYPE: 3198 case B_SIZE_T_TYPE: 3199 case B_SSIZE_T_TYPE: 3200 case B_STRING_TYPE: 3201 case B_TIME_TYPE: 3202 case B_UINT64_TYPE: 3203 case B_UINT32_TYPE: 3204 case B_UINT16_TYPE: 3205 case B_UINT8_TYPE: 3206 case B_ASCII_TYPE: 3207 case B_MIME_STRING_TYPE: 3208 return true; 3209 3210 //B_RGB_32_BIT_TYPE: We could translate it, but it's heavy... 3211 } 3212 3213 return false; 3214 } 3215 3216 // _ConvertAttribute 3217 void 3218 ClientConnection::_ConvertAttribute(const attr_info& info, void* buffer) 3219 { 3220 swap_data(info.type, buffer, info.size, B_SWAP_ALWAYS); 3221 } 3222 3223 3224 // #pragma mark - 3225 3226 // _OpenQuery 3227 status_t 3228 ClientConnection::_OpenQuery(const char* queryString, uint32 flags, 3229 port_id remotePort, int32 remoteToken, QueryHandle** _handle) 3230 { 3231 if (!queryString || !_handle) 3232 return B_BAD_VALUE; 3233 3234 // open query 3235 QueryHandle* queryHandle; 3236 status_t error = VolumeManager::GetDefault()->OpenQuery(this, queryString, 3237 flags, remotePort, remoteToken, &queryHandle); 3238 if (error != B_OK) 3239 return error; 3240 BReference<QueryHandle> handleReference(queryHandle, true); 3241 3242 // lock the handle 3243 queryHandle->Lock(); 3244 3245 // add the handle 3246 error = fQueryHandles->AddNodeHandle(queryHandle); 3247 if (error != B_OK) 3248 return error; 3249 3250 handleReference.Detach(); 3251 *_handle = queryHandle; 3252 return B_OK; 3253 } 3254 3255 // _CloseQuery 3256 status_t 3257 ClientConnection::_CloseQuery(QueryHandle* handle) 3258 { 3259 if (!handle || !fQueryHandles->RemoveNodeHandle(handle)) 3260 return B_BAD_VALUE; 3261 3262 return B_OK; 3263 } 3264 3265 // _LockQueryHandle 3266 // 3267 // VolumeManager must NOT be locked. 3268 status_t 3269 ClientConnection::_LockQueryHandle(int32 cookie, QueryHandle** _handle) 3270 { 3271 NodeHandle* handle; 3272 status_t error = fQueryHandles->LockNodeHandle(cookie, &handle); 3273 if (error == B_OK) 3274 *_handle = static_cast<QueryHandle*>(handle); 3275 return error; 3276 } 3277 3278 // _UnlockQueryHandle 3279 // 3280 // VolumeManager may or may not be locked. 3281 void 3282 ClientConnection::_UnlockQueryHandle(NodeHandle* nodeHandle) 3283 { 3284 fQueryHandles->UnlockNodeHandle(nodeHandle); 3285 } 3286 3287 3288 // #pragma mark - 3289 3290 // _GetAllClientVolumeIDs 3291 int32 3292 ClientConnection::_GetAllClientVolumeIDs(int32* volumeIDs, int32 arraySize, 3293 ClientVolumeFilter* filter) 3294 { 3295 int32 count = 0; 3296 AutoLocker<VolumeMap> volumesLocker(fVolumes); 3297 for (VolumeMap::Iterator it = fVolumes->GetIterator(); 3298 it.HasNext() && arraySize > count;) { 3299 ClientVolume* clientVolume = it.Next().value; 3300 if (!filter || filter->FilterVolume(this, clientVolume)) 3301 volumeIDs[count++] = clientVolume->GetID(); 3302 } 3303 3304 return count; 3305 } 3306 3307 // _GetContainingClientVolumes 3308 int32 3309 ClientConnection::_GetContainingClientVolumes(Directory* directory, 3310 int32* volumeIDs, int32 arraySize, ClientVolumeFilter* filter) 3311 { 3312 int32 count = 0; 3313 VolumeManager* volumeManager = VolumeManager::GetDefault(); 3314 AutoLocker<VolumeMap> volumesLocker(fVolumes); 3315 for (VolumeMap::Iterator it = fVolumes->GetIterator(); 3316 it.HasNext() && arraySize > count;) { 3317 ClientVolume* clientVolume = it.Next().value; 3318 Directory* clientVolumeRoot = clientVolume->GetRootDirectory(); 3319 if (volumeManager->DirectoryContains(clientVolumeRoot, directory, true) 3320 && (!filter || filter->FilterVolume(this, clientVolume))) { 3321 volumeIDs[count++] = clientVolume->GetID(); 3322 } 3323 } 3324 3325 return count; 3326 } 3327 3328 3329 // #pragma mark - 3330 // #pragma mark ----- ClientConnectionListener ----- 3331 3332 // constructor 3333 ClientConnectionListener::ClientConnectionListener() 3334 { 3335 } 3336 3337 // destructor 3338 ClientConnectionListener::~ClientConnectionListener() 3339 { 3340 } 3341 3342