mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 18:15:11 +00:00
ba447018c8
Effectively mountmgr.sys is an essential part of the storage stack
610 lines
22 KiB
C
610 lines
22 KiB
C
/*
|
|
* ReactOS kernel
|
|
* Copyright (C) 2011-2012 ReactOS Team
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
* PROJECT: ReactOS kernel
|
|
* FILE: drivers/filesystem/mountmgr/point.c
|
|
* PURPOSE: Mount Manager - Mount points
|
|
* PROGRAMMER: Pierre Schweitzer (pierre.schweitzer@reactos.org)
|
|
*/
|
|
|
|
#include "mntmgr.h"
|
|
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
NTSTATUS
|
|
MountMgrCreatePointWorker(IN PDEVICE_EXTENSION DeviceExtension,
|
|
IN PUNICODE_STRING SymbolicLinkName,
|
|
IN PUNICODE_STRING DeviceName)
|
|
{
|
|
NTSTATUS Status;
|
|
PLIST_ENTRY DeviceEntry;
|
|
PMOUNTDEV_UNIQUE_ID UniqueId;
|
|
PSYMLINK_INFORMATION SymlinkInformation;
|
|
UNICODE_STRING SymLink, TargetDeviceName;
|
|
PDEVICE_INFORMATION DeviceInformation = NULL, DeviceInfo;
|
|
|
|
/* Get device name */
|
|
Status = QueryDeviceInformation(DeviceName,
|
|
&TargetDeviceName,
|
|
NULL, NULL, NULL,
|
|
NULL, NULL, NULL);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
return Status;
|
|
}
|
|
|
|
/* First of all, try to find device */
|
|
for (DeviceEntry = DeviceExtension->DeviceListHead.Flink;
|
|
DeviceEntry != &(DeviceExtension->DeviceListHead);
|
|
DeviceEntry = DeviceEntry->Flink)
|
|
{
|
|
DeviceInformation = CONTAINING_RECORD(DeviceEntry, DEVICE_INFORMATION, DeviceListEntry);
|
|
|
|
if (RtlEqualUnicodeString(&TargetDeviceName, &(DeviceInformation->DeviceName), TRUE))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Copy symbolic link name and null terminate it */
|
|
SymLink.Buffer = AllocatePool(SymbolicLinkName->Length + sizeof(UNICODE_NULL));
|
|
if (!SymLink.Buffer)
|
|
{
|
|
FreePool(TargetDeviceName.Buffer);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
RtlCopyMemory(SymLink.Buffer, SymbolicLinkName->Buffer, SymbolicLinkName->Length);
|
|
SymLink.Buffer[SymbolicLinkName->Length / sizeof(WCHAR)] = UNICODE_NULL;
|
|
SymLink.Length = SymbolicLinkName->Length;
|
|
SymLink.MaximumLength = SymbolicLinkName->Length + sizeof(UNICODE_NULL);
|
|
|
|
/* If we didn't find device */
|
|
if (DeviceEntry == &(DeviceExtension->DeviceListHead))
|
|
{
|
|
/* Then, try with unique ID */
|
|
Status = QueryDeviceInformation(SymbolicLinkName,
|
|
NULL, &UniqueId,
|
|
NULL, NULL, NULL,
|
|
NULL, NULL);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
FreePool(TargetDeviceName.Buffer);
|
|
FreePool(SymLink.Buffer);
|
|
return Status;
|
|
}
|
|
|
|
/* Create a link to the device */
|
|
Status = GlobalCreateSymbolicLink(&SymLink, &TargetDeviceName);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
FreePool(UniqueId);
|
|
FreePool(TargetDeviceName.Buffer);
|
|
FreePool(SymLink.Buffer);
|
|
return Status;
|
|
}
|
|
|
|
/* If caller provided driver letter, delete it */
|
|
if (IsDriveLetter(&SymLink))
|
|
{
|
|
DeleteRegistryDriveLetter(UniqueId);
|
|
}
|
|
|
|
/* Device will be identified with its unique ID */
|
|
Status = RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE,
|
|
DatabasePath,
|
|
SymLink.Buffer,
|
|
REG_BINARY,
|
|
UniqueId->UniqueId,
|
|
UniqueId->UniqueIdLength);
|
|
|
|
FreePool(UniqueId);
|
|
FreePool(TargetDeviceName.Buffer);
|
|
FreePool(SymLink.Buffer);
|
|
return Status;
|
|
}
|
|
|
|
/* If call provided a driver letter whereas device already has one
|
|
* fail, this is not doable
|
|
*/
|
|
if (IsDriveLetter(&SymLink) && HasDriveLetter(DeviceInformation))
|
|
{
|
|
FreePool(TargetDeviceName.Buffer);
|
|
FreePool(SymLink.Buffer);
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
/* Now, create a link */
|
|
Status = GlobalCreateSymbolicLink(&SymLink, &TargetDeviceName);
|
|
FreePool(TargetDeviceName.Buffer);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
FreePool(SymLink.Buffer);
|
|
return Status;
|
|
}
|
|
|
|
/* Associate Unique ID <-> symbolic name */
|
|
UniqueId = DeviceInformation->UniqueId;
|
|
Status = RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE,
|
|
DatabasePath,
|
|
SymLink.Buffer,
|
|
REG_BINARY,
|
|
UniqueId->UniqueId,
|
|
UniqueId->UniqueIdLength);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
GlobalDeleteSymbolicLink(&SymLink);
|
|
FreePool(SymLink.Buffer);
|
|
return Status;
|
|
}
|
|
|
|
/* Now, prepare to save the link with the device */
|
|
SymlinkInformation = AllocatePool(sizeof(SYMLINK_INFORMATION));
|
|
if (!SymlinkInformation)
|
|
{
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
GlobalDeleteSymbolicLink(&SymLink);
|
|
FreePool(SymLink.Buffer);
|
|
return Status;
|
|
}
|
|
|
|
SymlinkInformation->Name.Length = SymLink.Length;
|
|
SymlinkInformation->Name.MaximumLength = SymLink.Length + sizeof(UNICODE_NULL);
|
|
SymlinkInformation->Name.Buffer = AllocatePool(SymlinkInformation->Name.MaximumLength);
|
|
if (!SymlinkInformation->Name.Buffer)
|
|
{
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
FreePool(SymlinkInformation);
|
|
GlobalDeleteSymbolicLink(&SymLink);
|
|
FreePool(SymLink.Buffer);
|
|
return Status;
|
|
}
|
|
|
|
/* Save the link and mark it online */
|
|
RtlCopyMemory(SymlinkInformation->Name.Buffer, SymLink.Buffer, SymlinkInformation->Name.Length);
|
|
SymlinkInformation->Name.Buffer[SymlinkInformation->Name.Length / sizeof(WCHAR)] = UNICODE_NULL;
|
|
SymlinkInformation->Online = TRUE;
|
|
InsertTailList(&DeviceInformation->SymbolicLinksListHead, &SymlinkInformation->SymbolicLinksListEntry);
|
|
SendLinkCreated(&(SymlinkInformation->Name));
|
|
|
|
/* If we have a drive letter */
|
|
if (IsDriveLetter(&SymLink))
|
|
{
|
|
/* Then, delete the no drive letter entry */
|
|
DeleteNoDriveLetterEntry(UniqueId);
|
|
|
|
/* And post online notification if asked */
|
|
if (!DeviceInformation->SkipNotifications)
|
|
{
|
|
PostOnlineNotification(DeviceExtension, &DeviceInformation->SymbolicName);
|
|
}
|
|
}
|
|
|
|
/* If that's a volume with automatic drive letter, it's now time to resync databases */
|
|
if (MOUNTMGR_IS_VOLUME_NAME(&SymLink) && DeviceExtension->AutomaticDriveLetter)
|
|
{
|
|
for (DeviceEntry = DeviceExtension->DeviceListHead.Flink;
|
|
DeviceEntry != &(DeviceExtension->DeviceListHead);
|
|
DeviceEntry = DeviceEntry->Flink)
|
|
{
|
|
DeviceInfo = CONTAINING_RECORD(DeviceEntry, DEVICE_INFORMATION, DeviceListEntry);
|
|
|
|
/* If there's one, ofc! */
|
|
if (!DeviceInfo->NoDatabase)
|
|
{
|
|
ReconcileThisDatabaseWithMaster(DeviceExtension, DeviceInfo);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Notify & quit */
|
|
FreePool(SymLink.Buffer);
|
|
MountMgrNotify(DeviceExtension);
|
|
|
|
if (!DeviceInformation->ManuallyRegistered)
|
|
{
|
|
MountMgrNotifyNameChange(DeviceExtension, DeviceName, FALSE);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
NTSTATUS
|
|
QueryPointsFromMemory(IN PDEVICE_EXTENSION DeviceExtension,
|
|
IN PIRP Irp,
|
|
IN PMOUNTDEV_UNIQUE_ID UniqueId OPTIONAL,
|
|
IN PUNICODE_STRING SymbolicName OPTIONAL)
|
|
{
|
|
NTSTATUS Status;
|
|
PIO_STACK_LOCATION Stack;
|
|
UNICODE_STRING DeviceName;
|
|
PMOUNTMGR_MOUNT_POINTS MountPoints;
|
|
PDEVICE_INFORMATION DeviceInformation;
|
|
PLIST_ENTRY DeviceEntry, SymlinksEntry;
|
|
PSYMLINK_INFORMATION SymlinkInformation;
|
|
USHORT UniqueIdLength, DeviceNameLength;
|
|
ULONG TotalSize, TotalSymLinks, UniqueIdOffset, DeviceNameOffset;
|
|
|
|
/* If we got a symbolic link, query device */
|
|
if (SymbolicName)
|
|
{
|
|
Status = QueryDeviceInformation(SymbolicName,
|
|
&DeviceName,
|
|
NULL, NULL,
|
|
NULL, NULL,
|
|
NULL, NULL);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
/* Browse all the links to count number of links & size used */
|
|
TotalSize = 0;
|
|
TotalSymLinks = 0;
|
|
for (DeviceEntry = DeviceExtension->DeviceListHead.Flink;
|
|
DeviceEntry != &(DeviceExtension->DeviceListHead);
|
|
DeviceEntry = DeviceEntry->Flink)
|
|
{
|
|
DeviceInformation = CONTAINING_RECORD(DeviceEntry, DEVICE_INFORMATION, DeviceListEntry);
|
|
|
|
/* If we were given an unique ID, it has to match */
|
|
if (UniqueId)
|
|
{
|
|
if (UniqueId->UniqueIdLength != DeviceInformation->UniqueId->UniqueIdLength)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (RtlCompareMemory(UniqueId->UniqueId,
|
|
DeviceInformation->UniqueId->UniqueId,
|
|
UniqueId->UniqueIdLength) != UniqueId->UniqueIdLength)
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
/* Or, if we had a symlink, it has to match */
|
|
else if (SymbolicName)
|
|
{
|
|
if (!RtlEqualUnicodeString(&DeviceName, &(DeviceInformation->DeviceName), TRUE))
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
|
|
/* Once here, it matched, save device name & unique ID size */
|
|
TotalSize += DeviceInformation->DeviceName.Length + DeviceInformation->UniqueId->UniqueIdLength;
|
|
|
|
/* And count number of symlinks (and their size) */
|
|
for (SymlinksEntry = DeviceInformation->SymbolicLinksListHead.Flink;
|
|
SymlinksEntry != &(DeviceInformation->SymbolicLinksListHead);
|
|
SymlinksEntry = SymlinksEntry->Flink)
|
|
{
|
|
SymlinkInformation = CONTAINING_RECORD(SymlinksEntry, SYMLINK_INFORMATION, SymbolicLinksListEntry);
|
|
|
|
TotalSize += SymlinkInformation->Name.Length;
|
|
TotalSymLinks++;
|
|
}
|
|
|
|
/* We had a specific item to find
|
|
* if we reach that point, we found it, no need to continue
|
|
*/
|
|
if (UniqueId || SymbolicName)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* If we were looking for specific item, ensure we found it */
|
|
if (UniqueId || SymbolicName)
|
|
{
|
|
if (DeviceEntry == &(DeviceExtension->DeviceListHead))
|
|
{
|
|
if (SymbolicName)
|
|
{
|
|
FreePool(DeviceName.Buffer);
|
|
}
|
|
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
|
|
/* Now, ensure output buffer can hold everything */
|
|
Stack = IoGetCurrentIrpStackLocation(Irp);
|
|
MountPoints = (PMOUNTMGR_MOUNT_POINTS)Irp->AssociatedIrp.SystemBuffer;
|
|
RtlZeroMemory(MountPoints, Stack->Parameters.DeviceIoControl.OutputBufferLength);
|
|
|
|
/* Ensure we set output to let user reallocate! */
|
|
MountPoints->Size = sizeof(MOUNTMGR_MOUNT_POINTS) + TotalSymLinks * sizeof(MOUNTMGR_MOUNT_POINT) + TotalSize;
|
|
MountPoints->NumberOfMountPoints = TotalSymLinks;
|
|
Irp->IoStatus.Information = MountPoints->Size;
|
|
|
|
if (MountPoints->Size > Stack->Parameters.DeviceIoControl.OutputBufferLength)
|
|
{
|
|
Irp->IoStatus.Information = sizeof(MOUNTMGR_MOUNT_POINTS);
|
|
|
|
if (SymbolicName)
|
|
{
|
|
FreePool(DeviceName.Buffer);
|
|
}
|
|
|
|
return STATUS_BUFFER_OVERFLOW;
|
|
}
|
|
|
|
/* Now, start putting mount points */
|
|
TotalSize = sizeof(MOUNTMGR_MOUNT_POINTS) + TotalSymLinks * sizeof(MOUNTMGR_MOUNT_POINT);
|
|
TotalSymLinks = 0;
|
|
for (DeviceEntry = DeviceExtension->DeviceListHead.Flink;
|
|
DeviceEntry != &(DeviceExtension->DeviceListHead);
|
|
DeviceEntry = DeviceEntry->Flink)
|
|
{
|
|
DeviceInformation = CONTAINING_RECORD(DeviceEntry, DEVICE_INFORMATION, DeviceListEntry);
|
|
|
|
/* Find back correct mount point */
|
|
if (UniqueId)
|
|
{
|
|
if (UniqueId->UniqueIdLength != DeviceInformation->UniqueId->UniqueIdLength)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (RtlCompareMemory(UniqueId->UniqueId,
|
|
DeviceInformation->UniqueId->UniqueId,
|
|
UniqueId->UniqueIdLength) != UniqueId->UniqueIdLength)
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
else if (SymbolicName)
|
|
{
|
|
if (!RtlEqualUnicodeString(&DeviceName, &(DeviceInformation->DeviceName), TRUE))
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
|
|
/* Save our information about shared data */
|
|
UniqueIdOffset = TotalSize;
|
|
UniqueIdLength = DeviceInformation->UniqueId->UniqueIdLength;
|
|
DeviceNameOffset = TotalSize + UniqueIdLength;
|
|
DeviceNameLength = DeviceInformation->DeviceName.Length;
|
|
|
|
/* Initialize first symlink */
|
|
MountPoints->MountPoints[TotalSymLinks].UniqueIdOffset = UniqueIdOffset;
|
|
MountPoints->MountPoints[TotalSymLinks].UniqueIdLength = UniqueIdLength;
|
|
MountPoints->MountPoints[TotalSymLinks].DeviceNameOffset = DeviceNameOffset;
|
|
MountPoints->MountPoints[TotalSymLinks].DeviceNameLength = DeviceNameLength;
|
|
|
|
/* And copy data */
|
|
RtlCopyMemory((PWSTR)((ULONG_PTR)MountPoints + UniqueIdOffset),
|
|
DeviceInformation->UniqueId->UniqueId, UniqueIdLength);
|
|
RtlCopyMemory((PWSTR)((ULONG_PTR)MountPoints + DeviceNameOffset),
|
|
DeviceInformation->DeviceName.Buffer, DeviceNameLength);
|
|
|
|
TotalSize += DeviceInformation->UniqueId->UniqueIdLength + DeviceInformation->DeviceName.Length;
|
|
|
|
/* Now we've got it, but all the data */
|
|
for (SymlinksEntry = DeviceInformation->SymbolicLinksListHead.Flink;
|
|
SymlinksEntry != &(DeviceInformation->SymbolicLinksListHead);
|
|
SymlinksEntry = SymlinksEntry->Flink)
|
|
{
|
|
SymlinkInformation = CONTAINING_RECORD(SymlinksEntry, SYMLINK_INFORMATION, SymbolicLinksListEntry);
|
|
|
|
/* First, set shared data */
|
|
|
|
/* Only put UniqueID if online */
|
|
if (SymlinkInformation->Online)
|
|
{
|
|
MountPoints->MountPoints[TotalSymLinks].UniqueIdOffset = UniqueIdOffset;
|
|
MountPoints->MountPoints[TotalSymLinks].UniqueIdLength = UniqueIdLength;
|
|
}
|
|
else
|
|
{
|
|
MountPoints->MountPoints[TotalSymLinks].UniqueIdOffset = 0;
|
|
MountPoints->MountPoints[TotalSymLinks].UniqueIdLength = 0;
|
|
}
|
|
|
|
MountPoints->MountPoints[TotalSymLinks].DeviceNameOffset = DeviceNameOffset;
|
|
MountPoints->MountPoints[TotalSymLinks].DeviceNameLength = DeviceNameLength;
|
|
|
|
/* And now, copy specific symlink info */
|
|
MountPoints->MountPoints[TotalSymLinks].SymbolicLinkNameOffset = TotalSize;
|
|
MountPoints->MountPoints[TotalSymLinks].SymbolicLinkNameLength = SymlinkInformation->Name.Length;
|
|
|
|
RtlCopyMemory((PWSTR)((ULONG_PTR)MountPoints + MountPoints->MountPoints[TotalSymLinks].SymbolicLinkNameOffset),
|
|
SymlinkInformation->Name.Buffer, SymlinkInformation->Name.Length);
|
|
|
|
/* Update counters */
|
|
TotalSymLinks++;
|
|
TotalSize += SymlinkInformation->Name.Length;
|
|
}
|
|
|
|
if (UniqueId || SymbolicName)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (SymbolicName)
|
|
{
|
|
FreePool(DeviceName.Buffer);
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
NTSTATUS
|
|
QueryPointsFromSymbolicLinkName(IN PDEVICE_EXTENSION DeviceExtension,
|
|
IN PUNICODE_STRING SymbolicName,
|
|
IN PIRP Irp)
|
|
{
|
|
NTSTATUS Status;
|
|
ULONG TotalLength;
|
|
PIO_STACK_LOCATION Stack;
|
|
UNICODE_STRING DeviceName;
|
|
PMOUNTMGR_MOUNT_POINTS MountPoints;
|
|
PDEVICE_INFORMATION DeviceInformation = NULL;
|
|
PLIST_ENTRY DeviceEntry, SymlinksEntry;
|
|
PSYMLINK_INFORMATION SymlinkInformation;
|
|
|
|
/* Find device */
|
|
Status = QueryDeviceInformation(SymbolicName, &DeviceName,
|
|
NULL, NULL, NULL,
|
|
NULL, NULL, NULL);
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
/* Look for the device information */
|
|
for (DeviceEntry = DeviceExtension->DeviceListHead.Flink;
|
|
DeviceEntry != &(DeviceExtension->DeviceListHead);
|
|
DeviceEntry = DeviceEntry->Flink)
|
|
{
|
|
DeviceInformation = CONTAINING_RECORD(DeviceEntry, DEVICE_INFORMATION, DeviceListEntry);
|
|
|
|
if (RtlEqualUnicodeString(&DeviceName, &(DeviceInformation->DeviceName), TRUE))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
FreePool(DeviceName.Buffer);
|
|
|
|
if (DeviceEntry == &(DeviceExtension->DeviceListHead))
|
|
{
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
/* Check for the link */
|
|
for (SymlinksEntry = DeviceInformation->SymbolicLinksListHead.Flink;
|
|
SymlinksEntry != &(DeviceInformation->SymbolicLinksListHead);
|
|
SymlinksEntry = SymlinksEntry->Flink)
|
|
{
|
|
SymlinkInformation = CONTAINING_RECORD(SymlinksEntry, SYMLINK_INFORMATION, SymbolicLinksListEntry);
|
|
|
|
if (RtlEqualUnicodeString(SymbolicName, &SymlinkInformation->Name, TRUE))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (SymlinksEntry == &(DeviceInformation->SymbolicLinksListHead))
|
|
{
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Browse all the devices to try to find the one
|
|
* that has the given link...
|
|
*/
|
|
for (DeviceEntry = DeviceExtension->DeviceListHead.Flink;
|
|
DeviceEntry != &(DeviceExtension->DeviceListHead);
|
|
DeviceEntry = DeviceEntry->Flink)
|
|
{
|
|
DeviceInformation = CONTAINING_RECORD(DeviceEntry, DEVICE_INFORMATION, DeviceListEntry);
|
|
|
|
for (SymlinksEntry = DeviceInformation->SymbolicLinksListHead.Flink;
|
|
SymlinksEntry != &(DeviceInformation->SymbolicLinksListHead);
|
|
SymlinksEntry = SymlinksEntry->Flink)
|
|
{
|
|
SymlinkInformation = CONTAINING_RECORD(SymlinksEntry, SYMLINK_INFORMATION, SymbolicLinksListEntry);
|
|
|
|
if (RtlEqualUnicodeString(SymbolicName, &SymlinkInformation->Name, TRUE))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (SymlinksEntry != &(DeviceInformation->SymbolicLinksListHead))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Even that way we didn't find, give up! */
|
|
if (DeviceEntry == &(DeviceExtension->DeviceListHead))
|
|
{
|
|
return STATUS_OBJECT_NAME_NOT_FOUND;
|
|
}
|
|
}
|
|
|
|
/* Get output buffer */
|
|
Stack = IoGetCurrentIrpStackLocation(Irp);
|
|
MountPoints = (PMOUNTMGR_MOUNT_POINTS)Irp->AssociatedIrp.SystemBuffer;
|
|
|
|
/* Compute output length */
|
|
TotalLength = DeviceInformation->UniqueId->UniqueIdLength +
|
|
SymlinkInformation->Name.Length + DeviceInformation->DeviceName.Length;
|
|
|
|
/* Give length to allow reallocation */
|
|
MountPoints->Size = sizeof(MOUNTMGR_MOUNT_POINTS) + TotalLength;
|
|
MountPoints->NumberOfMountPoints = 1;
|
|
Irp->IoStatus.Information = sizeof(MOUNTMGR_MOUNT_POINTS) + TotalLength;
|
|
|
|
if (MountPoints->Size > Stack->Parameters.DeviceIoControl.OutputBufferLength)
|
|
{
|
|
Irp->IoStatus.Information = sizeof(MOUNTMGR_MOUNT_POINTS);
|
|
|
|
return STATUS_BUFFER_OVERFLOW;
|
|
}
|
|
|
|
/* Write out data */
|
|
MountPoints->MountPoints[0].SymbolicLinkNameOffset = sizeof(MOUNTMGR_MOUNT_POINTS);
|
|
MountPoints->MountPoints[0].SymbolicLinkNameLength = SymlinkInformation->Name.Length;
|
|
/* If link is online write it's unique ID, otherwise, forget about it */
|
|
if (SymlinkInformation->Online)
|
|
{
|
|
MountPoints->MountPoints[0].UniqueIdOffset = sizeof(MOUNTMGR_MOUNT_POINTS) +
|
|
SymlinkInformation->Name.Length;
|
|
MountPoints->MountPoints[0].UniqueIdLength = DeviceInformation->UniqueId->UniqueIdLength;
|
|
}
|
|
else
|
|
{
|
|
MountPoints->MountPoints[0].UniqueIdOffset = 0;
|
|
MountPoints->MountPoints[0].UniqueIdLength = 0;
|
|
}
|
|
|
|
MountPoints->MountPoints[0].DeviceNameOffset = sizeof(MOUNTMGR_MOUNT_POINTS) +
|
|
SymlinkInformation->Name.Length +
|
|
DeviceInformation->UniqueId->UniqueIdLength;
|
|
MountPoints->MountPoints[0].DeviceNameLength = DeviceInformation->DeviceName.Length;
|
|
|
|
RtlCopyMemory((PWSTR)((ULONG_PTR)MountPoints + MountPoints->MountPoints[0].SymbolicLinkNameOffset),
|
|
SymlinkInformation->Name.Buffer, SymlinkInformation->Name.Length);
|
|
|
|
if (SymlinkInformation->Online)
|
|
{
|
|
RtlCopyMemory((PWSTR)((ULONG_PTR)MountPoints + MountPoints->MountPoints[0].UniqueIdOffset),
|
|
DeviceInformation->UniqueId->UniqueId, DeviceInformation->UniqueId->UniqueIdLength);
|
|
}
|
|
|
|
RtlCopyMemory((PWSTR)((ULONG_PTR)MountPoints + MountPoints->MountPoints[0].DeviceNameOffset),
|
|
DeviceInformation->DeviceName.Buffer, DeviceInformation->DeviceName.Length);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|