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)
27 /* INCLUDES *****************************************************************/
35 GUID MountedDevicesGuid
= {0x53F5630D, 0xB6BF, 0x11D0, {0x94, 0xF2, 0x00, 0xA0, 0xC9, 0x1E, 0xFB, 0x8B}};
37 PDEVICE_OBJECT gdeviceObject
;
41 static const WCHAR Cunc
[] = L
"\\??\\C:";
45 * - MountMgrQueryDosVolumePath
46 * - MountMgrQueryDosVolumePaths
47 * - MountMgrQueryVolumePaths
48 * - MountMgrValidateBackPointer
49 * - MountMgrVolumeMountPointCreated
50 * - MountMgrVolumeMountPointDeleted
51 * - ReconcileThisDatabaseWithMasterWorker
58 IsOffline(PUNICODE_STRING SymbolicName
)
61 ULONG IsOffline
, Default
;
62 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
64 /* Prepare to look in the registry to see if
65 * given volume is offline
67 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
68 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
69 QueryTable
[0].Name
= SymbolicName
->Buffer
;
70 QueryTable
[0].EntryContext
= &IsOffline
;
71 QueryTable
[0].DefaultType
= REG_DWORD
;
72 QueryTable
[0].DefaultLength
= sizeof(ULONG
);
73 QueryTable
[0].DefaultData
= &Default
;
78 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
83 if (!NT_SUCCESS(Status
))
88 return (IsOffline
!= 0);
95 HasDriveLetter(IN PDEVICE_INFORMATION DeviceInformation
)
97 PLIST_ENTRY NextEntry
;
98 PSYMLINK_INFORMATION SymlinkInfo
;
100 /* To have a drive letter, a device must have symbolic links */
101 if (IsListEmpty(&(DeviceInformation
->SymbolicLinksListHead
)))
106 /* Browse all the links untill a drive letter is found */
107 NextEntry
= &(DeviceInformation
->SymbolicLinksListHead
);
110 SymlinkInfo
= CONTAINING_RECORD(NextEntry
, SYMLINK_INFORMATION
, SymbolicLinksListEntry
);
112 if (SymlinkInfo
->Online
)
114 if (IsDriveLetter(&(SymlinkInfo
->Name
)))
120 NextEntry
= NextEntry
->Flink
;
121 } while (NextEntry
!= &(DeviceInformation
->SymbolicLinksListHead
));
130 CreateNewDriveLetterName(OUT PUNICODE_STRING DriveLetter
,
131 IN PUNICODE_STRING DeviceName
,
133 IN PMOUNTDEV_UNIQUE_ID UniqueId OPTIONAL
)
135 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
137 /* Allocate a big enough buffer to contain the symbolic link */
138 DriveLetter
->MaximumLength
= sizeof(DosDevices
.Buffer
) + 3 * sizeof(WCHAR
);
139 DriveLetter
->Buffer
= AllocatePool(sizeof(DosDevices
.Buffer
) + 3 * sizeof(WCHAR
));
140 if (!DriveLetter
->Buffer
)
142 return STATUS_INSUFFICIENT_RESOURCES
;
146 RtlCopyUnicodeString(DriveLetter
, &DosDevices
);
148 /* Update string to reflect real contents */
149 DriveLetter
->Length
= sizeof(DosDevices
.Buffer
) + 2 * sizeof(WCHAR
);
150 DriveLetter
->Buffer
[(sizeof(DosDevices
.Buffer
) + 2 * sizeof(WCHAR
)) / sizeof (WCHAR
)] = UNICODE_NULL
;
151 DriveLetter
->Buffer
[(sizeof(DosDevices
.Buffer
) + sizeof(WCHAR
)) / sizeof (WCHAR
)] = L
':';
153 /* If caller wants a no drive entry */
154 if (Letter
== (UCHAR
)-1)
156 /* Then, create a no letter entry */
157 CreateNoDriveLetterEntry(UniqueId
);
158 FreePool(DriveLetter
->Buffer
);
159 return STATUS_UNSUCCESSFUL
;
163 /* Use the letter given by the caller */
164 DriveLetter
->Buffer
[sizeof(DosDevices
.Buffer
) / sizeof(WCHAR
)] = (WCHAR
)Letter
;
165 Status
= GlobalCreateSymbolicLink(DriveLetter
, DeviceName
);
166 if (NT_SUCCESS(Status
))
172 /* If caller didn't provide a letter, let's find one for him.
173 * If device is a floppy, start with letter A
175 if (RtlPrefixUnicodeString(&DeviceFloppy
, DeviceName
, TRUE
))
181 /* Otherwise, if device is a cd rom, then, start with D.
182 * Finally, if a disk, use C
184 Letter
= RtlPrefixUnicodeString(&DeviceCdRom
, DeviceName
, TRUE
) + '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 /* Don't get notification any longer */
820 IoUnregisterShutdownNotification(gdeviceObject
);
822 /* Free registry buffer */
823 DeviceExtension
= gdeviceObject
->DeviceExtension
;
824 if (DeviceExtension
->RegistryPath
.Buffer
)
826 FreePool(DeviceExtension
->RegistryPath
.Buffer
);
827 DeviceExtension
->RegistryPath
.Buffer
= NULL
;
830 InterlockedExchange(&Unloading
, TRUE
);
832 KeInitializeEvent(&UnloadEvent
, NotificationEvent
, FALSE
);
834 /* Wait for workers to finish */
835 if (InterlockedIncrement(&DeviceExtension
->WorkerReferences
))
837 KeReleaseSemaphore(&(DeviceExtension
->WorkerSemaphore
),
838 IO_NO_INCREMENT
, 1, FALSE
);
840 KeWaitForSingleObject(&UnloadEvent
, Executive
, KernelMode
, FALSE
, NULL
);
844 InterlockedDecrement(&(DeviceExtension
->WorkerReferences
));
847 /* Don't get any notification any longer² */
848 IoUnregisterPlugPlayNotification(DeviceExtension
->NotificationEntry
);
850 /* Acquire the driver exclusively */
851 KeWaitForSingleObject(&(DeviceExtension
->DeviceLock
), Executive
, KernelMode
,
854 /* Clear offline devices list */
855 while (!IsListEmpty(&(DeviceExtension
->OfflineDeviceListHead
)))
857 NextEntry
= RemoveHeadList(&(DeviceExtension
->OfflineDeviceListHead
));
858 DeviceInformation
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
859 MountMgrFreeDeadDeviceInfo(DeviceInformation
);
862 /* Clear saved links list */
863 while (!IsListEmpty(&(DeviceExtension
->SavedLinksListHead
)))
865 NextEntry
= RemoveHeadList(&(DeviceExtension
->SavedLinksListHead
));
866 SavedLinkInformation
= CONTAINING_RECORD(NextEntry
, SAVED_LINK_INFORMATION
, SavedLinksListEntry
);
867 MountMgrFreeSavedLink(SavedLinkInformation
);
870 /* Clear workers list */
871 while (!IsListEmpty(&(DeviceExtension
->UniqueIdWorkerItemListHead
)))
873 NextEntry
= RemoveHeadList(&(DeviceExtension
->UniqueIdWorkerItemListHead
));
874 WorkItem
= CONTAINING_RECORD(NextEntry
, UNIQUE_ID_WORK_ITEM
, UniqueIdWorkerItemListEntry
);
876 KeResetEvent(&UnloadEvent
);
877 WorkItem
->Event
= &UnloadEvent
;
879 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
,
882 IoCancelIrp(WorkItem
->Irp
);
883 KeWaitForSingleObject(&UnloadEvent
, Executive
, KernelMode
, FALSE
, NULL
);
885 IoFreeIrp(WorkItem
->Irp
);
886 FreePool(WorkItem
->DeviceName
.Buffer
);
887 FreePool(WorkItem
->IrpBuffer
);
890 KeWaitForSingleObject(&(DeviceExtension
->DeviceLock
), Executive
, KernelMode
,
894 /* If we have drive letter data, release */
895 if (DeviceExtension
->DriveLetterData
)
897 FreePool(DeviceExtension
->DriveLetterData
);
898 DeviceExtension
->DriveLetterData
= NULL
;
901 /* Release driver & quit */
902 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
, 1, FALSE
);
904 GlobalDeleteSymbolicLink(&DosDevicesMount
);
905 IoDeleteDevice(gdeviceObject
);
912 MountmgrReadNoAutoMount(IN PUNICODE_STRING RegistryPath
)
915 ULONG Result
, Default
= 0;
916 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
918 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
920 /* Simply read data from register */
921 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
922 QueryTable
[0].Name
= L
"NoAutoMount";
923 QueryTable
[0].EntryContext
= &Result
;
924 QueryTable
[0].DefaultType
= REG_NONE
;
925 QueryTable
[0].DefaultData
= &Default
;
926 QueryTable
[0].DefaultLength
= sizeof(ULONG
);
928 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
929 RegistryPath
->Buffer
,
933 if (!NT_SUCCESS(Status
))
935 return (Default
!= 0);
938 return (Result
!= 0);
945 MountMgrMountedDeviceArrival(IN PDEVICE_EXTENSION DeviceExtension
,
946 IN PUNICODE_STRING SymbolicName
,
947 IN BOOLEAN FromVolume
)
952 ULONG SymLinkCount
, i
;
953 PLIST_ENTRY NextEntry
;
954 PUNICODE_STRING SymLinks
;
955 NTSTATUS Status
, IntStatus
;
956 OBJECT_ATTRIBUTES ObjectAttributes
;
957 PSYMLINK_INFORMATION SymlinkInformation
;
958 PMOUNTDEV_UNIQUE_ID UniqueId
, NewUniqueId
;
959 PSAVED_LINK_INFORMATION SavedLinkInformation
;
960 PDEVICE_INFORMATION DeviceInformation
, CurrentDevice
;
961 WCHAR CSymLinkBuffer
[MAX_PATH
], LinkTargetBuffer
[MAX_PATH
];
962 UNICODE_STRING TargetDeviceName
, SuggestedLinkName
, DeviceName
, VolumeName
, DriveLetter
, LinkTarget
, CSymLink
;
963 BOOLEAN HasGuid
, HasGptDriveLetter
, Valid
, UseOnlyIfThereAreNoOtherLinks
, IsDrvLetter
, IsOff
, IsVolumeName
, LinkError
;
965 /* New device = new structure to represent it */
966 DeviceInformation
= AllocatePool(sizeof(DEVICE_INFORMATION
));
967 if (!DeviceInformation
)
969 return STATUS_INSUFFICIENT_RESOURCES
;
972 /* Initialise device structure */
973 RtlZeroMemory(DeviceInformation
, sizeof(DEVICE_INFORMATION
));
974 InitializeListHead(&(DeviceInformation
->SymbolicLinksListHead
));
975 InitializeListHead(&(DeviceInformation
->ReplicatedUniqueIdsListHead
));
976 InitializeListHead(&(DeviceInformation
->AssociatedDevicesHead
));
977 DeviceInformation
->SymbolicName
.Length
= SymbolicName
->Length
;
978 DeviceInformation
->SymbolicName
.MaximumLength
= SymbolicName
->Length
+ sizeof(UNICODE_NULL
);
979 DeviceInformation
->SymbolicName
.Buffer
= AllocatePool(DeviceInformation
->SymbolicName
.MaximumLength
);
980 if (!DeviceInformation
->SymbolicName
.Buffer
)
982 FreePool(DeviceInformation
);
983 return STATUS_INSUFFICIENT_RESOURCES
;
986 /* Copy symbolic name */
987 RtlCopyMemory(DeviceInformation
->SymbolicName
.Buffer
, SymbolicName
->Buffer
, SymbolicName
->Length
);
988 DeviceInformation
->SymbolicName
.Buffer
[DeviceInformation
->SymbolicName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
989 DeviceInformation
->Volume
= FromVolume
;
990 DeviceInformation
->DeviceExtension
= DeviceExtension
;
992 /* Query as much data as possible about device */
993 Status
= QueryDeviceInformation(SymbolicName
,
996 &(DeviceInformation
->Removable
),
1001 if (!NT_SUCCESS(Status
))
1003 KeWaitForSingleObject(&(DeviceExtension
->DeviceLock
), Executive
, KernelMode
, FALSE
, NULL
);
1005 for (NextEntry
= DeviceExtension
->OfflineDeviceListHead
.Flink
;
1006 NextEntry
!= &(DeviceExtension
->OfflineDeviceListHead
);
1007 NextEntry
= NextEntry
->Flink
)
1009 CurrentDevice
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
1011 if (RtlEqualUnicodeString(&(DeviceInformation
->SymbolicName
), &(CurrentDevice
->SymbolicName
), TRUE
))
1017 if (NextEntry
!= &(DeviceExtension
->OfflineDeviceListHead
))
1019 MountMgrFreeDeadDeviceInfo(DeviceInformation
);
1023 InsertTailList(&(DeviceExtension
->OfflineDeviceListHead
), &(DeviceInformation
->DeviceListEntry
));
1026 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
, 1, FALSE
);
1031 /* Save gathered data */
1032 DeviceInformation
->UniqueId
= UniqueId
;
1033 DeviceInformation
->DeviceName
= TargetDeviceName
;
1034 DeviceInformation
->KeepLinks
= FALSE
;
1036 /* If we found system partition, mark it */
1037 if (DeviceExtension
->DriveLetterData
&& UniqueId
->UniqueIdLength
== DeviceExtension
->DriveLetterData
->UniqueIdLength
)
1039 if (RtlCompareMemory(UniqueId
->UniqueId
, DeviceExtension
->DriveLetterData
->UniqueId
, UniqueId
->UniqueIdLength
)
1040 == UniqueId
->UniqueIdLength
)
1042 IoSetSystemPartition(&TargetDeviceName
);
1046 /* Check suggested link name */
1047 Status
= QuerySuggestedLinkName(&(DeviceInformation
->SymbolicName
),
1049 &UseOnlyIfThereAreNoOtherLinks
);
1050 if (!NT_SUCCESS(Status
))
1052 SuggestedLinkName
.Buffer
= NULL
;
1055 /* If it's OK, set it and save its letter (if any) */
1056 if (SuggestedLinkName
.Buffer
&& IsDriveLetter(&SuggestedLinkName
))
1058 DeviceInformation
->SuggestedDriveLetter
= (UCHAR
)SuggestedLinkName
.Buffer
[LETTER_POSITION
];
1061 /* Acquire driver exclusively */
1062 KeWaitForSingleObject(&(DeviceExtension
->DeviceLock
), Executive
, KernelMode
, FALSE
, NULL
);
1064 /* Check if we already have device in to prevent double registration */
1065 for (NextEntry
= DeviceExtension
->DeviceListHead
.Flink
;
1066 NextEntry
!= &(DeviceExtension
->DeviceListHead
);
1067 NextEntry
= NextEntry
->Flink
)
1069 CurrentDevice
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
1071 if (RtlEqualUnicodeString(&(DeviceInformation
->DeviceName
), &TargetDeviceName
, TRUE
))
1077 /* If we found it, clear ours, and return success, all correct */
1078 if (NextEntry
!= &(DeviceExtension
->DeviceListHead
))
1080 if (SuggestedLinkName
.Buffer
)
1082 FreePool(SuggestedLinkName
.Buffer
);
1086 FreePool(TargetDeviceName
.Buffer
);
1087 FreePool(DeviceInformation
->DeviceName
.Buffer
);
1088 FreePool(DeviceInformation
);
1090 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
, 1, FALSE
);
1092 return STATUS_SUCCESS
;
1095 /* Check if there are symlinks associated with our device in registry */
1096 Status
= QuerySymbolicLinkNamesFromStorage(DeviceExtension
,
1098 (SuggestedLinkName
.Buffer
) ? &SuggestedLinkName
: NULL
,
1099 UseOnlyIfThereAreNoOtherLinks
,
1105 /* If our device is a CD-ROM */
1106 if (RtlPrefixUnicodeString(&DeviceCdRom
, &TargetDeviceName
, TRUE
))
1108 LinkTarget
.Length
= 0;
1109 LinkTarget
.MaximumLength
= sizeof(LinkTargetBuffer
);
1110 LinkTarget
.Buffer
= LinkTargetBuffer
;
1112 RtlCopyMemory(CSymLinkBuffer
, Cunc
, sizeof(Cunc
));
1113 RtlInitUnicodeString(&CSymLink
, CSymLinkBuffer
);
1115 /* Start checking all letters that could have been associated */
1116 for (Letter
= L
'D'; Letter
<= L
'Z'; Letter
++)
1118 CSymLink
.Buffer
[LETTER_POSITION
] = Letter
;
1120 InitializeObjectAttributes(&ObjectAttributes
,
1122 OBJ_CASE_INSENSITIVE
,
1126 /* Try to open the associated symlink */
1127 Status
= ZwOpenSymbolicLinkObject(&LinkHandle
, SYMBOLIC_LINK_QUERY
, &ObjectAttributes
);
1128 if (!NT_SUCCESS(Status
))
1133 /* And query its target */
1134 Status
= ZwQuerySymbolicLinkObject(LinkHandle
, &LinkTarget
, NULL
);
1135 ZwClose(LinkHandle
);
1137 if (!NT_SUCCESS(Status
))
1142 IntStatus
= STATUS_UNSUCCESSFUL
;
1143 if (!RtlEqualUnicodeString(&LinkTarget
, &DeviceInformation
->DeviceName
, FALSE
))
1148 /* This link is matching our device, whereas it's not supposed to have any
1149 * symlink associated.
1154 IoDeleteSymbolicLink(&CSymLink
);
1158 /* Now, for all the symlinks, check for ours */
1159 for (i
= 0; i
< SymLinkCount
; i
++)
1161 if (IsDriveLetter(&(SymLinks
[i
])))
1163 /* If it exists, that's correct */
1164 if (SymLinks
[i
].Buffer
[LETTER_POSITION
] == Letter
)
1166 IntStatus
= STATUS_SUCCESS
;
1171 /* Useless link, delete it */
1172 if (IntStatus
== STATUS_UNSUCCESSFUL
)
1174 IoDeleteSymbolicLink(&CSymLink
);
1179 /* Suggested name is no longer required */
1180 if (SuggestedLinkName
.Buffer
)
1182 FreePool(SuggestedLinkName
.Buffer
);
1185 /* If if failed, ensure we don't take symlinks into account */
1186 if (!NT_SUCCESS(Status
))
1192 /* Now we queried them, remove the symlinks */
1193 SavedLinkInformation
= RemoveSavedLinks(DeviceExtension
, UniqueId
);
1195 IsDrvLetter
= FALSE
;
1197 IsVolumeName
= FALSE
;
1198 /* For all the symlinks */
1199 for (i
= 0; i
< SymLinkCount
; i
++)
1201 /* Check if our device is a volume */
1202 if (MOUNTMGR_IS_VOLUME_NAME(&(SymLinks
[i
])))
1204 IsVolumeName
= TRUE
;
1206 /* If it has a drive letter */
1207 else if (IsDriveLetter(&(SymLinks
[i
])))
1211 DeleteFromLocalDatabase(&(SymLinks
[i
]), UniqueId
);
1220 /* And recreate the symlink to our device */
1221 Status
= GlobalCreateSymbolicLink(&(SymLinks
[i
]), &TargetDeviceName
);
1222 if (!NT_SUCCESS(Status
))
1226 if ((SavedLinkInformation
&& !RedirectSavedLink(SavedLinkInformation
, &(SymLinks
[i
]), &TargetDeviceName
)) ||
1227 !SavedLinkInformation
)
1229 Status
= QueryDeviceInformation(&(SymLinks
[i
]), &DeviceName
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
1230 if (NT_SUCCESS(Status
))
1232 LinkError
= RtlEqualUnicodeString(&TargetDeviceName
, &DeviceName
, TRUE
);
1233 FreePool(DeviceName
.Buffer
);
1238 if (IsDriveLetter(&(SymLinks
[i
])))
1240 IsDrvLetter
= FALSE
;
1241 DeleteFromLocalDatabase(&(SymLinks
[i
]), UniqueId
);
1244 FreePool(SymLinks
[i
].Buffer
);
1250 /* Check if was offline */
1251 if (IsOffline(&(SymLinks
[i
])))
1256 /* Finally, associate this symlink with the device */
1257 SymlinkInformation
= AllocatePool(sizeof(SYMLINK_INFORMATION
));
1258 if (!SymlinkInformation
)
1260 GlobalDeleteSymbolicLink(&(SymLinks
[i
]));
1261 FreePool(SymLinks
[i
].Buffer
);
1265 SymlinkInformation
->Name
= SymLinks
[i
];
1266 SymlinkInformation
->Online
= TRUE
;
1268 InsertTailList(&(DeviceInformation
->SymbolicLinksListHead
),
1269 &(SymlinkInformation
->SymbolicLinksListEntry
));
1272 /* Now, for all the recreated symlinks, notify their recreation */
1273 for (NextEntry
= DeviceInformation
->SymbolicLinksListHead
.Flink
;
1274 NextEntry
!= &(DeviceInformation
->SymbolicLinksListHead
);
1275 NextEntry
= NextEntry
->Flink
)
1277 SymlinkInformation
= CONTAINING_RECORD(NextEntry
, SYMLINK_INFORMATION
, SymbolicLinksListEntry
);
1279 SendLinkCreated(&(SymlinkInformation
->Name
));
1282 /* If we had saved links, it's time to free them */
1283 if (SavedLinkInformation
)
1285 MountMgrFreeSavedLink(SavedLinkInformation
);
1288 /* If our device doesn't have a volume name */
1291 /* It's time to create one */
1292 Status
= CreateNewVolumeName(&VolumeName
, NULL
);
1293 if (NT_SUCCESS(Status
))
1295 /* Write it to global database */
1296 RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE
,
1301 UniqueId
->UniqueIdLength
);
1303 /* And create the symlink */
1304 GlobalCreateSymbolicLink(&VolumeName
, &TargetDeviceName
);
1306 SymlinkInformation
= AllocatePool(sizeof(SYMLINK_INFORMATION
));
1307 if (!SymlinkInformation
)
1309 FreePool(VolumeName
.Buffer
);
1311 /* Finally, associate it with the device and notify creation */
1314 SymlinkInformation
->Name
= VolumeName
;
1315 SymlinkInformation
->Online
= TRUE
;
1316 InsertTailList(&(DeviceInformation
->SymbolicLinksListHead
),
1317 &(SymlinkInformation
->SymbolicLinksListEntry
));
1319 SendLinkCreated(&VolumeName
);
1324 /* If we found a drive letter, then, ignore the suggested one */
1327 DeviceInformation
->SuggestedDriveLetter
= 0;
1329 /* Else, it's time to set up one */
1330 else if (!DeviceExtension
->NoAutoMount
&& !DeviceInformation
->Removable
&&
1331 DeviceExtension
->AutomaticDriveLetter
&& HasGptDriveLetter
&&
1332 DeviceInformation
->SuggestedDriveLetter
&&
1333 !HasNoDriveLetterEntry(UniqueId
))
1335 /* Create a new drive letter */
1336 Status
= CreateNewDriveLetterName(&DriveLetter
, &TargetDeviceName
,
1337 DeviceInformation
->SuggestedDriveLetter
,
1339 if (!NT_SUCCESS(Status
))
1341 CreateNoDriveLetterEntry(UniqueId
);
1345 /* Save it to global database */
1346 RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE
,
1351 UniqueId
->UniqueIdLength
);
1353 /* Associate it with the device and notify creation */
1354 SymlinkInformation
= AllocatePool(sizeof(SYMLINK_INFORMATION
));
1355 if (!SymlinkInformation
)
1357 FreePool(DriveLetter
.Buffer
);
1361 SymlinkInformation
->Name
= DriveLetter
;
1362 SymlinkInformation
->Online
= TRUE
;
1363 InsertTailList(&(DeviceInformation
->SymbolicLinksListHead
),
1364 &(SymlinkInformation
->SymbolicLinksListEntry
));
1366 SendLinkCreated(&DriveLetter
);
1371 /* If required, register for notifications about the device */
1374 RegisterForTargetDeviceNotification(DeviceExtension
, DeviceInformation
);
1377 /* Finally, insert the device into our devices list */
1378 InsertTailList(&(DeviceExtension
->DeviceListHead
), &(DeviceInformation
->DeviceListEntry
));
1380 /* Copy device unique ID */
1381 NewUniqueId
= AllocatePool(UniqueId
->UniqueIdLength
+ sizeof(MOUNTDEV_UNIQUE_ID
));
1384 NewUniqueId
->UniqueIdLength
= UniqueId
->UniqueIdLength
;
1385 RtlCopyMemory(NewUniqueId
->UniqueId
, UniqueId
->UniqueId
, UniqueId
->UniqueIdLength
);
1388 /* If device's offline or valid, skip its notifications */
1391 DeviceInformation
->SkipNotifications
= TRUE
;
1394 /* In case device is valid and is set to no automount,
1397 if (DeviceExtension
->NoAutoMount
|| IsDrvLetter
)
1399 IsOff
= !DeviceInformation
->SkipNotifications
;
1406 /* Finally, release the exclusive lock */
1407 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
, 1, FALSE
);
1409 /* If device is not offline, notify its arrival */
1412 SendOnlineNotification(SymbolicName
);
1415 /* If we had symlinks (from storage), free them */
1421 /* Notify about unique id change */
1424 IssueUniqueIdChangeNotify(DeviceExtension
, SymbolicName
, NewUniqueId
);
1425 FreePool(NewUniqueId
);
1428 /* If this drive was set to have a drive letter automatically
1429 * Now it's back, local databases sync will be required
1431 if (DeviceExtension
->AutomaticDriveLetter
)
1433 KeWaitForSingleObject(&(DeviceExtension
->DeviceLock
), Executive
, KernelMode
, FALSE
, NULL
);
1435 ReconcileThisDatabaseWithMaster(DeviceExtension
, DeviceInformation
);
1437 NextEntry
= DeviceExtension
->DeviceListHead
.Flink
;
1438 CurrentDevice
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
1439 while (CurrentDevice
!= DeviceInformation
)
1441 if (!CurrentDevice
->NoDatabase
)
1443 ReconcileThisDatabaseWithMaster(DeviceExtension
, CurrentDevice
);
1446 NextEntry
= NextEntry
->Flink
;
1447 CurrentDevice
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
1450 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
, 1, FALSE
);
1453 return STATUS_SUCCESS
;
1460 MountMgrMountedDeviceRemoval(IN PDEVICE_EXTENSION DeviceExtension
,
1461 IN PUNICODE_STRING DeviceName
)
1463 PLIST_ENTRY NextEntry
, DeviceEntry
;
1464 PUNIQUE_ID_REPLICATE UniqueIdReplicate
;
1465 PSYMLINK_INFORMATION SymlinkInformation
;
1466 PASSOCIATED_DEVICE_ENTRY AssociatedDevice
;
1467 PSAVED_LINK_INFORMATION SavedLinkInformation
= NULL
;
1468 PDEVICE_INFORMATION DeviceInformation
, CurrentDevice
;
1470 /* Acquire device exclusively */
1471 KeWaitForSingleObject(&(DeviceExtension
->DeviceLock
), Executive
, KernelMode
, FALSE
, NULL
);
1473 /* Look for the leaving device */
1474 for (NextEntry
= DeviceExtension
->DeviceListHead
.Flink
;
1475 NextEntry
!= &(DeviceExtension
->DeviceListHead
);
1476 NextEntry
= NextEntry
->Flink
)
1478 DeviceInformation
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
1480 if (!RtlCompareUnicodeString(&(DeviceInformation
->SymbolicName
), DeviceName
, TRUE
))
1486 /* If we found it */
1487 if (NextEntry
!= &(DeviceExtension
->DeviceListHead
))
1489 /* If it's asked to keep links, then, prepare to save them */
1490 if (DeviceInformation
->KeepLinks
)
1492 SavedLinkInformation
= AllocatePool(sizeof(SAVED_LINK_INFORMATION
));
1493 if (!SavedLinkInformation
)
1495 DeviceInformation
->KeepLinks
= FALSE
;
1499 /* If it's possible (and asked), start to save them */
1500 if (DeviceInformation
->KeepLinks
)
1502 InsertTailList(&(DeviceExtension
->SavedLinksListHead
), &(SavedLinkInformation
->SavedLinksListEntry
));
1503 InitializeListHead(&(SavedLinkInformation
->SymbolicLinksListHead
));
1504 SavedLinkInformation
->UniqueId
= DeviceInformation
->UniqueId
;
1507 /* For all the symlinks */
1508 while (!IsListEmpty(&(DeviceInformation
->SymbolicLinksListHead
)))
1510 NextEntry
= RemoveHeadList(&(DeviceInformation
->SymbolicLinksListHead
));
1511 SymlinkInformation
= CONTAINING_RECORD(NextEntry
, SYMLINK_INFORMATION
, SymbolicLinksListEntry
);
1513 /* If we have to, save the link */
1514 if (DeviceInformation
->KeepLinks
)
1516 InsertTailList(&(SavedLinkInformation
->SymbolicLinksListHead
), &(SymlinkInformation
->SymbolicLinksListEntry
));
1518 /* Otherwise, just release it */
1521 GlobalDeleteSymbolicLink(&(SymlinkInformation
->Name
));
1522 FreePool(SymlinkInformation
->Name
.Buffer
);
1523 FreePool(SymlinkInformation
);
1527 /* Free all the replicated unique IDs */
1528 while (!IsListEmpty(&(DeviceInformation
->ReplicatedUniqueIdsListHead
)))
1530 NextEntry
= RemoveHeadList(&(DeviceInformation
->ReplicatedUniqueIdsListHead
));
1531 UniqueIdReplicate
= CONTAINING_RECORD(NextEntry
, UNIQUE_ID_REPLICATE
, ReplicatedUniqueIdsListEntry
);
1534 FreePool(UniqueIdReplicate
->UniqueId
);
1535 FreePool(UniqueIdReplicate
);
1538 while (!IsListEmpty(&(DeviceInformation
->AssociatedDevicesHead
)))
1540 NextEntry
= RemoveHeadList(&(DeviceInformation
->AssociatedDevicesHead
));
1541 AssociatedDevice
= CONTAINING_RECORD(NextEntry
, ASSOCIATED_DEVICE_ENTRY
, AssociatedDevicesEntry
);
1543 DeviceInformation
->NoDatabase
= TRUE
;
1544 FreePool(AssociatedDevice
->String
.Buffer
);
1545 FreePool(AssociatedDevice
);
1548 /* Remove device from the device list */
1549 RemoveEntryList(&(DeviceInformation
->DeviceListEntry
));
1551 /* If there are still devices, check if some were associated with ours */
1552 if (!IsListEmpty(&(DeviceInformation
->DeviceListEntry
)))
1554 for (NextEntry
= DeviceExtension
->DeviceListHead
.Flink
;
1555 NextEntry
!= &(DeviceExtension
->DeviceListHead
);
1556 NextEntry
= NextEntry
->Flink
)
1558 CurrentDevice
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
1560 /* And then, remove them */
1561 DeviceEntry
= CurrentDevice
->AssociatedDevicesHead
.Flink
;
1562 while (DeviceEntry
!= &(CurrentDevice
->AssociatedDevicesHead
))
1564 AssociatedDevice
= CONTAINING_RECORD(NextEntry
, ASSOCIATED_DEVICE_ENTRY
, AssociatedDevicesEntry
);
1565 DeviceEntry
= DeviceEntry
->Flink
;
1567 if (AssociatedDevice
->DeviceInformation
!= DeviceInformation
)
1572 RemoveEntryList(&(AssociatedDevice
->AssociatedDevicesEntry
));
1573 FreePool(AssociatedDevice
->String
.Buffer
);
1574 FreePool(AssociatedDevice
);
1579 /* Finally, clean up device name, symbolic name */
1580 FreePool(DeviceInformation
->SymbolicName
.Buffer
);
1581 if (!DeviceInformation
->KeepLinks
)
1583 FreePool(DeviceInformation
->UniqueId
);
1585 FreePool(DeviceInformation
->DeviceName
.Buffer
);
1587 /* Unregister notifications */
1588 if (DeviceInformation
->TargetDeviceNotificationEntry
)
1590 IoUnregisterPlugPlayNotification(DeviceInformation
->TargetDeviceNotificationEntry
);
1594 FreePool(DeviceInformation
);
1598 /* We didn't find device, perhaps because it was offline */
1599 for (NextEntry
= DeviceExtension
->OfflineDeviceListHead
.Flink
;
1600 NextEntry
!= &(DeviceExtension
->OfflineDeviceListHead
);
1601 NextEntry
= NextEntry
->Flink
)
1603 DeviceInformation
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
1605 /* It was, remove it */
1606 if (RtlCompareUnicodeString(&(DeviceInformation
->SymbolicName
), DeviceName
, TRUE
) == 0)
1608 RemoveEntryList(&(DeviceInformation
->DeviceListEntry
));
1609 MountMgrFreeDeadDeviceInfo(DeviceInformation
);
1615 /* Releave driver */
1616 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
, 1, FALSE
);
1624 MountMgrMountedDeviceNotification(IN PVOID NotificationStructure
,
1628 PDEVICE_EXTENSION DeviceExtension
;
1629 PDEVICE_INTERFACE_CHANGE_NOTIFICATION Notification
;
1631 /* Notification for a device arrived */
1632 /* Disable hard errors */
1633 OldState
= PsGetThreadHardErrorsAreDisabled(PsGetCurrentThread());
1634 PsSetThreadHardErrorsAreDisabled(PsGetCurrentThread(), TRUE
);
1636 DeviceExtension
= Context
;
1637 Notification
= NotificationStructure
;
1639 /* Dispatch according to the event */
1640 if (IsEqualGUID(&(Notification
->Event
), &GUID_DEVICE_INTERFACE_ARRIVAL
))
1642 MountMgrMountedDeviceArrival(DeviceExtension
, Notification
->SymbolicLinkName
, FALSE
);
1644 else if (IsEqualGUID(&(Notification
->Event
), &GUID_DEVICE_INTERFACE_REMOVAL
))
1646 MountMgrMountedDeviceRemoval(DeviceExtension
, Notification
->SymbolicLinkName
);
1649 /* Reset hard errors */
1650 PsSetThreadHardErrorsAreDisabled(PsGetCurrentThread(), OldState
);
1652 return STATUS_SUCCESS
;
1660 MountMgrCreateClose(IN PDEVICE_OBJECT DeviceObject
,
1663 PIO_STACK_LOCATION Stack
;
1664 NTSTATUS Status
= STATUS_SUCCESS
;
1666 Stack
= IoGetCurrentIrpStackLocation(Irp
);
1668 /* Allow driver opening for communication
1669 * as long as it's not taken for a directory
1671 if (Stack
->MajorFunction
== IRP_MJ_CREATE
&&
1672 Stack
->Parameters
.Create
.Options
& FILE_DIRECTORY_FILE
)
1674 Status
= STATUS_NOT_A_DIRECTORY
;
1677 Irp
->IoStatus
.Status
= Status
;
1678 Irp
->IoStatus
.Information
= 0;
1679 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1688 MountMgrCancel(IN PDEVICE_OBJECT DeviceObject
,
1691 RemoveEntryList(&(Irp
->Tail
.Overlay
.ListEntry
));
1693 IoReleaseCancelSpinLock(Irp
->CancelIrql
);
1695 Irp
->IoStatus
.Information
= 0;
1696 Irp
->IoStatus
.Status
= STATUS_CANCELLED
;
1697 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1705 MountMgrCleanup(IN PDEVICE_OBJECT DeviceObject
,
1710 PLIST_ENTRY NextEntry
;
1711 PFILE_OBJECT FileObject
;
1712 PIO_STACK_LOCATION Stack
;
1713 PDEVICE_EXTENSION DeviceExtension
;
1715 DeviceExtension
= DeviceObject
->DeviceExtension
;
1716 Stack
= IoGetCurrentIrpStackLocation(Irp
);
1717 FileObject
= Stack
->FileObject
;
1719 IoAcquireCancelSpinLock(&OldIrql
);
1721 /* If IRP list if empty, it's OK */
1722 if (IsListEmpty(&(DeviceExtension
->IrpListHead
)))
1724 IoReleaseCancelSpinLock(OldIrql
);
1726 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1727 Irp
->IoStatus
.Information
= 0;
1728 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1730 return STATUS_SUCCESS
;
1733 /* Otherwise, cancel all the IRPs */
1734 NextEntry
= &(DeviceExtension
->IrpListHead
);
1737 ListIrp
= CONTAINING_RECORD(NextEntry
, IRP
, Tail
.Overlay
.ListEntry
);
1738 if (IoGetCurrentIrpStackLocation(ListIrp
)->FileObject
== FileObject
)
1740 ListIrp
->Cancel
= TRUE
;
1741 ListIrp
->CancelIrql
= OldIrql
;
1742 ListIrp
->CancelRoutine
= NULL
;
1743 MountMgrCancel(DeviceObject
, ListIrp
);
1745 IoAcquireCancelSpinLock(&OldIrql
);
1748 NextEntry
= NextEntry
->Flink
;
1750 while (NextEntry
!= &(DeviceExtension
->IrpListHead
));
1752 IoReleaseCancelSpinLock(OldIrql
);
1754 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1755 Irp
->IoStatus
.Information
= 0;
1756 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1758 return STATUS_SUCCESS
;
1766 MountMgrShutdown(IN PDEVICE_OBJECT DeviceObject
,
1769 PDEVICE_EXTENSION DeviceExtension
;
1771 DeviceExtension
= DeviceObject
->DeviceExtension
;
1773 InterlockedExchange(&Unloading
, TRUE
);
1775 KeInitializeEvent(&UnloadEvent
, NotificationEvent
, FALSE
);
1777 /* Wait for workers */
1778 if (InterlockedIncrement(&(DeviceExtension
->WorkerReferences
)))
1780 KeReleaseSemaphore(&(DeviceExtension
->WorkerSemaphore
),
1784 KeWaitForSingleObject(&UnloadEvent
, Executive
, KernelMode
, FALSE
, NULL
);
1788 InterlockedDecrement(&(DeviceExtension
->WorkerReferences
));
1791 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1792 Irp
->IoStatus
.Information
= 0;
1793 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1795 return STATUS_SUCCESS
;
1798 /* FUNCTIONS ****************************************************************/
1802 DriverEntry(IN PDRIVER_OBJECT DriverObject
,
1803 IN PUNICODE_STRING RegistryPath
)
1806 PDEVICE_OBJECT DeviceObject
;
1807 PDEVICE_EXTENSION DeviceExtension
;
1809 RtlCreateRegistryKey(RTL_REGISTRY_ABSOLUTE
, DatabasePath
);
1811 Status
= IoCreateDevice(DriverObject
,
1812 sizeof(DEVICE_EXTENSION
),
1814 FILE_DEVICE_NETWORK
,
1815 FILE_DEVICE_SECURE_OPEN
,
1818 if (!NT_SUCCESS(Status
))
1823 DriverObject
->DriverUnload
= MountMgrUnload
;
1825 DeviceExtension
= DeviceObject
->DeviceExtension
;
1826 RtlZeroMemory(DeviceExtension
, sizeof(DEVICE_EXTENSION
));
1827 DeviceExtension
->DeviceObject
= DeviceObject
;
1828 DeviceExtension
->DriverObject
= DriverObject
;
1830 InitializeListHead(&(DeviceExtension
->DeviceListHead
));
1831 InitializeListHead(&(DeviceExtension
->OfflineDeviceListHead
));
1833 KeInitializeSemaphore(&(DeviceExtension
->DeviceLock
), 1, 1);
1834 KeInitializeSemaphore(&(DeviceExtension
->RemoteDatabaseLock
), 1, 1);
1836 InitializeListHead(&(DeviceExtension
->IrpListHead
));
1837 DeviceExtension
->EpicNumber
= 1;
1839 InitializeListHead(&(DeviceExtension
->SavedLinksListHead
));
1841 InitializeListHead(&(DeviceExtension
->WorkerQueueListHead
));
1842 KeInitializeSemaphore(&(DeviceExtension
->WorkerSemaphore
), 0, MAXLONG
);
1843 DeviceExtension
->WorkerReferences
= -1;
1844 KeInitializeSpinLock(&(DeviceExtension
->WorkerLock
));
1846 InitializeListHead(&(DeviceExtension
->UniqueIdWorkerItemListHead
));
1847 InitializeListHead(&(DeviceExtension
->OnlineNotificationListHead
));
1848 DeviceExtension
->OnlineNotificationCount
= 1;
1850 DeviceExtension
->RegistryPath
.Length
= RegistryPath
->Length
;
1851 DeviceExtension
->RegistryPath
.MaximumLength
= RegistryPath
->Length
+ sizeof(WCHAR
);
1852 DeviceExtension
->RegistryPath
.Buffer
= AllocatePool(DeviceExtension
->RegistryPath
.MaximumLength
);
1853 if (!DeviceExtension
->RegistryPath
.Buffer
)
1855 IoDeleteDevice(DeviceObject
);
1856 return STATUS_INSUFFICIENT_RESOURCES
;
1859 RtlCopyUnicodeString(&(DeviceExtension
->RegistryPath
), RegistryPath
);
1861 DeviceExtension
->NoAutoMount
= MountmgrReadNoAutoMount(&(DeviceExtension
->RegistryPath
));
1863 GlobalCreateSymbolicLink(&DosDevicesMount
, &DeviceMount
);
1865 /* Register for device arrival & removal. Ask to be notified for already
1868 Status
= IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange
,
1869 PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES
,
1870 &MountedDevicesGuid
,
1872 MountMgrMountedDeviceNotification
,
1874 &(DeviceExtension
->NotificationEntry
));
1876 if (!NT_SUCCESS(Status
))
1878 IoDeleteDevice(DeviceObject
);
1882 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] =
1883 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = MountMgrCreateClose
;
1884 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = MountMgrDeviceControl
;
1885 DriverObject
->MajorFunction
[IRP_MJ_CLEANUP
] = MountMgrCleanup
;
1886 DriverObject
->MajorFunction
[IRP_MJ_SHUTDOWN
] = MountMgrShutdown
;
1888 gdeviceObject
= DeviceObject
;
1890 Status
= IoRegisterShutdownNotification(DeviceObject
);
1891 if (!NT_SUCCESS(Status
))
1893 IoDeleteDevice(DeviceObject
);