* PROGRAMMER: Pierre Schweitzer (pierre.schweitzer@reactos.org)
*/
-/* INCLUDES *****************************************************************/
-
#include "mntmgr.h"
+#define MAX_DEVICES 0x3E8 /* Matches 1000 devices */
+
#define NDEBUG
#include <debug.h>
PDEVICE_INFORMATION DeviceInformation;
NTSTATUS ArrivalStatus, Status = STATUS_SUCCESS;
+ UNREFERENCED_PARAMETER(Irp);
+
/* No offline volumes, nothing more to do */
if (IsListEmpty(&(DeviceExtension->OfflineDeviceListHead)))
{
ArrivalStatus = MountMgrMountedDeviceArrival(DeviceExtension,
&(DeviceInformation->SymbolicName),
- DeviceInformation->Volume);
+ DeviceInformation->ManuallyRegistered);
/* Then, remove them dead information */
MountMgrFreeDeadDeviceInfo(DeviceInformation);
}
}
- /* 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)
}
/* 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 */
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) ||
UNICODE_STRING ValueString;
PUNICODE_STRING SystemVolumeName;
+ UNREFERENCED_PARAMETER(ValueName);
+ UNREFERENCED_PARAMETER(ValueLength);
+ UNREFERENCED_PARAMETER(EntryContext);
+
if (ValueType != REG_SZ)
{
return STATUS_SUCCESS;
}
}
-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,
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))
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))
}
/* 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;
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;
}
/*
NTSTATUS Status, LockStatus;
PDEVICE_EXTENSION DeviceExtension;
- Stack = IoGetNextIrpStackLocation(Irp);
+ Stack = IoGetCurrentIrpStackLocation(Irp);
DeviceExtension = DeviceObject->DeviceExtension;
KeWaitForSingleObject(&(DeviceExtension->DeviceLock), Executive, KernelMode, FALSE, NULL);
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;
}