[MOUNTMGR] Fix buffer length checking
[reactos.git] / drivers / filters / mountmgr / device.c
index 081f514..17d720e 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>
 
@@ -265,7 +265,7 @@ MountMgrCreatePoint(IN PDEVICE_EXTENSION DeviceExtension,
 
     MaxLength = MAX((Point->DeviceNameOffset + Point->DeviceNameLength),
                     (Point->SymbolicLinkNameLength + Point->SymbolicLinkNameOffset));
-    if (MaxLength >= Stack->Parameters.DeviceIoControl.InputBufferLength)
+    if (MaxLength > Stack->Parameters.DeviceIoControl.InputBufferLength)
     {
         return STATUS_INVALID_PARAMETER;
     }
@@ -292,6 +292,8 @@ MountMgrCheckUnprocessedVolumes(IN PDEVICE_EXTENSION DeviceExtension,
     PDEVICE_INFORMATION DeviceInformation;
     NTSTATUS ArrivalStatus, Status = STATUS_SUCCESS;
 
+    UNREFERENCED_PARAMETER(Irp);
+
     /* No offline volumes, nothing more to do */
     if (IsListEmpty(&(DeviceExtension->OfflineDeviceListHead)))
     {
@@ -309,7 +311,7 @@ MountMgrCheckUnprocessedVolumes(IN PDEVICE_EXTENSION DeviceExtension,
 
         ArrivalStatus = MountMgrMountedDeviceArrival(DeviceExtension,
                                                      &(DeviceInformation->SymbolicName),
-                                                     DeviceInformation->Volume);
+                                                     DeviceInformation->ManuallyRegistered);
         /* Then, remove them dead information */
         MountMgrFreeDeadDeviceInfo(DeviceInformation);
 
@@ -535,7 +537,7 @@ MountMgrNextDriveLetterWorker(IN PDEVICE_EXTENSION DeviceExtension,
         }
     }
 
-    /* No, ensure that the device is not automonted nor removable */
+    /* No, ensure that the device is not automounted nor removable */
     if (!DeviceExtension->NoAutoMount && !Removable)
     {
         if (DriveLetterInfo->DriveLetterWasAssigned)
@@ -553,13 +555,21 @@ MountMgrNextDriveLetterWorker(IN PDEVICE_EXTENSION DeviceExtension,
     }
 
     /* Now everything is fine, start processing */
+
     if (RtlPrefixUnicodeString(&DeviceFloppy, &TargetDeviceName, TRUE))
     {
+        /* If the device is a floppy, start with letter A */
         DriveLetter = 'A';
     }
+    else if (RtlPrefixUnicodeString(&DeviceCdRom, &TargetDeviceName, TRUE))
+    {
+        /* If the device is a CD-ROM, start with letter D */
+        DriveLetter = 'D';
+    }
     else
     {
-        DriveLetter = 'C' + RtlPrefixUnicodeString(&DeviceCdRom, &TargetDeviceName, TRUE);
+        /* Finally, if it's a disk, use C */
+        DriveLetter = 'C';
     }
 
     /* We cannot set NO drive letter */
@@ -643,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) ||
@@ -690,6 +700,10 @@ MountMgrQuerySystemVolumeNameQueryRoutine(IN PWSTR ValueName,
     UNICODE_STRING ValueString;
     PUNICODE_STRING SystemVolumeName;
 
+    UNREFERENCED_PARAMETER(ValueName);
+    UNREFERENCED_PARAMETER(ValueLength);
+    UNREFERENCED_PARAMETER(EntryContext);
+
     if (ValueType != REG_SZ)
     {
         return STATUS_SUCCESS;
@@ -815,232 +829,989 @@ MountMgrAssignDriveLetters(IN PDEVICE_EXTENSION DeviceExtension)
     }
 }
 
-NTSTATUS
-MountMgrQueryDosVolumePath(IN PDEVICE_EXTENSION DeviceExtension,
-                           IN PIRP Irp)
-{
-    return STATUS_NOT_IMPLEMENTED;
-}
-
-NTSTATUS
-MountMgrQueryDosVolumePaths(IN PDEVICE_EXTENSION DeviceExtension,
-                            IN PIRP Irp)
-{
-    return STATUS_NOT_IMPLEMENTED;
-}
-
 /*
  * @implemented
  */
 NTSTATUS
-MountMgrKeepLinksWhenOffline(IN PDEVICE_EXTENSION DeviceExtension,
-                             IN PIRP Irp)
+MountMgrQueryDosVolumePath(IN PDEVICE_EXTENSION DeviceExtension,
+                           IN PIRP Irp)
 {
     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 = IoGetNextIrpStackLocation(Irp);
+    Stack = IoGetCurrentIrpStackLocation(Irp);
 
-    /* Validate input */
+    /* 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 + sizeof(USHORT) > Stack->Parameters.DeviceIoControl.InputBufferLength)
+    if (Target->DeviceNameLength & 1)
     {
         return STATUS_INVALID_PARAMETER;
     }
 
-    SymbolicName.Length =
-    SymbolicName.MaximumLength = Target->DeviceNameLength;
+    /* 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 the associated device */
+    /* Find device with our info */
     Status = FindDeviceInfo(DeviceExtension, &SymbolicName, FALSE, &DeviceInformation);
     if (!NT_SUCCESS(Status))
     {
         return Status;
     }
 
-    /* Mark we want to keep links */
-    DeviceInformation->KeepLinks = TRUE;
+    DeviceLength = 0;
+    DeviceString = NULL;
+    DevicesFound = 0;
 
-    return STATUS_SUCCESS;
-}
+    /* 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);
 
-/*
- * @implemented
- */
-NTSTATUS
-MountMgrVolumeArrivalNotification(IN PDEVICE_EXTENSION DeviceExtension,
-                                  IN PIRP Irp)
-{
-    NTSTATUS Status;
-    BOOLEAN OldState;
-    PIO_STACK_LOCATION Stack;
-    UNICODE_STRING SymbolicName;
-    PMOUNTMGR_TARGET_NAME Target;
+            /* Try to find with drive letter */
+            if (MOUNTMGR_IS_DRIVE_LETTER(&SymlinkInformation->Name) && SymlinkInformation->Online)
+            {
+                break;
+            }
+        }
 
-    Stack = IoGetNextIrpStackLocation(Irp);
+        /* We didn't find, break */
+        if (SymlinksEntry == &(DeviceInformation->SymbolicLinksListHead))
+        {
+            break;
+        }
 
-    /* Validate input */
-    if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(MOUNTMGR_TARGET_NAME))
+        /* 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)
     {
-        return STATUS_INVALID_PARAMETER;
+        if (OldBuffer)
+        {
+            FreePool(OldBuffer);
+        }
+
+        return STATUS_INSUFFICIENT_RESOURCES;
     }
 
-    Target = (PMOUNTMGR_TARGET_NAME)Irp->AssociatedIrp.SystemBuffer;
-    if (Target->DeviceNameLength + sizeof(USHORT) > Stack->Parameters.DeviceIoControl.InputBufferLength)
+    /* Get the letter */
+    DeviceString[0] = SymlinkInformation->Name.Buffer[LETTER_POSITION];
+    DeviceString[1] = L':';
+
+    /* And copy the rest */
+    if (OldBuffer)
     {
-        return STATUS_INVALID_PARAMETER;
+        RtlCopyMemory(&DeviceString[2], OldBuffer, OldLength);
+        FreePool(OldBuffer);
     }
 
-    SymbolicName.Length =
-    SymbolicName.MaximumLength = Target->DeviceNameLength;
-    SymbolicName.Buffer = Target->DeviceName;
+TryWithVolumeName:
+    /* If we didn't find anything, try differently */
+    if (DeviceLength < 2 * sizeof(WCHAR) || DeviceString[1] != L':')
+    {
+        if (DeviceString)
+        {
+            FreePool(DeviceString);
+            DeviceLength = 0;
+        }
 
-    /* Disable hard errors */
-    OldState = PsGetThreadHardErrorsAreDisabled(PsGetCurrentThread());
-    PsSetThreadHardErrorsAreDisabled(PsGetCurrentThread(), TRUE);
+        /* 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);
 
-    /* Call real worker */
-    Status = MountMgrMountedDeviceArrival(DeviceExtension, &SymbolicName, TRUE);
+            if (MOUNTMGR_IS_VOLUME_NAME(&SymlinkInformation->Name))
+            {
+                break;
+            }
+        }
 
-    PsSetThreadHardErrorsAreDisabled(PsGetCurrentThread(), OldState);
+        /* If found copy */
+        if (SymlinksEntry != &(DeviceInformation->SymbolicLinksListHead))
+        {
+            DeviceLength = SymlinkInformation->Name.Length;
+            DeviceString = AllocatePool(DeviceLength);
+            if (!DeviceString)
+            {
+                return STATUS_INSUFFICIENT_RESOURCES;
+            }
 
-    return Status;
+            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;
 }
 
 /*
  * @implemented
  */
 NTSTATUS
-MountMgrQueryPoints(IN PDEVICE_EXTENSION DeviceExtension,
-                    IN PIRP Irp)
+MountMgrValidateBackPointer(IN PASSOCIATED_DEVICE_ENTRY AssociatedDeviceEntry,
+                            IN PDEVICE_INFORMATION DeviceInformation,
+                            OUT PBOOLEAN Invalid)
 {
+    HANDLE Handle;
     NTSTATUS Status;
-    PIO_STACK_LOCATION Stack;
-    PMOUNTDEV_UNIQUE_ID UniqueId;
-    PMOUNTMGR_MOUNT_POINT MountPoint;
-    UNICODE_STRING SymbolicName, DeviceName;
-
-    Stack = IoGetNextIrpStackLocation(Irp);
+    PLIST_ENTRY SymlinksEntry;
+    IO_STATUS_BLOCK IoStatusBlock;
+    PREPARSE_DATA_BUFFER ReparseData;
+    OBJECT_ATTRIBUTES ObjectAttributes;
+    UNICODE_STRING FullName, SubstituteName;
+    PSYMLINK_INFORMATION SymlinkInformation;
 
-    /* Validate input... */
-    if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(MOUNTMGR_MOUNT_POINT))
+    /* Initialize & allocate a string big enough to contain our complete mount point name */
+    FullName.Length = AssociatedDeviceEntry->String.Length + AssociatedDeviceEntry->DeviceInformation->DeviceName.Length + sizeof(WCHAR);
+    FullName.MaximumLength = FullName.Length + sizeof(UNICODE_NULL);
+    FullName.Buffer = AllocatePool(FullName.MaximumLength);
+    if (!FullName.Buffer)
     {
-        return STATUS_INVALID_PARAMETER;
+        return STATUS_INSUFFICIENT_RESOURCES;
     }
 
-    MountPoint = (PMOUNTMGR_MOUNT_POINT)Irp->AssociatedIrp.SystemBuffer;
-    if (!MountPoint->SymbolicLinkNameLength)
+    /* Create the path  */
+    RtlCopyMemory(FullName.Buffer, AssociatedDeviceEntry->DeviceInformation->DeviceName.Buffer, AssociatedDeviceEntry->DeviceInformation->DeviceName.Length);
+    FullName.Buffer[AssociatedDeviceEntry->DeviceInformation->DeviceName.Length / sizeof(WCHAR)] = L'\\';
+    RtlCopyMemory(&FullName.Buffer[AssociatedDeviceEntry->DeviceInformation->DeviceName.Length / sizeof(WCHAR) + 1], AssociatedDeviceEntry->String.Buffer, AssociatedDeviceEntry->String.Length);
+    FullName.Buffer[FullName.Length / sizeof(WCHAR)] = UNICODE_NULL;
+
+    /* Open it to query the reparse point */
+    InitializeObjectAttributes(&ObjectAttributes,
+                               &FullName,
+                               OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
+                               NULL,
+                               NULL);
+    Status = ZwOpenFile(&Handle,
+                        SYNCHRONIZE | FILE_READ_ATTRIBUTES,
+                        &ObjectAttributes, &IoStatusBlock,
+                        FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+                        FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_REPARSE_POINT);
+    FreePool(FullName.Buffer);
+
+    if (!NT_SUCCESS(Status))
     {
-        MountPoint->SymbolicLinkNameOffset = 0;
+        *Invalid = TRUE;
+        return STATUS_SUCCESS;
     }
 
-    if (!MountPoint->UniqueIdLength)
+    /* Allocate a buffer big enough to read reparse data */
+    ReparseData = AllocatePool(MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
+    if (ReparseData == NULL)
     {
-        MountPoint->UniqueIdOffset = 0;
+        ZwClose(Handle);
+        return STATUS_INSUFFICIENT_RESOURCES;
     }
 
-    if (!MountPoint->DeviceNameLength)
+    /* Query reparse data */
+    Status = ZwFsControlFile(Handle,
+                             NULL, NULL, NULL,
+                             &IoStatusBlock,
+                             FSCTL_GET_REPARSE_POINT,
+                             NULL, 0,
+                             ReparseData, MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
+    ZwClose(Handle);
+
+    if (!NT_SUCCESS(Status))
     {
-        MountPoint->DeviceNameOffset = 0;
+        FreePool(ReparseData);
+        *Invalid = TRUE;
+        return STATUS_SUCCESS;
     }
 
-    /* Addresses can't be odd */
-    if ((MountPoint->SymbolicLinkNameOffset & 1) ||
-        (MountPoint->SymbolicLinkNameLength & 1))
+    /* Create a string with the substitute name */
+    SubstituteName.Length = ReparseData->SymbolicLinkReparseBuffer.SubstituteNameLength;
+    SubstituteName.MaximumLength = SubstituteName.Length;
+    SubstituteName.Buffer = (PWSTR)((ULONG_PTR)ReparseData->SymbolicLinkReparseBuffer.PathBuffer + ReparseData->SymbolicLinkReparseBuffer.SubstituteNameOffset);
+
+    /* If that's a volume name that matches our associated device, that's a success! */
+    if (MOUNTMGR_IS_VOLUME_NAME(&SubstituteName))
     {
-        return STATUS_INVALID_PARAMETER;
+        if (SubstituteName.Length == 98 && SubstituteName.Buffer[1] == L'?')
+        {
+            for (SymlinksEntry = DeviceInformation->SymbolicLinksListHead.Flink;
+                 SymlinksEntry != &(DeviceInformation->SymbolicLinksListHead);
+                 SymlinksEntry = SymlinksEntry->Flink)
+            {
+                SymlinkInformation = CONTAINING_RECORD(SymlinksEntry, SYMLINK_INFORMATION, SymbolicLinksListEntry);
+
+                if (RtlEqualUnicodeString(&SubstituteName, &SymlinkInformation->Name, TRUE))
+                {
+                    FreePool(ReparseData);
+                    return STATUS_SUCCESS;
+                }
+            }
+        }
     }
 
-    if ((MountPoint->UniqueIdOffset & 1) ||
-        (MountPoint->UniqueIdLength & 1))
+    FreePool(ReparseData);
+    *Invalid = TRUE;
+    return STATUS_SUCCESS;
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+MountMgrQueryVolumePaths(IN PDEVICE_EXTENSION DeviceExtension,
+                         IN PDEVICE_INFORMATION DeviceInformation,
+                         IN PLIST_ENTRY DeviceInfoList,
+                         OUT PMOUNTMGR_VOLUME_PATHS * VolumePaths,
+                         OUT PDEVICE_INFORMATION *FailedDevice)
+{
+    ULONG Written;
+    NTSTATUS Status;
+    PLIST_ENTRY Entry;
+    PSYMLINK_INFORMATION SymlinkInformation;
+    PDEVICE_INFORMATION_ENTRY DeviceInfoEntry;
+    PASSOCIATED_DEVICE_ENTRY AssociatedDeviceEntry;
+    PMOUNTMGR_VOLUME_PATHS * Paths = NULL, * CurrentPath;
+    ULONG OutputPathLength, NumberOfPaths, ReturnedPaths;
+
+    /* We return at least null char */
+    OutputPathLength = sizeof(UNICODE_NULL);
+
+    for (Entry = DeviceInformation->SymbolicLinksListHead.Flink;
+         Entry != &(DeviceInformation->SymbolicLinksListHead);
+         Entry = Entry->Flink)
     {
-        return STATUS_INVALID_PARAMETER;
+        SymlinkInformation = CONTAINING_RECORD(Entry, SYMLINK_INFORMATION, SymbolicLinksListEntry);
+
+        /* Try to find the drive letter (ie, DOS device) */
+        if (MOUNTMGR_IS_DRIVE_LETTER(&SymlinkInformation->Name) && SymlinkInformation->Online)
+        {
+            /* We'll return the letter */
+            OutputPathLength = 4 * sizeof(WCHAR);
+            break;
+        }
     }
 
-    if ((MountPoint->DeviceNameOffset & 1) ||
-        (MountPoint->DeviceNameLength & 1))
+    /* We didn't find any */
+    if (Entry == &(DeviceInformation->SymbolicLinksListHead))
     {
-        return STATUS_INVALID_PARAMETER;
+        SymlinkInformation = NULL;
     }
 
-    /* We can't go beyond */
-    if (((ULONG)MountPoint->SymbolicLinkNameLength + MountPoint->UniqueIdLength +
-        MountPoint->DeviceNameLength) < Stack->Parameters.DeviceIoControl.InputBufferLength)
+    /* Do we have any device info to return? */
+    for (Entry = DeviceInfoList->Flink; Entry != DeviceInfoList; Entry = Entry->Flink)
     {
-        return STATUS_INVALID_PARAMETER;
+        DeviceInfoEntry = CONTAINING_RECORD(Entry, DEVICE_INFORMATION_ENTRY, DeviceInformationEntry);
+
+        /* Matching current device */
+        if (DeviceInfoEntry->DeviceInformation == DeviceInformation)
+        {
+            /* Allocate the output buffer */
+            *VolumePaths = AllocatePool(sizeof(ULONG) + OutputPathLength);
+            if (*VolumePaths == NULL)
+            {
+                return STATUS_INSUFFICIENT_RESOURCES;
+            }
+
+            /* Set size */
+            (*VolumePaths)->MultiSzLength = OutputPathLength;
+            /* If we have a drive letter, return it */
+            if (SymlinkInformation != NULL)
+            {
+                (*VolumePaths)->MultiSz[0] = SymlinkInformation->Name.Buffer[LETTER_POSITION];
+                (*VolumePaths)->MultiSz[1] = L':';
+                (*VolumePaths)->MultiSz[2] = UNICODE_NULL;
+                (*VolumePaths)->MultiSz[3] = UNICODE_NULL;
+            }
+            else
+            {
+                (*VolumePaths)->MultiSz[0] = UNICODE_NULL;
+            }
+
+            return STATUS_SUCCESS;
+        }
     }
 
-    if (Stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(MOUNTMGR_MOUNT_POINTS))
+    /* Allocate a new device entry */
+    DeviceInfoEntry = AllocatePool(sizeof(DEVICE_INFORMATION_ENTRY));
+    if (DeviceInfoEntry == NULL)
     {
-        return STATUS_INVALID_PARAMETER;
+        return STATUS_INSUFFICIENT_RESOURCES;
     }
 
-    /* If caller provided a Symlink, use it */
-    if (MountPoint->SymbolicLinkNameLength != 0)
+    /* Add it to the list */
+    DeviceInfoEntry->DeviceInformation = DeviceInformation;
+    InsertTailList(DeviceInfoList, &DeviceInfoEntry->DeviceInformationEntry);
+
+    NumberOfPaths = 0;
+    /* Count the amount of devices we will have to handle */
+    if (!IsListEmpty(&DeviceInformation->AssociatedDevicesHead))
     {
-        if (MountPoint->SymbolicLinkNameLength > MAXSHORT)
+        for (Entry = DeviceInformation->AssociatedDevicesHead.Flink;
+                     Entry != &DeviceInformation->AssociatedDevicesHead;
+                     Entry = Entry->Flink)
         {
-            return STATUS_INVALID_PARAMETER;
+            ++NumberOfPaths;
         }
 
-        SymbolicName.Length = MountPoint->SymbolicLinkNameLength;
-        SymbolicName.MaximumLength = MountPoint->SymbolicLinkNameLength + sizeof(WCHAR);
-        SymbolicName.Buffer = AllocatePool(SymbolicName.MaximumLength);
-        if (!SymbolicName.Buffer)
+        ASSERT(NumberOfPaths != 0);
+        /* And allocate a big enough buffer */
+        Paths = AllocatePool(NumberOfPaths * sizeof(PMOUNTMGR_VOLUME_PATHS));
+        if (Paths == NULL)
         {
+            RemoveEntryList(&DeviceInfoEntry->DeviceInformationEntry);
+            FreePool(DeviceInfoEntry);
             return STATUS_INSUFFICIENT_RESOURCES;
         }
-
-        RtlCopyMemory(SymbolicName.Buffer,
-                      (PWSTR)((ULONG_PTR)MountPoint + MountPoint->SymbolicLinkNameOffset),
-                      SymbolicName.Length);
-        SymbolicName.Buffer[SymbolicName.Length / sizeof(WCHAR)] = UNICODE_NULL;
-
-        /* Query links using it */
-        Status = QueryPointsFromSymbolicLinkName(DeviceExtension, &SymbolicName, Irp);
-        FreePool(SymbolicName.Buffer);
     }
-    /* If user provided an unique ID */
-    else if (MountPoint->UniqueIdLength != 0)
+
+    /* Start the hot loop to gather all the paths and be able to compute total output length! */
+    ReturnedPaths = 0;
+    CurrentPath = Paths;
+    for (Entry = DeviceInformation->AssociatedDevicesHead.Flink;
+         Entry != &DeviceInformation->AssociatedDevicesHead;
+         Entry = Entry->Flink)
     {
-        UniqueId = AllocatePool(MountPoint->UniqueIdLength + sizeof(MOUNTDEV_UNIQUE_ID));
-        if (!UniqueId)
-        {
-            return STATUS_INSUFFICIENT_RESOURCES;
-        }
+        USHORT InnerStrings;
+        BOOLEAN Invalid = FALSE;
 
-        UniqueId->UniqueIdLength = MountPoint->UniqueIdLength;
-        RtlCopyMemory(UniqueId->UniqueId,
-                      (PVOID)((ULONG_PTR)MountPoint + MountPoint->UniqueIdOffset),
-                      MountPoint->UniqueIdLength);
+        AssociatedDeviceEntry = CONTAINING_RECORD(Entry, ASSOCIATED_DEVICE_ENTRY, AssociatedDevicesEntry);
 
-         /* Query links using it */
-         Status = QueryPointsFromMemory(DeviceExtension, Irp, UniqueId, NULL);
-         FreePool(UniqueId);
-    }
-    /* If caller provided a device name */
-    else if (MountPoint->DeviceNameLength != 0)
-    {
-        if (MountPoint->DeviceNameLength > MAXSHORT)
+        /* Validate the fact its a mount point by query reparse data */
+        Status = MountMgrValidateBackPointer(AssociatedDeviceEntry, DeviceInformation, &Invalid);
+
+        /* If we found an invalid device, that's a failure */
+        if (Invalid)
         {
-            return STATUS_INVALID_PARAMETER;
+            *FailedDevice = AssociatedDeviceEntry->DeviceInformation;
+            Status = STATUS_UNSUCCESSFUL;
         }
 
-        DeviceName.Length = MountPoint->DeviceNameLength;
-        DeviceName.MaximumLength = MountPoint->DeviceNameLength + sizeof(WCHAR);
-        DeviceName.Buffer = AllocatePool(DeviceName.MaximumLength);
-        if (!DeviceName.Buffer)
+        /* Check whether we failed, if so, bail out */
+        if (!NT_SUCCESS(Status))
         {
-            return STATUS_INSUFFICIENT_RESOURCES;
+            ULONG i;
+
+            for (i = 0; i < ReturnedPaths; ++i)
+            {
+                FreePool(Paths[i]);
+            }
+
+            if (Paths != NULL)
+            {
+                FreePool(Paths);
+            }
+            RemoveEntryList(&DeviceInfoEntry->DeviceInformationEntry);
+            FreePool(DeviceInfoEntry);
+            return Status;
+        }
+
+        /* Query associated paths (hello ourselves :-)) */
+        Status = MountMgrQueryVolumePaths(DeviceExtension,
+                                          AssociatedDeviceEntry->DeviceInformation,
+                                          DeviceInfoList,
+                                          CurrentPath,
+                                          FailedDevice);
+        if (!NT_SUCCESS(Status))
+        {
+            ULONG i;
+
+            for (i = 0; i < ReturnedPaths; ++i)
+            {
+                FreePool(Paths[i]);
+            }
+
+            if (Paths != NULL)
+            {
+                FreePool(Paths);
+            }
+            RemoveEntryList(&DeviceInfoEntry->DeviceInformationEntry);
+            FreePool(DeviceInfoEntry);
+            return Status;
+        }
+
+        /* Count the number of strings we have in the multi string buffer */
+        InnerStrings = 0;
+        if ((*CurrentPath)->MultiSzLength != sizeof(UNICODE_NULL))
+        {
+            ULONG i;
+            PWSTR MultiSz = (*CurrentPath)->MultiSz;
+
+            for (i = 0; i < (*CurrentPath)->MultiSzLength / sizeof(WCHAR); ++i, ++MultiSz)
+            {
+                if (*MultiSz == UNICODE_NULL)
+                {
+                    ++InnerStrings;
+                }
+            }
+        }
+
+        /* We returned one more path (ie, one more allocated buffer) */
+        ++ReturnedPaths;
+        /* Move the next pointer to use in the array */
+        ++CurrentPath;
+        /* Multiply String.Length by the number of found paths, we always add it after a path */
+        OutputPathLength += (*CurrentPath)->MultiSzLength + InnerStrings * AssociatedDeviceEntry->String.Length - sizeof(UNICODE_NULL);
+    }
+
+    /* Allocate the output buffer */
+    *VolumePaths = AllocatePool(sizeof(ULONG) + OutputPathLength);
+    if (*VolumePaths == NULL)
+    {
+        ULONG i;
+
+        for (i = 0; i < ReturnedPaths; ++i)
+        {
+            FreePool(Paths[i]);
+        }
+
+        if (Paths != NULL)
+        {
+            FreePool(Paths);
+        }
+        RemoveEntryList(&DeviceInfoEntry->DeviceInformationEntry);
+        FreePool(DeviceInfoEntry);
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    Written = 0;
+    /* If we had found a DOS letter, that's the first thing we return */
+    (*VolumePaths)->MultiSzLength = OutputPathLength;
+    if (SymlinkInformation != NULL)
+    {
+        (*VolumePaths)->MultiSz[0] = SymlinkInformation->Name.Buffer[LETTER_POSITION];
+        (*VolumePaths)->MultiSz[1] = L':';
+        (*VolumePaths)->MultiSz[2] = UNICODE_NULL;
+        Written = 3;
+    }
+
+    /* Now, browse again all our paths to return them */
+    CurrentPath = Paths;
+    for (Entry = DeviceInformation->AssociatedDevicesHead.Flink;
+         Entry != &DeviceInformation->AssociatedDevicesHead;
+         Entry = Entry->Flink)
+    {
+        AssociatedDeviceEntry = CONTAINING_RECORD(Entry, ASSOCIATED_DEVICE_ENTRY, AssociatedDevicesEntry);
+
+        /* If we had a path... */
+        if ((*CurrentPath)->MultiSzLength != sizeof(UNICODE_NULL))
+        {
+            ULONG i, Offset;
+            PWSTR MultiSz;
+
+            /* This offset is used to "jump" into MultiSz, so, start with the string begin (ie, skip MultiSzLength) */
+            Offset = sizeof(ULONG);
+            /* Browse every single letter, and skip last UNICODE_NULL */
+            for (i = 0; i < (*CurrentPath)->MultiSzLength / sizeof(WCHAR) - 1; ++i)
+            {
+                /* Get the letter */
+                MultiSz = (PWSTR)((ULONG_PTR)(*CurrentPath) + Offset);
+                /* If it was part of the path, just return it */
+                if (*MultiSz != UNICODE_NULL)
+                {
+                    (*VolumePaths)->MultiSz[Written] = *MultiSz;
+                }
+                else
+                {
+                    /* Otherwise, as planed, return our whole associated device name */
+                    RtlCopyMemory(&(*VolumePaths)->MultiSz[Written],
+                                  AssociatedDeviceEntry->String.Buffer,
+                                  AssociatedDeviceEntry->String.Length);
+                    Written += AssociatedDeviceEntry->String.Length / sizeof(WCHAR);
+                    /* And don't forget to nullify */
+                    (*VolumePaths)->MultiSz[Written] = UNICODE_NULL;
+                }
+
+                /* We at least return a letter or a null char */
+                ++Written;
+                /* Move to the next letter */
+                Offset += sizeof(WCHAR);
+            }
+        }
+
+        FreePool(*CurrentPath);
+        ++CurrentPath;
+    }
+
+    /* MultiSz: don't forget last null char */
+    (*VolumePaths)->MultiSz[Written] = UNICODE_NULL;
+    /* Cleanup everything and return success! */
+    if (Paths != NULL)
+    {
+        FreePool(Paths);
+    }
+    RemoveEntryList(&DeviceInfoEntry->DeviceInformationEntry);
+    FreePool(DeviceInfoEntry);
+    return STATUS_SUCCESS;
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+MountMgrQueryDosVolumePaths(IN PDEVICE_EXTENSION DeviceExtension,
+                            IN PIRP Irp)
+{
+    NTSTATUS Status;
+    PLIST_ENTRY Entry;
+    LIST_ENTRY Devices;
+    BOOLEAN NeedNotification;
+    PIO_STACK_LOCATION Stack;
+    UNICODE_STRING SymbolicName;
+    ULONG Attempts, OutputLength;
+    PMOUNTMGR_TARGET_NAME Target;
+    PMOUNTMGR_VOLUME_PATHS Paths, Output;
+    RECONCILE_WORK_ITEM_CONTEXT ReconcileContext;
+    PDEVICE_INFORMATION DeviceInformation, ListDeviceInfo, FailedDevice;
+
+    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 + FIELD_OFFSET(MOUNTMGR_TARGET_NAME, DeviceName) > 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;
+    }
+
+    NeedNotification = FALSE;
+    Attempts = 0;
+    for (;;)
+    {
+        FailedDevice = NULL;
+        InitializeListHead(&Devices);
+
+        /* Query paths */
+        Status = MountMgrQueryVolumePaths(DeviceExtension, DeviceInformation, &Devices, &Paths, &FailedDevice);
+        if (NT_SUCCESS(Status))
+        {
+            break;
+        }
+
+        /* If it failed for generic reason (memory, whatever), bail out (ie, FailedDevice not set) */
+        if (FailedDevice == NULL)
+        {
+            return Status;
+        }
+
+        /* If PnP, let's notify in case of success */
+        if (!DeviceInformation->ManuallyRegistered)
+        {
+            NeedNotification = TRUE;
+        }
+
+        /* Reconcile database */
+        ReconcileContext.DeviceExtension = DeviceExtension;
+        ReconcileContext.DeviceInformation = FailedDevice;
+        KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
+        ReconcileThisDatabaseWithMasterWorker(&ReconcileContext);
+        KeWaitForSingleObject(&DeviceExtension->DeviceLock, Executive, KernelMode, FALSE, NULL);
+
+        /* Look for our device, to check it's online */
+        for (Entry = DeviceExtension->DeviceListHead.Flink;
+             Entry != &DeviceExtension->DeviceListHead;
+             Entry = Entry->Flink)
+        {
+            ListDeviceInfo = CONTAINING_RECORD(Entry, DEVICE_INFORMATION, DeviceListEntry);
+            /* It's online, it's OK! */
+            if (ListDeviceInfo == DeviceInformation)
+            {
+                break;
+            }
+        }
+
+        /* It's not online, it's not good */
+        if (Entry == &DeviceExtension->DeviceListHead)
+        {
+            return STATUS_OBJECT_NAME_NOT_FOUND;
+        }
+
+        /* Increase attempts count */
+        ++Attempts;
+        /* Don't look forever and fail if we get out of attempts */
+        if (Attempts >= 1000)
+        {
+            return Status;
+        }
+    }
+
+    /* We need to notify? Go ahead */
+    if (NeedNotification)
+    {
+        MountMgrNotifyNameChange(DeviceExtension, &SymbolicName, FALSE);
+    }
+
+    /* Get output buffer */
+    Output = (PMOUNTMGR_VOLUME_PATHS)Irp->AssociatedIrp.SystemBuffer;
+
+    /* Set required size */
+    Output->MultiSzLength = Paths->MultiSzLength;
+
+    /* Compute total length */
+    OutputLength = Output->MultiSzLength + sizeof(ULONG);
+
+    /* If it cannot fit, just return need size and quit */
+    if (OutputLength > Stack->Parameters.DeviceIoControl.OutputBufferLength)
+    {
+        Irp->IoStatus.Information = sizeof(ULONG);
+        FreePool(Paths);
+        return STATUS_BUFFER_OVERFLOW;
+    }
+
+    /* Copy data and quit */
+    Irp->IoStatus.Information = OutputLength;
+    RtlCopyMemory(Output->MultiSz, Paths->MultiSz, Output->MultiSzLength);
+    FreePool(Paths);
+    return STATUS_SUCCESS;
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+MountMgrKeepLinksWhenOffline(IN PDEVICE_EXTENSION DeviceExtension,
+                             IN PIRP Irp)
+{
+    NTSTATUS Status;
+    PIO_STACK_LOCATION Stack;
+    UNICODE_STRING SymbolicName;
+    PMOUNTMGR_TARGET_NAME Target;
+    PDEVICE_INFORMATION DeviceInformation;
+
+    Stack = IoGetCurrentIrpStackLocation(Irp);
+
+    /* Validate input */
+    if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(MOUNTMGR_TARGET_NAME))
+    {
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    Target = (PMOUNTMGR_TARGET_NAME)Irp->AssociatedIrp.SystemBuffer;
+    if (Target->DeviceNameLength + sizeof(USHORT) > Stack->Parameters.DeviceIoControl.InputBufferLength)
+    {
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    SymbolicName.Length =
+    SymbolicName.MaximumLength = Target->DeviceNameLength;
+    SymbolicName.Buffer = Target->DeviceName;
+
+    /* Find the associated device */
+    Status = FindDeviceInfo(DeviceExtension, &SymbolicName, FALSE, &DeviceInformation);
+    if (!NT_SUCCESS(Status))
+    {
+        return Status;
+    }
+
+    /* Mark we want to keep links */
+    DeviceInformation->KeepLinks = TRUE;
+
+    return STATUS_SUCCESS;
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+MountMgrVolumeArrivalNotification(IN PDEVICE_EXTENSION DeviceExtension,
+                                  IN PIRP Irp)
+{
+    NTSTATUS Status;
+    BOOLEAN OldState;
+    PIO_STACK_LOCATION Stack;
+    UNICODE_STRING SymbolicName;
+    PMOUNTMGR_TARGET_NAME Target;
+
+    Stack = IoGetCurrentIrpStackLocation(Irp);
+
+    /* Validate input */
+    if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(MOUNTMGR_TARGET_NAME))
+    {
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    Target = (PMOUNTMGR_TARGET_NAME)Irp->AssociatedIrp.SystemBuffer;
+    if (Target->DeviceNameLength + sizeof(USHORT) > Stack->Parameters.DeviceIoControl.InputBufferLength)
+    {
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    SymbolicName.Length =
+    SymbolicName.MaximumLength = Target->DeviceNameLength;
+    SymbolicName.Buffer = Target->DeviceName;
+
+    /* Disable hard errors */
+    OldState = PsGetThreadHardErrorsAreDisabled(PsGetCurrentThread());
+    PsSetThreadHardErrorsAreDisabled(PsGetCurrentThread(), TRUE);
+
+    /* Call real worker */
+    Status = MountMgrMountedDeviceArrival(DeviceExtension, &SymbolicName, TRUE);
+
+    PsSetThreadHardErrorsAreDisabled(PsGetCurrentThread(), OldState);
+
+    return Status;
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+MountMgrQueryPoints(IN PDEVICE_EXTENSION DeviceExtension,
+                    IN PIRP Irp)
+{
+    NTSTATUS Status;
+    PIO_STACK_LOCATION Stack;
+    PMOUNTDEV_UNIQUE_ID UniqueId;
+    PMOUNTMGR_MOUNT_POINT MountPoint;
+    UNICODE_STRING SymbolicName, DeviceName;
+
+    Stack = IoGetCurrentIrpStackLocation(Irp);
+
+    /* Validate input... */
+    if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(MOUNTMGR_MOUNT_POINT))
+    {
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    MountPoint = (PMOUNTMGR_MOUNT_POINT)Irp->AssociatedIrp.SystemBuffer;
+    if (!MountPoint->SymbolicLinkNameLength)
+    {
+        MountPoint->SymbolicLinkNameOffset = 0;
+    }
+
+    if (!MountPoint->UniqueIdLength)
+    {
+        MountPoint->UniqueIdOffset = 0;
+    }
+
+    if (!MountPoint->DeviceNameLength)
+    {
+        MountPoint->DeviceNameOffset = 0;
+    }
+
+    /* Addresses can't be odd */
+    if ((MountPoint->SymbolicLinkNameOffset & 1) ||
+        (MountPoint->SymbolicLinkNameLength & 1))
+    {
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    if ((MountPoint->UniqueIdOffset & 1) ||
+        (MountPoint->UniqueIdLength & 1))
+    {
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    if ((MountPoint->DeviceNameOffset & 1) ||
+        (MountPoint->DeviceNameLength & 1))
+    {
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    /* We can't go beyond */
+    if (((ULONG)MountPoint->SymbolicLinkNameLength + MountPoint->UniqueIdLength +
+        MountPoint->DeviceNameLength) < Stack->Parameters.DeviceIoControl.InputBufferLength)
+    {
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    if (Stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(MOUNTMGR_MOUNT_POINTS))
+    {
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    /* If caller provided a Symlink, use it */
+    if (MountPoint->SymbolicLinkNameLength != 0)
+    {
+        if (MountPoint->SymbolicLinkNameLength > MAXSHORT)
+        {
+            return STATUS_INVALID_PARAMETER;
+        }
+
+        SymbolicName.Length = MountPoint->SymbolicLinkNameLength;
+        SymbolicName.MaximumLength = MountPoint->SymbolicLinkNameLength + sizeof(WCHAR);
+        SymbolicName.Buffer = AllocatePool(SymbolicName.MaximumLength);
+        if (!SymbolicName.Buffer)
+        {
+            return STATUS_INSUFFICIENT_RESOURCES;
+        }
+
+        RtlCopyMemory(SymbolicName.Buffer,
+                      (PWSTR)((ULONG_PTR)MountPoint + MountPoint->SymbolicLinkNameOffset),
+                      SymbolicName.Length);
+        SymbolicName.Buffer[SymbolicName.Length / sizeof(WCHAR)] = UNICODE_NULL;
+
+        /* Query links using it */
+        Status = QueryPointsFromSymbolicLinkName(DeviceExtension, &SymbolicName, Irp);
+        FreePool(SymbolicName.Buffer);
+    }
+    /* If user provided an unique ID */
+    else if (MountPoint->UniqueIdLength != 0)
+    {
+        UniqueId = AllocatePool(MountPoint->UniqueIdLength + sizeof(MOUNTDEV_UNIQUE_ID));
+        if (!UniqueId)
+        {
+            return STATUS_INSUFFICIENT_RESOURCES;
+        }
+
+        UniqueId->UniqueIdLength = MountPoint->UniqueIdLength;
+        RtlCopyMemory(UniqueId->UniqueId,
+                      (PVOID)((ULONG_PTR)MountPoint + MountPoint->UniqueIdOffset),
+                      MountPoint->UniqueIdLength);
+
+         /* Query links using it */
+         Status = QueryPointsFromMemory(DeviceExtension, Irp, UniqueId, NULL);
+         FreePool(UniqueId);
+    }
+    /* If caller provided a device name */
+    else if (MountPoint->DeviceNameLength != 0)
+    {
+        if (MountPoint->DeviceNameLength > MAXSHORT)
+        {
+            return STATUS_INVALID_PARAMETER;
+        }
+
+        DeviceName.Length = MountPoint->DeviceNameLength;
+        DeviceName.MaximumLength = MountPoint->DeviceNameLength + sizeof(WCHAR);
+        DeviceName.Buffer = AllocatePool(DeviceName.MaximumLength);
+        if (!DeviceName.Buffer)
+        {
+            return STATUS_INSUFFICIENT_RESOURCES;
         }
 
         RtlCopyMemory(DeviceName.Buffer,
@@ -1077,7 +1848,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))
@@ -1256,7 +2027,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))
@@ -1319,7 +2090,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;
@@ -1455,20 +2226,455 @@ Cleanup:
     return Status;
 }
 
+/*
+ * @implemented
+ */
 NTSTATUS
 MountMgrVolumeMountPointCreated(IN PDEVICE_EXTENSION DeviceExtension,
                                 IN PIRP Irp,
                                 IN NTSTATUS 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)
 {
-    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;
 }
 
 /*
@@ -1483,7 +2689,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);
@@ -1582,6 +2788,9 @@ MountMgrDeviceControl(IN PDEVICE_OBJECT DeviceObject,
             Status = MountMgrSetAutoMount(DeviceExtension, Irp);
             break;
 
+        case IOCTL_MOUNTMGR_DEFINE_UNIX_DRIVE:
+        case IOCTL_MOUNTMGR_QUERY_UNIX_DRIVE:
+            DPRINT1("Winism! Rewrite the caller!\n");
         default:
             Status = STATUS_INVALID_DEVICE_REQUEST;
     }