3 * Copyright (C) 2011 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/mountmgr.c
22 * PURPOSE: Mount Manager
23 * PROGRAMMER: Pierre Schweitzer (pierre.schweitzer@reactos.org)
24 * Alex Ionescu (alex.ionescu@reactos.org)
32 #if defined(ALLOC_PRAGMA)
33 #pragma alloc_text(INIT, MountmgrReadNoAutoMount)
34 #pragma alloc_text(INIT, DriverEntry)
38 GUID MountedDevicesGuid
= {0x53F5630D, 0xB6BF, 0x11D0, {0x94, 0xF2, 0x00, 0xA0, 0xC9, 0x1E, 0xFB, 0x8B}};
40 PDEVICE_OBJECT gdeviceObject
;
44 static const WCHAR Cunc
[] = L
"\\??\\C:";
50 IsOffline(PUNICODE_STRING SymbolicName
)
53 ULONG IsOffline
, Default
;
54 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
56 /* Prepare to look in the registry to see if
57 * given volume is offline
59 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
60 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
61 QueryTable
[0].Name
= SymbolicName
->Buffer
;
62 QueryTable
[0].EntryContext
= &IsOffline
;
63 QueryTable
[0].DefaultType
= REG_DWORD
;
64 QueryTable
[0].DefaultLength
= sizeof(ULONG
);
65 QueryTable
[0].DefaultData
= &Default
;
70 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
75 if (!NT_SUCCESS(Status
))
80 return (IsOffline
!= 0);
87 HasDriveLetter(IN PDEVICE_INFORMATION DeviceInformation
)
89 PLIST_ENTRY NextEntry
;
90 PSYMLINK_INFORMATION SymlinkInfo
;
92 /* Browse all the symlinks to check if there is at least a drive letter */
93 for (NextEntry
= DeviceInformation
->SymbolicLinksListHead
.Flink
;
94 NextEntry
!= &DeviceInformation
->SymbolicLinksListHead
;
95 NextEntry
= NextEntry
->Flink
)
97 SymlinkInfo
= CONTAINING_RECORD(NextEntry
, SYMLINK_INFORMATION
, SymbolicLinksListEntry
);
99 if (IsDriveLetter(&SymlinkInfo
->Name
) && SymlinkInfo
->Online
)
112 CreateNewDriveLetterName(OUT PUNICODE_STRING DriveLetter
,
113 IN PUNICODE_STRING DeviceName
,
115 IN PMOUNTDEV_UNIQUE_ID UniqueId OPTIONAL
)
117 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
119 /* Allocate a big enough buffer to contain the symbolic link */
120 DriveLetter
->MaximumLength
= DosDevices
.Length
+ 3 * sizeof(WCHAR
);
121 DriveLetter
->Buffer
= AllocatePool(DriveLetter
->MaximumLength
);
122 if (!DriveLetter
->Buffer
)
124 return STATUS_INSUFFICIENT_RESOURCES
;
128 RtlCopyUnicodeString(DriveLetter
, &DosDevices
);
130 /* Update string to reflect real contents */
131 DriveLetter
->Length
= DosDevices
.Length
+ 2 * sizeof(WCHAR
);
132 DriveLetter
->Buffer
[DosDevices
.Length
/ sizeof(WCHAR
) + 2] = UNICODE_NULL
;
133 DriveLetter
->Buffer
[DosDevices
.Length
/ sizeof(WCHAR
) + 1] = L
':';
135 /* If caller wants a no drive entry */
136 if (Letter
== (UCHAR
)-1)
138 /* Then, create a no letter entry */
139 CreateNoDriveLetterEntry(UniqueId
);
140 FreePool(DriveLetter
->Buffer
);
141 return STATUS_UNSUCCESSFUL
;
145 /* Use the letter given by the caller */
146 DriveLetter
->Buffer
[DosDevices
.Length
/ sizeof(WCHAR
)] = (WCHAR
)Letter
;
147 Status
= GlobalCreateSymbolicLink(DriveLetter
, DeviceName
);
148 if (NT_SUCCESS(Status
))
154 /* If caller didn't provide a letter, let's find one for him */
156 if (RtlPrefixUnicodeString(&DeviceFloppy
, DeviceName
, TRUE
))
158 /* If the device is a floppy, start with letter A */
161 else if (RtlPrefixUnicodeString(&DeviceCdRom
, DeviceName
, TRUE
))
163 /* If the device is a CD-ROM, start with letter D */
168 /* Finally, if it's a disk, use C */
172 /* Try to affect a letter (up to Z, ofc) until it's possible */
173 for (; Letter
<= 'Z'; Letter
++)
175 DriveLetter
->Buffer
[DosDevices
.Length
/ sizeof(WCHAR
)] = (WCHAR
)Letter
;
176 Status
= GlobalCreateSymbolicLink(DriveLetter
, DeviceName
);
177 if (NT_SUCCESS(Status
))
179 DPRINT("Assigned drive %c: to %wZ\n", Letter
, DeviceName
);
184 /* We failed to allocate a letter */
185 FreePool(DriveLetter
->Buffer
);
186 DPRINT("Failed to create a drive letter for %wZ\n", DeviceName
);
194 QueryDeviceInformation(IN PUNICODE_STRING SymbolicName
,
195 OUT PUNICODE_STRING DeviceName OPTIONAL
,
196 OUT PMOUNTDEV_UNIQUE_ID
* UniqueId OPTIONAL
,
197 OUT PBOOLEAN Removable OPTIONAL
,
198 OUT PBOOLEAN GptDriveLetter OPTIONAL
,
199 OUT PBOOLEAN HasGuid OPTIONAL
,
200 IN OUT LPGUID StableGuid OPTIONAL
,
201 OUT PBOOLEAN Valid OPTIONAL
)
208 PMOUNTDEV_UNIQUE_ID Id
;
209 PFILE_OBJECT FileObject
;
210 PIO_STACK_LOCATION Stack
;
211 NTSTATUS Status
, IntStatus
;
212 PDEVICE_OBJECT DeviceObject
;
213 IO_STATUS_BLOCK IoStatusBlock
;
214 PARTITION_INFORMATION_EX PartitionInfo
;
215 STORAGE_DEVICE_NUMBER StorageDeviceNumber
;
216 VOLUME_GET_GPT_ATTRIBUTES_INFORMATION GptAttributes
;
218 /* Get device associated with the symbolic name */
219 Status
= IoGetDeviceObjectPointer(SymbolicName
,
220 FILE_READ_ATTRIBUTES
,
223 if (!NT_SUCCESS(Status
))
228 /* The associate FO can't have a file name */
229 if (FileObject
->FileName
.Length
)
231 ObDereferenceObject(FileObject
);
232 return STATUS_OBJECT_NAME_NOT_FOUND
;
235 /* Check if it's removable & return to the user (if asked to) */
236 IsRemovable
= (FileObject
->DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
);
239 *Removable
= IsRemovable
;
242 /* Get the attached device */
243 DeviceObject
= IoGetAttachedDeviceReference(FileObject
->DeviceObject
);
245 /* If we've been asked for a GPT drive letter */
248 /* Consider it has one */
249 *GptDriveLetter
= TRUE
;
253 /* Query the GPT attributes */
254 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
255 Irp
= IoBuildDeviceIoControlRequest(IOCTL_VOLUME_GET_GPT_ATTRIBUTES
,
260 sizeof(GptAttributes
),
266 ObDereferenceObject(DeviceObject
);
267 ObDereferenceObject(FileObject
);
268 return STATUS_INSUFFICIENT_RESOURCES
;
271 Status
= IoCallDriver(DeviceObject
, Irp
);
272 if (Status
== STATUS_PENDING
)
274 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
275 Status
= IoStatusBlock
.Status
;
278 /* In case of failure, don't fail, that's no vital */
279 if (!NT_SUCCESS(Status
))
281 Status
= STATUS_SUCCESS
;
283 /* Check if it has a drive letter */
284 else if (!(GptAttributes
.GptAttributes
&
285 GPT_BASIC_DATA_ATTRIBUTE_NO_DRIVE_LETTER
))
287 *GptDriveLetter
= FALSE
;
292 /* If caller wants to know if there's valid contents */
295 /* Suppose it's not OK */
300 /* Query partitions information */
301 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
302 Irp
= IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_PARTITION_INFO_EX
,
307 sizeof(PartitionInfo
),
313 ObDereferenceObject(DeviceObject
);
314 ObDereferenceObject(FileObject
);
315 return STATUS_INSUFFICIENT_RESOURCES
;
318 Status
= IoCallDriver(DeviceObject
, Irp
);
319 if (Status
== STATUS_PENDING
)
321 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
322 Status
= IoStatusBlock
.Status
;
325 /* Once again here, failure isn't major */
326 if (!NT_SUCCESS(Status
))
328 Status
= STATUS_SUCCESS
;
330 /* Verify we know something in */
331 else if (PartitionInfo
.PartitionStyle
== PARTITION_STYLE_MBR
&&
332 IsRecognizedPartition(PartitionInfo
.Mbr
.PartitionType
))
337 /* It looks correct, ensure it is & query device number */
340 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
341 Irp
= IoBuildDeviceIoControlRequest(IOCTL_STORAGE_GET_DEVICE_NUMBER
,
345 &StorageDeviceNumber
,
346 sizeof(StorageDeviceNumber
),
352 ObDereferenceObject(DeviceObject
);
353 ObDereferenceObject(FileObject
);
354 return STATUS_INSUFFICIENT_RESOURCES
;
357 Status
= IoCallDriver(DeviceObject
, Irp
);
358 if (Status
== STATUS_PENDING
)
360 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
361 Status
= IoStatusBlock
.Status
;
364 if (!NT_SUCCESS(Status
))
366 Status
= STATUS_SUCCESS
;
376 /* If caller needs device name */
379 /* Allocate a buffer just to request length */
380 Name
= AllocatePool(sizeof(MOUNTDEV_NAME
));
383 ObDereferenceObject(DeviceObject
);
384 ObDereferenceObject(FileObject
);
385 return STATUS_INSUFFICIENT_RESOURCES
;
388 /* Query device name */
389 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
390 Irp
= IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_DEVICE_NAME
,
395 sizeof(MOUNTDEV_NAME
),
402 ObDereferenceObject(DeviceObject
);
403 ObDereferenceObject(FileObject
);
404 return STATUS_INSUFFICIENT_RESOURCES
;
407 Stack
= IoGetNextIrpStackLocation(Irp
);
408 Stack
->FileObject
= FileObject
;
410 Status
= IoCallDriver(DeviceObject
, Irp
);
411 if (Status
== STATUS_PENDING
)
413 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
414 Status
= IoStatusBlock
.Status
;
417 /* Now, we've got the correct length */
418 if (Status
== STATUS_BUFFER_OVERFLOW
)
420 Size
= Name
->NameLength
+ sizeof(MOUNTDEV_NAME
);
424 /* Allocate proper size */
425 Name
= AllocatePool(Size
);
428 ObDereferenceObject(DeviceObject
);
429 ObDereferenceObject(FileObject
);
430 return STATUS_INSUFFICIENT_RESOURCES
;
433 /* And query name (for real that time) */
434 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
435 Irp
= IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_DEVICE_NAME
,
447 ObDereferenceObject(DeviceObject
);
448 ObDereferenceObject(FileObject
);
449 return STATUS_INSUFFICIENT_RESOURCES
;
452 Stack
= IoGetNextIrpStackLocation(Irp
);
453 Stack
->FileObject
= FileObject
;
455 Status
= IoCallDriver(DeviceObject
, Irp
);
456 if (Status
== STATUS_PENDING
)
458 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
459 Status
= IoStatusBlock
.Status
;
463 if (NT_SUCCESS(Status
))
465 /* Copy back found name to the caller */
466 DeviceName
->Length
= Name
->NameLength
;
467 DeviceName
->MaximumLength
= Name
->NameLength
+ sizeof(WCHAR
);
468 DeviceName
->Buffer
= AllocatePool(DeviceName
->MaximumLength
);
469 if (!DeviceName
->Buffer
)
471 Status
= STATUS_INSUFFICIENT_RESOURCES
;
475 RtlCopyMemory(DeviceName
->Buffer
, Name
->Name
, Name
->NameLength
);
476 DeviceName
->Buffer
[Name
->NameLength
/ sizeof(WCHAR
)] = UNICODE_NULL
;
483 if (!NT_SUCCESS(Status
))
485 ObDereferenceObject(DeviceObject
);
486 ObDereferenceObject(FileObject
);
490 /* If caller wants device unique ID */
493 /* Prepare buffer to probe length */
494 Id
= AllocatePool(sizeof(MOUNTDEV_UNIQUE_ID
));
497 ObDereferenceObject(DeviceObject
);
498 ObDereferenceObject(FileObject
);
499 return STATUS_INSUFFICIENT_RESOURCES
;
502 /* Query unique ID length */
503 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
504 Irp
= IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_UNIQUE_ID
,
509 sizeof(MOUNTDEV_UNIQUE_ID
),
516 ObDereferenceObject(DeviceObject
);
517 ObDereferenceObject(FileObject
);
518 return STATUS_INSUFFICIENT_RESOURCES
;
521 Stack
= IoGetNextIrpStackLocation(Irp
);
522 Stack
->FileObject
= FileObject
;
524 Status
= IoCallDriver(DeviceObject
, Irp
);
525 if (Status
== STATUS_PENDING
)
527 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
528 Status
= IoStatusBlock
.Status
;
531 /* Retry with appropriate length */
532 if (Status
== STATUS_BUFFER_OVERFLOW
)
534 Size
= Id
->UniqueIdLength
+ sizeof(MOUNTDEV_UNIQUE_ID
);
538 /* Allocate the correct buffer */
539 Id
= AllocatePool(Size
);
542 ObDereferenceObject(DeviceObject
);
543 ObDereferenceObject(FileObject
);
544 return STATUS_INSUFFICIENT_RESOURCES
;
547 /* Query unique ID */
548 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
549 Irp
= IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_UNIQUE_ID
,
561 ObDereferenceObject(DeviceObject
);
562 ObDereferenceObject(FileObject
);
563 return STATUS_INSUFFICIENT_RESOURCES
;
566 Stack
= IoGetNextIrpStackLocation(Irp
);
567 Stack
->FileObject
= FileObject
;
569 Status
= IoCallDriver(DeviceObject
, Irp
);
570 if (Status
== STATUS_PENDING
)
572 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
573 Status
= IoStatusBlock
.Status
;
577 /* Hands back unique ID */
578 if (NT_SUCCESS(Status
))
584 /* In case of failure, also free the rest */
586 if (DeviceName
->Length
)
588 FreePool(DeviceName
->Buffer
);
591 ObDereferenceObject(DeviceObject
);
592 ObDereferenceObject(FileObject
);
598 /* If user wants to know about GUID */
601 /* Query device stable GUID */
602 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
603 Irp
= IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_STABLE_GUID
,
614 ObDereferenceObject(DeviceObject
);
615 ObDereferenceObject(FileObject
);
616 return STATUS_INSUFFICIENT_RESOURCES
;
619 Stack
= IoGetNextIrpStackLocation(Irp
);
620 Stack
->FileObject
= FileObject
;
622 IntStatus
= IoCallDriver(DeviceObject
, Irp
);
623 if (IntStatus
== STATUS_PENDING
)
625 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
626 IntStatus
= IoStatusBlock
.Status
;
629 *HasGuid
= NT_SUCCESS(IntStatus
);
632 ObDereferenceObject(DeviceObject
);
633 ObDereferenceObject(FileObject
);
641 FindDeviceInfo(IN PDEVICE_EXTENSION DeviceExtension
,
642 IN PUNICODE_STRING SymbolicName
,
643 IN BOOLEAN DeviceNameGiven
,
644 OUT PDEVICE_INFORMATION
* DeviceInformation
)
647 PLIST_ENTRY NextEntry
;
648 UNICODE_STRING DeviceName
;
649 PDEVICE_INFORMATION DeviceInfo
= NULL
;
651 /* If a device name was given, use it */
654 DeviceName
.Length
= SymbolicName
->Length
;
655 DeviceName
.Buffer
= SymbolicName
->Buffer
;
659 /* Otherwise, query it */
660 Status
= QueryDeviceInformation(SymbolicName
,
665 if (!NT_SUCCESS(Status
))
671 /* Look for device information matching devive */
672 for (NextEntry
= DeviceExtension
->DeviceListHead
.Flink
;
673 NextEntry
!= &(DeviceExtension
->DeviceListHead
);
674 NextEntry
= NextEntry
->Flink
)
676 DeviceInfo
= CONTAINING_RECORD(NextEntry
,
680 if (RtlEqualUnicodeString(&DeviceName
, &(DeviceInfo
->DeviceName
), TRUE
))
686 /* Release our buffer if required */
687 if (!DeviceNameGiven
)
689 FreePool(DeviceName
.Buffer
);
692 /* Return found information */
693 if (NextEntry
== &(DeviceExtension
->DeviceListHead
))
695 return STATUS_OBJECT_NAME_NOT_FOUND
;
698 *DeviceInformation
= DeviceInfo
;
699 return STATUS_SUCCESS
;
706 MountMgrFreeDeadDeviceInfo(IN PDEVICE_INFORMATION DeviceInformation
)
708 FreePool(DeviceInformation
->SymbolicName
.Buffer
);
709 FreePool(DeviceInformation
);
716 MountMgrFreeMountedDeviceInfo(IN PDEVICE_INFORMATION DeviceInformation
)
718 PLIST_ENTRY NextEntry
;
719 PSYMLINK_INFORMATION SymLink
;
720 PUNIQUE_ID_REPLICATE UniqueId
;
721 PASSOCIATED_DEVICE_ENTRY AssociatedDevice
;
723 /* Purge symbolic links list */
724 while (!IsListEmpty(&(DeviceInformation
->SymbolicLinksListHead
)))
726 NextEntry
= RemoveHeadList(&(DeviceInformation
->SymbolicLinksListHead
));
727 SymLink
= CONTAINING_RECORD(NextEntry
, SYMLINK_INFORMATION
, SymbolicLinksListEntry
);
729 GlobalDeleteSymbolicLink(&(SymLink
->Name
));
730 FreePool(SymLink
->Name
.Buffer
);
733 /* Purge replicated unique IDs list */
734 while (!IsListEmpty(&(DeviceInformation
->ReplicatedUniqueIdsListHead
)))
736 NextEntry
= RemoveHeadList(&(DeviceInformation
->ReplicatedUniqueIdsListHead
));
737 UniqueId
= CONTAINING_RECORD(NextEntry
, UNIQUE_ID_REPLICATE
, ReplicatedUniqueIdsListEntry
);
739 FreePool(UniqueId
->UniqueId
);
743 while (!IsListEmpty(&(DeviceInformation
->AssociatedDevicesHead
)))
745 NextEntry
= RemoveHeadList(&(DeviceInformation
->AssociatedDevicesHead
));
746 AssociatedDevice
= CONTAINING_RECORD(NextEntry
, ASSOCIATED_DEVICE_ENTRY
, AssociatedDevicesEntry
);
748 FreePool(AssociatedDevice
->String
.Buffer
);
749 FreePool(AssociatedDevice
);
752 /* Free the rest of the buffers */
753 FreePool(DeviceInformation
->SymbolicName
.Buffer
);
754 if (DeviceInformation
->KeepLinks
)
756 FreePool(DeviceInformation
->UniqueId
);
758 FreePool(DeviceInformation
->DeviceName
.Buffer
);
760 /* Finally, stop waiting for notifications for this device */
761 if (DeviceInformation
->TargetDeviceNotificationEntry
)
763 IoUnregisterPlugPlayNotification(DeviceInformation
->TargetDeviceNotificationEntry
);
771 MountMgrFreeSavedLink(IN PSAVED_LINK_INFORMATION SavedLinkInformation
)
773 PLIST_ENTRY NextEntry
;
774 PSYMLINK_INFORMATION SymlinkInformation
;
776 /* For all the saved links */
777 while (!IsListEmpty(&(SavedLinkInformation
->SymbolicLinksListHead
)))
779 NextEntry
= RemoveHeadList(&(SavedLinkInformation
->SymbolicLinksListHead
));
780 SymlinkInformation
= CONTAINING_RECORD(NextEntry
, SYMLINK_INFORMATION
, SymbolicLinksListEntry
);
782 /* Remove from system & free */
783 GlobalDeleteSymbolicLink(&(SymlinkInformation
->Name
));
784 FreePool(SymlinkInformation
->Name
.Buffer
);
785 FreePool(SymlinkInformation
);
788 /* And free unique ID & entry */
789 FreePool(SavedLinkInformation
->UniqueId
);
790 FreePool(SavedLinkInformation
);
799 MountMgrUnload(IN
struct _DRIVER_OBJECT
*DriverObject
)
801 PLIST_ENTRY NextEntry
;
802 PUNIQUE_ID_WORK_ITEM WorkItem
;
803 PDEVICE_EXTENSION DeviceExtension
;
804 PDEVICE_INFORMATION DeviceInformation
;
805 PSAVED_LINK_INFORMATION SavedLinkInformation
;
807 UNREFERENCED_PARAMETER(DriverObject
);
809 /* Don't get notification any longer */
810 IoUnregisterShutdownNotification(gdeviceObject
);
812 /* Free registry buffer */
813 DeviceExtension
= gdeviceObject
->DeviceExtension
;
814 if (DeviceExtension
->RegistryPath
.Buffer
)
816 FreePool(DeviceExtension
->RegistryPath
.Buffer
);
817 DeviceExtension
->RegistryPath
.Buffer
= NULL
;
820 InterlockedExchange(&Unloading
, TRUE
);
822 KeInitializeEvent(&UnloadEvent
, NotificationEvent
, FALSE
);
824 /* Wait for workers to finish */
825 if (InterlockedIncrement(&DeviceExtension
->WorkerReferences
))
827 KeReleaseSemaphore(&(DeviceExtension
->WorkerSemaphore
),
828 IO_NO_INCREMENT
, 1, FALSE
);
830 KeWaitForSingleObject(&UnloadEvent
, Executive
, KernelMode
, FALSE
, NULL
);
834 InterlockedDecrement(&(DeviceExtension
->WorkerReferences
));
837 /* Don't get any notification any longer² */
838 IoUnregisterPlugPlayNotification(DeviceExtension
->NotificationEntry
);
840 /* Acquire the driver exclusively */
841 KeWaitForSingleObject(&(DeviceExtension
->DeviceLock
), Executive
, KernelMode
,
844 /* Clear offline devices list */
845 while (!IsListEmpty(&(DeviceExtension
->OfflineDeviceListHead
)))
847 NextEntry
= RemoveHeadList(&(DeviceExtension
->OfflineDeviceListHead
));
848 DeviceInformation
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
849 MountMgrFreeDeadDeviceInfo(DeviceInformation
);
852 /* Clear saved links list */
853 while (!IsListEmpty(&(DeviceExtension
->SavedLinksListHead
)))
855 NextEntry
= RemoveHeadList(&(DeviceExtension
->SavedLinksListHead
));
856 SavedLinkInformation
= CONTAINING_RECORD(NextEntry
, SAVED_LINK_INFORMATION
, SavedLinksListEntry
);
857 MountMgrFreeSavedLink(SavedLinkInformation
);
860 /* Clear workers list */
861 while (!IsListEmpty(&(DeviceExtension
->UniqueIdWorkerItemListHead
)))
863 NextEntry
= RemoveHeadList(&(DeviceExtension
->UniqueIdWorkerItemListHead
));
864 WorkItem
= CONTAINING_RECORD(NextEntry
, UNIQUE_ID_WORK_ITEM
, UniqueIdWorkerItemListEntry
);
866 KeClearEvent(&UnloadEvent
);
867 WorkItem
->Event
= &UnloadEvent
;
869 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
,
872 IoCancelIrp(WorkItem
->Irp
);
873 KeWaitForSingleObject(&UnloadEvent
, Executive
, KernelMode
, FALSE
, NULL
);
875 IoFreeIrp(WorkItem
->Irp
);
876 FreePool(WorkItem
->DeviceName
.Buffer
);
877 FreePool(WorkItem
->IrpBuffer
);
880 KeWaitForSingleObject(&(DeviceExtension
->DeviceLock
), Executive
, KernelMode
,
884 /* If we have drive letter data, release */
885 if (DeviceExtension
->DriveLetterData
)
887 FreePool(DeviceExtension
->DriveLetterData
);
888 DeviceExtension
->DriveLetterData
= NULL
;
891 /* Release driver & quit */
892 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
, 1, FALSE
);
894 GlobalDeleteSymbolicLink(&DosDevicesMount
);
895 IoDeleteDevice(gdeviceObject
);
903 MountmgrReadNoAutoMount(IN PUNICODE_STRING RegistryPath
)
906 ULONG Result
, Default
= 0;
907 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
909 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
911 /* Simply read data from register */
912 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
913 QueryTable
[0].Name
= L
"NoAutoMount";
914 QueryTable
[0].EntryContext
= &Result
;
915 QueryTable
[0].DefaultType
= REG_NONE
;
916 QueryTable
[0].DefaultData
= &Default
;
917 QueryTable
[0].DefaultLength
= sizeof(ULONG
);
919 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
920 RegistryPath
->Buffer
,
924 if (!NT_SUCCESS(Status
))
926 return (Default
!= 0);
929 return (Result
!= 0);
936 MountMgrMountedDeviceArrival(IN PDEVICE_EXTENSION DeviceExtension
,
937 IN PUNICODE_STRING SymbolicName
,
938 IN BOOLEAN ManuallyRegistered
)
943 ULONG SymLinkCount
, i
;
944 PLIST_ENTRY NextEntry
;
945 PUNICODE_STRING SymLinks
;
946 NTSTATUS Status
, IntStatus
;
947 OBJECT_ATTRIBUTES ObjectAttributes
;
948 PSYMLINK_INFORMATION SymlinkInformation
;
949 PMOUNTDEV_UNIQUE_ID UniqueId
, NewUniqueId
;
950 PSAVED_LINK_INFORMATION SavedLinkInformation
;
951 PDEVICE_INFORMATION DeviceInformation
, CurrentDevice
;
952 WCHAR CSymLinkBuffer
[RTL_NUMBER_OF(Cunc
)], LinkTargetBuffer
[MAX_PATH
];
953 UNICODE_STRING TargetDeviceName
, SuggestedLinkName
, DeviceName
, VolumeName
, DriveLetter
, LinkTarget
, CSymLink
;
954 BOOLEAN HasGuid
, HasGptDriveLetter
, Valid
, UseOnlyIfThereAreNoOtherLinks
, IsDrvLetter
, IsOff
, IsVolumeName
, LinkError
;
956 /* New device = new structure to represent it */
957 DeviceInformation
= AllocatePool(sizeof(DEVICE_INFORMATION
));
958 if (!DeviceInformation
)
960 return STATUS_INSUFFICIENT_RESOURCES
;
963 /* Initialise device structure */
964 RtlZeroMemory(DeviceInformation
, sizeof(DEVICE_INFORMATION
));
965 InitializeListHead(&(DeviceInformation
->SymbolicLinksListHead
));
966 InitializeListHead(&(DeviceInformation
->ReplicatedUniqueIdsListHead
));
967 InitializeListHead(&(DeviceInformation
->AssociatedDevicesHead
));
968 DeviceInformation
->SymbolicName
.Length
= SymbolicName
->Length
;
969 DeviceInformation
->SymbolicName
.MaximumLength
= SymbolicName
->Length
+ sizeof(UNICODE_NULL
);
970 DeviceInformation
->SymbolicName
.Buffer
= AllocatePool(DeviceInformation
->SymbolicName
.MaximumLength
);
971 if (!DeviceInformation
->SymbolicName
.Buffer
)
973 FreePool(DeviceInformation
);
974 return STATUS_INSUFFICIENT_RESOURCES
;
977 /* Copy symbolic name */
978 RtlCopyMemory(DeviceInformation
->SymbolicName
.Buffer
, SymbolicName
->Buffer
, SymbolicName
->Length
);
979 DeviceInformation
->SymbolicName
.Buffer
[DeviceInformation
->SymbolicName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
980 DeviceInformation
->ManuallyRegistered
= ManuallyRegistered
;
981 DeviceInformation
->DeviceExtension
= DeviceExtension
;
983 /* Query as much data as possible about device */
984 Status
= QueryDeviceInformation(SymbolicName
,
987 &(DeviceInformation
->Removable
),
992 if (!NT_SUCCESS(Status
))
994 KeWaitForSingleObject(&(DeviceExtension
->DeviceLock
), Executive
, KernelMode
, FALSE
, NULL
);
996 for (NextEntry
= DeviceExtension
->OfflineDeviceListHead
.Flink
;
997 NextEntry
!= &(DeviceExtension
->OfflineDeviceListHead
);
998 NextEntry
= NextEntry
->Flink
)
1000 CurrentDevice
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
1002 if (RtlEqualUnicodeString(&(DeviceInformation
->SymbolicName
), &(CurrentDevice
->SymbolicName
), TRUE
))
1008 if (NextEntry
!= &(DeviceExtension
->OfflineDeviceListHead
))
1010 MountMgrFreeDeadDeviceInfo(DeviceInformation
);
1014 InsertTailList(&(DeviceExtension
->OfflineDeviceListHead
), &(DeviceInformation
->DeviceListEntry
));
1017 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
, 1, FALSE
);
1022 /* Save gathered data */
1023 DeviceInformation
->UniqueId
= UniqueId
;
1024 DeviceInformation
->DeviceName
= TargetDeviceName
;
1025 DeviceInformation
->KeepLinks
= FALSE
;
1027 /* If we found system partition, mark it */
1028 if (DeviceExtension
->DriveLetterData
&& UniqueId
->UniqueIdLength
== DeviceExtension
->DriveLetterData
->UniqueIdLength
)
1030 if (RtlCompareMemory(UniqueId
->UniqueId
, DeviceExtension
->DriveLetterData
->UniqueId
, UniqueId
->UniqueIdLength
)
1031 == UniqueId
->UniqueIdLength
)
1033 IoSetSystemPartition(&TargetDeviceName
);
1037 /* Check suggested link name */
1038 Status
= QuerySuggestedLinkName(&(DeviceInformation
->SymbolicName
),
1040 &UseOnlyIfThereAreNoOtherLinks
);
1041 if (!NT_SUCCESS(Status
))
1043 SuggestedLinkName
.Buffer
= NULL
;
1046 /* If it's OK, set it and save its letter (if any) */
1047 if (SuggestedLinkName
.Buffer
&& IsDriveLetter(&SuggestedLinkName
))
1049 DeviceInformation
->SuggestedDriveLetter
= (UCHAR
)SuggestedLinkName
.Buffer
[LETTER_POSITION
];
1052 /* Acquire driver exclusively */
1053 KeWaitForSingleObject(&(DeviceExtension
->DeviceLock
), Executive
, KernelMode
, FALSE
, NULL
);
1055 /* Check if we already have device in to prevent double registration */
1056 for (NextEntry
= DeviceExtension
->DeviceListHead
.Flink
;
1057 NextEntry
!= &(DeviceExtension
->DeviceListHead
);
1058 NextEntry
= NextEntry
->Flink
)
1060 CurrentDevice
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
1062 if (RtlEqualUnicodeString(&(CurrentDevice
->DeviceName
), &TargetDeviceName
, TRUE
))
1068 /* If we found it, clear ours, and return success, all correct */
1069 if (NextEntry
!= &(DeviceExtension
->DeviceListHead
))
1071 if (SuggestedLinkName
.Buffer
)
1073 FreePool(SuggestedLinkName
.Buffer
);
1077 FreePool(TargetDeviceName
.Buffer
);
1078 FreePool(DeviceInformation
->DeviceName
.Buffer
);
1079 FreePool(DeviceInformation
);
1081 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
, 1, FALSE
);
1083 return STATUS_SUCCESS
;
1086 /* Check if there are symlinks associated with our device in registry */
1087 Status
= QuerySymbolicLinkNamesFromStorage(DeviceExtension
,
1089 (SuggestedLinkName
.Buffer
) ? &SuggestedLinkName
: NULL
,
1090 UseOnlyIfThereAreNoOtherLinks
,
1096 /* If our device is a CD-ROM */
1097 if (RtlPrefixUnicodeString(&DeviceCdRom
, &TargetDeviceName
, TRUE
))
1099 LinkTarget
.Length
= 0;
1100 LinkTarget
.MaximumLength
= sizeof(LinkTargetBuffer
);
1101 LinkTarget
.Buffer
= LinkTargetBuffer
;
1103 RtlCopyMemory(CSymLinkBuffer
, Cunc
, sizeof(Cunc
));
1104 RtlInitUnicodeString(&CSymLink
, CSymLinkBuffer
);
1106 /* Start checking all letters that could have been associated */
1107 for (Letter
= L
'D'; Letter
<= L
'Z'; Letter
++)
1109 CSymLink
.Buffer
[LETTER_POSITION
] = Letter
;
1111 InitializeObjectAttributes(&ObjectAttributes
,
1113 OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
,
1117 /* Try to open the associated symlink */
1118 Status
= ZwOpenSymbolicLinkObject(&LinkHandle
, SYMBOLIC_LINK_QUERY
, &ObjectAttributes
);
1119 if (!NT_SUCCESS(Status
))
1124 /* And query its target */
1125 Status
= ZwQuerySymbolicLinkObject(LinkHandle
, &LinkTarget
, NULL
);
1126 ZwClose(LinkHandle
);
1128 if (!NT_SUCCESS(Status
))
1133 IntStatus
= STATUS_UNSUCCESSFUL
;
1134 if (!RtlEqualUnicodeString(&LinkTarget
, &DeviceInformation
->DeviceName
, FALSE
))
1139 /* This link is matching our device, whereas it's not supposed to have any
1140 * symlink associated.
1145 IoDeleteSymbolicLink(&CSymLink
);
1149 /* Now, for all the symlinks, check for ours */
1150 for (i
= 0; i
< SymLinkCount
; i
++)
1152 if (IsDriveLetter(&(SymLinks
[i
])))
1154 /* If it exists, that's correct */
1155 if (SymLinks
[i
].Buffer
[LETTER_POSITION
] == Letter
)
1157 IntStatus
= STATUS_SUCCESS
;
1162 /* Useless link, delete it */
1163 if (IntStatus
== STATUS_UNSUCCESSFUL
)
1165 IoDeleteSymbolicLink(&CSymLink
);
1170 /* Suggested name is no longer required */
1171 if (SuggestedLinkName
.Buffer
)
1173 FreePool(SuggestedLinkName
.Buffer
);
1176 /* If if failed, ensure we don't take symlinks into account */
1177 if (!NT_SUCCESS(Status
))
1183 /* Now we queried them, remove the symlinks */
1184 SavedLinkInformation
= RemoveSavedLinks(DeviceExtension
, UniqueId
);
1186 IsDrvLetter
= FALSE
;
1188 IsVolumeName
= FALSE
;
1189 /* For all the symlinks */
1190 for (i
= 0; i
< SymLinkCount
; i
++)
1192 /* Check if our device is a volume */
1193 if (MOUNTMGR_IS_VOLUME_NAME(&(SymLinks
[i
])))
1195 IsVolumeName
= TRUE
;
1197 /* If it has a drive letter */
1198 else if (IsDriveLetter(&(SymLinks
[i
])))
1202 DeleteFromLocalDatabase(&(SymLinks
[i
]), UniqueId
);
1211 /* And recreate the symlink to our device */
1212 Status
= GlobalCreateSymbolicLink(&(SymLinks
[i
]), &TargetDeviceName
);
1213 if (!NT_SUCCESS(Status
))
1217 if ((SavedLinkInformation
&& !RedirectSavedLink(SavedLinkInformation
, &(SymLinks
[i
]), &TargetDeviceName
)) ||
1218 !SavedLinkInformation
)
1220 Status
= QueryDeviceInformation(&(SymLinks
[i
]), &DeviceName
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
1221 if (NT_SUCCESS(Status
))
1223 LinkError
= RtlEqualUnicodeString(&TargetDeviceName
, &DeviceName
, TRUE
);
1224 FreePool(DeviceName
.Buffer
);
1229 if (IsDriveLetter(&(SymLinks
[i
])))
1231 IsDrvLetter
= FALSE
;
1232 DeleteFromLocalDatabase(&(SymLinks
[i
]), UniqueId
);
1235 FreePool(SymLinks
[i
].Buffer
);
1241 /* Check if was offline */
1242 if (IsOffline(&(SymLinks
[i
])))
1247 /* Finally, associate this symlink with the device */
1248 SymlinkInformation
= AllocatePool(sizeof(SYMLINK_INFORMATION
));
1249 if (!SymlinkInformation
)
1251 GlobalDeleteSymbolicLink(&(SymLinks
[i
]));
1252 FreePool(SymLinks
[i
].Buffer
);
1256 SymlinkInformation
->Name
= SymLinks
[i
];
1257 SymlinkInformation
->Online
= TRUE
;
1259 InsertTailList(&(DeviceInformation
->SymbolicLinksListHead
),
1260 &(SymlinkInformation
->SymbolicLinksListEntry
));
1263 /* Now, for all the recreated symlinks, notify their recreation */
1264 for (NextEntry
= DeviceInformation
->SymbolicLinksListHead
.Flink
;
1265 NextEntry
!= &(DeviceInformation
->SymbolicLinksListHead
);
1266 NextEntry
= NextEntry
->Flink
)
1268 SymlinkInformation
= CONTAINING_RECORD(NextEntry
, SYMLINK_INFORMATION
, SymbolicLinksListEntry
);
1270 SendLinkCreated(&(SymlinkInformation
->Name
));
1273 /* If we had saved links, it's time to free them */
1274 if (SavedLinkInformation
)
1276 MountMgrFreeSavedLink(SavedLinkInformation
);
1279 /* If our device doesn't have a volume name */
1282 /* It's time to create one */
1283 Status
= CreateNewVolumeName(&VolumeName
, NULL
);
1284 if (NT_SUCCESS(Status
))
1286 /* Write it to global database */
1287 RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE
,
1292 UniqueId
->UniqueIdLength
);
1294 /* And create the symlink */
1295 GlobalCreateSymbolicLink(&VolumeName
, &TargetDeviceName
);
1297 SymlinkInformation
= AllocatePool(sizeof(SYMLINK_INFORMATION
));
1298 if (!SymlinkInformation
)
1300 FreePool(VolumeName
.Buffer
);
1302 /* Finally, associate it with the device and notify creation */
1305 SymlinkInformation
->Name
= VolumeName
;
1306 SymlinkInformation
->Online
= TRUE
;
1307 InsertTailList(&(DeviceInformation
->SymbolicLinksListHead
),
1308 &(SymlinkInformation
->SymbolicLinksListEntry
));
1310 SendLinkCreated(&VolumeName
);
1315 /* If we found a drive letter, then, ignore the suggested one */
1318 DeviceInformation
->SuggestedDriveLetter
= 0;
1320 /* Else, it's time to set up one */
1321 else if ((DeviceExtension
->NoAutoMount
|| DeviceInformation
->Removable
) &&
1322 DeviceExtension
->AutomaticDriveLetter
&&
1323 (HasGptDriveLetter
|| DeviceInformation
->SuggestedDriveLetter
) &&
1324 !HasNoDriveLetterEntry(UniqueId
))
1326 /* Create a new drive letter */
1327 Status
= CreateNewDriveLetterName(&DriveLetter
, &TargetDeviceName
,
1328 DeviceInformation
->SuggestedDriveLetter
,
1330 if (!NT_SUCCESS(Status
))
1332 CreateNoDriveLetterEntry(UniqueId
);
1336 /* Save it to global database */
1337 RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE
,
1342 UniqueId
->UniqueIdLength
);
1344 /* Associate it with the device and notify creation */
1345 SymlinkInformation
= AllocatePool(sizeof(SYMLINK_INFORMATION
));
1346 if (!SymlinkInformation
)
1348 FreePool(DriveLetter
.Buffer
);
1352 SymlinkInformation
->Name
= DriveLetter
;
1353 SymlinkInformation
->Online
= TRUE
;
1354 InsertTailList(&(DeviceInformation
->SymbolicLinksListHead
),
1355 &(SymlinkInformation
->SymbolicLinksListEntry
));
1357 SendLinkCreated(&DriveLetter
);
1362 /* If that's a PnP device, register for notifications */
1363 if (!ManuallyRegistered
)
1365 RegisterForTargetDeviceNotification(DeviceExtension
, DeviceInformation
);
1368 /* Finally, insert the device into our devices list */
1369 InsertTailList(&(DeviceExtension
->DeviceListHead
), &(DeviceInformation
->DeviceListEntry
));
1371 /* Copy device unique ID */
1372 NewUniqueId
= AllocatePool(UniqueId
->UniqueIdLength
+ sizeof(MOUNTDEV_UNIQUE_ID
));
1375 NewUniqueId
->UniqueIdLength
= UniqueId
->UniqueIdLength
;
1376 RtlCopyMemory(NewUniqueId
->UniqueId
, UniqueId
->UniqueId
, UniqueId
->UniqueIdLength
);
1379 /* If device's offline or valid, skip its notifications */
1382 DeviceInformation
->SkipNotifications
= TRUE
;
1385 /* In case device is valid and is set to no automount,
1388 if (DeviceExtension
->NoAutoMount
|| IsDrvLetter
)
1390 IsOff
= !DeviceInformation
->SkipNotifications
;
1397 /* Finally, release the exclusive lock */
1398 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
, 1, FALSE
);
1400 /* If device is not offline, notify its arrival */
1403 SendOnlineNotification(SymbolicName
);
1406 /* If we had symlinks (from storage), free them */
1412 /* Notify about unique id change */
1415 IssueUniqueIdChangeNotify(DeviceExtension
, SymbolicName
, NewUniqueId
);
1416 FreePool(NewUniqueId
);
1419 /* If this drive was set to have a drive letter automatically
1420 * Now it's back, local databases sync will be required
1422 if (DeviceExtension
->AutomaticDriveLetter
)
1424 KeWaitForSingleObject(&(DeviceExtension
->DeviceLock
), Executive
, KernelMode
, FALSE
, NULL
);
1426 ReconcileThisDatabaseWithMaster(DeviceExtension
, DeviceInformation
);
1428 NextEntry
= DeviceExtension
->DeviceListHead
.Flink
;
1429 CurrentDevice
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
1430 while (CurrentDevice
!= DeviceInformation
)
1432 if (!CurrentDevice
->NoDatabase
)
1434 ReconcileThisDatabaseWithMaster(DeviceExtension
, CurrentDevice
);
1437 NextEntry
= NextEntry
->Flink
;
1438 CurrentDevice
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
1441 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
, 1, FALSE
);
1444 return STATUS_SUCCESS
;
1451 MountMgrMountedDeviceRemoval(IN PDEVICE_EXTENSION DeviceExtension
,
1452 IN PUNICODE_STRING DeviceName
)
1454 PLIST_ENTRY NextEntry
, DeviceEntry
;
1455 PUNIQUE_ID_REPLICATE UniqueIdReplicate
;
1456 PSYMLINK_INFORMATION SymlinkInformation
;
1457 PASSOCIATED_DEVICE_ENTRY AssociatedDevice
;
1458 PSAVED_LINK_INFORMATION SavedLinkInformation
= NULL
;
1459 PDEVICE_INFORMATION DeviceInformation
, CurrentDevice
;
1461 /* Acquire device exclusively */
1462 KeWaitForSingleObject(&(DeviceExtension
->DeviceLock
), Executive
, KernelMode
, FALSE
, NULL
);
1464 /* Look for the leaving device */
1465 for (NextEntry
= DeviceExtension
->DeviceListHead
.Flink
;
1466 NextEntry
!= &(DeviceExtension
->DeviceListHead
);
1467 NextEntry
= NextEntry
->Flink
)
1469 DeviceInformation
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
1471 if (!RtlCompareUnicodeString(&(DeviceInformation
->SymbolicName
), DeviceName
, TRUE
))
1477 /* If we found it */
1478 if (NextEntry
!= &(DeviceExtension
->DeviceListHead
))
1480 /* If it's asked to keep links, then, prepare to save them */
1481 if (DeviceInformation
->KeepLinks
)
1483 SavedLinkInformation
= AllocatePool(sizeof(SAVED_LINK_INFORMATION
));
1484 if (!SavedLinkInformation
)
1486 DeviceInformation
->KeepLinks
= FALSE
;
1490 /* If it's possible (and asked), start to save them */
1491 if (DeviceInformation
->KeepLinks
)
1493 InsertTailList(&(DeviceExtension
->SavedLinksListHead
), &(SavedLinkInformation
->SavedLinksListEntry
));
1494 InitializeListHead(&(SavedLinkInformation
->SymbolicLinksListHead
));
1495 SavedLinkInformation
->UniqueId
= DeviceInformation
->UniqueId
;
1498 /* For all the symlinks */
1499 while (!IsListEmpty(&(DeviceInformation
->SymbolicLinksListHead
)))
1501 NextEntry
= RemoveHeadList(&(DeviceInformation
->SymbolicLinksListHead
));
1502 SymlinkInformation
= CONTAINING_RECORD(NextEntry
, SYMLINK_INFORMATION
, SymbolicLinksListEntry
);
1504 /* If we have to, save the link */
1505 if (DeviceInformation
->KeepLinks
)
1507 InsertTailList(&(SavedLinkInformation
->SymbolicLinksListHead
), &(SymlinkInformation
->SymbolicLinksListEntry
));
1509 /* Otherwise, just release it */
1512 GlobalDeleteSymbolicLink(&(SymlinkInformation
->Name
));
1513 FreePool(SymlinkInformation
->Name
.Buffer
);
1514 FreePool(SymlinkInformation
);
1518 /* Free all the replicated unique IDs */
1519 while (!IsListEmpty(&(DeviceInformation
->ReplicatedUniqueIdsListHead
)))
1521 NextEntry
= RemoveHeadList(&(DeviceInformation
->ReplicatedUniqueIdsListHead
));
1522 UniqueIdReplicate
= CONTAINING_RECORD(NextEntry
, UNIQUE_ID_REPLICATE
, ReplicatedUniqueIdsListEntry
);
1525 FreePool(UniqueIdReplicate
->UniqueId
);
1526 FreePool(UniqueIdReplicate
);
1529 while (!IsListEmpty(&(DeviceInformation
->AssociatedDevicesHead
)))
1531 NextEntry
= RemoveHeadList(&(DeviceInformation
->AssociatedDevicesHead
));
1532 AssociatedDevice
= CONTAINING_RECORD(NextEntry
, ASSOCIATED_DEVICE_ENTRY
, AssociatedDevicesEntry
);
1534 DeviceInformation
->NoDatabase
= TRUE
;
1535 FreePool(AssociatedDevice
->String
.Buffer
);
1536 FreePool(AssociatedDevice
);
1539 /* Remove device from the device list */
1540 RemoveEntryList(&(DeviceInformation
->DeviceListEntry
));
1542 /* If there are still devices, check if some were associated with ours */
1543 if (!IsListEmpty(&(DeviceInformation
->DeviceListEntry
)))
1545 for (NextEntry
= DeviceExtension
->DeviceListHead
.Flink
;
1546 NextEntry
!= &(DeviceExtension
->DeviceListHead
);
1547 NextEntry
= NextEntry
->Flink
)
1549 CurrentDevice
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
1551 /* And then, remove them */
1552 DeviceEntry
= CurrentDevice
->AssociatedDevicesHead
.Flink
;
1553 while (DeviceEntry
!= &(CurrentDevice
->AssociatedDevicesHead
))
1555 AssociatedDevice
= CONTAINING_RECORD(NextEntry
, ASSOCIATED_DEVICE_ENTRY
, AssociatedDevicesEntry
);
1556 DeviceEntry
= DeviceEntry
->Flink
;
1558 if (AssociatedDevice
->DeviceInformation
!= DeviceInformation
)
1563 RemoveEntryList(&(AssociatedDevice
->AssociatedDevicesEntry
));
1564 FreePool(AssociatedDevice
->String
.Buffer
);
1565 FreePool(AssociatedDevice
);
1570 /* Finally, clean up device name, symbolic name */
1571 FreePool(DeviceInformation
->SymbolicName
.Buffer
);
1572 if (!DeviceInformation
->KeepLinks
)
1574 FreePool(DeviceInformation
->UniqueId
);
1576 FreePool(DeviceInformation
->DeviceName
.Buffer
);
1578 /* Unregister notifications */
1579 if (DeviceInformation
->TargetDeviceNotificationEntry
)
1581 IoUnregisterPlugPlayNotification(DeviceInformation
->TargetDeviceNotificationEntry
);
1585 FreePool(DeviceInformation
);
1589 /* We didn't find device, perhaps because it was offline */
1590 for (NextEntry
= DeviceExtension
->OfflineDeviceListHead
.Flink
;
1591 NextEntry
!= &(DeviceExtension
->OfflineDeviceListHead
);
1592 NextEntry
= NextEntry
->Flink
)
1594 DeviceInformation
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
1596 /* It was, remove it */
1597 if (RtlCompareUnicodeString(&(DeviceInformation
->SymbolicName
), DeviceName
, TRUE
) == 0)
1599 RemoveEntryList(&(DeviceInformation
->DeviceListEntry
));
1600 MountMgrFreeDeadDeviceInfo(DeviceInformation
);
1606 /* Release driver */
1607 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
, 1, FALSE
);
1615 MountMgrMountedDeviceNotification(IN PVOID NotificationStructure
,
1619 PDEVICE_EXTENSION DeviceExtension
;
1620 PDEVICE_INTERFACE_CHANGE_NOTIFICATION Notification
;
1622 /* Notification for a device arrived */
1623 /* Disable hard errors */
1624 OldState
= PsGetThreadHardErrorsAreDisabled(PsGetCurrentThread());
1625 PsSetThreadHardErrorsAreDisabled(PsGetCurrentThread(), TRUE
);
1627 DeviceExtension
= Context
;
1628 Notification
= NotificationStructure
;
1630 /* Dispatch according to the event */
1631 if (IsEqualGUID(&(Notification
->Event
), &GUID_DEVICE_INTERFACE_ARRIVAL
))
1633 MountMgrMountedDeviceArrival(DeviceExtension
, Notification
->SymbolicLinkName
, FALSE
);
1635 else if (IsEqualGUID(&(Notification
->Event
), &GUID_DEVICE_INTERFACE_REMOVAL
))
1637 MountMgrMountedDeviceRemoval(DeviceExtension
, Notification
->SymbolicLinkName
);
1640 /* Reset hard errors */
1641 PsSetThreadHardErrorsAreDisabled(PsGetCurrentThread(), OldState
);
1643 return STATUS_SUCCESS
;
1651 MountMgrCreateClose(IN PDEVICE_OBJECT DeviceObject
,
1654 PIO_STACK_LOCATION Stack
;
1655 NTSTATUS Status
= STATUS_SUCCESS
;
1657 UNREFERENCED_PARAMETER(DeviceObject
);
1659 Stack
= IoGetCurrentIrpStackLocation(Irp
);
1661 /* Allow driver opening for communication
1662 * as long as it's not taken for a directory
1664 if (Stack
->MajorFunction
== IRP_MJ_CREATE
&&
1665 Stack
->Parameters
.Create
.Options
& FILE_DIRECTORY_FILE
)
1667 Status
= STATUS_NOT_A_DIRECTORY
;
1670 Irp
->IoStatus
.Status
= Status
;
1671 Irp
->IoStatus
.Information
= 0;
1672 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1681 MountMgrCancel(IN PDEVICE_OBJECT DeviceObject
,
1684 UNREFERENCED_PARAMETER(DeviceObject
);
1686 RemoveEntryList(&(Irp
->Tail
.Overlay
.ListEntry
));
1688 IoReleaseCancelSpinLock(Irp
->CancelIrql
);
1690 Irp
->IoStatus
.Information
= 0;
1691 Irp
->IoStatus
.Status
= STATUS_CANCELLED
;
1692 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1700 MountMgrCleanup(IN PDEVICE_OBJECT DeviceObject
,
1705 PLIST_ENTRY NextEntry
;
1706 PFILE_OBJECT FileObject
;
1707 PIO_STACK_LOCATION Stack
;
1708 PDEVICE_EXTENSION DeviceExtension
;
1710 DeviceExtension
= DeviceObject
->DeviceExtension
;
1711 Stack
= IoGetCurrentIrpStackLocation(Irp
);
1712 FileObject
= Stack
->FileObject
;
1714 IoAcquireCancelSpinLock(&OldIrql
);
1716 /* If IRP list if empty, it's OK */
1717 if (IsListEmpty(&(DeviceExtension
->IrpListHead
)))
1719 IoReleaseCancelSpinLock(OldIrql
);
1721 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1722 Irp
->IoStatus
.Information
= 0;
1723 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1725 return STATUS_SUCCESS
;
1728 /* Otherwise, cancel all the IRPs */
1729 NextEntry
= DeviceExtension
->IrpListHead
.Flink
;
1732 ListIrp
= CONTAINING_RECORD(NextEntry
, IRP
, Tail
.Overlay
.ListEntry
);
1733 if (IoGetCurrentIrpStackLocation(ListIrp
)->FileObject
== FileObject
)
1735 ListIrp
->Cancel
= TRUE
;
1736 ListIrp
->CancelIrql
= OldIrql
;
1737 ListIrp
->CancelRoutine
= NULL
;
1738 MountMgrCancel(DeviceObject
, ListIrp
);
1740 IoAcquireCancelSpinLock(&OldIrql
);
1743 NextEntry
= NextEntry
->Flink
;
1745 while (NextEntry
!= &(DeviceExtension
->IrpListHead
));
1747 IoReleaseCancelSpinLock(OldIrql
);
1749 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1750 Irp
->IoStatus
.Information
= 0;
1751 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1753 return STATUS_SUCCESS
;
1761 MountMgrShutdown(IN PDEVICE_OBJECT DeviceObject
,
1764 PDEVICE_EXTENSION DeviceExtension
;
1766 DeviceExtension
= DeviceObject
->DeviceExtension
;
1768 InterlockedExchange(&Unloading
, TRUE
);
1770 KeInitializeEvent(&UnloadEvent
, NotificationEvent
, FALSE
);
1772 /* Wait for workers */
1773 if (InterlockedIncrement(&(DeviceExtension
->WorkerReferences
)))
1775 KeReleaseSemaphore(&(DeviceExtension
->WorkerSemaphore
),
1779 KeWaitForSingleObject(&UnloadEvent
, Executive
, KernelMode
, FALSE
, NULL
);
1783 InterlockedDecrement(&(DeviceExtension
->WorkerReferences
));
1786 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1787 Irp
->IoStatus
.Information
= 0;
1788 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1790 return STATUS_SUCCESS
;
1793 /* FUNCTIONS ****************************************************************/
1798 DriverEntry(IN PDRIVER_OBJECT DriverObject
,
1799 IN PUNICODE_STRING RegistryPath
)
1802 PDEVICE_OBJECT DeviceObject
;
1803 PDEVICE_EXTENSION DeviceExtension
;
1805 RtlCreateRegistryKey(RTL_REGISTRY_ABSOLUTE
, DatabasePath
);
1807 Status
= IoCreateDevice(DriverObject
,
1808 sizeof(DEVICE_EXTENSION
),
1810 FILE_DEVICE_NETWORK
,
1811 FILE_DEVICE_SECURE_OPEN
,
1814 if (!NT_SUCCESS(Status
))
1819 DriverObject
->DriverUnload
= MountMgrUnload
;
1821 DeviceExtension
= DeviceObject
->DeviceExtension
;
1822 RtlZeroMemory(DeviceExtension
, sizeof(DEVICE_EXTENSION
));
1823 DeviceExtension
->DeviceObject
= DeviceObject
;
1824 DeviceExtension
->DriverObject
= DriverObject
;
1826 InitializeListHead(&(DeviceExtension
->DeviceListHead
));
1827 InitializeListHead(&(DeviceExtension
->OfflineDeviceListHead
));
1829 KeInitializeSemaphore(&(DeviceExtension
->DeviceLock
), 1, 1);
1830 KeInitializeSemaphore(&(DeviceExtension
->RemoteDatabaseLock
), 1, 1);
1832 InitializeListHead(&(DeviceExtension
->IrpListHead
));
1833 DeviceExtension
->EpicNumber
= 1;
1835 InitializeListHead(&(DeviceExtension
->SavedLinksListHead
));
1837 InitializeListHead(&(DeviceExtension
->WorkerQueueListHead
));
1838 KeInitializeSemaphore(&(DeviceExtension
->WorkerSemaphore
), 0, MAXLONG
);
1839 DeviceExtension
->WorkerReferences
= -1;
1840 KeInitializeSpinLock(&(DeviceExtension
->WorkerLock
));
1842 InitializeListHead(&(DeviceExtension
->UniqueIdWorkerItemListHead
));
1843 InitializeListHead(&(DeviceExtension
->OnlineNotificationListHead
));
1844 DeviceExtension
->OnlineNotificationCount
= 1;
1846 DeviceExtension
->RegistryPath
.Length
= RegistryPath
->Length
;
1847 DeviceExtension
->RegistryPath
.MaximumLength
= RegistryPath
->Length
+ sizeof(WCHAR
);
1848 DeviceExtension
->RegistryPath
.Buffer
= AllocatePool(DeviceExtension
->RegistryPath
.MaximumLength
);
1849 if (!DeviceExtension
->RegistryPath
.Buffer
)
1851 IoDeleteDevice(DeviceObject
);
1852 return STATUS_INSUFFICIENT_RESOURCES
;
1855 RtlCopyUnicodeString(&(DeviceExtension
->RegistryPath
), RegistryPath
);
1857 DeviceExtension
->NoAutoMount
= MountmgrReadNoAutoMount(&(DeviceExtension
->RegistryPath
));
1859 GlobalCreateSymbolicLink(&DosDevicesMount
, &DeviceMount
);
1861 /* Register for device arrival & removal. Ask to be notified for already
1864 Status
= IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange
,
1865 PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES
,
1866 &MountedDevicesGuid
,
1868 MountMgrMountedDeviceNotification
,
1870 &(DeviceExtension
->NotificationEntry
));
1872 if (!NT_SUCCESS(Status
))
1874 IoDeleteDevice(DeviceObject
);
1878 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] =
1879 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = MountMgrCreateClose
;
1880 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = MountMgrDeviceControl
;
1881 DriverObject
->MajorFunction
[IRP_MJ_CLEANUP
] = MountMgrCleanup
;
1882 DriverObject
->MajorFunction
[IRP_MJ_SHUTDOWN
] = MountMgrShutdown
;
1884 gdeviceObject
= DeviceObject
;
1886 Status
= IoRegisterShutdownNotification(DeviceObject
);
1887 if (!NT_SUCCESS(Status
))
1889 IoDeleteDevice(DeviceObject
);