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 "%" B_PRId32 " 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 "%" B_PRId32 " 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(" %" B_PRId32 " 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 %" B_PRIdINO "\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: %" B_PRIdINO ", remote: (%" B_PRIdDEV 1170 ", %" B_PRIdINO ")\n", node->GetID(), node->GetRemoteID().volumeID, 1171 node->GetRemoteID().nodeID); 1172 RETURN_ERROR(reply->error); 1173 } 1174 1175 // update the node 1176 _UpdateNode(reply->nodeInfo); 1177 1178 // init the cookie 1179 iterator->SetCookie(reply->cookie); 1180 cookie->iterator = iterator; 1181 1182 *_cookie = cookie; 1183 cookieDeleter.Detach(); 1184 iteratorDeleter.Detach(); 1185 return B_OK; 1186 } 1187 1188 // CloseDir 1189 status_t 1190 ShareVolume::CloseDir(Node* _node, void* cookie) 1191 { 1192 // no-op: FreeDirCookie does the job 1193 return B_OK; 1194 } 1195 1196 // FreeDirCookie 1197 status_t 1198 ShareVolume::FreeDirCookie(Node* _node, void* _cookie) 1199 { 1200 DirCookie* cookie = (DirCookie*)_cookie; 1201 ObjectDeleter<DirCookie> _(cookie); 1202 ShareDirIterator* iterator = cookie->iterator; 1203 1204 status_t error = B_OK; 1205 if (RemoteShareDirIterator* remoteIterator 1206 = dynamic_cast<RemoteShareDirIterator*>(iterator)) { 1207 // prepare the request 1208 CloseRequest request; 1209 request.volumeID = fID; 1210 request.cookie = remoteIterator->GetCookie(); 1211 1212 // send the request 1213 if (!_EnsureShareMounted()) 1214 error = ERROR_NOT_CONNECTED; 1215 1216 if (error == B_OK) { 1217 CloseReply* reply; 1218 error = SendRequest(fConnection, &request, &reply); 1219 if (error == B_OK) { 1220 error = reply->error; 1221 delete reply; 1222 } 1223 } 1224 } 1225 1226 // delete the iterator 1227 AutoLocker<Locker> locker(fLock); 1228 delete iterator; 1229 1230 return error; 1231 } 1232 1233 // ReadDir 1234 status_t 1235 ShareVolume::ReadDir(Node* _dir, void* _cookie, struct dirent* buffer, 1236 size_t bufferSize, int32 count, int32* countRead) 1237 { 1238 ShareDir* directory = dynamic_cast<ShareDir*>(_dir); 1239 1240 if (!_EnsureShareMounted()) 1241 return ERROR_NOT_CONNECTED; 1242 1243 *countRead = 0; 1244 if (count <= 0) 1245 return B_OK; 1246 1247 DirCookie* cookie = (DirCookie*)_cookie; 1248 ShareDirIterator* iterator = cookie->iterator; 1249 1250 while (true) { 1251 status_t error; 1252 AutoLocker<Locker> locker(fLock); 1253 while (ShareDirEntry* entry = iterator->GetCurrentEntry()) { 1254 // re-get the entry -- it might already have been removed 1255 const char* name = entry->GetName(); 1256 entry = _GetEntryByLocalID(directory->GetID(), name); 1257 if (entry) { 1258 // set the name: this also checks the size of the buffer 1259 error = set_dirent_name(buffer, bufferSize, name, 1260 strlen(name)); 1261 if (error != B_OK) { 1262 // if something has been read at all, we're content 1263 if (*countRead > 0) 1264 return B_OK; 1265 RETURN_ERROR(error); 1266 } 1267 1268 // fill in the other fields 1269 buffer->d_pdev = fVolumeManager->GetID(); 1270 buffer->d_pino = directory->GetID(); 1271 buffer->d_dev = fVolumeManager->GetID(); 1272 buffer->d_ino = entry->GetNode()->GetID(); 1273 1274 // if the entry is the parent of the share root, we need to 1275 // fix the node ID 1276 if (directory == fRootNode && strcmp(name, "..") == 0) { 1277 if (Volume* parentVolume = GetParentVolume()) 1278 buffer->d_ino = parentVolume->GetRootID(); 1279 } 1280 1281 iterator->NextEntry(); 1282 (*countRead)++; 1283 if (*countRead >= count || !next_dirent(buffer, bufferSize)) 1284 return B_OK; 1285 } else 1286 iterator->NextEntry(); 1287 } 1288 1289 // no more entries: check, if we're completely through 1290 if (iterator->IsDone()) 1291 return B_OK; 1292 1293 // we need to actually get entries from the server 1294 locker.Unlock(); 1295 if (RemoteShareDirIterator* remoteIterator 1296 = dynamic_cast<RemoteShareDirIterator*>(iterator)) { 1297 error = _ReadRemoteDir(directory, remoteIterator); 1298 if (error != B_OK) 1299 return error; 1300 } 1301 } 1302 } 1303 1304 // RewindDir 1305 status_t 1306 ShareVolume::RewindDir(Node* _node, void* _cookie) 1307 { 1308 DirCookie* cookie = (DirCookie*)_cookie; 1309 ShareDirIterator* iterator = cookie->iterator; 1310 AutoLocker<Locker> _(fLock); 1311 iterator->Rewind(); 1312 return B_OK; 1313 } 1314 1315 // Walk 1316 status_t 1317 ShareVolume::Walk(Node* _dir, const char* entryName, char** resolvedPath, 1318 vnode_id* vnid) 1319 { 1320 ShareDir* dir = dynamic_cast<ShareDir*>(_dir); 1321 if (!dir) 1322 return B_BAD_VALUE; 1323 1324 // we always resolve "." and ".." of the root node 1325 if (dir == fRootNode) { 1326 if (strcmp(entryName, ".") == 0 || strcmp(entryName, "..") == 0) { 1327 AutoLocker<Locker> _(fLock); 1328 if (strcmp(entryName, ".") == 0) { 1329 *vnid = fRootNode->GetID(); 1330 } else if (Volume* parentVolume = GetParentVolume()) { 1331 *vnid = parentVolume->GetRootID(); 1332 } else 1333 *vnid = fRootNode->GetID(); 1334 Node* node; 1335 return GetVNode(*vnid, &node); 1336 } 1337 } 1338 1339 if (!_EnsureShareMounted()) 1340 return ERROR_NOT_CONNECTED; 1341 1342 // check, if the entry is already known 1343 { 1344 AutoLocker<Locker> _(fLock); 1345 ShareDirEntry* entry = _GetEntryByLocalID(dir->GetID(), entryName); 1346 if (entry) { 1347 *vnid = entry->GetNode()->GetID(); 1348 Node* node; 1349 return GetVNode(*vnid, &node); 1350 } else if (dir->IsComplete()) 1351 return B_ENTRY_NOT_FOUND; 1352 } 1353 1354 WalkReply* reply; 1355 while (true) { 1356 // send the request 1357 status_t error = _Walk(dir->GetRemoteID(), entryName, resolvedPath, 1358 &reply); 1359 if (error != B_OK) 1360 RETURN_ERROR(error); 1361 ObjectDeleter<Request> replyDeleter(reply); 1362 1363 AutoLocker<Locker> locker(fLock); 1364 1365 // check, if the returned info is obsolete 1366 if (_IsObsoleteEntryInfo(reply->entryInfo)) 1367 continue; 1368 1369 // load the entry 1370 ShareDirEntry* entry; 1371 error = _LoadEntry(dir, reply->entryInfo, &entry); 1372 if (error != B_OK) 1373 RETURN_ERROR(error); 1374 *vnid = entry->GetNode()->GetID(); 1375 1376 // deal with symlinks 1377 if (reply->linkPath.GetString() && resolvedPath) { 1378 *resolvedPath = strdup(reply->linkPath.GetString()); 1379 if (!*resolvedPath) 1380 RETURN_ERROR(B_NO_MEMORY); 1381 return B_OK; 1382 } 1383 1384 break; 1385 } 1386 1387 // no symlink or we shall not resolve it: get the node 1388 Node* _node; 1389 RETURN_ERROR(GetVNode(*vnid, &_node)); 1390 } 1391 1392 1393 // #pragma mark - 1394 // #pragma mark ----- attributes ----- 1395 1396 // OpenAttrDir 1397 status_t 1398 ShareVolume::OpenAttrDir(Node* _node, void** _cookie) 1399 { 1400 ShareNode* node = dynamic_cast<ShareNode*>(_node); 1401 1402 // TODO: Allow opening the root node? 1403 if (!_EnsureShareMounted()) 1404 return ERROR_NOT_CONNECTED; 1405 1406 // allocate a dir cookie 1407 AttrDirCookie* cookie = new(std::nothrow) AttrDirCookie; 1408 if (!cookie) 1409 RETURN_ERROR(B_NO_MEMORY); 1410 ObjectDeleter<AttrDirCookie> cookieDeleter(cookie); 1411 1412 AutoLocker<Locker> locker(fLock); 1413 1414 if (!node->GetAttrDir() || !node->GetAttrDir()->IsUpToDate()) { 1415 // prepare the request 1416 OpenAttrDirRequest request; 1417 request.volumeID = fID; 1418 request.nodeID = node->GetRemoteID(); 1419 1420 locker.Unlock(); 1421 1422 // send the request 1423 OpenAttrDirReply* reply; 1424 status_t error = SendRequest(fConnection, &request, &reply); 1425 if (error != B_OK) 1426 RETURN_ERROR(error); 1427 ObjectDeleter<Request> replyDeleter(reply); 1428 if (reply->error != B_OK) 1429 RETURN_ERROR(reply->error); 1430 1431 // If no AttrDirInfo was supplied, we just save the cookie and be done. 1432 // This usually happens when the attr dir is too big to be cached. 1433 if (!reply->attrDirInfo.isValid) { 1434 cookie->cookie = reply->cookie; 1435 cookie->rewind = false; 1436 *_cookie = cookie; 1437 cookieDeleter.Detach(); 1438 return B_OK; 1439 } 1440 1441 locker.SetTo(fLock, false); 1442 1443 // a AttrDirInfo has been supplied: load the attr dir 1444 error = _LoadAttrDir(node, reply->attrDirInfo); 1445 if (error != B_OK) 1446 return error; 1447 } 1448 1449 // we have a valid attr dir: create an attr dir iterator 1450 ShareAttrDirIterator* iterator = new(std::nothrow) ShareAttrDirIterator; 1451 if (!iterator) 1452 return B_NO_MEMORY; 1453 iterator->SetAttrDir(node->GetAttrDir()); 1454 1455 // add the iterator 1456 status_t error = _AddAttrDirIterator(node, iterator); 1457 if (error != B_OK) { 1458 delete iterator; 1459 return error; 1460 } 1461 1462 cookie->iterator = iterator; 1463 *_cookie = cookie; 1464 cookieDeleter.Detach(); 1465 return B_OK; 1466 } 1467 1468 // CloseAttrDir 1469 status_t 1470 ShareVolume::CloseAttrDir(Node* _node, void* cookie) 1471 { 1472 // no-op: FreeAttrDirCookie does the job 1473 return B_OK; 1474 } 1475 1476 // FreeAttrDirCookie 1477 status_t 1478 ShareVolume::FreeAttrDirCookie(Node* _node, void* _cookie) 1479 { 1480 ShareNode* node = dynamic_cast<ShareNode*>(_node); 1481 AttrDirCookie* cookie = (AttrDirCookie*)_cookie; 1482 ObjectDeleter<AttrDirCookie> _(cookie); 1483 1484 // if this is a local iterator, we just delete it and be done 1485 if (cookie->iterator) { 1486 AutoLocker<Locker> locker(fLock); 1487 1488 // remove and delete the iterator 1489 _RemoveAttrDirIterator(node, cookie->iterator); 1490 delete cookie->iterator; 1491 1492 return B_OK; 1493 } 1494 1495 // prepare the request 1496 CloseRequest request; 1497 request.volumeID = fID; 1498 request.cookie = cookie->cookie; 1499 1500 // send the request 1501 if (!_EnsureShareMounted()) 1502 return ERROR_NOT_CONNECTED; 1503 CloseReply* reply; 1504 status_t error = SendRequest(fConnection, &request, &reply); 1505 if (error != B_OK) 1506 RETURN_ERROR(error); 1507 ObjectDeleter<Request> replyDeleter(reply); 1508 if (reply->error != B_OK) 1509 RETURN_ERROR(reply->error); 1510 1511 return B_OK; 1512 } 1513 1514 // ReadAttrDir 1515 status_t 1516 ShareVolume::ReadAttrDir(Node* _node, void* _cookie, struct dirent* buffer, 1517 size_t bufferSize, int32 count, int32* countRead) 1518 { 1519 if (!_EnsureShareMounted()) 1520 return ERROR_NOT_CONNECTED; 1521 1522 *countRead = 0; 1523 AttrDirCookie* cookie = (AttrDirCookie*)_cookie; 1524 1525 // if we have a local iterator, things are easy 1526 if (ShareAttrDirIterator* iterator = cookie->iterator) { 1527 AutoLocker<Locker> locker(fLock); 1528 1529 // get the current attribute 1530 Attribute* attribute = iterator->GetCurrentAttribute(); 1531 if (!attribute) 1532 return B_OK; 1533 1534 // set the name: this also checks the size of the buffer 1535 const char* name = attribute->GetName(); 1536 status_t error = set_dirent_name(buffer, bufferSize, name, 1537 strlen(name)); 1538 if (error != B_OK) 1539 RETURN_ERROR(error); 1540 1541 // fill in the other fields 1542 buffer->d_dev = fVolumeManager->GetID(); 1543 buffer->d_ino = -1; 1544 *countRead = 1; 1545 1546 iterator->NextAttribute(); 1547 return B_OK; 1548 } 1549 1550 // prepare the request 1551 ReadAttrDirRequest request; 1552 request.volumeID = fID; 1553 request.cookie = cookie->cookie; 1554 request.count = 1; 1555 request.rewind = cookie->rewind; 1556 1557 // send the request 1558 ReadAttrDirReply* reply; 1559 status_t error = SendRequest(fConnection, &request, &reply); 1560 if (error != B_OK) 1561 RETURN_ERROR(error); 1562 ObjectDeleter<Request> replyDeleter(reply); 1563 if (reply->error != B_OK) 1564 RETURN_ERROR(reply->error); 1565 cookie->rewind = false; 1566 1567 // check, if anything has been read at all 1568 if (reply->count == 0) { 1569 *countRead = 0; 1570 return B_OK; 1571 } 1572 const char* name = reply->name.GetString(); 1573 int32 nameLen = reply->name.GetSize(); 1574 if (!name || nameLen < 2) 1575 return B_BAD_DATA; 1576 1577 // set the name: this also checks the size of the buffer 1578 error = set_dirent_name(buffer, bufferSize, name, nameLen - 1); 1579 if (error != B_OK) 1580 RETURN_ERROR(error); 1581 1582 // fill in the other fields 1583 buffer->d_dev = fVolumeManager->GetID(); 1584 buffer->d_ino = -1; 1585 *countRead = 1; 1586 return B_OK; 1587 } 1588 1589 // RewindAttrDir 1590 status_t 1591 ShareVolume::RewindAttrDir(Node* _node, void* _cookie) 1592 { 1593 AttrDirCookie* cookie = (AttrDirCookie*)_cookie; 1594 1595 // if we have a local iterator, rewind it 1596 if (ShareAttrDirIterator* iterator = cookie->iterator) { 1597 AutoLocker<Locker> locker(fLock); 1598 1599 iterator->Rewind(); 1600 } else 1601 cookie->rewind = true; 1602 1603 return B_OK; 1604 } 1605 1606 // ReadAttr 1607 status_t 1608 ShareVolume::ReadAttr(Node* _node, const char* name, int type, off_t pos, 1609 void* _buffer, size_t bufferSize, size_t* _bytesRead) 1610 { 1611 ShareNode* node = dynamic_cast<ShareNode*>(_node); 1612 1613 if (!_EnsureShareMounted()) 1614 return ERROR_NOT_CONNECTED; 1615 1616 *_bytesRead = 0; 1617 if (bufferSize == 0) 1618 return B_OK; 1619 uint8* buffer = (uint8*)_buffer; 1620 1621 // if we have the attribute directory cached, we can first check, if the 1622 // attribute exists at all -- maybe its data are cached, too 1623 { 1624 AutoLocker<Locker> locker(fLock); 1625 1626 ShareAttrDir* attrDir = node->GetAttrDir(); 1627 if (attrDir && attrDir->IsUpToDate()) { 1628 // get the attribute 1629 Attribute* attribute = attrDir->GetAttribute(name); 1630 if (!attribute) 1631 return B_ENTRY_NOT_FOUND; 1632 1633 // get the data 1634 if (const void* data = attribute->GetData()) { 1635 // first check, if we can read anything at all 1636 if (pos < 0) 1637 pos = 0; 1638 int32 size = attribute->GetSize(); 1639 if (pos >= size) 1640 return B_OK; 1641 1642 // get the data 1643 bufferSize = min(bufferSize, size_t(size - pos)); 1644 memcpy(buffer, data, bufferSize); 1645 *_bytesRead = bufferSize; 1646 return B_OK; 1647 } 1648 } 1649 } 1650 1651 // prepare the request 1652 ReadAttrRequest request; 1653 request.volumeID = fID; 1654 request.nodeID = node->GetRemoteID(); 1655 request.name.SetTo(name); 1656 request.type = type; 1657 request.pos = pos; 1658 request.size = bufferSize; 1659 1660 struct ReadRequestHandler : public RequestHandler { 1661 uint8* buffer; 1662 off_t pos; 1663 int32 bufferSize; 1664 int32 bytesRead; 1665 1666 ReadRequestHandler(uint8* buffer, off_t pos, int32 bufferSize) 1667 : buffer(buffer), 1668 pos(pos), 1669 bufferSize(bufferSize), 1670 bytesRead(0) 1671 { 1672 } 1673 1674 virtual status_t HandleRequest(Request* _reply, RequestChannel* channel) 1675 { 1676 // the passed request is deleted by the request port 1677 ReadAttrReply* reply = dynamic_cast<ReadAttrReply*>(_reply); 1678 if (!reply) 1679 RETURN_ERROR(B_BAD_DATA); 1680 // process the reply 1681 status_t error = ProcessReply(reply); 1682 if (error != B_OK) 1683 return error; 1684 bool moreToCome = reply->moreToCome; 1685 while (moreToCome) { 1686 // receive a reply 1687 error = ReceiveRequest(channel, &reply); 1688 if (error != B_OK) 1689 RETURN_ERROR(error); 1690 moreToCome = reply->moreToCome; 1691 ObjectDeleter<Request> replyDeleter(reply); 1692 // process the reply 1693 error = ProcessReply(reply); 1694 if (error != B_OK) 1695 return error; 1696 } 1697 return B_OK; 1698 } 1699 1700 status_t ProcessReply(ReadAttrReply* reply) 1701 { 1702 if (reply->error != B_OK) 1703 RETURN_ERROR(reply->error); 1704 // check the fields 1705 if (reply->pos != pos) 1706 RETURN_ERROR(B_BAD_DATA); 1707 int32 bytesRead = reply->data.GetSize(); 1708 if (bytesRead > (int32)bufferSize) 1709 RETURN_ERROR(B_BAD_DATA); 1710 // copy the data into the buffer 1711 if (bytesRead > 0) 1712 memcpy(buffer, reply->data.GetData(), bytesRead); 1713 pos += bytesRead; 1714 buffer += bytesRead; 1715 bufferSize -= bytesRead; 1716 this->bytesRead += bytesRead; 1717 return B_OK; 1718 } 1719 } requestHandler(buffer, pos, bufferSize); 1720 1721 // send the request 1722 status_t error = fConnection->SendRequest(&request, &requestHandler); 1723 if (error != B_OK) 1724 RETURN_ERROR(error); 1725 *_bytesRead = requestHandler.bytesRead; 1726 return B_OK; 1727 } 1728 1729 // WriteAttr 1730 status_t 1731 ShareVolume::WriteAttr(Node* _node, const char* name, int type, off_t pos, 1732 const void* _buffer, size_t bufferSize, size_t* bytesWritten) 1733 { 1734 ShareNode* node = dynamic_cast<ShareNode*>(_node); 1735 1736 if (!_EnsureShareMounted()) 1737 return ERROR_NOT_CONNECTED; 1738 1739 // check permissions 1740 if (IsReadOnly()) 1741 return B_PERMISSION_DENIED; 1742 1743 *bytesWritten = 0; 1744 off_t bytesLeft = bufferSize; 1745 const char* buffer = (const char*)_buffer; 1746 while (bytesLeft > 0) { 1747 // store the current attibute dir revision for reference below 1748 int64 attrDirRevision = -1; 1749 { 1750 AutoLocker<Locker> _(fLock); 1751 if (ShareAttrDir* attrDir = node->GetAttrDir()) { 1752 if (attrDir->IsUpToDate()) 1753 attrDirRevision = attrDir->GetRevision(); 1754 } 1755 } 1756 1757 off_t toWrite = bytesLeft; 1758 if (toWrite > kMaxWriteBufferSize) 1759 toWrite = kMaxWriteBufferSize; 1760 1761 // prepare the request 1762 WriteAttrRequest request; 1763 request.volumeID = fID; 1764 request.nodeID = node->GetRemoteID(); 1765 request.name.SetTo(name); 1766 request.type = type; 1767 request.pos = pos; 1768 request.data.SetTo(buffer, toWrite); 1769 1770 // send the request 1771 WriteAttrReply* reply; 1772 status_t error = SendRequest(fConnection, &request, &reply); 1773 if (error != B_OK) 1774 RETURN_ERROR(error); 1775 1776 ObjectDeleter<Request> replyDeleter(reply); 1777 if (reply->error != B_OK) 1778 RETURN_ERROR(reply->error); 1779 1780 bytesLeft -= toWrite; 1781 pos += toWrite; 1782 buffer += toWrite; 1783 1784 // If the request was successful, we consider the cached attr dir 1785 // no longer up to date. 1786 if (attrDirRevision >= 0) { 1787 AutoLocker<Locker> _(fLock); 1788 ShareAttrDir* attrDir = node->GetAttrDir(); 1789 if (attrDir && attrDir->GetRevision() == attrDirRevision) 1790 attrDir->SetUpToDate(false); 1791 } 1792 } 1793 1794 *bytesWritten = bufferSize; 1795 return B_OK; 1796 } 1797 1798 // RemoveAttr 1799 status_t 1800 ShareVolume::RemoveAttr(Node* _node, const char* name) 1801 { 1802 ShareNode* node = dynamic_cast<ShareNode*>(_node); 1803 1804 if (!_EnsureShareMounted()) 1805 return ERROR_NOT_CONNECTED; 1806 1807 // check permissions 1808 if (IsReadOnly()) 1809 return B_PERMISSION_DENIED; 1810 1811 // store the current attibute dir revision for reference below 1812 int64 attrDirRevision = -1; 1813 { 1814 AutoLocker<Locker> _(fLock); 1815 if (ShareAttrDir* attrDir = node->GetAttrDir()) { 1816 if (attrDir->IsUpToDate()) 1817 attrDirRevision = attrDir->GetRevision(); 1818 } 1819 } 1820 1821 // prepare the request 1822 RemoveAttrRequest request; 1823 request.volumeID = fID; 1824 request.nodeID = node->GetRemoteID(); 1825 request.name.SetTo(name); 1826 1827 // send the request 1828 RemoveAttrReply* reply; 1829 status_t error = SendRequest(fConnection, &request, &reply); 1830 if (error != B_OK) 1831 RETURN_ERROR(error); 1832 ObjectDeleter<Request> replyDeleter(reply); 1833 1834 // If the request was successful, we consider the cached attr dir 1835 // no longer up to date. 1836 if (reply->error == B_OK && attrDirRevision >= 0) { 1837 AutoLocker<Locker> _(fLock); 1838 ShareAttrDir* attrDir = node->GetAttrDir(); 1839 if (attrDir && attrDir->GetRevision() == attrDirRevision) 1840 attrDir->SetUpToDate(false); 1841 } 1842 1843 RETURN_ERROR(reply->error); 1844 } 1845 1846 // RenameAttr 1847 status_t 1848 ShareVolume::RenameAttr(Node* _node, const char* oldName, const char* newName) 1849 { 1850 ShareNode* node = dynamic_cast<ShareNode*>(_node); 1851 1852 if (!_EnsureShareMounted()) 1853 return ERROR_NOT_CONNECTED; 1854 1855 // check permissions 1856 if (IsReadOnly()) 1857 return B_PERMISSION_DENIED; 1858 1859 // store the current attibute dir revision for reference below 1860 int64 attrDirRevision = -1; 1861 { 1862 AutoLocker<Locker> _(fLock); 1863 if (ShareAttrDir* attrDir = node->GetAttrDir()) { 1864 if (attrDir->IsUpToDate()) 1865 attrDirRevision = attrDir->GetRevision(); 1866 } 1867 } 1868 1869 // prepare the request 1870 RenameAttrRequest request; 1871 request.volumeID = fID; 1872 request.nodeID = node->GetRemoteID(); 1873 request.oldName.SetTo(oldName); 1874 request.newName.SetTo(newName); 1875 1876 // send the request 1877 RenameAttrReply* reply; 1878 status_t error = SendRequest(fConnection, &request, &reply); 1879 if (error != B_OK) 1880 RETURN_ERROR(error); 1881 ObjectDeleter<Request> replyDeleter(reply); 1882 1883 // If the request was successful, we consider the cached attr dir 1884 // no longer up to date. 1885 if (reply->error == B_OK && attrDirRevision >= 0) { 1886 AutoLocker<Locker> _(fLock); 1887 ShareAttrDir* attrDir = node->GetAttrDir(); 1888 if (attrDir && attrDir->GetRevision() == attrDirRevision) 1889 attrDir->SetUpToDate(false); 1890 } 1891 1892 RETURN_ERROR(reply->error); 1893 } 1894 1895 // StatAttr 1896 status_t 1897 ShareVolume::StatAttr(Node* _node, const char* name, struct attr_info* attrInfo) 1898 { 1899 ShareNode* node = dynamic_cast<ShareNode*>(_node); 1900 1901 if (!_EnsureShareMounted()) 1902 return ERROR_NOT_CONNECTED; 1903 1904 // if we have the attribute directory cached, get the info from there 1905 { 1906 AutoLocker<Locker> locker(fLock); 1907 1908 ShareAttrDir* attrDir = node->GetAttrDir(); 1909 if (attrDir && attrDir->IsUpToDate()) { 1910 // get the attribute 1911 Attribute* attribute = attrDir->GetAttribute(name); 1912 if (!attribute) 1913 return B_ENTRY_NOT_FOUND; 1914 1915 attribute->GetInfo(attrInfo); 1916 return B_OK; 1917 } 1918 } 1919 1920 // prepare the request 1921 StatAttrRequest request; 1922 request.volumeID = fID; 1923 request.nodeID = node->GetRemoteID(); 1924 request.name.SetTo(name); 1925 1926 // send the request 1927 StatAttrReply* reply; 1928 status_t error = SendRequest(fConnection, &request, &reply); 1929 if (error != B_OK) 1930 RETURN_ERROR(error); 1931 ObjectDeleter<Request> replyDeleter(reply); 1932 if (reply->error != B_OK) 1933 RETURN_ERROR(reply->error); 1934 1935 // set the result 1936 *attrInfo = reply->attrInfo.info; 1937 return B_OK; 1938 } 1939 1940 1941 // #pragma mark - 1942 // #pragma mark ----- queries ----- 1943 1944 // GetQueryEntry 1945 status_t 1946 ShareVolume::GetQueryEntry(const EntryInfo& entryInfo, 1947 const NodeInfo& dirInfo, struct dirent* buffer, size_t bufferSize, 1948 int32* countRead) 1949 { 1950 status_t error = B_OK; 1951 1952 const char* name = entryInfo.name.GetString(); 1953 int32 nameLen = entryInfo.name.GetSize(); 1954 if (!name || nameLen < 2) 1955 RETURN_ERROR(B_BAD_DATA); 1956 1957 // load the directory 1958 vnode_id localDirID = -1; 1959 { 1960 AutoLocker<Locker> _(fLock); 1961 ShareNode* node; 1962 error = _LoadNode(dirInfo, &node); 1963 if (error != B_OK) 1964 RETURN_ERROR(error); 1965 ShareDir* directory = dynamic_cast<ShareDir*>(node); 1966 if (!directory) 1967 RETURN_ERROR(B_ENTRY_NOT_FOUND); 1968 localDirID = directory->GetID(); 1969 } 1970 1971 // add/update the entry 1972 vnode_id localNodeID = -1; 1973 const EntryInfo* resolvedEntryInfo = &entryInfo; 1974 while (error == B_OK) { 1975 // get an up to date entry info 1976 WalkReply* walkReply = NULL; 1977 if (!resolvedEntryInfo) { 1978 error = _Walk(entryInfo.directoryID, name, false, 1979 &walkReply); 1980 if (error != B_OK) 1981 RETURN_ERROR(error); 1982 1983 resolvedEntryInfo = &walkReply->entryInfo; 1984 } 1985 ObjectDeleter<Request> walkReplyDeleter(walkReply); 1986 1987 AutoLocker<Locker> locker(fLock); 1988 1989 // check, if the info is obsolete 1990 if (_IsObsoleteEntryInfo(*resolvedEntryInfo)) { 1991 resolvedEntryInfo = NULL; 1992 continue; 1993 } 1994 1995 // get the directory 1996 ShareDir* dir = dynamic_cast<ShareDir*>(_GetNodeByLocalID(localDirID)); 1997 if (!dir) 1998 RETURN_ERROR(B_ERROR); 1999 2000 // load the entry 2001 ShareDirEntry* entry; 2002 error = _LoadEntry(dir, *resolvedEntryInfo, &entry); 2003 if (error == B_OK) 2004 localNodeID = entry->GetNode()->GetID(); 2005 2006 break; 2007 } 2008 2009 // set the name: this also checks the size of the buffer 2010 error = set_dirent_name(buffer, bufferSize, name, nameLen - 1); 2011 if (error != B_OK) 2012 RETURN_ERROR(error); 2013 2014 // fill in the other fields 2015 buffer->d_pdev = fVolumeManager->GetID(); 2016 buffer->d_pino = localDirID; 2017 buffer->d_dev = fVolumeManager->GetID(); 2018 buffer->d_ino = localNodeID; 2019 2020 *countRead = 1; 2021 PRINT(" entry: d_dev: %" B_PRIdDEV ", d_pdev: %" B_PRIdDEV ", d_ino: %" 2022 B_PRIdINO ", d_pino: %" B_PRIdINO ", d_reclen: %hu, d_name: `%s'\n", 2023 buffer->d_dev, buffer->d_pdev, buffer->d_ino, buffer->d_pino, 2024 buffer->d_reclen, buffer->d_name); 2025 return B_OK; 2026 } 2027 2028 2029 // #pragma mark - 2030 2031 // ProcessNodeMonitoringRequest 2032 void 2033 ShareVolume::ProcessNodeMonitoringRequest(NodeMonitoringRequest* request) 2034 { 2035 switch (request->opcode) { 2036 case B_ENTRY_CREATED: 2037 _HandleEntryCreatedRequest( 2038 dynamic_cast<EntryCreatedRequest*>(request)); 2039 break; 2040 case B_ENTRY_REMOVED: 2041 _HandleEntryRemovedRequest( 2042 dynamic_cast<EntryRemovedRequest*>(request)); 2043 break; 2044 case B_ENTRY_MOVED: 2045 _HandleEntryMovedRequest( 2046 dynamic_cast<EntryMovedRequest*>(request)); 2047 break; 2048 case B_STAT_CHANGED: 2049 _HandleStatChangedRequest( 2050 dynamic_cast<StatChangedRequest*>(request)); 2051 break; 2052 case B_ATTR_CHANGED: 2053 _HandleAttributeChangedRequest( 2054 dynamic_cast<AttributeChangedRequest*>(request)); 2055 break; 2056 } 2057 } 2058 2059 // ConnectionClosed 2060 void 2061 ShareVolume::ConnectionClosed() 2062 { 2063 AutoLocker<Locker> _(fMountLock); 2064 fConnectionState = CONNECTION_CLOSED; 2065 } 2066 2067 2068 // #pragma mark - 2069 2070 // _ReadRemoteDir 2071 status_t 2072 ShareVolume::_ReadRemoteDir(ShareDir* directory, 2073 RemoteShareDirIterator* iterator) 2074 { 2075 // prepare the request 2076 fLock.Lock(); 2077 ReadDirRequest request; 2078 request.volumeID = fID; 2079 request.cookie = iterator->GetCookie(); 2080 request.count = iterator->GetCapacity(); 2081 request.rewind = iterator->GetRewind(); 2082 fLock.Unlock(); 2083 2084 // send the request 2085 ReadDirReply* reply; 2086 status_t error = SendRequest(fConnection, &request, &reply); 2087 if (error != B_OK) 2088 RETURN_ERROR(error); 2089 ObjectDeleter<Request> replyDeleter(reply); 2090 if (reply->error != B_OK) 2091 RETURN_ERROR(reply->error); 2092 2093 RequestMemberArray<EntryInfo>* entryInfos = &reply->entryInfos; 2094 while (true) { 2095 // get up to date entry infos 2096 MultiWalkReply* walkReply = NULL; 2097 if (!entryInfos) { 2098 error = _MultiWalk(reply->entryInfos, &walkReply); 2099 if (error != B_OK) 2100 RETURN_ERROR(error); 2101 2102 entryInfos = &walkReply->entryInfos; 2103 } 2104 ObjectDeleter<Request> walkReplyDeleter(walkReply); 2105 2106 AutoLocker<Locker> locker(fLock); 2107 2108 // check, if any info is obsolete 2109 int32 count = entryInfos->CountElements(); 2110 for (int32 i = 0; i < count; i++) { 2111 const EntryInfo& entryInfo = entryInfos->GetElements()[i]; 2112 if (_IsObsoleteEntryInfo(entryInfo)) { 2113 entryInfos = NULL; 2114 continue; 2115 } 2116 } 2117 2118 // init the iterator's revision, if it's new or has been rewinded 2119 if (request.rewind || iterator->GetRevision() < 0) 2120 iterator->SetRevision(reply->revision); 2121 2122 iterator->Clear(); 2123 iterator->SetDone(reply->done); 2124 2125 // iterate through the entries 2126 for (int32 i = 0; i < count; i++) { 2127 const EntryInfo& entryInfo = entryInfos->GetElements()[i]; 2128 const char* name = entryInfo.name.GetString(); 2129 int32 nameLen = entryInfo.name.GetSize(); 2130 if (!name || nameLen < 2) 2131 return B_BAD_DATA; 2132 2133 // load the node/entry 2134 ShareDirEntry* entry; 2135 error = _LoadEntry(directory, entryInfo, &entry); 2136 if (error != B_OK) 2137 RETURN_ERROR(error); 2138 2139 // add the entry 2140 if (!iterator->AddEntry(entry)) { 2141 ERROR("ShareVolume::_ReadRemoteDir(): ERROR: Failed to add " 2142 "entry to remote iterator!\n"); 2143 } 2144 } 2145 2146 // directory now complete? 2147 if (reply->done && directory->GetEntryRemovedEventRevision() 2148 < iterator->GetRevision()) { 2149 directory->SetComplete(true); 2150 } 2151 2152 break; 2153 } 2154 2155 return B_OK; 2156 } 2157 2158 // _HandleEntryCreatedRequest 2159 void 2160 ShareVolume::_HandleEntryCreatedRequest(EntryCreatedRequest* request) 2161 { 2162 if (!request) 2163 return; 2164 2165 nspace_id nsid = fVolumeManager->GetID(); 2166 const char* name = request->name.GetString(); 2167 2168 // translate the node IDs 2169 vnode_id vnida = 0; 2170 vnode_id vnidb = 0; 2171 vnode_id vnidc = 0; 2172 status_t error = _GetLocalNodeID(request->directoryID, &vnida, true); 2173 if (error == B_OK) 2174 error = _GetLocalNodeID(request->nodeID, &vnidc, true); 2175 PRINT("ShareVolume::_HandleEntryCreatedRequest(): error: 0x%" B_PRIx32 2176 ", name: \"%s\", dir: %" B_PRIdINO " (remote: (%" B_PRIdDEV ", %" 2177 B_PRIdINO ")), node: %" B_PRIdINO " (remote: (%" B_PRIdDEV ", %" 2178 B_PRIdINO "))\n", error, name, vnida, 2179 request->directoryID.volumeID, request->directoryID.nodeID, vnidc, 2180 request->nodeID.volumeID, request->nodeID.nodeID); 2181 2182 // send notifications / do additional processing 2183 if (request->queryUpdate) { 2184 if (error == B_OK) { 2185 SendNotification(request->port, request->token, 2186 B_QUERY_UPDATE, request->opcode, nsid, 0, vnida, vnidb, 2187 vnidc, name); 2188 } 2189 } else { 2190 _EntryCreated(request->directoryID, name, 2191 (request->entryInfoValid ? &request->entryInfo : NULL), 2192 request->revision); 2193 if (error == B_OK) 2194 NotifyListener(request->opcode, nsid, vnida, vnidb, vnidc, name); 2195 } 2196 } 2197 2198 // _HandleEntryRemovedRequest 2199 void 2200 ShareVolume::_HandleEntryRemovedRequest(EntryRemovedRequest* request) 2201 { 2202 if (!request) 2203 return; 2204 2205 nspace_id nsid = fVolumeManager->GetID(); 2206 const char* name = request->name.GetString(); 2207 2208 // translate the node IDs 2209 vnode_id vnida = 0; 2210 vnode_id vnidb = 0; 2211 vnode_id vnidc = 0; 2212 status_t error = _GetLocalNodeID(request->directoryID, &vnida, true); 2213 if (error == B_OK) 2214 error = _GetLocalNodeID(request->nodeID, &vnidc, false); 2215 // TODO: We don't enter a node ID mapping here, which might cause 2216 // undesired behavior in some cases. Queries should usually be 2217 // fine, since, if the entry was in the query set, then the 2218 // respective node ID should definately be known at this point. 2219 // If an entry is removed and the node monitoring event comes 2220 // before a live query event for the same entry, the former one 2221 // will cause the ID to be removed, so that it is already gone 2222 // when the latter one arrives. I haven't observed this yet, 2223 // though. The query events always seem to be sent before the 2224 // node monitoring events (and the server processes them in a 2225 // single-threaded way). I guess, this is FS implementation 2226 // dependent, though. 2227 // A node monitoring event that will always get lost, is when the 2228 // FS user watches a directory that hasn't been read before. Its 2229 // entries will not be known yet and thus "entry removed" events 2230 // will be dropped here. I guess, it's arguable whether this is 2231 // a practical problem (why should the watcher care that an entry 2232 // has been removed, when they didn't know what entries were in 2233 // the directory in the first place?). 2234 // A possible solution would be to never remove node ID mappings. 2235 // We would only need to take care that the cached node info is 2236 // correctly flushed, so that e.g. a subsequent ReadVNode() has to 2237 // ask the server and doesn't work with obsolete data. We would 2238 // also enter a yet unknown ID into the node ID map here. The only 2239 // problem is that the ID maps will keep growing, especially when 2240 // there's a lot of FS activity on the server. 2241 2242 // send notifications / do additional processing 2243 if (request->queryUpdate) { 2244 if (error == B_OK) { 2245 SendNotification(request->port, request->token, 2246 B_QUERY_UPDATE, request->opcode, nsid, 0, vnida, vnidb, 2247 vnidc, name); 2248 } 2249 } else { 2250 _EntryRemoved(request->directoryID, name, request->revision); 2251 _NodeRemoved(request->nodeID); 2252 if (error == B_OK) 2253 NotifyListener(request->opcode, nsid, vnida, vnidb, vnidc, name); 2254 } 2255 } 2256 2257 // _HandleEntryMovedRequest 2258 void 2259 ShareVolume::_HandleEntryMovedRequest(EntryMovedRequest* request) 2260 { 2261 if (!request) 2262 return; 2263 2264 nspace_id nsid = fVolumeManager->GetID(); 2265 const char* oldName = request->fromName.GetString(); 2266 const char* name = request->toName.GetString(); 2267 2268 // translate the node IDs 2269 vnode_id vnida = 0; 2270 vnode_id vnidb = 0; 2271 vnode_id vnidc = 0; 2272 status_t error = _GetLocalNodeID(request->fromDirectoryID, &vnida, true); 2273 if (error == B_OK) 2274 error = _GetLocalNodeID(request->toDirectoryID, &vnidb, true); 2275 if (error == B_OK) 2276 error = _GetLocalNodeID(request->nodeID, &vnidc, true); 2277 2278 // send notifications / do additional processing 2279 if (!request->queryUpdate) { 2280 _EntryMoved(request->fromDirectoryID, oldName, request->toDirectoryID, 2281 name, (request->entryInfoValid ? &request->entryInfo : NULL), 2282 request->revision); 2283 if (error == B_OK) 2284 NotifyListener(request->opcode, nsid, vnida, vnidb, vnidc, name); 2285 } 2286 } 2287 2288 // _HandleStatChangedRequest 2289 void 2290 ShareVolume::_HandleStatChangedRequest(StatChangedRequest* request) 2291 { 2292 if (!request) 2293 return; 2294 2295 nspace_id nsid = fVolumeManager->GetID(); 2296 2297 // translate the node IDs 2298 vnode_id vnida = 0; 2299 vnode_id vnidb = 0; 2300 vnode_id vnidc = 0; 2301 status_t error = _GetLocalNodeID(request->nodeID, &vnidc, true); 2302 2303 // send notifications / do additional processing 2304 if (!request->queryUpdate) { 2305 _UpdateNode(request->nodeInfo); 2306 if (error == B_OK) 2307 NotifyListener(request->opcode, nsid, vnida, vnidb, vnidc, NULL); 2308 } 2309 } 2310 2311 // _HandleAttributeChangedRequest 2312 void 2313 ShareVolume::_HandleAttributeChangedRequest(AttributeChangedRequest* request) 2314 { 2315 if (!request) 2316 return; 2317 2318 nspace_id nsid = fVolumeManager->GetID(); 2319 const char* name = request->attrInfo.name.GetString(); 2320 2321 // translate the node IDs 2322 vnode_id vnida = 0; 2323 vnode_id vnidb = 0; 2324 vnode_id vnidc = 0; 2325 status_t error = _GetLocalNodeID(request->nodeID, &vnidc, true); 2326 2327 // send notifications / do additional processing 2328 if (!request->queryUpdate) { 2329 _UpdateAttrDir(request->nodeID, request->attrDirInfo); 2330 if (error == B_OK) 2331 NotifyListener(request->opcode, nsid, vnida, vnidb, vnidc, name); 2332 } 2333 } 2334 2335 // _GetLocalNodeID 2336 status_t 2337 ShareVolume::_GetLocalNodeID(NodeID remoteID, ino_t* _localID, bool enter) 2338 { 2339 AutoLocker<Locker> _(fLock); 2340 // if the ID is already know, just return it 2341 if (fLocalNodeIDs->ContainsKey(remoteID)) { 2342 *_localID = fLocalNodeIDs->Get(remoteID); 2343 return B_OK; 2344 } 2345 2346 // ID not yet known 2347 // enter it? Do this only, if requested and we're not already unmounting. 2348 if (!enter) 2349 return B_ENTRY_NOT_FOUND; 2350 if (fUnmounting) 2351 return ERROR_NOT_CONNECTED; 2352 2353 // get a fresh ID from the volume manager 2354 vnode_id localID = fVolumeManager->NewNodeID(this); 2355 if (localID < 0) 2356 return localID; 2357 2358 // put the IDs into local map 2359 status_t error = fLocalNodeIDs->Put(remoteID, localID); 2360 if (error != B_OK) { 2361 fVolumeManager->RemoveNodeID(localID); 2362 return error; 2363 } 2364 2365 // put the IDs into remote map 2366 error = fRemoteNodeIDs->Put(localID, remoteID); 2367 if (error != B_OK) { 2368 fLocalNodeIDs->Remove(remoteID); 2369 fVolumeManager->RemoveNodeID(localID); 2370 return error; 2371 } 2372 PRINT("ShareVolume(%" B_PRId32 "): added node ID mapping: local: %" 2373 B_PRIdINO " -> remote: (%" B_PRIdDEV ", %" B_PRIdINO ")\n", fID, 2374 localID, remoteID.volumeID, remoteID.nodeID); 2375 2376 *_localID = localID; 2377 return B_OK; 2378 } 2379 2380 // _GetRemoteNodeID 2381 status_t 2382 ShareVolume::_GetRemoteNodeID(ino_t localID, NodeID* remoteID) 2383 { 2384 AutoLocker<Locker> _(fLock); 2385 2386 // check, if the ID is known 2387 if (!fRemoteNodeIDs->ContainsKey(localID)) 2388 return B_ENTRY_NOT_FOUND; 2389 2390 *remoteID = fRemoteNodeIDs->Get(localID); 2391 return B_OK; 2392 } 2393 2394 // _RemoveLocalNodeID 2395 void 2396 ShareVolume::_RemoveLocalNodeID(ino_t localID) 2397 { 2398 AutoLocker<Locker> _(fLock); 2399 2400 // check, if the ID is known 2401 if (!fRemoteNodeIDs->ContainsKey(localID)) 2402 return; 2403 2404 // remove from ID maps 2405 NodeID remoteID = fRemoteNodeIDs->Get(localID); 2406 PRINT("ShareVolume::_RemoveLocalNodeID(%" B_PRIdINO "): remote: (%" 2407 B_PRIdDEV ", %" B_PRIdINO ")\n", localID, remoteID.volumeID, 2408 remoteID.nodeID); 2409 fRemoteNodeIDs->Remove(localID); 2410 fLocalNodeIDs->Remove(remoteID); 2411 2412 // remove from volume manager 2413 fVolumeManager->RemoveNodeID(localID); 2414 } 2415 2416 // _GetNodeByLocalID 2417 ShareNode* 2418 ShareVolume::_GetNodeByLocalID(ino_t localID) 2419 { 2420 AutoLocker<Locker> _(fLock); 2421 return fNodes->Get(localID); 2422 } 2423 2424 // _GetNodeByRemoteID 2425 ShareNode* 2426 ShareVolume::_GetNodeByRemoteID(NodeID remoteID) 2427 { 2428 AutoLocker<Locker> _(fLock); 2429 2430 ino_t localID; 2431 if (_GetLocalNodeID(remoteID, &localID, false) == B_OK) 2432 return fNodes->Get(localID); 2433 2434 return NULL; 2435 } 2436 2437 // _LoadNode 2438 status_t 2439 ShareVolume::_LoadNode(const NodeInfo& nodeInfo, ShareNode** _node) 2440 { 2441 AutoLocker<Locker> _(fLock); 2442 2443 // check, if the node is already known 2444 ShareNode* node = _GetNodeByRemoteID(nodeInfo.GetID()); 2445 if (node) { 2446 node->Update(nodeInfo); 2447 } else { 2448 // don't load the node when already unmounting 2449 if (fUnmounting) 2450 return B_ERROR; 2451 2452 // get a local node ID 2453 vnode_id localID; 2454 status_t error = _GetLocalNodeID(nodeInfo.GetID(), &localID, true); 2455 if (error != B_OK) 2456 return error; 2457 2458 // create a new node 2459 if (S_ISDIR(nodeInfo.st.st_mode)) 2460 node = new(std::nothrow) ShareDir(this, localID, &nodeInfo); 2461 else 2462 node = new(std::nothrow) ShareNode(this, localID, &nodeInfo); 2463 if (!node) { 2464 _RemoveLocalNodeID(localID); 2465 return B_NO_MEMORY; 2466 } 2467 2468 // add it 2469 error = fNodes->Put(node->GetID(), node); 2470 if (error != B_OK) { 2471 _RemoveLocalNodeID(localID); 2472 delete node; 2473 return error; 2474 } 2475 PRINT("ShareVolume: added node: %" B_PRIdINO ": remote: (%" B_PRIdDEV 2476 ", %" B_PRIdINO "), localID: %" B_PRIdINO "\n", node->GetID(), 2477 node->GetRemoteID().volumeID, 2478 node->GetRemoteID().nodeID, localID); 2479 } 2480 2481 if (_node) 2482 *_node = node; 2483 return B_OK; 2484 } 2485 2486 // _UpdateNode 2487 status_t 2488 ShareVolume::_UpdateNode(const NodeInfo& nodeInfo) 2489 { 2490 AutoLocker<Locker> _(fLock); 2491 2492 if (fUnmounting) 2493 return ERROR_NOT_CONNECTED; 2494 2495 ShareNode* node = _GetNodeByRemoteID(nodeInfo.GetID()); 2496 if (node) { 2497 node->Update(nodeInfo); 2498 return B_OK; 2499 } 2500 return B_ENTRY_NOT_FOUND; 2501 } 2502 2503 // _GetEntryByLocalID 2504 ShareDirEntry* 2505 ShareVolume::_GetEntryByLocalID(ino_t localDirID, const char* name) 2506 { 2507 if (!name) 2508 return NULL; 2509 2510 AutoLocker<Locker> _(fLock); 2511 return fEntries->Get(EntryKey(localDirID, name)); 2512 } 2513 2514 // _GetEntryByRemoteID 2515 ShareDirEntry* 2516 ShareVolume::_GetEntryByRemoteID(NodeID remoteDirID, const char* name) 2517 { 2518 if (!name) 2519 return NULL; 2520 2521 AutoLocker<Locker> _(fLock); 2522 2523 ino_t localDirID; 2524 if (_GetLocalNodeID(remoteDirID, &localDirID, false) == B_OK) 2525 return fEntries->Get(EntryKey(localDirID, name)); 2526 2527 return NULL; 2528 } 2529 2530 // _LoadEntry 2531 // 2532 // If _entry is supplied, fLock should be held, otherwise the returned entry 2533 // might as well be deleted. 2534 status_t 2535 ShareVolume::_LoadEntry(ShareDir* directory, const EntryInfo& entryInfo, 2536 ShareDirEntry** _entry) 2537 { 2538 const char* name = entryInfo.name.GetString(); 2539 if (!directory || !name) 2540 return B_BAD_VALUE; 2541 2542 AutoLocker<Locker> _(fLock); 2543 2544 ShareDirEntry* entry = _GetEntryByLocalID(directory->GetID(), name); 2545 if (entry) { 2546 if (entryInfo.nodeInfo.revision > entry->GetRevision()) { 2547 if (entryInfo.nodeInfo.GetID() != entry->GetNode()->GetRemoteID()) { 2548 // The node the existing entry refers to is not the node it 2549 // should refer to. Remove the old entry and create a new one. 2550 _EntryRemoved(directory->GetRemoteID(), name, 2551 entryInfo.nodeInfo.revision); 2552 _EntryCreated(directory->GetRemoteID(), name, &entryInfo, 2553 entryInfo.nodeInfo.revision); 2554 2555 // re-get the entry and check, if everything is fine 2556 entry = _GetEntryByLocalID(directory->GetID(), name); 2557 if (!entry) 2558 return B_ERROR; 2559 if (entryInfo.nodeInfo.GetID() 2560 != entry->GetNode()->GetRemoteID()) { 2561 return B_ERROR; 2562 } 2563 } else { 2564 entry->SetRevision(entryInfo.nodeInfo.revision); 2565 _UpdateNode(entryInfo.nodeInfo); 2566 } 2567 } 2568 } else { 2569 // entry not known yet: create it 2570 2571 // don't load the entry when already unmounting 2572 if (fUnmounting) 2573 return B_ERROR; 2574 2575 // load the node 2576 ShareNode* node; 2577 status_t error = _LoadNode(entryInfo.nodeInfo, &node); 2578 if (error != B_OK) 2579 return error; 2580 2581 // if the directory or the node are marked remove, we don't create the 2582 // entry 2583 if (IsVNodeRemoved(directory->GetID()) > 0 2584 || IsVNodeRemoved(node->GetID()) > 0) { 2585 return B_NOT_ALLOWED; 2586 } 2587 2588 // create the entry 2589 entry = new(std::nothrow) ShareDirEntry(directory, name, node); 2590 if (!entry) 2591 return B_NO_MEMORY; 2592 ObjectDeleter<ShareDirEntry> entryDeleter(entry); 2593 error = entry->InitCheck(); 2594 if (error != B_OK) 2595 return error; 2596 2597 // add the entry 2598 error = fEntries->Put(EntryKey(directory->GetID(), entry->GetName()), 2599 entry); 2600 if (error != B_OK) 2601 return error; 2602 2603 // set the entry revision 2604 entry->SetRevision(entryInfo.nodeInfo.revision); 2605 2606 // add the entry to the directory and the node 2607 directory->AddEntry(entry); 2608 entry->GetNode()->AddReferringEntry(entry); 2609 2610 // everything went fine 2611 entryDeleter.Detach(); 2612 } 2613 2614 if (_entry) 2615 *_entry = entry; 2616 return B_OK; 2617 } 2618 2619 // _RemoveEntry 2620 // 2621 // fLock must be held. 2622 void 2623 ShareVolume::_RemoveEntry(ShareDirEntry* entry) 2624 { 2625 fEntries->Remove(EntryKey(entry->GetDirectory()->GetID(), 2626 entry->GetName())); 2627 entry->GetDirectory()->RemoveEntry(entry); 2628 entry->GetNode()->RemoveReferringEntry(entry); 2629 entry->ReleaseReference(); 2630 } 2631 2632 // _IsObsoleteEntryInfo 2633 // 2634 // fLock must be held. 2635 bool 2636 ShareVolume::_IsObsoleteEntryInfo(const EntryInfo& entryInfo) 2637 { 2638 // get the directory 2639 ShareDir* dir 2640 = dynamic_cast<ShareDir*>(_GetNodeByRemoteID(entryInfo.directoryID)); 2641 if (!dir) 2642 return false; 2643 2644 return (entryInfo.nodeInfo.revision <= dir->GetEntryRemovedEventRevision()); 2645 } 2646 2647 // _LoadAttrDir 2648 status_t 2649 ShareVolume::_LoadAttrDir(ShareNode* node, const AttrDirInfo& attrDirInfo) 2650 { 2651 if (!node || !attrDirInfo.isValid) 2652 return B_BAD_VALUE; 2653 2654 AutoLocker<Locker> _(fLock); 2655 2656 if (fUnmounting) 2657 return ERROR_NOT_CONNECTED; 2658 2659 ShareAttrDir* attrDir = node->GetAttrDir(); 2660 if (attrDir) { 2661 if (attrDir->GetRevision() > attrDirInfo.revision) 2662 return B_OK; 2663 2664 // update the attr dir 2665 return attrDir->Update(attrDirInfo, 2666 fAttrDirIterators->Get(node->GetID())); 2667 } else { 2668 // no attribute directory yet: create one 2669 attrDir = new(std::nothrow) ShareAttrDir; 2670 if (!attrDir) 2671 return B_NO_MEMORY; 2672 ObjectDeleter<ShareAttrDir> attrDirDeleter(attrDir); 2673 2674 // initialize it 2675 status_t error = attrDir->Init(attrDirInfo); 2676 if (error != B_OK) 2677 return error; 2678 2679 // set it 2680 node->SetAttrDir(attrDir); 2681 attrDirDeleter.Detach(); 2682 return B_OK; 2683 } 2684 } 2685 2686 // _UpdateAttrDir 2687 status_t 2688 ShareVolume::_UpdateAttrDir(NodeID remoteID, const AttrDirInfo& attrDirInfo) 2689 { 2690 AutoLocker<Locker> _(fLock); 2691 2692 // get the node 2693 ShareNode* node = _GetNodeByRemoteID(remoteID); 2694 if (!node) 2695 return B_ENTRY_NOT_FOUND; 2696 2697 if (!attrDirInfo.isValid || _LoadAttrDir(node, attrDirInfo) != B_OK) { 2698 // updating/creating the attr dir failed; if existing, we mark it 2699 // obsolete 2700 if (ShareAttrDir* attrDir = node->GetAttrDir()) 2701 attrDir->SetUpToDate(false); 2702 } 2703 2704 return B_OK; 2705 } 2706 2707 // _AddAttrDirIterator 2708 status_t 2709 ShareVolume::_AddAttrDirIterator(ShareNode* node, 2710 ShareAttrDirIterator* iterator) 2711 { 2712 if (!node || !iterator) 2713 return B_BAD_VALUE; 2714 2715 AutoLocker<Locker> locker(fLock); 2716 2717 // get the iterator list 2718 DoublyLinkedList<ShareAttrDirIterator>* iteratorList 2719 = fAttrDirIterators->Get(node->GetID()); 2720 if (!iteratorList) { 2721 // no list for the node yet: create one 2722 iteratorList = new(std::nothrow) DoublyLinkedList<ShareAttrDirIterator>; 2723 if (!iteratorList) 2724 return B_NO_MEMORY; 2725 2726 // add it 2727 status_t error = fAttrDirIterators->Put(node->GetID(), iteratorList); 2728 if (error != B_OK) { 2729 delete iteratorList; 2730 return error; 2731 } 2732 } 2733 2734 // add the iterator 2735 iteratorList->Insert(iterator); 2736 2737 return B_OK; 2738 } 2739 2740 // _RemoveAttrDirIterator 2741 void 2742 ShareVolume::_RemoveAttrDirIterator(ShareNode* node, 2743 ShareAttrDirIterator* iterator) 2744 { 2745 if (!node || !iterator) 2746 return; 2747 2748 AutoLocker<Locker> locker(fLock); 2749 2750 // get the iterator list 2751 DoublyLinkedList<ShareAttrDirIterator>* iteratorList 2752 = fAttrDirIterators->Get(node->GetID()); 2753 if (!iteratorList) { 2754 WARN("ShareVolume::_RemoveAttrDirIterator(): Iterator list not " 2755 "found: node: %" B_PRIdINO "\n", node->GetID()); 2756 return; 2757 } 2758 2759 // remove the iterator 2760 iteratorList->Remove(iterator); 2761 2762 // if the list is empty now, discard it 2763 if (!iteratorList->First()) { 2764 fAttrDirIterators->Remove(node->GetID()); 2765 delete iteratorList; 2766 } 2767 } 2768 2769 // _NodeRemoved 2770 void 2771 ShareVolume::_NodeRemoved(NodeID remoteID) 2772 { 2773 AutoLocker<Locker> locker(fLock); 2774 2775 ShareNode* node = _GetNodeByRemoteID(remoteID); 2776 if (!node) 2777 return; 2778 2779 // if the node still has referring entries, we do nothing 2780 if (node->GetActualReferringEntry()) 2781 return; 2782 2783 // if the node is a directory, we remove its entries first 2784 if (ShareDir* dir = dynamic_cast<ShareDir*>(node)) { 2785 while (ShareDirEntry* entry = dir->GetFirstEntry()) 2786 _RemoveEntry(entry); 2787 } 2788 2789 // remove all entries still referring to the node 2790 while (ShareDirEntry* entry = node->GetFirstReferringEntry()) 2791 _RemoveEntry(entry); 2792 2793 ino_t localID = node->GetID(); 2794 2795 // Remove the node ID in all cases -- even, if the node is still 2796 // known to the VFS. Otherwise there could be a race condition, that the 2797 // server re-uses the remote ID and we have it still associated with an 2798 // obsolete local ID. 2799 _RemoveLocalNodeID(localID); 2800 2801 if (node->IsKnownToVFS()) { 2802 Node* _node; 2803 if (GetVNode(localID, &_node) != B_OK) 2804 return; 2805 Volume::RemoveVNode(localID); 2806 locker.Unlock(); 2807 PutVNode(localID); 2808 2809 } else { 2810 fNodes->Remove(localID); 2811 delete node; 2812 } 2813 } 2814 2815 // _EntryCreated 2816 void 2817 ShareVolume::_EntryCreated(NodeID remoteDirID, const char* name, 2818 const EntryInfo* entryInfo, int64 revision) 2819 { 2820 if (!name) 2821 return; 2822 2823 AutoLocker<Locker> locker(fLock); 2824 2825 // get the directory 2826 ShareDir* dir = dynamic_cast<ShareDir*>(_GetNodeByRemoteID(remoteDirID)); 2827 if (!dir) 2828 return; 2829 2830 // load the entry, if possible 2831 ShareDirEntry* entry; 2832 bool entryLoaded = false; 2833 if (entryInfo && _LoadEntry(dir, *entryInfo, &entry) == B_OK) 2834 entryLoaded = true; 2835 2836 // if the entry could not be loaded, we have to mark the dir incomplete 2837 // and update its revision counter 2838 if (!entryLoaded) { 2839 dir->UpdateEntryCreatedEventRevision(revision); 2840 dir->SetComplete(false); 2841 } 2842 } 2843 2844 // _EntryRemoved 2845 void 2846 ShareVolume::_EntryRemoved(NodeID remoteDirID, const char* name, int64 revision) 2847 { 2848 if (!name) 2849 return; 2850 2851 AutoLocker<Locker> locker(fLock); 2852 2853 // get the directory 2854 ShareDir* dir = dynamic_cast<ShareDir*>(_GetNodeByRemoteID(remoteDirID)); 2855 if (!dir) 2856 return; 2857 2858 // update the directory's "entry removed" event revision 2859 dir->UpdateEntryRemovedEventRevision(revision); 2860 2861 // get the entry 2862 ShareDirEntry* entry = _GetEntryByRemoteID(remoteDirID, name); 2863 if (!entry) 2864 return; 2865 2866 // check the entry revision 2867 if (entry->GetRevision() > revision) 2868 return; 2869 2870 // remove the entry 2871 _RemoveEntry(entry); 2872 } 2873 2874 // _EntryMoved 2875 void 2876 ShareVolume::_EntryMoved(NodeID remoteOldDirID, const char* oldName, 2877 NodeID remoteNewDirID, const char* name, const EntryInfo* entryInfo, 2878 int64 revision) 2879 { 2880 AutoLocker<Locker> locker(fLock); 2881 2882 _EntryRemoved(remoteOldDirID, oldName, revision); 2883 _EntryCreated(remoteNewDirID, name, entryInfo, revision); 2884 } 2885 2886 // _Walk 2887 status_t 2888 ShareVolume::_Walk(NodeID remoteDirID, const char* entryName, bool resolveLink, 2889 WalkReply** _reply) 2890 { 2891 // prepare the request 2892 WalkRequest request; 2893 request.volumeID = fID; 2894 request.nodeID = remoteDirID; 2895 request.name.SetTo(entryName); 2896 request.resolveLink = resolveLink; 2897 2898 // send the request 2899 WalkReply* reply; 2900 status_t error = SendRequest(fConnection, &request, &reply); 2901 if (error != B_OK) 2902 RETURN_ERROR(error); 2903 ObjectDeleter<Request> replyDeleter(reply); 2904 if (reply->error != B_OK) 2905 RETURN_ERROR(reply->error); 2906 2907 replyDeleter.Detach(); 2908 *_reply = reply; 2909 return B_OK; 2910 } 2911 2912 // _MultiWalk 2913 status_t 2914 ShareVolume::_MultiWalk(RequestMemberArray<EntryInfo>& _entryInfos, 2915 MultiWalkReply** _reply) 2916 { 2917 int32 count = _entryInfos.CountElements(); 2918 if (!_reply || count == 0) 2919 return B_BAD_VALUE; 2920 2921 EntryInfo* entryInfos = _entryInfos.GetElements(); 2922 2923 // prepare the request 2924 MultiWalkRequest request; 2925 request.volumeID = fID; 2926 request.nodeID = entryInfos[0].directoryID; 2927 2928 // add the names 2929 for (int32 i = 0; i < count; i++) { 2930 StringData name; 2931 name.SetTo(entryInfos[i].name.GetString()); 2932 2933 status_t error = request.names.Append(name); 2934 if (error != B_OK) 2935 return error; 2936 } 2937 2938 // send the request 2939 MultiWalkReply* reply; 2940 status_t error = SendRequest(fConnection, &request, &reply); 2941 if (error != B_OK) 2942 RETURN_ERROR(error); 2943 ObjectDeleter<Request> replyDeleter(reply); 2944 if (reply->error != B_OK) 2945 RETURN_ERROR(reply->error); 2946 2947 replyDeleter.Detach(); 2948 *_reply = reply; 2949 return B_OK; 2950 } 2951 2952 // _Close 2953 status_t 2954 ShareVolume::_Close(int32 cookie) 2955 { 2956 if (!_EnsureShareMounted()) 2957 return ERROR_NOT_CONNECTED; 2958 2959 // prepare the request 2960 CloseRequest request; 2961 request.volumeID = fID; 2962 request.cookie = cookie; 2963 // send the request 2964 CloseReply* reply; 2965 status_t error = SendRequest(fConnection, &request, &reply); 2966 if (error != B_OK) 2967 RETURN_ERROR(error); 2968 ObjectDeleter<Request> replyDeleter(reply); 2969 if (reply->error != B_OK) 2970 RETURN_ERROR(reply->error); 2971 return B_OK; 2972 } 2973 2974 // _GetConnectionState 2975 // 2976 // Must not be called with fLock being held! 2977 uint32 2978 ShareVolume::_GetConnectionState() 2979 { 2980 AutoLocker<Locker> _(fMountLock); 2981 return fConnectionState; 2982 } 2983 2984 // _IsConnected 2985 // 2986 // Must not be called with fLock being held! 2987 bool 2988 ShareVolume::_IsConnected() 2989 { 2990 return (_GetConnectionState() == CONNECTION_READY); 2991 } 2992 2993 // _EnsureShareMounted 2994 // 2995 // Must not be called with fLock being held! 2996 bool 2997 ShareVolume::_EnsureShareMounted() 2998 { 2999 AutoLocker<Locker> _(fMountLock); 3000 if (fConnectionState == CONNECTION_NOT_INITIALIZED) 3001 _MountShare(); 3002 3003 return (fConnectionState == CONNECTION_READY); 3004 } 3005 3006 // _MountShare 3007 // 3008 // fMountLock must be held. 3009 status_t 3010 ShareVolume::_MountShare() 3011 { 3012 // get references to the server and share info 3013 AutoLocker<Locker> locker(fLock); 3014 BReference<ExtendedServerInfo> serverInfoReference(fServerInfo); 3015 BReference<ExtendedShareInfo> shareInfoReference(fShareInfo); 3016 ExtendedServerInfo* serverInfo = fServerInfo; 3017 ExtendedShareInfo* shareInfo = fShareInfo; 3018 locker.Unlock(); 3019 3020 // get server address as string 3021 HashString serverAddressString; 3022 status_t error = serverInfo->GetAddress().GetString(&serverAddressString, 3023 false); 3024 if (error != B_OK) 3025 return error; 3026 const char* server = serverAddressString.GetString(); 3027 3028 // get the server name 3029 const char* serverName = serverInfo->GetServerName(); 3030 if (serverName && strlen(serverName) == 0) 3031 serverName = NULL; 3032 3033 // get the share name 3034 const char* share = shareInfo->GetShareName(); 3035 3036 PRINT("ShareVolume::_MountShare(%s, %s)\n", server, share); 3037 // init a connection to the authentication server 3038 AuthenticationServer authenticationServer; 3039 error = authenticationServer.InitCheck(); 3040 if (error != B_OK) 3041 RETURN_ERROR(error); 3042 3043 // get the server connection 3044 fConnectionState = CONNECTION_CLOSED; 3045 if (!fServerConnection) { 3046 status_t error = fServerConnectionProvider->GetServerConnection( 3047 &fServerConnection); 3048 if (error != B_OK) 3049 return error; 3050 fConnection = fServerConnection->GetRequestConnection(); 3051 } 3052 3053 // the mount loop 3054 bool badPassword = false; 3055 MountReply* reply = NULL; 3056 do { 3057 // get the user and password from the authentication server 3058 char user[kUserBufferSize]; 3059 char password[kPasswordBufferSize]; 3060 bool cancelled; 3061 error = authenticationServer.GetAuthentication("netfs", 3062 (serverName ? serverName : server), share, 3063 fVolumeManager->GetMountUID(), badPassword, 3064 &cancelled, user, sizeof(user), password, sizeof(password)); 3065 if (cancelled || error != B_OK) 3066 RETURN_ERROR(error); 3067 3068 // prepare the request 3069 MountRequest request; 3070 request.share.SetTo(share); 3071 request.user.SetTo(user); 3072 request.password.SetTo(password); 3073 3074 // send the request 3075 error = SendRequest(fConnection, &request, &reply); 3076 if (error != B_OK) 3077 RETURN_ERROR(error); 3078 ObjectDeleter<Request> replyDeleter(reply); 3079 3080 // if no permission, try again 3081 badPassword = reply->noPermission; 3082 if (!badPassword) { 3083 if (reply->error != B_OK) 3084 RETURN_ERROR(reply->error); 3085 fSharePermissions = reply->sharePermissions; 3086 } 3087 } while (badPassword); 3088 3089 AutoLocker<Locker> _(fLock); 3090 3091 fID = reply->volumeID; 3092 3093 // update the root node and enter its ID 3094 fRootNode->Update(reply->nodeInfo); 3095 3096 // put the IDs into local map 3097 error = fLocalNodeIDs->Put(fRootNode->GetRemoteID(), fRootNode->GetID()); 3098 if (error != B_OK) 3099 RETURN_ERROR(error); 3100 3101 // put the IDs into remote map 3102 error = fRemoteNodeIDs->Put(fRootNode->GetID(), fRootNode->GetRemoteID()); 3103 if (error != B_OK) { 3104 fLocalNodeIDs->Remove(fRootNode->GetRemoteID()); 3105 RETURN_ERROR(error); 3106 } 3107 PRINT("ShareVolume::_MountShare(): root node: local: %" B_PRIdINO 3108 ", remote: (%" B_PRIdDEV ", %" B_PRIdINO ")\n", fRootNode->GetID(), 3109 fRootNode->GetRemoteID().volumeID, 3110 fRootNode->GetRemoteID().nodeID); 3111 3112 // Add ourselves to the server connection, so that we can receive 3113 // node monitoring events. There a race condition: We might already 3114 // have missed events for the root node. 3115 error = fServerConnection->AddVolume(this); 3116 if (error != B_OK) { 3117 _RemoveLocalNodeID(fRootNode->GetID()); 3118 return error; 3119 } 3120 3121 fConnectionState = CONNECTION_READY; 3122 return B_OK; 3123 } 3124 3125