[MOUNTMGR]

Implement the IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATHS:
- Implement MountMgrQueryVolumePaths()
- Implement MountMgrValidateBackPointer()
- Implement MountMgrQueryDosVolumePaths()
- Rename a struct var to reflect its real usage

svn path=/trunk/; revision=69284
This commit is contained in:
Pierre Schweitzer 2015-09-19 13:03:41 +00:00
parent 7a7073bedc
commit 9391f1ae05
5 changed files with 554 additions and 16 deletions

View file

@ -311,7 +311,7 @@ MountMgrCheckUnprocessedVolumes(IN PDEVICE_EXTENSION DeviceExtension,
ArrivalStatus = MountMgrMountedDeviceArrival(DeviceExtension,
&(DeviceInformation->SymbolicName),
DeviceInformation->Volume);
DeviceInformation->ManuallyRegistered);
/* Then, remove them dead information */
MountMgrFreeDeadDeviceInfo(DeviceInformation);
@ -829,6 +829,9 @@ MountMgrAssignDriveLetters(IN PDEVICE_EXTENSION DeviceExtension)
}
}
/*
* @implemented
*/
NTSTATUS
MountMgrQueryDosVolumePath(IN PDEVICE_EXTENSION DeviceExtension,
IN PIRP Irp)
@ -967,7 +970,7 @@ MountMgrQueryDosVolumePath(IN PDEVICE_EXTENSION DeviceExtension,
}
/* Get the letter */
DeviceString[0] = SymlinkInformation->Name.Buffer[12];
DeviceString[0] = SymlinkInformation->Name.Buffer[LETTER_POSITION];
DeviceString[1] = L':';
/* And copy the rest */
@ -1053,13 +1056,539 @@ TryWithVolumeName:
return STATUS_NOT_FOUND;
}
/*
* @implemented
*/
NTSTATUS
MountMgrValidateBackPointer(IN PASSOCIATED_DEVICE_ENTRY AssociatedDeviceEntry,
IN PDEVICE_INFORMATION DeviceInformation,
OUT PBOOLEAN Invalid)
{
HANDLE Handle;
NTSTATUS Status;
PLIST_ENTRY SymlinksEntry;
IO_STATUS_BLOCK IoStatusBlock;
PREPARSE_DATA_BUFFER ReparseData;
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING FullName, SubstituteName;
PSYMLINK_INFORMATION SymlinkInformation;
/* 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_INSUFFICIENT_RESOURCES;
}
/* 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))
{
*Invalid = TRUE;
return STATUS_SUCCESS;
}
/* Allocate a buffer big enough to read reparse data */
ReparseData = AllocatePool(0x4000);
if (ReparseData == NULL)
{
ZwClose(Handle);
return STATUS_INSUFFICIENT_RESOURCES;
}
/* Query reparse data */
Status = ZwFsControlFile(Handle,
NULL, NULL, NULL,
&IoStatusBlock,
FSCTL_GET_REPARSE_POINT,
NULL, 0,
ReparseData, 0x4000);
ZwClose(Handle);
if (!NT_SUCCESS(Status))
{
FreePool(ReparseData);
*Invalid = TRUE;
return STATUS_SUCCESS;
}
/* 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))
{
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;
}
}
}
}
FreePool(ReparseData);
*Invalid = TRUE;
return STATUS_SUCCESS;
}
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)
{
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;
}
}
/* We didn't find any */
if (Entry == &(DeviceInformation->SymbolicLinksListHead))
{
SymlinkInformation = NULL;
}
/* Do we have any device info to return? */
for (Entry = DeviceInfoList->Flink; Entry != DeviceInfoList; Entry = Entry->Flink)
{
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;
}
}
/* Allocate a new device entry */
DeviceInfoEntry = AllocatePool(sizeof(DEVICE_INFORMATION_ENTRY));
if (DeviceInfoEntry == NULL)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
/* 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))
{
for (Entry = DeviceInformation->AssociatedDevicesHead.Flink;
Entry != &DeviceInformation->AssociatedDevicesHead;
Entry = Entry->Flink)
{
++NumberOfPaths;
}
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;
}
}
/* 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)
{
USHORT InnerStrings;
BOOLEAN Invalid = FALSE;
AssociatedDeviceEntry = CONTAINING_RECORD(Entry, ASSOCIATED_DEVICE_ENTRY, AssociatedDevicesEntry);
/* 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)
{
*FailedDevice = AssociatedDeviceEntry->DeviceInformation;
Status = STATUS_UNSUCCESSFUL;
}
/* Check whether we failed, if so, bail out */
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;
}
/* 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;
}
NTSTATUS
MountMgrQueryDosVolumePaths(IN PDEVICE_EXTENSION DeviceExtension,
IN PIRP Irp)
{
UNREFERENCED_PARAMETER(DeviceExtension);
UNREFERENCED_PARAMETER(Irp);
return STATUS_NOT_IMPLEMENTED;
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;
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 */
KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
ReconcileThisDatabaseWithMasterWorker(&DeviceExtension);
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;
}
/*
@ -1930,7 +2459,6 @@ MountMgrVolumeMountPointCreated(IN PDEVICE_EXTENSION DeviceExtension,
/*
* @implemented
*/
NTSTATUS
MountMgrVolumeMountPointDeleted(IN PDEVICE_EXTENSION DeviceExtension,
IN PIRP Irp,

View file

@ -67,7 +67,7 @@ typedef struct _DEVICE_INFORMATION
UNICODE_STRING DeviceName; // 0x2C
BOOLEAN KeepLinks; // 0x34
UCHAR SuggestedDriveLetter; // 0x35
BOOLEAN Volume; // 0x36
BOOLEAN ManuallyRegistered; // 0x36
BOOLEAN Removable; // 0x37
BOOLEAN LetterAssigned; // 0x38
BOOLEAN NeedsReconcile; // 0x39
@ -116,6 +116,12 @@ typedef struct _ASSOCIATED_DEVICE_ENTRY
UNICODE_STRING String; // 0x0C
} ASSOCIATED_DEVICE_ENTRY, *PASSOCIATED_DEVICE_ENTRY; // 0x14
typedef struct _DEVICE_INFORMATION_ENTRY
{
LIST_ENTRY DeviceInformationEntry; // 0x00
PDEVICE_INFORMATION DeviceInformation; // 0x08
} DEVICE_INFORMATION_ENTRY, *PDEVICE_INFORMATION_ENTRY; // 0x0C
typedef struct _ONLINE_NOTIFICATION_WORK_ITEM
{
WORK_QUEUE_ITEM; // 0x00
@ -334,6 +340,12 @@ DeleteRemoteDatabaseEntry(
IN LONG StartingOffset
);
VOID
NTAPI
ReconcileThisDatabaseWithMasterWorker(
IN PVOID Parameter
);
/* device.c */
DRIVER_DISPATCH MountMgrDeviceControl;

View file

@ -45,9 +45,6 @@ static const WCHAR Cunc[] = L"\\??\\C:";
/*
* TODO:
* - MountMgrQueryDosVolumePaths
* - MountMgrQueryVolumePaths
* - MountMgrValidateBackPointer
* - ReconcileThisDatabaseWithMasterWorker
*/
@ -952,7 +949,7 @@ MountmgrReadNoAutoMount(IN PUNICODE_STRING RegistryPath)
NTSTATUS
MountMgrMountedDeviceArrival(IN PDEVICE_EXTENSION DeviceExtension,
IN PUNICODE_STRING SymbolicName,
IN BOOLEAN FromVolume)
IN BOOLEAN ManuallyRegistered)
{
WCHAR Letter;
GUID StableGuid;
@ -994,7 +991,7 @@ MountMgrMountedDeviceArrival(IN PDEVICE_EXTENSION DeviceExtension,
/* Copy symbolic name */
RtlCopyMemory(DeviceInformation->SymbolicName.Buffer, SymbolicName->Buffer, SymbolicName->Length);
DeviceInformation->SymbolicName.Buffer[DeviceInformation->SymbolicName.Length / sizeof(WCHAR)] = UNICODE_NULL;
DeviceInformation->Volume = FromVolume;
DeviceInformation->ManuallyRegistered = ManuallyRegistered;
DeviceInformation->DeviceExtension = DeviceExtension;
/* Query as much data as possible about device */
@ -1376,8 +1373,8 @@ MountMgrMountedDeviceArrival(IN PDEVICE_EXTENSION DeviceExtension,
}
}
/* If required, register for notifications about the device */
if (!FromVolume)
/* If that's a PnP device, register for notifications */
if (!ManuallyRegistered)
{
RegisterForTargetDeviceNotification(DeviceExtension, DeviceInformation);
}

View file

@ -379,8 +379,9 @@ MountMgrNotifyNameChange(IN PDEVICE_EXTENSION DeviceExtension,
}
}
/* No need to notify for a PnP device or if we didn't find the device */
if (NextEntry == &(DeviceExtension->DeviceListHead) ||
!DeviceInformation->Volume)
!DeviceInformation->ManuallyRegistered)
{
return;
}

View file

@ -221,7 +221,7 @@ MountMgrCreatePointWorker(IN PDEVICE_EXTENSION DeviceExtension,
FreePool(SymLink.Buffer);
MountMgrNotify(DeviceExtension);
if (!DeviceInformation->Volume)
if (!DeviceInformation->ManuallyRegistered)
{
MountMgrNotifyNameChange(DeviceExtension, DeviceName, FALSE);
}