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 * - MountMgrVolumeMountPointCreated
52 * - MountMgrVolumeMountPointDeleted
53 * - ReconcileThisDatabaseWithMasterWorker
60 IsOffline(PUNICODE_STRING SymbolicName
)
63 ULONG IsOffline
, Default
;
64 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
66 /* Prepare to look in the registry to see if
67 * given volume is offline
69 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
70 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
71 QueryTable
[0].Name
= SymbolicName
->Buffer
;
72 QueryTable
[0].EntryContext
= &IsOffline
;
73 QueryTable
[0].DefaultType
= REG_DWORD
;
74 QueryTable
[0].DefaultLength
= sizeof(ULONG
);
75 QueryTable
[0].DefaultData
= &Default
;
80 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
85 if (!NT_SUCCESS(Status
))
90 return (IsOffline
!= 0);
97 HasDriveLetter(IN PDEVICE_INFORMATION DeviceInformation
)
99 PLIST_ENTRY NextEntry
;
100 PSYMLINK_INFORMATION SymlinkInfo
;
102 /* To have a drive letter, a device must have symbolic links */
103 if (IsListEmpty(&(DeviceInformation
->SymbolicLinksListHead
)))
108 /* Browse all the links untill a drive letter is found */
109 NextEntry
= &(DeviceInformation
->SymbolicLinksListHead
);
112 SymlinkInfo
= CONTAINING_RECORD(NextEntry
, SYMLINK_INFORMATION
, SymbolicLinksListEntry
);
114 if (SymlinkInfo
->Online
)
116 if (IsDriveLetter(&(SymlinkInfo
->Name
)))
122 NextEntry
= NextEntry
->Flink
;
123 } while (NextEntry
!= &(DeviceInformation
->SymbolicLinksListHead
));
132 CreateNewDriveLetterName(OUT PUNICODE_STRING DriveLetter
,
133 IN PUNICODE_STRING DeviceName
,
135 IN PMOUNTDEV_UNIQUE_ID UniqueId OPTIONAL
)
137 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
139 /* Allocate a big enough buffer to contain the symbolic link */
140 DriveLetter
->MaximumLength
= DosDevices
.Length
+ 3 * sizeof(WCHAR
);
141 DriveLetter
->Buffer
= AllocatePool(DriveLetter
->MaximumLength
);
142 if (!DriveLetter
->Buffer
)
144 return STATUS_INSUFFICIENT_RESOURCES
;
148 RtlCopyUnicodeString(DriveLetter
, &DosDevices
);
150 /* Update string to reflect real contents */
151 DriveLetter
->Length
= DosDevices
.Length
+ 2 * sizeof(WCHAR
);
152 DriveLetter
->Buffer
[DosDevices
.Length
/ sizeof(WCHAR
) + 2] = UNICODE_NULL
;
153 DriveLetter
->Buffer
[DosDevices
.Length
/ sizeof(WCHAR
) + 1] = L
':';
155 /* If caller wants a no drive entry */
156 if (Letter
== (UCHAR
)-1)
158 /* Then, create a no letter entry */
159 CreateNoDriveLetterEntry(UniqueId
);
160 FreePool(DriveLetter
->Buffer
);
161 return STATUS_UNSUCCESSFUL
;
165 /* Use the letter given by the caller */
166 DriveLetter
->Buffer
[DosDevices
.Length
/ sizeof(WCHAR
)] = (WCHAR
)Letter
;
167 Status
= GlobalCreateSymbolicLink(DriveLetter
, DeviceName
);
168 if (NT_SUCCESS(Status
))
174 /* If caller didn't provide a letter, let's find one for him */
176 if (RtlPrefixUnicodeString(&DeviceFloppy
, DeviceName
, TRUE
))
178 /* If the device is a floppy, start with letter A */
181 else if (RtlPrefixUnicodeString(&DeviceCdRom
, DeviceName
, TRUE
))
183 /* If the device is a CD-ROM, start with letter D */
188 /* Finally, if it's a disk, use C */
192 /* Try to affect a letter (up to Z, ofc) until it's possible */
193 for (; Letter
<= 'Z'; Letter
++)
195 DriveLetter
->Buffer
[DosDevices
.Length
/ sizeof(WCHAR
)] = (WCHAR
)Letter
;
196 Status
= GlobalCreateSymbolicLink(DriveLetter
, DeviceName
);
197 if (NT_SUCCESS(Status
))
199 DPRINT("Assigned drive %c: to %wZ\n", Letter
, DeviceName
);
204 /* We failed to allocate a letter */
205 FreePool(DriveLetter
->Buffer
);
206 DPRINT("Failed to create a drive letter for %wZ\n", DeviceName
);
214 QueryDeviceInformation(IN PUNICODE_STRING SymbolicName
,
215 OUT PUNICODE_STRING DeviceName OPTIONAL
,
216 OUT PMOUNTDEV_UNIQUE_ID
* UniqueId OPTIONAL
,
217 OUT PBOOLEAN Removable OPTIONAL
,
218 OUT PBOOLEAN GptDriveLetter OPTIONAL
,
219 OUT PBOOLEAN HasGuid OPTIONAL
,
220 IN OUT LPGUID StableGuid OPTIONAL
,
221 OUT PBOOLEAN Valid OPTIONAL
)
229 PMOUNTDEV_UNIQUE_ID Id
;
230 PFILE_OBJECT FileObject
;
231 PIO_STACK_LOCATION Stack
;
232 PDEVICE_OBJECT DeviceObject
;
233 IO_STATUS_BLOCK IoStatusBlock
;
234 PARTITION_INFORMATION_EX PartitionInfo
;
235 STORAGE_DEVICE_NUMBER StorageDeviceNumber
;
236 VOLUME_GET_GPT_ATTRIBUTES_INFORMATION GptAttributes
;
238 /* Get device associated with the symbolic name */
239 Status
= IoGetDeviceObjectPointer(SymbolicName
,
240 FILE_READ_ATTRIBUTES
,
243 if (!NT_SUCCESS(Status
))
248 /* The associate FO can't have a file name */
249 if (FileObject
->FileName
.Length
)
251 ObDereferenceObject(FileObject
);
252 return STATUS_OBJECT_NAME_NOT_FOUND
;
255 /* Check if it's removable & return to the user (if asked to) */
256 IsRemovable
= (FileObject
->DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
);
259 *Removable
= IsRemovable
;
262 /* Get the attached device */
263 DeviceObject
= IoGetAttachedDeviceReference(FileObject
->DeviceObject
);
265 /* If we've been asked for a GPT drive letter */
268 /* Consider it has one */
269 *GptDriveLetter
= TRUE
;
273 /* Query the GPT attributes */
274 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
275 Irp
= IoBuildDeviceIoControlRequest(IOCTL_VOLUME_GET_GPT_ATTRIBUTES
,
280 sizeof(GptAttributes
),
286 ObDereferenceObject(DeviceObject
);
287 ObDereferenceObject(FileObject
);
288 return STATUS_INSUFFICIENT_RESOURCES
;
291 Status
= IoCallDriver(DeviceObject
, Irp
);
292 if (Status
== STATUS_PENDING
)
294 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
295 Status
= IoStatusBlock
.Status
;
298 /* In case of failure, don't fail, that's no vital */
299 if (!NT_SUCCESS(Status
))
301 Status
= STATUS_SUCCESS
;
303 /* Check if it has a drive letter */
304 else if (!(GptAttributes
.GptAttributes
&
305 GPT_BASIC_DATA_ATTRIBUTE_NO_DRIVE_LETTER
))
307 *GptDriveLetter
= FALSE
;
312 /* If caller wants to know if there's valid contents */
315 /* Suppose it's not OK */
320 /* Query partitions information */
321 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
322 Irp
= IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_PARTITION_INFO_EX
,
327 sizeof(PartitionInfo
),
333 ObDereferenceObject(DeviceObject
);
334 ObDereferenceObject(FileObject
);
335 return STATUS_INSUFFICIENT_RESOURCES
;
338 Status
= IoCallDriver(DeviceObject
, Irp
);
339 if (Status
== STATUS_PENDING
)
341 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
342 Status
= IoStatusBlock
.Status
;
345 /* Once again here, failure isn't major */
346 if (!NT_SUCCESS(Status
))
348 Status
= STATUS_SUCCESS
;
350 /* Verify we know something in */
351 else if (PartitionInfo
.PartitionStyle
== PARTITION_STYLE_MBR
&&
352 IsRecognizedPartition(PartitionInfo
.Mbr
.PartitionType
))
357 /* It looks correct, ensure it is & query device number */
360 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
361 Irp
= IoBuildDeviceIoControlRequest(IOCTL_STORAGE_GET_DEVICE_NUMBER
,
365 &StorageDeviceNumber
,
366 sizeof(StorageDeviceNumber
),
372 ObDereferenceObject(DeviceObject
);
373 ObDereferenceObject(FileObject
);
374 return STATUS_INSUFFICIENT_RESOURCES
;
377 Status
= IoCallDriver(DeviceObject
, Irp
);
378 if (Status
== STATUS_PENDING
)
380 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
381 Status
= IoStatusBlock
.Status
;
384 if (!NT_SUCCESS(Status
))
386 Status
= STATUS_SUCCESS
;
396 /* If caller needs device name */
399 /* Allocate a buffer just to request length */
400 Name
= AllocatePool(sizeof(MOUNTDEV_NAME
));
403 ObDereferenceObject(DeviceObject
);
404 ObDereferenceObject(FileObject
);
405 return STATUS_INSUFFICIENT_RESOURCES
;
408 /* Query device name */
409 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
410 Irp
= IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_DEVICE_NAME
,
415 sizeof(MOUNTDEV_NAME
),
422 ObDereferenceObject(DeviceObject
);
423 ObDereferenceObject(FileObject
);
424 return STATUS_INSUFFICIENT_RESOURCES
;
427 Stack
= IoGetNextIrpStackLocation(Irp
);
428 Stack
->FileObject
= FileObject
;
430 Status
= IoCallDriver(DeviceObject
, Irp
);
431 if (Status
== STATUS_PENDING
)
433 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
434 Status
= IoStatusBlock
.Status
;
437 /* Now, we've got the correct length */
438 if (Status
== STATUS_BUFFER_OVERFLOW
)
440 Size
= Name
->NameLength
+ sizeof(MOUNTDEV_NAME
);
444 /* Allocate proper size */
445 Name
= AllocatePool(Size
);
448 ObDereferenceObject(DeviceObject
);
449 ObDereferenceObject(FileObject
);
450 return STATUS_INSUFFICIENT_RESOURCES
;
453 /* And query name (for real that time) */
454 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
455 Irp
= IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_DEVICE_NAME
,
467 ObDereferenceObject(DeviceObject
);
468 ObDereferenceObject(FileObject
);
469 return STATUS_INSUFFICIENT_RESOURCES
;
472 Stack
= IoGetNextIrpStackLocation(Irp
);
473 Stack
->FileObject
= FileObject
;
475 Status
= IoCallDriver(DeviceObject
, Irp
);
476 if (Status
== STATUS_PENDING
)
478 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
479 Status
= IoStatusBlock
.Status
;
483 /* Here we can't fail and assume default value */
484 if (!NT_SUCCESS(Status
))
487 ObDereferenceObject(DeviceObject
);
488 ObDereferenceObject(FileObject
);
492 /* Copy back found name to the caller */
493 DeviceName
->Length
= Name
->NameLength
;
494 DeviceName
->MaximumLength
= Name
->NameLength
+ sizeof(WCHAR
);
495 DeviceName
->Buffer
= AllocatePool(DeviceName
->MaximumLength
);
496 if (!DeviceName
->Buffer
)
499 ObDereferenceObject(DeviceObject
);
500 ObDereferenceObject(FileObject
);
501 return STATUS_INSUFFICIENT_RESOURCES
;
504 RtlCopyMemory(DeviceName
->Buffer
, Name
->Name
, Name
->NameLength
);
505 DeviceName
->Buffer
[Name
->NameLength
/ sizeof(WCHAR
)] = UNICODE_NULL
;
509 /* If caller wants device unique ID */
512 /* Prepare buffer to probe length */
513 Id
= AllocatePool(sizeof(MOUNTDEV_UNIQUE_ID
));
516 ObDereferenceObject(DeviceObject
);
517 ObDereferenceObject(FileObject
);
518 return STATUS_INSUFFICIENT_RESOURCES
;
521 /* Query unique ID length */
522 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
523 Irp
= IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_UNIQUE_ID
,
528 sizeof(MOUNTDEV_UNIQUE_ID
),
535 ObDereferenceObject(DeviceObject
);
536 ObDereferenceObject(FileObject
);
537 return STATUS_INSUFFICIENT_RESOURCES
;
540 Stack
= IoGetNextIrpStackLocation(Irp
);
541 Stack
->FileObject
= FileObject
;
543 Status
= IoCallDriver(DeviceObject
, Irp
);
544 if (Status
== STATUS_PENDING
)
546 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
547 Status
= IoStatusBlock
.Status
;
550 /* Retry with appropriate length */
551 if (Status
== STATUS_BUFFER_OVERFLOW
)
553 Size
= Id
->UniqueIdLength
+ sizeof(MOUNTDEV_UNIQUE_ID
);
557 /* Allocate the correct buffer */
558 Id
= AllocatePool(Size
);
561 ObDereferenceObject(DeviceObject
);
562 ObDereferenceObject(FileObject
);
563 return STATUS_INSUFFICIENT_RESOURCES
;
566 /* Query unique ID */
567 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
568 Irp
= IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_UNIQUE_ID
,
580 ObDereferenceObject(DeviceObject
);
581 ObDereferenceObject(FileObject
);
582 return STATUS_INSUFFICIENT_RESOURCES
;
585 Stack
= IoGetNextIrpStackLocation(Irp
);
586 Stack
->FileObject
= FileObject
;
588 Status
= IoCallDriver(DeviceObject
, Irp
);
589 if (Status
== STATUS_PENDING
)
591 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
592 Status
= IoStatusBlock
.Status
;
596 /* Hands back unique ID */
597 if (NT_SUCCESS(Status
))
603 /* In case of failure, also free the rest */
605 if (DeviceName
->Length
)
607 FreePool(DeviceName
->Buffer
);
610 ObDereferenceObject(DeviceObject
);
611 ObDereferenceObject(FileObject
);
617 /* If user wants to know about GUID */
620 /* Query device stable GUID */
621 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
622 Irp
= IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_STABLE_GUID
,
633 ObDereferenceObject(DeviceObject
);
634 ObDereferenceObject(FileObject
);
635 return STATUS_INSUFFICIENT_RESOURCES
;
638 Stack
= IoGetNextIrpStackLocation(Irp
);
639 Stack
->FileObject
= FileObject
;
641 Status
= IoCallDriver(DeviceObject
, Irp
);
642 if (Status
== STATUS_PENDING
)
644 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
645 Status
= IoStatusBlock
.Status
;
648 *HasGuid
= NT_SUCCESS(Status
);
651 ObDereferenceObject(DeviceObject
);
652 ObDereferenceObject(FileObject
);
660 FindDeviceInfo(IN PDEVICE_EXTENSION DeviceExtension
,
661 IN PUNICODE_STRING SymbolicName
,
662 IN BOOLEAN DeviceNameGiven
,
663 OUT PDEVICE_INFORMATION
* DeviceInformation
)
666 PLIST_ENTRY NextEntry
;
667 UNICODE_STRING DeviceName
;
668 PDEVICE_INFORMATION DeviceInfo
= NULL
;
670 /* If a device name was given, use it */
673 DeviceName
.Length
= SymbolicName
->Length
;
674 DeviceName
.Buffer
= SymbolicName
->Buffer
;
678 /* Otherwise, query it */
679 Status
= QueryDeviceInformation(SymbolicName
,
684 if (!NT_SUCCESS(Status
))
690 /* Look for device information matching devive */
691 for (NextEntry
= DeviceExtension
->DeviceListHead
.Flink
;
692 NextEntry
!= &(DeviceExtension
->DeviceListHead
);
693 NextEntry
= NextEntry
->Flink
)
695 DeviceInfo
= CONTAINING_RECORD(NextEntry
,
699 if (RtlEqualUnicodeString(&DeviceName
, &(DeviceInfo
->DeviceName
), TRUE
))
705 /* Release our buffer if required */
706 if (!DeviceNameGiven
)
708 FreePool(DeviceName
.Buffer
);
711 /* Return found intormation */
712 if (NextEntry
== &(DeviceExtension
->DeviceListHead
))
714 return STATUS_OBJECT_NAME_NOT_FOUND
;
717 *DeviceInformation
= DeviceInfo
;
718 return STATUS_SUCCESS
;
725 MountMgrFreeDeadDeviceInfo(IN PDEVICE_INFORMATION DeviceInformation
)
727 FreePool(DeviceInformation
->SymbolicName
.Buffer
);
728 FreePool(DeviceInformation
);
735 MountMgrFreeMountedDeviceInfo(IN PDEVICE_INFORMATION DeviceInformation
)
737 PLIST_ENTRY NextEntry
;
738 PSYMLINK_INFORMATION SymLink
;
739 PUNIQUE_ID_REPLICATE UniqueId
;
740 PASSOCIATED_DEVICE_ENTRY AssociatedDevice
;
742 /* Purge symbolic links list */
743 while (!IsListEmpty(&(DeviceInformation
->SymbolicLinksListHead
)))
745 NextEntry
= RemoveHeadList(&(DeviceInformation
->SymbolicLinksListHead
));
746 SymLink
= CONTAINING_RECORD(NextEntry
, SYMLINK_INFORMATION
, SymbolicLinksListEntry
);
748 GlobalDeleteSymbolicLink(&(SymLink
->Name
));
749 FreePool(SymLink
->Name
.Buffer
);
752 /* Purge replicated unique IDs list */
753 while (!IsListEmpty(&(DeviceInformation
->ReplicatedUniqueIdsListHead
)))
755 NextEntry
= RemoveHeadList(&(DeviceInformation
->ReplicatedUniqueIdsListHead
));
756 UniqueId
= CONTAINING_RECORD(NextEntry
, UNIQUE_ID_REPLICATE
, ReplicatedUniqueIdsListEntry
);
758 FreePool(UniqueId
->UniqueId
);
762 while (!IsListEmpty(&(DeviceInformation
->AssociatedDevicesHead
)))
764 NextEntry
= RemoveHeadList(&(DeviceInformation
->AssociatedDevicesHead
));
765 AssociatedDevice
= CONTAINING_RECORD(NextEntry
, ASSOCIATED_DEVICE_ENTRY
, AssociatedDevicesEntry
);
767 FreePool(AssociatedDevice
->String
.Buffer
);
768 FreePool(AssociatedDevice
);
771 /* Free the rest of the buffers */
772 FreePool(DeviceInformation
->SymbolicName
.Buffer
);
773 if (DeviceInformation
->KeepLinks
)
775 FreePool(DeviceInformation
->UniqueId
);
777 FreePool(DeviceInformation
->DeviceName
.Buffer
);
779 /* Finally, stop waiting for notifications for this device */
780 if (DeviceInformation
->TargetDeviceNotificationEntry
)
782 IoUnregisterPlugPlayNotification(DeviceInformation
->TargetDeviceNotificationEntry
);
790 MountMgrFreeSavedLink(IN PSAVED_LINK_INFORMATION SavedLinkInformation
)
792 PLIST_ENTRY NextEntry
;
793 PSYMLINK_INFORMATION SymlinkInformation
;
795 /* For all the saved links */
796 while (!IsListEmpty(&(SavedLinkInformation
->SymbolicLinksListHead
)))
798 NextEntry
= RemoveHeadList(&(SavedLinkInformation
->SymbolicLinksListHead
));
799 SymlinkInformation
= CONTAINING_RECORD(NextEntry
, SYMLINK_INFORMATION
, SymbolicLinksListEntry
);
801 /* Remove from system & free */
802 GlobalDeleteSymbolicLink(&(SymlinkInformation
->Name
));
803 FreePool(SymlinkInformation
->Name
.Buffer
);
804 FreePool(SymlinkInformation
);
807 /* And free unique ID & entry */
808 FreePool(SavedLinkInformation
->UniqueId
);
809 FreePool(SavedLinkInformation
);
818 MountMgrUnload(IN
struct _DRIVER_OBJECT
*DriverObject
)
820 PLIST_ENTRY NextEntry
;
821 PUNIQUE_ID_WORK_ITEM WorkItem
;
822 PDEVICE_EXTENSION DeviceExtension
;
823 PDEVICE_INFORMATION DeviceInformation
;
824 PSAVED_LINK_INFORMATION SavedLinkInformation
;
826 UNREFERENCED_PARAMETER(DriverObject
);
828 /* Don't get notification any longer */
829 IoUnregisterShutdownNotification(gdeviceObject
);
831 /* Free registry buffer */
832 DeviceExtension
= gdeviceObject
->DeviceExtension
;
833 if (DeviceExtension
->RegistryPath
.Buffer
)
835 FreePool(DeviceExtension
->RegistryPath
.Buffer
);
836 DeviceExtension
->RegistryPath
.Buffer
= NULL
;
839 InterlockedExchange(&Unloading
, TRUE
);
841 KeInitializeEvent(&UnloadEvent
, NotificationEvent
, FALSE
);
843 /* Wait for workers to finish */
844 if (InterlockedIncrement(&DeviceExtension
->WorkerReferences
))
846 KeReleaseSemaphore(&(DeviceExtension
->WorkerSemaphore
),
847 IO_NO_INCREMENT
, 1, FALSE
);
849 KeWaitForSingleObject(&UnloadEvent
, Executive
, KernelMode
, FALSE
, NULL
);
853 InterlockedDecrement(&(DeviceExtension
->WorkerReferences
));
856 /* Don't get any notification any longer² */
857 IoUnregisterPlugPlayNotification(DeviceExtension
->NotificationEntry
);
859 /* Acquire the driver exclusively */
860 KeWaitForSingleObject(&(DeviceExtension
->DeviceLock
), Executive
, KernelMode
,
863 /* Clear offline devices list */
864 while (!IsListEmpty(&(DeviceExtension
->OfflineDeviceListHead
)))
866 NextEntry
= RemoveHeadList(&(DeviceExtension
->OfflineDeviceListHead
));
867 DeviceInformation
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
868 MountMgrFreeDeadDeviceInfo(DeviceInformation
);
871 /* Clear saved links list */
872 while (!IsListEmpty(&(DeviceExtension
->SavedLinksListHead
)))
874 NextEntry
= RemoveHeadList(&(DeviceExtension
->SavedLinksListHead
));
875 SavedLinkInformation
= CONTAINING_RECORD(NextEntry
, SAVED_LINK_INFORMATION
, SavedLinksListEntry
);
876 MountMgrFreeSavedLink(SavedLinkInformation
);
879 /* Clear workers list */
880 while (!IsListEmpty(&(DeviceExtension
->UniqueIdWorkerItemListHead
)))
882 NextEntry
= RemoveHeadList(&(DeviceExtension
->UniqueIdWorkerItemListHead
));
883 WorkItem
= CONTAINING_RECORD(NextEntry
, UNIQUE_ID_WORK_ITEM
, UniqueIdWorkerItemListEntry
);
885 KeResetEvent(&UnloadEvent
);
886 WorkItem
->Event
= &UnloadEvent
;
888 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
,
891 IoCancelIrp(WorkItem
->Irp
);
892 KeWaitForSingleObject(&UnloadEvent
, Executive
, KernelMode
, FALSE
, NULL
);
894 IoFreeIrp(WorkItem
->Irp
);
895 FreePool(WorkItem
->DeviceName
.Buffer
);
896 FreePool(WorkItem
->IrpBuffer
);
899 KeWaitForSingleObject(&(DeviceExtension
->DeviceLock
), Executive
, KernelMode
,
903 /* If we have drive letter data, release */
904 if (DeviceExtension
->DriveLetterData
)
906 FreePool(DeviceExtension
->DriveLetterData
);
907 DeviceExtension
->DriveLetterData
= NULL
;
910 /* Release driver & quit */
911 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
, 1, FALSE
);
913 GlobalDeleteSymbolicLink(&DosDevicesMount
);
914 IoDeleteDevice(gdeviceObject
);
922 MountmgrReadNoAutoMount(IN PUNICODE_STRING RegistryPath
)
925 ULONG Result
, Default
= 0;
926 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
928 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
930 /* Simply read data from register */
931 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
932 QueryTable
[0].Name
= L
"NoAutoMount";
933 QueryTable
[0].EntryContext
= &Result
;
934 QueryTable
[0].DefaultType
= REG_NONE
;
935 QueryTable
[0].DefaultData
= &Default
;
936 QueryTable
[0].DefaultLength
= sizeof(ULONG
);
938 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
939 RegistryPath
->Buffer
,
943 if (!NT_SUCCESS(Status
))
945 return (Default
!= 0);
948 return (Result
!= 0);
955 MountMgrMountedDeviceArrival(IN PDEVICE_EXTENSION DeviceExtension
,
956 IN PUNICODE_STRING SymbolicName
,
957 IN BOOLEAN FromVolume
)
962 ULONG SymLinkCount
, i
;
963 PLIST_ENTRY NextEntry
;
964 PUNICODE_STRING SymLinks
;
965 NTSTATUS Status
, IntStatus
;
966 OBJECT_ATTRIBUTES ObjectAttributes
;
967 PSYMLINK_INFORMATION SymlinkInformation
;
968 PMOUNTDEV_UNIQUE_ID UniqueId
, NewUniqueId
;
969 PSAVED_LINK_INFORMATION SavedLinkInformation
;
970 PDEVICE_INFORMATION DeviceInformation
, CurrentDevice
;
971 WCHAR CSymLinkBuffer
[MAX_PATH
], LinkTargetBuffer
[MAX_PATH
];
972 UNICODE_STRING TargetDeviceName
, SuggestedLinkName
, DeviceName
, VolumeName
, DriveLetter
, LinkTarget
, CSymLink
;
973 BOOLEAN HasGuid
, HasGptDriveLetter
, Valid
, UseOnlyIfThereAreNoOtherLinks
, IsDrvLetter
, IsOff
, IsVolumeName
, LinkError
;
975 /* New device = new structure to represent it */
976 DeviceInformation
= AllocatePool(sizeof(DEVICE_INFORMATION
));
977 if (!DeviceInformation
)
979 return STATUS_INSUFFICIENT_RESOURCES
;
982 /* Initialise device structure */
983 RtlZeroMemory(DeviceInformation
, sizeof(DEVICE_INFORMATION
));
984 InitializeListHead(&(DeviceInformation
->SymbolicLinksListHead
));
985 InitializeListHead(&(DeviceInformation
->ReplicatedUniqueIdsListHead
));
986 InitializeListHead(&(DeviceInformation
->AssociatedDevicesHead
));
987 DeviceInformation
->SymbolicName
.Length
= SymbolicName
->Length
;
988 DeviceInformation
->SymbolicName
.MaximumLength
= SymbolicName
->Length
+ sizeof(UNICODE_NULL
);
989 DeviceInformation
->SymbolicName
.Buffer
= AllocatePool(DeviceInformation
->SymbolicName
.MaximumLength
);
990 if (!DeviceInformation
->SymbolicName
.Buffer
)
992 FreePool(DeviceInformation
);
993 return STATUS_INSUFFICIENT_RESOURCES
;
996 /* Copy symbolic name */
997 RtlCopyMemory(DeviceInformation
->SymbolicName
.Buffer
, SymbolicName
->Buffer
, SymbolicName
->Length
);
998 DeviceInformation
->SymbolicName
.Buffer
[DeviceInformation
->SymbolicName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
999 DeviceInformation
->Volume
= FromVolume
;
1000 DeviceInformation
->DeviceExtension
= DeviceExtension
;
1002 /* Query as much data as possible about device */
1003 Status
= QueryDeviceInformation(SymbolicName
,
1006 &(DeviceInformation
->Removable
),
1011 if (!NT_SUCCESS(Status
))
1013 KeWaitForSingleObject(&(DeviceExtension
->DeviceLock
), Executive
, KernelMode
, FALSE
, NULL
);
1015 for (NextEntry
= DeviceExtension
->OfflineDeviceListHead
.Flink
;
1016 NextEntry
!= &(DeviceExtension
->OfflineDeviceListHead
);
1017 NextEntry
= NextEntry
->Flink
)
1019 CurrentDevice
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
1021 if (RtlEqualUnicodeString(&(DeviceInformation
->SymbolicName
), &(CurrentDevice
->SymbolicName
), TRUE
))
1027 if (NextEntry
!= &(DeviceExtension
->OfflineDeviceListHead
))
1029 MountMgrFreeDeadDeviceInfo(DeviceInformation
);
1033 InsertTailList(&(DeviceExtension
->OfflineDeviceListHead
), &(DeviceInformation
->DeviceListEntry
));
1036 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
, 1, FALSE
);
1041 /* Save gathered data */
1042 DeviceInformation
->UniqueId
= UniqueId
;
1043 DeviceInformation
->DeviceName
= TargetDeviceName
;
1044 DeviceInformation
->KeepLinks
= FALSE
;
1046 /* If we found system partition, mark it */
1047 if (DeviceExtension
->DriveLetterData
&& UniqueId
->UniqueIdLength
== DeviceExtension
->DriveLetterData
->UniqueIdLength
)
1049 if (RtlCompareMemory(UniqueId
->UniqueId
, DeviceExtension
->DriveLetterData
->UniqueId
, UniqueId
->UniqueIdLength
)
1050 == UniqueId
->UniqueIdLength
)
1052 IoSetSystemPartition(&TargetDeviceName
);
1056 /* Check suggested link name */
1057 Status
= QuerySuggestedLinkName(&(DeviceInformation
->SymbolicName
),
1059 &UseOnlyIfThereAreNoOtherLinks
);
1060 if (!NT_SUCCESS(Status
))
1062 SuggestedLinkName
.Buffer
= NULL
;
1065 /* If it's OK, set it and save its letter (if any) */
1066 if (SuggestedLinkName
.Buffer
&& IsDriveLetter(&SuggestedLinkName
))
1068 DeviceInformation
->SuggestedDriveLetter
= (UCHAR
)SuggestedLinkName
.Buffer
[LETTER_POSITION
];
1071 /* Acquire driver exclusively */
1072 KeWaitForSingleObject(&(DeviceExtension
->DeviceLock
), Executive
, KernelMode
, FALSE
, NULL
);
1074 /* Check if we already have device in to prevent double registration */
1075 for (NextEntry
= DeviceExtension
->DeviceListHead
.Flink
;
1076 NextEntry
!= &(DeviceExtension
->DeviceListHead
);
1077 NextEntry
= NextEntry
->Flink
)
1079 CurrentDevice
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
1081 if (RtlEqualUnicodeString(&(CurrentDevice
->DeviceName
), &TargetDeviceName
, TRUE
))
1087 /* If we found it, clear ours, and return success, all correct */
1088 if (NextEntry
!= &(DeviceExtension
->DeviceListHead
))
1090 if (SuggestedLinkName
.Buffer
)
1092 FreePool(SuggestedLinkName
.Buffer
);
1096 FreePool(TargetDeviceName
.Buffer
);
1097 FreePool(DeviceInformation
->DeviceName
.Buffer
);
1098 FreePool(DeviceInformation
);
1100 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
, 1, FALSE
);
1102 return STATUS_SUCCESS
;
1105 /* Check if there are symlinks associated with our device in registry */
1106 Status
= QuerySymbolicLinkNamesFromStorage(DeviceExtension
,
1108 (SuggestedLinkName
.Buffer
) ? &SuggestedLinkName
: NULL
,
1109 UseOnlyIfThereAreNoOtherLinks
,
1115 /* If our device is a CD-ROM */
1116 if (RtlPrefixUnicodeString(&DeviceCdRom
, &TargetDeviceName
, TRUE
))
1118 LinkTarget
.Length
= 0;
1119 LinkTarget
.MaximumLength
= sizeof(LinkTargetBuffer
);
1120 LinkTarget
.Buffer
= LinkTargetBuffer
;
1122 RtlCopyMemory(CSymLinkBuffer
, Cunc
, sizeof(Cunc
));
1123 RtlInitUnicodeString(&CSymLink
, CSymLinkBuffer
);
1125 /* Start checking all letters that could have been associated */
1126 for (Letter
= L
'D'; Letter
<= L
'Z'; Letter
++)
1128 CSymLink
.Buffer
[LETTER_POSITION
] = Letter
;
1130 InitializeObjectAttributes(&ObjectAttributes
,
1132 OBJ_CASE_INSENSITIVE
,
1136 /* Try to open the associated symlink */
1137 Status
= ZwOpenSymbolicLinkObject(&LinkHandle
, SYMBOLIC_LINK_QUERY
, &ObjectAttributes
);
1138 if (!NT_SUCCESS(Status
))
1143 /* And query its target */
1144 Status
= ZwQuerySymbolicLinkObject(LinkHandle
, &LinkTarget
, NULL
);
1145 ZwClose(LinkHandle
);
1147 if (!NT_SUCCESS(Status
))
1152 IntStatus
= STATUS_UNSUCCESSFUL
;
1153 if (!RtlEqualUnicodeString(&LinkTarget
, &DeviceInformation
->DeviceName
, FALSE
))
1158 /* This link is matching our device, whereas it's not supposed to have any
1159 * symlink associated.
1164 IoDeleteSymbolicLink(&CSymLink
);
1168 /* Now, for all the symlinks, check for ours */
1169 for (i
= 0; i
< SymLinkCount
; i
++)
1171 if (IsDriveLetter(&(SymLinks
[i
])))
1173 /* If it exists, that's correct */
1174 if (SymLinks
[i
].Buffer
[LETTER_POSITION
] == Letter
)
1176 IntStatus
= STATUS_SUCCESS
;
1181 /* Useless link, delete it */
1182 if (IntStatus
== STATUS_UNSUCCESSFUL
)
1184 IoDeleteSymbolicLink(&CSymLink
);
1189 /* Suggested name is no longer required */
1190 if (SuggestedLinkName
.Buffer
)
1192 FreePool(SuggestedLinkName
.Buffer
);
1195 /* If if failed, ensure we don't take symlinks into account */
1196 if (!NT_SUCCESS(Status
))
1202 /* Now we queried them, remove the symlinks */
1203 SavedLinkInformation
= RemoveSavedLinks(DeviceExtension
, UniqueId
);
1205 IsDrvLetter
= FALSE
;
1207 IsVolumeName
= FALSE
;
1208 /* For all the symlinks */
1209 for (i
= 0; i
< SymLinkCount
; i
++)
1211 /* Check if our device is a volume */
1212 if (MOUNTMGR_IS_VOLUME_NAME(&(SymLinks
[i
])))
1214 IsVolumeName
= TRUE
;
1216 /* If it has a drive letter */
1217 else if (IsDriveLetter(&(SymLinks
[i
])))
1221 DeleteFromLocalDatabase(&(SymLinks
[i
]), UniqueId
);
1230 /* And recreate the symlink to our device */
1231 Status
= GlobalCreateSymbolicLink(&(SymLinks
[i
]), &TargetDeviceName
);
1232 if (!NT_SUCCESS(Status
))
1236 if ((SavedLinkInformation
&& !RedirectSavedLink(SavedLinkInformation
, &(SymLinks
[i
]), &TargetDeviceName
)) ||
1237 !SavedLinkInformation
)
1239 Status
= QueryDeviceInformation(&(SymLinks
[i
]), &DeviceName
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
1240 if (NT_SUCCESS(Status
))
1242 LinkError
= RtlEqualUnicodeString(&TargetDeviceName
, &DeviceName
, TRUE
);
1243 FreePool(DeviceName
.Buffer
);
1248 if (IsDriveLetter(&(SymLinks
[i
])))
1250 IsDrvLetter
= FALSE
;
1251 DeleteFromLocalDatabase(&(SymLinks
[i
]), UniqueId
);
1254 FreePool(SymLinks
[i
].Buffer
);
1260 /* Check if was offline */
1261 if (IsOffline(&(SymLinks
[i
])))
1266 /* Finally, associate this symlink with the device */
1267 SymlinkInformation
= AllocatePool(sizeof(SYMLINK_INFORMATION
));
1268 if (!SymlinkInformation
)
1270 GlobalDeleteSymbolicLink(&(SymLinks
[i
]));
1271 FreePool(SymLinks
[i
].Buffer
);
1275 SymlinkInformation
->Name
= SymLinks
[i
];
1276 SymlinkInformation
->Online
= TRUE
;
1278 InsertTailList(&(DeviceInformation
->SymbolicLinksListHead
),
1279 &(SymlinkInformation
->SymbolicLinksListEntry
));
1282 /* Now, for all the recreated symlinks, notify their recreation */
1283 for (NextEntry
= DeviceInformation
->SymbolicLinksListHead
.Flink
;
1284 NextEntry
!= &(DeviceInformation
->SymbolicLinksListHead
);
1285 NextEntry
= NextEntry
->Flink
)
1287 SymlinkInformation
= CONTAINING_RECORD(NextEntry
, SYMLINK_INFORMATION
, SymbolicLinksListEntry
);
1289 SendLinkCreated(&(SymlinkInformation
->Name
));
1292 /* If we had saved links, it's time to free them */
1293 if (SavedLinkInformation
)
1295 MountMgrFreeSavedLink(SavedLinkInformation
);
1298 /* If our device doesn't have a volume name */
1301 /* It's time to create one */
1302 Status
= CreateNewVolumeName(&VolumeName
, NULL
);
1303 if (NT_SUCCESS(Status
))
1305 /* Write it to global database */
1306 RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE
,
1311 UniqueId
->UniqueIdLength
);
1313 /* And create the symlink */
1314 GlobalCreateSymbolicLink(&VolumeName
, &TargetDeviceName
);
1316 SymlinkInformation
= AllocatePool(sizeof(SYMLINK_INFORMATION
));
1317 if (!SymlinkInformation
)
1319 FreePool(VolumeName
.Buffer
);
1321 /* Finally, associate it with the device and notify creation */
1324 SymlinkInformation
->Name
= VolumeName
;
1325 SymlinkInformation
->Online
= TRUE
;
1326 InsertTailList(&(DeviceInformation
->SymbolicLinksListHead
),
1327 &(SymlinkInformation
->SymbolicLinksListEntry
));
1329 SendLinkCreated(&VolumeName
);
1334 /* If we found a drive letter, then, ignore the suggested one */
1337 DeviceInformation
->SuggestedDriveLetter
= 0;
1339 /* Else, it's time to set up one */
1340 else if ((DeviceExtension
->NoAutoMount
|| DeviceInformation
->Removable
) &&
1341 DeviceExtension
->AutomaticDriveLetter
&&
1342 (HasGptDriveLetter
|| DeviceInformation
->SuggestedDriveLetter
) &&
1343 !HasNoDriveLetterEntry(UniqueId
))
1345 /* Create a new drive letter */
1346 Status
= CreateNewDriveLetterName(&DriveLetter
, &TargetDeviceName
,
1347 DeviceInformation
->SuggestedDriveLetter
,
1349 if (!NT_SUCCESS(Status
))
1351 CreateNoDriveLetterEntry(UniqueId
);
1355 /* Save it to global database */
1356 RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE
,
1361 UniqueId
->UniqueIdLength
);
1363 /* Associate it with the device and notify creation */
1364 SymlinkInformation
= AllocatePool(sizeof(SYMLINK_INFORMATION
));
1365 if (!SymlinkInformation
)
1367 FreePool(DriveLetter
.Buffer
);
1371 SymlinkInformation
->Name
= DriveLetter
;
1372 SymlinkInformation
->Online
= TRUE
;
1373 InsertTailList(&(DeviceInformation
->SymbolicLinksListHead
),
1374 &(SymlinkInformation
->SymbolicLinksListEntry
));
1376 SendLinkCreated(&DriveLetter
);
1381 /* If required, register for notifications about the device */
1384 RegisterForTargetDeviceNotification(DeviceExtension
, DeviceInformation
);
1387 /* Finally, insert the device into our devices list */
1388 InsertTailList(&(DeviceExtension
->DeviceListHead
), &(DeviceInformation
->DeviceListEntry
));
1390 /* Copy device unique ID */
1391 NewUniqueId
= AllocatePool(UniqueId
->UniqueIdLength
+ sizeof(MOUNTDEV_UNIQUE_ID
));
1394 NewUniqueId
->UniqueIdLength
= UniqueId
->UniqueIdLength
;
1395 RtlCopyMemory(NewUniqueId
->UniqueId
, UniqueId
->UniqueId
, UniqueId
->UniqueIdLength
);
1398 /* If device's offline or valid, skip its notifications */
1401 DeviceInformation
->SkipNotifications
= TRUE
;
1404 /* In case device is valid and is set to no automount,
1407 if (DeviceExtension
->NoAutoMount
|| IsDrvLetter
)
1409 IsOff
= !DeviceInformation
->SkipNotifications
;
1416 /* Finally, release the exclusive lock */
1417 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
, 1, FALSE
);
1419 /* If device is not offline, notify its arrival */
1422 SendOnlineNotification(SymbolicName
);
1425 /* If we had symlinks (from storage), free them */
1431 /* Notify about unique id change */
1434 IssueUniqueIdChangeNotify(DeviceExtension
, SymbolicName
, NewUniqueId
);
1435 FreePool(NewUniqueId
);
1438 /* If this drive was set to have a drive letter automatically
1439 * Now it's back, local databases sync will be required
1441 if (DeviceExtension
->AutomaticDriveLetter
)
1443 KeWaitForSingleObject(&(DeviceExtension
->DeviceLock
), Executive
, KernelMode
, FALSE
, NULL
);
1445 ReconcileThisDatabaseWithMaster(DeviceExtension
, DeviceInformation
);
1447 NextEntry
= DeviceExtension
->DeviceListHead
.Flink
;
1448 CurrentDevice
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
1449 while (CurrentDevice
!= DeviceInformation
)
1451 if (!CurrentDevice
->NoDatabase
)
1453 ReconcileThisDatabaseWithMaster(DeviceExtension
, CurrentDevice
);
1456 NextEntry
= NextEntry
->Flink
;
1457 CurrentDevice
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
1460 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
, 1, FALSE
);
1463 return STATUS_SUCCESS
;
1470 MountMgrMountedDeviceRemoval(IN PDEVICE_EXTENSION DeviceExtension
,
1471 IN PUNICODE_STRING DeviceName
)
1473 PLIST_ENTRY NextEntry
, DeviceEntry
;
1474 PUNIQUE_ID_REPLICATE UniqueIdReplicate
;
1475 PSYMLINK_INFORMATION SymlinkInformation
;
1476 PASSOCIATED_DEVICE_ENTRY AssociatedDevice
;
1477 PSAVED_LINK_INFORMATION SavedLinkInformation
= NULL
;
1478 PDEVICE_INFORMATION DeviceInformation
, CurrentDevice
;
1480 /* Acquire device exclusively */
1481 KeWaitForSingleObject(&(DeviceExtension
->DeviceLock
), Executive
, KernelMode
, FALSE
, NULL
);
1483 /* Look for the leaving device */
1484 for (NextEntry
= DeviceExtension
->DeviceListHead
.Flink
;
1485 NextEntry
!= &(DeviceExtension
->DeviceListHead
);
1486 NextEntry
= NextEntry
->Flink
)
1488 DeviceInformation
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
1490 if (!RtlCompareUnicodeString(&(DeviceInformation
->SymbolicName
), DeviceName
, TRUE
))
1496 /* If we found it */
1497 if (NextEntry
!= &(DeviceExtension
->DeviceListHead
))
1499 /* If it's asked to keep links, then, prepare to save them */
1500 if (DeviceInformation
->KeepLinks
)
1502 SavedLinkInformation
= AllocatePool(sizeof(SAVED_LINK_INFORMATION
));
1503 if (!SavedLinkInformation
)
1505 DeviceInformation
->KeepLinks
= FALSE
;
1509 /* If it's possible (and asked), start to save them */
1510 if (DeviceInformation
->KeepLinks
)
1512 InsertTailList(&(DeviceExtension
->SavedLinksListHead
), &(SavedLinkInformation
->SavedLinksListEntry
));
1513 InitializeListHead(&(SavedLinkInformation
->SymbolicLinksListHead
));
1514 SavedLinkInformation
->UniqueId
= DeviceInformation
->UniqueId
;
1517 /* For all the symlinks */
1518 while (!IsListEmpty(&(DeviceInformation
->SymbolicLinksListHead
)))
1520 NextEntry
= RemoveHeadList(&(DeviceInformation
->SymbolicLinksListHead
));
1521 SymlinkInformation
= CONTAINING_RECORD(NextEntry
, SYMLINK_INFORMATION
, SymbolicLinksListEntry
);
1523 /* If we have to, save the link */
1524 if (DeviceInformation
->KeepLinks
)
1526 InsertTailList(&(SavedLinkInformation
->SymbolicLinksListHead
), &(SymlinkInformation
->SymbolicLinksListEntry
));
1528 /* Otherwise, just release it */
1531 GlobalDeleteSymbolicLink(&(SymlinkInformation
->Name
));
1532 FreePool(SymlinkInformation
->Name
.Buffer
);
1533 FreePool(SymlinkInformation
);
1537 /* Free all the replicated unique IDs */
1538 while (!IsListEmpty(&(DeviceInformation
->ReplicatedUniqueIdsListHead
)))
1540 NextEntry
= RemoveHeadList(&(DeviceInformation
->ReplicatedUniqueIdsListHead
));
1541 UniqueIdReplicate
= CONTAINING_RECORD(NextEntry
, UNIQUE_ID_REPLICATE
, ReplicatedUniqueIdsListEntry
);
1544 FreePool(UniqueIdReplicate
->UniqueId
);
1545 FreePool(UniqueIdReplicate
);
1548 while (!IsListEmpty(&(DeviceInformation
->AssociatedDevicesHead
)))
1550 NextEntry
= RemoveHeadList(&(DeviceInformation
->AssociatedDevicesHead
));
1551 AssociatedDevice
= CONTAINING_RECORD(NextEntry
, ASSOCIATED_DEVICE_ENTRY
, AssociatedDevicesEntry
);
1553 DeviceInformation
->NoDatabase
= TRUE
;
1554 FreePool(AssociatedDevice
->String
.Buffer
);
1555 FreePool(AssociatedDevice
);
1558 /* Remove device from the device list */
1559 RemoveEntryList(&(DeviceInformation
->DeviceListEntry
));
1561 /* If there are still devices, check if some were associated with ours */
1562 if (!IsListEmpty(&(DeviceInformation
->DeviceListEntry
)))
1564 for (NextEntry
= DeviceExtension
->DeviceListHead
.Flink
;
1565 NextEntry
!= &(DeviceExtension
->DeviceListHead
);
1566 NextEntry
= NextEntry
->Flink
)
1568 CurrentDevice
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
1570 /* And then, remove them */
1571 DeviceEntry
= CurrentDevice
->AssociatedDevicesHead
.Flink
;
1572 while (DeviceEntry
!= &(CurrentDevice
->AssociatedDevicesHead
))
1574 AssociatedDevice
= CONTAINING_RECORD(NextEntry
, ASSOCIATED_DEVICE_ENTRY
, AssociatedDevicesEntry
);
1575 DeviceEntry
= DeviceEntry
->Flink
;
1577 if (AssociatedDevice
->DeviceInformation
!= DeviceInformation
)
1582 RemoveEntryList(&(AssociatedDevice
->AssociatedDevicesEntry
));
1583 FreePool(AssociatedDevice
->String
.Buffer
);
1584 FreePool(AssociatedDevice
);
1589 /* Finally, clean up device name, symbolic name */
1590 FreePool(DeviceInformation
->SymbolicName
.Buffer
);
1591 if (!DeviceInformation
->KeepLinks
)
1593 FreePool(DeviceInformation
->UniqueId
);
1595 FreePool(DeviceInformation
->DeviceName
.Buffer
);
1597 /* Unregister notifications */
1598 if (DeviceInformation
->TargetDeviceNotificationEntry
)
1600 IoUnregisterPlugPlayNotification(DeviceInformation
->TargetDeviceNotificationEntry
);
1604 FreePool(DeviceInformation
);
1608 /* We didn't find device, perhaps because it was offline */
1609 for (NextEntry
= DeviceExtension
->OfflineDeviceListHead
.Flink
;
1610 NextEntry
!= &(DeviceExtension
->OfflineDeviceListHead
);
1611 NextEntry
= NextEntry
->Flink
)
1613 DeviceInformation
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
1615 /* It was, remove it */
1616 if (RtlCompareUnicodeString(&(DeviceInformation
->SymbolicName
), DeviceName
, TRUE
) == 0)
1618 RemoveEntryList(&(DeviceInformation
->DeviceListEntry
));
1619 MountMgrFreeDeadDeviceInfo(DeviceInformation
);
1625 /* Releave driver */
1626 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
, 1, FALSE
);
1634 MountMgrMountedDeviceNotification(IN PVOID NotificationStructure
,
1638 PDEVICE_EXTENSION DeviceExtension
;
1639 PDEVICE_INTERFACE_CHANGE_NOTIFICATION Notification
;
1641 /* Notification for a device arrived */
1642 /* Disable hard errors */
1643 OldState
= PsGetThreadHardErrorsAreDisabled(PsGetCurrentThread());
1644 PsSetThreadHardErrorsAreDisabled(PsGetCurrentThread(), TRUE
);
1646 DeviceExtension
= Context
;
1647 Notification
= NotificationStructure
;
1649 /* Dispatch according to the event */
1650 if (IsEqualGUID(&(Notification
->Event
), &GUID_DEVICE_INTERFACE_ARRIVAL
))
1652 MountMgrMountedDeviceArrival(DeviceExtension
, Notification
->SymbolicLinkName
, FALSE
);
1654 else if (IsEqualGUID(&(Notification
->Event
), &GUID_DEVICE_INTERFACE_REMOVAL
))
1656 MountMgrMountedDeviceRemoval(DeviceExtension
, Notification
->SymbolicLinkName
);
1659 /* Reset hard errors */
1660 PsSetThreadHardErrorsAreDisabled(PsGetCurrentThread(), OldState
);
1662 return STATUS_SUCCESS
;
1670 MountMgrCreateClose(IN PDEVICE_OBJECT DeviceObject
,
1673 PIO_STACK_LOCATION Stack
;
1674 NTSTATUS Status
= STATUS_SUCCESS
;
1676 UNREFERENCED_PARAMETER(DeviceObject
);
1678 Stack
= IoGetCurrentIrpStackLocation(Irp
);
1680 /* Allow driver opening for communication
1681 * as long as it's not taken for a directory
1683 if (Stack
->MajorFunction
== IRP_MJ_CREATE
&&
1684 Stack
->Parameters
.Create
.Options
& FILE_DIRECTORY_FILE
)
1686 Status
= STATUS_NOT_A_DIRECTORY
;
1689 Irp
->IoStatus
.Status
= Status
;
1690 Irp
->IoStatus
.Information
= 0;
1691 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1700 MountMgrCancel(IN PDEVICE_OBJECT DeviceObject
,
1703 UNREFERENCED_PARAMETER(DeviceObject
);
1705 RemoveEntryList(&(Irp
->Tail
.Overlay
.ListEntry
));
1707 IoReleaseCancelSpinLock(Irp
->CancelIrql
);
1709 Irp
->IoStatus
.Information
= 0;
1710 Irp
->IoStatus
.Status
= STATUS_CANCELLED
;
1711 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1719 MountMgrCleanup(IN PDEVICE_OBJECT DeviceObject
,
1724 PLIST_ENTRY NextEntry
;
1725 PFILE_OBJECT FileObject
;
1726 PIO_STACK_LOCATION Stack
;
1727 PDEVICE_EXTENSION DeviceExtension
;
1729 DeviceExtension
= DeviceObject
->DeviceExtension
;
1730 Stack
= IoGetCurrentIrpStackLocation(Irp
);
1731 FileObject
= Stack
->FileObject
;
1733 IoAcquireCancelSpinLock(&OldIrql
);
1735 /* If IRP list if empty, it's OK */
1736 if (IsListEmpty(&(DeviceExtension
->IrpListHead
)))
1738 IoReleaseCancelSpinLock(OldIrql
);
1740 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1741 Irp
->IoStatus
.Information
= 0;
1742 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1744 return STATUS_SUCCESS
;
1747 /* Otherwise, cancel all the IRPs */
1748 NextEntry
= &(DeviceExtension
->IrpListHead
);
1751 ListIrp
= CONTAINING_RECORD(NextEntry
, IRP
, Tail
.Overlay
.ListEntry
);
1752 if (IoGetCurrentIrpStackLocation(ListIrp
)->FileObject
== FileObject
)
1754 ListIrp
->Cancel
= TRUE
;
1755 ListIrp
->CancelIrql
= OldIrql
;
1756 ListIrp
->CancelRoutine
= NULL
;
1757 MountMgrCancel(DeviceObject
, ListIrp
);
1759 IoAcquireCancelSpinLock(&OldIrql
);
1762 NextEntry
= NextEntry
->Flink
;
1764 while (NextEntry
!= &(DeviceExtension
->IrpListHead
));
1766 IoReleaseCancelSpinLock(OldIrql
);
1768 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1769 Irp
->IoStatus
.Information
= 0;
1770 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1772 return STATUS_SUCCESS
;
1780 MountMgrShutdown(IN PDEVICE_OBJECT DeviceObject
,
1783 PDEVICE_EXTENSION DeviceExtension
;
1785 DeviceExtension
= DeviceObject
->DeviceExtension
;
1787 InterlockedExchange(&Unloading
, TRUE
);
1789 KeInitializeEvent(&UnloadEvent
, NotificationEvent
, FALSE
);
1791 /* Wait for workers */
1792 if (InterlockedIncrement(&(DeviceExtension
->WorkerReferences
)))
1794 KeReleaseSemaphore(&(DeviceExtension
->WorkerSemaphore
),
1798 KeWaitForSingleObject(&UnloadEvent
, Executive
, KernelMode
, FALSE
, NULL
);
1802 InterlockedDecrement(&(DeviceExtension
->WorkerReferences
));
1805 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1806 Irp
->IoStatus
.Information
= 0;
1807 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1809 return STATUS_SUCCESS
;
1812 /* FUNCTIONS ****************************************************************/
1817 DriverEntry(IN PDRIVER_OBJECT DriverObject
,
1818 IN PUNICODE_STRING RegistryPath
)
1821 PDEVICE_OBJECT DeviceObject
;
1822 PDEVICE_EXTENSION DeviceExtension
;
1824 RtlCreateRegistryKey(RTL_REGISTRY_ABSOLUTE
, DatabasePath
);
1826 Status
= IoCreateDevice(DriverObject
,
1827 sizeof(DEVICE_EXTENSION
),
1829 FILE_DEVICE_NETWORK
,
1830 FILE_DEVICE_SECURE_OPEN
,
1833 if (!NT_SUCCESS(Status
))
1838 DriverObject
->DriverUnload
= MountMgrUnload
;
1840 DeviceExtension
= DeviceObject
->DeviceExtension
;
1841 RtlZeroMemory(DeviceExtension
, sizeof(DEVICE_EXTENSION
));
1842 DeviceExtension
->DeviceObject
= DeviceObject
;
1843 DeviceExtension
->DriverObject
= DriverObject
;
1845 InitializeListHead(&(DeviceExtension
->DeviceListHead
));
1846 InitializeListHead(&(DeviceExtension
->OfflineDeviceListHead
));
1848 KeInitializeSemaphore(&(DeviceExtension
->DeviceLock
), 1, 1);
1849 KeInitializeSemaphore(&(DeviceExtension
->RemoteDatabaseLock
), 1, 1);
1851 InitializeListHead(&(DeviceExtension
->IrpListHead
));
1852 DeviceExtension
->EpicNumber
= 1;
1854 InitializeListHead(&(DeviceExtension
->SavedLinksListHead
));
1856 InitializeListHead(&(DeviceExtension
->WorkerQueueListHead
));
1857 KeInitializeSemaphore(&(DeviceExtension
->WorkerSemaphore
), 0, MAXLONG
);
1858 DeviceExtension
->WorkerReferences
= -1;
1859 KeInitializeSpinLock(&(DeviceExtension
->WorkerLock
));
1861 InitializeListHead(&(DeviceExtension
->UniqueIdWorkerItemListHead
));
1862 InitializeListHead(&(DeviceExtension
->OnlineNotificationListHead
));
1863 DeviceExtension
->OnlineNotificationCount
= 1;
1865 DeviceExtension
->RegistryPath
.Length
= RegistryPath
->Length
;
1866 DeviceExtension
->RegistryPath
.MaximumLength
= RegistryPath
->Length
+ sizeof(WCHAR
);
1867 DeviceExtension
->RegistryPath
.Buffer
= AllocatePool(DeviceExtension
->RegistryPath
.MaximumLength
);
1868 if (!DeviceExtension
->RegistryPath
.Buffer
)
1870 IoDeleteDevice(DeviceObject
);
1871 return STATUS_INSUFFICIENT_RESOURCES
;
1874 RtlCopyUnicodeString(&(DeviceExtension
->RegistryPath
), RegistryPath
);
1876 DeviceExtension
->NoAutoMount
= MountmgrReadNoAutoMount(&(DeviceExtension
->RegistryPath
));
1878 GlobalCreateSymbolicLink(&DosDevicesMount
, &DeviceMount
);
1880 /* Register for device arrival & removal. Ask to be notified for already
1883 Status
= IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange
,
1884 PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES
,
1885 &MountedDevicesGuid
,
1887 MountMgrMountedDeviceNotification
,
1889 &(DeviceExtension
->NotificationEntry
));
1891 if (!NT_SUCCESS(Status
))
1893 IoDeleteDevice(DeviceObject
);
1897 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] =
1898 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = MountMgrCreateClose
;
1899 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = MountMgrDeviceControl
;
1900 DriverObject
->MajorFunction
[IRP_MJ_CLEANUP
] = MountMgrCleanup
;
1901 DriverObject
->MajorFunction
[IRP_MJ_SHUTDOWN
] = MountMgrShutdown
;
1903 gdeviceObject
= DeviceObject
;
1905 Status
= IoRegisterShutdownNotification(DeviceObject
);
1906 if (!NT_SUCCESS(Status
))
1908 IoDeleteDevice(DeviceObject
);