1 // ShareVolume.cpp 2 3 #include "ShareVolume.h" 4 5 #include <new> 6 #include <unistd.h> 7 8 #include <AppDefs.h> // for B_QUERY_UPDATE 9 #include <AutoDeleter.h> 10 #include <AutoLocker.h> 11 #include <HashMap.h> 12 13 #include "AuthenticationServer.h" 14 #include "Compatibility.h" 15 #include "Connection.h" 16 #include "ConnectionFactory.h" 17 #include "DebugSupport.h" 18 #include "ExtendedServerInfo.h" 19 #include "Permissions.h" 20 #include "Node.h" 21 #include "QueryManager.h" 22 #include "RequestChannel.h" 23 #include "RequestConnection.h" 24 #include "Requests.h" 25 #include "RootVolume.h" 26 #include "SendReceiveRequest.h" 27 #include "ServerConnection.h" 28 #include "ServerConnectionProvider.h" 29 #include "ShareAttrDir.h" 30 #include "ShareAttrDirIterator.h" 31 #include "ShareNode.h" 32 #include "Utils.h" 33 #include "VolumeManager.h" 34 #include "VolumeSupport.h" 35 36 // TODO: Request timeouts! 37 38 static const int32 kMaxWriteBufferSize = 64 * 1024; // 64 KB 39 static const int32 kUserBufferSize = 256; 40 static const int32 kPasswordBufferSize = 256; 41 42 // connection states 43 enum { 44 CONNECTION_NOT_INITIALIZED, 45 CONNECTION_READY, 46 CONNECTION_CLOSED, 47 }; 48 49 // NodeMap 50 struct ShareVolume::NodeMap : HashMap<HashKey64<ino_t>, ShareNode*> { 51 }; 52 53 // EntryKey 54 // 55 // NOTE: This class doesn't make a copy of the name string it is constructed 56 // with. So, when entering the key in a map, one must make sure, that the 57 // string stays valid as long as the entry is in the map. 58 struct ShareVolume::EntryKey { 59 EntryKey() {} 60 61 EntryKey(ino_t directoryID, const char* name) 62 : directoryID(directoryID), 63 name(name) 64 { 65 } 66 67 EntryKey(const EntryKey& other) 68 : directoryID(other.directoryID), 69 name(other.name) 70 { 71 } 72 73 uint32 GetHashCode() const 74 { 75 uint32 hash = (uint32)directoryID; 76 hash = 31 * hash + (uint32)(directoryID >> 32); 77 hash = 31 * hash + string_hash(name); 78 return hash; 79 } 80 81 EntryKey& operator=(const EntryKey& other) 82 { 83 directoryID = other.directoryID; 84 name = other.name; 85 return *this; 86 } 87 88 bool operator==(const EntryKey& other) const 89 { 90 if (directoryID != other.directoryID) 91 return false; 92 93 if (name) 94 return (other.name && strcmp(name, other.name) == 0); 95 96 return !other.name; 97 } 98 99 bool operator!=(const EntryKey& other) const 100 { 101 return !(*this == other); 102 } 103 104 ino_t directoryID; 105 const char* name; 106 }; 107 108 // EntryMap 109 struct ShareVolume::EntryMap : HashMap<EntryKey, ShareDirEntry*> { 110 }; 111 112 // LocalNodeIDMap 113 struct ShareVolume::LocalNodeIDMap : HashMap<NodeID, ino_t> { 114 }; 115 116 // RemoteNodeIDMap 117 struct ShareVolume::RemoteNodeIDMap : HashMap<HashKey64<ino_t>, NodeID> { 118 }; 119 120 // DirCookie 121 struct ShareVolume::DirCookie { 122 ShareDirIterator* iterator; 123 }; 124 125 // AttrDirCookie 126 struct ShareVolume::AttrDirCookie { 127 AttrDirCookie() 128 : iterator(NULL), 129 cookie(-1), 130 rewind(false) 131 { 132 } 133 134 ShareAttrDirIterator* iterator; 135 int32 cookie; 136 bool rewind; 137 }; 138 139 // AttrDirIteratorMap 140 struct ShareVolume::AttrDirIteratorMap 141 : HashMap<HashKey64<ino_t>, DoublyLinkedList<ShareAttrDirIterator>*> { 142 }; 143 144 145 // #pragma mark - 146 147 // constructor 148 ShareVolume::ShareVolume(VolumeManager* volumeManager, 149 ServerConnectionProvider* connectionProvider, 150 ExtendedServerInfo* serverInfo, ExtendedShareInfo* shareInfo) 151 : Volume(volumeManager), 152 fID(-1), 153 fFlags(0), 154 fMountLock("share mount lock"), 155 fNodes(NULL), 156 fEntries(NULL), 157 fAttrDirIterators(NULL), 158 fLocalNodeIDs(NULL), 159 fRemoteNodeIDs(NULL), 160 fServerConnectionProvider(connectionProvider), 161 fServerInfo(serverInfo), 162 fShareInfo(shareInfo), 163 fServerConnection(NULL), 164 fConnection(NULL), 165 fSharePermissions(0), 166 fConnectionState(CONNECTION_NOT_INITIALIZED) 167 { 168 fFlags = fVolumeManager->GetMountFlags(); 169 if (fServerConnectionProvider) 170 fServerConnectionProvider->AcquireReference(); 171 if (fServerInfo) 172 fServerInfo->AcquireReference(); 173 if (fShareInfo) 174 fShareInfo->AcquireReference(); 175 } 176 177 // destructor 178 ShareVolume::~ShareVolume() 179 { 180 PRINT(("ShareVolume::~ShareVolume()\n")); 181 // delete the root node 182 if (fRootNode) { 183 if (fNodes) 184 fNodes->Remove(fRootNode->GetID()); 185 delete fRootNode; 186 fRootNode = NULL; 187 } 188 189 // delete the nodes 190 if (fNodes) { 191 // there shouldn't be any more nodes 192 if (fNodes->Size() > 0) { 193 WARN("ShareVolume::~ShareVolume(): WARNING: There are still " 194 "%ld nodes\n", fNodes->Size()); 195 } 196 for (NodeMap::Iterator it = fNodes->GetIterator(); it.HasNext();) 197 delete it.Next().value; 198 delete fNodes; 199 } 200 201 // delete the entries 202 if (fEntries) { 203 // there shouldn't be any more entries 204 if (fEntries->Size() > 0) { 205 WARN("ShareVolume::~ShareVolume(): WARNING: There are still " 206 "%ld entries\n", fEntries->Size()); 207 } 208 for (EntryMap::Iterator it = fEntries->GetIterator(); it.HasNext();) 209 delete it.Next().value; 210 delete fEntries; 211 } 212 213 delete fLocalNodeIDs; 214 delete fRemoteNodeIDs; 215 216 if (fShareInfo) 217 fShareInfo->ReleaseReference(); 218 if (fServerInfo) 219 fServerInfo->ReleaseReference(); 220 if (fServerConnection) 221 fServerConnection->ReleaseReference(); 222 if (fServerConnectionProvider) 223 fServerConnectionProvider->ReleaseReference(); 224 } 225 226 // GetID 227 nspace_id 228 ShareVolume::GetID() const 229 { 230 return fID; 231 } 232 233 // IsReadOnly 234 bool 235 ShareVolume::IsReadOnly() const 236 { 237 return (fFlags & B_MOUNT_READ_ONLY); 238 } 239 240 // SupportsQueries 241 bool 242 ShareVolume::SupportsQueries() const 243 { 244 return (fSharePermissions & QUERY_SHARE_PERMISSION); 245 } 246 247 // Init 248 status_t 249 ShareVolume::Init(const char* name) 250 { 251 status_t error = Volume::Init(name); 252 if (error != B_OK) 253 return error; 254 255 // create node map 256 fNodes = new(std::nothrow) NodeMap; 257 if (!fNodes) 258 RETURN_ERROR(B_NO_MEMORY); 259 error = fNodes->InitCheck(); 260 if (error != B_OK) 261 return error; 262 263 // create entry map 264 fEntries = new(std::nothrow) EntryMap; 265 if (!fEntries) 266 RETURN_ERROR(B_NO_MEMORY); 267 error = fEntries->InitCheck(); 268 if (error != B_OK) 269 return error; 270 271 // create attribute iterator map 272 fAttrDirIterators = new(std::nothrow) AttrDirIteratorMap; 273 if (!fAttrDirIterators) 274 RETURN_ERROR(B_NO_MEMORY); 275 error = fAttrDirIterators->InitCheck(); 276 if (error != B_OK) 277 return error; 278 279 // create local node ID map 280 fLocalNodeIDs = new(std::nothrow) LocalNodeIDMap; 281 if (!fLocalNodeIDs) 282 RETURN_ERROR(B_NO_MEMORY); 283 error = fLocalNodeIDs->InitCheck(); 284 if (error != B_OK) 285 return error; 286 287 // create remote node ID map 288 fRemoteNodeIDs = new(std::nothrow) RemoteNodeIDMap; 289 if (!fRemoteNodeIDs) 290 RETURN_ERROR(B_NO_MEMORY); 291 error = fRemoteNodeIDs->InitCheck(); 292 if (error != B_OK) 293 return error; 294 295 // get a local node ID for our root node 296 vnode_id localID = fVolumeManager->NewNodeID(this); 297 if (localID < 0) 298 return localID; 299 300 // create the root node 301 fRootNode = new(std::nothrow) ShareDir(this, localID, NULL); 302 if (!fRootNode) { 303 fVolumeManager->RemoveNodeID(localID); 304 return B_NO_MEMORY; 305 } 306 307 // add the root node to the node map 308 error = fNodes->Put(localID, fRootNode); 309 if (error != B_OK) 310 return error; 311 312 return B_OK; 313 } 314 315 // Uninit 316 void 317 ShareVolume::Uninit() 318 { 319 Volume::Uninit(); 320 } 321 322 // GetRootNode 323 Node* 324 ShareVolume::GetRootNode() const 325 { 326 return fRootNode; 327 } 328 329 // PrepareToUnmount 330 void 331 ShareVolume::PrepareToUnmount() 332 { 333 PRINT(("ShareVolume::PrepareToUnmount()\n")); 334 Volume::PrepareToUnmount(); 335 336 ConnectionClosed(); 337 338 AutoLocker<Locker> locker(fLock); 339 340 // remove all entries and send respective "entry removed" events 341 for (EntryMap::Iterator it = fEntries->GetIterator(); it.HasNext();) { 342 ShareDirEntry* entry = it.Next().value; 343 344 NotifyListener(B_ENTRY_REMOVED, fVolumeManager->GetID(), 345 entry->GetDirectory()->GetID(), 0, entry->GetNode()->GetID(), 346 entry->GetName()); 347 348 it.Remove(); 349 _RemoveEntry(entry); 350 } 351 352 // get all IDs 353 int32 count = fNodes->Size(); 354 if (count == 0) 355 return; 356 PRINT((" %ld nodes to remove\n", count)); 357 vnode_id* ids = new(std::nothrow) vnode_id[count]; 358 if (!ids) { 359 ERROR("ShareVolume::PrepareToUnmount(): ERROR: Insufficient memory to " 360 "allocate the node ID array!\n"); 361 return; 362 } 363 ArrayDeleter<vnode_id> _(ids); 364 count = 0; 365 for (NodeMap::Iterator it = fNodes->GetIterator(); it.HasNext();) { 366 ShareNode* node = it.Next().value; 367 ids[count++] = node->GetID(); 368 } 369 370 // Remove all nodes that are not known to the VFS right away. 371 // If the netfs is already in the process of being unmounted, GetVNode() 372 // will fail and the GetVNode(), RemoveVNode(), PutVNode() method won't 373 // work for removing them. 374 int32 remainingCount = 0; 375 for (int32 i = 0; i < count; i++) { 376 if (Node* node = fNodes->Get(ids[i])) { 377 if (node->IsKnownToVFS()) { 378 // node is known to VFS; we need to use the GetVNode(), 379 // RemoveVNode(), PutVNode() method 380 ids[remainingCount++] = ids[i]; 381 } else { 382 // node is not known to VFS; just remove and delete it 383 fNodes->Remove(node->GetID()); 384 _RemoveLocalNodeID(node->GetID()); 385 if (node != fRootNode) 386 delete node; 387 } 388 } 389 } 390 count = remainingCount; 391 392 locker.Unlock(); 393 394 // remove the nodes 395 for (int32 i = 0; i < count; i++) { 396 Node* node; 397 if (GetVNode(ids[i], &node) == B_OK) { 398 PRINT((" removing node %lld\n", ids[i])); 399 Volume::RemoveVNode(ids[i]); 400 PutVNode(ids[i]); 401 } 402 } 403 404 // remove ourselves for the server connection 405 if (fServerConnection) 406 fServerConnection->RemoveVolume(this); 407 408 // delete all entries 409 410 PRINT(("ShareVolume::PrepareToUnmount() done\n")); 411 } 412 413 // RemoveChildVolume 414 void 415 ShareVolume::RemoveChildVolume(Volume* volume) 416 { 417 // should never be called 418 WARN("WARNING: ShareVolume::RemoveChildVolume(%p) invoked!\n", volume); 419 } 420 421 422 // #pragma mark - 423 // #pragma mark ----- FS ----- 424 425 // Unmount 426 status_t 427 ShareVolume::Unmount() 428 { 429 if (_IsConnected()) { 430 // send the request 431 UnmountRequest request; 432 request.volumeID = fID; 433 fConnection->SendRequest(&request); 434 } 435 return B_OK; 436 } 437 438 // Sync 439 status_t 440 ShareVolume::Sync() 441 { 442 // TODO: Implement? 443 // We can't implement this without risking an endless recursion. The server 444 // could only invoke sync(), which would sync all FSs, including a NetFS 445 // which might be connected with a server running alongside this client. 446 // We could introduce a sync flag to break the recursion. This might be 447 // risky though. 448 return B_OK; 449 } 450 451 452 // #pragma mark - 453 // #pragma mark ----- vnodes ----- 454 455 // ReadVNode 456 status_t 457 ShareVolume::ReadVNode(vnode_id vnid, char reenter, Node** _node) 458 { 459 // check the map, maybe it's already loaded 460 ShareNode* node = NULL; 461 { 462 AutoLocker<Locker> _(fLock); 463 node = _GetNodeByLocalID(vnid); 464 if (node) { 465 node->SetKnownToVFS(true); 466 *_node = node; 467 468 // add a volume reference for the node 469 AcquireReference(); 470 471 return B_OK; 472 } 473 } 474 475 // not yet loaded: send a request to the server 476 if (!_EnsureShareMounted()) 477 return ERROR_NOT_CONNECTED; 478 479 // get the remote ID 480 NodeID remoteID; 481 status_t error = _GetRemoteNodeID(vnid, &remoteID); 482 if (error != B_OK) 483 return error; 484 485 // prepare the request 486 ReadVNodeRequest request; 487 request.volumeID = fID; 488 request.nodeID = remoteID; 489 490 // send the request 491 ReadVNodeReply* reply; 492 error = SendRequest(fConnection, &request, &reply); 493 if (error != B_OK) 494 RETURN_ERROR(error); 495 ObjectDeleter<Request> replyDeleter(reply); 496 if (reply->error != B_OK) 497 RETURN_ERROR(reply->error); 498 499 // add the node 500 AutoLocker<Locker> _(fLock); 501 error = _LoadNode(reply->nodeInfo, &node); 502 if (error != B_OK) 503 RETURN_ERROR(error); 504 node->SetKnownToVFS(true); 505 *_node = node; 506 507 // add a volume reference for the node 508 AcquireReference(); 509 510 return B_OK; 511 } 512 513 // WriteVNode 514 status_t 515 ShareVolume::WriteVNode(Node* node, char reenter) 516 { 517 AutoLocker<Locker> locker(fLock); 518 node->SetKnownToVFS(false); 519 520 // surrender the node's volume reference 521 locker.Unlock(); 522 PutVolume(); 523 524 return B_OK; 525 } 526 527 // RemoveVNode 528 status_t 529 ShareVolume::RemoveVNode(Node* node, char reenter) 530 { 531 AutoLocker<Locker> locker(fLock); 532 node->SetKnownToVFS(false); 533 fNodes->Remove(node->GetID()); 534 _RemoveLocalNodeID(node->GetID()); 535 if (node != fRootNode) 536 delete node; 537 538 // surrender the node's volume reference 539 locker.Unlock(); 540 PutVolume(); 541 542 return B_OK; 543 } 544 545 546 // #pragma mark - 547 // #pragma mark ----- nodes ----- 548 549 // FSync 550 status_t 551 ShareVolume::FSync(Node* _node) 552 { 553 // TODO: Implement! 554 return B_BAD_VALUE; 555 } 556 557 // ReadStat 558 status_t 559 ShareVolume::ReadStat(Node* _node, struct stat* st) 560 { 561 ShareNode* node = dynamic_cast<ShareNode*>(_node); 562 563 AutoLocker<Locker> _(fLock); 564 *st = node->GetNodeInfo().st; 565 st->st_dev = fVolumeManager->GetID(); 566 st->st_ino = node->GetID(); 567 // we set the UID/GID fields to the one who mounted the FS 568 st->st_uid = fVolumeManager->GetMountUID(); 569 st->st_gid = fVolumeManager->GetMountGID(); 570 return B_OK; 571 } 572 573 // WriteStat 574 status_t 575 ShareVolume::WriteStat(Node* _node, struct stat *st, uint32 mask) 576 { 577 ShareNode* node = dynamic_cast<ShareNode*>(_node); 578 579 if (!_EnsureShareMounted()) 580 return ERROR_NOT_CONNECTED; 581 582 // check read-only 583 if (IsReadOnly()) 584 return B_PERMISSION_DENIED; 585 // prepare the request 586 WriteStatRequest request; 587 request.volumeID = fID; 588 request.nodeID = node->GetRemoteID(); 589 request.nodeInfo.st = *st; 590 request.mask = mask; 591 // send the request 592 WriteStatReply* reply; 593 status_t error = SendRequest(fConnection, &request, &reply); 594 if (error != B_OK) 595 RETURN_ERROR(error); 596 ObjectDeleter<Request> replyDeleter(reply); 597 // update the node 598 if (reply->nodeInfoValid) 599 _UpdateNode(reply->nodeInfo); 600 if (reply->error != B_OK) 601 RETURN_ERROR(reply->error); 602 return B_OK; 603 } 604 605 // Access 606 status_t 607 ShareVolume::Access(Node* _node, int mode) 608 { 609 // TODO: Implement. 610 return B_OK; 611 } 612 613 614 // #pragma mark - 615 // #pragma mark ----- files ----- 616 617 // Create 618 status_t 619 ShareVolume::Create(Node* _dir, const char* name, int openMode, int mode, 620 vnode_id* vnid, void** cookie) 621 { 622 ShareDir* dir = dynamic_cast<ShareDir*>(_dir); 623 if (!dir) 624 return B_BAD_VALUE; 625 626 if (!_EnsureShareMounted()) 627 return ERROR_NOT_CONNECTED; 628 629 // check permissions 630 if (IsReadOnly()) 631 return B_PERMISSION_DENIED; 632 if (IsVNodeRemoved(dir->GetID()) > 0) 633 RETURN_ERROR(B_NOT_ALLOWED); 634 635 // prepare the request 636 CreateFileRequest request; 637 request.volumeID = fID; 638 request.directoryID = dir->GetRemoteID(); 639 request.name.SetTo(name); 640 request.openMode = openMode; 641 request.mode = mode; 642 643 // send the request 644 CreateFileReply* reply; 645 status_t error = SendRequest(fConnection, &request, &reply); 646 if (error != B_OK) 647 RETURN_ERROR(error); 648 ObjectDeleter<Request> replyDeleter(reply); 649 if (reply->error != B_OK) 650 RETURN_ERROR(reply->error); 651 652 // add/update the entry 653 vnode_id localID = -1; 654 EntryInfo* entryInfo = &reply->entryInfo; 655 while (true) { 656 // get an up to date entry info 657 WalkReply* walkReply = NULL; 658 if (!entryInfo) { 659 error = _Walk(reply->entryInfo.directoryID, 660 reply->entryInfo.name.GetString(), false, &walkReply); 661 if (error != B_OK) 662 break; 663 664 entryInfo = &walkReply->entryInfo; 665 } 666 ObjectDeleter<Request> walkReplyDeleter(walkReply); 667 668 AutoLocker<Locker> locker(fLock); 669 670 // check, if the info is obsolete 671 if (_IsObsoleteEntryInfo(*entryInfo)) { 672 entryInfo = NULL; 673 continue; 674 } 675 676 // load the entry 677 ShareDirEntry* entry; 678 error = _LoadEntry(dir, *entryInfo, &entry); 679 if (error == B_OK) 680 localID = entry->GetNode()->GetID(); 681 682 break; 683 } 684 685 if (error == B_OK) { 686 Node* _node; 687 error = GetVNode(localID, &_node); 688 } 689 690 // set the results / close the handle on error 691 if (error == B_OK) { 692 *vnid = localID; 693 *cookie = (void*)reply->cookie; 694 } else 695 _Close(reply->cookie); 696 697 RETURN_ERROR(error); 698 } 699 700 // Open 701 status_t 702 ShareVolume::Open(Node* _node, int openMode, void** cookie) 703 { 704 ShareNode* node = dynamic_cast<ShareNode*>(_node); 705 706 // TODO: Allow opening the root node? 707 if (!_EnsureShareMounted()) 708 return ERROR_NOT_CONNECTED; 709 710 // check the open mode 711 if (IsReadOnly()) { 712 if ((openMode & O_RWMASK) == O_WRONLY) 713 return B_PERMISSION_DENIED; 714 if (openMode & O_TRUNC) 715 return B_PERMISSION_DENIED; 716 if ((openMode & O_RWMASK) == O_RDWR) 717 openMode = (openMode & ~O_RWMASK) | O_RDONLY; 718 } 719 // prepare the request 720 OpenRequest request; 721 request.volumeID = fID; 722 request.nodeID = node->GetRemoteID(); 723 request.openMode = openMode; 724 // send the request 725 OpenReply* reply; 726 status_t error = SendRequest(fConnection, &request, &reply); 727 if (error != B_OK) 728 RETURN_ERROR(error); 729 ObjectDeleter<Request> replyDeleter(reply); 730 if (reply->error != B_OK) 731 RETURN_ERROR(reply->error); 732 // update the node 733 _UpdateNode(reply->nodeInfo); 734 *cookie = (void*)reply->cookie; 735 return B_OK; 736 } 737 738 // Close 739 status_t 740 ShareVolume::Close(Node* _node, void* cookie) 741 { 742 // no-op: FreeCookie does the job 743 return B_OK; 744 } 745 746 // FreeCookie 747 status_t 748 ShareVolume::FreeCookie(Node* _node, void* cookie) 749 { 750 return _Close((int32)cookie); 751 } 752 753 // Read 754 status_t 755 ShareVolume::Read(Node* _node, void* cookie, off_t pos, void* _buffer, 756 size_t bufferSize, size_t* _bytesRead) 757 { 758 if (!_EnsureShareMounted()) 759 return ERROR_NOT_CONNECTED; 760 761 *_bytesRead = 0; 762 if (bufferSize == 0) 763 return B_OK; 764 uint8* buffer = (uint8*)_buffer; 765 // prepare the request 766 ReadRequest request; 767 request.volumeID = fID; 768 request.cookie = (int32)cookie; 769 request.pos = pos; 770 request.size = bufferSize; 771 772 struct ReadRequestHandler : public RequestHandler { 773 uint8* buffer; 774 off_t pos; 775 int32 bufferSize; 776 int32 bytesRead; 777 778 ReadRequestHandler(uint8* buffer, off_t pos, int32 bufferSize) 779 : buffer(buffer), 780 pos(pos), 781 bufferSize(bufferSize), 782 bytesRead(0) 783 { 784 } 785 786 virtual status_t HandleRequest(Request* _reply, RequestChannel* channel) 787 { 788 // the passed request is deleted by the request port 789 ReadReply* reply = dynamic_cast<ReadReply*>(_reply); 790 if (!reply) 791 RETURN_ERROR(B_BAD_DATA); 792 // process the reply 793 status_t error = ProcessReply(reply); 794 if (error != B_OK) 795 return error; 796 bool moreToCome = reply->moreToCome; 797 while (moreToCome) { 798 // receive a reply 799 error = ReceiveRequest(channel, &reply); 800 if (error != B_OK) 801 RETURN_ERROR(error); 802 moreToCome = reply->moreToCome; 803 ObjectDeleter<Request> replyDeleter(reply); 804 // process the reply 805 error = ProcessReply(reply); 806 if (error != B_OK) 807 return error; 808 } 809 return B_OK; 810 } 811 812 status_t ProcessReply(ReadReply* reply) 813 { 814 if (reply->error != B_OK) 815 RETURN_ERROR(reply->error); 816 // check the fields 817 if (reply->pos != pos) 818 RETURN_ERROR(B_BAD_DATA); 819 int32 bytesRead = reply->data.GetSize(); 820 if (bytesRead > (int32)bufferSize) 821 RETURN_ERROR(B_BAD_DATA); 822 // copy the data into the buffer 823 if (bytesRead > 0) 824 memcpy(buffer, reply->data.GetData(), bytesRead); 825 pos += bytesRead; 826 buffer += bytesRead; 827 bufferSize -= bytesRead; 828 this->bytesRead += bytesRead; 829 return B_OK; 830 } 831 } requestHandler(buffer, pos, bufferSize); 832 833 // send the request 834 status_t error = fConnection->SendRequest(&request, &requestHandler); 835 if (error != B_OK) 836 RETURN_ERROR(error); 837 *_bytesRead = requestHandler.bytesRead; 838 return B_OK; 839 } 840 841 // Write 842 status_t 843 ShareVolume::Write(Node* _node, void* cookie, off_t pos, const void* _buffer, 844 size_t bufferSize, size_t* bytesWritten) 845 { 846 if (!_EnsureShareMounted()) 847 return ERROR_NOT_CONNECTED; 848 849 // check permissions 850 if (IsReadOnly()) 851 return B_PERMISSION_DENIED; 852 853 *bytesWritten = 0; 854 off_t bytesLeft = bufferSize; 855 const char* buffer = (const char*)_buffer; 856 while (bytesLeft > 0) { 857 off_t toWrite = bytesLeft; 858 if (toWrite > kMaxWriteBufferSize) 859 toWrite = kMaxWriteBufferSize; 860 861 // prepare the request 862 WriteRequest request; 863 request.volumeID = fID; 864 request.cookie = (int32)cookie; 865 request.pos = pos; 866 request.data.SetTo(buffer, toWrite); 867 868 // send the request 869 WriteReply* reply; 870 status_t error = SendRequest(fConnection, &request, &reply); 871 if (error != B_OK) 872 RETURN_ERROR(error); 873 ObjectDeleter<Request> replyDeleter(reply); 874 if (reply->error != B_OK) 875 RETURN_ERROR(reply->error); 876 877 bytesLeft -= toWrite; 878 pos += toWrite; 879 buffer += toWrite; 880 881 // TODO: We should probably add an "up to date" flag for ShareNode (just as 882 // done for ShareAttrDir) and clear it at this point. Currently continuity 883 // inconsistencies could occur (e.g. a stat() after a write() returns 884 // obsolete data), depending on when the node monitoring update arrives. 885 } 886 887 *bytesWritten = bufferSize; 888 return B_OK; 889 } 890 891 892 // #pragma mark - 893 // #pragma mark ----- hard links / symlinks ----- 894 895 // Link 896 status_t 897 ShareVolume::Link(Node* _dir, const char* name, Node* _node) 898 { 899 ShareNode* dir = dynamic_cast<ShareNode*>(_dir); 900 ShareNode* node = dynamic_cast<ShareNode*>(_node); 901 902 if (!node || node->GetVolume() != this) 903 return B_NOT_ALLOWED; 904 905 if (!_EnsureShareMounted()) 906 return ERROR_NOT_CONNECTED; 907 908 // check permissions 909 if (IsReadOnly()) 910 return B_PERMISSION_DENIED; 911 if (IsVNodeRemoved(dir->GetID()) > 0) 912 RETURN_ERROR(B_NOT_ALLOWED); 913 if (IsVNodeRemoved(node->GetID()) > 0) 914 RETURN_ERROR(B_NOT_ALLOWED); 915 // prepare the request 916 CreateLinkRequest request; 917 request.volumeID = fID; 918 request.directoryID = dir->GetRemoteID(); 919 request.name.SetTo(name); 920 request.nodeID = node->GetRemoteID(); 921 // send the request 922 CreateLinkReply* reply; 923 status_t error = SendRequest(fConnection, &request, &reply); 924 if (error != B_OK) 925 RETURN_ERROR(error); 926 ObjectDeleter<Request> replyDeleter(reply); 927 RETURN_ERROR(reply->error); 928 } 929 930 // Unlink 931 status_t 932 ShareVolume::Unlink(Node* _dir, const char* name) 933 { 934 ShareNode* dir = dynamic_cast<ShareNode*>(_dir); 935 936 if (!_EnsureShareMounted()) 937 return ERROR_NOT_CONNECTED; 938 939 // check permissions 940 if (IsReadOnly()) 941 return B_PERMISSION_DENIED; 942 // prepare the request 943 UnlinkRequest request; 944 request.volumeID = fID; 945 request.directoryID = dir->GetRemoteID(); 946 request.name.SetTo(name); 947 // send the request 948 UnlinkReply* reply; 949 status_t error = SendRequest(fConnection, &request, &reply); 950 if (error != B_OK) 951 RETURN_ERROR(error); 952 ObjectDeleter<Request> replyDeleter(reply); 953 RETURN_ERROR(reply->error); 954 } 955 956 // Symlink 957 status_t 958 ShareVolume::Symlink(Node* _dir, const char* name, const char* target) 959 { 960 ShareNode* dir = dynamic_cast<ShareNode*>(_dir); 961 962 if (!_EnsureShareMounted()) 963 return ERROR_NOT_CONNECTED; 964 965 // check permissions 966 if (IsReadOnly()) 967 return B_PERMISSION_DENIED; 968 if (IsVNodeRemoved(dir->GetID()) > 0) 969 RETURN_ERROR(B_NOT_ALLOWED); 970 // prepare the request 971 CreateSymlinkRequest request; 972 request.volumeID = fID; 973 request.directoryID = dir->GetRemoteID(); 974 request.name.SetTo(name); 975 request.target.SetTo(target); 976 // send the request 977 CreateSymlinkReply* reply; 978 status_t error = SendRequest(fConnection, &request, &reply); 979 if (error != B_OK) 980 RETURN_ERROR(error); 981 ObjectDeleter<Request> replyDeleter(reply); 982 RETURN_ERROR(reply->error); 983 } 984 985 // ReadLink 986 status_t 987 ShareVolume::ReadLink(Node* _node, char* buffer, size_t bufferSize, 988 size_t* bytesRead) 989 { 990 ShareNode* node = dynamic_cast<ShareNode*>(_node); 991 992 if (!_EnsureShareMounted()) 993 return ERROR_NOT_CONNECTED; 994 995 *bytesRead = 0; 996 // prepare the request 997 ReadLinkRequest request; 998 request.volumeID = fID; 999 request.nodeID = node->GetRemoteID(); 1000 request.maxSize = bufferSize; 1001 // send the request 1002 ReadLinkReply* reply; 1003 status_t error = SendRequest(fConnection, &request, &reply); 1004 if (error != B_OK) 1005 RETURN_ERROR(error); 1006 ObjectDeleter<Request> replyDeleter(reply); 1007 if (reply->error != B_OK) 1008 RETURN_ERROR(reply->error); 1009 if (reply->data.GetSize() > (int32)bufferSize) 1010 RETURN_ERROR(B_BAD_DATA); 1011 *bytesRead = reply->data.GetSize(); 1012 if (*bytesRead > 0) 1013 memcpy(buffer, reply->data.GetData(), *bytesRead); 1014 _UpdateNode(reply->nodeInfo); 1015 return B_OK; 1016 } 1017 1018 // Rename 1019 status_t 1020 ShareVolume::Rename(Node* _oldDir, const char* oldName, Node* _newDir, 1021 const char* newName) 1022 { 1023 ShareNode* oldDir = dynamic_cast<ShareNode*>(_oldDir); 1024 ShareNode* newDir = dynamic_cast<ShareNode*>(_newDir); 1025 1026 if (!newDir || newDir->GetVolume() != this) 1027 return B_NOT_ALLOWED; 1028 1029 if (!_EnsureShareMounted()) 1030 return ERROR_NOT_CONNECTED; 1031 1032 // check permissions 1033 if (IsReadOnly()) 1034 return B_PERMISSION_DENIED; 1035 if (IsVNodeRemoved(newDir->GetID()) > 0) 1036 RETURN_ERROR(B_NOT_ALLOWED); 1037 // prepare the request 1038 RenameRequest request; 1039 request.volumeID = fID; 1040 request.oldDirectoryID = oldDir->GetRemoteID(); 1041 request.oldName.SetTo(oldName); 1042 request.newDirectoryID = newDir->GetRemoteID(); 1043 request.newName.SetTo(newName); 1044 // send the request 1045 RenameReply* reply; 1046 status_t error = SendRequest(fConnection, &request, &reply); 1047 if (error != B_OK) 1048 RETURN_ERROR(error); 1049 ObjectDeleter<Request> replyDeleter(reply); 1050 RETURN_ERROR(reply->error); 1051 } 1052 1053 1054 // #pragma mark - 1055 // #pragma mark ----- directories ----- 1056 1057 // MkDir 1058 status_t 1059 ShareVolume::MkDir(Node* _dir, const char* name, int mode) 1060 { 1061 ShareNode* dir = dynamic_cast<ShareNode*>(_dir); 1062 1063 if (!_EnsureShareMounted()) 1064 return ERROR_NOT_CONNECTED; 1065 1066 // check permissions 1067 if (IsReadOnly()) 1068 return B_PERMISSION_DENIED; 1069 if (IsVNodeRemoved(dir->GetID()) > 0) 1070 RETURN_ERROR(B_NOT_ALLOWED); 1071 // prepare the request 1072 MakeDirRequest request; 1073 request.volumeID = fID; 1074 request.directoryID = dir->GetRemoteID(); 1075 request.name.SetTo(name); 1076 request.mode = mode; 1077 // send the request 1078 MakeDirReply* reply; 1079 status_t error = SendRequest(fConnection, &request, &reply); 1080 if (error != B_OK) 1081 RETURN_ERROR(error); 1082 ObjectDeleter<Request> replyDeleter(reply); 1083 RETURN_ERROR(reply->error); 1084 } 1085 1086 // RmDir 1087 status_t 1088 ShareVolume::RmDir(Node* _dir, const char* name) 1089 { 1090 ShareNode* dir = dynamic_cast<ShareNode*>(_dir); 1091 1092 if (!_EnsureShareMounted()) 1093 return ERROR_NOT_CONNECTED; 1094 1095 // check permissions 1096 if (IsReadOnly()) 1097 return B_PERMISSION_DENIED; 1098 // prepare the request 1099 RemoveDirRequest request; 1100 request.volumeID = fID; 1101 request.directoryID = dir->GetRemoteID(); 1102 request.name.SetTo(name); 1103 // send the request 1104 RemoveDirReply* reply; 1105 status_t error = SendRequest(fConnection, &request, &reply); 1106 if (error != B_OK) 1107 RETURN_ERROR(error); 1108 ObjectDeleter<Request> replyDeleter(reply); 1109 RETURN_ERROR(reply->error); 1110 } 1111 1112 // OpenDir 1113 status_t 1114 ShareVolume::OpenDir(Node* _node, void** _cookie) 1115 { 1116 // we opendir() only directories 1117 ShareDir* node = dynamic_cast<ShareDir*>(_node); 1118 if (!node) 1119 return B_NOT_ALLOWED; 1120 1121 // TODO: Allow opening the root node? 1122 if (!_EnsureShareMounted()) 1123 return ERROR_NOT_CONNECTED; 1124 1125 // allocate a dir cookie 1126 DirCookie* cookie = new(std::nothrow) DirCookie; 1127 if (!cookie) 1128 RETURN_ERROR(B_NO_MEMORY); 1129 ObjectDeleter<DirCookie> cookieDeleter(cookie); 1130 1131 // if the directory is fully cached, we allocate a local iterator 1132 { 1133 AutoLocker<Locker> locker(fLock); 1134 if (node->IsComplete()) { 1135 // create a local dir iterator 1136 LocalShareDirIterator* iterator 1137 = new(std::nothrow) LocalShareDirIterator(); 1138 if (!iterator) 1139 RETURN_ERROR(B_NO_MEMORY); 1140 iterator->SetDirectory(node); 1141 1142 // init the cookie 1143 cookie->iterator = iterator; 1144 *_cookie = cookie; 1145 cookieDeleter.Detach(); 1146 return B_OK; 1147 } 1148 } 1149 1150 // allocate a remote dir iterator 1151 RemoteShareDirIterator* iterator = new(std::nothrow) RemoteShareDirIterator; 1152 if (!iterator) 1153 RETURN_ERROR(B_NO_MEMORY); 1154 ObjectDeleter<RemoteShareDirIterator> iteratorDeleter(iterator); 1155 1156 // prepare the request 1157 OpenDirRequest request; 1158 request.volumeID = fID; 1159 request.nodeID = node->GetRemoteID(); 1160 1161 // send the request 1162 OpenDirReply* reply; 1163 status_t error = SendRequest(fConnection, &request, &reply); 1164 if (error != B_OK) 1165 RETURN_ERROR(error); 1166 ObjectDeleter<Request> replyDeleter(reply); 1167 if (reply->error != B_OK) 1168 { 1169 PRINT(("OpenDir() failed: node: %lld, remote: (%ld, %lld)\n", 1170 node->GetID(), node->GetRemoteID().volumeID, node->GetRemoteID().nodeID)); 1171 RETURN_ERROR(reply->error); 1172 } 1173 1174 // update the node 1175 _UpdateNode(reply->nodeInfo); 1176 1177 // init the cookie 1178 iterator->SetCookie(reply->cookie); 1179 cookie->iterator = iterator; 1180 1181 *_cookie = cookie; 1182 cookieDeleter.Detach(); 1183 iteratorDeleter.Detach(); 1184 return B_OK; 1185 } 1186 1187 // CloseDir 1188 status_t 1189 ShareVolume::CloseDir(Node* _node, void* cookie) 1190 { 1191 // no-op: FreeDirCookie does the job 1192 return B_OK; 1193 } 1194 1195 // FreeDirCookie 1196 status_t 1197 ShareVolume::FreeDirCookie(Node* _node, void* _cookie) 1198 { 1199 DirCookie* cookie = (DirCookie*)_cookie; 1200 ObjectDeleter<DirCookie> _(cookie); 1201 ShareDirIterator* iterator = cookie->iterator; 1202 1203 status_t error = B_OK; 1204 if (RemoteShareDirIterator* remoteIterator 1205 = dynamic_cast<RemoteShareDirIterator*>(iterator)) { 1206 // prepare the request 1207 CloseRequest request; 1208 request.volumeID = fID; 1209 request.cookie = remoteIterator->GetCookie(); 1210 1211 // send the request 1212 if (!_EnsureShareMounted()) 1213 error = ERROR_NOT_CONNECTED; 1214 1215 if (error == B_OK) { 1216 CloseReply* reply; 1217 error = SendRequest(fConnection, &request, &reply); 1218 if (error == B_OK) { 1219 error = reply->error; 1220 delete reply; 1221 } 1222 } 1223 } 1224 1225 // delete the iterator 1226 AutoLocker<Locker> locker(fLock); 1227 delete iterator; 1228 1229 return error; 1230 } 1231 1232 // ReadDir 1233 status_t 1234 ShareVolume::ReadDir(Node* _dir, void* _cookie, struct dirent* buffer, 1235 size_t bufferSize, int32 count, int32* countRead) 1236 { 1237 ShareDir* directory = dynamic_cast<ShareDir*>(_dir); 1238 1239 if (!_EnsureShareMounted()) 1240 return ERROR_NOT_CONNECTED; 1241 1242 *countRead = 0; 1243 if (count <= 0) 1244 return B_OK; 1245 1246 DirCookie* cookie = (DirCookie*)_cookie; 1247 ShareDirIterator* iterator = cookie->iterator; 1248 1249 while (true) { 1250 status_t error; 1251 AutoLocker<Locker> locker(fLock); 1252 while (ShareDirEntry* entry = iterator->GetCurrentEntry()) { 1253 // re-get the entry -- it might already have been removed 1254 const char* name = entry->GetName(); 1255 entry = _GetEntryByLocalID(directory->GetID(), name); 1256 if (entry) { 1257 // set the name: this also checks the size of the buffer 1258 error = set_dirent_name(buffer, bufferSize, name, 1259 strlen(name)); 1260 if (error != B_OK) { 1261 // if something has been read at all, we're content 1262 if (*countRead > 0) 1263 return B_OK; 1264 RETURN_ERROR(error); 1265 } 1266 1267 // fill in the other fields 1268 buffer->d_pdev = fVolumeManager->GetID(); 1269 buffer->d_pino = directory->GetID(); 1270 buffer->d_dev = fVolumeManager->GetID(); 1271 buffer->d_ino = entry->GetNode()->GetID(); 1272 1273 // if the entry is the parent of the share root, we need to 1274 // fix the node ID 1275 if (directory == fRootNode && strcmp(name, "..") == 0) { 1276 if (Volume* parentVolume = GetParentVolume()) 1277 buffer->d_ino = parentVolume->GetRootID(); 1278 } 1279 1280 iterator->NextEntry(); 1281 (*countRead)++; 1282 if (*countRead >= count || !next_dirent(buffer, bufferSize)) 1283 return B_OK; 1284 } else 1285 iterator->NextEntry(); 1286 } 1287 1288 // no more entries: check, if we're completely through 1289 if (iterator->IsDone()) 1290 return B_OK; 1291 1292 // we need to actually get entries from the server 1293 locker.Unlock(); 1294 if (RemoteShareDirIterator* remoteIterator 1295 = dynamic_cast<RemoteShareDirIterator*>(iterator)) { 1296 error = _ReadRemoteDir(directory, remoteIterator); 1297 if (error != B_OK) 1298 return error; 1299 } 1300 } 1301 } 1302 1303 // RewindDir 1304 status_t 1305 ShareVolume::RewindDir(Node* _node, void* _cookie) 1306 { 1307 DirCookie* cookie = (DirCookie*)_cookie; 1308 ShareDirIterator* iterator = cookie->iterator; 1309 AutoLocker<Locker> _(fLock); 1310 iterator->Rewind(); 1311 return B_OK; 1312 } 1313 1314 // Walk 1315 status_t 1316 ShareVolume::Walk(Node* _dir, const char* entryName, char** resolvedPath, 1317 vnode_id* vnid) 1318 { 1319 ShareDir* dir = dynamic_cast<ShareDir*>(_dir); 1320 if (!dir) 1321 return B_BAD_VALUE; 1322 1323 // we always resolve "." and ".." of the root node 1324 if (dir == fRootNode) { 1325 if (strcmp(entryName, ".") == 0 || strcmp(entryName, "..") == 0) { 1326 AutoLocker<Locker> _(fLock); 1327 if (strcmp(entryName, ".") == 0) { 1328 *vnid = fRootNode->GetID(); 1329 } else if (Volume* parentVolume = GetParentVolume()) { 1330 *vnid = parentVolume->GetRootID(); 1331 } else 1332 *vnid = fRootNode->GetID(); 1333 Node* node; 1334 return GetVNode(*vnid, &node); 1335 } 1336 } 1337 1338 if (!_EnsureShareMounted()) 1339 return ERROR_NOT_CONNECTED; 1340 1341 // check, if the entry is already known 1342 { 1343 AutoLocker<Locker> _(fLock); 1344 ShareDirEntry* entry = _GetEntryByLocalID(dir->GetID(), entryName); 1345 if (entry) { 1346 *vnid = entry->GetNode()->GetID(); 1347 Node* node; 1348 return GetVNode(*vnid, &node); 1349 } else if (dir->IsComplete()) 1350 return B_ENTRY_NOT_FOUND; 1351 } 1352 1353 WalkReply* reply; 1354 while (true) { 1355 // send the request 1356 status_t error = _Walk(dir->GetRemoteID(), entryName, resolvedPath, 1357 &reply); 1358 if (error != B_OK) 1359 RETURN_ERROR(error); 1360 ObjectDeleter<Request> replyDeleter(reply); 1361 1362 AutoLocker<Locker> locker(fLock); 1363 1364 // check, if the returned info is obsolete 1365 if (_IsObsoleteEntryInfo(reply->entryInfo)) 1366 continue; 1367 1368 // load the entry 1369 ShareDirEntry* entry; 1370 error = _LoadEntry(dir, reply->entryInfo, &entry); 1371 if (error != B_OK) 1372 RETURN_ERROR(error); 1373 *vnid = entry->GetNode()->GetID(); 1374 1375 // deal with symlinks 1376 if (reply->linkPath.GetString() && resolvedPath) { 1377 *resolvedPath = strdup(reply->linkPath.GetString()); 1378 if (!*resolvedPath) 1379 RETURN_ERROR(B_NO_MEMORY); 1380 return B_OK; 1381 } 1382 1383 break; 1384 } 1385 1386 // no symlink or we shall not resolve it: get the node 1387 Node* _node; 1388 RETURN_ERROR(GetVNode(*vnid, &_node)); 1389 } 1390 1391 1392 // #pragma mark - 1393 // #pragma mark ----- attributes ----- 1394 1395 // OpenAttrDir 1396 status_t 1397 ShareVolume::OpenAttrDir(Node* _node, void** _cookie) 1398 { 1399 ShareNode* node = dynamic_cast<ShareNode*>(_node); 1400 1401 // TODO: Allow opening the root node? 1402 if (!_EnsureShareMounted()) 1403 return ERROR_NOT_CONNECTED; 1404 1405 // allocate a dir cookie 1406 AttrDirCookie* cookie = new(std::nothrow) AttrDirCookie; 1407 if (!cookie) 1408 RETURN_ERROR(B_NO_MEMORY); 1409 ObjectDeleter<AttrDirCookie> cookieDeleter(cookie); 1410 1411 AutoLocker<Locker> locker(fLock); 1412 1413 if (!node->GetAttrDir() || !node->GetAttrDir()->IsUpToDate()) { 1414 // prepare the request 1415 OpenAttrDirRequest request; 1416 request.volumeID = fID; 1417 request.nodeID = node->GetRemoteID(); 1418 1419 locker.Unlock(); 1420 1421 // send the request 1422 OpenAttrDirReply* reply; 1423 status_t error = SendRequest(fConnection, &request, &reply); 1424 if (error != B_OK) 1425 RETURN_ERROR(error); 1426 ObjectDeleter<Request> replyDeleter(reply); 1427 if (reply->error != B_OK) 1428 RETURN_ERROR(reply->error); 1429 1430 // If no AttrDirInfo was supplied, we just save the cookie and be done. 1431 // This usually happens when the attr dir is too big to be cached. 1432 if (!reply->attrDirInfo.isValid) { 1433 cookie->cookie = reply->cookie; 1434 cookie->rewind = false; 1435 *_cookie = cookie; 1436 cookieDeleter.Detach(); 1437 return B_OK; 1438 } 1439 1440 locker.SetTo(fLock, false); 1441 1442 // a AttrDirInfo has been supplied: load the attr dir 1443 error = _LoadAttrDir(node, reply->attrDirInfo); 1444 if (error != B_OK) 1445 return error; 1446 } 1447 1448 // we have a valid attr dir: create an attr dir iterator 1449 ShareAttrDirIterator* iterator = new(std::nothrow) ShareAttrDirIterator; 1450 if (!iterator) 1451 return B_NO_MEMORY; 1452 iterator->SetAttrDir(node->GetAttrDir()); 1453 1454 // add the iterator 1455 status_t error = _AddAttrDirIterator(node, iterator); 1456 if (error != B_OK) { 1457 delete iterator; 1458 return error; 1459 } 1460 1461 cookie->iterator = iterator; 1462 *_cookie = cookie; 1463 cookieDeleter.Detach(); 1464 return B_OK; 1465 } 1466 1467 // CloseAttrDir 1468 status_t 1469 ShareVolume::CloseAttrDir(Node* _node, void* cookie) 1470 { 1471 // no-op: FreeAttrDirCookie does the job 1472 return B_OK; 1473 } 1474 1475 // FreeAttrDirCookie 1476 status_t 1477 ShareVolume::FreeAttrDirCookie(Node* _node, void* _cookie) 1478 { 1479 ShareNode* node = dynamic_cast<ShareNode*>(_node); 1480 AttrDirCookie* cookie = (AttrDirCookie*)_cookie; 1481 ObjectDeleter<AttrDirCookie> _(cookie); 1482 1483 // if this is a local iterator, we just delete it and be done 1484 if (cookie->iterator) { 1485 AutoLocker<Locker> locker(fLock); 1486 1487 // remove and delete the iterator 1488 _RemoveAttrDirIterator(node, cookie->iterator); 1489 delete cookie->iterator; 1490 1491 return B_OK; 1492 } 1493 1494 // prepare the request 1495 CloseRequest request; 1496 request.volumeID = fID; 1497 request.cookie = cookie->cookie; 1498 1499 // send the request 1500 if (!_EnsureShareMounted()) 1501 return ERROR_NOT_CONNECTED; 1502 CloseReply* reply; 1503 status_t error = SendRequest(fConnection, &request, &reply); 1504 if (error != B_OK) 1505 RETURN_ERROR(error); 1506 ObjectDeleter<Request> replyDeleter(reply); 1507 if (reply->error != B_OK) 1508 RETURN_ERROR(reply->error); 1509 1510 return B_OK; 1511 } 1512 1513 // ReadAttrDir 1514 status_t 1515 ShareVolume::ReadAttrDir(Node* _node, void* _cookie, struct dirent* buffer, 1516 size_t bufferSize, int32 count, int32* countRead) 1517 { 1518 if (!_EnsureShareMounted()) 1519 return ERROR_NOT_CONNECTED; 1520 1521 *countRead = 0; 1522 AttrDirCookie* cookie = (AttrDirCookie*)_cookie; 1523 1524 // if we have a local iterator, things are easy 1525 if (ShareAttrDirIterator* iterator = cookie->iterator) { 1526 AutoLocker<Locker> locker(fLock); 1527 1528 // get the current attribute 1529 Attribute* attribute = iterator->GetCurrentAttribute(); 1530 if (!attribute) 1531 return B_OK; 1532 1533 // set the name: this also checks the size of the buffer 1534 const char* name = attribute->GetName(); 1535 status_t error = set_dirent_name(buffer, bufferSize, name, 1536 strlen(name)); 1537 if (error != B_OK) 1538 RETURN_ERROR(error); 1539 1540 // fill in the other fields 1541 buffer->d_dev = fVolumeManager->GetID(); 1542 buffer->d_ino = -1; 1543 *countRead = 1; 1544 1545 iterator->NextAttribute(); 1546 return B_OK; 1547 } 1548 1549 // prepare the request 1550 ReadAttrDirRequest request; 1551 request.volumeID = fID; 1552 request.cookie = cookie->cookie; 1553 request.count = 1; 1554 request.rewind = cookie->rewind; 1555 1556 // send the request 1557 ReadAttrDirReply* reply; 1558 status_t error = SendRequest(fConnection, &request, &reply); 1559 if (error != B_OK) 1560 RETURN_ERROR(error); 1561 ObjectDeleter<Request> replyDeleter(reply); 1562 if (reply->error != B_OK) 1563 RETURN_ERROR(reply->error); 1564 cookie->rewind = false; 1565 1566 // check, if anything has been read at all 1567 if (reply->count == 0) { 1568 *countRead = 0; 1569 return B_OK; 1570 } 1571 const char* name = reply->name.GetString(); 1572 int32 nameLen = reply->name.GetSize(); 1573 if (!name || nameLen < 2) 1574 return B_BAD_DATA; 1575 1576 // set the name: this also checks the size of the buffer 1577 error = set_dirent_name(buffer, bufferSize, name, nameLen - 1); 1578 if (error != B_OK) 1579 RETURN_ERROR(error); 1580 1581 // fill in the other fields 1582 buffer->d_dev = fVolumeManager->GetID(); 1583 buffer->d_ino = -1; 1584 *countRead = 1; 1585 return B_OK; 1586 } 1587 1588 // RewindAttrDir 1589 status_t 1590 ShareVolume::RewindAttrDir(Node* _node, void* _cookie) 1591 { 1592 AttrDirCookie* cookie = (AttrDirCookie*)_cookie; 1593 1594 // if we have a local iterator, rewind it 1595 if (ShareAttrDirIterator* iterator = cookie->iterator) { 1596 AutoLocker<Locker> locker(fLock); 1597 1598 iterator->Rewind(); 1599 } else 1600 cookie->rewind = true; 1601 1602 return B_OK; 1603 } 1604 1605 // ReadAttr 1606 status_t 1607 ShareVolume::ReadAttr(Node* _node, const char* name, int type, off_t pos, 1608 void* _buffer, size_t bufferSize, size_t* _bytesRead) 1609 { 1610 ShareNode* node = dynamic_cast<ShareNode*>(_node); 1611 1612 if (!_EnsureShareMounted()) 1613 return ERROR_NOT_CONNECTED; 1614 1615 *_bytesRead = 0; 1616 if (bufferSize == 0) 1617 return B_OK; 1618 uint8* buffer = (uint8*)_buffer; 1619 1620 // if we have the attribute directory cached, we can first check, if the 1621 // attribute exists at all -- maybe its data are cached, too 1622 { 1623 AutoLocker<Locker> locker(fLock); 1624 1625 ShareAttrDir* attrDir = node->GetAttrDir(); 1626 if (attrDir && attrDir->IsUpToDate()) { 1627 // get the attribute 1628 Attribute* attribute = attrDir->GetAttribute(name); 1629 if (!attribute) 1630 return B_ENTRY_NOT_FOUND; 1631 1632 // get the data 1633 if (const void* data = attribute->GetData()) { 1634 // first check, if we can read anything at all 1635 if (pos < 0) 1636 pos = 0; 1637 int32 size = attribute->GetSize(); 1638 if (pos >= size) 1639 return B_OK; 1640 1641 // get the data 1642 bufferSize = min(bufferSize, size_t(size - pos)); 1643 memcpy(buffer, data, bufferSize); 1644 *_bytesRead = bufferSize; 1645 return B_OK; 1646 } 1647 } 1648 } 1649 1650 // prepare the request 1651 ReadAttrRequest request; 1652 request.volumeID = fID; 1653 request.nodeID = node->GetRemoteID(); 1654 request.name.SetTo(name); 1655 request.type = type; 1656 request.pos = pos; 1657 request.size = bufferSize; 1658 1659 struct ReadRequestHandler : public RequestHandler { 1660 uint8* buffer; 1661 off_t pos; 1662 int32 bufferSize; 1663 int32 bytesRead; 1664 1665 ReadRequestHandler(uint8* buffer, off_t pos, int32 bufferSize) 1666 : buffer(buffer), 1667 pos(pos), 1668 bufferSize(bufferSize), 1669 bytesRead(0) 1670 { 1671 } 1672 1673 virtual status_t HandleRequest(Request* _reply, RequestChannel* channel) 1674 { 1675 // the passed request is deleted by the request port 1676 ReadAttrReply* reply = dynamic_cast<ReadAttrReply*>(_reply); 1677 if (!reply) 1678 RETURN_ERROR(B_BAD_DATA); 1679 // process the reply 1680 status_t error = ProcessReply(reply); 1681 if (error != B_OK) 1682 return error; 1683 bool moreToCome = reply->moreToCome; 1684 while (moreToCome) { 1685 // receive a reply 1686 error = ReceiveRequest(channel, &reply); 1687 if (error != B_OK) 1688 RETURN_ERROR(error); 1689 moreToCome = reply->moreToCome; 1690 ObjectDeleter<Request> replyDeleter(reply); 1691 // process the reply 1692 error = ProcessReply(reply); 1693 if (error != B_OK) 1694 return error; 1695 } 1696 return B_OK; 1697 } 1698 1699 status_t ProcessReply(ReadAttrReply* reply) 1700 { 1701 if (reply->error != B_OK) 1702 RETURN_ERROR(reply->error); 1703 // check the fields 1704 if (reply->pos != pos) 1705 RETURN_ERROR(B_BAD_DATA); 1706 int32 bytesRead = reply->data.GetSize(); 1707 if (bytesRead > (int32)bufferSize) 1708 RETURN_ERROR(B_BAD_DATA); 1709 // copy the data into the buffer 1710 if (bytesRead > 0) 1711 memcpy(buffer, reply->data.GetData(), bytesRead); 1712 pos += bytesRead; 1713 buffer += bytesRead; 1714 bufferSize -= bytesRead; 1715 this->bytesRead += bytesRead; 1716 return B_OK; 1717 } 1718 } requestHandler(buffer, pos, bufferSize); 1719 1720 // send the request 1721 status_t error = fConnection->SendRequest(&request, &requestHandler); 1722 if (error != B_OK) 1723 RETURN_ERROR(error); 1724 *_bytesRead = requestHandler.bytesRead; 1725 return B_OK; 1726 } 1727 1728 // WriteAttr 1729 status_t 1730 ShareVolume::WriteAttr(Node* _node, const char* name, int type, off_t pos, 1731 const void* _buffer, size_t bufferSize, size_t* bytesWritten) 1732 { 1733 ShareNode* node = dynamic_cast<ShareNode*>(_node); 1734 1735 if (!_EnsureShareMounted()) 1736 return ERROR_NOT_CONNECTED; 1737 1738 // check permissions 1739 if (IsReadOnly()) 1740 return B_PERMISSION_DENIED; 1741 1742 *bytesWritten = 0; 1743 off_t bytesLeft = bufferSize; 1744 const char* buffer = (const char*)_buffer; 1745 while (bytesLeft > 0) { 1746 // store the current attibute dir revision for reference below 1747 int64 attrDirRevision = -1; 1748 { 1749 AutoLocker<Locker> _(fLock); 1750 if (ShareAttrDir* attrDir = node->GetAttrDir()) { 1751 if (attrDir->IsUpToDate()) 1752 attrDirRevision = attrDir->GetRevision(); 1753 } 1754 } 1755 1756 off_t toWrite = bytesLeft; 1757 if (toWrite > kMaxWriteBufferSize) 1758 toWrite = kMaxWriteBufferSize; 1759 1760 // prepare the request 1761 WriteAttrRequest request; 1762 request.volumeID = fID; 1763 request.nodeID = node->GetRemoteID(); 1764 request.name.SetTo(name); 1765 request.type = type; 1766 request.pos = pos; 1767 request.data.SetTo(buffer, toWrite); 1768 1769 // send the request 1770 WriteAttrReply* reply; 1771 status_t error = SendRequest(fConnection, &request, &reply); 1772 if (error != B_OK) 1773 RETURN_ERROR(error); 1774 1775 ObjectDeleter<Request> replyDeleter(reply); 1776 if (reply->error != B_OK) 1777 RETURN_ERROR(reply->error); 1778 1779 bytesLeft -= toWrite; 1780 pos += toWrite; 1781 buffer += toWrite; 1782 1783 // If the request was successful, we consider the cached attr dir 1784 // no longer up to date. 1785 if (attrDirRevision >= 0) { 1786 AutoLocker<Locker> _(fLock); 1787 ShareAttrDir* attrDir = node->GetAttrDir(); 1788 if (attrDir && attrDir->GetRevision() == attrDirRevision) 1789 attrDir->SetUpToDate(false); 1790 } 1791 } 1792 1793 *bytesWritten = bufferSize; 1794 return B_OK; 1795 } 1796 1797 // RemoveAttr 1798 status_t 1799 ShareVolume::RemoveAttr(Node* _node, const char* name) 1800 { 1801 ShareNode* node = dynamic_cast<ShareNode*>(_node); 1802 1803 if (!_EnsureShareMounted()) 1804 return ERROR_NOT_CONNECTED; 1805 1806 // check permissions 1807 if (IsReadOnly()) 1808 return B_PERMISSION_DENIED; 1809 1810 // store the current attibute dir revision for reference below 1811 int64 attrDirRevision = -1; 1812 { 1813 AutoLocker<Locker> _(fLock); 1814 if (ShareAttrDir* attrDir = node->GetAttrDir()) { 1815 if (attrDir->IsUpToDate()) 1816 attrDirRevision = attrDir->GetRevision(); 1817 } 1818 } 1819 1820 // prepare the request 1821 RemoveAttrRequest request; 1822 request.volumeID = fID; 1823 request.nodeID = node->GetRemoteID(); 1824 request.name.SetTo(name); 1825 1826 // send the request 1827 RemoveAttrReply* reply; 1828 status_t error = SendRequest(fConnection, &request, &reply); 1829 if (error != B_OK) 1830 RETURN_ERROR(error); 1831 ObjectDeleter<Request> replyDeleter(reply); 1832 1833 // If the request was successful, we consider the cached attr dir 1834 // no longer up to date. 1835 if (reply->error == B_OK && attrDirRevision >= 0) { 1836 AutoLocker<Locker> _(fLock); 1837 ShareAttrDir* attrDir = node->GetAttrDir(); 1838 if (attrDir && attrDir->GetRevision() == attrDirRevision) 1839 attrDir->SetUpToDate(false); 1840 } 1841 1842 RETURN_ERROR(reply->error); 1843 } 1844 1845 // RenameAttr 1846 status_t 1847 ShareVolume::RenameAttr(Node* _node, const char* oldName, const char* newName) 1848 { 1849 ShareNode* node = dynamic_cast<ShareNode*>(_node); 1850 1851 if (!_EnsureShareMounted()) 1852 return ERROR_NOT_CONNECTED; 1853 1854 // check permissions 1855 if (IsReadOnly()) 1856 return B_PERMISSION_DENIED; 1857 1858 // store the current attibute dir revision for reference below 1859 int64 attrDirRevision = -1; 1860 { 1861 AutoLocker<Locker> _(fLock); 1862 if (ShareAttrDir* attrDir = node->GetAttrDir()) { 1863 if (attrDir->IsUpToDate()) 1864 attrDirRevision = attrDir->GetRevision(); 1865 } 1866 } 1867 1868 // prepare the request 1869 RenameAttrRequest request; 1870 request.volumeID = fID; 1871 request.nodeID = node->GetRemoteID(); 1872 request.oldName.SetTo(oldName); 1873 request.newName.SetTo(newName); 1874 1875 // send the request 1876 RenameAttrReply* reply; 1877 status_t error = SendRequest(fConnection, &request, &reply); 1878 if (error != B_OK) 1879 RETURN_ERROR(error); 1880 ObjectDeleter<Request> replyDeleter(reply); 1881 1882 // If the request was successful, we consider the cached attr dir 1883 // no longer up to date. 1884 if (reply->error == B_OK && attrDirRevision >= 0) { 1885 AutoLocker<Locker> _(fLock); 1886 ShareAttrDir* attrDir = node->GetAttrDir(); 1887 if (attrDir && attrDir->GetRevision() == attrDirRevision) 1888 attrDir->SetUpToDate(false); 1889 } 1890 1891 RETURN_ERROR(reply->error); 1892 } 1893 1894 // StatAttr 1895 status_t 1896 ShareVolume::StatAttr(Node* _node, const char* name, struct attr_info* attrInfo) 1897 { 1898 ShareNode* node = dynamic_cast<ShareNode*>(_node); 1899 1900 if (!_EnsureShareMounted()) 1901 return ERROR_NOT_CONNECTED; 1902 1903 // if we have the attribute directory cached, get the info from there 1904 { 1905 AutoLocker<Locker> locker(fLock); 1906 1907 ShareAttrDir* attrDir = node->GetAttrDir(); 1908 if (attrDir && attrDir->IsUpToDate()) { 1909 // get the attribute 1910 Attribute* attribute = attrDir->GetAttribute(name); 1911 if (!attribute) 1912 return B_ENTRY_NOT_FOUND; 1913 1914 attribute->GetInfo(attrInfo); 1915 return B_OK; 1916 } 1917 } 1918 1919 // prepare the request 1920 StatAttrRequest request; 1921 request.volumeID = fID; 1922 request.nodeID = node->GetRemoteID(); 1923 request.name.SetTo(name); 1924 1925 // send the request 1926 StatAttrReply* reply; 1927 status_t error = SendRequest(fConnection, &request, &reply); 1928 if (error != B_OK) 1929 RETURN_ERROR(error); 1930 ObjectDeleter<Request> replyDeleter(reply); 1931 if (reply->error != B_OK) 1932 RETURN_ERROR(reply->error); 1933 1934 // set the result 1935 *attrInfo = reply->attrInfo.info; 1936 return B_OK; 1937 } 1938 1939 1940 // #pragma mark - 1941 // #pragma mark ----- queries ----- 1942 1943 // GetQueryEntry 1944 status_t 1945 ShareVolume::GetQueryEntry(const EntryInfo& entryInfo, 1946 const NodeInfo& dirInfo, struct dirent* buffer, size_t bufferSize, 1947 int32* countRead) 1948 { 1949 status_t error = B_OK; 1950 1951 const char* name = entryInfo.name.GetString(); 1952 int32 nameLen = entryInfo.name.GetSize(); 1953 if (!name || nameLen < 2) 1954 RETURN_ERROR(B_BAD_DATA); 1955 1956 // load the directory 1957 vnode_id localDirID = -1; 1958 { 1959 AutoLocker<Locker> _(fLock); 1960 ShareNode* node; 1961 error = _LoadNode(dirInfo, &node); 1962 if (error != B_OK) 1963 RETURN_ERROR(error); 1964 ShareDir* directory = dynamic_cast<ShareDir*>(node); 1965 if (!directory) 1966 RETURN_ERROR(B_ENTRY_NOT_FOUND); 1967 localDirID = directory->GetID(); 1968 } 1969 1970 // add/update the entry 1971 vnode_id localNodeID = -1; 1972 const EntryInfo* resolvedEntryInfo = &entryInfo; 1973 while (error == B_OK) { 1974 // get an up to date entry info 1975 WalkReply* walkReply = NULL; 1976 if (!resolvedEntryInfo) { 1977 error = _Walk(entryInfo.directoryID, name, false, 1978 &walkReply); 1979 if (error != B_OK) 1980 RETURN_ERROR(error); 1981 1982 resolvedEntryInfo = &walkReply->entryInfo; 1983 } 1984 ObjectDeleter<Request> walkReplyDeleter(walkReply); 1985 1986 AutoLocker<Locker> locker(fLock); 1987 1988 // check, if the info is obsolete 1989 if (_IsObsoleteEntryInfo(*resolvedEntryInfo)) { 1990 resolvedEntryInfo = NULL; 1991 continue; 1992 } 1993 1994 // get the directory 1995 ShareDir* dir = dynamic_cast<ShareDir*>(_GetNodeByLocalID(localDirID)); 1996 if (!dir) 1997 RETURN_ERROR(B_ERROR); 1998 1999 // load the entry 2000 ShareDirEntry* entry; 2001 error = _LoadEntry(dir, *resolvedEntryInfo, &entry); 2002 if (error == B_OK) 2003 localNodeID = entry->GetNode()->GetID(); 2004 2005 break; 2006 } 2007 2008 // set the name: this also checks the size of the buffer 2009 error = set_dirent_name(buffer, bufferSize, name, nameLen - 1); 2010 if (error != B_OK) 2011 RETURN_ERROR(error); 2012 2013 // fill in the other fields 2014 buffer->d_pdev = fVolumeManager->GetID(); 2015 buffer->d_pino = localDirID; 2016 buffer->d_dev = fVolumeManager->GetID(); 2017 buffer->d_ino = localNodeID; 2018 2019 *countRead = 1; 2020 PRINT((" entry: d_dev: %ld, d_pdev: %ld, d_ino: %Ld, d_pino: %Ld, " 2021 "d_reclen: %hu, d_name: `%s'\n", 2022 buffer->d_dev, buffer->d_pdev, buffer->d_ino, buffer->d_pino, 2023 buffer->d_reclen, buffer->d_name)); 2024 return B_OK; 2025 } 2026 2027 2028 // #pragma mark - 2029 2030 // ProcessNodeMonitoringRequest 2031 void 2032 ShareVolume::ProcessNodeMonitoringRequest(NodeMonitoringRequest* request) 2033 { 2034 switch (request->opcode) { 2035 case B_ENTRY_CREATED: 2036 _HandleEntryCreatedRequest( 2037 dynamic_cast<EntryCreatedRequest*>(request)); 2038 break; 2039 case B_ENTRY_REMOVED: 2040 _HandleEntryRemovedRequest( 2041 dynamic_cast<EntryRemovedRequest*>(request)); 2042 break; 2043 case B_ENTRY_MOVED: 2044 _HandleEntryMovedRequest( 2045 dynamic_cast<EntryMovedRequest*>(request)); 2046 break; 2047 case B_STAT_CHANGED: 2048 _HandleStatChangedRequest( 2049 dynamic_cast<StatChangedRequest*>(request)); 2050 break; 2051 case B_ATTR_CHANGED: 2052 _HandleAttributeChangedRequest( 2053 dynamic_cast<AttributeChangedRequest*>(request)); 2054 break; 2055 } 2056 } 2057 2058 // ConnectionClosed 2059 void 2060 ShareVolume::ConnectionClosed() 2061 { 2062 AutoLocker<Locker> _(fMountLock); 2063 fConnectionState = CONNECTION_CLOSED; 2064 } 2065 2066 2067 // #pragma mark - 2068 2069 // _ReadRemoteDir 2070 status_t 2071 ShareVolume::_ReadRemoteDir(ShareDir* directory, 2072 RemoteShareDirIterator* iterator) 2073 { 2074 // prepare the request 2075 fLock.Lock(); 2076 ReadDirRequest request; 2077 request.volumeID = fID; 2078 request.cookie = iterator->GetCookie(); 2079 request.count = iterator->GetCapacity(); 2080 request.rewind = iterator->GetRewind(); 2081 fLock.Unlock(); 2082 2083 // send the request 2084 ReadDirReply* reply; 2085 status_t error = SendRequest(fConnection, &request, &reply); 2086 if (error != B_OK) 2087 RETURN_ERROR(error); 2088 ObjectDeleter<Request> replyDeleter(reply); 2089 if (reply->error != B_OK) 2090 RETURN_ERROR(reply->error); 2091 2092 RequestMemberArray<EntryInfo>* entryInfos = &reply->entryInfos; 2093 while (true) { 2094 // get up to date entry infos 2095 MultiWalkReply* walkReply = NULL; 2096 if (!entryInfos) { 2097 error = _MultiWalk(reply->entryInfos, &walkReply); 2098 if (error != B_OK) 2099 RETURN_ERROR(error); 2100 2101 entryInfos = &walkReply->entryInfos; 2102 } 2103 ObjectDeleter<Request> walkReplyDeleter(walkReply); 2104 2105 AutoLocker<Locker> locker(fLock); 2106 2107 // check, if any info is obsolete 2108 int32 count = entryInfos->CountElements(); 2109 for (int32 i = 0; i < count; i++) { 2110 const EntryInfo& entryInfo = entryInfos->GetElements()[i]; 2111 if (_IsObsoleteEntryInfo(entryInfo)) { 2112 entryInfos = NULL; 2113 continue; 2114 } 2115 } 2116 2117 // init the iterator's revision, if it's new or has been rewinded 2118 if (request.rewind || iterator->GetRevision() < 0) 2119 iterator->SetRevision(reply->revision); 2120 2121 iterator->Clear(); 2122 iterator->SetDone(reply->done); 2123 2124 // iterate through the entries 2125 for (int32 i = 0; i < count; i++) { 2126 const EntryInfo& entryInfo = entryInfos->GetElements()[i]; 2127 const char* name = entryInfo.name.GetString(); 2128 int32 nameLen = entryInfo.name.GetSize(); 2129 if (!name || nameLen < 2) 2130 return B_BAD_DATA; 2131 2132 // load the node/entry 2133 ShareDirEntry* entry; 2134 error = _LoadEntry(directory, entryInfo, &entry); 2135 if (error != B_OK) 2136 RETURN_ERROR(error); 2137 2138 // add the entry 2139 if (!iterator->AddEntry(entry)) { 2140 ERROR("ShareVolume::_ReadRemoteDir(): ERROR: Failed to add " 2141 "entry to remote iterator!\n"); 2142 } 2143 } 2144 2145 // directory now complete? 2146 if (reply->done && directory->GetEntryRemovedEventRevision() 2147 < iterator->GetRevision()) { 2148 directory->SetComplete(true); 2149 } 2150 2151 break; 2152 } 2153 2154 return B_OK; 2155 } 2156 2157 // _HandleEntryCreatedRequest 2158 void 2159 ShareVolume::_HandleEntryCreatedRequest(EntryCreatedRequest* request) 2160 { 2161 if (!request) 2162 return; 2163 2164 nspace_id nsid = fVolumeManager->GetID(); 2165 const char* name = request->name.GetString(); 2166 2167 // translate the node IDs 2168 vnode_id vnida = 0; 2169 vnode_id vnidb = 0; 2170 vnode_id vnidc = 0; 2171 status_t error = _GetLocalNodeID(request->directoryID, &vnida, true); 2172 if (error == B_OK) 2173 error = _GetLocalNodeID(request->nodeID, &vnidc, true); 2174 PRINT(("ShareVolume::_HandleEntryCreatedRequest(): error: 0x%lx, name: \"%s\", dir: %lld (remote: (%ld, %lld)), node: %lld (remote: (%ld, %lld))\n", error, name, vnida, request->directoryID.volumeID, request->directoryID.nodeID, vnidc, request->nodeID.volumeID, request->nodeID.nodeID)); 2175 2176 // send notifications / do additional processing 2177 if (request->queryUpdate) { 2178 if (error == B_OK) { 2179 SendNotification(request->port, request->token, 2180 B_QUERY_UPDATE, request->opcode, nsid, 0, vnida, vnidb, 2181 vnidc, name); 2182 } 2183 } else { 2184 _EntryCreated(request->directoryID, name, 2185 (request->entryInfoValid ? &request->entryInfo : NULL), 2186 request->revision); 2187 if (error == B_OK) 2188 NotifyListener(request->opcode, nsid, vnida, vnidb, vnidc, name); 2189 } 2190 } 2191 2192 // _HandleEntryRemovedRequest 2193 void 2194 ShareVolume::_HandleEntryRemovedRequest(EntryRemovedRequest* request) 2195 { 2196 if (!request) 2197 return; 2198 2199 nspace_id nsid = fVolumeManager->GetID(); 2200 const char* name = request->name.GetString(); 2201 2202 // translate the node IDs 2203 vnode_id vnida = 0; 2204 vnode_id vnidb = 0; 2205 vnode_id vnidc = 0; 2206 status_t error = _GetLocalNodeID(request->directoryID, &vnida, true); 2207 if (error == B_OK) 2208 error = _GetLocalNodeID(request->nodeID, &vnidc, false); 2209 // TODO: We don't enter a node ID mapping here, which might cause 2210 // undesired behavior in some cases. Queries should usually be 2211 // fine, since, if the entry was in the query set, then the 2212 // respective node ID should definately be known at this point. 2213 // If an entry is removed and the node monitoring event comes 2214 // before a live query event for the same entry, the former one 2215 // will cause the ID to be removed, so that it is already gone 2216 // when the latter one arrives. I haven't observed this yet, 2217 // though. The query events always seem to be sent before the 2218 // node monitoring events (and the server processes them in a 2219 // single-threaded way). I guess, this is FS implementation 2220 // dependent, though. 2221 // A node monitoring event that will always get lost, is when the 2222 // FS user watches a directory that hasn't been read before. Its 2223 // entries will not be known yet and thus "entry removed" events 2224 // will be dropped here. I guess, it's arguable whether this is 2225 // a practical problem (why should the watcher care that an entry 2226 // has been removed, when they didn't know what entries were in 2227 // the directory in the first place?). 2228 // A possible solution would be to never remove node ID mappings. 2229 // We would only need to take care that the cached node info is 2230 // correctly flushed, so that e.g. a subsequent ReadVNode() has to 2231 // ask the server and doesn't work with obsolete data. We would 2232 // also enter a yet unknown ID into the node ID map here. The only 2233 // problem is that the ID maps will keep growing, especially when 2234 // there's a lot of FS activity on the server. 2235 2236 // send notifications / do additional processing 2237 if (request->queryUpdate) { 2238 if (error == B_OK) { 2239 SendNotification(request->port, request->token, 2240 B_QUERY_UPDATE, request->opcode, nsid, 0, vnida, vnidb, 2241 vnidc, name); 2242 } 2243 } else { 2244 _EntryRemoved(request->directoryID, name, request->revision); 2245 _NodeRemoved(request->nodeID); 2246 if (error == B_OK) 2247 NotifyListener(request->opcode, nsid, vnida, vnidb, vnidc, name); 2248 } 2249 } 2250 2251 // _HandleEntryMovedRequest 2252 void 2253 ShareVolume::_HandleEntryMovedRequest(EntryMovedRequest* request) 2254 { 2255 if (!request) 2256 return; 2257 2258 nspace_id nsid = fVolumeManager->GetID(); 2259 const char* oldName = request->fromName.GetString(); 2260 const char* name = request->toName.GetString(); 2261 2262 // translate the node IDs 2263 vnode_id vnida = 0; 2264 vnode_id vnidb = 0; 2265 vnode_id vnidc = 0; 2266 status_t error = _GetLocalNodeID(request->fromDirectoryID, &vnida, true); 2267 if (error == B_OK) 2268 error = _GetLocalNodeID(request->toDirectoryID, &vnidb, true); 2269 if (error == B_OK) 2270 error = _GetLocalNodeID(request->nodeID, &vnidc, true); 2271 2272 // send notifications / do additional processing 2273 if (!request->queryUpdate) { 2274 _EntryMoved(request->fromDirectoryID, oldName, request->toDirectoryID, 2275 name, (request->entryInfoValid ? &request->entryInfo : NULL), 2276 request->revision); 2277 if (error == B_OK) 2278 NotifyListener(request->opcode, nsid, vnida, vnidb, vnidc, name); 2279 } 2280 } 2281 2282 // _HandleStatChangedRequest 2283 void 2284 ShareVolume::_HandleStatChangedRequest(StatChangedRequest* request) 2285 { 2286 if (!request) 2287 return; 2288 2289 nspace_id nsid = fVolumeManager->GetID(); 2290 2291 // translate the node IDs 2292 vnode_id vnida = 0; 2293 vnode_id vnidb = 0; 2294 vnode_id vnidc = 0; 2295 status_t error = _GetLocalNodeID(request->nodeID, &vnidc, true); 2296 2297 // send notifications / do additional processing 2298 if (!request->queryUpdate) { 2299 _UpdateNode(request->nodeInfo); 2300 if (error == B_OK) 2301 NotifyListener(request->opcode, nsid, vnida, vnidb, vnidc, NULL); 2302 } 2303 } 2304 2305 // _HandleAttributeChangedRequest 2306 void 2307 ShareVolume::_HandleAttributeChangedRequest(AttributeChangedRequest* request) 2308 { 2309 if (!request) 2310 return; 2311 2312 nspace_id nsid = fVolumeManager->GetID(); 2313 const char* name = request->attrInfo.name.GetString(); 2314 2315 // translate the node IDs 2316 vnode_id vnida = 0; 2317 vnode_id vnidb = 0; 2318 vnode_id vnidc = 0; 2319 status_t error = _GetLocalNodeID(request->nodeID, &vnidc, true); 2320 2321 // send notifications / do additional processing 2322 if (!request->queryUpdate) { 2323 _UpdateAttrDir(request->nodeID, request->attrDirInfo); 2324 if (error == B_OK) 2325 NotifyListener(request->opcode, nsid, vnida, vnidb, vnidc, name); 2326 } 2327 } 2328 2329 // _GetLocalNodeID 2330 status_t 2331 ShareVolume::_GetLocalNodeID(NodeID remoteID, ino_t* _localID, bool enter) 2332 { 2333 AutoLocker<Locker> _(fLock); 2334 // if the ID is already know, just return it 2335 if (fLocalNodeIDs->ContainsKey(remoteID)) { 2336 *_localID = fLocalNodeIDs->Get(remoteID); 2337 return B_OK; 2338 } 2339 2340 // ID not yet known 2341 // enter it? Do this only, if requested and we're not already unmounting. 2342 if (!enter) 2343 return B_ENTRY_NOT_FOUND; 2344 if (fUnmounting) 2345 return ERROR_NOT_CONNECTED; 2346 2347 // get a fresh ID from the volume manager 2348 vnode_id localID = fVolumeManager->NewNodeID(this); 2349 if (localID < 0) 2350 return localID; 2351 2352 // put the IDs into local map 2353 status_t error = fLocalNodeIDs->Put(remoteID, localID); 2354 if (error != B_OK) { 2355 fVolumeManager->RemoveNodeID(localID); 2356 return error; 2357 } 2358 2359 // put the IDs into remote map 2360 error = fRemoteNodeIDs->Put(localID, remoteID); 2361 if (error != B_OK) { 2362 fLocalNodeIDs->Remove(remoteID); 2363 fVolumeManager->RemoveNodeID(localID); 2364 return error; 2365 } 2366 PRINT(("ShareVolume(%ld): added node ID mapping: local: %lld -> " 2367 "remote: (%ld, %lld)\n", fID, localID, remoteID.volumeID, remoteID.nodeID)); 2368 2369 *_localID = localID; 2370 return B_OK; 2371 } 2372 2373 // _GetRemoteNodeID 2374 status_t 2375 ShareVolume::_GetRemoteNodeID(ino_t localID, NodeID* remoteID) 2376 { 2377 AutoLocker<Locker> _(fLock); 2378 2379 // check, if the ID is known 2380 if (!fRemoteNodeIDs->ContainsKey(localID)) 2381 return B_ENTRY_NOT_FOUND; 2382 2383 *remoteID = fRemoteNodeIDs->Get(localID); 2384 return B_OK; 2385 } 2386 2387 // _RemoveLocalNodeID 2388 void 2389 ShareVolume::_RemoveLocalNodeID(ino_t localID) 2390 { 2391 AutoLocker<Locker> _(fLock); 2392 2393 // check, if the ID is known 2394 if (!fRemoteNodeIDs->ContainsKey(localID)) 2395 return; 2396 2397 // remove from ID maps 2398 NodeID remoteID = fRemoteNodeIDs->Get(localID); 2399 PRINT(("ShareVolume::_RemoveLocalNodeID(%lld): remote: (%ld, %lld)\n", localID, remoteID.volumeID, remoteID.nodeID)); 2400 fRemoteNodeIDs->Remove(localID); 2401 fLocalNodeIDs->Remove(remoteID); 2402 2403 // remove from volume manager 2404 fVolumeManager->RemoveNodeID(localID); 2405 } 2406 2407 // _GetNodeByLocalID 2408 ShareNode* 2409 ShareVolume::_GetNodeByLocalID(ino_t localID) 2410 { 2411 AutoLocker<Locker> _(fLock); 2412 return fNodes->Get(localID); 2413 } 2414 2415 // _GetNodeByRemoteID 2416 ShareNode* 2417 ShareVolume::_GetNodeByRemoteID(NodeID remoteID) 2418 { 2419 AutoLocker<Locker> _(fLock); 2420 2421 ino_t localID; 2422 if (_GetLocalNodeID(remoteID, &localID, false) == B_OK) 2423 return fNodes->Get(localID); 2424 2425 return NULL; 2426 } 2427 2428 // _LoadNode 2429 status_t 2430 ShareVolume::_LoadNode(const NodeInfo& nodeInfo, ShareNode** _node) 2431 { 2432 AutoLocker<Locker> _(fLock); 2433 2434 // check, if the node is already known 2435 ShareNode* node = _GetNodeByRemoteID(nodeInfo.GetID()); 2436 if (node) { 2437 node->Update(nodeInfo); 2438 } else { 2439 // don't load the node when already unmounting 2440 if (fUnmounting) 2441 return B_ERROR; 2442 2443 // get a local node ID 2444 vnode_id localID; 2445 status_t error = _GetLocalNodeID(nodeInfo.GetID(), &localID, true); 2446 if (error != B_OK) 2447 return error; 2448 2449 // create a new node 2450 if (S_ISDIR(nodeInfo.st.st_mode)) 2451 node = new(std::nothrow) ShareDir(this, localID, &nodeInfo); 2452 else 2453 node = new(std::nothrow) ShareNode(this, localID, &nodeInfo); 2454 if (!node) { 2455 _RemoveLocalNodeID(localID); 2456 return B_NO_MEMORY; 2457 } 2458 2459 // add it 2460 error = fNodes->Put(node->GetID(), node); 2461 if (error != B_OK) { 2462 _RemoveLocalNodeID(localID); 2463 delete node; 2464 return error; 2465 } 2466 PRINT(("ShareVolume: added node: %lld: remote: (%ld, %lld), localID: %lld\n", 2467 node->GetID(), node->GetRemoteID().volumeID, node->GetRemoteID().nodeID, 2468 localID)); 2469 } 2470 2471 if (_node) 2472 *_node = node; 2473 return B_OK; 2474 } 2475 2476 // _UpdateNode 2477 status_t 2478 ShareVolume::_UpdateNode(const NodeInfo& nodeInfo) 2479 { 2480 AutoLocker<Locker> _(fLock); 2481 2482 if (fUnmounting) 2483 return ERROR_NOT_CONNECTED; 2484 2485 ShareNode* node = _GetNodeByRemoteID(nodeInfo.GetID()); 2486 if (node) { 2487 node->Update(nodeInfo); 2488 return B_OK; 2489 } 2490 return B_ENTRY_NOT_FOUND; 2491 } 2492 2493 // _GetEntryByLocalID 2494 ShareDirEntry* 2495 ShareVolume::_GetEntryByLocalID(ino_t localDirID, const char* name) 2496 { 2497 if (!name) 2498 return NULL; 2499 2500 AutoLocker<Locker> _(fLock); 2501 return fEntries->Get(EntryKey(localDirID, name)); 2502 } 2503 2504 // _GetEntryByRemoteID 2505 ShareDirEntry* 2506 ShareVolume::_GetEntryByRemoteID(NodeID remoteDirID, const char* name) 2507 { 2508 if (!name) 2509 return NULL; 2510 2511 AutoLocker<Locker> _(fLock); 2512 2513 ino_t localDirID; 2514 if (_GetLocalNodeID(remoteDirID, &localDirID, false) == B_OK) 2515 return fEntries->Get(EntryKey(localDirID, name)); 2516 2517 return NULL; 2518 } 2519 2520 // _LoadEntry 2521 // 2522 // If _entry is supplied, fLock should be held, otherwise the returned entry 2523 // might as well be deleted. 2524 status_t 2525 ShareVolume::_LoadEntry(ShareDir* directory, const EntryInfo& entryInfo, 2526 ShareDirEntry** _entry) 2527 { 2528 const char* name = entryInfo.name.GetString(); 2529 if (!directory || !name) 2530 return B_BAD_VALUE; 2531 2532 AutoLocker<Locker> _(fLock); 2533 2534 ShareDirEntry* entry = _GetEntryByLocalID(directory->GetID(), name); 2535 if (entry) { 2536 if (entryInfo.nodeInfo.revision > entry->GetRevision()) { 2537 if (entryInfo.nodeInfo.GetID() != entry->GetNode()->GetRemoteID()) { 2538 // The node the existing entry refers to is not the node it 2539 // should refer to. Remove the old entry and create a new one. 2540 _EntryRemoved(directory->GetRemoteID(), name, 2541 entryInfo.nodeInfo.revision); 2542 _EntryCreated(directory->GetRemoteID(), name, &entryInfo, 2543 entryInfo.nodeInfo.revision); 2544 2545 // re-get the entry and check, if everything is fine 2546 entry = _GetEntryByLocalID(directory->GetID(), name); 2547 if (!entry) 2548 return B_ERROR; 2549 if (entryInfo.nodeInfo.GetID() 2550 != entry->GetNode()->GetRemoteID()) { 2551 return B_ERROR; 2552 } 2553 } else { 2554 entry->SetRevision(entryInfo.nodeInfo.revision); 2555 _UpdateNode(entryInfo.nodeInfo); 2556 } 2557 } 2558 } else { 2559 // entry not known yet: create it 2560 2561 // don't load the entry when already unmounting 2562 if (fUnmounting) 2563 return B_ERROR; 2564 2565 // load the node 2566 ShareNode* node; 2567 status_t error = _LoadNode(entryInfo.nodeInfo, &node); 2568 if (error != B_OK) 2569 return error; 2570 2571 // if the directory or the node are marked remove, we don't create the 2572 // entry 2573 if (IsVNodeRemoved(directory->GetID()) > 0 2574 || IsVNodeRemoved(node->GetID()) > 0) { 2575 return B_NOT_ALLOWED; 2576 } 2577 2578 // create the entry 2579 entry = new(std::nothrow) ShareDirEntry(directory, name, node); 2580 if (!entry) 2581 return B_NO_MEMORY; 2582 ObjectDeleter<ShareDirEntry> entryDeleter(entry); 2583 error = entry->InitCheck(); 2584 if (error != B_OK) 2585 return error; 2586 2587 // add the entry 2588 error = fEntries->Put(EntryKey(directory->GetID(), entry->GetName()), 2589 entry); 2590 if (error != B_OK) 2591 return error; 2592 2593 // set the entry revision 2594 entry->SetRevision(entryInfo.nodeInfo.revision); 2595 2596 // add the entry to the directory and the node 2597 directory->AddEntry(entry); 2598 entry->GetNode()->AddReferringEntry(entry); 2599 2600 // everything went fine 2601 entryDeleter.Detach(); 2602 } 2603 2604 if (_entry) 2605 *_entry = entry; 2606 return B_OK; 2607 } 2608 2609 // _RemoveEntry 2610 // 2611 // fLock must be held. 2612 void 2613 ShareVolume::_RemoveEntry(ShareDirEntry* entry) 2614 { 2615 fEntries->Remove(EntryKey(entry->GetDirectory()->GetID(), 2616 entry->GetName())); 2617 entry->GetDirectory()->RemoveEntry(entry); 2618 entry->GetNode()->RemoveReferringEntry(entry); 2619 entry->ReleaseReference(); 2620 } 2621 2622 // _IsObsoleteEntryInfo 2623 // 2624 // fLock must be held. 2625 bool 2626 ShareVolume::_IsObsoleteEntryInfo(const EntryInfo& entryInfo) 2627 { 2628 // get the directory 2629 ShareDir* dir 2630 = dynamic_cast<ShareDir*>(_GetNodeByRemoteID(entryInfo.directoryID)); 2631 if (!dir) 2632 return false; 2633 2634 return (entryInfo.nodeInfo.revision <= dir->GetEntryRemovedEventRevision()); 2635 } 2636 2637 // _LoadAttrDir 2638 status_t 2639 ShareVolume::_LoadAttrDir(ShareNode* node, const AttrDirInfo& attrDirInfo) 2640 { 2641 if (!node || !attrDirInfo.isValid) 2642 return B_BAD_VALUE; 2643 2644 AutoLocker<Locker> _(fLock); 2645 2646 if (fUnmounting) 2647 return ERROR_NOT_CONNECTED; 2648 2649 ShareAttrDir* attrDir = node->GetAttrDir(); 2650 if (attrDir) { 2651 if (attrDir->GetRevision() > attrDirInfo.revision) 2652 return B_OK; 2653 2654 // update the attr dir 2655 return attrDir->Update(attrDirInfo, 2656 fAttrDirIterators->Get(node->GetID())); 2657 } else { 2658 // no attribute directory yet: create one 2659 attrDir = new(std::nothrow) ShareAttrDir; 2660 if (!attrDir) 2661 return B_NO_MEMORY; 2662 ObjectDeleter<ShareAttrDir> attrDirDeleter(attrDir); 2663 2664 // initialize it 2665 status_t error = attrDir->Init(attrDirInfo); 2666 if (error != B_OK) 2667 return error; 2668 2669 // set it 2670 node->SetAttrDir(attrDir); 2671 attrDirDeleter.Detach(); 2672 return B_OK; 2673 } 2674 } 2675 2676 // _UpdateAttrDir 2677 status_t 2678 ShareVolume::_UpdateAttrDir(NodeID remoteID, const AttrDirInfo& attrDirInfo) 2679 { 2680 AutoLocker<Locker> _(fLock); 2681 2682 // get the node 2683 ShareNode* node = _GetNodeByRemoteID(remoteID); 2684 if (!node) 2685 return B_ENTRY_NOT_FOUND; 2686 2687 if (!attrDirInfo.isValid || _LoadAttrDir(node, attrDirInfo) != B_OK) { 2688 // updating/creating the attr dir failed; if existing, we mark it 2689 // obsolete 2690 if (ShareAttrDir* attrDir = node->GetAttrDir()) 2691 attrDir->SetUpToDate(false); 2692 } 2693 2694 return B_OK; 2695 } 2696 2697 // _AddAttrDirIterator 2698 status_t 2699 ShareVolume::_AddAttrDirIterator(ShareNode* node, 2700 ShareAttrDirIterator* iterator) 2701 { 2702 if (!node || !iterator) 2703 return B_BAD_VALUE; 2704 2705 AutoLocker<Locker> locker(fLock); 2706 2707 // get the iterator list 2708 DoublyLinkedList<ShareAttrDirIterator>* iteratorList 2709 = fAttrDirIterators->Get(node->GetID()); 2710 if (!iteratorList) { 2711 // no list for the node yet: create one 2712 iteratorList = new(std::nothrow) DoublyLinkedList<ShareAttrDirIterator>; 2713 if (!iteratorList) 2714 return B_NO_MEMORY; 2715 2716 // add it 2717 status_t error = fAttrDirIterators->Put(node->GetID(), iteratorList); 2718 if (error != B_OK) { 2719 delete iteratorList; 2720 return error; 2721 } 2722 } 2723 2724 // add the iterator 2725 iteratorList->Insert(iterator); 2726 2727 return B_OK; 2728 } 2729 2730 // _RemoveAttrDirIterator 2731 void 2732 ShareVolume::_RemoveAttrDirIterator(ShareNode* node, 2733 ShareAttrDirIterator* iterator) 2734 { 2735 if (!node || !iterator) 2736 return; 2737 2738 AutoLocker<Locker> locker(fLock); 2739 2740 // get the iterator list 2741 DoublyLinkedList<ShareAttrDirIterator>* iteratorList 2742 = fAttrDirIterators->Get(node->GetID()); 2743 if (!iteratorList) { 2744 WARN("ShareVolume::_RemoveAttrDirIterator(): Iterator list not " 2745 "found: node: %lld\n", node->GetID()); 2746 return; 2747 } 2748 2749 // remove the iterator 2750 iteratorList->Remove(iterator); 2751 2752 // if the list is empty now, discard it 2753 if (!iteratorList->First()) { 2754 fAttrDirIterators->Remove(node->GetID()); 2755 delete iteratorList; 2756 } 2757 } 2758 2759 // _NodeRemoved 2760 void 2761 ShareVolume::_NodeRemoved(NodeID remoteID) 2762 { 2763 AutoLocker<Locker> locker(fLock); 2764 2765 ShareNode* node = _GetNodeByRemoteID(remoteID); 2766 if (!node) 2767 return; 2768 2769 // if the node still has referring entries, we do nothing 2770 if (node->GetActualReferringEntry()) 2771 return; 2772 2773 // if the node is a directory, we remove its entries first 2774 if (ShareDir* dir = dynamic_cast<ShareDir*>(node)) { 2775 while (ShareDirEntry* entry = dir->GetFirstEntry()) 2776 _RemoveEntry(entry); 2777 } 2778 2779 // remove all entries still referring to the node 2780 while (ShareDirEntry* entry = node->GetFirstReferringEntry()) 2781 _RemoveEntry(entry); 2782 2783 ino_t localID = node->GetID(); 2784 2785 // Remove the node ID in all cases -- even, if the node is still 2786 // known to the VFS. Otherwise there could be a race condition, that the 2787 // server re-uses the remote ID and we have it still associated with an 2788 // obsolete local ID. 2789 _RemoveLocalNodeID(localID); 2790 2791 if (node->IsKnownToVFS()) { 2792 Node* _node; 2793 if (GetVNode(localID, &_node) != B_OK) 2794 return; 2795 Volume::RemoveVNode(localID); 2796 locker.Unlock(); 2797 PutVNode(localID); 2798 2799 } else { 2800 fNodes->Remove(localID); 2801 delete node; 2802 } 2803 } 2804 2805 // _EntryCreated 2806 void 2807 ShareVolume::_EntryCreated(NodeID remoteDirID, const char* name, 2808 const EntryInfo* entryInfo, int64 revision) 2809 { 2810 if (!name) 2811 return; 2812 2813 AutoLocker<Locker> locker(fLock); 2814 2815 // get the directory 2816 ShareDir* dir = dynamic_cast<ShareDir*>(_GetNodeByRemoteID(remoteDirID)); 2817 if (!dir) 2818 return; 2819 2820 // load the entry, if possible 2821 ShareDirEntry* entry; 2822 bool entryLoaded = false; 2823 if (entryInfo && _LoadEntry(dir, *entryInfo, &entry) == B_OK) 2824 entryLoaded = true; 2825 2826 // if the entry could not be loaded, we have to mark the dir incomplete 2827 // and update its revision counter 2828 if (!entryLoaded) { 2829 dir->UpdateEntryCreatedEventRevision(revision); 2830 dir->SetComplete(false); 2831 } 2832 } 2833 2834 // _EntryRemoved 2835 void 2836 ShareVolume::_EntryRemoved(NodeID remoteDirID, const char* name, int64 revision) 2837 { 2838 if (!name) 2839 return; 2840 2841 AutoLocker<Locker> locker(fLock); 2842 2843 // get the directory 2844 ShareDir* dir = dynamic_cast<ShareDir*>(_GetNodeByRemoteID(remoteDirID)); 2845 if (!dir) 2846 return; 2847 2848 // update the directory's "entry removed" event revision 2849 dir->UpdateEntryRemovedEventRevision(revision); 2850 2851 // get the entry 2852 ShareDirEntry* entry = _GetEntryByRemoteID(remoteDirID, name); 2853 if (!entry) 2854 return; 2855 2856 // check the entry revision 2857 if (entry->GetRevision() > revision) 2858 return; 2859 2860 // remove the entry 2861 _RemoveEntry(entry); 2862 } 2863 2864 // _EntryMoved 2865 void 2866 ShareVolume::_EntryMoved(NodeID remoteOldDirID, const char* oldName, 2867 NodeID remoteNewDirID, const char* name, const EntryInfo* entryInfo, 2868 int64 revision) 2869 { 2870 AutoLocker<Locker> locker(fLock); 2871 2872 _EntryRemoved(remoteOldDirID, oldName, revision); 2873 _EntryCreated(remoteNewDirID, name, entryInfo, revision); 2874 } 2875 2876 // _Walk 2877 status_t 2878 ShareVolume::_Walk(NodeID remoteDirID, const char* entryName, bool resolveLink, 2879 WalkReply** _reply) 2880 { 2881 // prepare the request 2882 WalkRequest request; 2883 request.volumeID = fID; 2884 request.nodeID = remoteDirID; 2885 request.name.SetTo(entryName); 2886 request.resolveLink = resolveLink; 2887 2888 // send the request 2889 WalkReply* reply; 2890 status_t error = SendRequest(fConnection, &request, &reply); 2891 if (error != B_OK) 2892 RETURN_ERROR(error); 2893 ObjectDeleter<Request> replyDeleter(reply); 2894 if (reply->error != B_OK) 2895 RETURN_ERROR(reply->error); 2896 2897 replyDeleter.Detach(); 2898 *_reply = reply; 2899 return B_OK; 2900 } 2901 2902 // _MultiWalk 2903 status_t 2904 ShareVolume::_MultiWalk(RequestMemberArray<EntryInfo>& _entryInfos, 2905 MultiWalkReply** _reply) 2906 { 2907 int32 count = _entryInfos.CountElements(); 2908 if (!_reply || count == 0) 2909 return B_BAD_VALUE; 2910 2911 EntryInfo* entryInfos = _entryInfos.GetElements(); 2912 2913 // prepare the request 2914 MultiWalkRequest request; 2915 request.volumeID = fID; 2916 request.nodeID = entryInfos[0].directoryID; 2917 2918 // add the names 2919 for (int32 i = 0; i < count; i++) { 2920 StringData name; 2921 name.SetTo(entryInfos[i].name.GetString()); 2922 2923 status_t error = request.names.Append(name); 2924 if (error != B_OK) 2925 return error; 2926 } 2927 2928 // send the request 2929 MultiWalkReply* reply; 2930 status_t error = SendRequest(fConnection, &request, &reply); 2931 if (error != B_OK) 2932 RETURN_ERROR(error); 2933 ObjectDeleter<Request> replyDeleter(reply); 2934 if (reply->error != B_OK) 2935 RETURN_ERROR(reply->error); 2936 2937 replyDeleter.Detach(); 2938 *_reply = reply; 2939 return B_OK; 2940 } 2941 2942 // _Close 2943 status_t 2944 ShareVolume::_Close(int32 cookie) 2945 { 2946 if (!_EnsureShareMounted()) 2947 return ERROR_NOT_CONNECTED; 2948 2949 // prepare the request 2950 CloseRequest request; 2951 request.volumeID = fID; 2952 request.cookie = cookie; 2953 // send the request 2954 CloseReply* reply; 2955 status_t error = SendRequest(fConnection, &request, &reply); 2956 if (error != B_OK) 2957 RETURN_ERROR(error); 2958 ObjectDeleter<Request> replyDeleter(reply); 2959 if (reply->error != B_OK) 2960 RETURN_ERROR(reply->error); 2961 return B_OK; 2962 } 2963 2964 // _GetConnectionState 2965 // 2966 // Must not be called with fLock being held! 2967 uint32 2968 ShareVolume::_GetConnectionState() 2969 { 2970 AutoLocker<Locker> _(fMountLock); 2971 return fConnectionState; 2972 } 2973 2974 // _IsConnected 2975 // 2976 // Must not be called with fLock being held! 2977 bool 2978 ShareVolume::_IsConnected() 2979 { 2980 return (_GetConnectionState() == CONNECTION_READY); 2981 } 2982 2983 // _EnsureShareMounted 2984 // 2985 // Must not be called with fLock being held! 2986 bool 2987 ShareVolume::_EnsureShareMounted() 2988 { 2989 AutoLocker<Locker> _(fMountLock); 2990 if (fConnectionState == CONNECTION_NOT_INITIALIZED) 2991 _MountShare(); 2992 2993 return (fConnectionState == CONNECTION_READY); 2994 } 2995 2996 // _MountShare 2997 // 2998 // fMountLock must be held. 2999 status_t 3000 ShareVolume::_MountShare() 3001 { 3002 // get references to the server and share info 3003 AutoLocker<Locker> locker(fLock); 3004 BReference<ExtendedServerInfo> serverInfoReference(fServerInfo); 3005 BReference<ExtendedShareInfo> shareInfoReference(fShareInfo); 3006 ExtendedServerInfo* serverInfo = fServerInfo; 3007 ExtendedShareInfo* shareInfo = fShareInfo; 3008 locker.Unlock(); 3009 3010 // get server address as string 3011 HashString serverAddressString; 3012 status_t error = serverInfo->GetAddress().GetString(&serverAddressString, 3013 false); 3014 if (error != B_OK) 3015 return error; 3016 const char* server = serverAddressString.GetString(); 3017 3018 // get the server name 3019 const char* serverName = serverInfo->GetServerName(); 3020 if (serverName && strlen(serverName) == 0) 3021 serverName = NULL; 3022 3023 // get the share name 3024 const char* share = shareInfo->GetShareName(); 3025 3026 PRINT(("ShareVolume::_MountShare(%s, %s)\n", server, share)); 3027 // init a connection to the authentication server 3028 AuthenticationServer authenticationServer; 3029 error = authenticationServer.InitCheck(); 3030 if (error != B_OK) 3031 RETURN_ERROR(error); 3032 3033 // get the server connection 3034 fConnectionState = CONNECTION_CLOSED; 3035 if (!fServerConnection) { 3036 status_t error = fServerConnectionProvider->GetServerConnection( 3037 &fServerConnection); 3038 if (error != B_OK) 3039 return error; 3040 fConnection = fServerConnection->GetRequestConnection(); 3041 } 3042 3043 // the mount loop 3044 bool badPassword = false; 3045 MountReply* reply = NULL; 3046 do { 3047 // get the user and password from the authentication server 3048 char user[kUserBufferSize]; 3049 char password[kPasswordBufferSize]; 3050 bool cancelled; 3051 error = authenticationServer.GetAuthentication("netfs", 3052 (serverName ? serverName : server), share, 3053 fVolumeManager->GetMountUID(), badPassword, 3054 &cancelled, user, sizeof(user), password, sizeof(password)); 3055 if (cancelled || error != B_OK) 3056 RETURN_ERROR(error); 3057 3058 // prepare the request 3059 MountRequest request; 3060 request.share.SetTo(share); 3061 request.user.SetTo(user); 3062 request.password.SetTo(password); 3063 3064 // send the request 3065 error = SendRequest(fConnection, &request, &reply); 3066 if (error != B_OK) 3067 RETURN_ERROR(error); 3068 ObjectDeleter<Request> replyDeleter(reply); 3069 3070 // if no permission, try again 3071 badPassword = reply->noPermission; 3072 if (!badPassword) { 3073 if (reply->error != B_OK) 3074 RETURN_ERROR(reply->error); 3075 fSharePermissions = reply->sharePermissions; 3076 } 3077 } while (badPassword); 3078 3079 AutoLocker<Locker> _(fLock); 3080 3081 fID = reply->volumeID; 3082 3083 // update the root node and enter its ID 3084 fRootNode->Update(reply->nodeInfo); 3085 3086 // put the IDs into local map 3087 error = fLocalNodeIDs->Put(fRootNode->GetRemoteID(), fRootNode->GetID()); 3088 if (error != B_OK) 3089 RETURN_ERROR(error); 3090 3091 // put the IDs into remote map 3092 error = fRemoteNodeIDs->Put(fRootNode->GetID(), fRootNode->GetRemoteID()); 3093 if (error != B_OK) { 3094 fLocalNodeIDs->Remove(fRootNode->GetRemoteID()); 3095 RETURN_ERROR(error); 3096 } 3097 PRINT(("ShareVolume::_MountShare(): root node: local: %lld, remote: (%ld, %lld)\n", fRootNode->GetID(), fRootNode->GetRemoteID().volumeID, fRootNode->GetRemoteID().nodeID)); 3098 3099 // Add ourselves to the server connection, so that we can receive 3100 // node monitoring events. There a race condition: We might already 3101 // have missed events for the root node. 3102 error = fServerConnection->AddVolume(this); 3103 if (error != B_OK) { 3104 _RemoveLocalNodeID(fRootNode->GetID()); 3105 return error; 3106 } 3107 3108 fConnectionState = CONNECTION_READY; 3109 return B_OK; 3110 } 3111 3112