3 * Copyright (C) 2011 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
19 * COPYRIGHT: See COPYING in the top level directory
20 * PROJECT: ReactOS kernel
21 * FILE: drivers/filesystem/mountmgr/mountmgr.c
22 * PURPOSE: Mount Manager
23 * PROGRAMMER: Pierre Schweitzer (pierre.schweitzer@reactos.org)
24 * Alex Ionescu (alex.ionescu@reactos.org)
32 #if defined(ALLOC_PRAGMA)
33 #pragma alloc_text(INIT, MountmgrReadNoAutoMount)
34 #pragma alloc_text(INIT, DriverEntry)
38 GUID MountedDevicesGuid
= {0x53F5630D, 0xB6BF, 0x11D0, {0x94, 0xF2, 0x00, 0xA0, 0xC9, 0x1E, 0xFB, 0x8B}};
40 PDEVICE_OBJECT gdeviceObject
;
44 static const WCHAR Cunc
[] = L
"\\??\\C:";
50 IsOffline(PUNICODE_STRING SymbolicName
)
53 ULONG IsOffline
, Default
;
54 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
56 /* Prepare to look in the registry to see if
57 * given volume is offline
59 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
60 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
61 QueryTable
[0].Name
= SymbolicName
->Buffer
;
62 QueryTable
[0].EntryContext
= &IsOffline
;
63 QueryTable
[0].DefaultType
= REG_DWORD
;
64 QueryTable
[0].DefaultLength
= sizeof(ULONG
);
65 QueryTable
[0].DefaultData
= &Default
;
70 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
75 if (!NT_SUCCESS(Status
))
80 return (IsOffline
!= 0);
87 HasDriveLetter(IN PDEVICE_INFORMATION DeviceInformation
)
89 PLIST_ENTRY NextEntry
;
90 PSYMLINK_INFORMATION SymlinkInfo
;
92 /* To have a drive letter, a device must have symbolic links */
93 if (IsListEmpty(&(DeviceInformation
->SymbolicLinksListHead
)))
98 /* Browse all the links untill a drive letter is found */
99 NextEntry
= &(DeviceInformation
->SymbolicLinksListHead
);
102 SymlinkInfo
= CONTAINING_RECORD(NextEntry
, SYMLINK_INFORMATION
, SymbolicLinksListEntry
);
104 if (SymlinkInfo
->Online
)
106 if (IsDriveLetter(&(SymlinkInfo
->Name
)))
112 NextEntry
= NextEntry
->Flink
;
113 } while (NextEntry
!= &(DeviceInformation
->SymbolicLinksListHead
));
122 CreateNewDriveLetterName(OUT PUNICODE_STRING DriveLetter
,
123 IN PUNICODE_STRING DeviceName
,
125 IN PMOUNTDEV_UNIQUE_ID UniqueId OPTIONAL
)
127 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
129 /* Allocate a big enough buffer to contain the symbolic link */
130 DriveLetter
->MaximumLength
= DosDevices
.Length
+ 3 * sizeof(WCHAR
);
131 DriveLetter
->Buffer
= AllocatePool(DriveLetter
->MaximumLength
);
132 if (!DriveLetter
->Buffer
)
134 return STATUS_INSUFFICIENT_RESOURCES
;
138 RtlCopyUnicodeString(DriveLetter
, &DosDevices
);
140 /* Update string to reflect real contents */
141 DriveLetter
->Length
= DosDevices
.Length
+ 2 * sizeof(WCHAR
);
142 DriveLetter
->Buffer
[DosDevices
.Length
/ sizeof(WCHAR
) + 2] = UNICODE_NULL
;
143 DriveLetter
->Buffer
[DosDevices
.Length
/ sizeof(WCHAR
) + 1] = L
':';
145 /* If caller wants a no drive entry */
146 if (Letter
== (UCHAR
)-1)
148 /* Then, create a no letter entry */
149 CreateNoDriveLetterEntry(UniqueId
);
150 FreePool(DriveLetter
->Buffer
);
151 return STATUS_UNSUCCESSFUL
;
155 /* Use the letter given by the caller */
156 DriveLetter
->Buffer
[DosDevices
.Length
/ sizeof(WCHAR
)] = (WCHAR
)Letter
;
157 Status
= GlobalCreateSymbolicLink(DriveLetter
, DeviceName
);
158 if (NT_SUCCESS(Status
))
164 /* If caller didn't provide a letter, let's find one for him */
166 if (RtlPrefixUnicodeString(&DeviceFloppy
, DeviceName
, TRUE
))
168 /* If the device is a floppy, start with letter A */
171 else if (RtlPrefixUnicodeString(&DeviceCdRom
, DeviceName
, TRUE
))
173 /* If the device is a CD-ROM, start with letter D */
178 /* Finally, if it's a disk, use C */
182 /* Try to affect a letter (up to Z, ofc) until it's possible */
183 for (; Letter
<= 'Z'; Letter
++)
185 DriveLetter
->Buffer
[DosDevices
.Length
/ sizeof(WCHAR
)] = (WCHAR
)Letter
;
186 Status
= GlobalCreateSymbolicLink(DriveLetter
, DeviceName
);
187 if (NT_SUCCESS(Status
))
189 DPRINT("Assigned drive %c: to %wZ\n", Letter
, DeviceName
);
194 /* We failed to allocate a letter */
195 FreePool(DriveLetter
->Buffer
);
196 DPRINT("Failed to create a drive letter for %wZ\n", DeviceName
);
204 QueryDeviceInformation(IN PUNICODE_STRING SymbolicName
,
205 OUT PUNICODE_STRING DeviceName OPTIONAL
,
206 OUT PMOUNTDEV_UNIQUE_ID
* UniqueId OPTIONAL
,
207 OUT PBOOLEAN Removable OPTIONAL
,
208 OUT PBOOLEAN GptDriveLetter OPTIONAL
,
209 OUT PBOOLEAN HasGuid OPTIONAL
,
210 IN OUT LPGUID StableGuid OPTIONAL
,
211 OUT PBOOLEAN Valid OPTIONAL
)
218 PMOUNTDEV_UNIQUE_ID Id
;
219 PFILE_OBJECT FileObject
;
220 PIO_STACK_LOCATION Stack
;
221 NTSTATUS Status
, IntStatus
;
222 PDEVICE_OBJECT DeviceObject
;
223 IO_STATUS_BLOCK IoStatusBlock
;
224 PARTITION_INFORMATION_EX PartitionInfo
;
225 STORAGE_DEVICE_NUMBER StorageDeviceNumber
;
226 VOLUME_GET_GPT_ATTRIBUTES_INFORMATION GptAttributes
;
228 /* Get device associated with the symbolic name */
229 Status
= IoGetDeviceObjectPointer(SymbolicName
,
230 FILE_READ_ATTRIBUTES
,
233 if (!NT_SUCCESS(Status
))
238 /* The associate FO can't have a file name */
239 if (FileObject
->FileName
.Length
)
241 ObDereferenceObject(FileObject
);
242 return STATUS_OBJECT_NAME_NOT_FOUND
;
245 /* Check if it's removable & return to the user (if asked to) */
246 IsRemovable
= (FileObject
->DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
);
249 *Removable
= IsRemovable
;
252 /* Get the attached device */
253 DeviceObject
= IoGetAttachedDeviceReference(FileObject
->DeviceObject
);
255 /* If we've been asked for a GPT drive letter */
258 /* Consider it has one */
259 *GptDriveLetter
= TRUE
;
263 /* Query the GPT attributes */
264 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
265 Irp
= IoBuildDeviceIoControlRequest(IOCTL_VOLUME_GET_GPT_ATTRIBUTES
,
270 sizeof(GptAttributes
),
276 ObDereferenceObject(DeviceObject
);
277 ObDereferenceObject(FileObject
);
278 return STATUS_INSUFFICIENT_RESOURCES
;
281 Status
= IoCallDriver(DeviceObject
, Irp
);
282 if (Status
== STATUS_PENDING
)
284 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
285 Status
= IoStatusBlock
.Status
;
288 /* In case of failure, don't fail, that's no vital */
289 if (!NT_SUCCESS(Status
))
291 Status
= STATUS_SUCCESS
;
293 /* Check if it has a drive letter */
294 else if (!(GptAttributes
.GptAttributes
&
295 GPT_BASIC_DATA_ATTRIBUTE_NO_DRIVE_LETTER
))
297 *GptDriveLetter
= FALSE
;
302 /* If caller wants to know if there's valid contents */
305 /* Suppose it's not OK */
310 /* Query partitions information */
311 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
312 Irp
= IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_PARTITION_INFO_EX
,
317 sizeof(PartitionInfo
),
323 ObDereferenceObject(DeviceObject
);
324 ObDereferenceObject(FileObject
);
325 return STATUS_INSUFFICIENT_RESOURCES
;
328 Status
= IoCallDriver(DeviceObject
, Irp
);
329 if (Status
== STATUS_PENDING
)
331 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
332 Status
= IoStatusBlock
.Status
;
335 /* Once again here, failure isn't major */
336 if (!NT_SUCCESS(Status
))
338 Status
= STATUS_SUCCESS
;
340 /* Verify we know something in */
341 else if (PartitionInfo
.PartitionStyle
== PARTITION_STYLE_MBR
&&
342 IsRecognizedPartition(PartitionInfo
.Mbr
.PartitionType
))
347 /* It looks correct, ensure it is & query device number */
350 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
351 Irp
= IoBuildDeviceIoControlRequest(IOCTL_STORAGE_GET_DEVICE_NUMBER
,
355 &StorageDeviceNumber
,
356 sizeof(StorageDeviceNumber
),
362 ObDereferenceObject(DeviceObject
);
363 ObDereferenceObject(FileObject
);
364 return STATUS_INSUFFICIENT_RESOURCES
;
367 Status
= IoCallDriver(DeviceObject
, Irp
);
368 if (Status
== STATUS_PENDING
)
370 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
371 Status
= IoStatusBlock
.Status
;
374 if (!NT_SUCCESS(Status
))
376 Status
= STATUS_SUCCESS
;
386 /* If caller needs device name */
389 /* Allocate a buffer just to request length */
390 Name
= AllocatePool(sizeof(MOUNTDEV_NAME
));
393 ObDereferenceObject(DeviceObject
);
394 ObDereferenceObject(FileObject
);
395 return STATUS_INSUFFICIENT_RESOURCES
;
398 /* Query device name */
399 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
400 Irp
= IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_DEVICE_NAME
,
405 sizeof(MOUNTDEV_NAME
),
412 ObDereferenceObject(DeviceObject
);
413 ObDereferenceObject(FileObject
);
414 return STATUS_INSUFFICIENT_RESOURCES
;
417 Stack
= IoGetNextIrpStackLocation(Irp
);
418 Stack
->FileObject
= FileObject
;
420 Status
= IoCallDriver(DeviceObject
, Irp
);
421 if (Status
== STATUS_PENDING
)
423 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
424 Status
= IoStatusBlock
.Status
;
427 /* Now, we've got the correct length */
428 if (Status
== STATUS_BUFFER_OVERFLOW
)
430 Size
= Name
->NameLength
+ sizeof(MOUNTDEV_NAME
);
434 /* Allocate proper size */
435 Name
= AllocatePool(Size
);
438 ObDereferenceObject(DeviceObject
);
439 ObDereferenceObject(FileObject
);
440 return STATUS_INSUFFICIENT_RESOURCES
;
443 /* And query name (for real that time) */
444 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
445 Irp
= IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_DEVICE_NAME
,
457 ObDereferenceObject(DeviceObject
);
458 ObDereferenceObject(FileObject
);
459 return STATUS_INSUFFICIENT_RESOURCES
;
462 Stack
= IoGetNextIrpStackLocation(Irp
);
463 Stack
->FileObject
= FileObject
;
465 Status
= IoCallDriver(DeviceObject
, Irp
);
466 if (Status
== STATUS_PENDING
)
468 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
469 Status
= IoStatusBlock
.Status
;
473 if (NT_SUCCESS(Status
))
475 /* Copy back found name to the caller */
476 DeviceName
->Length
= Name
->NameLength
;
477 DeviceName
->MaximumLength
= Name
->NameLength
+ sizeof(WCHAR
);
478 DeviceName
->Buffer
= AllocatePool(DeviceName
->MaximumLength
);
479 if (!DeviceName
->Buffer
)
481 Status
= STATUS_INSUFFICIENT_RESOURCES
;
485 RtlCopyMemory(DeviceName
->Buffer
, Name
->Name
, Name
->NameLength
);
486 DeviceName
->Buffer
[Name
->NameLength
/ sizeof(WCHAR
)] = UNICODE_NULL
;
493 if (!NT_SUCCESS(Status
))
495 ObDereferenceObject(DeviceObject
);
496 ObDereferenceObject(FileObject
);
500 /* If caller wants device unique ID */
503 /* Prepare buffer to probe length */
504 Id
= AllocatePool(sizeof(MOUNTDEV_UNIQUE_ID
));
507 ObDereferenceObject(DeviceObject
);
508 ObDereferenceObject(FileObject
);
509 return STATUS_INSUFFICIENT_RESOURCES
;
512 /* Query unique ID length */
513 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
514 Irp
= IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_UNIQUE_ID
,
519 sizeof(MOUNTDEV_UNIQUE_ID
),
526 ObDereferenceObject(DeviceObject
);
527 ObDereferenceObject(FileObject
);
528 return STATUS_INSUFFICIENT_RESOURCES
;
531 Stack
= IoGetNextIrpStackLocation(Irp
);
532 Stack
->FileObject
= FileObject
;
534 Status
= IoCallDriver(DeviceObject
, Irp
);
535 if (Status
== STATUS_PENDING
)
537 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
538 Status
= IoStatusBlock
.Status
;
541 /* Retry with appropriate length */
542 if (Status
== STATUS_BUFFER_OVERFLOW
)
544 Size
= Id
->UniqueIdLength
+ sizeof(MOUNTDEV_UNIQUE_ID
);
548 /* Allocate the correct buffer */
549 Id
= AllocatePool(Size
);
552 ObDereferenceObject(DeviceObject
);
553 ObDereferenceObject(FileObject
);
554 return STATUS_INSUFFICIENT_RESOURCES
;
557 /* Query unique ID */
558 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
559 Irp
= IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_UNIQUE_ID
,
571 ObDereferenceObject(DeviceObject
);
572 ObDereferenceObject(FileObject
);
573 return STATUS_INSUFFICIENT_RESOURCES
;
576 Stack
= IoGetNextIrpStackLocation(Irp
);
577 Stack
->FileObject
= FileObject
;
579 Status
= IoCallDriver(DeviceObject
, Irp
);
580 if (Status
== STATUS_PENDING
)
582 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
583 Status
= IoStatusBlock
.Status
;
587 /* Hands back unique ID */
588 if (NT_SUCCESS(Status
))
594 /* In case of failure, also free the rest */
596 if (DeviceName
->Length
)
598 FreePool(DeviceName
->Buffer
);
601 ObDereferenceObject(DeviceObject
);
602 ObDereferenceObject(FileObject
);
608 /* If user wants to know about GUID */
611 /* Query device stable GUID */
612 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
613 Irp
= IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_STABLE_GUID
,
624 ObDereferenceObject(DeviceObject
);
625 ObDereferenceObject(FileObject
);
626 return STATUS_INSUFFICIENT_RESOURCES
;
629 Stack
= IoGetNextIrpStackLocation(Irp
);
630 Stack
->FileObject
= FileObject
;
632 IntStatus
= IoCallDriver(DeviceObject
, Irp
);
633 if (IntStatus
== STATUS_PENDING
)
635 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
636 IntStatus
= IoStatusBlock
.Status
;
639 *HasGuid
= NT_SUCCESS(IntStatus
);
642 ObDereferenceObject(DeviceObject
);
643 ObDereferenceObject(FileObject
);
651 FindDeviceInfo(IN PDEVICE_EXTENSION DeviceExtension
,
652 IN PUNICODE_STRING SymbolicName
,
653 IN BOOLEAN DeviceNameGiven
,
654 OUT PDEVICE_INFORMATION
* DeviceInformation
)
657 PLIST_ENTRY NextEntry
;
658 UNICODE_STRING DeviceName
;
659 PDEVICE_INFORMATION DeviceInfo
= NULL
;
661 /* If a device name was given, use it */
664 DeviceName
.Length
= SymbolicName
->Length
;
665 DeviceName
.Buffer
= SymbolicName
->Buffer
;
669 /* Otherwise, query it */
670 Status
= QueryDeviceInformation(SymbolicName
,
675 if (!NT_SUCCESS(Status
))
681 /* Look for device information matching devive */
682 for (NextEntry
= DeviceExtension
->DeviceListHead
.Flink
;
683 NextEntry
!= &(DeviceExtension
->DeviceListHead
);
684 NextEntry
= NextEntry
->Flink
)
686 DeviceInfo
= CONTAINING_RECORD(NextEntry
,
690 if (RtlEqualUnicodeString(&DeviceName
, &(DeviceInfo
->DeviceName
), TRUE
))
696 /* Release our buffer if required */
697 if (!DeviceNameGiven
)
699 FreePool(DeviceName
.Buffer
);
702 /* Return found information */
703 if (NextEntry
== &(DeviceExtension
->DeviceListHead
))
705 return STATUS_OBJECT_NAME_NOT_FOUND
;
708 *DeviceInformation
= DeviceInfo
;
709 return STATUS_SUCCESS
;
716 MountMgrFreeDeadDeviceInfo(IN PDEVICE_INFORMATION DeviceInformation
)
718 FreePool(DeviceInformation
->SymbolicName
.Buffer
);
719 FreePool(DeviceInformation
);
726 MountMgrFreeMountedDeviceInfo(IN PDEVICE_INFORMATION DeviceInformation
)
728 PLIST_ENTRY NextEntry
;
729 PSYMLINK_INFORMATION SymLink
;
730 PUNIQUE_ID_REPLICATE UniqueId
;
731 PASSOCIATED_DEVICE_ENTRY AssociatedDevice
;
733 /* Purge symbolic links list */
734 while (!IsListEmpty(&(DeviceInformation
->SymbolicLinksListHead
)))
736 NextEntry
= RemoveHeadList(&(DeviceInformation
->SymbolicLinksListHead
));
737 SymLink
= CONTAINING_RECORD(NextEntry
, SYMLINK_INFORMATION
, SymbolicLinksListEntry
);
739 GlobalDeleteSymbolicLink(&(SymLink
->Name
));
740 FreePool(SymLink
->Name
.Buffer
);
743 /* Purge replicated unique IDs list */
744 while (!IsListEmpty(&(DeviceInformation
->ReplicatedUniqueIdsListHead
)))
746 NextEntry
= RemoveHeadList(&(DeviceInformation
->ReplicatedUniqueIdsListHead
));
747 UniqueId
= CONTAINING_RECORD(NextEntry
, UNIQUE_ID_REPLICATE
, ReplicatedUniqueIdsListEntry
);
749 FreePool(UniqueId
->UniqueId
);
753 while (!IsListEmpty(&(DeviceInformation
->AssociatedDevicesHead
)))
755 NextEntry
= RemoveHeadList(&(DeviceInformation
->AssociatedDevicesHead
));
756 AssociatedDevice
= CONTAINING_RECORD(NextEntry
, ASSOCIATED_DEVICE_ENTRY
, AssociatedDevicesEntry
);
758 FreePool(AssociatedDevice
->String
.Buffer
);
759 FreePool(AssociatedDevice
);
762 /* Free the rest of the buffers */
763 FreePool(DeviceInformation
->SymbolicName
.Buffer
);
764 if (DeviceInformation
->KeepLinks
)
766 FreePool(DeviceInformation
->UniqueId
);
768 FreePool(DeviceInformation
->DeviceName
.Buffer
);
770 /* Finally, stop waiting for notifications for this device */
771 if (DeviceInformation
->TargetDeviceNotificationEntry
)
773 IoUnregisterPlugPlayNotification(DeviceInformation
->TargetDeviceNotificationEntry
);
781 MountMgrFreeSavedLink(IN PSAVED_LINK_INFORMATION SavedLinkInformation
)
783 PLIST_ENTRY NextEntry
;
784 PSYMLINK_INFORMATION SymlinkInformation
;
786 /* For all the saved links */
787 while (!IsListEmpty(&(SavedLinkInformation
->SymbolicLinksListHead
)))
789 NextEntry
= RemoveHeadList(&(SavedLinkInformation
->SymbolicLinksListHead
));
790 SymlinkInformation
= CONTAINING_RECORD(NextEntry
, SYMLINK_INFORMATION
, SymbolicLinksListEntry
);
792 /* Remove from system & free */
793 GlobalDeleteSymbolicLink(&(SymlinkInformation
->Name
));
794 FreePool(SymlinkInformation
->Name
.Buffer
);
795 FreePool(SymlinkInformation
);
798 /* And free unique ID & entry */
799 FreePool(SavedLinkInformation
->UniqueId
);
800 FreePool(SavedLinkInformation
);
809 MountMgrUnload(IN
struct _DRIVER_OBJECT
*DriverObject
)
811 PLIST_ENTRY NextEntry
;
812 PUNIQUE_ID_WORK_ITEM WorkItem
;
813 PDEVICE_EXTENSION DeviceExtension
;
814 PDEVICE_INFORMATION DeviceInformation
;
815 PSAVED_LINK_INFORMATION SavedLinkInformation
;
817 UNREFERENCED_PARAMETER(DriverObject
);
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 KeClearEvent(&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
);
913 MountmgrReadNoAutoMount(IN PUNICODE_STRING RegistryPath
)
916 ULONG Result
, Default
= 0;
917 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
919 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
921 /* Simply read data from register */
922 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
923 QueryTable
[0].Name
= L
"NoAutoMount";
924 QueryTable
[0].EntryContext
= &Result
;
925 QueryTable
[0].DefaultType
= REG_NONE
;
926 QueryTable
[0].DefaultData
= &Default
;
927 QueryTable
[0].DefaultLength
= sizeof(ULONG
);
929 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
930 RegistryPath
->Buffer
,
934 if (!NT_SUCCESS(Status
))
936 return (Default
!= 0);
939 return (Result
!= 0);
946 MountMgrMountedDeviceArrival(IN PDEVICE_EXTENSION DeviceExtension
,
947 IN PUNICODE_STRING SymbolicName
,
948 IN BOOLEAN ManuallyRegistered
)
953 ULONG SymLinkCount
, i
;
954 PLIST_ENTRY NextEntry
;
955 PUNICODE_STRING SymLinks
;
956 NTSTATUS Status
, IntStatus
;
957 OBJECT_ATTRIBUTES ObjectAttributes
;
958 PSYMLINK_INFORMATION SymlinkInformation
;
959 PMOUNTDEV_UNIQUE_ID UniqueId
, NewUniqueId
;
960 PSAVED_LINK_INFORMATION SavedLinkInformation
;
961 PDEVICE_INFORMATION DeviceInformation
, CurrentDevice
;
962 WCHAR CSymLinkBuffer
[RTL_NUMBER_OF(Cunc
)], LinkTargetBuffer
[MAX_PATH
];
963 UNICODE_STRING TargetDeviceName
, SuggestedLinkName
, DeviceName
, VolumeName
, DriveLetter
, LinkTarget
, CSymLink
;
964 BOOLEAN HasGuid
, HasGptDriveLetter
, Valid
, UseOnlyIfThereAreNoOtherLinks
, IsDrvLetter
, IsOff
, IsVolumeName
, LinkError
;
966 /* New device = new structure to represent it */
967 DeviceInformation
= AllocatePool(sizeof(DEVICE_INFORMATION
));
968 if (!DeviceInformation
)
970 return STATUS_INSUFFICIENT_RESOURCES
;
973 /* Initialise device structure */
974 RtlZeroMemory(DeviceInformation
, sizeof(DEVICE_INFORMATION
));
975 InitializeListHead(&(DeviceInformation
->SymbolicLinksListHead
));
976 InitializeListHead(&(DeviceInformation
->ReplicatedUniqueIdsListHead
));
977 InitializeListHead(&(DeviceInformation
->AssociatedDevicesHead
));
978 DeviceInformation
->SymbolicName
.Length
= SymbolicName
->Length
;
979 DeviceInformation
->SymbolicName
.MaximumLength
= SymbolicName
->Length
+ sizeof(UNICODE_NULL
);
980 DeviceInformation
->SymbolicName
.Buffer
= AllocatePool(DeviceInformation
->SymbolicName
.MaximumLength
);
981 if (!DeviceInformation
->SymbolicName
.Buffer
)
983 FreePool(DeviceInformation
);
984 return STATUS_INSUFFICIENT_RESOURCES
;
987 /* Copy symbolic name */
988 RtlCopyMemory(DeviceInformation
->SymbolicName
.Buffer
, SymbolicName
->Buffer
, SymbolicName
->Length
);
989 DeviceInformation
->SymbolicName
.Buffer
[DeviceInformation
->SymbolicName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
990 DeviceInformation
->ManuallyRegistered
= ManuallyRegistered
;
991 DeviceInformation
->DeviceExtension
= DeviceExtension
;
993 /* Query as much data as possible about device */
994 Status
= QueryDeviceInformation(SymbolicName
,
997 &(DeviceInformation
->Removable
),
1002 if (!NT_SUCCESS(Status
))
1004 KeWaitForSingleObject(&(DeviceExtension
->DeviceLock
), Executive
, KernelMode
, FALSE
, NULL
);
1006 for (NextEntry
= DeviceExtension
->OfflineDeviceListHead
.Flink
;
1007 NextEntry
!= &(DeviceExtension
->OfflineDeviceListHead
);
1008 NextEntry
= NextEntry
->Flink
)
1010 CurrentDevice
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
1012 if (RtlEqualUnicodeString(&(DeviceInformation
->SymbolicName
), &(CurrentDevice
->SymbolicName
), TRUE
))
1018 if (NextEntry
!= &(DeviceExtension
->OfflineDeviceListHead
))
1020 MountMgrFreeDeadDeviceInfo(DeviceInformation
);
1024 InsertTailList(&(DeviceExtension
->OfflineDeviceListHead
), &(DeviceInformation
->DeviceListEntry
));
1027 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
, 1, FALSE
);
1032 /* Save gathered data */
1033 DeviceInformation
->UniqueId
= UniqueId
;
1034 DeviceInformation
->DeviceName
= TargetDeviceName
;
1035 DeviceInformation
->KeepLinks
= FALSE
;
1037 /* If we found system partition, mark it */
1038 if (DeviceExtension
->DriveLetterData
&& UniqueId
->UniqueIdLength
== DeviceExtension
->DriveLetterData
->UniqueIdLength
)
1040 if (RtlCompareMemory(UniqueId
->UniqueId
, DeviceExtension
->DriveLetterData
->UniqueId
, UniqueId
->UniqueIdLength
)
1041 == UniqueId
->UniqueIdLength
)
1043 IoSetSystemPartition(&TargetDeviceName
);
1047 /* Check suggested link name */
1048 Status
= QuerySuggestedLinkName(&(DeviceInformation
->SymbolicName
),
1050 &UseOnlyIfThereAreNoOtherLinks
);
1051 if (!NT_SUCCESS(Status
))
1053 SuggestedLinkName
.Buffer
= NULL
;
1056 /* If it's OK, set it and save its letter (if any) */
1057 if (SuggestedLinkName
.Buffer
&& IsDriveLetter(&SuggestedLinkName
))
1059 DeviceInformation
->SuggestedDriveLetter
= (UCHAR
)SuggestedLinkName
.Buffer
[LETTER_POSITION
];
1062 /* Acquire driver exclusively */
1063 KeWaitForSingleObject(&(DeviceExtension
->DeviceLock
), Executive
, KernelMode
, FALSE
, NULL
);
1065 /* Check if we already have device in to prevent double registration */
1066 for (NextEntry
= DeviceExtension
->DeviceListHead
.Flink
;
1067 NextEntry
!= &(DeviceExtension
->DeviceListHead
);
1068 NextEntry
= NextEntry
->Flink
)
1070 CurrentDevice
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
1072 if (RtlEqualUnicodeString(&(CurrentDevice
->DeviceName
), &TargetDeviceName
, TRUE
))
1078 /* If we found it, clear ours, and return success, all correct */
1079 if (NextEntry
!= &(DeviceExtension
->DeviceListHead
))
1081 if (SuggestedLinkName
.Buffer
)
1083 FreePool(SuggestedLinkName
.Buffer
);
1087 FreePool(TargetDeviceName
.Buffer
);
1088 FreePool(DeviceInformation
->DeviceName
.Buffer
);
1089 FreePool(DeviceInformation
);
1091 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
, 1, FALSE
);
1093 return STATUS_SUCCESS
;
1096 /* Check if there are symlinks associated with our device in registry */
1097 Status
= QuerySymbolicLinkNamesFromStorage(DeviceExtension
,
1099 (SuggestedLinkName
.Buffer
) ? &SuggestedLinkName
: NULL
,
1100 UseOnlyIfThereAreNoOtherLinks
,
1106 /* If our device is a CD-ROM */
1107 if (RtlPrefixUnicodeString(&DeviceCdRom
, &TargetDeviceName
, TRUE
))
1109 LinkTarget
.Length
= 0;
1110 LinkTarget
.MaximumLength
= sizeof(LinkTargetBuffer
);
1111 LinkTarget
.Buffer
= LinkTargetBuffer
;
1113 RtlCopyMemory(CSymLinkBuffer
, Cunc
, sizeof(Cunc
));
1114 RtlInitUnicodeString(&CSymLink
, CSymLinkBuffer
);
1116 /* Start checking all letters that could have been associated */
1117 for (Letter
= L
'D'; Letter
<= L
'Z'; Letter
++)
1119 CSymLink
.Buffer
[LETTER_POSITION
] = Letter
;
1121 InitializeObjectAttributes(&ObjectAttributes
,
1123 OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
,
1127 /* Try to open the associated symlink */
1128 Status
= ZwOpenSymbolicLinkObject(&LinkHandle
, SYMBOLIC_LINK_QUERY
, &ObjectAttributes
);
1129 if (!NT_SUCCESS(Status
))
1134 /* And query its target */
1135 Status
= ZwQuerySymbolicLinkObject(LinkHandle
, &LinkTarget
, NULL
);
1136 ZwClose(LinkHandle
);
1138 if (!NT_SUCCESS(Status
))
1143 IntStatus
= STATUS_UNSUCCESSFUL
;
1144 if (!RtlEqualUnicodeString(&LinkTarget
, &DeviceInformation
->DeviceName
, FALSE
))
1149 /* This link is matching our device, whereas it's not supposed to have any
1150 * symlink associated.
1155 IoDeleteSymbolicLink(&CSymLink
);
1159 /* Now, for all the symlinks, check for ours */
1160 for (i
= 0; i
< SymLinkCount
; i
++)
1162 if (IsDriveLetter(&(SymLinks
[i
])))
1164 /* If it exists, that's correct */
1165 if (SymLinks
[i
].Buffer
[LETTER_POSITION
] == Letter
)
1167 IntStatus
= STATUS_SUCCESS
;
1172 /* Useless link, delete it */
1173 if (IntStatus
== STATUS_UNSUCCESSFUL
)
1175 IoDeleteSymbolicLink(&CSymLink
);
1180 /* Suggested name is no longer required */
1181 if (SuggestedLinkName
.Buffer
)
1183 FreePool(SuggestedLinkName
.Buffer
);
1186 /* If if failed, ensure we don't take symlinks into account */
1187 if (!NT_SUCCESS(Status
))
1193 /* Now we queried them, remove the symlinks */
1194 SavedLinkInformation
= RemoveSavedLinks(DeviceExtension
, UniqueId
);
1196 IsDrvLetter
= FALSE
;
1198 IsVolumeName
= FALSE
;
1199 /* For all the symlinks */
1200 for (i
= 0; i
< SymLinkCount
; i
++)
1202 /* Check if our device is a volume */
1203 if (MOUNTMGR_IS_VOLUME_NAME(&(SymLinks
[i
])))
1205 IsVolumeName
= TRUE
;
1207 /* If it has a drive letter */
1208 else if (IsDriveLetter(&(SymLinks
[i
])))
1212 DeleteFromLocalDatabase(&(SymLinks
[i
]), UniqueId
);
1221 /* And recreate the symlink to our device */
1222 Status
= GlobalCreateSymbolicLink(&(SymLinks
[i
]), &TargetDeviceName
);
1223 if (!NT_SUCCESS(Status
))
1227 if ((SavedLinkInformation
&& !RedirectSavedLink(SavedLinkInformation
, &(SymLinks
[i
]), &TargetDeviceName
)) ||
1228 !SavedLinkInformation
)
1230 Status
= QueryDeviceInformation(&(SymLinks
[i
]), &DeviceName
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
1231 if (NT_SUCCESS(Status
))
1233 LinkError
= RtlEqualUnicodeString(&TargetDeviceName
, &DeviceName
, TRUE
);
1234 FreePool(DeviceName
.Buffer
);
1239 if (IsDriveLetter(&(SymLinks
[i
])))
1241 IsDrvLetter
= FALSE
;
1242 DeleteFromLocalDatabase(&(SymLinks
[i
]), UniqueId
);
1245 FreePool(SymLinks
[i
].Buffer
);
1251 /* Check if was offline */
1252 if (IsOffline(&(SymLinks
[i
])))
1257 /* Finally, associate this symlink with the device */
1258 SymlinkInformation
= AllocatePool(sizeof(SYMLINK_INFORMATION
));
1259 if (!SymlinkInformation
)
1261 GlobalDeleteSymbolicLink(&(SymLinks
[i
]));
1262 FreePool(SymLinks
[i
].Buffer
);
1266 SymlinkInformation
->Name
= SymLinks
[i
];
1267 SymlinkInformation
->Online
= TRUE
;
1269 InsertTailList(&(DeviceInformation
->SymbolicLinksListHead
),
1270 &(SymlinkInformation
->SymbolicLinksListEntry
));
1273 /* Now, for all the recreated symlinks, notify their recreation */
1274 for (NextEntry
= DeviceInformation
->SymbolicLinksListHead
.Flink
;
1275 NextEntry
!= &(DeviceInformation
->SymbolicLinksListHead
);
1276 NextEntry
= NextEntry
->Flink
)
1278 SymlinkInformation
= CONTAINING_RECORD(NextEntry
, SYMLINK_INFORMATION
, SymbolicLinksListEntry
);
1280 SendLinkCreated(&(SymlinkInformation
->Name
));
1283 /* If we had saved links, it's time to free them */
1284 if (SavedLinkInformation
)
1286 MountMgrFreeSavedLink(SavedLinkInformation
);
1289 /* If our device doesn't have a volume name */
1292 /* It's time to create one */
1293 Status
= CreateNewVolumeName(&VolumeName
, NULL
);
1294 if (NT_SUCCESS(Status
))
1296 /* Write it to global database */
1297 RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE
,
1302 UniqueId
->UniqueIdLength
);
1304 /* And create the symlink */
1305 GlobalCreateSymbolicLink(&VolumeName
, &TargetDeviceName
);
1307 SymlinkInformation
= AllocatePool(sizeof(SYMLINK_INFORMATION
));
1308 if (!SymlinkInformation
)
1310 FreePool(VolumeName
.Buffer
);
1312 /* Finally, associate it with the device and notify creation */
1315 SymlinkInformation
->Name
= VolumeName
;
1316 SymlinkInformation
->Online
= TRUE
;
1317 InsertTailList(&(DeviceInformation
->SymbolicLinksListHead
),
1318 &(SymlinkInformation
->SymbolicLinksListEntry
));
1320 SendLinkCreated(&VolumeName
);
1325 /* If we found a drive letter, then, ignore the suggested one */
1328 DeviceInformation
->SuggestedDriveLetter
= 0;
1330 /* Else, it's time to set up one */
1331 else if ((DeviceExtension
->NoAutoMount
|| DeviceInformation
->Removable
) &&
1332 DeviceExtension
->AutomaticDriveLetter
&&
1333 (HasGptDriveLetter
|| DeviceInformation
->SuggestedDriveLetter
) &&
1334 !HasNoDriveLetterEntry(UniqueId
))
1336 /* Create a new drive letter */
1337 Status
= CreateNewDriveLetterName(&DriveLetter
, &TargetDeviceName
,
1338 DeviceInformation
->SuggestedDriveLetter
,
1340 if (!NT_SUCCESS(Status
))
1342 CreateNoDriveLetterEntry(UniqueId
);
1346 /* Save it to global database */
1347 RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE
,
1352 UniqueId
->UniqueIdLength
);
1354 /* Associate it with the device and notify creation */
1355 SymlinkInformation
= AllocatePool(sizeof(SYMLINK_INFORMATION
));
1356 if (!SymlinkInformation
)
1358 FreePool(DriveLetter
.Buffer
);
1362 SymlinkInformation
->Name
= DriveLetter
;
1363 SymlinkInformation
->Online
= TRUE
;
1364 InsertTailList(&(DeviceInformation
->SymbolicLinksListHead
),
1365 &(SymlinkInformation
->SymbolicLinksListEntry
));
1367 SendLinkCreated(&DriveLetter
);
1372 /* If that's a PnP device, register for notifications */
1373 if (!ManuallyRegistered
)
1375 RegisterForTargetDeviceNotification(DeviceExtension
, DeviceInformation
);
1378 /* Finally, insert the device into our devices list */
1379 InsertTailList(&(DeviceExtension
->DeviceListHead
), &(DeviceInformation
->DeviceListEntry
));
1381 /* Copy device unique ID */
1382 NewUniqueId
= AllocatePool(UniqueId
->UniqueIdLength
+ sizeof(MOUNTDEV_UNIQUE_ID
));
1385 NewUniqueId
->UniqueIdLength
= UniqueId
->UniqueIdLength
;
1386 RtlCopyMemory(NewUniqueId
->UniqueId
, UniqueId
->UniqueId
, UniqueId
->UniqueIdLength
);
1389 /* If device's offline or valid, skip its notifications */
1392 DeviceInformation
->SkipNotifications
= TRUE
;
1395 /* In case device is valid and is set to no automount,
1398 if (DeviceExtension
->NoAutoMount
|| IsDrvLetter
)
1400 IsOff
= !DeviceInformation
->SkipNotifications
;
1407 /* Finally, release the exclusive lock */
1408 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
, 1, FALSE
);
1410 /* If device is not offline, notify its arrival */
1413 SendOnlineNotification(SymbolicName
);
1416 /* If we had symlinks (from storage), free them */
1422 /* Notify about unique id change */
1425 IssueUniqueIdChangeNotify(DeviceExtension
, SymbolicName
, NewUniqueId
);
1426 FreePool(NewUniqueId
);
1429 /* If this drive was set to have a drive letter automatically
1430 * Now it's back, local databases sync will be required
1432 if (DeviceExtension
->AutomaticDriveLetter
)
1434 KeWaitForSingleObject(&(DeviceExtension
->DeviceLock
), Executive
, KernelMode
, FALSE
, NULL
);
1436 ReconcileThisDatabaseWithMaster(DeviceExtension
, DeviceInformation
);
1438 NextEntry
= DeviceExtension
->DeviceListHead
.Flink
;
1439 CurrentDevice
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
1440 while (CurrentDevice
!= DeviceInformation
)
1442 if (!CurrentDevice
->NoDatabase
)
1444 ReconcileThisDatabaseWithMaster(DeviceExtension
, CurrentDevice
);
1447 NextEntry
= NextEntry
->Flink
;
1448 CurrentDevice
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
1451 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
, 1, FALSE
);
1454 return STATUS_SUCCESS
;
1461 MountMgrMountedDeviceRemoval(IN PDEVICE_EXTENSION DeviceExtension
,
1462 IN PUNICODE_STRING DeviceName
)
1464 PLIST_ENTRY NextEntry
, DeviceEntry
;
1465 PUNIQUE_ID_REPLICATE UniqueIdReplicate
;
1466 PSYMLINK_INFORMATION SymlinkInformation
;
1467 PASSOCIATED_DEVICE_ENTRY AssociatedDevice
;
1468 PSAVED_LINK_INFORMATION SavedLinkInformation
= NULL
;
1469 PDEVICE_INFORMATION DeviceInformation
, CurrentDevice
;
1471 /* Acquire device exclusively */
1472 KeWaitForSingleObject(&(DeviceExtension
->DeviceLock
), Executive
, KernelMode
, FALSE
, NULL
);
1474 /* Look for the leaving device */
1475 for (NextEntry
= DeviceExtension
->DeviceListHead
.Flink
;
1476 NextEntry
!= &(DeviceExtension
->DeviceListHead
);
1477 NextEntry
= NextEntry
->Flink
)
1479 DeviceInformation
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
1481 if (!RtlCompareUnicodeString(&(DeviceInformation
->SymbolicName
), DeviceName
, TRUE
))
1487 /* If we found it */
1488 if (NextEntry
!= &(DeviceExtension
->DeviceListHead
))
1490 /* If it's asked to keep links, then, prepare to save them */
1491 if (DeviceInformation
->KeepLinks
)
1493 SavedLinkInformation
= AllocatePool(sizeof(SAVED_LINK_INFORMATION
));
1494 if (!SavedLinkInformation
)
1496 DeviceInformation
->KeepLinks
= FALSE
;
1500 /* If it's possible (and asked), start to save them */
1501 if (DeviceInformation
->KeepLinks
)
1503 InsertTailList(&(DeviceExtension
->SavedLinksListHead
), &(SavedLinkInformation
->SavedLinksListEntry
));
1504 InitializeListHead(&(SavedLinkInformation
->SymbolicLinksListHead
));
1505 SavedLinkInformation
->UniqueId
= DeviceInformation
->UniqueId
;
1508 /* For all the symlinks */
1509 while (!IsListEmpty(&(DeviceInformation
->SymbolicLinksListHead
)))
1511 NextEntry
= RemoveHeadList(&(DeviceInformation
->SymbolicLinksListHead
));
1512 SymlinkInformation
= CONTAINING_RECORD(NextEntry
, SYMLINK_INFORMATION
, SymbolicLinksListEntry
);
1514 /* If we have to, save the link */
1515 if (DeviceInformation
->KeepLinks
)
1517 InsertTailList(&(SavedLinkInformation
->SymbolicLinksListHead
), &(SymlinkInformation
->SymbolicLinksListEntry
));
1519 /* Otherwise, just release it */
1522 GlobalDeleteSymbolicLink(&(SymlinkInformation
->Name
));
1523 FreePool(SymlinkInformation
->Name
.Buffer
);
1524 FreePool(SymlinkInformation
);
1528 /* Free all the replicated unique IDs */
1529 while (!IsListEmpty(&(DeviceInformation
->ReplicatedUniqueIdsListHead
)))
1531 NextEntry
= RemoveHeadList(&(DeviceInformation
->ReplicatedUniqueIdsListHead
));
1532 UniqueIdReplicate
= CONTAINING_RECORD(NextEntry
, UNIQUE_ID_REPLICATE
, ReplicatedUniqueIdsListEntry
);
1535 FreePool(UniqueIdReplicate
->UniqueId
);
1536 FreePool(UniqueIdReplicate
);
1539 while (!IsListEmpty(&(DeviceInformation
->AssociatedDevicesHead
)))
1541 NextEntry
= RemoveHeadList(&(DeviceInformation
->AssociatedDevicesHead
));
1542 AssociatedDevice
= CONTAINING_RECORD(NextEntry
, ASSOCIATED_DEVICE_ENTRY
, AssociatedDevicesEntry
);
1544 DeviceInformation
->NoDatabase
= TRUE
;
1545 FreePool(AssociatedDevice
->String
.Buffer
);
1546 FreePool(AssociatedDevice
);
1549 /* Remove device from the device list */
1550 RemoveEntryList(&(DeviceInformation
->DeviceListEntry
));
1552 /* If there are still devices, check if some were associated with ours */
1553 if (!IsListEmpty(&(DeviceInformation
->DeviceListEntry
)))
1555 for (NextEntry
= DeviceExtension
->DeviceListHead
.Flink
;
1556 NextEntry
!= &(DeviceExtension
->DeviceListHead
);
1557 NextEntry
= NextEntry
->Flink
)
1559 CurrentDevice
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
1561 /* And then, remove them */
1562 DeviceEntry
= CurrentDevice
->AssociatedDevicesHead
.Flink
;
1563 while (DeviceEntry
!= &(CurrentDevice
->AssociatedDevicesHead
))
1565 AssociatedDevice
= CONTAINING_RECORD(NextEntry
, ASSOCIATED_DEVICE_ENTRY
, AssociatedDevicesEntry
);
1566 DeviceEntry
= DeviceEntry
->Flink
;
1568 if (AssociatedDevice
->DeviceInformation
!= DeviceInformation
)
1573 RemoveEntryList(&(AssociatedDevice
->AssociatedDevicesEntry
));
1574 FreePool(AssociatedDevice
->String
.Buffer
);
1575 FreePool(AssociatedDevice
);
1580 /* Finally, clean up device name, symbolic name */
1581 FreePool(DeviceInformation
->SymbolicName
.Buffer
);
1582 if (!DeviceInformation
->KeepLinks
)
1584 FreePool(DeviceInformation
->UniqueId
);
1586 FreePool(DeviceInformation
->DeviceName
.Buffer
);
1588 /* Unregister notifications */
1589 if (DeviceInformation
->TargetDeviceNotificationEntry
)
1591 IoUnregisterPlugPlayNotification(DeviceInformation
->TargetDeviceNotificationEntry
);
1595 FreePool(DeviceInformation
);
1599 /* We didn't find device, perhaps because it was offline */
1600 for (NextEntry
= DeviceExtension
->OfflineDeviceListHead
.Flink
;
1601 NextEntry
!= &(DeviceExtension
->OfflineDeviceListHead
);
1602 NextEntry
= NextEntry
->Flink
)
1604 DeviceInformation
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
1606 /* It was, remove it */
1607 if (RtlCompareUnicodeString(&(DeviceInformation
->SymbolicName
), DeviceName
, TRUE
) == 0)
1609 RemoveEntryList(&(DeviceInformation
->DeviceListEntry
));
1610 MountMgrFreeDeadDeviceInfo(DeviceInformation
);
1616 /* Release driver */
1617 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
, 1, FALSE
);
1625 MountMgrMountedDeviceNotification(IN PVOID NotificationStructure
,
1629 PDEVICE_EXTENSION DeviceExtension
;
1630 PDEVICE_INTERFACE_CHANGE_NOTIFICATION Notification
;
1632 /* Notification for a device arrived */
1633 /* Disable hard errors */
1634 OldState
= PsGetThreadHardErrorsAreDisabled(PsGetCurrentThread());
1635 PsSetThreadHardErrorsAreDisabled(PsGetCurrentThread(), TRUE
);
1637 DeviceExtension
= Context
;
1638 Notification
= NotificationStructure
;
1640 /* Dispatch according to the event */
1641 if (IsEqualGUID(&(Notification
->Event
), &GUID_DEVICE_INTERFACE_ARRIVAL
))
1643 MountMgrMountedDeviceArrival(DeviceExtension
, Notification
->SymbolicLinkName
, FALSE
);
1645 else if (IsEqualGUID(&(Notification
->Event
), &GUID_DEVICE_INTERFACE_REMOVAL
))
1647 MountMgrMountedDeviceRemoval(DeviceExtension
, Notification
->SymbolicLinkName
);
1650 /* Reset hard errors */
1651 PsSetThreadHardErrorsAreDisabled(PsGetCurrentThread(), OldState
);
1653 return STATUS_SUCCESS
;
1661 MountMgrCreateClose(IN PDEVICE_OBJECT DeviceObject
,
1664 PIO_STACK_LOCATION Stack
;
1665 NTSTATUS Status
= STATUS_SUCCESS
;
1667 UNREFERENCED_PARAMETER(DeviceObject
);
1669 Stack
= IoGetCurrentIrpStackLocation(Irp
);
1671 /* Allow driver opening for communication
1672 * as long as it's not taken for a directory
1674 if (Stack
->MajorFunction
== IRP_MJ_CREATE
&&
1675 Stack
->Parameters
.Create
.Options
& FILE_DIRECTORY_FILE
)
1677 Status
= STATUS_NOT_A_DIRECTORY
;
1680 Irp
->IoStatus
.Status
= Status
;
1681 Irp
->IoStatus
.Information
= 0;
1682 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1691 MountMgrCancel(IN PDEVICE_OBJECT DeviceObject
,
1694 UNREFERENCED_PARAMETER(DeviceObject
);
1696 RemoveEntryList(&(Irp
->Tail
.Overlay
.ListEntry
));
1698 IoReleaseCancelSpinLock(Irp
->CancelIrql
);
1700 Irp
->IoStatus
.Information
= 0;
1701 Irp
->IoStatus
.Status
= STATUS_CANCELLED
;
1702 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1710 MountMgrCleanup(IN PDEVICE_OBJECT DeviceObject
,
1715 PLIST_ENTRY NextEntry
;
1716 PFILE_OBJECT FileObject
;
1717 PIO_STACK_LOCATION Stack
;
1718 PDEVICE_EXTENSION DeviceExtension
;
1720 DeviceExtension
= DeviceObject
->DeviceExtension
;
1721 Stack
= IoGetCurrentIrpStackLocation(Irp
);
1722 FileObject
= Stack
->FileObject
;
1724 IoAcquireCancelSpinLock(&OldIrql
);
1726 /* If IRP list if empty, it's OK */
1727 if (IsListEmpty(&(DeviceExtension
->IrpListHead
)))
1729 IoReleaseCancelSpinLock(OldIrql
);
1731 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1732 Irp
->IoStatus
.Information
= 0;
1733 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1735 return STATUS_SUCCESS
;
1738 /* Otherwise, cancel all the IRPs */
1739 NextEntry
= DeviceExtension
->IrpListHead
.Flink
;
1742 ListIrp
= CONTAINING_RECORD(NextEntry
, IRP
, Tail
.Overlay
.ListEntry
);
1743 if (IoGetCurrentIrpStackLocation(ListIrp
)->FileObject
== FileObject
)
1745 ListIrp
->Cancel
= TRUE
;
1746 ListIrp
->CancelIrql
= OldIrql
;
1747 ListIrp
->CancelRoutine
= NULL
;
1748 MountMgrCancel(DeviceObject
, ListIrp
);
1750 IoAcquireCancelSpinLock(&OldIrql
);
1753 NextEntry
= NextEntry
->Flink
;
1755 while (NextEntry
!= &(DeviceExtension
->IrpListHead
));
1757 IoReleaseCancelSpinLock(OldIrql
);
1759 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1760 Irp
->IoStatus
.Information
= 0;
1761 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1763 return STATUS_SUCCESS
;
1771 MountMgrShutdown(IN PDEVICE_OBJECT DeviceObject
,
1774 PDEVICE_EXTENSION DeviceExtension
;
1776 DeviceExtension
= DeviceObject
->DeviceExtension
;
1778 InterlockedExchange(&Unloading
, TRUE
);
1780 KeInitializeEvent(&UnloadEvent
, NotificationEvent
, FALSE
);
1782 /* Wait for workers */
1783 if (InterlockedIncrement(&(DeviceExtension
->WorkerReferences
)))
1785 KeReleaseSemaphore(&(DeviceExtension
->WorkerSemaphore
),
1789 KeWaitForSingleObject(&UnloadEvent
, Executive
, KernelMode
, FALSE
, NULL
);
1793 InterlockedDecrement(&(DeviceExtension
->WorkerReferences
));
1796 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1797 Irp
->IoStatus
.Information
= 0;
1798 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1800 return STATUS_SUCCESS
;
1803 /* 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
);