[MOUNTMGR] Fix broken check
[reactos.git] / drivers / filters / mountmgr / database.c
index 77b9e21..aa0c6a4 100644 (file)
@@ -32,7 +32,6 @@ PWSTR DatabasePath = L"\\Registry\\Machine\\System\\MountedDevices";
 PWSTR OfflinePath = L"\\Registry\\Machine\\System\\MountedDevices\\Offline";
 
 UNICODE_STRING RemoteDatabase = RTL_CONSTANT_STRING(L"\\System Volume Information\\MountPointManagerRemoteDatabase");
-UNICODE_STRING RemoteDatabaseFile = RTL_CONSTANT_STRING(L"\\:$MountMgrRemoteDatabase");
 
 /*
  * @implemented
@@ -71,7 +70,7 @@ AddRemoteDatabaseEntry(IN HANDLE Database,
     /* Get size to append data */
     Size.QuadPart = GetRemoteDatabaseSize(Database);
 
-    return ZwWriteFile(Database, 0, NULL, NULL,
+    return ZwWriteFile(Database, NULL, NULL, NULL,
                        &IoStatusBlock, Entry,
                        Entry->EntrySize, &Size, NULL);
 }
@@ -194,6 +193,39 @@ GetRemoteDatabaseEntry(IN HANDLE Database,
     return Entry;
 }
 
+/*
+ * @implemented
+ */
+NTSTATUS
+WriteRemoteDatabaseEntry(IN HANDLE Database,
+                         IN LONG Offset,
+                         IN PDATABASE_ENTRY Entry)
+{
+    NTSTATUS Status;
+    LARGE_INTEGER ByteOffset;
+    IO_STATUS_BLOCK IoStatusBlock;
+
+    ByteOffset.QuadPart = Offset;
+    Status = ZwWriteFile(Database,
+                         NULL,
+                         NULL,
+                         NULL,
+                         &IoStatusBlock,
+                         Entry,
+                         Entry->EntrySize,
+                         &ByteOffset,
+                         NULL);
+    if (NT_SUCCESS(Status))
+    {
+        if (IoStatusBlock.Information < Entry->EntrySize)
+        {
+            Status = STATUS_INSUFFICIENT_RESOURCES;
+        }
+    }
+
+    return Status;
+}
+
 /*
  * @implemented
  */
@@ -325,47 +357,787 @@ DeleteFromLocalDatabase(IN PUNICODE_STRING SymbolicLink,
     QueryTable[0].QueryRoutine = DeleteFromLocalDatabaseRoutine;
     QueryTable[0].Name = SymbolicLink->Buffer;
 
-    RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
-                           DatabasePath,
-                           QueryTable,
-                           UniqueId,
-                           NULL);
-}
+    RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
+                           DatabasePath,
+                           QueryTable,
+                           UniqueId,
+                           NULL);
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+WaitForRemoteDatabaseSemaphore(IN PDEVICE_EXTENSION DeviceExtension)
+{
+    NTSTATUS Status;
+    LARGE_INTEGER Timeout;
+
+    /* Wait for 7 minutes */
+    Timeout.QuadPart = 0xFA0A1F00;
+    Status = KeWaitForSingleObject(&(DeviceExtension->RemoteDatabaseLock), Executive, KernelMode, FALSE, &Timeout);
+    if (Status != STATUS_TIMEOUT)
+    {
+        return Status;
+    }
+
+    return STATUS_IO_TIMEOUT;
+}
+
+/*
+ * @implemented
+ */
+VOID
+ReleaseRemoteDatabaseSemaphore(IN PDEVICE_EXTENSION DeviceExtension)
+{
+    KeReleaseSemaphore(&(DeviceExtension->RemoteDatabaseLock), IO_NO_INCREMENT, 1, FALSE);
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+NTAPI
+QueryUniqueIdQueryRoutine(IN PWSTR ValueName,
+                          IN ULONG ValueType,
+                          IN PVOID ValueData,
+                          IN ULONG ValueLength,
+                          IN PVOID Context,
+                          IN PVOID EntryContext)
+{
+    PMOUNTDEV_UNIQUE_ID IntUniqueId;
+    PMOUNTDEV_UNIQUE_ID * UniqueId;
+
+    UNREFERENCED_PARAMETER(ValueName);
+    UNREFERENCED_PARAMETER(ValueType);
+    UNREFERENCED_PARAMETER(EntryContext);
+
+    /* Sanity check */
+    if (ValueLength >= 0x10000)
+    {
+        return STATUS_SUCCESS;
+    }
+
+    /* Allocate the Unique ID */
+    IntUniqueId = AllocatePool(sizeof(UniqueId) + ValueLength);
+    if (IntUniqueId)
+    {
+        /* Copy data & return */
+        IntUniqueId->UniqueIdLength = (USHORT)ValueLength;
+        RtlCopyMemory(&(IntUniqueId->UniqueId), ValueData, ValueLength);
+
+        UniqueId = Context;
+        *UniqueId = IntUniqueId;
+    }
+
+    return STATUS_SUCCESS;
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+QueryUniqueIdFromMaster(IN PDEVICE_EXTENSION DeviceExtension,
+                        IN PUNICODE_STRING SymbolicName,
+                        OUT PMOUNTDEV_UNIQUE_ID * UniqueId)
+{
+    NTSTATUS Status;
+    PDEVICE_INFORMATION DeviceInformation;
+    RTL_QUERY_REGISTRY_TABLE QueryTable[2];
+
+    /* Query the unique ID */
+    RtlZeroMemory(QueryTable, sizeof(QueryTable));
+    QueryTable[0].QueryRoutine = QueryUniqueIdQueryRoutine;
+    QueryTable[0].Name = SymbolicName->Buffer;
+
+    *UniqueId = NULL;
+    RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
+                           DatabasePath,
+                           QueryTable,
+                           UniqueId,
+                           NULL);
+    /* Unique ID found, no need to go farther */
+    if (*UniqueId)
+    {
+        return STATUS_SUCCESS;
+    }
+
+    /* Otherwise, find associate device information */
+    Status = FindDeviceInfo(DeviceExtension, SymbolicName, FALSE, &DeviceInformation);
+    if (!NT_SUCCESS(Status))
+    {
+        return Status;
+    }
+
+    *UniqueId = AllocatePool(DeviceInformation->UniqueId->UniqueIdLength + sizeof(MOUNTDEV_UNIQUE_ID));
+    if (!*UniqueId)
+    {
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    /* Return this unique ID (better than nothing) */
+    (*UniqueId)->UniqueIdLength = DeviceInformation->UniqueId->UniqueIdLength;
+    RtlCopyMemory(&((*UniqueId)->UniqueId), &(DeviceInformation->UniqueId->UniqueId), (*UniqueId)->UniqueIdLength);
+
+    return STATUS_SUCCESS;
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+WriteUniqueIdToMaster(IN PDEVICE_EXTENSION DeviceExtension,
+                      IN PDATABASE_ENTRY DatabaseEntry)
+{
+    NTSTATUS Status;
+    PWCHAR SymbolicName;
+    PLIST_ENTRY NextEntry;
+    UNICODE_STRING SymbolicString;
+    PDEVICE_INFORMATION DeviceInformation;
+
+    /* Create symbolic name from database entry */
+    SymbolicName = AllocatePool(DatabaseEntry->SymbolicNameLength + sizeof(WCHAR));
+    if (!SymbolicName)
+    {
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    RtlCopyMemory(SymbolicName,
+                  (PVOID)((ULONG_PTR)DatabaseEntry + DatabaseEntry->SymbolicNameOffset),
+                  DatabaseEntry->SymbolicNameLength);
+    SymbolicName[DatabaseEntry->SymbolicNameLength / sizeof(WCHAR)] = UNICODE_NULL;
+
+    /* Associate the unique ID with the name from remote database */
+    Status = RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE,
+                                   DatabasePath,
+                                   SymbolicName,
+                                   REG_BINARY,
+                                   (PVOID)((ULONG_PTR)DatabaseEntry + DatabaseEntry->UniqueIdOffset),
+                                   DatabaseEntry->UniqueIdLength);
+    FreePool(SymbolicName);
+
+    /* Reget symbolic name */
+    SymbolicString.Length = DatabaseEntry->SymbolicNameLength;
+    SymbolicString.MaximumLength = DatabaseEntry->SymbolicNameLength;
+    SymbolicString.Buffer = (PVOID)((ULONG_PTR)DatabaseEntry + DatabaseEntry->SymbolicNameOffset);
+
+    /* Find the device using this unique ID */
+    for (NextEntry = DeviceExtension->DeviceListHead.Flink;
+         NextEntry != &(DeviceExtension->DeviceListHead);
+         NextEntry = NextEntry->Flink)
+    {
+        DeviceInformation = CONTAINING_RECORD(NextEntry,
+                                              DEVICE_INFORMATION,
+                                              DeviceListEntry);
+
+        if (DeviceInformation->UniqueId->UniqueIdLength != DatabaseEntry->UniqueIdLength)
+        {
+            continue;
+        }
+
+        if (RtlCompareMemory((PVOID)((ULONG_PTR)DatabaseEntry + DatabaseEntry->UniqueIdOffset),
+                             DeviceInformation->UniqueId->UniqueId,
+                             DatabaseEntry->UniqueIdLength) == DatabaseEntry->UniqueIdLength)
+        {
+            break;
+        }
+    }
+
+    /* If found, create a mount point */
+    if (NextEntry != &(DeviceExtension->DeviceListHead))
+    {
+        MountMgrCreatePointWorker(DeviceExtension, &SymbolicString, &(DeviceInformation->DeviceName));
+    }
+
+    return Status;
+}
+
+/*
+ * @implemented
+ */
+VOID
+NTAPI
+ReconcileThisDatabaseWithMasterWorker(IN PVOID Parameter)
+{
+    ULONG Offset;
+    NTSTATUS Status;
+    PFILE_OBJECT FileObject;
+    PDEVICE_OBJECT DeviceObject;
+    PMOUNTDEV_UNIQUE_ID UniqueId;
+    PDATABASE_ENTRY DatabaseEntry;
+    HANDLE DatabaseHandle, Handle;
+    IO_STATUS_BLOCK IoStatusBlock;
+    OBJECT_ATTRIBUTES ObjectAttributes;
+    PDEVICE_INFORMATION ListDeviceInfo;
+    PLIST_ENTRY Entry, EntryInfo, NextEntry;
+    PASSOCIATED_DEVICE_ENTRY AssociatedDevice;
+    BOOLEAN HardwareErrors, Restart, FailedFinding;
+    WCHAR FileNameBuffer[0x8], SymbolicNameBuffer[100];
+    UNICODE_STRING ReparseFile, FileName, SymbolicName, VolumeName;
+    FILE_REPARSE_POINT_INFORMATION ReparsePointInformation, SavedReparsePointInformation;
+    PDEVICE_EXTENSION DeviceExtension = ((PRECONCILE_WORK_ITEM_CONTEXT)Parameter)->DeviceExtension;
+    PDEVICE_INFORMATION DeviceInformation = ((PRECONCILE_WORK_ITEM_CONTEXT)Parameter)->DeviceInformation;
+
+    /* We're unloading, do nothing */
+    if (Unloading)
+    {
+        return;
+    }
+
+    /* Lock remote DB */
+    if (!NT_SUCCESS(WaitForRemoteDatabaseSemaphore(DeviceExtension)))
+    {
+        return;
+    }
+
+    /* Recheck for unloading */
+    if (Unloading)
+    {
+        goto ReleaseRDS;
+    }
+
+    /* Find the DB to reconcile */
+    KeWaitForSingleObject(&DeviceExtension->DeviceLock, Executive, KernelMode, FALSE, NULL);
+    for (Entry = DeviceExtension->DeviceListHead.Flink;
+         Entry != &DeviceExtension->DeviceListHead;
+         Entry = Entry->Flink)
+    {
+        ListDeviceInfo = CONTAINING_RECORD(Entry, DEVICE_INFORMATION, DeviceListEntry);
+        if (ListDeviceInfo == DeviceInformation)
+        {
+            break;
+        }
+    }
+
+    /* If not found, or if removable, bail out */
+    if (Entry == &DeviceExtension->DeviceListHead || DeviceInformation->Removable)
+    {
+        KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
+        goto ReleaseRDS;
+    }
+
+    /* Get our device object */
+    Status = IoGetDeviceObjectPointer(&ListDeviceInfo->DeviceName, FILE_READ_ATTRIBUTES, &FileObject, &DeviceObject);
+    if (!NT_SUCCESS(Status))
+    {
+        KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
+        goto ReleaseRDS;
+    }
+
+    /* Mark mounted only if not unloading */
+    if (!(DeviceObject->Flags & DO_UNLOAD_PENDING))
+    {
+        InterlockedExchangeAdd(&ListDeviceInfo->MountState, 1);
+    }
+
+    ObDereferenceObject(FileObject);
+
+    /* Force default: no DB, and need for reconcile */
+    DeviceInformation->NeedsReconcile = TRUE;
+    DeviceInformation->NoDatabase = TRUE;
+    FailedFinding = FALSE;
+
+    /* Remove any associated device that refers to the DB to reconcile */
+    for (Entry = DeviceExtension->DeviceListHead.Flink;
+         Entry != &DeviceExtension->DeviceListHead;
+         Entry = Entry->Flink)
+    {
+        ListDeviceInfo = CONTAINING_RECORD(Entry, DEVICE_INFORMATION, DeviceListEntry);
+
+        EntryInfo = ListDeviceInfo->AssociatedDevicesHead.Flink;
+        while (EntryInfo != &ListDeviceInfo->AssociatedDevicesHead)
+        {
+            AssociatedDevice = CONTAINING_RECORD(EntryInfo, ASSOCIATED_DEVICE_ENTRY, AssociatedDevicesEntry);
+            NextEntry = EntryInfo->Flink;
+
+            if (AssociatedDevice->DeviceInformation == DeviceInformation)
+            {
+                RemoveEntryList(&AssociatedDevice->AssociatedDevicesEntry);
+                FreePool(AssociatedDevice->String.Buffer);
+                FreePool(AssociatedDevice);
+            }
+
+            EntryInfo = NextEntry;
+        }
+    }
+
+    /* Open the remote database */
+    DatabaseHandle = OpenRemoteDatabase(DeviceInformation, FALSE);
+
+    /* Prepare a string with reparse point index */
+    ReparseFile.Length = DeviceInformation->DeviceName.Length + ReparseIndex.Length;
+    ReparseFile.MaximumLength = ReparseFile.Length + sizeof(UNICODE_NULL);
+    ReparseFile.Buffer = AllocatePool(ReparseFile.MaximumLength);
+    if (ReparseFile.Buffer == NULL)
+    {
+        if (DatabaseHandle != 0)
+        {
+            CloseRemoteDatabase(DatabaseHandle);
+        }
+        KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
+        goto ReleaseRDS;
+    }
+
+    
+    RtlCopyMemory(ReparseFile.Buffer, DeviceInformation->DeviceName.Buffer,
+                  DeviceInformation->DeviceName.Length);
+    RtlCopyMemory((PVOID)((ULONG_PTR)ReparseFile.Buffer + DeviceInformation->DeviceName.Length),
+                  ReparseFile.Buffer, ReparseFile.Length);
+    ReparseFile.Buffer[ReparseFile.Length / sizeof(WCHAR)] = UNICODE_NULL;
+
+    InitializeObjectAttributes(&ObjectAttributes,
+                               &ReparseFile,
+                               OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
+                               NULL,
+                               NULL);
+
+    /* Open reparse point directory */
+    HardwareErrors = IoSetThreadHardErrorMode(FALSE);
+    Status = ZwOpenFile(&Handle,
+                        FILE_GENERIC_READ,
+                        &ObjectAttributes,
+                        &IoStatusBlock,
+                        FILE_SHARE_READ | FILE_SHARE_WRITE,
+                        FILE_SYNCHRONOUS_IO_ALERT);
+    IoSetThreadHardErrorMode(HardwareErrors);
+
+    FreePool(ReparseFile.Buffer);
+
+    if (!NT_SUCCESS(Status))
+    {
+        if (DatabaseHandle != 0)
+        {
+            TruncateRemoteDatabase(DatabaseHandle, 0);
+            CloseRemoteDatabase(DatabaseHandle);
+        }
+        KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
+        goto ReleaseRDS;
+    }
+
+    /* Query reparse point information
+     * We only pay attention to mout point
+     */
+    RtlZeroMemory(FileNameBuffer, sizeof(FileNameBuffer));
+    FileName.Buffer = FileNameBuffer;
+    FileName.Length = sizeof(FileNameBuffer);
+    FileName.MaximumLength = sizeof(FileNameBuffer);
+    ((PULONG)FileNameBuffer)[0] = IO_REPARSE_TAG_MOUNT_POINT;
+    Status = ZwQueryDirectoryFile(Handle,
+                                  NULL,
+                                  NULL,
+                                  NULL,
+                                  &IoStatusBlock,
+                                  &ReparsePointInformation,
+                                  sizeof(FILE_REPARSE_POINT_INFORMATION),
+                                  FileReparsePointInformation,
+                                  TRUE,
+                                  &FileName,
+                                  FALSE);
+    if (!NT_SUCCESS(Status))
+    {
+        ZwClose(Handle);
+        if (DatabaseHandle != 0)
+        {
+            TruncateRemoteDatabase(DatabaseHandle, 0);
+            CloseRemoteDatabase(DatabaseHandle);
+        }
+        KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
+        goto ReleaseRDS;
+    }
+
+    /* If we failed to open the remote DB previously,
+     * retry this time allowing migration (and thus, creation if required)
+     */
+    if (DatabaseHandle == 0)
+    {
+        DatabaseHandle = OpenRemoteDatabase(DeviceInformation, TRUE);
+        if (DatabaseHandle == 0)
+        {
+            KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
+            goto ReleaseRDS;
+        }
+    }
+
+    KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
+
+    /* Reset all the references to our DB entries */
+    Offset = 0;
+    for (;;)
+    {
+        DatabaseEntry = GetRemoteDatabaseEntry(DatabaseHandle, Offset);
+        if (DatabaseEntry == NULL)
+        {
+            break;
+        }
+
+        DatabaseEntry->EntryReferences = 0;
+        Status = WriteRemoteDatabaseEntry(DatabaseHandle, Offset, DatabaseEntry);
+        if (!NT_SUCCESS(Status))
+        {
+            FreePool(DatabaseEntry);
+            goto CloseReparse;
+        }
+
+        Offset += DatabaseEntry->EntrySize;
+        FreePool(DatabaseEntry);
+    }
+
+    /* Init string for QueryVolumeName call */
+    SymbolicName.MaximumLength = sizeof(SymbolicNameBuffer);
+    SymbolicName.Length = 0;
+    SymbolicName.Buffer = SymbolicNameBuffer;
+    Restart = TRUE;
+
+    /* Start looping on reparse points */
+    for (;;)
+    {
+        RtlCopyMemory(&SavedReparsePointInformation, &ReparsePointInformation, sizeof(FILE_REPARSE_POINT_INFORMATION));
+        Status = ZwQueryDirectoryFile(Handle,
+                                      NULL,
+                                      NULL,
+                                      NULL,
+                                      &IoStatusBlock,
+                                      &ReparsePointInformation,
+                                      sizeof(FILE_REPARSE_POINT_INFORMATION),
+                                      FileReparsePointInformation,
+                                      TRUE,
+                                      Restart ? &FileName : NULL,
+                                      Restart);
+        /* Restart only once */
+        if (Restart)
+        {
+            Restart = FALSE;
+        }
+        else
+        {
+            /* If we get the same one, we're done, bail out */
+            if (ReparsePointInformation.FileReference == SavedReparsePointInformation.FileReference &&
+                ReparsePointInformation.Tag == SavedReparsePointInformation.Tag)
+            {
+                break;
+            }
+        }
+
+        /* If querying failed, or if onloading, or if not returning mount points, bail out */
+        if (!NT_SUCCESS(Status) || Unloading || ReparsePointInformation.Tag != IO_REPARSE_TAG_MOUNT_POINT)
+        {
+            break;
+        }
+
+        /* Get the volume name associated to the mount point */
+        Status = QueryVolumeName(Handle, &ReparsePointInformation, 0, &SymbolicName, &VolumeName);
+        if (!NT_SUCCESS(Status))
+        {
+            continue;
+        }
+
+        /* Browse the DB to find the name */
+        Offset = 0;
+        for (;;)
+        {
+            UNICODE_STRING DbName;
+
+            DatabaseEntry = GetRemoteDatabaseEntry(DatabaseHandle, Offset);
+            if (DatabaseEntry == NULL)
+            {
+                break;
+            }
+
+            DbName.MaximumLength = DatabaseEntry->SymbolicNameLength;
+            DbName.Length = DbName.MaximumLength;
+            DbName.Buffer = (PWSTR)((ULONG_PTR)DatabaseEntry + DatabaseEntry->SymbolicNameOffset);
+            /* Found, we're done! */
+            if (RtlEqualUnicodeString(&DbName, &SymbolicName, TRUE))
+            {
+                break;
+            }
+
+            Offset += DatabaseEntry->EntrySize;
+            FreePool(DatabaseEntry);
+        }
+
+        /* If we found the mount point.... */
+        if (DatabaseEntry != NULL)
+        {
+            /* If it was referenced, reference it once more and update to remote */
+            if (DatabaseEntry->EntryReferences)
+            {
+                ++DatabaseEntry->EntryReferences;
+                Status = WriteRemoteDatabaseEntry(DatabaseHandle, Offset, DatabaseEntry);
+                if (!NT_SUCCESS(Status))
+                {
+                    goto FreeDBEntry;
+                }
+
+                FreePool(DatabaseEntry);
+            }
+            else
+            {
+                /* Query the Unique ID associated to that mount point in case it changed */
+                KeWaitForSingleObject(&DeviceExtension->DeviceLock, Executive, KernelMode, FALSE, NULL);
+                Status = QueryUniqueIdFromMaster(DeviceExtension, &SymbolicName, &UniqueId);
+                if (!NT_SUCCESS(Status))
+                {
+                    /* If we failed doing so, reuse the old Unique ID and push it to master */
+                    Status = WriteUniqueIdToMaster(DeviceExtension, DatabaseEntry);
+                    if (!NT_SUCCESS(Status))
+                    {
+                        goto ReleaseDeviceLock;
+                    }
+
+                    /* And then, reference & write the entry */
+                    ++DatabaseEntry->EntryReferences;
+                    Status = WriteRemoteDatabaseEntry(DatabaseHandle, Offset, DatabaseEntry);
+                    if (!NT_SUCCESS(Status))
+                    {
+                        goto ReleaseDeviceLock;
+                    }
+
+                    KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
+                    FreePool(DatabaseEntry);
+                }
+                /* If the Unique ID didn't change */
+                else if (UniqueId->UniqueIdLength == DatabaseEntry->UniqueIdLength &&
+                         RtlCompareMemory(UniqueId->UniqueId,
+                                          (PVOID)((ULONG_PTR)DatabaseEntry + DatabaseEntry->UniqueIdOffset),
+                                          UniqueId->UniqueIdLength) == UniqueId->UniqueIdLength)
+                {
+                    /* Reference the entry, and update to remote */
+                    ++DatabaseEntry->EntryReferences;
+                    Status = WriteRemoteDatabaseEntry(DatabaseHandle, Offset, DatabaseEntry);
+                    if (!NT_SUCCESS(Status))
+                    {
+                        goto FreeUniqueId;
+                    }
+
+                    FreePool(UniqueId);
+                    KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
+                    FreePool(DatabaseEntry);
+                }
+                /* Would, by chance, the Unique ID be present elsewhere? */
+                else if (IsUniqueIdPresent(DeviceExtension, DatabaseEntry))
+                {
+                    /* Push the ID to master */
+                    Status = WriteUniqueIdToMaster(DeviceExtension, DatabaseEntry);
+                    if (!NT_SUCCESS(Status))
+                    {
+                        goto FreeUniqueId;
+                    }
+
+                    /* And then, reference & write the entry */
+                    ++DatabaseEntry->EntryReferences;
+                    Status = WriteRemoteDatabaseEntry(DatabaseHandle, Offset, DatabaseEntry);
+                    if (!NT_SUCCESS(Status))
+                    {
+                        goto FreeUniqueId;
+                    }
+
+                    FreePool(UniqueId);
+                    KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
+                    FreePool(DatabaseEntry);
+                }
+                else
+                {
+                    /* OK, at that point, we're facing a totally unknown unique ID
+                     * So, get rid of the old entry, and recreate a new one with
+                     * the know unique ID
+                     */
+                    Status = DeleteRemoteDatabaseEntry(DatabaseHandle, Offset);
+                    if (!NT_SUCCESS(Status))
+                    {
+                        goto FreeUniqueId;
+                    }
+
+                    FreePool(DatabaseEntry);
+                    /* Allocate a new entry big enough */
+                    DatabaseEntry = AllocatePool(UniqueId->UniqueIdLength + SymbolicName.Length + sizeof(DATABASE_ENTRY));
+                    if (DatabaseEntry == NULL)
+                    {
+                       goto FreeUniqueId;
+                    }
+
+                    /* Configure it */
+                    DatabaseEntry->EntrySize = UniqueId->UniqueIdLength + SymbolicName.Length + sizeof(DATABASE_ENTRY);
+                    DatabaseEntry->EntryReferences = 1;
+                    DatabaseEntry->SymbolicNameOffset = sizeof(DATABASE_ENTRY);
+                    DatabaseEntry->SymbolicNameLength = SymbolicName.Length;
+                    DatabaseEntry->UniqueIdOffset = SymbolicName.Length + sizeof(DATABASE_ENTRY);
+                    DatabaseEntry->UniqueIdLength = UniqueId->UniqueIdLength;
+                    RtlCopyMemory((PVOID)((ULONG_PTR)DatabaseEntry + DatabaseEntry->SymbolicNameOffset), SymbolicName.Buffer, DatabaseEntry->SymbolicNameLength);
+                    RtlCopyMemory((PVOID)((ULONG_PTR)DatabaseEntry + DatabaseEntry->UniqueIdOffset), UniqueId->UniqueId, UniqueId->UniqueIdLength);
+
+                    /* And write it remotely */
+                    Status = AddRemoteDatabaseEntry(DatabaseHandle, DatabaseEntry);
+                    if (!NT_SUCCESS(Status))
+                    {
+                       FreePool(DatabaseEntry);
+                       goto FreeUniqueId;
+                    }
+
+                    FreePool(UniqueId);
+                    FreePool(DatabaseEntry);
+                    KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
+                }
+            }
+        }
+        else
+        {
+            /* We failed finding it remotely
+             * So, let's allocate a new remote DB entry
+             */
+            KeWaitForSingleObject(&DeviceExtension->DeviceLock, Executive, KernelMode, FALSE, NULL);
+            /* To be able to do so, we need the device Unique ID, ask master */
+            Status = QueryUniqueIdFromMaster(DeviceExtension, &SymbolicName, &UniqueId);
+            KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
+            if (NT_SUCCESS(Status))
+            {
+                /* Allocate a new entry big enough */
+                DatabaseEntry = AllocatePool(UniqueId->UniqueIdLength + SymbolicName.Length + sizeof(DATABASE_ENTRY));
+                if (DatabaseEntry != NULL)
+                {
+                    /* Configure it */
+                    DatabaseEntry->EntrySize = UniqueId->UniqueIdLength + SymbolicName.Length + sizeof(DATABASE_ENTRY);
+                    DatabaseEntry->EntryReferences = 1;
+                    DatabaseEntry->SymbolicNameOffset = sizeof(DATABASE_ENTRY);
+                    DatabaseEntry->SymbolicNameLength = SymbolicName.Length;
+                    DatabaseEntry->UniqueIdOffset = SymbolicName.Length + sizeof(DATABASE_ENTRY);
+                    DatabaseEntry->UniqueIdLength = UniqueId->UniqueIdLength;
+                    RtlCopyMemory((PVOID)((ULONG_PTR)DatabaseEntry + DatabaseEntry->SymbolicNameOffset), SymbolicName.Buffer, DatabaseEntry->SymbolicNameLength);
+                    RtlCopyMemory((PVOID)((ULONG_PTR)DatabaseEntry + DatabaseEntry->UniqueIdOffset), UniqueId->UniqueId, UniqueId->UniqueIdLength);
+
+                    /* And write it remotely */
+                    Status = AddRemoteDatabaseEntry(DatabaseHandle, DatabaseEntry);
+                    FreePool(DatabaseEntry);
+                    FreePool(UniqueId);
+
+                    if (!NT_SUCCESS(Status))
+                    {
+                        goto FreeVolume;
+                    }
+                }
+                else
+                {
+                    FreePool(UniqueId);
+                }
+            }
+        }
+
+        /* Find info about the device associated associated with the mount point */
+        KeWaitForSingleObject(&DeviceExtension->DeviceLock, Executive, KernelMode, FALSE, NULL);
+        Status = FindDeviceInfo(DeviceExtension, &SymbolicName, FALSE, &ListDeviceInfo);
+        if (!NT_SUCCESS(Status))
+        {
+            FailedFinding = TRUE;
+            FreePool(VolumeName.Buffer);
+        }
+        else
+        {
+            /* Associate the device with the currrent DB */
+            AssociatedDevice = AllocatePool(sizeof(ASSOCIATED_DEVICE_ENTRY));
+            if (AssociatedDevice == NULL)
+            {
+                FreePool(VolumeName.Buffer);
+            }
+            else
+            {
+                AssociatedDevice->DeviceInformation = DeviceInformation;
+                AssociatedDevice->String.Length = VolumeName.Length;
+                AssociatedDevice->String.MaximumLength = VolumeName.MaximumLength;
+                AssociatedDevice->String.Buffer = VolumeName.Buffer;
+                InsertTailList(&ListDeviceInfo->AssociatedDevicesHead, &AssociatedDevice->AssociatedDevicesEntry);
+            }
+
+            /* If we don't have to skip notifications, notify */
+            if (!ListDeviceInfo->SkipNotifications)
+            {
+                PostOnlineNotification(DeviceExtension, &ListDeviceInfo->SymbolicName);
+            }
+        }
+
+        KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
+    }
+
+    /* We don't need mount points any longer */
+    ZwClose(Handle);
+
+    /* Look for the DB again */
+    KeWaitForSingleObject(&DeviceExtension->DeviceLock, Executive, KernelMode, FALSE, NULL);
+    for (Entry = DeviceExtension->DeviceListHead.Flink;
+         Entry != &DeviceExtension->DeviceListHead;
+         Entry = Entry->Flink)
+    {
+        ListDeviceInfo = CONTAINING_RECORD(Entry, DEVICE_INFORMATION, DeviceListEntry);
+        if (ListDeviceInfo == DeviceInformation)
+        {
+            break;
+        }
+    }
+
+    if (Entry == &DeviceExtension->DeviceListHead)
+    {
+        ListDeviceInfo = NULL;
+    }
+
+    /* Start the pruning loop */
+    Offset = 0;
+    for (;;)
+    {
+        /* Get the entry */
+        DatabaseEntry = GetRemoteDatabaseEntry(DatabaseHandle, Offset);
+        if (DatabaseEntry == NULL)
+        {
+            break;
+        }
+
+        /* It's not referenced anylonger? Prune it */
+        if (DatabaseEntry->EntryReferences == 0)
+        {
+            Status = DeleteRemoteDatabaseEntry(DatabaseHandle, Offset);
+            if (!NT_SUCCESS(Status))
+            {
+                FreePool(DatabaseEntry);
+                KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
+                goto CloseRDB;
+            }
+        }
+        /* Update the Unique IDs to reflect the changes we might have done previously */
+        else
+        {
+            if (ListDeviceInfo != NULL)
+            {
+                UpdateReplicatedUniqueIds(ListDeviceInfo, DatabaseEntry);
+            }
+
+            Offset += DatabaseEntry->EntrySize;
+        }
 
-/*
- * @implemented
- */
-NTSTATUS
-WaitForRemoteDatabaseSemaphore(IN PDEVICE_EXTENSION DeviceExtension)
-{
-    NTSTATUS Status;
-    LARGE_INTEGER Timeout;
+        FreePool(DatabaseEntry);
+    }
 
-    /* Wait for 7 minutes */
-    Timeout.QuadPart = 0xFA0A1F00;
-    Status = KeWaitForSingleObject(&(DeviceExtension->RemoteDatabaseLock), Executive, KernelMode, FALSE, &Timeout);
-    if (Status != STATUS_TIMEOUT)
+    /* We do have a DB now :-) */
+    if (ListDeviceInfo != NULL && !FailedFinding)
     {
-        return Status;
+        DeviceInformation->NoDatabase = FALSE;
     }
 
-    return STATUS_IO_TIMEOUT;
-}
+    KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
 
-/*
- * @implemented
- */
-VOID
-ReleaseRemoteDatabaseSemaphore(IN PDEVICE_EXTENSION DeviceExtension)
-{
-    KeReleaseSemaphore(&(DeviceExtension->RemoteDatabaseLock), IO_NO_INCREMENT, 1, FALSE);
-}
+    goto CloseRDB;
 
-VOID
-NTAPI
-ReconcileThisDatabaseWithMasterWorker(IN PVOID Parameter)
-{
-    UNREFERENCED_PARAMETER(Parameter);
+FreeUniqueId:
+    FreePool(UniqueId);
+ReleaseDeviceLock:
+    KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
+FreeDBEntry:
+    FreePool(DatabaseEntry);
+FreeVolume:
+    FreePool(VolumeName.Buffer);
+CloseReparse:
+    ZwClose(Handle);
+CloseRDB:
+    CloseRemoteDatabase(DatabaseHandle);
+ReleaseRDS:
+    ReleaseRemoteDatabaseSemaphore(DeviceExtension);
     return;
 }
 
@@ -578,7 +1350,7 @@ QueryVolumeName(IN HANDLE RootDirectory,
         return STATUS_BUFFER_TOO_SMALL;
     }
 
-    /* Copy symoblic name */
+    /* Copy symbolic name */
     SymbolicName->Length = ReparseDataBuffer->MountPointReparseBuffer.SubstituteNameLength;
     RtlCopyMemory(SymbolicName->Buffer,
                   (PWSTR)((ULONG_PTR)ReparseDataBuffer->MountPointReparseBuffer.PathBuffer +
@@ -892,22 +1664,16 @@ ReconcileAllDatabasesWithMaster(IN PDEVICE_EXTENSION DeviceExtension)
  */
 VOID
 NTAPI
-MigrateRemoteDatabaseWorker(IN PDEVICE_OBJECT DeviceObject,
-                            IN PVOID Context)
+CreateRemoteDatabaseWorker(IN PDEVICE_OBJECT DeviceObject,
+                           IN PVOID Context)
 {
-    ULONG Length;
     NTSTATUS Status;
-    PVOID TmpBuffer;
-    CHAR Disposition;
-    LARGE_INTEGER ByteOffset;
+    HANDLE Database = 0;
+    UNICODE_STRING DatabaseName;
     PMIGRATE_WORK_ITEM WorkItem;
     IO_STATUS_BLOCK IoStatusBlock;
-    HANDLE Migrate = 0, Database = 0;
+    OBJECT_ATTRIBUTES ObjectAttributes;
     PDEVICE_INFORMATION DeviceInformation;
-    BOOLEAN PreviousMode, Complete = FALSE;
-    UNICODE_STRING DatabaseName, DatabaseFile;
-    OBJECT_ATTRIBUTES ObjectAttributes, MigrateAttributes;
-#define TEMP_BUFFER_SIZE 0x200
 
     UNREFERENCED_PARAMETER(DeviceObject);
 
@@ -918,15 +1684,8 @@ MigrateRemoteDatabaseWorker(IN PDEVICE_OBJECT DeviceObject,
     /* Reconstruct appropriate string */
     DatabaseName.Length = DeviceInformation->DeviceName.Length + RemoteDatabase.Length;
     DatabaseName.MaximumLength = DatabaseName.Length + sizeof(WCHAR);
-
-    DatabaseFile.Length = DeviceInformation->DeviceName.Length + RemoteDatabaseFile.Length;
-    DatabaseFile.MaximumLength = DatabaseFile.Length + sizeof(WCHAR);
-
     DatabaseName.Buffer = AllocatePool(DatabaseName.MaximumLength);
-    DatabaseFile.Buffer = AllocatePool(DatabaseFile.MaximumLength);
-    /* Allocate buffer that will be used to swap contents */
-    TmpBuffer = AllocatePool(TEMP_BUFFER_SIZE);
-    if (!DatabaseName.Buffer || !DatabaseFile.Buffer || !TmpBuffer)
+    if (DatabaseName.Buffer == NULL)
     {
         Status = STATUS_INSUFFICIENT_RESOURCES;
         goto Cleanup;
@@ -941,15 +1700,11 @@ MigrateRemoteDatabaseWorker(IN PDEVICE_OBJECT DeviceObject,
         goto Cleanup;
     }
 
-    /* Finish initating strings */
+    /* Finish initiating strings */
     RtlCopyMemory(DatabaseName.Buffer, DeviceInformation->DeviceName.Buffer, DeviceInformation->DeviceName.Length);
-    RtlCopyMemory(DatabaseFile.Buffer, DeviceInformation->DeviceName.Buffer, DeviceInformation->DeviceName.Length);
     RtlCopyMemory(DatabaseName.Buffer + (DeviceInformation->DeviceName.Length / sizeof(WCHAR)),
                   RemoteDatabase.Buffer, RemoteDatabase.Length);
-    RtlCopyMemory(DatabaseFile.Buffer + (DeviceInformation->DeviceName.Length / sizeof(WCHAR)),
-                  RemoteDatabaseFile.Buffer, RemoteDatabaseFile.Length);
     DatabaseName.Buffer[DatabaseName.Length / sizeof(WCHAR)] = UNICODE_NULL;
-    DatabaseFile.Buffer[DatabaseFile.Length / sizeof(WCHAR)] = UNICODE_NULL;
 
     /* Create database */
     InitializeObjectAttributes(&ObjectAttributes,
@@ -958,9 +1713,9 @@ MigrateRemoteDatabaseWorker(IN PDEVICE_OBJECT DeviceObject,
                                NULL,
                                NULL);
 
-    Status = ZwCreateFile(&Database,
+    Status = IoCreateFile(&Database,
                           SYNCHRONIZE | READ_CONTROL | FILE_WRITE_ATTRIBUTES |
-                          FILE_READ_ATTRIBUTES | FILE_WRITE_PROPERTIES | FILE_READ_PROPERTIES |
+                          FILE_READ_ATTRIBUTES | FILE_WRITE_EA | FILE_READ_EA |
                           FILE_APPEND_DATA | FILE_WRITE_DATA | FILE_READ_DATA,
                           &ObjectAttributes,
                           &IoStatusBlock,
@@ -970,123 +1725,32 @@ MigrateRemoteDatabaseWorker(IN PDEVICE_OBJECT DeviceObject,
                           FILE_CREATE,
                           FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_ALERT,
                           NULL,
-                          0);
-    if (!NT_SUCCESS(Status))
-    {
-        Database = 0;
-        goto Cleanup;
-    }
-
-    InitializeObjectAttributes(&MigrateAttributes,
-                               &DatabaseFile,
-                               OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
-                               NULL,
-                               NULL);
-
-    /* Disable hard errors and open the database that will be copied */
-    PreviousMode = IoSetThreadHardErrorMode(FALSE);
-    Status = ZwCreateFile(&Migrate,
-                          SYNCHRONIZE | READ_CONTROL | FILE_WRITE_ATTRIBUTES |
-                          FILE_READ_ATTRIBUTES | FILE_WRITE_PROPERTIES | FILE_READ_PROPERTIES |
-                          FILE_APPEND_DATA | FILE_WRITE_DATA | FILE_READ_DATA,
-                          &MigrateAttributes,
-                          &IoStatusBlock,
-                          NULL,
-                          FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN,
                           0,
-                          FILE_OPEN,
-                          FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_ALERT,
+                          CreateFileTypeNone,
                           NULL,
-                          0);
-    IoSetThreadHardErrorMode(PreviousMode);
+                          IO_STOP_ON_SYMLINK | IO_NO_PARAMETER_CHECKING);
     if (!NT_SUCCESS(Status))
     {
-        Migrate = 0;
-    }
-    if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
-    {
-        Status = STATUS_SUCCESS;
-        Complete = TRUE;
-    }
-    if (!NT_SUCCESS(Status) || Complete)
-    {
-        goto Cleanup;
-    }
-
-    ByteOffset.QuadPart = 0LL;
-    PreviousMode = IoSetThreadHardErrorMode(FALSE);
-    /* Now, loop as long it's possible */
-    while (Status == STATUS_SUCCESS)
-    {
-        /* Read data from existing database */
-        Status = ZwReadFile(Migrate,
-                            NULL,
-                            NULL,
-                            NULL,
-                            &IoStatusBlock,
-                            TmpBuffer,
-                            TEMP_BUFFER_SIZE,
-                            &ByteOffset,
-                            NULL);
-        if (!NT_SUCCESS(Status))
+        if (Status == STATUS_STOPPED_ON_SYMLINK)
         {
-            break;
+            DPRINT1("Attempt to exploit CVE-2015-1769. See CORE-10216\n");
         }
 
-        /* And write them into new database */
-        Length = (ULONG)IoStatusBlock.Information;
-        Status = ZwWriteFile(Database,
-                             NULL,
-                             NULL,
-                             NULL,
-                             &IoStatusBlock,
-                             TmpBuffer,
-                             Length,
-                             &ByteOffset,
-                             NULL);
-        ByteOffset.QuadPart += Length;
-    }
-    IoSetThreadHardErrorMode(PreviousMode);
-
-    /* Delete old databse if it was well copied */
-    if (Status == STATUS_END_OF_FILE)
-    {
-        Disposition = 1;
-        Status = ZwSetInformationFile(Migrate,
-                                      &IoStatusBlock,
-                                      &Disposition,
-                                      sizeof(Disposition),
-                                      FileDispositionInformation);
+        Database = 0;
+        goto Cleanup;
     }
 
-    /* Migration is over */
-
 Cleanup:
-    if (TmpBuffer)
-    {
-        FreePool(TmpBuffer);
-    }
-
-    if (DatabaseFile.Buffer)
-    {
-        FreePool(DatabaseFile.Buffer);
-    }
-
     if (DatabaseName.Buffer)
     {
         FreePool(DatabaseName.Buffer);
     }
 
-    if (Migrate)
-    {
-        ZwClose(Migrate);
-    }
-
     if (NT_SUCCESS(Status))
     {
         DeviceInformation->Migrated = 1;
     }
-    else if (Database)
+    else if (Database != 0)
     {
         ZwClose(Database);
     }
@@ -1098,15 +1762,14 @@ Cleanup:
     WorkItem->Database = Database;
 
     KeSetEvent(WorkItem->Event, 0, FALSE);
-#undef TEMP_BUFFER_SIZE
 }
 
 /*
  * @implemented
  */
 NTSTATUS
-MigrateRemoteDatabase(IN PDEVICE_INFORMATION DeviceInformation,
-                      IN OUT PHANDLE Database)
+CreateRemoteDatabase(IN PDEVICE_INFORMATION DeviceInformation,
+                     IN OUT PHANDLE Database)
 {
     KEVENT Event;
     NTSTATUS Status;
@@ -1135,7 +1798,7 @@ MigrateRemoteDatabase(IN PDEVICE_INFORMATION DeviceInformation,
 
     /* And queue it */
     IoQueueWorkItem(WorkItem->WorkItem,
-                    MigrateRemoteDatabaseWorker,
+                    CreateRemoteDatabaseWorker,
                     DelayedWorkQueue,
                     WorkItem);
 
@@ -1188,9 +1851,9 @@ OpenRemoteDatabase(IN PDEVICE_INFORMATION DeviceInformation,
     /* Disable hard errors */
     PreviousMode = IoSetThreadHardErrorMode(FALSE);
 
-    Status = ZwCreateFile(&Database,
+    Status = IoCreateFile(&Database,
                           SYNCHRONIZE | READ_CONTROL | FILE_WRITE_ATTRIBUTES |
-                          FILE_READ_ATTRIBUTES | FILE_WRITE_PROPERTIES | FILE_READ_PROPERTIES |
+                          FILE_READ_ATTRIBUTES | FILE_WRITE_EA | FILE_READ_EA |
                           FILE_APPEND_DATA | FILE_WRITE_DATA | FILE_READ_DATA,
                           &ObjectAttributes,
                           &IoStatusBlock,
@@ -1200,12 +1863,19 @@ OpenRemoteDatabase(IN PDEVICE_INFORMATION DeviceInformation,
                           (!MigrateDatabase || DeviceInformation->Migrated == 0) ? FILE_OPEN_IF : FILE_OPEN,
                           FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_ALERT,
                           NULL,
-                          0);
+                          0,
+                          CreateFileTypeNone,
+                          NULL,
+                          IO_STOP_ON_SYMLINK | IO_NO_PARAMETER_CHECKING);
+    if (Status == STATUS_STOPPED_ON_SYMLINK)
+    {
+        DPRINT1("Attempt to exploit CVE-2015-1769. See CORE-10216\n");
+    }
 
     /* If base it to be migrated and was opened successfully, go ahead */
     if (MigrateDatabase && NT_SUCCESS(Status))
     {
-        MigrateRemoteDatabase(DeviceInformation, &Database);
+        CreateRemoteDatabase(DeviceInformation, &Database);
     }
 
     IoSetThreadHardErrorMode(PreviousMode);
@@ -1214,165 +1884,6 @@ OpenRemoteDatabase(IN PDEVICE_INFORMATION DeviceInformation,
     return Database;
 }
 
-/*
- * @implemented
- */
-NTSTATUS
-NTAPI
-QueryUniqueIdQueryRoutine(IN PWSTR ValueName,
-                          IN ULONG ValueType,
-                          IN PVOID ValueData,
-                          IN ULONG ValueLength,
-                          IN PVOID Context,
-                          IN PVOID EntryContext)
-{
-    PMOUNTDEV_UNIQUE_ID IntUniqueId;
-    PMOUNTDEV_UNIQUE_ID * UniqueId;
-
-    UNREFERENCED_PARAMETER(ValueName);
-    UNREFERENCED_PARAMETER(ValueType);
-    UNREFERENCED_PARAMETER(EntryContext);
-
-    /* Sanity check */
-    if (ValueLength >= 0x10000)
-    {
-        return STATUS_SUCCESS;
-    }
-
-    /* Allocate the Unique ID */
-    IntUniqueId = AllocatePool(sizeof(UniqueId) + ValueLength);
-    if (IntUniqueId)
-    {
-        /* Copy data & return */
-        IntUniqueId->UniqueIdLength = (USHORT)ValueLength;
-        RtlCopyMemory(&(IntUniqueId->UniqueId), ValueData, ValueLength);
-
-        UniqueId = Context;
-        *UniqueId = IntUniqueId;
-    }
-
-    return STATUS_SUCCESS;
-}
-
-/*
- * @implemented
- */
-NTSTATUS
-QueryUniqueIdFromMaster(IN PDEVICE_EXTENSION DeviceExtension,
-                        IN PUNICODE_STRING SymbolicName,
-                        OUT PMOUNTDEV_UNIQUE_ID * UniqueId)
-{
-    NTSTATUS Status;
-    PDEVICE_INFORMATION DeviceInformation;
-    RTL_QUERY_REGISTRY_TABLE QueryTable[2];
-
-    /* Query the unique ID */
-    RtlZeroMemory(QueryTable, sizeof(QueryTable));
-    QueryTable[0].QueryRoutine = QueryUniqueIdQueryRoutine;
-    QueryTable[0].Name = SymbolicName->Buffer;
-
-    *UniqueId = NULL;
-    RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
-                           DatabasePath,
-                           QueryTable,
-                           UniqueId,
-                           NULL);
-    /* Unique ID found, no need to go farther */
-    if (*UniqueId)
-    {
-        return STATUS_SUCCESS;
-    }
-
-    /* Otherwise, find associate device information */
-    Status = FindDeviceInfo(DeviceExtension, SymbolicName, FALSE, &DeviceInformation);
-    if (!NT_SUCCESS(Status))
-    {
-        return Status;
-    }
-
-    *UniqueId = AllocatePool(DeviceInformation->UniqueId->UniqueIdLength + sizeof(MOUNTDEV_UNIQUE_ID));
-    if (!*UniqueId)
-    {
-        return STATUS_INSUFFICIENT_RESOURCES;
-    }
-
-    /* Return this unique ID (better than nothing) */
-    (*UniqueId)->UniqueIdLength = DeviceInformation->UniqueId->UniqueIdLength;
-    RtlCopyMemory(&((*UniqueId)->UniqueId), &(DeviceInformation->UniqueId->UniqueId), (*UniqueId)->UniqueIdLength);
-
-    return STATUS_SUCCESS;
-}
-
-/*
- * @implemented
- */
-NTSTATUS
-WriteUniqueIdToMaster(IN PDEVICE_EXTENSION DeviceExtension,
-                      IN PDATABASE_ENTRY DatabaseEntry)
-{
-    NTSTATUS Status;
-    PWCHAR SymbolicName;
-    PLIST_ENTRY NextEntry;
-    UNICODE_STRING SymbolicString;
-    PDEVICE_INFORMATION DeviceInformation;
-
-    /* Create symbolic name from database entry */
-    SymbolicName = AllocatePool(DatabaseEntry->SymbolicNameLength + sizeof(WCHAR));
-    if (!SymbolicName)
-    {
-        return STATUS_INSUFFICIENT_RESOURCES;
-    }
-
-    RtlCopyMemory(SymbolicName,
-                  (PVOID)((ULONG_PTR)DatabaseEntry + DatabaseEntry->SymbolicNameOffset),
-                  DatabaseEntry->SymbolicNameLength);
-    SymbolicName[DatabaseEntry->SymbolicNameLength / sizeof(WCHAR)] = UNICODE_NULL;
-
-    /* Associate the unique ID with the name from remote database */
-    Status = RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE,
-                                   DatabasePath,
-                                   SymbolicName,
-                                   REG_BINARY,
-                                   (PVOID)((ULONG_PTR)DatabaseEntry + DatabaseEntry->UniqueIdOffset),
-                                   DatabaseEntry->UniqueIdLength);
-    FreePool(SymbolicName);
-
-    /* Reget symbolic name */
-    SymbolicString.Length = DatabaseEntry->SymbolicNameLength;
-    SymbolicString.MaximumLength = DatabaseEntry->SymbolicNameLength;
-    SymbolicString.Buffer = (PVOID)((ULONG_PTR)DatabaseEntry + DatabaseEntry->SymbolicNameOffset);
-
-    /* Find the device using this unique ID */
-    for (NextEntry = DeviceExtension->DeviceListHead.Flink;
-         NextEntry != &(DeviceExtension->DeviceListHead);
-         NextEntry = NextEntry->Flink)
-    {
-        DeviceInformation = CONTAINING_RECORD(NextEntry,
-                                              DEVICE_INFORMATION,
-                                              DeviceListEntry);
-
-        if (DeviceInformation->UniqueId->UniqueIdLength != DatabaseEntry->UniqueIdLength)
-        {
-            continue;
-        }
-
-        if (RtlCompareMemory((PVOID)((ULONG_PTR)DatabaseEntry + DatabaseEntry->UniqueIdOffset),
-                             DeviceInformation->UniqueId->UniqueId,
-                             DatabaseEntry->UniqueIdLength) == DatabaseEntry->UniqueIdLength)
-        {
-            break;
-        }
-    }
-
-    /* If found, create a mount point */
-    if (NextEntry != &(DeviceExtension->DeviceListHead))
-    {
-        MountMgrCreatePointWorker(DeviceExtension, &SymbolicString, &(DeviceInformation->DeviceName));
-    }
-
-    return Status;
-}
-
 /*
  * @implemented
  */
@@ -1431,7 +1942,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);