3 * Copyright (C) 2011 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
19 * COPYRIGHT: See COPYING in the top level directory
20 * PROJECT: ReactOS kernel
21 * FILE: drivers/filesystem/mountmgr/mountmgr.c
22 * PURPOSE: Mount Manager
23 * PROGRAMMER: Pierre Schweitzer (pierre.schweitzer@reactos.org)
24 * Alex Ionescu (alex.ionescu@reactos.org)
33 GUID MountedDevicesGuid
= {0x53F5630D, 0xB6BF, 0x11D0, {0x94, 0xF2, 0x00, 0xA0, 0xC9, 0x1E, 0xFB, 0x8B}};
35 PDEVICE_OBJECT gdeviceObject
;
39 static const WCHAR Cunc
[] = L
"\\??\\C:";
43 * - MountMgrQueryDosVolumePaths
44 * - MountMgrQueryVolumePaths
45 * - MountMgrValidateBackPointer
46 * - MountMgrVolumeMountPointCreated
47 * - MountMgrVolumeMountPointDeleted
48 * - ReconcileThisDatabaseWithMasterWorker
55 IsOffline(PUNICODE_STRING SymbolicName
)
58 ULONG IsOffline
, Default
;
59 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
61 /* Prepare to look in the registry to see if
62 * given volume is offline
64 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
65 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
66 QueryTable
[0].Name
= SymbolicName
->Buffer
;
67 QueryTable
[0].EntryContext
= &IsOffline
;
68 QueryTable
[0].DefaultType
= REG_DWORD
;
69 QueryTable
[0].DefaultLength
= sizeof(ULONG
);
70 QueryTable
[0].DefaultData
= &Default
;
75 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
80 if (!NT_SUCCESS(Status
))
85 return (IsOffline
!= 0);
92 HasDriveLetter(IN PDEVICE_INFORMATION DeviceInformation
)
94 PLIST_ENTRY NextEntry
;
95 PSYMLINK_INFORMATION SymlinkInfo
;
97 /* To have a drive letter, a device must have symbolic links */
98 if (IsListEmpty(&(DeviceInformation
->SymbolicLinksListHead
)))
103 /* Browse all the links untill a drive letter is found */
104 NextEntry
= &(DeviceInformation
->SymbolicLinksListHead
);
107 SymlinkInfo
= CONTAINING_RECORD(NextEntry
, SYMLINK_INFORMATION
, SymbolicLinksListEntry
);
109 if (SymlinkInfo
->Online
)
111 if (IsDriveLetter(&(SymlinkInfo
->Name
)))
117 NextEntry
= NextEntry
->Flink
;
118 } while (NextEntry
!= &(DeviceInformation
->SymbolicLinksListHead
));
127 CreateNewDriveLetterName(OUT PUNICODE_STRING DriveLetter
,
128 IN PUNICODE_STRING DeviceName
,
130 IN PMOUNTDEV_UNIQUE_ID UniqueId OPTIONAL
)
132 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
134 /* Allocate a big enough buffer to contain the symbolic link */
135 DriveLetter
->MaximumLength
= DosDevices
.Length
+ 3 * sizeof(WCHAR
);
136 DriveLetter
->Buffer
= AllocatePool(DriveLetter
->MaximumLength
);
137 if (!DriveLetter
->Buffer
)
139 return STATUS_INSUFFICIENT_RESOURCES
;
143 RtlCopyUnicodeString(DriveLetter
, &DosDevices
);
145 /* Update string to reflect real contents */
146 DriveLetter
->Length
= DosDevices
.Length
+ 2 * sizeof(WCHAR
);
147 DriveLetter
->Buffer
[DosDevices
.Length
/ sizeof(WCHAR
) + 2] = UNICODE_NULL
;
148 DriveLetter
->Buffer
[DosDevices
.Length
/ sizeof(WCHAR
) + 1] = L
':';
150 /* If caller wants a no drive entry */
151 if (Letter
== (UCHAR
)-1)
153 /* Then, create a no letter entry */
154 CreateNoDriveLetterEntry(UniqueId
);
155 FreePool(DriveLetter
->Buffer
);
156 return STATUS_UNSUCCESSFUL
;
160 /* Use the letter given by the caller */
161 DriveLetter
->Buffer
[DosDevices
.Length
/ sizeof(WCHAR
)] = (WCHAR
)Letter
;
162 Status
= GlobalCreateSymbolicLink(DriveLetter
, DeviceName
);
163 if (NT_SUCCESS(Status
))
169 /* If caller didn't provide a letter, let's find one for him */
171 if (RtlPrefixUnicodeString(&DeviceFloppy
, DeviceName
, TRUE
))
173 /* If the device is a floppy, start with letter A */
176 else if (RtlPrefixUnicodeString(&DeviceCdRom
, DeviceName
, TRUE
))
178 /* If the device is a CD-ROM, start with letter D */
183 /* Finally, if it's a disk, use C */
187 /* Try to affect a letter (up to Z, ofc) until it's possible */
188 for (; Letter
<= 'Z'; Letter
++)
190 DriveLetter
->Buffer
[DosDevices
.Length
/ sizeof(WCHAR
)] = (WCHAR
)Letter
;
191 Status
= GlobalCreateSymbolicLink(DriveLetter
, DeviceName
);
192 if (NT_SUCCESS(Status
))
194 DPRINT("Assigned drive %c: to %wZ\n", Letter
, DeviceName
);
199 /* We failed to allocate a letter */
200 FreePool(DriveLetter
->Buffer
);
201 DPRINT("Failed to create a drive letter for %wZ\n", DeviceName
);
209 QueryDeviceInformation(IN PUNICODE_STRING SymbolicName
,
210 OUT PUNICODE_STRING DeviceName OPTIONAL
,
211 OUT PMOUNTDEV_UNIQUE_ID
* UniqueId OPTIONAL
,
212 OUT PBOOLEAN Removable OPTIONAL
,
213 OUT PBOOLEAN GptDriveLetter OPTIONAL
,
214 OUT PBOOLEAN HasGuid OPTIONAL
,
215 IN OUT LPGUID StableGuid OPTIONAL
,
216 OUT PBOOLEAN Valid OPTIONAL
)
224 PMOUNTDEV_UNIQUE_ID Id
;
225 PFILE_OBJECT FileObject
;
226 PIO_STACK_LOCATION Stack
;
227 PDEVICE_OBJECT DeviceObject
;
228 IO_STATUS_BLOCK IoStatusBlock
;
229 PARTITION_INFORMATION_EX PartitionInfo
;
230 STORAGE_DEVICE_NUMBER StorageDeviceNumber
;
231 VOLUME_GET_GPT_ATTRIBUTES_INFORMATION GptAttributes
;
233 /* Get device associated with the symbolic name */
234 Status
= IoGetDeviceObjectPointer(SymbolicName
,
235 FILE_READ_ATTRIBUTES
,
238 if (!NT_SUCCESS(Status
))
243 /* The associate FO can't have a file name */
244 if (FileObject
->FileName
.Length
)
246 ObDereferenceObject(FileObject
);
247 return STATUS_OBJECT_NAME_NOT_FOUND
;
250 /* Check if it's removable & return to the user (if asked to) */
251 IsRemovable
= (FileObject
->DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
);
254 *Removable
= IsRemovable
;
257 /* Get the attached device */
258 DeviceObject
= IoGetAttachedDeviceReference(FileObject
->DeviceObject
);
260 /* If we've been asked for a GPT drive letter */
263 /* Consider it has one */
264 *GptDriveLetter
= TRUE
;
268 /* Query the GPT attributes */
269 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
270 Irp
= IoBuildDeviceIoControlRequest(IOCTL_VOLUME_GET_GPT_ATTRIBUTES
,
275 sizeof(GptAttributes
),
281 ObDereferenceObject(DeviceObject
);
282 ObDereferenceObject(FileObject
);
283 return STATUS_INSUFFICIENT_RESOURCES
;
286 Status
= IoCallDriver(DeviceObject
, Irp
);
287 if (Status
== STATUS_PENDING
)
289 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
290 Status
= IoStatusBlock
.Status
;
293 /* In case of failure, don't fail, that's no vital */
294 if (!NT_SUCCESS(Status
))
296 Status
= STATUS_SUCCESS
;
298 /* Check if it has a drive letter */
299 else if (!(GptAttributes
.GptAttributes
&
300 GPT_BASIC_DATA_ATTRIBUTE_NO_DRIVE_LETTER
))
302 *GptDriveLetter
= FALSE
;
307 /* If caller wants to know if there's valid contents */
310 /* Suppose it's not OK */
315 /* Query partitions information */
316 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
317 Irp
= IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_PARTITION_INFO_EX
,
322 sizeof(PartitionInfo
),
328 ObDereferenceObject(DeviceObject
);
329 ObDereferenceObject(FileObject
);
330 return STATUS_INSUFFICIENT_RESOURCES
;
333 Status
= IoCallDriver(DeviceObject
, Irp
);
334 if (Status
== STATUS_PENDING
)
336 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
337 Status
= IoStatusBlock
.Status
;
340 /* Once again here, failure isn't major */
341 if (!NT_SUCCESS(Status
))
343 Status
= STATUS_SUCCESS
;
345 /* Verify we know something in */
346 else if (PartitionInfo
.PartitionStyle
== PARTITION_STYLE_MBR
&&
347 IsRecognizedPartition(PartitionInfo
.Mbr
.PartitionType
))
352 /* It looks correct, ensure it is & query device number */
355 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
356 Irp
= IoBuildDeviceIoControlRequest(IOCTL_STORAGE_GET_DEVICE_NUMBER
,
360 &StorageDeviceNumber
,
361 sizeof(StorageDeviceNumber
),
367 ObDereferenceObject(DeviceObject
);
368 ObDereferenceObject(FileObject
);
369 return STATUS_INSUFFICIENT_RESOURCES
;
372 Status
= IoCallDriver(DeviceObject
, Irp
);
373 if (Status
== STATUS_PENDING
)
375 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
376 Status
= IoStatusBlock
.Status
;
379 if (!NT_SUCCESS(Status
))
381 Status
= STATUS_SUCCESS
;
391 /* If caller needs device name */
394 /* Allocate a buffer just to request length */
395 Name
= AllocatePool(sizeof(MOUNTDEV_NAME
));
398 ObDereferenceObject(DeviceObject
);
399 ObDereferenceObject(FileObject
);
400 return STATUS_INSUFFICIENT_RESOURCES
;
403 /* Query device name */
404 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
405 Irp
= IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_DEVICE_NAME
,
410 sizeof(MOUNTDEV_NAME
),
417 ObDereferenceObject(DeviceObject
);
418 ObDereferenceObject(FileObject
);
419 return STATUS_INSUFFICIENT_RESOURCES
;
422 Stack
= IoGetNextIrpStackLocation(Irp
);
423 Stack
->FileObject
= FileObject
;
425 Status
= IoCallDriver(DeviceObject
, Irp
);
426 if (Status
== STATUS_PENDING
)
428 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
429 Status
= IoStatusBlock
.Status
;
432 /* Now, we've got the correct length */
433 if (Status
== STATUS_BUFFER_OVERFLOW
)
435 Size
= Name
->NameLength
+ sizeof(MOUNTDEV_NAME
);
439 /* Allocate proper size */
440 Name
= AllocatePool(Size
);
443 ObDereferenceObject(DeviceObject
);
444 ObDereferenceObject(FileObject
);
445 return STATUS_INSUFFICIENT_RESOURCES
;
448 /* And query name (for real that time) */
449 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
450 Irp
= IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_DEVICE_NAME
,
462 ObDereferenceObject(DeviceObject
);
463 ObDereferenceObject(FileObject
);
464 return STATUS_INSUFFICIENT_RESOURCES
;
467 Stack
= IoGetNextIrpStackLocation(Irp
);
468 Stack
->FileObject
= FileObject
;
470 Status
= IoCallDriver(DeviceObject
, Irp
);
471 if (Status
== STATUS_PENDING
)
473 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
474 Status
= IoStatusBlock
.Status
;
478 /* Here we can't fail and assume default value */
479 if (!NT_SUCCESS(Status
))
482 ObDereferenceObject(DeviceObject
);
483 ObDereferenceObject(FileObject
);
487 /* Copy back found name to the caller */
488 DeviceName
->Length
= Name
->NameLength
;
489 DeviceName
->MaximumLength
= Name
->NameLength
+ sizeof(WCHAR
);
490 DeviceName
->Buffer
= AllocatePool(DeviceName
->MaximumLength
);
491 if (!DeviceName
->Buffer
)
494 ObDereferenceObject(DeviceObject
);
495 ObDereferenceObject(FileObject
);
496 return STATUS_INSUFFICIENT_RESOURCES
;
499 RtlCopyMemory(DeviceName
->Buffer
, Name
->Name
, Name
->NameLength
);
500 DeviceName
->Buffer
[Name
->NameLength
/ sizeof(WCHAR
)] = UNICODE_NULL
;
504 /* If caller wants device unique ID */
507 /* Prepare buffer to probe length */
508 Id
= AllocatePool(sizeof(MOUNTDEV_UNIQUE_ID
));
511 ObDereferenceObject(DeviceObject
);
512 ObDereferenceObject(FileObject
);
513 return STATUS_INSUFFICIENT_RESOURCES
;
516 /* Query unique ID length */
517 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
518 Irp
= IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_UNIQUE_ID
,
523 sizeof(MOUNTDEV_UNIQUE_ID
),
530 ObDereferenceObject(DeviceObject
);
531 ObDereferenceObject(FileObject
);
532 return STATUS_INSUFFICIENT_RESOURCES
;
535 Stack
= IoGetNextIrpStackLocation(Irp
);
536 Stack
->FileObject
= FileObject
;
538 Status
= IoCallDriver(DeviceObject
, Irp
);
539 if (Status
== STATUS_PENDING
)
541 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
542 Status
= IoStatusBlock
.Status
;
545 /* Retry with appropriate length */
546 if (Status
== STATUS_BUFFER_OVERFLOW
)
548 Size
= Id
->UniqueIdLength
+ sizeof(MOUNTDEV_UNIQUE_ID
);
552 /* Allocate the correct buffer */
553 Id
= AllocatePool(Size
);
556 ObDereferenceObject(DeviceObject
);
557 ObDereferenceObject(FileObject
);
558 return STATUS_INSUFFICIENT_RESOURCES
;
561 /* Query unique ID */
562 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
563 Irp
= IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_UNIQUE_ID
,
575 ObDereferenceObject(DeviceObject
);
576 ObDereferenceObject(FileObject
);
577 return STATUS_INSUFFICIENT_RESOURCES
;
580 Stack
= IoGetNextIrpStackLocation(Irp
);
581 Stack
->FileObject
= FileObject
;
583 Status
= IoCallDriver(DeviceObject
, Irp
);
584 if (Status
== STATUS_PENDING
)
586 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
587 Status
= IoStatusBlock
.Status
;
591 /* Hands back unique ID */
592 if (NT_SUCCESS(Status
))
598 /* In case of failure, also free the rest */
600 if (DeviceName
->Length
)
602 FreePool(DeviceName
->Buffer
);
605 ObDereferenceObject(DeviceObject
);
606 ObDereferenceObject(FileObject
);
612 /* If user wants to know about GUID */
615 /* Query device stable GUID */
616 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
617 Irp
= IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_STABLE_GUID
,
628 ObDereferenceObject(DeviceObject
);
629 ObDereferenceObject(FileObject
);
630 return STATUS_INSUFFICIENT_RESOURCES
;
633 Stack
= IoGetNextIrpStackLocation(Irp
);
634 Stack
->FileObject
= FileObject
;
636 Status
= IoCallDriver(DeviceObject
, Irp
);
637 if (Status
== STATUS_PENDING
)
639 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
640 Status
= IoStatusBlock
.Status
;
643 *HasGuid
= NT_SUCCESS(Status
);
646 ObDereferenceObject(DeviceObject
);
647 ObDereferenceObject(FileObject
);
655 FindDeviceInfo(IN PDEVICE_EXTENSION DeviceExtension
,
656 IN PUNICODE_STRING SymbolicName
,
657 IN BOOLEAN DeviceNameGiven
,
658 OUT PDEVICE_INFORMATION
* DeviceInformation
)
661 PLIST_ENTRY NextEntry
;
662 UNICODE_STRING DeviceName
;
663 PDEVICE_INFORMATION DeviceInfo
= NULL
;
665 /* If a device name was given, use it */
668 DeviceName
.Length
= SymbolicName
->Length
;
669 DeviceName
.Buffer
= SymbolicName
->Buffer
;
673 /* Otherwise, query it */
674 Status
= QueryDeviceInformation(SymbolicName
,
679 if (!NT_SUCCESS(Status
))
685 /* Look for device information matching devive */
686 for (NextEntry
= DeviceExtension
->DeviceListHead
.Flink
;
687 NextEntry
!= &(DeviceExtension
->DeviceListHead
);
688 NextEntry
= NextEntry
->Flink
)
690 DeviceInfo
= CONTAINING_RECORD(NextEntry
,
694 if (RtlEqualUnicodeString(&DeviceName
, &(DeviceInfo
->DeviceName
), TRUE
))
700 /* Release our buffer if required */
701 if (!DeviceNameGiven
)
703 FreePool(DeviceName
.Buffer
);
706 /* Return found intormation */
707 if (NextEntry
== &(DeviceExtension
->DeviceListHead
))
709 return STATUS_OBJECT_NAME_NOT_FOUND
;
712 *DeviceInformation
= DeviceInfo
;
713 return STATUS_SUCCESS
;
720 MountMgrFreeDeadDeviceInfo(IN PDEVICE_INFORMATION DeviceInformation
)
722 FreePool(DeviceInformation
->SymbolicName
.Buffer
);
723 FreePool(DeviceInformation
);
730 MountMgrFreeMountedDeviceInfo(IN PDEVICE_INFORMATION DeviceInformation
)
732 PLIST_ENTRY NextEntry
;
733 PSYMLINK_INFORMATION SymLink
;
734 PUNIQUE_ID_REPLICATE UniqueId
;
735 PASSOCIATED_DEVICE_ENTRY AssociatedDevice
;
737 /* Purge symbolic links list */
738 while (!IsListEmpty(&(DeviceInformation
->SymbolicLinksListHead
)))
740 NextEntry
= RemoveHeadList(&(DeviceInformation
->SymbolicLinksListHead
));
741 SymLink
= CONTAINING_RECORD(NextEntry
, SYMLINK_INFORMATION
, SymbolicLinksListEntry
);
743 GlobalDeleteSymbolicLink(&(SymLink
->Name
));
744 FreePool(SymLink
->Name
.Buffer
);
747 /* Purge replicated unique IDs list */
748 while (!IsListEmpty(&(DeviceInformation
->ReplicatedUniqueIdsListHead
)))
750 NextEntry
= RemoveHeadList(&(DeviceInformation
->ReplicatedUniqueIdsListHead
));
751 UniqueId
= CONTAINING_RECORD(NextEntry
, UNIQUE_ID_REPLICATE
, ReplicatedUniqueIdsListEntry
);
753 FreePool(UniqueId
->UniqueId
);
757 while (!IsListEmpty(&(DeviceInformation
->AssociatedDevicesHead
)))
759 NextEntry
= RemoveHeadList(&(DeviceInformation
->AssociatedDevicesHead
));
760 AssociatedDevice
= CONTAINING_RECORD(NextEntry
, ASSOCIATED_DEVICE_ENTRY
, AssociatedDevicesEntry
);
762 FreePool(AssociatedDevice
->String
.Buffer
);
763 FreePool(AssociatedDevice
);
766 /* Free the rest of the buffers */
767 FreePool(DeviceInformation
->SymbolicName
.Buffer
);
768 if (DeviceInformation
->KeepLinks
)
770 FreePool(DeviceInformation
->UniqueId
);
772 FreePool(DeviceInformation
->DeviceName
.Buffer
);
774 /* Finally, stop waiting for notifications for this device */
775 if (DeviceInformation
->TargetDeviceNotificationEntry
)
777 IoUnregisterPlugPlayNotification(DeviceInformation
->TargetDeviceNotificationEntry
);
785 MountMgrFreeSavedLink(IN PSAVED_LINK_INFORMATION SavedLinkInformation
)
787 PLIST_ENTRY NextEntry
;
788 PSYMLINK_INFORMATION SymlinkInformation
;
790 /* For all the saved links */
791 while (!IsListEmpty(&(SavedLinkInformation
->SymbolicLinksListHead
)))
793 NextEntry
= RemoveHeadList(&(SavedLinkInformation
->SymbolicLinksListHead
));
794 SymlinkInformation
= CONTAINING_RECORD(NextEntry
, SYMLINK_INFORMATION
, SymbolicLinksListEntry
);
796 /* Remove from system & free */
797 GlobalDeleteSymbolicLink(&(SymlinkInformation
->Name
));
798 FreePool(SymlinkInformation
->Name
.Buffer
);
799 FreePool(SymlinkInformation
);
802 /* And free unique ID & entry */
803 FreePool(SavedLinkInformation
->UniqueId
);
804 FreePool(SavedLinkInformation
);
813 MountMgrUnload(IN
struct _DRIVER_OBJECT
*DriverObject
)
815 PLIST_ENTRY NextEntry
;
816 PUNIQUE_ID_WORK_ITEM WorkItem
;
817 PDEVICE_EXTENSION DeviceExtension
;
818 PDEVICE_INFORMATION DeviceInformation
;
819 PSAVED_LINK_INFORMATION SavedLinkInformation
;
821 UNREFERENCED_PARAMETER(DriverObject
);
823 /* Don't get notification any longer */
824 IoUnregisterShutdownNotification(gdeviceObject
);
826 /* Free registry buffer */
827 DeviceExtension
= gdeviceObject
->DeviceExtension
;
828 if (DeviceExtension
->RegistryPath
.Buffer
)
830 FreePool(DeviceExtension
->RegistryPath
.Buffer
);
831 DeviceExtension
->RegistryPath
.Buffer
= NULL
;
834 InterlockedExchange(&Unloading
, TRUE
);
836 KeInitializeEvent(&UnloadEvent
, NotificationEvent
, FALSE
);
838 /* Wait for workers to finish */
839 if (InterlockedIncrement(&DeviceExtension
->WorkerReferences
))
841 KeReleaseSemaphore(&(DeviceExtension
->WorkerSemaphore
),
842 IO_NO_INCREMENT
, 1, FALSE
);
844 KeWaitForSingleObject(&UnloadEvent
, Executive
, KernelMode
, FALSE
, NULL
);
848 InterlockedDecrement(&(DeviceExtension
->WorkerReferences
));
851 /* Don't get any notification any longer² */
852 IoUnregisterPlugPlayNotification(DeviceExtension
->NotificationEntry
);
854 /* Acquire the driver exclusively */
855 KeWaitForSingleObject(&(DeviceExtension
->DeviceLock
), Executive
, KernelMode
,
858 /* Clear offline devices list */
859 while (!IsListEmpty(&(DeviceExtension
->OfflineDeviceListHead
)))
861 NextEntry
= RemoveHeadList(&(DeviceExtension
->OfflineDeviceListHead
));
862 DeviceInformation
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
863 MountMgrFreeDeadDeviceInfo(DeviceInformation
);
866 /* Clear saved links list */
867 while (!IsListEmpty(&(DeviceExtension
->SavedLinksListHead
)))
869 NextEntry
= RemoveHeadList(&(DeviceExtension
->SavedLinksListHead
));
870 SavedLinkInformation
= CONTAINING_RECORD(NextEntry
, SAVED_LINK_INFORMATION
, SavedLinksListEntry
);
871 MountMgrFreeSavedLink(SavedLinkInformation
);
874 /* Clear workers list */
875 while (!IsListEmpty(&(DeviceExtension
->UniqueIdWorkerItemListHead
)))
877 NextEntry
= RemoveHeadList(&(DeviceExtension
->UniqueIdWorkerItemListHead
));
878 WorkItem
= CONTAINING_RECORD(NextEntry
, UNIQUE_ID_WORK_ITEM
, UniqueIdWorkerItemListEntry
);
880 KeResetEvent(&UnloadEvent
);
881 WorkItem
->Event
= &UnloadEvent
;
883 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
,
886 IoCancelIrp(WorkItem
->Irp
);
887 KeWaitForSingleObject(&UnloadEvent
, Executive
, KernelMode
, FALSE
, NULL
);
889 IoFreeIrp(WorkItem
->Irp
);
890 FreePool(WorkItem
->DeviceName
.Buffer
);
891 FreePool(WorkItem
->IrpBuffer
);
894 KeWaitForSingleObject(&(DeviceExtension
->DeviceLock
), Executive
, KernelMode
,
898 /* If we have drive letter data, release */
899 if (DeviceExtension
->DriveLetterData
)
901 FreePool(DeviceExtension
->DriveLetterData
);
902 DeviceExtension
->DriveLetterData
= NULL
;
905 /* Release driver & quit */
906 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
, 1, FALSE
);
908 GlobalDeleteSymbolicLink(&DosDevicesMount
);
909 IoDeleteDevice(gdeviceObject
);
916 MountmgrReadNoAutoMount(IN PUNICODE_STRING RegistryPath
)
919 ULONG Result
, Default
= 0;
920 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
922 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
924 /* Simply read data from register */
925 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
926 QueryTable
[0].Name
= L
"NoAutoMount";
927 QueryTable
[0].EntryContext
= &Result
;
928 QueryTable
[0].DefaultType
= REG_NONE
;
929 QueryTable
[0].DefaultData
= &Default
;
930 QueryTable
[0].DefaultLength
= sizeof(ULONG
);
932 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
933 RegistryPath
->Buffer
,
937 if (!NT_SUCCESS(Status
))
939 return (Default
!= 0);
942 return (Result
!= 0);
949 MountMgrMountedDeviceArrival(IN PDEVICE_EXTENSION DeviceExtension
,
950 IN PUNICODE_STRING SymbolicName
,
951 IN BOOLEAN FromVolume
)
956 ULONG SymLinkCount
, i
;
957 PLIST_ENTRY NextEntry
;
958 PUNICODE_STRING SymLinks
;
959 NTSTATUS Status
, IntStatus
;
960 OBJECT_ATTRIBUTES ObjectAttributes
;
961 PSYMLINK_INFORMATION SymlinkInformation
;
962 PMOUNTDEV_UNIQUE_ID UniqueId
, NewUniqueId
;
963 PSAVED_LINK_INFORMATION SavedLinkInformation
;
964 PDEVICE_INFORMATION DeviceInformation
, CurrentDevice
;
965 WCHAR CSymLinkBuffer
[MAX_PATH
], LinkTargetBuffer
[MAX_PATH
];
966 UNICODE_STRING TargetDeviceName
, SuggestedLinkName
, DeviceName
, VolumeName
, DriveLetter
, LinkTarget
, CSymLink
;
967 BOOLEAN HasGuid
, HasGptDriveLetter
, Valid
, UseOnlyIfThereAreNoOtherLinks
, IsDrvLetter
, IsOff
, IsVolumeName
, LinkError
;
969 /* New device = new structure to represent it */
970 DeviceInformation
= AllocatePool(sizeof(DEVICE_INFORMATION
));
971 if (!DeviceInformation
)
973 return STATUS_INSUFFICIENT_RESOURCES
;
976 /* Initialise device structure */
977 RtlZeroMemory(DeviceInformation
, sizeof(DEVICE_INFORMATION
));
978 InitializeListHead(&(DeviceInformation
->SymbolicLinksListHead
));
979 InitializeListHead(&(DeviceInformation
->ReplicatedUniqueIdsListHead
));
980 InitializeListHead(&(DeviceInformation
->AssociatedDevicesHead
));
981 DeviceInformation
->SymbolicName
.Length
= SymbolicName
->Length
;
982 DeviceInformation
->SymbolicName
.MaximumLength
= SymbolicName
->Length
+ sizeof(UNICODE_NULL
);
983 DeviceInformation
->SymbolicName
.Buffer
= AllocatePool(DeviceInformation
->SymbolicName
.MaximumLength
);
984 if (!DeviceInformation
->SymbolicName
.Buffer
)
986 FreePool(DeviceInformation
);
987 return STATUS_INSUFFICIENT_RESOURCES
;
990 /* Copy symbolic name */
991 RtlCopyMemory(DeviceInformation
->SymbolicName
.Buffer
, SymbolicName
->Buffer
, SymbolicName
->Length
);
992 DeviceInformation
->SymbolicName
.Buffer
[DeviceInformation
->SymbolicName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
993 DeviceInformation
->Volume
= FromVolume
;
994 DeviceInformation
->DeviceExtension
= DeviceExtension
;
996 /* Query as much data as possible about device */
997 Status
= QueryDeviceInformation(SymbolicName
,
1000 &(DeviceInformation
->Removable
),
1005 if (!NT_SUCCESS(Status
))
1007 KeWaitForSingleObject(&(DeviceExtension
->DeviceLock
), Executive
, KernelMode
, FALSE
, NULL
);
1009 for (NextEntry
= DeviceExtension
->OfflineDeviceListHead
.Flink
;
1010 NextEntry
!= &(DeviceExtension
->OfflineDeviceListHead
);
1011 NextEntry
= NextEntry
->Flink
)
1013 CurrentDevice
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
1015 if (RtlEqualUnicodeString(&(DeviceInformation
->SymbolicName
), &(CurrentDevice
->SymbolicName
), TRUE
))
1021 if (NextEntry
!= &(DeviceExtension
->OfflineDeviceListHead
))
1023 MountMgrFreeDeadDeviceInfo(DeviceInformation
);
1027 InsertTailList(&(DeviceExtension
->OfflineDeviceListHead
), &(DeviceInformation
->DeviceListEntry
));
1030 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
, 1, FALSE
);
1035 /* Save gathered data */
1036 DeviceInformation
->UniqueId
= UniqueId
;
1037 DeviceInformation
->DeviceName
= TargetDeviceName
;
1038 DeviceInformation
->KeepLinks
= FALSE
;
1040 /* If we found system partition, mark it */
1041 if (DeviceExtension
->DriveLetterData
&& UniqueId
->UniqueIdLength
== DeviceExtension
->DriveLetterData
->UniqueIdLength
)
1043 if (RtlCompareMemory(UniqueId
->UniqueId
, DeviceExtension
->DriveLetterData
->UniqueId
, UniqueId
->UniqueIdLength
)
1044 == UniqueId
->UniqueIdLength
)
1046 IoSetSystemPartition(&TargetDeviceName
);
1050 /* Check suggested link name */
1051 Status
= QuerySuggestedLinkName(&(DeviceInformation
->SymbolicName
),
1053 &UseOnlyIfThereAreNoOtherLinks
);
1054 if (!NT_SUCCESS(Status
))
1056 SuggestedLinkName
.Buffer
= NULL
;
1059 /* If it's OK, set it and save its letter (if any) */
1060 if (SuggestedLinkName
.Buffer
&& IsDriveLetter(&SuggestedLinkName
))
1062 DeviceInformation
->SuggestedDriveLetter
= (UCHAR
)SuggestedLinkName
.Buffer
[LETTER_POSITION
];
1065 /* Acquire driver exclusively */
1066 KeWaitForSingleObject(&(DeviceExtension
->DeviceLock
), Executive
, KernelMode
, FALSE
, NULL
);
1068 /* Check if we already have device in to prevent double registration */
1069 for (NextEntry
= DeviceExtension
->DeviceListHead
.Flink
;
1070 NextEntry
!= &(DeviceExtension
->DeviceListHead
);
1071 NextEntry
= NextEntry
->Flink
)
1073 CurrentDevice
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
1075 if (RtlEqualUnicodeString(&(CurrentDevice
->DeviceName
), &TargetDeviceName
, TRUE
))
1081 /* If we found it, clear ours, and return success, all correct */
1082 if (NextEntry
!= &(DeviceExtension
->DeviceListHead
))
1084 if (SuggestedLinkName
.Buffer
)
1086 FreePool(SuggestedLinkName
.Buffer
);
1090 FreePool(TargetDeviceName
.Buffer
);
1091 FreePool(DeviceInformation
->DeviceName
.Buffer
);
1092 FreePool(DeviceInformation
);
1094 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
, 1, FALSE
);
1096 return STATUS_SUCCESS
;
1099 /* Check if there are symlinks associated with our device in registry */
1100 Status
= QuerySymbolicLinkNamesFromStorage(DeviceExtension
,
1102 (SuggestedLinkName
.Buffer
) ? &SuggestedLinkName
: NULL
,
1103 UseOnlyIfThereAreNoOtherLinks
,
1109 /* If our device is a CD-ROM */
1110 if (RtlPrefixUnicodeString(&DeviceCdRom
, &TargetDeviceName
, TRUE
))
1112 LinkTarget
.Length
= 0;
1113 LinkTarget
.MaximumLength
= sizeof(LinkTargetBuffer
);
1114 LinkTarget
.Buffer
= LinkTargetBuffer
;
1116 RtlCopyMemory(CSymLinkBuffer
, Cunc
, sizeof(Cunc
));
1117 RtlInitUnicodeString(&CSymLink
, CSymLinkBuffer
);
1119 /* Start checking all letters that could have been associated */
1120 for (Letter
= L
'D'; Letter
<= L
'Z'; Letter
++)
1122 CSymLink
.Buffer
[LETTER_POSITION
] = Letter
;
1124 InitializeObjectAttributes(&ObjectAttributes
,
1126 OBJ_CASE_INSENSITIVE
,
1130 /* Try to open the associated symlink */
1131 Status
= ZwOpenSymbolicLinkObject(&LinkHandle
, SYMBOLIC_LINK_QUERY
, &ObjectAttributes
);
1132 if (!NT_SUCCESS(Status
))
1137 /* And query its target */
1138 Status
= ZwQuerySymbolicLinkObject(LinkHandle
, &LinkTarget
, NULL
);
1139 ZwClose(LinkHandle
);
1141 if (!NT_SUCCESS(Status
))
1146 IntStatus
= STATUS_UNSUCCESSFUL
;
1147 if (!RtlEqualUnicodeString(&LinkTarget
, &DeviceInformation
->DeviceName
, FALSE
))
1152 /* This link is matching our device, whereas it's not supposed to have any
1153 * symlink associated.
1158 IoDeleteSymbolicLink(&CSymLink
);
1162 /* Now, for all the symlinks, check for ours */
1163 for (i
= 0; i
< SymLinkCount
; i
++)
1165 if (IsDriveLetter(&(SymLinks
[i
])))
1167 /* If it exists, that's correct */
1168 if (SymLinks
[i
].Buffer
[LETTER_POSITION
] == Letter
)
1170 IntStatus
= STATUS_SUCCESS
;
1175 /* Useless link, delete it */
1176 if (IntStatus
== STATUS_UNSUCCESSFUL
)
1178 IoDeleteSymbolicLink(&CSymLink
);
1183 /* Suggested name is no longer required */
1184 if (SuggestedLinkName
.Buffer
)
1186 FreePool(SuggestedLinkName
.Buffer
);
1189 /* If if failed, ensure we don't take symlinks into account */
1190 if (!NT_SUCCESS(Status
))
1196 /* Now we queried them, remove the symlinks */
1197 SavedLinkInformation
= RemoveSavedLinks(DeviceExtension
, UniqueId
);
1199 IsDrvLetter
= FALSE
;
1201 IsVolumeName
= FALSE
;
1202 /* For all the symlinks */
1203 for (i
= 0; i
< SymLinkCount
; i
++)
1205 /* Check if our device is a volume */
1206 if (MOUNTMGR_IS_VOLUME_NAME(&(SymLinks
[i
])))
1208 IsVolumeName
= TRUE
;
1210 /* If it has a drive letter */
1211 else if (IsDriveLetter(&(SymLinks
[i
])))
1215 DeleteFromLocalDatabase(&(SymLinks
[i
]), UniqueId
);
1224 /* And recreate the symlink to our device */
1225 Status
= GlobalCreateSymbolicLink(&(SymLinks
[i
]), &TargetDeviceName
);
1226 if (!NT_SUCCESS(Status
))
1230 if ((SavedLinkInformation
&& !RedirectSavedLink(SavedLinkInformation
, &(SymLinks
[i
]), &TargetDeviceName
)) ||
1231 !SavedLinkInformation
)
1233 Status
= QueryDeviceInformation(&(SymLinks
[i
]), &DeviceName
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
1234 if (NT_SUCCESS(Status
))
1236 LinkError
= RtlEqualUnicodeString(&TargetDeviceName
, &DeviceName
, TRUE
);
1237 FreePool(DeviceName
.Buffer
);
1242 if (IsDriveLetter(&(SymLinks
[i
])))
1244 IsDrvLetter
= FALSE
;
1245 DeleteFromLocalDatabase(&(SymLinks
[i
]), UniqueId
);
1248 FreePool(SymLinks
[i
].Buffer
);
1254 /* Check if was offline */
1255 if (IsOffline(&(SymLinks
[i
])))
1260 /* Finally, associate this symlink with the device */
1261 SymlinkInformation
= AllocatePool(sizeof(SYMLINK_INFORMATION
));
1262 if (!SymlinkInformation
)
1264 GlobalDeleteSymbolicLink(&(SymLinks
[i
]));
1265 FreePool(SymLinks
[i
].Buffer
);
1269 SymlinkInformation
->Name
= SymLinks
[i
];
1270 SymlinkInformation
->Online
= TRUE
;
1272 InsertTailList(&(DeviceInformation
->SymbolicLinksListHead
),
1273 &(SymlinkInformation
->SymbolicLinksListEntry
));
1276 /* Now, for all the recreated symlinks, notify their recreation */
1277 for (NextEntry
= DeviceInformation
->SymbolicLinksListHead
.Flink
;
1278 NextEntry
!= &(DeviceInformation
->SymbolicLinksListHead
);
1279 NextEntry
= NextEntry
->Flink
)
1281 SymlinkInformation
= CONTAINING_RECORD(NextEntry
, SYMLINK_INFORMATION
, SymbolicLinksListEntry
);
1283 SendLinkCreated(&(SymlinkInformation
->Name
));
1286 /* If we had saved links, it's time to free them */
1287 if (SavedLinkInformation
)
1289 MountMgrFreeSavedLink(SavedLinkInformation
);
1292 /* If our device doesn't have a volume name */
1295 /* It's time to create one */
1296 Status
= CreateNewVolumeName(&VolumeName
, NULL
);
1297 if (NT_SUCCESS(Status
))
1299 /* Write it to global database */
1300 RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE
,
1305 UniqueId
->UniqueIdLength
);
1307 /* And create the symlink */
1308 GlobalCreateSymbolicLink(&VolumeName
, &TargetDeviceName
);
1310 SymlinkInformation
= AllocatePool(sizeof(SYMLINK_INFORMATION
));
1311 if (!SymlinkInformation
)
1313 FreePool(VolumeName
.Buffer
);
1315 /* Finally, associate it with the device and notify creation */
1318 SymlinkInformation
->Name
= VolumeName
;
1319 SymlinkInformation
->Online
= TRUE
;
1320 InsertTailList(&(DeviceInformation
->SymbolicLinksListHead
),
1321 &(SymlinkInformation
->SymbolicLinksListEntry
));
1323 SendLinkCreated(&VolumeName
);
1328 /* If we found a drive letter, then, ignore the suggested one */
1331 DeviceInformation
->SuggestedDriveLetter
= 0;
1333 /* Else, it's time to set up one */
1334 else if (!DeviceExtension
->NoAutoMount
&& !DeviceInformation
->Removable
&&
1335 DeviceExtension
->AutomaticDriveLetter
&& HasGptDriveLetter
&&
1336 DeviceInformation
->SuggestedDriveLetter
&&
1337 !HasNoDriveLetterEntry(UniqueId
))
1339 /* Create a new drive letter */
1340 Status
= CreateNewDriveLetterName(&DriveLetter
, &TargetDeviceName
,
1341 DeviceInformation
->SuggestedDriveLetter
,
1343 if (!NT_SUCCESS(Status
))
1345 CreateNoDriveLetterEntry(UniqueId
);
1349 /* Save it to global database */
1350 RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE
,
1355 UniqueId
->UniqueIdLength
);
1357 /* Associate it with the device and notify creation */
1358 SymlinkInformation
= AllocatePool(sizeof(SYMLINK_INFORMATION
));
1359 if (!SymlinkInformation
)
1361 FreePool(DriveLetter
.Buffer
);
1365 SymlinkInformation
->Name
= DriveLetter
;
1366 SymlinkInformation
->Online
= TRUE
;
1367 InsertTailList(&(DeviceInformation
->SymbolicLinksListHead
),
1368 &(SymlinkInformation
->SymbolicLinksListEntry
));
1370 SendLinkCreated(&DriveLetter
);
1375 /* If required, register for notifications about the device */
1378 RegisterForTargetDeviceNotification(DeviceExtension
, DeviceInformation
);
1381 /* Finally, insert the device into our devices list */
1382 InsertTailList(&(DeviceExtension
->DeviceListHead
), &(DeviceInformation
->DeviceListEntry
));
1384 /* Copy device unique ID */
1385 NewUniqueId
= AllocatePool(UniqueId
->UniqueIdLength
+ sizeof(MOUNTDEV_UNIQUE_ID
));
1388 NewUniqueId
->UniqueIdLength
= UniqueId
->UniqueIdLength
;
1389 RtlCopyMemory(NewUniqueId
->UniqueId
, UniqueId
->UniqueId
, UniqueId
->UniqueIdLength
);
1392 /* If device's offline or valid, skip its notifications */
1395 DeviceInformation
->SkipNotifications
= TRUE
;
1398 /* In case device is valid and is set to no automount,
1401 if (DeviceExtension
->NoAutoMount
|| IsDrvLetter
)
1403 IsOff
= !DeviceInformation
->SkipNotifications
;
1410 /* Finally, release the exclusive lock */
1411 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
, 1, FALSE
);
1413 /* If device is not offline, notify its arrival */
1416 SendOnlineNotification(SymbolicName
);
1419 /* If we had symlinks (from storage), free them */
1425 /* Notify about unique id change */
1428 IssueUniqueIdChangeNotify(DeviceExtension
, SymbolicName
, NewUniqueId
);
1429 FreePool(NewUniqueId
);
1432 /* If this drive was set to have a drive letter automatically
1433 * Now it's back, local databases sync will be required
1435 if (DeviceExtension
->AutomaticDriveLetter
)
1437 KeWaitForSingleObject(&(DeviceExtension
->DeviceLock
), Executive
, KernelMode
, FALSE
, NULL
);
1439 ReconcileThisDatabaseWithMaster(DeviceExtension
, DeviceInformation
);
1441 NextEntry
= DeviceExtension
->DeviceListHead
.Flink
;
1442 CurrentDevice
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
1443 while (CurrentDevice
!= DeviceInformation
)
1445 if (!CurrentDevice
->NoDatabase
)
1447 ReconcileThisDatabaseWithMaster(DeviceExtension
, CurrentDevice
);
1450 NextEntry
= NextEntry
->Flink
;
1451 CurrentDevice
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
1454 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
, 1, FALSE
);
1457 return STATUS_SUCCESS
;
1464 MountMgrMountedDeviceRemoval(IN PDEVICE_EXTENSION DeviceExtension
,
1465 IN PUNICODE_STRING DeviceName
)
1467 PLIST_ENTRY NextEntry
, DeviceEntry
;
1468 PUNIQUE_ID_REPLICATE UniqueIdReplicate
;
1469 PSYMLINK_INFORMATION SymlinkInformation
;
1470 PASSOCIATED_DEVICE_ENTRY AssociatedDevice
;
1471 PSAVED_LINK_INFORMATION SavedLinkInformation
= NULL
;
1472 PDEVICE_INFORMATION DeviceInformation
, CurrentDevice
;
1474 /* Acquire device exclusively */
1475 KeWaitForSingleObject(&(DeviceExtension
->DeviceLock
), Executive
, KernelMode
, FALSE
, NULL
);
1477 /* Look for the leaving device */
1478 for (NextEntry
= DeviceExtension
->DeviceListHead
.Flink
;
1479 NextEntry
!= &(DeviceExtension
->DeviceListHead
);
1480 NextEntry
= NextEntry
->Flink
)
1482 DeviceInformation
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
1484 if (!RtlCompareUnicodeString(&(DeviceInformation
->SymbolicName
), DeviceName
, TRUE
))
1490 /* If we found it */
1491 if (NextEntry
!= &(DeviceExtension
->DeviceListHead
))
1493 /* If it's asked to keep links, then, prepare to save them */
1494 if (DeviceInformation
->KeepLinks
)
1496 SavedLinkInformation
= AllocatePool(sizeof(SAVED_LINK_INFORMATION
));
1497 if (!SavedLinkInformation
)
1499 DeviceInformation
->KeepLinks
= FALSE
;
1503 /* If it's possible (and asked), start to save them */
1504 if (DeviceInformation
->KeepLinks
)
1506 InsertTailList(&(DeviceExtension
->SavedLinksListHead
), &(SavedLinkInformation
->SavedLinksListEntry
));
1507 InitializeListHead(&(SavedLinkInformation
->SymbolicLinksListHead
));
1508 SavedLinkInformation
->UniqueId
= DeviceInformation
->UniqueId
;
1511 /* For all the symlinks */
1512 while (!IsListEmpty(&(DeviceInformation
->SymbolicLinksListHead
)))
1514 NextEntry
= RemoveHeadList(&(DeviceInformation
->SymbolicLinksListHead
));
1515 SymlinkInformation
= CONTAINING_RECORD(NextEntry
, SYMLINK_INFORMATION
, SymbolicLinksListEntry
);
1517 /* If we have to, save the link */
1518 if (DeviceInformation
->KeepLinks
)
1520 InsertTailList(&(SavedLinkInformation
->SymbolicLinksListHead
), &(SymlinkInformation
->SymbolicLinksListEntry
));
1522 /* Otherwise, just release it */
1525 GlobalDeleteSymbolicLink(&(SymlinkInformation
->Name
));
1526 FreePool(SymlinkInformation
->Name
.Buffer
);
1527 FreePool(SymlinkInformation
);
1531 /* Free all the replicated unique IDs */
1532 while (!IsListEmpty(&(DeviceInformation
->ReplicatedUniqueIdsListHead
)))
1534 NextEntry
= RemoveHeadList(&(DeviceInformation
->ReplicatedUniqueIdsListHead
));
1535 UniqueIdReplicate
= CONTAINING_RECORD(NextEntry
, UNIQUE_ID_REPLICATE
, ReplicatedUniqueIdsListEntry
);
1538 FreePool(UniqueIdReplicate
->UniqueId
);
1539 FreePool(UniqueIdReplicate
);
1542 while (!IsListEmpty(&(DeviceInformation
->AssociatedDevicesHead
)))
1544 NextEntry
= RemoveHeadList(&(DeviceInformation
->AssociatedDevicesHead
));
1545 AssociatedDevice
= CONTAINING_RECORD(NextEntry
, ASSOCIATED_DEVICE_ENTRY
, AssociatedDevicesEntry
);
1547 DeviceInformation
->NoDatabase
= TRUE
;
1548 FreePool(AssociatedDevice
->String
.Buffer
);
1549 FreePool(AssociatedDevice
);
1552 /* Remove device from the device list */
1553 RemoveEntryList(&(DeviceInformation
->DeviceListEntry
));
1555 /* If there are still devices, check if some were associated with ours */
1556 if (!IsListEmpty(&(DeviceInformation
->DeviceListEntry
)))
1558 for (NextEntry
= DeviceExtension
->DeviceListHead
.Flink
;
1559 NextEntry
!= &(DeviceExtension
->DeviceListHead
);
1560 NextEntry
= NextEntry
->Flink
)
1562 CurrentDevice
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
1564 /* And then, remove them */
1565 DeviceEntry
= CurrentDevice
->AssociatedDevicesHead
.Flink
;
1566 while (DeviceEntry
!= &(CurrentDevice
->AssociatedDevicesHead
))
1568 AssociatedDevice
= CONTAINING_RECORD(NextEntry
, ASSOCIATED_DEVICE_ENTRY
, AssociatedDevicesEntry
);
1569 DeviceEntry
= DeviceEntry
->Flink
;
1571 if (AssociatedDevice
->DeviceInformation
!= DeviceInformation
)
1576 RemoveEntryList(&(AssociatedDevice
->AssociatedDevicesEntry
));
1577 FreePool(AssociatedDevice
->String
.Buffer
);
1578 FreePool(AssociatedDevice
);
1583 /* Finally, clean up device name, symbolic name */
1584 FreePool(DeviceInformation
->SymbolicName
.Buffer
);
1585 if (!DeviceInformation
->KeepLinks
)
1587 FreePool(DeviceInformation
->UniqueId
);
1589 FreePool(DeviceInformation
->DeviceName
.Buffer
);
1591 /* Unregister notifications */
1592 if (DeviceInformation
->TargetDeviceNotificationEntry
)
1594 IoUnregisterPlugPlayNotification(DeviceInformation
->TargetDeviceNotificationEntry
);
1598 FreePool(DeviceInformation
);
1602 /* We didn't find device, perhaps because it was offline */
1603 for (NextEntry
= DeviceExtension
->OfflineDeviceListHead
.Flink
;
1604 NextEntry
!= &(DeviceExtension
->OfflineDeviceListHead
);
1605 NextEntry
= NextEntry
->Flink
)
1607 DeviceInformation
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
1609 /* It was, remove it */
1610 if (RtlCompareUnicodeString(&(DeviceInformation
->SymbolicName
), DeviceName
, TRUE
) == 0)
1612 RemoveEntryList(&(DeviceInformation
->DeviceListEntry
));
1613 MountMgrFreeDeadDeviceInfo(DeviceInformation
);
1619 /* Releave driver */
1620 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
, 1, FALSE
);
1628 MountMgrMountedDeviceNotification(IN PVOID NotificationStructure
,
1632 PDEVICE_EXTENSION DeviceExtension
;
1633 PDEVICE_INTERFACE_CHANGE_NOTIFICATION Notification
;
1635 /* Notification for a device arrived */
1636 /* Disable hard errors */
1637 OldState
= PsGetThreadHardErrorsAreDisabled(PsGetCurrentThread());
1638 PsSetThreadHardErrorsAreDisabled(PsGetCurrentThread(), TRUE
);
1640 DeviceExtension
= Context
;
1641 Notification
= NotificationStructure
;
1643 /* Dispatch according to the event */
1644 if (IsEqualGUID(&(Notification
->Event
), &GUID_DEVICE_INTERFACE_ARRIVAL
))
1646 MountMgrMountedDeviceArrival(DeviceExtension
, Notification
->SymbolicLinkName
, FALSE
);
1648 else if (IsEqualGUID(&(Notification
->Event
), &GUID_DEVICE_INTERFACE_REMOVAL
))
1650 MountMgrMountedDeviceRemoval(DeviceExtension
, Notification
->SymbolicLinkName
);
1653 /* Reset hard errors */
1654 PsSetThreadHardErrorsAreDisabled(PsGetCurrentThread(), OldState
);
1656 return STATUS_SUCCESS
;
1664 MountMgrCreateClose(IN PDEVICE_OBJECT DeviceObject
,
1667 PIO_STACK_LOCATION Stack
;
1668 NTSTATUS Status
= STATUS_SUCCESS
;
1670 UNREFERENCED_PARAMETER(DeviceObject
);
1672 Stack
= IoGetCurrentIrpStackLocation(Irp
);
1674 /* Allow driver opening for communication
1675 * as long as it's not taken for a directory
1677 if (Stack
->MajorFunction
== IRP_MJ_CREATE
&&
1678 Stack
->Parameters
.Create
.Options
& FILE_DIRECTORY_FILE
)
1680 Status
= STATUS_NOT_A_DIRECTORY
;
1683 Irp
->IoStatus
.Status
= Status
;
1684 Irp
->IoStatus
.Information
= 0;
1685 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1694 MountMgrCancel(IN PDEVICE_OBJECT DeviceObject
,
1697 UNREFERENCED_PARAMETER(DeviceObject
);
1699 RemoveEntryList(&(Irp
->Tail
.Overlay
.ListEntry
));
1701 IoReleaseCancelSpinLock(Irp
->CancelIrql
);
1703 Irp
->IoStatus
.Information
= 0;
1704 Irp
->IoStatus
.Status
= STATUS_CANCELLED
;
1705 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1713 MountMgrCleanup(IN PDEVICE_OBJECT DeviceObject
,
1718 PLIST_ENTRY NextEntry
;
1719 PFILE_OBJECT FileObject
;
1720 PIO_STACK_LOCATION Stack
;
1721 PDEVICE_EXTENSION DeviceExtension
;
1723 DeviceExtension
= DeviceObject
->DeviceExtension
;
1724 Stack
= IoGetCurrentIrpStackLocation(Irp
);
1725 FileObject
= Stack
->FileObject
;
1727 IoAcquireCancelSpinLock(&OldIrql
);
1729 /* If IRP list if empty, it's OK */
1730 if (IsListEmpty(&(DeviceExtension
->IrpListHead
)))
1732 IoReleaseCancelSpinLock(OldIrql
);
1734 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1735 Irp
->IoStatus
.Information
= 0;
1736 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1738 return STATUS_SUCCESS
;
1741 /* Otherwise, cancel all the IRPs */
1742 NextEntry
= &(DeviceExtension
->IrpListHead
);
1745 ListIrp
= CONTAINING_RECORD(NextEntry
, IRP
, Tail
.Overlay
.ListEntry
);
1746 if (IoGetCurrentIrpStackLocation(ListIrp
)->FileObject
== FileObject
)
1748 ListIrp
->Cancel
= TRUE
;
1749 ListIrp
->CancelIrql
= OldIrql
;
1750 ListIrp
->CancelRoutine
= NULL
;
1751 MountMgrCancel(DeviceObject
, ListIrp
);
1753 IoAcquireCancelSpinLock(&OldIrql
);
1756 NextEntry
= NextEntry
->Flink
;
1758 while (NextEntry
!= &(DeviceExtension
->IrpListHead
));
1760 IoReleaseCancelSpinLock(OldIrql
);
1762 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1763 Irp
->IoStatus
.Information
= 0;
1764 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1766 return STATUS_SUCCESS
;
1774 MountMgrShutdown(IN PDEVICE_OBJECT DeviceObject
,
1777 PDEVICE_EXTENSION DeviceExtension
;
1779 DeviceExtension
= DeviceObject
->DeviceExtension
;
1781 InterlockedExchange(&Unloading
, TRUE
);
1783 KeInitializeEvent(&UnloadEvent
, NotificationEvent
, FALSE
);
1785 /* Wait for workers */
1786 if (InterlockedIncrement(&(DeviceExtension
->WorkerReferences
)))
1788 KeReleaseSemaphore(&(DeviceExtension
->WorkerSemaphore
),
1792 KeWaitForSingleObject(&UnloadEvent
, Executive
, KernelMode
, FALSE
, NULL
);
1796 InterlockedDecrement(&(DeviceExtension
->WorkerReferences
));
1799 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1800 Irp
->IoStatus
.Information
= 0;
1801 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1803 return STATUS_SUCCESS
;
1806 /* FUNCTIONS ****************************************************************/
1810 DriverEntry(IN PDRIVER_OBJECT DriverObject
,
1811 IN PUNICODE_STRING RegistryPath
)
1814 PDEVICE_OBJECT DeviceObject
;
1815 PDEVICE_EXTENSION DeviceExtension
;
1817 RtlCreateRegistryKey(RTL_REGISTRY_ABSOLUTE
, DatabasePath
);
1819 Status
= IoCreateDevice(DriverObject
,
1820 sizeof(DEVICE_EXTENSION
),
1822 FILE_DEVICE_NETWORK
,
1823 FILE_DEVICE_SECURE_OPEN
,
1826 if (!NT_SUCCESS(Status
))
1831 DriverObject
->DriverUnload
= MountMgrUnload
;
1833 DeviceExtension
= DeviceObject
->DeviceExtension
;
1834 RtlZeroMemory(DeviceExtension
, sizeof(DEVICE_EXTENSION
));
1835 DeviceExtension
->DeviceObject
= DeviceObject
;
1836 DeviceExtension
->DriverObject
= DriverObject
;
1838 InitializeListHead(&(DeviceExtension
->DeviceListHead
));
1839 InitializeListHead(&(DeviceExtension
->OfflineDeviceListHead
));
1841 KeInitializeSemaphore(&(DeviceExtension
->DeviceLock
), 1, 1);
1842 KeInitializeSemaphore(&(DeviceExtension
->RemoteDatabaseLock
), 1, 1);
1844 InitializeListHead(&(DeviceExtension
->IrpListHead
));
1845 DeviceExtension
->EpicNumber
= 1;
1847 InitializeListHead(&(DeviceExtension
->SavedLinksListHead
));
1849 InitializeListHead(&(DeviceExtension
->WorkerQueueListHead
));
1850 KeInitializeSemaphore(&(DeviceExtension
->WorkerSemaphore
), 0, MAXLONG
);
1851 DeviceExtension
->WorkerReferences
= -1;
1852 KeInitializeSpinLock(&(DeviceExtension
->WorkerLock
));
1854 InitializeListHead(&(DeviceExtension
->UniqueIdWorkerItemListHead
));
1855 InitializeListHead(&(DeviceExtension
->OnlineNotificationListHead
));
1856 DeviceExtension
->OnlineNotificationCount
= 1;
1858 DeviceExtension
->RegistryPath
.Length
= RegistryPath
->Length
;
1859 DeviceExtension
->RegistryPath
.MaximumLength
= RegistryPath
->Length
+ sizeof(WCHAR
);
1860 DeviceExtension
->RegistryPath
.Buffer
= AllocatePool(DeviceExtension
->RegistryPath
.MaximumLength
);
1861 if (!DeviceExtension
->RegistryPath
.Buffer
)
1863 IoDeleteDevice(DeviceObject
);
1864 return STATUS_INSUFFICIENT_RESOURCES
;
1867 RtlCopyUnicodeString(&(DeviceExtension
->RegistryPath
), RegistryPath
);
1869 DeviceExtension
->NoAutoMount
= MountmgrReadNoAutoMount(&(DeviceExtension
->RegistryPath
));
1871 GlobalCreateSymbolicLink(&DosDevicesMount
, &DeviceMount
);
1873 /* Register for device arrival & removal. Ask to be notified for already
1876 Status
= IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange
,
1877 PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES
,
1878 &MountedDevicesGuid
,
1880 MountMgrMountedDeviceNotification
,
1882 &(DeviceExtension
->NotificationEntry
));
1884 if (!NT_SUCCESS(Status
))
1886 IoDeleteDevice(DeviceObject
);
1890 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] =
1891 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = MountMgrCreateClose
;
1892 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = MountMgrDeviceControl
;
1893 DriverObject
->MajorFunction
[IRP_MJ_CLEANUP
] = MountMgrCleanup
;
1894 DriverObject
->MajorFunction
[IRP_MJ_SHUTDOWN
] = MountMgrShutdown
;
1896 gdeviceObject
= DeviceObject
;
1898 Status
= IoRegisterShutdownNotification(DeviceObject
);
1899 if (!NT_SUCCESS(Status
))
1901 IoDeleteDevice(DeviceObject
);