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:";
48 * - MountMgrQueryDosVolumePaths
49 * - MountMgrQueryVolumePaths
50 * - MountMgrValidateBackPointer
51 * - MountMgrVolumeMountPointDeleted
52 * - ReconcileThisDatabaseWithMasterWorker
59 IsOffline(PUNICODE_STRING SymbolicName
)
62 ULONG IsOffline
, Default
;
63 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
65 /* Prepare to look in the registry to see if
66 * given volume is offline
68 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
69 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
70 QueryTable
[0].Name
= SymbolicName
->Buffer
;
71 QueryTable
[0].EntryContext
= &IsOffline
;
72 QueryTable
[0].DefaultType
= REG_DWORD
;
73 QueryTable
[0].DefaultLength
= sizeof(ULONG
);
74 QueryTable
[0].DefaultData
= &Default
;
79 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
84 if (!NT_SUCCESS(Status
))
89 return (IsOffline
!= 0);
96 HasDriveLetter(IN PDEVICE_INFORMATION DeviceInformation
)
98 PLIST_ENTRY NextEntry
;
99 PSYMLINK_INFORMATION SymlinkInfo
;
101 /* To have a drive letter, a device must have symbolic links */
102 if (IsListEmpty(&(DeviceInformation
->SymbolicLinksListHead
)))
107 /* Browse all the links untill a drive letter is found */
108 NextEntry
= &(DeviceInformation
->SymbolicLinksListHead
);
111 SymlinkInfo
= CONTAINING_RECORD(NextEntry
, SYMLINK_INFORMATION
, SymbolicLinksListEntry
);
113 if (SymlinkInfo
->Online
)
115 if (IsDriveLetter(&(SymlinkInfo
->Name
)))
121 NextEntry
= NextEntry
->Flink
;
122 } while (NextEntry
!= &(DeviceInformation
->SymbolicLinksListHead
));
131 CreateNewDriveLetterName(OUT PUNICODE_STRING DriveLetter
,
132 IN PUNICODE_STRING DeviceName
,
134 IN PMOUNTDEV_UNIQUE_ID UniqueId OPTIONAL
)
136 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
138 /* Allocate a big enough buffer to contain the symbolic link */
139 DriveLetter
->MaximumLength
= DosDevices
.Length
+ 3 * sizeof(WCHAR
);
140 DriveLetter
->Buffer
= AllocatePool(DriveLetter
->MaximumLength
);
141 if (!DriveLetter
->Buffer
)
143 return STATUS_INSUFFICIENT_RESOURCES
;
147 RtlCopyUnicodeString(DriveLetter
, &DosDevices
);
149 /* Update string to reflect real contents */
150 DriveLetter
->Length
= DosDevices
.Length
+ 2 * sizeof(WCHAR
);
151 DriveLetter
->Buffer
[DosDevices
.Length
/ sizeof(WCHAR
) + 2] = UNICODE_NULL
;
152 DriveLetter
->Buffer
[DosDevices
.Length
/ sizeof(WCHAR
) + 1] = L
':';
154 /* If caller wants a no drive entry */
155 if (Letter
== (UCHAR
)-1)
157 /* Then, create a no letter entry */
158 CreateNoDriveLetterEntry(UniqueId
);
159 FreePool(DriveLetter
->Buffer
);
160 return STATUS_UNSUCCESSFUL
;
164 /* Use the letter given by the caller */
165 DriveLetter
->Buffer
[DosDevices
.Length
/ sizeof(WCHAR
)] = (WCHAR
)Letter
;
166 Status
= GlobalCreateSymbolicLink(DriveLetter
, DeviceName
);
167 if (NT_SUCCESS(Status
))
173 /* If caller didn't provide a letter, let's find one for him */
175 if (RtlPrefixUnicodeString(&DeviceFloppy
, DeviceName
, TRUE
))
177 /* If the device is a floppy, start with letter A */
180 else if (RtlPrefixUnicodeString(&DeviceCdRom
, DeviceName
, TRUE
))
182 /* If the device is a CD-ROM, start with letter D */
187 /* Finally, if it's a disk, use C */
191 /* Try to affect a letter (up to Z, ofc) until it's possible */
192 for (; Letter
<= 'Z'; Letter
++)
194 DriveLetter
->Buffer
[DosDevices
.Length
/ sizeof(WCHAR
)] = (WCHAR
)Letter
;
195 Status
= GlobalCreateSymbolicLink(DriveLetter
, DeviceName
);
196 if (NT_SUCCESS(Status
))
198 DPRINT("Assigned drive %c: to %wZ\n", Letter
, DeviceName
);
203 /* We failed to allocate a letter */
204 FreePool(DriveLetter
->Buffer
);
205 DPRINT("Failed to create a drive letter for %wZ\n", DeviceName
);
213 QueryDeviceInformation(IN PUNICODE_STRING SymbolicName
,
214 OUT PUNICODE_STRING DeviceName OPTIONAL
,
215 OUT PMOUNTDEV_UNIQUE_ID
* UniqueId OPTIONAL
,
216 OUT PBOOLEAN Removable OPTIONAL
,
217 OUT PBOOLEAN GptDriveLetter OPTIONAL
,
218 OUT PBOOLEAN HasGuid OPTIONAL
,
219 IN OUT LPGUID StableGuid OPTIONAL
,
220 OUT PBOOLEAN Valid OPTIONAL
)
228 PMOUNTDEV_UNIQUE_ID Id
;
229 PFILE_OBJECT FileObject
;
230 PIO_STACK_LOCATION Stack
;
231 PDEVICE_OBJECT DeviceObject
;
232 IO_STATUS_BLOCK IoStatusBlock
;
233 PARTITION_INFORMATION_EX PartitionInfo
;
234 STORAGE_DEVICE_NUMBER StorageDeviceNumber
;
235 VOLUME_GET_GPT_ATTRIBUTES_INFORMATION GptAttributes
;
237 /* Get device associated with the symbolic name */
238 Status
= IoGetDeviceObjectPointer(SymbolicName
,
239 FILE_READ_ATTRIBUTES
,
242 if (!NT_SUCCESS(Status
))
247 /* The associate FO can't have a file name */
248 if (FileObject
->FileName
.Length
)
250 ObDereferenceObject(FileObject
);
251 return STATUS_OBJECT_NAME_NOT_FOUND
;
254 /* Check if it's removable & return to the user (if asked to) */
255 IsRemovable
= (FileObject
->DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
);
258 *Removable
= IsRemovable
;
261 /* Get the attached device */
262 DeviceObject
= IoGetAttachedDeviceReference(FileObject
->DeviceObject
);
264 /* If we've been asked for a GPT drive letter */
267 /* Consider it has one */
268 *GptDriveLetter
= TRUE
;
272 /* Query the GPT attributes */
273 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
274 Irp
= IoBuildDeviceIoControlRequest(IOCTL_VOLUME_GET_GPT_ATTRIBUTES
,
279 sizeof(GptAttributes
),
285 ObDereferenceObject(DeviceObject
);
286 ObDereferenceObject(FileObject
);
287 return STATUS_INSUFFICIENT_RESOURCES
;
290 Status
= IoCallDriver(DeviceObject
, Irp
);
291 if (Status
== STATUS_PENDING
)
293 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
294 Status
= IoStatusBlock
.Status
;
297 /* In case of failure, don't fail, that's no vital */
298 if (!NT_SUCCESS(Status
))
300 Status
= STATUS_SUCCESS
;
302 /* Check if it has a drive letter */
303 else if (!(GptAttributes
.GptAttributes
&
304 GPT_BASIC_DATA_ATTRIBUTE_NO_DRIVE_LETTER
))
306 *GptDriveLetter
= FALSE
;
311 /* If caller wants to know if there's valid contents */
314 /* Suppose it's not OK */
319 /* Query partitions information */
320 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
321 Irp
= IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_PARTITION_INFO_EX
,
326 sizeof(PartitionInfo
),
332 ObDereferenceObject(DeviceObject
);
333 ObDereferenceObject(FileObject
);
334 return STATUS_INSUFFICIENT_RESOURCES
;
337 Status
= IoCallDriver(DeviceObject
, Irp
);
338 if (Status
== STATUS_PENDING
)
340 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
341 Status
= IoStatusBlock
.Status
;
344 /* Once again here, failure isn't major */
345 if (!NT_SUCCESS(Status
))
347 Status
= STATUS_SUCCESS
;
349 /* Verify we know something in */
350 else if (PartitionInfo
.PartitionStyle
== PARTITION_STYLE_MBR
&&
351 IsRecognizedPartition(PartitionInfo
.Mbr
.PartitionType
))
356 /* It looks correct, ensure it is & query device number */
359 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
360 Irp
= IoBuildDeviceIoControlRequest(IOCTL_STORAGE_GET_DEVICE_NUMBER
,
364 &StorageDeviceNumber
,
365 sizeof(StorageDeviceNumber
),
371 ObDereferenceObject(DeviceObject
);
372 ObDereferenceObject(FileObject
);
373 return STATUS_INSUFFICIENT_RESOURCES
;
376 Status
= IoCallDriver(DeviceObject
, Irp
);
377 if (Status
== STATUS_PENDING
)
379 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
380 Status
= IoStatusBlock
.Status
;
383 if (!NT_SUCCESS(Status
))
385 Status
= STATUS_SUCCESS
;
395 /* If caller needs device name */
398 /* Allocate a buffer just to request length */
399 Name
= AllocatePool(sizeof(MOUNTDEV_NAME
));
402 ObDereferenceObject(DeviceObject
);
403 ObDereferenceObject(FileObject
);
404 return STATUS_INSUFFICIENT_RESOURCES
;
407 /* Query device name */
408 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
409 Irp
= IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_DEVICE_NAME
,
414 sizeof(MOUNTDEV_NAME
),
421 ObDereferenceObject(DeviceObject
);
422 ObDereferenceObject(FileObject
);
423 return STATUS_INSUFFICIENT_RESOURCES
;
426 Stack
= IoGetNextIrpStackLocation(Irp
);
427 Stack
->FileObject
= FileObject
;
429 Status
= IoCallDriver(DeviceObject
, Irp
);
430 if (Status
== STATUS_PENDING
)
432 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
433 Status
= IoStatusBlock
.Status
;
436 /* Now, we've got the correct length */
437 if (Status
== STATUS_BUFFER_OVERFLOW
)
439 Size
= Name
->NameLength
+ sizeof(MOUNTDEV_NAME
);
443 /* Allocate proper size */
444 Name
= AllocatePool(Size
);
447 ObDereferenceObject(DeviceObject
);
448 ObDereferenceObject(FileObject
);
449 return STATUS_INSUFFICIENT_RESOURCES
;
452 /* And query name (for real that time) */
453 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
454 Irp
= IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_DEVICE_NAME
,
466 ObDereferenceObject(DeviceObject
);
467 ObDereferenceObject(FileObject
);
468 return STATUS_INSUFFICIENT_RESOURCES
;
471 Stack
= IoGetNextIrpStackLocation(Irp
);
472 Stack
->FileObject
= FileObject
;
474 Status
= IoCallDriver(DeviceObject
, Irp
);
475 if (Status
== STATUS_PENDING
)
477 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
478 Status
= IoStatusBlock
.Status
;
482 /* Here we can't fail and assume default value */
483 if (!NT_SUCCESS(Status
))
486 ObDereferenceObject(DeviceObject
);
487 ObDereferenceObject(FileObject
);
491 /* Copy back found name to the caller */
492 DeviceName
->Length
= Name
->NameLength
;
493 DeviceName
->MaximumLength
= Name
->NameLength
+ sizeof(WCHAR
);
494 DeviceName
->Buffer
= AllocatePool(DeviceName
->MaximumLength
);
495 if (!DeviceName
->Buffer
)
498 ObDereferenceObject(DeviceObject
);
499 ObDereferenceObject(FileObject
);
500 return STATUS_INSUFFICIENT_RESOURCES
;
503 RtlCopyMemory(DeviceName
->Buffer
, Name
->Name
, Name
->NameLength
);
504 DeviceName
->Buffer
[Name
->NameLength
/ sizeof(WCHAR
)] = UNICODE_NULL
;
508 /* If caller wants device unique ID */
511 /* Prepare buffer to probe length */
512 Id
= AllocatePool(sizeof(MOUNTDEV_UNIQUE_ID
));
515 ObDereferenceObject(DeviceObject
);
516 ObDereferenceObject(FileObject
);
517 return STATUS_INSUFFICIENT_RESOURCES
;
520 /* Query unique ID length */
521 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
522 Irp
= IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_UNIQUE_ID
,
527 sizeof(MOUNTDEV_UNIQUE_ID
),
534 ObDereferenceObject(DeviceObject
);
535 ObDereferenceObject(FileObject
);
536 return STATUS_INSUFFICIENT_RESOURCES
;
539 Stack
= IoGetNextIrpStackLocation(Irp
);
540 Stack
->FileObject
= FileObject
;
542 Status
= IoCallDriver(DeviceObject
, Irp
);
543 if (Status
== STATUS_PENDING
)
545 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
546 Status
= IoStatusBlock
.Status
;
549 /* Retry with appropriate length */
550 if (Status
== STATUS_BUFFER_OVERFLOW
)
552 Size
= Id
->UniqueIdLength
+ sizeof(MOUNTDEV_UNIQUE_ID
);
556 /* Allocate the correct buffer */
557 Id
= AllocatePool(Size
);
560 ObDereferenceObject(DeviceObject
);
561 ObDereferenceObject(FileObject
);
562 return STATUS_INSUFFICIENT_RESOURCES
;
565 /* Query unique ID */
566 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
567 Irp
= IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_UNIQUE_ID
,
579 ObDereferenceObject(DeviceObject
);
580 ObDereferenceObject(FileObject
);
581 return STATUS_INSUFFICIENT_RESOURCES
;
584 Stack
= IoGetNextIrpStackLocation(Irp
);
585 Stack
->FileObject
= FileObject
;
587 Status
= IoCallDriver(DeviceObject
, Irp
);
588 if (Status
== STATUS_PENDING
)
590 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
591 Status
= IoStatusBlock
.Status
;
595 /* Hands back unique ID */
596 if (NT_SUCCESS(Status
))
602 /* In case of failure, also free the rest */
604 if (DeviceName
->Length
)
606 FreePool(DeviceName
->Buffer
);
609 ObDereferenceObject(DeviceObject
);
610 ObDereferenceObject(FileObject
);
616 /* If user wants to know about GUID */
619 /* Query device stable GUID */
620 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
621 Irp
= IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_STABLE_GUID
,
632 ObDereferenceObject(DeviceObject
);
633 ObDereferenceObject(FileObject
);
634 return STATUS_INSUFFICIENT_RESOURCES
;
637 Stack
= IoGetNextIrpStackLocation(Irp
);
638 Stack
->FileObject
= FileObject
;
640 Status
= IoCallDriver(DeviceObject
, Irp
);
641 if (Status
== STATUS_PENDING
)
643 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
644 Status
= IoStatusBlock
.Status
;
647 *HasGuid
= NT_SUCCESS(Status
);
650 ObDereferenceObject(DeviceObject
);
651 ObDereferenceObject(FileObject
);
659 FindDeviceInfo(IN PDEVICE_EXTENSION DeviceExtension
,
660 IN PUNICODE_STRING SymbolicName
,
661 IN BOOLEAN DeviceNameGiven
,
662 OUT PDEVICE_INFORMATION
* DeviceInformation
)
665 PLIST_ENTRY NextEntry
;
666 UNICODE_STRING DeviceName
;
667 PDEVICE_INFORMATION DeviceInfo
= NULL
;
669 /* If a device name was given, use it */
672 DeviceName
.Length
= SymbolicName
->Length
;
673 DeviceName
.Buffer
= SymbolicName
->Buffer
;
677 /* Otherwise, query it */
678 Status
= QueryDeviceInformation(SymbolicName
,
683 if (!NT_SUCCESS(Status
))
689 /* Look for device information matching devive */
690 for (NextEntry
= DeviceExtension
->DeviceListHead
.Flink
;
691 NextEntry
!= &(DeviceExtension
->DeviceListHead
);
692 NextEntry
= NextEntry
->Flink
)
694 DeviceInfo
= CONTAINING_RECORD(NextEntry
,
698 if (RtlEqualUnicodeString(&DeviceName
, &(DeviceInfo
->DeviceName
), TRUE
))
704 /* Release our buffer if required */
705 if (!DeviceNameGiven
)
707 FreePool(DeviceName
.Buffer
);
710 /* Return found intormation */
711 if (NextEntry
== &(DeviceExtension
->DeviceListHead
))
713 return STATUS_OBJECT_NAME_NOT_FOUND
;
716 *DeviceInformation
= DeviceInfo
;
717 return STATUS_SUCCESS
;
724 MountMgrFreeDeadDeviceInfo(IN PDEVICE_INFORMATION DeviceInformation
)
726 FreePool(DeviceInformation
->SymbolicName
.Buffer
);
727 FreePool(DeviceInformation
);
734 MountMgrFreeMountedDeviceInfo(IN PDEVICE_INFORMATION DeviceInformation
)
736 PLIST_ENTRY NextEntry
;
737 PSYMLINK_INFORMATION SymLink
;
738 PUNIQUE_ID_REPLICATE UniqueId
;
739 PASSOCIATED_DEVICE_ENTRY AssociatedDevice
;
741 /* Purge symbolic links list */
742 while (!IsListEmpty(&(DeviceInformation
->SymbolicLinksListHead
)))
744 NextEntry
= RemoveHeadList(&(DeviceInformation
->SymbolicLinksListHead
));
745 SymLink
= CONTAINING_RECORD(NextEntry
, SYMLINK_INFORMATION
, SymbolicLinksListEntry
);
747 GlobalDeleteSymbolicLink(&(SymLink
->Name
));
748 FreePool(SymLink
->Name
.Buffer
);
751 /* Purge replicated unique IDs list */
752 while (!IsListEmpty(&(DeviceInformation
->ReplicatedUniqueIdsListHead
)))
754 NextEntry
= RemoveHeadList(&(DeviceInformation
->ReplicatedUniqueIdsListHead
));
755 UniqueId
= CONTAINING_RECORD(NextEntry
, UNIQUE_ID_REPLICATE
, ReplicatedUniqueIdsListEntry
);
757 FreePool(UniqueId
->UniqueId
);
761 while (!IsListEmpty(&(DeviceInformation
->AssociatedDevicesHead
)))
763 NextEntry
= RemoveHeadList(&(DeviceInformation
->AssociatedDevicesHead
));
764 AssociatedDevice
= CONTAINING_RECORD(NextEntry
, ASSOCIATED_DEVICE_ENTRY
, AssociatedDevicesEntry
);
766 FreePool(AssociatedDevice
->String
.Buffer
);
767 FreePool(AssociatedDevice
);
770 /* Free the rest of the buffers */
771 FreePool(DeviceInformation
->SymbolicName
.Buffer
);
772 if (DeviceInformation
->KeepLinks
)
774 FreePool(DeviceInformation
->UniqueId
);
776 FreePool(DeviceInformation
->DeviceName
.Buffer
);
778 /* Finally, stop waiting for notifications for this device */
779 if (DeviceInformation
->TargetDeviceNotificationEntry
)
781 IoUnregisterPlugPlayNotification(DeviceInformation
->TargetDeviceNotificationEntry
);
789 MountMgrFreeSavedLink(IN PSAVED_LINK_INFORMATION SavedLinkInformation
)
791 PLIST_ENTRY NextEntry
;
792 PSYMLINK_INFORMATION SymlinkInformation
;
794 /* For all the saved links */
795 while (!IsListEmpty(&(SavedLinkInformation
->SymbolicLinksListHead
)))
797 NextEntry
= RemoveHeadList(&(SavedLinkInformation
->SymbolicLinksListHead
));
798 SymlinkInformation
= CONTAINING_RECORD(NextEntry
, SYMLINK_INFORMATION
, SymbolicLinksListEntry
);
800 /* Remove from system & free */
801 GlobalDeleteSymbolicLink(&(SymlinkInformation
->Name
));
802 FreePool(SymlinkInformation
->Name
.Buffer
);
803 FreePool(SymlinkInformation
);
806 /* And free unique ID & entry */
807 FreePool(SavedLinkInformation
->UniqueId
);
808 FreePool(SavedLinkInformation
);
817 MountMgrUnload(IN
struct _DRIVER_OBJECT
*DriverObject
)
819 PLIST_ENTRY NextEntry
;
820 PUNIQUE_ID_WORK_ITEM WorkItem
;
821 PDEVICE_EXTENSION DeviceExtension
;
822 PDEVICE_INFORMATION DeviceInformation
;
823 PSAVED_LINK_INFORMATION SavedLinkInformation
;
825 UNREFERENCED_PARAMETER(DriverObject
);
827 /* Don't get notification any longer */
828 IoUnregisterShutdownNotification(gdeviceObject
);
830 /* Free registry buffer */
831 DeviceExtension
= gdeviceObject
->DeviceExtension
;
832 if (DeviceExtension
->RegistryPath
.Buffer
)
834 FreePool(DeviceExtension
->RegistryPath
.Buffer
);
835 DeviceExtension
->RegistryPath
.Buffer
= NULL
;
838 InterlockedExchange(&Unloading
, TRUE
);
840 KeInitializeEvent(&UnloadEvent
, NotificationEvent
, FALSE
);
842 /* Wait for workers to finish */
843 if (InterlockedIncrement(&DeviceExtension
->WorkerReferences
))
845 KeReleaseSemaphore(&(DeviceExtension
->WorkerSemaphore
),
846 IO_NO_INCREMENT
, 1, FALSE
);
848 KeWaitForSingleObject(&UnloadEvent
, Executive
, KernelMode
, FALSE
, NULL
);
852 InterlockedDecrement(&(DeviceExtension
->WorkerReferences
));
855 /* Don't get any notification any longer² */
856 IoUnregisterPlugPlayNotification(DeviceExtension
->NotificationEntry
);
858 /* Acquire the driver exclusively */
859 KeWaitForSingleObject(&(DeviceExtension
->DeviceLock
), Executive
, KernelMode
,
862 /* Clear offline devices list */
863 while (!IsListEmpty(&(DeviceExtension
->OfflineDeviceListHead
)))
865 NextEntry
= RemoveHeadList(&(DeviceExtension
->OfflineDeviceListHead
));
866 DeviceInformation
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
867 MountMgrFreeDeadDeviceInfo(DeviceInformation
);
870 /* Clear saved links list */
871 while (!IsListEmpty(&(DeviceExtension
->SavedLinksListHead
)))
873 NextEntry
= RemoveHeadList(&(DeviceExtension
->SavedLinksListHead
));
874 SavedLinkInformation
= CONTAINING_RECORD(NextEntry
, SAVED_LINK_INFORMATION
, SavedLinksListEntry
);
875 MountMgrFreeSavedLink(SavedLinkInformation
);
878 /* Clear workers list */
879 while (!IsListEmpty(&(DeviceExtension
->UniqueIdWorkerItemListHead
)))
881 NextEntry
= RemoveHeadList(&(DeviceExtension
->UniqueIdWorkerItemListHead
));
882 WorkItem
= CONTAINING_RECORD(NextEntry
, UNIQUE_ID_WORK_ITEM
, UniqueIdWorkerItemListEntry
);
884 KeResetEvent(&UnloadEvent
);
885 WorkItem
->Event
= &UnloadEvent
;
887 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
,
890 IoCancelIrp(WorkItem
->Irp
);
891 KeWaitForSingleObject(&UnloadEvent
, Executive
, KernelMode
, FALSE
, NULL
);
893 IoFreeIrp(WorkItem
->Irp
);
894 FreePool(WorkItem
->DeviceName
.Buffer
);
895 FreePool(WorkItem
->IrpBuffer
);
898 KeWaitForSingleObject(&(DeviceExtension
->DeviceLock
), Executive
, KernelMode
,
902 /* If we have drive letter data, release */
903 if (DeviceExtension
->DriveLetterData
)
905 FreePool(DeviceExtension
->DriveLetterData
);
906 DeviceExtension
->DriveLetterData
= NULL
;
909 /* Release driver & quit */
910 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
, 1, FALSE
);
912 GlobalDeleteSymbolicLink(&DosDevicesMount
);
913 IoDeleteDevice(gdeviceObject
);
921 MountmgrReadNoAutoMount(IN PUNICODE_STRING RegistryPath
)
924 ULONG Result
, Default
= 0;
925 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
927 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
929 /* Simply read data from register */
930 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
931 QueryTable
[0].Name
= L
"NoAutoMount";
932 QueryTable
[0].EntryContext
= &Result
;
933 QueryTable
[0].DefaultType
= REG_NONE
;
934 QueryTable
[0].DefaultData
= &Default
;
935 QueryTable
[0].DefaultLength
= sizeof(ULONG
);
937 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
938 RegistryPath
->Buffer
,
942 if (!NT_SUCCESS(Status
))
944 return (Default
!= 0);
947 return (Result
!= 0);
954 MountMgrMountedDeviceArrival(IN PDEVICE_EXTENSION DeviceExtension
,
955 IN PUNICODE_STRING SymbolicName
,
956 IN BOOLEAN FromVolume
)
961 ULONG SymLinkCount
, i
;
962 PLIST_ENTRY NextEntry
;
963 PUNICODE_STRING SymLinks
;
964 NTSTATUS Status
, IntStatus
;
965 OBJECT_ATTRIBUTES ObjectAttributes
;
966 PSYMLINK_INFORMATION SymlinkInformation
;
967 PMOUNTDEV_UNIQUE_ID UniqueId
, NewUniqueId
;
968 PSAVED_LINK_INFORMATION SavedLinkInformation
;
969 PDEVICE_INFORMATION DeviceInformation
, CurrentDevice
;
970 WCHAR CSymLinkBuffer
[MAX_PATH
], LinkTargetBuffer
[MAX_PATH
];
971 UNICODE_STRING TargetDeviceName
, SuggestedLinkName
, DeviceName
, VolumeName
, DriveLetter
, LinkTarget
, CSymLink
;
972 BOOLEAN HasGuid
, HasGptDriveLetter
, Valid
, UseOnlyIfThereAreNoOtherLinks
, IsDrvLetter
, IsOff
, IsVolumeName
, LinkError
;
974 /* New device = new structure to represent it */
975 DeviceInformation
= AllocatePool(sizeof(DEVICE_INFORMATION
));
976 if (!DeviceInformation
)
978 return STATUS_INSUFFICIENT_RESOURCES
;
981 /* Initialise device structure */
982 RtlZeroMemory(DeviceInformation
, sizeof(DEVICE_INFORMATION
));
983 InitializeListHead(&(DeviceInformation
->SymbolicLinksListHead
));
984 InitializeListHead(&(DeviceInformation
->ReplicatedUniqueIdsListHead
));
985 InitializeListHead(&(DeviceInformation
->AssociatedDevicesHead
));
986 DeviceInformation
->SymbolicName
.Length
= SymbolicName
->Length
;
987 DeviceInformation
->SymbolicName
.MaximumLength
= SymbolicName
->Length
+ sizeof(UNICODE_NULL
);
988 DeviceInformation
->SymbolicName
.Buffer
= AllocatePool(DeviceInformation
->SymbolicName
.MaximumLength
);
989 if (!DeviceInformation
->SymbolicName
.Buffer
)
991 FreePool(DeviceInformation
);
992 return STATUS_INSUFFICIENT_RESOURCES
;
995 /* Copy symbolic name */
996 RtlCopyMemory(DeviceInformation
->SymbolicName
.Buffer
, SymbolicName
->Buffer
, SymbolicName
->Length
);
997 DeviceInformation
->SymbolicName
.Buffer
[DeviceInformation
->SymbolicName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
998 DeviceInformation
->Volume
= FromVolume
;
999 DeviceInformation
->DeviceExtension
= DeviceExtension
;
1001 /* Query as much data as possible about device */
1002 Status
= QueryDeviceInformation(SymbolicName
,
1005 &(DeviceInformation
->Removable
),
1010 if (!NT_SUCCESS(Status
))
1012 KeWaitForSingleObject(&(DeviceExtension
->DeviceLock
), Executive
, KernelMode
, FALSE
, NULL
);
1014 for (NextEntry
= DeviceExtension
->OfflineDeviceListHead
.Flink
;
1015 NextEntry
!= &(DeviceExtension
->OfflineDeviceListHead
);
1016 NextEntry
= NextEntry
->Flink
)
1018 CurrentDevice
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
1020 if (RtlEqualUnicodeString(&(DeviceInformation
->SymbolicName
), &(CurrentDevice
->SymbolicName
), TRUE
))
1026 if (NextEntry
!= &(DeviceExtension
->OfflineDeviceListHead
))
1028 MountMgrFreeDeadDeviceInfo(DeviceInformation
);
1032 InsertTailList(&(DeviceExtension
->OfflineDeviceListHead
), &(DeviceInformation
->DeviceListEntry
));
1035 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
, 1, FALSE
);
1040 /* Save gathered data */
1041 DeviceInformation
->UniqueId
= UniqueId
;
1042 DeviceInformation
->DeviceName
= TargetDeviceName
;
1043 DeviceInformation
->KeepLinks
= FALSE
;
1045 /* If we found system partition, mark it */
1046 if (DeviceExtension
->DriveLetterData
&& UniqueId
->UniqueIdLength
== DeviceExtension
->DriveLetterData
->UniqueIdLength
)
1048 if (RtlCompareMemory(UniqueId
->UniqueId
, DeviceExtension
->DriveLetterData
->UniqueId
, UniqueId
->UniqueIdLength
)
1049 == UniqueId
->UniqueIdLength
)
1051 IoSetSystemPartition(&TargetDeviceName
);
1055 /* Check suggested link name */
1056 Status
= QuerySuggestedLinkName(&(DeviceInformation
->SymbolicName
),
1058 &UseOnlyIfThereAreNoOtherLinks
);
1059 if (!NT_SUCCESS(Status
))
1061 SuggestedLinkName
.Buffer
= NULL
;
1064 /* If it's OK, set it and save its letter (if any) */
1065 if (SuggestedLinkName
.Buffer
&& IsDriveLetter(&SuggestedLinkName
))
1067 DeviceInformation
->SuggestedDriveLetter
= (UCHAR
)SuggestedLinkName
.Buffer
[LETTER_POSITION
];
1070 /* Acquire driver exclusively */
1071 KeWaitForSingleObject(&(DeviceExtension
->DeviceLock
), Executive
, KernelMode
, FALSE
, NULL
);
1073 /* Check if we already have device in to prevent double registration */
1074 for (NextEntry
= DeviceExtension
->DeviceListHead
.Flink
;
1075 NextEntry
!= &(DeviceExtension
->DeviceListHead
);
1076 NextEntry
= NextEntry
->Flink
)
1078 CurrentDevice
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
1080 if (RtlEqualUnicodeString(&(CurrentDevice
->DeviceName
), &TargetDeviceName
, TRUE
))
1086 /* If we found it, clear ours, and return success, all correct */
1087 if (NextEntry
!= &(DeviceExtension
->DeviceListHead
))
1089 if (SuggestedLinkName
.Buffer
)
1091 FreePool(SuggestedLinkName
.Buffer
);
1095 FreePool(TargetDeviceName
.Buffer
);
1096 FreePool(DeviceInformation
->DeviceName
.Buffer
);
1097 FreePool(DeviceInformation
);
1099 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
, 1, FALSE
);
1101 return STATUS_SUCCESS
;
1104 /* Check if there are symlinks associated with our device in registry */
1105 Status
= QuerySymbolicLinkNamesFromStorage(DeviceExtension
,
1107 (SuggestedLinkName
.Buffer
) ? &SuggestedLinkName
: NULL
,
1108 UseOnlyIfThereAreNoOtherLinks
,
1114 /* If our device is a CD-ROM */
1115 if (RtlPrefixUnicodeString(&DeviceCdRom
, &TargetDeviceName
, TRUE
))
1117 LinkTarget
.Length
= 0;
1118 LinkTarget
.MaximumLength
= sizeof(LinkTargetBuffer
);
1119 LinkTarget
.Buffer
= LinkTargetBuffer
;
1121 RtlCopyMemory(CSymLinkBuffer
, Cunc
, sizeof(Cunc
));
1122 RtlInitUnicodeString(&CSymLink
, CSymLinkBuffer
);
1124 /* Start checking all letters that could have been associated */
1125 for (Letter
= L
'D'; Letter
<= L
'Z'; Letter
++)
1127 CSymLink
.Buffer
[LETTER_POSITION
] = Letter
;
1129 InitializeObjectAttributes(&ObjectAttributes
,
1131 OBJ_CASE_INSENSITIVE
,
1135 /* Try to open the associated symlink */
1136 Status
= ZwOpenSymbolicLinkObject(&LinkHandle
, SYMBOLIC_LINK_QUERY
, &ObjectAttributes
);
1137 if (!NT_SUCCESS(Status
))
1142 /* And query its target */
1143 Status
= ZwQuerySymbolicLinkObject(LinkHandle
, &LinkTarget
, NULL
);
1144 ZwClose(LinkHandle
);
1146 if (!NT_SUCCESS(Status
))
1151 IntStatus
= STATUS_UNSUCCESSFUL
;
1152 if (!RtlEqualUnicodeString(&LinkTarget
, &DeviceInformation
->DeviceName
, FALSE
))
1157 /* This link is matching our device, whereas it's not supposed to have any
1158 * symlink associated.
1163 IoDeleteSymbolicLink(&CSymLink
);
1167 /* Now, for all the symlinks, check for ours */
1168 for (i
= 0; i
< SymLinkCount
; i
++)
1170 if (IsDriveLetter(&(SymLinks
[i
])))
1172 /* If it exists, that's correct */
1173 if (SymLinks
[i
].Buffer
[LETTER_POSITION
] == Letter
)
1175 IntStatus
= STATUS_SUCCESS
;
1180 /* Useless link, delete it */
1181 if (IntStatus
== STATUS_UNSUCCESSFUL
)
1183 IoDeleteSymbolicLink(&CSymLink
);
1188 /* Suggested name is no longer required */
1189 if (SuggestedLinkName
.Buffer
)
1191 FreePool(SuggestedLinkName
.Buffer
);
1194 /* If if failed, ensure we don't take symlinks into account */
1195 if (!NT_SUCCESS(Status
))
1201 /* Now we queried them, remove the symlinks */
1202 SavedLinkInformation
= RemoveSavedLinks(DeviceExtension
, UniqueId
);
1204 IsDrvLetter
= FALSE
;
1206 IsVolumeName
= FALSE
;
1207 /* For all the symlinks */
1208 for (i
= 0; i
< SymLinkCount
; i
++)
1210 /* Check if our device is a volume */
1211 if (MOUNTMGR_IS_VOLUME_NAME(&(SymLinks
[i
])))
1213 IsVolumeName
= TRUE
;
1215 /* If it has a drive letter */
1216 else if (IsDriveLetter(&(SymLinks
[i
])))
1220 DeleteFromLocalDatabase(&(SymLinks
[i
]), UniqueId
);
1229 /* And recreate the symlink to our device */
1230 Status
= GlobalCreateSymbolicLink(&(SymLinks
[i
]), &TargetDeviceName
);
1231 if (!NT_SUCCESS(Status
))
1235 if ((SavedLinkInformation
&& !RedirectSavedLink(SavedLinkInformation
, &(SymLinks
[i
]), &TargetDeviceName
)) ||
1236 !SavedLinkInformation
)
1238 Status
= QueryDeviceInformation(&(SymLinks
[i
]), &DeviceName
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
1239 if (NT_SUCCESS(Status
))
1241 LinkError
= RtlEqualUnicodeString(&TargetDeviceName
, &DeviceName
, TRUE
);
1242 FreePool(DeviceName
.Buffer
);
1247 if (IsDriveLetter(&(SymLinks
[i
])))
1249 IsDrvLetter
= FALSE
;
1250 DeleteFromLocalDatabase(&(SymLinks
[i
]), UniqueId
);
1253 FreePool(SymLinks
[i
].Buffer
);
1259 /* Check if was offline */
1260 if (IsOffline(&(SymLinks
[i
])))
1265 /* Finally, associate this symlink with the device */
1266 SymlinkInformation
= AllocatePool(sizeof(SYMLINK_INFORMATION
));
1267 if (!SymlinkInformation
)
1269 GlobalDeleteSymbolicLink(&(SymLinks
[i
]));
1270 FreePool(SymLinks
[i
].Buffer
);
1274 SymlinkInformation
->Name
= SymLinks
[i
];
1275 SymlinkInformation
->Online
= TRUE
;
1277 InsertTailList(&(DeviceInformation
->SymbolicLinksListHead
),
1278 &(SymlinkInformation
->SymbolicLinksListEntry
));
1281 /* Now, for all the recreated symlinks, notify their recreation */
1282 for (NextEntry
= DeviceInformation
->SymbolicLinksListHead
.Flink
;
1283 NextEntry
!= &(DeviceInformation
->SymbolicLinksListHead
);
1284 NextEntry
= NextEntry
->Flink
)
1286 SymlinkInformation
= CONTAINING_RECORD(NextEntry
, SYMLINK_INFORMATION
, SymbolicLinksListEntry
);
1288 SendLinkCreated(&(SymlinkInformation
->Name
));
1291 /* If we had saved links, it's time to free them */
1292 if (SavedLinkInformation
)
1294 MountMgrFreeSavedLink(SavedLinkInformation
);
1297 /* If our device doesn't have a volume name */
1300 /* It's time to create one */
1301 Status
= CreateNewVolumeName(&VolumeName
, NULL
);
1302 if (NT_SUCCESS(Status
))
1304 /* Write it to global database */
1305 RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE
,
1310 UniqueId
->UniqueIdLength
);
1312 /* And create the symlink */
1313 GlobalCreateSymbolicLink(&VolumeName
, &TargetDeviceName
);
1315 SymlinkInformation
= AllocatePool(sizeof(SYMLINK_INFORMATION
));
1316 if (!SymlinkInformation
)
1318 FreePool(VolumeName
.Buffer
);
1320 /* Finally, associate it with the device and notify creation */
1323 SymlinkInformation
->Name
= VolumeName
;
1324 SymlinkInformation
->Online
= TRUE
;
1325 InsertTailList(&(DeviceInformation
->SymbolicLinksListHead
),
1326 &(SymlinkInformation
->SymbolicLinksListEntry
));
1328 SendLinkCreated(&VolumeName
);
1333 /* If we found a drive letter, then, ignore the suggested one */
1336 DeviceInformation
->SuggestedDriveLetter
= 0;
1338 /* Else, it's time to set up one */
1339 else if ((DeviceExtension
->NoAutoMount
|| DeviceInformation
->Removable
) &&
1340 DeviceExtension
->AutomaticDriveLetter
&&
1341 (HasGptDriveLetter
|| DeviceInformation
->SuggestedDriveLetter
) &&
1342 !HasNoDriveLetterEntry(UniqueId
))
1344 /* Create a new drive letter */
1345 Status
= CreateNewDriveLetterName(&DriveLetter
, &TargetDeviceName
,
1346 DeviceInformation
->SuggestedDriveLetter
,
1348 if (!NT_SUCCESS(Status
))
1350 CreateNoDriveLetterEntry(UniqueId
);
1354 /* Save it to global database */
1355 RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE
,
1360 UniqueId
->UniqueIdLength
);
1362 /* Associate it with the device and notify creation */
1363 SymlinkInformation
= AllocatePool(sizeof(SYMLINK_INFORMATION
));
1364 if (!SymlinkInformation
)
1366 FreePool(DriveLetter
.Buffer
);
1370 SymlinkInformation
->Name
= DriveLetter
;
1371 SymlinkInformation
->Online
= TRUE
;
1372 InsertTailList(&(DeviceInformation
->SymbolicLinksListHead
),
1373 &(SymlinkInformation
->SymbolicLinksListEntry
));
1375 SendLinkCreated(&DriveLetter
);
1380 /* If required, register for notifications about the device */
1383 RegisterForTargetDeviceNotification(DeviceExtension
, DeviceInformation
);
1386 /* Finally, insert the device into our devices list */
1387 InsertTailList(&(DeviceExtension
->DeviceListHead
), &(DeviceInformation
->DeviceListEntry
));
1389 /* Copy device unique ID */
1390 NewUniqueId
= AllocatePool(UniqueId
->UniqueIdLength
+ sizeof(MOUNTDEV_UNIQUE_ID
));
1393 NewUniqueId
->UniqueIdLength
= UniqueId
->UniqueIdLength
;
1394 RtlCopyMemory(NewUniqueId
->UniqueId
, UniqueId
->UniqueId
, UniqueId
->UniqueIdLength
);
1397 /* If device's offline or valid, skip its notifications */
1400 DeviceInformation
->SkipNotifications
= TRUE
;
1403 /* In case device is valid and is set to no automount,
1406 if (DeviceExtension
->NoAutoMount
|| IsDrvLetter
)
1408 IsOff
= !DeviceInformation
->SkipNotifications
;
1415 /* Finally, release the exclusive lock */
1416 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
, 1, FALSE
);
1418 /* If device is not offline, notify its arrival */
1421 SendOnlineNotification(SymbolicName
);
1424 /* If we had symlinks (from storage), free them */
1430 /* Notify about unique id change */
1433 IssueUniqueIdChangeNotify(DeviceExtension
, SymbolicName
, NewUniqueId
);
1434 FreePool(NewUniqueId
);
1437 /* If this drive was set to have a drive letter automatically
1438 * Now it's back, local databases sync will be required
1440 if (DeviceExtension
->AutomaticDriveLetter
)
1442 KeWaitForSingleObject(&(DeviceExtension
->DeviceLock
), Executive
, KernelMode
, FALSE
, NULL
);
1444 ReconcileThisDatabaseWithMaster(DeviceExtension
, DeviceInformation
);
1446 NextEntry
= DeviceExtension
->DeviceListHead
.Flink
;
1447 CurrentDevice
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
1448 while (CurrentDevice
!= DeviceInformation
)
1450 if (!CurrentDevice
->NoDatabase
)
1452 ReconcileThisDatabaseWithMaster(DeviceExtension
, CurrentDevice
);
1455 NextEntry
= NextEntry
->Flink
;
1456 CurrentDevice
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
1459 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
, 1, FALSE
);
1462 return STATUS_SUCCESS
;
1469 MountMgrMountedDeviceRemoval(IN PDEVICE_EXTENSION DeviceExtension
,
1470 IN PUNICODE_STRING DeviceName
)
1472 PLIST_ENTRY NextEntry
, DeviceEntry
;
1473 PUNIQUE_ID_REPLICATE UniqueIdReplicate
;
1474 PSYMLINK_INFORMATION SymlinkInformation
;
1475 PASSOCIATED_DEVICE_ENTRY AssociatedDevice
;
1476 PSAVED_LINK_INFORMATION SavedLinkInformation
= NULL
;
1477 PDEVICE_INFORMATION DeviceInformation
, CurrentDevice
;
1479 /* Acquire device exclusively */
1480 KeWaitForSingleObject(&(DeviceExtension
->DeviceLock
), Executive
, KernelMode
, FALSE
, NULL
);
1482 /* Look for the leaving device */
1483 for (NextEntry
= DeviceExtension
->DeviceListHead
.Flink
;
1484 NextEntry
!= &(DeviceExtension
->DeviceListHead
);
1485 NextEntry
= NextEntry
->Flink
)
1487 DeviceInformation
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
1489 if (!RtlCompareUnicodeString(&(DeviceInformation
->SymbolicName
), DeviceName
, TRUE
))
1495 /* If we found it */
1496 if (NextEntry
!= &(DeviceExtension
->DeviceListHead
))
1498 /* If it's asked to keep links, then, prepare to save them */
1499 if (DeviceInformation
->KeepLinks
)
1501 SavedLinkInformation
= AllocatePool(sizeof(SAVED_LINK_INFORMATION
));
1502 if (!SavedLinkInformation
)
1504 DeviceInformation
->KeepLinks
= FALSE
;
1508 /* If it's possible (and asked), start to save them */
1509 if (DeviceInformation
->KeepLinks
)
1511 InsertTailList(&(DeviceExtension
->SavedLinksListHead
), &(SavedLinkInformation
->SavedLinksListEntry
));
1512 InitializeListHead(&(SavedLinkInformation
->SymbolicLinksListHead
));
1513 SavedLinkInformation
->UniqueId
= DeviceInformation
->UniqueId
;
1516 /* For all the symlinks */
1517 while (!IsListEmpty(&(DeviceInformation
->SymbolicLinksListHead
)))
1519 NextEntry
= RemoveHeadList(&(DeviceInformation
->SymbolicLinksListHead
));
1520 SymlinkInformation
= CONTAINING_RECORD(NextEntry
, SYMLINK_INFORMATION
, SymbolicLinksListEntry
);
1522 /* If we have to, save the link */
1523 if (DeviceInformation
->KeepLinks
)
1525 InsertTailList(&(SavedLinkInformation
->SymbolicLinksListHead
), &(SymlinkInformation
->SymbolicLinksListEntry
));
1527 /* Otherwise, just release it */
1530 GlobalDeleteSymbolicLink(&(SymlinkInformation
->Name
));
1531 FreePool(SymlinkInformation
->Name
.Buffer
);
1532 FreePool(SymlinkInformation
);
1536 /* Free all the replicated unique IDs */
1537 while (!IsListEmpty(&(DeviceInformation
->ReplicatedUniqueIdsListHead
)))
1539 NextEntry
= RemoveHeadList(&(DeviceInformation
->ReplicatedUniqueIdsListHead
));
1540 UniqueIdReplicate
= CONTAINING_RECORD(NextEntry
, UNIQUE_ID_REPLICATE
, ReplicatedUniqueIdsListEntry
);
1543 FreePool(UniqueIdReplicate
->UniqueId
);
1544 FreePool(UniqueIdReplicate
);
1547 while (!IsListEmpty(&(DeviceInformation
->AssociatedDevicesHead
)))
1549 NextEntry
= RemoveHeadList(&(DeviceInformation
->AssociatedDevicesHead
));
1550 AssociatedDevice
= CONTAINING_RECORD(NextEntry
, ASSOCIATED_DEVICE_ENTRY
, AssociatedDevicesEntry
);
1552 DeviceInformation
->NoDatabase
= TRUE
;
1553 FreePool(AssociatedDevice
->String
.Buffer
);
1554 FreePool(AssociatedDevice
);
1557 /* Remove device from the device list */
1558 RemoveEntryList(&(DeviceInformation
->DeviceListEntry
));
1560 /* If there are still devices, check if some were associated with ours */
1561 if (!IsListEmpty(&(DeviceInformation
->DeviceListEntry
)))
1563 for (NextEntry
= DeviceExtension
->DeviceListHead
.Flink
;
1564 NextEntry
!= &(DeviceExtension
->DeviceListHead
);
1565 NextEntry
= NextEntry
->Flink
)
1567 CurrentDevice
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
1569 /* And then, remove them */
1570 DeviceEntry
= CurrentDevice
->AssociatedDevicesHead
.Flink
;
1571 while (DeviceEntry
!= &(CurrentDevice
->AssociatedDevicesHead
))
1573 AssociatedDevice
= CONTAINING_RECORD(NextEntry
, ASSOCIATED_DEVICE_ENTRY
, AssociatedDevicesEntry
);
1574 DeviceEntry
= DeviceEntry
->Flink
;
1576 if (AssociatedDevice
->DeviceInformation
!= DeviceInformation
)
1581 RemoveEntryList(&(AssociatedDevice
->AssociatedDevicesEntry
));
1582 FreePool(AssociatedDevice
->String
.Buffer
);
1583 FreePool(AssociatedDevice
);
1588 /* Finally, clean up device name, symbolic name */
1589 FreePool(DeviceInformation
->SymbolicName
.Buffer
);
1590 if (!DeviceInformation
->KeepLinks
)
1592 FreePool(DeviceInformation
->UniqueId
);
1594 FreePool(DeviceInformation
->DeviceName
.Buffer
);
1596 /* Unregister notifications */
1597 if (DeviceInformation
->TargetDeviceNotificationEntry
)
1599 IoUnregisterPlugPlayNotification(DeviceInformation
->TargetDeviceNotificationEntry
);
1603 FreePool(DeviceInformation
);
1607 /* We didn't find device, perhaps because it was offline */
1608 for (NextEntry
= DeviceExtension
->OfflineDeviceListHead
.Flink
;
1609 NextEntry
!= &(DeviceExtension
->OfflineDeviceListHead
);
1610 NextEntry
= NextEntry
->Flink
)
1612 DeviceInformation
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
1614 /* It was, remove it */
1615 if (RtlCompareUnicodeString(&(DeviceInformation
->SymbolicName
), DeviceName
, TRUE
) == 0)
1617 RemoveEntryList(&(DeviceInformation
->DeviceListEntry
));
1618 MountMgrFreeDeadDeviceInfo(DeviceInformation
);
1624 /* Releave driver */
1625 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
, 1, FALSE
);
1633 MountMgrMountedDeviceNotification(IN PVOID NotificationStructure
,
1637 PDEVICE_EXTENSION DeviceExtension
;
1638 PDEVICE_INTERFACE_CHANGE_NOTIFICATION Notification
;
1640 /* Notification for a device arrived */
1641 /* Disable hard errors */
1642 OldState
= PsGetThreadHardErrorsAreDisabled(PsGetCurrentThread());
1643 PsSetThreadHardErrorsAreDisabled(PsGetCurrentThread(), TRUE
);
1645 DeviceExtension
= Context
;
1646 Notification
= NotificationStructure
;
1648 /* Dispatch according to the event */
1649 if (IsEqualGUID(&(Notification
->Event
), &GUID_DEVICE_INTERFACE_ARRIVAL
))
1651 MountMgrMountedDeviceArrival(DeviceExtension
, Notification
->SymbolicLinkName
, FALSE
);
1653 else if (IsEqualGUID(&(Notification
->Event
), &GUID_DEVICE_INTERFACE_REMOVAL
))
1655 MountMgrMountedDeviceRemoval(DeviceExtension
, Notification
->SymbolicLinkName
);
1658 /* Reset hard errors */
1659 PsSetThreadHardErrorsAreDisabled(PsGetCurrentThread(), OldState
);
1661 return STATUS_SUCCESS
;
1669 MountMgrCreateClose(IN PDEVICE_OBJECT DeviceObject
,
1672 PIO_STACK_LOCATION Stack
;
1673 NTSTATUS Status
= STATUS_SUCCESS
;
1675 UNREFERENCED_PARAMETER(DeviceObject
);
1677 Stack
= IoGetCurrentIrpStackLocation(Irp
);
1679 /* Allow driver opening for communication
1680 * as long as it's not taken for a directory
1682 if (Stack
->MajorFunction
== IRP_MJ_CREATE
&&
1683 Stack
->Parameters
.Create
.Options
& FILE_DIRECTORY_FILE
)
1685 Status
= STATUS_NOT_A_DIRECTORY
;
1688 Irp
->IoStatus
.Status
= Status
;
1689 Irp
->IoStatus
.Information
= 0;
1690 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1699 MountMgrCancel(IN PDEVICE_OBJECT DeviceObject
,
1702 UNREFERENCED_PARAMETER(DeviceObject
);
1704 RemoveEntryList(&(Irp
->Tail
.Overlay
.ListEntry
));
1706 IoReleaseCancelSpinLock(Irp
->CancelIrql
);
1708 Irp
->IoStatus
.Information
= 0;
1709 Irp
->IoStatus
.Status
= STATUS_CANCELLED
;
1710 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1718 MountMgrCleanup(IN PDEVICE_OBJECT DeviceObject
,
1723 PLIST_ENTRY NextEntry
;
1724 PFILE_OBJECT FileObject
;
1725 PIO_STACK_LOCATION Stack
;
1726 PDEVICE_EXTENSION DeviceExtension
;
1728 DeviceExtension
= DeviceObject
->DeviceExtension
;
1729 Stack
= IoGetCurrentIrpStackLocation(Irp
);
1730 FileObject
= Stack
->FileObject
;
1732 IoAcquireCancelSpinLock(&OldIrql
);
1734 /* If IRP list if empty, it's OK */
1735 if (IsListEmpty(&(DeviceExtension
->IrpListHead
)))
1737 IoReleaseCancelSpinLock(OldIrql
);
1739 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1740 Irp
->IoStatus
.Information
= 0;
1741 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1743 return STATUS_SUCCESS
;
1746 /* Otherwise, cancel all the IRPs */
1747 NextEntry
= &(DeviceExtension
->IrpListHead
);
1750 ListIrp
= CONTAINING_RECORD(NextEntry
, IRP
, Tail
.Overlay
.ListEntry
);
1751 if (IoGetCurrentIrpStackLocation(ListIrp
)->FileObject
== FileObject
)
1753 ListIrp
->Cancel
= TRUE
;
1754 ListIrp
->CancelIrql
= OldIrql
;
1755 ListIrp
->CancelRoutine
= NULL
;
1756 MountMgrCancel(DeviceObject
, ListIrp
);
1758 IoAcquireCancelSpinLock(&OldIrql
);
1761 NextEntry
= NextEntry
->Flink
;
1763 while (NextEntry
!= &(DeviceExtension
->IrpListHead
));
1765 IoReleaseCancelSpinLock(OldIrql
);
1767 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1768 Irp
->IoStatus
.Information
= 0;
1769 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1771 return STATUS_SUCCESS
;
1779 MountMgrShutdown(IN PDEVICE_OBJECT DeviceObject
,
1782 PDEVICE_EXTENSION DeviceExtension
;
1784 DeviceExtension
= DeviceObject
->DeviceExtension
;
1786 InterlockedExchange(&Unloading
, TRUE
);
1788 KeInitializeEvent(&UnloadEvent
, NotificationEvent
, FALSE
);
1790 /* Wait for workers */
1791 if (InterlockedIncrement(&(DeviceExtension
->WorkerReferences
)))
1793 KeReleaseSemaphore(&(DeviceExtension
->WorkerSemaphore
),
1797 KeWaitForSingleObject(&UnloadEvent
, Executive
, KernelMode
, FALSE
, NULL
);
1801 InterlockedDecrement(&(DeviceExtension
->WorkerReferences
));
1804 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1805 Irp
->IoStatus
.Information
= 0;
1806 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1808 return STATUS_SUCCESS
;
1811 /* FUNCTIONS ****************************************************************/
1816 DriverEntry(IN PDRIVER_OBJECT DriverObject
,
1817 IN PUNICODE_STRING RegistryPath
)
1820 PDEVICE_OBJECT DeviceObject
;
1821 PDEVICE_EXTENSION DeviceExtension
;
1823 RtlCreateRegistryKey(RTL_REGISTRY_ABSOLUTE
, DatabasePath
);
1825 Status
= IoCreateDevice(DriverObject
,
1826 sizeof(DEVICE_EXTENSION
),
1828 FILE_DEVICE_NETWORK
,
1829 FILE_DEVICE_SECURE_OPEN
,
1832 if (!NT_SUCCESS(Status
))
1837 DriverObject
->DriverUnload
= MountMgrUnload
;
1839 DeviceExtension
= DeviceObject
->DeviceExtension
;
1840 RtlZeroMemory(DeviceExtension
, sizeof(DEVICE_EXTENSION
));
1841 DeviceExtension
->DeviceObject
= DeviceObject
;
1842 DeviceExtension
->DriverObject
= DriverObject
;
1844 InitializeListHead(&(DeviceExtension
->DeviceListHead
));
1845 InitializeListHead(&(DeviceExtension
->OfflineDeviceListHead
));
1847 KeInitializeSemaphore(&(DeviceExtension
->DeviceLock
), 1, 1);
1848 KeInitializeSemaphore(&(DeviceExtension
->RemoteDatabaseLock
), 1, 1);
1850 InitializeListHead(&(DeviceExtension
->IrpListHead
));
1851 DeviceExtension
->EpicNumber
= 1;
1853 InitializeListHead(&(DeviceExtension
->SavedLinksListHead
));
1855 InitializeListHead(&(DeviceExtension
->WorkerQueueListHead
));
1856 KeInitializeSemaphore(&(DeviceExtension
->WorkerSemaphore
), 0, MAXLONG
);
1857 DeviceExtension
->WorkerReferences
= -1;
1858 KeInitializeSpinLock(&(DeviceExtension
->WorkerLock
));
1860 InitializeListHead(&(DeviceExtension
->UniqueIdWorkerItemListHead
));
1861 InitializeListHead(&(DeviceExtension
->OnlineNotificationListHead
));
1862 DeviceExtension
->OnlineNotificationCount
= 1;
1864 DeviceExtension
->RegistryPath
.Length
= RegistryPath
->Length
;
1865 DeviceExtension
->RegistryPath
.MaximumLength
= RegistryPath
->Length
+ sizeof(WCHAR
);
1866 DeviceExtension
->RegistryPath
.Buffer
= AllocatePool(DeviceExtension
->RegistryPath
.MaximumLength
);
1867 if (!DeviceExtension
->RegistryPath
.Buffer
)
1869 IoDeleteDevice(DeviceObject
);
1870 return STATUS_INSUFFICIENT_RESOURCES
;
1873 RtlCopyUnicodeString(&(DeviceExtension
->RegistryPath
), RegistryPath
);
1875 DeviceExtension
->NoAutoMount
= MountmgrReadNoAutoMount(&(DeviceExtension
->RegistryPath
));
1877 GlobalCreateSymbolicLink(&DosDevicesMount
, &DeviceMount
);
1879 /* Register for device arrival & removal. Ask to be notified for already
1882 Status
= IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange
,
1883 PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES
,
1884 &MountedDevicesGuid
,
1886 MountMgrMountedDeviceNotification
,
1888 &(DeviceExtension
->NotificationEntry
));
1890 if (!NT_SUCCESS(Status
))
1892 IoDeleteDevice(DeviceObject
);
1896 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] =
1897 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = MountMgrCreateClose
;
1898 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = MountMgrDeviceControl
;
1899 DriverObject
->MajorFunction
[IRP_MJ_CLEANUP
] = MountMgrCleanup
;
1900 DriverObject
->MajorFunction
[IRP_MJ_SHUTDOWN
] = MountMgrShutdown
;
1902 gdeviceObject
= DeviceObject
;
1904 Status
= IoRegisterShutdownNotification(DeviceObject
);
1905 if (!NT_SUCCESS(Status
))
1907 IoDeleteDevice(DeviceObject
);