15a1d355fSStephan Aßmus // VolumeManager.cpp
25a1d355fSStephan Aßmus
35a1d355fSStephan Aßmus #include "VolumeManager.h"
45a1d355fSStephan Aßmus
55a1d355fSStephan Aßmus #include <new>
65a1d355fSStephan Aßmus
75a1d355fSStephan Aßmus #include <sys/stat.h>
85a1d355fSStephan Aßmus
95a1d355fSStephan Aßmus #include <AutoDeleter.h>
105a1d355fSStephan Aßmus #include <Entry.h>
115a1d355fSStephan Aßmus #include <fs_info.h>
125a1d355fSStephan Aßmus #include <fs_query.h>
135a1d355fSStephan Aßmus #include <HashMap.h>
145a1d355fSStephan Aßmus #include <NodeMonitor.h>
155a1d355fSStephan Aßmus #include <Volume.h>
165a1d355fSStephan Aßmus
175a1d355fSStephan Aßmus #include "ClientVolume.h"
185a1d355fSStephan Aßmus #include "DebugSupport.h"
195a1d355fSStephan Aßmus #include "Directory.h"
205a1d355fSStephan Aßmus #include "Entry.h"
215a1d355fSStephan Aßmus #include "FDManager.h"
225a1d355fSStephan Aßmus #include "NodeHandle.h"
235a1d355fSStephan Aßmus #include "Path.h"
245a1d355fSStephan Aßmus #include "QueryDomain.h"
255a1d355fSStephan Aßmus #include "Volume.h"
265a1d355fSStephan Aßmus
275a1d355fSStephan Aßmus // TODO: We should filter recent events at some point. Otherwise we'll end up
285a1d355fSStephan Aßmus // with one event of each kind for each entry/node.
295a1d355fSStephan Aßmus
305a1d355fSStephan Aßmus const bigtime_t kRecentEventLifeTime = 100000; // 0.1 s
315a1d355fSStephan Aßmus
325a1d355fSStephan Aßmus // QueryHandler
335a1d355fSStephan Aßmus class VolumeManager::QueryHandler : public BHandler, public QueryListener,
345a1d355fSStephan Aßmus public BReferenceable {
355a1d355fSStephan Aßmus public:
QueryHandler(NodeMonitorListener * listener,QueryDomain * queryDomain,QueryHandle * handle)365a1d355fSStephan Aßmus QueryHandler(NodeMonitorListener* listener, QueryDomain* queryDomain,
375a1d355fSStephan Aßmus QueryHandle* handle)
385a1d355fSStephan Aßmus :
395a1d355fSStephan Aßmus BHandler(),
405a1d355fSStephan Aßmus QueryListener(),
4188e38c17SIngo Weinhold BReferenceable(),
425a1d355fSStephan Aßmus fListener(listener),
435a1d355fSStephan Aßmus fQueryDomain(queryDomain),
445a1d355fSStephan Aßmus fHandle(handle)
455a1d355fSStephan Aßmus {
465a1d355fSStephan Aßmus }
475a1d355fSStephan Aßmus
GetQueryDomain() const485a1d355fSStephan Aßmus QueryDomain* GetQueryDomain() const
495a1d355fSStephan Aßmus {
505a1d355fSStephan Aßmus return fQueryDomain;
515a1d355fSStephan Aßmus }
525a1d355fSStephan Aßmus
GetQueryHandle() const535a1d355fSStephan Aßmus QueryHandle* GetQueryHandle() const
545a1d355fSStephan Aßmus {
555a1d355fSStephan Aßmus return fHandle;
565a1d355fSStephan Aßmus }
575a1d355fSStephan Aßmus
MessageReceived(BMessage * message)585a1d355fSStephan Aßmus virtual void MessageReceived(BMessage* message)
595a1d355fSStephan Aßmus {
605a1d355fSStephan Aßmus switch (message->what) {
615a1d355fSStephan Aßmus case B_QUERY_UPDATE:
625a1d355fSStephan Aßmus {
635a1d355fSStephan Aßmus NodeMonitoringEvent* event = NULL;
645a1d355fSStephan Aßmus int32 opcode;
655a1d355fSStephan Aßmus if (message->FindInt32("opcode", &opcode) == B_OK) {
665a1d355fSStephan Aßmus switch (opcode) {
675a1d355fSStephan Aßmus case B_ENTRY_CREATED:
685a1d355fSStephan Aßmus event = new(std::nothrow) EntryCreatedEvent;
695a1d355fSStephan Aßmus break;
705a1d355fSStephan Aßmus case B_ENTRY_REMOVED:
715a1d355fSStephan Aßmus event = new(std::nothrow) EntryRemovedEvent;
725a1d355fSStephan Aßmus break;
735a1d355fSStephan Aßmus case B_ENTRY_MOVED:
745a1d355fSStephan Aßmus event = new(std::nothrow) EntryMovedEvent;
755a1d355fSStephan Aßmus break;
765a1d355fSStephan Aßmus }
775a1d355fSStephan Aßmus }
785a1d355fSStephan Aßmus if (event) {
795a1d355fSStephan Aßmus event->queryHandler = this;
8088e38c17SIngo Weinhold AcquireReference();
815a1d355fSStephan Aßmus if (event->Init(message) == B_OK)
825a1d355fSStephan Aßmus fListener->ProcessNodeMonitoringEvent(event);
835a1d355fSStephan Aßmus else
845a1d355fSStephan Aßmus delete event;
855a1d355fSStephan Aßmus }
865a1d355fSStephan Aßmus break;
875a1d355fSStephan Aßmus }
885a1d355fSStephan Aßmus default:
895a1d355fSStephan Aßmus BHandler::MessageReceived(message);
905a1d355fSStephan Aßmus }
915a1d355fSStephan Aßmus }
925a1d355fSStephan Aßmus
QueryHandleClosed(QueryHandle * handle)935a1d355fSStephan Aßmus virtual void QueryHandleClosed(QueryHandle* handle)
945a1d355fSStephan Aßmus {
955a1d355fSStephan Aßmus BLooper* looper = Looper();
965a1d355fSStephan Aßmus if (looper && looper->Lock()) {
975a1d355fSStephan Aßmus looper->RemoveHandler(this);
985a1d355fSStephan Aßmus looper->Unlock();
995a1d355fSStephan Aßmus }
1005a1d355fSStephan Aßmus handle->SetQueryListener(NULL);
10188e38c17SIngo Weinhold ReleaseReference();
1025a1d355fSStephan Aßmus }
1035a1d355fSStephan Aßmus
1045a1d355fSStephan Aßmus private:
1055a1d355fSStephan Aßmus NodeMonitorListener* fListener;
1065a1d355fSStephan Aßmus QueryDomain* fQueryDomain;
1075a1d355fSStephan Aßmus QueryHandle* fHandle;
1085a1d355fSStephan Aßmus };
1095a1d355fSStephan Aßmus
1105a1d355fSStephan Aßmus // VolumeMap
1115a1d355fSStephan Aßmus struct VolumeManager::VolumeMap : HashMap<HashKey32<dev_t>, Volume*> {
1125a1d355fSStephan Aßmus };
1135a1d355fSStephan Aßmus
1145a1d355fSStephan Aßmus // ClientVolumeMap
1155a1d355fSStephan Aßmus struct VolumeManager::ClientVolumeMap
1165a1d355fSStephan Aßmus : HashMap<HashKey32<int32>, ClientVolume*> {
1175a1d355fSStephan Aßmus };
1185a1d355fSStephan Aßmus
1195a1d355fSStephan Aßmus // private BeOS syscalls to set the FD and node monitor slot limits
1205a1d355fSStephan Aßmus extern "C" int _kset_fd_limit_(int num);
1215a1d355fSStephan Aßmus extern "C" int _kset_mon_limit_(int num);
1225a1d355fSStephan Aßmus
1235a1d355fSStephan Aßmus
1245a1d355fSStephan Aßmus // EntryCreatedEventMap
1255a1d355fSStephan Aßmus struct VolumeManager::EntryCreatedEventMap
1265a1d355fSStephan Aßmus : HashMap<EntryRef, EntryCreatedEvent*> {
1275a1d355fSStephan Aßmus };
1285a1d355fSStephan Aßmus
1295a1d355fSStephan Aßmus // EntryRemovedEventMap
1305a1d355fSStephan Aßmus struct VolumeManager::EntryRemovedEventMap
1315a1d355fSStephan Aßmus : HashMap<EntryRef, EntryRemovedEvent*> {
1325a1d355fSStephan Aßmus };
1335a1d355fSStephan Aßmus
1345a1d355fSStephan Aßmus // EntryMovedEventKey
1355a1d355fSStephan Aßmus struct EntryMovedEventKey : public EntryRef {
EntryMovedEventKeyEntryMovedEventKey1365a1d355fSStephan Aßmus EntryMovedEventKey()
1375a1d355fSStephan Aßmus {
1385a1d355fSStephan Aßmus }
1395a1d355fSStephan Aßmus
EntryMovedEventKeyEntryMovedEventKey1405a1d355fSStephan Aßmus EntryMovedEventKey(dev_t volumeID, ino_t fromDirectory,
1415a1d355fSStephan Aßmus const char* fromName, ino_t toDirectory, const char* toName)
1425a1d355fSStephan Aßmus : EntryRef(volumeID, fromDirectory, fromName),
1435a1d355fSStephan Aßmus toDirectory(toDirectory),
1445a1d355fSStephan Aßmus toName(toName)
1455a1d355fSStephan Aßmus {
1465a1d355fSStephan Aßmus
1475a1d355fSStephan Aßmus }
1485a1d355fSStephan Aßmus
GetHashCodeEntryMovedEventKey1495a1d355fSStephan Aßmus uint32 GetHashCode() const
1505a1d355fSStephan Aßmus {
1515a1d355fSStephan Aßmus uint32 hash = EntryRef::GetHashCode();
1525a1d355fSStephan Aßmus hash = 17 * hash + (uint32)(toDirectory >> 32);
1535a1d355fSStephan Aßmus hash = 17 * hash + (uint32)toDirectory;
1545a1d355fSStephan Aßmus hash = 17 * hash + string_hash(toName.GetString());
1555a1d355fSStephan Aßmus return hash;
1565a1d355fSStephan Aßmus }
1575a1d355fSStephan Aßmus
operator ==EntryMovedEventKey1585a1d355fSStephan Aßmus bool operator==(const EntryMovedEventKey& other) const
1595a1d355fSStephan Aßmus {
1605a1d355fSStephan Aßmus return (*(const EntryRef*)this) == other
1615a1d355fSStephan Aßmus && toDirectory == other.toDirectory
1625a1d355fSStephan Aßmus && toName == other.toName;
1635a1d355fSStephan Aßmus }
1645a1d355fSStephan Aßmus
operator !=EntryMovedEventKey1655a1d355fSStephan Aßmus bool operator!=(const EntryMovedEventKey& other) const
1665a1d355fSStephan Aßmus {
1675a1d355fSStephan Aßmus return !(*this == other);
1685a1d355fSStephan Aßmus }
1695a1d355fSStephan Aßmus
1705a1d355fSStephan Aßmus ino_t toDirectory;
1715a1d355fSStephan Aßmus HashString toName;
1725a1d355fSStephan Aßmus };
1735a1d355fSStephan Aßmus
1745a1d355fSStephan Aßmus // EntryMovedEventMap
1755a1d355fSStephan Aßmus struct VolumeManager::EntryMovedEventMap : HashMap<EntryRef, EntryMovedEvent*> {
1765a1d355fSStephan Aßmus };
1775a1d355fSStephan Aßmus
1785a1d355fSStephan Aßmus // NodeStatChangedEventMap
1795a1d355fSStephan Aßmus struct VolumeManager::NodeStatChangedEventMap
1805a1d355fSStephan Aßmus : HashMap<NodeRef, StatChangedEvent*> {
1815a1d355fSStephan Aßmus };
1825a1d355fSStephan Aßmus
1835a1d355fSStephan Aßmus typedef EntryRef AttributeRef;
1845a1d355fSStephan Aßmus
1855a1d355fSStephan Aßmus // NodeAttributeChangedEventMap
1865a1d355fSStephan Aßmus struct VolumeManager::NodeAttributeChangedEventMap
1875a1d355fSStephan Aßmus : HashMap<AttributeRef, AttributeChangedEvent*> {
1885a1d355fSStephan Aßmus };
1895a1d355fSStephan Aßmus
1905a1d355fSStephan Aßmus
1915a1d355fSStephan Aßmus // #pragma mark -
1925a1d355fSStephan Aßmus
1935a1d355fSStephan Aßmus // constructor
VolumeManager()1945a1d355fSStephan Aßmus VolumeManager::VolumeManager()
1955a1d355fSStephan Aßmus : fLock("volume manager"),
1965a1d355fSStephan Aßmus fVolumes(NULL),
1975a1d355fSStephan Aßmus fRootVolume(NULL),
1985a1d355fSStephan Aßmus fClientVolumes(NULL),
1995a1d355fSStephan Aßmus fNodeMonitor(NULL),
2005a1d355fSStephan Aßmus fNodeMonitoringProcessor(-1),
2015a1d355fSStephan Aßmus fNodeMonitoringEvents(),
2025a1d355fSStephan Aßmus fRecentNodeMonitoringEvents(),
2035a1d355fSStephan Aßmus fEntryCreatedEvents(NULL),
2045a1d355fSStephan Aßmus fEntryRemovedEvents(NULL),
2055a1d355fSStephan Aßmus fEntryMovedEvents(NULL),
2065a1d355fSStephan Aßmus fNodeStatChangedEvents(NULL),
2075a1d355fSStephan Aßmus fNodeAttributeChangedEvents(NULL),
2085a1d355fSStephan Aßmus fRevision(0),
2095a1d355fSStephan Aßmus fTerminating(false)
2105a1d355fSStephan Aßmus {
2115a1d355fSStephan Aßmus }
2125a1d355fSStephan Aßmus
2135a1d355fSStephan Aßmus // destructor
~VolumeManager()2145a1d355fSStephan Aßmus VolumeManager::~VolumeManager()
2155a1d355fSStephan Aßmus {
2165a1d355fSStephan Aßmus // terminate the node monitor and the node monitoring processor
2175a1d355fSStephan Aßmus fTerminating = true;
2185a1d355fSStephan Aßmus if (fNodeMonitor && fNodeMonitor->Lock())
2195a1d355fSStephan Aßmus fNodeMonitor->Quit();
2205a1d355fSStephan Aßmus fNodeMonitoringEvents.Close(true);
2215a1d355fSStephan Aßmus if (fNodeMonitoringProcessor >= 0) {
2225a1d355fSStephan Aßmus int32 result;
2235a1d355fSStephan Aßmus wait_for_thread(fNodeMonitoringProcessor, &result);
2245a1d355fSStephan Aßmus }
2255a1d355fSStephan Aßmus
2265a1d355fSStephan Aßmus // delete all events
2275a1d355fSStephan Aßmus // entry created events
2285a1d355fSStephan Aßmus for (EntryCreatedEventMap::Iterator it = fEntryCreatedEvents->GetIterator();
2295a1d355fSStephan Aßmus it.HasNext();) {
23088e38c17SIngo Weinhold it.Next().value->ReleaseReference();
2315a1d355fSStephan Aßmus }
2325a1d355fSStephan Aßmus delete fEntryCreatedEvents;
2335a1d355fSStephan Aßmus
2345a1d355fSStephan Aßmus // entry removed events
2355a1d355fSStephan Aßmus for (EntryRemovedEventMap::Iterator it = fEntryRemovedEvents->GetIterator();
2365a1d355fSStephan Aßmus it.HasNext();) {
23788e38c17SIngo Weinhold it.Next().value->ReleaseReference();
2385a1d355fSStephan Aßmus }
2395a1d355fSStephan Aßmus delete fEntryRemovedEvents;
2405a1d355fSStephan Aßmus
2415a1d355fSStephan Aßmus // entry moved events
2425a1d355fSStephan Aßmus for (EntryMovedEventMap::Iterator it = fEntryMovedEvents->GetIterator();
2435a1d355fSStephan Aßmus it.HasNext();) {
24488e38c17SIngo Weinhold it.Next().value->ReleaseReference();
2455a1d355fSStephan Aßmus }
2465a1d355fSStephan Aßmus delete fEntryMovedEvents;
2475a1d355fSStephan Aßmus
2485a1d355fSStephan Aßmus // stat changed events
2495a1d355fSStephan Aßmus for (NodeStatChangedEventMap::Iterator it
2505a1d355fSStephan Aßmus = fNodeStatChangedEvents->GetIterator();
2515a1d355fSStephan Aßmus it.HasNext();) {
25288e38c17SIngo Weinhold it.Next().value->ReleaseReference();
2535a1d355fSStephan Aßmus }
2545a1d355fSStephan Aßmus delete fNodeStatChangedEvents;
2555a1d355fSStephan Aßmus
2565a1d355fSStephan Aßmus // attribute changed events
2575a1d355fSStephan Aßmus for (NodeAttributeChangedEventMap::Iterator it
2585a1d355fSStephan Aßmus = fNodeAttributeChangedEvents->GetIterator();
2595a1d355fSStephan Aßmus it.HasNext();) {
26088e38c17SIngo Weinhold it.Next().value->ReleaseReference();
2615a1d355fSStephan Aßmus }
2625a1d355fSStephan Aßmus delete fNodeAttributeChangedEvents;
2635a1d355fSStephan Aßmus
2645a1d355fSStephan Aßmus delete fClientVolumes;
2655a1d355fSStephan Aßmus
2665a1d355fSStephan Aßmus // delete the volumes
2675a1d355fSStephan Aßmus for (VolumeMap::Iterator it = fVolumes->GetIterator(); it.HasNext();) {
2685a1d355fSStephan Aßmus Volume* volume = it.Next().value;
2695a1d355fSStephan Aßmus delete volume;
2705a1d355fSStephan Aßmus }
2715a1d355fSStephan Aßmus delete fVolumes;
2725a1d355fSStephan Aßmus }
2735a1d355fSStephan Aßmus
2745a1d355fSStephan Aßmus // Init
2755a1d355fSStephan Aßmus status_t
Init()2765a1d355fSStephan Aßmus VolumeManager::Init()
2775a1d355fSStephan Aßmus {
2785a1d355fSStephan Aßmus // check node monitoring message queue
2795a1d355fSStephan Aßmus status_t error = fNodeMonitoringEvents.InitCheck();
2805a1d355fSStephan Aßmus if (error != B_OK)
2815a1d355fSStephan Aßmus return error;
2825a1d355fSStephan Aßmus
2835a1d355fSStephan Aßmus // entry created event map
2845a1d355fSStephan Aßmus fEntryCreatedEvents = new(std::nothrow) EntryCreatedEventMap;
2855a1d355fSStephan Aßmus if (!fEntryCreatedEvents)
2865a1d355fSStephan Aßmus return B_NO_MEMORY;
2875a1d355fSStephan Aßmus
2885a1d355fSStephan Aßmus // entry removed event map
2895a1d355fSStephan Aßmus fEntryRemovedEvents = new(std::nothrow) EntryRemovedEventMap;
2905a1d355fSStephan Aßmus if (!fEntryRemovedEvents)
2915a1d355fSStephan Aßmus return B_NO_MEMORY;
2925a1d355fSStephan Aßmus
2935a1d355fSStephan Aßmus // entry moved event map
2945a1d355fSStephan Aßmus fEntryMovedEvents = new(std::nothrow) EntryMovedEventMap;
2955a1d355fSStephan Aßmus if (!fEntryMovedEvents)
2965a1d355fSStephan Aßmus return B_NO_MEMORY;
2975a1d355fSStephan Aßmus
2985a1d355fSStephan Aßmus // node stat changed event map
2995a1d355fSStephan Aßmus fNodeStatChangedEvents = new(std::nothrow) NodeStatChangedEventMap;
3005a1d355fSStephan Aßmus if (!fNodeStatChangedEvents)
3015a1d355fSStephan Aßmus return B_NO_MEMORY;
3025a1d355fSStephan Aßmus
3035a1d355fSStephan Aßmus // node attribute changed event map
3045a1d355fSStephan Aßmus fNodeAttributeChangedEvents = new(std::nothrow) NodeAttributeChangedEventMap;
3055a1d355fSStephan Aßmus if (!fNodeAttributeChangedEvents)
3065a1d355fSStephan Aßmus return B_NO_MEMORY;
3075a1d355fSStephan Aßmus
3085a1d355fSStephan Aßmus // create the node monitor
3095a1d355fSStephan Aßmus fNodeMonitor = new(std::nothrow) NodeMonitor(this);
3105a1d355fSStephan Aßmus if (!fNodeMonitor)
3115a1d355fSStephan Aßmus return B_NO_MEMORY;
3125a1d355fSStephan Aßmus
3135a1d355fSStephan Aßmus // create the volume map
3145a1d355fSStephan Aßmus fVolumes = new(std::nothrow) VolumeMap;
3155a1d355fSStephan Aßmus if (!fVolumes)
3165a1d355fSStephan Aßmus return B_NO_MEMORY;
3175a1d355fSStephan Aßmus if (fVolumes->InitCheck() != B_OK)
3185a1d355fSStephan Aßmus return fVolumes->InitCheck();
3195a1d355fSStephan Aßmus
3205a1d355fSStephan Aßmus // create the client volume map
3215a1d355fSStephan Aßmus fClientVolumes = new(std::nothrow) ClientVolumeMap;
3225a1d355fSStephan Aßmus if (!fClientVolumes)
3235a1d355fSStephan Aßmus return B_NO_MEMORY;
3245a1d355fSStephan Aßmus if (fClientVolumes->InitCheck() != B_OK)
3255a1d355fSStephan Aßmus return fClientVolumes->InitCheck();
3265a1d355fSStephan Aßmus
3275a1d355fSStephan Aßmus // start the node monitor
3285a1d355fSStephan Aßmus thread_id monitorThread = fNodeMonitor->Run();
3295a1d355fSStephan Aßmus if (monitorThread < 0) {
3305a1d355fSStephan Aßmus delete fNodeMonitor;
3315a1d355fSStephan Aßmus fNodeMonitor = NULL;
3325a1d355fSStephan Aßmus return monitorThread;
3335a1d355fSStephan Aßmus }
3345a1d355fSStephan Aßmus
3355a1d355fSStephan Aßmus // create all volumes
3365a1d355fSStephan Aßmus int32 cookie = 0;
3375a1d355fSStephan Aßmus dev_t volumeID;
3385a1d355fSStephan Aßmus while ((volumeID = next_dev(&cookie)) >= 0)
3395a1d355fSStephan Aßmus _AddVolume(volumeID);
3405a1d355fSStephan Aßmus
3415a1d355fSStephan Aßmus // get the root volume
3425a1d355fSStephan Aßmus volumeID = dev_for_path("/");
3435a1d355fSStephan Aßmus if (volumeID < 0)
3445a1d355fSStephan Aßmus return volumeID;
3455a1d355fSStephan Aßmus fRootVolume = GetVolume(volumeID, true);
3465a1d355fSStephan Aßmus if (!fRootVolume)
3475a1d355fSStephan Aßmus return B_ERROR;
3485a1d355fSStephan Aßmus
3495a1d355fSStephan Aßmus // spawn the node monitoring message processor
3505a1d355fSStephan Aßmus fNodeMonitoringProcessor = spawn_thread(&_NodeMonitoringProcessorEntry,
3515a1d355fSStephan Aßmus "node monitoring processor", B_NORMAL_PRIORITY, this);
3525a1d355fSStephan Aßmus if (fNodeMonitoringProcessor < 0)
3535a1d355fSStephan Aßmus return fNodeMonitoringProcessor;
3545a1d355fSStephan Aßmus resume_thread(fNodeMonitoringProcessor);
3555a1d355fSStephan Aßmus
3565a1d355fSStephan Aßmus return B_OK;
3575a1d355fSStephan Aßmus }
3585a1d355fSStephan Aßmus
3595a1d355fSStephan Aßmus // GetRootVolume
3605a1d355fSStephan Aßmus Volume*
GetRootVolume() const3615a1d355fSStephan Aßmus VolumeManager::GetRootVolume() const
3625a1d355fSStephan Aßmus {
3635a1d355fSStephan Aßmus return fRootVolume;
3645a1d355fSStephan Aßmus }
3655a1d355fSStephan Aßmus
3665a1d355fSStephan Aßmus // AddClientVolume
3675a1d355fSStephan Aßmus status_t
AddClientVolume(ClientVolume * clientVolume)3685a1d355fSStephan Aßmus VolumeManager::AddClientVolume(ClientVolume* clientVolume)
3695a1d355fSStephan Aßmus {
3705a1d355fSStephan Aßmus if (!clientVolume)
3715a1d355fSStephan Aßmus return B_BAD_VALUE;
3725a1d355fSStephan Aßmus
3735a1d355fSStephan Aßmus return fClientVolumes->Put(clientVolume->GetID(), clientVolume);
3745a1d355fSStephan Aßmus }
3755a1d355fSStephan Aßmus
3765a1d355fSStephan Aßmus // RemoveClientVolume
3775a1d355fSStephan Aßmus void
RemoveClientVolume(ClientVolume * clientVolume)3785a1d355fSStephan Aßmus VolumeManager::RemoveClientVolume(ClientVolume* clientVolume)
3795a1d355fSStephan Aßmus {
3805a1d355fSStephan Aßmus if (!clientVolume)
3815a1d355fSStephan Aßmus return;
3825a1d355fSStephan Aßmus
3835a1d355fSStephan Aßmus fClientVolumes->Remove(clientVolume->GetID());
3845a1d355fSStephan Aßmus }
3855a1d355fSStephan Aßmus
3865a1d355fSStephan Aßmus // CreateDefault
3875a1d355fSStephan Aßmus status_t
CreateDefault()3885a1d355fSStephan Aßmus VolumeManager::CreateDefault()
3895a1d355fSStephan Aßmus {
3905a1d355fSStephan Aßmus if (sManager)
3915a1d355fSStephan Aßmus return B_OK;
3925a1d355fSStephan Aßmus
3935a1d355fSStephan Aßmus VolumeManager* manager = new(std::nothrow) VolumeManager;
3945a1d355fSStephan Aßmus if (!manager)
3955a1d355fSStephan Aßmus return B_NO_MEMORY;
3965a1d355fSStephan Aßmus
3975a1d355fSStephan Aßmus status_t error = manager->Init();
3985a1d355fSStephan Aßmus if (error != B_OK) {
3995a1d355fSStephan Aßmus delete manager;
4005a1d355fSStephan Aßmus return error;
4015a1d355fSStephan Aßmus }
4025a1d355fSStephan Aßmus
4035a1d355fSStephan Aßmus sManager = manager;
4045a1d355fSStephan Aßmus return B_OK;
4055a1d355fSStephan Aßmus }
4065a1d355fSStephan Aßmus
4075a1d355fSStephan Aßmus // DeleteDefault
4085a1d355fSStephan Aßmus void
DeleteDefault()4095a1d355fSStephan Aßmus VolumeManager::DeleteDefault()
4105a1d355fSStephan Aßmus {
4115a1d355fSStephan Aßmus if (sManager) {
4125a1d355fSStephan Aßmus delete sManager;
4135a1d355fSStephan Aßmus sManager = NULL;
4145a1d355fSStephan Aßmus }
4155a1d355fSStephan Aßmus }
4165a1d355fSStephan Aßmus
4175a1d355fSStephan Aßmus // GetDefault
4185a1d355fSStephan Aßmus VolumeManager*
GetDefault()4195a1d355fSStephan Aßmus VolumeManager::GetDefault()
4205a1d355fSStephan Aßmus {
4215a1d355fSStephan Aßmus return sManager;
4225a1d355fSStephan Aßmus }
4235a1d355fSStephan Aßmus
4245a1d355fSStephan Aßmus // Lock
4255a1d355fSStephan Aßmus bool
Lock()4265a1d355fSStephan Aßmus VolumeManager::Lock()
4275a1d355fSStephan Aßmus {
4285a1d355fSStephan Aßmus bool alreadyLocked = fLock.IsLocked();
4295a1d355fSStephan Aßmus
4305a1d355fSStephan Aßmus bool success = fLock.Lock();
4315a1d355fSStephan Aßmus
4325a1d355fSStephan Aßmus // If locking was successful and we didn't have a lock before, we increment
4335a1d355fSStephan Aßmus // the revision.
4345a1d355fSStephan Aßmus if (success && !alreadyLocked)
4355a1d355fSStephan Aßmus fRevision++;
4365a1d355fSStephan Aßmus
4375a1d355fSStephan Aßmus return success;
4385a1d355fSStephan Aßmus }
4395a1d355fSStephan Aßmus
4405a1d355fSStephan Aßmus // Unlock
4415a1d355fSStephan Aßmus void
Unlock()4425a1d355fSStephan Aßmus VolumeManager::Unlock()
4435a1d355fSStephan Aßmus {
4445a1d355fSStephan Aßmus return fLock.Unlock();
4455a1d355fSStephan Aßmus }
4465a1d355fSStephan Aßmus
4475a1d355fSStephan Aßmus // GetRevision
4485a1d355fSStephan Aßmus int64
GetRevision() const4495a1d355fSStephan Aßmus VolumeManager::GetRevision() const
4505a1d355fSStephan Aßmus {
4515a1d355fSStephan Aßmus return fRevision;
4525a1d355fSStephan Aßmus }
4535a1d355fSStephan Aßmus
4545a1d355fSStephan Aßmus // GetVolume
4555a1d355fSStephan Aßmus Volume*
GetVolume(dev_t volumeID,bool add)4565a1d355fSStephan Aßmus VolumeManager::GetVolume(dev_t volumeID, bool add)
4575a1d355fSStephan Aßmus {
4585a1d355fSStephan Aßmus Volume* volume = fVolumes->Get(volumeID);
4595a1d355fSStephan Aßmus if (!volume && add)
4605a1d355fSStephan Aßmus _AddVolume(volumeID, &volume);
4615a1d355fSStephan Aßmus
4625a1d355fSStephan Aßmus return volume;
4635a1d355fSStephan Aßmus }
4645a1d355fSStephan Aßmus
4655a1d355fSStephan Aßmus
4665a1d355fSStephan Aßmus // #pragma mark -
4675a1d355fSStephan Aßmus
4685a1d355fSStephan Aßmus // AddNode
4695a1d355fSStephan Aßmus status_t
AddNode(Node * node)4705a1d355fSStephan Aßmus VolumeManager::AddNode(Node* node)
4715a1d355fSStephan Aßmus {
4725a1d355fSStephan Aßmus if (!node || !node->GetVolume())
4735a1d355fSStephan Aßmus return B_BAD_VALUE;
4745a1d355fSStephan Aßmus
4755a1d355fSStephan Aßmus status_t error = node->GetVolume()->AddNode(node);
4765a1d355fSStephan Aßmus
4775a1d355fSStephan Aßmus // start watching the node
4785a1d355fSStephan Aßmus if (error == B_OK)
4795a1d355fSStephan Aßmus fNodeMonitor->StartWatching(node->GetNodeRef());
4805a1d355fSStephan Aßmus
4815a1d355fSStephan Aßmus return error;
4825a1d355fSStephan Aßmus }
4835a1d355fSStephan Aßmus
4845a1d355fSStephan Aßmus // RemoveNode
4855a1d355fSStephan Aßmus void
RemoveNode(Node * node)4865a1d355fSStephan Aßmus VolumeManager::RemoveNode(Node* node)
4875a1d355fSStephan Aßmus {
4885a1d355fSStephan Aßmus if (!node)
4895a1d355fSStephan Aßmus return;
4905a1d355fSStephan Aßmus
4915a1d355fSStephan Aßmus // if the node is a directory, we remove all its entries first
4925a1d355fSStephan Aßmus if (Directory* directory = dynamic_cast<Directory*>(node)) {
4935a1d355fSStephan Aßmus while (Entry* entry = directory->GetFirstEntry()) {
4945a1d355fSStephan Aßmus RemoveEntry(entry);
4955a1d355fSStephan Aßmus delete entry;
4965a1d355fSStephan Aßmus }
4975a1d355fSStephan Aßmus }
4985a1d355fSStephan Aßmus
4995a1d355fSStephan Aßmus // remove all referring entries
5005a1d355fSStephan Aßmus while (Entry* entry = node->GetFirstReferringEntry())
5015a1d355fSStephan Aßmus RemoveEntry(entry);
5025a1d355fSStephan Aßmus
5035a1d355fSStephan Aßmus // remove the node from the volume
5045a1d355fSStephan Aßmus if (node->GetVolume())
5055a1d355fSStephan Aßmus node->GetVolume()->RemoveNode(node);
5065a1d355fSStephan Aßmus
5075a1d355fSStephan Aßmus // stop watching the node
5085a1d355fSStephan Aßmus fNodeMonitor->StopWatching(node->GetNodeRef());
5095a1d355fSStephan Aßmus }
5105a1d355fSStephan Aßmus
5115a1d355fSStephan Aßmus // GetNode
5125a1d355fSStephan Aßmus Node*
GetNode(dev_t volumeID,ino_t nodeID)5135a1d355fSStephan Aßmus VolumeManager::GetNode(dev_t volumeID, ino_t nodeID)
5145a1d355fSStephan Aßmus {
5155a1d355fSStephan Aßmus if (Volume* volume = GetVolume(volumeID))
5165a1d355fSStephan Aßmus return volume->GetNode(nodeID);
5175a1d355fSStephan Aßmus return NULL;
5185a1d355fSStephan Aßmus }
5195a1d355fSStephan Aßmus
5205a1d355fSStephan Aßmus // LoadNode
5215a1d355fSStephan Aßmus status_t
LoadNode(const struct stat & st,Node ** _node)5225a1d355fSStephan Aßmus VolumeManager::LoadNode(const struct stat& st, Node** _node)
5235a1d355fSStephan Aßmus {
5245a1d355fSStephan Aßmus Node* node = GetNode(st.st_dev, st.st_ino);
5255a1d355fSStephan Aßmus if (!node) {
5265a1d355fSStephan Aßmus // node not known yet: create it
5275a1d355fSStephan Aßmus
5285a1d355fSStephan Aßmus // get the volume
5295a1d355fSStephan Aßmus Volume* volume = GetVolume(st.st_dev, true);
5305a1d355fSStephan Aßmus if (!volume)
5315a1d355fSStephan Aßmus return B_BAD_VALUE;
5325a1d355fSStephan Aßmus
5335a1d355fSStephan Aßmus // create the node
5345a1d355fSStephan Aßmus if (S_ISDIR(st.st_mode))
5355a1d355fSStephan Aßmus node = new(std::nothrow) Directory(volume, st);
5365a1d355fSStephan Aßmus else
5375a1d355fSStephan Aßmus node = new(std::nothrow) Node(volume, st);
5385a1d355fSStephan Aßmus if (!node)
5395a1d355fSStephan Aßmus return B_NO_MEMORY;
5405a1d355fSStephan Aßmus
5415a1d355fSStephan Aßmus // add it
5425a1d355fSStephan Aßmus status_t error = AddNode(node);
5435a1d355fSStephan Aßmus if (error != B_OK) {
5445a1d355fSStephan Aßmus delete node;
5455a1d355fSStephan Aßmus return error;
5465a1d355fSStephan Aßmus }
5475a1d355fSStephan Aßmus }
5485a1d355fSStephan Aßmus
5495a1d355fSStephan Aßmus if (_node)
5505a1d355fSStephan Aßmus *_node = node;
5515a1d355fSStephan Aßmus return B_OK;
5525a1d355fSStephan Aßmus }
5535a1d355fSStephan Aßmus
5545a1d355fSStephan Aßmus
5555a1d355fSStephan Aßmus // #pragma mark -
5565a1d355fSStephan Aßmus
5575a1d355fSStephan Aßmus // GetDirectory
5585a1d355fSStephan Aßmus Directory*
GetDirectory(dev_t volumeID,ino_t nodeID)5595a1d355fSStephan Aßmus VolumeManager::GetDirectory(dev_t volumeID, ino_t nodeID)
5605a1d355fSStephan Aßmus {
5615a1d355fSStephan Aßmus return dynamic_cast<Directory*>(GetNode(volumeID, nodeID));
5625a1d355fSStephan Aßmus }
5635a1d355fSStephan Aßmus
5645a1d355fSStephan Aßmus // GetRootDirectory
5655a1d355fSStephan Aßmus Directory*
GetRootDirectory() const5665a1d355fSStephan Aßmus VolumeManager::GetRootDirectory() const
5675a1d355fSStephan Aßmus {
5685a1d355fSStephan Aßmus return (fRootVolume ? fRootVolume->GetRootDirectory() : NULL);
5695a1d355fSStephan Aßmus }
5705a1d355fSStephan Aßmus
5715a1d355fSStephan Aßmus // GetParentDirectory
5725a1d355fSStephan Aßmus Directory*
GetParentDirectory(Directory * directory)5735a1d355fSStephan Aßmus VolumeManager::GetParentDirectory(Directory* directory)
5745a1d355fSStephan Aßmus {
5755a1d355fSStephan Aßmus if (!directory)
5765a1d355fSStephan Aßmus return NULL;
5775a1d355fSStephan Aßmus
5785a1d355fSStephan Aßmus // get ".." entry
5795a1d355fSStephan Aßmus Entry* parentEntry;
5805a1d355fSStephan Aßmus if (LoadEntry(directory->GetVolumeID(), directory->GetID(), "..", true,
5815a1d355fSStephan Aßmus &parentEntry) != B_OK) {
5825a1d355fSStephan Aßmus return NULL;
5835a1d355fSStephan Aßmus }
5845a1d355fSStephan Aßmus
5855a1d355fSStephan Aßmus return dynamic_cast<Directory*>(parentEntry->GetNode());
5865a1d355fSStephan Aßmus }
5875a1d355fSStephan Aßmus
5885a1d355fSStephan Aßmus // LoadDirectory
5895a1d355fSStephan Aßmus status_t
LoadDirectory(dev_t volumeID,ino_t directoryID,Directory ** _directory)5905a1d355fSStephan Aßmus VolumeManager::LoadDirectory(dev_t volumeID, ino_t directoryID,
5915a1d355fSStephan Aßmus Directory** _directory)
5925a1d355fSStephan Aßmus {
5935a1d355fSStephan Aßmus // try to get the node
5945a1d355fSStephan Aßmus Node* node = GetNode(volumeID, directoryID);
5955a1d355fSStephan Aßmus bool newNode = false;
5965a1d355fSStephan Aßmus if (!node) {
5975a1d355fSStephan Aßmus // directory not yet loaded: stat it
5985a1d355fSStephan Aßmus NoAllocEntryRef entryRef(volumeID, directoryID, ".");
5995a1d355fSStephan Aßmus struct stat st;
6005a1d355fSStephan Aßmus BEntry bEntry;
6015a1d355fSStephan Aßmus status_t error = FDManager::SetEntry(&bEntry, &entryRef);
6025a1d355fSStephan Aßmus if (error == B_OK)
6035a1d355fSStephan Aßmus error = bEntry.GetStat(&st);
6045a1d355fSStephan Aßmus if (error != B_OK)
6055a1d355fSStephan Aßmus return error;
6065a1d355fSStephan Aßmus
6075a1d355fSStephan Aßmus // load the node
6085a1d355fSStephan Aßmus error = LoadNode(st, &node);
6095a1d355fSStephan Aßmus if (error != B_OK)
6105a1d355fSStephan Aßmus return error;
6115a1d355fSStephan Aßmus
6125a1d355fSStephan Aßmus newNode = true;
6135a1d355fSStephan Aßmus }
6145a1d355fSStephan Aßmus
6155a1d355fSStephan Aßmus // check, if the node is a directory
6165a1d355fSStephan Aßmus Directory* directory = dynamic_cast<Directory*>(node);
6175a1d355fSStephan Aßmus if (!directory)
6185a1d355fSStephan Aßmus return B_NOT_A_DIRECTORY;
6195a1d355fSStephan Aßmus
6205a1d355fSStephan Aßmus if (newNode)
6215a1d355fSStephan Aßmus CompletePathToRoot(directory);
6225a1d355fSStephan Aßmus
6235a1d355fSStephan Aßmus if (_directory)
6245a1d355fSStephan Aßmus *_directory = directory;
6255a1d355fSStephan Aßmus return B_OK;
6265a1d355fSStephan Aßmus }
6275a1d355fSStephan Aßmus
6285a1d355fSStephan Aßmus
6295a1d355fSStephan Aßmus // #pragma mark -
6305a1d355fSStephan Aßmus
6315a1d355fSStephan Aßmus // AddEntry
6325a1d355fSStephan Aßmus status_t
AddEntry(Entry * entry)6335a1d355fSStephan Aßmus VolumeManager::AddEntry(Entry* entry)
6345a1d355fSStephan Aßmus {
6355a1d355fSStephan Aßmus if (!entry || !entry->GetVolume() || !entry->GetDirectory()
6365a1d355fSStephan Aßmus || ! entry->GetNode()) {
6375a1d355fSStephan Aßmus return B_BAD_VALUE;
6385a1d355fSStephan Aßmus }
6395a1d355fSStephan Aßmus
6405a1d355fSStephan Aßmus // add the entry to the volume
6415a1d355fSStephan Aßmus status_t error = entry->GetVolume()->AddEntry(entry);
6425a1d355fSStephan Aßmus if (error != B_OK)
6435a1d355fSStephan Aßmus return error;
6445a1d355fSStephan Aßmus
6455a1d355fSStephan Aßmus // add the entry to its directory and node
6465a1d355fSStephan Aßmus entry->GetDirectory()->AddEntry(entry);
6475a1d355fSStephan Aßmus entry->GetNode()->AddReferringEntry(entry);
6485a1d355fSStephan Aßmus
6495a1d355fSStephan Aßmus //PRINT(("VolumeManager::AddEntry(): %ld, %lld, `%s', dir: %p, "
6505a1d355fSStephan Aßmus //"entry count: %ld\n", entry->GetVolumeID(), entry->GetDirectoryID(),
6515a1d355fSStephan Aßmus //entry->GetName(), entry->GetDirectory(),
6525a1d355fSStephan Aßmus //entry->GetDirectory()->CountEntries()));
6535a1d355fSStephan Aßmus
6545a1d355fSStephan Aßmus return B_OK;
6555a1d355fSStephan Aßmus }
6565a1d355fSStephan Aßmus
6575a1d355fSStephan Aßmus // RemoveEntry
6585a1d355fSStephan Aßmus void
RemoveEntry(Entry * entry)6595a1d355fSStephan Aßmus VolumeManager::RemoveEntry(Entry* entry)
6605a1d355fSStephan Aßmus {
6615a1d355fSStephan Aßmus if (entry) {
6625a1d355fSStephan Aßmus // remove the entry from the volume
6635a1d355fSStephan Aßmus if (entry->GetVolume())
6645a1d355fSStephan Aßmus entry->GetVolume()->RemoveEntry(entry);
6655a1d355fSStephan Aßmus
6665a1d355fSStephan Aßmus // remove the entry from the directory and its node
6675a1d355fSStephan Aßmus entry->GetDirectory()->RemoveEntry(entry);
6685a1d355fSStephan Aßmus entry->GetNode()->RemoveReferringEntry(entry);
6695a1d355fSStephan Aßmus
6705a1d355fSStephan Aßmus //PRINT(("VolumeManager::RemoveEntry(): %ld, %lld, `%s', dir: %p, "
6715a1d355fSStephan Aßmus //"entry count: %ld\n", entry->GetVolumeID(), entry->GetDirectoryID(),
6725a1d355fSStephan Aßmus //entry->GetName(), entry->GetDirectory(),
6735a1d355fSStephan Aßmus //entry->GetDirectory()->CountEntries()));
6745a1d355fSStephan Aßmus }
6755a1d355fSStephan Aßmus }
6765a1d355fSStephan Aßmus
6775a1d355fSStephan Aßmus // DeleteEntry
6785a1d355fSStephan Aßmus void
DeleteEntry(Entry * entry,bool keepNode)6795a1d355fSStephan Aßmus VolumeManager::DeleteEntry(Entry* entry, bool keepNode)
6805a1d355fSStephan Aßmus {
6815a1d355fSStephan Aßmus if (!entry)
6825a1d355fSStephan Aßmus return;
6835a1d355fSStephan Aßmus
6845a1d355fSStephan Aßmus Node* node = entry->GetNode();
6855a1d355fSStephan Aßmus
6865a1d355fSStephan Aßmus // remove the entry
6875a1d355fSStephan Aßmus RemoveEntry(entry);
6885a1d355fSStephan Aßmus delete entry;
6895a1d355fSStephan Aßmus
6905a1d355fSStephan Aßmus // remove the node, if it doesn't have any more actual referring entries
6915a1d355fSStephan Aßmus if (!keepNode && !node->GetActualReferringEntry()) {
6925a1d355fSStephan Aßmus RemoveNode(node);
6935a1d355fSStephan Aßmus if (node != node->GetVolume()->GetRootDirectory())
6945a1d355fSStephan Aßmus delete node;
6955a1d355fSStephan Aßmus }
6965a1d355fSStephan Aßmus }
6975a1d355fSStephan Aßmus
6985a1d355fSStephan Aßmus // GetEntry
6995a1d355fSStephan Aßmus Entry*
GetEntry(dev_t volumeID,ino_t directoryID,const char * name)7005a1d355fSStephan Aßmus VolumeManager::GetEntry(dev_t volumeID, ino_t directoryID, const char* name)
7015a1d355fSStephan Aßmus {
7025a1d355fSStephan Aßmus if (Volume* volume = GetVolume(volumeID))
7035a1d355fSStephan Aßmus return volume->GetEntry(directoryID, name);
7045a1d355fSStephan Aßmus return NULL;
7055a1d355fSStephan Aßmus }
7065a1d355fSStephan Aßmus
7075a1d355fSStephan Aßmus // GetEntry
7085a1d355fSStephan Aßmus Entry*
GetEntry(const entry_ref & ref)7095a1d355fSStephan Aßmus VolumeManager::GetEntry(const entry_ref& ref)
7105a1d355fSStephan Aßmus {
7115a1d355fSStephan Aßmus return GetEntry(ref.device, ref.directory, ref.name);
7125a1d355fSStephan Aßmus }
7135a1d355fSStephan Aßmus
7145a1d355fSStephan Aßmus // LoadEntry
7155a1d355fSStephan Aßmus status_t
LoadEntry(dev_t volumeID,ino_t directoryID,const char * name,bool loadDir,Entry ** _entry)7165a1d355fSStephan Aßmus VolumeManager::LoadEntry(dev_t volumeID, ino_t directoryID, const char* name,
7175a1d355fSStephan Aßmus bool loadDir, Entry** _entry)
7185a1d355fSStephan Aßmus {
7195a1d355fSStephan Aßmus Entry* entry = GetEntry(volumeID, directoryID, name);
7205a1d355fSStephan Aßmus if (!entry) {
7215a1d355fSStephan Aßmus // entry not known yet: create it
722*ebb21bd1SMurai Takashi PRINT("VolumeManager::LoadEntry(%" B_PRIdDEV ", "
723*ebb21bd1SMurai Takashi "%" B_PRIdINO ", `%s')\n", volumeID, directoryID, name);
7245a1d355fSStephan Aßmus
7255a1d355fSStephan Aßmus // get the volume
7265a1d355fSStephan Aßmus Volume* volume = GetVolume(volumeID, true);
7275a1d355fSStephan Aßmus if (!volume)
7285a1d355fSStephan Aßmus return B_BAD_VALUE;
7295a1d355fSStephan Aßmus
7305a1d355fSStephan Aßmus // get the directory
7315a1d355fSStephan Aßmus status_t error = B_OK;
7325a1d355fSStephan Aßmus Directory* directory = GetDirectory(volumeID, directoryID);
7335a1d355fSStephan Aßmus if (!directory) {
7345a1d355fSStephan Aßmus if (!loadDir)
7355a1d355fSStephan Aßmus return B_ENTRY_NOT_FOUND;
7365a1d355fSStephan Aßmus
7375a1d355fSStephan Aßmus //PRINT((" loading directory...\n"));
7385a1d355fSStephan Aßmus // load the directory
7395a1d355fSStephan Aßmus error = LoadDirectory(volumeID, directoryID, &directory);
7405a1d355fSStephan Aßmus if (error != B_OK)
7415a1d355fSStephan Aßmus return error;
7425a1d355fSStephan Aßmus }
7435a1d355fSStephan Aßmus
7445a1d355fSStephan Aßmus //PRINT((" opening BNode...\n"));
7455a1d355fSStephan Aßmus // stat the entry
7465a1d355fSStephan Aßmus NoAllocEntryRef entryRef(volumeID, directoryID, name);
7475a1d355fSStephan Aßmus struct stat st;
7485a1d355fSStephan Aßmus BNode bNode;
7495a1d355fSStephan Aßmus error = bNode.SetTo(&entryRef);
7505a1d355fSStephan Aßmus //PRINT((" stat()ing BNode...\n"));
7515a1d355fSStephan Aßmus if (error == B_OK)
7525a1d355fSStephan Aßmus error = bNode.GetStat(&st);
7535a1d355fSStephan Aßmus if (error != B_OK)
7545a1d355fSStephan Aßmus return error;
7555a1d355fSStephan Aßmus
7565a1d355fSStephan Aßmus //PRINT((" loading node...\n"));
7575a1d355fSStephan Aßmus // load the node
7585a1d355fSStephan Aßmus Node* node;
7595a1d355fSStephan Aßmus error = LoadNode(st, &node);
7605a1d355fSStephan Aßmus if (error != B_OK)
7615a1d355fSStephan Aßmus return error;
7625a1d355fSStephan Aßmus
7635a1d355fSStephan Aßmus //PRINT((" creating and adding entry...\n"));
7645a1d355fSStephan Aßmus // create the entry
7655a1d355fSStephan Aßmus entry = new(std::nothrow) Entry(volume, directory, name, node);
7665a1d355fSStephan Aßmus if (!entry)
7675a1d355fSStephan Aßmus return B_NO_MEMORY;
7685a1d355fSStephan Aßmus
7695a1d355fSStephan Aßmus // add it
7705a1d355fSStephan Aßmus error = AddEntry(entry);
7715a1d355fSStephan Aßmus if (error != B_OK) {
7725a1d355fSStephan Aßmus delete entry;
7735a1d355fSStephan Aßmus return error;
7745a1d355fSStephan Aßmus }
7755a1d355fSStephan Aßmus //PRINT((" adding entry done\n"));
7765a1d355fSStephan Aßmus }
7775a1d355fSStephan Aßmus
7785a1d355fSStephan Aßmus if (_entry)
7795a1d355fSStephan Aßmus *_entry = entry;
7805a1d355fSStephan Aßmus return B_OK;
7815a1d355fSStephan Aßmus }
7825a1d355fSStephan Aßmus
7835a1d355fSStephan Aßmus
7845a1d355fSStephan Aßmus // #pragma mark -
7855a1d355fSStephan Aßmus
7865a1d355fSStephan Aßmus // OpenQuery
7875a1d355fSStephan Aßmus status_t
OpenQuery(QueryDomain * queryDomain,const char * queryString,uint32 flags,port_id remotePort,int32 remoteToken,QueryHandle ** handle)7885a1d355fSStephan Aßmus VolumeManager::OpenQuery(QueryDomain* queryDomain, const char* queryString,
7895a1d355fSStephan Aßmus uint32 flags, port_id remotePort, int32 remoteToken, QueryHandle** handle)
7905a1d355fSStephan Aßmus {
7915a1d355fSStephan Aßmus if (!queryDomain || !queryString || !handle)
7925a1d355fSStephan Aßmus return B_BAD_VALUE;
7935a1d355fSStephan Aßmus bool liveQuery = (flags & B_LIVE_QUERY);
794*ebb21bd1SMurai Takashi PRINT("VolumeManager::OpenQuery(%p, \"%s\", 0x%" B_PRIx32 ", "
795*ebb21bd1SMurai Takashi "%" B_PRId32 ", %" B_PRId32 ")\n",
7963c1afd35SPawel Dziepak queryDomain, queryString, flags, remotePort, remoteToken);
7975a1d355fSStephan Aßmus
7985a1d355fSStephan Aßmus // allocate the handle
7995a1d355fSStephan Aßmus QueryHandle* queryHandle = new(std::nothrow) QueryHandle(remotePort,
8005a1d355fSStephan Aßmus remoteToken);
801cee04e80SArtur Wyszynski if (!queryHandle)
8025a1d355fSStephan Aßmus return B_NO_MEMORY;
8035a1d355fSStephan Aßmus ObjectDeleter<QueryHandle> handleDeleter(queryHandle);
8045a1d355fSStephan Aßmus
8055a1d355fSStephan Aßmus // allocate a query handler, if this is a live query
8065a1d355fSStephan Aßmus QueryHandler* queryHandler = NULL;
8075a1d355fSStephan Aßmus if (liveQuery) {
8085a1d355fSStephan Aßmus queryHandler = new(std::nothrow) QueryHandler(this, queryDomain,
8095a1d355fSStephan Aßmus queryHandle);
8105a1d355fSStephan Aßmus if (!queryHandler)
8115a1d355fSStephan Aßmus return B_NO_MEMORY;
8125a1d355fSStephan Aßmus
8135a1d355fSStephan Aßmus fNodeMonitor->Lock();
8145a1d355fSStephan Aßmus fNodeMonitor->AddHandler(queryHandler);
8155a1d355fSStephan Aßmus fNodeMonitor->Unlock();
8165a1d355fSStephan Aßmus queryHandle->SetQueryListener(queryHandler);
8175a1d355fSStephan Aßmus }
8185a1d355fSStephan Aßmus
8195a1d355fSStephan Aßmus // iterate through the volumes and create a query for each one
8205a1d355fSStephan Aßmus // supporting queries
8215a1d355fSStephan Aßmus for (VolumeMap::Iterator it = fVolumes->GetIterator(); it.HasNext();) {
8225a1d355fSStephan Aßmus Volume* volume = it.Next().value;
8235a1d355fSStephan Aßmus if (!volume->KnowsQuery())
8245a1d355fSStephan Aßmus continue;
8255a1d355fSStephan Aßmus
8265a1d355fSStephan Aßmus // The volume should either be contained by the client volume or
8275a1d355fSStephan Aßmus // the other way around. Otherwise they are located in different
8285a1d355fSStephan Aßmus // branches of the FS tree and don't have common nodes.
8295a1d355fSStephan Aßmus if (!queryDomain->QueryDomainIntersectsWith(volume))
8305a1d355fSStephan Aßmus continue;
831*ebb21bd1SMurai Takashi PRINT("VolumeManager::OpenQuery(): adding Query for volume "
832*ebb21bd1SMurai Takashi "%" B_PRIdDEV "\n", volume->GetID());
8335a1d355fSStephan Aßmus
8345a1d355fSStephan Aßmus // create the query for this volume
8355a1d355fSStephan Aßmus BVolume bVolume(volume->GetID());
8365a1d355fSStephan Aßmus Query* query = new(std::nothrow) Query;
8375a1d355fSStephan Aßmus if (!query)
8385a1d355fSStephan Aßmus return B_NO_MEMORY;
8395a1d355fSStephan Aßmus
8405a1d355fSStephan Aßmus // init the query
8415a1d355fSStephan Aßmus ObjectDeleter<Query> queryDeleter(query);
8425a1d355fSStephan Aßmus status_t error = query->SetVolume(&bVolume);
8435a1d355fSStephan Aßmus if (error != B_OK)
8445a1d355fSStephan Aßmus return error;
8455a1d355fSStephan Aßmus error = query->SetPredicate(queryString);
8465a1d355fSStephan Aßmus if (error != B_OK)
8475a1d355fSStephan Aßmus return error;
8485a1d355fSStephan Aßmus if (liveQuery) {
8495a1d355fSStephan Aßmus error = query->SetTarget(queryHandler);
8505a1d355fSStephan Aßmus if (error != B_OK)
8515a1d355fSStephan Aßmus return error;
8525a1d355fSStephan Aßmus }
8535a1d355fSStephan Aßmus
8545a1d355fSStephan Aßmus // fetch
8555a1d355fSStephan Aßmus error = query->Fetch();
8565a1d355fSStephan Aßmus if (error != B_OK)
8575a1d355fSStephan Aßmus return error;
8585a1d355fSStephan Aßmus
8595a1d355fSStephan Aßmus queryHandle->AddQuery(query);
8605a1d355fSStephan Aßmus queryDeleter.Detach();
8615a1d355fSStephan Aßmus }
8625a1d355fSStephan Aßmus
8635a1d355fSStephan Aßmus *handle = queryHandle;
8645a1d355fSStephan Aßmus handleDeleter.Detach();
8655a1d355fSStephan Aßmus return B_OK;
8665a1d355fSStephan Aßmus }
8675a1d355fSStephan Aßmus
8685a1d355fSStephan Aßmus // CompletePathToRoot
8695a1d355fSStephan Aßmus status_t
CompletePathToRoot(Directory * directory)8705a1d355fSStephan Aßmus VolumeManager::CompletePathToRoot(Directory* directory)
8715a1d355fSStephan Aßmus {
8725a1d355fSStephan Aßmus if (!directory)
8735a1d355fSStephan Aßmus return B_BAD_VALUE;
8745a1d355fSStephan Aßmus
8755a1d355fSStephan Aßmus while (directory != GetRootDirectory()) {
8765a1d355fSStephan Aßmus // if the dir has a valid entry referring to it, we've nothing to do
8775a1d355fSStephan Aßmus if (directory->GetActualReferringEntry())
8785a1d355fSStephan Aßmus return B_OK;
8795a1d355fSStephan Aßmus
8805a1d355fSStephan Aßmus // get a proper entry_ref
8815a1d355fSStephan Aßmus BEntry bEntry;
8825a1d355fSStephan Aßmus entry_ref entryRef(directory->GetVolumeID(), directory->GetID(), ".");
8835a1d355fSStephan Aßmus status_t error = FDManager::SetEntry(&bEntry, &entryRef);
8845a1d355fSStephan Aßmus if (error == B_OK)
8855a1d355fSStephan Aßmus error = bEntry.GetRef(&entryRef);
8865a1d355fSStephan Aßmus if (error != B_OK)
8875a1d355fSStephan Aßmus return error;
8885a1d355fSStephan Aßmus
8895a1d355fSStephan Aßmus // if the entry is already loaded, we're done
8905a1d355fSStephan Aßmus if (GetEntry(entryRef))
8915a1d355fSStephan Aßmus return B_OK;
8925a1d355fSStephan Aßmus
8935a1d355fSStephan Aßmus // the entry is not yet known -- load it
8945a1d355fSStephan Aßmus Entry* entry;
8955a1d355fSStephan Aßmus error = LoadEntry(entryRef.device, entryRef.directory, entryRef.name,
8965a1d355fSStephan Aßmus true, &entry);
8975a1d355fSStephan Aßmus if (error != B_OK)
8985a1d355fSStephan Aßmus return error;
8995a1d355fSStephan Aßmus
9005a1d355fSStephan Aßmus // get the entry's parent dir and enter the next round
9015a1d355fSStephan Aßmus directory = entry->GetDirectory();
9025a1d355fSStephan Aßmus }
9035a1d355fSStephan Aßmus
9045a1d355fSStephan Aßmus return B_OK;
9055a1d355fSStephan Aßmus }
9065a1d355fSStephan Aßmus
9075a1d355fSStephan Aßmus // GetPath
9085a1d355fSStephan Aßmus status_t
GetPath(Entry * entry,Path * path)9095a1d355fSStephan Aßmus VolumeManager::GetPath(Entry* entry, Path* path)
9105a1d355fSStephan Aßmus {
9115a1d355fSStephan Aßmus // get directory path
9125a1d355fSStephan Aßmus status_t error = GetPath(entry->GetDirectory(), path);
9135a1d355fSStephan Aßmus if (error != B_OK)
9145a1d355fSStephan Aßmus return error;
9155a1d355fSStephan Aßmus
9165a1d355fSStephan Aßmus // append the entry name
9175a1d355fSStephan Aßmus return path->Append(entry->GetName());
9185a1d355fSStephan Aßmus }
9195a1d355fSStephan Aßmus
9205a1d355fSStephan Aßmus // GetPath
9215a1d355fSStephan Aßmus status_t
GetPath(Node * node,Path * path)9225a1d355fSStephan Aßmus VolumeManager::GetPath(Node* node, Path* path)
9235a1d355fSStephan Aßmus {
9245a1d355fSStephan Aßmus if (node == GetRootDirectory())
9255a1d355fSStephan Aßmus return path->SetTo("/");
9265a1d355fSStephan Aßmus
9275a1d355fSStephan Aßmus // get an entry referring to the node
9285a1d355fSStephan Aßmus Entry* entry = node->GetActualReferringEntry();
9295a1d355fSStephan Aßmus if (!entry) {
9305a1d355fSStephan Aßmus // if the node is a directory, we complete the path to the root and
9315a1d355fSStephan Aßmus // try again
9325a1d355fSStephan Aßmus if (Directory* directory = dynamic_cast<Directory*>(node)) {
9335a1d355fSStephan Aßmus CompletePathToRoot(directory);
9345a1d355fSStephan Aßmus entry = node->GetActualReferringEntry();
9355a1d355fSStephan Aßmus }
9365a1d355fSStephan Aßmus
9375a1d355fSStephan Aßmus if (!entry)
9385a1d355fSStephan Aßmus return B_ERROR;
9395a1d355fSStephan Aßmus }
9405a1d355fSStephan Aßmus
9415a1d355fSStephan Aßmus return GetPath(entry, path);
9425a1d355fSStephan Aßmus }
9435a1d355fSStephan Aßmus
9445a1d355fSStephan Aßmus // DirectoryContains
9455a1d355fSStephan Aßmus bool
DirectoryContains(Directory * directory,Entry * entry)9465a1d355fSStephan Aßmus VolumeManager::DirectoryContains(Directory* directory, Entry* entry)
9475a1d355fSStephan Aßmus {
9485a1d355fSStephan Aßmus if (!directory || !entry)
9495a1d355fSStephan Aßmus return false;
9505a1d355fSStephan Aßmus
9515a1d355fSStephan Aßmus return DirectoryContains(directory, entry->GetDirectory(), true);
9525a1d355fSStephan Aßmus }
9535a1d355fSStephan Aßmus
9545a1d355fSStephan Aßmus // DirectoryContains
9555a1d355fSStephan Aßmus bool
DirectoryContains(Directory * directory,Directory * descendant,bool reflexive)9565a1d355fSStephan Aßmus VolumeManager::DirectoryContains(Directory* directory, Directory* descendant,
9575a1d355fSStephan Aßmus bool reflexive)
9585a1d355fSStephan Aßmus {
9595a1d355fSStephan Aßmus if (!directory || !descendant)
9605a1d355fSStephan Aßmus return false;
9615a1d355fSStephan Aßmus
9625a1d355fSStephan Aßmus // a directory contains itself, just as defined by the caller
9635a1d355fSStephan Aßmus if (directory == descendant)
9645a1d355fSStephan Aßmus return reflexive;
9655a1d355fSStephan Aßmus
9665a1d355fSStephan Aßmus // if the directory is the root directory, it contains everything
9675a1d355fSStephan Aßmus Directory* rootDir = GetRootDirectory();
9685a1d355fSStephan Aßmus if (directory == rootDir)
9695a1d355fSStephan Aßmus return true;
9705a1d355fSStephan Aßmus
9715a1d355fSStephan Aßmus // recursively get the descendant's parent dir until reaching the root dir
9725a1d355fSStephan Aßmus // or the given dir
9735a1d355fSStephan Aßmus while (descendant != rootDir) {
9745a1d355fSStephan Aßmus descendant = GetParentDirectory(descendant);
9755a1d355fSStephan Aßmus if (!descendant)
9765a1d355fSStephan Aßmus return false;
9775a1d355fSStephan Aßmus
9785a1d355fSStephan Aßmus if (descendant == directory)
9795a1d355fSStephan Aßmus return true;
9805a1d355fSStephan Aßmus }
9815a1d355fSStephan Aßmus
9825a1d355fSStephan Aßmus return false;
9835a1d355fSStephan Aßmus }
9845a1d355fSStephan Aßmus
9855a1d355fSStephan Aßmus // DirectoryContains
9865a1d355fSStephan Aßmus bool
DirectoryContains(Directory * directory,Node * descendant,bool reflexive)9875a1d355fSStephan Aßmus VolumeManager::DirectoryContains(Directory* directory, Node* descendant,
9885a1d355fSStephan Aßmus bool reflexive)
9895a1d355fSStephan Aßmus {
9905a1d355fSStephan Aßmus if (!directory || !descendant)
9915a1d355fSStephan Aßmus return false;
9925a1d355fSStephan Aßmus
9935a1d355fSStephan Aßmus // if the node is a directory, let the other version do the job
9945a1d355fSStephan Aßmus if (Directory* dir = dynamic_cast<Directory*>(descendant))
9955a1d355fSStephan Aßmus return DirectoryContains(directory, dir, reflexive);
9965a1d355fSStephan Aßmus
9975a1d355fSStephan Aßmus // iterate through the referring entries and check, if the directory
9985a1d355fSStephan Aßmus // contains any of them
9995a1d355fSStephan Aßmus for (Entry* entry = descendant->GetFirstReferringEntry();
10005a1d355fSStephan Aßmus entry;
10015a1d355fSStephan Aßmus entry = descendant->GetNextReferringEntry(entry)) {
10025a1d355fSStephan Aßmus if (DirectoryContains(directory, entry))
10035a1d355fSStephan Aßmus return true;
10045a1d355fSStephan Aßmus }
10055a1d355fSStephan Aßmus
10065a1d355fSStephan Aßmus return false;
10075a1d355fSStephan Aßmus }
10085a1d355fSStephan Aßmus
10095a1d355fSStephan Aßmus
10105a1d355fSStephan Aßmus // #pragma mark -
10115a1d355fSStephan Aßmus
10125a1d355fSStephan Aßmus // ProcessNodeMonitoringEvent
10135a1d355fSStephan Aßmus void
ProcessNodeMonitoringEvent(NodeMonitoringEvent * event)10145a1d355fSStephan Aßmus VolumeManager::ProcessNodeMonitoringEvent(NodeMonitoringEvent* event)
10155a1d355fSStephan Aßmus {
10165a1d355fSStephan Aßmus if (fNodeMonitoringEvents.Push(event) != B_OK)
10175a1d355fSStephan Aßmus delete event;
10185a1d355fSStephan Aßmus }
10195a1d355fSStephan Aßmus
10205a1d355fSStephan Aßmus // _AddVolume
10215a1d355fSStephan Aßmus status_t
_AddVolume(dev_t volumeID,Volume ** _volume)10225a1d355fSStephan Aßmus VolumeManager::_AddVolume(dev_t volumeID, Volume** _volume)
10235a1d355fSStephan Aßmus {
10245a1d355fSStephan Aßmus if (GetVolume(volumeID))
10255a1d355fSStephan Aßmus return B_OK;
10265a1d355fSStephan Aßmus
10275a1d355fSStephan Aßmus // create the volume
10285a1d355fSStephan Aßmus Volume* volume = new(std::nothrow) Volume(volumeID);
10295a1d355fSStephan Aßmus if (!volume)
10305a1d355fSStephan Aßmus RETURN_ERROR(B_NO_MEMORY);
10315a1d355fSStephan Aßmus ObjectDeleter<Volume> volumeDeleter(volume);
10325a1d355fSStephan Aßmus status_t error = volume->Init();
10335a1d355fSStephan Aßmus if (error != B_OK)
10345a1d355fSStephan Aßmus RETURN_ERROR(error);
10355a1d355fSStephan Aßmus
10365a1d355fSStephan Aßmus // add it
10375a1d355fSStephan Aßmus error = fVolumes->Put(volumeID, volume);
10385a1d355fSStephan Aßmus if (error != B_OK)
10395a1d355fSStephan Aßmus RETURN_ERROR(error);
10405a1d355fSStephan Aßmus
10415a1d355fSStephan Aßmus // add the root node
10425a1d355fSStephan Aßmus error = AddNode(volume->GetRootDirectory());
10435a1d355fSStephan Aßmus if (error != B_OK) {
10445a1d355fSStephan Aßmus fVolumes->Remove(volumeID);
10455a1d355fSStephan Aßmus RETURN_ERROR(error);
10465a1d355fSStephan Aßmus }
10475a1d355fSStephan Aßmus
10485a1d355fSStephan Aßmus // complete the root dir path
10495a1d355fSStephan Aßmus CompletePathToRoot(volume->GetRootDirectory());
10505a1d355fSStephan Aßmus
10515a1d355fSStephan Aßmus volumeDeleter.Detach();
10525a1d355fSStephan Aßmus if (_volume)
10535a1d355fSStephan Aßmus *_volume = volume;
10545a1d355fSStephan Aßmus return B_OK;
10555a1d355fSStephan Aßmus }
10565a1d355fSStephan Aßmus
10575a1d355fSStephan Aßmus // _EntryCreated
10585a1d355fSStephan Aßmus void
_EntryCreated(EntryCreatedEvent * event)10595a1d355fSStephan Aßmus VolumeManager::_EntryCreated(EntryCreatedEvent* event)
10605a1d355fSStephan Aßmus {
10615a1d355fSStephan Aßmus // get the directory
10625a1d355fSStephan Aßmus Directory* directory = GetDirectory(event->volumeID, event->directoryID);
10635a1d355fSStephan Aßmus if (!directory)
10645a1d355fSStephan Aßmus return;
10655a1d355fSStephan Aßmus
10665a1d355fSStephan Aßmus // check, if there is an earlier similar event
10675a1d355fSStephan Aßmus bool notify = true;
10685a1d355fSStephan Aßmus NoAllocEntryRef ref(event->volumeID, event->directoryID,
10695a1d355fSStephan Aßmus event->name.GetString());
10705a1d355fSStephan Aßmus EntryCreatedEvent* oldEvent = fEntryCreatedEvents->Get(ref);
10715a1d355fSStephan Aßmus
10725a1d355fSStephan Aßmus // remove the old event
10735a1d355fSStephan Aßmus if (oldEvent) {
10745a1d355fSStephan Aßmus fEntryCreatedEvents->Remove(ref);
10755a1d355fSStephan Aßmus fRecentNodeMonitoringEvents.Remove(oldEvent);
10765a1d355fSStephan Aßmus notify = !_IsRecentEvent(oldEvent);
107788e38c17SIngo Weinhold oldEvent->ReleaseReference();
10785a1d355fSStephan Aßmus }
10795a1d355fSStephan Aßmus
10805a1d355fSStephan Aßmus // add the new event
10815a1d355fSStephan Aßmus if (fEntryCreatedEvents->Put(ref, event) == B_OK) {
10825a1d355fSStephan Aßmus fRecentNodeMonitoringEvents.Insert(event);
108388e38c17SIngo Weinhold event->AcquireReference();
10845a1d355fSStephan Aßmus }
10855a1d355fSStephan Aßmus
10865a1d355fSStephan Aßmus // if the directory is complete or at least has iterators attached to it,
10875a1d355fSStephan Aßmus // we load the entry
10885a1d355fSStephan Aßmus if (directory->IsComplete() || directory->HasDirIterators()) {
10895a1d355fSStephan Aßmus Entry* entry;
10905a1d355fSStephan Aßmus LoadEntry(ref.device, ref.directory, ref.name, false, &entry);
10915a1d355fSStephan Aßmus }
10925a1d355fSStephan Aßmus
10935a1d355fSStephan Aßmus // send notifications
10945a1d355fSStephan Aßmus if (notify) {
10955a1d355fSStephan Aßmus for (ClientVolumeMap::Iterator it = fClientVolumes->GetIterator();
10965a1d355fSStephan Aßmus it.HasNext();) {
10975a1d355fSStephan Aßmus ClientVolume* clientVolume = it.Next().value;
10985a1d355fSStephan Aßmus if (DirectoryContains(clientVolume->GetRootDirectory(), directory,
10995a1d355fSStephan Aßmus true)) {
11005a1d355fSStephan Aßmus clientVolume->ProcessNodeMonitoringEvent(event);
11015a1d355fSStephan Aßmus }
11025a1d355fSStephan Aßmus }
11035a1d355fSStephan Aßmus }
11045a1d355fSStephan Aßmus }
11055a1d355fSStephan Aßmus
11065a1d355fSStephan Aßmus // _EntryRemoved
11075a1d355fSStephan Aßmus void
_EntryRemoved(EntryRemovedEvent * event,bool keepNode)11085a1d355fSStephan Aßmus VolumeManager::_EntryRemoved(EntryRemovedEvent* event, bool keepNode)
11095a1d355fSStephan Aßmus {
11105a1d355fSStephan Aßmus // get node and directory
11115a1d355fSStephan Aßmus Node* node = GetNode(event->nodeVolumeID, event->nodeID);
11125a1d355fSStephan Aßmus Directory* directory = GetDirectory(event->volumeID, event->directoryID);
11135a1d355fSStephan Aßmus if (!directory)
11145a1d355fSStephan Aßmus return;
11155a1d355fSStephan Aßmus
11165a1d355fSStephan Aßmus // find the entry
11175a1d355fSStephan Aßmus Entry* entry = NULL;
11185a1d355fSStephan Aßmus if (node) {
11195a1d355fSStephan Aßmus if (event->name.GetLength() == 0) {
11205a1d355fSStephan Aßmus for (entry = node->GetFirstReferringEntry();
11215a1d355fSStephan Aßmus entry;
11225a1d355fSStephan Aßmus entry = node->GetNextReferringEntry(entry)) {
11235a1d355fSStephan Aßmus if (!entry->Exists()) {
11245a1d355fSStephan Aßmus event->name.SetTo(entry->GetName());
11255a1d355fSStephan Aßmus break;
11265a1d355fSStephan Aßmus }
11275a1d355fSStephan Aßmus }
11285a1d355fSStephan Aßmus } else {
11295a1d355fSStephan Aßmus entry = GetEntry(directory->GetVolumeID(), directory->GetID(),
11305a1d355fSStephan Aßmus event->name.GetString());
11315a1d355fSStephan Aßmus }
11325a1d355fSStephan Aßmus }
11335a1d355fSStephan Aßmus
11345a1d355fSStephan Aßmus // check, if there is an earlier similar event
11355a1d355fSStephan Aßmus bool notify = true;
11365a1d355fSStephan Aßmus NoAllocEntryRef ref(event->volumeID, event->directoryID,
11375a1d355fSStephan Aßmus event->name.GetString());
11385a1d355fSStephan Aßmus EntryRemovedEvent* oldEvent = fEntryRemovedEvents->Get(ref);
11395a1d355fSStephan Aßmus // TODO: Under BeOS R5 the entry name is not encoded in the
11405a1d355fSStephan Aßmus // "entry removed" node monitoring message. If we have seen the entry
11415a1d355fSStephan Aßmus // before, we can get the entry nevertheless (see above). Usually we
11425a1d355fSStephan Aßmus // get 2 "entry removed" events: One for watching the directory and one
11435a1d355fSStephan Aßmus // for watching the node. After the first one has been processed, we've
11445a1d355fSStephan Aßmus // forgotten everything about the entry and we won't be able to find out
11455a1d355fSStephan Aßmus // the entry's name for the second one. Hence we will never find the
11465a1d355fSStephan Aßmus // previous event in the fEntryRemovedEvents map. We should probably
11475a1d355fSStephan Aßmus // fall back to using a NodeRef as key under BeOS R5.
11485a1d355fSStephan Aßmus
11495a1d355fSStephan Aßmus // remove the old event
11505a1d355fSStephan Aßmus if (oldEvent) {
11515a1d355fSStephan Aßmus fEntryRemovedEvents->Remove(ref);
11525a1d355fSStephan Aßmus fRecentNodeMonitoringEvents.Remove(oldEvent);
11535a1d355fSStephan Aßmus notify = !_IsRecentEvent(oldEvent);
115488e38c17SIngo Weinhold oldEvent->ReleaseReference();
11555a1d355fSStephan Aßmus }
11565a1d355fSStephan Aßmus
11575a1d355fSStephan Aßmus // add the new event
11585a1d355fSStephan Aßmus if (fEntryRemovedEvents->Put(ref, event) == B_OK) {
11595a1d355fSStephan Aßmus fRecentNodeMonitoringEvents.Insert(event);
116088e38c17SIngo Weinhold event->AcquireReference();
11615a1d355fSStephan Aßmus }
11625a1d355fSStephan Aßmus
11635a1d355fSStephan Aßmus // remove the entry
11645a1d355fSStephan Aßmus if (entry) {
11655a1d355fSStephan Aßmus RemoveEntry(entry);
11665a1d355fSStephan Aßmus delete entry;
11675a1d355fSStephan Aßmus }
11685a1d355fSStephan Aßmus
11695a1d355fSStephan Aßmus // remove the node, if it doesn't have any more actual referring entries
11705a1d355fSStephan Aßmus if (node && !keepNode && !node->GetActualReferringEntry()) {
11715a1d355fSStephan Aßmus RemoveNode(node);
11725a1d355fSStephan Aßmus if (node != node->GetVolume()->GetRootDirectory())
11735a1d355fSStephan Aßmus delete node;
11745a1d355fSStephan Aßmus }
11755a1d355fSStephan Aßmus
11765a1d355fSStephan Aßmus // send notifications
11775a1d355fSStephan Aßmus if (notify) {
11785a1d355fSStephan Aßmus NodeRef nodeRef(event->nodeVolumeID, event->nodeID);
11795a1d355fSStephan Aßmus for (ClientVolumeMap::Iterator it = fClientVolumes->GetIterator();
11805a1d355fSStephan Aßmus it.HasNext();) {
11815a1d355fSStephan Aßmus // We send a notification, if the client volume contains the entry,
11825a1d355fSStephan Aßmus // but also, if the removed entry refers to the client volume's
11835a1d355fSStephan Aßmus // root. The client connection has a special handling for this
11845a1d355fSStephan Aßmus // case.
11855a1d355fSStephan Aßmus ClientVolume* clientVolume = it.Next().value;
11865a1d355fSStephan Aßmus Directory* rootDir = clientVolume->GetRootDirectory();
11875a1d355fSStephan Aßmus if (DirectoryContains(rootDir, directory, true)
11885a1d355fSStephan Aßmus || clientVolume->GetRootNodeRef() == nodeRef) {
11895a1d355fSStephan Aßmus clientVolume->ProcessNodeMonitoringEvent(event);
11905a1d355fSStephan Aßmus }
11915a1d355fSStephan Aßmus }
11925a1d355fSStephan Aßmus }
11935a1d355fSStephan Aßmus }
11945a1d355fSStephan Aßmus
11955a1d355fSStephan Aßmus // _EntryMoved
11965a1d355fSStephan Aßmus void
_EntryMoved(EntryMovedEvent * event)11975a1d355fSStephan Aßmus VolumeManager::_EntryMoved(EntryMovedEvent* event)
11985a1d355fSStephan Aßmus {
11995a1d355fSStephan Aßmus _CheckVolumeRootMoved(event);
12005a1d355fSStephan Aßmus
12015a1d355fSStephan Aßmus Directory* fromDirectory
12025a1d355fSStephan Aßmus = GetDirectory(event->volumeID, event->fromDirectoryID);
12035a1d355fSStephan Aßmus Directory* toDirectory
12045a1d355fSStephan Aßmus = GetDirectory(event->volumeID, event->toDirectoryID);
12055a1d355fSStephan Aßmus Node* node = GetNode(event->nodeVolumeID, event->nodeID);
12065a1d355fSStephan Aßmus
12075a1d355fSStephan Aßmus // we should at least have one of the directories
12085a1d355fSStephan Aßmus if (!fromDirectory && !toDirectory)
12095a1d355fSStephan Aßmus return;
12105a1d355fSStephan Aßmus
12115a1d355fSStephan Aßmus // find the old entry
12125a1d355fSStephan Aßmus Entry* oldEntry = NULL;
12135a1d355fSStephan Aßmus if (node) {
12145a1d355fSStephan Aßmus if (event->fromName.GetLength() == 0) {
12155a1d355fSStephan Aßmus for (oldEntry = node->GetFirstReferringEntry();
12165a1d355fSStephan Aßmus oldEntry;
12175a1d355fSStephan Aßmus oldEntry = node->GetNextReferringEntry(oldEntry)) {
12185a1d355fSStephan Aßmus if (!oldEntry->Exists()) {
12195a1d355fSStephan Aßmus event->fromName.SetTo(oldEntry->GetName());
12205a1d355fSStephan Aßmus break;
12215a1d355fSStephan Aßmus }
12225a1d355fSStephan Aßmus }
12235a1d355fSStephan Aßmus } else {
12245a1d355fSStephan Aßmus oldEntry = GetEntry(event->volumeID, event->fromDirectoryID,
12255a1d355fSStephan Aßmus event->fromName.GetString());
12265a1d355fSStephan Aßmus }
12275a1d355fSStephan Aßmus }
12285a1d355fSStephan Aßmus
12295a1d355fSStephan Aßmus // check, if there is an earlier similar event
12305a1d355fSStephan Aßmus bool notify = true;
12315a1d355fSStephan Aßmus if (event->fromName.GetLength() > 0) {
12325a1d355fSStephan Aßmus EntryMovedEventKey key(event->volumeID, event->fromDirectoryID,
12335a1d355fSStephan Aßmus event->fromName.GetString(), event->toDirectoryID,
12345a1d355fSStephan Aßmus event->toName.GetString());
12355a1d355fSStephan Aßmus EntryMovedEvent* oldEvent = fEntryMovedEvents->Get(key);
12365a1d355fSStephan Aßmus
12375a1d355fSStephan Aßmus // remove the old event
12385a1d355fSStephan Aßmus if (oldEvent) {
12395a1d355fSStephan Aßmus fEntryMovedEvents->Remove(key);
12405a1d355fSStephan Aßmus fRecentNodeMonitoringEvents.Remove(oldEvent);
12415a1d355fSStephan Aßmus notify = !_IsRecentEvent(oldEvent);
124288e38c17SIngo Weinhold oldEvent->ReleaseReference();
12435a1d355fSStephan Aßmus }
12445a1d355fSStephan Aßmus
12455a1d355fSStephan Aßmus // add the new event
12465a1d355fSStephan Aßmus if (fEntryMovedEvents->Put(key, event) == B_OK) {
12475a1d355fSStephan Aßmus fRecentNodeMonitoringEvents.Insert(event);
124888e38c17SIngo Weinhold event->AcquireReference();
12495a1d355fSStephan Aßmus }
12505a1d355fSStephan Aßmus }
12515a1d355fSStephan Aßmus
12525a1d355fSStephan Aßmus // remove the old entry
12535a1d355fSStephan Aßmus if (oldEntry) {
12545a1d355fSStephan Aßmus RemoveEntry(oldEntry);
12555a1d355fSStephan Aßmus delete oldEntry;
12565a1d355fSStephan Aßmus }
12575a1d355fSStephan Aßmus
12585a1d355fSStephan Aßmus // If the to directory is complete or at least has iterators attached to it,
12595a1d355fSStephan Aßmus // we load the new entry. We also load it, if the node is the root of a
12605a1d355fSStephan Aßmus // volume.
12615a1d355fSStephan Aßmus if (toDirectory
12625a1d355fSStephan Aßmus && (toDirectory->IsComplete() || toDirectory->HasDirIterators()
12635a1d355fSStephan Aßmus || (node && node == node->GetVolume()->GetRootDirectory()))) {
12645a1d355fSStephan Aßmus Entry* newEntry;
12655a1d355fSStephan Aßmus LoadEntry(event->volumeID, event->toDirectoryID,
12665a1d355fSStephan Aßmus event->toName.GetString(), false, &newEntry);
12675a1d355fSStephan Aßmus }
12685a1d355fSStephan Aßmus
12695a1d355fSStephan Aßmus // remove the node, if it doesn't have any more actual referring entries
12705a1d355fSStephan Aßmus if (node && !node->GetActualReferringEntry()) {
12715a1d355fSStephan Aßmus RemoveNode(node);
12725a1d355fSStephan Aßmus if (node != node->GetVolume()->GetRootDirectory())
12735a1d355fSStephan Aßmus delete node;
12745a1d355fSStephan Aßmus }
12755a1d355fSStephan Aßmus
12765a1d355fSStephan Aßmus // send notifications
12775a1d355fSStephan Aßmus if (notify) {
12785a1d355fSStephan Aßmus for (ClientVolumeMap::Iterator it = fClientVolumes->GetIterator();
12795a1d355fSStephan Aßmus it.HasNext();) {
12805a1d355fSStephan Aßmus ClientVolume* clientVolume = it.Next().value;
12815a1d355fSStephan Aßmus
12825a1d355fSStephan Aßmus // check, if it contains the from/to directories
12835a1d355fSStephan Aßmus Directory* rootDir = clientVolume->GetRootDirectory();
12845a1d355fSStephan Aßmus bool containsFrom = DirectoryContains(rootDir, fromDirectory, true);
12855a1d355fSStephan Aßmus bool containsTo = DirectoryContains(rootDir, toDirectory, true);
12865a1d355fSStephan Aßmus
12875a1d355fSStephan Aßmus if (containsFrom) {
12885a1d355fSStephan Aßmus if (containsTo) {
12895a1d355fSStephan Aßmus // contains source and target dir
12905a1d355fSStephan Aßmus clientVolume->ProcessNodeMonitoringEvent(event);
12915a1d355fSStephan Aßmus } else {
12925a1d355fSStephan Aßmus // contains only the source dir: generate an "entry removed"
12935a1d355fSStephan Aßmus // event
12945a1d355fSStephan Aßmus EntryRemovedEvent *removedEvent
12955a1d355fSStephan Aßmus = new(std::nothrow) EntryRemovedEvent;
12965a1d355fSStephan Aßmus if (!removedEvent)
12975a1d355fSStephan Aßmus continue;
12985a1d355fSStephan Aßmus removedEvent->opcode = B_ENTRY_REMOVED;
12995a1d355fSStephan Aßmus removedEvent->time = event->time;
13005a1d355fSStephan Aßmus removedEvent->volumeID = event->volumeID;
13015a1d355fSStephan Aßmus removedEvent->directoryID = event->fromDirectoryID;
13025a1d355fSStephan Aßmus removedEvent->nodeVolumeID = event->nodeVolumeID;
13035a1d355fSStephan Aßmus removedEvent->nodeID = event->nodeID;
13045a1d355fSStephan Aßmus if (event->fromName.GetLength() > 0)
13055a1d355fSStephan Aßmus removedEvent->name = event->fromName;
13065a1d355fSStephan Aßmus clientVolume->ProcessNodeMonitoringEvent(removedEvent);
130788e38c17SIngo Weinhold removedEvent->ReleaseReference();
13085a1d355fSStephan Aßmus }
13095a1d355fSStephan Aßmus } else if (containsTo) {
13105a1d355fSStephan Aßmus // contains only the target directory: generate an
13115a1d355fSStephan Aßmus // "entry created" event
13125a1d355fSStephan Aßmus EntryCreatedEvent *createdEvent
13135a1d355fSStephan Aßmus = new(std::nothrow) EntryCreatedEvent;
13145a1d355fSStephan Aßmus if (!createdEvent)
13155a1d355fSStephan Aßmus continue;
13165a1d355fSStephan Aßmus createdEvent->opcode = B_ENTRY_CREATED;
13175a1d355fSStephan Aßmus createdEvent->time = event->time;
13185a1d355fSStephan Aßmus createdEvent->volumeID = event->volumeID;
13195a1d355fSStephan Aßmus createdEvent->directoryID = event->toDirectoryID;
13205a1d355fSStephan Aßmus createdEvent->name = event->toName;
13215a1d355fSStephan Aßmus clientVolume->ProcessNodeMonitoringEvent(createdEvent);
132288e38c17SIngo Weinhold createdEvent->ReleaseReference();
13235a1d355fSStephan Aßmus }
13245a1d355fSStephan Aßmus }
13255a1d355fSStephan Aßmus }
13265a1d355fSStephan Aßmus }
13275a1d355fSStephan Aßmus
13285a1d355fSStephan Aßmus // _NodeStatChanged
13295a1d355fSStephan Aßmus void
_NodeStatChanged(StatChangedEvent * event)13305a1d355fSStephan Aßmus VolumeManager::_NodeStatChanged(StatChangedEvent* event)
13315a1d355fSStephan Aßmus {
13325a1d355fSStephan Aßmus // get the node
13335a1d355fSStephan Aßmus Node* node = GetNode(event->volumeID, event->nodeID);
13345a1d355fSStephan Aßmus if (!node)
13355a1d355fSStephan Aßmus return;
13365a1d355fSStephan Aßmus
13375a1d355fSStephan Aßmus // check, if there is an earlier similar event
13385a1d355fSStephan Aßmus bool notify = true;
13395a1d355fSStephan Aßmus NodeRef ref(event->volumeID, event->nodeID);
13405a1d355fSStephan Aßmus StatChangedEvent* oldEvent = fNodeStatChangedEvents->Get(ref);
13415a1d355fSStephan Aßmus
13425a1d355fSStephan Aßmus // remove the old event
13435a1d355fSStephan Aßmus if (oldEvent) {
13445a1d355fSStephan Aßmus fNodeStatChangedEvents->Remove(ref);
13455a1d355fSStephan Aßmus fRecentNodeMonitoringEvents.Remove(oldEvent);
13465a1d355fSStephan Aßmus notify = !_IsRecentEvent(oldEvent);
134788e38c17SIngo Weinhold oldEvent->ReleaseReference();
13485a1d355fSStephan Aßmus }
13495a1d355fSStephan Aßmus
13505a1d355fSStephan Aßmus // add the new event
13515a1d355fSStephan Aßmus if (fNodeStatChangedEvents->Put(ref, event) == B_OK) {
13525a1d355fSStephan Aßmus fRecentNodeMonitoringEvents.Insert(event);
135388e38c17SIngo Weinhold event->AcquireReference();
13545a1d355fSStephan Aßmus }
13555a1d355fSStephan Aßmus
13565a1d355fSStephan Aßmus if (notify) {
13575a1d355fSStephan Aßmus // update the cached node stat
13585a1d355fSStephan Aßmus node->UpdateStat();
13595a1d355fSStephan Aßmus
13605a1d355fSStephan Aßmus // send notifications
13615a1d355fSStephan Aßmus for (ClientVolumeMap::Iterator it = fClientVolumes->GetIterator();
13625a1d355fSStephan Aßmus it.HasNext();) {
13635a1d355fSStephan Aßmus ClientVolume* clientVolume = it.Next().value;
13645a1d355fSStephan Aßmus if (DirectoryContains(clientVolume->GetRootDirectory(), node, true))
13655a1d355fSStephan Aßmus clientVolume->ProcessNodeMonitoringEvent(event);
13665a1d355fSStephan Aßmus }
13675a1d355fSStephan Aßmus }
13685a1d355fSStephan Aßmus }
13695a1d355fSStephan Aßmus
13705a1d355fSStephan Aßmus // _NodeAttributeChanged
13715a1d355fSStephan Aßmus void
_NodeAttributeChanged(AttributeChangedEvent * event)13725a1d355fSStephan Aßmus VolumeManager::_NodeAttributeChanged(AttributeChangedEvent* event)
13735a1d355fSStephan Aßmus {
13745a1d355fSStephan Aßmus // get the node
13755a1d355fSStephan Aßmus Node* node = GetNode(event->volumeID, event->nodeID);
13765a1d355fSStephan Aßmus if (!node)
13775a1d355fSStephan Aßmus return;
13785a1d355fSStephan Aßmus
13795a1d355fSStephan Aßmus // check, if there is an earlier similar event
13805a1d355fSStephan Aßmus bool notify = true;
13815a1d355fSStephan Aßmus AttributeRef ref(event->volumeID, event->nodeID,
13825a1d355fSStephan Aßmus event->attribute.GetString());
13835a1d355fSStephan Aßmus AttributeChangedEvent* oldEvent = fNodeAttributeChangedEvents->Get(ref);
13845a1d355fSStephan Aßmus
13855a1d355fSStephan Aßmus // remove the old event
13865a1d355fSStephan Aßmus if (oldEvent) {
13875a1d355fSStephan Aßmus fNodeAttributeChangedEvents->Remove(ref);
13885a1d355fSStephan Aßmus fRecentNodeMonitoringEvents.Remove(oldEvent);
13895a1d355fSStephan Aßmus notify = !_IsRecentEvent(oldEvent);
139088e38c17SIngo Weinhold oldEvent->ReleaseReference();
13915a1d355fSStephan Aßmus }
13925a1d355fSStephan Aßmus
13935a1d355fSStephan Aßmus // add the new event
13945a1d355fSStephan Aßmus if (fNodeAttributeChangedEvents->Put(ref, event) == B_OK) {
13955a1d355fSStephan Aßmus fRecentNodeMonitoringEvents.Insert(event);
139688e38c17SIngo Weinhold event->AcquireReference();
13975a1d355fSStephan Aßmus }
13985a1d355fSStephan Aßmus
13995a1d355fSStephan Aßmus // send notifications
14005a1d355fSStephan Aßmus if (notify) {
14015a1d355fSStephan Aßmus for (ClientVolumeMap::Iterator it = fClientVolumes->GetIterator();
14025a1d355fSStephan Aßmus it.HasNext();) {
14035a1d355fSStephan Aßmus ClientVolume* clientVolume = it.Next().value;
14045a1d355fSStephan Aßmus if (DirectoryContains(clientVolume->GetRootDirectory(), node, true))
14055a1d355fSStephan Aßmus clientVolume->ProcessNodeMonitoringEvent(event);
14065a1d355fSStephan Aßmus }
14075a1d355fSStephan Aßmus }
14085a1d355fSStephan Aßmus }
14095a1d355fSStephan Aßmus
14105a1d355fSStephan Aßmus // _VolumeMounted
14115a1d355fSStephan Aßmus void
_VolumeMounted(VolumeMountedEvent * event)14125a1d355fSStephan Aßmus VolumeManager::_VolumeMounted(VolumeMountedEvent* event)
14135a1d355fSStephan Aßmus {
14145a1d355fSStephan Aßmus entry_ref rootRef;
14155a1d355fSStephan Aßmus bool rootRefInitialized = false;
14165a1d355fSStephan Aßmus
14175a1d355fSStephan Aßmus // remove the entry referring to the covered directory
14185a1d355fSStephan Aßmus Directory* coveredDirectory = GetDirectory(event->volumeID,
14195a1d355fSStephan Aßmus event->directoryID);
14205a1d355fSStephan Aßmus if (coveredDirectory) {
14215a1d355fSStephan Aßmus if (Entry* entry = coveredDirectory->GetActualReferringEntry()) {
14225a1d355fSStephan Aßmus // get an entry for later
14235a1d355fSStephan Aßmus rootRef = entry->GetEntryRef();
14245a1d355fSStephan Aßmus rootRefInitialized = true;
14255a1d355fSStephan Aßmus
14265a1d355fSStephan Aßmus // send the "entry removed" event
14275a1d355fSStephan Aßmus EntryRemovedEvent* event;
14285a1d355fSStephan Aßmus if (_GenerateEntryRemovedEvent(entry, system_time(),
14295a1d355fSStephan Aßmus &event) == B_OK) {
14305a1d355fSStephan Aßmus _EntryRemoved(event, true);
143188e38c17SIngo Weinhold event->ReleaseReference();
14325a1d355fSStephan Aßmus } else {
14335a1d355fSStephan Aßmus RemoveEntry(entry);
14345a1d355fSStephan Aßmus delete entry;
14355a1d355fSStephan Aßmus }
14365a1d355fSStephan Aßmus }
14375a1d355fSStephan Aßmus }
14385a1d355fSStephan Aßmus
14395a1d355fSStephan Aßmus // add the volume
14405a1d355fSStephan Aßmus _AddVolume(event->newVolumeID);
14415a1d355fSStephan Aßmus
14425a1d355fSStephan Aßmus // generate an "entry created" event for the root dir entry
14435a1d355fSStephan Aßmus if (rootRefInitialized)
14445a1d355fSStephan Aßmus _GenerateEntryCreatedEvent(rootRef, event->time);
14455a1d355fSStephan Aßmus }
14465a1d355fSStephan Aßmus
14475a1d355fSStephan Aßmus // _VolumeUnmounted
14485a1d355fSStephan Aßmus void
_VolumeUnmounted(VolumeUnmountedEvent * event)14495a1d355fSStephan Aßmus VolumeManager::_VolumeUnmounted(VolumeUnmountedEvent* event)
14505a1d355fSStephan Aßmus {
14515a1d355fSStephan Aßmus // get the volume
14525a1d355fSStephan Aßmus Volume* volume = GetVolume(event->volumeID);
14535a1d355fSStephan Aßmus if (!volume)
14545a1d355fSStephan Aßmus return;
14555a1d355fSStephan Aßmus
14565a1d355fSStephan Aßmus entry_ref rootRef;
14575a1d355fSStephan Aßmus bool rootRefInitialized = false;
14585a1d355fSStephan Aßmus
14595a1d355fSStephan Aßmus // remove all actual entries referring to the root directory (should only
14605a1d355fSStephan Aßmus // be one)
14615a1d355fSStephan Aßmus if (Directory* rootDir = volume->GetRootDirectory()) {
14625a1d355fSStephan Aßmus // get an entry ref for the root dir
14635a1d355fSStephan Aßmus if (Entry* entry = rootDir->GetActualReferringEntry()) {
14645a1d355fSStephan Aßmus rootRef = entry->GetEntryRef();
14655a1d355fSStephan Aßmus rootRefInitialized = true;
14665a1d355fSStephan Aßmus }
14675a1d355fSStephan Aßmus
14685a1d355fSStephan Aßmus Entry* entry = rootDir->GetFirstReferringEntry();
14695a1d355fSStephan Aßmus while (entry) {
14705a1d355fSStephan Aßmus Entry* nextEntry = rootDir->GetNextReferringEntry(entry);
14715a1d355fSStephan Aßmus
14725a1d355fSStephan Aßmus if (entry->IsActualEntry()) {
14735a1d355fSStephan Aßmus EntryRemovedEvent* removedEvent;
14745a1d355fSStephan Aßmus if (_GenerateEntryRemovedEvent(entry, event->time,
14755a1d355fSStephan Aßmus &removedEvent) == B_OK) {
14765a1d355fSStephan Aßmus _EntryRemoved(removedEvent, true);
147788e38c17SIngo Weinhold removedEvent->ReleaseReference();
14785a1d355fSStephan Aßmus } else {
14795a1d355fSStephan Aßmus RemoveEntry(entry);
14805a1d355fSStephan Aßmus delete entry;
14815a1d355fSStephan Aßmus }
14825a1d355fSStephan Aßmus }
14835a1d355fSStephan Aßmus
14845a1d355fSStephan Aßmus entry = nextEntry;
14855a1d355fSStephan Aßmus }
14865a1d355fSStephan Aßmus }
14875a1d355fSStephan Aßmus
14885a1d355fSStephan Aßmus // remove all entries of the volume
14895a1d355fSStephan Aßmus while (Entry* entry = volume->GetFirstEntry()) {
14905a1d355fSStephan Aßmus bool remove = true;
14915a1d355fSStephan Aßmus if (entry->IsActualEntry()) {
14925a1d355fSStephan Aßmus if (_GenerateEntryRemovedEvent(entry, event->time) != B_OK)
14935a1d355fSStephan Aßmus remove = false;
14945a1d355fSStephan Aßmus }
14955a1d355fSStephan Aßmus
14965a1d355fSStephan Aßmus if (remove) {
14975a1d355fSStephan Aßmus RemoveEntry(entry);
14985a1d355fSStephan Aßmus delete entry;
14995a1d355fSStephan Aßmus }
15005a1d355fSStephan Aßmus }
15015a1d355fSStephan Aßmus
15025a1d355fSStephan Aßmus // remove all nodes
15035a1d355fSStephan Aßmus while (Node* node = volume->GetFirstNode()) {
15045a1d355fSStephan Aßmus RemoveNode(node);
15055a1d355fSStephan Aßmus if (node != volume->GetRootDirectory())
15065a1d355fSStephan Aßmus delete node;
15075a1d355fSStephan Aßmus }
15085a1d355fSStephan Aßmus
15095a1d355fSStephan Aßmus // remove the volume
15105a1d355fSStephan Aßmus fVolumes->Remove(volume->GetID());
15115a1d355fSStephan Aßmus delete volume;
15125a1d355fSStephan Aßmus
15135a1d355fSStephan Aßmus // generate an "entry created" event for the covered node
15145a1d355fSStephan Aßmus if (rootRefInitialized)
15155a1d355fSStephan Aßmus _GenerateEntryCreatedEvent(rootRef, event->time);
15165a1d355fSStephan Aßmus }
15175a1d355fSStephan Aßmus
15185a1d355fSStephan Aßmus // _QueryEntryCreated
15195a1d355fSStephan Aßmus void
_QueryEntryCreated(EntryCreatedEvent * event)15205a1d355fSStephan Aßmus VolumeManager::_QueryEntryCreated(EntryCreatedEvent* event)
15215a1d355fSStephan Aßmus {
15225a1d355fSStephan Aßmus // get the query handler
15235a1d355fSStephan Aßmus QueryHandler* queryHandler
15245a1d355fSStephan Aßmus = dynamic_cast<QueryHandler*>(event->queryHandler);
15255a1d355fSStephan Aßmus if (!queryHandler)
15265a1d355fSStephan Aßmus return;
15275a1d355fSStephan Aßmus
15285a1d355fSStephan Aßmus // load the entry (just to make sure that it really exists)
15295a1d355fSStephan Aßmus Entry* entry = NULL;
15305a1d355fSStephan Aßmus status_t error = LoadEntry(event->volumeID, event->directoryID,
15315a1d355fSStephan Aßmus event->name.GetString(), true, &entry);
15325a1d355fSStephan Aßmus if (error != B_OK)
15335a1d355fSStephan Aßmus return;
15345a1d355fSStephan Aßmus
15355a1d355fSStephan Aßmus // get remote port and token
15365a1d355fSStephan Aßmus if (!queryHandler->LockLooper())
15375a1d355fSStephan Aßmus return;
15385a1d355fSStephan Aßmus
15395a1d355fSStephan Aßmus QueryHandle* queryHandle = queryHandler->GetQueryHandle();
15405a1d355fSStephan Aßmus event->remotePort = queryHandle->GetRemotePort();
15415a1d355fSStephan Aßmus event->remoteToken = queryHandle->GetRemoteToken();
15425a1d355fSStephan Aßmus queryHandler->UnlockLooper();
15435a1d355fSStephan Aßmus
15445a1d355fSStephan Aßmus // send a notification to the client volume
15455a1d355fSStephan Aßmus queryHandler->GetQueryDomain()->ProcessQueryEvent(event);
15465a1d355fSStephan Aßmus }
15475a1d355fSStephan Aßmus
15485a1d355fSStephan Aßmus // _QueryEntryRemoved
15495a1d355fSStephan Aßmus void
_QueryEntryRemoved(EntryRemovedEvent * event)15505a1d355fSStephan Aßmus VolumeManager::_QueryEntryRemoved(EntryRemovedEvent* event)
15515a1d355fSStephan Aßmus {
15525a1d355fSStephan Aßmus // get the query handler
15535a1d355fSStephan Aßmus QueryHandler* queryHandler
15545a1d355fSStephan Aßmus = dynamic_cast<QueryHandler*>(event->queryHandler);
15555a1d355fSStephan Aßmus if (!queryHandler)
15565a1d355fSStephan Aßmus return;
15575a1d355fSStephan Aßmus
15585a1d355fSStephan Aßmus // load the directory (just to make sure that it really exists)
15595a1d355fSStephan Aßmus Directory* directory = NULL;
15605a1d355fSStephan Aßmus status_t error = LoadDirectory(event->volumeID, event->directoryID,
15615a1d355fSStephan Aßmus &directory);
15625a1d355fSStephan Aßmus if (error != B_OK)
15635a1d355fSStephan Aßmus return;
15645a1d355fSStephan Aßmus
15655a1d355fSStephan Aßmus // get remote port and token
15665a1d355fSStephan Aßmus if (!queryHandler->LockLooper())
15675a1d355fSStephan Aßmus return;
15685a1d355fSStephan Aßmus QueryHandle* queryHandle = queryHandler->GetQueryHandle();
15695a1d355fSStephan Aßmus event->remotePort = queryHandle->GetRemotePort();
15705a1d355fSStephan Aßmus event->remoteToken = queryHandle->GetRemoteToken();
15715a1d355fSStephan Aßmus queryHandler->UnlockLooper();
15725a1d355fSStephan Aßmus
15735a1d355fSStephan Aßmus // send a notification to the client volume
15745a1d355fSStephan Aßmus queryHandler->GetQueryDomain()->ProcessQueryEvent(event);
15755a1d355fSStephan Aßmus }
15765a1d355fSStephan Aßmus
15775a1d355fSStephan Aßmus // _QueryEntryMoved
15785a1d355fSStephan Aßmus void
_QueryEntryMoved(EntryMovedEvent * event)15795a1d355fSStephan Aßmus VolumeManager::_QueryEntryMoved(EntryMovedEvent* event)
15805a1d355fSStephan Aßmus {
15815a1d355fSStephan Aßmus // we simply split the event into a `removed' and a `created' event
15825a1d355fSStephan Aßmus
15835a1d355fSStephan Aßmus // allocate the events
15845a1d355fSStephan Aßmus EntryRemovedEvent* removedEvent = new(std::nothrow) EntryRemovedEvent;
15855a1d355fSStephan Aßmus EntryCreatedEvent* createdEvent = new(std::nothrow) EntryCreatedEvent;
15865a1d355fSStephan Aßmus if (!removedEvent || !createdEvent) {
15875a1d355fSStephan Aßmus delete removedEvent;
15885a1d355fSStephan Aßmus delete createdEvent;
15895a1d355fSStephan Aßmus return;
15905a1d355fSStephan Aßmus }
15915a1d355fSStephan Aßmus
15925a1d355fSStephan Aßmus // init the removed event
15935a1d355fSStephan Aßmus removedEvent->opcode = B_ENTRY_REMOVED;
15945a1d355fSStephan Aßmus removedEvent->time = event->time;
15955a1d355fSStephan Aßmus removedEvent->queryHandler = event->queryHandler;
159688e38c17SIngo Weinhold removedEvent->queryHandler->AcquireReference();
15975a1d355fSStephan Aßmus removedEvent->volumeID = event->volumeID;
15985a1d355fSStephan Aßmus removedEvent->directoryID = event->fromDirectoryID;
15995a1d355fSStephan Aßmus removedEvent->nodeVolumeID = event->volumeID;
16005a1d355fSStephan Aßmus removedEvent->nodeID = event->nodeID;
16015a1d355fSStephan Aßmus removedEvent->name = event->fromName;
16025a1d355fSStephan Aßmus
16035a1d355fSStephan Aßmus // init the created event
16045a1d355fSStephan Aßmus createdEvent->opcode = B_ENTRY_CREATED;
16055a1d355fSStephan Aßmus createdEvent->time = event->time;
16065a1d355fSStephan Aßmus createdEvent->queryHandler = event->queryHandler;
160788e38c17SIngo Weinhold createdEvent->queryHandler->AcquireReference();
16085a1d355fSStephan Aßmus createdEvent->volumeID = event->volumeID;
16095a1d355fSStephan Aßmus createdEvent->directoryID = event->toDirectoryID;
16105a1d355fSStephan Aßmus createdEvent->nodeID = event->nodeID;
16115a1d355fSStephan Aßmus createdEvent->name = event->toName;
16125a1d355fSStephan Aßmus
16135a1d355fSStephan Aßmus // send them
16145a1d355fSStephan Aßmus _QueryEntryRemoved(removedEvent);
161588e38c17SIngo Weinhold removedEvent->ReleaseReference();
16165a1d355fSStephan Aßmus _QueryEntryCreated(createdEvent);
161788e38c17SIngo Weinhold createdEvent->ReleaseReference();
16185a1d355fSStephan Aßmus }
16195a1d355fSStephan Aßmus
16205a1d355fSStephan Aßmus // _IsRecentEvent
16215a1d355fSStephan Aßmus bool
_IsRecentEvent(NodeMonitoringEvent * event) const16225a1d355fSStephan Aßmus VolumeManager::_IsRecentEvent(NodeMonitoringEvent* event) const
16235a1d355fSStephan Aßmus {
16245a1d355fSStephan Aßmus return (event && system_time() < event->time + kRecentEventLifeTime);
16255a1d355fSStephan Aßmus }
16265a1d355fSStephan Aßmus
16275a1d355fSStephan Aßmus // _GenerateEntryCreatedEvent
16285a1d355fSStephan Aßmus status_t
_GenerateEntryCreatedEvent(const entry_ref & ref,bigtime_t time,EntryCreatedEvent ** _event)16295a1d355fSStephan Aßmus VolumeManager::_GenerateEntryCreatedEvent(const entry_ref& ref, bigtime_t time,
16305a1d355fSStephan Aßmus EntryCreatedEvent** _event)
16315a1d355fSStephan Aßmus {
16325a1d355fSStephan Aßmus // load the entry
16335a1d355fSStephan Aßmus Entry* entry;
16345a1d355fSStephan Aßmus status_t error = LoadEntry(ref.device, ref.directory, ref.name, true,
16355a1d355fSStephan Aßmus &entry);
16365a1d355fSStephan Aßmus if (error != B_OK)
16375a1d355fSStephan Aßmus return error;
16385a1d355fSStephan Aßmus
16395a1d355fSStephan Aßmus // create the event
16405a1d355fSStephan Aßmus EntryCreatedEvent* event = new(std::nothrow) EntryCreatedEvent;
16415a1d355fSStephan Aßmus if (!event)
16425a1d355fSStephan Aßmus return B_NO_MEMORY;
16435a1d355fSStephan Aßmus
16445a1d355fSStephan Aßmus // fill in the fields
16455a1d355fSStephan Aßmus event->opcode = B_ENTRY_CREATED;
16465a1d355fSStephan Aßmus event->time = time;
16475a1d355fSStephan Aßmus event->volumeID = entry->GetVolumeID();
16485a1d355fSStephan Aßmus event->directoryID = entry->GetDirectoryID();
16495a1d355fSStephan Aßmus event->nodeID = entry->GetNode()->GetID();
16505a1d355fSStephan Aßmus event->name.SetTo(entry->GetName());
16515a1d355fSStephan Aßmus
16525a1d355fSStephan Aßmus if (_event) {
16535a1d355fSStephan Aßmus *_event = event;
16545a1d355fSStephan Aßmus } else {
16555a1d355fSStephan Aßmus _EntryCreated(event);
165688e38c17SIngo Weinhold event->ReleaseReference();
16575a1d355fSStephan Aßmus }
16585a1d355fSStephan Aßmus
16595a1d355fSStephan Aßmus return B_OK;
16605a1d355fSStephan Aßmus }
16615a1d355fSStephan Aßmus
16625a1d355fSStephan Aßmus // _GenerateEntryRemovedEvent
16635a1d355fSStephan Aßmus status_t
_GenerateEntryRemovedEvent(Entry * entry,bigtime_t time,EntryRemovedEvent ** _event)16645a1d355fSStephan Aßmus VolumeManager::_GenerateEntryRemovedEvent(Entry* entry, bigtime_t time,
16655a1d355fSStephan Aßmus EntryRemovedEvent** _event)
16665a1d355fSStephan Aßmus {
16675a1d355fSStephan Aßmus if (!entry)
16685a1d355fSStephan Aßmus return B_BAD_VALUE;
16695a1d355fSStephan Aßmus
16705a1d355fSStephan Aßmus // create the event
16715a1d355fSStephan Aßmus EntryRemovedEvent* event = new(std::nothrow) EntryRemovedEvent;
16725a1d355fSStephan Aßmus if (!event)
16735a1d355fSStephan Aßmus return B_NO_MEMORY;
16745a1d355fSStephan Aßmus
16755a1d355fSStephan Aßmus // fill in the fields
16765a1d355fSStephan Aßmus event->opcode = B_ENTRY_REMOVED;
16775a1d355fSStephan Aßmus event->time = time;
16785a1d355fSStephan Aßmus event->volumeID = entry->GetVolumeID();
16795a1d355fSStephan Aßmus event->directoryID = entry->GetDirectoryID();
16805a1d355fSStephan Aßmus event->nodeVolumeID = entry->GetNode()->GetVolumeID();
16815a1d355fSStephan Aßmus event->nodeID = entry->GetNode()->GetID();
16825a1d355fSStephan Aßmus event->name.SetTo(entry->GetName());
16835a1d355fSStephan Aßmus
16845a1d355fSStephan Aßmus if (_event) {
16855a1d355fSStephan Aßmus *_event = event;
16865a1d355fSStephan Aßmus } else {
16875a1d355fSStephan Aßmus _EntryRemoved(event, false);
168888e38c17SIngo Weinhold event->ReleaseReference();
16895a1d355fSStephan Aßmus }
16905a1d355fSStephan Aßmus
16915a1d355fSStephan Aßmus return B_OK;
16925a1d355fSStephan Aßmus }
16935a1d355fSStephan Aßmus
16945a1d355fSStephan Aßmus // _CheckVolumeRootMoved
16955a1d355fSStephan Aßmus void
_CheckVolumeRootMoved(EntryMovedEvent * event)16965a1d355fSStephan Aßmus VolumeManager::_CheckVolumeRootMoved(EntryMovedEvent* event)
16975a1d355fSStephan Aßmus {
16985a1d355fSStephan Aßmus // If a volume root is moved, the sent node monitoring message does
16995a1d355fSStephan Aßmus // unforunately contain the node_ref of the covered node, not that of the
17005a1d355fSStephan Aßmus // volume root -- a BeOS R5 VFS bug. Since we have the entry_ref of the
17015a1d355fSStephan Aßmus // new entry, we can stat the node.
17025a1d355fSStephan Aßmus
17035a1d355fSStephan Aßmus // check whether the node is the root of a volume
17045a1d355fSStephan Aßmus NoAllocEntryRef ref(event->volumeID, event->toDirectoryID,
17055a1d355fSStephan Aßmus event->toName.GetString());
17065a1d355fSStephan Aßmus BEntry entry;
17075a1d355fSStephan Aßmus struct stat st;
17085a1d355fSStephan Aßmus if (FDManager::SetEntry(&entry, &ref) == B_OK
17095a1d355fSStephan Aßmus && entry.GetStat(&st) == B_OK) {
17105a1d355fSStephan Aßmus event->nodeVolumeID = st.st_dev;
17115a1d355fSStephan Aßmus event->nodeID = st.st_ino;
17125a1d355fSStephan Aßmus if (Volume* volume = GetVolume(st.st_dev)) {
17135a1d355fSStephan Aßmus if (volume->GetRootID() == st.st_ino) {
1714*ebb21bd1SMurai Takashi PRINT("Mount point for volume %" B_PRIdDEV " renamed\n",
17153c1afd35SPawel Dziepak volume->GetID());
17165a1d355fSStephan Aßmus }
17175a1d355fSStephan Aßmus }
17185a1d355fSStephan Aßmus }
17195a1d355fSStephan Aßmus }
17205a1d355fSStephan Aßmus
17215a1d355fSStephan Aßmus // _NodeMonitoringProcessorEntry
17225a1d355fSStephan Aßmus int32
_NodeMonitoringProcessorEntry(void * data)17235a1d355fSStephan Aßmus VolumeManager::_NodeMonitoringProcessorEntry(void* data)
17245a1d355fSStephan Aßmus {
17255a1d355fSStephan Aßmus return ((VolumeManager*)data)->_NodeMonitoringProcessor();
17265a1d355fSStephan Aßmus }
17275a1d355fSStephan Aßmus
17285a1d355fSStephan Aßmus // _NodeMonitoryProcessor
17295a1d355fSStephan Aßmus int32
_NodeMonitoringProcessor()17305a1d355fSStephan Aßmus VolumeManager::_NodeMonitoringProcessor()
17315a1d355fSStephan Aßmus {
17325a1d355fSStephan Aßmus do {
17335a1d355fSStephan Aßmus NodeMonitoringEvent* event = NULL;
17345a1d355fSStephan Aßmus status_t error = fNodeMonitoringEvents.Pop(&event);
17355a1d355fSStephan Aßmus
17365a1d355fSStephan Aßmus VolumeManagerLocker managerLocker;
17375a1d355fSStephan Aßmus
17385a1d355fSStephan Aßmus while (error == B_OK) {
17395a1d355fSStephan Aßmus if (event->queryHandler) {
17405a1d355fSStephan Aßmus switch (event->opcode) {
17415a1d355fSStephan Aßmus case B_ENTRY_CREATED:
17425a1d355fSStephan Aßmus _QueryEntryCreated(
17435a1d355fSStephan Aßmus dynamic_cast<EntryCreatedEvent*>(event));
17445a1d355fSStephan Aßmus break;
17455a1d355fSStephan Aßmus case B_ENTRY_REMOVED:
17465a1d355fSStephan Aßmus _QueryEntryRemoved(
17475a1d355fSStephan Aßmus dynamic_cast<EntryRemovedEvent*>(event));
17485a1d355fSStephan Aßmus break;
17495a1d355fSStephan Aßmus case B_ENTRY_MOVED:
17505a1d355fSStephan Aßmus _QueryEntryMoved(dynamic_cast<EntryMovedEvent*>(event));
17515a1d355fSStephan Aßmus break;
17525a1d355fSStephan Aßmus }
17535a1d355fSStephan Aßmus } else {
17545a1d355fSStephan Aßmus switch (event->opcode) {
17555a1d355fSStephan Aßmus case B_ENTRY_CREATED:
17565a1d355fSStephan Aßmus _EntryCreated(dynamic_cast<EntryCreatedEvent*>(event));
17575a1d355fSStephan Aßmus break;
17585a1d355fSStephan Aßmus case B_ENTRY_REMOVED:
17595a1d355fSStephan Aßmus _EntryRemoved(dynamic_cast<EntryRemovedEvent*>(event),
17605a1d355fSStephan Aßmus false);
17615a1d355fSStephan Aßmus break;
17625a1d355fSStephan Aßmus case B_ENTRY_MOVED:
17635a1d355fSStephan Aßmus _EntryMoved(dynamic_cast<EntryMovedEvent*>(event));
17645a1d355fSStephan Aßmus break;
17655a1d355fSStephan Aßmus case B_STAT_CHANGED:
17665a1d355fSStephan Aßmus _NodeStatChanged(
17675a1d355fSStephan Aßmus dynamic_cast<StatChangedEvent*>(event));
17685a1d355fSStephan Aßmus break;
17695a1d355fSStephan Aßmus case B_ATTR_CHANGED:
17705a1d355fSStephan Aßmus _NodeAttributeChanged(
17715a1d355fSStephan Aßmus dynamic_cast<AttributeChangedEvent*>(event));
17725a1d355fSStephan Aßmus break;
17735a1d355fSStephan Aßmus case B_DEVICE_MOUNTED:
17745a1d355fSStephan Aßmus _VolumeMounted(dynamic_cast<VolumeMountedEvent*>(event));
17755a1d355fSStephan Aßmus break;
17765a1d355fSStephan Aßmus case B_DEVICE_UNMOUNTED:
17775a1d355fSStephan Aßmus _VolumeUnmounted(
17785a1d355fSStephan Aßmus dynamic_cast<VolumeUnmountedEvent*>(event));
17795a1d355fSStephan Aßmus break;
17805a1d355fSStephan Aßmus }
17815a1d355fSStephan Aßmus }
178288e38c17SIngo Weinhold event->ReleaseReference();
17835a1d355fSStephan Aßmus
17845a1d355fSStephan Aßmus // If there is another event available, get it as long as we
17855a1d355fSStephan Aßmus // have the VolumeManager lock.
17865a1d355fSStephan Aßmus error = fNodeMonitoringEvents.Pop(&event, 0);
17875a1d355fSStephan Aßmus }
17885a1d355fSStephan Aßmus } while (!fTerminating);
17895a1d355fSStephan Aßmus
17905a1d355fSStephan Aßmus return 0;
17915a1d355fSStephan Aßmus }
17925a1d355fSStephan Aßmus
17935a1d355fSStephan Aßmus
17945a1d355fSStephan Aßmus // sManager
17955a1d355fSStephan Aßmus VolumeManager* VolumeManager::sManager = NULL;
1796