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(%" B_PRIdDEV ", " 723 "%" B_PRIdINO ", `%s')\n", volumeID, 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%" B_PRIx32 ", " 795 "%" B_PRId32 ", %" B_PRId32 ")\n", 796 queryDomain, queryString, flags, remotePort, remoteToken); 797 798 // allocate the handle 799 QueryHandle* queryHandle = new(std::nothrow) QueryHandle(remotePort, 800 remoteToken); 801 if (!queryHandle) 802 return B_NO_MEMORY; 803 ObjectDeleter<QueryHandle> handleDeleter(queryHandle); 804 805 // allocate a query handler, if this is a live query 806 QueryHandler* queryHandler = NULL; 807 if (liveQuery) { 808 queryHandler = new(std::nothrow) QueryHandler(this, queryDomain, 809 queryHandle); 810 if (!queryHandler) 811 return B_NO_MEMORY; 812 813 fNodeMonitor->Lock(); 814 fNodeMonitor->AddHandler(queryHandler); 815 fNodeMonitor->Unlock(); 816 queryHandle->SetQueryListener(queryHandler); 817 } 818 819 // iterate through the volumes and create a query for each one 820 // supporting queries 821 for (VolumeMap::Iterator it = fVolumes->GetIterator(); it.HasNext();) { 822 Volume* volume = it.Next().value; 823 if (!volume->KnowsQuery()) 824 continue; 825 826 // The volume should either be contained by the client volume or 827 // the other way around. Otherwise they are located in different 828 // branches of the FS tree and don't have common nodes. 829 if (!queryDomain->QueryDomainIntersectsWith(volume)) 830 continue; 831 PRINT("VolumeManager::OpenQuery(): adding Query for volume " 832 "%" B_PRIdDEV "\n", volume->GetID()); 833 834 // create the query for this volume 835 BVolume bVolume(volume->GetID()); 836 Query* query = new(std::nothrow) Query; 837 if (!query) 838 return B_NO_MEMORY; 839 840 // init the query 841 ObjectDeleter<Query> queryDeleter(query); 842 status_t error = query->SetVolume(&bVolume); 843 if (error != B_OK) 844 return error; 845 error = query->SetPredicate(queryString); 846 if (error != B_OK) 847 return error; 848 if (liveQuery) { 849 error = query->SetTarget(queryHandler); 850 if (error != B_OK) 851 return error; 852 } 853 854 // fetch 855 error = query->Fetch(); 856 if (error != B_OK) 857 return error; 858 859 queryHandle->AddQuery(query); 860 queryDeleter.Detach(); 861 } 862 863 *handle = queryHandle; 864 handleDeleter.Detach(); 865 return B_OK; 866 } 867 868 // CompletePathToRoot 869 status_t 870 VolumeManager::CompletePathToRoot(Directory* directory) 871 { 872 if (!directory) 873 return B_BAD_VALUE; 874 875 while (directory != GetRootDirectory()) { 876 // if the dir has a valid entry referring to it, we've nothing to do 877 if (directory->GetActualReferringEntry()) 878 return B_OK; 879 880 // get a proper entry_ref 881 BEntry bEntry; 882 entry_ref entryRef(directory->GetVolumeID(), directory->GetID(), "."); 883 status_t error = FDManager::SetEntry(&bEntry, &entryRef); 884 if (error == B_OK) 885 error = bEntry.GetRef(&entryRef); 886 if (error != B_OK) 887 return error; 888 889 // if the entry is already loaded, we're done 890 if (GetEntry(entryRef)) 891 return B_OK; 892 893 // the entry is not yet known -- load it 894 Entry* entry; 895 error = LoadEntry(entryRef.device, entryRef.directory, entryRef.name, 896 true, &entry); 897 if (error != B_OK) 898 return error; 899 900 // get the entry's parent dir and enter the next round 901 directory = entry->GetDirectory(); 902 } 903 904 return B_OK; 905 } 906 907 // GetPath 908 status_t 909 VolumeManager::GetPath(Entry* entry, Path* path) 910 { 911 // get directory path 912 status_t error = GetPath(entry->GetDirectory(), path); 913 if (error != B_OK) 914 return error; 915 916 // append the entry name 917 return path->Append(entry->GetName()); 918 } 919 920 // GetPath 921 status_t 922 VolumeManager::GetPath(Node* node, Path* path) 923 { 924 if (node == GetRootDirectory()) 925 return path->SetTo("/"); 926 927 // get an entry referring to the node 928 Entry* entry = node->GetActualReferringEntry(); 929 if (!entry) { 930 // if the node is a directory, we complete the path to the root and 931 // try again 932 if (Directory* directory = dynamic_cast<Directory*>(node)) { 933 CompletePathToRoot(directory); 934 entry = node->GetActualReferringEntry(); 935 } 936 937 if (!entry) 938 return B_ERROR; 939 } 940 941 return GetPath(entry, path); 942 } 943 944 // DirectoryContains 945 bool 946 VolumeManager::DirectoryContains(Directory* directory, Entry* entry) 947 { 948 if (!directory || !entry) 949 return false; 950 951 return DirectoryContains(directory, entry->GetDirectory(), true); 952 } 953 954 // DirectoryContains 955 bool 956 VolumeManager::DirectoryContains(Directory* directory, Directory* descendant, 957 bool reflexive) 958 { 959 if (!directory || !descendant) 960 return false; 961 962 // a directory contains itself, just as defined by the caller 963 if (directory == descendant) 964 return reflexive; 965 966 // if the directory is the root directory, it contains everything 967 Directory* rootDir = GetRootDirectory(); 968 if (directory == rootDir) 969 return true; 970 971 // recursively get the descendant's parent dir until reaching the root dir 972 // or the given dir 973 while (descendant != rootDir) { 974 descendant = GetParentDirectory(descendant); 975 if (!descendant) 976 return false; 977 978 if (descendant == directory) 979 return true; 980 } 981 982 return false; 983 } 984 985 // DirectoryContains 986 bool 987 VolumeManager::DirectoryContains(Directory* directory, Node* descendant, 988 bool reflexive) 989 { 990 if (!directory || !descendant) 991 return false; 992 993 // if the node is a directory, let the other version do the job 994 if (Directory* dir = dynamic_cast<Directory*>(descendant)) 995 return DirectoryContains(directory, dir, reflexive); 996 997 // iterate through the referring entries and check, if the directory 998 // contains any of them 999 for (Entry* entry = descendant->GetFirstReferringEntry(); 1000 entry; 1001 entry = descendant->GetNextReferringEntry(entry)) { 1002 if (DirectoryContains(directory, entry)) 1003 return true; 1004 } 1005 1006 return false; 1007 } 1008 1009 1010 // #pragma mark - 1011 1012 // ProcessNodeMonitoringEvent 1013 void 1014 VolumeManager::ProcessNodeMonitoringEvent(NodeMonitoringEvent* event) 1015 { 1016 if (fNodeMonitoringEvents.Push(event) != B_OK) 1017 delete event; 1018 } 1019 1020 // _AddVolume 1021 status_t 1022 VolumeManager::_AddVolume(dev_t volumeID, Volume** _volume) 1023 { 1024 if (GetVolume(volumeID)) 1025 return B_OK; 1026 1027 // create the volume 1028 Volume* volume = new(std::nothrow) Volume(volumeID); 1029 if (!volume) 1030 RETURN_ERROR(B_NO_MEMORY); 1031 ObjectDeleter<Volume> volumeDeleter(volume); 1032 status_t error = volume->Init(); 1033 if (error != B_OK) 1034 RETURN_ERROR(error); 1035 1036 // add it 1037 error = fVolumes->Put(volumeID, volume); 1038 if (error != B_OK) 1039 RETURN_ERROR(error); 1040 1041 // add the root node 1042 error = AddNode(volume->GetRootDirectory()); 1043 if (error != B_OK) { 1044 fVolumes->Remove(volumeID); 1045 RETURN_ERROR(error); 1046 } 1047 1048 // complete the root dir path 1049 CompletePathToRoot(volume->GetRootDirectory()); 1050 1051 volumeDeleter.Detach(); 1052 if (_volume) 1053 *_volume = volume; 1054 return B_OK; 1055 } 1056 1057 // _EntryCreated 1058 void 1059 VolumeManager::_EntryCreated(EntryCreatedEvent* event) 1060 { 1061 // get the directory 1062 Directory* directory = GetDirectory(event->volumeID, event->directoryID); 1063 if (!directory) 1064 return; 1065 1066 // check, if there is an earlier similar event 1067 bool notify = true; 1068 NoAllocEntryRef ref(event->volumeID, event->directoryID, 1069 event->name.GetString()); 1070 EntryCreatedEvent* oldEvent = fEntryCreatedEvents->Get(ref); 1071 1072 // remove the old event 1073 if (oldEvent) { 1074 fEntryCreatedEvents->Remove(ref); 1075 fRecentNodeMonitoringEvents.Remove(oldEvent); 1076 notify = !_IsRecentEvent(oldEvent); 1077 oldEvent->ReleaseReference(); 1078 } 1079 1080 // add the new event 1081 if (fEntryCreatedEvents->Put(ref, event) == B_OK) { 1082 fRecentNodeMonitoringEvents.Insert(event); 1083 event->AcquireReference(); 1084 } 1085 1086 // if the directory is complete or at least has iterators attached to it, 1087 // we load the entry 1088 if (directory->IsComplete() || directory->HasDirIterators()) { 1089 Entry* entry; 1090 LoadEntry(ref.device, ref.directory, ref.name, false, &entry); 1091 } 1092 1093 // send notifications 1094 if (notify) { 1095 for (ClientVolumeMap::Iterator it = fClientVolumes->GetIterator(); 1096 it.HasNext();) { 1097 ClientVolume* clientVolume = it.Next().value; 1098 if (DirectoryContains(clientVolume->GetRootDirectory(), directory, 1099 true)) { 1100 clientVolume->ProcessNodeMonitoringEvent(event); 1101 } 1102 } 1103 } 1104 } 1105 1106 // _EntryRemoved 1107 void 1108 VolumeManager::_EntryRemoved(EntryRemovedEvent* event, bool keepNode) 1109 { 1110 // get node and directory 1111 Node* node = GetNode(event->nodeVolumeID, event->nodeID); 1112 Directory* directory = GetDirectory(event->volumeID, event->directoryID); 1113 if (!directory) 1114 return; 1115 1116 // find the entry 1117 Entry* entry = NULL; 1118 if (node) { 1119 if (event->name.GetLength() == 0) { 1120 for (entry = node->GetFirstReferringEntry(); 1121 entry; 1122 entry = node->GetNextReferringEntry(entry)) { 1123 if (!entry->Exists()) { 1124 event->name.SetTo(entry->GetName()); 1125 break; 1126 } 1127 } 1128 } else { 1129 entry = GetEntry(directory->GetVolumeID(), directory->GetID(), 1130 event->name.GetString()); 1131 } 1132 } 1133 1134 // check, if there is an earlier similar event 1135 bool notify = true; 1136 NoAllocEntryRef ref(event->volumeID, event->directoryID, 1137 event->name.GetString()); 1138 EntryRemovedEvent* oldEvent = fEntryRemovedEvents->Get(ref); 1139 // TODO: Under BeOS R5 the entry name is not encoded in the 1140 // "entry removed" node monitoring message. If we have seen the entry 1141 // before, we can get the entry nevertheless (see above). Usually we 1142 // get 2 "entry removed" events: One for watching the directory and one 1143 // for watching the node. After the first one has been processed, we've 1144 // forgotten everything about the entry and we won't be able to find out 1145 // the entry's name for the second one. Hence we will never find the 1146 // previous event in the fEntryRemovedEvents map. We should probably 1147 // fall back to using a NodeRef as key under BeOS R5. 1148 1149 // remove the old event 1150 if (oldEvent) { 1151 fEntryRemovedEvents->Remove(ref); 1152 fRecentNodeMonitoringEvents.Remove(oldEvent); 1153 notify = !_IsRecentEvent(oldEvent); 1154 oldEvent->ReleaseReference(); 1155 } 1156 1157 // add the new event 1158 if (fEntryRemovedEvents->Put(ref, event) == B_OK) { 1159 fRecentNodeMonitoringEvents.Insert(event); 1160 event->AcquireReference(); 1161 } 1162 1163 // remove the entry 1164 if (entry) { 1165 RemoveEntry(entry); 1166 delete entry; 1167 } 1168 1169 // remove the node, if it doesn't have any more actual referring entries 1170 if (node && !keepNode && !node->GetActualReferringEntry()) { 1171 RemoveNode(node); 1172 if (node != node->GetVolume()->GetRootDirectory()) 1173 delete node; 1174 } 1175 1176 // send notifications 1177 if (notify) { 1178 NodeRef nodeRef(event->nodeVolumeID, event->nodeID); 1179 for (ClientVolumeMap::Iterator it = fClientVolumes->GetIterator(); 1180 it.HasNext();) { 1181 // We send a notification, if the client volume contains the entry, 1182 // but also, if the removed entry refers to the client volume's 1183 // root. The client connection has a special handling for this 1184 // case. 1185 ClientVolume* clientVolume = it.Next().value; 1186 Directory* rootDir = clientVolume->GetRootDirectory(); 1187 if (DirectoryContains(rootDir, directory, true) 1188 || clientVolume->GetRootNodeRef() == nodeRef) { 1189 clientVolume->ProcessNodeMonitoringEvent(event); 1190 } 1191 } 1192 } 1193 } 1194 1195 // _EntryMoved 1196 void 1197 VolumeManager::_EntryMoved(EntryMovedEvent* event) 1198 { 1199 _CheckVolumeRootMoved(event); 1200 1201 Directory* fromDirectory 1202 = GetDirectory(event->volumeID, event->fromDirectoryID); 1203 Directory* toDirectory 1204 = GetDirectory(event->volumeID, event->toDirectoryID); 1205 Node* node = GetNode(event->nodeVolumeID, event->nodeID); 1206 1207 // we should at least have one of the directories 1208 if (!fromDirectory && !toDirectory) 1209 return; 1210 1211 // find the old entry 1212 Entry* oldEntry = NULL; 1213 if (node) { 1214 if (event->fromName.GetLength() == 0) { 1215 for (oldEntry = node->GetFirstReferringEntry(); 1216 oldEntry; 1217 oldEntry = node->GetNextReferringEntry(oldEntry)) { 1218 if (!oldEntry->Exists()) { 1219 event->fromName.SetTo(oldEntry->GetName()); 1220 break; 1221 } 1222 } 1223 } else { 1224 oldEntry = GetEntry(event->volumeID, event->fromDirectoryID, 1225 event->fromName.GetString()); 1226 } 1227 } 1228 1229 // check, if there is an earlier similar event 1230 bool notify = true; 1231 if (event->fromName.GetLength() > 0) { 1232 EntryMovedEventKey key(event->volumeID, event->fromDirectoryID, 1233 event->fromName.GetString(), event->toDirectoryID, 1234 event->toName.GetString()); 1235 EntryMovedEvent* oldEvent = fEntryMovedEvents->Get(key); 1236 1237 // remove the old event 1238 if (oldEvent) { 1239 fEntryMovedEvents->Remove(key); 1240 fRecentNodeMonitoringEvents.Remove(oldEvent); 1241 notify = !_IsRecentEvent(oldEvent); 1242 oldEvent->ReleaseReference(); 1243 } 1244 1245 // add the new event 1246 if (fEntryMovedEvents->Put(key, event) == B_OK) { 1247 fRecentNodeMonitoringEvents.Insert(event); 1248 event->AcquireReference(); 1249 } 1250 } 1251 1252 // remove the old entry 1253 if (oldEntry) { 1254 RemoveEntry(oldEntry); 1255 delete oldEntry; 1256 } 1257 1258 // If the to directory is complete or at least has iterators attached to it, 1259 // we load the new entry. We also load it, if the node is the root of a 1260 // volume. 1261 if (toDirectory 1262 && (toDirectory->IsComplete() || toDirectory->HasDirIterators() 1263 || (node && node == node->GetVolume()->GetRootDirectory()))) { 1264 Entry* newEntry; 1265 LoadEntry(event->volumeID, event->toDirectoryID, 1266 event->toName.GetString(), false, &newEntry); 1267 } 1268 1269 // remove the node, if it doesn't have any more actual referring entries 1270 if (node && !node->GetActualReferringEntry()) { 1271 RemoveNode(node); 1272 if (node != node->GetVolume()->GetRootDirectory()) 1273 delete node; 1274 } 1275 1276 // send notifications 1277 if (notify) { 1278 for (ClientVolumeMap::Iterator it = fClientVolumes->GetIterator(); 1279 it.HasNext();) { 1280 ClientVolume* clientVolume = it.Next().value; 1281 1282 // check, if it contains the from/to directories 1283 Directory* rootDir = clientVolume->GetRootDirectory(); 1284 bool containsFrom = DirectoryContains(rootDir, fromDirectory, true); 1285 bool containsTo = DirectoryContains(rootDir, toDirectory, true); 1286 1287 if (containsFrom) { 1288 if (containsTo) { 1289 // contains source and target dir 1290 clientVolume->ProcessNodeMonitoringEvent(event); 1291 } else { 1292 // contains only the source dir: generate an "entry removed" 1293 // event 1294 EntryRemovedEvent *removedEvent 1295 = new(std::nothrow) EntryRemovedEvent; 1296 if (!removedEvent) 1297 continue; 1298 removedEvent->opcode = B_ENTRY_REMOVED; 1299 removedEvent->time = event->time; 1300 removedEvent->volumeID = event->volumeID; 1301 removedEvent->directoryID = event->fromDirectoryID; 1302 removedEvent->nodeVolumeID = event->nodeVolumeID; 1303 removedEvent->nodeID = event->nodeID; 1304 if (event->fromName.GetLength() > 0) 1305 removedEvent->name = event->fromName; 1306 clientVolume->ProcessNodeMonitoringEvent(removedEvent); 1307 removedEvent->ReleaseReference(); 1308 } 1309 } else if (containsTo) { 1310 // contains only the target directory: generate an 1311 // "entry created" event 1312 EntryCreatedEvent *createdEvent 1313 = new(std::nothrow) EntryCreatedEvent; 1314 if (!createdEvent) 1315 continue; 1316 createdEvent->opcode = B_ENTRY_CREATED; 1317 createdEvent->time = event->time; 1318 createdEvent->volumeID = event->volumeID; 1319 createdEvent->directoryID = event->toDirectoryID; 1320 createdEvent->name = event->toName; 1321 clientVolume->ProcessNodeMonitoringEvent(createdEvent); 1322 createdEvent->ReleaseReference(); 1323 } 1324 } 1325 } 1326 } 1327 1328 // _NodeStatChanged 1329 void 1330 VolumeManager::_NodeStatChanged(StatChangedEvent* event) 1331 { 1332 // get the node 1333 Node* node = GetNode(event->volumeID, event->nodeID); 1334 if (!node) 1335 return; 1336 1337 // check, if there is an earlier similar event 1338 bool notify = true; 1339 NodeRef ref(event->volumeID, event->nodeID); 1340 StatChangedEvent* oldEvent = fNodeStatChangedEvents->Get(ref); 1341 1342 // remove the old event 1343 if (oldEvent) { 1344 fNodeStatChangedEvents->Remove(ref); 1345 fRecentNodeMonitoringEvents.Remove(oldEvent); 1346 notify = !_IsRecentEvent(oldEvent); 1347 oldEvent->ReleaseReference(); 1348 } 1349 1350 // add the new event 1351 if (fNodeStatChangedEvents->Put(ref, event) == B_OK) { 1352 fRecentNodeMonitoringEvents.Insert(event); 1353 event->AcquireReference(); 1354 } 1355 1356 if (notify) { 1357 // update the cached node stat 1358 node->UpdateStat(); 1359 1360 // send notifications 1361 for (ClientVolumeMap::Iterator it = fClientVolumes->GetIterator(); 1362 it.HasNext();) { 1363 ClientVolume* clientVolume = it.Next().value; 1364 if (DirectoryContains(clientVolume->GetRootDirectory(), node, true)) 1365 clientVolume->ProcessNodeMonitoringEvent(event); 1366 } 1367 } 1368 } 1369 1370 // _NodeAttributeChanged 1371 void 1372 VolumeManager::_NodeAttributeChanged(AttributeChangedEvent* event) 1373 { 1374 // get the node 1375 Node* node = GetNode(event->volumeID, event->nodeID); 1376 if (!node) 1377 return; 1378 1379 // check, if there is an earlier similar event 1380 bool notify = true; 1381 AttributeRef ref(event->volumeID, event->nodeID, 1382 event->attribute.GetString()); 1383 AttributeChangedEvent* oldEvent = fNodeAttributeChangedEvents->Get(ref); 1384 1385 // remove the old event 1386 if (oldEvent) { 1387 fNodeAttributeChangedEvents->Remove(ref); 1388 fRecentNodeMonitoringEvents.Remove(oldEvent); 1389 notify = !_IsRecentEvent(oldEvent); 1390 oldEvent->ReleaseReference(); 1391 } 1392 1393 // add the new event 1394 if (fNodeAttributeChangedEvents->Put(ref, event) == B_OK) { 1395 fRecentNodeMonitoringEvents.Insert(event); 1396 event->AcquireReference(); 1397 } 1398 1399 // send notifications 1400 if (notify) { 1401 for (ClientVolumeMap::Iterator it = fClientVolumes->GetIterator(); 1402 it.HasNext();) { 1403 ClientVolume* clientVolume = it.Next().value; 1404 if (DirectoryContains(clientVolume->GetRootDirectory(), node, true)) 1405 clientVolume->ProcessNodeMonitoringEvent(event); 1406 } 1407 } 1408 } 1409 1410 // _VolumeMounted 1411 void 1412 VolumeManager::_VolumeMounted(VolumeMountedEvent* event) 1413 { 1414 entry_ref rootRef; 1415 bool rootRefInitialized = false; 1416 1417 // remove the entry referring to the covered directory 1418 Directory* coveredDirectory = GetDirectory(event->volumeID, 1419 event->directoryID); 1420 if (coveredDirectory) { 1421 if (Entry* entry = coveredDirectory->GetActualReferringEntry()) { 1422 // get an entry for later 1423 rootRef = entry->GetEntryRef(); 1424 rootRefInitialized = true; 1425 1426 // send the "entry removed" event 1427 EntryRemovedEvent* event; 1428 if (_GenerateEntryRemovedEvent(entry, system_time(), 1429 &event) == B_OK) { 1430 _EntryRemoved(event, true); 1431 event->ReleaseReference(); 1432 } else { 1433 RemoveEntry(entry); 1434 delete entry; 1435 } 1436 } 1437 } 1438 1439 // add the volume 1440 _AddVolume(event->newVolumeID); 1441 1442 // generate an "entry created" event for the root dir entry 1443 if (rootRefInitialized) 1444 _GenerateEntryCreatedEvent(rootRef, event->time); 1445 } 1446 1447 // _VolumeUnmounted 1448 void 1449 VolumeManager::_VolumeUnmounted(VolumeUnmountedEvent* event) 1450 { 1451 // get the volume 1452 Volume* volume = GetVolume(event->volumeID); 1453 if (!volume) 1454 return; 1455 1456 entry_ref rootRef; 1457 bool rootRefInitialized = false; 1458 1459 // remove all actual entries referring to the root directory (should only 1460 // be one) 1461 if (Directory* rootDir = volume->GetRootDirectory()) { 1462 // get an entry ref for the root dir 1463 if (Entry* entry = rootDir->GetActualReferringEntry()) { 1464 rootRef = entry->GetEntryRef(); 1465 rootRefInitialized = true; 1466 } 1467 1468 Entry* entry = rootDir->GetFirstReferringEntry(); 1469 while (entry) { 1470 Entry* nextEntry = rootDir->GetNextReferringEntry(entry); 1471 1472 if (entry->IsActualEntry()) { 1473 EntryRemovedEvent* removedEvent; 1474 if (_GenerateEntryRemovedEvent(entry, event->time, 1475 &removedEvent) == B_OK) { 1476 _EntryRemoved(removedEvent, true); 1477 removedEvent->ReleaseReference(); 1478 } else { 1479 RemoveEntry(entry); 1480 delete entry; 1481 } 1482 } 1483 1484 entry = nextEntry; 1485 } 1486 } 1487 1488 // remove all entries of the volume 1489 while (Entry* entry = volume->GetFirstEntry()) { 1490 bool remove = true; 1491 if (entry->IsActualEntry()) { 1492 if (_GenerateEntryRemovedEvent(entry, event->time) != B_OK) 1493 remove = false; 1494 } 1495 1496 if (remove) { 1497 RemoveEntry(entry); 1498 delete entry; 1499 } 1500 } 1501 1502 // remove all nodes 1503 while (Node* node = volume->GetFirstNode()) { 1504 RemoveNode(node); 1505 if (node != volume->GetRootDirectory()) 1506 delete node; 1507 } 1508 1509 // remove the volume 1510 fVolumes->Remove(volume->GetID()); 1511 delete volume; 1512 1513 // generate an "entry created" event for the covered node 1514 if (rootRefInitialized) 1515 _GenerateEntryCreatedEvent(rootRef, event->time); 1516 } 1517 1518 // _QueryEntryCreated 1519 void 1520 VolumeManager::_QueryEntryCreated(EntryCreatedEvent* event) 1521 { 1522 // get the query handler 1523 QueryHandler* queryHandler 1524 = dynamic_cast<QueryHandler*>(event->queryHandler); 1525 if (!queryHandler) 1526 return; 1527 1528 // load the entry (just to make sure that it really exists) 1529 Entry* entry = NULL; 1530 status_t error = LoadEntry(event->volumeID, event->directoryID, 1531 event->name.GetString(), true, &entry); 1532 if (error != B_OK) 1533 return; 1534 1535 // get remote port and token 1536 if (!queryHandler->LockLooper()) 1537 return; 1538 1539 QueryHandle* queryHandle = queryHandler->GetQueryHandle(); 1540 event->remotePort = queryHandle->GetRemotePort(); 1541 event->remoteToken = queryHandle->GetRemoteToken(); 1542 queryHandler->UnlockLooper(); 1543 1544 // send a notification to the client volume 1545 queryHandler->GetQueryDomain()->ProcessQueryEvent(event); 1546 } 1547 1548 // _QueryEntryRemoved 1549 void 1550 VolumeManager::_QueryEntryRemoved(EntryRemovedEvent* event) 1551 { 1552 // get the query handler 1553 QueryHandler* queryHandler 1554 = dynamic_cast<QueryHandler*>(event->queryHandler); 1555 if (!queryHandler) 1556 return; 1557 1558 // load the directory (just to make sure that it really exists) 1559 Directory* directory = NULL; 1560 status_t error = LoadDirectory(event->volumeID, event->directoryID, 1561 &directory); 1562 if (error != B_OK) 1563 return; 1564 1565 // get remote port and token 1566 if (!queryHandler->LockLooper()) 1567 return; 1568 QueryHandle* queryHandle = queryHandler->GetQueryHandle(); 1569 event->remotePort = queryHandle->GetRemotePort(); 1570 event->remoteToken = queryHandle->GetRemoteToken(); 1571 queryHandler->UnlockLooper(); 1572 1573 // send a notification to the client volume 1574 queryHandler->GetQueryDomain()->ProcessQueryEvent(event); 1575 } 1576 1577 // _QueryEntryMoved 1578 void 1579 VolumeManager::_QueryEntryMoved(EntryMovedEvent* event) 1580 { 1581 // we simply split the event into a `removed' and a `created' event 1582 1583 // allocate the events 1584 EntryRemovedEvent* removedEvent = new(std::nothrow) EntryRemovedEvent; 1585 EntryCreatedEvent* createdEvent = new(std::nothrow) EntryCreatedEvent; 1586 if (!removedEvent || !createdEvent) { 1587 delete removedEvent; 1588 delete createdEvent; 1589 return; 1590 } 1591 1592 // init the removed event 1593 removedEvent->opcode = B_ENTRY_REMOVED; 1594 removedEvent->time = event->time; 1595 removedEvent->queryHandler = event->queryHandler; 1596 removedEvent->queryHandler->AcquireReference(); 1597 removedEvent->volumeID = event->volumeID; 1598 removedEvent->directoryID = event->fromDirectoryID; 1599 removedEvent->nodeVolumeID = event->volumeID; 1600 removedEvent->nodeID = event->nodeID; 1601 removedEvent->name = event->fromName; 1602 1603 // init the created event 1604 createdEvent->opcode = B_ENTRY_CREATED; 1605 createdEvent->time = event->time; 1606 createdEvent->queryHandler = event->queryHandler; 1607 createdEvent->queryHandler->AcquireReference(); 1608 createdEvent->volumeID = event->volumeID; 1609 createdEvent->directoryID = event->toDirectoryID; 1610 createdEvent->nodeID = event->nodeID; 1611 createdEvent->name = event->toName; 1612 1613 // send them 1614 _QueryEntryRemoved(removedEvent); 1615 removedEvent->ReleaseReference(); 1616 _QueryEntryCreated(createdEvent); 1617 createdEvent->ReleaseReference(); 1618 } 1619 1620 // _IsRecentEvent 1621 bool 1622 VolumeManager::_IsRecentEvent(NodeMonitoringEvent* event) const 1623 { 1624 return (event && system_time() < event->time + kRecentEventLifeTime); 1625 } 1626 1627 // _GenerateEntryCreatedEvent 1628 status_t 1629 VolumeManager::_GenerateEntryCreatedEvent(const entry_ref& ref, bigtime_t time, 1630 EntryCreatedEvent** _event) 1631 { 1632 // load the entry 1633 Entry* entry; 1634 status_t error = LoadEntry(ref.device, ref.directory, ref.name, true, 1635 &entry); 1636 if (error != B_OK) 1637 return error; 1638 1639 // create the event 1640 EntryCreatedEvent* event = new(std::nothrow) EntryCreatedEvent; 1641 if (!event) 1642 return B_NO_MEMORY; 1643 1644 // fill in the fields 1645 event->opcode = B_ENTRY_CREATED; 1646 event->time = time; 1647 event->volumeID = entry->GetVolumeID(); 1648 event->directoryID = entry->GetDirectoryID(); 1649 event->nodeID = entry->GetNode()->GetID(); 1650 event->name.SetTo(entry->GetName()); 1651 1652 if (_event) { 1653 *_event = event; 1654 } else { 1655 _EntryCreated(event); 1656 event->ReleaseReference(); 1657 } 1658 1659 return B_OK; 1660 } 1661 1662 // _GenerateEntryRemovedEvent 1663 status_t 1664 VolumeManager::_GenerateEntryRemovedEvent(Entry* entry, bigtime_t time, 1665 EntryRemovedEvent** _event) 1666 { 1667 if (!entry) 1668 return B_BAD_VALUE; 1669 1670 // create the event 1671 EntryRemovedEvent* event = new(std::nothrow) EntryRemovedEvent; 1672 if (!event) 1673 return B_NO_MEMORY; 1674 1675 // fill in the fields 1676 event->opcode = B_ENTRY_REMOVED; 1677 event->time = time; 1678 event->volumeID = entry->GetVolumeID(); 1679 event->directoryID = entry->GetDirectoryID(); 1680 event->nodeVolumeID = entry->GetNode()->GetVolumeID(); 1681 event->nodeID = entry->GetNode()->GetID(); 1682 event->name.SetTo(entry->GetName()); 1683 1684 if (_event) { 1685 *_event = event; 1686 } else { 1687 _EntryRemoved(event, false); 1688 event->ReleaseReference(); 1689 } 1690 1691 return B_OK; 1692 } 1693 1694 // _CheckVolumeRootMoved 1695 void 1696 VolumeManager::_CheckVolumeRootMoved(EntryMovedEvent* event) 1697 { 1698 // If a volume root is moved, the sent node monitoring message does 1699 // unforunately contain the node_ref of the covered node, not that of the 1700 // volume root -- a BeOS R5 VFS bug. Since we have the entry_ref of the 1701 // new entry, we can stat the node. 1702 1703 // check whether the node is the root of a volume 1704 NoAllocEntryRef ref(event->volumeID, event->toDirectoryID, 1705 event->toName.GetString()); 1706 BEntry entry; 1707 struct stat st; 1708 if (FDManager::SetEntry(&entry, &ref) == B_OK 1709 && entry.GetStat(&st) == B_OK) { 1710 event->nodeVolumeID = st.st_dev; 1711 event->nodeID = st.st_ino; 1712 if (Volume* volume = GetVolume(st.st_dev)) { 1713 if (volume->GetRootID() == st.st_ino) { 1714 PRINT("Mount point for volume %" B_PRIdDEV " renamed\n", 1715 volume->GetID()); 1716 } 1717 } 1718 } 1719 } 1720 1721 // _NodeMonitoringProcessorEntry 1722 int32 1723 VolumeManager::_NodeMonitoringProcessorEntry(void* data) 1724 { 1725 return ((VolumeManager*)data)->_NodeMonitoringProcessor(); 1726 } 1727 1728 // _NodeMonitoryProcessor 1729 int32 1730 VolumeManager::_NodeMonitoringProcessor() 1731 { 1732 do { 1733 NodeMonitoringEvent* event = NULL; 1734 status_t error = fNodeMonitoringEvents.Pop(&event); 1735 1736 VolumeManagerLocker managerLocker; 1737 1738 while (error == B_OK) { 1739 if (event->queryHandler) { 1740 switch (event->opcode) { 1741 case B_ENTRY_CREATED: 1742 _QueryEntryCreated( 1743 dynamic_cast<EntryCreatedEvent*>(event)); 1744 break; 1745 case B_ENTRY_REMOVED: 1746 _QueryEntryRemoved( 1747 dynamic_cast<EntryRemovedEvent*>(event)); 1748 break; 1749 case B_ENTRY_MOVED: 1750 _QueryEntryMoved(dynamic_cast<EntryMovedEvent*>(event)); 1751 break; 1752 } 1753 } else { 1754 switch (event->opcode) { 1755 case B_ENTRY_CREATED: 1756 _EntryCreated(dynamic_cast<EntryCreatedEvent*>(event)); 1757 break; 1758 case B_ENTRY_REMOVED: 1759 _EntryRemoved(dynamic_cast<EntryRemovedEvent*>(event), 1760 false); 1761 break; 1762 case B_ENTRY_MOVED: 1763 _EntryMoved(dynamic_cast<EntryMovedEvent*>(event)); 1764 break; 1765 case B_STAT_CHANGED: 1766 _NodeStatChanged( 1767 dynamic_cast<StatChangedEvent*>(event)); 1768 break; 1769 case B_ATTR_CHANGED: 1770 _NodeAttributeChanged( 1771 dynamic_cast<AttributeChangedEvent*>(event)); 1772 break; 1773 case B_DEVICE_MOUNTED: 1774 _VolumeMounted(dynamic_cast<VolumeMountedEvent*>(event)); 1775 break; 1776 case B_DEVICE_UNMOUNTED: 1777 _VolumeUnmounted( 1778 dynamic_cast<VolumeUnmountedEvent*>(event)); 1779 break; 1780 } 1781 } 1782 event->ReleaseReference(); 1783 1784 // If there is another event available, get it as long as we 1785 // have the VolumeManager lock. 1786 error = fNodeMonitoringEvents.Pop(&event, 0); 1787 } 1788 } while (!fTerminating); 1789 1790 return 0; 1791 } 1792 1793 1794 // sManager 1795 VolumeManager* VolumeManager::sManager = NULL; 1796