1 // VolumeManager.cpp 2 3 #include "VolumeManager.h" 4 5 #include <new> 6 7 #include <sys/stat.h> 8 9 #include <AutoDeleter.h> 10 #include <Entry.h> 11 #include <fs_info.h> 12 #include <fs_query.h> 13 #include <HashMap.h> 14 #include <NodeMonitor.h> 15 #include <Volume.h> 16 17 #include "ClientVolume.h" 18 #include "DebugSupport.h" 19 #include "Directory.h" 20 #include "Entry.h" 21 #include "FDManager.h" 22 #include "NodeHandle.h" 23 #include "Path.h" 24 #include "QueryDomain.h" 25 #include "Volume.h" 26 27 // TODO: We should filter recent events at some point. Otherwise we'll end up 28 // with one event of each kind for each entry/node. 29 30 const bigtime_t kRecentEventLifeTime = 100000; // 0.1 s 31 32 // QueryHandler 33 class VolumeManager::QueryHandler : public BHandler, public QueryListener, 34 public BReferenceable { 35 public: 36 QueryHandler(NodeMonitorListener* listener, QueryDomain* queryDomain, 37 QueryHandle* handle) 38 : 39 BHandler(), 40 QueryListener(), 41 BReferenceable(), 42 fListener(listener), 43 fQueryDomain(queryDomain), 44 fHandle(handle) 45 { 46 } 47 48 QueryDomain* GetQueryDomain() const 49 { 50 return fQueryDomain; 51 } 52 53 QueryHandle* GetQueryHandle() const 54 { 55 return fHandle; 56 } 57 58 virtual void MessageReceived(BMessage* message) 59 { 60 switch (message->what) { 61 case B_QUERY_UPDATE: 62 { 63 NodeMonitoringEvent* event = NULL; 64 int32 opcode; 65 if (message->FindInt32("opcode", &opcode) == B_OK) { 66 switch (opcode) { 67 case B_ENTRY_CREATED: 68 event = new(std::nothrow) EntryCreatedEvent; 69 break; 70 case B_ENTRY_REMOVED: 71 event = new(std::nothrow) EntryRemovedEvent; 72 break; 73 case B_ENTRY_MOVED: 74 event = new(std::nothrow) EntryMovedEvent; 75 break; 76 } 77 } 78 if (event) { 79 event->queryHandler = this; 80 AcquireReference(); 81 if (event->Init(message) == B_OK) 82 fListener->ProcessNodeMonitoringEvent(event); 83 else 84 delete event; 85 } 86 break; 87 } 88 default: 89 BHandler::MessageReceived(message); 90 } 91 } 92 93 virtual void QueryHandleClosed(QueryHandle* handle) 94 { 95 BLooper* looper = Looper(); 96 if (looper && looper->Lock()) { 97 looper->RemoveHandler(this); 98 looper->Unlock(); 99 } 100 handle->SetQueryListener(NULL); 101 ReleaseReference(); 102 } 103 104 private: 105 NodeMonitorListener* fListener; 106 QueryDomain* fQueryDomain; 107 QueryHandle* fHandle; 108 }; 109 110 // VolumeMap 111 struct VolumeManager::VolumeMap : HashMap<HashKey32<dev_t>, Volume*> { 112 }; 113 114 // ClientVolumeMap 115 struct VolumeManager::ClientVolumeMap 116 : HashMap<HashKey32<int32>, ClientVolume*> { 117 }; 118 119 // private BeOS syscalls to set the FD and node monitor slot limits 120 extern "C" int _kset_fd_limit_(int num); 121 extern "C" int _kset_mon_limit_(int num); 122 123 124 // EntryCreatedEventMap 125 struct VolumeManager::EntryCreatedEventMap 126 : HashMap<EntryRef, EntryCreatedEvent*> { 127 }; 128 129 // EntryRemovedEventMap 130 struct VolumeManager::EntryRemovedEventMap 131 : HashMap<EntryRef, EntryRemovedEvent*> { 132 }; 133 134 // EntryMovedEventKey 135 struct EntryMovedEventKey : public EntryRef { 136 EntryMovedEventKey() 137 { 138 } 139 140 EntryMovedEventKey(dev_t volumeID, ino_t fromDirectory, 141 const char* fromName, ino_t toDirectory, const char* toName) 142 : EntryRef(volumeID, fromDirectory, fromName), 143 toDirectory(toDirectory), 144 toName(toName) 145 { 146 147 } 148 149 uint32 GetHashCode() const 150 { 151 uint32 hash = EntryRef::GetHashCode(); 152 hash = 17 * hash + (uint32)(toDirectory >> 32); 153 hash = 17 * hash + (uint32)toDirectory; 154 hash = 17 * hash + string_hash(toName.GetString()); 155 return hash; 156 } 157 158 bool operator==(const EntryMovedEventKey& other) const 159 { 160 return (*(const EntryRef*)this) == other 161 && toDirectory == other.toDirectory 162 && toName == other.toName; 163 } 164 165 bool operator!=(const EntryMovedEventKey& other) const 166 { 167 return !(*this == other); 168 } 169 170 ino_t toDirectory; 171 HashString toName; 172 }; 173 174 // EntryMovedEventMap 175 struct VolumeManager::EntryMovedEventMap : HashMap<EntryRef, EntryMovedEvent*> { 176 }; 177 178 // NodeStatChangedEventMap 179 struct VolumeManager::NodeStatChangedEventMap 180 : HashMap<NodeRef, StatChangedEvent*> { 181 }; 182 183 typedef EntryRef AttributeRef; 184 185 // NodeAttributeChangedEventMap 186 struct VolumeManager::NodeAttributeChangedEventMap 187 : HashMap<AttributeRef, AttributeChangedEvent*> { 188 }; 189 190 191 // #pragma mark - 192 193 // constructor 194 VolumeManager::VolumeManager() 195 : fLock("volume manager"), 196 fVolumes(NULL), 197 fRootVolume(NULL), 198 fClientVolumes(NULL), 199 fNodeMonitor(NULL), 200 fNodeMonitoringProcessor(-1), 201 fNodeMonitoringEvents(), 202 fRecentNodeMonitoringEvents(), 203 fEntryCreatedEvents(NULL), 204 fEntryRemovedEvents(NULL), 205 fEntryMovedEvents(NULL), 206 fNodeStatChangedEvents(NULL), 207 fNodeAttributeChangedEvents(NULL), 208 fRevision(0), 209 fTerminating(false) 210 { 211 } 212 213 // destructor 214 VolumeManager::~VolumeManager() 215 { 216 // terminate the node monitor and the node monitoring processor 217 fTerminating = true; 218 if (fNodeMonitor && fNodeMonitor->Lock()) 219 fNodeMonitor->Quit(); 220 fNodeMonitoringEvents.Close(true); 221 if (fNodeMonitoringProcessor >= 0) { 222 int32 result; 223 wait_for_thread(fNodeMonitoringProcessor, &result); 224 } 225 226 // delete all events 227 // entry created events 228 for (EntryCreatedEventMap::Iterator it = fEntryCreatedEvents->GetIterator(); 229 it.HasNext();) { 230 it.Next().value->ReleaseReference(); 231 } 232 delete fEntryCreatedEvents; 233 234 // entry removed events 235 for (EntryRemovedEventMap::Iterator it = fEntryRemovedEvents->GetIterator(); 236 it.HasNext();) { 237 it.Next().value->ReleaseReference(); 238 } 239 delete fEntryRemovedEvents; 240 241 // entry moved events 242 for (EntryMovedEventMap::Iterator it = fEntryMovedEvents->GetIterator(); 243 it.HasNext();) { 244 it.Next().value->ReleaseReference(); 245 } 246 delete fEntryMovedEvents; 247 248 // stat changed events 249 for (NodeStatChangedEventMap::Iterator it 250 = fNodeStatChangedEvents->GetIterator(); 251 it.HasNext();) { 252 it.Next().value->ReleaseReference(); 253 } 254 delete fNodeStatChangedEvents; 255 256 // attribute changed events 257 for (NodeAttributeChangedEventMap::Iterator it 258 = fNodeAttributeChangedEvents->GetIterator(); 259 it.HasNext();) { 260 it.Next().value->ReleaseReference(); 261 } 262 delete fNodeAttributeChangedEvents; 263 264 delete fClientVolumes; 265 266 // delete the volumes 267 for (VolumeMap::Iterator it = fVolumes->GetIterator(); it.HasNext();) { 268 Volume* volume = it.Next().value; 269 delete volume; 270 } 271 delete fVolumes; 272 } 273 274 // Init 275 status_t 276 VolumeManager::Init() 277 { 278 // check node monitoring message queue 279 status_t error = fNodeMonitoringEvents.InitCheck(); 280 if (error != B_OK) 281 return error; 282 283 // entry created event map 284 fEntryCreatedEvents = new(std::nothrow) EntryCreatedEventMap; 285 if (!fEntryCreatedEvents) 286 return B_NO_MEMORY; 287 288 // entry removed event map 289 fEntryRemovedEvents = new(std::nothrow) EntryRemovedEventMap; 290 if (!fEntryRemovedEvents) 291 return B_NO_MEMORY; 292 293 // entry moved event map 294 fEntryMovedEvents = new(std::nothrow) EntryMovedEventMap; 295 if (!fEntryMovedEvents) 296 return B_NO_MEMORY; 297 298 // node stat changed event map 299 fNodeStatChangedEvents = new(std::nothrow) NodeStatChangedEventMap; 300 if (!fNodeStatChangedEvents) 301 return B_NO_MEMORY; 302 303 // node attribute changed event map 304 fNodeAttributeChangedEvents = new(std::nothrow) NodeAttributeChangedEventMap; 305 if (!fNodeAttributeChangedEvents) 306 return B_NO_MEMORY; 307 308 // create the node monitor 309 fNodeMonitor = new(std::nothrow) NodeMonitor(this); 310 if (!fNodeMonitor) 311 return B_NO_MEMORY; 312 313 // create the volume map 314 fVolumes = new(std::nothrow) VolumeMap; 315 if (!fVolumes) 316 return B_NO_MEMORY; 317 if (fVolumes->InitCheck() != B_OK) 318 return fVolumes->InitCheck(); 319 320 // create the client volume map 321 fClientVolumes = new(std::nothrow) ClientVolumeMap; 322 if (!fClientVolumes) 323 return B_NO_MEMORY; 324 if (fClientVolumes->InitCheck() != B_OK) 325 return fClientVolumes->InitCheck(); 326 327 // start the node monitor 328 thread_id monitorThread = fNodeMonitor->Run(); 329 if (monitorThread < 0) { 330 delete fNodeMonitor; 331 fNodeMonitor = NULL; 332 return monitorThread; 333 } 334 335 // create all volumes 336 int32 cookie = 0; 337 dev_t volumeID; 338 while ((volumeID = next_dev(&cookie)) >= 0) 339 _AddVolume(volumeID); 340 341 // get the root volume 342 volumeID = dev_for_path("/"); 343 if (volumeID < 0) 344 return volumeID; 345 fRootVolume = GetVolume(volumeID, true); 346 if (!fRootVolume) 347 return B_ERROR; 348 349 // spawn the node monitoring message processor 350 fNodeMonitoringProcessor = spawn_thread(&_NodeMonitoringProcessorEntry, 351 "node monitoring processor", B_NORMAL_PRIORITY, this); 352 if (fNodeMonitoringProcessor < 0) 353 return fNodeMonitoringProcessor; 354 resume_thread(fNodeMonitoringProcessor); 355 356 return B_OK; 357 } 358 359 // GetRootVolume 360 Volume* 361 VolumeManager::GetRootVolume() const 362 { 363 return fRootVolume; 364 } 365 366 // AddClientVolume 367 status_t 368 VolumeManager::AddClientVolume(ClientVolume* clientVolume) 369 { 370 if (!clientVolume) 371 return B_BAD_VALUE; 372 373 return fClientVolumes->Put(clientVolume->GetID(), clientVolume); 374 } 375 376 // RemoveClientVolume 377 void 378 VolumeManager::RemoveClientVolume(ClientVolume* clientVolume) 379 { 380 if (!clientVolume) 381 return; 382 383 fClientVolumes->Remove(clientVolume->GetID()); 384 } 385 386 // CreateDefault 387 status_t 388 VolumeManager::CreateDefault() 389 { 390 if (sManager) 391 return B_OK; 392 393 VolumeManager* manager = new(std::nothrow) VolumeManager; 394 if (!manager) 395 return B_NO_MEMORY; 396 397 status_t error = manager->Init(); 398 if (error != B_OK) { 399 delete manager; 400 return error; 401 } 402 403 sManager = manager; 404 return B_OK; 405 } 406 407 // DeleteDefault 408 void 409 VolumeManager::DeleteDefault() 410 { 411 if (sManager) { 412 delete sManager; 413 sManager = NULL; 414 } 415 } 416 417 // GetDefault 418 VolumeManager* 419 VolumeManager::GetDefault() 420 { 421 return sManager; 422 } 423 424 // Lock 425 bool 426 VolumeManager::Lock() 427 { 428 bool alreadyLocked = fLock.IsLocked(); 429 430 bool success = fLock.Lock(); 431 432 // If locking was successful and we didn't have a lock before, we increment 433 // the revision. 434 if (success && !alreadyLocked) 435 fRevision++; 436 437 return success; 438 } 439 440 // Unlock 441 void 442 VolumeManager::Unlock() 443 { 444 return fLock.Unlock(); 445 } 446 447 // GetRevision 448 int64 449 VolumeManager::GetRevision() const 450 { 451 return fRevision; 452 } 453 454 // GetVolume 455 Volume* 456 VolumeManager::GetVolume(dev_t volumeID, bool add) 457 { 458 Volume* volume = fVolumes->Get(volumeID); 459 if (!volume && add) 460 _AddVolume(volumeID, &volume); 461 462 return volume; 463 } 464 465 466 // #pragma mark - 467 468 // AddNode 469 status_t 470 VolumeManager::AddNode(Node* node) 471 { 472 if (!node || !node->GetVolume()) 473 return B_BAD_VALUE; 474 475 status_t error = node->GetVolume()->AddNode(node); 476 477 // start watching the node 478 if (error == B_OK) 479 fNodeMonitor->StartWatching(node->GetNodeRef()); 480 481 return error; 482 } 483 484 // RemoveNode 485 void 486 VolumeManager::RemoveNode(Node* node) 487 { 488 if (!node) 489 return; 490 491 // if the node is a directory, we remove all its entries first 492 if (Directory* directory = dynamic_cast<Directory*>(node)) { 493 while (Entry* entry = directory->GetFirstEntry()) { 494 RemoveEntry(entry); 495 delete entry; 496 } 497 } 498 499 // remove all referring entries 500 while (Entry* entry = node->GetFirstReferringEntry()) 501 RemoveEntry(entry); 502 503 // remove the node from the volume 504 if (node->GetVolume()) 505 node->GetVolume()->RemoveNode(node); 506 507 // stop watching the node 508 fNodeMonitor->StopWatching(node->GetNodeRef()); 509 } 510 511 // GetNode 512 Node* 513 VolumeManager::GetNode(dev_t volumeID, ino_t nodeID) 514 { 515 if (Volume* volume = GetVolume(volumeID)) 516 return volume->GetNode(nodeID); 517 return NULL; 518 } 519 520 // LoadNode 521 status_t 522 VolumeManager::LoadNode(const struct stat& st, Node** _node) 523 { 524 Node* node = GetNode(st.st_dev, st.st_ino); 525 if (!node) { 526 // node not known yet: create it 527 528 // get the volume 529 Volume* volume = GetVolume(st.st_dev, true); 530 if (!volume) 531 return B_BAD_VALUE; 532 533 // create the node 534 if (S_ISDIR(st.st_mode)) 535 node = new(std::nothrow) Directory(volume, st); 536 else 537 node = new(std::nothrow) Node(volume, st); 538 if (!node) 539 return B_NO_MEMORY; 540 541 // add it 542 status_t error = AddNode(node); 543 if (error != B_OK) { 544 delete node; 545 return error; 546 } 547 } 548 549 if (_node) 550 *_node = node; 551 return B_OK; 552 } 553 554 555 // #pragma mark - 556 557 // GetDirectory 558 Directory* 559 VolumeManager::GetDirectory(dev_t volumeID, ino_t nodeID) 560 { 561 return dynamic_cast<Directory*>(GetNode(volumeID, nodeID)); 562 } 563 564 // GetRootDirectory 565 Directory* 566 VolumeManager::GetRootDirectory() const 567 { 568 return (fRootVolume ? fRootVolume->GetRootDirectory() : NULL); 569 } 570 571 // GetParentDirectory 572 Directory* 573 VolumeManager::GetParentDirectory(Directory* directory) 574 { 575 if (!directory) 576 return NULL; 577 578 // get ".." entry 579 Entry* parentEntry; 580 if (LoadEntry(directory->GetVolumeID(), directory->GetID(), "..", true, 581 &parentEntry) != B_OK) { 582 return NULL; 583 } 584 585 return dynamic_cast<Directory*>(parentEntry->GetNode()); 586 } 587 588 // LoadDirectory 589 status_t 590 VolumeManager::LoadDirectory(dev_t volumeID, ino_t directoryID, 591 Directory** _directory) 592 { 593 // try to get the node 594 Node* node = GetNode(volumeID, directoryID); 595 bool newNode = false; 596 if (!node) { 597 // directory not yet loaded: stat it 598 NoAllocEntryRef entryRef(volumeID, directoryID, "."); 599 struct stat st; 600 BEntry bEntry; 601 status_t error = FDManager::SetEntry(&bEntry, &entryRef); 602 if (error == B_OK) 603 error = bEntry.GetStat(&st); 604 if (error != B_OK) 605 return error; 606 607 // load the node 608 error = LoadNode(st, &node); 609 if (error != B_OK) 610 return error; 611 612 newNode = true; 613 } 614 615 // check, if the node is a directory 616 Directory* directory = dynamic_cast<Directory*>(node); 617 if (!directory) 618 return B_NOT_A_DIRECTORY; 619 620 if (newNode) 621 CompletePathToRoot(directory); 622 623 if (_directory) 624 *_directory = directory; 625 return B_OK; 626 } 627 628 629 // #pragma mark - 630 631 // AddEntry 632 status_t 633 VolumeManager::AddEntry(Entry* entry) 634 { 635 if (!entry || !entry->GetVolume() || !entry->GetDirectory() 636 || ! entry->GetNode()) { 637 return B_BAD_VALUE; 638 } 639 640 // add the entry to the volume 641 status_t error = entry->GetVolume()->AddEntry(entry); 642 if (error != B_OK) 643 return error; 644 645 // add the entry to its directory and node 646 entry->GetDirectory()->AddEntry(entry); 647 entry->GetNode()->AddReferringEntry(entry); 648 649 //PRINT(("VolumeManager::AddEntry(): %ld, %lld, `%s', dir: %p, " 650 //"entry count: %ld\n", entry->GetVolumeID(), entry->GetDirectoryID(), 651 //entry->GetName(), entry->GetDirectory(), 652 //entry->GetDirectory()->CountEntries())); 653 654 return B_OK; 655 } 656 657 // RemoveEntry 658 void 659 VolumeManager::RemoveEntry(Entry* entry) 660 { 661 if (entry) { 662 // remove the entry from the volume 663 if (entry->GetVolume()) 664 entry->GetVolume()->RemoveEntry(entry); 665 666 // remove the entry from the directory and its node 667 entry->GetDirectory()->RemoveEntry(entry); 668 entry->GetNode()->RemoveReferringEntry(entry); 669 670 //PRINT(("VolumeManager::RemoveEntry(): %ld, %lld, `%s', dir: %p, " 671 //"entry count: %ld\n", entry->GetVolumeID(), entry->GetDirectoryID(), 672 //entry->GetName(), entry->GetDirectory(), 673 //entry->GetDirectory()->CountEntries())); 674 } 675 } 676 677 // DeleteEntry 678 void 679 VolumeManager::DeleteEntry(Entry* entry, bool keepNode) 680 { 681 if (!entry) 682 return; 683 684 Node* node = entry->GetNode(); 685 686 // remove the entry 687 RemoveEntry(entry); 688 delete entry; 689 690 // remove the node, if it doesn't have any more actual referring entries 691 if (!keepNode && !node->GetActualReferringEntry()) { 692 RemoveNode(node); 693 if (node != node->GetVolume()->GetRootDirectory()) 694 delete node; 695 } 696 } 697 698 // GetEntry 699 Entry* 700 VolumeManager::GetEntry(dev_t volumeID, ino_t directoryID, const char* name) 701 { 702 if (Volume* volume = GetVolume(volumeID)) 703 return volume->GetEntry(directoryID, name); 704 return NULL; 705 } 706 707 // GetEntry 708 Entry* 709 VolumeManager::GetEntry(const entry_ref& ref) 710 { 711 return GetEntry(ref.device, ref.directory, ref.name); 712 } 713 714 // LoadEntry 715 status_t 716 VolumeManager::LoadEntry(dev_t volumeID, ino_t directoryID, const char* name, 717 bool loadDir, Entry** _entry) 718 { 719 Entry* entry = GetEntry(volumeID, directoryID, name); 720 if (!entry) { 721 // entry not known yet: create it 722 PRINT("VolumeManager::LoadEntry(%ld, %lld, `%s')\n", volumeID, 723 directoryID, name); 724 725 // get the volume 726 Volume* volume = GetVolume(volumeID, true); 727 if (!volume) 728 return B_BAD_VALUE; 729 730 // get the directory 731 status_t error = B_OK; 732 Directory* directory = GetDirectory(volumeID, directoryID); 733 if (!directory) { 734 if (!loadDir) 735 return B_ENTRY_NOT_FOUND; 736 737 //PRINT((" loading directory...\n")); 738 // load the directory 739 error = LoadDirectory(volumeID, directoryID, &directory); 740 if (error != B_OK) 741 return error; 742 } 743 744 //PRINT((" opening BNode...\n")); 745 // stat the entry 746 NoAllocEntryRef entryRef(volumeID, directoryID, name); 747 struct stat st; 748 BNode bNode; 749 error = bNode.SetTo(&entryRef); 750 //PRINT((" stat()ing BNode...\n")); 751 if (error == B_OK) 752 error = bNode.GetStat(&st); 753 if (error != B_OK) 754 return error; 755 756 //PRINT((" loading node...\n")); 757 // load the node 758 Node* node; 759 error = LoadNode(st, &node); 760 if (error != B_OK) 761 return error; 762 763 //PRINT((" creating and adding entry...\n")); 764 // create the entry 765 entry = new(std::nothrow) Entry(volume, directory, name, node); 766 if (!entry) 767 return B_NO_MEMORY; 768 769 // add it 770 error = AddEntry(entry); 771 if (error != B_OK) { 772 delete entry; 773 return error; 774 } 775 //PRINT((" adding entry done\n")); 776 } 777 778 if (_entry) 779 *_entry = entry; 780 return B_OK; 781 } 782 783 784 // #pragma mark - 785 786 // OpenQuery 787 status_t 788 VolumeManager::OpenQuery(QueryDomain* queryDomain, const char* queryString, 789 uint32 flags, port_id remotePort, int32 remoteToken, QueryHandle** handle) 790 { 791 if (!queryDomain || !queryString || !handle) 792 return B_BAD_VALUE; 793 bool liveQuery = (flags & B_LIVE_QUERY); 794 PRINT("VolumeManager::OpenQuery(%p, \"%s\", 0x%lx, %ld, %ld)\n", 795 queryDomain, queryString, flags, remotePort, remoteToken); 796 797 // allocate the handle 798 QueryHandle* queryHandle = new(std::nothrow) QueryHandle(remotePort, 799 remoteToken); 800 if (!queryHandle) 801 return B_NO_MEMORY; 802 ObjectDeleter<QueryHandle> handleDeleter(queryHandle); 803 804 // allocate a query handler, if this is a live query 805 QueryHandler* queryHandler = NULL; 806 if (liveQuery) { 807 queryHandler = new(std::nothrow) QueryHandler(this, queryDomain, 808 queryHandle); 809 if (!queryHandler) 810 return B_NO_MEMORY; 811 812 fNodeMonitor->Lock(); 813 fNodeMonitor->AddHandler(queryHandler); 814 fNodeMonitor->Unlock(); 815 queryHandle->SetQueryListener(queryHandler); 816 } 817 818 // iterate through the volumes and create a query for each one 819 // supporting queries 820 for (VolumeMap::Iterator it = fVolumes->GetIterator(); it.HasNext();) { 821 Volume* volume = it.Next().value; 822 if (!volume->KnowsQuery()) 823 continue; 824 825 // The volume should either be contained by the client volume or 826 // the other way around. Otherwise they are located in different 827 // branches of the FS tree and don't have common nodes. 828 if (!queryDomain->QueryDomainIntersectsWith(volume)) 829 continue; 830 PRINT("VolumeManager::OpenQuery(): adding Query for volume %ld" 831 "\n", volume->GetID()); 832 833 // create the query for this volume 834 BVolume bVolume(volume->GetID()); 835 Query* query = new(std::nothrow) Query; 836 if (!query) 837 return B_NO_MEMORY; 838 839 // init the query 840 ObjectDeleter<Query> queryDeleter(query); 841 status_t error = query->SetVolume(&bVolume); 842 if (error != B_OK) 843 return error; 844 error = query->SetPredicate(queryString); 845 if (error != B_OK) 846 return error; 847 if (liveQuery) { 848 error = query->SetTarget(queryHandler); 849 if (error != B_OK) 850 return error; 851 } 852 853 // fetch 854 error = query->Fetch(); 855 if (error != B_OK) 856 return error; 857 858 queryHandle->AddQuery(query); 859 queryDeleter.Detach(); 860 } 861 862 *handle = queryHandle; 863 handleDeleter.Detach(); 864 return B_OK; 865 } 866 867 // CompletePathToRoot 868 status_t 869 VolumeManager::CompletePathToRoot(Directory* directory) 870 { 871 if (!directory) 872 return B_BAD_VALUE; 873 874 while (directory != GetRootDirectory()) { 875 // if the dir has a valid entry referring to it, we've nothing to do 876 if (directory->GetActualReferringEntry()) 877 return B_OK; 878 879 // get a proper entry_ref 880 BEntry bEntry; 881 entry_ref entryRef(directory->GetVolumeID(), directory->GetID(), "."); 882 status_t error = FDManager::SetEntry(&bEntry, &entryRef); 883 if (error == B_OK) 884 error = bEntry.GetRef(&entryRef); 885 if (error != B_OK) 886 return error; 887 888 // if the entry is already loaded, we're done 889 if (GetEntry(entryRef)) 890 return B_OK; 891 892 // the entry is not yet known -- load it 893 Entry* entry; 894 error = LoadEntry(entryRef.device, entryRef.directory, entryRef.name, 895 true, &entry); 896 if (error != B_OK) 897 return error; 898 899 // get the entry's parent dir and enter the next round 900 directory = entry->GetDirectory(); 901 } 902 903 return B_OK; 904 } 905 906 // GetPath 907 status_t 908 VolumeManager::GetPath(Entry* entry, Path* path) 909 { 910 // get directory path 911 status_t error = GetPath(entry->GetDirectory(), path); 912 if (error != B_OK) 913 return error; 914 915 // append the entry name 916 return path->Append(entry->GetName()); 917 } 918 919 // GetPath 920 status_t 921 VolumeManager::GetPath(Node* node, Path* path) 922 { 923 if (node == GetRootDirectory()) 924 return path->SetTo("/"); 925 926 // get an entry referring to the node 927 Entry* entry = node->GetActualReferringEntry(); 928 if (!entry) { 929 // if the node is a directory, we complete the path to the root and 930 // try again 931 if (Directory* directory = dynamic_cast<Directory*>(node)) { 932 CompletePathToRoot(directory); 933 entry = node->GetActualReferringEntry(); 934 } 935 936 if (!entry) 937 return B_ERROR; 938 } 939 940 return GetPath(entry, path); 941 } 942 943 // DirectoryContains 944 bool 945 VolumeManager::DirectoryContains(Directory* directory, Entry* entry) 946 { 947 if (!directory || !entry) 948 return false; 949 950 return DirectoryContains(directory, entry->GetDirectory(), true); 951 } 952 953 // DirectoryContains 954 bool 955 VolumeManager::DirectoryContains(Directory* directory, Directory* descendant, 956 bool reflexive) 957 { 958 if (!directory || !descendant) 959 return false; 960 961 // a directory contains itself, just as defined by the caller 962 if (directory == descendant) 963 return reflexive; 964 965 // if the directory is the root directory, it contains everything 966 Directory* rootDir = GetRootDirectory(); 967 if (directory == rootDir) 968 return true; 969 970 // recursively get the descendant's parent dir until reaching the root dir 971 // or the given dir 972 while (descendant != rootDir) { 973 descendant = GetParentDirectory(descendant); 974 if (!descendant) 975 return false; 976 977 if (descendant == directory) 978 return true; 979 } 980 981 return false; 982 } 983 984 // DirectoryContains 985 bool 986 VolumeManager::DirectoryContains(Directory* directory, Node* descendant, 987 bool reflexive) 988 { 989 if (!directory || !descendant) 990 return false; 991 992 // if the node is a directory, let the other version do the job 993 if (Directory* dir = dynamic_cast<Directory*>(descendant)) 994 return DirectoryContains(directory, dir, reflexive); 995 996 // iterate through the referring entries and check, if the directory 997 // contains any of them 998 for (Entry* entry = descendant->GetFirstReferringEntry(); 999 entry; 1000 entry = descendant->GetNextReferringEntry(entry)) { 1001 if (DirectoryContains(directory, entry)) 1002 return true; 1003 } 1004 1005 return false; 1006 } 1007 1008 1009 // #pragma mark - 1010 1011 // ProcessNodeMonitoringEvent 1012 void 1013 VolumeManager::ProcessNodeMonitoringEvent(NodeMonitoringEvent* event) 1014 { 1015 if (fNodeMonitoringEvents.Push(event) != B_OK) 1016 delete event; 1017 } 1018 1019 // _AddVolume 1020 status_t 1021 VolumeManager::_AddVolume(dev_t volumeID, Volume** _volume) 1022 { 1023 if (GetVolume(volumeID)) 1024 return B_OK; 1025 1026 // create the volume 1027 Volume* volume = new(std::nothrow) Volume(volumeID); 1028 if (!volume) 1029 RETURN_ERROR(B_NO_MEMORY); 1030 ObjectDeleter<Volume> volumeDeleter(volume); 1031 status_t error = volume->Init(); 1032 if (error != B_OK) 1033 RETURN_ERROR(error); 1034 1035 // add it 1036 error = fVolumes->Put(volumeID, volume); 1037 if (error != B_OK) 1038 RETURN_ERROR(error); 1039 1040 // add the root node 1041 error = AddNode(volume->GetRootDirectory()); 1042 if (error != B_OK) { 1043 fVolumes->Remove(volumeID); 1044 RETURN_ERROR(error); 1045 } 1046 1047 // complete the root dir path 1048 CompletePathToRoot(volume->GetRootDirectory()); 1049 1050 volumeDeleter.Detach(); 1051 if (_volume) 1052 *_volume = volume; 1053 return B_OK; 1054 } 1055 1056 // _EntryCreated 1057 void 1058 VolumeManager::_EntryCreated(EntryCreatedEvent* event) 1059 { 1060 // get the directory 1061 Directory* directory = GetDirectory(event->volumeID, event->directoryID); 1062 if (!directory) 1063 return; 1064 1065 // check, if there is an earlier similar event 1066 bool notify = true; 1067 NoAllocEntryRef ref(event->volumeID, event->directoryID, 1068 event->name.GetString()); 1069 EntryCreatedEvent* oldEvent = fEntryCreatedEvents->Get(ref); 1070 1071 // remove the old event 1072 if (oldEvent) { 1073 fEntryCreatedEvents->Remove(ref); 1074 fRecentNodeMonitoringEvents.Remove(oldEvent); 1075 notify = !_IsRecentEvent(oldEvent); 1076 oldEvent->ReleaseReference(); 1077 } 1078 1079 // add the new event 1080 if (fEntryCreatedEvents->Put(ref, event) == B_OK) { 1081 fRecentNodeMonitoringEvents.Insert(event); 1082 event->AcquireReference(); 1083 } 1084 1085 // if the directory is complete or at least has iterators attached to it, 1086 // we load the entry 1087 if (directory->IsComplete() || directory->HasDirIterators()) { 1088 Entry* entry; 1089 LoadEntry(ref.device, ref.directory, ref.name, false, &entry); 1090 } 1091 1092 // send notifications 1093 if (notify) { 1094 for (ClientVolumeMap::Iterator it = fClientVolumes->GetIterator(); 1095 it.HasNext();) { 1096 ClientVolume* clientVolume = it.Next().value; 1097 if (DirectoryContains(clientVolume->GetRootDirectory(), directory, 1098 true)) { 1099 clientVolume->ProcessNodeMonitoringEvent(event); 1100 } 1101 } 1102 } 1103 } 1104 1105 // _EntryRemoved 1106 void 1107 VolumeManager::_EntryRemoved(EntryRemovedEvent* event, bool keepNode) 1108 { 1109 // get node and directory 1110 Node* node = GetNode(event->nodeVolumeID, event->nodeID); 1111 Directory* directory = GetDirectory(event->volumeID, event->directoryID); 1112 if (!directory) 1113 return; 1114 1115 // find the entry 1116 Entry* entry = NULL; 1117 if (node) { 1118 if (event->name.GetLength() == 0) { 1119 for (entry = node->GetFirstReferringEntry(); 1120 entry; 1121 entry = node->GetNextReferringEntry(entry)) { 1122 if (!entry->Exists()) { 1123 event->name.SetTo(entry->GetName()); 1124 break; 1125 } 1126 } 1127 } else { 1128 entry = GetEntry(directory->GetVolumeID(), directory->GetID(), 1129 event->name.GetString()); 1130 } 1131 } 1132 1133 // check, if there is an earlier similar event 1134 bool notify = true; 1135 NoAllocEntryRef ref(event->volumeID, event->directoryID, 1136 event->name.GetString()); 1137 EntryRemovedEvent* oldEvent = fEntryRemovedEvents->Get(ref); 1138 // TODO: Under BeOS R5 the entry name is not encoded in the 1139 // "entry removed" node monitoring message. If we have seen the entry 1140 // before, we can get the entry nevertheless (see above). Usually we 1141 // get 2 "entry removed" events: One for watching the directory and one 1142 // for watching the node. After the first one has been processed, we've 1143 // forgotten everything about the entry and we won't be able to find out 1144 // the entry's name for the second one. Hence we will never find the 1145 // previous event in the fEntryRemovedEvents map. We should probably 1146 // fall back to using a NodeRef as key under BeOS R5. 1147 1148 // remove the old event 1149 if (oldEvent) { 1150 fEntryRemovedEvents->Remove(ref); 1151 fRecentNodeMonitoringEvents.Remove(oldEvent); 1152 notify = !_IsRecentEvent(oldEvent); 1153 oldEvent->ReleaseReference(); 1154 } 1155 1156 // add the new event 1157 if (fEntryRemovedEvents->Put(ref, event) == B_OK) { 1158 fRecentNodeMonitoringEvents.Insert(event); 1159 event->AcquireReference(); 1160 } 1161 1162 // remove the entry 1163 if (entry) { 1164 RemoveEntry(entry); 1165 delete entry; 1166 } 1167 1168 // remove the node, if it doesn't have any more actual referring entries 1169 if (node && !keepNode && !node->GetActualReferringEntry()) { 1170 RemoveNode(node); 1171 if (node != node->GetVolume()->GetRootDirectory()) 1172 delete node; 1173 } 1174 1175 // send notifications 1176 if (notify) { 1177 NodeRef nodeRef(event->nodeVolumeID, event->nodeID); 1178 for (ClientVolumeMap::Iterator it = fClientVolumes->GetIterator(); 1179 it.HasNext();) { 1180 // We send a notification, if the client volume contains the entry, 1181 // but also, if the removed entry refers to the client volume's 1182 // root. The client connection has a special handling for this 1183 // case. 1184 ClientVolume* clientVolume = it.Next().value; 1185 Directory* rootDir = clientVolume->GetRootDirectory(); 1186 if (DirectoryContains(rootDir, directory, true) 1187 || clientVolume->GetRootNodeRef() == nodeRef) { 1188 clientVolume->ProcessNodeMonitoringEvent(event); 1189 } 1190 } 1191 } 1192 } 1193 1194 // _EntryMoved 1195 void 1196 VolumeManager::_EntryMoved(EntryMovedEvent* event) 1197 { 1198 _CheckVolumeRootMoved(event); 1199 1200 Directory* fromDirectory 1201 = GetDirectory(event->volumeID, event->fromDirectoryID); 1202 Directory* toDirectory 1203 = GetDirectory(event->volumeID, event->toDirectoryID); 1204 Node* node = GetNode(event->nodeVolumeID, event->nodeID); 1205 1206 // we should at least have one of the directories 1207 if (!fromDirectory && !toDirectory) 1208 return; 1209 1210 // find the old entry 1211 Entry* oldEntry = NULL; 1212 if (node) { 1213 if (event->fromName.GetLength() == 0) { 1214 for (oldEntry = node->GetFirstReferringEntry(); 1215 oldEntry; 1216 oldEntry = node->GetNextReferringEntry(oldEntry)) { 1217 if (!oldEntry->Exists()) { 1218 event->fromName.SetTo(oldEntry->GetName()); 1219 break; 1220 } 1221 } 1222 } else { 1223 oldEntry = GetEntry(event->volumeID, event->fromDirectoryID, 1224 event->fromName.GetString()); 1225 } 1226 } 1227 1228 // check, if there is an earlier similar event 1229 bool notify = true; 1230 if (event->fromName.GetLength() > 0) { 1231 EntryMovedEventKey key(event->volumeID, event->fromDirectoryID, 1232 event->fromName.GetString(), event->toDirectoryID, 1233 event->toName.GetString()); 1234 EntryMovedEvent* oldEvent = fEntryMovedEvents->Get(key); 1235 1236 // remove the old event 1237 if (oldEvent) { 1238 fEntryMovedEvents->Remove(key); 1239 fRecentNodeMonitoringEvents.Remove(oldEvent); 1240 notify = !_IsRecentEvent(oldEvent); 1241 oldEvent->ReleaseReference(); 1242 } 1243 1244 // add the new event 1245 if (fEntryMovedEvents->Put(key, event) == B_OK) { 1246 fRecentNodeMonitoringEvents.Insert(event); 1247 event->AcquireReference(); 1248 } 1249 } 1250 1251 // remove the old entry 1252 if (oldEntry) { 1253 RemoveEntry(oldEntry); 1254 delete oldEntry; 1255 } 1256 1257 // If the to directory is complete or at least has iterators attached to it, 1258 // we load the new entry. We also load it, if the node is the root of a 1259 // volume. 1260 if (toDirectory 1261 && (toDirectory->IsComplete() || toDirectory->HasDirIterators() 1262 || (node && node == node->GetVolume()->GetRootDirectory()))) { 1263 Entry* newEntry; 1264 LoadEntry(event->volumeID, event->toDirectoryID, 1265 event->toName.GetString(), false, &newEntry); 1266 } 1267 1268 // remove the node, if it doesn't have any more actual referring entries 1269 if (node && !node->GetActualReferringEntry()) { 1270 RemoveNode(node); 1271 if (node != node->GetVolume()->GetRootDirectory()) 1272 delete node; 1273 } 1274 1275 // send notifications 1276 if (notify) { 1277 for (ClientVolumeMap::Iterator it = fClientVolumes->GetIterator(); 1278 it.HasNext();) { 1279 ClientVolume* clientVolume = it.Next().value; 1280 1281 // check, if it contains the from/to directories 1282 Directory* rootDir = clientVolume->GetRootDirectory(); 1283 bool containsFrom = DirectoryContains(rootDir, fromDirectory, true); 1284 bool containsTo = DirectoryContains(rootDir, toDirectory, true); 1285 1286 if (containsFrom) { 1287 if (containsTo) { 1288 // contains source and target dir 1289 clientVolume->ProcessNodeMonitoringEvent(event); 1290 } else { 1291 // contains only the source dir: generate an "entry removed" 1292 // event 1293 EntryRemovedEvent *removedEvent 1294 = new(std::nothrow) EntryRemovedEvent; 1295 if (!removedEvent) 1296 continue; 1297 removedEvent->opcode = B_ENTRY_REMOVED; 1298 removedEvent->time = event->time; 1299 removedEvent->volumeID = event->volumeID; 1300 removedEvent->directoryID = event->fromDirectoryID; 1301 removedEvent->nodeVolumeID = event->nodeVolumeID; 1302 removedEvent->nodeID = event->nodeID; 1303 if (event->fromName.GetLength() > 0) 1304 removedEvent->name = event->fromName; 1305 clientVolume->ProcessNodeMonitoringEvent(removedEvent); 1306 removedEvent->ReleaseReference(); 1307 } 1308 } else if (containsTo) { 1309 // contains only the target directory: generate an 1310 // "entry created" event 1311 EntryCreatedEvent *createdEvent 1312 = new(std::nothrow) EntryCreatedEvent; 1313 if (!createdEvent) 1314 continue; 1315 createdEvent->opcode = B_ENTRY_CREATED; 1316 createdEvent->time = event->time; 1317 createdEvent->volumeID = event->volumeID; 1318 createdEvent->directoryID = event->toDirectoryID; 1319 createdEvent->name = event->toName; 1320 clientVolume->ProcessNodeMonitoringEvent(createdEvent); 1321 createdEvent->ReleaseReference(); 1322 } 1323 } 1324 } 1325 } 1326 1327 // _NodeStatChanged 1328 void 1329 VolumeManager::_NodeStatChanged(StatChangedEvent* event) 1330 { 1331 // get the node 1332 Node* node = GetNode(event->volumeID, event->nodeID); 1333 if (!node) 1334 return; 1335 1336 // check, if there is an earlier similar event 1337 bool notify = true; 1338 NodeRef ref(event->volumeID, event->nodeID); 1339 StatChangedEvent* oldEvent = fNodeStatChangedEvents->Get(ref); 1340 1341 // remove the old event 1342 if (oldEvent) { 1343 fNodeStatChangedEvents->Remove(ref); 1344 fRecentNodeMonitoringEvents.Remove(oldEvent); 1345 notify = !_IsRecentEvent(oldEvent); 1346 oldEvent->ReleaseReference(); 1347 } 1348 1349 // add the new event 1350 if (fNodeStatChangedEvents->Put(ref, event) == B_OK) { 1351 fRecentNodeMonitoringEvents.Insert(event); 1352 event->AcquireReference(); 1353 } 1354 1355 if (notify) { 1356 // update the cached node stat 1357 node->UpdateStat(); 1358 1359 // send notifications 1360 for (ClientVolumeMap::Iterator it = fClientVolumes->GetIterator(); 1361 it.HasNext();) { 1362 ClientVolume* clientVolume = it.Next().value; 1363 if (DirectoryContains(clientVolume->GetRootDirectory(), node, true)) 1364 clientVolume->ProcessNodeMonitoringEvent(event); 1365 } 1366 } 1367 } 1368 1369 // _NodeAttributeChanged 1370 void 1371 VolumeManager::_NodeAttributeChanged(AttributeChangedEvent* event) 1372 { 1373 // get the node 1374 Node* node = GetNode(event->volumeID, event->nodeID); 1375 if (!node) 1376 return; 1377 1378 // check, if there is an earlier similar event 1379 bool notify = true; 1380 AttributeRef ref(event->volumeID, event->nodeID, 1381 event->attribute.GetString()); 1382 AttributeChangedEvent* oldEvent = fNodeAttributeChangedEvents->Get(ref); 1383 1384 // remove the old event 1385 if (oldEvent) { 1386 fNodeAttributeChangedEvents->Remove(ref); 1387 fRecentNodeMonitoringEvents.Remove(oldEvent); 1388 notify = !_IsRecentEvent(oldEvent); 1389 oldEvent->ReleaseReference(); 1390 } 1391 1392 // add the new event 1393 if (fNodeAttributeChangedEvents->Put(ref, event) == B_OK) { 1394 fRecentNodeMonitoringEvents.Insert(event); 1395 event->AcquireReference(); 1396 } 1397 1398 // send notifications 1399 if (notify) { 1400 for (ClientVolumeMap::Iterator it = fClientVolumes->GetIterator(); 1401 it.HasNext();) { 1402 ClientVolume* clientVolume = it.Next().value; 1403 if (DirectoryContains(clientVolume->GetRootDirectory(), node, true)) 1404 clientVolume->ProcessNodeMonitoringEvent(event); 1405 } 1406 } 1407 } 1408 1409 // _VolumeMounted 1410 void 1411 VolumeManager::_VolumeMounted(VolumeMountedEvent* event) 1412 { 1413 entry_ref rootRef; 1414 bool rootRefInitialized = false; 1415 1416 // remove the entry referring to the covered directory 1417 Directory* coveredDirectory = GetDirectory(event->volumeID, 1418 event->directoryID); 1419 if (coveredDirectory) { 1420 if (Entry* entry = coveredDirectory->GetActualReferringEntry()) { 1421 // get an entry for later 1422 rootRef = entry->GetEntryRef(); 1423 rootRefInitialized = true; 1424 1425 // send the "entry removed" event 1426 EntryRemovedEvent* event; 1427 if (_GenerateEntryRemovedEvent(entry, system_time(), 1428 &event) == B_OK) { 1429 _EntryRemoved(event, true); 1430 event->ReleaseReference(); 1431 } else { 1432 RemoveEntry(entry); 1433 delete entry; 1434 } 1435 } 1436 } 1437 1438 // add the volume 1439 _AddVolume(event->newVolumeID); 1440 1441 // generate an "entry created" event for the root dir entry 1442 if (rootRefInitialized) 1443 _GenerateEntryCreatedEvent(rootRef, event->time); 1444 } 1445 1446 // _VolumeUnmounted 1447 void 1448 VolumeManager::_VolumeUnmounted(VolumeUnmountedEvent* event) 1449 { 1450 // get the volume 1451 Volume* volume = GetVolume(event->volumeID); 1452 if (!volume) 1453 return; 1454 1455 entry_ref rootRef; 1456 bool rootRefInitialized = false; 1457 1458 // remove all actual entries referring to the root directory (should only 1459 // be one) 1460 if (Directory* rootDir = volume->GetRootDirectory()) { 1461 // get an entry ref for the root dir 1462 if (Entry* entry = rootDir->GetActualReferringEntry()) { 1463 rootRef = entry->GetEntryRef(); 1464 rootRefInitialized = true; 1465 } 1466 1467 Entry* entry = rootDir->GetFirstReferringEntry(); 1468 while (entry) { 1469 Entry* nextEntry = rootDir->GetNextReferringEntry(entry); 1470 1471 if (entry->IsActualEntry()) { 1472 EntryRemovedEvent* removedEvent; 1473 if (_GenerateEntryRemovedEvent(entry, event->time, 1474 &removedEvent) == B_OK) { 1475 _EntryRemoved(removedEvent, true); 1476 removedEvent->ReleaseReference(); 1477 } else { 1478 RemoveEntry(entry); 1479 delete entry; 1480 } 1481 } 1482 1483 entry = nextEntry; 1484 } 1485 } 1486 1487 // remove all entries of the volume 1488 while (Entry* entry = volume->GetFirstEntry()) { 1489 bool remove = true; 1490 if (entry->IsActualEntry()) { 1491 if (_GenerateEntryRemovedEvent(entry, event->time) != B_OK) 1492 remove = false; 1493 } 1494 1495 if (remove) { 1496 RemoveEntry(entry); 1497 delete entry; 1498 } 1499 } 1500 1501 // remove all nodes 1502 while (Node* node = volume->GetFirstNode()) { 1503 RemoveNode(node); 1504 if (node != volume->GetRootDirectory()) 1505 delete node; 1506 } 1507 1508 // remove the volume 1509 fVolumes->Remove(volume->GetID()); 1510 delete volume; 1511 1512 // generate an "entry created" event for the covered node 1513 if (rootRefInitialized) 1514 _GenerateEntryCreatedEvent(rootRef, event->time); 1515 } 1516 1517 // _QueryEntryCreated 1518 void 1519 VolumeManager::_QueryEntryCreated(EntryCreatedEvent* event) 1520 { 1521 // get the query handler 1522 QueryHandler* queryHandler 1523 = dynamic_cast<QueryHandler*>(event->queryHandler); 1524 if (!queryHandler) 1525 return; 1526 1527 // load the entry (just to make sure that it really exists) 1528 Entry* entry = NULL; 1529 status_t error = LoadEntry(event->volumeID, event->directoryID, 1530 event->name.GetString(), true, &entry); 1531 if (error != B_OK) 1532 return; 1533 1534 // get remote port and token 1535 if (!queryHandler->LockLooper()) 1536 return; 1537 1538 QueryHandle* queryHandle = queryHandler->GetQueryHandle(); 1539 event->remotePort = queryHandle->GetRemotePort(); 1540 event->remoteToken = queryHandle->GetRemoteToken(); 1541 queryHandler->UnlockLooper(); 1542 1543 // send a notification to the client volume 1544 queryHandler->GetQueryDomain()->ProcessQueryEvent(event); 1545 } 1546 1547 // _QueryEntryRemoved 1548 void 1549 VolumeManager::_QueryEntryRemoved(EntryRemovedEvent* event) 1550 { 1551 // get the query handler 1552 QueryHandler* queryHandler 1553 = dynamic_cast<QueryHandler*>(event->queryHandler); 1554 if (!queryHandler) 1555 return; 1556 1557 // load the directory (just to make sure that it really exists) 1558 Directory* directory = NULL; 1559 status_t error = LoadDirectory(event->volumeID, event->directoryID, 1560 &directory); 1561 if (error != B_OK) 1562 return; 1563 1564 // get remote port and token 1565 if (!queryHandler->LockLooper()) 1566 return; 1567 QueryHandle* queryHandle = queryHandler->GetQueryHandle(); 1568 event->remotePort = queryHandle->GetRemotePort(); 1569 event->remoteToken = queryHandle->GetRemoteToken(); 1570 queryHandler->UnlockLooper(); 1571 1572 // send a notification to the client volume 1573 queryHandler->GetQueryDomain()->ProcessQueryEvent(event); 1574 } 1575 1576 // _QueryEntryMoved 1577 void 1578 VolumeManager::_QueryEntryMoved(EntryMovedEvent* event) 1579 { 1580 // we simply split the event into a `removed' and a `created' event 1581 1582 // allocate the events 1583 EntryRemovedEvent* removedEvent = new(std::nothrow) EntryRemovedEvent; 1584 EntryCreatedEvent* createdEvent = new(std::nothrow) EntryCreatedEvent; 1585 if (!removedEvent || !createdEvent) { 1586 delete removedEvent; 1587 delete createdEvent; 1588 return; 1589 } 1590 1591 // init the removed event 1592 removedEvent->opcode = B_ENTRY_REMOVED; 1593 removedEvent->time = event->time; 1594 removedEvent->queryHandler = event->queryHandler; 1595 removedEvent->queryHandler->AcquireReference(); 1596 removedEvent->volumeID = event->volumeID; 1597 removedEvent->directoryID = event->fromDirectoryID; 1598 removedEvent->nodeVolumeID = event->volumeID; 1599 removedEvent->nodeID = event->nodeID; 1600 removedEvent->name = event->fromName; 1601 1602 // init the created event 1603 createdEvent->opcode = B_ENTRY_CREATED; 1604 createdEvent->time = event->time; 1605 createdEvent->queryHandler = event->queryHandler; 1606 createdEvent->queryHandler->AcquireReference(); 1607 createdEvent->volumeID = event->volumeID; 1608 createdEvent->directoryID = event->toDirectoryID; 1609 createdEvent->nodeID = event->nodeID; 1610 createdEvent->name = event->toName; 1611 1612 // send them 1613 _QueryEntryRemoved(removedEvent); 1614 removedEvent->ReleaseReference(); 1615 _QueryEntryCreated(createdEvent); 1616 createdEvent->ReleaseReference(); 1617 } 1618 1619 // _IsRecentEvent 1620 bool 1621 VolumeManager::_IsRecentEvent(NodeMonitoringEvent* event) const 1622 { 1623 return (event && system_time() < event->time + kRecentEventLifeTime); 1624 } 1625 1626 // _GenerateEntryCreatedEvent 1627 status_t 1628 VolumeManager::_GenerateEntryCreatedEvent(const entry_ref& ref, bigtime_t time, 1629 EntryCreatedEvent** _event) 1630 { 1631 // load the entry 1632 Entry* entry; 1633 status_t error = LoadEntry(ref.device, ref.directory, ref.name, true, 1634 &entry); 1635 if (error != B_OK) 1636 return error; 1637 1638 // create the event 1639 EntryCreatedEvent* event = new(std::nothrow) EntryCreatedEvent; 1640 if (!event) 1641 return B_NO_MEMORY; 1642 1643 // fill in the fields 1644 event->opcode = B_ENTRY_CREATED; 1645 event->time = time; 1646 event->volumeID = entry->GetVolumeID(); 1647 event->directoryID = entry->GetDirectoryID(); 1648 event->nodeID = entry->GetNode()->GetID(); 1649 event->name.SetTo(entry->GetName()); 1650 1651 if (_event) { 1652 *_event = event; 1653 } else { 1654 _EntryCreated(event); 1655 event->ReleaseReference(); 1656 } 1657 1658 return B_OK; 1659 } 1660 1661 // _GenerateEntryRemovedEvent 1662 status_t 1663 VolumeManager::_GenerateEntryRemovedEvent(Entry* entry, bigtime_t time, 1664 EntryRemovedEvent** _event) 1665 { 1666 if (!entry) 1667 return B_BAD_VALUE; 1668 1669 // create the event 1670 EntryRemovedEvent* event = new(std::nothrow) EntryRemovedEvent; 1671 if (!event) 1672 return B_NO_MEMORY; 1673 1674 // fill in the fields 1675 event->opcode = B_ENTRY_REMOVED; 1676 event->time = time; 1677 event->volumeID = entry->GetVolumeID(); 1678 event->directoryID = entry->GetDirectoryID(); 1679 event->nodeVolumeID = entry->GetNode()->GetVolumeID(); 1680 event->nodeID = entry->GetNode()->GetID(); 1681 event->name.SetTo(entry->GetName()); 1682 1683 if (_event) { 1684 *_event = event; 1685 } else { 1686 _EntryRemoved(event, false); 1687 event->ReleaseReference(); 1688 } 1689 1690 return B_OK; 1691 } 1692 1693 // _CheckVolumeRootMoved 1694 void 1695 VolumeManager::_CheckVolumeRootMoved(EntryMovedEvent* event) 1696 { 1697 // If a volume root is moved, the sent node monitoring message does 1698 // unforunately contain the node_ref of the covered node, not that of the 1699 // volume root -- a BeOS R5 VFS bug. Since we have the entry_ref of the 1700 // new entry, we can stat the node. 1701 1702 // check whether the node is the root of a volume 1703 NoAllocEntryRef ref(event->volumeID, event->toDirectoryID, 1704 event->toName.GetString()); 1705 BEntry entry; 1706 struct stat st; 1707 if (FDManager::SetEntry(&entry, &ref) == B_OK 1708 && entry.GetStat(&st) == B_OK) { 1709 event->nodeVolumeID = st.st_dev; 1710 event->nodeID = st.st_ino; 1711 if (Volume* volume = GetVolume(st.st_dev)) { 1712 if (volume->GetRootID() == st.st_ino) { 1713 PRINT("Mount point for volume %ld renamed\n", 1714 volume->GetID()); 1715 } 1716 } 1717 } 1718 } 1719 1720 // _NodeMonitoringProcessorEntry 1721 int32 1722 VolumeManager::_NodeMonitoringProcessorEntry(void* data) 1723 { 1724 return ((VolumeManager*)data)->_NodeMonitoringProcessor(); 1725 } 1726 1727 // _NodeMonitoryProcessor 1728 int32 1729 VolumeManager::_NodeMonitoringProcessor() 1730 { 1731 do { 1732 NodeMonitoringEvent* event = NULL; 1733 status_t error = fNodeMonitoringEvents.Pop(&event); 1734 1735 VolumeManagerLocker managerLocker; 1736 1737 while (error == B_OK) { 1738 if (event->queryHandler) { 1739 switch (event->opcode) { 1740 case B_ENTRY_CREATED: 1741 _QueryEntryCreated( 1742 dynamic_cast<EntryCreatedEvent*>(event)); 1743 break; 1744 case B_ENTRY_REMOVED: 1745 _QueryEntryRemoved( 1746 dynamic_cast<EntryRemovedEvent*>(event)); 1747 break; 1748 case B_ENTRY_MOVED: 1749 _QueryEntryMoved(dynamic_cast<EntryMovedEvent*>(event)); 1750 break; 1751 } 1752 } else { 1753 switch (event->opcode) { 1754 case B_ENTRY_CREATED: 1755 _EntryCreated(dynamic_cast<EntryCreatedEvent*>(event)); 1756 break; 1757 case B_ENTRY_REMOVED: 1758 _EntryRemoved(dynamic_cast<EntryRemovedEvent*>(event), 1759 false); 1760 break; 1761 case B_ENTRY_MOVED: 1762 _EntryMoved(dynamic_cast<EntryMovedEvent*>(event)); 1763 break; 1764 case B_STAT_CHANGED: 1765 _NodeStatChanged( 1766 dynamic_cast<StatChangedEvent*>(event)); 1767 break; 1768 case B_ATTR_CHANGED: 1769 _NodeAttributeChanged( 1770 dynamic_cast<AttributeChangedEvent*>(event)); 1771 break; 1772 case B_DEVICE_MOUNTED: 1773 _VolumeMounted(dynamic_cast<VolumeMountedEvent*>(event)); 1774 break; 1775 case B_DEVICE_UNMOUNTED: 1776 _VolumeUnmounted( 1777 dynamic_cast<VolumeUnmountedEvent*>(event)); 1778 break; 1779 } 1780 } 1781 event->ReleaseReference(); 1782 1783 // If there is another event available, get it as long as we 1784 // have the VolumeManager lock. 1785 error = fNodeMonitoringEvents.Pop(&event, 0); 1786 } 1787 } while (!fTerminating); 1788 1789 return 0; 1790 } 1791 1792 1793 // sManager 1794 VolumeManager* VolumeManager::sManager = NULL; 1795