From 8c0d5e25464e57f27df801ba54fe4eae07a81dc4 Mon Sep 17 00:00:00 2001 From: Pierre Schweitzer Date: Mon, 14 Sep 2015 22:30:13 +0000 Subject: [PATCH] [MOUNTMGR] Implement the IOCTL IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_DELETED: - Implement MountMgrVolumeMountPointDeleteed() - Rename a struct var to reflect its real usage svn path=/trunk/; revision=69232 --- reactos/drivers/filters/mountmgr/database.c | 2 +- reactos/drivers/filters/mountmgr/device.c | 215 +++++++++++++++++++- reactos/drivers/filters/mountmgr/mntmgr.h | 8 +- reactos/drivers/filters/mountmgr/mountmgr.c | 1 - 4 files changed, 217 insertions(+), 9 deletions(-) diff --git a/reactos/drivers/filters/mountmgr/database.c b/reactos/drivers/filters/mountmgr/database.c index a2e5fcd1a49..534286188b5 100644 --- a/reactos/drivers/filters/mountmgr/database.c +++ b/reactos/drivers/filters/mountmgr/database.c @@ -1464,7 +1464,7 @@ ChangeRemoteDatabaseUniqueId(IN PDEVICE_INFORMATION DeviceInformation, /* Recreate the entry from the previous one */ NewEntry->EntrySize = Entry->EntrySize + NewUniqueId->UniqueIdLength - OldUniqueId->UniqueIdLength; - NewEntry->DatabaseOffset = Entry->DatabaseOffset; + NewEntry->EntryReferences = Entry->EntryReferences; NewEntry->SymbolicNameOffset = sizeof(DATABASE_ENTRY); NewEntry->SymbolicNameLength = Entry->SymbolicNameLength; NewEntry->UniqueIdOffset = Entry->SymbolicNameLength + sizeof(DATABASE_ENTRY); diff --git a/reactos/drivers/filters/mountmgr/device.c b/reactos/drivers/filters/mountmgr/device.c index dada24a5f9d..3f822b4eda7 100644 --- a/reactos/drivers/filters/mountmgr/device.c +++ b/reactos/drivers/filters/mountmgr/device.c @@ -1813,7 +1813,8 @@ MountMgrVolumeMountPointCreated(IN PDEVICE_EXTENSION DeviceExtension, DbName.Buffer = (PWSTR)((ULONG_PTR)DatabaseEntry + DatabaseEntry->SymbolicNameOffset); if (RtlEqualUnicodeString(&TargetVolumeName, &DbName, TRUE)) { - ++DatabaseEntry->DatabaseOffset; + /* Reference ourselves and update the entry */ + ++DatabaseEntry->EntryReferences; Status = WriteRemoteDatabaseEntry(RemoteDatabase, Offset, DatabaseEntry); FreePool(DatabaseEntry); Found = TRUE; @@ -1852,7 +1853,7 @@ MountMgrVolumeMountPointCreated(IN PDEVICE_EXTENSION DeviceExtension, /* Fill it in */ DatabaseEntry->EntrySize = EntrySize; - DatabaseEntry->DatabaseOffset = 1; + DatabaseEntry->EntryReferences = 1; DatabaseEntry->SymbolicNameOffset = sizeof(DATABASE_ENTRY); DatabaseEntry->SymbolicNameLength = TargetVolumeName.Length; DatabaseEntry->UniqueIdOffset = TargetVolumeName.Length + sizeof(DATABASE_ENTRY); @@ -1926,15 +1927,217 @@ MountMgrVolumeMountPointCreated(IN PDEVICE_EXTENSION DeviceExtension, return STATUS_SUCCESS; } +/* + * @implemented + */ + NTSTATUS MountMgrVolumeMountPointDeleted(IN PDEVICE_EXTENSION DeviceExtension, IN PIRP Irp, IN NTSTATUS LockStatus) { - UNREFERENCED_PARAMETER(DeviceExtension); - UNREFERENCED_PARAMETER(Irp); - UNREFERENCED_PARAMETER(LockStatus); - return STATUS_NOT_IMPLEMENTED; + LONG Offset; + NTSTATUS Status; + PLIST_ENTRY Entry; + HANDLE RemoteDatabase; + PDATABASE_ENTRY DatabaseEntry; + PUNIQUE_ID_REPLICATE UniqueIdReplicate; + PASSOCIATED_DEVICE_ENTRY AssociatedEntry; + PDEVICE_INFORMATION DeviceInformation, TargetDeviceInformation; + UNICODE_STRING LinkTarget, SourceDeviceName, SourceSymbolicName, TargetVolumeName, VolumeName, DbName; + + /* Initialize string */ + LinkTarget.Length = 0; + LinkTarget.MaximumLength = 0xC8; + LinkTarget.Buffer = AllocatePool(LinkTarget.MaximumLength); + if (LinkTarget.Buffer == NULL) + { + return STATUS_INSUFFICIENT_RESOURCES; + } + + /* If the mount point was deleted, then, it changed! + * Also use it to query some information + */ + Status = MountMgrVolumeMountPointChanged(DeviceExtension, Irp, LockStatus, &SourceDeviceName, &SourceSymbolicName, &TargetVolumeName); + /* Pending means DB are under synchronization, bail out */ + if (Status == STATUS_PENDING) + { + FreePool(LinkTarget.Buffer); + FreePool(SourceDeviceName.Buffer); + FreePool(SourceSymbolicName.Buffer); + return STATUS_SUCCESS; + } + else if (!NT_SUCCESS(Status)) + { + FreePool(LinkTarget.Buffer); + return Status; + } + + /* Query the device information */ + Status = FindDeviceInfo(DeviceExtension, &SourceDeviceName, FALSE, &DeviceInformation); + if (!NT_SUCCESS(Status)) + { + /* If it failed, first try to get volume name */ + Status = QueryVolumeName(0, NULL, &SourceDeviceName, &LinkTarget, &VolumeName); + if (!NT_SUCCESS(Status)) + { + /* Then, try to read the symlink */ + Status = MountMgrQuerySymbolicLink(&SourceDeviceName, &LinkTarget); + if (!NT_SUCCESS(Status)) + { + FreePool(LinkTarget.Buffer); + FreePool(SourceDeviceName.Buffer); + FreePool(SourceSymbolicName.Buffer); + return Status; + } + } + else + { + FreePool(VolumeName.Buffer); + } + + FreePool(SourceDeviceName.Buffer); + + SourceDeviceName.Length = LinkTarget.Length; + SourceDeviceName.MaximumLength = LinkTarget.MaximumLength; + SourceDeviceName.Buffer = LinkTarget.Buffer; + + /* Now that we have the correct source, reattempt to query information */ + Status = FindDeviceInfo(DeviceExtension, &SourceDeviceName, FALSE, &DeviceInformation); + if (!NT_SUCCESS(Status)) + { + FreePool(SourceDeviceName.Buffer); + FreePool(SourceSymbolicName.Buffer); + return Status; + } + } + + FreePool(SourceDeviceName.Buffer); + + /* Get information about target device */ + Status = FindDeviceInfo(DeviceExtension, &TargetVolumeName, FALSE, &TargetDeviceInformation); + if (!NT_SUCCESS(Status)) + { + FreePool(SourceSymbolicName.Buffer); + return Status; + } + + /* Open the remote database */ + RemoteDatabase = OpenRemoteDatabase(DeviceInformation, TRUE); + if (RemoteDatabase == 0) + { + FreePool(SourceSymbolicName.Buffer); + return STATUS_INSUFFICIENT_RESOURCES; + } + + /* Browse all the entries */ + Offset = 0; + for (;;) + { + DatabaseEntry = GetRemoteDatabaseEntry(RemoteDatabase, Offset); + if (DatabaseEntry == NULL) + { + /* We didn't find ourselves, that's infortunate! */ + FreePool(SourceSymbolicName.Buffer); + CloseRemoteDatabase(RemoteDatabase); + return STATUS_INVALID_PARAMETER; + } + + /* Try to find ourselves */ + DbName.MaximumLength = DatabaseEntry->SymbolicNameLength; + DbName.Length = DbName.MaximumLength; + DbName.Buffer = (PWSTR)((ULONG_PTR)DatabaseEntry + DatabaseEntry->SymbolicNameOffset); + if (RtlEqualUnicodeString(&TargetVolumeName, &DbName, TRUE)) + { + break; + } + + Offset += DatabaseEntry->EntrySize; + FreePool(DatabaseEntry); + } + + /* Dereference ourselves */ + DatabaseEntry->EntryReferences--; + if (DatabaseEntry->EntryReferences == 0) + { + /* If we're still referenced, just update the entry */ + Status = WriteRemoteDatabaseEntry(RemoteDatabase, Offset, DatabaseEntry); + } + else + { + /* Otherwise, delete the entry */ + Status = DeleteRemoteDatabaseEntry(RemoteDatabase, Offset); + if (!NT_SUCCESS(Status)) + { + FreePool(DatabaseEntry); + FreePool(SourceSymbolicName.Buffer); + CloseRemoteDatabase(RemoteDatabase); + return Status; + } + + /* Also, delete our unique ID replicated record */ + for (Entry = DeviceInformation->ReplicatedUniqueIdsListHead.Flink; + Entry != &DeviceInformation->ReplicatedUniqueIdsListHead; + Entry = Entry->Flink) + { + UniqueIdReplicate = CONTAINING_RECORD(Entry, UNIQUE_ID_REPLICATE, ReplicatedUniqueIdsListEntry); + + if (UniqueIdReplicate->UniqueId->UniqueIdLength == DatabaseEntry->UniqueIdLength && + RtlCompareMemory(UniqueIdReplicate->UniqueId->UniqueId, + (PVOID)((ULONG_PTR)DatabaseEntry + DatabaseEntry->UniqueIdOffset), + DatabaseEntry->UniqueIdLength) == DatabaseEntry->UniqueIdLength) + { + break; + } + } + + /* It has to exist! */ + if (Entry == &DeviceInformation->ReplicatedUniqueIdsListHead) + { + FreePool(DatabaseEntry); + FreePool(SourceSymbolicName.Buffer); + CloseRemoteDatabase(RemoteDatabase); + return STATUS_UNSUCCESSFUL; + } + + /* Remove it and free it */ + RemoveEntryList(&UniqueIdReplicate->ReplicatedUniqueIdsListEntry); + FreePool(UniqueIdReplicate->UniqueId); + FreePool(UniqueIdReplicate); + } + + /* We're done with the remote database */ + FreePool(DatabaseEntry); + CloseRemoteDatabase(RemoteDatabase); + + /* Check write operation succeed */ + if (!NT_SUCCESS(Status)) + { + FreePool(SourceSymbolicName.Buffer); + return Status; + } + + /* Try to find our associated device entry */ + for (Entry = TargetDeviceInformation->AssociatedDevicesHead.Flink; + Entry != &TargetDeviceInformation->AssociatedDevicesHead; + Entry = Entry->Flink) + { + AssociatedEntry = CONTAINING_RECORD(Entry, ASSOCIATED_DEVICE_ENTRY, AssociatedDevicesEntry); + + /* If found, delete it */ + if (AssociatedEntry->DeviceInformation == DeviceInformation && + RtlEqualUnicodeString(&AssociatedEntry->String, &SourceSymbolicName, TRUE)) + { + RemoveEntryList(&AssociatedEntry->AssociatedDevicesEntry); + FreePool(AssociatedEntry->String.Buffer); + FreePool(AssociatedEntry); + break; + } + } + + /* We're done! */ + FreePool(SourceSymbolicName.Buffer); + return STATUS_SUCCESS; } /* diff --git a/reactos/drivers/filters/mountmgr/mntmgr.h b/reactos/drivers/filters/mountmgr/mntmgr.h index 144249b8f3c..f909d75ceee 100644 --- a/reactos/drivers/filters/mountmgr/mntmgr.h +++ b/reactos/drivers/filters/mountmgr/mntmgr.h @@ -102,7 +102,7 @@ typedef struct _UNIQUE_ID_REPLICATE typedef struct _DATABASE_ENTRY { ULONG EntrySize; // 0x00 - ULONG DatabaseOffset; // 0x04 + ULONG EntryReferences; // 0x04 USHORT SymbolicNameOffset; // 0x08 USHORT SymbolicNameLength; // 0x0A USHORT UniqueIdOffset; // 0x0C @@ -328,6 +328,12 @@ AddRemoteDatabaseEntry( IN PDATABASE_ENTRY Entry ); +NTSTATUS +DeleteRemoteDatabaseEntry( + IN HANDLE Database, + IN LONG StartingOffset +); + /* device.c */ DRIVER_DISPATCH MountMgrDeviceControl; diff --git a/reactos/drivers/filters/mountmgr/mountmgr.c b/reactos/drivers/filters/mountmgr/mountmgr.c index e018a57cb64..ec917537c29 100644 --- a/reactos/drivers/filters/mountmgr/mountmgr.c +++ b/reactos/drivers/filters/mountmgr/mountmgr.c @@ -48,7 +48,6 @@ static const WCHAR Cunc[] = L"\\??\\C:"; * - MountMgrQueryDosVolumePaths * - MountMgrQueryVolumePaths * - MountMgrValidateBackPointer - * - MountMgrVolumeMountPointDeleted * - ReconcileThisDatabaseWithMasterWorker */