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