diff --git a/src/servers/registrar/DiskDeviceManager.cpp b/src/servers/registrar/DiskDeviceManager.cpp index 79e7ea7437..6824a59ef2 100644 --- a/src/servers/registrar/DiskDeviceManager.cpp +++ b/src/servers/registrar/DiskDeviceManager.cpp @@ -7,30 +7,33 @@ #include #include "DiskDeviceManager.h" +#include "Debug.h" +#include "EventMaskWatcher.h" #include "RDiskDevice.h" #include "RDiskDeviceList.h" #include "RPartition.h" #include "RSession.h" -#include "Debug.h" enum { - REQUEST_PRIORITY = 0, - NODE_MONITOR_PRIORITY = 10, + REQUEST_PRIORITY = 0, + NODE_MONITOR_PRIORITY = 10, + WATCHING_REQUEST_PRIORITY = 20, }; // constructor DiskDeviceManager::DiskDeviceManager() : BLooper("disk device manager"), fDeviceListLock(), + fWatchingService(), fVolumeList(BMessenger(this), fDeviceListLock), - fDeviceList(BMessenger(this), fDeviceListLock, fVolumeList), + fDeviceList(BMessenger(this), fDeviceListLock, fVolumeList, + &fWatchingService), fMessageQueue(), fWorker(-1), fMessageCounter(-1), fTerminating(false) { // set up the device list - fVolumeList.Rescan(); fVolumeList.Dump(); fDeviceList.Rescan(); fDeviceList.Dump(); @@ -61,10 +64,14 @@ DiskDeviceManager::MessageReceived(BMessage *message) case B_REG_NEXT_DISK_DEVICE: case B_REG_GET_DISK_DEVICE: case B_REG_UPDATE_DISK_DEVICE: + DetachCurrentMessage(); + if (!_PushMessage(message, REQUEST_PRIORITY)) + delete message; + break; case B_REG_DEVICE_START_WATCHING: case B_REG_DEVICE_STOP_WATCHING: DetachCurrentMessage(); - if (!_PushMessage(message, REQUEST_PRIORITY)) + if (!_PushMessage(message, WATCHING_REQUEST_PRIORITY)) delete message; break; case B_NODE_MONITOR: @@ -80,13 +87,14 @@ DiskDeviceManager::MessageReceived(BMessage *message) // _NextDiskDeviceRequest void -DiskDeviceManager::_NextDiskDeviceRequest(BMessage *message) +DiskDeviceManager::_NextDiskDeviceRequest(BMessage *request) { FUNCTION_START(); + Lock(); status_t error = B_OK; int32 cookie = 0; BMessage reply(B_REG_RESULT); - if (message->FindInt32("cookie", &cookie) == B_OK) { + if (request->FindInt32("cookie", &cookie) == B_OK) { // get next device if (RDiskDevice *device = fDeviceList.DeviceWithID(cookie, false)) { // archive device @@ -103,23 +111,25 @@ DiskDeviceManager::_NextDiskDeviceRequest(BMessage *message) SET_ERROR(error, B_BAD_VALUE); // add result and send reply reply.AddInt32("result", error); - message->SendReply(&reply); + request->SendReply(&reply); + Unlock(); } // _GetDiskDeviceRequest void -DiskDeviceManager::_GetDiskDeviceRequest(BMessage *message) +DiskDeviceManager::_GetDiskDeviceRequest(BMessage *request) { + Lock(); status_t error = B_ENTRY_NOT_FOUND; // get the device RDiskDevice *device = NULL; int32 id = 0; - if (message->FindInt32("device_id", &id) == B_OK) + if (request->FindInt32("device_id", &id) == B_OK) device = fDeviceList.DeviceWithID(id); - else if (message->FindInt32("session_id", &id) == B_OK) { + else if (request->FindInt32("session_id", &id) == B_OK) { if (RSession *session = fDeviceList.SessionWithID(id)) device = session->Device(); - } else if (message->FindInt32("partition_id", &id) == B_OK) { + } else if (request->FindInt32("partition_id", &id) == B_OK) { if (RPartition *partition = fDeviceList.PartitionWithID(id)) device = partition->Device(); } else @@ -134,13 +144,15 @@ DiskDeviceManager::_GetDiskDeviceRequest(BMessage *message) } // add result and send reply reply.AddInt32("result", error); - message->SendReply(&reply); + request->SendReply(&reply); + Unlock(); } // _UpdateDiskDeviceRequest void -DiskDeviceManager::_UpdateDiskDeviceRequest(BMessage *message) +DiskDeviceManager::_UpdateDiskDeviceRequest(BMessage *request) { + Lock(); status_t error = B_ENTRY_NOT_FOUND; // get the device and check the object is up to date bool upToDate = false; @@ -148,20 +160,20 @@ DiskDeviceManager::_UpdateDiskDeviceRequest(BMessage *message) int32 id = 0; int32 changeCounter = 0; uint32 policy = 0; - if (message->FindInt32("change_counter", &changeCounter) != B_OK - || message->FindInt32("update_policy", (int32*)&policy) != B_OK) { - // bad request message + if (request->FindInt32("change_counter", &changeCounter) != B_OK + || request->FindInt32("update_policy", (int32*)&policy) != B_OK) { + // bad request request SET_ERROR(error, B_BAD_VALUE); - } else if (message->FindInt32("device_id", &id) == B_OK) { + } else if (request->FindInt32("device_id", &id) == B_OK) { device = fDeviceList.DeviceWithID(id); if (device) upToDate = (device->ChangeCounter() == changeCounter); - } else if (message->FindInt32("session_id", &id) == B_OK) { + } else if (request->FindInt32("session_id", &id) == B_OK) { if (RSession *session = fDeviceList.SessionWithID(id)) { device = session->Device(); upToDate = (session->ChangeCounter() == changeCounter); } - } else if (message->FindInt32("partition_id", &id) == B_OK) { + } else if (request->FindInt32("partition_id", &id) == B_OK) { if (RPartition *partition = fDeviceList.PartitionWithID(id)) { device = partition->Device(); upToDate = (partition->ChangeCounter() == changeCounter); @@ -184,9 +196,66 @@ DiskDeviceManager::_UpdateDiskDeviceRequest(BMessage *message) if (error == B_OK) error = reply.AddBool("up_to_date", upToDate); reply.AddInt32("result", error); - message->SendReply(&reply); + request->SendReply(&reply); + Unlock(); } +// _StartWatchingRequest +void +DiskDeviceManager::_StartWatchingRequest(BMessage *request) +{ + FUNCTION_START(); + Lock(); + status_t error = B_OK; + // get the parameters + BMessenger target; + uint32 events; + if (error == B_OK + && (request->FindMessenger("target", &target) != B_OK + || request->FindInt32("events", (int32*)&events) != B_OK)) { + SET_ERROR(error, B_BAD_VALUE); + } + // add the new watcher + if (error == B_OK) { + Watcher *watcher = new(nothrow) EventMaskWatcher(target, events); + if (watcher) { + if (!fWatchingService.AddWatcher(watcher)) { + SET_ERROR(error, B_NO_MEMORY); + delete watcher; + } + } else + SET_ERROR(error, B_NO_MEMORY); + } + // add result and send reply + BMessage reply(B_REG_RESULT); + reply.AddInt32("result", error); + request->SendReply(&reply); + Unlock(); +}; + +// _StopWatchingRequest +void +DiskDeviceManager::_StopWatchingRequest(BMessage *request) +{ + FUNCTION_START(); + Lock(); + status_t error = B_OK; + // get the parameters + BMessenger target; + if (error == B_OK && request->FindMessenger("target", &target) != B_OK) + error = B_BAD_VALUE; + // remove the watcher + if (error == B_OK) { + if (!fWatchingService.RemoveWatcher(target)) + error = B_BAD_VALUE; + } + // add result and send reply + BMessage reply(B_REG_RESULT); + reply.AddInt32("result", error); + request->SendReply(&reply); + Unlock(); +}; + // _PushMessage bool DiskDeviceManager::_PushMessage(BMessage *message, int32 priority) @@ -233,7 +302,10 @@ DiskDeviceManager::_Worker() _UpdateDiskDeviceRequest(message); break; case B_REG_DEVICE_START_WATCHING: + _StartWatchingRequest(message); + break; case B_REG_DEVICE_STOP_WATCHING: + _StopWatchingRequest(message); break; case B_NODE_MONITOR: { diff --git a/src/servers/registrar/DiskDeviceManager.h b/src/servers/registrar/DiskDeviceManager.h index 6f98d314d7..732e76dbfa 100644 --- a/src/servers/registrar/DiskDeviceManager.h +++ b/src/servers/registrar/DiskDeviceManager.h @@ -13,6 +13,7 @@ #include "PriorityMessageQueue.h" #include "RDiskDeviceList.h" #include "RVolumeList.h" +#include "WatchingService.h" class DiskDeviceManager : public BLooper { public: @@ -23,9 +24,11 @@ public: private: // requests - void _NextDiskDeviceRequest(BMessage *message); - void _GetDiskDeviceRequest(BMessage *message); - void _UpdateDiskDeviceRequest(BMessage *message); + void _NextDiskDeviceRequest(BMessage *request); + void _GetDiskDeviceRequest(BMessage *request); + void _UpdateDiskDeviceRequest(BMessage *request); + void _StartWatchingRequest(BMessage *request); + void _StopWatchingRequest(BMessage *request); bool _PushMessage(BMessage *message, int32 priority); BMessage *_PopMessage(); @@ -35,6 +38,7 @@ private: private: BLocker fDeviceListLock; + WatchingService fWatchingService; RVolumeList fVolumeList; RDiskDeviceList fDeviceList; PriorityMessageQueue fMessageQueue; diff --git a/src/servers/registrar/RDiskDevice.cpp b/src/servers/registrar/RDiskDevice.cpp index a78a84be1a..14af023f34 100644 --- a/src/servers/registrar/RDiskDevice.cpp +++ b/src/servers/registrar/RDiskDevice.cpp @@ -141,10 +141,10 @@ RDiskDevice::RemoveSession(int32 index) { RSession *session = SessionAt(index); if (session) { - session->SetDevice(NULL); - fSessions.RemoveItemAt(index); if (RDiskDeviceList *deviceList = DeviceList()) deviceList->SessionRemoved(session); + session->SetDevice(NULL); + fSessions.RemoveItemAt(index); delete session; } return (session != NULL); diff --git a/src/servers/registrar/RDiskDeviceList.cpp b/src/servers/registrar/RDiskDeviceList.cpp index 25fd4f5c52..ffc3d7adac 100644 --- a/src/servers/registrar/RDiskDeviceList.cpp +++ b/src/servers/registrar/RDiskDeviceList.cpp @@ -12,6 +12,7 @@ #include #include +#include #include #include #include @@ -19,24 +20,13 @@ #include "RDiskDeviceList.h" #include "Debug.h" +#include "EventMaskWatcher.h" #include "RDiskDevice.h" #include "RPartition.h" #include "RSession.h" +#include "WatchingService.h" -// compare_ids -/*template -static -int -compare_ids(const T *object1, const T *object2) -{ - int32 id1 = object1->ID(); - int32 id2 = object2->ID(); - if (id1 < id2) - return -1; - if (id1 > id2) - return 1; - return 0; -}*/ +namespace RDiskDeviceListPredicates { // CompareIDPredicate template @@ -71,14 +61,36 @@ private: const char *fPath; }; +// ComparePartitionPathPredicate +struct ComparePartitionPathPredicate : public UnaryPredicate { + ComparePartitionPathPredicate(const char *path) : fPath(path) {} + + virtual int operator()(const RPartition *partition) const + { + char path[B_FILE_NAME_LENGTH]; + partition->GetPath(path); + return strcmp(fPath, path); + } + +private: + const char *fPath; +}; + +} // namespace RDiskDeviceListPredicates + +using namespace RDiskDeviceListPredicates; + + // constructor RDiskDeviceList::RDiskDeviceList(BMessenger target, BLocker &lock, - RVolumeList &volumeList) + RVolumeList &volumeList, + WatchingService *watchingService) : MessageHandler(), RVolumeListListener(), fLock(lock), fTarget(target), fVolumeList(volumeList), + fWatchingService(watchingService), fDevices(20, true), fSessions(40, false), fPartitions(80, false) @@ -110,6 +122,21 @@ void RDiskDeviceList::VolumeMounted(const RVolume *volume) { PRINT(("RDiskDeviceList::VolumeMounted(%ld)\n", volume->ID())); + Lock(); + // get the partition and set its volume + const char *devicePath = volume->DevicePath(); + if (RPartition *partition = PartitionWithPath(devicePath)) { + partition->SetVolume(volume); + // send notifications + BMessage notification(B_DEVICE_UPDATE); + if (_InitNotificationMessage(¬ification, + B_DEVICE_PARTITION_MOUNTED, B_DEVICE_CAUSE_UNKNOWN, + partition) == B_OK) { + EventMaskWatcherFilter filter(B_DEVICE_REQUEST_MOUNTING); + fWatchingService->NotifyWatchers(¬ification, &filter); + } + } + Unlock(); } // VolumeUnmounted @@ -117,13 +144,46 @@ void RDiskDeviceList::VolumeUnmounted(const RVolume *volume) { PRINT(("RDiskDeviceList::VolumeUnmounted(%ld)\n", volume->ID())); + Lock(); + // get the partition and set its volume + const char *devicePath = volume->DevicePath(); + if (RPartition *partition = PartitionWithPath(devicePath)) { + partition->SetVolume(NULL); + // send notifications + BMessage notification(B_DEVICE_UPDATE); + if (_InitNotificationMessage(¬ification, + B_DEVICE_PARTITION_UNMOUNTED, B_DEVICE_CAUSE_UNKNOWN, + partition) == B_OK) { + EventMaskWatcherFilter filter(B_DEVICE_REQUEST_MOUNTING); + fWatchingService->NotifyWatchers(¬ification, &filter); + } + } + Unlock(); } // MountPointMoved void -RDiskDeviceList::MountPointMoved(const RVolume *volume) +RDiskDeviceList::MountPointMoved(const RVolume *volume, + const entry_ref *oldRoot, + const entry_ref *newRoot) { PRINT(("RDiskDeviceList::MountPointMoved(%ld)\n", volume->ID())); + Lock(); + // get the partition + const char *devicePath = volume->DevicePath(); + if (RPartition *partition = PartitionWithPath(devicePath)) { + // send notifications + BMessage notification(B_DEVICE_UPDATE); + if (_InitNotificationMessage(¬ification, + B_DEVICE_MOUNT_POINT_MOVED, B_DEVICE_CAUSE_UNKNOWN, + partition) == B_OK + && notification.AddRef("old_directory", oldRoot) == B_OK + && notification.AddRef("new_directory", newRoot) == B_OK) { + EventMaskWatcherFilter filter(B_DEVICE_REQUEST_MOUNT_POINT); + fWatchingService->NotifyWatchers(¬ification, &filter); + } + } + Unlock(); } // AddDevice @@ -145,9 +205,9 @@ RDiskDeviceList::RemoveDevice(int32 index) { RDiskDevice *device = DeviceAt(index); if (device) { + DeviceRemoved(device); device->SetDeviceList(NULL); fDevices.RemoveItemAt(index); - DeviceRemoved(device); delete device; } return (device != NULL); @@ -206,6 +266,15 @@ RDiskDeviceList::DeviceWithPath(const char *path) const return const_cast(device); } +// PartitionWithPath +RPartition * +RDiskDeviceList::PartitionWithPath(const char *path) const +{ + const RPartition *partition + = fPartitions.FindIf(ComparePartitionPathPredicate(path)); + return const_cast(partition); +} + // Rescan status_t RDiskDeviceList::Rescan() @@ -273,6 +342,8 @@ RDiskDeviceList::DeviceRemoved(RDiskDevice *device, uint32 cause) void RDiskDeviceList::SessionAdded(RSession *session, uint32 cause) { + // add the session to our list + fSessions.BinaryInsert(session, CompareIDPredicate(session)); // propagate to partitions for (int32 i = 0; RPartition *partition = session->PartitionAt(i); i++) PartitionAdded(partition, B_DEVICE_CAUSE_PARENT_CHANGED); @@ -284,6 +355,12 @@ RDiskDeviceList::SessionAdded(RSession *session, uint32 cause) void RDiskDeviceList::SessionRemoved(RSession *session, uint32 cause) { + // remove the session from our list + bool success = false; + int32 index = fSessions.FindBinaryInsertionIndex( + CompareIDPredicate(session), &success); + if (success) + fSessions.RemoveItemAt(index); // propagate to partitions for (int32 i = 0; RPartition *partition = session->PartitionAt(i); i++) PartitionRemoved(partition, B_DEVICE_CAUSE_PARENT_CHANGED); @@ -295,6 +372,9 @@ RDiskDeviceList::SessionRemoved(RSession *session, uint32 cause) void RDiskDeviceList::PartitionAdded(RPartition *partition, uint32 cause) { + // add the partition to our list + fPartitions.BinaryInsert(partition, + CompareIDPredicate(partition)); // get the corresponding volume, if partition is mounted char path[B_FILE_NAME_LENGTH]; partition->GetPath(path); @@ -308,6 +388,12 @@ RDiskDeviceList::PartitionAdded(RPartition *partition, uint32 cause) void RDiskDeviceList::PartitionRemoved(RPartition *partition, uint32 cause) { + // remove the partition from our list + bool success = false; + int32 index = fPartitions.FindBinaryInsertionIndex( + CompareIDPredicate(partition), &success); + if (success) + fPartitions.RemoveItemAt(index); // notifications // ... } @@ -393,3 +479,64 @@ RDiskDeviceList::_ScanDevice(const char *path) return error; } +// _InitNotificationMessage +status_t +RDiskDeviceList::_InitNotificationMessage(BMessage *message, uint32 event, + uint32 cause) +{ + status_t error = (message ? B_OK : B_BAD_VALUE); + if (error == B_OK) { + message->what = B_DEVICE_UPDATE; + error = message->AddInt32("event", event); + } + if (error == B_OK) + error = message->AddInt32("cause", cause); + return error; +} + +// _InitNotificationMessage +status_t +RDiskDeviceList::_InitNotificationMessage(BMessage *message, uint32 event, + uint32 cause, + const RDiskDevice *device) +{ + status_t error = (device ? B_OK : B_BAD_VALUE); + if (error == B_OK) + error = _InitNotificationMessage(message, event, cause); + if (error == B_OK) + error = message->AddInt32("device_id", device->ID()); + return error; +} + +// _InitNotificationMessage +status_t +RDiskDeviceList::_InitNotificationMessage(BMessage *message, uint32 event, + uint32 cause, + const RSession *session) +{ + status_t error = (session ? B_OK : B_BAD_VALUE); + if (error == B_OK) { + error = _InitNotificationMessage(message, event, cause, + session->Device()); + } + if (error == B_OK) + error = message->AddInt32("session_id", session->ID()); + return error; +} + +// _InitNotificationMessage +status_t +RDiskDeviceList::_InitNotificationMessage(BMessage *message, uint32 event, + uint32 cause, + const RPartition *partition) +{ + status_t error = (partition ? B_OK : B_BAD_VALUE); + if (error == B_OK) { + error = _InitNotificationMessage(message, event, cause, + partition->Session()); + } + if (error == B_OK) + error = message->AddInt32("partition_id", partition->ID()); + return error; +} + diff --git a/src/servers/registrar/RDiskDeviceList.h b/src/servers/registrar/RDiskDeviceList.h index 1e7edc57d6..d044fff395 100644 --- a/src/servers/registrar/RDiskDeviceList.h +++ b/src/servers/registrar/RDiskDeviceList.h @@ -19,6 +19,7 @@ class BLocker; class RDiskDevice; class RPartition; class RSession; +class WatchingService; // device list modification causes // TODO: to be moved to @@ -36,14 +37,17 @@ enum { class RDiskDeviceList : public MessageHandler, public RVolumeListListener { public: - RDiskDeviceList(BMessenger target, BLocker &lock, RVolumeList &volumeList); + RDiskDeviceList(BMessenger target, BLocker &lock, RVolumeList &volumeList, + WatchingService *watchingService); ~RDiskDeviceList(); virtual void HandleMessage(BMessage *message); virtual void VolumeMounted(const RVolume *volume); virtual void VolumeUnmounted(const RVolume *volume); - virtual void MountPointMoved(const RVolume *volume); + virtual void MountPointMoved(const RVolume *volume, + const entry_ref *oldRoot, + const entry_ref *newRoot); bool AddDevice(RDiskDevice *device); bool RemoveDevice(int32 index); @@ -63,6 +67,7 @@ public: RPartition *PartitionWithID(int32 id) const; RDiskDevice *DeviceWithPath(const char *path) const; + RPartition *PartitionWithPath(const char *path) const; status_t Rescan(); @@ -88,10 +93,21 @@ private: status_t _Scan(BDirectory &dir); status_t _ScanDevice(const char *path); + status_t _InitNotificationMessage(BMessage *message, uint32 event, + uint32 cause); + status_t _InitNotificationMessage(BMessage *message, uint32 event, + uint32 cause, const RDiskDevice *device); + status_t _InitNotificationMessage(BMessage *message, uint32 event, + uint32 cause, const RSession *session); + status_t _InitNotificationMessage(BMessage *message, uint32 event, + uint32 cause, + const RPartition *partition); + private: mutable BLocker &fLock; BMessenger fTarget; RVolumeList &fVolumeList; + WatchingService *fWatchingService; BObjectList fDevices; // sorted by ID BObjectList fSessions; // BObjectList fPartitions; // diff --git a/src/servers/registrar/RSession.cpp b/src/servers/registrar/RSession.cpp index 01d54c97ef..b652aa6485 100644 --- a/src/servers/registrar/RSession.cpp +++ b/src/servers/registrar/RSession.cpp @@ -109,10 +109,10 @@ RSession::RemovePartition(int32 index) { RPartition *partition = PartitionAt(index); if (partition) { - partition->SetSession(NULL); - fPartitions.RemoveItemAt(index); if (RDiskDeviceList *deviceList = DeviceList()) deviceList->PartitionRemoved(partition); + partition->SetSession(NULL); + fPartitions.RemoveItemAt(index); delete partition; } return (partition != NULL); diff --git a/src/servers/registrar/RVolumeList.cpp b/src/servers/registrar/RVolumeList.cpp index 05b407960b..df7c73fa30 100644 --- a/src/servers/registrar/RVolumeList.cpp +++ b/src/servers/registrar/RVolumeList.cpp @@ -5,14 +5,19 @@ #include +#include +#include #include #include #include +#include #include #include "RVolumeList.h" #include "Debug.h" +namespace RVolumeListPredicates { + // CompareIDPredicate struct CompareIDPredicate : public UnaryPredicate { CompareIDPredicate(dev_t id) : fID(id) {} @@ -45,13 +50,18 @@ private: const char *fPath; }; +} // namespace RVolumeListPredicates + +using namespace RVolumeListPredicates; + // RVolume // constructor RVolume::RVolume() : fID(-1), - fRootNode(-1) + fRootNode(-1), + fRootEntry() { } @@ -60,13 +70,31 @@ status_t RVolume::SetTo(dev_t id) { status_t error = B_OK; + // get general info fs_info info; error = fs_stat_dev(id, &info); if (error == B_OK) { fID = id; fRootNode = info.root; - strcpy(fDevicePath, info.device_name); - } else + if (info.device_name[0] != '\0') + strcpy(fDevicePath, info.device_name); + else // generate a pseudo name -- needed for the list + sprintf(fDevicePath, "%ld", id); + } + // get root dir entry_ref + if (error == B_OK) { + node_ref ref; + GetRootDirNode(&ref); + BDirectory dir; + error = dir.SetTo(&ref); + BEntry entry; + if (error == B_OK) + error = dir.GetEntry(&entry); + if (error == B_OK) + error = entry.GetRef(&fRootEntry); + } + // cleanup on error + if (error != B_OK) Unset(); return error; } @@ -126,7 +154,9 @@ RVolumeListListener::VolumeUnmounted(const RVolume *volume) // MountPointMoved void -RVolumeListListener::MountPointMoved(const RVolume *volume) +RVolumeListListener::MountPointMoved(const RVolume *volume, + const entry_ref *oldRoot, + const entry_ref *newRoot) { } @@ -194,12 +224,15 @@ RVolumeList::HandleMessage(BMessage *message) status_t RVolumeList::Rescan() { - fVolumes.MakeEmpty(); +PRINT(("RVolumeList::Rescan()\n")); + for (int32 i = fVolumes.CountItems() - 1; i >= 0; i--) + _RemoveVolumeAt(i); fRoster.Rewind(); BVolume bVolume; while (fRoster.GetNextVolume(&bVolume) == B_OK) _AddVolume(bVolume.Device()); - return B_ERROR; +PRINT(("RVolumeList::Rescan() done\n")); + return B_OK; } // VolumeForDevicePath @@ -272,6 +305,18 @@ RVolumeList::_AddVolume(dev_t id) return volume; } +// _RemoveVolumeAt +bool +RVolumeList::_RemoveVolumeAt(int32 index) +{ + bool result = false; + if (RVolume *volume = fVolumes.RemoveItemAt(index)) { + volume->StopWatching(fTarget); + delete volume; + } + return result; +} + // _DeviceMounted void RVolumeList::_DeviceMounted(BMessage *message) @@ -307,12 +352,33 @@ RVolumeList::_DeviceUnmounted(BMessage *message) void RVolumeList::_MountPointMoved(BMessage *message) { + // Note: The "device" field of the message refers to the device of the + // parent directory. Therefore we need to get an entry_ref, turn it into + // a path and get the device for that path. + // get the message fields dev_t device; - if (message->FindInt32("device", &device) == B_OK) { - PRINT(("RVolumeList::_MountPointMoved(%ld)\n", device)); - if (RVolume *volume = fVolumes.FindIf(CompareIDPredicate(device))) { - if (fListener) - fListener->MountPointMoved(volume); + ino_t directory; + const char *name; + if (message->FindInt32("device", &device) == B_OK + && message->FindInt64("to directory", &directory) == B_OK + && message->FindString("name", &name) == B_OK) { + // init an entry_ref + entry_ref ref; + ref.device = device; + ref.directory = directory; + ref.set_name(name); + // get the path and the device for that path + BPath path; + if (path.SetTo(&ref) == B_OK + && (device = dev_for_path(path.Path())) >= 0) { + PRINT(("RVolumeList::_MountPointMoved(%ld)\n", device)); + if (RVolume *volume = fVolumes.FindIf(CompareIDPredicate(device))) { + entry_ref oldRoot; + volume->GetRootDirEntry(&oldRoot); + volume->SetRootDirEntry(&ref); + if (fListener) + fListener->MountPointMoved(volume, &oldRoot, &ref); + } } } } diff --git a/src/servers/registrar/RVolumeList.h b/src/servers/registrar/RVolumeList.h index 7555ffc006..00a8bf570f 100644 --- a/src/servers/registrar/RVolumeList.h +++ b/src/servers/registrar/RVolumeList.h @@ -6,6 +6,7 @@ #ifndef VOLUME_LIST_H #define VOLUME_LIST_H +#include #include #include #include @@ -26,17 +27,21 @@ public: dev_t ID() const { return fID; } ino_t RootNode() const { return fRootNode; } - void GetRootNodeRef(node_ref *ref) const + void GetRootDirNode(node_ref *ref) const { ref->device = fID; ref->node = fRootNode; } + void GetRootDirEntry(entry_ref *ref) const { *ref = fRootEntry; } const char *DevicePath() const { return fDevicePath; } + void SetRootDirEntry(const entry_ref *ref) { fRootEntry = *ref; } + status_t StartWatching(BMessenger target) const; status_t StopWatching(BMessenger target) const; private: - dev_t fID; - ino_t fRootNode; - char fDevicePath[B_FILE_NAME_LENGTH]; + dev_t fID; + ino_t fRootNode; + entry_ref fRootEntry; + char fDevicePath[B_FILE_NAME_LENGTH]; }; // RVolumeListListener @@ -47,7 +52,9 @@ public: virtual void VolumeMounted(const RVolume *volume); virtual void VolumeUnmounted(const RVolume *volume); - virtual void MountPointMoved(const RVolume *volume); + virtual void MountPointMoved(const RVolume *volume, + const entry_ref *oldRoot, + const entry_ref *newRoot); }; // RVolumeList @@ -71,6 +78,7 @@ public: private: RVolume *_AddVolume(dev_t id); + bool _RemoveVolumeAt(int32 index); void _DeviceMounted(BMessage *message); void _DeviceUnmounted(BMessage *message); void _MountPointMoved(BMessage *message);