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}};
40 PWSTR Cunc
= L
"\\??\\C:";
44 * - MountMgrQueryDosVolumePath
45 * - MountMgrQueryDosVolumePaths
46 * - MountMgrQueryVolumePaths
47 * - MountMgrValidateBackPointer
48 * - MountMgrVolumeMountPointCreated
49 * - MountMgrVolumeMountPointDeleted
50 * - ReconcileThisDatabaseWithMasterWorker
57 IsOffline(PUNICODE_STRING SymbolicName
)
60 ULONG IsOffline
, Default
;
61 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
63 /* Prepare to look in the registry to see if
64 * given volume is offline
66 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
67 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
68 QueryTable
[0].Name
= SymbolicName
->Buffer
;
69 QueryTable
[0].EntryContext
= &IsOffline
;
70 QueryTable
[0].DefaultType
= REG_DWORD
;
71 QueryTable
[0].DefaultLength
= sizeof(ULONG
);
72 QueryTable
[0].DefaultData
= &Default
;
77 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
82 if (!NT_SUCCESS(Status
))
87 return (IsOffline
!= 0);
94 HasDriveLetter(IN PDEVICE_INFORMATION DeviceInformation
)
96 PLIST_ENTRY NextEntry
;
97 PSYMLINK_INFORMATION SymlinkInfo
;
99 /* To have a drive letter, a device must have symbolic links */
100 if (IsListEmpty(&(DeviceInformation
->SymbolicLinksListHead
)))
105 /* Browse all the links untill a drive letter is found */
106 NextEntry
= &(DeviceInformation
->SymbolicLinksListHead
);
109 SymlinkInfo
= CONTAINING_RECORD(NextEntry
, SYMLINK_INFORMATION
, SymbolicLinksListEntry
);
111 if (SymlinkInfo
->Online
)
113 if (IsDriveLetter(&(SymlinkInfo
->Name
)))
119 NextEntry
= NextEntry
->Flink
;
120 } while (NextEntry
!= &(DeviceInformation
->SymbolicLinksListHead
));
129 CreateNewDriveLetterName(OUT PUNICODE_STRING DriveLetter
,
130 IN PUNICODE_STRING DeviceName
,
132 IN PMOUNTDEV_UNIQUE_ID UniqueId OPTIONAL
)
134 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
136 /* Allocate a big enough buffer to contain the symbolic link */
137 DriveLetter
->MaximumLength
= sizeof(DosDevices
.Buffer
) + 3 * sizeof(WCHAR
);
138 DriveLetter
->Buffer
= AllocatePool(sizeof(DosDevices
.Buffer
) + 3 * sizeof(WCHAR
));
139 if (!DriveLetter
->Buffer
)
141 return STATUS_INSUFFICIENT_RESOURCES
;
145 RtlCopyUnicodeString(DriveLetter
, &DosDevices
);
147 /* Update string to reflect real contents */
148 DriveLetter
->Length
= sizeof(DosDevices
.Buffer
) + 2 * sizeof(WCHAR
);
149 DriveLetter
->Buffer
[(sizeof(DosDevices
.Buffer
) + 2 * sizeof(WCHAR
)) / sizeof (WCHAR
)] = UNICODE_NULL
;
150 DriveLetter
->Buffer
[(sizeof(DosDevices
.Buffer
) + sizeof(WCHAR
)) / sizeof (WCHAR
)] = L
':';
152 /* If caller wants a no drive entry */
153 if (Letter
== (UCHAR
)-1)
155 /* Then, create a no letter entry */
156 CreateNoDriveLetterEntry(UniqueId
);
157 FreePool(DriveLetter
->Buffer
);
158 return STATUS_UNSUCCESSFUL
;
162 /* Use the letter given by the caller */
163 DriveLetter
->Buffer
[sizeof(DosDevices
.Buffer
) / sizeof(WCHAR
)] = (WCHAR
)Letter
;
164 Status
= GlobalCreateSymbolicLink(DriveLetter
, DeviceName
);
165 if (NT_SUCCESS(Status
))
171 /* If caller didn't provide a letter, let's find one for him.
172 * If device is a floppy, start with letter A
174 if (RtlPrefixUnicodeString(&DeviceFloppy
, DeviceName
, TRUE
))
180 /* Otherwise, if device is a cd rom, then, start with D.
181 * Finally, if a disk, use C
183 Letter
= RtlPrefixUnicodeString(&DeviceCdRom
, DeviceName
, TRUE
) + 'C';
186 /* Try to affect a letter (up to Z, ofc) until it's possible */
187 for (; Letter
<= 'Z'; Letter
++)
189 DriveLetter
->Buffer
[sizeof(DosDevices
.Buffer
) / sizeof(WCHAR
)] = (WCHAR
)Letter
;
190 Status
= GlobalCreateSymbolicLink(DriveLetter
, DeviceName
);
191 if (NT_SUCCESS(Status
))
197 /* We failed to allocate a letter */
198 FreePool(DriveLetter
->Buffer
);
206 QueryDeviceInformation(IN PUNICODE_STRING SymbolicName
,
207 OUT PUNICODE_STRING DeviceName OPTIONAL
,
208 OUT PMOUNTDEV_UNIQUE_ID
* UniqueId OPTIONAL
,
209 OUT PBOOLEAN Removable OPTIONAL
,
210 OUT PBOOLEAN GptDriveLetter OPTIONAL
,
211 OUT PBOOLEAN HasGuid OPTIONAL
,
212 IN OUT LPGUID StableGuid OPTIONAL
,
213 OUT PBOOLEAN Valid OPTIONAL
)
221 PMOUNTDEV_UNIQUE_ID Id
;
222 PFILE_OBJECT FileObject
;
223 PIO_STACK_LOCATION Stack
;
224 PDEVICE_OBJECT DeviceObject
;
225 IO_STATUS_BLOCK IoStatusBlock
;
226 PARTITION_INFORMATION_EX PartitionInfo
;
227 STORAGE_DEVICE_NUMBER StorageDeviceNumber
;
228 VOLUME_GET_GPT_ATTRIBUTES_INFORMATION GptAttributes
;
230 /* Get device associated with the symbolic name */
231 Status
= IoGetDeviceObjectPointer(SymbolicName
,
232 FILE_READ_ATTRIBUTES
,
235 if (!NT_SUCCESS(Status
))
240 /* The associate FO can't have a file name */
241 if (FileObject
->FileName
.Length
)
243 ObDereferenceObject(FileObject
);
244 return STATUS_OBJECT_NAME_NOT_FOUND
;
247 /* Check if it's removable & return to the user (if asked to) */
248 IsRemovable
= (FileObject
->DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
);
251 *Removable
= IsRemovable
;
254 /* Get the attached device */
255 DeviceObject
= IoGetAttachedDeviceReference(FileObject
->DeviceObject
);
257 /* If we've been asked for a GPT drive letter */
260 /* Consider it has one */
261 *GptDriveLetter
= TRUE
;
265 /* Query the GPT attributes */
266 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
267 Irp
= IoBuildDeviceIoControlRequest(IOCTL_VOLUME_GET_GPT_ATTRIBUTES
,
272 sizeof(GptAttributes
),
278 ObDereferenceObject(DeviceObject
);
279 ObDereferenceObject(FileObject
);
280 return STATUS_INSUFFICIENT_RESOURCES
;
283 Status
= IoCallDriver(DeviceObject
, Irp
);
284 if (Status
== STATUS_PENDING
)
286 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
287 Status
= IoStatusBlock
.Status
;
290 /* In case of failure, don't fail, that's no vital */
291 if (!NT_SUCCESS(Status
))
293 Status
= STATUS_SUCCESS
;
295 /* Check if it has a drive letter */
296 else if (!(GptAttributes
.GptAttributes
&
297 GPT_BASIC_DATA_ATTRIBUTE_NO_DRIVE_LETTER
))
299 *GptDriveLetter
= FALSE
;
304 /* If caller wants to know if there's valid contents */
307 /* Suppose it's not OK */
312 /* Query partitions information */
313 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
314 Irp
= IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_PARTITION_INFO_EX
,
319 sizeof(PartitionInfo
),
325 ObDereferenceObject(DeviceObject
);
326 ObDereferenceObject(FileObject
);
327 return STATUS_INSUFFICIENT_RESOURCES
;
330 Status
= IoCallDriver(DeviceObject
, Irp
);
331 if (Status
== STATUS_PENDING
)
333 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
334 Status
= IoStatusBlock
.Status
;
337 /* Once again here, failure isn't major */
338 if (!NT_SUCCESS(Status
))
340 Status
= STATUS_SUCCESS
;
342 /* Verify we know something in */
343 else if (PartitionInfo
.PartitionStyle
== PARTITION_STYLE_MBR
&&
344 IsRecognizedPartition(PartitionInfo
.Mbr
.PartitionType
))
349 /* It looks correct, ensure it is & query device number */
352 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
353 Irp
= IoBuildDeviceIoControlRequest(IOCTL_STORAGE_GET_DEVICE_NUMBER
,
357 &StorageDeviceNumber
,
358 sizeof(StorageDeviceNumber
),
364 ObDereferenceObject(DeviceObject
);
365 ObDereferenceObject(FileObject
);
366 return STATUS_INSUFFICIENT_RESOURCES
;
369 Status
= IoCallDriver(DeviceObject
, Irp
);
370 if (Status
== STATUS_PENDING
)
372 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
373 Status
= IoStatusBlock
.Status
;
376 if (!NT_SUCCESS(Status
))
378 Status
= STATUS_SUCCESS
;
388 /* If caller needs device name */
391 /* Allocate a buffer just to request length */
392 Name
= AllocatePool(sizeof(MOUNTDEV_NAME
));
395 ObDereferenceObject(DeviceObject
);
396 ObDereferenceObject(FileObject
);
397 return STATUS_INSUFFICIENT_RESOURCES
;
400 /* Query device name */
401 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
402 Irp
= IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_DEVICE_NAME
,
407 sizeof(MOUNTDEV_NAME
),
414 ObDereferenceObject(DeviceObject
);
415 ObDereferenceObject(FileObject
);
416 return STATUS_INSUFFICIENT_RESOURCES
;
419 Stack
= IoGetNextIrpStackLocation(Irp
);
420 Stack
->FileObject
= FileObject
;
422 Status
= IoCallDriver(DeviceObject
, Irp
);
423 if (Status
== STATUS_PENDING
)
425 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
426 Status
= IoStatusBlock
.Status
;
429 /* Now, we've got the correct length */
430 if (Status
== STATUS_BUFFER_OVERFLOW
)
432 Size
= Name
->NameLength
+ sizeof(MOUNTDEV_NAME
);
436 /* Allocate proper size */
437 Name
= AllocatePool(Size
);
440 ObDereferenceObject(DeviceObject
);
441 ObDereferenceObject(FileObject
);
442 return STATUS_INSUFFICIENT_RESOURCES
;
445 /* And query name (for real that time) */
446 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
447 Irp
= IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_DEVICE_NAME
,
459 ObDereferenceObject(DeviceObject
);
460 ObDereferenceObject(FileObject
);
461 return STATUS_INSUFFICIENT_RESOURCES
;
464 Stack
= IoGetNextIrpStackLocation(Irp
);
465 Stack
->FileObject
= FileObject
;
467 Status
= IoCallDriver(DeviceObject
, Irp
);
468 if (Status
== STATUS_PENDING
)
470 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
471 Status
= IoStatusBlock
.Status
;
475 /* Here we can't fail and assume default value */
476 if (!NT_SUCCESS(Status
))
479 ObDereferenceObject(DeviceObject
);
480 ObDereferenceObject(FileObject
);
484 /* Copy back found name to the caller */
485 DeviceName
->Length
= Name
->NameLength
;
486 DeviceName
->MaximumLength
= Name
->NameLength
+ sizeof(WCHAR
);
487 DeviceName
->Buffer
= AllocatePool(DeviceName
->MaximumLength
);
488 if (!DeviceName
->Buffer
)
491 ObDereferenceObject(DeviceObject
);
492 ObDereferenceObject(FileObject
);
493 return STATUS_INSUFFICIENT_RESOURCES
;
496 RtlCopyMemory(DeviceName
->Buffer
, Name
->Name
, Name
->NameLength
);
497 DeviceName
->Buffer
[Name
->NameLength
/ sizeof(WCHAR
)] = UNICODE_NULL
;
501 /* If caller wants device unique ID */
504 /* Prepare buffer to probe length */
505 Id
= AllocatePool(sizeof(MOUNTDEV_UNIQUE_ID
));
508 ObDereferenceObject(DeviceObject
);
509 ObDereferenceObject(FileObject
);
510 return STATUS_INSUFFICIENT_RESOURCES
;
513 /* Query unique ID length */
514 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
515 Irp
= IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_UNIQUE_ID
,
520 sizeof(MOUNTDEV_UNIQUE_ID
),
527 ObDereferenceObject(DeviceObject
);
528 ObDereferenceObject(FileObject
);
529 return STATUS_INSUFFICIENT_RESOURCES
;
532 Stack
= IoGetNextIrpStackLocation(Irp
);
533 Stack
->FileObject
= FileObject
;
535 Status
= IoCallDriver(DeviceObject
, Irp
);
536 if (Status
== STATUS_PENDING
)
538 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
539 Status
= IoStatusBlock
.Status
;
542 /* Retry with appropriate length */
543 if (Status
== STATUS_BUFFER_OVERFLOW
)
545 Size
= Id
->UniqueIdLength
+ sizeof(MOUNTDEV_UNIQUE_ID
);
549 /* Allocate the correct buffer */
550 Id
= AllocatePool(Size
);
553 ObDereferenceObject(DeviceObject
);
554 ObDereferenceObject(FileObject
);
555 return STATUS_INSUFFICIENT_RESOURCES
;
558 /* Query unique ID */
559 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
560 Irp
= IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_DEVICE_NAME
,
572 ObDereferenceObject(DeviceObject
);
573 ObDereferenceObject(FileObject
);
574 return STATUS_INSUFFICIENT_RESOURCES
;
577 Stack
= IoGetNextIrpStackLocation(Irp
);
578 Stack
->FileObject
= FileObject
;
580 Status
= IoCallDriver(DeviceObject
, Irp
);
581 if (Status
== STATUS_PENDING
)
583 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
584 Status
= IoStatusBlock
.Status
;
588 /* Hands back unique ID */
589 if (NT_SUCCESS(Status
))
595 /* In case of failure, also free the rest */
597 if (DeviceName
->Length
)
599 FreePool(DeviceName
->Buffer
);
602 ObDereferenceObject(DeviceObject
);
603 ObDereferenceObject(FileObject
);
609 /* If user wants to know about GUID */
612 /* Query device stable GUID */
613 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
614 Irp
= IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_STABLE_GUID
,
625 ObDereferenceObject(DeviceObject
);
626 ObDereferenceObject(FileObject
);
627 return STATUS_INSUFFICIENT_RESOURCES
;
630 Stack
= IoGetNextIrpStackLocation(Irp
);
631 Stack
->FileObject
= FileObject
;
633 Status
= IoCallDriver(DeviceObject
, Irp
);
634 if (Status
== STATUS_PENDING
)
636 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
637 Status
= IoStatusBlock
.Status
;
640 *HasGuid
= NT_SUCCESS(Status
);
643 ObDereferenceObject(DeviceObject
);
644 ObDereferenceObject(FileObject
);
652 FindDeviceInfo(IN PDEVICE_EXTENSION DeviceExtension
,
653 IN PUNICODE_STRING SymbolicName
,
654 IN BOOLEAN DeviceNameGiven
,
655 OUT PDEVICE_INFORMATION
* DeviceInformation
)
658 PLIST_ENTRY NextEntry
;
659 UNICODE_STRING DeviceName
;
660 PDEVICE_INFORMATION DeviceInfo
= NULL
;
662 /* If a device name was given, use it */
665 DeviceName
.Length
= SymbolicName
->Length
;
666 DeviceName
.Buffer
= SymbolicName
->Buffer
;
670 /* Otherwise, query it */
671 Status
= QueryDeviceInformation(SymbolicName
,
676 if (!NT_SUCCESS(Status
))
682 /* Look for device information matching devive */
683 for (NextEntry
= DeviceExtension
->DeviceListHead
.Flink
;
684 NextEntry
!= &(DeviceExtension
->DeviceListHead
);
685 NextEntry
= NextEntry
->Flink
)
687 DeviceInfo
= CONTAINING_RECORD(NextEntry
,
691 if (RtlEqualUnicodeString(&DeviceName
, &(DeviceInfo
->DeviceName
), TRUE
))
697 /* Release our buffer if required */
698 if (!DeviceNameGiven
)
700 FreePool(DeviceName
.Buffer
);
703 /* Return found intormation */
704 if (NextEntry
== &(DeviceExtension
->DeviceListHead
))
706 return STATUS_OBJECT_NAME_NOT_FOUND
;
709 *DeviceInformation
= DeviceInfo
;
710 return STATUS_SUCCESS
;
717 MountMgrFreeDeadDeviceInfo(IN PDEVICE_INFORMATION DeviceInformation
)
719 FreePool(DeviceInformation
->SymbolicName
.Buffer
);
720 FreePool(DeviceInformation
);
727 MountMgrFreeMountedDeviceInfo(IN PDEVICE_INFORMATION DeviceInformation
)
729 PLIST_ENTRY NextEntry
;
730 PSYMLINK_INFORMATION SymLink
;
731 PUNIQUE_ID_REPLICATE UniqueId
;
732 PASSOCIATED_DEVICE_ENTRY AssociatedDevice
;
734 /* Purge symbolic links list */
735 while (!IsListEmpty(&(DeviceInformation
->SymbolicLinksListHead
)))
737 NextEntry
= RemoveHeadList(&(DeviceInformation
->SymbolicLinksListHead
));
738 SymLink
= CONTAINING_RECORD(NextEntry
, SYMLINK_INFORMATION
, SymbolicLinksListEntry
);
740 GlobalDeleteSymbolicLink(&(SymLink
->Name
));
741 FreePool(SymLink
->Name
.Buffer
);
744 /* Purge replicated unique IDs list */
745 while (!IsListEmpty(&(DeviceInformation
->ReplicatedUniqueIdsListHead
)))
747 NextEntry
= RemoveHeadList(&(DeviceInformation
->ReplicatedUniqueIdsListHead
));
748 UniqueId
= CONTAINING_RECORD(NextEntry
, UNIQUE_ID_REPLICATE
, ReplicatedUniqueIdsListEntry
);
750 FreePool(UniqueId
->UniqueId
);
754 while (!IsListEmpty(&(DeviceInformation
->AssociatedDevicesHead
)))
756 NextEntry
= RemoveHeadList(&(DeviceInformation
->AssociatedDevicesHead
));
757 AssociatedDevice
= CONTAINING_RECORD(NextEntry
, ASSOCIATED_DEVICE_ENTRY
, AssociatedDevicesEntry
);
759 FreePool(AssociatedDevice
->String
.Buffer
);
760 FreePool(AssociatedDevice
);
763 /* Free the rest of the buffers */
764 FreePool(DeviceInformation
->SymbolicName
.Buffer
);
765 if (DeviceInformation
->KeepLinks
)
767 FreePool(DeviceInformation
->UniqueId
);
769 FreePool(DeviceInformation
->DeviceName
.Buffer
);
771 /* Finally, stop waiting for notifications for this device */
772 if (DeviceInformation
->TargetDeviceNotificationEntry
)
774 IoUnregisterPlugPlayNotification(DeviceInformation
->TargetDeviceNotificationEntry
);
782 MountMgrFreeSavedLink(IN PSAVED_LINK_INFORMATION SavedLinkInformation
)
784 PLIST_ENTRY NextEntry
;
785 PSYMLINK_INFORMATION SymlinkInformation
;
787 /* For all the saved links */
788 while (!IsListEmpty(&(SavedLinkInformation
->SymbolicLinksListHead
)))
790 NextEntry
= RemoveHeadList(&(SavedLinkInformation
->SymbolicLinksListHead
));
791 SymlinkInformation
= CONTAINING_RECORD(NextEntry
, SYMLINK_INFORMATION
, SymbolicLinksListEntry
);
793 /* Remove from system & free */
794 GlobalDeleteSymbolicLink(&(SymlinkInformation
->Name
));
795 FreePool(SymlinkInformation
->Name
.Buffer
);
796 FreePool(SymlinkInformation
);
799 /* And free unique ID & entry */
800 FreePool(SavedLinkInformation
->UniqueId
);
801 FreePool(SavedLinkInformation
);
810 MountMgrUnload(IN
struct _DRIVER_OBJECT
*DriverObject
)
812 PLIST_ENTRY NextEntry
;
813 PUNIQUE_ID_WORK_ITEM WorkItem
;
814 PDEVICE_EXTENSION DeviceExtension
;
815 PDEVICE_INFORMATION DeviceInformation
;
816 PSAVED_LINK_INFORMATION SavedLinkInformation
;
818 /* Don't get notification any longer */
819 IoUnregisterShutdownNotification(gdeviceObject
);
821 /* Free registry buffer */
822 DeviceExtension
= gdeviceObject
->DeviceExtension
;
823 if (DeviceExtension
->RegistryPath
.Buffer
)
825 FreePool(DeviceExtension
->RegistryPath
.Buffer
);
826 DeviceExtension
->RegistryPath
.Buffer
= NULL
;
829 InterlockedExchange(&Unloading
, TRUE
);
831 KeInitializeEvent(&UnloadEvent
, NotificationEvent
, FALSE
);
833 /* Wait for workers to finish */
834 if (InterlockedIncrement(&DeviceExtension
->WorkerReferences
))
836 KeReleaseSemaphore(&(DeviceExtension
->WorkerSemaphore
),
837 IO_NO_INCREMENT
, 1, FALSE
);
839 KeWaitForSingleObject(&UnloadEvent
, Executive
, KernelMode
, FALSE
, NULL
);
843 InterlockedDecrement(&(DeviceExtension
->WorkerReferences
));
846 /* Don't get any notification any longer² */
847 IoUnregisterPlugPlayNotification(DeviceExtension
->NotificationEntry
);
849 /* Acquire the driver exclusively */
850 KeWaitForSingleObject(&(DeviceExtension
->DeviceLock
), Executive
, KernelMode
,
853 /* Clear offline devices list */
854 while (!IsListEmpty(&(DeviceExtension
->OfflineDeviceListHead
)))
856 NextEntry
= RemoveHeadList(&(DeviceExtension
->OfflineDeviceListHead
));
857 DeviceInformation
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
858 MountMgrFreeDeadDeviceInfo(DeviceInformation
);
861 /* Clear saved links list */
862 while (!IsListEmpty(&(DeviceExtension
->SavedLinksListHead
)))
864 NextEntry
= RemoveHeadList(&(DeviceExtension
->SavedLinksListHead
));
865 SavedLinkInformation
= CONTAINING_RECORD(NextEntry
, SAVED_LINK_INFORMATION
, SavedLinksListEntry
);
866 MountMgrFreeSavedLink(SavedLinkInformation
);
869 /* Clear workers list */
870 while (!IsListEmpty(&(DeviceExtension
->UniqueIdWorkerItemListHead
)))
872 NextEntry
= RemoveHeadList(&(DeviceExtension
->UniqueIdWorkerItemListHead
));
873 WorkItem
= CONTAINING_RECORD(NextEntry
, UNIQUE_ID_WORK_ITEM
, UniqueIdWorkerItemListEntry
);
875 KeResetEvent(&UnloadEvent
);
876 WorkItem
->Event
= &UnloadEvent
;
878 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
,
881 IoCancelIrp(WorkItem
->Irp
);
882 KeWaitForSingleObject(&UnloadEvent
, Executive
, KernelMode
, FALSE
, NULL
);
884 IoFreeIrp(WorkItem
->Irp
);
885 FreePool(WorkItem
->DeviceName
.Buffer
);
886 FreePool(WorkItem
->IrpBuffer
);
889 KeWaitForSingleObject(&(DeviceExtension
->DeviceLock
), Executive
, KernelMode
,
893 /* If we have drive letter data, release */
894 if (DeviceExtension
->DriveLetterData
)
896 FreePool(DeviceExtension
->DriveLetterData
);
897 DeviceExtension
->DriveLetterData
= NULL
;
900 /* Release driver & quit */
901 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
, 1, FALSE
);
903 GlobalDeleteSymbolicLink(&DosDevicesMount
);
904 IoDeleteDevice(gdeviceObject
);
911 MountmgrReadNoAutoMount(IN PUNICODE_STRING RegistryPath
)
914 ULONG Result
, Default
= 0;
915 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
917 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
919 /* Simply read data from register */
920 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
921 QueryTable
[0].Name
= L
"NoAutoMount";
922 QueryTable
[0].EntryContext
= &Result
;
923 QueryTable
[0].DefaultType
= REG_NONE
;
924 QueryTable
[0].DefaultData
= &Default
;
925 QueryTable
[0].DefaultLength
= sizeof(ULONG
);
927 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
928 RegistryPath
->Buffer
,
932 if (!NT_SUCCESS(Status
))
934 return (Default
!= 0);
937 return (Result
!= 0);
944 MountMgrMountedDeviceArrival(IN PDEVICE_EXTENSION DeviceExtension
,
945 IN PUNICODE_STRING SymbolicName
,
946 IN BOOLEAN FromVolume
)
951 ULONG SymLinkCount
, i
;
952 PLIST_ENTRY NextEntry
;
953 PUNICODE_STRING SymLinks
;
954 NTSTATUS Status
, IntStatus
;
955 OBJECT_ATTRIBUTES ObjectAttributes
;
956 PSYMLINK_INFORMATION SymlinkInformation
;
957 PMOUNTDEV_UNIQUE_ID UniqueId
, NewUniqueId
;
958 PSAVED_LINK_INFORMATION SavedLinkInformation
;
959 PDEVICE_INFORMATION DeviceInformation
, CurrentDevice
;
960 WCHAR CSymLinkBuffer
[MAX_PATH
], LinkTargetBuffer
[MAX_PATH
];
961 UNICODE_STRING TargetDeviceName
, SuggestedLinkName
, DeviceName
, VolumeName
, DriveLetter
, LinkTarget
, CSymLink
;
962 BOOLEAN HasGuid
, HasGptDriveLetter
, Valid
, UseOnlyIfThereAreNoOtherLinks
, IsDrvLetter
, IsOff
, IsVolumeName
, LinkError
;
964 /* New device = new structure to represent it */
965 DeviceInformation
= AllocatePool(sizeof(DEVICE_INFORMATION
));
966 if (!DeviceInformation
)
968 return STATUS_INSUFFICIENT_RESOURCES
;
971 /* Initialise device structure */
972 RtlZeroMemory(DeviceInformation
, sizeof(DEVICE_INFORMATION
));
973 InitializeListHead(&(DeviceInformation
->SymbolicLinksListHead
));
974 InitializeListHead(&(DeviceInformation
->ReplicatedUniqueIdsListHead
));
975 InitializeListHead(&(DeviceInformation
->AssociatedDevicesHead
));
976 DeviceInformation
->SymbolicName
.Length
= SymbolicName
->Length
;
977 DeviceInformation
->SymbolicName
.MaximumLength
= SymbolicName
->Length
+ sizeof(UNICODE_NULL
);
978 DeviceInformation
->SymbolicName
.Buffer
= AllocatePool(DeviceInformation
->SymbolicName
.MaximumLength
);
979 if (!DeviceInformation
->SymbolicName
.Buffer
)
981 FreePool(DeviceInformation
);
982 return STATUS_INSUFFICIENT_RESOURCES
;
985 /* Copy symbolic name */
986 RtlCopyMemory(DeviceInformation
->SymbolicName
.Buffer
, SymbolicName
->Buffer
, SymbolicName
->Length
);
987 DeviceInformation
->SymbolicName
.Buffer
[DeviceInformation
->SymbolicName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
988 DeviceInformation
->Volume
= FromVolume
;
989 DeviceInformation
->DeviceExtension
= DeviceExtension
;
991 /* Query as much data as possible about device */
992 Status
= QueryDeviceInformation(SymbolicName
,
995 &(DeviceInformation
->Removable
),
1000 if (!NT_SUCCESS(Status
))
1002 KeWaitForSingleObject(&(DeviceExtension
->DeviceLock
), Executive
, KernelMode
, FALSE
, NULL
);
1004 for (NextEntry
= DeviceExtension
->OfflineDeviceListHead
.Flink
;
1005 NextEntry
!= &(DeviceExtension
->OfflineDeviceListHead
);
1006 NextEntry
= NextEntry
->Flink
)
1008 CurrentDevice
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
1010 if (RtlEqualUnicodeString(&(DeviceInformation
->SymbolicName
), &(CurrentDevice
->SymbolicName
), TRUE
))
1016 if (NextEntry
!= &(DeviceExtension
->OfflineDeviceListHead
))
1018 MountMgrFreeDeadDeviceInfo(DeviceInformation
);
1022 InsertTailList(&(DeviceExtension
->OfflineDeviceListHead
), &(DeviceInformation
->DeviceListEntry
));
1025 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
, 1, FALSE
);
1030 /* Save gathered data */
1031 DeviceInformation
->UniqueId
= UniqueId
;
1032 DeviceInformation
->DeviceName
= TargetDeviceName
;
1033 DeviceInformation
->KeepLinks
= FALSE
;
1035 /* If we found system partition, mark it */
1036 if (DeviceExtension
->DriveLetterData
&& UniqueId
->UniqueIdLength
== DeviceExtension
->DriveLetterData
->UniqueIdLength
)
1038 if (RtlCompareMemory(UniqueId
->UniqueId
, DeviceExtension
->DriveLetterData
->UniqueId
, UniqueId
->UniqueIdLength
)
1039 == UniqueId
->UniqueIdLength
)
1041 IoSetSystemPartition(&TargetDeviceName
);
1045 /* Check suggested link name */
1046 Status
= QuerySuggestedLinkName(&(DeviceInformation
->SymbolicName
),
1048 &UseOnlyIfThereAreNoOtherLinks
);
1049 if (!NT_SUCCESS(Status
))
1051 SuggestedLinkName
.Buffer
= NULL
;
1054 /* If it's OK, set it and save its letter (if any) */
1055 if (SuggestedLinkName
.Buffer
&& IsDriveLetter(&SuggestedLinkName
))
1057 DeviceInformation
->SuggestedDriveLetter
= (UCHAR
)SuggestedLinkName
.Buffer
[LETTER_POSITION
];
1060 /* Acquire driver exclusively */
1061 KeWaitForSingleObject(&(DeviceExtension
->DeviceLock
), Executive
, KernelMode
, FALSE
, NULL
);
1063 /* Check if we already have device in to prevent double registration */
1064 for (NextEntry
= DeviceExtension
->DeviceListHead
.Flink
;
1065 NextEntry
!= &(DeviceExtension
->DeviceListHead
);
1066 NextEntry
= NextEntry
->Flink
)
1068 CurrentDevice
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
1070 if (RtlEqualUnicodeString(&(DeviceInformation
->DeviceName
), &TargetDeviceName
, TRUE
))
1076 /* If we found it, clear ours, and return success, all correct */
1077 if (NextEntry
!= &(DeviceExtension
->DeviceListHead
))
1079 if (SuggestedLinkName
.Buffer
)
1081 FreePool(SuggestedLinkName
.Buffer
);
1085 FreePool(TargetDeviceName
.Buffer
);
1086 FreePool(DeviceInformation
->DeviceName
.Buffer
);
1087 FreePool(DeviceInformation
);
1089 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
, 1, FALSE
);
1091 return STATUS_SUCCESS
;
1094 /* Check if there are symlinks associated with our device in registry */
1095 Status
= QuerySymbolicLinkNamesFromStorage(DeviceExtension
,
1097 (SuggestedLinkName
.Buffer
) ? &SuggestedLinkName
: NULL
,
1098 UseOnlyIfThereAreNoOtherLinks
,
1104 /* If our device is a CD-ROM */
1105 if (RtlPrefixUnicodeString(&DeviceCdRom
, &TargetDeviceName
, TRUE
))
1107 LinkTarget
.Length
= 0;
1108 LinkTarget
.MaximumLength
= sizeof(LinkTargetBuffer
);
1109 LinkTarget
.Buffer
= LinkTargetBuffer
;
1111 RtlCopyMemory(CSymLinkBuffer
, Cunc
, sizeof(Cunc
));
1112 RtlInitUnicodeString(&CSymLink
, CSymLinkBuffer
);
1114 /* Start checking all letters that could have been associated */
1115 for (Letter
= L
'D'; Letter
<= L
'Z'; Letter
++)
1117 CSymLink
.Buffer
[LETTER_POSITION
] = Letter
;
1119 InitializeObjectAttributes(&ObjectAttributes
,
1121 OBJ_CASE_INSENSITIVE
,
1125 /* Try to open the associated symlink */
1126 Status
= ZwOpenSymbolicLinkObject(&LinkHandle
, SYMBOLIC_LINK_QUERY
, &ObjectAttributes
);
1127 if (!NT_SUCCESS(Status
))
1132 /* And query its target */
1133 Status
= ZwQuerySymbolicLinkObject(LinkHandle
, &LinkTarget
, NULL
);
1134 ZwClose(LinkHandle
);
1136 if (!NT_SUCCESS(Status
))
1141 IntStatus
= STATUS_UNSUCCESSFUL
;
1142 if (!RtlEqualUnicodeString(&LinkTarget
, &DeviceInformation
->DeviceName
, FALSE
))
1147 /* This link is matching our device, whereas it's not supposed to have any
1148 * symlink associated.
1153 IoDeleteSymbolicLink(&CSymLink
);
1157 /* Now, for all the symlinks, check for ours */
1158 for (i
= 0; i
< SymLinkCount
; i
++)
1160 if (IsDriveLetter(&(SymLinks
[i
])))
1162 /* If it exists, that's correct */
1163 if (SymLinks
[i
].Buffer
[LETTER_POSITION
] == Letter
)
1165 IntStatus
= STATUS_SUCCESS
;
1170 /* Useless link, delete it */
1171 if (IntStatus
== STATUS_UNSUCCESSFUL
)
1173 IoDeleteSymbolicLink(&CSymLink
);
1178 /* Suggested name is no longer required */
1179 if (SuggestedLinkName
.Buffer
)
1181 FreePool(SuggestedLinkName
.Buffer
);
1184 /* If if failed, ensure we don't take symlinks into account */
1185 if (!NT_SUCCESS(Status
))
1191 /* Now we queried them, remove the symlinks */
1192 SavedLinkInformation
= RemoveSavedLinks(DeviceExtension
, UniqueId
);
1194 IsDrvLetter
= FALSE
;
1196 IsVolumeName
= FALSE
;
1197 /* For all the symlinks */
1198 for (i
= 0; i
< SymLinkCount
; i
++)
1200 /* Check if our device is a volume */
1201 if (MOUNTMGR_IS_VOLUME_NAME(&(SymLinks
[i
])))
1203 IsVolumeName
= TRUE
;
1205 /* If it has a drive letter */
1206 else if (IsDriveLetter(&(SymLinks
[i
])))
1210 DeleteFromLocalDatabase(&(SymLinks
[i
]), UniqueId
);
1219 /* And recreate the symlink to our device */
1220 Status
= GlobalCreateSymbolicLink(&(SymLinks
[i
]), &TargetDeviceName
);
1221 if (!NT_SUCCESS(Status
))
1225 if ((SavedLinkInformation
&& !RedirectSavedLink(SavedLinkInformation
, &(SymLinks
[i
]), &TargetDeviceName
)) ||
1226 !SavedLinkInformation
)
1228 Status
= QueryDeviceInformation(&(SymLinks
[i
]), &DeviceName
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
1229 if (NT_SUCCESS(Status
))
1231 LinkError
= RtlEqualUnicodeString(&TargetDeviceName
, &DeviceName
, TRUE
);
1232 FreePool(DeviceName
.Buffer
);
1237 if (IsDriveLetter(&(SymLinks
[i
])))
1239 IsDrvLetter
= FALSE
;
1240 DeleteFromLocalDatabase(&(SymLinks
[i
]), UniqueId
);
1243 FreePool(SymLinks
[i
].Buffer
);
1249 /* Check if was offline */
1250 if (IsOffline(&(SymLinks
[i
])))
1255 /* Finally, associate this symlink with the device */
1256 SymlinkInformation
= AllocatePool(sizeof(SYMLINK_INFORMATION
));
1257 if (!SymlinkInformation
)
1259 GlobalDeleteSymbolicLink(&(SymLinks
[i
]));
1260 FreePool(SymLinks
[i
].Buffer
);
1264 SymlinkInformation
->Name
= SymLinks
[i
];
1265 SymlinkInformation
->Online
= TRUE
;
1267 InsertTailList(&(DeviceInformation
->SymbolicLinksListHead
),
1268 &(SymlinkInformation
->SymbolicLinksListEntry
));
1271 /* Now, for all the recreated symlinks, notify their recreation */
1272 for (NextEntry
= DeviceInformation
->SymbolicLinksListHead
.Flink
;
1273 NextEntry
!= &(DeviceInformation
->SymbolicLinksListHead
);
1274 NextEntry
= NextEntry
->Flink
)
1276 SymlinkInformation
= CONTAINING_RECORD(NextEntry
, SYMLINK_INFORMATION
, SymbolicLinksListEntry
);
1278 SendLinkCreated(&(SymlinkInformation
->Name
));
1281 /* If we had saved links, it's time to free them */
1282 if (SavedLinkInformation
)
1284 MountMgrFreeSavedLink(SavedLinkInformation
);
1287 /* If our device doesn't have a volume name */
1290 /* It's time to create one */
1291 Status
= CreateNewVolumeName(&VolumeName
, NULL
);
1292 if (NT_SUCCESS(Status
))
1294 /* Write it to global database */
1295 RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE
,
1300 UniqueId
->UniqueIdLength
);
1302 /* And create the symlink */
1303 GlobalCreateSymbolicLink(&VolumeName
, &TargetDeviceName
);
1305 SymlinkInformation
= AllocatePool(sizeof(SYMLINK_INFORMATION
));
1306 if (!SymlinkInformation
)
1308 FreePool(VolumeName
.Buffer
);
1310 /* Finally, associate it with the device and notify creation */
1313 SymlinkInformation
->Name
= VolumeName
;
1314 SymlinkInformation
->Online
= TRUE
;
1315 InsertTailList(&(DeviceInformation
->SymbolicLinksListHead
),
1316 &(SymlinkInformation
->SymbolicLinksListEntry
));
1318 SendLinkCreated(&VolumeName
);
1323 /* If we found a drive letter, then, ignore the suggested one */
1326 DeviceInformation
->SuggestedDriveLetter
= 0;
1328 /* Else, it's time to set up one */
1329 else if (!DeviceExtension
->NoAutoMount
&& !DeviceInformation
->Removable
&&
1330 DeviceExtension
->AutomaticDriveLetter
&& HasGptDriveLetter
&&
1331 DeviceInformation
->SuggestedDriveLetter
&&
1332 !HasNoDriveLetterEntry(UniqueId
))
1334 /* Create a new drive letter */
1335 Status
= CreateNewDriveLetterName(&DriveLetter
, &TargetDeviceName
,
1336 DeviceInformation
->SuggestedDriveLetter
,
1338 if (!NT_SUCCESS(Status
))
1340 CreateNoDriveLetterEntry(UniqueId
);
1344 /* Save it to global database */
1345 RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE
,
1350 UniqueId
->UniqueIdLength
);
1352 /* Associate it with the device and notify creation */
1353 SymlinkInformation
= AllocatePool(sizeof(SYMLINK_INFORMATION
));
1354 if (!SymlinkInformation
)
1356 FreePool(DriveLetter
.Buffer
);
1360 SymlinkInformation
->Name
= DriveLetter
;
1361 SymlinkInformation
->Online
= TRUE
;
1362 InsertTailList(&(DeviceInformation
->SymbolicLinksListHead
),
1363 &(SymlinkInformation
->SymbolicLinksListEntry
));
1365 SendLinkCreated(&DriveLetter
);
1370 /* If required, register for notifications about the device */
1373 RegisterForTargetDeviceNotification(DeviceExtension
, DeviceInformation
);
1376 /* Finally, insert the device into our devices list */
1377 InsertTailList(&(DeviceExtension
->DeviceListHead
), &(DeviceInformation
->DeviceListEntry
));
1379 /* Copy device unique ID */
1380 NewUniqueId
= AllocatePool(UniqueId
->UniqueIdLength
+ sizeof(MOUNTDEV_UNIQUE_ID
));
1383 NewUniqueId
->UniqueIdLength
= UniqueId
->UniqueIdLength
;
1384 RtlCopyMemory(NewUniqueId
->UniqueId
, UniqueId
->UniqueId
, UniqueId
->UniqueIdLength
);
1387 /* If device's offline or valid, skip its notifications */
1390 DeviceInformation
->SkipNotifications
= TRUE
;
1393 /* In case device is valid and is set to no automount,
1396 if (DeviceExtension
->NoAutoMount
|| IsDrvLetter
)
1398 IsOff
= !DeviceInformation
->SkipNotifications
;
1405 /* Finally, release the exclusive lock */
1406 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
, 1, FALSE
);
1408 /* If device is not offline, notify its arrival */
1411 SendOnlineNotification(SymbolicName
);
1414 /* If we had symlinks (from storage), free them */
1420 /* Notify about unique id change */
1423 IssueUniqueIdChangeNotify(DeviceExtension
, SymbolicName
, NewUniqueId
);
1424 FreePool(NewUniqueId
);
1427 /* If this drive was set to have a drive letter automatically
1428 * Now it's back, local databases sync will be required
1430 if (DeviceExtension
->AutomaticDriveLetter
)
1432 KeWaitForSingleObject(&(DeviceExtension
->DeviceLock
), Executive
, KernelMode
, FALSE
, NULL
);
1434 ReconcileThisDatabaseWithMaster(DeviceExtension
, DeviceInformation
);
1436 NextEntry
= DeviceExtension
->DeviceListHead
.Flink
;
1437 CurrentDevice
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
1438 while (CurrentDevice
!= DeviceInformation
)
1440 if (!CurrentDevice
->NoDatabase
)
1442 ReconcileThisDatabaseWithMaster(DeviceExtension
, CurrentDevice
);
1445 NextEntry
= NextEntry
->Flink
;
1446 CurrentDevice
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
1449 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
, 1, FALSE
);
1452 return STATUS_SUCCESS
;
1459 MountMgrMountedDeviceRemoval(IN PDEVICE_EXTENSION DeviceExtension
,
1460 IN PUNICODE_STRING DeviceName
)
1462 PLIST_ENTRY NextEntry
, DeviceEntry
;
1463 PUNIQUE_ID_REPLICATE UniqueIdReplicate
;
1464 PSYMLINK_INFORMATION SymlinkInformation
;
1465 PASSOCIATED_DEVICE_ENTRY AssociatedDevice
;
1466 PSAVED_LINK_INFORMATION SavedLinkInformation
= NULL
;
1467 PDEVICE_INFORMATION DeviceInformation
, CurrentDevice
;
1469 /* Acquire device exclusively */
1470 KeWaitForSingleObject(&(DeviceExtension
->DeviceLock
), Executive
, KernelMode
, FALSE
, NULL
);
1472 /* Look for the leaving device */
1473 for (NextEntry
= DeviceExtension
->DeviceListHead
.Flink
;
1474 NextEntry
!= &(DeviceExtension
->DeviceListHead
);
1475 NextEntry
= NextEntry
->Flink
)
1477 DeviceInformation
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
1479 if (!RtlCompareUnicodeString(&(DeviceInformation
->SymbolicName
), DeviceName
, TRUE
))
1485 /* If we found it */
1486 if (NextEntry
!= &(DeviceExtension
->DeviceListHead
))
1488 /* If it's asked to keep links, then, prepare to save them */
1489 if (DeviceInformation
->KeepLinks
)
1491 SavedLinkInformation
= AllocatePool(sizeof(SAVED_LINK_INFORMATION
));
1492 if (!SavedLinkInformation
)
1494 DeviceInformation
->KeepLinks
= FALSE
;
1498 /* If it's possible (and asked), start to save them */
1499 if (DeviceInformation
->KeepLinks
)
1501 InsertTailList(&(DeviceExtension
->SavedLinksListHead
), &(SavedLinkInformation
->SavedLinksListEntry
));
1502 InitializeListHead(&(SavedLinkInformation
->SymbolicLinksListHead
));
1503 SavedLinkInformation
->UniqueId
= DeviceInformation
->UniqueId
;
1506 /* For all the symlinks */
1507 while (!IsListEmpty(&(DeviceInformation
->SymbolicLinksListHead
)))
1509 NextEntry
= RemoveHeadList(&(DeviceInformation
->SymbolicLinksListHead
));
1510 SymlinkInformation
= CONTAINING_RECORD(NextEntry
, SYMLINK_INFORMATION
, SymbolicLinksListEntry
);
1512 /* If we have to, save the link */
1513 if (DeviceInformation
->KeepLinks
)
1515 InsertTailList(&(SavedLinkInformation
->SymbolicLinksListHead
), &(SymlinkInformation
->SymbolicLinksListEntry
));
1517 /* Otherwise, just release it */
1520 GlobalDeleteSymbolicLink(&(SymlinkInformation
->Name
));
1521 FreePool(SymlinkInformation
->Name
.Buffer
);
1522 FreePool(SymlinkInformation
);
1526 /* Free all the replicated unique IDs */
1527 while (!IsListEmpty(&(DeviceInformation
->ReplicatedUniqueIdsListHead
)))
1529 NextEntry
= RemoveHeadList(&(DeviceInformation
->ReplicatedUniqueIdsListHead
));
1530 UniqueIdReplicate
= CONTAINING_RECORD(NextEntry
, UNIQUE_ID_REPLICATE
, ReplicatedUniqueIdsListEntry
);
1533 FreePool(UniqueIdReplicate
->UniqueId
);
1534 FreePool(UniqueIdReplicate
);
1537 while (!IsListEmpty(&(DeviceInformation
->AssociatedDevicesHead
)))
1539 NextEntry
= RemoveHeadList(&(DeviceInformation
->AssociatedDevicesHead
));
1540 AssociatedDevice
= CONTAINING_RECORD(NextEntry
, ASSOCIATED_DEVICE_ENTRY
, AssociatedDevicesEntry
);
1542 DeviceInformation
->NoDatabase
= TRUE
;
1543 FreePool(AssociatedDevice
->String
.Buffer
);
1544 FreePool(AssociatedDevice
);
1547 /* Remove device from the device list */
1548 RemoveEntryList(&(DeviceInformation
->DeviceListEntry
));
1550 /* If there are still devices, check if some were associated with ours */
1551 if (!IsListEmpty(&(DeviceInformation
->DeviceListEntry
)))
1553 for (NextEntry
= DeviceExtension
->DeviceListHead
.Flink
;
1554 NextEntry
!= &(DeviceExtension
->DeviceListHead
);
1555 NextEntry
= NextEntry
->Flink
)
1557 CurrentDevice
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
1559 /* And then, remove them */
1560 DeviceEntry
= CurrentDevice
->AssociatedDevicesHead
.Flink
;
1561 while (DeviceEntry
!= &(CurrentDevice
->AssociatedDevicesHead
))
1563 AssociatedDevice
= CONTAINING_RECORD(NextEntry
, ASSOCIATED_DEVICE_ENTRY
, AssociatedDevicesEntry
);
1564 DeviceEntry
= DeviceEntry
->Flink
;
1566 if (AssociatedDevice
->DeviceInformation
!= DeviceInformation
)
1571 RemoveEntryList(&(AssociatedDevice
->AssociatedDevicesEntry
));
1572 FreePool(AssociatedDevice
->String
.Buffer
);
1573 FreePool(AssociatedDevice
);
1578 /* Finally, clean up device name, symbolic name */
1579 FreePool(DeviceInformation
->SymbolicName
.Buffer
);
1580 if (!DeviceInformation
->KeepLinks
)
1582 FreePool(DeviceInformation
->UniqueId
);
1584 FreePool(DeviceInformation
->DeviceName
.Buffer
);
1586 /* Unregister notifications */
1587 if (DeviceInformation
->TargetDeviceNotificationEntry
)
1589 IoUnregisterPlugPlayNotification(DeviceInformation
->TargetDeviceNotificationEntry
);
1593 FreePool(DeviceInformation
);
1597 /* We didn't find device, perhaps because it was offline */
1598 for (NextEntry
= DeviceExtension
->OfflineDeviceListHead
.Flink
;
1599 NextEntry
!= &(DeviceExtension
->OfflineDeviceListHead
);
1600 NextEntry
= NextEntry
->Flink
)
1602 DeviceInformation
= CONTAINING_RECORD(NextEntry
, DEVICE_INFORMATION
, DeviceListEntry
);
1604 /* It was, remove it */
1605 if (RtlCompareUnicodeString(&(DeviceInformation
->SymbolicName
), DeviceName
, TRUE
) == 0)
1607 RemoveEntryList(&(DeviceInformation
->DeviceListEntry
));
1608 MountMgrFreeDeadDeviceInfo(DeviceInformation
);
1614 /* Releave driver */
1615 KeReleaseSemaphore(&(DeviceExtension
->DeviceLock
), IO_NO_INCREMENT
, 1, FALSE
);
1623 MountMgrMountedDeviceNotification(IN PVOID NotificationStructure
,
1627 PDEVICE_EXTENSION DeviceExtension
;
1628 PDEVICE_INTERFACE_CHANGE_NOTIFICATION Notification
;
1630 /* Notification for a device arrived */
1631 /* Disable hard errors */
1632 OldState
= PsGetThreadHardErrorsAreDisabled(PsGetCurrentThread());
1633 PsSetThreadHardErrorsAreDisabled(PsGetCurrentThread(), TRUE
);
1635 DeviceExtension
= Context
;
1636 Notification
= NotificationStructure
;
1638 /* Dispatch according to the event */
1639 if (IsEqualGUID(&(Notification
->Event
), &GUID_DEVICE_INTERFACE_ARRIVAL
))
1641 MountMgrMountedDeviceArrival(DeviceExtension
, Notification
->SymbolicLinkName
, FALSE
);
1643 else if (IsEqualGUID(&(Notification
->Event
), &GUID_DEVICE_INTERFACE_REMOVAL
))
1645 MountMgrMountedDeviceRemoval(DeviceExtension
, Notification
->SymbolicLinkName
);
1648 /* Reset hard errors */
1649 PsSetThreadHardErrorsAreDisabled(PsGetCurrentThread(), OldState
);
1651 return STATUS_SUCCESS
;
1659 MountMgrCreateClose(IN PDEVICE_OBJECT DeviceObject
,
1662 PIO_STACK_LOCATION Stack
;
1663 NTSTATUS Status
= STATUS_SUCCESS
;
1665 Stack
= IoGetCurrentIrpStackLocation(Irp
);
1667 /* Allow driver opening for communication
1668 * as long as it's not taken for a directory
1670 if (Stack
->MajorFunction
== IRP_MJ_CREATE
&&
1671 Stack
->Parameters
.Create
.Options
& FILE_DIRECTORY_FILE
)
1673 Status
= STATUS_NOT_A_DIRECTORY
;
1676 Irp
->IoStatus
.Status
= Status
;
1677 Irp
->IoStatus
.Information
= 0;
1678 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1687 MountMgrCancel(IN PDEVICE_OBJECT DeviceObject
,
1690 RemoveEntryList(&(Irp
->Tail
.Overlay
.ListEntry
));
1692 IoReleaseCancelSpinLock(Irp
->CancelIrql
);
1694 Irp
->IoStatus
.Information
= 0;
1695 Irp
->IoStatus
.Status
= STATUS_CANCELLED
;
1696 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1704 MountMgrCleanup(IN PDEVICE_OBJECT DeviceObject
,
1709 PLIST_ENTRY NextEntry
;
1710 PFILE_OBJECT FileObject
;
1711 PIO_STACK_LOCATION Stack
;
1712 PDEVICE_EXTENSION DeviceExtension
;
1714 DeviceExtension
= DeviceObject
->DeviceExtension
;
1715 Stack
= IoGetCurrentIrpStackLocation(Irp
);
1716 FileObject
= Stack
->FileObject
;
1718 IoAcquireCancelSpinLock(&OldIrql
);
1720 /* If IRP list if empty, it's OK */
1721 if (IsListEmpty(&(DeviceExtension
->IrpListHead
)))
1723 IoReleaseCancelSpinLock(OldIrql
);
1725 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1726 Irp
->IoStatus
.Information
= 0;
1727 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1729 return STATUS_SUCCESS
;
1732 /* Otherwise, cancel all the IRPs */
1733 NextEntry
= &(DeviceExtension
->IrpListHead
);
1736 ListIrp
= CONTAINING_RECORD(NextEntry
, IRP
, Tail
.Overlay
.ListEntry
);
1737 if (IoGetCurrentIrpStackLocation(ListIrp
)->FileObject
== FileObject
)
1739 ListIrp
->Cancel
= TRUE
;
1740 ListIrp
->CancelIrql
= OldIrql
;
1741 ListIrp
->CancelRoutine
= NULL
;
1742 MountMgrCancel(DeviceObject
, ListIrp
);
1744 IoAcquireCancelSpinLock(&OldIrql
);
1747 NextEntry
= NextEntry
->Flink
;
1749 while (NextEntry
!= &(DeviceExtension
->IrpListHead
));
1751 IoReleaseCancelSpinLock(OldIrql
);
1753 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1754 Irp
->IoStatus
.Information
= 0;
1755 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1757 return STATUS_SUCCESS
;
1765 MountMgrShutdown(IN PDEVICE_OBJECT DeviceObject
,
1768 PDEVICE_EXTENSION DeviceExtension
;
1770 DeviceExtension
= DeviceObject
->DeviceExtension
;
1772 InterlockedExchange(&Unloading
, TRUE
);
1774 KeInitializeEvent(&UnloadEvent
, NotificationEvent
, FALSE
);
1776 /* Wait for workers */
1777 if (InterlockedIncrement(&(DeviceExtension
->WorkerReferences
)))
1779 KeReleaseSemaphore(&(DeviceExtension
->WorkerSemaphore
),
1783 KeWaitForSingleObject(&UnloadEvent
, Executive
, KernelMode
, FALSE
, NULL
);
1787 InterlockedDecrement(&(DeviceExtension
->WorkerReferences
));
1790 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1791 Irp
->IoStatus
.Information
= 0;
1792 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1794 return STATUS_SUCCESS
;
1797 /* FUNCTIONS ****************************************************************/
1801 DriverEntry(IN PDRIVER_OBJECT DriverObject
,
1802 IN PUNICODE_STRING RegistryPath
)
1805 PDEVICE_OBJECT DeviceObject
;
1806 PDEVICE_EXTENSION DeviceExtension
;
1808 RtlCreateRegistryKey(RTL_REGISTRY_ABSOLUTE
, DatabasePath
);
1810 Status
= IoCreateDevice(DriverObject
,
1811 sizeof(DEVICE_EXTENSION
),
1813 FILE_DEVICE_NETWORK
,
1814 FILE_DEVICE_SECURE_OPEN
,
1817 if (!NT_SUCCESS(Status
))
1822 DriverObject
->DriverUnload
= MountMgrUnload
;
1824 DeviceExtension
= DeviceObject
->DeviceExtension
;
1825 RtlZeroMemory(DeviceExtension
, sizeof(DEVICE_EXTENSION
));
1826 DeviceExtension
->DeviceObject
= DeviceObject
;
1827 DeviceExtension
->DriverObject
= DriverObject
;
1829 InitializeListHead(&(DeviceExtension
->DeviceListHead
));
1830 InitializeListHead(&(DeviceExtension
->OfflineDeviceListHead
));
1832 KeInitializeSemaphore(&(DeviceExtension
->DeviceLock
), 1, 1);
1833 KeInitializeSemaphore(&(DeviceExtension
->RemoteDatabaseLock
), 1, 1);
1835 InitializeListHead(&(DeviceExtension
->IrpListHead
));
1836 DeviceExtension
->EpicNumber
= 1;
1838 InitializeListHead(&(DeviceExtension
->SavedLinksListHead
));
1840 InitializeListHead(&(DeviceExtension
->WorkerQueueListHead
));
1841 KeInitializeSemaphore(&(DeviceExtension
->WorkerSemaphore
), 0, MAXLONG
);
1842 DeviceExtension
->WorkerReferences
= -1;
1843 KeInitializeSpinLock(&(DeviceExtension
->WorkerLock
));
1845 InitializeListHead(&(DeviceExtension
->UniqueIdWorkerItemListHead
));
1846 InitializeListHead(&(DeviceExtension
->OnlineNotificationListHead
));
1847 DeviceExtension
->OnlineNotificationCount
= 1;
1849 DeviceExtension
->RegistryPath
.Length
= RegistryPath
->Length
;
1850 DeviceExtension
->RegistryPath
.MaximumLength
= RegistryPath
->Length
+ sizeof(WCHAR
);
1851 DeviceExtension
->RegistryPath
.Buffer
= AllocatePool(DeviceExtension
->RegistryPath
.MaximumLength
);
1852 if (!DeviceExtension
->RegistryPath
.Buffer
)
1854 IoDeleteDevice(DeviceObject
);
1855 return STATUS_INSUFFICIENT_RESOURCES
;
1858 RtlCopyUnicodeString(&(DeviceExtension
->RegistryPath
), RegistryPath
);
1860 DeviceExtension
->NoAutoMount
= MountmgrReadNoAutoMount(&(DeviceExtension
->RegistryPath
));
1862 GlobalCreateSymbolicLink(&DosDevicesMount
, &DeviceMount
);
1864 /* Register for device arrival & removal. Ask to be notified for already
1867 Status
= IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange
,
1868 PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES
,
1869 &MountedDevicesGuid
,
1871 MountMgrMountedDeviceNotification
,
1873 &(DeviceExtension
->NotificationEntry
));
1875 if (!NT_SUCCESS(Status
))
1877 IoDeleteDevice(DeviceObject
);
1881 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] =
1882 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = MountMgrCreateClose
;
1883 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = MountMgrDeviceControl
;
1884 DriverObject
->MajorFunction
[IRP_MJ_CLEANUP
] = MountMgrCleanup
;
1885 DriverObject
->MajorFunction
[IRP_MJ_SHUTDOWN
] = MountMgrShutdown
;
1887 gdeviceObject
= DeviceObject
;
1889 Status
= IoRegisterShutdownNotification(DeviceObject
);
1890 if (!NT_SUCCESS(Status
))
1892 IoDeleteDevice(DeviceObject
);