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:";
48 * - MountMgrQueryDosVolumePaths
49 * - MountMgrQueryVolumePaths
50 * - MountMgrValidateBackPointer
51 * - ReconcileThisDatabaseWithMasterWorker
58 IsOffline(PUNICODE_STRING SymbolicName
)
61 ULONG IsOffline
, Default
;
62 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
64 /* Prepare to look in the registry to see if
65 * given volume is offline
67 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
68 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
69 QueryTable
[0].Name
= SymbolicName
->Buffer
;
70 QueryTable
[0].EntryContext
= &IsOffline
;
71 QueryTable
[0].DefaultType
= REG_DWORD
;
72 QueryTable
[0].DefaultLength
= sizeof(ULONG
);
73 QueryTable
[0].DefaultData
= &Default
;
78 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
83 if (!NT_SUCCESS(Status
))
88 return (IsOffline
!= 0);
95 HasDriveLetter(IN PDEVICE_INFORMATION DeviceInformation
)
97 PLIST_ENTRY NextEntry
;
98 PSYMLINK_INFORMATION SymlinkInfo
;
100 /* To have a drive letter, a device must have symbolic links */
101 if (IsListEmpty(&(DeviceInformation
->SymbolicLinksListHead
)))
106 /* Browse all the links untill a drive letter is found */
107 NextEntry
= &(DeviceInformation
->SymbolicLinksListHead
);
110 SymlinkInfo
= CONTAINING_RECORD(NextEntry
, SYMLINK_INFORMATION
, SymbolicLinksListEntry
);
112 if (SymlinkInfo
->Online
)
114 if (IsDriveLetter(&(SymlinkInfo
->Name
)))
120 NextEntry
= NextEntry
->Flink
;
121 } while (NextEntry
!= &(DeviceInformation
->SymbolicLinksListHead
));
130 CreateNewDriveLetterName(OUT PUNICODE_STRING DriveLetter
,
131 IN PUNICODE_STRING DeviceName
,
133 IN PMOUNTDEV_UNIQUE_ID UniqueId OPTIONAL
)
135 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
137 /* Allocate a big enough buffer to contain the symbolic link */
138 DriveLetter
->MaximumLength
= DosDevices
.Length
+ 3 * sizeof(WCHAR
);
139 DriveLetter
->Buffer
= AllocatePool(DriveLetter
->MaximumLength
);
140 if (!DriveLetter
->Buffer
)
142 return STATUS_INSUFFICIENT_RESOURCES
;
146 RtlCopyUnicodeString(DriveLetter
, &DosDevices
);
148 /* Update string to reflect real contents */
149 DriveLetter
->Length
= DosDevices
.Length
+ 2 * sizeof(WCHAR
);
150 DriveLetter
->Buffer
[DosDevices
.Length
/ sizeof(WCHAR
) + 2] = UNICODE_NULL
;
151 DriveLetter
->Buffer
[DosDevices
.Length
/ sizeof(WCHAR
) + 1] = L
':';
153 /* If caller wants a no drive entry */
154 if (Letter
== (UCHAR
)-1)
156 /* Then, create a no letter entry */
157 CreateNoDriveLetterEntry(UniqueId
);
158 FreePool(DriveLetter
->Buffer
);
159 return STATUS_UNSUCCESSFUL
;
163 /* Use the letter given by the caller */
164 DriveLetter
->Buffer
[DosDevices
.Length
/ sizeof(WCHAR
)] = (WCHAR
)Letter
;
165 Status
= GlobalCreateSymbolicLink(DriveLetter
, DeviceName
);
166 if (NT_SUCCESS(Status
))
172 /* If caller didn't provide a letter, let's find one for him */
174 if (RtlPrefixUnicodeString(&DeviceFloppy
, DeviceName
, TRUE
))
176 /* If the device is a floppy, start with letter A */
179 else if (RtlPrefixUnicodeString(&DeviceCdRom
, DeviceName
, TRUE
))
181 /* If the device is a CD-ROM, start with letter D */
186 /* Finally, if it's a disk, use C */
190 /* Try to affect a letter (up to Z, ofc) until it's possible */
191 for (; Letter
<= 'Z'; Letter
++)
193 DriveLetter
->Buffer
[DosDevices
.Length
/ sizeof(WCHAR
)] = (WCHAR
)Letter
;
194 Status
= GlobalCreateSymbolicLink(DriveLetter
, DeviceName
);
195 if (NT_SUCCESS(Status
))
197 DPRINT("Assigned drive %c: to %wZ\n", Letter
, DeviceName
);
202 /* We failed to allocate a letter */
203 FreePool(DriveLetter
->Buffer
);
204 DPRINT("Failed to create a drive letter for %wZ\n", DeviceName
);
212 QueryDeviceInformation(IN PUNICODE_STRING SymbolicName
,
213 OUT PUNICODE_STRING DeviceName OPTIONAL
,
214 OUT PMOUNTDEV_UNIQUE_ID
* UniqueId OPTIONAL
,
215 OUT PBOOLEAN Removable OPTIONAL
,
216 OUT PBOOLEAN GptDriveLetter OPTIONAL
,
217 OUT PBOOLEAN HasGuid OPTIONAL
,
218 IN OUT LPGUID StableGuid OPTIONAL
,
219 OUT PBOOLEAN Valid OPTIONAL
)
227 PMOUNTDEV_UNIQUE_ID Id
;
228 PFILE_OBJECT FileObject
;
229 PIO_STACK_LOCATION Stack
;
230 PDEVICE_OBJECT DeviceObject
;
231 IO_STATUS_BLOCK IoStatusBlock
;
232 PARTITION_INFORMATION_EX PartitionInfo
;
233 STORAGE_DEVICE_NUMBER StorageDeviceNumber
;
234 VOLUME_GET_GPT_ATTRIBUTES_INFORMATION GptAttributes
;
236 /* Get device associated with the symbolic name */
237 Status
= IoGetDeviceObjectPointer(SymbolicName
,
238 FILE_READ_ATTRIBUTES
,
241 if (!NT_SUCCESS(Status
))
246 /* The associate FO can't have a file name */
247 if (FileObject
->FileName
.Length
)
249 ObDereferenceObject(FileObject
);
250 return STATUS_OBJECT_NAME_NOT_FOUND
;
253 /* Check if it's removable & return to the user (if asked to) */
254 IsRemovable
= (FileObject
->DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
);
257 *Removable
= IsRemovable
;
260 /* Get the attached device */
261 DeviceObject
= IoGetAttachedDeviceReference(FileObject
->DeviceObject
);
263 /* If we've been asked for a GPT drive letter */
266 /* Consider it has one */
267 *GptDriveLetter
= TRUE
;
271 /* Query the GPT attributes */
272 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
273 Irp
= IoBuildDeviceIoControlRequest(IOCTL_VOLUME_GET_GPT_ATTRIBUTES
,
278 sizeof(GptAttributes
),
284 ObDereferenceObject(DeviceObject
);
285 ObDereferenceObject(FileObject
);
286 return STATUS_INSUFFICIENT_RESOURCES
;
289 Status
= IoCallDriver(DeviceObject
, Irp
);
290 if (Status
== STATUS_PENDING
)
292 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
293 Status
= IoStatusBlock
.Status
;
296 /* In case of failure, don't fail, that's no vital */
297 if (!NT_SUCCESS(Status
))
299 Status
= STATUS_SUCCESS
;
301 /* Check if it has a drive letter */
302 else if (!(GptAttributes
.GptAttributes
&
303 GPT_BASIC_DATA_ATTRIBUTE_NO_DRIVE_LETTER
))
305 *GptDriveLetter
= FALSE
;
310 /* If caller wants to know if there's valid contents */
313 /* Suppose it's not OK */
318 /* Query partitions information */
319 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
320 Irp
= IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_PARTITION_INFO_EX
,
325 sizeof(PartitionInfo
),
331 ObDereferenceObject(DeviceObject
);
332 ObDereferenceObject(FileObject
);
333 return STATUS_INSUFFICIENT_RESOURCES
;
336 Status
= IoCallDriver(DeviceObject
, Irp
);
337 if (Status
== STATUS_PENDING
)
339 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
340 Status
= IoStatusBlock
.Status
;
343 /* Once again here, failure isn't major */
344 if (!NT_SUCCESS(Status
))
346 Status
= STATUS_SUCCESS
;
348 /* Verify we know something in */
349 else if (PartitionInfo
.PartitionStyle
== PARTITION_STYLE_MBR
&&
350 IsRecognizedPartition(PartitionInfo
.Mbr
.PartitionType
))
355 /* It looks correct, ensure it is & query device number */
358 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
359 Irp
= IoBuildDeviceIoControlRequest(IOCTL_STORAGE_GET_DEVICE_NUMBER
,
363 &StorageDeviceNumber
,
364 sizeof(StorageDeviceNumber
),
370 ObDereferenceObject(DeviceObject
);
371 ObDereferenceObject(FileObject
);
372 return STATUS_INSUFFICIENT_RESOURCES
;
375 Status
= IoCallDriver(DeviceObject
, Irp
);
376 if (Status
== STATUS_PENDING
)
378 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
379 Status
= IoStatusBlock
.Status
;
382 if (!NT_SUCCESS(Status
))
384 Status
= STATUS_SUCCESS
;
394 /* If caller needs device name */
397 /* Allocate a buffer just to request length */
398 Name
= AllocatePool(sizeof(MOUNTDEV_NAME
));
401 ObDereferenceObject(DeviceObject
);
402 ObDereferenceObject(FileObject
);
403 return STATUS_INSUFFICIENT_RESOURCES
;
406 /* Query device name */
407 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
408 Irp
= IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_DEVICE_NAME
,
413 sizeof(MOUNTDEV_NAME
),
420 ObDereferenceObject(DeviceObject
);
421 ObDereferenceObject(FileObject
);
422 return STATUS_INSUFFICIENT_RESOURCES
;
425 Stack
= IoGetNextIrpStackLocation(Irp
);
426 Stack
->FileObject
= FileObject
;
428 Status
= IoCallDriver(DeviceObject
, Irp
);
429 if (Status
== STATUS_PENDING
)
431 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
432 Status
= IoStatusBlock
.Status
;
435 /* Now, we've got the correct length */
436 if (Status
== STATUS_BUFFER_OVERFLOW
)
438 Size
= Name
->NameLength
+ sizeof(MOUNTDEV_NAME
);
442 /* Allocate proper size */
443 Name
= AllocatePool(Size
);
446 ObDereferenceObject(DeviceObject
);
447 ObDereferenceObject(FileObject
);
448 return STATUS_INSUFFICIENT_RESOURCES
;
451 /* And query name (for real that time) */
452 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
453 Irp
= IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_DEVICE_NAME
,
465 ObDereferenceObject(DeviceObject
);
466 ObDereferenceObject(FileObject
);
467 return STATUS_INSUFFICIENT_RESOURCES
;
470 Stack
= IoGetNextIrpStackLocation(Irp
);
471 Stack
->FileObject
= FileObject
;
473 Status
= IoCallDriver(DeviceObject
, Irp
);
474 if (Status
== STATUS_PENDING
)
476 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
477 Status
= IoStatusBlock
.Status
;
481 /* Here we can't fail and assume default value */
482 if (!NT_SUCCESS(Status
))
485 ObDereferenceObject(DeviceObject
);
486 ObDereferenceObject(FileObject
);
490 /* Copy back found name to the caller */
491 DeviceName
->Length
= Name
->NameLength
;
492 DeviceName
->MaximumLength
= Name
->NameLength
+ sizeof(WCHAR
);
493 DeviceName
->Buffer
= AllocatePool(DeviceName
->MaximumLength
);
494 if (!DeviceName
->Buffer
)
497 ObDereferenceObject(DeviceObject
);
498 ObDereferenceObject(FileObject
);
499 return STATUS_INSUFFICIENT_RESOURCES
;
502 RtlCopyMemory(DeviceName
->Buffer
, Name
->Name
, Name
->NameLength
);
503 DeviceName
->Buffer
[Name
->NameLength
/ sizeof(WCHAR
)] = UNICODE_NULL
;
507 /* If caller wants device unique ID */
510 /* Prepare buffer to probe length */
511 Id
= AllocatePool(sizeof(MOUNTDEV_UNIQUE_ID
));
514 ObDereferenceObject(DeviceObject
);
515 ObDereferenceObject(FileObject
);
516 return STATUS_INSUFFICIENT_RESOURCES
;
519 /* Query unique ID length */
520 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
521 Irp
= IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_UNIQUE_ID
,
526 sizeof(MOUNTDEV_UNIQUE_ID
),
533 ObDereferenceObject(DeviceObject
);
534 ObDereferenceObject(FileObject
);
535 return STATUS_INSUFFICIENT_RESOURCES
;
538 Stack
= IoGetNextIrpStackLocation(Irp
);
539 Stack
->FileObject
= FileObject
;
541 Status
= IoCallDriver(DeviceObject
, Irp
);
542 if (Status
== STATUS_PENDING
)
544 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
545 Status
= IoStatusBlock
.Status
;
548 /* Retry with appropriate length */
549 if (Status
== STATUS_BUFFER_OVERFLOW
)
551 Size
= Id
->UniqueIdLength
+ sizeof(MOUNTDEV_UNIQUE_ID
);
555 /* Allocate the correct buffer */
556 Id
= AllocatePool(Size
);
559 ObDereferenceObject(DeviceObject
);
560 ObDereferenceObject(FileObject
);
561 return STATUS_INSUFFICIENT_RESOURCES
;
564 /* Query unique ID */
565 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
566 Irp
= IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_UNIQUE_ID
,
578 ObDereferenceObject(DeviceObject
);
579 ObDereferenceObject(FileObject
);
580 return STATUS_INSUFFICIENT_RESOURCES
;
583 Stack
= IoGetNextIrpStackLocation(Irp
);
584 Stack
->FileObject
= FileObject
;
586 Status
= IoCallDriver(DeviceObject
, Irp
);
587 if (Status
== STATUS_PENDING
)
589 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
590 Status
= IoStatusBlock
.Status
;
594 /* Hands back unique ID */
595 if (NT_SUCCESS(Status
))
601 /* In case of failure, also free the rest */
603 if (DeviceName
->Length
)
605 FreePool(DeviceName
->Buffer
);
608 ObDereferenceObject(DeviceObject
);
609 ObDereferenceObject(FileObject
);
615 /* If user wants to know about GUID */
618 /* Query device stable GUID */
619 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
620 Irp
= IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_STABLE_GUID
,
631 ObDereferenceObject(DeviceObject
);
632 ObDereferenceObject(FileObject
);
633 return STATUS_INSUFFICIENT_RESOURCES
;
636 Stack
= IoGetNextIrpStackLocation(Irp
);
637 Stack
->FileObject
= FileObject
;
639 Status
= IoCallDriver(DeviceObject
, Irp
);
640 if (Status
== STATUS_PENDING
)
642 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
643 Status
= IoStatusBlock
.Status
;
646 *HasGuid
= NT_SUCCESS(Status
);
649 ObDereferenceObject(DeviceObject
);
650 ObDereferenceObject(FileObject
);
658 FindDeviceInfo(IN PDEVICE_EXTENSION DeviceExtension
,
659 IN PUNICODE_STRING SymbolicName
,
660 IN BOOLEAN DeviceNameGiven
,
661 OUT PDEVICE_INFORMATION
* DeviceInformation
)
664 PLIST_ENTRY NextEntry
;
665 UNICODE_STRING DeviceName
;
666 PDEVICE_INFORMATION DeviceInfo
= NULL
;
668 /* If a device name was given, use it */
671 DeviceName
.Length
= SymbolicName
->Length
;
672 DeviceName
.Buffer
= SymbolicName
->Buffer
;
676 /* Otherwise, query it */
677 Status
= QueryDeviceInformation(SymbolicName
,
682 if (!NT_SUCCESS(Status
))
688 /* Look for device information matching devive */
689 for (NextEntry
= DeviceExtension
->DeviceListHead
.Flink
;
690 NextEntry
!= &(DeviceExtension
->DeviceListHead
);
691 NextEntry
= NextEntry
->Flink
)
693 DeviceInfo
= CONTAINING_RECORD(NextEntry
,
697 if (RtlEqualUnicodeString(&DeviceName
, &(DeviceInfo
->DeviceName
), TRUE
))
703 /* Release our buffer if required */
704 if (!DeviceNameGiven
)
706 FreePool(DeviceName
.Buffer
);
709 /* Return found intormation */
710 if (NextEntry
== &(DeviceExtension
->DeviceListHead
))
712 return STATUS_OBJECT_NAME_NOT_FOUND
;
715 *DeviceInformation
= DeviceInfo
;
716 return STATUS_SUCCESS
;
723 MountMgrFreeDeadDeviceInfo(IN PDEVICE_INFORMATION DeviceInformation
)
725 FreePool(DeviceInformation
->SymbolicName
.Buffer
);
726 FreePool(DeviceInformation
);
733 MountMgrFreeMountedDeviceInfo(IN PDEVICE_INFORMATION DeviceInformation
)
735 PLIST_ENTRY NextEntry
;
736 PSYMLINK_INFORMATION SymLink
;
737 PUNIQUE_ID_REPLICATE UniqueId
;
738 PASSOCIATED_DEVICE_ENTRY AssociatedDevice
;
740 /* Purge symbolic links list */
741 while (!IsListEmpty(&(DeviceInformation
->SymbolicLinksListHead
)))
743 NextEntry
= RemoveHeadList(&(DeviceInformation
->SymbolicLinksListHead
));
744 SymLink
= CONTAINING_RECORD(NextEntry
, SYMLINK_INFORMATION
, SymbolicLinksListEntry
);
746 GlobalDeleteSymbolicLink(&(SymLink
->Name
));
747 FreePool(SymLink
->Name
.Buffer
);
750 /* Purge replicated unique IDs list */
751 while (!IsListEmpty(&(DeviceInformation
->ReplicatedUniqueIdsListHead
)))
753 NextEntry
= RemoveHeadList(&(DeviceInformation
->ReplicatedUniqueIdsListHead
));
754 UniqueId
= CONTAINING_RECORD(NextEntry
, UNIQUE_ID_REPLICATE
, ReplicatedUniqueIdsListEntry
);
756 FreePool(UniqueId
->UniqueId
);
760 while (!IsListEmpty(&(DeviceInformation
->AssociatedDevicesHead
)))
762 NextEntry
= RemoveHeadList(&(DeviceInformation
->AssociatedDevicesHead
));
763 AssociatedDevice
= CONTAINING_RECORD(NextEntry
, ASSOCIATED_DEVICE_ENTRY
, AssociatedDevicesEntry
);
765 FreePool(AssociatedDevice
->String
.Buffer
);
766 FreePool(AssociatedDevice
);
769 /* Free the rest of the buffers */
770 FreePool(DeviceInformation
->SymbolicName
.Buffer
);
771 if (DeviceInformation
->KeepLinks
)
773 FreePool(DeviceInformation
->UniqueId
);
775 FreePool(DeviceInformation
->DeviceName
.Buffer
);
777 /* Finally, stop waiting for notifications for this device */
778 if (DeviceInformation
->TargetDeviceNotificationEntry
)
780 IoUnregisterPlugPlayNotification(DeviceInformation
->TargetDeviceNotificationEntry
);
788 MountMgrFreeSavedLink(IN PSAVED_LINK_INFORMATION SavedLinkInformation
)
790 PLIST_ENTRY NextEntry
;
791 PSYMLINK_INFORMATION SymlinkInformation
;
793 /* For all the saved links */
794 while (!IsListEmpty(&(SavedLinkInformation
->SymbolicLinksListHead
)))
796 NextEntry
= RemoveHeadList(&(SavedLinkInformation
->SymbolicLinksListHead
));
797 SymlinkInformation
= CONTAINING_RECORD(NextEntry
, SYMLINK_INFORMATION
, SymbolicLinksListEntry
);
799 /* Remove from system & free */
800 GlobalDeleteSymbolicLink(&(SymlinkInformation
->Name
));
801 FreePool(SymlinkInformation
->Name
.Buffer
);
802 FreePool(SymlinkInformation
);
805 /* And free unique ID & entry */
806 FreePool(SavedLinkInformation
->UniqueId
);
807 FreePool(SavedLinkInformation
);
816 MountMgrUnload(IN
struct _DRIVER_OBJECT
*DriverObject
)
818 PLIST_ENTRY NextEntry
;
819 PUNIQUE_ID_WORK_ITEM WorkItem
;
820 PDEVICE_EXTENSION DeviceExtension
;
821 PDEVICE_INFORMATION DeviceInformation
;
822 PSAVED_LINK_INFORMATION SavedLinkInformation
;
824 UNREFERENCED_PARAMETER(DriverObject
);
826 /* Don't get notification any longer */
827 IoUnregisterShutdownNotification(gdeviceObject
);
829 /* Free registry buffer */
830 DeviceExtension
= gdeviceObject
->DeviceExtension
;
831 if (DeviceExtension
->RegistryPath
.Buffer
)
833 FreePool(DeviceExtension
->RegistryPath
.Buffer
);
834 DeviceExtension
->RegistryPath
.Buffer
= NULL
;
837 InterlockedExchange(&Unloading
, TRUE
);
839 KeInitializeEvent(&UnloadEvent
, NotificationEvent
, FALSE
);
841 /* Wait for workers to finish */
842 if (InterlockedIncrement(&DeviceExtension
->WorkerReferences
))
844 KeReleaseSemaphore(&(DeviceExtension
->WorkerSemaphore
),
845 IO_NO_INCREMENT
, 1, FALSE
);
847 KeWaitForSingleObject(&UnloadEvent
, Executive
, KernelMode
, FALSE
, NULL
);
851 InterlockedDecrement(&(DeviceExtension
->WorkerReferences
));
854 /* Don't get any notification any longer² */
855 IoUnregisterPlugPlayNotification(DeviceExtension
->NotificationEntry
);
857 /* Acquire the driver exclusively */
858 KeWaitForSingleObject(&(DeviceExtension
->DeviceLock
), Executive
, KernelMode
,
861 /* Clear offline devices list */
862 while (!IsListEmpty(&(DeviceExtension
->OfflineDeviceListHead
)))
864 NextEntry
= RemoveHeadList(&(DeviceExtension
->OfflineDeviceListHead
));
865 DeviceInformation
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
866 MountMgrFreeDeadDeviceInfo(DeviceInformation
);
869 /* Clear saved links list */
870 while (!IsListEmpty(&(DeviceExtension
->SavedLinksListHead
)))
872 NextEntry
= RemoveHeadList(&(DeviceExtension
->SavedLinksListHead
));
873 SavedLinkInformation
= CONTAINING_RECORD(NextEntry
, SAVED_LINK_INFORMATION
, SavedLinksListEntry
);
874 MountMgrFreeSavedLink(SavedLinkInformation
);
877 /* Clear workers list */
878 while (!IsListEmpty(&(DeviceExtension
->UniqueIdWorkerItemListHead
)))
880 NextEntry
= RemoveHeadList(&(DeviceExtension
->UniqueIdWorkerItemListHead
));
881 WorkItem
= CONTAINING_RECORD(NextEntry
, UNIQUE_ID_WORK_ITEM
, UniqueIdWorkerItemListEntry
);
883 KeResetEvent(&UnloadEvent
);
884 WorkItem
->Event
= &UnloadEvent
;
886 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
,
889 IoCancelIrp(WorkItem
->Irp
);
890 KeWaitForSingleObject(&UnloadEvent
, Executive
, KernelMode
, FALSE
, NULL
);
892 IoFreeIrp(WorkItem
->Irp
);
893 FreePool(WorkItem
->DeviceName
.Buffer
);
894 FreePool(WorkItem
->IrpBuffer
);
897 KeWaitForSingleObject(&(DeviceExtension
->DeviceLock
), Executive
, KernelMode
,
901 /* If we have drive letter data, release */
902 if (DeviceExtension
->DriveLetterData
)
904 FreePool(DeviceExtension
->DriveLetterData
);
905 DeviceExtension
->DriveLetterData
= NULL
;
908 /* Release driver & quit */
909 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
, 1, FALSE
);
911 GlobalDeleteSymbolicLink(&DosDevicesMount
);
912 IoDeleteDevice(gdeviceObject
);
920 MountmgrReadNoAutoMount(IN PUNICODE_STRING RegistryPath
)
923 ULONG Result
, Default
= 0;
924 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
926 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
928 /* Simply read data from register */
929 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
930 QueryTable
[0].Name
= L
"NoAutoMount";
931 QueryTable
[0].EntryContext
= &Result
;
932 QueryTable
[0].DefaultType
= REG_NONE
;
933 QueryTable
[0].DefaultData
= &Default
;
934 QueryTable
[0].DefaultLength
= sizeof(ULONG
);
936 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
937 RegistryPath
->Buffer
,
941 if (!NT_SUCCESS(Status
))
943 return (Default
!= 0);
946 return (Result
!= 0);
953 MountMgrMountedDeviceArrival(IN PDEVICE_EXTENSION DeviceExtension
,
954 IN PUNICODE_STRING SymbolicName
,
955 IN BOOLEAN FromVolume
)
960 ULONG SymLinkCount
, i
;
961 PLIST_ENTRY NextEntry
;
962 PUNICODE_STRING SymLinks
;
963 NTSTATUS Status
, IntStatus
;
964 OBJECT_ATTRIBUTES ObjectAttributes
;
965 PSYMLINK_INFORMATION SymlinkInformation
;
966 PMOUNTDEV_UNIQUE_ID UniqueId
, NewUniqueId
;
967 PSAVED_LINK_INFORMATION SavedLinkInformation
;
968 PDEVICE_INFORMATION DeviceInformation
, CurrentDevice
;
969 WCHAR CSymLinkBuffer
[MAX_PATH
], LinkTargetBuffer
[MAX_PATH
];
970 UNICODE_STRING TargetDeviceName
, SuggestedLinkName
, DeviceName
, VolumeName
, DriveLetter
, LinkTarget
, CSymLink
;
971 BOOLEAN HasGuid
, HasGptDriveLetter
, Valid
, UseOnlyIfThereAreNoOtherLinks
, IsDrvLetter
, IsOff
, IsVolumeName
, LinkError
;
973 /* New device = new structure to represent it */
974 DeviceInformation
= AllocatePool(sizeof(DEVICE_INFORMATION
));
975 if (!DeviceInformation
)
977 return STATUS_INSUFFICIENT_RESOURCES
;
980 /* Initialise device structure */
981 RtlZeroMemory(DeviceInformation
, sizeof(DEVICE_INFORMATION
));
982 InitializeListHead(&(DeviceInformation
->SymbolicLinksListHead
));
983 InitializeListHead(&(DeviceInformation
->ReplicatedUniqueIdsListHead
));
984 InitializeListHead(&(DeviceInformation
->AssociatedDevicesHead
));
985 DeviceInformation
->SymbolicName
.Length
= SymbolicName
->Length
;
986 DeviceInformation
->SymbolicName
.MaximumLength
= SymbolicName
->Length
+ sizeof(UNICODE_NULL
);
987 DeviceInformation
->SymbolicName
.Buffer
= AllocatePool(DeviceInformation
->SymbolicName
.MaximumLength
);
988 if (!DeviceInformation
->SymbolicName
.Buffer
)
990 FreePool(DeviceInformation
);
991 return STATUS_INSUFFICIENT_RESOURCES
;
994 /* Copy symbolic name */
995 RtlCopyMemory(DeviceInformation
->SymbolicName
.Buffer
, SymbolicName
->Buffer
, SymbolicName
->Length
);
996 DeviceInformation
->SymbolicName
.Buffer
[DeviceInformation
->SymbolicName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
997 DeviceInformation
->Volume
= FromVolume
;
998 DeviceInformation
->DeviceExtension
= DeviceExtension
;
1000 /* Query as much data as possible about device */
1001 Status
= QueryDeviceInformation(SymbolicName
,
1004 &(DeviceInformation
->Removable
),
1009 if (!NT_SUCCESS(Status
))
1011 KeWaitForSingleObject(&(DeviceExtension
->DeviceLock
), Executive
, KernelMode
, FALSE
, NULL
);
1013 for (NextEntry
= DeviceExtension
->OfflineDeviceListHead
.Flink
;
1014 NextEntry
!= &(DeviceExtension
->OfflineDeviceListHead
);
1015 NextEntry
= NextEntry
->Flink
)
1017 CurrentDevice
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
1019 if (RtlEqualUnicodeString(&(DeviceInformation
->SymbolicName
), &(CurrentDevice
->SymbolicName
), TRUE
))
1025 if (NextEntry
!= &(DeviceExtension
->OfflineDeviceListHead
))
1027 MountMgrFreeDeadDeviceInfo(DeviceInformation
);
1031 InsertTailList(&(DeviceExtension
->OfflineDeviceListHead
), &(DeviceInformation
->DeviceListEntry
));
1034 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
, 1, FALSE
);
1039 /* Save gathered data */
1040 DeviceInformation
->UniqueId
= UniqueId
;
1041 DeviceInformation
->DeviceName
= TargetDeviceName
;
1042 DeviceInformation
->KeepLinks
= FALSE
;
1044 /* If we found system partition, mark it */
1045 if (DeviceExtension
->DriveLetterData
&& UniqueId
->UniqueIdLength
== DeviceExtension
->DriveLetterData
->UniqueIdLength
)
1047 if (RtlCompareMemory(UniqueId
->UniqueId
, DeviceExtension
->DriveLetterData
->UniqueId
, UniqueId
->UniqueIdLength
)
1048 == UniqueId
->UniqueIdLength
)
1050 IoSetSystemPartition(&TargetDeviceName
);
1054 /* Check suggested link name */
1055 Status
= QuerySuggestedLinkName(&(DeviceInformation
->SymbolicName
),
1057 &UseOnlyIfThereAreNoOtherLinks
);
1058 if (!NT_SUCCESS(Status
))
1060 SuggestedLinkName
.Buffer
= NULL
;
1063 /* If it's OK, set it and save its letter (if any) */
1064 if (SuggestedLinkName
.Buffer
&& IsDriveLetter(&SuggestedLinkName
))
1066 DeviceInformation
->SuggestedDriveLetter
= (UCHAR
)SuggestedLinkName
.Buffer
[LETTER_POSITION
];
1069 /* Acquire driver exclusively */
1070 KeWaitForSingleObject(&(DeviceExtension
->DeviceLock
), Executive
, KernelMode
, FALSE
, NULL
);
1072 /* Check if we already have device in to prevent double registration */
1073 for (NextEntry
= DeviceExtension
->DeviceListHead
.Flink
;
1074 NextEntry
!= &(DeviceExtension
->DeviceListHead
);
1075 NextEntry
= NextEntry
->Flink
)
1077 CurrentDevice
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
1079 if (RtlEqualUnicodeString(&(CurrentDevice
->DeviceName
), &TargetDeviceName
, TRUE
))
1085 /* If we found it, clear ours, and return success, all correct */
1086 if (NextEntry
!= &(DeviceExtension
->DeviceListHead
))
1088 if (SuggestedLinkName
.Buffer
)
1090 FreePool(SuggestedLinkName
.Buffer
);
1094 FreePool(TargetDeviceName
.Buffer
);
1095 FreePool(DeviceInformation
->DeviceName
.Buffer
);
1096 FreePool(DeviceInformation
);
1098 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
, 1, FALSE
);
1100 return STATUS_SUCCESS
;
1103 /* Check if there are symlinks associated with our device in registry */
1104 Status
= QuerySymbolicLinkNamesFromStorage(DeviceExtension
,
1106 (SuggestedLinkName
.Buffer
) ? &SuggestedLinkName
: NULL
,
1107 UseOnlyIfThereAreNoOtherLinks
,
1113 /* If our device is a CD-ROM */
1114 if (RtlPrefixUnicodeString(&DeviceCdRom
, &TargetDeviceName
, TRUE
))
1116 LinkTarget
.Length
= 0;
1117 LinkTarget
.MaximumLength
= sizeof(LinkTargetBuffer
);
1118 LinkTarget
.Buffer
= LinkTargetBuffer
;
1120 RtlCopyMemory(CSymLinkBuffer
, Cunc
, sizeof(Cunc
));
1121 RtlInitUnicodeString(&CSymLink
, CSymLinkBuffer
);
1123 /* Start checking all letters that could have been associated */
1124 for (Letter
= L
'D'; Letter
<= L
'Z'; Letter
++)
1126 CSymLink
.Buffer
[LETTER_POSITION
] = Letter
;
1128 InitializeObjectAttributes(&ObjectAttributes
,
1130 OBJ_CASE_INSENSITIVE
,
1134 /* Try to open the associated symlink */
1135 Status
= ZwOpenSymbolicLinkObject(&LinkHandle
, SYMBOLIC_LINK_QUERY
, &ObjectAttributes
);
1136 if (!NT_SUCCESS(Status
))
1141 /* And query its target */
1142 Status
= ZwQuerySymbolicLinkObject(LinkHandle
, &LinkTarget
, NULL
);
1143 ZwClose(LinkHandle
);
1145 if (!NT_SUCCESS(Status
))
1150 IntStatus
= STATUS_UNSUCCESSFUL
;
1151 if (!RtlEqualUnicodeString(&LinkTarget
, &DeviceInformation
->DeviceName
, FALSE
))
1156 /* This link is matching our device, whereas it's not supposed to have any
1157 * symlink associated.
1162 IoDeleteSymbolicLink(&CSymLink
);
1166 /* Now, for all the symlinks, check for ours */
1167 for (i
= 0; i
< SymLinkCount
; i
++)
1169 if (IsDriveLetter(&(SymLinks
[i
])))
1171 /* If it exists, that's correct */
1172 if (SymLinks
[i
].Buffer
[LETTER_POSITION
] == Letter
)
1174 IntStatus
= STATUS_SUCCESS
;
1179 /* Useless link, delete it */
1180 if (IntStatus
== STATUS_UNSUCCESSFUL
)
1182 IoDeleteSymbolicLink(&CSymLink
);
1187 /* Suggested name is no longer required */
1188 if (SuggestedLinkName
.Buffer
)
1190 FreePool(SuggestedLinkName
.Buffer
);
1193 /* If if failed, ensure we don't take symlinks into account */
1194 if (!NT_SUCCESS(Status
))
1200 /* Now we queried them, remove the symlinks */
1201 SavedLinkInformation
= RemoveSavedLinks(DeviceExtension
, UniqueId
);
1203 IsDrvLetter
= FALSE
;
1205 IsVolumeName
= FALSE
;
1206 /* For all the symlinks */
1207 for (i
= 0; i
< SymLinkCount
; i
++)
1209 /* Check if our device is a volume */
1210 if (MOUNTMGR_IS_VOLUME_NAME(&(SymLinks
[i
])))
1212 IsVolumeName
= TRUE
;
1214 /* If it has a drive letter */
1215 else if (IsDriveLetter(&(SymLinks
[i
])))
1219 DeleteFromLocalDatabase(&(SymLinks
[i
]), UniqueId
);
1228 /* And recreate the symlink to our device */
1229 Status
= GlobalCreateSymbolicLink(&(SymLinks
[i
]), &TargetDeviceName
);
1230 if (!NT_SUCCESS(Status
))
1234 if ((SavedLinkInformation
&& !RedirectSavedLink(SavedLinkInformation
, &(SymLinks
[i
]), &TargetDeviceName
)) ||
1235 !SavedLinkInformation
)
1237 Status
= QueryDeviceInformation(&(SymLinks
[i
]), &DeviceName
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
1238 if (NT_SUCCESS(Status
))
1240 LinkError
= RtlEqualUnicodeString(&TargetDeviceName
, &DeviceName
, TRUE
);
1241 FreePool(DeviceName
.Buffer
);
1246 if (IsDriveLetter(&(SymLinks
[i
])))
1248 IsDrvLetter
= FALSE
;
1249 DeleteFromLocalDatabase(&(SymLinks
[i
]), UniqueId
);
1252 FreePool(SymLinks
[i
].Buffer
);
1258 /* Check if was offline */
1259 if (IsOffline(&(SymLinks
[i
])))
1264 /* Finally, associate this symlink with the device */
1265 SymlinkInformation
= AllocatePool(sizeof(SYMLINK_INFORMATION
));
1266 if (!SymlinkInformation
)
1268 GlobalDeleteSymbolicLink(&(SymLinks
[i
]));
1269 FreePool(SymLinks
[i
].Buffer
);
1273 SymlinkInformation
->Name
= SymLinks
[i
];
1274 SymlinkInformation
->Online
= TRUE
;
1276 InsertTailList(&(DeviceInformation
->SymbolicLinksListHead
),
1277 &(SymlinkInformation
->SymbolicLinksListEntry
));
1280 /* Now, for all the recreated symlinks, notify their recreation */
1281 for (NextEntry
= DeviceInformation
->SymbolicLinksListHead
.Flink
;
1282 NextEntry
!= &(DeviceInformation
->SymbolicLinksListHead
);
1283 NextEntry
= NextEntry
->Flink
)
1285 SymlinkInformation
= CONTAINING_RECORD(NextEntry
, SYMLINK_INFORMATION
, SymbolicLinksListEntry
);
1287 SendLinkCreated(&(SymlinkInformation
->Name
));
1290 /* If we had saved links, it's time to free them */
1291 if (SavedLinkInformation
)
1293 MountMgrFreeSavedLink(SavedLinkInformation
);
1296 /* If our device doesn't have a volume name */
1299 /* It's time to create one */
1300 Status
= CreateNewVolumeName(&VolumeName
, NULL
);
1301 if (NT_SUCCESS(Status
))
1303 /* Write it to global database */
1304 RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE
,
1309 UniqueId
->UniqueIdLength
);
1311 /* And create the symlink */
1312 GlobalCreateSymbolicLink(&VolumeName
, &TargetDeviceName
);
1314 SymlinkInformation
= AllocatePool(sizeof(SYMLINK_INFORMATION
));
1315 if (!SymlinkInformation
)
1317 FreePool(VolumeName
.Buffer
);
1319 /* Finally, associate it with the device and notify creation */
1322 SymlinkInformation
->Name
= VolumeName
;
1323 SymlinkInformation
->Online
= TRUE
;
1324 InsertTailList(&(DeviceInformation
->SymbolicLinksListHead
),
1325 &(SymlinkInformation
->SymbolicLinksListEntry
));
1327 SendLinkCreated(&VolumeName
);
1332 /* If we found a drive letter, then, ignore the suggested one */
1335 DeviceInformation
->SuggestedDriveLetter
= 0;
1337 /* Else, it's time to set up one */
1338 else if ((DeviceExtension
->NoAutoMount
|| DeviceInformation
->Removable
) &&
1339 DeviceExtension
->AutomaticDriveLetter
&&
1340 (HasGptDriveLetter
|| DeviceInformation
->SuggestedDriveLetter
) &&
1341 !HasNoDriveLetterEntry(UniqueId
))
1343 /* Create a new drive letter */
1344 Status
= CreateNewDriveLetterName(&DriveLetter
, &TargetDeviceName
,
1345 DeviceInformation
->SuggestedDriveLetter
,
1347 if (!NT_SUCCESS(Status
))
1349 CreateNoDriveLetterEntry(UniqueId
);
1353 /* Save it to global database */
1354 RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE
,
1359 UniqueId
->UniqueIdLength
);
1361 /* Associate it with the device and notify creation */
1362 SymlinkInformation
= AllocatePool(sizeof(SYMLINK_INFORMATION
));
1363 if (!SymlinkInformation
)
1365 FreePool(DriveLetter
.Buffer
);
1369 SymlinkInformation
->Name
= DriveLetter
;
1370 SymlinkInformation
->Online
= TRUE
;
1371 InsertTailList(&(DeviceInformation
->SymbolicLinksListHead
),
1372 &(SymlinkInformation
->SymbolicLinksListEntry
));
1374 SendLinkCreated(&DriveLetter
);
1379 /* If required, register for notifications about the device */
1382 RegisterForTargetDeviceNotification(DeviceExtension
, DeviceInformation
);
1385 /* Finally, insert the device into our devices list */
1386 InsertTailList(&(DeviceExtension
->DeviceListHead
), &(DeviceInformation
->DeviceListEntry
));
1388 /* Copy device unique ID */
1389 NewUniqueId
= AllocatePool(UniqueId
->UniqueIdLength
+ sizeof(MOUNTDEV_UNIQUE_ID
));
1392 NewUniqueId
->UniqueIdLength
= UniqueId
->UniqueIdLength
;
1393 RtlCopyMemory(NewUniqueId
->UniqueId
, UniqueId
->UniqueId
, UniqueId
->UniqueIdLength
);
1396 /* If device's offline or valid, skip its notifications */
1399 DeviceInformation
->SkipNotifications
= TRUE
;
1402 /* In case device is valid and is set to no automount,
1405 if (DeviceExtension
->NoAutoMount
|| IsDrvLetter
)
1407 IsOff
= !DeviceInformation
->SkipNotifications
;
1414 /* Finally, release the exclusive lock */
1415 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
, 1, FALSE
);
1417 /* If device is not offline, notify its arrival */
1420 SendOnlineNotification(SymbolicName
);
1423 /* If we had symlinks (from storage), free them */
1429 /* Notify about unique id change */
1432 IssueUniqueIdChangeNotify(DeviceExtension
, SymbolicName
, NewUniqueId
);
1433 FreePool(NewUniqueId
);
1436 /* If this drive was set to have a drive letter automatically
1437 * Now it's back, local databases sync will be required
1439 if (DeviceExtension
->AutomaticDriveLetter
)
1441 KeWaitForSingleObject(&(DeviceExtension
->DeviceLock
), Executive
, KernelMode
, FALSE
, NULL
);
1443 ReconcileThisDatabaseWithMaster(DeviceExtension
, DeviceInformation
);
1445 NextEntry
= DeviceExtension
->DeviceListHead
.Flink
;
1446 CurrentDevice
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
1447 while (CurrentDevice
!= DeviceInformation
)
1449 if (!CurrentDevice
->NoDatabase
)
1451 ReconcileThisDatabaseWithMaster(DeviceExtension
, CurrentDevice
);
1454 NextEntry
= NextEntry
->Flink
;
1455 CurrentDevice
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
1458 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
, 1, FALSE
);
1461 return STATUS_SUCCESS
;
1468 MountMgrMountedDeviceRemoval(IN PDEVICE_EXTENSION DeviceExtension
,
1469 IN PUNICODE_STRING DeviceName
)
1471 PLIST_ENTRY NextEntry
, DeviceEntry
;
1472 PUNIQUE_ID_REPLICATE UniqueIdReplicate
;
1473 PSYMLINK_INFORMATION SymlinkInformation
;
1474 PASSOCIATED_DEVICE_ENTRY AssociatedDevice
;
1475 PSAVED_LINK_INFORMATION SavedLinkInformation
= NULL
;
1476 PDEVICE_INFORMATION DeviceInformation
, CurrentDevice
;
1478 /* Acquire device exclusively */
1479 KeWaitForSingleObject(&(DeviceExtension
->DeviceLock
), Executive
, KernelMode
, FALSE
, NULL
);
1481 /* Look for the leaving device */
1482 for (NextEntry
= DeviceExtension
->DeviceListHead
.Flink
;
1483 NextEntry
!= &(DeviceExtension
->DeviceListHead
);
1484 NextEntry
= NextEntry
->Flink
)
1486 DeviceInformation
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
1488 if (!RtlCompareUnicodeString(&(DeviceInformation
->SymbolicName
), DeviceName
, TRUE
))
1494 /* If we found it */
1495 if (NextEntry
!= &(DeviceExtension
->DeviceListHead
))
1497 /* If it's asked to keep links, then, prepare to save them */
1498 if (DeviceInformation
->KeepLinks
)
1500 SavedLinkInformation
= AllocatePool(sizeof(SAVED_LINK_INFORMATION
));
1501 if (!SavedLinkInformation
)
1503 DeviceInformation
->KeepLinks
= FALSE
;
1507 /* If it's possible (and asked), start to save them */
1508 if (DeviceInformation
->KeepLinks
)
1510 InsertTailList(&(DeviceExtension
->SavedLinksListHead
), &(SavedLinkInformation
->SavedLinksListEntry
));
1511 InitializeListHead(&(SavedLinkInformation
->SymbolicLinksListHead
));
1512 SavedLinkInformation
->UniqueId
= DeviceInformation
->UniqueId
;
1515 /* For all the symlinks */
1516 while (!IsListEmpty(&(DeviceInformation
->SymbolicLinksListHead
)))
1518 NextEntry
= RemoveHeadList(&(DeviceInformation
->SymbolicLinksListHead
));
1519 SymlinkInformation
= CONTAINING_RECORD(NextEntry
, SYMLINK_INFORMATION
, SymbolicLinksListEntry
);
1521 /* If we have to, save the link */
1522 if (DeviceInformation
->KeepLinks
)
1524 InsertTailList(&(SavedLinkInformation
->SymbolicLinksListHead
), &(SymlinkInformation
->SymbolicLinksListEntry
));
1526 /* Otherwise, just release it */
1529 GlobalDeleteSymbolicLink(&(SymlinkInformation
->Name
));
1530 FreePool(SymlinkInformation
->Name
.Buffer
);
1531 FreePool(SymlinkInformation
);
1535 /* Free all the replicated unique IDs */
1536 while (!IsListEmpty(&(DeviceInformation
->ReplicatedUniqueIdsListHead
)))
1538 NextEntry
= RemoveHeadList(&(DeviceInformation
->ReplicatedUniqueIdsListHead
));
1539 UniqueIdReplicate
= CONTAINING_RECORD(NextEntry
, UNIQUE_ID_REPLICATE
, ReplicatedUniqueIdsListEntry
);
1542 FreePool(UniqueIdReplicate
->UniqueId
);
1543 FreePool(UniqueIdReplicate
);
1546 while (!IsListEmpty(&(DeviceInformation
->AssociatedDevicesHead
)))
1548 NextEntry
= RemoveHeadList(&(DeviceInformation
->AssociatedDevicesHead
));
1549 AssociatedDevice
= CONTAINING_RECORD(NextEntry
, ASSOCIATED_DEVICE_ENTRY
, AssociatedDevicesEntry
);
1551 DeviceInformation
->NoDatabase
= TRUE
;
1552 FreePool(AssociatedDevice
->String
.Buffer
);
1553 FreePool(AssociatedDevice
);
1556 /* Remove device from the device list */
1557 RemoveEntryList(&(DeviceInformation
->DeviceListEntry
));
1559 /* If there are still devices, check if some were associated with ours */
1560 if (!IsListEmpty(&(DeviceInformation
->DeviceListEntry
)))
1562 for (NextEntry
= DeviceExtension
->DeviceListHead
.Flink
;
1563 NextEntry
!= &(DeviceExtension
->DeviceListHead
);
1564 NextEntry
= NextEntry
->Flink
)
1566 CurrentDevice
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
1568 /* And then, remove them */
1569 DeviceEntry
= CurrentDevice
->AssociatedDevicesHead
.Flink
;
1570 while (DeviceEntry
!= &(CurrentDevice
->AssociatedDevicesHead
))
1572 AssociatedDevice
= CONTAINING_RECORD(NextEntry
, ASSOCIATED_DEVICE_ENTRY
, AssociatedDevicesEntry
);
1573 DeviceEntry
= DeviceEntry
->Flink
;
1575 if (AssociatedDevice
->DeviceInformation
!= DeviceInformation
)
1580 RemoveEntryList(&(AssociatedDevice
->AssociatedDevicesEntry
));
1581 FreePool(AssociatedDevice
->String
.Buffer
);
1582 FreePool(AssociatedDevice
);
1587 /* Finally, clean up device name, symbolic name */
1588 FreePool(DeviceInformation
->SymbolicName
.Buffer
);
1589 if (!DeviceInformation
->KeepLinks
)
1591 FreePool(DeviceInformation
->UniqueId
);
1593 FreePool(DeviceInformation
->DeviceName
.Buffer
);
1595 /* Unregister notifications */
1596 if (DeviceInformation
->TargetDeviceNotificationEntry
)
1598 IoUnregisterPlugPlayNotification(DeviceInformation
->TargetDeviceNotificationEntry
);
1602 FreePool(DeviceInformation
);
1606 /* We didn't find device, perhaps because it was offline */
1607 for (NextEntry
= DeviceExtension
->OfflineDeviceListHead
.Flink
;
1608 NextEntry
!= &(DeviceExtension
->OfflineDeviceListHead
);
1609 NextEntry
= NextEntry
->Flink
)
1611 DeviceInformation
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
1613 /* It was, remove it */
1614 if (RtlCompareUnicodeString(&(DeviceInformation
->SymbolicName
), DeviceName
, TRUE
) == 0)
1616 RemoveEntryList(&(DeviceInformation
->DeviceListEntry
));
1617 MountMgrFreeDeadDeviceInfo(DeviceInformation
);
1623 /* Releave driver */
1624 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
, 1, FALSE
);
1632 MountMgrMountedDeviceNotification(IN PVOID NotificationStructure
,
1636 PDEVICE_EXTENSION DeviceExtension
;
1637 PDEVICE_INTERFACE_CHANGE_NOTIFICATION Notification
;
1639 /* Notification for a device arrived */
1640 /* Disable hard errors */
1641 OldState
= PsGetThreadHardErrorsAreDisabled(PsGetCurrentThread());
1642 PsSetThreadHardErrorsAreDisabled(PsGetCurrentThread(), TRUE
);
1644 DeviceExtension
= Context
;
1645 Notification
= NotificationStructure
;
1647 /* Dispatch according to the event */
1648 if (IsEqualGUID(&(Notification
->Event
), &GUID_DEVICE_INTERFACE_ARRIVAL
))
1650 MountMgrMountedDeviceArrival(DeviceExtension
, Notification
->SymbolicLinkName
, FALSE
);
1652 else if (IsEqualGUID(&(Notification
->Event
), &GUID_DEVICE_INTERFACE_REMOVAL
))
1654 MountMgrMountedDeviceRemoval(DeviceExtension
, Notification
->SymbolicLinkName
);
1657 /* Reset hard errors */
1658 PsSetThreadHardErrorsAreDisabled(PsGetCurrentThread(), OldState
);
1660 return STATUS_SUCCESS
;
1668 MountMgrCreateClose(IN PDEVICE_OBJECT DeviceObject
,
1671 PIO_STACK_LOCATION Stack
;
1672 NTSTATUS Status
= STATUS_SUCCESS
;
1674 UNREFERENCED_PARAMETER(DeviceObject
);
1676 Stack
= IoGetCurrentIrpStackLocation(Irp
);
1678 /* Allow driver opening for communication
1679 * as long as it's not taken for a directory
1681 if (Stack
->MajorFunction
== IRP_MJ_CREATE
&&
1682 Stack
->Parameters
.Create
.Options
& FILE_DIRECTORY_FILE
)
1684 Status
= STATUS_NOT_A_DIRECTORY
;
1687 Irp
->IoStatus
.Status
= Status
;
1688 Irp
->IoStatus
.Information
= 0;
1689 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1698 MountMgrCancel(IN PDEVICE_OBJECT DeviceObject
,
1701 UNREFERENCED_PARAMETER(DeviceObject
);
1703 RemoveEntryList(&(Irp
->Tail
.Overlay
.ListEntry
));
1705 IoReleaseCancelSpinLock(Irp
->CancelIrql
);
1707 Irp
->IoStatus
.Information
= 0;
1708 Irp
->IoStatus
.Status
= STATUS_CANCELLED
;
1709 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1717 MountMgrCleanup(IN PDEVICE_OBJECT DeviceObject
,
1722 PLIST_ENTRY NextEntry
;
1723 PFILE_OBJECT FileObject
;
1724 PIO_STACK_LOCATION Stack
;
1725 PDEVICE_EXTENSION DeviceExtension
;
1727 DeviceExtension
= DeviceObject
->DeviceExtension
;
1728 Stack
= IoGetCurrentIrpStackLocation(Irp
);
1729 FileObject
= Stack
->FileObject
;
1731 IoAcquireCancelSpinLock(&OldIrql
);
1733 /* If IRP list if empty, it's OK */
1734 if (IsListEmpty(&(DeviceExtension
->IrpListHead
)))
1736 IoReleaseCancelSpinLock(OldIrql
);
1738 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1739 Irp
->IoStatus
.Information
= 0;
1740 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1742 return STATUS_SUCCESS
;
1745 /* Otherwise, cancel all the IRPs */
1746 NextEntry
= &(DeviceExtension
->IrpListHead
);
1749 ListIrp
= CONTAINING_RECORD(NextEntry
, IRP
, Tail
.Overlay
.ListEntry
);
1750 if (IoGetCurrentIrpStackLocation(ListIrp
)->FileObject
== FileObject
)
1752 ListIrp
->Cancel
= TRUE
;
1753 ListIrp
->CancelIrql
= OldIrql
;
1754 ListIrp
->CancelRoutine
= NULL
;
1755 MountMgrCancel(DeviceObject
, ListIrp
);
1757 IoAcquireCancelSpinLock(&OldIrql
);
1760 NextEntry
= NextEntry
->Flink
;
1762 while (NextEntry
!= &(DeviceExtension
->IrpListHead
));
1764 IoReleaseCancelSpinLock(OldIrql
);
1766 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1767 Irp
->IoStatus
.Information
= 0;
1768 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1770 return STATUS_SUCCESS
;
1778 MountMgrShutdown(IN PDEVICE_OBJECT DeviceObject
,
1781 PDEVICE_EXTENSION DeviceExtension
;
1783 DeviceExtension
= DeviceObject
->DeviceExtension
;
1785 InterlockedExchange(&Unloading
, TRUE
);
1787 KeInitializeEvent(&UnloadEvent
, NotificationEvent
, FALSE
);
1789 /* Wait for workers */
1790 if (InterlockedIncrement(&(DeviceExtension
->WorkerReferences
)))
1792 KeReleaseSemaphore(&(DeviceExtension
->WorkerSemaphore
),
1796 KeWaitForSingleObject(&UnloadEvent
, Executive
, KernelMode
, FALSE
, NULL
);
1800 InterlockedDecrement(&(DeviceExtension
->WorkerReferences
));
1803 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1804 Irp
->IoStatus
.Information
= 0;
1805 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1807 return STATUS_SUCCESS
;
1810 /* FUNCTIONS ****************************************************************/
1815 DriverEntry(IN PDRIVER_OBJECT DriverObject
,
1816 IN PUNICODE_STRING RegistryPath
)
1819 PDEVICE_OBJECT DeviceObject
;
1820 PDEVICE_EXTENSION DeviceExtension
;
1822 RtlCreateRegistryKey(RTL_REGISTRY_ABSOLUTE
, DatabasePath
);
1824 Status
= IoCreateDevice(DriverObject
,
1825 sizeof(DEVICE_EXTENSION
),
1827 FILE_DEVICE_NETWORK
,
1828 FILE_DEVICE_SECURE_OPEN
,
1831 if (!NT_SUCCESS(Status
))
1836 DriverObject
->DriverUnload
= MountMgrUnload
;
1838 DeviceExtension
= DeviceObject
->DeviceExtension
;
1839 RtlZeroMemory(DeviceExtension
, sizeof(DEVICE_EXTENSION
));
1840 DeviceExtension
->DeviceObject
= DeviceObject
;
1841 DeviceExtension
->DriverObject
= DriverObject
;
1843 InitializeListHead(&(DeviceExtension
->DeviceListHead
));
1844 InitializeListHead(&(DeviceExtension
->OfflineDeviceListHead
));
1846 KeInitializeSemaphore(&(DeviceExtension
->DeviceLock
), 1, 1);
1847 KeInitializeSemaphore(&(DeviceExtension
->RemoteDatabaseLock
), 1, 1);
1849 InitializeListHead(&(DeviceExtension
->IrpListHead
));
1850 DeviceExtension
->EpicNumber
= 1;
1852 InitializeListHead(&(DeviceExtension
->SavedLinksListHead
));
1854 InitializeListHead(&(DeviceExtension
->WorkerQueueListHead
));
1855 KeInitializeSemaphore(&(DeviceExtension
->WorkerSemaphore
), 0, MAXLONG
);
1856 DeviceExtension
->WorkerReferences
= -1;
1857 KeInitializeSpinLock(&(DeviceExtension
->WorkerLock
));
1859 InitializeListHead(&(DeviceExtension
->UniqueIdWorkerItemListHead
));
1860 InitializeListHead(&(DeviceExtension
->OnlineNotificationListHead
));
1861 DeviceExtension
->OnlineNotificationCount
= 1;
1863 DeviceExtension
->RegistryPath
.Length
= RegistryPath
->Length
;
1864 DeviceExtension
->RegistryPath
.MaximumLength
= RegistryPath
->Length
+ sizeof(WCHAR
);
1865 DeviceExtension
->RegistryPath
.Buffer
= AllocatePool(DeviceExtension
->RegistryPath
.MaximumLength
);
1866 if (!DeviceExtension
->RegistryPath
.Buffer
)
1868 IoDeleteDevice(DeviceObject
);
1869 return STATUS_INSUFFICIENT_RESOURCES
;
1872 RtlCopyUnicodeString(&(DeviceExtension
->RegistryPath
), RegistryPath
);
1874 DeviceExtension
->NoAutoMount
= MountmgrReadNoAutoMount(&(DeviceExtension
->RegistryPath
));
1876 GlobalCreateSymbolicLink(&DosDevicesMount
, &DeviceMount
);
1878 /* Register for device arrival & removal. Ask to be notified for already
1881 Status
= IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange
,
1882 PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES
,
1883 &MountedDevicesGuid
,
1885 MountMgrMountedDeviceNotification
,
1887 &(DeviceExtension
->NotificationEntry
));
1889 if (!NT_SUCCESS(Status
))
1891 IoDeleteDevice(DeviceObject
);
1895 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] =
1896 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = MountMgrCreateClose
;
1897 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = MountMgrDeviceControl
;
1898 DriverObject
->MajorFunction
[IRP_MJ_CLEANUP
] = MountMgrCleanup
;
1899 DriverObject
->MajorFunction
[IRP_MJ_SHUTDOWN
] = MountMgrShutdown
;
1901 gdeviceObject
= DeviceObject
;
1903 Status
= IoRegisterShutdownNotification(DeviceObject
);
1904 if (!NT_SUCCESS(Status
))
1906 IoDeleteDevice(DeviceObject
);