3 * Copyright (C) 2011-2012 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
19 * COPYRIGHT: See COPYING in the top level directory
20 * PROJECT: ReactOS kernel
21 * FILE: drivers/filesystem/mountmgr/device.c
22 * PURPOSE: Mount Manager - Device Control
23 * PROGRAMMER: Pierre Schweitzer (pierre.schweitzer@reactos.org)
28 #define MAX_DEVICES 0x3E8 /* Matches 1000 devices */
37 MountMgrChangeNotify(IN PDEVICE_EXTENSION DeviceExtension
,
42 PIO_STACK_LOCATION Stack
;
43 PMOUNTMGR_CHANGE_NOTIFY_INFO ChangeNotify
;
45 /* Get the I/O buffer */
46 Stack
= IoGetCurrentIrpStackLocation(Irp
);
47 ChangeNotify
= (PMOUNTMGR_CHANGE_NOTIFY_INFO
)Irp
->AssociatedIrp
.SystemBuffer
;
50 if (Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(MOUNTMGR_CHANGE_NOTIFY_INFO
) ||
51 Stack
->Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(MOUNTMGR_CHANGE_NOTIFY_INFO
))
53 return STATUS_INVALID_PARAMETER
;
56 /* If epic number doesn't match, just return now one */
57 if (DeviceExtension
->EpicNumber
!= ChangeNotify
->EpicNumber
)
59 ChangeNotify
->EpicNumber
= DeviceExtension
->EpicNumber
;
60 Irp
->IoStatus
.Information
= sizeof(MOUNTMGR_CHANGE_NOTIFY_INFO
);
61 return STATUS_SUCCESS
;
64 /* If IRP is to be canceled, forget about that */
65 IoAcquireCancelSpinLock(&OldIrql
);
68 Status
= STATUS_CANCELLED
;
70 /* Otherwise queue the IRP to be notified with the next epic number change */
73 InsertTailList(&(DeviceExtension
->IrpListHead
), &(Irp
->Tail
.Overlay
.ListEntry
));
74 IoMarkIrpPending(Irp
);
75 IoSetCancelRoutine(Irp
, MountMgrCancel
);
76 Status
= STATUS_PENDING
;
78 IoReleaseCancelSpinLock(OldIrql
);
87 MountmgrWriteNoAutoMount(IN PDEVICE_EXTENSION DeviceExtension
)
89 ULONG Value
= DeviceExtension
->NoAutoMount
;
91 return RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE
,
92 DeviceExtension
->RegistryPath
.Buffer
,
104 MountMgrSetAutoMount(IN PDEVICE_EXTENSION DeviceExtension
,
107 PIO_STACK_LOCATION Stack
;
108 PMOUNTMGR_SET_AUTO_MOUNT SetState
;
110 Stack
= IoGetCurrentIrpStackLocation(Irp
);
112 if (Stack
->Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(MOUNTMGR_SET_AUTO_MOUNT
))
114 Irp
->IoStatus
.Information
= 0;
115 return STATUS_INVALID_PARAMETER
;
118 /* Only change if there's a real difference */
119 SetState
= (PMOUNTMGR_SET_AUTO_MOUNT
)Irp
->AssociatedIrp
.SystemBuffer
;
120 if (SetState
->NewState
== !DeviceExtension
->NoAutoMount
)
122 Irp
->IoStatus
.Information
= 0;
123 return STATUS_SUCCESS
;
126 /* Set new state; ! on purpose */
127 DeviceExtension
->NoAutoMount
= !SetState
->NewState
;
128 Irp
->IoStatus
.Information
= 0;
129 return MountmgrWriteNoAutoMount(DeviceExtension
);
136 MountMgrQueryAutoMount(IN PDEVICE_EXTENSION DeviceExtension
,
139 PIO_STACK_LOCATION Stack
;
140 PMOUNTMGR_QUERY_AUTO_MOUNT QueryState
;
142 Stack
= IoGetCurrentIrpStackLocation(Irp
);
144 if (Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(MOUNTMGR_QUERY_AUTO_MOUNT
))
146 Irp
->IoStatus
.Information
= 0;
147 return STATUS_INVALID_PARAMETER
;
150 QueryState
= (PMOUNTMGR_QUERY_AUTO_MOUNT
)Irp
->AssociatedIrp
.SystemBuffer
;
151 QueryState
->CurrentState
= !DeviceExtension
->NoAutoMount
;
152 Irp
->IoStatus
.Information
= sizeof(MOUNTMGR_QUERY_AUTO_MOUNT
);
154 return STATUS_SUCCESS
;
162 ScrubRegistryRoutine(IN PWSTR ValueName
,
165 IN ULONG ValueLength
,
167 IN PVOID EntryContext
)
170 PLIST_ENTRY NextEntry
;
171 PDEVICE_INFORMATION DeviceInfo
;
172 PBOOLEAN Continue
= EntryContext
;
173 PDEVICE_EXTENSION DeviceExtension
= Context
;
175 if (ValueType
!= REG_BINARY
)
177 return STATUS_SUCCESS
;
180 /* Delete values for devices that don't have the matching unique ID */
181 if (!IsListEmpty(&(DeviceExtension
->DeviceListHead
)))
183 for (NextEntry
= DeviceExtension
->DeviceListHead
.Flink
;
184 NextEntry
!= &(DeviceExtension
->DeviceListHead
);
185 NextEntry
= NextEntry
->Flink
)
187 DeviceInfo
= CONTAINING_RECORD(NextEntry
,
191 if (!DeviceInfo
->UniqueId
|| DeviceInfo
->UniqueId
->UniqueIdLength
!= ValueLength
)
196 if (RtlCompareMemory(DeviceInfo
->UniqueId
->UniqueId
, ValueData
, ValueLength
) == ValueLength
)
198 return STATUS_SUCCESS
;
203 /* Wrong unique ID, scrub it */
204 Status
= RtlDeleteRegistryValue(RTL_REGISTRY_ABSOLUTE
,
207 if (!NT_SUCCESS(Status
))
210 return STATUS_UNSUCCESSFUL
;
221 MountMgrScrubRegistry(IN PDEVICE_EXTENSION DeviceExtension
)
225 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
229 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
230 QueryTable
[0].QueryRoutine
= ScrubRegistryRoutine
;
231 QueryTable
[0].EntryContext
= &Continue
;
234 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
249 MountMgrCreatePoint(IN PDEVICE_EXTENSION DeviceExtension
,
253 PIO_STACK_LOCATION Stack
;
254 PMOUNTMGR_CREATE_POINT_INPUT Point
;
255 UNICODE_STRING DeviceName
, SymbolicName
;
257 Stack
= IoGetCurrentIrpStackLocation(Irp
);
259 if (Stack
->Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(MOUNTMGR_CREATE_POINT_INPUT
))
261 return STATUS_INVALID_PARAMETER
;
264 Point
= (PMOUNTMGR_CREATE_POINT_INPUT
)Irp
->AssociatedIrp
.SystemBuffer
;
266 MaxLength
= MAX((Point
->DeviceNameOffset
+ Point
->DeviceNameLength
),
267 (Point
->SymbolicLinkNameLength
+ Point
->SymbolicLinkNameOffset
));
268 if (MaxLength
> Stack
->Parameters
.DeviceIoControl
.InputBufferLength
)
270 return STATUS_INVALID_PARAMETER
;
273 /* Get all the strings and call the worker */
274 SymbolicName
.Length
= Point
->SymbolicLinkNameLength
;
275 SymbolicName
.MaximumLength
= Point
->SymbolicLinkNameLength
;
276 DeviceName
.Length
= Point
->DeviceNameLength
;
277 DeviceName
.MaximumLength
= Point
->DeviceNameLength
;
278 SymbolicName
.Buffer
= (PVOID
)((ULONG_PTR
)Point
+ Point
->SymbolicLinkNameOffset
);
279 DeviceName
.Buffer
= (PVOID
)((ULONG_PTR
)Point
+ Point
->DeviceNameOffset
);
281 return MountMgrCreatePointWorker(DeviceExtension
, &SymbolicName
, &DeviceName
);
288 MountMgrCheckUnprocessedVolumes(IN PDEVICE_EXTENSION DeviceExtension
,
291 PLIST_ENTRY NextEntry
;
292 PDEVICE_INFORMATION DeviceInformation
;
293 NTSTATUS ArrivalStatus
, Status
= STATUS_SUCCESS
;
295 UNREFERENCED_PARAMETER(Irp
);
297 /* No offline volumes, nothing more to do */
298 if (IsListEmpty(&(DeviceExtension
->OfflineDeviceListHead
)))
300 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
, 1, FALSE
);
301 return STATUS_SUCCESS
;
304 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
, 1, FALSE
);
306 /* Reactivate all the offline volumes */
307 while (!IsListEmpty(&(DeviceExtension
->OfflineDeviceListHead
)))
309 NextEntry
= RemoveHeadList(&(DeviceExtension
->OfflineDeviceListHead
));
310 DeviceInformation
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
312 ArrivalStatus
= MountMgrMountedDeviceArrival(DeviceExtension
,
313 &(DeviceInformation
->SymbolicName
),
314 DeviceInformation
->ManuallyRegistered
);
315 /* Then, remove them dead information */
316 MountMgrFreeDeadDeviceInfo(DeviceInformation
);
318 if (NT_SUCCESS(Status
))
320 Status
= ArrivalStatus
;
331 IsFtVolume(IN PUNICODE_STRING SymbolicName
)
336 PFILE_OBJECT FileObject
;
337 IO_STATUS_BLOCK IoStatusBlock
;
338 PARTITION_INFORMATION PartitionInfo
;
339 PDEVICE_OBJECT DeviceObject
, FileDeviceObject
;
341 /* Get device object */
342 Status
= IoGetDeviceObjectPointer(SymbolicName
,
343 FILE_READ_ATTRIBUTES
,
346 if (!NT_SUCCESS(Status
))
351 /* Get attached device */
352 FileDeviceObject
= FileObject
->DeviceObject
;
353 DeviceObject
= IoGetAttachedDeviceReference(FileDeviceObject
);
355 /* FT volume can't be removable */
356 if (FileDeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
)
358 ObDereferenceObject(DeviceObject
);
359 ObDereferenceObject(FileObject
);
363 ObDereferenceObject(FileObject
);
365 /* Get partition information */
366 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
367 Irp
= IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_PARTITION_INFO
,
372 sizeof(PartitionInfo
),
378 ObDereferenceObject(DeviceObject
);
382 Status
= IoCallDriver(DeviceObject
, Irp
);
383 if (Status
== STATUS_PENDING
)
385 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
386 Status
= IoStatusBlock
.Status
;
389 ObDereferenceObject(DeviceObject
);
390 if (!NT_SUCCESS(Status
))
395 /* Check if this is a FT volume */
396 return IsFTPartition(PartitionInfo
.PartitionType
);
403 ProcessSuggestedDriveLetters(IN PDEVICE_EXTENSION DeviceExtension
)
405 WCHAR NameBuffer
[DRIVE_LETTER_LENGTH
/ sizeof(WCHAR
)];
406 PLIST_ENTRY NextEntry
;
407 UNICODE_STRING SymbolicName
;
408 PDEVICE_INFORMATION DeviceInformation
;
410 /* No devices? Nothing to do! */
411 if (IsListEmpty(&(DeviceExtension
->DeviceListHead
)))
416 /* For all the devices */
417 for (NextEntry
= DeviceExtension
->DeviceListHead
.Flink
;
418 NextEntry
!= &(DeviceExtension
->DeviceListHead
);
419 NextEntry
= NextEntry
->Flink
)
421 DeviceInformation
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
423 /* If no drive letter */
424 if (DeviceInformation
->SuggestedDriveLetter
== (UCHAR
)-1)
426 /* Ensure it has no entry yet */
427 if (!HasDriveLetter(DeviceInformation
) &&
428 !HasNoDriveLetterEntry(DeviceInformation
->UniqueId
))
431 CreateNoDriveLetterEntry(DeviceInformation
->UniqueId
);
434 DeviceInformation
->SuggestedDriveLetter
= 0;
436 /* Suggested letter & no entry */
437 else if (DeviceInformation
->SuggestedDriveLetter
&&
438 !HasNoDriveLetterEntry(DeviceInformation
->UniqueId
))
440 /* Just create a mount point */
441 SymbolicName
.Buffer
= NameBuffer
;
442 RtlCopyMemory(NameBuffer
, DosDevices
.Buffer
, DosDevices
.Length
);
443 NameBuffer
[LETTER_POSITION
] = DeviceInformation
->SuggestedDriveLetter
;
444 NameBuffer
[COLON_POSITION
] = L
':';
445 SymbolicName
.Length
=
446 SymbolicName
.MaximumLength
= DRIVE_LETTER_LENGTH
;
448 MountMgrCreatePointWorker(DeviceExtension
, &SymbolicName
, &(DeviceInformation
->DeviceName
));
457 MountMgrNextDriveLetterWorker(IN PDEVICE_EXTENSION DeviceExtension
,
458 IN PUNICODE_STRING DeviceName
,
459 OUT PMOUNTMGR_DRIVE_LETTER_INFORMATION DriveLetterInfo
)
463 PLIST_ENTRY NextEntry
;
464 PMOUNTDEV_UNIQUE_ID UniqueId
;
465 BOOLEAN Removable
, GptDriveLetter
;
466 PDEVICE_INFORMATION DeviceInformation
;
467 WCHAR NameBuffer
[DRIVE_LETTER_LENGTH
];
468 PSYMLINK_INFORMATION SymlinkInformation
;
469 UNICODE_STRING TargetDeviceName
, SymbolicName
;
471 /* First, process suggested letters */
472 if (!DeviceExtension
->ProcessedSuggestions
)
474 ProcessSuggestedDriveLetters(DeviceExtension
);
475 DeviceExtension
->ProcessedSuggestions
= TRUE
;
478 /* Then, get information about the device */
479 Status
= QueryDeviceInformation(DeviceName
, &TargetDeviceName
, NULL
, &Removable
, &GptDriveLetter
, NULL
, NULL
, NULL
);
480 if (!NT_SUCCESS(Status
))
485 /* Ensure we have such device */
486 NextEntry
= DeviceExtension
->DeviceListHead
.Flink
;
487 while (NextEntry
!= &(DeviceExtension
->DeviceListHead
))
489 DeviceInformation
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
491 if (RtlCompareUnicodeString(&(DeviceInformation
->DeviceName
), &TargetDeviceName
, TRUE
) == 0)
496 NextEntry
= NextEntry
->Flink
;
499 if (NextEntry
== &(DeviceExtension
->DeviceListHead
))
501 FreePool(TargetDeviceName
.Buffer
);
502 return STATUS_OBJECT_NAME_NOT_FOUND
;
505 /* Now, mark we have assigned a letter (assumption) */
506 DeviceInformation
->LetterAssigned
=
507 DriveLetterInfo
->DriveLetterWasAssigned
= TRUE
;
509 /* Browse all the symlinks to check if there is already a drive letter */
510 NextEntry
= DeviceInformation
->SymbolicLinksListHead
.Flink
;
511 while (NextEntry
!= &(DeviceInformation
->SymbolicLinksListHead
))
513 SymlinkInformation
= CONTAINING_RECORD(NextEntry
, SYMLINK_INFORMATION
, SymbolicLinksListEntry
);
515 /* If this is a drive letter and it is online, forget about new drive letter */
516 if (IsDriveLetter(&(SymlinkInformation
->Name
)) && SymlinkInformation
->Online
)
518 DriveLetterInfo
->DriveLetterWasAssigned
= FALSE
;
519 DriveLetterInfo
->CurrentDriveLetter
= (CHAR
)SymlinkInformation
->Name
.Buffer
[LETTER_POSITION
];
523 NextEntry
= NextEntry
->Flink
;
526 /* If we didn't find a drive letter online
527 * ensure this is not a no drive entry
528 * by querying GPT attributes & database
530 if (NextEntry
== &(DeviceInformation
->SymbolicLinksListHead
))
532 if (!GptDriveLetter
|| HasNoDriveLetterEntry(DeviceInformation
->UniqueId
))
534 DriveLetterInfo
->DriveLetterWasAssigned
= FALSE
;
535 DriveLetterInfo
->CurrentDriveLetter
= 0;
541 /* No, ensure that the device is not automounted nor removable */
542 if (!DeviceExtension
->NoAutoMount
&& !Removable
)
544 if (DriveLetterInfo
->DriveLetterWasAssigned
)
546 DriveLetterInfo
->DriveLetterWasAssigned
= FALSE
;
547 DriveLetterInfo
->CurrentDriveLetter
= 0;
553 if (!DriveLetterInfo
->DriveLetterWasAssigned
)
558 /* Now everything is fine, start processing */
560 if (RtlPrefixUnicodeString(&DeviceFloppy
, &TargetDeviceName
, TRUE
))
562 /* If the device is a floppy, start with letter A */
565 else if (RtlPrefixUnicodeString(&DeviceCdRom
, &TargetDeviceName
, TRUE
))
567 /* If the device is a CD-ROM, start with letter D */
572 /* Finally, if it's a disk, use C */
576 /* We cannot set NO drive letter */
577 ASSERT(DeviceInformation
->SuggestedDriveLetter
!= (UCHAR
)-1);
579 /* If we don't have suggested letter but it's a FT volume, fail */
580 if (!DeviceInformation
->SuggestedDriveLetter
&& IsFtVolume(&(DeviceInformation
->DeviceName
)))
582 DriveLetterInfo
->DriveLetterWasAssigned
= FALSE
;
583 DriveLetterInfo
->CurrentDriveLetter
= 0;
589 RtlCopyMemory(NameBuffer
, DosDevices
.Buffer
, DosDevices
.Length
);
590 NameBuffer
[COLON_POSITION
] = L
':';
591 SymbolicName
.Buffer
= NameBuffer
;
592 SymbolicName
.Length
=
593 SymbolicName
.MaximumLength
= DRIVE_LETTER_LENGTH
;
595 /* It's all prepared, create mount point */
596 if (DeviceInformation
->SuggestedDriveLetter
)
598 DriveLetterInfo
->CurrentDriveLetter
= DeviceInformation
->SuggestedDriveLetter
;
599 NameBuffer
[LETTER_POSITION
] = DeviceInformation
->SuggestedDriveLetter
;
601 Status
= MountMgrCreatePointWorker(DeviceExtension
, &SymbolicName
, &TargetDeviceName
);
602 if (NT_SUCCESS(Status
))
608 /* It failed with this letter... Try another one! */
609 for (DriveLetterInfo
->CurrentDriveLetter
= DriveLetter
;
610 DriveLetterInfo
->CurrentDriveLetter
<= L
'Z';
611 DriveLetterInfo
->CurrentDriveLetter
++)
613 NameBuffer
[LETTER_POSITION
] = DriveLetterInfo
->CurrentDriveLetter
;
615 Status
= MountMgrCreatePointWorker(DeviceExtension
, &SymbolicName
, &TargetDeviceName
);
616 if (NT_SUCCESS(Status
))
622 /* We failed setting a letter */
623 if (DriveLetterInfo
->CurrentDriveLetter
> L
'Z')
625 DriveLetterInfo
->DriveLetterWasAssigned
= FALSE
;
626 DriveLetterInfo
->CurrentDriveLetter
= 0;
628 /* Try at least to add a no drive letter entry */
629 Status
= QueryDeviceInformation(&TargetDeviceName
, NULL
, &UniqueId
, NULL
, NULL
, NULL
, NULL
, NULL
);
630 if (NT_SUCCESS(Status
))
632 CreateNoDriveLetterEntry(UniqueId
);
638 FreePool(TargetDeviceName
.Buffer
);
640 return STATUS_SUCCESS
;
648 MountMgrNextDriveLetter(IN PDEVICE_EXTENSION DeviceExtension
,
652 PIO_STACK_LOCATION Stack
;
653 UNICODE_STRING DeviceName
;
654 PMOUNTMGR_DRIVE_LETTER_TARGET DriveLetterTarget
;
655 MOUNTMGR_DRIVE_LETTER_INFORMATION DriveLetterInformation
;
657 Stack
= IoGetCurrentIrpStackLocation(Irp
);
660 if (Stack
->Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(MOUNTMGR_DRIVE_LETTER_TARGET
) ||
661 Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(MOUNTMGR_DRIVE_LETTER_INFORMATION
))
663 return STATUS_INVALID_PARAMETER
;
666 DriveLetterTarget
= (PMOUNTMGR_DRIVE_LETTER_TARGET
)Irp
->AssociatedIrp
.SystemBuffer
;
667 if (DriveLetterTarget
->DeviceNameLength
+ sizeof(USHORT
) > Stack
->Parameters
.DeviceIoControl
.InputBufferLength
)
669 return STATUS_INVALID_PARAMETER
;
672 /* Call the worker */
673 DeviceName
.Buffer
= DriveLetterTarget
->DeviceName
;
675 DeviceName
.MaximumLength
= DriveLetterTarget
->DeviceNameLength
;
677 Status
= MountMgrNextDriveLetterWorker(DeviceExtension
, &DeviceName
,
678 &DriveLetterInformation
);
679 if (NT_SUCCESS(Status
))
681 *(PMOUNTMGR_DRIVE_LETTER_INFORMATION
)Irp
->AssociatedIrp
.SystemBuffer
=
682 DriveLetterInformation
;
683 Irp
->IoStatus
.Information
= sizeof(MOUNTMGR_DRIVE_LETTER_INFORMATION
);
694 MountMgrQuerySystemVolumeNameQueryRoutine(IN PWSTR ValueName
,
697 IN ULONG ValueLength
,
699 IN PVOID EntryContext
)
701 UNICODE_STRING ValueString
;
702 PUNICODE_STRING SystemVolumeName
;
704 UNREFERENCED_PARAMETER(ValueName
);
705 UNREFERENCED_PARAMETER(ValueLength
);
706 UNREFERENCED_PARAMETER(EntryContext
);
708 if (ValueType
!= REG_SZ
)
710 return STATUS_SUCCESS
;
713 RtlInitUnicodeString(&ValueString
, ValueData
);
714 SystemVolumeName
= Context
;
716 /* Return a string containing system volume name */
717 SystemVolumeName
->Length
= ValueString
.Length
;
718 SystemVolumeName
->MaximumLength
= ValueString
.Length
+ sizeof(WCHAR
);
719 SystemVolumeName
->Buffer
= AllocatePool(SystemVolumeName
->MaximumLength
);
720 if (SystemVolumeName
->Buffer
)
722 RtlCopyMemory(SystemVolumeName
->Buffer
, ValueData
, ValueString
.Length
);
723 SystemVolumeName
->Buffer
[ValueString
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
726 return STATUS_SUCCESS
;
734 MountMgrQuerySystemVolumeName(OUT PUNICODE_STRING SystemVolumeName
)
736 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
738 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
739 QueryTable
[0].QueryRoutine
= MountMgrQuerySystemVolumeNameQueryRoutine
;
740 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_REQUIRED
;
741 QueryTable
[0].Name
= L
"SystemPartition";
743 SystemVolumeName
->Buffer
= NULL
;
745 RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
746 L
"\\Registry\\Machine\\System\\Setup",
751 if (SystemVolumeName
->Buffer
)
753 return STATUS_SUCCESS
;
756 return STATUS_UNSUCCESSFUL
;
763 MountMgrAssignDriveLetters(IN PDEVICE_EXTENSION DeviceExtension
)
766 PLIST_ENTRY NextEntry
;
767 UNICODE_STRING SystemVolumeName
;
768 PDEVICE_INFORMATION DeviceInformation
;
769 MOUNTMGR_DRIVE_LETTER_INFORMATION DriveLetterInformation
;
771 /* First, get system volume name */
772 Status
= MountMgrQuerySystemVolumeName(&SystemVolumeName
);
774 /* If there are no device, it's all done */
775 if (IsListEmpty(&(DeviceExtension
->DeviceListHead
)))
777 if (NT_SUCCESS(Status
))
779 FreePool(SystemVolumeName
.Buffer
);
785 /* Now, for all the devices... */
786 for (NextEntry
= DeviceExtension
->DeviceListHead
.Flink
;
787 NextEntry
!= &(DeviceExtension
->DeviceListHead
);
788 NextEntry
= NextEntry
->Flink
)
790 DeviceInformation
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
792 /* If the device doesn't have a letter assigned, do it! */
793 if (!DeviceInformation
->LetterAssigned
)
795 MountMgrNextDriveLetterWorker(DeviceExtension
,
796 &(DeviceInformation
->DeviceName
),
797 &DriveLetterInformation
);
800 /* If it was the system volume */
801 if (NT_SUCCESS(Status
) && RtlEqualUnicodeString(&SystemVolumeName
, &(DeviceInformation
->DeviceName
), TRUE
))
803 /* Keep track of it */
804 DeviceExtension
->DriveLetterData
= AllocatePool(DeviceInformation
->UniqueId
->UniqueIdLength
+
805 sizeof(MOUNTDEV_UNIQUE_ID
));
806 if (DeviceExtension
->DriveLetterData
)
808 RtlCopyMemory(DeviceExtension
->DriveLetterData
,
809 DeviceInformation
->UniqueId
,
810 DeviceInformation
->UniqueId
->UniqueIdLength
+ sizeof(MOUNTDEV_UNIQUE_ID
));
813 /* If it was not automount, ensure it gets mounted */
814 if (!DeviceExtension
->NoAutoMount
)
816 DeviceExtension
->NoAutoMount
= TRUE
;
818 MountMgrNextDriveLetterWorker(DeviceExtension
,
819 &(DeviceInformation
->DeviceName
),
820 &DriveLetterInformation
);
822 DeviceExtension
->NoAutoMount
= FALSE
;
827 if (NT_SUCCESS(Status
))
829 FreePool(SystemVolumeName
.Buffer
);
837 MountMgrQueryDosVolumePath(IN PDEVICE_EXTENSION DeviceExtension
,
842 PIO_STACK_LOCATION Stack
;
843 PLIST_ENTRY SymlinksEntry
;
844 UNICODE_STRING SymbolicName
;
845 PMOUNTMGR_TARGET_NAME Target
;
846 PWSTR DeviceString
, OldBuffer
;
847 USHORT DeviceLength
, OldLength
;
848 PDEVICE_INFORMATION DeviceInformation
;
849 PSYMLINK_INFORMATION SymlinkInformation
;
850 PASSOCIATED_DEVICE_ENTRY AssociatedDevice
;
852 Stack
= IoGetCurrentIrpStackLocation(Irp
);
854 /* Validate input size */
855 if (Stack
->Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(MOUNTMGR_TARGET_NAME
))
857 return STATUS_INVALID_PARAMETER
;
860 /* Ensure we have received UNICODE_STRING */
861 Target
= (PMOUNTMGR_TARGET_NAME
)Irp
->AssociatedIrp
.SystemBuffer
;
862 if (Target
->DeviceNameLength
& 1)
864 return STATUS_INVALID_PARAMETER
;
867 /* Validate the entry structure size */
868 if (Target
->DeviceNameLength
+ sizeof(UNICODE_NULL
) > Stack
->Parameters
.DeviceIoControl
.InputBufferLength
)
870 return STATUS_INVALID_PARAMETER
;
873 /* Ensure we can at least return needed size */
874 if (Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(ULONG
))
876 return STATUS_INVALID_PARAMETER
;
879 /* Construct string for query */
880 SymbolicName
.Length
= Target
->DeviceNameLength
;
881 SymbolicName
.MaximumLength
= Target
->DeviceNameLength
+ sizeof(UNICODE_NULL
);
882 SymbolicName
.Buffer
= Target
->DeviceName
;
884 /* Find device with our info */
885 Status
= FindDeviceInfo(DeviceExtension
, &SymbolicName
, FALSE
, &DeviceInformation
);
886 if (!NT_SUCCESS(Status
))
895 /* Try to find associated device info */
898 for (SymlinksEntry
= DeviceInformation
->SymbolicLinksListHead
.Flink
;
899 SymlinksEntry
!= &(DeviceInformation
->SymbolicLinksListHead
);
900 SymlinksEntry
= SymlinksEntry
->Flink
)
902 SymlinkInformation
= CONTAINING_RECORD(SymlinksEntry
, SYMLINK_INFORMATION
, SymbolicLinksListEntry
);
904 /* Try to find with drive letter */
905 if (MOUNTMGR_IS_DRIVE_LETTER(&SymlinkInformation
->Name
) && SymlinkInformation
->Online
)
911 /* We didn't find, break */
912 if (SymlinksEntry
== &(DeviceInformation
->SymbolicLinksListHead
))
917 /* It doesn't have associated device, go to fallback method */
918 if (IsListEmpty(&DeviceInformation
->AssociatedDevicesHead
))
920 goto TryWithVolumeName
;
923 /* Create a string with the information about the device */
924 AssociatedDevice
= CONTAINING_RECORD(&(DeviceInformation
->SymbolicLinksListHead
), ASSOCIATED_DEVICE_ENTRY
, AssociatedDevicesEntry
);
925 OldLength
= DeviceLength
;
926 OldBuffer
= DeviceString
;
927 DeviceLength
+= AssociatedDevice
->String
.Length
;
928 DeviceString
= AllocatePool(DeviceLength
);
936 return STATUS_INSUFFICIENT_RESOURCES
;
939 /* Store our info and previous if any */
940 RtlCopyMemory(DeviceString
, AssociatedDevice
->String
.Buffer
, AssociatedDevice
->String
.Length
);
943 RtlCopyMemory(&DeviceString
[AssociatedDevice
->String
.Length
/ sizeof(WCHAR
)], OldBuffer
, OldLength
);
947 /* Count and continue looking */
949 DeviceInformation
= AssociatedDevice
->DeviceInformation
;
951 /* If too many devices, try another way */
952 if (DevicesFound
> MAX_DEVICES
) /* 1000 */
954 goto TryWithVolumeName
;
958 /* Reallocate our string, so that we can prepend disk letter */
959 OldBuffer
= DeviceString
;
960 OldLength
= DeviceLength
;
961 DeviceLength
+= 2 * sizeof(WCHAR
);
962 DeviceString
= AllocatePool(DeviceLength
);
970 return STATUS_INSUFFICIENT_RESOURCES
;
974 DeviceString
[0] = SymlinkInformation
->Name
.Buffer
[LETTER_POSITION
];
975 DeviceString
[1] = L
':';
977 /* And copy the rest */
980 RtlCopyMemory(&DeviceString
[2], OldBuffer
, OldLength
);
985 /* If we didn't find anything, try differently */
986 if (DeviceLength
< 2 * sizeof(WCHAR
) || DeviceString
[1] != L
':')
990 FreePool(DeviceString
);
994 /* Try to find a volume name matching */
995 for (SymlinksEntry
= DeviceInformation
->SymbolicLinksListHead
.Flink
;
996 SymlinksEntry
!= &(DeviceInformation
->SymbolicLinksListHead
);
997 SymlinksEntry
= SymlinksEntry
->Flink
)
999 SymlinkInformation
= CONTAINING_RECORD(SymlinksEntry
, SYMLINK_INFORMATION
, SymbolicLinksListEntry
);
1001 if (MOUNTMGR_IS_VOLUME_NAME(&SymlinkInformation
->Name
))
1008 if (SymlinksEntry
!= &(DeviceInformation
->SymbolicLinksListHead
))
1010 DeviceLength
= SymlinkInformation
->Name
.Length
;
1011 DeviceString
= AllocatePool(DeviceLength
);
1014 return STATUS_INSUFFICIENT_RESOURCES
;
1017 RtlCopyMemory(DeviceString
, SymlinkInformation
->Name
.Buffer
, DeviceLength
);
1018 /* Ensure we are in the right namespace; [1] can be ? */
1019 DeviceString
[1] = L
'\\';
1023 /* If we found something */
1026 /* At least, we will return our length */
1027 ((PMOUNTMGR_VOLUME_PATHS
)Irp
->AssociatedIrp
.SystemBuffer
)->MultiSzLength
= DeviceLength
;
1028 /* MOUNTMGR_VOLUME_PATHS is a string + a ULONG */
1029 Irp
->IoStatus
.Information
= DeviceLength
+ sizeof(ULONG
);
1031 /* If we have enough room for copying the string */
1032 if (sizeof(ULONG
) + DeviceLength
<= Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
)
1037 RtlCopyMemory(((PMOUNTMGR_VOLUME_PATHS
)Irp
->AssociatedIrp
.SystemBuffer
)->MultiSz
, DeviceString
, DeviceLength
);
1040 /* And double zero at its end - this is needed in case of multiple paths which are separated by a single 0 */
1041 FreePool(DeviceString
);
1042 ((PMOUNTMGR_VOLUME_PATHS
)Irp
->AssociatedIrp
.SystemBuffer
)->MultiSz
[DeviceLength
/ sizeof(WCHAR
)] = 0;
1043 ((PMOUNTMGR_VOLUME_PATHS
)Irp
->AssociatedIrp
.SystemBuffer
)->MultiSz
[DeviceLength
/ sizeof(WCHAR
) + 1] = 0;
1045 return STATUS_SUCCESS
;
1049 /* Just return appropriate size and leave */
1050 FreePool(DeviceString
);
1051 Irp
->IoStatus
.Information
= sizeof(ULONG
);
1052 return STATUS_BUFFER_OVERFLOW
;
1057 return STATUS_NOT_FOUND
;
1064 MountMgrValidateBackPointer(IN PASSOCIATED_DEVICE_ENTRY AssociatedDeviceEntry
,
1065 IN PDEVICE_INFORMATION DeviceInformation
,
1066 OUT PBOOLEAN Invalid
)
1070 PLIST_ENTRY SymlinksEntry
;
1071 IO_STATUS_BLOCK IoStatusBlock
;
1072 PREPARSE_DATA_BUFFER ReparseData
;
1073 OBJECT_ATTRIBUTES ObjectAttributes
;
1074 UNICODE_STRING FullName
, SubstituteName
;
1075 PSYMLINK_INFORMATION SymlinkInformation
;
1077 /* Initialize & allocate a string big enough to contain our complete mount point name */
1078 FullName
.Length
= AssociatedDeviceEntry
->String
.Length
+ AssociatedDeviceEntry
->DeviceInformation
->DeviceName
.Length
+ sizeof(WCHAR
);
1079 FullName
.MaximumLength
= FullName
.Length
+ sizeof(UNICODE_NULL
);
1080 FullName
.Buffer
= AllocatePool(FullName
.MaximumLength
);
1081 if (!FullName
.Buffer
)
1083 return STATUS_INSUFFICIENT_RESOURCES
;
1086 /* Create the path */
1087 RtlCopyMemory(FullName
.Buffer
, AssociatedDeviceEntry
->DeviceInformation
->DeviceName
.Buffer
, AssociatedDeviceEntry
->DeviceInformation
->DeviceName
.Length
);
1088 FullName
.Buffer
[AssociatedDeviceEntry
->DeviceInformation
->DeviceName
.Length
/ sizeof(WCHAR
)] = L
'\\';
1089 RtlCopyMemory(&FullName
.Buffer
[AssociatedDeviceEntry
->DeviceInformation
->DeviceName
.Length
/ sizeof(WCHAR
) + 1], AssociatedDeviceEntry
->String
.Buffer
, AssociatedDeviceEntry
->String
.Length
);
1090 FullName
.Buffer
[FullName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1092 /* Open it to query the reparse point */
1093 InitializeObjectAttributes(&ObjectAttributes
,
1095 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
1098 Status
= ZwOpenFile(&Handle
,
1099 SYNCHRONIZE
| FILE_READ_ATTRIBUTES
,
1100 &ObjectAttributes
, &IoStatusBlock
,
1101 FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
,
1102 FILE_SYNCHRONOUS_IO_NONALERT
| FILE_OPEN_REPARSE_POINT
);
1103 FreePool(FullName
.Buffer
);
1105 if (!NT_SUCCESS(Status
))
1108 return STATUS_SUCCESS
;
1111 /* Allocate a buffer big enough to read reparse data */
1112 ReparseData
= AllocatePool(MAXIMUM_REPARSE_DATA_BUFFER_SIZE
);
1113 if (ReparseData
== NULL
)
1116 return STATUS_INSUFFICIENT_RESOURCES
;
1119 /* Query reparse data */
1120 Status
= ZwFsControlFile(Handle
,
1123 FSCTL_GET_REPARSE_POINT
,
1125 ReparseData
, MAXIMUM_REPARSE_DATA_BUFFER_SIZE
);
1128 if (!NT_SUCCESS(Status
))
1130 FreePool(ReparseData
);
1132 return STATUS_SUCCESS
;
1135 /* Create a string with the substitute name */
1136 SubstituteName
.Length
= ReparseData
->SymbolicLinkReparseBuffer
.SubstituteNameLength
;
1137 SubstituteName
.MaximumLength
= SubstituteName
.Length
;
1138 SubstituteName
.Buffer
= (PWSTR
)((ULONG_PTR
)ReparseData
->SymbolicLinkReparseBuffer
.PathBuffer
+ ReparseData
->SymbolicLinkReparseBuffer
.SubstituteNameOffset
);
1140 /* If that's a volume name that matches our associated device, that's a success! */
1141 if (MOUNTMGR_IS_VOLUME_NAME(&SubstituteName
))
1143 if (SubstituteName
.Length
== 98 && SubstituteName
.Buffer
[1] == L
'?')
1145 for (SymlinksEntry
= DeviceInformation
->SymbolicLinksListHead
.Flink
;
1146 SymlinksEntry
!= &(DeviceInformation
->SymbolicLinksListHead
);
1147 SymlinksEntry
= SymlinksEntry
->Flink
)
1149 SymlinkInformation
= CONTAINING_RECORD(SymlinksEntry
, SYMLINK_INFORMATION
, SymbolicLinksListEntry
);
1151 if (RtlEqualUnicodeString(&SubstituteName
, &SymlinkInformation
->Name
, TRUE
))
1153 FreePool(ReparseData
);
1154 return STATUS_SUCCESS
;
1160 FreePool(ReparseData
);
1162 return STATUS_SUCCESS
;
1169 MountMgrQueryVolumePaths(IN PDEVICE_EXTENSION DeviceExtension
,
1170 IN PDEVICE_INFORMATION DeviceInformation
,
1171 IN PLIST_ENTRY DeviceInfoList
,
1172 OUT PMOUNTMGR_VOLUME_PATHS
* VolumePaths
,
1173 OUT PDEVICE_INFORMATION
*FailedDevice
)
1178 PSYMLINK_INFORMATION SymlinkInformation
;
1179 PDEVICE_INFORMATION_ENTRY DeviceInfoEntry
;
1180 PASSOCIATED_DEVICE_ENTRY AssociatedDeviceEntry
;
1181 PMOUNTMGR_VOLUME_PATHS
* Paths
= NULL
, * CurrentPath
;
1182 ULONG OutputPathLength
, NumberOfPaths
, ReturnedPaths
;
1184 /* We return at least null char */
1185 OutputPathLength
= sizeof(UNICODE_NULL
);
1187 for (Entry
= DeviceInformation
->SymbolicLinksListHead
.Flink
;
1188 Entry
!= &(DeviceInformation
->SymbolicLinksListHead
);
1189 Entry
= Entry
->Flink
)
1191 SymlinkInformation
= CONTAINING_RECORD(Entry
, SYMLINK_INFORMATION
, SymbolicLinksListEntry
);
1193 /* Try to find the drive letter (ie, DOS device) */
1194 if (MOUNTMGR_IS_DRIVE_LETTER(&SymlinkInformation
->Name
) && SymlinkInformation
->Online
)
1196 /* We'll return the letter */
1197 OutputPathLength
= 4 * sizeof(WCHAR
);
1202 /* We didn't find any */
1203 if (Entry
== &(DeviceInformation
->SymbolicLinksListHead
))
1205 SymlinkInformation
= NULL
;
1208 /* Do we have any device info to return? */
1209 for (Entry
= DeviceInfoList
->Flink
; Entry
!= DeviceInfoList
; Entry
= Entry
->Flink
)
1211 DeviceInfoEntry
= CONTAINING_RECORD(Entry
, DEVICE_INFORMATION_ENTRY
, DeviceInformationEntry
);
1213 /* Matching current device */
1214 if (DeviceInfoEntry
->DeviceInformation
== DeviceInformation
)
1216 /* Allocate the output buffer */
1217 *VolumePaths
= AllocatePool(sizeof(ULONG
) + OutputPathLength
);
1218 if (*VolumePaths
== NULL
)
1220 return STATUS_INSUFFICIENT_RESOURCES
;
1224 (*VolumePaths
)->MultiSzLength
= OutputPathLength
;
1225 /* If we have a drive letter, return it */
1226 if (SymlinkInformation
!= NULL
)
1228 (*VolumePaths
)->MultiSz
[0] = SymlinkInformation
->Name
.Buffer
[LETTER_POSITION
];
1229 (*VolumePaths
)->MultiSz
[1] = L
':';
1230 (*VolumePaths
)->MultiSz
[2] = UNICODE_NULL
;
1231 (*VolumePaths
)->MultiSz
[3] = UNICODE_NULL
;
1235 (*VolumePaths
)->MultiSz
[0] = UNICODE_NULL
;
1238 return STATUS_SUCCESS
;
1242 /* Allocate a new device entry */
1243 DeviceInfoEntry
= AllocatePool(sizeof(DEVICE_INFORMATION_ENTRY
));
1244 if (DeviceInfoEntry
== NULL
)
1246 return STATUS_INSUFFICIENT_RESOURCES
;
1249 /* Add it to the list */
1250 DeviceInfoEntry
->DeviceInformation
= DeviceInformation
;
1251 InsertTailList(DeviceInfoList
, &DeviceInfoEntry
->DeviceInformationEntry
);
1254 /* Count the amount of devices we will have to handle */
1255 if (!IsListEmpty(&DeviceInformation
->AssociatedDevicesHead
))
1257 for (Entry
= DeviceInformation
->AssociatedDevicesHead
.Flink
;
1258 Entry
!= &DeviceInformation
->AssociatedDevicesHead
;
1259 Entry
= Entry
->Flink
)
1264 ASSERT(NumberOfPaths
!= 0);
1265 /* And allocate a big enough buffer */
1266 Paths
= AllocatePool(NumberOfPaths
* sizeof(PMOUNTMGR_VOLUME_PATHS
));
1269 RemoveEntryList(&DeviceInfoEntry
->DeviceInformationEntry
);
1270 FreePool(DeviceInfoEntry
);
1271 return STATUS_INSUFFICIENT_RESOURCES
;
1275 /* Start the hot loop to gather all the paths and be able to compute total output length! */
1277 CurrentPath
= Paths
;
1278 for (Entry
= DeviceInformation
->AssociatedDevicesHead
.Flink
;
1279 Entry
!= &DeviceInformation
->AssociatedDevicesHead
;
1280 Entry
= Entry
->Flink
)
1282 USHORT InnerStrings
;
1283 BOOLEAN Invalid
= FALSE
;
1285 AssociatedDeviceEntry
= CONTAINING_RECORD(Entry
, ASSOCIATED_DEVICE_ENTRY
, AssociatedDevicesEntry
);
1287 /* Validate the fact its a mount point by query reparse data */
1288 Status
= MountMgrValidateBackPointer(AssociatedDeviceEntry
, DeviceInformation
, &Invalid
);
1290 /* If we found an invalid device, that's a failure */
1293 *FailedDevice
= AssociatedDeviceEntry
->DeviceInformation
;
1294 Status
= STATUS_UNSUCCESSFUL
;
1297 /* Check whether we failed, if so, bail out */
1298 if (!NT_SUCCESS(Status
))
1302 for (i
= 0; i
< ReturnedPaths
; ++i
)
1311 RemoveEntryList(&DeviceInfoEntry
->DeviceInformationEntry
);
1312 FreePool(DeviceInfoEntry
);
1316 /* Query associated paths (hello ourselves :-)) */
1317 Status
= MountMgrQueryVolumePaths(DeviceExtension
,
1318 AssociatedDeviceEntry
->DeviceInformation
,
1322 if (!NT_SUCCESS(Status
))
1326 for (i
= 0; i
< ReturnedPaths
; ++i
)
1335 RemoveEntryList(&DeviceInfoEntry
->DeviceInformationEntry
);
1336 FreePool(DeviceInfoEntry
);
1340 /* Count the number of strings we have in the multi string buffer */
1342 if ((*CurrentPath
)->MultiSzLength
!= sizeof(UNICODE_NULL
))
1345 PWSTR MultiSz
= (*CurrentPath
)->MultiSz
;
1347 for (i
= 0; i
< (*CurrentPath
)->MultiSzLength
/ sizeof(WCHAR
); ++i
, ++MultiSz
)
1349 if (*MultiSz
== UNICODE_NULL
)
1356 /* We returned one more path (ie, one more allocated buffer) */
1358 /* Move the next pointer to use in the array */
1360 /* Multiply String.Length by the number of found paths, we always add it after a path */
1361 OutputPathLength
+= (*CurrentPath
)->MultiSzLength
+ InnerStrings
* AssociatedDeviceEntry
->String
.Length
- sizeof(UNICODE_NULL
);
1364 /* Allocate the output buffer */
1365 *VolumePaths
= AllocatePool(sizeof(ULONG
) + OutputPathLength
);
1366 if (*VolumePaths
== NULL
)
1370 for (i
= 0; i
< ReturnedPaths
; ++i
)
1379 RemoveEntryList(&DeviceInfoEntry
->DeviceInformationEntry
);
1380 FreePool(DeviceInfoEntry
);
1381 return STATUS_INSUFFICIENT_RESOURCES
;
1385 /* If we had found a DOS letter, that's the first thing we return */
1386 (*VolumePaths
)->MultiSzLength
= OutputPathLength
;
1387 if (SymlinkInformation
!= NULL
)
1389 (*VolumePaths
)->MultiSz
[0] = SymlinkInformation
->Name
.Buffer
[LETTER_POSITION
];
1390 (*VolumePaths
)->MultiSz
[1] = L
':';
1391 (*VolumePaths
)->MultiSz
[2] = UNICODE_NULL
;
1395 /* Now, browse again all our paths to return them */
1396 CurrentPath
= Paths
;
1397 for (Entry
= DeviceInformation
->AssociatedDevicesHead
.Flink
;
1398 Entry
!= &DeviceInformation
->AssociatedDevicesHead
;
1399 Entry
= Entry
->Flink
)
1401 AssociatedDeviceEntry
= CONTAINING_RECORD(Entry
, ASSOCIATED_DEVICE_ENTRY
, AssociatedDevicesEntry
);
1403 /* If we had a path... */
1404 if ((*CurrentPath
)->MultiSzLength
!= sizeof(UNICODE_NULL
))
1409 /* This offset is used to "jump" into MultiSz, so, start with the string begin (ie, skip MultiSzLength) */
1410 Offset
= sizeof(ULONG
);
1411 /* Browse every single letter, and skip last UNICODE_NULL */
1412 for (i
= 0; i
< (*CurrentPath
)->MultiSzLength
/ sizeof(WCHAR
) - 1; ++i
)
1414 /* Get the letter */
1415 MultiSz
= (PWSTR
)((ULONG_PTR
)(*CurrentPath
) + Offset
);
1416 /* If it was part of the path, just return it */
1417 if (*MultiSz
!= UNICODE_NULL
)
1419 (*VolumePaths
)->MultiSz
[Written
] = *MultiSz
;
1423 /* Otherwise, as planed, return our whole associated device name */
1424 RtlCopyMemory(&(*VolumePaths
)->MultiSz
[Written
],
1425 AssociatedDeviceEntry
->String
.Buffer
,
1426 AssociatedDeviceEntry
->String
.Length
);
1427 Written
+= AssociatedDeviceEntry
->String
.Length
/ sizeof(WCHAR
);
1428 /* And don't forget to nullify */
1429 (*VolumePaths
)->MultiSz
[Written
] = UNICODE_NULL
;
1432 /* We at least return a letter or a null char */
1434 /* Move to the next letter */
1435 Offset
+= sizeof(WCHAR
);
1439 FreePool(*CurrentPath
);
1443 /* MultiSz: don't forget last null char */
1444 (*VolumePaths
)->MultiSz
[Written
] = UNICODE_NULL
;
1445 /* Cleanup everything and return success! */
1450 RemoveEntryList(&DeviceInfoEntry
->DeviceInformationEntry
);
1451 FreePool(DeviceInfoEntry
);
1452 return STATUS_SUCCESS
;
1459 MountMgrQueryDosVolumePaths(IN PDEVICE_EXTENSION DeviceExtension
,
1465 BOOLEAN NeedNotification
;
1466 PIO_STACK_LOCATION Stack
;
1467 UNICODE_STRING SymbolicName
;
1468 ULONG Attempts
, OutputLength
;
1469 PMOUNTMGR_TARGET_NAME Target
;
1470 PMOUNTMGR_VOLUME_PATHS Paths
, Output
;
1471 RECONCILE_WORK_ITEM_CONTEXT ReconcileContext
;
1472 PDEVICE_INFORMATION DeviceInformation
, ListDeviceInfo
, FailedDevice
;
1474 Stack
= IoGetCurrentIrpStackLocation(Irp
);
1476 /* Validate input size */
1477 if (Stack
->Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(MOUNTMGR_TARGET_NAME
))
1479 return STATUS_INVALID_PARAMETER
;
1482 /* Ensure we have received UNICODE_STRING */
1483 Target
= (PMOUNTMGR_TARGET_NAME
)Irp
->AssociatedIrp
.SystemBuffer
;
1484 if (Target
->DeviceNameLength
& 1)
1486 return STATUS_INVALID_PARAMETER
;
1489 /* Validate the entry structure size */
1490 if (Target
->DeviceNameLength
+ FIELD_OFFSET(MOUNTMGR_TARGET_NAME
, DeviceName
) > Stack
->Parameters
.DeviceIoControl
.InputBufferLength
)
1492 return STATUS_INVALID_PARAMETER
;
1495 /* Ensure we can at least return needed size */
1496 if (Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(ULONG
))
1498 return STATUS_INVALID_PARAMETER
;
1501 /* Construct string for query */
1502 SymbolicName
.Length
= Target
->DeviceNameLength
;
1503 SymbolicName
.MaximumLength
= Target
->DeviceNameLength
+ sizeof(UNICODE_NULL
);
1504 SymbolicName
.Buffer
= Target
->DeviceName
;
1506 /* Find device with our info */
1507 Status
= FindDeviceInfo(DeviceExtension
, &SymbolicName
, FALSE
, &DeviceInformation
);
1508 if (!NT_SUCCESS(Status
))
1513 NeedNotification
= FALSE
;
1517 FailedDevice
= NULL
;
1518 InitializeListHead(&Devices
);
1521 Status
= MountMgrQueryVolumePaths(DeviceExtension
, DeviceInformation
, &Devices
, &Paths
, &FailedDevice
);
1522 if (NT_SUCCESS(Status
))
1527 /* If it failed for generic reason (memory, whatever), bail out (ie, FailedDevice not set) */
1528 if (FailedDevice
== NULL
)
1533 /* If PnP, let's notify in case of success */
1534 if (!DeviceInformation
->ManuallyRegistered
)
1536 NeedNotification
= TRUE
;
1539 /* Reconcile database */
1540 ReconcileContext
.DeviceExtension
= DeviceExtension
;
1541 ReconcileContext
.DeviceInformation
= FailedDevice
;
1542 KeReleaseSemaphore(&DeviceExtension
->DeviceLock
, IO_NO_INCREMENT
, 1, FALSE
);
1543 ReconcileThisDatabaseWithMasterWorker(&ReconcileContext
);
1544 KeWaitForSingleObject(&DeviceExtension
->DeviceLock
, Executive
, KernelMode
, FALSE
, NULL
);
1546 /* Look for our device, to check it's online */
1547 for (Entry
= DeviceExtension
->DeviceListHead
.Flink
;
1548 Entry
!= &DeviceExtension
->DeviceListHead
;
1549 Entry
= Entry
->Flink
)
1551 ListDeviceInfo
= CONTAINING_RECORD(Entry
, DEVICE_INFORMATION
, DeviceListEntry
);
1552 /* It's online, it's OK! */
1553 if (ListDeviceInfo
== DeviceInformation
)
1559 /* It's not online, it's not good */
1560 if (Entry
== &DeviceExtension
->DeviceListHead
)
1562 return STATUS_OBJECT_NAME_NOT_FOUND
;
1565 /* Increase attempts count */
1567 /* Don't look forever and fail if we get out of attempts */
1568 if (Attempts
>= 1000)
1574 /* We need to notify? Go ahead */
1575 if (NeedNotification
)
1577 MountMgrNotifyNameChange(DeviceExtension
, &SymbolicName
, FALSE
);
1580 /* Get output buffer */
1581 Output
= (PMOUNTMGR_VOLUME_PATHS
)Irp
->AssociatedIrp
.SystemBuffer
;
1583 /* Set required size */
1584 Output
->MultiSzLength
= Paths
->MultiSzLength
;
1586 /* Compute total length */
1587 OutputLength
= Output
->MultiSzLength
+ sizeof(ULONG
);
1589 /* If it cannot fit, just return need size and quit */
1590 if (OutputLength
> Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
)
1592 Irp
->IoStatus
.Information
= sizeof(ULONG
);
1594 return STATUS_BUFFER_OVERFLOW
;
1597 /* Copy data and quit */
1598 Irp
->IoStatus
.Information
= OutputLength
;
1599 RtlCopyMemory(Output
->MultiSz
, Paths
->MultiSz
, Output
->MultiSzLength
);
1601 return STATUS_SUCCESS
;
1608 MountMgrKeepLinksWhenOffline(IN PDEVICE_EXTENSION DeviceExtension
,
1612 PIO_STACK_LOCATION Stack
;
1613 UNICODE_STRING SymbolicName
;
1614 PMOUNTMGR_TARGET_NAME Target
;
1615 PDEVICE_INFORMATION DeviceInformation
;
1617 Stack
= IoGetCurrentIrpStackLocation(Irp
);
1619 /* Validate input */
1620 if (Stack
->Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(MOUNTMGR_TARGET_NAME
))
1622 return STATUS_INVALID_PARAMETER
;
1625 Target
= (PMOUNTMGR_TARGET_NAME
)Irp
->AssociatedIrp
.SystemBuffer
;
1626 if (Target
->DeviceNameLength
+ sizeof(USHORT
) > Stack
->Parameters
.DeviceIoControl
.InputBufferLength
)
1628 return STATUS_INVALID_PARAMETER
;
1631 SymbolicName
.Length
=
1632 SymbolicName
.MaximumLength
= Target
->DeviceNameLength
;
1633 SymbolicName
.Buffer
= Target
->DeviceName
;
1635 /* Find the associated device */
1636 Status
= FindDeviceInfo(DeviceExtension
, &SymbolicName
, FALSE
, &DeviceInformation
);
1637 if (!NT_SUCCESS(Status
))
1642 /* Mark we want to keep links */
1643 DeviceInformation
->KeepLinks
= TRUE
;
1645 return STATUS_SUCCESS
;
1652 MountMgrVolumeArrivalNotification(IN PDEVICE_EXTENSION DeviceExtension
,
1657 PIO_STACK_LOCATION Stack
;
1658 UNICODE_STRING SymbolicName
;
1659 PMOUNTMGR_TARGET_NAME Target
;
1661 Stack
= IoGetCurrentIrpStackLocation(Irp
);
1663 /* Validate input */
1664 if (Stack
->Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(MOUNTMGR_TARGET_NAME
))
1666 return STATUS_INVALID_PARAMETER
;
1669 Target
= (PMOUNTMGR_TARGET_NAME
)Irp
->AssociatedIrp
.SystemBuffer
;
1670 if (Target
->DeviceNameLength
+ sizeof(USHORT
) > Stack
->Parameters
.DeviceIoControl
.InputBufferLength
)
1672 return STATUS_INVALID_PARAMETER
;
1675 SymbolicName
.Length
=
1676 SymbolicName
.MaximumLength
= Target
->DeviceNameLength
;
1677 SymbolicName
.Buffer
= Target
->DeviceName
;
1679 /* Disable hard errors */
1680 OldState
= PsGetThreadHardErrorsAreDisabled(PsGetCurrentThread());
1681 PsSetThreadHardErrorsAreDisabled(PsGetCurrentThread(), TRUE
);
1683 /* Call real worker */
1684 Status
= MountMgrMountedDeviceArrival(DeviceExtension
, &SymbolicName
, TRUE
);
1686 PsSetThreadHardErrorsAreDisabled(PsGetCurrentThread(), OldState
);
1695 MountMgrQueryPoints(IN PDEVICE_EXTENSION DeviceExtension
,
1699 PIO_STACK_LOCATION Stack
;
1700 PMOUNTDEV_UNIQUE_ID UniqueId
;
1701 PMOUNTMGR_MOUNT_POINT MountPoint
;
1702 UNICODE_STRING SymbolicName
, DeviceName
;
1704 Stack
= IoGetCurrentIrpStackLocation(Irp
);
1706 /* Validate input... */
1707 if (Stack
->Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(MOUNTMGR_MOUNT_POINT
))
1709 return STATUS_INVALID_PARAMETER
;
1712 MountPoint
= (PMOUNTMGR_MOUNT_POINT
)Irp
->AssociatedIrp
.SystemBuffer
;
1713 if (!MountPoint
->SymbolicLinkNameLength
)
1715 MountPoint
->SymbolicLinkNameOffset
= 0;
1718 if (!MountPoint
->UniqueIdLength
)
1720 MountPoint
->UniqueIdOffset
= 0;
1723 if (!MountPoint
->DeviceNameLength
)
1725 MountPoint
->DeviceNameOffset
= 0;
1728 /* Addresses can't be odd */
1729 if ((MountPoint
->SymbolicLinkNameOffset
& 1) ||
1730 (MountPoint
->SymbolicLinkNameLength
& 1))
1732 return STATUS_INVALID_PARAMETER
;
1735 if ((MountPoint
->UniqueIdOffset
& 1) ||
1736 (MountPoint
->UniqueIdLength
& 1))
1738 return STATUS_INVALID_PARAMETER
;
1741 if ((MountPoint
->DeviceNameOffset
& 1) ||
1742 (MountPoint
->DeviceNameLength
& 1))
1744 return STATUS_INVALID_PARAMETER
;
1747 /* We can't go beyond */
1748 if (((ULONG
)MountPoint
->SymbolicLinkNameLength
+ MountPoint
->UniqueIdLength
+
1749 MountPoint
->DeviceNameLength
) > Stack
->Parameters
.DeviceIoControl
.InputBufferLength
)
1751 return STATUS_INVALID_PARAMETER
;
1754 if (Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(MOUNTMGR_MOUNT_POINTS
))
1756 return STATUS_INVALID_PARAMETER
;
1759 /* If caller provided a Symlink, use it */
1760 if (MountPoint
->SymbolicLinkNameLength
!= 0)
1762 if (MountPoint
->SymbolicLinkNameLength
> MAXSHORT
)
1764 return STATUS_INVALID_PARAMETER
;
1767 SymbolicName
.Length
= MountPoint
->SymbolicLinkNameLength
;
1768 SymbolicName
.MaximumLength
= MountPoint
->SymbolicLinkNameLength
+ sizeof(WCHAR
);
1769 SymbolicName
.Buffer
= AllocatePool(SymbolicName
.MaximumLength
);
1770 if (!SymbolicName
.Buffer
)
1772 return STATUS_INSUFFICIENT_RESOURCES
;
1775 RtlCopyMemory(SymbolicName
.Buffer
,
1776 (PWSTR
)((ULONG_PTR
)MountPoint
+ MountPoint
->SymbolicLinkNameOffset
),
1777 SymbolicName
.Length
);
1778 SymbolicName
.Buffer
[SymbolicName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1780 /* Query links using it */
1781 Status
= QueryPointsFromSymbolicLinkName(DeviceExtension
, &SymbolicName
, Irp
);
1782 FreePool(SymbolicName
.Buffer
);
1784 /* If user provided an unique ID */
1785 else if (MountPoint
->UniqueIdLength
!= 0)
1787 UniqueId
= AllocatePool(MountPoint
->UniqueIdLength
+ sizeof(MOUNTDEV_UNIQUE_ID
));
1790 return STATUS_INSUFFICIENT_RESOURCES
;
1793 UniqueId
->UniqueIdLength
= MountPoint
->UniqueIdLength
;
1794 RtlCopyMemory(UniqueId
->UniqueId
,
1795 (PVOID
)((ULONG_PTR
)MountPoint
+ MountPoint
->UniqueIdOffset
),
1796 MountPoint
->UniqueIdLength
);
1798 /* Query links using it */
1799 Status
= QueryPointsFromMemory(DeviceExtension
, Irp
, UniqueId
, NULL
);
1802 /* If caller provided a device name */
1803 else if (MountPoint
->DeviceNameLength
!= 0)
1805 if (MountPoint
->DeviceNameLength
> MAXSHORT
)
1807 return STATUS_INVALID_PARAMETER
;
1810 DeviceName
.Length
= MountPoint
->DeviceNameLength
;
1811 DeviceName
.MaximumLength
= MountPoint
->DeviceNameLength
+ sizeof(WCHAR
);
1812 DeviceName
.Buffer
= AllocatePool(DeviceName
.MaximumLength
);
1813 if (!DeviceName
.Buffer
)
1815 return STATUS_INSUFFICIENT_RESOURCES
;
1818 RtlCopyMemory(DeviceName
.Buffer
,
1819 (PWSTR
)((ULONG_PTR
)MountPoint
+ MountPoint
->DeviceNameOffset
),
1821 DeviceName
.Buffer
[DeviceName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1823 /* Query links using it */
1824 Status
= QueryPointsFromMemory(DeviceExtension
, Irp
, NULL
, &DeviceName
);
1825 FreePool(DeviceName
.Buffer
);
1829 /* Otherwise, query all links */
1830 Status
= QueryPointsFromMemory(DeviceExtension
, Irp
, NULL
, NULL
);
1840 MountMgrDeletePoints(IN PDEVICE_EXTENSION DeviceExtension
,
1845 BOOLEAN CreateNoDrive
;
1846 PIO_STACK_LOCATION Stack
;
1847 PMOUNTDEV_UNIQUE_ID UniqueId
;
1848 PMOUNTMGR_MOUNT_POINT MountPoint
;
1849 PMOUNTMGR_MOUNT_POINTS MountPoints
;
1850 UNICODE_STRING SymbolicName
, DeviceName
;
1852 Stack
= IoGetCurrentIrpStackLocation(Irp
);
1854 /* Validate input */
1855 if (Stack
->Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(MOUNTMGR_MOUNT_POINT
))
1857 return STATUS_INVALID_PARAMETER
;
1861 MountPoint
= (PMOUNTMGR_MOUNT_POINT
)Irp
->AssociatedIrp
.SystemBuffer
;
1862 CreateNoDrive
= (MountPoint
->SymbolicLinkNameOffset
&& MountPoint
->SymbolicLinkNameLength
);
1864 Status
= MountMgrQueryPoints(DeviceExtension
, Irp
);
1865 if (!NT_SUCCESS(Status
))
1870 /* For all the points matching the request */
1871 MountPoints
= (PMOUNTMGR_MOUNT_POINTS
)Irp
->AssociatedIrp
.SystemBuffer
;
1872 for (Link
= 0; Link
< MountPoints
->NumberOfMountPoints
; Link
++)
1874 SymbolicName
.Length
= MountPoints
->MountPoints
[Link
].SymbolicLinkNameLength
;
1875 SymbolicName
.MaximumLength
= SymbolicName
.Length
+ sizeof(WCHAR
);
1876 SymbolicName
.Buffer
= AllocatePool(SymbolicName
.MaximumLength
);
1877 if (!SymbolicName
.Buffer
)
1879 return STATUS_INSUFFICIENT_RESOURCES
;
1882 RtlCopyMemory(SymbolicName
.Buffer
,
1883 (PWSTR
)((ULONG_PTR
)MountPoints
+ MountPoints
->MountPoints
[Link
].SymbolicLinkNameOffset
),
1884 SymbolicName
.Length
);
1885 SymbolicName
.Buffer
[SymbolicName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1887 /* Create a no drive entry for the drive letters */
1888 if (CreateNoDrive
&& IsDriveLetter(&SymbolicName
))
1890 UniqueId
= AllocatePool(MountPoints
->MountPoints
[Link
].UniqueIdLength
+ sizeof(MOUNTDEV_UNIQUE_ID
));
1893 UniqueId
->UniqueIdLength
= MountPoints
->MountPoints
[Link
].UniqueIdLength
;
1894 RtlCopyMemory(UniqueId
->UniqueId
,
1895 (PMOUNTDEV_UNIQUE_ID
)((ULONG_PTR
)MountPoints
+ MountPoints
->MountPoints
[Link
].UniqueIdOffset
),
1896 MountPoints
->MountPoints
[Link
].UniqueIdLength
);
1898 CreateNoDriveLetterEntry(UniqueId
);
1903 /* If there are no link any more, and no need to create a no drive entry */
1904 if (Link
== 0 && !CreateNoDrive
)
1906 /* Then, delete everything */
1907 UniqueId
= AllocatePool(MountPoints
->MountPoints
[Link
].UniqueIdLength
);
1910 RtlCopyMemory(UniqueId
,
1911 (PMOUNTDEV_UNIQUE_ID
)((ULONG_PTR
)MountPoints
+ MountPoints
->MountPoints
[Link
].UniqueIdOffset
),
1912 MountPoints
->MountPoints
[Link
].UniqueIdLength
);
1914 DeleteNoDriveLetterEntry(UniqueId
);
1919 /* Delete all the information about the mount point */
1920 GlobalDeleteSymbolicLink(&SymbolicName
);
1921 DeleteSymbolicLinkNameFromMemory(DeviceExtension
, &SymbolicName
, FALSE
);
1922 RtlDeleteRegistryValue(RTL_REGISTRY_ABSOLUTE
, DatabasePath
, SymbolicName
.Buffer
);
1923 FreePool(SymbolicName
.Buffer
);
1925 /* Notify the change */
1926 DeviceName
.Length
= DeviceName
.MaximumLength
=
1927 MountPoints
->MountPoints
[Link
].DeviceNameLength
;
1928 DeviceName
.Buffer
= (PWSTR
)((ULONG_PTR
)MountPoints
+ MountPoints
->MountPoints
[Link
].DeviceNameOffset
);
1929 MountMgrNotifyNameChange(DeviceExtension
, &DeviceName
, TRUE
);
1932 MountMgrNotify(DeviceExtension
);
1941 MountMgrDeletePointsDbOnly(IN PDEVICE_EXTENSION DeviceExtension
,
1946 UNICODE_STRING SymbolicName
;
1947 PMOUNTDEV_UNIQUE_ID UniqueId
;
1948 PMOUNTMGR_MOUNT_POINTS MountPoints
;
1951 Status
= MountMgrQueryPoints(DeviceExtension
, Irp
);
1952 if (!NT_SUCCESS(Status
))
1957 MountPoints
= (PMOUNTMGR_MOUNT_POINTS
)Irp
->AssociatedIrp
.SystemBuffer
;
1958 if (MountPoints
->NumberOfMountPoints
== 0)
1963 /* For all the mount points */
1964 for (Link
= 0; Link
< MountPoints
->NumberOfMountPoints
; Link
++)
1966 SymbolicName
.Length
= MountPoints
->MountPoints
[Link
].SymbolicLinkNameLength
;
1967 SymbolicName
.MaximumLength
= SymbolicName
.Length
+ sizeof(WCHAR
);
1968 SymbolicName
.Buffer
= AllocatePool(SymbolicName
.MaximumLength
);
1969 if (!SymbolicName
.Buffer
)
1971 return STATUS_INSUFFICIENT_RESOURCES
;
1974 RtlCopyMemory(SymbolicName
.Buffer
,
1975 (PWSTR
)((ULONG_PTR
)MountPoints
+ MountPoints
->MountPoints
[Link
].SymbolicLinkNameOffset
),
1976 SymbolicName
.Length
);
1977 SymbolicName
.Buffer
[SymbolicName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1979 /* If the only mount point is a drive letter, then create a no letter drive entry */
1980 if (MountPoints
->NumberOfMountPoints
== 1 && IsDriveLetter(&SymbolicName
))
1982 UniqueId
= AllocatePool(MountPoints
->MountPoints
[Link
].UniqueIdLength
+ sizeof(MOUNTDEV_UNIQUE_ID
));
1985 UniqueId
->UniqueIdLength
= MountPoints
->MountPoints
[Link
].UniqueIdLength
;
1986 RtlCopyMemory(UniqueId
->UniqueId
,
1987 (PMOUNTDEV_UNIQUE_ID
)((ULONG_PTR
)MountPoints
+ MountPoints
->MountPoints
[Link
].UniqueIdOffset
),
1988 MountPoints
->MountPoints
[Link
].UniqueIdLength
);
1990 CreateNoDriveLetterEntry(UniqueId
);
1995 /* Simply delete mount point from DB */
1996 DeleteSymbolicLinkNameFromMemory(DeviceExtension
, &SymbolicName
, TRUE
);
1997 RtlDeleteRegistryValue(RTL_REGISTRY_ABSOLUTE
, DatabasePath
, SymbolicName
.Buffer
);
1998 FreePool(SymbolicName
.Buffer
);
2008 MountMgrVolumeMountPointChanged(IN PDEVICE_EXTENSION DeviceExtension
,
2010 IN NTSTATUS LockStatus
,
2011 OUT PUNICODE_STRING SourceDeviceName
,
2012 OUT PUNICODE_STRING SourceSymbolicName
,
2013 OUT PUNICODE_STRING TargetVolumeName
)
2017 PFILE_OBJECT FileObject
;
2018 PIO_STACK_LOCATION Stack
;
2019 ULONG Length
, SavedLength
;
2020 BOOLEAN FOReferenced
= FALSE
;
2021 IO_STATUS_BLOCK IoStatusBlock
;
2022 OBJECT_ATTRIBUTES ObjectAttributes
;
2023 PDEVICE_INFORMATION DeviceInformation
;
2024 OBJECT_NAME_INFORMATION ObjectNameInfo
;
2025 FILE_FS_DEVICE_INFORMATION FsDeviceInfo
;
2026 PFILE_NAME_INFORMATION FileNameInfo
= NULL
;
2027 PMOUNTMGR_VOLUME_MOUNT_POINT VolumeMountPoint
;
2028 POBJECT_NAME_INFORMATION ObjectNameInfoPtr
= NULL
;
2029 UNICODE_STRING SourceVolumeName
, TargetDeviceName
;
2031 Stack
= IoGetCurrentIrpStackLocation(Irp
);
2033 /* Validate input */
2034 if (Stack
->Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(MOUNTMGR_VOLUME_MOUNT_POINT
))
2036 return STATUS_INVALID_PARAMETER
;
2039 VolumeMountPoint
= (PMOUNTMGR_VOLUME_MOUNT_POINT
)Irp
->AssociatedIrp
.SystemBuffer
;
2041 if (((ULONG
)VolumeMountPoint
->SourceVolumeNameLength
+ VolumeMountPoint
->TargetVolumeNameLength
) <
2042 Stack
->Parameters
.DeviceIoControl
.InputBufferLength
)
2044 return STATUS_INVALID_PARAMETER
;
2047 /* Get source volume name */
2048 SourceVolumeName
.Length
=
2049 SourceVolumeName
.MaximumLength
= VolumeMountPoint
->SourceVolumeNameLength
;
2050 SourceVolumeName
.Buffer
= (PWSTR
)((ULONG_PTR
)VolumeMountPoint
+ VolumeMountPoint
->SourceVolumeNameOffset
);
2052 InitializeObjectAttributes(&ObjectAttributes
,
2054 OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
,
2059 Status
= ZwOpenFile(&Handle
,
2060 SYNCHRONIZE
| FILE_READ_ATTRIBUTES
,
2063 FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
,
2064 FILE_SYNCHRONOUS_IO_NONALERT
| FILE_OPEN_REPARSE_POINT
);
2065 if (!NT_SUCCESS(Status
))
2070 TargetDeviceName
.Buffer
= NULL
;
2072 /* Query its attributes */
2073 Status
= ZwQueryVolumeInformationFile(Handle
,
2076 sizeof(FsDeviceInfo
),
2077 FileFsDeviceInformation
);
2078 if (!NT_SUCCESS(Status
))
2083 if (FsDeviceInfo
.DeviceType
!= FILE_DEVICE_DISK
&& FsDeviceInfo
.DeviceType
!= FILE_DEVICE_VIRTUAL_DISK
)
2088 if (FsDeviceInfo
.Characteristics
!= (FILE_REMOTE_DEVICE
| FILE_REMOVABLE_MEDIA
))
2094 Status
= ObReferenceObjectByHandle(Handle
, 0, *IoFileObjectType
, KernelMode
, (PVOID
*)&FileObject
, NULL
);
2095 if (!NT_SUCCESS(Status
))
2099 FOReferenced
= TRUE
;
2102 FileNameInfo
= AllocatePool(sizeof(FILE_NAME_INFORMATION
));
2105 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2109 Status
= ZwQueryInformationFile(Handle
, &IoStatusBlock
, FileNameInfo
,
2110 sizeof(FILE_NAME_INFORMATION
),
2111 FileNameInformation
);
2112 if (Status
== STATUS_BUFFER_OVERFLOW
)
2114 /* Now we have real length, use it */
2115 Length
= FileNameInfo
->FileNameLength
;
2116 FreePool(FileNameInfo
);
2118 FileNameInfo
= AllocatePool(sizeof(FILE_NAME_INFORMATION
) + Length
);
2121 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2125 /* Really query file name */
2126 Status
= ZwQueryInformationFile(Handle
, &IoStatusBlock
, FileNameInfo
,
2127 sizeof(FILE_NAME_INFORMATION
) + Length
,
2128 FileNameInformation
);
2131 if (!NT_SUCCESS(Status
))
2136 /* Get symbolic name */
2137 ObjectNameInfoPtr
= &ObjectNameInfo
;
2138 SavedLength
= sizeof(OBJECT_NAME_INFORMATION
);
2139 Status
= ObQueryNameString(FileObject
->DeviceObject
, ObjectNameInfoPtr
, sizeof(OBJECT_NAME_INFORMATION
), &Length
);
2140 if (Status
== STATUS_INFO_LENGTH_MISMATCH
)
2142 /* Once again, with proper size, it works better */
2143 ObjectNameInfoPtr
= AllocatePool(Length
);
2144 if (!ObjectNameInfoPtr
)
2146 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2150 SavedLength
= Length
;
2151 Status
= ObQueryNameString(FileObject
->DeviceObject
, ObjectNameInfoPtr
, SavedLength
, &Length
);
2154 if (!NT_SUCCESS(Status
))
2159 /* Now, query the device name */
2160 Status
= QueryDeviceInformation(&ObjectNameInfoPtr
->Name
, SourceDeviceName
,
2161 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
2162 if (!NT_SUCCESS(Status
))
2167 /* For target volume name, use input */
2168 TargetVolumeName
->Length
=
2169 TargetVolumeName
->MaximumLength
= VolumeMountPoint
->TargetVolumeNameLength
;
2170 TargetVolumeName
->Buffer
= (PWSTR
)((ULONG_PTR
)VolumeMountPoint
+ VolumeMountPoint
->TargetVolumeNameOffset
);
2172 /* Query its device name */
2173 Status
= QueryDeviceInformation(TargetVolumeName
, &TargetDeviceName
,
2174 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
2175 if (!NT_SUCCESS(Status
))
2180 /* Return symbolic name */
2181 SourceSymbolicName
->Length
=
2182 SourceSymbolicName
->MaximumLength
= (USHORT
)FileNameInfo
->FileNameLength
;
2183 SourceSymbolicName
->Buffer
= (PWSTR
)FileNameInfo
;
2184 /* memmove allows memory overlap */
2185 RtlMoveMemory(SourceSymbolicName
->Buffer
, FileNameInfo
->FileName
, SourceSymbolicName
->Length
);
2186 FileNameInfo
= NULL
;
2188 /* Notify the change */
2189 MountMgrNotify(DeviceExtension
);
2190 MountMgrNotifyNameChange(DeviceExtension
, &TargetDeviceName
, TRUE
);
2192 /* If we are locked, sync databases if possible */
2193 if (NT_SUCCESS(LockStatus
))
2195 Status
= FindDeviceInfo(DeviceExtension
, SourceDeviceName
, FALSE
, &DeviceInformation
);
2196 if (NT_SUCCESS(Status
))
2198 ReconcileThisDatabaseWithMaster(DeviceExtension
, DeviceInformation
);
2202 Status
= STATUS_PENDING
;
2207 if (TargetDeviceName
.Buffer
)
2209 FreePool(TargetDeviceName
.Buffer
);
2212 if (ObjectNameInfoPtr
&& ObjectNameInfoPtr
!= &ObjectNameInfo
)
2214 FreePool(ObjectNameInfoPtr
);
2219 FreePool(FileNameInfo
);
2224 ObDereferenceObject(FileObject
);
2234 MountMgrVolumeMountPointCreated(IN PDEVICE_EXTENSION DeviceExtension
,
2236 IN NTSTATUS LockStatus
)
2241 HANDLE RemoteDatabase
;
2242 PMOUNTDEV_UNIQUE_ID UniqueId
;
2243 PDATABASE_ENTRY DatabaseEntry
;
2244 PASSOCIATED_DEVICE_ENTRY AssociatedEntry
;
2245 PDEVICE_INFORMATION DeviceInformation
, TargetDeviceInformation
;
2246 UNICODE_STRING LinkTarget
, SourceDeviceName
, SourceSymbolicName
, TargetVolumeName
, VolumeName
, DbName
;
2248 /* Initialize string */
2249 LinkTarget
.Length
= 0;
2250 LinkTarget
.MaximumLength
= 0xC8;
2251 LinkTarget
.Buffer
= AllocatePool(LinkTarget
.MaximumLength
);
2252 if (LinkTarget
.Buffer
== NULL
)
2254 return STATUS_INSUFFICIENT_RESOURCES
;
2257 /* If the mount point was created, then, it changed!
2258 * Also use it to query some information
2260 Status
= MountMgrVolumeMountPointChanged(DeviceExtension
, Irp
, LockStatus
, &SourceDeviceName
, &SourceSymbolicName
, &TargetVolumeName
);
2261 /* Pending means DB are under synchronization, bail out */
2262 if (Status
== STATUS_PENDING
)
2264 FreePool(LinkTarget
.Buffer
);
2265 FreePool(SourceDeviceName
.Buffer
);
2266 FreePool(SourceSymbolicName
.Buffer
);
2267 return STATUS_SUCCESS
;
2269 else if (!NT_SUCCESS(Status
))
2271 FreePool(LinkTarget
.Buffer
);
2275 /* Query the device information */
2276 Status
= FindDeviceInfo(DeviceExtension
, &SourceDeviceName
, FALSE
, &DeviceInformation
);
2277 if (!NT_SUCCESS(Status
))
2279 /* If it failed, first try to get volume name */
2280 Status
= QueryVolumeName(0, NULL
, &SourceDeviceName
, &LinkTarget
, &VolumeName
);
2281 if (!NT_SUCCESS(Status
))
2283 /* Then, try to read the symlink */
2284 Status
= MountMgrQuerySymbolicLink(&SourceDeviceName
, &LinkTarget
);
2285 if (!NT_SUCCESS(Status
))
2287 FreePool(LinkTarget
.Buffer
);
2288 FreePool(SourceDeviceName
.Buffer
);
2289 FreePool(SourceSymbolicName
.Buffer
);
2295 FreePool(VolumeName
.Buffer
);
2298 FreePool(SourceDeviceName
.Buffer
);
2300 SourceDeviceName
.Length
= LinkTarget
.Length
;
2301 SourceDeviceName
.MaximumLength
= LinkTarget
.MaximumLength
;
2302 SourceDeviceName
.Buffer
= LinkTarget
.Buffer
;
2304 /* Now that we have the correct source, reattempt to query information */
2305 Status
= FindDeviceInfo(DeviceExtension
, &SourceDeviceName
, FALSE
, &DeviceInformation
);
2306 if (!NT_SUCCESS(Status
))
2308 FreePool(SourceDeviceName
.Buffer
);
2309 FreePool(SourceSymbolicName
.Buffer
);
2314 FreePool(SourceDeviceName
.Buffer
);
2316 /* Get information about target device */
2317 Status
= FindDeviceInfo(DeviceExtension
, &TargetVolumeName
, FALSE
, &TargetDeviceInformation
);
2318 if (!NT_SUCCESS(Status
))
2320 FreePool(SourceSymbolicName
.Buffer
);
2324 /* Notify if not disabled */
2325 if (!TargetDeviceInformation
->SkipNotifications
)
2327 PostOnlineNotification(DeviceExtension
, &TargetDeviceInformation
->SymbolicName
);
2330 /* Open the remote database */
2331 RemoteDatabase
= OpenRemoteDatabase(DeviceInformation
, TRUE
);
2332 if (RemoteDatabase
== 0)
2334 FreePool(SourceSymbolicName
.Buffer
);
2335 return STATUS_INSUFFICIENT_RESOURCES
;
2338 /* Browse all the entries */
2343 DatabaseEntry
= GetRemoteDatabaseEntry(RemoteDatabase
, Offset
);
2344 if (DatabaseEntry
== NULL
)
2349 /* Try to find ourselves */
2350 DbName
.MaximumLength
= DatabaseEntry
->SymbolicNameLength
;
2351 DbName
.Length
= DbName
.MaximumLength
;
2352 DbName
.Buffer
= (PWSTR
)((ULONG_PTR
)DatabaseEntry
+ DatabaseEntry
->SymbolicNameOffset
);
2353 if (RtlEqualUnicodeString(&TargetVolumeName
, &DbName
, TRUE
))
2355 /* Reference ourselves and update the entry */
2356 ++DatabaseEntry
->EntryReferences
;
2357 Status
= WriteRemoteDatabaseEntry(RemoteDatabase
, Offset
, DatabaseEntry
);
2358 FreePool(DatabaseEntry
);
2363 Offset
+= DatabaseEntry
->EntrySize
;
2364 FreePool(DatabaseEntry
);
2367 /* We couldn't find ourselves, we'll have to add ourselves */
2371 PUNIQUE_ID_REPLICATE UniqueIdReplicate
;
2373 /* Query the device unique ID */
2374 Status
= QueryDeviceInformation(&TargetVolumeName
, NULL
, &UniqueId
, NULL
, NULL
, NULL
, NULL
, NULL
);
2375 if (!NT_SUCCESS(Status
))
2377 FreePool(SourceSymbolicName
.Buffer
);
2378 CloseRemoteDatabase(RemoteDatabase
);
2382 /* Allocate a database entry */
2383 EntrySize
= UniqueId
->UniqueIdLength
+ TargetVolumeName
.Length
+ sizeof(DATABASE_ENTRY
);
2384 DatabaseEntry
= AllocatePool(EntrySize
);
2385 if (DatabaseEntry
== NULL
)
2388 FreePool(SourceSymbolicName
.Buffer
);
2389 CloseRemoteDatabase(RemoteDatabase
);
2390 return STATUS_INSUFFICIENT_RESOURCES
;
2394 DatabaseEntry
->EntrySize
= EntrySize
;
2395 DatabaseEntry
->EntryReferences
= 1;
2396 DatabaseEntry
->SymbolicNameOffset
= sizeof(DATABASE_ENTRY
);
2397 DatabaseEntry
->SymbolicNameLength
= TargetVolumeName
.Length
;
2398 DatabaseEntry
->UniqueIdOffset
= TargetVolumeName
.Length
+ sizeof(DATABASE_ENTRY
);
2399 DatabaseEntry
->UniqueIdLength
= UniqueId
->UniqueIdLength
;
2400 RtlCopyMemory((PVOID
)((ULONG_PTR
)DatabaseEntry
+ sizeof(DATABASE_ENTRY
)), TargetVolumeName
.Buffer
, DatabaseEntry
->SymbolicNameLength
);
2401 RtlCopyMemory((PVOID
)((ULONG_PTR
)DatabaseEntry
+ DatabaseEntry
->UniqueIdOffset
), UniqueId
->UniqueId
, UniqueId
->UniqueIdLength
);
2403 /* And write it down */
2404 Status
= AddRemoteDatabaseEntry(RemoteDatabase
, DatabaseEntry
);
2405 FreePool(DatabaseEntry
);
2406 if (!NT_SUCCESS(Status
))
2409 FreePool(SourceSymbolicName
.Buffer
);
2410 CloseRemoteDatabase(RemoteDatabase
);
2414 /* And now, allocate an Unique ID item */
2415 UniqueIdReplicate
= AllocatePool(sizeof(UNIQUE_ID_REPLICATE
));
2416 if (UniqueIdReplicate
== NULL
)
2419 FreePool(SourceSymbolicName
.Buffer
);
2420 CloseRemoteDatabase(RemoteDatabase
);
2424 /* To associate it with the device */
2425 UniqueIdReplicate
->UniqueId
= UniqueId
;
2426 InsertTailList(&DeviceInformation
->ReplicatedUniqueIdsListHead
, &UniqueIdReplicate
->ReplicatedUniqueIdsListEntry
);
2429 /* We're done with the remote database */
2430 CloseRemoteDatabase(RemoteDatabase
);
2432 /* Check we were find writing the entry */
2433 if (!NT_SUCCESS(Status
))
2435 FreePool(SourceSymbolicName
.Buffer
);
2439 /* This is the end, allocate an associated entry */
2440 AssociatedEntry
= AllocatePool(sizeof(ASSOCIATED_DEVICE_ENTRY
));
2441 if (AssociatedEntry
== NULL
)
2443 FreePool(SourceSymbolicName
.Buffer
);
2444 return STATUS_INSUFFICIENT_RESOURCES
;
2447 /* Initialize its source name string */
2448 AssociatedEntry
->String
.Length
= SourceSymbolicName
.Length
;
2449 AssociatedEntry
->String
.MaximumLength
= AssociatedEntry
->String
.Length
+ sizeof(UNICODE_NULL
);
2450 AssociatedEntry
->String
.Buffer
= AllocatePool(AssociatedEntry
->String
.MaximumLength
);
2451 if (AssociatedEntry
->String
.Buffer
== NULL
)
2453 FreePool(AssociatedEntry
);
2454 FreePool(SourceSymbolicName
.Buffer
);
2455 return STATUS_INSUFFICIENT_RESOURCES
;
2458 /* Copy data & insert in list */
2459 RtlCopyMemory(AssociatedEntry
->String
.Buffer
, SourceSymbolicName
.Buffer
, SourceSymbolicName
.Length
);
2460 AssociatedEntry
->String
.Buffer
[SourceSymbolicName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
2461 AssociatedEntry
->DeviceInformation
= DeviceInformation
;
2462 InsertTailList(&TargetDeviceInformation
->AssociatedDevicesHead
, &AssociatedEntry
->AssociatedDevicesEntry
);
2465 FreePool(SourceSymbolicName
.Buffer
);
2466 return STATUS_SUCCESS
;
2473 MountMgrVolumeMountPointDeleted(IN PDEVICE_EXTENSION DeviceExtension
,
2475 IN NTSTATUS LockStatus
)
2480 HANDLE RemoteDatabase
;
2481 PDATABASE_ENTRY DatabaseEntry
;
2482 PUNIQUE_ID_REPLICATE UniqueIdReplicate
;
2483 PASSOCIATED_DEVICE_ENTRY AssociatedEntry
;
2484 PDEVICE_INFORMATION DeviceInformation
, TargetDeviceInformation
;
2485 UNICODE_STRING LinkTarget
, SourceDeviceName
, SourceSymbolicName
, TargetVolumeName
, VolumeName
, DbName
;
2487 /* Initialize string */
2488 LinkTarget
.Length
= 0;
2489 LinkTarget
.MaximumLength
= 0xC8;
2490 LinkTarget
.Buffer
= AllocatePool(LinkTarget
.MaximumLength
);
2491 if (LinkTarget
.Buffer
== NULL
)
2493 return STATUS_INSUFFICIENT_RESOURCES
;
2496 /* If the mount point was deleted, then, it changed!
2497 * Also use it to query some information
2499 Status
= MountMgrVolumeMountPointChanged(DeviceExtension
, Irp
, LockStatus
, &SourceDeviceName
, &SourceSymbolicName
, &TargetVolumeName
);
2500 /* Pending means DB are under synchronization, bail out */
2501 if (Status
== STATUS_PENDING
)
2503 FreePool(LinkTarget
.Buffer
);
2504 FreePool(SourceDeviceName
.Buffer
);
2505 FreePool(SourceSymbolicName
.Buffer
);
2506 return STATUS_SUCCESS
;
2508 else if (!NT_SUCCESS(Status
))
2510 FreePool(LinkTarget
.Buffer
);
2514 /* Query the device information */
2515 Status
= FindDeviceInfo(DeviceExtension
, &SourceDeviceName
, FALSE
, &DeviceInformation
);
2516 if (!NT_SUCCESS(Status
))
2518 /* If it failed, first try to get volume name */
2519 Status
= QueryVolumeName(0, NULL
, &SourceDeviceName
, &LinkTarget
, &VolumeName
);
2520 if (!NT_SUCCESS(Status
))
2522 /* Then, try to read the symlink */
2523 Status
= MountMgrQuerySymbolicLink(&SourceDeviceName
, &LinkTarget
);
2524 if (!NT_SUCCESS(Status
))
2526 FreePool(LinkTarget
.Buffer
);
2527 FreePool(SourceDeviceName
.Buffer
);
2528 FreePool(SourceSymbolicName
.Buffer
);
2534 FreePool(VolumeName
.Buffer
);
2537 FreePool(SourceDeviceName
.Buffer
);
2539 SourceDeviceName
.Length
= LinkTarget
.Length
;
2540 SourceDeviceName
.MaximumLength
= LinkTarget
.MaximumLength
;
2541 SourceDeviceName
.Buffer
= LinkTarget
.Buffer
;
2543 /* Now that we have the correct source, reattempt to query information */
2544 Status
= FindDeviceInfo(DeviceExtension
, &SourceDeviceName
, FALSE
, &DeviceInformation
);
2545 if (!NT_SUCCESS(Status
))
2547 FreePool(SourceDeviceName
.Buffer
);
2548 FreePool(SourceSymbolicName
.Buffer
);
2553 FreePool(SourceDeviceName
.Buffer
);
2555 /* Get information about target device */
2556 Status
= FindDeviceInfo(DeviceExtension
, &TargetVolumeName
, FALSE
, &TargetDeviceInformation
);
2557 if (!NT_SUCCESS(Status
))
2559 FreePool(SourceSymbolicName
.Buffer
);
2563 /* Open the remote database */
2564 RemoteDatabase
= OpenRemoteDatabase(DeviceInformation
, TRUE
);
2565 if (RemoteDatabase
== 0)
2567 FreePool(SourceSymbolicName
.Buffer
);
2568 return STATUS_INSUFFICIENT_RESOURCES
;
2571 /* Browse all the entries */
2575 DatabaseEntry
= GetRemoteDatabaseEntry(RemoteDatabase
, Offset
);
2576 if (DatabaseEntry
== NULL
)
2578 /* We didn't find ourselves, that's infortunate! */
2579 FreePool(SourceSymbolicName
.Buffer
);
2580 CloseRemoteDatabase(RemoteDatabase
);
2581 return STATUS_INVALID_PARAMETER
;
2584 /* Try to find ourselves */
2585 DbName
.MaximumLength
= DatabaseEntry
->SymbolicNameLength
;
2586 DbName
.Length
= DbName
.MaximumLength
;
2587 DbName
.Buffer
= (PWSTR
)((ULONG_PTR
)DatabaseEntry
+ DatabaseEntry
->SymbolicNameOffset
);
2588 if (RtlEqualUnicodeString(&TargetVolumeName
, &DbName
, TRUE
))
2593 Offset
+= DatabaseEntry
->EntrySize
;
2594 FreePool(DatabaseEntry
);
2597 /* Dereference ourselves */
2598 DatabaseEntry
->EntryReferences
--;
2599 if (DatabaseEntry
->EntryReferences
== 0)
2601 /* If we're still referenced, just update the entry */
2602 Status
= WriteRemoteDatabaseEntry(RemoteDatabase
, Offset
, DatabaseEntry
);
2606 /* Otherwise, delete the entry */
2607 Status
= DeleteRemoteDatabaseEntry(RemoteDatabase
, Offset
);
2608 if (!NT_SUCCESS(Status
))
2610 FreePool(DatabaseEntry
);
2611 FreePool(SourceSymbolicName
.Buffer
);
2612 CloseRemoteDatabase(RemoteDatabase
);
2616 /* Also, delete our unique ID replicated record */
2617 for (Entry
= DeviceInformation
->ReplicatedUniqueIdsListHead
.Flink
;
2618 Entry
!= &DeviceInformation
->ReplicatedUniqueIdsListHead
;
2619 Entry
= Entry
->Flink
)
2621 UniqueIdReplicate
= CONTAINING_RECORD(Entry
, UNIQUE_ID_REPLICATE
, ReplicatedUniqueIdsListEntry
);
2623 if (UniqueIdReplicate
->UniqueId
->UniqueIdLength
== DatabaseEntry
->UniqueIdLength
&&
2624 RtlCompareMemory(UniqueIdReplicate
->UniqueId
->UniqueId
,
2625 (PVOID
)((ULONG_PTR
)DatabaseEntry
+ DatabaseEntry
->UniqueIdOffset
),
2626 DatabaseEntry
->UniqueIdLength
) == DatabaseEntry
->UniqueIdLength
)
2632 /* It has to exist! */
2633 if (Entry
== &DeviceInformation
->ReplicatedUniqueIdsListHead
)
2635 FreePool(DatabaseEntry
);
2636 FreePool(SourceSymbolicName
.Buffer
);
2637 CloseRemoteDatabase(RemoteDatabase
);
2638 return STATUS_UNSUCCESSFUL
;
2641 /* Remove it and free it */
2642 RemoveEntryList(&UniqueIdReplicate
->ReplicatedUniqueIdsListEntry
);
2643 FreePool(UniqueIdReplicate
->UniqueId
);
2644 FreePool(UniqueIdReplicate
);
2647 /* We're done with the remote database */
2648 FreePool(DatabaseEntry
);
2649 CloseRemoteDatabase(RemoteDatabase
);
2651 /* Check write operation succeed */
2652 if (!NT_SUCCESS(Status
))
2654 FreePool(SourceSymbolicName
.Buffer
);
2658 /* Try to find our associated device entry */
2659 for (Entry
= TargetDeviceInformation
->AssociatedDevicesHead
.Flink
;
2660 Entry
!= &TargetDeviceInformation
->AssociatedDevicesHead
;
2661 Entry
= Entry
->Flink
)
2663 AssociatedEntry
= CONTAINING_RECORD(Entry
, ASSOCIATED_DEVICE_ENTRY
, AssociatedDevicesEntry
);
2665 /* If found, delete it */
2666 if (AssociatedEntry
->DeviceInformation
== DeviceInformation
&&
2667 RtlEqualUnicodeString(&AssociatedEntry
->String
, &SourceSymbolicName
, TRUE
))
2669 RemoveEntryList(&AssociatedEntry
->AssociatedDevicesEntry
);
2670 FreePool(AssociatedEntry
->String
.Buffer
);
2671 FreePool(AssociatedEntry
);
2677 FreePool(SourceSymbolicName
.Buffer
);
2678 return STATUS_SUCCESS
;
2686 MountMgrDeviceControl(IN PDEVICE_OBJECT DeviceObject
,
2689 PIO_STACK_LOCATION Stack
;
2690 NTSTATUS Status
, LockStatus
;
2691 PDEVICE_EXTENSION DeviceExtension
;
2693 Stack
= IoGetCurrentIrpStackLocation(Irp
);
2694 DeviceExtension
= DeviceObject
->DeviceExtension
;
2696 KeWaitForSingleObject(&(DeviceExtension
->DeviceLock
), Executive
, KernelMode
, FALSE
, NULL
);
2698 switch (Stack
->Parameters
.DeviceIoControl
.IoControlCode
)
2700 case IOCTL_MOUNTMGR_CREATE_POINT
:
2701 Status
= MountMgrCreatePoint(DeviceExtension
, Irp
);
2704 case IOCTL_MOUNTMGR_DELETE_POINTS
:
2705 Status
= MountMgrDeletePoints(DeviceExtension
, Irp
);
2708 case IOCTL_MOUNTMGR_QUERY_POINTS
:
2709 Status
= MountMgrQueryPoints(DeviceExtension
, Irp
);
2712 case IOCTL_MOUNTMGR_DELETE_POINTS_DBONLY
:
2713 Status
= MountMgrDeletePointsDbOnly(DeviceExtension
, Irp
);
2716 case IOCTL_MOUNTMGR_NEXT_DRIVE_LETTER
:
2717 Status
= MountMgrNextDriveLetter(DeviceExtension
, Irp
);
2720 case IOCTL_MOUNTMGR_AUTO_DL_ASSIGNMENTS
:
2721 DeviceExtension
->AutomaticDriveLetter
= TRUE
;
2722 Status
= STATUS_SUCCESS
;
2724 MountMgrAssignDriveLetters(DeviceExtension
);
2725 ReconcileAllDatabasesWithMaster(DeviceExtension
);
2726 WaitForOnlinesToComplete(DeviceExtension
);
2729 case IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_CREATED
:
2730 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
, 1, FALSE
);
2732 LockStatus
= WaitForRemoteDatabaseSemaphore(DeviceExtension
);
2733 KeWaitForSingleObject(&(DeviceExtension
->DeviceLock
), Executive
, KernelMode
, FALSE
, NULL
);
2734 Status
= MountMgrVolumeMountPointCreated(DeviceExtension
, Irp
, LockStatus
);
2735 if (NT_SUCCESS(LockStatus
))
2737 ReleaseRemoteDatabaseSemaphore(DeviceExtension
);
2742 case IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_DELETED
:
2743 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
, 1, FALSE
);
2745 LockStatus
= WaitForRemoteDatabaseSemaphore(DeviceExtension
);
2746 KeWaitForSingleObject(&(DeviceExtension
->DeviceLock
), Executive
, KernelMode
, FALSE
, NULL
);
2747 Status
= MountMgrVolumeMountPointDeleted(DeviceExtension
, Irp
, LockStatus
);
2748 if (NT_SUCCESS(LockStatus
))
2750 ReleaseRemoteDatabaseSemaphore(DeviceExtension
);
2755 case IOCTL_MOUNTMGR_CHANGE_NOTIFY
:
2756 Status
= MountMgrChangeNotify(DeviceExtension
, Irp
);
2759 case IOCTL_MOUNTMGR_KEEP_LINKS_WHEN_OFFLINE
:
2760 Status
= MountMgrKeepLinksWhenOffline(DeviceExtension
, Irp
);
2763 case IOCTL_MOUNTMGR_CHECK_UNPROCESSED_VOLUMES
:
2764 Status
= MountMgrCheckUnprocessedVolumes(DeviceExtension
, Irp
);
2767 case IOCTL_MOUNTMGR_VOLUME_ARRIVAL_NOTIFICATION
:
2768 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
, 1, FALSE
);
2769 Status
= MountMgrVolumeArrivalNotification(DeviceExtension
, Irp
);
2772 case IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATH
:
2773 Status
= MountMgrQueryDosVolumePath(DeviceExtension
, Irp
);
2776 case IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATHS
:
2777 Status
= MountMgrQueryDosVolumePaths(DeviceExtension
, Irp
);
2780 case IOCTL_MOUNTMGR_SCRUB_REGISTRY
:
2781 Status
= MountMgrScrubRegistry(DeviceExtension
);
2784 case IOCTL_MOUNTMGR_QUERY_AUTO_MOUNT
:
2785 Status
= MountMgrQueryAutoMount(DeviceExtension
, Irp
);
2788 case IOCTL_MOUNTMGR_SET_AUTO_MOUNT
:
2789 Status
= MountMgrSetAutoMount(DeviceExtension
, Irp
);
2792 case IOCTL_MOUNTMGR_DEFINE_UNIX_DRIVE
:
2793 case IOCTL_MOUNTMGR_QUERY_UNIX_DRIVE
:
2794 DPRINT1("Winism! Rewrite the caller!\n");
2796 Status
= STATUS_INVALID_DEVICE_REQUEST
;
2799 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
, 1, FALSE
);
2801 if (Status
!= STATUS_PENDING
)
2809 Irp
->IoStatus
.Status
= Status
;
2810 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);