[MOUNTMGR]
[reactos.git] / reactos / drivers / filters / mountmgr / device.c
index 9efdf07..3f822b4 100644 (file)
  * PROGRAMMER:       Pierre Schweitzer (pierre.schweitzer@reactos.org)
  */
 
-/* INCLUDES *****************************************************************/
-
 #include "mntmgr.h"
 
+#define MAX_DEVICES 0x3E8 /* Matches 1000 devices */
+
 #define NDEBUG
 #include <debug.h>
 
@@ -653,7 +653,7 @@ MountMgrNextDriveLetter(IN PDEVICE_EXTENSION DeviceExtension,
     PMOUNTMGR_DRIVE_LETTER_TARGET DriveLetterTarget;
     MOUNTMGR_DRIVE_LETTER_INFORMATION DriveLetterInformation;
 
-    Stack = IoGetNextIrpStackLocation(Irp);
+    Stack = IoGetCurrentIrpStackLocation(Irp);
 
     /* Validate input */
     if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(MOUNTMGR_DRIVE_LETTER_TARGET) ||
@@ -833,9 +833,224 @@ NTSTATUS
 MountMgrQueryDosVolumePath(IN PDEVICE_EXTENSION DeviceExtension,
                            IN PIRP Irp)
 {
-    UNREFERENCED_PARAMETER(DeviceExtension);
-    UNREFERENCED_PARAMETER(Irp);
-    return STATUS_NOT_IMPLEMENTED;
+    NTSTATUS Status;
+    ULONG DevicesFound;
+    PIO_STACK_LOCATION Stack;
+    PLIST_ENTRY SymlinksEntry;
+    UNICODE_STRING SymbolicName;
+    PMOUNTMGR_TARGET_NAME Target;
+    PWSTR DeviceString, OldBuffer;
+    USHORT DeviceLength, OldLength;
+    PDEVICE_INFORMATION DeviceInformation;
+    PSYMLINK_INFORMATION SymlinkInformation;
+    PASSOCIATED_DEVICE_ENTRY AssociatedDevice;
+
+    Stack = IoGetCurrentIrpStackLocation(Irp);
+
+    /* Validate input size */
+    if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(MOUNTMGR_TARGET_NAME))
+    {
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    /* Ensure we have received UNICODE_STRING */
+    Target = (PMOUNTMGR_TARGET_NAME)Irp->AssociatedIrp.SystemBuffer;
+    if (Target->DeviceNameLength & 1)
+    {
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    /* Validate the entry structure size */
+    if (Target->DeviceNameLength + sizeof(UNICODE_NULL) > Stack->Parameters.DeviceIoControl.InputBufferLength)
+    {
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    /* Ensure we can at least return needed size */
+    if (Stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG))
+    {
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    /* Construct string for query */
+    SymbolicName.Length = Target->DeviceNameLength;
+    SymbolicName.MaximumLength = Target->DeviceNameLength + sizeof(UNICODE_NULL);
+    SymbolicName.Buffer = Target->DeviceName;
+
+    /* Find device with our info */
+    Status = FindDeviceInfo(DeviceExtension, &SymbolicName, FALSE, &DeviceInformation);
+    if (!NT_SUCCESS(Status))
+    {
+        return Status;
+    }
+
+    DeviceLength = 0;
+    DeviceString = NULL;
+    DevicesFound = 0;
+
+    /* Try to find associated device info */
+    while (TRUE)
+    {
+        for (SymlinksEntry = DeviceInformation->SymbolicLinksListHead.Flink;
+             SymlinksEntry != &(DeviceInformation->SymbolicLinksListHead);
+             SymlinksEntry = SymlinksEntry->Flink)
+        {
+            SymlinkInformation = CONTAINING_RECORD(SymlinksEntry, SYMLINK_INFORMATION, SymbolicLinksListEntry);
+
+            /* Try to find with drive letter */
+            if (MOUNTMGR_IS_DRIVE_LETTER(&SymlinkInformation->Name) && SymlinkInformation->Online)
+            {
+                break;
+            }
+        }
+
+        /* We didn't find, break */
+        if (SymlinksEntry == &(DeviceInformation->SymbolicLinksListHead))
+        {
+            break;
+        }
+
+        /* It doesn't have associated device, go to fallback method */
+        if (IsListEmpty(&DeviceInformation->AssociatedDevicesHead))
+        {
+            goto TryWithVolumeName;
+        }
+
+        /* Create a string with the information about the device */
+        AssociatedDevice = CONTAINING_RECORD(&(DeviceInformation->SymbolicLinksListHead), ASSOCIATED_DEVICE_ENTRY, AssociatedDevicesEntry);
+        OldLength = DeviceLength;
+        OldBuffer = DeviceString;
+        DeviceLength += AssociatedDevice->String.Length;
+        DeviceString = AllocatePool(DeviceLength);
+        if (!DeviceString)
+        {
+            if (OldBuffer)
+            {
+                FreePool(OldBuffer);
+            }
+
+            return STATUS_INSUFFICIENT_RESOURCES;
+        }
+
+        /* Store our info and previous if any */
+        RtlCopyMemory(DeviceString, AssociatedDevice->String.Buffer, AssociatedDevice->String.Length);
+        if (OldBuffer)
+        {
+            RtlCopyMemory(&DeviceString[AssociatedDevice->String.Length / sizeof(WCHAR)], OldBuffer, OldLength);
+            FreePool(OldBuffer);
+        }
+
+        /* Count and continue looking */
+        ++DevicesFound;
+        DeviceInformation = AssociatedDevice->DeviceInformation;
+
+        /* If too many devices, try another way */
+        if (DevicesFound > MAX_DEVICES) /*  1000 */
+        {
+            goto TryWithVolumeName;
+        }
+    }
+
+    /* Reallocate our string, so that we can prepend disk letter */
+    OldBuffer = DeviceString;
+    OldLength = DeviceLength;
+    DeviceLength += 2 * sizeof(WCHAR);
+    DeviceString = AllocatePool(DeviceLength);
+    if (!DeviceString)
+    {
+        if (OldBuffer)
+        {
+            FreePool(OldBuffer);
+        }
+
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    /* Get the letter */
+    DeviceString[0] = SymlinkInformation->Name.Buffer[12];
+    DeviceString[1] = L':';
+
+    /* And copy the rest */
+    if (OldBuffer)
+    {
+        RtlCopyMemory(&DeviceString[2], OldBuffer, OldLength);
+        FreePool(OldBuffer);
+    }
+
+TryWithVolumeName:
+    /* If we didn't find anything, try differently */
+    if (DeviceLength < 2 * sizeof(WCHAR) || DeviceString[1] != L':')
+    {
+        if (DeviceString)
+        {
+            FreePool(DeviceString);
+            DeviceLength = 0;
+        }
+
+        /* Try to find a volume name matching */
+        for (SymlinksEntry = DeviceInformation->SymbolicLinksListHead.Flink;
+             SymlinksEntry != &(DeviceInformation->SymbolicLinksListHead);
+             SymlinksEntry = SymlinksEntry->Flink)
+        {
+            SymlinkInformation = CONTAINING_RECORD(SymlinksEntry, SYMLINK_INFORMATION, SymbolicLinksListEntry);
+
+            if (MOUNTMGR_IS_VOLUME_NAME(&SymlinkInformation->Name))
+            {
+                break;
+            }
+        }
+
+        /* If found copy */
+        if (SymlinksEntry != &(DeviceInformation->SymbolicLinksListHead))
+        {
+            DeviceLength = SymlinkInformation->Name.Length;
+            DeviceString = AllocatePool(DeviceLength);
+            if (!DeviceString)
+            {
+                return STATUS_INSUFFICIENT_RESOURCES;
+            }
+
+            RtlCopyMemory(DeviceString, SymlinkInformation->Name.Buffer, DeviceLength);
+            /* Ensure we are in the right namespace; [1] can be ? */
+            DeviceString[1] = L'\\';
+        }
+    }
+
+    /* If we found something */
+    if (DeviceString)
+    {
+        /* At least, we will return our length */
+        ((PMOUNTMGR_VOLUME_PATHS)Irp->AssociatedIrp.SystemBuffer)->MultiSzLength = DeviceLength;
+        /* MOUNTMGR_VOLUME_PATHS is a string + a ULONG */
+        Irp->IoStatus.Information = DeviceLength + sizeof(ULONG);
+
+        /* If we have enough room for copying the string */
+        if (sizeof(ULONG) + DeviceLength <= Stack->Parameters.DeviceIoControl.OutputBufferLength)
+        {
+            /* Copy it */
+            if (DeviceLength)
+            {
+                RtlCopyMemory(((PMOUNTMGR_VOLUME_PATHS)Irp->AssociatedIrp.SystemBuffer)->MultiSz, DeviceString, DeviceLength);
+            }
+
+            /* And double zero at its end - this is needed in case of multiple paths which are separated by a single 0 */
+            FreePool(DeviceString);
+            ((PMOUNTMGR_VOLUME_PATHS)Irp->AssociatedIrp.SystemBuffer)->MultiSz[DeviceLength / sizeof(WCHAR)] = 0;
+            ((PMOUNTMGR_VOLUME_PATHS)Irp->AssociatedIrp.SystemBuffer)->MultiSz[DeviceLength / sizeof(WCHAR) + 1] = 0;
+
+            return STATUS_SUCCESS;
+        }
+        else
+        {
+            /* Just return appropriate size and leave */
+            FreePool(DeviceString);
+            Irp->IoStatus.Information = sizeof(ULONG);
+            return STATUS_BUFFER_OVERFLOW;
+        }
+    }
+
+    /* Fail */
+    return STATUS_NOT_FOUND;
 }
 
 NTSTATUS
@@ -860,7 +1075,7 @@ MountMgrKeepLinksWhenOffline(IN PDEVICE_EXTENSION DeviceExtension,
     PMOUNTMGR_TARGET_NAME Target;
     PDEVICE_INFORMATION DeviceInformation;
 
-    Stack = IoGetNextIrpStackLocation(Irp);
+    Stack = IoGetCurrentIrpStackLocation(Irp);
 
     /* Validate input */
     if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(MOUNTMGR_TARGET_NAME))
@@ -904,7 +1119,7 @@ MountMgrVolumeArrivalNotification(IN PDEVICE_EXTENSION DeviceExtension,
     UNICODE_STRING SymbolicName;
     PMOUNTMGR_TARGET_NAME Target;
 
-    Stack = IoGetNextIrpStackLocation(Irp);
+    Stack = IoGetCurrentIrpStackLocation(Irp);
 
     /* Validate input */
     if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(MOUNTMGR_TARGET_NAME))
@@ -947,7 +1162,7 @@ MountMgrQueryPoints(IN PDEVICE_EXTENSION DeviceExtension,
     PMOUNTMGR_MOUNT_POINT MountPoint;
     UNICODE_STRING SymbolicName, DeviceName;
 
-    Stack = IoGetNextIrpStackLocation(Irp);
+    Stack = IoGetCurrentIrpStackLocation(Irp);
 
     /* Validate input... */
     if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(MOUNTMGR_MOUNT_POINT))
@@ -1095,7 +1310,7 @@ MountMgrDeletePoints(IN PDEVICE_EXTENSION DeviceExtension,
     PMOUNTMGR_MOUNT_POINTS MountPoints;
     UNICODE_STRING SymbolicName, DeviceName;
 
-    Stack = IoGetNextIrpStackLocation(Irp);
+    Stack = IoGetCurrentIrpStackLocation(Irp);
 
     /* Validate input */
     if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(MOUNTMGR_MOUNT_POINT))
@@ -1274,7 +1489,7 @@ MountMgrVolumeMountPointChanged(IN PDEVICE_EXTENSION DeviceExtension,
     POBJECT_NAME_INFORMATION ObjectNameInfoPtr = NULL;
     UNICODE_STRING SourceVolumeName, TargetDeviceName;
 
-    Stack = IoGetNextIrpStackLocation(Irp);
+    Stack = IoGetCurrentIrpStackLocation(Irp);
 
     /* Validate input */
     if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(MOUNTMGR_VOLUME_MOUNT_POINT))
@@ -1337,7 +1552,7 @@ MountMgrVolumeMountPointChanged(IN PDEVICE_EXTENSION DeviceExtension,
     }
 
     /* Reference it */
-    Status = ObReferenceObjectByHandle(Handle, 0, IoFileObjectType, KernelMode, (PVOID *)&FileObject, NULL);
+    Status = ObReferenceObjectByHandle(Handle, 0, *IoFileObjectType, KernelMode, (PVOID *)&FileObject, NULL);
     if (!NT_SUCCESS(Status))
     {
         goto Cleanup;
@@ -1473,26 +1688,456 @@ Cleanup:
     return Status;
 }
 
+/*
+ * @implemented
+ */
 NTSTATUS
 MountMgrVolumeMountPointCreated(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;
+    BOOLEAN Found;
+    NTSTATUS Status;
+    HANDLE RemoteDatabase;
+    PMOUNTDEV_UNIQUE_ID UniqueId;
+    PDATABASE_ENTRY DatabaseEntry;
+    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 created, 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;
+    }
+
+    /* Notify if not disabled */
+    if (!TargetDeviceInformation->SkipNotifications)
+    {
+        PostOnlineNotification(DeviceExtension, &TargetDeviceInformation->SymbolicName);
+    }
+
+    /* Open the remote database */
+    RemoteDatabase = OpenRemoteDatabase(DeviceInformation, TRUE);
+    if (RemoteDatabase == 0)
+    {
+        FreePool(SourceSymbolicName.Buffer);
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    /* Browse all the entries */
+    Offset = 0;
+    Found = FALSE;
+    for (;;)
+    {
+        DatabaseEntry = GetRemoteDatabaseEntry(RemoteDatabase, Offset);
+        if (DatabaseEntry == NULL)
+        {
+            break;
+        }
+
+        /* 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))
+        {
+            /* Reference ourselves and update the entry */
+            ++DatabaseEntry->EntryReferences;
+            Status = WriteRemoteDatabaseEntry(RemoteDatabase, Offset, DatabaseEntry);
+            FreePool(DatabaseEntry);
+            Found = TRUE;
+            break;
+        }
+
+        Offset += DatabaseEntry->EntrySize;
+        FreePool(DatabaseEntry);
+    }
+
+    /* We couldn't find ourselves, we'll have to add ourselves */
+    if (!Found)
+    {
+        ULONG EntrySize;
+        PUNIQUE_ID_REPLICATE UniqueIdReplicate;
+
+        /* Query the device unique ID */
+        Status = QueryDeviceInformation(&TargetVolumeName, NULL, &UniqueId, NULL, NULL, NULL, NULL, NULL);
+        if (!NT_SUCCESS(Status))
+        {
+            FreePool(SourceSymbolicName.Buffer);
+            CloseRemoteDatabase(RemoteDatabase);
+            return Status;
+        }
+
+        /* Allocate a database entry */
+        EntrySize = UniqueId->UniqueIdLength + TargetVolumeName.Length + sizeof(DATABASE_ENTRY);
+        DatabaseEntry = AllocatePool(EntrySize);
+        if (DatabaseEntry == NULL)
+        {
+            FreePool(UniqueId);
+            FreePool(SourceSymbolicName.Buffer);
+            CloseRemoteDatabase(RemoteDatabase);
+            return STATUS_INSUFFICIENT_RESOURCES;
+        }
+
+        /* Fill it in */
+        DatabaseEntry->EntrySize = EntrySize;
+        DatabaseEntry->EntryReferences = 1;
+        DatabaseEntry->SymbolicNameOffset = sizeof(DATABASE_ENTRY);
+        DatabaseEntry->SymbolicNameLength = TargetVolumeName.Length;
+        DatabaseEntry->UniqueIdOffset = TargetVolumeName.Length + sizeof(DATABASE_ENTRY);
+        DatabaseEntry->UniqueIdLength = UniqueId->UniqueIdLength;
+        RtlCopyMemory((PVOID)((ULONG_PTR)DatabaseEntry + sizeof(DATABASE_ENTRY)), TargetVolumeName.Buffer, DatabaseEntry->SymbolicNameLength);
+        RtlCopyMemory((PVOID)((ULONG_PTR)DatabaseEntry + DatabaseEntry->UniqueIdOffset), UniqueId->UniqueId, UniqueId->UniqueIdLength);
+
+        /* And write it down */
+        Status = AddRemoteDatabaseEntry(RemoteDatabase, DatabaseEntry);
+        FreePool(DatabaseEntry);
+        if (!NT_SUCCESS(Status))
+        {
+            FreePool(UniqueId);
+            FreePool(SourceSymbolicName.Buffer);
+            CloseRemoteDatabase(RemoteDatabase);
+            return Status;
+        }
+
+        /* And now, allocate an Unique ID item */
+        UniqueIdReplicate = AllocatePool(sizeof(UNIQUE_ID_REPLICATE));
+        if (UniqueIdReplicate == NULL)
+        {
+            FreePool(UniqueId);
+            FreePool(SourceSymbolicName.Buffer);
+            CloseRemoteDatabase(RemoteDatabase);
+            return Status;
+        }
+
+        /* To associate it with the device */
+        UniqueIdReplicate->UniqueId = UniqueId;
+        InsertTailList(&DeviceInformation->ReplicatedUniqueIdsListHead, &UniqueIdReplicate->ReplicatedUniqueIdsListEntry);
+    }
+
+    /* We're done with the remote database */
+    CloseRemoteDatabase(RemoteDatabase);
+
+    /* Check we were find writing the entry */
+    if (!NT_SUCCESS(Status))
+    {
+        FreePool(SourceSymbolicName.Buffer);
+        return Status;
+    }
+
+    /* This is the end, allocate an associated entry */
+    AssociatedEntry = AllocatePool(sizeof(ASSOCIATED_DEVICE_ENTRY));
+    if (AssociatedEntry == NULL)
+    {
+        FreePool(SourceSymbolicName.Buffer);
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    /* Initialize its source name string */
+    AssociatedEntry->String.Length = SourceSymbolicName.Length;
+    AssociatedEntry->String.MaximumLength = AssociatedEntry->String.Length + sizeof(UNICODE_NULL);
+    AssociatedEntry->String.Buffer = AllocatePool(AssociatedEntry->String.MaximumLength);
+    if (AssociatedEntry->String.Buffer == NULL)
+    {
+        FreePool(AssociatedEntry);
+        FreePool(SourceSymbolicName.Buffer);
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    /* Copy data & insert in list */
+    RtlCopyMemory(AssociatedEntry->String.Buffer, SourceSymbolicName.Buffer, SourceSymbolicName.Length);
+    AssociatedEntry->String.Buffer[SourceSymbolicName.Length / sizeof(WCHAR)] = UNICODE_NULL;
+    AssociatedEntry->DeviceInformation = DeviceInformation;
+    InsertTailList(&TargetDeviceInformation->AssociatedDevicesHead, &AssociatedEntry->AssociatedDevicesEntry);
+
+    /* We're done! */
+    FreePool(SourceSymbolicName.Buffer);
+    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;
 }
 
 /*
@@ -1507,7 +2152,7 @@ MountMgrDeviceControl(IN PDEVICE_OBJECT DeviceObject,
     NTSTATUS Status, LockStatus;
     PDEVICE_EXTENSION DeviceExtension;
 
-    Stack = IoGetNextIrpStackLocation(Irp);
+    Stack = IoGetCurrentIrpStackLocation(Irp);
     DeviceExtension = DeviceObject->DeviceExtension;
 
     KeWaitForSingleObject(&(DeviceExtension->DeviceLock), Executive, KernelMode, FALSE, NULL);