3 * Copyright (C) 2011-2012 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 - remote/local database handler
23 * PROGRAMMER: Pierre Schweitzer (pierre.schweitzer@reactos.org)
31 PWSTR DatabasePath
= L
"\\Registry\\Machine\\System\\MountedDevices";
32 PWSTR OfflinePath
= L
"\\Registry\\Machine\\System\\MountedDevices\\Offline";
34 UNICODE_STRING RemoteDatabase
= RTL_CONSTANT_STRING(L
"\\System Volume Information\\MountPointManagerRemoteDatabase");
40 GetRemoteDatabaseSize(IN HANDLE Database
)
43 IO_STATUS_BLOCK IoStatusBlock
;
44 FILE_STANDARD_INFORMATION StandardInfo
;
46 /* Just query the size */
47 Status
= ZwQueryInformationFile(Database
,
50 sizeof(FILE_STANDARD_INFORMATION
),
51 FileStandardInformation
);
52 if (NT_SUCCESS(Status
))
54 return StandardInfo
.EndOfFile
.LowPart
;
64 AddRemoteDatabaseEntry(IN HANDLE Database
,
65 IN PDATABASE_ENTRY Entry
)
68 IO_STATUS_BLOCK IoStatusBlock
;
70 /* Get size to append data */
71 Size
.QuadPart
= GetRemoteDatabaseSize(Database
);
73 return ZwWriteFile(Database
, 0, NULL
, NULL
,
74 &IoStatusBlock
, Entry
,
75 Entry
->EntrySize
, &Size
, NULL
);
82 CloseRemoteDatabase(IN HANDLE Database
)
84 return ZwClose(Database
);
91 TruncateRemoteDatabase(IN HANDLE Database
,
95 IO_STATUS_BLOCK IoStatusBlock
;
96 FILE_END_OF_FILE_INFORMATION EndOfFile
;
97 FILE_ALLOCATION_INFORMATION Allocation
;
99 EndOfFile
.EndOfFile
.QuadPart
= NewSize
;
100 Allocation
.AllocationSize
.QuadPart
= NewSize
;
103 Status
= ZwSetInformationFile(Database
,
106 sizeof(FILE_END_OF_FILE_INFORMATION
),
107 FileEndOfFileInformation
);
108 if (NT_SUCCESS(Status
))
110 /* And then, properly set allocation information */
111 Status
= ZwSetInformationFile(Database
,
114 sizeof(FILE_ALLOCATION_INFORMATION
),
115 FileAllocationInformation
);
125 GetRemoteDatabaseEntry(IN HANDLE Database
,
126 IN LONG StartingOffset
)
130 PDATABASE_ENTRY Entry
;
131 LARGE_INTEGER ByteOffset
;
132 IO_STATUS_BLOCK IoStatusBlock
;
134 /* Get the entry at the given position */
135 ByteOffset
.QuadPart
= StartingOffset
;
136 Status
= ZwReadFile(Database
,
145 if (!NT_SUCCESS(Status
))
150 /* If entry doesn't exist, truncate database */
153 TruncateRemoteDatabase(Database
, StartingOffset
);
157 /* Allocate the entry */
158 Entry
= AllocatePool(EntrySize
);
164 /* Effectively read the entry */
165 Status
= ZwReadFile(Database
,
174 /* If it fails or returns inconsistent data, drop it (= truncate) */
175 if (!NT_SUCCESS(Status
) ||
176 (IoStatusBlock
.Information
!= EntrySize
) ||
177 (EntrySize
< sizeof(DATABASE_ENTRY
)) )
179 TruncateRemoteDatabase(Database
, StartingOffset
);
185 if (MAX(Entry
->SymbolicNameOffset
+ Entry
->SymbolicNameLength
,
186 Entry
->UniqueIdOffset
+ Entry
->UniqueIdLength
) > (LONG
)EntrySize
)
188 TruncateRemoteDatabase(Database
, StartingOffset
);
200 WriteRemoteDatabaseEntry(IN HANDLE Database
,
202 IN PDATABASE_ENTRY Entry
)
205 LARGE_INTEGER ByteOffset
;
206 IO_STATUS_BLOCK IoStatusBlock
;
208 ByteOffset
.QuadPart
= Offset
;
209 Status
= ZwWriteFile(Database
,
218 if (NT_SUCCESS(Status
))
220 if (IoStatusBlock
.Information
< Entry
->EntrySize
)
222 Status
= STATUS_INSUFFICIENT_RESOURCES
;
233 DeleteRemoteDatabaseEntry(IN HANDLE Database
,
234 IN LONG StartingOffset
)
240 PDATABASE_ENTRY Entry
;
241 IO_STATUS_BLOCK IoStatusBlock
;
242 LARGE_INTEGER EndEntriesOffset
;
244 /* First, get database size */
245 DatabaseSize
= GetRemoteDatabaseSize(Database
);
248 return STATUS_INVALID_PARAMETER
;
251 /* Then, get the entry to remove */
252 Entry
= GetRemoteDatabaseEntry(Database
, StartingOffset
);
255 return STATUS_INVALID_PARAMETER
;
258 /* Validate parameters: ensure we won't get negative size */
259 if (Entry
->EntrySize
+ StartingOffset
> DatabaseSize
)
261 /* If we get invalid parameters, truncate the whole database
262 * starting the wrong entry. We can't rely on the rest
265 return TruncateRemoteDatabase(Database
, StartingOffset
);
268 /* Now, get the size of the remaining entries (those after the one to remove) */
269 EndSize
= DatabaseSize
- Entry
->EntrySize
- StartingOffset
;
270 /* Allocate a buffer big enough to hold them */
271 TmpBuffer
= AllocatePool(EndSize
);
275 return STATUS_INSUFFICIENT_RESOURCES
;
278 /* Get the offset of the entry right after the one to delete */
279 EndEntriesOffset
.QuadPart
= Entry
->EntrySize
+ StartingOffset
;
280 /* We don't need the entry any more */
283 /* Read the ending entries */
284 Status
= ZwReadFile(Database
, NULL
, NULL
, NULL
, &IoStatusBlock
,
285 TmpBuffer
, EndSize
, &EndEntriesOffset
, NULL
);
286 if (!NT_SUCCESS(Status
))
292 /* Ensure nothing went wrong - we don't want to corrupt the DB */
293 if (IoStatusBlock
.Information
!= EndSize
)
296 return STATUS_INVALID_PARAMETER
;
299 /* Remove the entry */
300 Status
= TruncateRemoteDatabase(Database
, StartingOffset
+ EndSize
);
301 if (!NT_SUCCESS(Status
))
307 /* Now, shift the ending entries to erase the entry */
308 EndEntriesOffset
.QuadPart
= StartingOffset
;
309 Status
= ZwWriteFile(Database
, NULL
, NULL
, NULL
, &IoStatusBlock
,
310 TmpBuffer
, EndSize
, &EndEntriesOffset
, NULL
);
322 DeleteFromLocalDatabaseRoutine(IN PWSTR ValueName
,
325 IN ULONG ValueLength
,
327 IN PVOID EntryContext
)
329 PMOUNTDEV_UNIQUE_ID UniqueId
= Context
;
331 UNREFERENCED_PARAMETER(ValueType
);
332 UNREFERENCED_PARAMETER(EntryContext
);
334 /* Ensure it matches, and delete */
335 if ((UniqueId
->UniqueIdLength
== ValueLength
) &&
336 (RtlCompareMemory(UniqueId
->UniqueId
, ValueData
, ValueLength
) ==
339 RtlDeleteRegistryValue(RTL_REGISTRY_ABSOLUTE
,
344 return STATUS_SUCCESS
;
351 DeleteFromLocalDatabase(IN PUNICODE_STRING SymbolicLink
,
352 IN PMOUNTDEV_UNIQUE_ID UniqueId
)
354 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
356 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
357 QueryTable
[0].QueryRoutine
= DeleteFromLocalDatabaseRoutine
;
358 QueryTable
[0].Name
= SymbolicLink
->Buffer
;
360 RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
371 WaitForRemoteDatabaseSemaphore(IN PDEVICE_EXTENSION DeviceExtension
)
374 LARGE_INTEGER Timeout
;
376 /* Wait for 7 minutes */
377 Timeout
.QuadPart
= 0xFA0A1F00;
378 Status
= KeWaitForSingleObject(&(DeviceExtension
->RemoteDatabaseLock
), Executive
, KernelMode
, FALSE
, &Timeout
);
379 if (Status
!= STATUS_TIMEOUT
)
384 return STATUS_IO_TIMEOUT
;
391 ReleaseRemoteDatabaseSemaphore(IN PDEVICE_EXTENSION DeviceExtension
)
393 KeReleaseSemaphore(&(DeviceExtension
->RemoteDatabaseLock
), IO_NO_INCREMENT
, 1, FALSE
);
401 QueryUniqueIdQueryRoutine(IN PWSTR ValueName
,
404 IN ULONG ValueLength
,
406 IN PVOID EntryContext
)
408 PMOUNTDEV_UNIQUE_ID IntUniqueId
;
409 PMOUNTDEV_UNIQUE_ID
* UniqueId
;
411 UNREFERENCED_PARAMETER(ValueName
);
412 UNREFERENCED_PARAMETER(ValueType
);
413 UNREFERENCED_PARAMETER(EntryContext
);
416 if (ValueLength
>= 0x10000)
418 return STATUS_SUCCESS
;
421 /* Allocate the Unique ID */
422 IntUniqueId
= AllocatePool(sizeof(UniqueId
) + ValueLength
);
425 /* Copy data & return */
426 IntUniqueId
->UniqueIdLength
= (USHORT
)ValueLength
;
427 RtlCopyMemory(&(IntUniqueId
->UniqueId
), ValueData
, ValueLength
);
430 *UniqueId
= IntUniqueId
;
433 return STATUS_SUCCESS
;
440 QueryUniqueIdFromMaster(IN PDEVICE_EXTENSION DeviceExtension
,
441 IN PUNICODE_STRING SymbolicName
,
442 OUT PMOUNTDEV_UNIQUE_ID
* UniqueId
)
445 PDEVICE_INFORMATION DeviceInformation
;
446 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
448 /* Query the unique ID */
449 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
450 QueryTable
[0].QueryRoutine
= QueryUniqueIdQueryRoutine
;
451 QueryTable
[0].Name
= SymbolicName
->Buffer
;
454 RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
459 /* Unique ID found, no need to go farther */
462 return STATUS_SUCCESS
;
465 /* Otherwise, find associate device information */
466 Status
= FindDeviceInfo(DeviceExtension
, SymbolicName
, FALSE
, &DeviceInformation
);
467 if (!NT_SUCCESS(Status
))
472 *UniqueId
= AllocatePool(DeviceInformation
->UniqueId
->UniqueIdLength
+ sizeof(MOUNTDEV_UNIQUE_ID
));
475 return STATUS_INSUFFICIENT_RESOURCES
;
478 /* Return this unique ID (better than nothing) */
479 (*UniqueId
)->UniqueIdLength
= DeviceInformation
->UniqueId
->UniqueIdLength
;
480 RtlCopyMemory(&((*UniqueId
)->UniqueId
), &(DeviceInformation
->UniqueId
->UniqueId
), (*UniqueId
)->UniqueIdLength
);
482 return STATUS_SUCCESS
;
489 WriteUniqueIdToMaster(IN PDEVICE_EXTENSION DeviceExtension
,
490 IN PDATABASE_ENTRY DatabaseEntry
)
494 PLIST_ENTRY NextEntry
;
495 UNICODE_STRING SymbolicString
;
496 PDEVICE_INFORMATION DeviceInformation
;
498 /* Create symbolic name from database entry */
499 SymbolicName
= AllocatePool(DatabaseEntry
->SymbolicNameLength
+ sizeof(WCHAR
));
502 return STATUS_INSUFFICIENT_RESOURCES
;
505 RtlCopyMemory(SymbolicName
,
506 (PVOID
)((ULONG_PTR
)DatabaseEntry
+ DatabaseEntry
->SymbolicNameOffset
),
507 DatabaseEntry
->SymbolicNameLength
);
508 SymbolicName
[DatabaseEntry
->SymbolicNameLength
/ sizeof(WCHAR
)] = UNICODE_NULL
;
510 /* Associate the unique ID with the name from remote database */
511 Status
= RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE
,
515 (PVOID
)((ULONG_PTR
)DatabaseEntry
+ DatabaseEntry
->UniqueIdOffset
),
516 DatabaseEntry
->UniqueIdLength
);
517 FreePool(SymbolicName
);
519 /* Reget symbolic name */
520 SymbolicString
.Length
= DatabaseEntry
->SymbolicNameLength
;
521 SymbolicString
.MaximumLength
= DatabaseEntry
->SymbolicNameLength
;
522 SymbolicString
.Buffer
= (PVOID
)((ULONG_PTR
)DatabaseEntry
+ DatabaseEntry
->SymbolicNameOffset
);
524 /* Find the device using this unique ID */
525 for (NextEntry
= DeviceExtension
->DeviceListHead
.Flink
;
526 NextEntry
!= &(DeviceExtension
->DeviceListHead
);
527 NextEntry
= NextEntry
->Flink
)
529 DeviceInformation
= CONTAINING_RECORD(NextEntry
,
533 if (DeviceInformation
->UniqueId
->UniqueIdLength
!= DatabaseEntry
->UniqueIdLength
)
538 if (RtlCompareMemory((PVOID
)((ULONG_PTR
)DatabaseEntry
+ DatabaseEntry
->UniqueIdOffset
),
539 DeviceInformation
->UniqueId
->UniqueId
,
540 DatabaseEntry
->UniqueIdLength
) == DatabaseEntry
->UniqueIdLength
)
546 /* If found, create a mount point */
547 if (NextEntry
!= &(DeviceExtension
->DeviceListHead
))
549 MountMgrCreatePointWorker(DeviceExtension
, &SymbolicString
, &(DeviceInformation
->DeviceName
));
560 ReconcileThisDatabaseWithMasterWorker(IN PVOID Parameter
)
564 PFILE_OBJECT FileObject
;
565 PDEVICE_OBJECT DeviceObject
;
566 PMOUNTDEV_UNIQUE_ID UniqueId
;
567 PDATABASE_ENTRY DatabaseEntry
;
568 HANDLE DatabaseHandle
, Handle
;
569 IO_STATUS_BLOCK IoStatusBlock
;
570 OBJECT_ATTRIBUTES ObjectAttributes
;
571 PDEVICE_INFORMATION ListDeviceInfo
;
572 PLIST_ENTRY Entry
, EntryInfo
, NextEntry
;
573 PASSOCIATED_DEVICE_ENTRY AssociatedDevice
;
574 BOOLEAN HardwareErrors
, Restart
, FailedFinding
;
575 WCHAR FileNameBuffer
[0x8], SymbolicNameBuffer
[100];
576 UNICODE_STRING ReparseFile
, FileName
, SymbolicName
, VolumeName
;
577 FILE_REPARSE_POINT_INFORMATION ReparsePointInformation
, SavedReparsePointInformation
;
578 PDEVICE_EXTENSION DeviceExtension
= ((PRECONCILE_WORK_ITEM_CONTEXT
)Parameter
)->DeviceExtension
;
579 PDEVICE_INFORMATION DeviceInformation
= ((PRECONCILE_WORK_ITEM_CONTEXT
)Parameter
)->DeviceInformation
;
581 /* We're unloading, do nothing */
588 if (!NT_SUCCESS(WaitForRemoteDatabaseSemaphore(DeviceExtension
)))
593 /* Recheck for unloading */
599 /* Find the DB to reconcile */
600 KeWaitForSingleObject(&DeviceExtension
->DeviceLock
, Executive
, KernelMode
, FALSE
, NULL
);
601 for (Entry
= DeviceExtension
->DeviceListHead
.Flink
;
602 Entry
!= &DeviceExtension
->DeviceListHead
;
603 Entry
= Entry
->Flink
)
605 ListDeviceInfo
= CONTAINING_RECORD(Entry
, DEVICE_INFORMATION
, DeviceListEntry
);
606 if (ListDeviceInfo
== DeviceInformation
)
612 /* If not found, or if removable, bail out */
613 if (Entry
== &DeviceExtension
->DeviceListHead
|| DeviceInformation
->Removable
)
615 KeReleaseSemaphore(&DeviceExtension
->DeviceLock
, IO_NO_INCREMENT
, 1, FALSE
);
619 /* Get our device object */
620 Status
= IoGetDeviceObjectPointer(&ListDeviceInfo
->DeviceName
, FILE_READ_ATTRIBUTES
, &FileObject
, &DeviceObject
);
621 if (!NT_SUCCESS(Status
))
623 KeReleaseSemaphore(&DeviceExtension
->DeviceLock
, IO_NO_INCREMENT
, 1, FALSE
);
627 if (DeviceObject
->Flags
& 1)
629 _InterlockedExchangeAdd(&ListDeviceInfo
->MountState
, 1u);
632 ObDereferenceObject(FileObject
);
634 /* Force default: no DB, and need for reconcile */
635 DeviceInformation
->NeedsReconcile
= TRUE
;
636 DeviceInformation
->NoDatabase
= TRUE
;
637 FailedFinding
= FALSE
;
639 /* Remove any associated device that refers to the DB to reconcile */
640 for (Entry
= DeviceExtension
->DeviceListHead
.Flink
;
641 Entry
!= &DeviceExtension
->DeviceListHead
;
642 Entry
= Entry
->Flink
)
644 ListDeviceInfo
= CONTAINING_RECORD(Entry
, DEVICE_INFORMATION
, DeviceListEntry
);
646 EntryInfo
= ListDeviceInfo
->AssociatedDevicesHead
.Flink
;
647 while (EntryInfo
!= &ListDeviceInfo
->AssociatedDevicesHead
)
649 AssociatedDevice
= CONTAINING_RECORD(EntryInfo
, ASSOCIATED_DEVICE_ENTRY
, AssociatedDevicesEntry
);
650 NextEntry
= EntryInfo
->Flink
;
652 if (AssociatedDevice
->DeviceInformation
== DeviceInformation
)
654 RemoveEntryList(&AssociatedDevice
->AssociatedDevicesEntry
);
655 FreePool(AssociatedDevice
->String
.Buffer
);
656 FreePool(AssociatedDevice
);
659 EntryInfo
= NextEntry
;
663 /* Open the remote database */
664 DatabaseHandle
= OpenRemoteDatabase(DeviceInformation
, FALSE
);
666 /* Prepare a string with reparse point index */
667 ReparseFile
.Length
= DeviceInformation
->DeviceName
.Length
+ ReparseIndex
.Length
;
668 ReparseFile
.MaximumLength
= ReparseFile
.Length
+ sizeof(UNICODE_NULL
);
669 ReparseFile
.Buffer
= AllocatePool(ReparseFile
.MaximumLength
);
670 if (ReparseFile
.Buffer
== NULL
)
672 if (DatabaseHandle
!= 0)
674 CloseRemoteDatabase(DatabaseHandle
);
676 KeReleaseSemaphore(&DeviceExtension
->DeviceLock
, IO_NO_INCREMENT
, 1, FALSE
);
681 RtlCopyMemory(ReparseFile
.Buffer
, DeviceInformation
->DeviceName
.Buffer
,
682 DeviceInformation
->DeviceName
.Length
);
683 RtlCopyMemory((PVOID
)((ULONG_PTR
)ReparseFile
.Buffer
+ DeviceInformation
->DeviceName
.Length
),
684 ReparseFile
.Buffer
, ReparseFile
.Length
);
685 ReparseFile
.Buffer
[ReparseFile
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
687 InitializeObjectAttributes(&ObjectAttributes
,
689 OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
,
693 /* Open reparse point directory */
694 HardwareErrors
= IoSetThreadHardErrorMode(FALSE
);
695 Status
= ZwOpenFile(&Handle
,
699 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
700 FILE_SYNCHRONOUS_IO_ALERT
);
701 IoSetThreadHardErrorMode(HardwareErrors
);
703 FreePool(ReparseFile
.Buffer
);
705 if (!NT_SUCCESS(Status
))
707 if (DatabaseHandle
!= 0)
709 TruncateRemoteDatabase(DatabaseHandle
, 0);
710 CloseRemoteDatabase(DatabaseHandle
);
712 KeReleaseSemaphore(&DeviceExtension
->DeviceLock
, IO_NO_INCREMENT
, 1, FALSE
);
716 /* Query reparse point information
717 * We only pay attention to mout point
719 RtlZeroMemory(FileNameBuffer
, sizeof(FileNameBuffer
));
720 FileName
.Buffer
= FileNameBuffer
;
721 FileName
.Length
= sizeof(FileNameBuffer
);
722 FileName
.MaximumLength
= sizeof(FileNameBuffer
);
723 ((PULONG
)FileNameBuffer
)[0] = IO_REPARSE_TAG_MOUNT_POINT
;
724 Status
= ZwQueryDirectoryFile(Handle
,
729 &ReparsePointInformation
,
730 sizeof(FILE_REPARSE_POINT_INFORMATION
),
731 FileReparsePointInformation
,
735 if (!NT_SUCCESS(Status
))
738 if (DatabaseHandle
!= 0)
740 TruncateRemoteDatabase(DatabaseHandle
, 0);
741 CloseRemoteDatabase(DatabaseHandle
);
743 KeReleaseSemaphore(&DeviceExtension
->DeviceLock
, IO_NO_INCREMENT
, 1, FALSE
);
747 /* If we failed to open the remote DB previously,
748 * retry this time allowing migration (and thus, creation if required)
750 if (DatabaseHandle
== 0)
752 DatabaseHandle
= OpenRemoteDatabase(DeviceInformation
, TRUE
);
753 if (DatabaseHandle
== 0)
755 KeReleaseSemaphore(&DeviceExtension
->DeviceLock
, IO_NO_INCREMENT
, 1, FALSE
);
760 KeReleaseSemaphore(&DeviceExtension
->DeviceLock
, IO_NO_INCREMENT
, 1, FALSE
);
762 /* Reset all the references to our DB entries */
766 DatabaseEntry
= GetRemoteDatabaseEntry(DatabaseHandle
, Offset
);
767 if (DatabaseEntry
== NULL
)
772 DatabaseEntry
->EntryReferences
= 0;
773 Status
= WriteRemoteDatabaseEntry(DatabaseHandle
, Offset
, DatabaseEntry
);
774 if (!NT_SUCCESS(Status
))
776 FreePool(DatabaseEntry
);
780 Offset
+= DatabaseEntry
->EntrySize
;
781 FreePool(DatabaseEntry
);
784 /* Init string for QueryVolumeName call */
785 SymbolicName
.MaximumLength
= sizeof(SymbolicNameBuffer
);
786 SymbolicName
.Length
= 0;
787 SymbolicName
.Buffer
= SymbolicNameBuffer
;
790 /* Start looping on reparse points */
793 RtlCopyMemory(&SavedReparsePointInformation
, &ReparsePointInformation
, sizeof(FILE_REPARSE_POINT_INFORMATION
));
794 Status
= ZwQueryDirectoryFile(Handle
,
799 &ReparsePointInformation
,
800 sizeof(FILE_REPARSE_POINT_INFORMATION
),
801 FileReparsePointInformation
,
803 Restart
? &FileName
: NULL
,
805 /* Restart only once */
812 /* If we get the same one, we're done, bail out */
813 if (ReparsePointInformation
.FileReference
== SavedReparsePointInformation
.FileReference
&&
814 ReparsePointInformation
.Tag
== SavedReparsePointInformation
.Tag
)
820 /* If querying failed, or if onloading, or if not returning mount points, bail out */
821 if (!NT_SUCCESS(Status
) || Unloading
|| ReparsePointInformation
.Tag
!= IO_REPARSE_TAG_MOUNT_POINT
)
826 /* Get the volume name associated to the mount point */
827 Status
= QueryVolumeName(Handle
, &ReparsePointInformation
, 0, &SymbolicName
, &VolumeName
);
828 if (!NT_SUCCESS(Status
))
833 /* Browse the DB to find the name */
837 UNICODE_STRING DbName
;
839 DatabaseEntry
= GetRemoteDatabaseEntry(DatabaseHandle
, Offset
);
840 if (DatabaseEntry
== NULL
)
845 DbName
.MaximumLength
= DatabaseEntry
->SymbolicNameLength
;
846 DbName
.Length
= DbName
.MaximumLength
;
847 DbName
.Buffer
= (PWSTR
)((ULONG_PTR
)DatabaseEntry
+ DatabaseEntry
->SymbolicNameOffset
);
848 /* Found, we're done! */
849 if (RtlEqualUnicodeString(&DbName
, &SymbolicName
, TRUE
))
854 Offset
+= DatabaseEntry
->EntrySize
;
855 FreePool(DatabaseEntry
);
858 /* If we found the mount point.... */
859 if (DatabaseEntry
!= NULL
)
861 /* If it was referenced, reference it once more and update to remote */
862 if (DatabaseEntry
->EntryReferences
)
864 ++DatabaseEntry
->EntryReferences
;
865 Status
= WriteRemoteDatabaseEntry(DatabaseHandle
, Offset
, DatabaseEntry
);
866 if (!NT_SUCCESS(Status
))
871 FreePool(DatabaseEntry
);
875 /* Query the Unique ID associated to that mount point in case it changed */
876 KeWaitForSingleObject(&DeviceExtension
->DeviceLock
, Executive
, KernelMode
, FALSE
, NULL
);
877 Status
= QueryUniqueIdFromMaster(DeviceExtension
, &SymbolicName
, &UniqueId
);
878 if (!NT_SUCCESS(Status
))
880 /* If we failed doing so, reuse the old Unique ID and push it to master */
881 Status
= WriteUniqueIdToMaster(DeviceExtension
, DatabaseEntry
);
882 if (!NT_SUCCESS(Status
))
884 goto ReleaseDeviceLock
;
887 /* And then, reference & write the entry */
888 ++DatabaseEntry
->EntryReferences
;
889 Status
= WriteRemoteDatabaseEntry(DatabaseHandle
, Offset
, DatabaseEntry
);
890 if (!NT_SUCCESS(Status
))
892 goto ReleaseDeviceLock
;
895 KeReleaseSemaphore(&DeviceExtension
->DeviceLock
, IO_NO_INCREMENT
, 1, FALSE
);
896 FreePool(DatabaseEntry
);
898 /* If the Unique ID didn't change */
899 else if (UniqueId
->UniqueIdLength
== DatabaseEntry
->UniqueIdLength
&&
900 RtlCompareMemory(UniqueId
->UniqueId
,
901 (PVOID
)((ULONG_PTR
)DatabaseEntry
+ DatabaseEntry
->UniqueIdOffset
),
902 UniqueId
->UniqueIdLength
) == UniqueId
->UniqueIdLength
)
904 /* Reference the entry, and update to remote */
905 ++DatabaseEntry
->EntryReferences
;
906 Status
= WriteRemoteDatabaseEntry(DatabaseHandle
, Offset
, DatabaseEntry
);
907 if (!NT_SUCCESS(Status
))
913 KeReleaseSemaphore(&DeviceExtension
->DeviceLock
, IO_NO_INCREMENT
, 1, FALSE
);
914 FreePool(DatabaseEntry
);
916 /* Would, by chance, the Unique ID be present elsewhere? */
917 else if (IsUniqueIdPresent(DeviceExtension
, DatabaseEntry
))
919 /* Push the ID to master */
920 Status
= WriteUniqueIdToMaster(DeviceExtension
, DatabaseEntry
);
921 if (!NT_SUCCESS(Status
))
926 /* And then, reference & write the entry */
927 ++DatabaseEntry
->EntryReferences
;
928 Status
= WriteRemoteDatabaseEntry(DatabaseHandle
, Offset
, DatabaseEntry
);
929 if (!NT_SUCCESS(Status
))
935 KeReleaseSemaphore(&DeviceExtension
->DeviceLock
, IO_NO_INCREMENT
, 1, FALSE
);
936 FreePool(DatabaseEntry
);
940 /* OK, at that point, we're facing a totally unknown unique ID
941 * So, get rid of the old entry, and recreate a new one with
944 Status
= DeleteRemoteDatabaseEntry(DatabaseHandle
, Offset
);
945 if (!NT_SUCCESS(Status
))
950 FreePool(DatabaseEntry
);
951 /* Allocate a new entry big enough */
952 DatabaseEntry
= AllocatePool(UniqueId
->UniqueIdLength
+ SymbolicName
.Length
+ sizeof(DATABASE_ENTRY
));
953 if (DatabaseEntry
== NULL
)
959 DatabaseEntry
->EntrySize
= UniqueId
->UniqueIdLength
+ SymbolicName
.Length
+ sizeof(DATABASE_ENTRY
);
960 DatabaseEntry
->EntryReferences
= 1;
961 DatabaseEntry
->SymbolicNameOffset
= sizeof(DATABASE_ENTRY
);
962 DatabaseEntry
->SymbolicNameLength
= SymbolicName
.Length
;
963 DatabaseEntry
->UniqueIdOffset
= SymbolicName
.Length
+ sizeof(DATABASE_ENTRY
);
964 DatabaseEntry
->UniqueIdLength
= UniqueId
->UniqueIdLength
;
965 RtlCopyMemory((PVOID
)((ULONG_PTR
)DatabaseEntry
+ DatabaseEntry
->SymbolicNameOffset
), SymbolicName
.Buffer
, DatabaseEntry
->SymbolicNameLength
);
966 RtlCopyMemory((PVOID
)((ULONG_PTR
)DatabaseEntry
+ DatabaseEntry
->UniqueIdOffset
), UniqueId
->UniqueId
, UniqueId
->UniqueIdLength
);
968 /* And write it remotely */
969 Status
= AddRemoteDatabaseEntry(DatabaseHandle
, DatabaseEntry
);
970 if (!NT_SUCCESS(Status
))
972 FreePool(DatabaseEntry
);
977 FreePool(DatabaseEntry
);
978 KeReleaseSemaphore(&DeviceExtension
->DeviceLock
, IO_NO_INCREMENT
, 1, FALSE
);
984 /* We failed finding it remotely
985 * So, let's allocate a new remote DB entry
987 KeWaitForSingleObject(&DeviceExtension
->DeviceLock
, Executive
, KernelMode
, FALSE
, NULL
);
988 /* To be able to do so, we need the device Unique ID, ask master */
989 Status
= QueryUniqueIdFromMaster(DeviceExtension
, &SymbolicName
, &UniqueId
);
990 KeReleaseSemaphore(&DeviceExtension
->DeviceLock
, IO_NO_INCREMENT
, 1, FALSE
);
991 if (NT_SUCCESS(Status
))
993 /* Allocate a new entry big enough */
994 DatabaseEntry
= AllocatePool(UniqueId
->UniqueIdLength
+ SymbolicName
.Length
+ sizeof(DATABASE_ENTRY
));
995 if (DatabaseEntry
!= NULL
)
998 DatabaseEntry
->EntrySize
= UniqueId
->UniqueIdLength
+ SymbolicName
.Length
+ sizeof(DATABASE_ENTRY
);
999 DatabaseEntry
->EntryReferences
= 1;
1000 DatabaseEntry
->SymbolicNameOffset
= sizeof(DATABASE_ENTRY
);
1001 DatabaseEntry
->SymbolicNameLength
= SymbolicName
.Length
;
1002 DatabaseEntry
->UniqueIdOffset
= SymbolicName
.Length
+ sizeof(DATABASE_ENTRY
);
1003 DatabaseEntry
->UniqueIdLength
= UniqueId
->UniqueIdLength
;
1004 RtlCopyMemory((PVOID
)((ULONG_PTR
)DatabaseEntry
+ DatabaseEntry
->SymbolicNameOffset
), SymbolicName
.Buffer
, DatabaseEntry
->SymbolicNameLength
);
1005 RtlCopyMemory((PVOID
)((ULONG_PTR
)DatabaseEntry
+ DatabaseEntry
->UniqueIdOffset
), UniqueId
->UniqueId
, UniqueId
->UniqueIdLength
);
1007 /* And write it remotely */
1008 Status
= AddRemoteDatabaseEntry(DatabaseHandle
, DatabaseEntry
);
1009 FreePool(DatabaseEntry
);
1012 if (!NT_SUCCESS(Status
))
1024 /* Find info about the device associated associated with the mount point */
1025 KeWaitForSingleObject(&DeviceExtension
->DeviceLock
, Executive
, KernelMode
, FALSE
, NULL
);
1026 Status
= FindDeviceInfo(DeviceExtension
, &SymbolicName
, FALSE
, &ListDeviceInfo
);
1027 if (!NT_SUCCESS(Status
))
1029 FailedFinding
= TRUE
;
1030 FreePool(VolumeName
.Buffer
);
1034 /* Associate the device with the currrent DB */
1035 AssociatedDevice
= AllocatePool(sizeof(ASSOCIATED_DEVICE_ENTRY
));
1036 if (AssociatedDevice
== NULL
)
1038 FreePool(VolumeName
.Buffer
);
1042 AssociatedDevice
->DeviceInformation
= DeviceInformation
;
1043 AssociatedDevice
->String
.Length
= VolumeName
.Length
;
1044 AssociatedDevice
->String
.MaximumLength
= VolumeName
.MaximumLength
;
1045 AssociatedDevice
->String
.Buffer
= VolumeName
.Buffer
;
1046 InsertTailList(&ListDeviceInfo
->AssociatedDevicesHead
, &AssociatedDevice
->AssociatedDevicesEntry
);
1049 /* If we don't have to skip notifications, notify */
1050 if (!ListDeviceInfo
->SkipNotifications
)
1052 PostOnlineNotification(DeviceExtension
, &ListDeviceInfo
->SymbolicName
);
1056 KeReleaseSemaphore(&DeviceExtension
->DeviceLock
, IO_NO_INCREMENT
, 1, FALSE
);
1059 /* We don't need mount points any longer */
1062 /* Look for the DB again */
1063 KeWaitForSingleObject(&DeviceExtension
->DeviceLock
, Executive
, KernelMode
, FALSE
, NULL
);
1064 for (Entry
= DeviceExtension
->DeviceListHead
.Flink
;
1065 Entry
!= &DeviceExtension
->DeviceListHead
;
1066 Entry
= Entry
->Flink
)
1068 ListDeviceInfo
= CONTAINING_RECORD(Entry
, DEVICE_INFORMATION
, DeviceListEntry
);
1069 if (ListDeviceInfo
== DeviceInformation
)
1075 if (Entry
== &DeviceExtension
->DeviceListHead
)
1077 ListDeviceInfo
= NULL
;
1080 /* Start the pruning loop */
1085 DatabaseEntry
= GetRemoteDatabaseEntry(DatabaseHandle
, Offset
);
1086 if (DatabaseEntry
== NULL
)
1091 /* It's not referenced anylonger? Prune it */
1092 if (DatabaseEntry
->EntryReferences
== 0)
1094 Status
= DeleteRemoteDatabaseEntry(DatabaseHandle
, Offset
);
1095 if (!NT_SUCCESS(Status
))
1097 FreePool(DatabaseEntry
);
1098 KeReleaseSemaphore(&DeviceExtension
->DeviceLock
, IO_NO_INCREMENT
, 1, FALSE
);
1102 /* Update the Unique IDs to reflect the changes we might have done previously */
1105 if (ListDeviceInfo
!= NULL
)
1107 UpdateReplicatedUniqueIds(ListDeviceInfo
, DatabaseEntry
);
1110 Offset
+= DatabaseEntry
->EntrySize
;
1113 FreePool(DatabaseEntry
);
1116 /* We do have a DB now :-) */
1117 if (ListDeviceInfo
!= NULL
&& !FailedFinding
)
1119 DeviceInformation
->NoDatabase
= FALSE
;
1122 KeReleaseSemaphore(&DeviceExtension
->DeviceLock
, IO_NO_INCREMENT
, 1, FALSE
);
1129 KeReleaseSemaphore(&DeviceExtension
->DeviceLock
, IO_NO_INCREMENT
, 1, FALSE
);
1131 FreePool(DatabaseEntry
);
1133 FreePool(VolumeName
.Buffer
);
1137 CloseRemoteDatabase(DatabaseHandle
);
1139 ReleaseRemoteDatabaseSemaphore(DeviceExtension
);
1148 WorkerThread(IN PDEVICE_OBJECT DeviceObject
,
1157 LARGE_INTEGER Timeout
;
1158 PRECONCILE_WORK_ITEM WorkItem
;
1159 PDEVICE_EXTENSION DeviceExtension
;
1160 OBJECT_ATTRIBUTES ObjectAttributes
;
1162 UNREFERENCED_PARAMETER(DeviceObject
);
1164 InitializeObjectAttributes(&ObjectAttributes
,
1166 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
1169 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
1170 Timeout
.LowPart
= 0xFFFFFFFF;
1171 Timeout
.HighPart
= 0xFF676980;
1173 /* Try to wait as long as possible */
1174 for (i
= (Unloading
? 999 : 0); i
< 1000; i
++)
1176 Status
= ZwOpenEvent(&SafeEvent
, EVENT_ALL_ACCESS
, &ObjectAttributes
);
1177 if (NT_SUCCESS(Status
))
1182 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, &Timeout
);
1189 Status
= ZwWaitForSingleObject(SafeEvent
, FALSE
, &Timeout
);
1191 while (Status
== STATUS_TIMEOUT
&& !Unloading
);
1196 DeviceExtension
= Context
;
1198 InterlockedExchange(&(DeviceExtension
->WorkerThreadStatus
), 1);
1200 /* Acquire workers lock */
1201 KeWaitForSingleObject(&(DeviceExtension
->WorkerSemaphore
), Executive
, KernelMode
, FALSE
, NULL
);
1203 KeAcquireSpinLock(&(DeviceExtension
->WorkerLock
), &OldIrql
);
1205 /* Ensure there are workers */
1206 while (!IsListEmpty(&(DeviceExtension
->WorkerQueueListHead
)))
1208 /* Unqueue a worker */
1209 Entry
= RemoveHeadList(&(DeviceExtension
->WorkerQueueListHead
));
1210 WorkItem
= CONTAINING_RECORD(Entry
,
1211 RECONCILE_WORK_ITEM
,
1212 WorkerQueueListEntry
);
1214 KeReleaseSpinLock(&(DeviceExtension
->WorkerLock
), OldIrql
);
1217 WorkItem
->WorkerRoutine(WorkItem
->Context
);
1219 IoFreeWorkItem(WorkItem
->WorkItem
);
1222 if (InterlockedDecrement(&(DeviceExtension
->WorkerReferences
)) == 0)
1227 KeWaitForSingleObject(&(DeviceExtension
->WorkerSemaphore
), Executive
, KernelMode
, FALSE
, NULL
);
1228 KeAcquireSpinLock(&(DeviceExtension
->WorkerLock
), &OldIrql
);
1230 KeReleaseSpinLock(&(DeviceExtension
->WorkerLock
), OldIrql
);
1232 InterlockedDecrement(&(DeviceExtension
->WorkerReferences
));
1235 KeSetEvent(&UnloadEvent
, IO_NO_INCREMENT
, FALSE
);
1242 QueueWorkItem(IN PDEVICE_EXTENSION DeviceExtension
,
1243 IN PRECONCILE_WORK_ITEM WorkItem
,
1248 WorkItem
->Context
= Context
;
1250 /* When called, lock is already acquired */
1252 /* If noone, start to work */
1253 if (InterlockedIncrement(&(DeviceExtension
->WorkerReferences
)))
1255 IoQueueWorkItem(WorkItem
->WorkItem
, WorkerThread
, DelayedWorkQueue
, DeviceExtension
);
1258 /* Otherwise queue worker for delayed execution */
1259 KeAcquireSpinLock(&(DeviceExtension
->WorkerLock
), &OldIrql
);
1260 InsertTailList(&(DeviceExtension
->WorkerQueueListHead
),
1261 &(WorkItem
->WorkerQueueListEntry
));
1262 KeReleaseSpinLock(&(DeviceExtension
->WorkerLock
), OldIrql
);
1264 KeReleaseSemaphore(&(DeviceExtension
->WorkerSemaphore
), IO_NO_INCREMENT
, 1, FALSE
);
1266 return STATUS_SUCCESS
;
1273 QueryVolumeName(IN HANDLE RootDirectory
,
1274 IN PFILE_REPARSE_POINT_INFORMATION ReparsePointInformation
,
1275 IN PUNICODE_STRING FileName OPTIONAL
,
1276 OUT PUNICODE_STRING SymbolicName
,
1277 OUT PUNICODE_STRING VolumeName
)
1282 IO_STATUS_BLOCK IoStatusBlock
;
1283 OBJECT_ATTRIBUTES ObjectAttributes
;
1284 PFILE_NAME_INFORMATION FileNameInfo
;
1285 PREPARSE_DATA_BUFFER ReparseDataBuffer
;
1287 UNREFERENCED_PARAMETER(ReparsePointInformation
);
1291 InitializeObjectAttributes(&ObjectAttributes
,
1299 InitializeObjectAttributes(&ObjectAttributes
,
1301 OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
,
1307 Status
= ZwOpenFile(&Handle
,
1308 SYNCHRONIZE
| FILE_READ_ATTRIBUTES
,
1311 FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
,
1312 (FileName
) ? FILE_SYNCHRONOUS_IO_NONALERT
| FILE_OPEN_REPARSE_POINT
:
1313 FILE_OPEN_BY_FILE_ID
| FILE_SYNCHRONOUS_IO_NONALERT
| FILE_OPEN_REPARSE_POINT
);
1314 if (!NT_SUCCESS(Status
))
1319 /* Get the reparse point data */
1320 ReparseDataBuffer
= AllocatePool(MAXIMUM_REPARSE_DATA_BUFFER_SIZE
);
1321 if (!ReparseDataBuffer
)
1324 return STATUS_INSUFFICIENT_RESOURCES
;
1327 Status
= ZwFsControlFile(Handle
,
1332 FSCTL_GET_REPARSE_POINT
,
1336 MAXIMUM_REPARSE_DATA_BUFFER_SIZE
);
1337 if (!NT_SUCCESS(Status
))
1339 FreePool(ReparseDataBuffer
);
1344 /* Check that name can fit in buffer */
1345 if (ReparseDataBuffer
->MountPointReparseBuffer
.SubstituteNameLength
+ sizeof(UNICODE_NULL
) > SymbolicName
->MaximumLength
)
1347 FreePool(ReparseDataBuffer
);
1349 return STATUS_BUFFER_TOO_SMALL
;
1352 /* Copy symoblic name */
1353 SymbolicName
->Length
= ReparseDataBuffer
->MountPointReparseBuffer
.SubstituteNameLength
;
1354 RtlCopyMemory(SymbolicName
->Buffer
,
1355 (PWSTR
)((ULONG_PTR
)ReparseDataBuffer
->MountPointReparseBuffer
.PathBuffer
+
1356 ReparseDataBuffer
->MountPointReparseBuffer
.SubstituteNameOffset
),
1357 ReparseDataBuffer
->MountPointReparseBuffer
.SubstituteNameLength
);
1359 FreePool(ReparseDataBuffer
);
1361 /* Name has to \ terminated */
1362 if (SymbolicName
->Buffer
[SymbolicName
->Length
/ sizeof(WCHAR
) - 1] != L
'\\')
1365 return STATUS_INVALID_PARAMETER
;
1368 /* So that we can delete it, and match mountmgr requirements */
1369 SymbolicName
->Length
-= sizeof(WCHAR
);
1370 SymbolicName
->Buffer
[SymbolicName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1372 /* Also ensure it's really a volume name... */
1373 if (!MOUNTMGR_IS_VOLUME_NAME(SymbolicName
))
1376 return STATUS_INVALID_PARAMETER
;
1379 /* Now prepare to really get the name */
1380 FileNameInfo
= AllocatePool(sizeof(FILE_NAME_INFORMATION
) + 2 * sizeof(WCHAR
));
1384 return STATUS_INSUFFICIENT_RESOURCES
;
1387 Status
= ZwQueryInformationFile(Handle
,
1390 sizeof(FILE_NAME_INFORMATION
) + 2 * sizeof(WCHAR
),
1391 FileNameInformation
);
1392 if (Status
== STATUS_BUFFER_OVERFLOW
)
1394 /* As expected... Reallocate with proper size */
1395 NeededLength
= FileNameInfo
->FileNameLength
;
1396 FreePool(FileNameInfo
);
1398 FileNameInfo
= AllocatePool(sizeof(FILE_NAME_INFORMATION
) + NeededLength
);
1402 return STATUS_INSUFFICIENT_RESOURCES
;
1405 /* And query name */
1406 Status
= ZwQueryInformationFile(Handle
,
1409 sizeof(FILE_NAME_INFORMATION
) + NeededLength
,
1410 FileNameInformation
);
1415 if (!NT_SUCCESS(Status
))
1420 /* Return the volume name */
1421 VolumeName
->Length
= (USHORT
)FileNameInfo
->FileNameLength
;
1422 VolumeName
->MaximumLength
= (USHORT
)FileNameInfo
->FileNameLength
+ sizeof(WCHAR
);
1423 VolumeName
->Buffer
= AllocatePool(VolumeName
->MaximumLength
);
1424 if (!VolumeName
->Buffer
)
1426 return STATUS_INSUFFICIENT_RESOURCES
;
1429 RtlCopyMemory(VolumeName
->Buffer
, FileNameInfo
->FileName
, FileNameInfo
->FileNameLength
);
1430 VolumeName
->Buffer
[FileNameInfo
->FileNameLength
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1432 FreePool(FileNameInfo
);
1434 return STATUS_SUCCESS
;
1441 OnlineMountedVolumes(IN PDEVICE_EXTENSION DeviceExtension
,
1442 IN PDEVICE_INFORMATION DeviceInformation
)
1446 BOOLEAN RestartScan
;
1447 IO_STATUS_BLOCK IoStatusBlock
;
1448 OBJECT_ATTRIBUTES ObjectAttributes
;
1449 PDEVICE_INFORMATION VolumeDeviceInformation
;
1450 WCHAR FileNameBuffer
[0x8], SymbolicNameBuffer
[0x64];
1451 UNICODE_STRING ReparseFile
, FileName
, SymbolicName
, VolumeName
;
1452 FILE_REPARSE_POINT_INFORMATION ReparsePointInformation
, SavedReparsePointInformation
;
1454 /* Removable devices don't have remote database on them */
1455 if (DeviceInformation
->Removable
)
1460 /* Prepare a string with reparse point index */
1461 ReparseFile
.Length
= DeviceInformation
->DeviceName
.Length
+ ReparseIndex
.Length
;
1462 ReparseFile
.MaximumLength
= ReparseFile
.Length
+ sizeof(UNICODE_NULL
);
1463 ReparseFile
.Buffer
= AllocatePool(ReparseFile
.MaximumLength
);
1464 if (!ReparseFile
.Buffer
)
1469 RtlCopyMemory(ReparseFile
.Buffer
, DeviceInformation
->DeviceName
.Buffer
,
1470 DeviceInformation
->DeviceName
.Length
);
1471 RtlCopyMemory((PVOID
)((ULONG_PTR
)ReparseFile
.Buffer
+ DeviceInformation
->DeviceName
.Length
),
1472 ReparseFile
.Buffer
, ReparseFile
.Length
);
1473 ReparseFile
.Buffer
[ReparseFile
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1475 InitializeObjectAttributes(&ObjectAttributes
,
1477 OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
,
1481 /* Open reparse point */
1482 Status
= ZwOpenFile(&Handle
,
1486 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
1487 FILE_SYNCHRONOUS_IO_ALERT
| FILE_OPEN_REPARSE_POINT
);
1488 FreePool(ReparseFile
.Buffer
);
1489 if (!NT_SUCCESS(Status
))
1491 DeviceInformation
->NoDatabase
= FALSE
;
1495 /* Query reparse point information
1496 * We only pay attention to mout point
1498 RtlZeroMemory(FileNameBuffer
, sizeof(FileNameBuffer
));
1499 FileName
.Buffer
= FileNameBuffer
;
1500 FileName
.Length
= sizeof(FileNameBuffer
);
1501 FileName
.MaximumLength
= sizeof(FileNameBuffer
);
1502 ((PULONG
)FileNameBuffer
)[0] = IO_REPARSE_TAG_MOUNT_POINT
;
1503 Status
= ZwQueryDirectoryFile(Handle
,
1508 &ReparsePointInformation
,
1509 sizeof(FILE_REPARSE_POINT_INFORMATION
),
1510 FileReparsePointInformation
,
1514 if (!NT_SUCCESS(Status
))
1522 /* Query mount points */
1525 SymbolicName
.Length
= 0;
1526 SymbolicName
.MaximumLength
= sizeof(SymbolicNameBuffer
);
1527 SymbolicName
.Buffer
= SymbolicNameBuffer
;
1528 RtlCopyMemory(&SavedReparsePointInformation
, &ReparsePointInformation
, sizeof(FILE_REPARSE_POINT_INFORMATION
));
1530 Status
= ZwQueryDirectoryFile(Handle
,
1535 &ReparsePointInformation
,
1536 sizeof(FILE_REPARSE_POINT_INFORMATION
),
1537 FileReparsePointInformation
,
1539 (RestartScan
) ? &FileName
: NULL
,
1543 if (ReparsePointInformation
.FileReference
== SavedReparsePointInformation
.FileReference
&&
1544 ReparsePointInformation
.Tag
== SavedReparsePointInformation
.Tag
)
1551 RestartScan
= FALSE
;
1554 if (!NT_SUCCESS(Status
) || ReparsePointInformation
.Tag
!= IO_REPARSE_TAG_MOUNT_POINT
)
1559 /* Get the volume name associated to the mount point */
1560 Status
= QueryVolumeName(Handle
,
1561 &ReparsePointInformation
,
1562 NULL
, &SymbolicName
,
1564 if (!NT_SUCCESS(Status
))
1569 FreePool(VolumeName
.Buffer
);
1571 /* Get its information */
1572 Status
= FindDeviceInfo(DeviceExtension
, &SymbolicName
,
1573 FALSE
, &VolumeDeviceInformation
);
1574 if (!NT_SUCCESS(Status
))
1576 DeviceInformation
->NoDatabase
= TRUE
;
1580 /* If notification are enabled, mark it online */
1581 if (!DeviceInformation
->SkipNotifications
)
1583 PostOnlineNotification(DeviceExtension
, &VolumeDeviceInformation
->SymbolicName
);
1594 ReconcileThisDatabaseWithMaster(IN PDEVICE_EXTENSION DeviceExtension
,
1595 IN PDEVICE_INFORMATION DeviceInformation
)
1597 PRECONCILE_WORK_ITEM WorkItem
;
1599 /* Removable devices don't have remote database */
1600 if (DeviceInformation
->Removable
)
1605 /* Allocate a work item */
1606 WorkItem
= AllocatePool(sizeof(RECONCILE_WORK_ITEM
));
1612 WorkItem
->WorkItem
= IoAllocateWorkItem(DeviceExtension
->DeviceObject
);
1613 if (!WorkItem
->WorkItem
)
1620 WorkItem
->WorkerRoutine
= ReconcileThisDatabaseWithMasterWorker
;
1621 WorkItem
->DeviceExtension
= DeviceExtension
;
1622 WorkItem
->DeviceInformation
= DeviceInformation
;
1623 QueueWorkItem(DeviceExtension
, WorkItem
, &(WorkItem
->DeviceExtension
));
1625 /* If there's no automount, and automatic letters
1626 * all volumes to find those online and notify there presence
1628 if (DeviceExtension
->WorkerThreadStatus
== 0 &&
1629 DeviceExtension
->AutomaticDriveLetter
== 1 &&
1630 DeviceExtension
->NoAutoMount
== FALSE
)
1632 OnlineMountedVolumes(DeviceExtension
, DeviceInformation
);
1640 ReconcileAllDatabasesWithMaster(IN PDEVICE_EXTENSION DeviceExtension
)
1642 PLIST_ENTRY NextEntry
;
1643 PDEVICE_INFORMATION DeviceInformation
;
1645 /* Browse all the devices */
1646 for (NextEntry
= DeviceExtension
->DeviceListHead
.Flink
;
1647 NextEntry
!= &(DeviceExtension
->DeviceListHead
);
1648 NextEntry
= NextEntry
->Flink
)
1650 DeviceInformation
= CONTAINING_RECORD(NextEntry
,
1653 /* If it's not removable, then, it might have a database to sync */
1654 if (!DeviceInformation
->Removable
)
1656 ReconcileThisDatabaseWithMaster(DeviceExtension
, DeviceInformation
);
1666 CreateRemoteDatabaseWorker(IN PDEVICE_OBJECT DeviceObject
,
1670 HANDLE Database
= 0;
1671 UNICODE_STRING DatabaseName
;
1672 PMIGRATE_WORK_ITEM WorkItem
;
1673 IO_STATUS_BLOCK IoStatusBlock
;
1674 OBJECT_ATTRIBUTES ObjectAttributes
;
1675 PDEVICE_INFORMATION DeviceInformation
;
1677 UNREFERENCED_PARAMETER(DeviceObject
);
1679 /* Extract context */
1681 DeviceInformation
= WorkItem
->DeviceInformation
;
1683 /* Reconstruct appropriate string */
1684 DatabaseName
.Length
= DeviceInformation
->DeviceName
.Length
+ RemoteDatabase
.Length
;
1685 DatabaseName
.MaximumLength
= DatabaseName
.Length
+ sizeof(WCHAR
);
1686 DatabaseName
.Buffer
= AllocatePool(DatabaseName
.MaximumLength
);
1687 if (DatabaseName
.Buffer
== NULL
)
1689 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1693 /* Create the required folder (in which the database will be stored
1694 * \System Volume Information at root of the volume
1696 Status
= RtlCreateSystemVolumeInformationFolder(&(DeviceInformation
->DeviceName
));
1697 if (!NT_SUCCESS(Status
))
1702 /* Finish initating strings */
1703 RtlCopyMemory(DatabaseName
.Buffer
, DeviceInformation
->DeviceName
.Buffer
, DeviceInformation
->DeviceName
.Length
);
1704 RtlCopyMemory(DatabaseName
.Buffer
+ (DeviceInformation
->DeviceName
.Length
/ sizeof(WCHAR
)),
1705 RemoteDatabase
.Buffer
, RemoteDatabase
.Length
);
1706 DatabaseName
.Buffer
[DatabaseName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1708 /* Create database */
1709 InitializeObjectAttributes(&ObjectAttributes
,
1711 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
1715 Status
= IoCreateFile(&Database
,
1716 SYNCHRONIZE
| READ_CONTROL
| FILE_WRITE_ATTRIBUTES
|
1717 FILE_READ_ATTRIBUTES
| FILE_WRITE_PROPERTIES
| FILE_READ_PROPERTIES
|
1718 FILE_APPEND_DATA
| FILE_WRITE_DATA
| FILE_READ_DATA
,
1722 FILE_ATTRIBUTE_NORMAL
| FILE_ATTRIBUTE_SYSTEM
| FILE_ATTRIBUTE_HIDDEN
,
1725 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_ALERT
,
1730 IO_STOP_ON_SYMLINK
);
1731 if (!NT_SUCCESS(Status
))
1733 if (Status
== STATUS_STOPPED_ON_SYMLINK
)
1735 DPRINT1("Attempt to exploit CVE-2015-1769. See CORE-10216\n");
1743 if (DatabaseName
.Buffer
)
1745 FreePool(DatabaseName
.Buffer
);
1748 if (NT_SUCCESS(Status
))
1750 DeviceInformation
->Migrated
= 1;
1752 else if (Database
!= 0)
1757 IoFreeWorkItem(WorkItem
->WorkItem
);
1759 WorkItem
->WorkItem
= NULL
;
1760 WorkItem
->Status
= Status
;
1761 WorkItem
->Database
= Database
;
1763 KeSetEvent(WorkItem
->Event
, 0, FALSE
);
1770 CreateRemoteDatabase(IN PDEVICE_INFORMATION DeviceInformation
,
1771 IN OUT PHANDLE Database
)
1775 PMIGRATE_WORK_ITEM WorkItem
;
1777 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
1779 /* Allocate a work item dedicated to migration */
1780 WorkItem
= AllocatePool(sizeof(MIGRATE_WORK_ITEM
));
1784 return STATUS_INSUFFICIENT_RESOURCES
;
1787 RtlZeroMemory(WorkItem
, sizeof(MIGRATE_WORK_ITEM
));
1788 WorkItem
->Event
= &Event
;
1789 WorkItem
->DeviceInformation
= DeviceInformation
;
1790 WorkItem
->WorkItem
= IoAllocateWorkItem(DeviceInformation
->DeviceExtension
->DeviceObject
);
1791 if (!WorkItem
->WorkItem
)
1795 return STATUS_INSUFFICIENT_RESOURCES
;
1799 IoQueueWorkItem(WorkItem
->WorkItem
,
1800 CreateRemoteDatabaseWorker
,
1804 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
1805 Status
= WorkItem
->Status
;
1807 *Database
= (NT_SUCCESS(Status
) ? WorkItem
->Database
: 0);
1817 OpenRemoteDatabase(IN PDEVICE_INFORMATION DeviceInformation
,
1818 IN BOOLEAN MigrateDatabase
)
1822 BOOLEAN PreviousMode
;
1823 IO_STATUS_BLOCK IoStatusBlock
;
1824 OBJECT_ATTRIBUTES ObjectAttributes
;
1825 UNICODE_STRING DeviceRemoteDatabase
;
1829 /* Get database name */
1830 DeviceRemoteDatabase
.Length
= DeviceInformation
->DeviceName
.Length
+ RemoteDatabase
.Length
;
1831 DeviceRemoteDatabase
.MaximumLength
= DeviceRemoteDatabase
.Length
+ sizeof(WCHAR
);
1832 DeviceRemoteDatabase
.Buffer
= AllocatePool(DeviceRemoteDatabase
.MaximumLength
);
1833 if (!DeviceRemoteDatabase
.Buffer
)
1838 RtlCopyMemory(DeviceRemoteDatabase
.Buffer
, DeviceInformation
->DeviceName
.Buffer
, DeviceInformation
->DeviceName
.Length
);
1839 RtlCopyMemory(DeviceRemoteDatabase
.Buffer
+ (DeviceInformation
->DeviceName
.Length
/ sizeof(WCHAR
)),
1840 RemoteDatabase
.Buffer
, RemoteDatabase
.Length
);
1841 DeviceRemoteDatabase
.Buffer
[DeviceRemoteDatabase
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1844 InitializeObjectAttributes(&ObjectAttributes
,
1845 &DeviceRemoteDatabase
,
1846 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
1850 /* Disable hard errors */
1851 PreviousMode
= IoSetThreadHardErrorMode(FALSE
);
1853 Status
= IoCreateFile(&Database
,
1854 SYNCHRONIZE
| READ_CONTROL
| FILE_WRITE_ATTRIBUTES
|
1855 FILE_READ_ATTRIBUTES
| FILE_WRITE_PROPERTIES
| FILE_READ_PROPERTIES
|
1856 FILE_APPEND_DATA
| FILE_WRITE_DATA
| FILE_READ_DATA
,
1860 FILE_ATTRIBUTE_NORMAL
| FILE_ATTRIBUTE_SYSTEM
| FILE_ATTRIBUTE_HIDDEN
,
1862 (!MigrateDatabase
|| DeviceInformation
->Migrated
== 0) ? FILE_OPEN_IF
: FILE_OPEN
,
1863 FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_ALERT
,
1868 IO_STOP_ON_SYMLINK
);
1869 if (Status
== STATUS_STOPPED_ON_SYMLINK
)
1871 DPRINT1("Attempt to exploit CVE-2015-1769. See CORE-10216\n");
1874 /* If base it to be migrated and was opened successfully, go ahead */
1875 if (MigrateDatabase
&& NT_SUCCESS(Status
))
1877 CreateRemoteDatabase(DeviceInformation
, &Database
);
1880 IoSetThreadHardErrorMode(PreviousMode
);
1881 FreePool(DeviceRemoteDatabase
.Buffer
);
1890 ChangeRemoteDatabaseUniqueId(IN PDEVICE_INFORMATION DeviceInformation
,
1891 IN PMOUNTDEV_UNIQUE_ID OldUniqueId
,
1892 IN PMOUNTDEV_UNIQUE_ID NewUniqueId
)
1896 PDATABASE_ENTRY Entry
, NewEntry
;
1897 NTSTATUS Status
= STATUS_SUCCESS
;
1899 /* Open the remote database */
1900 Database
= OpenRemoteDatabase(DeviceInformation
, FALSE
);
1906 /* Get all the entries */
1909 Entry
= GetRemoteDatabaseEntry(Database
, Offset
);
1915 /* Not the correct entry, skip it */
1916 if (Entry
->UniqueIdLength
!= OldUniqueId
->UniqueIdLength
)
1918 Offset
+= Entry
->EntrySize
;
1923 /* Not the correct entry, skip it */
1924 if (RtlCompareMemory(OldUniqueId
->UniqueId
,
1925 (PVOID
)((ULONG_PTR
)Entry
+ Entry
->UniqueIdOffset
),
1926 Entry
->UniqueIdLength
) != Entry
->UniqueIdLength
)
1928 Offset
+= Entry
->EntrySize
;
1933 /* Here, we have the correct entry */
1934 NewEntry
= AllocatePool(Entry
->EntrySize
+ NewUniqueId
->UniqueIdLength
- OldUniqueId
->UniqueIdLength
);
1937 Offset
+= Entry
->EntrySize
;
1942 /* Recreate the entry from the previous one */
1943 NewEntry
->EntrySize
= Entry
->EntrySize
+ NewUniqueId
->UniqueIdLength
- OldUniqueId
->UniqueIdLength
;
1944 NewEntry
->EntryReferences
= Entry
->EntryReferences
;
1945 NewEntry
->SymbolicNameOffset
= sizeof(DATABASE_ENTRY
);
1946 NewEntry
->SymbolicNameLength
= Entry
->SymbolicNameLength
;
1947 NewEntry
->UniqueIdOffset
= Entry
->SymbolicNameLength
+ sizeof(DATABASE_ENTRY
);
1948 NewEntry
->UniqueIdLength
= NewUniqueId
->UniqueIdLength
;
1949 RtlCopyMemory((PVOID
)((ULONG_PTR
)NewEntry
+ NewEntry
->SymbolicNameOffset
),
1950 (PVOID
)((ULONG_PTR
)Entry
+ Entry
->SymbolicNameOffset
),
1951 NewEntry
->SymbolicNameLength
);
1952 RtlCopyMemory((PVOID
)((ULONG_PTR
)NewEntry
+ NewEntry
->UniqueIdOffset
),
1953 NewUniqueId
->UniqueId
, NewEntry
->UniqueIdLength
);
1955 /* Delete old entry */
1956 Status
= DeleteRemoteDatabaseEntry(Database
, Offset
);
1957 if (!NT_SUCCESS(Status
))
1964 /* And replace with new one */
1965 Status
= AddRemoteDatabaseEntry(Database
, NewEntry
);
1968 } while (NT_SUCCESS(Status
));
1970 CloseRemoteDatabase(Database
);
1980 DeleteDriveLetterRoutine(IN PWSTR ValueName
,
1983 IN ULONG ValueLength
,
1985 IN PVOID EntryContext
)
1987 PMOUNTDEV_UNIQUE_ID UniqueId
;
1988 UNICODE_STRING RegistryEntry
;
1990 UNREFERENCED_PARAMETER(EntryContext
);
1992 if (ValueType
!= REG_BINARY
)
1994 return STATUS_SUCCESS
;
1999 /* First ensure we have the correct data */
2000 if (UniqueId
->UniqueIdLength
!= ValueLength
)
2002 return STATUS_SUCCESS
;
2005 if (RtlCompareMemory(UniqueId
->UniqueId
, ValueData
, ValueLength
) != ValueLength
)
2007 return STATUS_SUCCESS
;
2010 RtlInitUnicodeString(&RegistryEntry
, ValueName
);
2012 /* Then, it's a drive letter, erase it */
2013 if (IsDriveLetter(&RegistryEntry
))
2015 RtlDeleteRegistryValue(RTL_REGISTRY_ABSOLUTE
,
2020 return STATUS_SUCCESS
;
2027 DeleteRegistryDriveLetter(IN PMOUNTDEV_UNIQUE_ID UniqueId
)
2029 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
2031 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
2032 QueryTable
[0].QueryRoutine
= DeleteDriveLetterRoutine
;
2034 RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
2046 DeleteNoDriveLetterEntryRoutine(IN PWSTR ValueName
,
2049 IN ULONG ValueLength
,
2051 IN PVOID EntryContext
)
2053 PMOUNTDEV_UNIQUE_ID UniqueId
= Context
;
2055 UNREFERENCED_PARAMETER(EntryContext
);
2057 /* Ensure we have correct input */
2058 if (ValueName
[0] != L
'#' || ValueType
!= REG_BINARY
||
2059 UniqueId
->UniqueIdLength
!= ValueLength
)
2061 return STATUS_SUCCESS
;
2064 /* And then, if unique ID matching, delete entry */
2065 if (RtlCompareMemory(UniqueId
->UniqueId
, ValueData
, ValueLength
) != ValueLength
)
2067 RtlDeleteRegistryValue(RTL_REGISTRY_ABSOLUTE
,
2072 return STATUS_SUCCESS
;
2079 DeleteNoDriveLetterEntry(IN PMOUNTDEV_UNIQUE_ID UniqueId
)
2081 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
2083 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
2084 QueryTable
[0].QueryRoutine
= DeleteNoDriveLetterEntryRoutine
;
2086 RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,