3 * Copyright (C) 2011 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
19 * COPYRIGHT: See COPYING in the top level directory
20 * PROJECT: ReactOS kernel
21 * FILE: drivers/filesystem/mountmgr/mountmgr.c
22 * PURPOSE: Mount Manager
23 * PROGRAMMER: Pierre Schweitzer (pierre.schweitzer@reactos.org)
24 * Alex Ionescu (alex.ionescu@reactos.org)
27 /* INCLUDES *****************************************************************/
35 GUID MountedDevicesGuid
= {0x53F5630D, 0xB6BF, 0x11D0, {0x94, 0xF2, 0x00, 0xA0, 0xC9, 0x1E, 0xFB, 0x8B}};
37 PDEVICE_OBJECT gdeviceObject
;
41 static const WCHAR Cunc
[] = L
"\\??\\C:";
45 * - MountMgrQueryDosVolumePath
46 * - MountMgrQueryDosVolumePaths
47 * - MountMgrQueryVolumePaths
48 * - MountMgrValidateBackPointer
49 * - MountMgrVolumeMountPointCreated
50 * - MountMgrVolumeMountPointDeleted
51 * - ReconcileThisDatabaseWithMasterWorker
58 IsOffline(PUNICODE_STRING SymbolicName
)
61 ULONG IsOffline
, Default
;
62 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
64 /* Prepare to look in the registry to see if
65 * given volume is offline
67 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
68 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
69 QueryTable
[0].Name
= SymbolicName
->Buffer
;
70 QueryTable
[0].EntryContext
= &IsOffline
;
71 QueryTable
[0].DefaultType
= REG_DWORD
;
72 QueryTable
[0].DefaultLength
= sizeof(ULONG
);
73 QueryTable
[0].DefaultData
= &Default
;
78 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
83 if (!NT_SUCCESS(Status
))
88 return (IsOffline
!= 0);
95 HasDriveLetter(IN PDEVICE_INFORMATION DeviceInformation
)
97 PLIST_ENTRY NextEntry
;
98 PSYMLINK_INFORMATION SymlinkInfo
;
100 /* To have a drive letter, a device must have symbolic links */
101 if (IsListEmpty(&(DeviceInformation
->SymbolicLinksListHead
)))
106 /* Browse all the links untill a drive letter is found */
107 NextEntry
= &(DeviceInformation
->SymbolicLinksListHead
);
110 SymlinkInfo
= CONTAINING_RECORD(NextEntry
, SYMLINK_INFORMATION
, SymbolicLinksListEntry
);
112 if (SymlinkInfo
->Online
)
114 if (IsDriveLetter(&(SymlinkInfo
->Name
)))
120 NextEntry
= NextEntry
->Flink
;
121 } while (NextEntry
!= &(DeviceInformation
->SymbolicLinksListHead
));
130 CreateNewDriveLetterName(OUT PUNICODE_STRING DriveLetter
,
131 IN PUNICODE_STRING DeviceName
,
133 IN PMOUNTDEV_UNIQUE_ID UniqueId OPTIONAL
)
135 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
137 /* Allocate a big enough buffer to contain the symbolic link */
138 DriveLetter
->MaximumLength
= sizeof(DosDevices
.Buffer
) + 3 * sizeof(WCHAR
);
139 DriveLetter
->Buffer
= AllocatePool(sizeof(DosDevices
.Buffer
) + 3 * sizeof(WCHAR
));
140 if (!DriveLetter
->Buffer
)
142 return STATUS_INSUFFICIENT_RESOURCES
;
146 RtlCopyUnicodeString(DriveLetter
, &DosDevices
);
148 /* Update string to reflect real contents */
149 DriveLetter
->Length
= sizeof(DosDevices
.Buffer
) + 2 * sizeof(WCHAR
);
150 DriveLetter
->Buffer
[(sizeof(DosDevices
.Buffer
) + 2 * sizeof(WCHAR
)) / sizeof (WCHAR
)] = UNICODE_NULL
;
151 DriveLetter
->Buffer
[(sizeof(DosDevices
.Buffer
) + sizeof(WCHAR
)) / sizeof (WCHAR
)] = L
':';
153 /* If caller wants a no drive entry */
154 if (Letter
== (UCHAR
)-1)
156 /* Then, create a no letter entry */
157 CreateNoDriveLetterEntry(UniqueId
);
158 FreePool(DriveLetter
->Buffer
);
159 return STATUS_UNSUCCESSFUL
;
163 /* Use the letter given by the caller */
164 DriveLetter
->Buffer
[sizeof(DosDevices
.Buffer
) / sizeof(WCHAR
)] = (WCHAR
)Letter
;
165 Status
= GlobalCreateSymbolicLink(DriveLetter
, DeviceName
);
166 if (NT_SUCCESS(Status
))
172 /* If caller didn't provide a letter, let's find one for him */
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
[sizeof(DosDevices
.Buffer
) / sizeof(WCHAR
)] = (WCHAR
)Letter
;
194 Status
= GlobalCreateSymbolicLink(DriveLetter
, DeviceName
);
195 if (NT_SUCCESS(Status
))
201 /* We failed to allocate a letter */
202 FreePool(DriveLetter
->Buffer
);
210 QueryDeviceInformation(IN PUNICODE_STRING SymbolicName
,
211 OUT PUNICODE_STRING DeviceName OPTIONAL
,
212 OUT PMOUNTDEV_UNIQUE_ID
* UniqueId OPTIONAL
,
213 OUT PBOOLEAN Removable OPTIONAL
,
214 OUT PBOOLEAN GptDriveLetter OPTIONAL
,
215 OUT PBOOLEAN HasGuid OPTIONAL
,
216 IN OUT LPGUID StableGuid OPTIONAL
,
217 OUT PBOOLEAN Valid OPTIONAL
)
225 PMOUNTDEV_UNIQUE_ID Id
;
226 PFILE_OBJECT FileObject
;
227 PIO_STACK_LOCATION Stack
;
228 PDEVICE_OBJECT DeviceObject
;
229 IO_STATUS_BLOCK IoStatusBlock
;
230 PARTITION_INFORMATION_EX PartitionInfo
;
231 STORAGE_DEVICE_NUMBER StorageDeviceNumber
;
232 VOLUME_GET_GPT_ATTRIBUTES_INFORMATION GptAttributes
;
234 /* Get device associated with the symbolic name */
235 Status
= IoGetDeviceObjectPointer(SymbolicName
,
236 FILE_READ_ATTRIBUTES
,
239 if (!NT_SUCCESS(Status
))
244 /* The associate FO can't have a file name */
245 if (FileObject
->FileName
.Length
)
247 ObDereferenceObject(FileObject
);
248 return STATUS_OBJECT_NAME_NOT_FOUND
;
251 /* Check if it's removable & return to the user (if asked to) */
252 IsRemovable
= (FileObject
->DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
);
255 *Removable
= IsRemovable
;
258 /* Get the attached device */
259 DeviceObject
= IoGetAttachedDeviceReference(FileObject
->DeviceObject
);
261 /* If we've been asked for a GPT drive letter */
264 /* Consider it has one */
265 *GptDriveLetter
= TRUE
;
269 /* Query the GPT attributes */
270 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
271 Irp
= IoBuildDeviceIoControlRequest(IOCTL_VOLUME_GET_GPT_ATTRIBUTES
,
276 sizeof(GptAttributes
),
282 ObDereferenceObject(DeviceObject
);
283 ObDereferenceObject(FileObject
);
284 return STATUS_INSUFFICIENT_RESOURCES
;
287 Status
= IoCallDriver(DeviceObject
, Irp
);
288 if (Status
== STATUS_PENDING
)
290 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
291 Status
= IoStatusBlock
.Status
;
294 /* In case of failure, don't fail, that's no vital */
295 if (!NT_SUCCESS(Status
))
297 Status
= STATUS_SUCCESS
;
299 /* Check if it has a drive letter */
300 else if (!(GptAttributes
.GptAttributes
&
301 GPT_BASIC_DATA_ATTRIBUTE_NO_DRIVE_LETTER
))
303 *GptDriveLetter
= FALSE
;
308 /* If caller wants to know if there's valid contents */
311 /* Suppose it's not OK */
316 /* Query partitions information */
317 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
318 Irp
= IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_PARTITION_INFO_EX
,
323 sizeof(PartitionInfo
),
329 ObDereferenceObject(DeviceObject
);
330 ObDereferenceObject(FileObject
);
331 return STATUS_INSUFFICIENT_RESOURCES
;
334 Status
= IoCallDriver(DeviceObject
, Irp
);
335 if (Status
== STATUS_PENDING
)
337 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
338 Status
= IoStatusBlock
.Status
;
341 /* Once again here, failure isn't major */
342 if (!NT_SUCCESS(Status
))
344 Status
= STATUS_SUCCESS
;
346 /* Verify we know something in */
347 else if (PartitionInfo
.PartitionStyle
== PARTITION_STYLE_MBR
&&
348 IsRecognizedPartition(PartitionInfo
.Mbr
.PartitionType
))
353 /* It looks correct, ensure it is & query device number */
356 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
357 Irp
= IoBuildDeviceIoControlRequest(IOCTL_STORAGE_GET_DEVICE_NUMBER
,
361 &StorageDeviceNumber
,
362 sizeof(StorageDeviceNumber
),
368 ObDereferenceObject(DeviceObject
);
369 ObDereferenceObject(FileObject
);
370 return STATUS_INSUFFICIENT_RESOURCES
;
373 Status
= IoCallDriver(DeviceObject
, Irp
);
374 if (Status
== STATUS_PENDING
)
376 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
377 Status
= IoStatusBlock
.Status
;
380 if (!NT_SUCCESS(Status
))
382 Status
= STATUS_SUCCESS
;
392 /* If caller needs device name */
395 /* Allocate a buffer just to request length */
396 Name
= AllocatePool(sizeof(MOUNTDEV_NAME
));
399 ObDereferenceObject(DeviceObject
);
400 ObDereferenceObject(FileObject
);
401 return STATUS_INSUFFICIENT_RESOURCES
;
404 /* Query device name */
405 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
406 Irp
= IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_DEVICE_NAME
,
411 sizeof(MOUNTDEV_NAME
),
418 ObDereferenceObject(DeviceObject
);
419 ObDereferenceObject(FileObject
);
420 return STATUS_INSUFFICIENT_RESOURCES
;
423 Stack
= IoGetNextIrpStackLocation(Irp
);
424 Stack
->FileObject
= FileObject
;
426 Status
= IoCallDriver(DeviceObject
, Irp
);
427 if (Status
== STATUS_PENDING
)
429 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
430 Status
= IoStatusBlock
.Status
;
433 /* Now, we've got the correct length */
434 if (Status
== STATUS_BUFFER_OVERFLOW
)
436 Size
= Name
->NameLength
+ sizeof(MOUNTDEV_NAME
);
440 /* Allocate proper size */
441 Name
= AllocatePool(Size
);
444 ObDereferenceObject(DeviceObject
);
445 ObDereferenceObject(FileObject
);
446 return STATUS_INSUFFICIENT_RESOURCES
;
449 /* And query name (for real that time) */
450 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
451 Irp
= IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_DEVICE_NAME
,
463 ObDereferenceObject(DeviceObject
);
464 ObDereferenceObject(FileObject
);
465 return STATUS_INSUFFICIENT_RESOURCES
;
468 Stack
= IoGetNextIrpStackLocation(Irp
);
469 Stack
->FileObject
= FileObject
;
471 Status
= IoCallDriver(DeviceObject
, Irp
);
472 if (Status
== STATUS_PENDING
)
474 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
475 Status
= IoStatusBlock
.Status
;
479 /* Here we can't fail and assume default value */
480 if (!NT_SUCCESS(Status
))
483 ObDereferenceObject(DeviceObject
);
484 ObDereferenceObject(FileObject
);
488 /* Copy back found name to the caller */
489 DeviceName
->Length
= Name
->NameLength
;
490 DeviceName
->MaximumLength
= Name
->NameLength
+ sizeof(WCHAR
);
491 DeviceName
->Buffer
= AllocatePool(DeviceName
->MaximumLength
);
492 if (!DeviceName
->Buffer
)
495 ObDereferenceObject(DeviceObject
);
496 ObDereferenceObject(FileObject
);
497 return STATUS_INSUFFICIENT_RESOURCES
;
500 RtlCopyMemory(DeviceName
->Buffer
, Name
->Name
, Name
->NameLength
);
501 DeviceName
->Buffer
[Name
->NameLength
/ sizeof(WCHAR
)] = UNICODE_NULL
;
505 /* If caller wants device unique ID */
508 /* Prepare buffer to probe length */
509 Id
= AllocatePool(sizeof(MOUNTDEV_UNIQUE_ID
));
512 ObDereferenceObject(DeviceObject
);
513 ObDereferenceObject(FileObject
);
514 return STATUS_INSUFFICIENT_RESOURCES
;
517 /* Query unique ID length */
518 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
519 Irp
= IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_UNIQUE_ID
,
524 sizeof(MOUNTDEV_UNIQUE_ID
),
531 ObDereferenceObject(DeviceObject
);
532 ObDereferenceObject(FileObject
);
533 return STATUS_INSUFFICIENT_RESOURCES
;
536 Stack
= IoGetNextIrpStackLocation(Irp
);
537 Stack
->FileObject
= FileObject
;
539 Status
= IoCallDriver(DeviceObject
, Irp
);
540 if (Status
== STATUS_PENDING
)
542 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
543 Status
= IoStatusBlock
.Status
;
546 /* Retry with appropriate length */
547 if (Status
== STATUS_BUFFER_OVERFLOW
)
549 Size
= Id
->UniqueIdLength
+ sizeof(MOUNTDEV_UNIQUE_ID
);
553 /* Allocate the correct buffer */
554 Id
= AllocatePool(Size
);
557 ObDereferenceObject(DeviceObject
);
558 ObDereferenceObject(FileObject
);
559 return STATUS_INSUFFICIENT_RESOURCES
;
562 /* Query unique ID */
563 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
564 Irp
= IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_DEVICE_NAME
,
576 ObDereferenceObject(DeviceObject
);
577 ObDereferenceObject(FileObject
);
578 return STATUS_INSUFFICIENT_RESOURCES
;
581 Stack
= IoGetNextIrpStackLocation(Irp
);
582 Stack
->FileObject
= FileObject
;
584 Status
= IoCallDriver(DeviceObject
, Irp
);
585 if (Status
== STATUS_PENDING
)
587 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
588 Status
= IoStatusBlock
.Status
;
592 /* Hands back unique ID */
593 if (NT_SUCCESS(Status
))
599 /* In case of failure, also free the rest */
601 if (DeviceName
->Length
)
603 FreePool(DeviceName
->Buffer
);
606 ObDereferenceObject(DeviceObject
);
607 ObDereferenceObject(FileObject
);
613 /* If user wants to know about GUID */
616 /* Query device stable GUID */
617 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
618 Irp
= IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_STABLE_GUID
,
629 ObDereferenceObject(DeviceObject
);
630 ObDereferenceObject(FileObject
);
631 return STATUS_INSUFFICIENT_RESOURCES
;
634 Stack
= IoGetNextIrpStackLocation(Irp
);
635 Stack
->FileObject
= FileObject
;
637 Status
= IoCallDriver(DeviceObject
, Irp
);
638 if (Status
== STATUS_PENDING
)
640 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
641 Status
= IoStatusBlock
.Status
;
644 *HasGuid
= NT_SUCCESS(Status
);
647 ObDereferenceObject(DeviceObject
);
648 ObDereferenceObject(FileObject
);
656 FindDeviceInfo(IN PDEVICE_EXTENSION DeviceExtension
,
657 IN PUNICODE_STRING SymbolicName
,
658 IN BOOLEAN DeviceNameGiven
,
659 OUT PDEVICE_INFORMATION
* DeviceInformation
)
662 PLIST_ENTRY NextEntry
;
663 UNICODE_STRING DeviceName
;
664 PDEVICE_INFORMATION DeviceInfo
= NULL
;
666 /* If a device name was given, use it */
669 DeviceName
.Length
= SymbolicName
->Length
;
670 DeviceName
.Buffer
= SymbolicName
->Buffer
;
674 /* Otherwise, query it */
675 Status
= QueryDeviceInformation(SymbolicName
,
680 if (!NT_SUCCESS(Status
))
686 /* Look for device information matching devive */
687 for (NextEntry
= DeviceExtension
->DeviceListHead
.Flink
;
688 NextEntry
!= &(DeviceExtension
->DeviceListHead
);
689 NextEntry
= NextEntry
->Flink
)
691 DeviceInfo
= CONTAINING_RECORD(NextEntry
,
695 if (RtlEqualUnicodeString(&DeviceName
, &(DeviceInfo
->DeviceName
), TRUE
))
701 /* Release our buffer if required */
702 if (!DeviceNameGiven
)
704 FreePool(DeviceName
.Buffer
);
707 /* Return found intormation */
708 if (NextEntry
== &(DeviceExtension
->DeviceListHead
))
710 return STATUS_OBJECT_NAME_NOT_FOUND
;
713 *DeviceInformation
= DeviceInfo
;
714 return STATUS_SUCCESS
;
721 MountMgrFreeDeadDeviceInfo(IN PDEVICE_INFORMATION DeviceInformation
)
723 FreePool(DeviceInformation
->SymbolicName
.Buffer
);
724 FreePool(DeviceInformation
);
731 MountMgrFreeMountedDeviceInfo(IN PDEVICE_INFORMATION DeviceInformation
)
733 PLIST_ENTRY NextEntry
;
734 PSYMLINK_INFORMATION SymLink
;
735 PUNIQUE_ID_REPLICATE UniqueId
;
736 PASSOCIATED_DEVICE_ENTRY AssociatedDevice
;
738 /* Purge symbolic links list */
739 while (!IsListEmpty(&(DeviceInformation
->SymbolicLinksListHead
)))
741 NextEntry
= RemoveHeadList(&(DeviceInformation
->SymbolicLinksListHead
));
742 SymLink
= CONTAINING_RECORD(NextEntry
, SYMLINK_INFORMATION
, SymbolicLinksListEntry
);
744 GlobalDeleteSymbolicLink(&(SymLink
->Name
));
745 FreePool(SymLink
->Name
.Buffer
);
748 /* Purge replicated unique IDs list */
749 while (!IsListEmpty(&(DeviceInformation
->ReplicatedUniqueIdsListHead
)))
751 NextEntry
= RemoveHeadList(&(DeviceInformation
->ReplicatedUniqueIdsListHead
));
752 UniqueId
= CONTAINING_RECORD(NextEntry
, UNIQUE_ID_REPLICATE
, ReplicatedUniqueIdsListEntry
);
754 FreePool(UniqueId
->UniqueId
);
758 while (!IsListEmpty(&(DeviceInformation
->AssociatedDevicesHead
)))
760 NextEntry
= RemoveHeadList(&(DeviceInformation
->AssociatedDevicesHead
));
761 AssociatedDevice
= CONTAINING_RECORD(NextEntry
, ASSOCIATED_DEVICE_ENTRY
, AssociatedDevicesEntry
);
763 FreePool(AssociatedDevice
->String
.Buffer
);
764 FreePool(AssociatedDevice
);
767 /* Free the rest of the buffers */
768 FreePool(DeviceInformation
->SymbolicName
.Buffer
);
769 if (DeviceInformation
->KeepLinks
)
771 FreePool(DeviceInformation
->UniqueId
);
773 FreePool(DeviceInformation
->DeviceName
.Buffer
);
775 /* Finally, stop waiting for notifications for this device */
776 if (DeviceInformation
->TargetDeviceNotificationEntry
)
778 IoUnregisterPlugPlayNotification(DeviceInformation
->TargetDeviceNotificationEntry
);
786 MountMgrFreeSavedLink(IN PSAVED_LINK_INFORMATION SavedLinkInformation
)
788 PLIST_ENTRY NextEntry
;
789 PSYMLINK_INFORMATION SymlinkInformation
;
791 /* For all the saved links */
792 while (!IsListEmpty(&(SavedLinkInformation
->SymbolicLinksListHead
)))
794 NextEntry
= RemoveHeadList(&(SavedLinkInformation
->SymbolicLinksListHead
));
795 SymlinkInformation
= CONTAINING_RECORD(NextEntry
, SYMLINK_INFORMATION
, SymbolicLinksListEntry
);
797 /* Remove from system & free */
798 GlobalDeleteSymbolicLink(&(SymlinkInformation
->Name
));
799 FreePool(SymlinkInformation
->Name
.Buffer
);
800 FreePool(SymlinkInformation
);
803 /* And free unique ID & entry */
804 FreePool(SavedLinkInformation
->UniqueId
);
805 FreePool(SavedLinkInformation
);
814 MountMgrUnload(IN
struct _DRIVER_OBJECT
*DriverObject
)
816 PLIST_ENTRY NextEntry
;
817 PUNIQUE_ID_WORK_ITEM WorkItem
;
818 PDEVICE_EXTENSION DeviceExtension
;
819 PDEVICE_INFORMATION DeviceInformation
;
820 PSAVED_LINK_INFORMATION SavedLinkInformation
;
822 UNREFERENCED_PARAMETER(DriverObject
);
824 /* Don't get notification any longer */
825 IoUnregisterShutdownNotification(gdeviceObject
);
827 /* Free registry buffer */
828 DeviceExtension
= gdeviceObject
->DeviceExtension
;
829 if (DeviceExtension
->RegistryPath
.Buffer
)
831 FreePool(DeviceExtension
->RegistryPath
.Buffer
);
832 DeviceExtension
->RegistryPath
.Buffer
= NULL
;
835 InterlockedExchange(&Unloading
, TRUE
);
837 KeInitializeEvent(&UnloadEvent
, NotificationEvent
, FALSE
);
839 /* Wait for workers to finish */
840 if (InterlockedIncrement(&DeviceExtension
->WorkerReferences
))
842 KeReleaseSemaphore(&(DeviceExtension
->WorkerSemaphore
),
843 IO_NO_INCREMENT
, 1, FALSE
);
845 KeWaitForSingleObject(&UnloadEvent
, Executive
, KernelMode
, FALSE
, NULL
);
849 InterlockedDecrement(&(DeviceExtension
->WorkerReferences
));
852 /* Don't get any notification any longer² */
853 IoUnregisterPlugPlayNotification(DeviceExtension
->NotificationEntry
);
855 /* Acquire the driver exclusively */
856 KeWaitForSingleObject(&(DeviceExtension
->DeviceLock
), Executive
, KernelMode
,
859 /* Clear offline devices list */
860 while (!IsListEmpty(&(DeviceExtension
->OfflineDeviceListHead
)))
862 NextEntry
= RemoveHeadList(&(DeviceExtension
->OfflineDeviceListHead
));
863 DeviceInformation
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
864 MountMgrFreeDeadDeviceInfo(DeviceInformation
);
867 /* Clear saved links list */
868 while (!IsListEmpty(&(DeviceExtension
->SavedLinksListHead
)))
870 NextEntry
= RemoveHeadList(&(DeviceExtension
->SavedLinksListHead
));
871 SavedLinkInformation
= CONTAINING_RECORD(NextEntry
, SAVED_LINK_INFORMATION
, SavedLinksListEntry
);
872 MountMgrFreeSavedLink(SavedLinkInformation
);
875 /* Clear workers list */
876 while (!IsListEmpty(&(DeviceExtension
->UniqueIdWorkerItemListHead
)))
878 NextEntry
= RemoveHeadList(&(DeviceExtension
->UniqueIdWorkerItemListHead
));
879 WorkItem
= CONTAINING_RECORD(NextEntry
, UNIQUE_ID_WORK_ITEM
, UniqueIdWorkerItemListEntry
);
881 KeResetEvent(&UnloadEvent
);
882 WorkItem
->Event
= &UnloadEvent
;
884 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
,
887 IoCancelIrp(WorkItem
->Irp
);
888 KeWaitForSingleObject(&UnloadEvent
, Executive
, KernelMode
, FALSE
, NULL
);
890 IoFreeIrp(WorkItem
->Irp
);
891 FreePool(WorkItem
->DeviceName
.Buffer
);
892 FreePool(WorkItem
->IrpBuffer
);
895 KeWaitForSingleObject(&(DeviceExtension
->DeviceLock
), Executive
, KernelMode
,
899 /* If we have drive letter data, release */
900 if (DeviceExtension
->DriveLetterData
)
902 FreePool(DeviceExtension
->DriveLetterData
);
903 DeviceExtension
->DriveLetterData
= NULL
;
906 /* Release driver & quit */
907 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
, 1, FALSE
);
909 GlobalDeleteSymbolicLink(&DosDevicesMount
);
910 IoDeleteDevice(gdeviceObject
);
917 MountmgrReadNoAutoMount(IN PUNICODE_STRING RegistryPath
)
920 ULONG Result
, Default
= 0;
921 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
923 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
925 /* Simply read data from register */
926 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
927 QueryTable
[0].Name
= L
"NoAutoMount";
928 QueryTable
[0].EntryContext
= &Result
;
929 QueryTable
[0].DefaultType
= REG_NONE
;
930 QueryTable
[0].DefaultData
= &Default
;
931 QueryTable
[0].DefaultLength
= sizeof(ULONG
);
933 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
934 RegistryPath
->Buffer
,
938 if (!NT_SUCCESS(Status
))
940 return (Default
!= 0);
943 return (Result
!= 0);
950 MountMgrMountedDeviceArrival(IN PDEVICE_EXTENSION DeviceExtension
,
951 IN PUNICODE_STRING SymbolicName
,
952 IN BOOLEAN FromVolume
)
957 ULONG SymLinkCount
, i
;
958 PLIST_ENTRY NextEntry
;
959 PUNICODE_STRING SymLinks
;
960 NTSTATUS Status
, IntStatus
;
961 OBJECT_ATTRIBUTES ObjectAttributes
;
962 PSYMLINK_INFORMATION SymlinkInformation
;
963 PMOUNTDEV_UNIQUE_ID UniqueId
, NewUniqueId
;
964 PSAVED_LINK_INFORMATION SavedLinkInformation
;
965 PDEVICE_INFORMATION DeviceInformation
, CurrentDevice
;
966 WCHAR CSymLinkBuffer
[MAX_PATH
], LinkTargetBuffer
[MAX_PATH
];
967 UNICODE_STRING TargetDeviceName
, SuggestedLinkName
, DeviceName
, VolumeName
, DriveLetter
, LinkTarget
, CSymLink
;
968 BOOLEAN HasGuid
, HasGptDriveLetter
, Valid
, UseOnlyIfThereAreNoOtherLinks
, IsDrvLetter
, IsOff
, IsVolumeName
, LinkError
;
970 /* New device = new structure to represent it */
971 DeviceInformation
= AllocatePool(sizeof(DEVICE_INFORMATION
));
972 if (!DeviceInformation
)
974 return STATUS_INSUFFICIENT_RESOURCES
;
977 /* Initialise device structure */
978 RtlZeroMemory(DeviceInformation
, sizeof(DEVICE_INFORMATION
));
979 InitializeListHead(&(DeviceInformation
->SymbolicLinksListHead
));
980 InitializeListHead(&(DeviceInformation
->ReplicatedUniqueIdsListHead
));
981 InitializeListHead(&(DeviceInformation
->AssociatedDevicesHead
));
982 DeviceInformation
->SymbolicName
.Length
= SymbolicName
->Length
;
983 DeviceInformation
->SymbolicName
.MaximumLength
= SymbolicName
->Length
+ sizeof(UNICODE_NULL
);
984 DeviceInformation
->SymbolicName
.Buffer
= AllocatePool(DeviceInformation
->SymbolicName
.MaximumLength
);
985 if (!DeviceInformation
->SymbolicName
.Buffer
)
987 FreePool(DeviceInformation
);
988 return STATUS_INSUFFICIENT_RESOURCES
;
991 /* Copy symbolic name */
992 RtlCopyMemory(DeviceInformation
->SymbolicName
.Buffer
, SymbolicName
->Buffer
, SymbolicName
->Length
);
993 DeviceInformation
->SymbolicName
.Buffer
[DeviceInformation
->SymbolicName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
994 DeviceInformation
->Volume
= FromVolume
;
995 DeviceInformation
->DeviceExtension
= DeviceExtension
;
997 /* Query as much data as possible about device */
998 Status
= QueryDeviceInformation(SymbolicName
,
1001 &(DeviceInformation
->Removable
),
1006 if (!NT_SUCCESS(Status
))
1008 KeWaitForSingleObject(&(DeviceExtension
->DeviceLock
), Executive
, KernelMode
, FALSE
, NULL
);
1010 for (NextEntry
= DeviceExtension
->OfflineDeviceListHead
.Flink
;
1011 NextEntry
!= &(DeviceExtension
->OfflineDeviceListHead
);
1012 NextEntry
= NextEntry
->Flink
)
1014 CurrentDevice
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
1016 if (RtlEqualUnicodeString(&(DeviceInformation
->SymbolicName
), &(CurrentDevice
->SymbolicName
), TRUE
))
1022 if (NextEntry
!= &(DeviceExtension
->OfflineDeviceListHead
))
1024 MountMgrFreeDeadDeviceInfo(DeviceInformation
);
1028 InsertTailList(&(DeviceExtension
->OfflineDeviceListHead
), &(DeviceInformation
->DeviceListEntry
));
1031 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
, 1, FALSE
);
1036 /* Save gathered data */
1037 DeviceInformation
->UniqueId
= UniqueId
;
1038 DeviceInformation
->DeviceName
= TargetDeviceName
;
1039 DeviceInformation
->KeepLinks
= FALSE
;
1041 /* If we found system partition, mark it */
1042 if (DeviceExtension
->DriveLetterData
&& UniqueId
->UniqueIdLength
== DeviceExtension
->DriveLetterData
->UniqueIdLength
)
1044 if (RtlCompareMemory(UniqueId
->UniqueId
, DeviceExtension
->DriveLetterData
->UniqueId
, UniqueId
->UniqueIdLength
)
1045 == UniqueId
->UniqueIdLength
)
1047 IoSetSystemPartition(&TargetDeviceName
);
1051 /* Check suggested link name */
1052 Status
= QuerySuggestedLinkName(&(DeviceInformation
->SymbolicName
),
1054 &UseOnlyIfThereAreNoOtherLinks
);
1055 if (!NT_SUCCESS(Status
))
1057 SuggestedLinkName
.Buffer
= NULL
;
1060 /* If it's OK, set it and save its letter (if any) */
1061 if (SuggestedLinkName
.Buffer
&& IsDriveLetter(&SuggestedLinkName
))
1063 DeviceInformation
->SuggestedDriveLetter
= (UCHAR
)SuggestedLinkName
.Buffer
[LETTER_POSITION
];
1066 /* Acquire driver exclusively */
1067 KeWaitForSingleObject(&(DeviceExtension
->DeviceLock
), Executive
, KernelMode
, FALSE
, NULL
);
1069 /* Check if we already have device in to prevent double registration */
1070 for (NextEntry
= DeviceExtension
->DeviceListHead
.Flink
;
1071 NextEntry
!= &(DeviceExtension
->DeviceListHead
);
1072 NextEntry
= NextEntry
->Flink
)
1074 CurrentDevice
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
1076 if (RtlEqualUnicodeString(&(DeviceInformation
->DeviceName
), &TargetDeviceName
, TRUE
))
1082 /* If we found it, clear ours, and return success, all correct */
1083 if (NextEntry
!= &(DeviceExtension
->DeviceListHead
))
1085 if (SuggestedLinkName
.Buffer
)
1087 FreePool(SuggestedLinkName
.Buffer
);
1091 FreePool(TargetDeviceName
.Buffer
);
1092 FreePool(DeviceInformation
->DeviceName
.Buffer
);
1093 FreePool(DeviceInformation
);
1095 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
, 1, FALSE
);
1097 return STATUS_SUCCESS
;
1100 /* Check if there are symlinks associated with our device in registry */
1101 Status
= QuerySymbolicLinkNamesFromStorage(DeviceExtension
,
1103 (SuggestedLinkName
.Buffer
) ? &SuggestedLinkName
: NULL
,
1104 UseOnlyIfThereAreNoOtherLinks
,
1110 /* If our device is a CD-ROM */
1111 if (RtlPrefixUnicodeString(&DeviceCdRom
, &TargetDeviceName
, TRUE
))
1113 LinkTarget
.Length
= 0;
1114 LinkTarget
.MaximumLength
= sizeof(LinkTargetBuffer
);
1115 LinkTarget
.Buffer
= LinkTargetBuffer
;
1117 RtlCopyMemory(CSymLinkBuffer
, Cunc
, sizeof(Cunc
));
1118 RtlInitUnicodeString(&CSymLink
, CSymLinkBuffer
);
1120 /* Start checking all letters that could have been associated */
1121 for (Letter
= L
'D'; Letter
<= L
'Z'; Letter
++)
1123 CSymLink
.Buffer
[LETTER_POSITION
] = Letter
;
1125 InitializeObjectAttributes(&ObjectAttributes
,
1127 OBJ_CASE_INSENSITIVE
,
1131 /* Try to open the associated symlink */
1132 Status
= ZwOpenSymbolicLinkObject(&LinkHandle
, SYMBOLIC_LINK_QUERY
, &ObjectAttributes
);
1133 if (!NT_SUCCESS(Status
))
1138 /* And query its target */
1139 Status
= ZwQuerySymbolicLinkObject(LinkHandle
, &LinkTarget
, NULL
);
1140 ZwClose(LinkHandle
);
1142 if (!NT_SUCCESS(Status
))
1147 IntStatus
= STATUS_UNSUCCESSFUL
;
1148 if (!RtlEqualUnicodeString(&LinkTarget
, &DeviceInformation
->DeviceName
, FALSE
))
1153 /* This link is matching our device, whereas it's not supposed to have any
1154 * symlink associated.
1159 IoDeleteSymbolicLink(&CSymLink
);
1163 /* Now, for all the symlinks, check for ours */
1164 for (i
= 0; i
< SymLinkCount
; i
++)
1166 if (IsDriveLetter(&(SymLinks
[i
])))
1168 /* If it exists, that's correct */
1169 if (SymLinks
[i
].Buffer
[LETTER_POSITION
] == Letter
)
1171 IntStatus
= STATUS_SUCCESS
;
1176 /* Useless link, delete it */
1177 if (IntStatus
== STATUS_UNSUCCESSFUL
)
1179 IoDeleteSymbolicLink(&CSymLink
);
1184 /* Suggested name is no longer required */
1185 if (SuggestedLinkName
.Buffer
)
1187 FreePool(SuggestedLinkName
.Buffer
);
1190 /* If if failed, ensure we don't take symlinks into account */
1191 if (!NT_SUCCESS(Status
))
1197 /* Now we queried them, remove the symlinks */
1198 SavedLinkInformation
= RemoveSavedLinks(DeviceExtension
, UniqueId
);
1200 IsDrvLetter
= FALSE
;
1202 IsVolumeName
= FALSE
;
1203 /* For all the symlinks */
1204 for (i
= 0; i
< SymLinkCount
; i
++)
1206 /* Check if our device is a volume */
1207 if (MOUNTMGR_IS_VOLUME_NAME(&(SymLinks
[i
])))
1209 IsVolumeName
= TRUE
;
1211 /* If it has a drive letter */
1212 else if (IsDriveLetter(&(SymLinks
[i
])))
1216 DeleteFromLocalDatabase(&(SymLinks
[i
]), UniqueId
);
1225 /* And recreate the symlink to our device */
1226 Status
= GlobalCreateSymbolicLink(&(SymLinks
[i
]), &TargetDeviceName
);
1227 if (!NT_SUCCESS(Status
))
1231 if ((SavedLinkInformation
&& !RedirectSavedLink(SavedLinkInformation
, &(SymLinks
[i
]), &TargetDeviceName
)) ||
1232 !SavedLinkInformation
)
1234 Status
= QueryDeviceInformation(&(SymLinks
[i
]), &DeviceName
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
1235 if (NT_SUCCESS(Status
))
1237 LinkError
= RtlEqualUnicodeString(&TargetDeviceName
, &DeviceName
, TRUE
);
1238 FreePool(DeviceName
.Buffer
);
1243 if (IsDriveLetter(&(SymLinks
[i
])))
1245 IsDrvLetter
= FALSE
;
1246 DeleteFromLocalDatabase(&(SymLinks
[i
]), UniqueId
);
1249 FreePool(SymLinks
[i
].Buffer
);
1255 /* Check if was offline */
1256 if (IsOffline(&(SymLinks
[i
])))
1261 /* Finally, associate this symlink with the device */
1262 SymlinkInformation
= AllocatePool(sizeof(SYMLINK_INFORMATION
));
1263 if (!SymlinkInformation
)
1265 GlobalDeleteSymbolicLink(&(SymLinks
[i
]));
1266 FreePool(SymLinks
[i
].Buffer
);
1270 SymlinkInformation
->Name
= SymLinks
[i
];
1271 SymlinkInformation
->Online
= TRUE
;
1273 InsertTailList(&(DeviceInformation
->SymbolicLinksListHead
),
1274 &(SymlinkInformation
->SymbolicLinksListEntry
));
1277 /* Now, for all the recreated symlinks, notify their recreation */
1278 for (NextEntry
= DeviceInformation
->SymbolicLinksListHead
.Flink
;
1279 NextEntry
!= &(DeviceInformation
->SymbolicLinksListHead
);
1280 NextEntry
= NextEntry
->Flink
)
1282 SymlinkInformation
= CONTAINING_RECORD(NextEntry
, SYMLINK_INFORMATION
, SymbolicLinksListEntry
);
1284 SendLinkCreated(&(SymlinkInformation
->Name
));
1287 /* If we had saved links, it's time to free them */
1288 if (SavedLinkInformation
)
1290 MountMgrFreeSavedLink(SavedLinkInformation
);
1293 /* If our device doesn't have a volume name */
1296 /* It's time to create one */
1297 Status
= CreateNewVolumeName(&VolumeName
, NULL
);
1298 if (NT_SUCCESS(Status
))
1300 /* Write it to global database */
1301 RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE
,
1306 UniqueId
->UniqueIdLength
);
1308 /* And create the symlink */
1309 GlobalCreateSymbolicLink(&VolumeName
, &TargetDeviceName
);
1311 SymlinkInformation
= AllocatePool(sizeof(SYMLINK_INFORMATION
));
1312 if (!SymlinkInformation
)
1314 FreePool(VolumeName
.Buffer
);
1316 /* Finally, associate it with the device and notify creation */
1319 SymlinkInformation
->Name
= VolumeName
;
1320 SymlinkInformation
->Online
= TRUE
;
1321 InsertTailList(&(DeviceInformation
->SymbolicLinksListHead
),
1322 &(SymlinkInformation
->SymbolicLinksListEntry
));
1324 SendLinkCreated(&VolumeName
);
1329 /* If we found a drive letter, then, ignore the suggested one */
1332 DeviceInformation
->SuggestedDriveLetter
= 0;
1334 /* Else, it's time to set up one */
1335 else if (!DeviceExtension
->NoAutoMount
&& !DeviceInformation
->Removable
&&
1336 DeviceExtension
->AutomaticDriveLetter
&& HasGptDriveLetter
&&
1337 DeviceInformation
->SuggestedDriveLetter
&&
1338 !HasNoDriveLetterEntry(UniqueId
))
1340 /* Create a new drive letter */
1341 Status
= CreateNewDriveLetterName(&DriveLetter
, &TargetDeviceName
,
1342 DeviceInformation
->SuggestedDriveLetter
,
1344 if (!NT_SUCCESS(Status
))
1346 CreateNoDriveLetterEntry(UniqueId
);
1350 /* Save it to global database */
1351 RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE
,
1356 UniqueId
->UniqueIdLength
);
1358 /* Associate it with the device and notify creation */
1359 SymlinkInformation
= AllocatePool(sizeof(SYMLINK_INFORMATION
));
1360 if (!SymlinkInformation
)
1362 FreePool(DriveLetter
.Buffer
);
1366 SymlinkInformation
->Name
= DriveLetter
;
1367 SymlinkInformation
->Online
= TRUE
;
1368 InsertTailList(&(DeviceInformation
->SymbolicLinksListHead
),
1369 &(SymlinkInformation
->SymbolicLinksListEntry
));
1371 SendLinkCreated(&DriveLetter
);
1376 /* If required, register for notifications about the device */
1379 RegisterForTargetDeviceNotification(DeviceExtension
, DeviceInformation
);
1382 /* Finally, insert the device into our devices list */
1383 InsertTailList(&(DeviceExtension
->DeviceListHead
), &(DeviceInformation
->DeviceListEntry
));
1385 /* Copy device unique ID */
1386 NewUniqueId
= AllocatePool(UniqueId
->UniqueIdLength
+ sizeof(MOUNTDEV_UNIQUE_ID
));
1389 NewUniqueId
->UniqueIdLength
= UniqueId
->UniqueIdLength
;
1390 RtlCopyMemory(NewUniqueId
->UniqueId
, UniqueId
->UniqueId
, UniqueId
->UniqueIdLength
);
1393 /* If device's offline or valid, skip its notifications */
1396 DeviceInformation
->SkipNotifications
= TRUE
;
1399 /* In case device is valid and is set to no automount,
1402 if (DeviceExtension
->NoAutoMount
|| IsDrvLetter
)
1404 IsOff
= !DeviceInformation
->SkipNotifications
;
1411 /* Finally, release the exclusive lock */
1412 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
, 1, FALSE
);
1414 /* If device is not offline, notify its arrival */
1417 SendOnlineNotification(SymbolicName
);
1420 /* If we had symlinks (from storage), free them */
1426 /* Notify about unique id change */
1429 IssueUniqueIdChangeNotify(DeviceExtension
, SymbolicName
, NewUniqueId
);
1430 FreePool(NewUniqueId
);
1433 /* If this drive was set to have a drive letter automatically
1434 * Now it's back, local databases sync will be required
1436 if (DeviceExtension
->AutomaticDriveLetter
)
1438 KeWaitForSingleObject(&(DeviceExtension
->DeviceLock
), Executive
, KernelMode
, FALSE
, NULL
);
1440 ReconcileThisDatabaseWithMaster(DeviceExtension
, DeviceInformation
);
1442 NextEntry
= DeviceExtension
->DeviceListHead
.Flink
;
1443 CurrentDevice
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
1444 while (CurrentDevice
!= DeviceInformation
)
1446 if (!CurrentDevice
->NoDatabase
)
1448 ReconcileThisDatabaseWithMaster(DeviceExtension
, CurrentDevice
);
1451 NextEntry
= NextEntry
->Flink
;
1452 CurrentDevice
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
1455 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
, 1, FALSE
);
1458 return STATUS_SUCCESS
;
1465 MountMgrMountedDeviceRemoval(IN PDEVICE_EXTENSION DeviceExtension
,
1466 IN PUNICODE_STRING DeviceName
)
1468 PLIST_ENTRY NextEntry
, DeviceEntry
;
1469 PUNIQUE_ID_REPLICATE UniqueIdReplicate
;
1470 PSYMLINK_INFORMATION SymlinkInformation
;
1471 PASSOCIATED_DEVICE_ENTRY AssociatedDevice
;
1472 PSAVED_LINK_INFORMATION SavedLinkInformation
= NULL
;
1473 PDEVICE_INFORMATION DeviceInformation
, CurrentDevice
;
1475 /* Acquire device exclusively */
1476 KeWaitForSingleObject(&(DeviceExtension
->DeviceLock
), Executive
, KernelMode
, FALSE
, NULL
);
1478 /* Look for the leaving device */
1479 for (NextEntry
= DeviceExtension
->DeviceListHead
.Flink
;
1480 NextEntry
!= &(DeviceExtension
->DeviceListHead
);
1481 NextEntry
= NextEntry
->Flink
)
1483 DeviceInformation
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
1485 if (!RtlCompareUnicodeString(&(DeviceInformation
->SymbolicName
), DeviceName
, TRUE
))
1491 /* If we found it */
1492 if (NextEntry
!= &(DeviceExtension
->DeviceListHead
))
1494 /* If it's asked to keep links, then, prepare to save them */
1495 if (DeviceInformation
->KeepLinks
)
1497 SavedLinkInformation
= AllocatePool(sizeof(SAVED_LINK_INFORMATION
));
1498 if (!SavedLinkInformation
)
1500 DeviceInformation
->KeepLinks
= FALSE
;
1504 /* If it's possible (and asked), start to save them */
1505 if (DeviceInformation
->KeepLinks
)
1507 InsertTailList(&(DeviceExtension
->SavedLinksListHead
), &(SavedLinkInformation
->SavedLinksListEntry
));
1508 InitializeListHead(&(SavedLinkInformation
->SymbolicLinksListHead
));
1509 SavedLinkInformation
->UniqueId
= DeviceInformation
->UniqueId
;
1512 /* For all the symlinks */
1513 while (!IsListEmpty(&(DeviceInformation
->SymbolicLinksListHead
)))
1515 NextEntry
= RemoveHeadList(&(DeviceInformation
->SymbolicLinksListHead
));
1516 SymlinkInformation
= CONTAINING_RECORD(NextEntry
, SYMLINK_INFORMATION
, SymbolicLinksListEntry
);
1518 /* If we have to, save the link */
1519 if (DeviceInformation
->KeepLinks
)
1521 InsertTailList(&(SavedLinkInformation
->SymbolicLinksListHead
), &(SymlinkInformation
->SymbolicLinksListEntry
));
1523 /* Otherwise, just release it */
1526 GlobalDeleteSymbolicLink(&(SymlinkInformation
->Name
));
1527 FreePool(SymlinkInformation
->Name
.Buffer
);
1528 FreePool(SymlinkInformation
);
1532 /* Free all the replicated unique IDs */
1533 while (!IsListEmpty(&(DeviceInformation
->ReplicatedUniqueIdsListHead
)))
1535 NextEntry
= RemoveHeadList(&(DeviceInformation
->ReplicatedUniqueIdsListHead
));
1536 UniqueIdReplicate
= CONTAINING_RECORD(NextEntry
, UNIQUE_ID_REPLICATE
, ReplicatedUniqueIdsListEntry
);
1539 FreePool(UniqueIdReplicate
->UniqueId
);
1540 FreePool(UniqueIdReplicate
);
1543 while (!IsListEmpty(&(DeviceInformation
->AssociatedDevicesHead
)))
1545 NextEntry
= RemoveHeadList(&(DeviceInformation
->AssociatedDevicesHead
));
1546 AssociatedDevice
= CONTAINING_RECORD(NextEntry
, ASSOCIATED_DEVICE_ENTRY
, AssociatedDevicesEntry
);
1548 DeviceInformation
->NoDatabase
= TRUE
;
1549 FreePool(AssociatedDevice
->String
.Buffer
);
1550 FreePool(AssociatedDevice
);
1553 /* Remove device from the device list */
1554 RemoveEntryList(&(DeviceInformation
->DeviceListEntry
));
1556 /* If there are still devices, check if some were associated with ours */
1557 if (!IsListEmpty(&(DeviceInformation
->DeviceListEntry
)))
1559 for (NextEntry
= DeviceExtension
->DeviceListHead
.Flink
;
1560 NextEntry
!= &(DeviceExtension
->DeviceListHead
);
1561 NextEntry
= NextEntry
->Flink
)
1563 CurrentDevice
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
1565 /* And then, remove them */
1566 DeviceEntry
= CurrentDevice
->AssociatedDevicesHead
.Flink
;
1567 while (DeviceEntry
!= &(CurrentDevice
->AssociatedDevicesHead
))
1569 AssociatedDevice
= CONTAINING_RECORD(NextEntry
, ASSOCIATED_DEVICE_ENTRY
, AssociatedDevicesEntry
);
1570 DeviceEntry
= DeviceEntry
->Flink
;
1572 if (AssociatedDevice
->DeviceInformation
!= DeviceInformation
)
1577 RemoveEntryList(&(AssociatedDevice
->AssociatedDevicesEntry
));
1578 FreePool(AssociatedDevice
->String
.Buffer
);
1579 FreePool(AssociatedDevice
);
1584 /* Finally, clean up device name, symbolic name */
1585 FreePool(DeviceInformation
->SymbolicName
.Buffer
);
1586 if (!DeviceInformation
->KeepLinks
)
1588 FreePool(DeviceInformation
->UniqueId
);
1590 FreePool(DeviceInformation
->DeviceName
.Buffer
);
1592 /* Unregister notifications */
1593 if (DeviceInformation
->TargetDeviceNotificationEntry
)
1595 IoUnregisterPlugPlayNotification(DeviceInformation
->TargetDeviceNotificationEntry
);
1599 FreePool(DeviceInformation
);
1603 /* We didn't find device, perhaps because it was offline */
1604 for (NextEntry
= DeviceExtension
->OfflineDeviceListHead
.Flink
;
1605 NextEntry
!= &(DeviceExtension
->OfflineDeviceListHead
);
1606 NextEntry
= NextEntry
->Flink
)
1608 DeviceInformation
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
1610 /* It was, remove it */
1611 if (RtlCompareUnicodeString(&(DeviceInformation
->SymbolicName
), DeviceName
, TRUE
) == 0)
1613 RemoveEntryList(&(DeviceInformation
->DeviceListEntry
));
1614 MountMgrFreeDeadDeviceInfo(DeviceInformation
);
1620 /* Releave driver */
1621 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
, 1, FALSE
);
1629 MountMgrMountedDeviceNotification(IN PVOID NotificationStructure
,
1633 PDEVICE_EXTENSION DeviceExtension
;
1634 PDEVICE_INTERFACE_CHANGE_NOTIFICATION Notification
;
1636 /* Notification for a device arrived */
1637 /* Disable hard errors */
1638 OldState
= PsGetThreadHardErrorsAreDisabled(PsGetCurrentThread());
1639 PsSetThreadHardErrorsAreDisabled(PsGetCurrentThread(), TRUE
);
1641 DeviceExtension
= Context
;
1642 Notification
= NotificationStructure
;
1644 /* Dispatch according to the event */
1645 if (IsEqualGUID(&(Notification
->Event
), &GUID_DEVICE_INTERFACE_ARRIVAL
))
1647 MountMgrMountedDeviceArrival(DeviceExtension
, Notification
->SymbolicLinkName
, FALSE
);
1649 else if (IsEqualGUID(&(Notification
->Event
), &GUID_DEVICE_INTERFACE_REMOVAL
))
1651 MountMgrMountedDeviceRemoval(DeviceExtension
, Notification
->SymbolicLinkName
);
1654 /* Reset hard errors */
1655 PsSetThreadHardErrorsAreDisabled(PsGetCurrentThread(), OldState
);
1657 return STATUS_SUCCESS
;
1665 MountMgrCreateClose(IN PDEVICE_OBJECT DeviceObject
,
1668 PIO_STACK_LOCATION Stack
;
1669 NTSTATUS Status
= STATUS_SUCCESS
;
1671 UNREFERENCED_PARAMETER(DeviceObject
);
1673 Stack
= IoGetCurrentIrpStackLocation(Irp
);
1675 /* Allow driver opening for communication
1676 * as long as it's not taken for a directory
1678 if (Stack
->MajorFunction
== IRP_MJ_CREATE
&&
1679 Stack
->Parameters
.Create
.Options
& FILE_DIRECTORY_FILE
)
1681 Status
= STATUS_NOT_A_DIRECTORY
;
1684 Irp
->IoStatus
.Status
= Status
;
1685 Irp
->IoStatus
.Information
= 0;
1686 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1695 MountMgrCancel(IN PDEVICE_OBJECT DeviceObject
,
1698 UNREFERENCED_PARAMETER(DeviceObject
);
1700 RemoveEntryList(&(Irp
->Tail
.Overlay
.ListEntry
));
1702 IoReleaseCancelSpinLock(Irp
->CancelIrql
);
1704 Irp
->IoStatus
.Information
= 0;
1705 Irp
->IoStatus
.Status
= STATUS_CANCELLED
;
1706 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1714 MountMgrCleanup(IN PDEVICE_OBJECT DeviceObject
,
1719 PLIST_ENTRY NextEntry
;
1720 PFILE_OBJECT FileObject
;
1721 PIO_STACK_LOCATION Stack
;
1722 PDEVICE_EXTENSION DeviceExtension
;
1724 DeviceExtension
= DeviceObject
->DeviceExtension
;
1725 Stack
= IoGetCurrentIrpStackLocation(Irp
);
1726 FileObject
= Stack
->FileObject
;
1728 IoAcquireCancelSpinLock(&OldIrql
);
1730 /* If IRP list if empty, it's OK */
1731 if (IsListEmpty(&(DeviceExtension
->IrpListHead
)))
1733 IoReleaseCancelSpinLock(OldIrql
);
1735 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1736 Irp
->IoStatus
.Information
= 0;
1737 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1739 return STATUS_SUCCESS
;
1742 /* Otherwise, cancel all the IRPs */
1743 NextEntry
= &(DeviceExtension
->IrpListHead
);
1746 ListIrp
= CONTAINING_RECORD(NextEntry
, IRP
, Tail
.Overlay
.ListEntry
);
1747 if (IoGetCurrentIrpStackLocation(ListIrp
)->FileObject
== FileObject
)
1749 ListIrp
->Cancel
= TRUE
;
1750 ListIrp
->CancelIrql
= OldIrql
;
1751 ListIrp
->CancelRoutine
= NULL
;
1752 MountMgrCancel(DeviceObject
, ListIrp
);
1754 IoAcquireCancelSpinLock(&OldIrql
);
1757 NextEntry
= NextEntry
->Flink
;
1759 while (NextEntry
!= &(DeviceExtension
->IrpListHead
));
1761 IoReleaseCancelSpinLock(OldIrql
);
1763 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1764 Irp
->IoStatus
.Information
= 0;
1765 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1767 return STATUS_SUCCESS
;
1775 MountMgrShutdown(IN PDEVICE_OBJECT DeviceObject
,
1778 PDEVICE_EXTENSION DeviceExtension
;
1780 DeviceExtension
= DeviceObject
->DeviceExtension
;
1782 InterlockedExchange(&Unloading
, TRUE
);
1784 KeInitializeEvent(&UnloadEvent
, NotificationEvent
, FALSE
);
1786 /* Wait for workers */
1787 if (InterlockedIncrement(&(DeviceExtension
->WorkerReferences
)))
1789 KeReleaseSemaphore(&(DeviceExtension
->WorkerSemaphore
),
1793 KeWaitForSingleObject(&UnloadEvent
, Executive
, KernelMode
, FALSE
, NULL
);
1797 InterlockedDecrement(&(DeviceExtension
->WorkerReferences
));
1800 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1801 Irp
->IoStatus
.Information
= 0;
1802 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1804 return STATUS_SUCCESS
;
1807 /* FUNCTIONS ****************************************************************/
1811 DriverEntry(IN PDRIVER_OBJECT DriverObject
,
1812 IN PUNICODE_STRING RegistryPath
)
1815 PDEVICE_OBJECT DeviceObject
;
1816 PDEVICE_EXTENSION DeviceExtension
;
1818 RtlCreateRegistryKey(RTL_REGISTRY_ABSOLUTE
, DatabasePath
);
1820 Status
= IoCreateDevice(DriverObject
,
1821 sizeof(DEVICE_EXTENSION
),
1823 FILE_DEVICE_NETWORK
,
1824 FILE_DEVICE_SECURE_OPEN
,
1827 if (!NT_SUCCESS(Status
))
1832 DriverObject
->DriverUnload
= MountMgrUnload
;
1834 DeviceExtension
= DeviceObject
->DeviceExtension
;
1835 RtlZeroMemory(DeviceExtension
, sizeof(DEVICE_EXTENSION
));
1836 DeviceExtension
->DeviceObject
= DeviceObject
;
1837 DeviceExtension
->DriverObject
= DriverObject
;
1839 InitializeListHead(&(DeviceExtension
->DeviceListHead
));
1840 InitializeListHead(&(DeviceExtension
->OfflineDeviceListHead
));
1842 KeInitializeSemaphore(&(DeviceExtension
->DeviceLock
), 1, 1);
1843 KeInitializeSemaphore(&(DeviceExtension
->RemoteDatabaseLock
), 1, 1);
1845 InitializeListHead(&(DeviceExtension
->IrpListHead
));
1846 DeviceExtension
->EpicNumber
= 1;
1848 InitializeListHead(&(DeviceExtension
->SavedLinksListHead
));
1850 InitializeListHead(&(DeviceExtension
->WorkerQueueListHead
));
1851 KeInitializeSemaphore(&(DeviceExtension
->WorkerSemaphore
), 0, MAXLONG
);
1852 DeviceExtension
->WorkerReferences
= -1;
1853 KeInitializeSpinLock(&(DeviceExtension
->WorkerLock
));
1855 InitializeListHead(&(DeviceExtension
->UniqueIdWorkerItemListHead
));
1856 InitializeListHead(&(DeviceExtension
->OnlineNotificationListHead
));
1857 DeviceExtension
->OnlineNotificationCount
= 1;
1859 DeviceExtension
->RegistryPath
.Length
= RegistryPath
->Length
;
1860 DeviceExtension
->RegistryPath
.MaximumLength
= RegistryPath
->Length
+ sizeof(WCHAR
);
1861 DeviceExtension
->RegistryPath
.Buffer
= AllocatePool(DeviceExtension
->RegistryPath
.MaximumLength
);
1862 if (!DeviceExtension
->RegistryPath
.Buffer
)
1864 IoDeleteDevice(DeviceObject
);
1865 return STATUS_INSUFFICIENT_RESOURCES
;
1868 RtlCopyUnicodeString(&(DeviceExtension
->RegistryPath
), RegistryPath
);
1870 DeviceExtension
->NoAutoMount
= MountmgrReadNoAutoMount(&(DeviceExtension
->RegistryPath
));
1872 GlobalCreateSymbolicLink(&DosDevicesMount
, &DeviceMount
);
1874 /* Register for device arrival & removal. Ask to be notified for already
1877 Status
= IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange
,
1878 PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES
,
1879 &MountedDevicesGuid
,
1881 MountMgrMountedDeviceNotification
,
1883 &(DeviceExtension
->NotificationEntry
));
1885 if (!NT_SUCCESS(Status
))
1887 IoDeleteDevice(DeviceObject
);
1891 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] =
1892 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = MountMgrCreateClose
;
1893 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = MountMgrDeviceControl
;
1894 DriverObject
->MajorFunction
[IRP_MJ_CLEANUP
] = MountMgrCleanup
;
1895 DriverObject
->MajorFunction
[IRP_MJ_SHUTDOWN
] = MountMgrShutdown
;
1897 gdeviceObject
= DeviceObject
;
1899 Status
= IoRegisterShutdownNotification(DeviceObject
);
1900 if (!NT_SUCCESS(Status
))
1902 IoDeleteDevice(DeviceObject
);