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)
33 GUID MountedDevicesGuid
= {0x53F5630D, 0xB6BF, 0x11D0, {0x94, 0xF2, 0x00, 0xA0, 0xC9, 0x1E, 0xFB, 0x8B}};
35 PDEVICE_OBJECT gdeviceObject
;
39 static const WCHAR Cunc
[] = L
"\\??\\C:";
43 * - MountMgrQueryDosVolumePaths
44 * - MountMgrQueryVolumePaths
45 * - MountMgrValidateBackPointer
46 * - MountMgrVolumeMountPointCreated
47 * - MountMgrVolumeMountPointDeleted
48 * - ReconcileThisDatabaseWithMasterWorker
55 IsOffline(PUNICODE_STRING SymbolicName
)
58 ULONG IsOffline
, Default
;
59 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
61 /* Prepare to look in the registry to see if
62 * given volume is offline
64 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
65 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
66 QueryTable
[0].Name
= SymbolicName
->Buffer
;
67 QueryTable
[0].EntryContext
= &IsOffline
;
68 QueryTable
[0].DefaultType
= REG_DWORD
;
69 QueryTable
[0].DefaultLength
= sizeof(ULONG
);
70 QueryTable
[0].DefaultData
= &Default
;
75 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
80 if (!NT_SUCCESS(Status
))
85 return (IsOffline
!= 0);
92 HasDriveLetter(IN PDEVICE_INFORMATION DeviceInformation
)
94 PLIST_ENTRY NextEntry
;
95 PSYMLINK_INFORMATION SymlinkInfo
;
97 /* To have a drive letter, a device must have symbolic links */
98 if (IsListEmpty(&(DeviceInformation
->SymbolicLinksListHead
)))
103 /* Browse all the links untill a drive letter is found */
104 NextEntry
= &(DeviceInformation
->SymbolicLinksListHead
);
107 SymlinkInfo
= CONTAINING_RECORD(NextEntry
, SYMLINK_INFORMATION
, SymbolicLinksListEntry
);
109 if (SymlinkInfo
->Online
)
111 if (IsDriveLetter(&(SymlinkInfo
->Name
)))
117 NextEntry
= NextEntry
->Flink
;
118 } while (NextEntry
!= &(DeviceInformation
->SymbolicLinksListHead
));
127 CreateNewDriveLetterName(OUT PUNICODE_STRING DriveLetter
,
128 IN PUNICODE_STRING DeviceName
,
130 IN PMOUNTDEV_UNIQUE_ID UniqueId OPTIONAL
)
132 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
134 /* Allocate a big enough buffer to contain the symbolic link */
135 DriveLetter
->MaximumLength
= sizeof(DosDevices
.Buffer
) + 3 * sizeof(WCHAR
);
136 DriveLetter
->Buffer
= AllocatePool(sizeof(DosDevices
.Buffer
) + 3 * sizeof(WCHAR
));
137 if (!DriveLetter
->Buffer
)
139 return STATUS_INSUFFICIENT_RESOURCES
;
143 RtlCopyUnicodeString(DriveLetter
, &DosDevices
);
145 /* Update string to reflect real contents */
146 DriveLetter
->Length
= sizeof(DosDevices
.Buffer
) + 2 * sizeof(WCHAR
);
147 DriveLetter
->Buffer
[(sizeof(DosDevices
.Buffer
) + 2 * sizeof(WCHAR
)) / sizeof (WCHAR
)] = UNICODE_NULL
;
148 DriveLetter
->Buffer
[(sizeof(DosDevices
.Buffer
) + sizeof(WCHAR
)) / sizeof (WCHAR
)] = L
':';
150 /* If caller wants a no drive entry */
151 if (Letter
== (UCHAR
)-1)
153 /* Then, create a no letter entry */
154 CreateNoDriveLetterEntry(UniqueId
);
155 FreePool(DriveLetter
->Buffer
);
156 return STATUS_UNSUCCESSFUL
;
160 /* Use the letter given by the caller */
161 DriveLetter
->Buffer
[sizeof(DosDevices
.Buffer
) / sizeof(WCHAR
)] = (WCHAR
)Letter
;
162 Status
= GlobalCreateSymbolicLink(DriveLetter
, DeviceName
);
163 if (NT_SUCCESS(Status
))
169 /* If caller didn't provide a letter, let's find one for him */
171 if (RtlPrefixUnicodeString(&DeviceFloppy
, DeviceName
, TRUE
))
173 /* If the device is a floppy, start with letter A */
176 else if (RtlPrefixUnicodeString(&DeviceCdRom
, DeviceName
, TRUE
))
178 /* If the device is a CD-ROM, start with letter D */
183 /* Finally, if it's a disk, use C */
187 /* Try to affect a letter (up to Z, ofc) until it's possible */
188 for (; Letter
<= 'Z'; Letter
++)
190 DriveLetter
->Buffer
[sizeof(DosDevices
.Buffer
) / sizeof(WCHAR
)] = (WCHAR
)Letter
;
191 Status
= GlobalCreateSymbolicLink(DriveLetter
, DeviceName
);
192 if (NT_SUCCESS(Status
))
198 /* We failed to allocate a letter */
199 FreePool(DriveLetter
->Buffer
);
207 QueryDeviceInformation(IN PUNICODE_STRING SymbolicName
,
208 OUT PUNICODE_STRING DeviceName OPTIONAL
,
209 OUT PMOUNTDEV_UNIQUE_ID
* UniqueId OPTIONAL
,
210 OUT PBOOLEAN Removable OPTIONAL
,
211 OUT PBOOLEAN GptDriveLetter OPTIONAL
,
212 OUT PBOOLEAN HasGuid OPTIONAL
,
213 IN OUT LPGUID StableGuid OPTIONAL
,
214 OUT PBOOLEAN Valid OPTIONAL
)
222 PMOUNTDEV_UNIQUE_ID Id
;
223 PFILE_OBJECT FileObject
;
224 PIO_STACK_LOCATION Stack
;
225 PDEVICE_OBJECT DeviceObject
;
226 IO_STATUS_BLOCK IoStatusBlock
;
227 PARTITION_INFORMATION_EX PartitionInfo
;
228 STORAGE_DEVICE_NUMBER StorageDeviceNumber
;
229 VOLUME_GET_GPT_ATTRIBUTES_INFORMATION GptAttributes
;
231 /* Get device associated with the symbolic name */
232 Status
= IoGetDeviceObjectPointer(SymbolicName
,
233 FILE_READ_ATTRIBUTES
,
236 if (!NT_SUCCESS(Status
))
241 /* The associate FO can't have a file name */
242 if (FileObject
->FileName
.Length
)
244 ObDereferenceObject(FileObject
);
245 return STATUS_OBJECT_NAME_NOT_FOUND
;
248 /* Check if it's removable & return to the user (if asked to) */
249 IsRemovable
= (FileObject
->DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
);
252 *Removable
= IsRemovable
;
255 /* Get the attached device */
256 DeviceObject
= IoGetAttachedDeviceReference(FileObject
->DeviceObject
);
258 /* If we've been asked for a GPT drive letter */
261 /* Consider it has one */
262 *GptDriveLetter
= TRUE
;
266 /* Query the GPT attributes */
267 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
268 Irp
= IoBuildDeviceIoControlRequest(IOCTL_VOLUME_GET_GPT_ATTRIBUTES
,
273 sizeof(GptAttributes
),
279 ObDereferenceObject(DeviceObject
);
280 ObDereferenceObject(FileObject
);
281 return STATUS_INSUFFICIENT_RESOURCES
;
284 Status
= IoCallDriver(DeviceObject
, Irp
);
285 if (Status
== STATUS_PENDING
)
287 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
288 Status
= IoStatusBlock
.Status
;
291 /* In case of failure, don't fail, that's no vital */
292 if (!NT_SUCCESS(Status
))
294 Status
= STATUS_SUCCESS
;
296 /* Check if it has a drive letter */
297 else if (!(GptAttributes
.GptAttributes
&
298 GPT_BASIC_DATA_ATTRIBUTE_NO_DRIVE_LETTER
))
300 *GptDriveLetter
= FALSE
;
305 /* If caller wants to know if there's valid contents */
308 /* Suppose it's not OK */
313 /* Query partitions information */
314 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
315 Irp
= IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_PARTITION_INFO_EX
,
320 sizeof(PartitionInfo
),
326 ObDereferenceObject(DeviceObject
);
327 ObDereferenceObject(FileObject
);
328 return STATUS_INSUFFICIENT_RESOURCES
;
331 Status
= IoCallDriver(DeviceObject
, Irp
);
332 if (Status
== STATUS_PENDING
)
334 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
335 Status
= IoStatusBlock
.Status
;
338 /* Once again here, failure isn't major */
339 if (!NT_SUCCESS(Status
))
341 Status
= STATUS_SUCCESS
;
343 /* Verify we know something in */
344 else if (PartitionInfo
.PartitionStyle
== PARTITION_STYLE_MBR
&&
345 IsRecognizedPartition(PartitionInfo
.Mbr
.PartitionType
))
350 /* It looks correct, ensure it is & query device number */
353 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
354 Irp
= IoBuildDeviceIoControlRequest(IOCTL_STORAGE_GET_DEVICE_NUMBER
,
358 &StorageDeviceNumber
,
359 sizeof(StorageDeviceNumber
),
365 ObDereferenceObject(DeviceObject
);
366 ObDereferenceObject(FileObject
);
367 return STATUS_INSUFFICIENT_RESOURCES
;
370 Status
= IoCallDriver(DeviceObject
, Irp
);
371 if (Status
== STATUS_PENDING
)
373 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
374 Status
= IoStatusBlock
.Status
;
377 if (!NT_SUCCESS(Status
))
379 Status
= STATUS_SUCCESS
;
389 /* If caller needs device name */
392 /* Allocate a buffer just to request length */
393 Name
= AllocatePool(sizeof(MOUNTDEV_NAME
));
396 ObDereferenceObject(DeviceObject
);
397 ObDereferenceObject(FileObject
);
398 return STATUS_INSUFFICIENT_RESOURCES
;
401 /* Query device name */
402 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
403 Irp
= IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_DEVICE_NAME
,
408 sizeof(MOUNTDEV_NAME
),
415 ObDereferenceObject(DeviceObject
);
416 ObDereferenceObject(FileObject
);
417 return STATUS_INSUFFICIENT_RESOURCES
;
420 Stack
= IoGetNextIrpStackLocation(Irp
);
421 Stack
->FileObject
= FileObject
;
423 Status
= IoCallDriver(DeviceObject
, Irp
);
424 if (Status
== STATUS_PENDING
)
426 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
427 Status
= IoStatusBlock
.Status
;
430 /* Now, we've got the correct length */
431 if (Status
== STATUS_BUFFER_OVERFLOW
)
433 Size
= Name
->NameLength
+ sizeof(MOUNTDEV_NAME
);
437 /* Allocate proper size */
438 Name
= AllocatePool(Size
);
441 ObDereferenceObject(DeviceObject
);
442 ObDereferenceObject(FileObject
);
443 return STATUS_INSUFFICIENT_RESOURCES
;
446 /* And query name (for real that time) */
447 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
448 Irp
= IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_DEVICE_NAME
,
460 ObDereferenceObject(DeviceObject
);
461 ObDereferenceObject(FileObject
);
462 return STATUS_INSUFFICIENT_RESOURCES
;
465 Stack
= IoGetNextIrpStackLocation(Irp
);
466 Stack
->FileObject
= FileObject
;
468 Status
= IoCallDriver(DeviceObject
, Irp
);
469 if (Status
== STATUS_PENDING
)
471 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
472 Status
= IoStatusBlock
.Status
;
476 /* Here we can't fail and assume default value */
477 if (!NT_SUCCESS(Status
))
480 ObDereferenceObject(DeviceObject
);
481 ObDereferenceObject(FileObject
);
485 /* Copy back found name to the caller */
486 DeviceName
->Length
= Name
->NameLength
;
487 DeviceName
->MaximumLength
= Name
->NameLength
+ sizeof(WCHAR
);
488 DeviceName
->Buffer
= AllocatePool(DeviceName
->MaximumLength
);
489 if (!DeviceName
->Buffer
)
492 ObDereferenceObject(DeviceObject
);
493 ObDereferenceObject(FileObject
);
494 return STATUS_INSUFFICIENT_RESOURCES
;
497 RtlCopyMemory(DeviceName
->Buffer
, Name
->Name
, Name
->NameLength
);
498 DeviceName
->Buffer
[Name
->NameLength
/ sizeof(WCHAR
)] = UNICODE_NULL
;
502 /* If caller wants device unique ID */
505 /* Prepare buffer to probe length */
506 Id
= AllocatePool(sizeof(MOUNTDEV_UNIQUE_ID
));
509 ObDereferenceObject(DeviceObject
);
510 ObDereferenceObject(FileObject
);
511 return STATUS_INSUFFICIENT_RESOURCES
;
514 /* Query unique ID length */
515 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
516 Irp
= IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_UNIQUE_ID
,
521 sizeof(MOUNTDEV_UNIQUE_ID
),
528 ObDereferenceObject(DeviceObject
);
529 ObDereferenceObject(FileObject
);
530 return STATUS_INSUFFICIENT_RESOURCES
;
533 Stack
= IoGetNextIrpStackLocation(Irp
);
534 Stack
->FileObject
= FileObject
;
536 Status
= IoCallDriver(DeviceObject
, Irp
);
537 if (Status
== STATUS_PENDING
)
539 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
540 Status
= IoStatusBlock
.Status
;
543 /* Retry with appropriate length */
544 if (Status
== STATUS_BUFFER_OVERFLOW
)
546 Size
= Id
->UniqueIdLength
+ sizeof(MOUNTDEV_UNIQUE_ID
);
550 /* Allocate the correct buffer */
551 Id
= AllocatePool(Size
);
554 ObDereferenceObject(DeviceObject
);
555 ObDereferenceObject(FileObject
);
556 return STATUS_INSUFFICIENT_RESOURCES
;
559 /* Query unique ID */
560 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
561 Irp
= IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_DEVICE_NAME
,
573 ObDereferenceObject(DeviceObject
);
574 ObDereferenceObject(FileObject
);
575 return STATUS_INSUFFICIENT_RESOURCES
;
578 Stack
= IoGetNextIrpStackLocation(Irp
);
579 Stack
->FileObject
= FileObject
;
581 Status
= IoCallDriver(DeviceObject
, Irp
);
582 if (Status
== STATUS_PENDING
)
584 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
585 Status
= IoStatusBlock
.Status
;
589 /* Hands back unique ID */
590 if (NT_SUCCESS(Status
))
596 /* In case of failure, also free the rest */
598 if (DeviceName
->Length
)
600 FreePool(DeviceName
->Buffer
);
603 ObDereferenceObject(DeviceObject
);
604 ObDereferenceObject(FileObject
);
610 /* If user wants to know about GUID */
613 /* Query device stable GUID */
614 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
615 Irp
= IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_STABLE_GUID
,
626 ObDereferenceObject(DeviceObject
);
627 ObDereferenceObject(FileObject
);
628 return STATUS_INSUFFICIENT_RESOURCES
;
631 Stack
= IoGetNextIrpStackLocation(Irp
);
632 Stack
->FileObject
= FileObject
;
634 Status
= IoCallDriver(DeviceObject
, Irp
);
635 if (Status
== STATUS_PENDING
)
637 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
638 Status
= IoStatusBlock
.Status
;
641 *HasGuid
= NT_SUCCESS(Status
);
644 ObDereferenceObject(DeviceObject
);
645 ObDereferenceObject(FileObject
);
653 FindDeviceInfo(IN PDEVICE_EXTENSION DeviceExtension
,
654 IN PUNICODE_STRING SymbolicName
,
655 IN BOOLEAN DeviceNameGiven
,
656 OUT PDEVICE_INFORMATION
* DeviceInformation
)
659 PLIST_ENTRY NextEntry
;
660 UNICODE_STRING DeviceName
;
661 PDEVICE_INFORMATION DeviceInfo
= NULL
;
663 /* If a device name was given, use it */
666 DeviceName
.Length
= SymbolicName
->Length
;
667 DeviceName
.Buffer
= SymbolicName
->Buffer
;
671 /* Otherwise, query it */
672 Status
= QueryDeviceInformation(SymbolicName
,
677 if (!NT_SUCCESS(Status
))
683 /* Look for device information matching devive */
684 for (NextEntry
= DeviceExtension
->DeviceListHead
.Flink
;
685 NextEntry
!= &(DeviceExtension
->DeviceListHead
);
686 NextEntry
= NextEntry
->Flink
)
688 DeviceInfo
= CONTAINING_RECORD(NextEntry
,
692 if (RtlEqualUnicodeString(&DeviceName
, &(DeviceInfo
->DeviceName
), TRUE
))
698 /* Release our buffer if required */
699 if (!DeviceNameGiven
)
701 FreePool(DeviceName
.Buffer
);
704 /* Return found intormation */
705 if (NextEntry
== &(DeviceExtension
->DeviceListHead
))
707 return STATUS_OBJECT_NAME_NOT_FOUND
;
710 *DeviceInformation
= DeviceInfo
;
711 return STATUS_SUCCESS
;
718 MountMgrFreeDeadDeviceInfo(IN PDEVICE_INFORMATION DeviceInformation
)
720 FreePool(DeviceInformation
->SymbolicName
.Buffer
);
721 FreePool(DeviceInformation
);
728 MountMgrFreeMountedDeviceInfo(IN PDEVICE_INFORMATION DeviceInformation
)
730 PLIST_ENTRY NextEntry
;
731 PSYMLINK_INFORMATION SymLink
;
732 PUNIQUE_ID_REPLICATE UniqueId
;
733 PASSOCIATED_DEVICE_ENTRY AssociatedDevice
;
735 /* Purge symbolic links list */
736 while (!IsListEmpty(&(DeviceInformation
->SymbolicLinksListHead
)))
738 NextEntry
= RemoveHeadList(&(DeviceInformation
->SymbolicLinksListHead
));
739 SymLink
= CONTAINING_RECORD(NextEntry
, SYMLINK_INFORMATION
, SymbolicLinksListEntry
);
741 GlobalDeleteSymbolicLink(&(SymLink
->Name
));
742 FreePool(SymLink
->Name
.Buffer
);
745 /* Purge replicated unique IDs list */
746 while (!IsListEmpty(&(DeviceInformation
->ReplicatedUniqueIdsListHead
)))
748 NextEntry
= RemoveHeadList(&(DeviceInformation
->ReplicatedUniqueIdsListHead
));
749 UniqueId
= CONTAINING_RECORD(NextEntry
, UNIQUE_ID_REPLICATE
, ReplicatedUniqueIdsListEntry
);
751 FreePool(UniqueId
->UniqueId
);
755 while (!IsListEmpty(&(DeviceInformation
->AssociatedDevicesHead
)))
757 NextEntry
= RemoveHeadList(&(DeviceInformation
->AssociatedDevicesHead
));
758 AssociatedDevice
= CONTAINING_RECORD(NextEntry
, ASSOCIATED_DEVICE_ENTRY
, AssociatedDevicesEntry
);
760 FreePool(AssociatedDevice
->String
.Buffer
);
761 FreePool(AssociatedDevice
);
764 /* Free the rest of the buffers */
765 FreePool(DeviceInformation
->SymbolicName
.Buffer
);
766 if (DeviceInformation
->KeepLinks
)
768 FreePool(DeviceInformation
->UniqueId
);
770 FreePool(DeviceInformation
->DeviceName
.Buffer
);
772 /* Finally, stop waiting for notifications for this device */
773 if (DeviceInformation
->TargetDeviceNotificationEntry
)
775 IoUnregisterPlugPlayNotification(DeviceInformation
->TargetDeviceNotificationEntry
);
783 MountMgrFreeSavedLink(IN PSAVED_LINK_INFORMATION SavedLinkInformation
)
785 PLIST_ENTRY NextEntry
;
786 PSYMLINK_INFORMATION SymlinkInformation
;
788 /* For all the saved links */
789 while (!IsListEmpty(&(SavedLinkInformation
->SymbolicLinksListHead
)))
791 NextEntry
= RemoveHeadList(&(SavedLinkInformation
->SymbolicLinksListHead
));
792 SymlinkInformation
= CONTAINING_RECORD(NextEntry
, SYMLINK_INFORMATION
, SymbolicLinksListEntry
);
794 /* Remove from system & free */
795 GlobalDeleteSymbolicLink(&(SymlinkInformation
->Name
));
796 FreePool(SymlinkInformation
->Name
.Buffer
);
797 FreePool(SymlinkInformation
);
800 /* And free unique ID & entry */
801 FreePool(SavedLinkInformation
->UniqueId
);
802 FreePool(SavedLinkInformation
);
811 MountMgrUnload(IN
struct _DRIVER_OBJECT
*DriverObject
)
813 PLIST_ENTRY NextEntry
;
814 PUNIQUE_ID_WORK_ITEM WorkItem
;
815 PDEVICE_EXTENSION DeviceExtension
;
816 PDEVICE_INFORMATION DeviceInformation
;
817 PSAVED_LINK_INFORMATION SavedLinkInformation
;
819 UNREFERENCED_PARAMETER(DriverObject
);
821 /* Don't get notification any longer */
822 IoUnregisterShutdownNotification(gdeviceObject
);
824 /* Free registry buffer */
825 DeviceExtension
= gdeviceObject
->DeviceExtension
;
826 if (DeviceExtension
->RegistryPath
.Buffer
)
828 FreePool(DeviceExtension
->RegistryPath
.Buffer
);
829 DeviceExtension
->RegistryPath
.Buffer
= NULL
;
832 InterlockedExchange(&Unloading
, TRUE
);
834 KeInitializeEvent(&UnloadEvent
, NotificationEvent
, FALSE
);
836 /* Wait for workers to finish */
837 if (InterlockedIncrement(&DeviceExtension
->WorkerReferences
))
839 KeReleaseSemaphore(&(DeviceExtension
->WorkerSemaphore
),
840 IO_NO_INCREMENT
, 1, FALSE
);
842 KeWaitForSingleObject(&UnloadEvent
, Executive
, KernelMode
, FALSE
, NULL
);
846 InterlockedDecrement(&(DeviceExtension
->WorkerReferences
));
849 /* Don't get any notification any longer² */
850 IoUnregisterPlugPlayNotification(DeviceExtension
->NotificationEntry
);
852 /* Acquire the driver exclusively */
853 KeWaitForSingleObject(&(DeviceExtension
->DeviceLock
), Executive
, KernelMode
,
856 /* Clear offline devices list */
857 while (!IsListEmpty(&(DeviceExtension
->OfflineDeviceListHead
)))
859 NextEntry
= RemoveHeadList(&(DeviceExtension
->OfflineDeviceListHead
));
860 DeviceInformation
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
861 MountMgrFreeDeadDeviceInfo(DeviceInformation
);
864 /* Clear saved links list */
865 while (!IsListEmpty(&(DeviceExtension
->SavedLinksListHead
)))
867 NextEntry
= RemoveHeadList(&(DeviceExtension
->SavedLinksListHead
));
868 SavedLinkInformation
= CONTAINING_RECORD(NextEntry
, SAVED_LINK_INFORMATION
, SavedLinksListEntry
);
869 MountMgrFreeSavedLink(SavedLinkInformation
);
872 /* Clear workers list */
873 while (!IsListEmpty(&(DeviceExtension
->UniqueIdWorkerItemListHead
)))
875 NextEntry
= RemoveHeadList(&(DeviceExtension
->UniqueIdWorkerItemListHead
));
876 WorkItem
= CONTAINING_RECORD(NextEntry
, UNIQUE_ID_WORK_ITEM
, UniqueIdWorkerItemListEntry
);
878 KeResetEvent(&UnloadEvent
);
879 WorkItem
->Event
= &UnloadEvent
;
881 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
,
884 IoCancelIrp(WorkItem
->Irp
);
885 KeWaitForSingleObject(&UnloadEvent
, Executive
, KernelMode
, FALSE
, NULL
);
887 IoFreeIrp(WorkItem
->Irp
);
888 FreePool(WorkItem
->DeviceName
.Buffer
);
889 FreePool(WorkItem
->IrpBuffer
);
892 KeWaitForSingleObject(&(DeviceExtension
->DeviceLock
), Executive
, KernelMode
,
896 /* If we have drive letter data, release */
897 if (DeviceExtension
->DriveLetterData
)
899 FreePool(DeviceExtension
->DriveLetterData
);
900 DeviceExtension
->DriveLetterData
= NULL
;
903 /* Release driver & quit */
904 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
, 1, FALSE
);
906 GlobalDeleteSymbolicLink(&DosDevicesMount
);
907 IoDeleteDevice(gdeviceObject
);
914 MountmgrReadNoAutoMount(IN PUNICODE_STRING RegistryPath
)
917 ULONG Result
, Default
= 0;
918 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
920 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
922 /* Simply read data from register */
923 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
924 QueryTable
[0].Name
= L
"NoAutoMount";
925 QueryTable
[0].EntryContext
= &Result
;
926 QueryTable
[0].DefaultType
= REG_NONE
;
927 QueryTable
[0].DefaultData
= &Default
;
928 QueryTable
[0].DefaultLength
= sizeof(ULONG
);
930 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
931 RegistryPath
->Buffer
,
935 if (!NT_SUCCESS(Status
))
937 return (Default
!= 0);
940 return (Result
!= 0);
947 MountMgrMountedDeviceArrival(IN PDEVICE_EXTENSION DeviceExtension
,
948 IN PUNICODE_STRING SymbolicName
,
949 IN BOOLEAN FromVolume
)
954 ULONG SymLinkCount
, i
;
955 PLIST_ENTRY NextEntry
;
956 PUNICODE_STRING SymLinks
;
957 NTSTATUS Status
, IntStatus
;
958 OBJECT_ATTRIBUTES ObjectAttributes
;
959 PSYMLINK_INFORMATION SymlinkInformation
;
960 PMOUNTDEV_UNIQUE_ID UniqueId
, NewUniqueId
;
961 PSAVED_LINK_INFORMATION SavedLinkInformation
;
962 PDEVICE_INFORMATION DeviceInformation
, CurrentDevice
;
963 WCHAR CSymLinkBuffer
[MAX_PATH
], LinkTargetBuffer
[MAX_PATH
];
964 UNICODE_STRING TargetDeviceName
, SuggestedLinkName
, DeviceName
, VolumeName
, DriveLetter
, LinkTarget
, CSymLink
;
965 BOOLEAN HasGuid
, HasGptDriveLetter
, Valid
, UseOnlyIfThereAreNoOtherLinks
, IsDrvLetter
, IsOff
, IsVolumeName
, LinkError
;
967 /* New device = new structure to represent it */
968 DeviceInformation
= AllocatePool(sizeof(DEVICE_INFORMATION
));
969 if (!DeviceInformation
)
971 return STATUS_INSUFFICIENT_RESOURCES
;
974 /* Initialise device structure */
975 RtlZeroMemory(DeviceInformation
, sizeof(DEVICE_INFORMATION
));
976 InitializeListHead(&(DeviceInformation
->SymbolicLinksListHead
));
977 InitializeListHead(&(DeviceInformation
->ReplicatedUniqueIdsListHead
));
978 InitializeListHead(&(DeviceInformation
->AssociatedDevicesHead
));
979 DeviceInformation
->SymbolicName
.Length
= SymbolicName
->Length
;
980 DeviceInformation
->SymbolicName
.MaximumLength
= SymbolicName
->Length
+ sizeof(UNICODE_NULL
);
981 DeviceInformation
->SymbolicName
.Buffer
= AllocatePool(DeviceInformation
->SymbolicName
.MaximumLength
);
982 if (!DeviceInformation
->SymbolicName
.Buffer
)
984 FreePool(DeviceInformation
);
985 return STATUS_INSUFFICIENT_RESOURCES
;
988 /* Copy symbolic name */
989 RtlCopyMemory(DeviceInformation
->SymbolicName
.Buffer
, SymbolicName
->Buffer
, SymbolicName
->Length
);
990 DeviceInformation
->SymbolicName
.Buffer
[DeviceInformation
->SymbolicName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
991 DeviceInformation
->Volume
= FromVolume
;
992 DeviceInformation
->DeviceExtension
= DeviceExtension
;
994 /* Query as much data as possible about device */
995 Status
= QueryDeviceInformation(SymbolicName
,
998 &(DeviceInformation
->Removable
),
1003 if (!NT_SUCCESS(Status
))
1005 KeWaitForSingleObject(&(DeviceExtension
->DeviceLock
), Executive
, KernelMode
, FALSE
, NULL
);
1007 for (NextEntry
= DeviceExtension
->OfflineDeviceListHead
.Flink
;
1008 NextEntry
!= &(DeviceExtension
->OfflineDeviceListHead
);
1009 NextEntry
= NextEntry
->Flink
)
1011 CurrentDevice
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
1013 if (RtlEqualUnicodeString(&(DeviceInformation
->SymbolicName
), &(CurrentDevice
->SymbolicName
), TRUE
))
1019 if (NextEntry
!= &(DeviceExtension
->OfflineDeviceListHead
))
1021 MountMgrFreeDeadDeviceInfo(DeviceInformation
);
1025 InsertTailList(&(DeviceExtension
->OfflineDeviceListHead
), &(DeviceInformation
->DeviceListEntry
));
1028 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
, 1, FALSE
);
1033 /* Save gathered data */
1034 DeviceInformation
->UniqueId
= UniqueId
;
1035 DeviceInformation
->DeviceName
= TargetDeviceName
;
1036 DeviceInformation
->KeepLinks
= FALSE
;
1038 /* If we found system partition, mark it */
1039 if (DeviceExtension
->DriveLetterData
&& UniqueId
->UniqueIdLength
== DeviceExtension
->DriveLetterData
->UniqueIdLength
)
1041 if (RtlCompareMemory(UniqueId
->UniqueId
, DeviceExtension
->DriveLetterData
->UniqueId
, UniqueId
->UniqueIdLength
)
1042 == UniqueId
->UniqueIdLength
)
1044 IoSetSystemPartition(&TargetDeviceName
);
1048 /* Check suggested link name */
1049 Status
= QuerySuggestedLinkName(&(DeviceInformation
->SymbolicName
),
1051 &UseOnlyIfThereAreNoOtherLinks
);
1052 if (!NT_SUCCESS(Status
))
1054 SuggestedLinkName
.Buffer
= NULL
;
1057 /* If it's OK, set it and save its letter (if any) */
1058 if (SuggestedLinkName
.Buffer
&& IsDriveLetter(&SuggestedLinkName
))
1060 DeviceInformation
->SuggestedDriveLetter
= (UCHAR
)SuggestedLinkName
.Buffer
[LETTER_POSITION
];
1063 /* Acquire driver exclusively */
1064 KeWaitForSingleObject(&(DeviceExtension
->DeviceLock
), Executive
, KernelMode
, FALSE
, NULL
);
1066 /* Check if we already have device in to prevent double registration */
1067 for (NextEntry
= DeviceExtension
->DeviceListHead
.Flink
;
1068 NextEntry
!= &(DeviceExtension
->DeviceListHead
);
1069 NextEntry
= NextEntry
->Flink
)
1071 CurrentDevice
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
1073 if (RtlEqualUnicodeString(&(DeviceInformation
->DeviceName
), &TargetDeviceName
, TRUE
))
1079 /* If we found it, clear ours, and return success, all correct */
1080 if (NextEntry
!= &(DeviceExtension
->DeviceListHead
))
1082 if (SuggestedLinkName
.Buffer
)
1084 FreePool(SuggestedLinkName
.Buffer
);
1088 FreePool(TargetDeviceName
.Buffer
);
1089 FreePool(DeviceInformation
->DeviceName
.Buffer
);
1090 FreePool(DeviceInformation
);
1092 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
, 1, FALSE
);
1094 return STATUS_SUCCESS
;
1097 /* Check if there are symlinks associated with our device in registry */
1098 Status
= QuerySymbolicLinkNamesFromStorage(DeviceExtension
,
1100 (SuggestedLinkName
.Buffer
) ? &SuggestedLinkName
: NULL
,
1101 UseOnlyIfThereAreNoOtherLinks
,
1107 /* If our device is a CD-ROM */
1108 if (RtlPrefixUnicodeString(&DeviceCdRom
, &TargetDeviceName
, TRUE
))
1110 LinkTarget
.Length
= 0;
1111 LinkTarget
.MaximumLength
= sizeof(LinkTargetBuffer
);
1112 LinkTarget
.Buffer
= LinkTargetBuffer
;
1114 RtlCopyMemory(CSymLinkBuffer
, Cunc
, sizeof(Cunc
));
1115 RtlInitUnicodeString(&CSymLink
, CSymLinkBuffer
);
1117 /* Start checking all letters that could have been associated */
1118 for (Letter
= L
'D'; Letter
<= L
'Z'; Letter
++)
1120 CSymLink
.Buffer
[LETTER_POSITION
] = Letter
;
1122 InitializeObjectAttributes(&ObjectAttributes
,
1124 OBJ_CASE_INSENSITIVE
,
1128 /* Try to open the associated symlink */
1129 Status
= ZwOpenSymbolicLinkObject(&LinkHandle
, SYMBOLIC_LINK_QUERY
, &ObjectAttributes
);
1130 if (!NT_SUCCESS(Status
))
1135 /* And query its target */
1136 Status
= ZwQuerySymbolicLinkObject(LinkHandle
, &LinkTarget
, NULL
);
1137 ZwClose(LinkHandle
);
1139 if (!NT_SUCCESS(Status
))
1144 IntStatus
= STATUS_UNSUCCESSFUL
;
1145 if (!RtlEqualUnicodeString(&LinkTarget
, &DeviceInformation
->DeviceName
, FALSE
))
1150 /* This link is matching our device, whereas it's not supposed to have any
1151 * symlink associated.
1156 IoDeleteSymbolicLink(&CSymLink
);
1160 /* Now, for all the symlinks, check for ours */
1161 for (i
= 0; i
< SymLinkCount
; i
++)
1163 if (IsDriveLetter(&(SymLinks
[i
])))
1165 /* If it exists, that's correct */
1166 if (SymLinks
[i
].Buffer
[LETTER_POSITION
] == Letter
)
1168 IntStatus
= STATUS_SUCCESS
;
1173 /* Useless link, delete it */
1174 if (IntStatus
== STATUS_UNSUCCESSFUL
)
1176 IoDeleteSymbolicLink(&CSymLink
);
1181 /* Suggested name is no longer required */
1182 if (SuggestedLinkName
.Buffer
)
1184 FreePool(SuggestedLinkName
.Buffer
);
1187 /* If if failed, ensure we don't take symlinks into account */
1188 if (!NT_SUCCESS(Status
))
1194 /* Now we queried them, remove the symlinks */
1195 SavedLinkInformation
= RemoveSavedLinks(DeviceExtension
, UniqueId
);
1197 IsDrvLetter
= FALSE
;
1199 IsVolumeName
= FALSE
;
1200 /* For all the symlinks */
1201 for (i
= 0; i
< SymLinkCount
; i
++)
1203 /* Check if our device is a volume */
1204 if (MOUNTMGR_IS_VOLUME_NAME(&(SymLinks
[i
])))
1206 IsVolumeName
= TRUE
;
1208 /* If it has a drive letter */
1209 else if (IsDriveLetter(&(SymLinks
[i
])))
1213 DeleteFromLocalDatabase(&(SymLinks
[i
]), UniqueId
);
1222 /* And recreate the symlink to our device */
1223 Status
= GlobalCreateSymbolicLink(&(SymLinks
[i
]), &TargetDeviceName
);
1224 if (!NT_SUCCESS(Status
))
1228 if ((SavedLinkInformation
&& !RedirectSavedLink(SavedLinkInformation
, &(SymLinks
[i
]), &TargetDeviceName
)) ||
1229 !SavedLinkInformation
)
1231 Status
= QueryDeviceInformation(&(SymLinks
[i
]), &DeviceName
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
1232 if (NT_SUCCESS(Status
))
1234 LinkError
= RtlEqualUnicodeString(&TargetDeviceName
, &DeviceName
, TRUE
);
1235 FreePool(DeviceName
.Buffer
);
1240 if (IsDriveLetter(&(SymLinks
[i
])))
1242 IsDrvLetter
= FALSE
;
1243 DeleteFromLocalDatabase(&(SymLinks
[i
]), UniqueId
);
1246 FreePool(SymLinks
[i
].Buffer
);
1252 /* Check if was offline */
1253 if (IsOffline(&(SymLinks
[i
])))
1258 /* Finally, associate this symlink with the device */
1259 SymlinkInformation
= AllocatePool(sizeof(SYMLINK_INFORMATION
));
1260 if (!SymlinkInformation
)
1262 GlobalDeleteSymbolicLink(&(SymLinks
[i
]));
1263 FreePool(SymLinks
[i
].Buffer
);
1267 SymlinkInformation
->Name
= SymLinks
[i
];
1268 SymlinkInformation
->Online
= TRUE
;
1270 InsertTailList(&(DeviceInformation
->SymbolicLinksListHead
),
1271 &(SymlinkInformation
->SymbolicLinksListEntry
));
1274 /* Now, for all the recreated symlinks, notify their recreation */
1275 for (NextEntry
= DeviceInformation
->SymbolicLinksListHead
.Flink
;
1276 NextEntry
!= &(DeviceInformation
->SymbolicLinksListHead
);
1277 NextEntry
= NextEntry
->Flink
)
1279 SymlinkInformation
= CONTAINING_RECORD(NextEntry
, SYMLINK_INFORMATION
, SymbolicLinksListEntry
);
1281 SendLinkCreated(&(SymlinkInformation
->Name
));
1284 /* If we had saved links, it's time to free them */
1285 if (SavedLinkInformation
)
1287 MountMgrFreeSavedLink(SavedLinkInformation
);
1290 /* If our device doesn't have a volume name */
1293 /* It's time to create one */
1294 Status
= CreateNewVolumeName(&VolumeName
, NULL
);
1295 if (NT_SUCCESS(Status
))
1297 /* Write it to global database */
1298 RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE
,
1303 UniqueId
->UniqueIdLength
);
1305 /* And create the symlink */
1306 GlobalCreateSymbolicLink(&VolumeName
, &TargetDeviceName
);
1308 SymlinkInformation
= AllocatePool(sizeof(SYMLINK_INFORMATION
));
1309 if (!SymlinkInformation
)
1311 FreePool(VolumeName
.Buffer
);
1313 /* Finally, associate it with the device and notify creation */
1316 SymlinkInformation
->Name
= VolumeName
;
1317 SymlinkInformation
->Online
= TRUE
;
1318 InsertTailList(&(DeviceInformation
->SymbolicLinksListHead
),
1319 &(SymlinkInformation
->SymbolicLinksListEntry
));
1321 SendLinkCreated(&VolumeName
);
1326 /* If we found a drive letter, then, ignore the suggested one */
1329 DeviceInformation
->SuggestedDriveLetter
= 0;
1331 /* Else, it's time to set up one */
1332 else if (!DeviceExtension
->NoAutoMount
&& !DeviceInformation
->Removable
&&
1333 DeviceExtension
->AutomaticDriveLetter
&& HasGptDriveLetter
&&
1334 DeviceInformation
->SuggestedDriveLetter
&&
1335 !HasNoDriveLetterEntry(UniqueId
))
1337 /* Create a new drive letter */
1338 Status
= CreateNewDriveLetterName(&DriveLetter
, &TargetDeviceName
,
1339 DeviceInformation
->SuggestedDriveLetter
,
1341 if (!NT_SUCCESS(Status
))
1343 CreateNoDriveLetterEntry(UniqueId
);
1347 /* Save it to global database */
1348 RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE
,
1353 UniqueId
->UniqueIdLength
);
1355 /* Associate it with the device and notify creation */
1356 SymlinkInformation
= AllocatePool(sizeof(SYMLINK_INFORMATION
));
1357 if (!SymlinkInformation
)
1359 FreePool(DriveLetter
.Buffer
);
1363 SymlinkInformation
->Name
= DriveLetter
;
1364 SymlinkInformation
->Online
= TRUE
;
1365 InsertTailList(&(DeviceInformation
->SymbolicLinksListHead
),
1366 &(SymlinkInformation
->SymbolicLinksListEntry
));
1368 SendLinkCreated(&DriveLetter
);
1373 /* If required, register for notifications about the device */
1376 RegisterForTargetDeviceNotification(DeviceExtension
, DeviceInformation
);
1379 /* Finally, insert the device into our devices list */
1380 InsertTailList(&(DeviceExtension
->DeviceListHead
), &(DeviceInformation
->DeviceListEntry
));
1382 /* Copy device unique ID */
1383 NewUniqueId
= AllocatePool(UniqueId
->UniqueIdLength
+ sizeof(MOUNTDEV_UNIQUE_ID
));
1386 NewUniqueId
->UniqueIdLength
= UniqueId
->UniqueIdLength
;
1387 RtlCopyMemory(NewUniqueId
->UniqueId
, UniqueId
->UniqueId
, UniqueId
->UniqueIdLength
);
1390 /* If device's offline or valid, skip its notifications */
1393 DeviceInformation
->SkipNotifications
= TRUE
;
1396 /* In case device is valid and is set to no automount,
1399 if (DeviceExtension
->NoAutoMount
|| IsDrvLetter
)
1401 IsOff
= !DeviceInformation
->SkipNotifications
;
1408 /* Finally, release the exclusive lock */
1409 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
, 1, FALSE
);
1411 /* If device is not offline, notify its arrival */
1414 SendOnlineNotification(SymbolicName
);
1417 /* If we had symlinks (from storage), free them */
1423 /* Notify about unique id change */
1426 IssueUniqueIdChangeNotify(DeviceExtension
, SymbolicName
, NewUniqueId
);
1427 FreePool(NewUniqueId
);
1430 /* If this drive was set to have a drive letter automatically
1431 * Now it's back, local databases sync will be required
1433 if (DeviceExtension
->AutomaticDriveLetter
)
1435 KeWaitForSingleObject(&(DeviceExtension
->DeviceLock
), Executive
, KernelMode
, FALSE
, NULL
);
1437 ReconcileThisDatabaseWithMaster(DeviceExtension
, DeviceInformation
);
1439 NextEntry
= DeviceExtension
->DeviceListHead
.Flink
;
1440 CurrentDevice
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
1441 while (CurrentDevice
!= DeviceInformation
)
1443 if (!CurrentDevice
->NoDatabase
)
1445 ReconcileThisDatabaseWithMaster(DeviceExtension
, CurrentDevice
);
1448 NextEntry
= NextEntry
->Flink
;
1449 CurrentDevice
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
1452 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
, 1, FALSE
);
1455 return STATUS_SUCCESS
;
1462 MountMgrMountedDeviceRemoval(IN PDEVICE_EXTENSION DeviceExtension
,
1463 IN PUNICODE_STRING DeviceName
)
1465 PLIST_ENTRY NextEntry
, DeviceEntry
;
1466 PUNIQUE_ID_REPLICATE UniqueIdReplicate
;
1467 PSYMLINK_INFORMATION SymlinkInformation
;
1468 PASSOCIATED_DEVICE_ENTRY AssociatedDevice
;
1469 PSAVED_LINK_INFORMATION SavedLinkInformation
= NULL
;
1470 PDEVICE_INFORMATION DeviceInformation
, CurrentDevice
;
1472 /* Acquire device exclusively */
1473 KeWaitForSingleObject(&(DeviceExtension
->DeviceLock
), Executive
, KernelMode
, FALSE
, NULL
);
1475 /* Look for the leaving device */
1476 for (NextEntry
= DeviceExtension
->DeviceListHead
.Flink
;
1477 NextEntry
!= &(DeviceExtension
->DeviceListHead
);
1478 NextEntry
= NextEntry
->Flink
)
1480 DeviceInformation
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
1482 if (!RtlCompareUnicodeString(&(DeviceInformation
->SymbolicName
), DeviceName
, TRUE
))
1488 /* If we found it */
1489 if (NextEntry
!= &(DeviceExtension
->DeviceListHead
))
1491 /* If it's asked to keep links, then, prepare to save them */
1492 if (DeviceInformation
->KeepLinks
)
1494 SavedLinkInformation
= AllocatePool(sizeof(SAVED_LINK_INFORMATION
));
1495 if (!SavedLinkInformation
)
1497 DeviceInformation
->KeepLinks
= FALSE
;
1501 /* If it's possible (and asked), start to save them */
1502 if (DeviceInformation
->KeepLinks
)
1504 InsertTailList(&(DeviceExtension
->SavedLinksListHead
), &(SavedLinkInformation
->SavedLinksListEntry
));
1505 InitializeListHead(&(SavedLinkInformation
->SymbolicLinksListHead
));
1506 SavedLinkInformation
->UniqueId
= DeviceInformation
->UniqueId
;
1509 /* For all the symlinks */
1510 while (!IsListEmpty(&(DeviceInformation
->SymbolicLinksListHead
)))
1512 NextEntry
= RemoveHeadList(&(DeviceInformation
->SymbolicLinksListHead
));
1513 SymlinkInformation
= CONTAINING_RECORD(NextEntry
, SYMLINK_INFORMATION
, SymbolicLinksListEntry
);
1515 /* If we have to, save the link */
1516 if (DeviceInformation
->KeepLinks
)
1518 InsertTailList(&(SavedLinkInformation
->SymbolicLinksListHead
), &(SymlinkInformation
->SymbolicLinksListEntry
));
1520 /* Otherwise, just release it */
1523 GlobalDeleteSymbolicLink(&(SymlinkInformation
->Name
));
1524 FreePool(SymlinkInformation
->Name
.Buffer
);
1525 FreePool(SymlinkInformation
);
1529 /* Free all the replicated unique IDs */
1530 while (!IsListEmpty(&(DeviceInformation
->ReplicatedUniqueIdsListHead
)))
1532 NextEntry
= RemoveHeadList(&(DeviceInformation
->ReplicatedUniqueIdsListHead
));
1533 UniqueIdReplicate
= CONTAINING_RECORD(NextEntry
, UNIQUE_ID_REPLICATE
, ReplicatedUniqueIdsListEntry
);
1536 FreePool(UniqueIdReplicate
->UniqueId
);
1537 FreePool(UniqueIdReplicate
);
1540 while (!IsListEmpty(&(DeviceInformation
->AssociatedDevicesHead
)))
1542 NextEntry
= RemoveHeadList(&(DeviceInformation
->AssociatedDevicesHead
));
1543 AssociatedDevice
= CONTAINING_RECORD(NextEntry
, ASSOCIATED_DEVICE_ENTRY
, AssociatedDevicesEntry
);
1545 DeviceInformation
->NoDatabase
= TRUE
;
1546 FreePool(AssociatedDevice
->String
.Buffer
);
1547 FreePool(AssociatedDevice
);
1550 /* Remove device from the device list */
1551 RemoveEntryList(&(DeviceInformation
->DeviceListEntry
));
1553 /* If there are still devices, check if some were associated with ours */
1554 if (!IsListEmpty(&(DeviceInformation
->DeviceListEntry
)))
1556 for (NextEntry
= DeviceExtension
->DeviceListHead
.Flink
;
1557 NextEntry
!= &(DeviceExtension
->DeviceListHead
);
1558 NextEntry
= NextEntry
->Flink
)
1560 CurrentDevice
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
1562 /* And then, remove them */
1563 DeviceEntry
= CurrentDevice
->AssociatedDevicesHead
.Flink
;
1564 while (DeviceEntry
!= &(CurrentDevice
->AssociatedDevicesHead
))
1566 AssociatedDevice
= CONTAINING_RECORD(NextEntry
, ASSOCIATED_DEVICE_ENTRY
, AssociatedDevicesEntry
);
1567 DeviceEntry
= DeviceEntry
->Flink
;
1569 if (AssociatedDevice
->DeviceInformation
!= DeviceInformation
)
1574 RemoveEntryList(&(AssociatedDevice
->AssociatedDevicesEntry
));
1575 FreePool(AssociatedDevice
->String
.Buffer
);
1576 FreePool(AssociatedDevice
);
1581 /* Finally, clean up device name, symbolic name */
1582 FreePool(DeviceInformation
->SymbolicName
.Buffer
);
1583 if (!DeviceInformation
->KeepLinks
)
1585 FreePool(DeviceInformation
->UniqueId
);
1587 FreePool(DeviceInformation
->DeviceName
.Buffer
);
1589 /* Unregister notifications */
1590 if (DeviceInformation
->TargetDeviceNotificationEntry
)
1592 IoUnregisterPlugPlayNotification(DeviceInformation
->TargetDeviceNotificationEntry
);
1596 FreePool(DeviceInformation
);
1600 /* We didn't find device, perhaps because it was offline */
1601 for (NextEntry
= DeviceExtension
->OfflineDeviceListHead
.Flink
;
1602 NextEntry
!= &(DeviceExtension
->OfflineDeviceListHead
);
1603 NextEntry
= NextEntry
->Flink
)
1605 DeviceInformation
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
1607 /* It was, remove it */
1608 if (RtlCompareUnicodeString(&(DeviceInformation
->SymbolicName
), DeviceName
, TRUE
) == 0)
1610 RemoveEntryList(&(DeviceInformation
->DeviceListEntry
));
1611 MountMgrFreeDeadDeviceInfo(DeviceInformation
);
1617 /* Releave driver */
1618 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
, 1, FALSE
);
1626 MountMgrMountedDeviceNotification(IN PVOID NotificationStructure
,
1630 PDEVICE_EXTENSION DeviceExtension
;
1631 PDEVICE_INTERFACE_CHANGE_NOTIFICATION Notification
;
1633 /* Notification for a device arrived */
1634 /* Disable hard errors */
1635 OldState
= PsGetThreadHardErrorsAreDisabled(PsGetCurrentThread());
1636 PsSetThreadHardErrorsAreDisabled(PsGetCurrentThread(), TRUE
);
1638 DeviceExtension
= Context
;
1639 Notification
= NotificationStructure
;
1641 /* Dispatch according to the event */
1642 if (IsEqualGUID(&(Notification
->Event
), &GUID_DEVICE_INTERFACE_ARRIVAL
))
1644 MountMgrMountedDeviceArrival(DeviceExtension
, Notification
->SymbolicLinkName
, FALSE
);
1646 else if (IsEqualGUID(&(Notification
->Event
), &GUID_DEVICE_INTERFACE_REMOVAL
))
1648 MountMgrMountedDeviceRemoval(DeviceExtension
, Notification
->SymbolicLinkName
);
1651 /* Reset hard errors */
1652 PsSetThreadHardErrorsAreDisabled(PsGetCurrentThread(), OldState
);
1654 return STATUS_SUCCESS
;
1662 MountMgrCreateClose(IN PDEVICE_OBJECT DeviceObject
,
1665 PIO_STACK_LOCATION Stack
;
1666 NTSTATUS Status
= STATUS_SUCCESS
;
1668 UNREFERENCED_PARAMETER(DeviceObject
);
1670 Stack
= IoGetCurrentIrpStackLocation(Irp
);
1672 /* Allow driver opening for communication
1673 * as long as it's not taken for a directory
1675 if (Stack
->MajorFunction
== IRP_MJ_CREATE
&&
1676 Stack
->Parameters
.Create
.Options
& FILE_DIRECTORY_FILE
)
1678 Status
= STATUS_NOT_A_DIRECTORY
;
1681 Irp
->IoStatus
.Status
= Status
;
1682 Irp
->IoStatus
.Information
= 0;
1683 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1692 MountMgrCancel(IN PDEVICE_OBJECT DeviceObject
,
1695 UNREFERENCED_PARAMETER(DeviceObject
);
1697 RemoveEntryList(&(Irp
->Tail
.Overlay
.ListEntry
));
1699 IoReleaseCancelSpinLock(Irp
->CancelIrql
);
1701 Irp
->IoStatus
.Information
= 0;
1702 Irp
->IoStatus
.Status
= STATUS_CANCELLED
;
1703 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1711 MountMgrCleanup(IN PDEVICE_OBJECT DeviceObject
,
1716 PLIST_ENTRY NextEntry
;
1717 PFILE_OBJECT FileObject
;
1718 PIO_STACK_LOCATION Stack
;
1719 PDEVICE_EXTENSION DeviceExtension
;
1721 DeviceExtension
= DeviceObject
->DeviceExtension
;
1722 Stack
= IoGetCurrentIrpStackLocation(Irp
);
1723 FileObject
= Stack
->FileObject
;
1725 IoAcquireCancelSpinLock(&OldIrql
);
1727 /* If IRP list if empty, it's OK */
1728 if (IsListEmpty(&(DeviceExtension
->IrpListHead
)))
1730 IoReleaseCancelSpinLock(OldIrql
);
1732 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1733 Irp
->IoStatus
.Information
= 0;
1734 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1736 return STATUS_SUCCESS
;
1739 /* Otherwise, cancel all the IRPs */
1740 NextEntry
= &(DeviceExtension
->IrpListHead
);
1743 ListIrp
= CONTAINING_RECORD(NextEntry
, IRP
, Tail
.Overlay
.ListEntry
);
1744 if (IoGetCurrentIrpStackLocation(ListIrp
)->FileObject
== FileObject
)
1746 ListIrp
->Cancel
= TRUE
;
1747 ListIrp
->CancelIrql
= OldIrql
;
1748 ListIrp
->CancelRoutine
= NULL
;
1749 MountMgrCancel(DeviceObject
, ListIrp
);
1751 IoAcquireCancelSpinLock(&OldIrql
);
1754 NextEntry
= NextEntry
->Flink
;
1756 while (NextEntry
!= &(DeviceExtension
->IrpListHead
));
1758 IoReleaseCancelSpinLock(OldIrql
);
1760 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1761 Irp
->IoStatus
.Information
= 0;
1762 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1764 return STATUS_SUCCESS
;
1772 MountMgrShutdown(IN PDEVICE_OBJECT DeviceObject
,
1775 PDEVICE_EXTENSION DeviceExtension
;
1777 DeviceExtension
= DeviceObject
->DeviceExtension
;
1779 InterlockedExchange(&Unloading
, TRUE
);
1781 KeInitializeEvent(&UnloadEvent
, NotificationEvent
, FALSE
);
1783 /* Wait for workers */
1784 if (InterlockedIncrement(&(DeviceExtension
->WorkerReferences
)))
1786 KeReleaseSemaphore(&(DeviceExtension
->WorkerSemaphore
),
1790 KeWaitForSingleObject(&UnloadEvent
, Executive
, KernelMode
, FALSE
, NULL
);
1794 InterlockedDecrement(&(DeviceExtension
->WorkerReferences
));
1797 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1798 Irp
->IoStatus
.Information
= 0;
1799 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1801 return STATUS_SUCCESS
;
1804 /* FUNCTIONS ****************************************************************/
1808 DriverEntry(IN PDRIVER_OBJECT DriverObject
,
1809 IN PUNICODE_STRING RegistryPath
)
1812 PDEVICE_OBJECT DeviceObject
;
1813 PDEVICE_EXTENSION DeviceExtension
;
1815 RtlCreateRegistryKey(RTL_REGISTRY_ABSOLUTE
, DatabasePath
);
1817 Status
= IoCreateDevice(DriverObject
,
1818 sizeof(DEVICE_EXTENSION
),
1820 FILE_DEVICE_NETWORK
,
1821 FILE_DEVICE_SECURE_OPEN
,
1824 if (!NT_SUCCESS(Status
))
1829 DriverObject
->DriverUnload
= MountMgrUnload
;
1831 DeviceExtension
= DeviceObject
->DeviceExtension
;
1832 RtlZeroMemory(DeviceExtension
, sizeof(DEVICE_EXTENSION
));
1833 DeviceExtension
->DeviceObject
= DeviceObject
;
1834 DeviceExtension
->DriverObject
= DriverObject
;
1836 InitializeListHead(&(DeviceExtension
->DeviceListHead
));
1837 InitializeListHead(&(DeviceExtension
->OfflineDeviceListHead
));
1839 KeInitializeSemaphore(&(DeviceExtension
->DeviceLock
), 1, 1);
1840 KeInitializeSemaphore(&(DeviceExtension
->RemoteDatabaseLock
), 1, 1);
1842 InitializeListHead(&(DeviceExtension
->IrpListHead
));
1843 DeviceExtension
->EpicNumber
= 1;
1845 InitializeListHead(&(DeviceExtension
->SavedLinksListHead
));
1847 InitializeListHead(&(DeviceExtension
->WorkerQueueListHead
));
1848 KeInitializeSemaphore(&(DeviceExtension
->WorkerSemaphore
), 0, MAXLONG
);
1849 DeviceExtension
->WorkerReferences
= -1;
1850 KeInitializeSpinLock(&(DeviceExtension
->WorkerLock
));
1852 InitializeListHead(&(DeviceExtension
->UniqueIdWorkerItemListHead
));
1853 InitializeListHead(&(DeviceExtension
->OnlineNotificationListHead
));
1854 DeviceExtension
->OnlineNotificationCount
= 1;
1856 DeviceExtension
->RegistryPath
.Length
= RegistryPath
->Length
;
1857 DeviceExtension
->RegistryPath
.MaximumLength
= RegistryPath
->Length
+ sizeof(WCHAR
);
1858 DeviceExtension
->RegistryPath
.Buffer
= AllocatePool(DeviceExtension
->RegistryPath
.MaximumLength
);
1859 if (!DeviceExtension
->RegistryPath
.Buffer
)
1861 IoDeleteDevice(DeviceObject
);
1862 return STATUS_INSUFFICIENT_RESOURCES
;
1865 RtlCopyUnicodeString(&(DeviceExtension
->RegistryPath
), RegistryPath
);
1867 DeviceExtension
->NoAutoMount
= MountmgrReadNoAutoMount(&(DeviceExtension
->RegistryPath
));
1869 GlobalCreateSymbolicLink(&DosDevicesMount
, &DeviceMount
);
1871 /* Register for device arrival & removal. Ask to be notified for already
1874 Status
= IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange
,
1875 PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES
,
1876 &MountedDevicesGuid
,
1878 MountMgrMountedDeviceNotification
,
1880 &(DeviceExtension
->NotificationEntry
));
1882 if (!NT_SUCCESS(Status
))
1884 IoDeleteDevice(DeviceObject
);
1888 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] =
1889 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = MountMgrCreateClose
;
1890 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = MountMgrDeviceControl
;
1891 DriverObject
->MajorFunction
[IRP_MJ_CLEANUP
] = MountMgrCleanup
;
1892 DriverObject
->MajorFunction
[IRP_MJ_SHUTDOWN
] = MountMgrShutdown
;
1894 gdeviceObject
= DeviceObject
;
1896 Status
= IoRegisterShutdownNotification(DeviceObject
);
1897 if (!NT_SUCCESS(Status
))
1899 IoDeleteDevice(DeviceObject
);