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
)
219 PMOUNTDEV_UNIQUE_ID Id
;
220 PFILE_OBJECT FileObject
;
221 PIO_STACK_LOCATION Stack
;
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 /* Here we can't fail and assume default value */
474 if (!NT_SUCCESS(Status
))
477 ObDereferenceObject(DeviceObject
);
478 ObDereferenceObject(FileObject
);
482 /* Copy back found name to the caller */
483 DeviceName
->Length
= Name
->NameLength
;
484 DeviceName
->MaximumLength
= Name
->NameLength
+ sizeof(WCHAR
);
485 DeviceName
->Buffer
= AllocatePool(DeviceName
->MaximumLength
);
486 if (!DeviceName
->Buffer
)
489 ObDereferenceObject(DeviceObject
);
490 ObDereferenceObject(FileObject
);
491 return STATUS_INSUFFICIENT_RESOURCES
;
494 RtlCopyMemory(DeviceName
->Buffer
, Name
->Name
, Name
->NameLength
);
495 DeviceName
->Buffer
[Name
->NameLength
/ sizeof(WCHAR
)] = UNICODE_NULL
;
499 /* If caller wants device unique ID */
502 /* Prepare buffer to probe length */
503 Id
= AllocatePool(sizeof(MOUNTDEV_UNIQUE_ID
));
506 ObDereferenceObject(DeviceObject
);
507 ObDereferenceObject(FileObject
);
508 return STATUS_INSUFFICIENT_RESOURCES
;
511 /* Query unique ID length */
512 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
513 Irp
= IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_UNIQUE_ID
,
518 sizeof(MOUNTDEV_UNIQUE_ID
),
525 ObDereferenceObject(DeviceObject
);
526 ObDereferenceObject(FileObject
);
527 return STATUS_INSUFFICIENT_RESOURCES
;
530 Stack
= IoGetNextIrpStackLocation(Irp
);
531 Stack
->FileObject
= FileObject
;
533 Status
= IoCallDriver(DeviceObject
, Irp
);
534 if (Status
== STATUS_PENDING
)
536 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
537 Status
= IoStatusBlock
.Status
;
540 /* Retry with appropriate length */
541 if (Status
== STATUS_BUFFER_OVERFLOW
)
543 Size
= Id
->UniqueIdLength
+ sizeof(MOUNTDEV_UNIQUE_ID
);
547 /* Allocate the correct buffer */
548 Id
= AllocatePool(Size
);
551 ObDereferenceObject(DeviceObject
);
552 ObDereferenceObject(FileObject
);
553 return STATUS_INSUFFICIENT_RESOURCES
;
556 /* Query unique ID */
557 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
558 Irp
= IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_UNIQUE_ID
,
570 ObDereferenceObject(DeviceObject
);
571 ObDereferenceObject(FileObject
);
572 return STATUS_INSUFFICIENT_RESOURCES
;
575 Stack
= IoGetNextIrpStackLocation(Irp
);
576 Stack
->FileObject
= FileObject
;
578 Status
= IoCallDriver(DeviceObject
, Irp
);
579 if (Status
== STATUS_PENDING
)
581 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
582 Status
= IoStatusBlock
.Status
;
586 /* Hands back unique ID */
587 if (NT_SUCCESS(Status
))
593 /* In case of failure, also free the rest */
595 if (DeviceName
->Length
)
597 FreePool(DeviceName
->Buffer
);
600 ObDereferenceObject(DeviceObject
);
601 ObDereferenceObject(FileObject
);
607 /* If user wants to know about GUID */
610 /* Query device stable GUID */
611 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
612 Irp
= IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_STABLE_GUID
,
623 ObDereferenceObject(DeviceObject
);
624 ObDereferenceObject(FileObject
);
625 return STATUS_INSUFFICIENT_RESOURCES
;
628 Stack
= IoGetNextIrpStackLocation(Irp
);
629 Stack
->FileObject
= FileObject
;
631 Status
= IoCallDriver(DeviceObject
, Irp
);
632 if (Status
== STATUS_PENDING
)
634 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
635 Status
= IoStatusBlock
.Status
;
638 *HasGuid
= NT_SUCCESS(Status
);
641 ObDereferenceObject(DeviceObject
);
642 ObDereferenceObject(FileObject
);
650 FindDeviceInfo(IN PDEVICE_EXTENSION DeviceExtension
,
651 IN PUNICODE_STRING SymbolicName
,
652 IN BOOLEAN DeviceNameGiven
,
653 OUT PDEVICE_INFORMATION
* DeviceInformation
)
656 PLIST_ENTRY NextEntry
;
657 UNICODE_STRING DeviceName
;
658 PDEVICE_INFORMATION DeviceInfo
= NULL
;
660 /* If a device name was given, use it */
663 DeviceName
.Length
= SymbolicName
->Length
;
664 DeviceName
.Buffer
= SymbolicName
->Buffer
;
668 /* Otherwise, query it */
669 Status
= QueryDeviceInformation(SymbolicName
,
674 if (!NT_SUCCESS(Status
))
680 /* Look for device information matching devive */
681 for (NextEntry
= DeviceExtension
->DeviceListHead
.Flink
;
682 NextEntry
!= &(DeviceExtension
->DeviceListHead
);
683 NextEntry
= NextEntry
->Flink
)
685 DeviceInfo
= CONTAINING_RECORD(NextEntry
,
689 if (RtlEqualUnicodeString(&DeviceName
, &(DeviceInfo
->DeviceName
), TRUE
))
695 /* Release our buffer if required */
696 if (!DeviceNameGiven
)
698 FreePool(DeviceName
.Buffer
);
701 /* Return found information */
702 if (NextEntry
== &(DeviceExtension
->DeviceListHead
))
704 return STATUS_OBJECT_NAME_NOT_FOUND
;
707 *DeviceInformation
= DeviceInfo
;
708 return STATUS_SUCCESS
;
715 MountMgrFreeDeadDeviceInfo(IN PDEVICE_INFORMATION DeviceInformation
)
717 FreePool(DeviceInformation
->SymbolicName
.Buffer
);
718 FreePool(DeviceInformation
);
725 MountMgrFreeMountedDeviceInfo(IN PDEVICE_INFORMATION DeviceInformation
)
727 PLIST_ENTRY NextEntry
;
728 PSYMLINK_INFORMATION SymLink
;
729 PUNIQUE_ID_REPLICATE UniqueId
;
730 PASSOCIATED_DEVICE_ENTRY AssociatedDevice
;
732 /* Purge symbolic links list */
733 while (!IsListEmpty(&(DeviceInformation
->SymbolicLinksListHead
)))
735 NextEntry
= RemoveHeadList(&(DeviceInformation
->SymbolicLinksListHead
));
736 SymLink
= CONTAINING_RECORD(NextEntry
, SYMLINK_INFORMATION
, SymbolicLinksListEntry
);
738 GlobalDeleteSymbolicLink(&(SymLink
->Name
));
739 FreePool(SymLink
->Name
.Buffer
);
742 /* Purge replicated unique IDs list */
743 while (!IsListEmpty(&(DeviceInformation
->ReplicatedUniqueIdsListHead
)))
745 NextEntry
= RemoveHeadList(&(DeviceInformation
->ReplicatedUniqueIdsListHead
));
746 UniqueId
= CONTAINING_RECORD(NextEntry
, UNIQUE_ID_REPLICATE
, ReplicatedUniqueIdsListEntry
);
748 FreePool(UniqueId
->UniqueId
);
752 while (!IsListEmpty(&(DeviceInformation
->AssociatedDevicesHead
)))
754 NextEntry
= RemoveHeadList(&(DeviceInformation
->AssociatedDevicesHead
));
755 AssociatedDevice
= CONTAINING_RECORD(NextEntry
, ASSOCIATED_DEVICE_ENTRY
, AssociatedDevicesEntry
);
757 FreePool(AssociatedDevice
->String
.Buffer
);
758 FreePool(AssociatedDevice
);
761 /* Free the rest of the buffers */
762 FreePool(DeviceInformation
->SymbolicName
.Buffer
);
763 if (DeviceInformation
->KeepLinks
)
765 FreePool(DeviceInformation
->UniqueId
);
767 FreePool(DeviceInformation
->DeviceName
.Buffer
);
769 /* Finally, stop waiting for notifications for this device */
770 if (DeviceInformation
->TargetDeviceNotificationEntry
)
772 IoUnregisterPlugPlayNotification(DeviceInformation
->TargetDeviceNotificationEntry
);
780 MountMgrFreeSavedLink(IN PSAVED_LINK_INFORMATION SavedLinkInformation
)
782 PLIST_ENTRY NextEntry
;
783 PSYMLINK_INFORMATION SymlinkInformation
;
785 /* For all the saved links */
786 while (!IsListEmpty(&(SavedLinkInformation
->SymbolicLinksListHead
)))
788 NextEntry
= RemoveHeadList(&(SavedLinkInformation
->SymbolicLinksListHead
));
789 SymlinkInformation
= CONTAINING_RECORD(NextEntry
, SYMLINK_INFORMATION
, SymbolicLinksListEntry
);
791 /* Remove from system & free */
792 GlobalDeleteSymbolicLink(&(SymlinkInformation
->Name
));
793 FreePool(SymlinkInformation
->Name
.Buffer
);
794 FreePool(SymlinkInformation
);
797 /* And free unique ID & entry */
798 FreePool(SavedLinkInformation
->UniqueId
);
799 FreePool(SavedLinkInformation
);
808 MountMgrUnload(IN
struct _DRIVER_OBJECT
*DriverObject
)
810 PLIST_ENTRY NextEntry
;
811 PUNIQUE_ID_WORK_ITEM WorkItem
;
812 PDEVICE_EXTENSION DeviceExtension
;
813 PDEVICE_INFORMATION DeviceInformation
;
814 PSAVED_LINK_INFORMATION SavedLinkInformation
;
816 UNREFERENCED_PARAMETER(DriverObject
);
818 /* Don't get notification any longer */
819 IoUnregisterShutdownNotification(gdeviceObject
);
821 /* Free registry buffer */
822 DeviceExtension
= gdeviceObject
->DeviceExtension
;
823 if (DeviceExtension
->RegistryPath
.Buffer
)
825 FreePool(DeviceExtension
->RegistryPath
.Buffer
);
826 DeviceExtension
->RegistryPath
.Buffer
= NULL
;
829 InterlockedExchange(&Unloading
, TRUE
);
831 KeInitializeEvent(&UnloadEvent
, NotificationEvent
, FALSE
);
833 /* Wait for workers to finish */
834 if (InterlockedIncrement(&DeviceExtension
->WorkerReferences
))
836 KeReleaseSemaphore(&(DeviceExtension
->WorkerSemaphore
),
837 IO_NO_INCREMENT
, 1, FALSE
);
839 KeWaitForSingleObject(&UnloadEvent
, Executive
, KernelMode
, FALSE
, NULL
);
843 InterlockedDecrement(&(DeviceExtension
->WorkerReferences
));
846 /* Don't get any notification any longer² */
847 IoUnregisterPlugPlayNotification(DeviceExtension
->NotificationEntry
);
849 /* Acquire the driver exclusively */
850 KeWaitForSingleObject(&(DeviceExtension
->DeviceLock
), Executive
, KernelMode
,
853 /* Clear offline devices list */
854 while (!IsListEmpty(&(DeviceExtension
->OfflineDeviceListHead
)))
856 NextEntry
= RemoveHeadList(&(DeviceExtension
->OfflineDeviceListHead
));
857 DeviceInformation
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
858 MountMgrFreeDeadDeviceInfo(DeviceInformation
);
861 /* Clear saved links list */
862 while (!IsListEmpty(&(DeviceExtension
->SavedLinksListHead
)))
864 NextEntry
= RemoveHeadList(&(DeviceExtension
->SavedLinksListHead
));
865 SavedLinkInformation
= CONTAINING_RECORD(NextEntry
, SAVED_LINK_INFORMATION
, SavedLinksListEntry
);
866 MountMgrFreeSavedLink(SavedLinkInformation
);
869 /* Clear workers list */
870 while (!IsListEmpty(&(DeviceExtension
->UniqueIdWorkerItemListHead
)))
872 NextEntry
= RemoveHeadList(&(DeviceExtension
->UniqueIdWorkerItemListHead
));
873 WorkItem
= CONTAINING_RECORD(NextEntry
, UNIQUE_ID_WORK_ITEM
, UniqueIdWorkerItemListEntry
);
875 KeClearEvent(&UnloadEvent
);
876 WorkItem
->Event
= &UnloadEvent
;
878 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
,
881 IoCancelIrp(WorkItem
->Irp
);
882 KeWaitForSingleObject(&UnloadEvent
, Executive
, KernelMode
, FALSE
, NULL
);
884 IoFreeIrp(WorkItem
->Irp
);
885 FreePool(WorkItem
->DeviceName
.Buffer
);
886 FreePool(WorkItem
->IrpBuffer
);
889 KeWaitForSingleObject(&(DeviceExtension
->DeviceLock
), Executive
, KernelMode
,
893 /* If we have drive letter data, release */
894 if (DeviceExtension
->DriveLetterData
)
896 FreePool(DeviceExtension
->DriveLetterData
);
897 DeviceExtension
->DriveLetterData
= NULL
;
900 /* Release driver & quit */
901 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
, 1, FALSE
);
903 GlobalDeleteSymbolicLink(&DosDevicesMount
);
904 IoDeleteDevice(gdeviceObject
);
912 MountmgrReadNoAutoMount(IN PUNICODE_STRING RegistryPath
)
915 ULONG Result
, Default
= 0;
916 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
918 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
920 /* Simply read data from register */
921 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
922 QueryTable
[0].Name
= L
"NoAutoMount";
923 QueryTable
[0].EntryContext
= &Result
;
924 QueryTable
[0].DefaultType
= REG_NONE
;
925 QueryTable
[0].DefaultData
= &Default
;
926 QueryTable
[0].DefaultLength
= sizeof(ULONG
);
928 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
929 RegistryPath
->Buffer
,
933 if (!NT_SUCCESS(Status
))
935 return (Default
!= 0);
938 return (Result
!= 0);
945 MountMgrMountedDeviceArrival(IN PDEVICE_EXTENSION DeviceExtension
,
946 IN PUNICODE_STRING SymbolicName
,
947 IN BOOLEAN ManuallyRegistered
)
952 ULONG SymLinkCount
, i
;
953 PLIST_ENTRY NextEntry
;
954 PUNICODE_STRING SymLinks
;
955 NTSTATUS Status
, IntStatus
;
956 OBJECT_ATTRIBUTES ObjectAttributes
;
957 PSYMLINK_INFORMATION SymlinkInformation
;
958 PMOUNTDEV_UNIQUE_ID UniqueId
, NewUniqueId
;
959 PSAVED_LINK_INFORMATION SavedLinkInformation
;
960 PDEVICE_INFORMATION DeviceInformation
, CurrentDevice
;
961 WCHAR CSymLinkBuffer
[RTL_NUMBER_OF(Cunc
)], LinkTargetBuffer
[MAX_PATH
];
962 UNICODE_STRING TargetDeviceName
, SuggestedLinkName
, DeviceName
, VolumeName
, DriveLetter
, LinkTarget
, CSymLink
;
963 BOOLEAN HasGuid
, HasGptDriveLetter
, Valid
, UseOnlyIfThereAreNoOtherLinks
, IsDrvLetter
, IsOff
, IsVolumeName
, LinkError
;
965 /* New device = new structure to represent it */
966 DeviceInformation
= AllocatePool(sizeof(DEVICE_INFORMATION
));
967 if (!DeviceInformation
)
969 return STATUS_INSUFFICIENT_RESOURCES
;
972 /* Initialise device structure */
973 RtlZeroMemory(DeviceInformation
, sizeof(DEVICE_INFORMATION
));
974 InitializeListHead(&(DeviceInformation
->SymbolicLinksListHead
));
975 InitializeListHead(&(DeviceInformation
->ReplicatedUniqueIdsListHead
));
976 InitializeListHead(&(DeviceInformation
->AssociatedDevicesHead
));
977 DeviceInformation
->SymbolicName
.Length
= SymbolicName
->Length
;
978 DeviceInformation
->SymbolicName
.MaximumLength
= SymbolicName
->Length
+ sizeof(UNICODE_NULL
);
979 DeviceInformation
->SymbolicName
.Buffer
= AllocatePool(DeviceInformation
->SymbolicName
.MaximumLength
);
980 if (!DeviceInformation
->SymbolicName
.Buffer
)
982 FreePool(DeviceInformation
);
983 return STATUS_INSUFFICIENT_RESOURCES
;
986 /* Copy symbolic name */
987 RtlCopyMemory(DeviceInformation
->SymbolicName
.Buffer
, SymbolicName
->Buffer
, SymbolicName
->Length
);
988 DeviceInformation
->SymbolicName
.Buffer
[DeviceInformation
->SymbolicName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
989 DeviceInformation
->ManuallyRegistered
= ManuallyRegistered
;
990 DeviceInformation
->DeviceExtension
= DeviceExtension
;
992 /* Query as much data as possible about device */
993 Status
= QueryDeviceInformation(SymbolicName
,
996 &(DeviceInformation
->Removable
),
1001 if (!NT_SUCCESS(Status
))
1003 KeWaitForSingleObject(&(DeviceExtension
->DeviceLock
), Executive
, KernelMode
, FALSE
, NULL
);
1005 for (NextEntry
= DeviceExtension
->OfflineDeviceListHead
.Flink
;
1006 NextEntry
!= &(DeviceExtension
->OfflineDeviceListHead
);
1007 NextEntry
= NextEntry
->Flink
)
1009 CurrentDevice
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
1011 if (RtlEqualUnicodeString(&(DeviceInformation
->SymbolicName
), &(CurrentDevice
->SymbolicName
), TRUE
))
1017 if (NextEntry
!= &(DeviceExtension
->OfflineDeviceListHead
))
1019 MountMgrFreeDeadDeviceInfo(DeviceInformation
);
1023 InsertTailList(&(DeviceExtension
->OfflineDeviceListHead
), &(DeviceInformation
->DeviceListEntry
));
1026 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
, 1, FALSE
);
1031 /* Save gathered data */
1032 DeviceInformation
->UniqueId
= UniqueId
;
1033 DeviceInformation
->DeviceName
= TargetDeviceName
;
1034 DeviceInformation
->KeepLinks
= FALSE
;
1036 /* If we found system partition, mark it */
1037 if (DeviceExtension
->DriveLetterData
&& UniqueId
->UniqueIdLength
== DeviceExtension
->DriveLetterData
->UniqueIdLength
)
1039 if (RtlCompareMemory(UniqueId
->UniqueId
, DeviceExtension
->DriveLetterData
->UniqueId
, UniqueId
->UniqueIdLength
)
1040 == UniqueId
->UniqueIdLength
)
1042 IoSetSystemPartition(&TargetDeviceName
);
1046 /* Check suggested link name */
1047 Status
= QuerySuggestedLinkName(&(DeviceInformation
->SymbolicName
),
1049 &UseOnlyIfThereAreNoOtherLinks
);
1050 if (!NT_SUCCESS(Status
))
1052 SuggestedLinkName
.Buffer
= NULL
;
1055 /* If it's OK, set it and save its letter (if any) */
1056 if (SuggestedLinkName
.Buffer
&& IsDriveLetter(&SuggestedLinkName
))
1058 DeviceInformation
->SuggestedDriveLetter
= (UCHAR
)SuggestedLinkName
.Buffer
[LETTER_POSITION
];
1061 /* Acquire driver exclusively */
1062 KeWaitForSingleObject(&(DeviceExtension
->DeviceLock
), Executive
, KernelMode
, FALSE
, NULL
);
1064 /* Check if we already have device in to prevent double registration */
1065 for (NextEntry
= DeviceExtension
->DeviceListHead
.Flink
;
1066 NextEntry
!= &(DeviceExtension
->DeviceListHead
);
1067 NextEntry
= NextEntry
->Flink
)
1069 CurrentDevice
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
1071 if (RtlEqualUnicodeString(&(CurrentDevice
->DeviceName
), &TargetDeviceName
, TRUE
))
1077 /* If we found it, clear ours, and return success, all correct */
1078 if (NextEntry
!= &(DeviceExtension
->DeviceListHead
))
1080 if (SuggestedLinkName
.Buffer
)
1082 FreePool(SuggestedLinkName
.Buffer
);
1086 FreePool(TargetDeviceName
.Buffer
);
1087 FreePool(DeviceInformation
->DeviceName
.Buffer
);
1088 FreePool(DeviceInformation
);
1090 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
, 1, FALSE
);
1092 return STATUS_SUCCESS
;
1095 /* Check if there are symlinks associated with our device in registry */
1096 Status
= QuerySymbolicLinkNamesFromStorage(DeviceExtension
,
1098 (SuggestedLinkName
.Buffer
) ? &SuggestedLinkName
: NULL
,
1099 UseOnlyIfThereAreNoOtherLinks
,
1105 /* If our device is a CD-ROM */
1106 if (RtlPrefixUnicodeString(&DeviceCdRom
, &TargetDeviceName
, TRUE
))
1108 LinkTarget
.Length
= 0;
1109 LinkTarget
.MaximumLength
= sizeof(LinkTargetBuffer
);
1110 LinkTarget
.Buffer
= LinkTargetBuffer
;
1112 RtlCopyMemory(CSymLinkBuffer
, Cunc
, sizeof(Cunc
));
1113 RtlInitUnicodeString(&CSymLink
, CSymLinkBuffer
);
1115 /* Start checking all letters that could have been associated */
1116 for (Letter
= L
'D'; Letter
<= L
'Z'; Letter
++)
1118 CSymLink
.Buffer
[LETTER_POSITION
] = Letter
;
1120 InitializeObjectAttributes(&ObjectAttributes
,
1122 OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
,
1126 /* Try to open the associated symlink */
1127 Status
= ZwOpenSymbolicLinkObject(&LinkHandle
, SYMBOLIC_LINK_QUERY
, &ObjectAttributes
);
1128 if (!NT_SUCCESS(Status
))
1133 /* And query its target */
1134 Status
= ZwQuerySymbolicLinkObject(LinkHandle
, &LinkTarget
, NULL
);
1135 ZwClose(LinkHandle
);
1137 if (!NT_SUCCESS(Status
))
1142 IntStatus
= STATUS_UNSUCCESSFUL
;
1143 if (!RtlEqualUnicodeString(&LinkTarget
, &DeviceInformation
->DeviceName
, FALSE
))
1148 /* This link is matching our device, whereas it's not supposed to have any
1149 * symlink associated.
1154 IoDeleteSymbolicLink(&CSymLink
);
1158 /* Now, for all the symlinks, check for ours */
1159 for (i
= 0; i
< SymLinkCount
; i
++)
1161 if (IsDriveLetter(&(SymLinks
[i
])))
1163 /* If it exists, that's correct */
1164 if (SymLinks
[i
].Buffer
[LETTER_POSITION
] == Letter
)
1166 IntStatus
= STATUS_SUCCESS
;
1171 /* Useless link, delete it */
1172 if (IntStatus
== STATUS_UNSUCCESSFUL
)
1174 IoDeleteSymbolicLink(&CSymLink
);
1179 /* Suggested name is no longer required */
1180 if (SuggestedLinkName
.Buffer
)
1182 FreePool(SuggestedLinkName
.Buffer
);
1185 /* If if failed, ensure we don't take symlinks into account */
1186 if (!NT_SUCCESS(Status
))
1192 /* Now we queried them, remove the symlinks */
1193 SavedLinkInformation
= RemoveSavedLinks(DeviceExtension
, UniqueId
);
1195 IsDrvLetter
= FALSE
;
1197 IsVolumeName
= FALSE
;
1198 /* For all the symlinks */
1199 for (i
= 0; i
< SymLinkCount
; i
++)
1201 /* Check if our device is a volume */
1202 if (MOUNTMGR_IS_VOLUME_NAME(&(SymLinks
[i
])))
1204 IsVolumeName
= TRUE
;
1206 /* If it has a drive letter */
1207 else if (IsDriveLetter(&(SymLinks
[i
])))
1211 DeleteFromLocalDatabase(&(SymLinks
[i
]), UniqueId
);
1220 /* And recreate the symlink to our device */
1221 Status
= GlobalCreateSymbolicLink(&(SymLinks
[i
]), &TargetDeviceName
);
1222 if (!NT_SUCCESS(Status
))
1226 if ((SavedLinkInformation
&& !RedirectSavedLink(SavedLinkInformation
, &(SymLinks
[i
]), &TargetDeviceName
)) ||
1227 !SavedLinkInformation
)
1229 Status
= QueryDeviceInformation(&(SymLinks
[i
]), &DeviceName
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
1230 if (NT_SUCCESS(Status
))
1232 LinkError
= RtlEqualUnicodeString(&TargetDeviceName
, &DeviceName
, TRUE
);
1233 FreePool(DeviceName
.Buffer
);
1238 if (IsDriveLetter(&(SymLinks
[i
])))
1240 IsDrvLetter
= FALSE
;
1241 DeleteFromLocalDatabase(&(SymLinks
[i
]), UniqueId
);
1244 FreePool(SymLinks
[i
].Buffer
);
1250 /* Check if was offline */
1251 if (IsOffline(&(SymLinks
[i
])))
1256 /* Finally, associate this symlink with the device */
1257 SymlinkInformation
= AllocatePool(sizeof(SYMLINK_INFORMATION
));
1258 if (!SymlinkInformation
)
1260 GlobalDeleteSymbolicLink(&(SymLinks
[i
]));
1261 FreePool(SymLinks
[i
].Buffer
);
1265 SymlinkInformation
->Name
= SymLinks
[i
];
1266 SymlinkInformation
->Online
= TRUE
;
1268 InsertTailList(&(DeviceInformation
->SymbolicLinksListHead
),
1269 &(SymlinkInformation
->SymbolicLinksListEntry
));
1272 /* Now, for all the recreated symlinks, notify their recreation */
1273 for (NextEntry
= DeviceInformation
->SymbolicLinksListHead
.Flink
;
1274 NextEntry
!= &(DeviceInformation
->SymbolicLinksListHead
);
1275 NextEntry
= NextEntry
->Flink
)
1277 SymlinkInformation
= CONTAINING_RECORD(NextEntry
, SYMLINK_INFORMATION
, SymbolicLinksListEntry
);
1279 SendLinkCreated(&(SymlinkInformation
->Name
));
1282 /* If we had saved links, it's time to free them */
1283 if (SavedLinkInformation
)
1285 MountMgrFreeSavedLink(SavedLinkInformation
);
1288 /* If our device doesn't have a volume name */
1291 /* It's time to create one */
1292 Status
= CreateNewVolumeName(&VolumeName
, NULL
);
1293 if (NT_SUCCESS(Status
))
1295 /* Write it to global database */
1296 RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE
,
1301 UniqueId
->UniqueIdLength
);
1303 /* And create the symlink */
1304 GlobalCreateSymbolicLink(&VolumeName
, &TargetDeviceName
);
1306 SymlinkInformation
= AllocatePool(sizeof(SYMLINK_INFORMATION
));
1307 if (!SymlinkInformation
)
1309 FreePool(VolumeName
.Buffer
);
1311 /* Finally, associate it with the device and notify creation */
1314 SymlinkInformation
->Name
= VolumeName
;
1315 SymlinkInformation
->Online
= TRUE
;
1316 InsertTailList(&(DeviceInformation
->SymbolicLinksListHead
),
1317 &(SymlinkInformation
->SymbolicLinksListEntry
));
1319 SendLinkCreated(&VolumeName
);
1324 /* If we found a drive letter, then, ignore the suggested one */
1327 DeviceInformation
->SuggestedDriveLetter
= 0;
1329 /* Else, it's time to set up one */
1330 else if ((DeviceExtension
->NoAutoMount
|| DeviceInformation
->Removable
) &&
1331 DeviceExtension
->AutomaticDriveLetter
&&
1332 (HasGptDriveLetter
|| DeviceInformation
->SuggestedDriveLetter
) &&
1333 !HasNoDriveLetterEntry(UniqueId
))
1335 /* Create a new drive letter */
1336 Status
= CreateNewDriveLetterName(&DriveLetter
, &TargetDeviceName
,
1337 DeviceInformation
->SuggestedDriveLetter
,
1339 if (!NT_SUCCESS(Status
))
1341 CreateNoDriveLetterEntry(UniqueId
);
1345 /* Save it to global database */
1346 RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE
,
1351 UniqueId
->UniqueIdLength
);
1353 /* Associate it with the device and notify creation */
1354 SymlinkInformation
= AllocatePool(sizeof(SYMLINK_INFORMATION
));
1355 if (!SymlinkInformation
)
1357 FreePool(DriveLetter
.Buffer
);
1361 SymlinkInformation
->Name
= DriveLetter
;
1362 SymlinkInformation
->Online
= TRUE
;
1363 InsertTailList(&(DeviceInformation
->SymbolicLinksListHead
),
1364 &(SymlinkInformation
->SymbolicLinksListEntry
));
1366 SendLinkCreated(&DriveLetter
);
1371 /* If that's a PnP device, register for notifications */
1372 if (!ManuallyRegistered
)
1374 RegisterForTargetDeviceNotification(DeviceExtension
, DeviceInformation
);
1377 /* Finally, insert the device into our devices list */
1378 InsertTailList(&(DeviceExtension
->DeviceListHead
), &(DeviceInformation
->DeviceListEntry
));
1380 /* Copy device unique ID */
1381 NewUniqueId
= AllocatePool(UniqueId
->UniqueIdLength
+ sizeof(MOUNTDEV_UNIQUE_ID
));
1384 NewUniqueId
->UniqueIdLength
= UniqueId
->UniqueIdLength
;
1385 RtlCopyMemory(NewUniqueId
->UniqueId
, UniqueId
->UniqueId
, UniqueId
->UniqueIdLength
);
1388 /* If device's offline or valid, skip its notifications */
1391 DeviceInformation
->SkipNotifications
= TRUE
;
1394 /* In case device is valid and is set to no automount,
1397 if (DeviceExtension
->NoAutoMount
|| IsDrvLetter
)
1399 IsOff
= !DeviceInformation
->SkipNotifications
;
1406 /* Finally, release the exclusive lock */
1407 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
, 1, FALSE
);
1409 /* If device is not offline, notify its arrival */
1412 SendOnlineNotification(SymbolicName
);
1415 /* If we had symlinks (from storage), free them */
1421 /* Notify about unique id change */
1424 IssueUniqueIdChangeNotify(DeviceExtension
, SymbolicName
, NewUniqueId
);
1425 FreePool(NewUniqueId
);
1428 /* If this drive was set to have a drive letter automatically
1429 * Now it's back, local databases sync will be required
1431 if (DeviceExtension
->AutomaticDriveLetter
)
1433 KeWaitForSingleObject(&(DeviceExtension
->DeviceLock
), Executive
, KernelMode
, FALSE
, NULL
);
1435 ReconcileThisDatabaseWithMaster(DeviceExtension
, DeviceInformation
);
1437 NextEntry
= DeviceExtension
->DeviceListHead
.Flink
;
1438 CurrentDevice
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
1439 while (CurrentDevice
!= DeviceInformation
)
1441 if (!CurrentDevice
->NoDatabase
)
1443 ReconcileThisDatabaseWithMaster(DeviceExtension
, CurrentDevice
);
1446 NextEntry
= NextEntry
->Flink
;
1447 CurrentDevice
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
1450 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
, 1, FALSE
);
1453 return STATUS_SUCCESS
;
1460 MountMgrMountedDeviceRemoval(IN PDEVICE_EXTENSION DeviceExtension
,
1461 IN PUNICODE_STRING DeviceName
)
1463 PLIST_ENTRY NextEntry
, DeviceEntry
;
1464 PUNIQUE_ID_REPLICATE UniqueIdReplicate
;
1465 PSYMLINK_INFORMATION SymlinkInformation
;
1466 PASSOCIATED_DEVICE_ENTRY AssociatedDevice
;
1467 PSAVED_LINK_INFORMATION SavedLinkInformation
= NULL
;
1468 PDEVICE_INFORMATION DeviceInformation
, CurrentDevice
;
1470 /* Acquire device exclusively */
1471 KeWaitForSingleObject(&(DeviceExtension
->DeviceLock
), Executive
, KernelMode
, FALSE
, NULL
);
1473 /* Look for the leaving device */
1474 for (NextEntry
= DeviceExtension
->DeviceListHead
.Flink
;
1475 NextEntry
!= &(DeviceExtension
->DeviceListHead
);
1476 NextEntry
= NextEntry
->Flink
)
1478 DeviceInformation
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
1480 if (!RtlCompareUnicodeString(&(DeviceInformation
->SymbolicName
), DeviceName
, TRUE
))
1486 /* If we found it */
1487 if (NextEntry
!= &(DeviceExtension
->DeviceListHead
))
1489 /* If it's asked to keep links, then, prepare to save them */
1490 if (DeviceInformation
->KeepLinks
)
1492 SavedLinkInformation
= AllocatePool(sizeof(SAVED_LINK_INFORMATION
));
1493 if (!SavedLinkInformation
)
1495 DeviceInformation
->KeepLinks
= FALSE
;
1499 /* If it's possible (and asked), start to save them */
1500 if (DeviceInformation
->KeepLinks
)
1502 InsertTailList(&(DeviceExtension
->SavedLinksListHead
), &(SavedLinkInformation
->SavedLinksListEntry
));
1503 InitializeListHead(&(SavedLinkInformation
->SymbolicLinksListHead
));
1504 SavedLinkInformation
->UniqueId
= DeviceInformation
->UniqueId
;
1507 /* For all the symlinks */
1508 while (!IsListEmpty(&(DeviceInformation
->SymbolicLinksListHead
)))
1510 NextEntry
= RemoveHeadList(&(DeviceInformation
->SymbolicLinksListHead
));
1511 SymlinkInformation
= CONTAINING_RECORD(NextEntry
, SYMLINK_INFORMATION
, SymbolicLinksListEntry
);
1513 /* If we have to, save the link */
1514 if (DeviceInformation
->KeepLinks
)
1516 InsertTailList(&(SavedLinkInformation
->SymbolicLinksListHead
), &(SymlinkInformation
->SymbolicLinksListEntry
));
1518 /* Otherwise, just release it */
1521 GlobalDeleteSymbolicLink(&(SymlinkInformation
->Name
));
1522 FreePool(SymlinkInformation
->Name
.Buffer
);
1523 FreePool(SymlinkInformation
);
1527 /* Free all the replicated unique IDs */
1528 while (!IsListEmpty(&(DeviceInformation
->ReplicatedUniqueIdsListHead
)))
1530 NextEntry
= RemoveHeadList(&(DeviceInformation
->ReplicatedUniqueIdsListHead
));
1531 UniqueIdReplicate
= CONTAINING_RECORD(NextEntry
, UNIQUE_ID_REPLICATE
, ReplicatedUniqueIdsListEntry
);
1534 FreePool(UniqueIdReplicate
->UniqueId
);
1535 FreePool(UniqueIdReplicate
);
1538 while (!IsListEmpty(&(DeviceInformation
->AssociatedDevicesHead
)))
1540 NextEntry
= RemoveHeadList(&(DeviceInformation
->AssociatedDevicesHead
));
1541 AssociatedDevice
= CONTAINING_RECORD(NextEntry
, ASSOCIATED_DEVICE_ENTRY
, AssociatedDevicesEntry
);
1543 DeviceInformation
->NoDatabase
= TRUE
;
1544 FreePool(AssociatedDevice
->String
.Buffer
);
1545 FreePool(AssociatedDevice
);
1548 /* Remove device from the device list */
1549 RemoveEntryList(&(DeviceInformation
->DeviceListEntry
));
1551 /* If there are still devices, check if some were associated with ours */
1552 if (!IsListEmpty(&(DeviceInformation
->DeviceListEntry
)))
1554 for (NextEntry
= DeviceExtension
->DeviceListHead
.Flink
;
1555 NextEntry
!= &(DeviceExtension
->DeviceListHead
);
1556 NextEntry
= NextEntry
->Flink
)
1558 CurrentDevice
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
1560 /* And then, remove them */
1561 DeviceEntry
= CurrentDevice
->AssociatedDevicesHead
.Flink
;
1562 while (DeviceEntry
!= &(CurrentDevice
->AssociatedDevicesHead
))
1564 AssociatedDevice
= CONTAINING_RECORD(NextEntry
, ASSOCIATED_DEVICE_ENTRY
, AssociatedDevicesEntry
);
1565 DeviceEntry
= DeviceEntry
->Flink
;
1567 if (AssociatedDevice
->DeviceInformation
!= DeviceInformation
)
1572 RemoveEntryList(&(AssociatedDevice
->AssociatedDevicesEntry
));
1573 FreePool(AssociatedDevice
->String
.Buffer
);
1574 FreePool(AssociatedDevice
);
1579 /* Finally, clean up device name, symbolic name */
1580 FreePool(DeviceInformation
->SymbolicName
.Buffer
);
1581 if (!DeviceInformation
->KeepLinks
)
1583 FreePool(DeviceInformation
->UniqueId
);
1585 FreePool(DeviceInformation
->DeviceName
.Buffer
);
1587 /* Unregister notifications */
1588 if (DeviceInformation
->TargetDeviceNotificationEntry
)
1590 IoUnregisterPlugPlayNotification(DeviceInformation
->TargetDeviceNotificationEntry
);
1594 FreePool(DeviceInformation
);
1598 /* We didn't find device, perhaps because it was offline */
1599 for (NextEntry
= DeviceExtension
->OfflineDeviceListHead
.Flink
;
1600 NextEntry
!= &(DeviceExtension
->OfflineDeviceListHead
);
1601 NextEntry
= NextEntry
->Flink
)
1603 DeviceInformation
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
1605 /* It was, remove it */
1606 if (RtlCompareUnicodeString(&(DeviceInformation
->SymbolicName
), DeviceName
, TRUE
) == 0)
1608 RemoveEntryList(&(DeviceInformation
->DeviceListEntry
));
1609 MountMgrFreeDeadDeviceInfo(DeviceInformation
);
1615 /* Release driver */
1616 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
, 1, FALSE
);
1624 MountMgrMountedDeviceNotification(IN PVOID NotificationStructure
,
1628 PDEVICE_EXTENSION DeviceExtension
;
1629 PDEVICE_INTERFACE_CHANGE_NOTIFICATION Notification
;
1631 /* Notification for a device arrived */
1632 /* Disable hard errors */
1633 OldState
= PsGetThreadHardErrorsAreDisabled(PsGetCurrentThread());
1634 PsSetThreadHardErrorsAreDisabled(PsGetCurrentThread(), TRUE
);
1636 DeviceExtension
= Context
;
1637 Notification
= NotificationStructure
;
1639 /* Dispatch according to the event */
1640 if (IsEqualGUID(&(Notification
->Event
), &GUID_DEVICE_INTERFACE_ARRIVAL
))
1642 MountMgrMountedDeviceArrival(DeviceExtension
, Notification
->SymbolicLinkName
, FALSE
);
1644 else if (IsEqualGUID(&(Notification
->Event
), &GUID_DEVICE_INTERFACE_REMOVAL
))
1646 MountMgrMountedDeviceRemoval(DeviceExtension
, Notification
->SymbolicLinkName
);
1649 /* Reset hard errors */
1650 PsSetThreadHardErrorsAreDisabled(PsGetCurrentThread(), OldState
);
1652 return STATUS_SUCCESS
;
1660 MountMgrCreateClose(IN PDEVICE_OBJECT DeviceObject
,
1663 PIO_STACK_LOCATION Stack
;
1664 NTSTATUS Status
= STATUS_SUCCESS
;
1666 UNREFERENCED_PARAMETER(DeviceObject
);
1668 Stack
= IoGetCurrentIrpStackLocation(Irp
);
1670 /* Allow driver opening for communication
1671 * as long as it's not taken for a directory
1673 if (Stack
->MajorFunction
== IRP_MJ_CREATE
&&
1674 Stack
->Parameters
.Create
.Options
& FILE_DIRECTORY_FILE
)
1676 Status
= STATUS_NOT_A_DIRECTORY
;
1679 Irp
->IoStatus
.Status
= Status
;
1680 Irp
->IoStatus
.Information
= 0;
1681 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1690 MountMgrCancel(IN PDEVICE_OBJECT DeviceObject
,
1693 UNREFERENCED_PARAMETER(DeviceObject
);
1695 RemoveEntryList(&(Irp
->Tail
.Overlay
.ListEntry
));
1697 IoReleaseCancelSpinLock(Irp
->CancelIrql
);
1699 Irp
->IoStatus
.Information
= 0;
1700 Irp
->IoStatus
.Status
= STATUS_CANCELLED
;
1701 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1709 MountMgrCleanup(IN PDEVICE_OBJECT DeviceObject
,
1714 PLIST_ENTRY NextEntry
;
1715 PFILE_OBJECT FileObject
;
1716 PIO_STACK_LOCATION Stack
;
1717 PDEVICE_EXTENSION DeviceExtension
;
1719 DeviceExtension
= DeviceObject
->DeviceExtension
;
1720 Stack
= IoGetCurrentIrpStackLocation(Irp
);
1721 FileObject
= Stack
->FileObject
;
1723 IoAcquireCancelSpinLock(&OldIrql
);
1725 /* If IRP list if empty, it's OK */
1726 if (IsListEmpty(&(DeviceExtension
->IrpListHead
)))
1728 IoReleaseCancelSpinLock(OldIrql
);
1730 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1731 Irp
->IoStatus
.Information
= 0;
1732 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1734 return STATUS_SUCCESS
;
1737 /* Otherwise, cancel all the IRPs */
1738 NextEntry
= &(DeviceExtension
->IrpListHead
);
1741 ListIrp
= CONTAINING_RECORD(NextEntry
, IRP
, Tail
.Overlay
.ListEntry
);
1742 if (IoGetCurrentIrpStackLocation(ListIrp
)->FileObject
== FileObject
)
1744 ListIrp
->Cancel
= TRUE
;
1745 ListIrp
->CancelIrql
= OldIrql
;
1746 ListIrp
->CancelRoutine
= NULL
;
1747 MountMgrCancel(DeviceObject
, ListIrp
);
1749 IoAcquireCancelSpinLock(&OldIrql
);
1752 NextEntry
= NextEntry
->Flink
;
1754 while (NextEntry
!= &(DeviceExtension
->IrpListHead
));
1756 IoReleaseCancelSpinLock(OldIrql
);
1758 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1759 Irp
->IoStatus
.Information
= 0;
1760 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1762 return STATUS_SUCCESS
;
1770 MountMgrShutdown(IN PDEVICE_OBJECT DeviceObject
,
1773 PDEVICE_EXTENSION DeviceExtension
;
1775 DeviceExtension
= DeviceObject
->DeviceExtension
;
1777 InterlockedExchange(&Unloading
, TRUE
);
1779 KeInitializeEvent(&UnloadEvent
, NotificationEvent
, FALSE
);
1781 /* Wait for workers */
1782 if (InterlockedIncrement(&(DeviceExtension
->WorkerReferences
)))
1784 KeReleaseSemaphore(&(DeviceExtension
->WorkerSemaphore
),
1788 KeWaitForSingleObject(&UnloadEvent
, Executive
, KernelMode
, FALSE
, NULL
);
1792 InterlockedDecrement(&(DeviceExtension
->WorkerReferences
));
1795 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1796 Irp
->IoStatus
.Information
= 0;
1797 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1799 return STATUS_SUCCESS
;
1802 /* FUNCTIONS ****************************************************************/
1807 DriverEntry(IN PDRIVER_OBJECT DriverObject
,
1808 IN PUNICODE_STRING RegistryPath
)
1811 PDEVICE_OBJECT DeviceObject
;
1812 PDEVICE_EXTENSION DeviceExtension
;
1814 RtlCreateRegistryKey(RTL_REGISTRY_ABSOLUTE
, DatabasePath
);
1816 Status
= IoCreateDevice(DriverObject
,
1817 sizeof(DEVICE_EXTENSION
),
1819 FILE_DEVICE_NETWORK
,
1820 FILE_DEVICE_SECURE_OPEN
,
1823 if (!NT_SUCCESS(Status
))
1828 DriverObject
->DriverUnload
= MountMgrUnload
;
1830 DeviceExtension
= DeviceObject
->DeviceExtension
;
1831 RtlZeroMemory(DeviceExtension
, sizeof(DEVICE_EXTENSION
));
1832 DeviceExtension
->DeviceObject
= DeviceObject
;
1833 DeviceExtension
->DriverObject
= DriverObject
;
1835 InitializeListHead(&(DeviceExtension
->DeviceListHead
));
1836 InitializeListHead(&(DeviceExtension
->OfflineDeviceListHead
));
1838 KeInitializeSemaphore(&(DeviceExtension
->DeviceLock
), 1, 1);
1839 KeInitializeSemaphore(&(DeviceExtension
->RemoteDatabaseLock
), 1, 1);
1841 InitializeListHead(&(DeviceExtension
->IrpListHead
));
1842 DeviceExtension
->EpicNumber
= 1;
1844 InitializeListHead(&(DeviceExtension
->SavedLinksListHead
));
1846 InitializeListHead(&(DeviceExtension
->WorkerQueueListHead
));
1847 KeInitializeSemaphore(&(DeviceExtension
->WorkerSemaphore
), 0, MAXLONG
);
1848 DeviceExtension
->WorkerReferences
= -1;
1849 KeInitializeSpinLock(&(DeviceExtension
->WorkerLock
));
1851 InitializeListHead(&(DeviceExtension
->UniqueIdWorkerItemListHead
));
1852 InitializeListHead(&(DeviceExtension
->OnlineNotificationListHead
));
1853 DeviceExtension
->OnlineNotificationCount
= 1;
1855 DeviceExtension
->RegistryPath
.Length
= RegistryPath
->Length
;
1856 DeviceExtension
->RegistryPath
.MaximumLength
= RegistryPath
->Length
+ sizeof(WCHAR
);
1857 DeviceExtension
->RegistryPath
.Buffer
= AllocatePool(DeviceExtension
->RegistryPath
.MaximumLength
);
1858 if (!DeviceExtension
->RegistryPath
.Buffer
)
1860 IoDeleteDevice(DeviceObject
);
1861 return STATUS_INSUFFICIENT_RESOURCES
;
1864 RtlCopyUnicodeString(&(DeviceExtension
->RegistryPath
), RegistryPath
);
1866 DeviceExtension
->NoAutoMount
= MountmgrReadNoAutoMount(&(DeviceExtension
->RegistryPath
));
1868 GlobalCreateSymbolicLink(&DosDevicesMount
, &DeviceMount
);
1870 /* Register for device arrival & removal. Ask to be notified for already
1873 Status
= IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange
,
1874 PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES
,
1875 &MountedDevicesGuid
,
1877 MountMgrMountedDeviceNotification
,
1879 &(DeviceExtension
->NotificationEntry
));
1881 if (!NT_SUCCESS(Status
))
1883 IoDeleteDevice(DeviceObject
);
1887 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] =
1888 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = MountMgrCreateClose
;
1889 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = MountMgrDeviceControl
;
1890 DriverObject
->MajorFunction
[IRP_MJ_CLEANUP
] = MountMgrCleanup
;
1891 DriverObject
->MajorFunction
[IRP_MJ_SHUTDOWN
] = MountMgrShutdown
;
1893 gdeviceObject
= DeviceObject
;
1895 Status
= IoRegisterShutdownNotification(DeviceObject
);
1896 if (!NT_SUCCESS(Status
))
1898 IoDeleteDevice(DeviceObject
);