ReactOS 0.4.15-dev-8348-gc1b9bb5
database.c
Go to the documentation of this file.
1/*
2 * ReactOS kernel
3 * Copyright (C) 2011-2012 ReactOS Team
4 *
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.
9 *
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.
14 *
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.
18 *
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)
24 */
25
26#include "mntmgr.h"
27
28#define NDEBUG
29#include <debug.h>
30
31PWSTR DatabasePath = L"\\Registry\\Machine\\System\\MountedDevices";
32PWSTR OfflinePath = L"\\Registry\\Machine\\System\\MountedDevices\\Offline";
33
34UNICODE_STRING RemoteDatabase = RTL_CONSTANT_STRING(L"\\System Volume Information\\MountPointManagerRemoteDatabase");
35
36/*
37 * @implemented
38 */
39LONG
41{
44 FILE_STANDARD_INFORMATION StandardInfo;
45
46 /* Just query the size */
47 Status = ZwQueryInformationFile(Database,
49 &StandardInfo,
52 if (NT_SUCCESS(Status))
53 {
54 return StandardInfo.EndOfFile.LowPart;
55 }
56
57 return 0;
58}
59
60/*
61 * @implemented
62 */
66{
69
70 /* Get size to append data */
72
73 return ZwWriteFile(Database, NULL, NULL, NULL,
75 Entry->EntrySize, &Size, NULL);
76}
77
78/*
79 * @implemented
80 */
83{
84 return ZwClose(Database);
85}
86
87/*
88 * @implemented
89 */
93{
98
99 EndOfFile.EndOfFile.QuadPart = NewSize;
100 Allocation.AllocationSize.QuadPart = NewSize;
101
102 /* First set EOF */
103 Status = ZwSetInformationFile(Database,
105 &EndOfFile,
108 if (NT_SUCCESS(Status))
109 {
110 /* And then, properly set allocation information */
111 Status = ZwSetInformationFile(Database,
113 &Allocation,
116 }
117
118 return Status;
119}
120
121/*
122 * @implemented
123 */
127{
133
134 /* Get the entry at the given position */
135 ByteOffset.QuadPart = StartingOffset;
136 Status = ZwReadFile(Database,
137 NULL,
138 NULL,
139 NULL,
141 &EntrySize,
142 sizeof(EntrySize),
143 &ByteOffset,
144 NULL);
145 if (!NT_SUCCESS(Status))
146 {
147 return NULL;
148 }
149
150 /* If entry doesn't exist, truncate database */
151 if (!EntrySize)
152 {
154 return NULL;
155 }
156
157 /* Allocate the entry */
159 if (!Entry)
160 {
161 return NULL;
162 }
163
164 /* Effectively read the entry */
165 Status = ZwReadFile(Database,
166 NULL,
167 NULL,
168 NULL,
170 Entry,
171 EntrySize,
172 &ByteOffset,
173 NULL);
174 /* If it fails or returns inconsistent data, drop it (= truncate) */
175 if (!NT_SUCCESS(Status) ||
177 (EntrySize < sizeof(DATABASE_ENTRY)) )
178 {
181 return NULL;
182 }
183
184 /* Validate entry */
185 if (MAX(Entry->SymbolicNameOffset + Entry->SymbolicNameLength,
186 Entry->UniqueIdOffset + Entry->UniqueIdLength) > (LONG)EntrySize)
187 {
190 return NULL;
191 }
192
193 return Entry;
194}
195
196/*
197 * @implemented
198 */
201 IN LONG Offset,
203{
207
208 ByteOffset.QuadPart = Offset;
209 Status = ZwWriteFile(Database,
210 NULL,
211 NULL,
212 NULL,
214 Entry,
215 Entry->EntrySize,
216 &ByteOffset,
217 NULL);
218 if (NT_SUCCESS(Status))
219 {
220 if (IoStatusBlock.Information < Entry->EntrySize)
221 {
223 }
224 }
225
226 return Status;
227}
228
229/*
230 * @implemented
231 */
235{
236 ULONG EndSize;
237 PVOID TmpBuffer;
239 ULONG DatabaseSize;
242 LARGE_INTEGER EndEntriesOffset;
243
244 /* First, get database size */
245 DatabaseSize = GetRemoteDatabaseSize(Database);
246 if (!DatabaseSize)
247 {
249 }
250
251 /* Then, get the entry to remove */
253 if (!Entry)
254 {
256 }
257
258 /* Validate parameters: ensure we won't get negative size */
259 if (Entry->EntrySize + StartingOffset > DatabaseSize)
260 {
261 /* If we get invalid parameters, truncate the whole database
262 * starting the wrong entry. We can't rely on the rest
263 */
266 }
267
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);
272 if (!TmpBuffer)
273 {
276 }
277
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 */
282
283 /* Read the ending entries */
284 Status = ZwReadFile(Database, NULL, NULL, NULL, &IoStatusBlock,
285 TmpBuffer, EndSize, &EndEntriesOffset, NULL);
286 if (!NT_SUCCESS(Status))
287 {
288 FreePool(TmpBuffer);
289 return Status;
290 }
291
292 /* Ensure nothing went wrong - we don't want to corrupt the DB */
293 if (IoStatusBlock.Information != EndSize)
294 {
295 FreePool(TmpBuffer);
297 }
298
299 /* Remove the entry */
301 if (!NT_SUCCESS(Status))
302 {
303 FreePool(TmpBuffer);
304 return Status;
305 }
306
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);
311
312 FreePool(TmpBuffer);
313
314 return Status;
315}
316
317/*
318 * @implemented
319 */
321NTAPI
328{
329 PMOUNTDEV_UNIQUE_ID UniqueId = Context;
330
333
334 /* Ensure it matches, and delete */
335 if ((UniqueId->UniqueIdLength == ValueLength) &&
338 {
341 ValueName);
342 }
343
344 return STATUS_SUCCESS;
345}
346
347/*
348 * @implemented
349 */
350VOID
352 IN PMOUNTDEV_UNIQUE_ID UniqueId)
353{
355
358 QueryTable[0].Name = SymbolicLink->Buffer;
359
363 UniqueId,
364 NULL);
365}
366
367/*
368 * @implemented
369 */
372{
375
376 /* Wait for 7 minutes */
377 Timeout.QuadPart = 0xFA0A1F00;
378 Status = KeWaitForSingleObject(&(DeviceExtension->RemoteDatabaseLock), Executive, KernelMode, FALSE, &Timeout);
379 if (Status != STATUS_TIMEOUT)
380 {
381 return Status;
382 }
383
384 return STATUS_IO_TIMEOUT;
385}
386
387/*
388 * @implemented
389 */
390VOID
392{
393 KeReleaseSemaphore(&(DeviceExtension->RemoteDatabaseLock), IO_NO_INCREMENT, 1, FALSE);
394}
395
396/*
397 * @implemented
398 */
400NTAPI
407{
408 PMOUNTDEV_UNIQUE_ID IntUniqueId;
409 PMOUNTDEV_UNIQUE_ID * UniqueId;
410
414
415 /* Sanity check */
416 if (ValueLength >= 0x10000)
417 {
418 return STATUS_SUCCESS;
419 }
420
421 /* Allocate the Unique ID */
422 IntUniqueId = AllocatePool(sizeof(UniqueId) + ValueLength);
423 if (IntUniqueId)
424 {
425 /* Copy data & return */
426 IntUniqueId->UniqueIdLength = (USHORT)ValueLength;
427 RtlCopyMemory(&(IntUniqueId->UniqueId), ValueData, ValueLength);
428
429 UniqueId = Context;
430 *UniqueId = IntUniqueId;
431 }
432
433 return STATUS_SUCCESS;
434}
435
436/*
437 * @implemented
438 */
442 OUT PMOUNTDEV_UNIQUE_ID * UniqueId)
443{
445 PDEVICE_INFORMATION DeviceInformation;
447
448 /* Query the unique ID */
452
453 *UniqueId = NULL;
457 UniqueId,
458 NULL);
459 /* Unique ID found, no need to go farther */
460 if (*UniqueId)
461 {
462 return STATUS_SUCCESS;
463 }
464
465 /* Otherwise, find associate device information */
466 Status = FindDeviceInfo(DeviceExtension, SymbolicName, FALSE, &DeviceInformation);
467 if (!NT_SUCCESS(Status))
468 {
469 return Status;
470 }
471
472 *UniqueId = AllocatePool(DeviceInformation->UniqueId->UniqueIdLength + sizeof(MOUNTDEV_UNIQUE_ID));
473 if (!*UniqueId)
474 {
476 }
477
478 /* Return this unique ID (better than nothing) */
479 (*UniqueId)->UniqueIdLength = DeviceInformation->UniqueId->UniqueIdLength;
480 RtlCopyMemory(&((*UniqueId)->UniqueId), &(DeviceInformation->UniqueId->UniqueId), (*UniqueId)->UniqueIdLength);
481
482 return STATUS_SUCCESS;
483}
484
485/*
486 * @implemented
487 */
490 IN PDATABASE_ENTRY DatabaseEntry)
491{
494 PLIST_ENTRY NextEntry;
495 UNICODE_STRING SymbolicString;
496 PDEVICE_INFORMATION DeviceInformation;
497
498 /* Create symbolic name from database entry */
499 SymbolicName = AllocatePool(DatabaseEntry->SymbolicNameLength + sizeof(WCHAR));
500 if (!SymbolicName)
501 {
503 }
504
506 (PVOID)((ULONG_PTR)DatabaseEntry + DatabaseEntry->SymbolicNameOffset),
507 DatabaseEntry->SymbolicNameLength);
508 SymbolicName[DatabaseEntry->SymbolicNameLength / sizeof(WCHAR)] = UNICODE_NULL;
509
510 /* Associate the unique ID with the name from remote database */
515 (PVOID)((ULONG_PTR)DatabaseEntry + DatabaseEntry->UniqueIdOffset),
516 DatabaseEntry->UniqueIdLength);
518
519 /* Reget symbolic name */
520 SymbolicString.Length = DatabaseEntry->SymbolicNameLength;
521 SymbolicString.MaximumLength = DatabaseEntry->SymbolicNameLength;
522 SymbolicString.Buffer = (PVOID)((ULONG_PTR)DatabaseEntry + DatabaseEntry->SymbolicNameOffset);
523
524 /* Find the device using this unique ID */
525 for (NextEntry = DeviceExtension->DeviceListHead.Flink;
526 NextEntry != &(DeviceExtension->DeviceListHead);
527 NextEntry = NextEntry->Flink)
528 {
529 DeviceInformation = CONTAINING_RECORD(NextEntry,
531 DeviceListEntry);
532
533 if (DeviceInformation->UniqueId->UniqueIdLength != DatabaseEntry->UniqueIdLength)
534 {
535 continue;
536 }
537
538 if (RtlCompareMemory((PVOID)((ULONG_PTR)DatabaseEntry + DatabaseEntry->UniqueIdOffset),
539 DeviceInformation->UniqueId->UniqueId,
540 DatabaseEntry->UniqueIdLength) == DatabaseEntry->UniqueIdLength)
541 {
542 break;
543 }
544 }
545
546 /* If found, create a mount point */
547 if (NextEntry != &(DeviceExtension->DeviceListHead))
548 {
549 MountMgrCreatePointWorker(DeviceExtension, &SymbolicString, &(DeviceInformation->DeviceName));
550 }
551
552 return Status;
553}
554
555/*
556 * @implemented
557 */
558VOID
559NTAPI
561{
566 PMOUNTDEV_UNIQUE_ID UniqueId;
567 PDATABASE_ENTRY DatabaseEntry;
568 HANDLE DatabaseHandle, Handle;
571 PDEVICE_INFORMATION ListDeviceInfo;
572 PLIST_ENTRY Entry, EntryInfo, NextEntry;
574 BOOLEAN HardwareErrors, Restart, FailedFinding;
575 WCHAR FileNameBuffer[0x8], SymbolicNameBuffer[100];
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;
580
581 /* We're unloading, do nothing */
582 if (Unloading)
583 {
584 return;
585 }
586
587 /* Lock remote DB */
588 if (!NT_SUCCESS(WaitForRemoteDatabaseSemaphore(DeviceExtension)))
589 {
590 return;
591 }
592
593 /* Recheck for unloading */
594 if (Unloading)
595 {
596 goto ReleaseRDS;
597 }
598
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)
604 {
605 ListDeviceInfo = CONTAINING_RECORD(Entry, DEVICE_INFORMATION, DeviceListEntry);
606 if (ListDeviceInfo == DeviceInformation)
607 {
608 break;
609 }
610 }
611
612 /* If not found, or if removable, bail out */
613 if (Entry == &DeviceExtension->DeviceListHead || DeviceInformation->Removable)
614 {
615 KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
616 goto ReleaseRDS;
617 }
618
619 /* Get our device object */
621 if (!NT_SUCCESS(Status))
622 {
623 KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
624 goto ReleaseRDS;
625 }
626
627 /* Mark mounted only if not unloading */
628 if (!(DeviceObject->Flags & DO_UNLOAD_PENDING))
629 {
630 InterlockedExchangeAdd(&ListDeviceInfo->MountState, 1);
631 }
632
634
635 /* Force default: no DB, and need for reconcile */
636 DeviceInformation->NeedsReconcile = TRUE;
637 DeviceInformation->NoDatabase = TRUE;
638 FailedFinding = FALSE;
639
640 /* Remove any associated device that refers to the DB to reconcile */
641 for (Entry = DeviceExtension->DeviceListHead.Flink;
642 Entry != &DeviceExtension->DeviceListHead;
643 Entry = Entry->Flink)
644 {
645 ListDeviceInfo = CONTAINING_RECORD(Entry, DEVICE_INFORMATION, DeviceListEntry);
646
647 EntryInfo = ListDeviceInfo->AssociatedDevicesHead.Flink;
648 while (EntryInfo != &ListDeviceInfo->AssociatedDevicesHead)
649 {
650 AssociatedDevice = CONTAINING_RECORD(EntryInfo, ASSOCIATED_DEVICE_ENTRY, AssociatedDevicesEntry);
651 NextEntry = EntryInfo->Flink;
652
653 if (AssociatedDevice->DeviceInformation == DeviceInformation)
654 {
655 RemoveEntryList(&AssociatedDevice->AssociatedDevicesEntry);
656 FreePool(AssociatedDevice->String.Buffer);
658 }
659
660 EntryInfo = NextEntry;
661 }
662 }
663
664 /* Open the remote database */
665 DatabaseHandle = OpenRemoteDatabase(DeviceInformation, FALSE);
666
667 /* Prepare a string with reparse point index */
668 ReparseFile.Length = 0;
669 ReparseFile.MaximumLength = DeviceInformation->DeviceName.Length
671 + sizeof(UNICODE_NULL);
672 ReparseFile.Buffer = AllocatePool(ReparseFile.MaximumLength);
673 if (!ReparseFile.Buffer)
674 {
675 if (DatabaseHandle != 0)
676 {
677 CloseRemoteDatabase(DatabaseHandle);
678 }
679 KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
680 goto ReleaseRDS;
681 }
682
683 RtlAppendUnicodeStringToString(&ReparseFile, &DeviceInformation->DeviceName);
685 ReparseFile.Buffer[ReparseFile.Length / sizeof(WCHAR)] = UNICODE_NULL;
686
688 &ReparseFile,
690 NULL,
691 NULL);
692
693 /* Open reparse point directory */
694 HardwareErrors = IoSetThreadHardErrorMode(FALSE);
701 IoSetThreadHardErrorMode(HardwareErrors);
702
703 FreePool(ReparseFile.Buffer);
704
705 if (!NT_SUCCESS(Status))
706 {
707 if (DatabaseHandle != 0)
708 {
709 TruncateRemoteDatabase(DatabaseHandle, 0);
710 CloseRemoteDatabase(DatabaseHandle);
711 }
712 KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
713 goto ReleaseRDS;
714 }
715
716 /* Query reparse point information
717 * We only pay attention to mout point
718 */
720 FileName.Buffer = FileNameBuffer;
721 FileName.Length = sizeof(FileNameBuffer);
722 FileName.MaximumLength = sizeof(FileNameBuffer);
724 Status = ZwQueryDirectoryFile(Handle,
725 NULL,
726 NULL,
727 NULL,
729 &ReparsePointInformation,
732 TRUE,
733 &FileName,
734 FALSE);
735 if (!NT_SUCCESS(Status))
736 {
738 if (DatabaseHandle != 0)
739 {
740 TruncateRemoteDatabase(DatabaseHandle, 0);
741 CloseRemoteDatabase(DatabaseHandle);
742 }
743 KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
744 goto ReleaseRDS;
745 }
746
747 /* If we failed to open the remote DB previously,
748 * retry this time allowing migration (and thus, creation if required)
749 */
750 if (DatabaseHandle == 0)
751 {
752 DatabaseHandle = OpenRemoteDatabase(DeviceInformation, TRUE);
753 if (DatabaseHandle == 0)
754 {
755 KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
756 goto ReleaseRDS;
757 }
758 }
759
760 KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
761
762 /* Reset all the references to our DB entries */
763 Offset = 0;
764 for (;;)
765 {
766 DatabaseEntry = GetRemoteDatabaseEntry(DatabaseHandle, Offset);
767 if (DatabaseEntry == NULL)
768 {
769 break;
770 }
771
772 DatabaseEntry->EntryReferences = 0;
773 Status = WriteRemoteDatabaseEntry(DatabaseHandle, Offset, DatabaseEntry);
774 if (!NT_SUCCESS(Status))
775 {
776 FreePool(DatabaseEntry);
777 goto CloseReparse;
778 }
779
780 Offset += DatabaseEntry->EntrySize;
781 FreePool(DatabaseEntry);
782 }
783
784 /* Init string for QueryVolumeName call */
785 SymbolicName.MaximumLength = sizeof(SymbolicNameBuffer);
787 SymbolicName.Buffer = SymbolicNameBuffer;
788 Restart = TRUE;
789
790 /* Start looping on reparse points */
791 for (;;)
792 {
793 RtlCopyMemory(&SavedReparsePointInformation, &ReparsePointInformation, sizeof(FILE_REPARSE_POINT_INFORMATION));
794 Status = ZwQueryDirectoryFile(Handle,
795 NULL,
796 NULL,
797 NULL,
799 &ReparsePointInformation,
802 TRUE,
803 Restart ? &FileName : NULL,
804 Restart);
805 /* Restart only once */
806 if (Restart)
807 {
808 Restart = FALSE;
809 }
810 else
811 {
812 /* If we get the same one, we're done, bail out */
813 if (ReparsePointInformation.FileReference == SavedReparsePointInformation.FileReference &&
814 ReparsePointInformation.Tag == SavedReparsePointInformation.Tag)
815 {
816 break;
817 }
818 }
819
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)
822 {
823 break;
824 }
825
826 /* Get the volume name associated to the mount point */
827 Status = QueryVolumeName(Handle, &ReparsePointInformation, 0, &SymbolicName, &VolumeName);
828 if (!NT_SUCCESS(Status))
829 {
830 continue;
831 }
832
833 /* Browse the DB to find the name */
834 Offset = 0;
835 for (;;)
836 {
837 UNICODE_STRING DbName;
838
839 DatabaseEntry = GetRemoteDatabaseEntry(DatabaseHandle, Offset);
840 if (DatabaseEntry == NULL)
841 {
842 break;
843 }
844
845 DbName.MaximumLength = DatabaseEntry->SymbolicNameLength;
846 DbName.Length = DbName.MaximumLength;
847 DbName.Buffer = (PWSTR)((ULONG_PTR)DatabaseEntry + DatabaseEntry->SymbolicNameOffset);
848 /* Found, we're done! */
850 {
851 break;
852 }
853
854 Offset += DatabaseEntry->EntrySize;
855 FreePool(DatabaseEntry);
856 }
857
858 /* If we found the mount point.... */
859 if (DatabaseEntry != NULL)
860 {
861 /* If it was referenced, reference it once more and update to remote */
862 if (DatabaseEntry->EntryReferences)
863 {
864 ++DatabaseEntry->EntryReferences;
865 Status = WriteRemoteDatabaseEntry(DatabaseHandle, Offset, DatabaseEntry);
866 if (!NT_SUCCESS(Status))
867 {
868 goto FreeDBEntry;
869 }
870
871 FreePool(DatabaseEntry);
872 }
873 else
874 {
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))
879 {
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))
883 {
884 goto ReleaseDeviceLock;
885 }
886
887 /* And then, reference & write the entry */
888 ++DatabaseEntry->EntryReferences;
889 Status = WriteRemoteDatabaseEntry(DatabaseHandle, Offset, DatabaseEntry);
890 if (!NT_SUCCESS(Status))
891 {
892 goto ReleaseDeviceLock;
893 }
894
895 KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
896 FreePool(DatabaseEntry);
897 }
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)
903 {
904 /* Reference the entry, and update to remote */
905 ++DatabaseEntry->EntryReferences;
906 Status = WriteRemoteDatabaseEntry(DatabaseHandle, Offset, DatabaseEntry);
907 if (!NT_SUCCESS(Status))
908 {
909 goto FreeUniqueId;
910 }
911
912 FreePool(UniqueId);
913 KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
914 FreePool(DatabaseEntry);
915 }
916 /* Would, by chance, the Unique ID be present elsewhere? */
917 else if (IsUniqueIdPresent(DeviceExtension, DatabaseEntry))
918 {
919 /* Push the ID to master */
920 Status = WriteUniqueIdToMaster(DeviceExtension, DatabaseEntry);
921 if (!NT_SUCCESS(Status))
922 {
923 goto FreeUniqueId;
924 }
925
926 /* And then, reference & write the entry */
927 ++DatabaseEntry->EntryReferences;
928 Status = WriteRemoteDatabaseEntry(DatabaseHandle, Offset, DatabaseEntry);
929 if (!NT_SUCCESS(Status))
930 {
931 goto FreeUniqueId;
932 }
933
934 FreePool(UniqueId);
935 KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
936 FreePool(DatabaseEntry);
937 }
938 else
939 {
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
942 * the know unique ID
943 */
944 Status = DeleteRemoteDatabaseEntry(DatabaseHandle, Offset);
945 if (!NT_SUCCESS(Status))
946 {
947 goto FreeUniqueId;
948 }
949
950 FreePool(DatabaseEntry);
951 /* Allocate a new entry big enough */
952 DatabaseEntry = AllocatePool(UniqueId->UniqueIdLength + SymbolicName.Length + sizeof(DATABASE_ENTRY));
953 if (DatabaseEntry == NULL)
954 {
955 goto FreeUniqueId;
956 }
957
958 /* Configure it */
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);
967
968 /* And write it remotely */
969 Status = AddRemoteDatabaseEntry(DatabaseHandle, DatabaseEntry);
970 if (!NT_SUCCESS(Status))
971 {
972 FreePool(DatabaseEntry);
973 goto FreeUniqueId;
974 }
975
976 FreePool(UniqueId);
977 FreePool(DatabaseEntry);
978 KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
979 }
980 }
981 }
982 else
983 {
984 /* We failed finding it remotely
985 * So, let's allocate a new remote DB entry
986 */
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))
992 {
993 /* Allocate a new entry big enough */
994 DatabaseEntry = AllocatePool(UniqueId->UniqueIdLength + SymbolicName.Length + sizeof(DATABASE_ENTRY));
995 if (DatabaseEntry != NULL)
996 {
997 /* Configure it */
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);
1006
1007 /* And write it remotely */
1008 Status = AddRemoteDatabaseEntry(DatabaseHandle, DatabaseEntry);
1009 FreePool(DatabaseEntry);
1010 FreePool(UniqueId);
1011
1012 if (!NT_SUCCESS(Status))
1013 {
1014 goto FreeVolume;
1015 }
1016 }
1017 else
1018 {
1019 FreePool(UniqueId);
1020 }
1021 }
1022 }
1023
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))
1028 {
1029 FailedFinding = TRUE;
1031 }
1032 else
1033 {
1034 /* Associate the device with the currrent DB */
1036 if (AssociatedDevice == NULL)
1037 {
1039 }
1040 else
1041 {
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);
1047 }
1048
1049 /* If we don't have to skip notifications, notify */
1050 if (!ListDeviceInfo->SkipNotifications)
1051 {
1052 PostOnlineNotification(DeviceExtension, &ListDeviceInfo->SymbolicName);
1053 }
1054 }
1055
1056 KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
1057 }
1058
1059 /* We don't need mount points any longer */
1060 ZwClose(Handle);
1061
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)
1067 {
1068 ListDeviceInfo = CONTAINING_RECORD(Entry, DEVICE_INFORMATION, DeviceListEntry);
1069 if (ListDeviceInfo == DeviceInformation)
1070 {
1071 break;
1072 }
1073 }
1074
1075 if (Entry == &DeviceExtension->DeviceListHead)
1076 {
1077 ListDeviceInfo = NULL;
1078 }
1079
1080 /* Start the pruning loop */
1081 Offset = 0;
1082 for (;;)
1083 {
1084 /* Get the entry */
1085 DatabaseEntry = GetRemoteDatabaseEntry(DatabaseHandle, Offset);
1086 if (DatabaseEntry == NULL)
1087 {
1088 break;
1089 }
1090
1091 /* It's not referenced anylonger? Prune it */
1092 if (DatabaseEntry->EntryReferences == 0)
1093 {
1094 Status = DeleteRemoteDatabaseEntry(DatabaseHandle, Offset);
1095 if (!NT_SUCCESS(Status))
1096 {
1097 FreePool(DatabaseEntry);
1098 KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
1099 goto CloseRDB;
1100 }
1101 }
1102 /* Update the Unique IDs to reflect the changes we might have done previously */
1103 else
1104 {
1105 if (ListDeviceInfo != NULL)
1106 {
1107 UpdateReplicatedUniqueIds(ListDeviceInfo, DatabaseEntry);
1108 }
1109
1110 Offset += DatabaseEntry->EntrySize;
1111 }
1112
1113 FreePool(DatabaseEntry);
1114 }
1115
1116 /* We do have a DB now :-) */
1117 if (ListDeviceInfo != NULL && !FailedFinding)
1118 {
1119 DeviceInformation->NoDatabase = FALSE;
1120 }
1121
1122 KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
1123
1124 goto CloseRDB;
1125
1126FreeUniqueId:
1127 FreePool(UniqueId);
1128ReleaseDeviceLock:
1129 KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
1130FreeDBEntry:
1131 FreePool(DatabaseEntry);
1132FreeVolume:
1134CloseReparse:
1135 ZwClose(Handle);
1136CloseRDB:
1137 CloseRemoteDatabase(DatabaseHandle);
1138ReleaseRDS:
1139 ReleaseRemoteDatabaseSemaphore(DeviceExtension);
1140 return;
1141}
1142
1143/*
1144 * @implemented
1145 */
1146VOID
1147NTAPI
1150{
1151 ULONG i;
1152 KEVENT Event;
1153 KIRQL OldIrql;
1155 HANDLE SafeEvent;
1159 PDEVICE_EXTENSION DeviceExtension;
1161
1163
1165 &SafeVolumes,
1167 NULL,
1168 NULL);
1170 Timeout.QuadPart = -10000000LL; /* Wait for 1 second */
1171
1172 /* Wait as long as possible for clearance from autochk
1173 * We will write remote databases only if it is safe
1174 * to access volumes.
1175 * First, given we start before SMSS, wait for the
1176 * event creation.
1177 */
1178 i = 0;
1179 do
1180 {
1181 /* If we started to shutdown, stop waiting forever and jump to last attempt */
1182 if (Unloading)
1183 {
1184 i = 999;
1185 }
1186 else
1187 {
1188 /* Attempt to open the event */
1190 if (NT_SUCCESS(Status))
1191 {
1192 break;
1193 }
1194
1195 /* Wait a bit to give SMSS a chance to create the event */
1197 }
1198
1199 ++i;
1200 }
1201 while (i < 1000);
1202
1203 /* We managed to open the event, wait until autochk signals it */
1204 if (i < 1000)
1205 {
1206 do
1207 {
1208 Status = ZwWaitForSingleObject(SafeEvent, FALSE, &Timeout);
1209 }
1210 while (Status == STATUS_TIMEOUT && !Unloading);
1211
1212 ZwClose(SafeEvent);
1213 }
1214
1215 DeviceExtension = Context;
1216
1217 InterlockedExchange(&(DeviceExtension->WorkerThreadStatus), 1);
1218
1219 /* Acquire workers lock */
1220 KeWaitForSingleObject(&(DeviceExtension->WorkerSemaphore), Executive, KernelMode, FALSE, NULL);
1221
1222 KeAcquireSpinLock(&(DeviceExtension->WorkerLock), &OldIrql);
1223
1224 /* Ensure there are workers */
1225 while (!IsListEmpty(&(DeviceExtension->WorkerQueueListHead)))
1226 {
1227 /* Unqueue a worker */
1228 Entry = RemoveHeadList(&(DeviceExtension->WorkerQueueListHead));
1231 WorkerQueueListEntry);
1232
1233 KeReleaseSpinLock(&(DeviceExtension->WorkerLock), OldIrql);
1234
1235 /* Call it */
1236 WorkItem->WorkerRoutine(WorkItem->Context);
1237
1238 IoFreeWorkItem(WorkItem->WorkItem);
1240
1241 if (InterlockedDecrement(&(DeviceExtension->WorkerReferences)) < 0)
1242 {
1243 return;
1244 }
1245
1246 KeWaitForSingleObject(&(DeviceExtension->WorkerSemaphore), Executive, KernelMode, FALSE, NULL);
1247 KeAcquireSpinLock(&(DeviceExtension->WorkerLock), &OldIrql);
1248 }
1249 KeReleaseSpinLock(&(DeviceExtension->WorkerLock), OldIrql);
1250
1251 InterlockedDecrement(&(DeviceExtension->WorkerReferences));
1252
1253 /* Reset event */
1255}
1256
1257/*
1258 * @implemented
1259 */
1264{
1265 KIRQL OldIrql;
1266
1267 WorkItem->Context = Context;
1268
1269 /* When called, lock is already acquired */
1270
1271 /* If noone (-1 as references), start to work */
1272 if (InterlockedIncrement(&(DeviceExtension->WorkerReferences)) == 0)
1273 {
1274 IoQueueWorkItem(WorkItem->WorkItem, WorkerThread, DelayedWorkQueue, DeviceExtension);
1275 }
1276
1277 /* Otherwise queue worker for delayed execution */
1278 KeAcquireSpinLock(&(DeviceExtension->WorkerLock), &OldIrql);
1279 InsertTailList(&(DeviceExtension->WorkerQueueListHead),
1280 &(WorkItem->WorkerQueueListEntry));
1281 KeReleaseSpinLock(&(DeviceExtension->WorkerLock), OldIrql);
1282
1283 KeReleaseSemaphore(&(DeviceExtension->WorkerSemaphore), IO_NO_INCREMENT, 1, FALSE);
1284
1285 return STATUS_SUCCESS;
1286}
1287
1288/*
1289 * @implemented
1290 */
1293 IN PFILE_REPARSE_POINT_INFORMATION ReparsePointInformation,
1297{
1298 HANDLE Handle;
1300 ULONG NeededLength;
1303 PFILE_NAME_INFORMATION FileNameInfo;
1304 PREPARSE_DATA_BUFFER ReparseDataBuffer;
1305
1306 UNREFERENCED_PARAMETER(ReparsePointInformation);
1307
1308 if (!FileName)
1309 {
1311 NULL,
1314 NULL);
1315 }
1316 else
1317 {
1319 FileName,
1321 NULL,
1322 NULL);
1323 }
1324
1325 /* Open volume */
1333 if (!NT_SUCCESS(Status))
1334 {
1335 return Status;
1336 }
1337
1338 /* Get the reparse point data */
1340 if (!ReparseDataBuffer)
1341 {
1342 ZwClose(Handle);
1344 }
1345
1347 0,
1348 NULL,
1349 NULL,
1352 NULL,
1353 0,
1354 ReparseDataBuffer,
1356 if (!NT_SUCCESS(Status))
1357 {
1358 FreePool(ReparseDataBuffer);
1359 ZwClose(Handle);
1360 return Status;
1361 }
1362
1363 /* Check that name can fit in buffer */
1364 if (ReparseDataBuffer->MountPointReparseBuffer.SubstituteNameLength + sizeof(UNICODE_NULL) > SymbolicName->MaximumLength)
1365 {
1366 FreePool(ReparseDataBuffer);
1367 ZwClose(Handle);
1369 }
1370
1371 /* Copy symbolic name */
1372 SymbolicName->Length = ReparseDataBuffer->MountPointReparseBuffer.SubstituteNameLength;
1374 (PWSTR)((ULONG_PTR)ReparseDataBuffer->MountPointReparseBuffer.PathBuffer +
1375 ReparseDataBuffer->MountPointReparseBuffer.SubstituteNameOffset),
1376 ReparseDataBuffer->MountPointReparseBuffer.SubstituteNameLength);
1377
1378 FreePool(ReparseDataBuffer);
1379
1380 /* Name has to \ terminated */
1381 if (SymbolicName->Buffer[SymbolicName->Length / sizeof(WCHAR) - 1] != L'\\')
1382 {
1383 ZwClose(Handle);
1385 }
1386
1387 /* So that we can delete it, and match mountmgr requirements */
1388 SymbolicName->Length -= sizeof(WCHAR);
1390
1391 /* Also ensure it's really a volume name... */
1393 {
1394 ZwClose(Handle);
1396 }
1397
1398 /* Now prepare to really get the name */
1399 FileNameInfo = AllocatePool(sizeof(FILE_NAME_INFORMATION) + 2 * sizeof(WCHAR));
1400 if (!FileNameInfo)
1401 {
1402 ZwClose(Handle);
1404 }
1405
1406 Status = ZwQueryInformationFile(Handle,
1408 FileNameInfo,
1409 sizeof(FILE_NAME_INFORMATION) + 2 * sizeof(WCHAR),
1412 {
1413 /* As expected... Reallocate with proper size */
1414 NeededLength = FileNameInfo->FileNameLength;
1415 FreePool(FileNameInfo);
1416
1417 FileNameInfo = AllocatePool(sizeof(FILE_NAME_INFORMATION) + NeededLength);
1418 if (!FileNameInfo)
1419 {
1420 ZwClose(Handle);
1422 }
1423
1424 /* And query name */
1425 Status = ZwQueryInformationFile(Handle,
1427 FileNameInfo,
1428 sizeof(FILE_NAME_INFORMATION) + NeededLength,
1430 }
1431
1432 ZwClose(Handle);
1433
1434 if (!NT_SUCCESS(Status))
1435 {
1436 return Status;
1437 }
1438
1439 /* Return the volume name */
1440 VolumeName->Length = (USHORT)FileNameInfo->FileNameLength;
1441 VolumeName->MaximumLength = (USHORT)FileNameInfo->FileNameLength + sizeof(WCHAR);
1443 if (!VolumeName->Buffer)
1444 {
1446 }
1447
1448 RtlCopyMemory(VolumeName->Buffer, FileNameInfo->FileName, FileNameInfo->FileNameLength);
1449 VolumeName->Buffer[FileNameInfo->FileNameLength / sizeof(WCHAR)] = UNICODE_NULL;
1450
1451 FreePool(FileNameInfo);
1452
1453 return STATUS_SUCCESS;
1454}
1455
1456/*
1457 * @implemented
1458 */
1459VOID
1461 IN PDEVICE_INFORMATION DeviceInformation)
1462{
1463 HANDLE Handle;
1468 PDEVICE_INFORMATION VolumeDeviceInformation;
1469 WCHAR FileNameBuffer[0x8], SymbolicNameBuffer[0x64];
1471 FILE_REPARSE_POINT_INFORMATION ReparsePointInformation, SavedReparsePointInformation;
1472
1473 /* Removable devices don't have remote database on them */
1474 if (DeviceInformation->Removable)
1475 {
1476 return;
1477 }
1478
1479 /* Prepare a string with reparse point index */
1480 ReparseFile.Length = 0;
1481 ReparseFile.MaximumLength = DeviceInformation->DeviceName.Length
1483 + sizeof(UNICODE_NULL);
1484 ReparseFile.Buffer = AllocatePool(ReparseFile.MaximumLength);
1485 if (!ReparseFile.Buffer)
1486 {
1487 return;
1488 }
1489
1490 RtlAppendUnicodeStringToString(&ReparseFile, &DeviceInformation->DeviceName);
1492 ReparseFile.Buffer[ReparseFile.Length / sizeof(WCHAR)] = UNICODE_NULL;
1493
1495 &ReparseFile,
1497 NULL,
1498 NULL);
1499
1500 /* Open reparse point */
1507 FreePool(ReparseFile.Buffer);
1508 if (!NT_SUCCESS(Status))
1509 {
1510 DeviceInformation->NoDatabase = FALSE;
1511 return;
1512 }
1513
1514 /* Query reparse point information
1515 * We only pay attention to mout point
1516 */
1518 FileName.Buffer = FileNameBuffer;
1519 FileName.Length = sizeof(FileNameBuffer);
1520 FileName.MaximumLength = sizeof(FileNameBuffer);
1522 Status = ZwQueryDirectoryFile(Handle,
1523 NULL,
1524 NULL,
1525 NULL,
1527 &ReparsePointInformation,
1530 TRUE,
1531 &FileName,
1532 FALSE);
1533 if (!NT_SUCCESS(Status))
1534 {
1535 ZwClose(Handle);
1536 return;
1537 }
1538
1539 RestartScan = TRUE;
1540
1541 /* Query mount points */
1542 while (TRUE)
1543 {
1544 SymbolicName.Length = 0;
1545 SymbolicName.MaximumLength = sizeof(SymbolicNameBuffer);
1546 SymbolicName.Buffer = SymbolicNameBuffer;
1547 RtlCopyMemory(&SavedReparsePointInformation, &ReparsePointInformation, sizeof(FILE_REPARSE_POINT_INFORMATION));
1548
1549 Status = ZwQueryDirectoryFile(Handle,
1550 NULL,
1551 NULL,
1552 NULL,
1554 &ReparsePointInformation,
1557 TRUE,
1558 (RestartScan) ? &FileName : NULL,
1559 RestartScan);
1560 if (!RestartScan)
1561 {
1562 if (ReparsePointInformation.FileReference == SavedReparsePointInformation.FileReference &&
1563 ReparsePointInformation.Tag == SavedReparsePointInformation.Tag)
1564 {
1565 break;
1566 }
1567 }
1568 else
1569 {
1571 }
1572
1573 if (!NT_SUCCESS(Status) || ReparsePointInformation.Tag != IO_REPARSE_TAG_MOUNT_POINT)
1574 {
1575 break;
1576 }
1577
1578 /* Get the volume name associated to the mount point */
1580 &ReparsePointInformation,
1582 &VolumeName);
1583 if (!NT_SUCCESS(Status))
1584 {
1585 continue;
1586 }
1587
1589
1590 /* Get its information */
1591 Status = FindDeviceInfo(DeviceExtension, &SymbolicName,
1592 FALSE, &VolumeDeviceInformation);
1593 if (!NT_SUCCESS(Status))
1594 {
1595 DeviceInformation->NoDatabase = TRUE;
1596 continue;
1597 }
1598
1599 /* If notification are enabled, mark it online */
1600 if (!DeviceInformation->SkipNotifications)
1601 {
1602 PostOnlineNotification(DeviceExtension, &VolumeDeviceInformation->SymbolicName);
1603 }
1604 }
1605
1606 ZwClose(Handle);
1607}
1608
1609/*
1610 * @implemented
1611 */
1612VOID
1614 IN PDEVICE_INFORMATION DeviceInformation)
1615{
1617
1618 /* Removable devices don't have remote database */
1619 if (DeviceInformation->Removable)
1620 {
1621 return;
1622 }
1623
1624 /* Allocate a work item */
1626 if (!WorkItem)
1627 {
1628 return;
1629 }
1630
1631 WorkItem->WorkItem = IoAllocateWorkItem(DeviceExtension->DeviceObject);
1632 if (!WorkItem->WorkItem)
1633 {
1635 return;
1636 }
1637
1638 /* And queue it */
1640 WorkItem->DeviceExtension = DeviceExtension;
1641 WorkItem->DeviceInformation = DeviceInformation;
1642 QueueWorkItem(DeviceExtension, WorkItem, &(WorkItem->DeviceExtension));
1643
1644 /* If the worker thread isn't started yet, automatic drive letter is
1645 * enabled but automount disabled, manually set mounted volumes online.
1646 * Otherwise, they will be set online during database reconciliation. */
1647 if (DeviceExtension->WorkerThreadStatus == 0 &&
1648 DeviceExtension->AutomaticDriveLetter &&
1649 DeviceExtension->NoAutoMount)
1650 {
1651 OnlineMountedVolumes(DeviceExtension, DeviceInformation);
1652 }
1653}
1654
1655/*
1656 * @implemented
1657 */
1658VOID
1660{
1661 PLIST_ENTRY NextEntry;
1662 PDEVICE_INFORMATION DeviceInformation;
1663
1664 /* Browse all the devices */
1665 for (NextEntry = DeviceExtension->DeviceListHead.Flink;
1666 NextEntry != &(DeviceExtension->DeviceListHead);
1667 NextEntry = NextEntry->Flink)
1668 {
1669 DeviceInformation = CONTAINING_RECORD(NextEntry,
1671 DeviceListEntry);
1672 /* If it's not removable, then, it might have a database to sync */
1673 if (!DeviceInformation->Removable)
1674 {
1675 ReconcileThisDatabaseWithMaster(DeviceExtension, DeviceInformation);
1676 }
1677 }
1678}
1679
1680/*
1681 * @implemented
1682 */
1683VOID
1684NTAPI
1687{
1689 HANDLE Database = 0;
1690 UNICODE_STRING DatabaseName;
1694 PDEVICE_INFORMATION DeviceInformation;
1695
1697
1698 /* Extract context */
1699 WorkItem = Context;
1700 DeviceInformation = WorkItem->DeviceInformation;
1701
1702 /* Reconstruct appropriate string */
1703 DatabaseName.Length = 0;
1704 DatabaseName.MaximumLength = DeviceInformation->DeviceName.Length
1706 + sizeof(UNICODE_NULL);
1707 DatabaseName.Buffer = AllocatePool(DatabaseName.MaximumLength);
1708 if (DatabaseName.Buffer == NULL)
1709 {
1711 goto Cleanup;
1712 }
1713
1714 /* Create the required folder (in which the database will be stored
1715 * \System Volume Information at root of the volume
1716 */
1718 if (!NT_SUCCESS(Status))
1719 {
1720 goto Cleanup;
1721 }
1722
1723 /* Finish initiating strings */
1724 RtlAppendUnicodeStringToString(&DatabaseName, &DeviceInformation->DeviceName);
1726 DatabaseName.Buffer[DatabaseName.Length / sizeof(WCHAR)] = UNICODE_NULL;
1727
1728 /* Create database */
1730 &DatabaseName,
1732 NULL,
1733 NULL);
1734
1741 NULL,
1743 0,
1746 NULL,
1747 0,
1749 NULL,
1751 if (!NT_SUCCESS(Status))
1752 {
1754 {
1755 DPRINT1("Attempt to exploit CVE-2015-1769. See CORE-10216\n");
1756 }
1757
1758 Database = 0;
1759 goto Cleanup;
1760 }
1761
1762Cleanup:
1763 if (DatabaseName.Buffer)
1764 {
1765 FreePool(DatabaseName.Buffer);
1766 }
1767
1768 if (NT_SUCCESS(Status))
1769 {
1770 DeviceInformation->Migrated = 1;
1771 }
1772 else if (Database != 0)
1773 {
1775 }
1776
1777 IoFreeWorkItem(WorkItem->WorkItem);
1778
1779 WorkItem->WorkItem = NULL;
1780 WorkItem->Status = Status;
1781 WorkItem->Database = Database;
1782
1783 KeSetEvent(WorkItem->Event, 0, FALSE);
1784}
1785
1786/*
1787 * @implemented
1788 */
1792{
1793 KEVENT Event;
1796
1798
1799 /* Allocate a work item dedicated to migration */
1801 if (!WorkItem)
1802 {
1803 *Database = 0;
1805 }
1806
1808 WorkItem->Event = &Event;
1809 WorkItem->DeviceInformation = DeviceInformation;
1810 WorkItem->WorkItem = IoAllocateWorkItem(DeviceInformation->DeviceExtension->DeviceObject);
1811 if (!WorkItem->WorkItem)
1812 {
1814 *Database = 0;
1816 }
1817
1818 /* And queue it */
1819 IoQueueWorkItem(WorkItem->WorkItem,
1822 WorkItem);
1823
1825 Status = WorkItem->Status;
1826
1827 *Database = (NT_SUCCESS(Status) ? WorkItem->Database : 0);
1828
1830 return Status;
1831}
1832
1833/*
1834 * @implemented
1835 */
1836HANDLE
1838 IN BOOLEAN MigrateDatabase)
1839{
1845 UNICODE_STRING DeviceRemoteDatabase;
1846
1847 Database = 0;
1848
1849 /* Get database name */
1850 DeviceRemoteDatabase.Length = 0;
1851 DeviceRemoteDatabase.MaximumLength = DeviceInformation->DeviceName.Length
1853 + sizeof(UNICODE_NULL);
1854 DeviceRemoteDatabase.Buffer = AllocatePool(DeviceRemoteDatabase.MaximumLength);
1855 if (!DeviceRemoteDatabase.Buffer)
1856 {
1857 return 0;
1858 }
1859
1860 RtlAppendUnicodeStringToString(&DeviceRemoteDatabase, &DeviceInformation->DeviceName);
1861 RtlAppendUnicodeStringToString(&DeviceRemoteDatabase, &RemoteDatabase);
1862 DeviceRemoteDatabase.Buffer[DeviceRemoteDatabase.Length / sizeof(WCHAR)] = UNICODE_NULL;
1863
1864 /* Open database */
1866 &DeviceRemoteDatabase,
1868 NULL,
1869 NULL);
1870
1871 /* Disable hard errors */
1873
1880 NULL,
1882 0,
1883 (!MigrateDatabase || DeviceInformation->Migrated == 0) ? FILE_OPEN_IF : FILE_OPEN,
1885 NULL,
1886 0,
1888 NULL,
1891 {
1892 DPRINT1("Attempt to exploit CVE-2015-1769. See CORE-10216\n");
1893 }
1894
1895 /* If base it to be migrated and was opened successfully, go ahead */
1896 if (MigrateDatabase && NT_SUCCESS(Status))
1897 {
1898 CreateRemoteDatabase(DeviceInformation, &Database);
1899 }
1900
1902 FreePool(DeviceRemoteDatabase.Buffer);
1903
1904 return Database;
1905}
1906
1907/*
1908 * @implemented
1909 */
1910VOID
1912 IN PMOUNTDEV_UNIQUE_ID OldUniqueId,
1913 IN PMOUNTDEV_UNIQUE_ID NewUniqueId)
1914{
1915 LONG Offset = 0;
1917 PDATABASE_ENTRY Entry, NewEntry;
1919
1920 /* Open the remote database */
1921 Database = OpenRemoteDatabase(DeviceInformation, FALSE);
1922 if (!Database)
1923 {
1924 return;
1925 }
1926
1927 /* Get all the entries */
1928 do
1929 {
1931 if (!Entry)
1932 {
1933 break;
1934 }
1935
1936 /* Not the correct entry, skip it */
1937 if (Entry->UniqueIdLength != OldUniqueId->UniqueIdLength)
1938 {
1939 Offset += Entry->EntrySize;
1940 FreePool(Entry);
1941 continue;
1942 }
1943
1944 /* Not the correct entry, skip it */
1945 if (RtlCompareMemory(OldUniqueId->UniqueId,
1946 (PVOID)((ULONG_PTR)Entry + Entry->UniqueIdOffset),
1947 Entry->UniqueIdLength) != Entry->UniqueIdLength)
1948 {
1949 Offset += Entry->EntrySize;
1950 FreePool(Entry);
1951 continue;
1952 }
1953
1954 /* Here, we have the correct entry */
1955 NewEntry = AllocatePool(Entry->EntrySize + NewUniqueId->UniqueIdLength - OldUniqueId->UniqueIdLength);
1956 if (!NewEntry)
1957 {
1958 Offset += Entry->EntrySize;
1959 FreePool(Entry);
1960 continue;
1961 }
1962
1963 /* Recreate the entry from the previous one */
1964 NewEntry->EntrySize = Entry->EntrySize + NewUniqueId->UniqueIdLength - OldUniqueId->UniqueIdLength;
1965 NewEntry->EntryReferences = Entry->EntryReferences;
1966 NewEntry->SymbolicNameOffset = sizeof(DATABASE_ENTRY);
1967 NewEntry->SymbolicNameLength = Entry->SymbolicNameLength;
1968 NewEntry->UniqueIdOffset = Entry->SymbolicNameLength + sizeof(DATABASE_ENTRY);
1969 NewEntry->UniqueIdLength = NewUniqueId->UniqueIdLength;
1970 RtlCopyMemory((PVOID)((ULONG_PTR)NewEntry + NewEntry->SymbolicNameOffset),
1971 (PVOID)((ULONG_PTR)Entry + Entry->SymbolicNameOffset),
1972 NewEntry->SymbolicNameLength);
1973 RtlCopyMemory((PVOID)((ULONG_PTR)NewEntry + NewEntry->UniqueIdOffset),
1974 NewUniqueId->UniqueId, NewEntry->UniqueIdLength);
1975
1976 /* Delete old entry */
1978 if (!NT_SUCCESS(Status))
1979 {
1980 FreePool(Entry);
1981 FreePool(NewEntry);
1982 break;
1983 }
1984
1985 /* And replace with new one */
1987 FreePool(Entry);
1988 FreePool(NewEntry);
1989 } while (NT_SUCCESS(Status));
1990
1992
1993 return;
1994}
1995
1996/*
1997 * @implemented
1998 */
2000NTAPI
2007{
2008 PMOUNTDEV_UNIQUE_ID UniqueId;
2009 UNICODE_STRING RegistryEntry;
2010
2012
2013 if (ValueType != REG_BINARY)
2014 {
2015 return STATUS_SUCCESS;
2016 }
2017
2018 UniqueId = Context;
2019
2020 /* First ensure we have the correct data */
2021 if (UniqueId->UniqueIdLength != ValueLength)
2022 {
2023 return STATUS_SUCCESS;
2024 }
2025
2027 {
2028 return STATUS_SUCCESS;
2029 }
2030
2031 RtlInitUnicodeString(&RegistryEntry, ValueName);
2032
2033 /* Then, it's a drive letter, erase it */
2034 if (IsDriveLetter(&RegistryEntry))
2035 {
2038 ValueName);
2039 }
2040
2041 return STATUS_SUCCESS;
2042}
2043
2044/*
2045 * @implemented
2046 */
2047VOID
2049{
2051
2054
2057 QueryTable,
2058 UniqueId,
2059 NULL);
2060}
2061
2062/*
2063 * @implemented
2064 */
2066NTAPI
2073{
2074 PMOUNTDEV_UNIQUE_ID UniqueId = Context;
2075
2077
2078 /* Ensure we have correct input */
2079 if (ValueName[0] != L'#' || ValueType != REG_BINARY ||
2080 UniqueId->UniqueIdLength != ValueLength)
2081 {
2082 return STATUS_SUCCESS;
2083 }
2084
2085 /* And then, if unique ID matching, delete entry */
2087 {
2090 ValueName);
2091 }
2092
2093 return STATUS_SUCCESS;
2094}
2095
2096/*
2097 * @implemented
2098 */
2099VOID
2101{
2103
2106
2109 QueryTable,
2110 UniqueId,
2111 NULL);
2112}
unsigned char BOOLEAN
#define InterlockedIncrement
Definition: armddk.h:53
#define InterlockedExchange
Definition: armddk.h:54
#define InterlockedDecrement
Definition: armddk.h:52
LONG NTSTATUS
Definition: precomp.h:26
#define FILE_NON_DIRECTORY_FILE
Definition: constants.h:492
#define MAX(x, y)
Definition: rdesktop.h:175
#define DPRINT1
Definition: precomp.h:8
WCHAR FileNameBuffer[MAX_PATH]
Definition: framewnd.c:250
WCHAR RootDirectory[MAX_PATH]
Definition: format.c:74
_In_ PFCB _In_ LONGLONG StartingOffset
Definition: cdprocs.h:291
IN PUNICODE_STRING IN POBJECT_ATTRIBUTES ObjectAttributes
Definition: conport.c:36
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:33
#define FILE_ATTRIBUTE_NORMAL
Definition: compat.h:137
#define FILE_SHARE_READ
Definition: compat.h:136
static const WCHAR SymbolicLink[]
Definition: interface.c:31
static const WCHAR Cleanup[]
Definition: register.c:80
NTSTATUS CloseRemoteDatabase(IN HANDLE Database)
Definition: database.c:82
VOID OnlineMountedVolumes(IN PDEVICE_EXTENSION DeviceExtension, IN PDEVICE_INFORMATION DeviceInformation)
Definition: database.c:1460
NTSTATUS QueryUniqueIdFromMaster(IN PDEVICE_EXTENSION DeviceExtension, IN PUNICODE_STRING SymbolicName, OUT PMOUNTDEV_UNIQUE_ID *UniqueId)
Definition: database.c:440
NTSTATUS NTAPI DeleteFromLocalDatabaseRoutine(IN PWSTR ValueName, IN ULONG ValueType, IN PVOID ValueData, IN ULONG ValueLength, IN PVOID Context, IN PVOID EntryContext)
Definition: database.c:322
NTSTATUS DeleteRemoteDatabaseEntry(IN HANDLE Database, IN LONG StartingOffset)
Definition: database.c:233
NTSTATUS TruncateRemoteDatabase(IN HANDLE Database, IN LONG NewSize)
Definition: database.c:91
NTSTATUS WaitForRemoteDatabaseSemaphore(IN PDEVICE_EXTENSION DeviceExtension)
Definition: database.c:371
VOID ReconcileThisDatabaseWithMaster(IN PDEVICE_EXTENSION DeviceExtension, IN PDEVICE_INFORMATION DeviceInformation)
Definition: database.c:1613
VOID DeleteRegistryDriveLetter(IN PMOUNTDEV_UNIQUE_ID UniqueId)
Definition: database.c:2048
PWSTR OfflinePath
Definition: database.c:32
VOID NTAPI WorkerThread(IN PDEVICE_OBJECT DeviceObject, IN PVOID Context)
Definition: database.c:1148
VOID NTAPI ReconcileThisDatabaseWithMasterWorker(IN PVOID Parameter)
Definition: database.c:560
NTSTATUS CreateRemoteDatabase(IN PDEVICE_INFORMATION DeviceInformation, IN OUT PHANDLE Database)
Definition: database.c:1790
VOID DeleteNoDriveLetterEntry(IN PMOUNTDEV_UNIQUE_ID UniqueId)
Definition: database.c:2100
VOID ReleaseRemoteDatabaseSemaphore(IN PDEVICE_EXTENSION DeviceExtension)
Definition: database.c:391
PWSTR DatabasePath
Definition: database.c:31
NTSTATUS AddRemoteDatabaseEntry(IN HANDLE Database, IN PDATABASE_ENTRY Entry)
Definition: database.c:64
NTSTATUS WriteUniqueIdToMaster(IN PDEVICE_EXTENSION DeviceExtension, IN PDATABASE_ENTRY DatabaseEntry)
Definition: database.c:489
VOID NTAPI CreateRemoteDatabaseWorker(IN PDEVICE_OBJECT DeviceObject, IN PVOID Context)
Definition: database.c:1685
NTSTATUS WriteRemoteDatabaseEntry(IN HANDLE Database, IN LONG Offset, IN PDATABASE_ENTRY Entry)
Definition: database.c:200
VOID ReconcileAllDatabasesWithMaster(IN PDEVICE_EXTENSION DeviceExtension)
Definition: database.c:1659
HANDLE OpenRemoteDatabase(IN PDEVICE_INFORMATION DeviceInformation, IN BOOLEAN MigrateDatabase)
Definition: database.c:1837
LONG GetRemoteDatabaseSize(IN HANDLE Database)
Definition: database.c:40
PDATABASE_ENTRY GetRemoteDatabaseEntry(IN HANDLE Database, IN LONG StartingOffset)
Definition: database.c:125
NTSTATUS NTAPI DeleteDriveLetterRoutine(IN PWSTR ValueName, IN ULONG ValueType, IN PVOID ValueData, IN ULONG ValueLength, IN PVOID Context, IN PVOID EntryContext)
Definition: database.c:2001
VOID ChangeRemoteDatabaseUniqueId(IN PDEVICE_INFORMATION DeviceInformation, IN PMOUNTDEV_UNIQUE_ID OldUniqueId, IN PMOUNTDEV_UNIQUE_ID NewUniqueId)
Definition: database.c:1911
VOID DeleteFromLocalDatabase(IN PUNICODE_STRING SymbolicLink, IN PMOUNTDEV_UNIQUE_ID UniqueId)
Definition: database.c:351
NTSTATUS NTAPI DeleteNoDriveLetterEntryRoutine(IN PWSTR ValueName, IN ULONG ValueType, IN PVOID ValueData, IN ULONG ValueLength, IN PVOID Context, IN PVOID EntryContext)
Definition: database.c:2067
NTSTATUS QueueWorkItem(IN PDEVICE_EXTENSION DeviceExtension, IN PRECONCILE_WORK_ITEM WorkItem, IN PVOID Context)
Definition: database.c:1261
NTSTATUS NTAPI QueryUniqueIdQueryRoutine(IN PWSTR ValueName, IN ULONG ValueType, IN PVOID ValueData, IN ULONG ValueLength, IN PVOID Context, IN PVOID EntryContext)
Definition: database.c:401
UNICODE_STRING RemoteDatabase
Definition: database.c:34
NTSTATUS QueryVolumeName(IN HANDLE RootDirectory, IN PFILE_REPARSE_POINT_INFORMATION ReparsePointInformation, IN PUNICODE_STRING FileName OPTIONAL, OUT PUNICODE_STRING SymbolicName, OUT PUNICODE_STRING VolumeName)
Definition: database.c:1292
#define RemoveEntryList(Entry)
Definition: env_spec_w32.h:986
#define InsertTailList(ListHead, Entry)
#define IsListEmpty(ListHead)
Definition: env_spec_w32.h:954
UCHAR KIRQL
Definition: env_spec_w32.h:591
#define KeWaitForSingleObject(pEvt, foo, a, b, c)
Definition: env_spec_w32.h:478
#define RtlCompareMemory(s1, s2, l)
Definition: env_spec_w32.h:465
#define KeInitializeEvent(pEvt, foo, foo2)
Definition: env_spec_w32.h:477
#define KeReleaseSpinLock(sl, irql)
Definition: env_spec_w32.h:627
#define KeSetEvent(pEvt, foo, foo2)
Definition: env_spec_w32.h:476
#define KeAcquireSpinLock(sl, irql)
Definition: env_spec_w32.h:609
#define DO_UNLOAD_PENDING
Definition: env_spec_w32.h:392
#define RemoveHeadList(ListHead)
Definition: env_spec_w32.h:964
IN PDCB IN PCCB IN VBO IN OUT PULONG OUT PDIRENT OUT PBCB OUT PVBO ByteOffset
Definition: fatprocs.h:731
struct _FileName FileName
Definition: fatprocs.h:896
_Must_inspect_result_ _Inout_opt_ PUNICODE_STRING VolumeName
Definition: fltkernel.h:1117
_Must_inspect_result_ _In_ PFILE_OBJECT _In_ ULONG _In_ BOOLEAN _In_ ULONG _In_opt_ PULONG _In_ BOOLEAN RestartScan
Definition: fltkernel.h:2299
_Must_inspect_result_ _In_ USHORT NewSize
Definition: fltkernel.h:975
#define FILE_OPEN_BY_FILE_ID
Definition: from_kernel.h:41
@ FileEndOfFileInformation
Definition: from_kernel.h:81
@ FileReparsePointInformation
Definition: from_kernel.h:94
@ FileNameInformation
Definition: from_kernel.h:70
@ FileAllocationInformation
Definition: from_kernel.h:80
#define FILE_OPEN
Definition: from_kernel.h:54
#define FILE_CREATE
Definition: from_kernel.h:55
#define FILE_OPEN_REPARSE_POINT
Definition: from_kernel.h:46
#define FILE_SYNCHRONOUS_IO_NONALERT
Definition: from_kernel.h:31
#define FILE_OPEN_IF
Definition: from_kernel.h:56
#define FILE_SYNCHRONOUS_IO_ALERT
Definition: from_kernel.h:30
@ Unloading
Definition: fs_rec.h:188
ULONG Handle
Definition: gdb_input.c:15
Status
Definition: gdiplustypes.h:25
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
_In_ GUID _In_ PVOID ValueData
Definition: hubbusif.h:312
#define OBJ_KERNEL_HANDLE
Definition: winternl.h:231
#define OBJ_CASE_INSENSITIVE
Definition: winternl.h:228
NTSYSAPI NTSTATUS WINAPI RtlDeleteRegistryValue(ULONG, PCWSTR, PCWSTR)
NTSYSAPI NTSTATUS WINAPI RtlWriteRegistryValue(ULONG, PCWSTR, PCWSTR, ULONG, PVOID, ULONG)
NTSYSAPI NTSTATUS WINAPI RtlQueryRegistryValues(ULONG, PCWSTR, PRTL_QUERY_REGISTRY_TABLE, PVOID, PVOID)
#define InterlockedExchangeAdd
Definition: interlocked.h:181
VOID NTAPI IoQueueWorkItem(IN PIO_WORKITEM IoWorkItem, IN PIO_WORKITEM_ROUTINE WorkerRoutine, IN WORK_QUEUE_TYPE QueueType, IN PVOID Context)
Definition: iowork.c:40
VOID NTAPI IoFreeWorkItem(IN PIO_WORKITEM IoWorkItem)
Definition: iowork.c:64
PIO_WORKITEM NTAPI IoAllocateWorkItem(IN PDEVICE_OBJECT DeviceObject)
Definition: iowork.c:75
#define EVENT_ALL_ACCESS
Definition: isotest.c:82
struct _RECONCILE_WORK_ITEM_CONTEXT * PRECONCILE_WORK_ITEM_CONTEXT
UNICODE_STRING SafeVolumes
Definition: symlink.c:47
KEVENT UnloadEvent
Definition: mountmgr.c:36
UNICODE_STRING ReparseIndex
Definition: symlink.c:49
struct _DATABASE_ENTRY DATABASE_ENTRY
NTSTATUS FindDeviceInfo(IN PDEVICE_EXTENSION DeviceExtension, IN PUNICODE_STRING SymbolicName, IN BOOLEAN DeviceNameGiven, OUT PDEVICE_INFORMATION *DeviceInformation)
Definition: mountmgr.c:561
NTSTATUS MountMgrCreatePointWorker(IN PDEVICE_EXTENSION DeviceExtension, IN PUNICODE_STRING SymbolicLinkName, IN PUNICODE_STRING DeviceName)
Definition: point.c:35
VOID PostOnlineNotification(IN PDEVICE_EXTENSION DeviceExtension, IN PUNICODE_STRING SymbolicName)
Definition: notify.c:122
BOOLEAN IsDriveLetter(PUNICODE_STRING SymbolicName)
Definition: symlink.c:812
VOID UpdateReplicatedUniqueIds(IN PDEVICE_INFORMATION DeviceInformation, IN PDATABASE_ENTRY DatabaseEntry)
Definition: uniqueid.c:376
BOOLEAN IsUniqueIdPresent(IN PDEVICE_EXTENSION DeviceExtension, IN PDATABASE_ENTRY DatabaseEntry)
Definition: uniqueid.c:221
#define AllocatePool(Size)
Definition: mntmgr.h:153
#define FreePool(P)
Definition: mntmgr.h:154
static OUT PIO_STATUS_BLOCK IoStatusBlock
Definition: pipe.c:75
#define InitializeObjectAttributes(p, n, a, r, s)
Definition: reg.c:106
#define MOUNTMGR_IS_VOLUME_NAME(s)
Definition: mountmgr.h:81
_In_ PNDIS_STRING _In_ PNDIS_STRING SymbolicName
Definition: ndis.h:4677
#define KernelMode
Definition: asm.h:34
NTSYSCALLAPI NTSTATUS NTAPI ZwOpenEvent(_Out_ PHANDLE EventHandle, _In_ ACCESS_MASK DesiredAccess, _In_ POBJECT_ATTRIBUTES ObjectAttributes)
NTSYSAPI NTSTATUS NTAPI ZwOpenFile(_Out_ PHANDLE FileHandle, _In_ ACCESS_MASK DesiredAccess, _In_ POBJECT_ATTRIBUTES ObjectAttributes, _Out_ PIO_STATUS_BLOCK IoStatusBlock, _In_ ULONG ShareAccess, _In_ ULONG OpenOptions)
NTSYSAPI NTSTATUS NTAPI ZwClose(_In_ HANDLE Handle)
_In_ PCWSTR _Inout_ _At_ QueryTable EntryContext
Definition: rtlfuncs.h:4219
_In_ PCWSTR _Inout_ _At_ QueryTable _Pre_unknown_ PRTL_QUERY_REGISTRY_TABLE QueryTable
Definition: rtlfuncs.h:4220
#define FILE_SHARE_WRITE
Definition: nt_native.h:681
#define SYNCHRONIZE
Definition: nt_native.h:61
#define FILE_WRITE_DATA
Definition: nt_native.h:631
#define REG_BINARY
Definition: nt_native.h:1496
#define FILE_READ_DATA
Definition: nt_native.h:628
NTSYSAPI NTSTATUS NTAPI RtlAppendUnicodeStringToString(PUNICODE_STRING Destination, PUNICODE_STRING Source)
#define FILE_READ_ATTRIBUTES
Definition: nt_native.h:647
#define FILE_ATTRIBUTE_HIDDEN
Definition: nt_native.h:703
#define FILE_ATTRIBUTE_SYSTEM
Definition: nt_native.h:704
NTSYSAPI VOID NTAPI RtlInitUnicodeString(PUNICODE_STRING DestinationString, PCWSTR SourceString)
NTSYSAPI BOOLEAN NTAPI RtlEqualUnicodeString(PUNICODE_STRING String1, PUNICODE_STRING String2, BOOLEAN CaseInSensitive)
#define RTL_REGISTRY_ABSOLUTE
Definition: nt_native.h:161
#define FILE_READ_EA
Definition: nt_native.h:638
#define FILE_SHARE_DELETE
Definition: nt_native.h:682
#define FILE_WRITE_ATTRIBUTES
Definition: nt_native.h:649
#define FILE_APPEND_DATA
Definition: nt_native.h:634
#define READ_CONTROL
Definition: nt_native.h:58
#define FILE_GENERIC_READ
Definition: nt_native.h:653
#define FILE_WRITE_EA
Definition: nt_native.h:640
#define UNICODE_NULL
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:317
_In_ ULONG _In_ ULONG Offset
Definition: ntddpcm.h:101
@ NotificationEvent
NTSYSAPI NTSTATUS NTAPI ZwFsControlFile(IN HANDLE DeviceHandle, IN HANDLE Event OPTIONAL, IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, IN PVOID ApcContext OPTIONAL, OUT PIO_STATUS_BLOCK IoStatusBlock, IN ULONG IoControlCode, IN PVOID InputBuffer, IN ULONG InputBufferSize, OUT PVOID OutputBuffer, IN ULONG OutputBufferSize)
NTSTATUS NTAPI IoGetDeviceObjectPointer(IN PUNICODE_STRING ObjectName, IN ACCESS_MASK DesiredAccess, OUT PFILE_OBJECT *FileObject, OUT PDEVICE_OBJECT *DeviceObject)
Definition: device.c:1435
BOOLEAN NTAPI IoSetThreadHardErrorMode(IN BOOLEAN HardErrorEnabled)
Definition: error.c:726
NTSTATUS NTAPI IoCreateFile(OUT PHANDLE FileHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes, OUT PIO_STATUS_BLOCK IoStatusBlock, IN PLARGE_INTEGER AllocationSize OPTIONAL, IN ULONG FileAttributes, IN ULONG ShareAccess, IN ULONG Disposition, IN ULONG CreateOptions, IN PVOID EaBuffer OPTIONAL, IN ULONG EaLength, IN CREATE_FILE_TYPE CreateFileType, IN PVOID ExtraCreateParameters OPTIONAL, IN ULONG Options)
Definition: file.c:3010
PVOID *typedef PHANDLE
Definition: ntsecpkg.h:455
#define STATUS_TIMEOUT
Definition: ntstatus.h:81
#define STATUS_STOPPED_ON_SYMLINK
Definition: ntstatus.h:224
#define L(x)
Definition: ntvdm.h:50
long LONG
Definition: pedump.c:60
unsigned short USHORT
Definition: pedump.c:61
static ULONG Timeout
Definition: ping.c:61
#define FileStandardInformation
Definition: propsheet.cpp:61
#define FSCTL_GET_REPARSE_POINT
Definition: winioctl.h:746
@ Restart
Definition: sacdrv.h:269
LONG NTAPI KeReleaseSemaphore(IN PKSEMAPHORE Semaphore, IN KPRIORITY Increment, IN LONG Adjustment, IN BOOLEAN Wait)
Definition: semphobj.c:54
#define STATUS_SUCCESS
Definition: shellext.h:65
#define STATUS_BUFFER_TOO_SMALL
Definition: shellext.h:69
#define STATUS_BUFFER_OVERFLOW
Definition: shellext.h:66
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68
base of all file and directory entries
Definition: entries.h:83
Definition: mntmgr.h:96
Definition: mntmgr.h:86
USHORT UniqueIdOffset
Definition: mntmgr.h:91
USHORT SymbolicNameLength
Definition: mntmgr.h:90
USHORT UniqueIdLength
Definition: mntmgr.h:92
ULONG EntrySize
Definition: mntmgr.h:87
ULONG EntryReferences
Definition: mntmgr.h:88
USHORT SymbolicNameOffset
Definition: mntmgr.h:89
BOOLEAN Removable
Definition: mntmgr.h:54
UNICODE_STRING SymbolicName
Definition: mntmgr.h:48
BOOLEAN NoDatabase
Definition: mntmgr.h:57
PMOUNTDEV_UNIQUE_ID UniqueId
Definition: mntmgr.h:49
BOOLEAN SkipNotifications
Definition: mntmgr.h:58
UNICODE_STRING DeviceName
Definition: mntmgr.h:50
BOOLEAN NeedsReconcile
Definition: mntmgr.h:56
LIST_ENTRY AssociatedDevicesHead
Definition: mntmgr.h:47
Definition: typedefs.h:120
struct _LIST_ENTRY * Flink
Definition: typedefs.h:121
USHORT UniqueIdLength
Definition: imports.h:138
UCHAR UniqueId[1]
Definition: imports.h:139
struct _REPARSE_DATA_BUFFER::@312::@315 MountPointReparseBuffer
PRTL_QUERY_REGISTRY_ROUTINE QueryRoutine
Definition: nt_native.h:109
USHORT MaximumLength
Definition: env_spec_w32.h:370
NTSTATUS NTAPI RtlCreateSystemVolumeInformationFolder(IN PUNICODE_STRING VolumeRootPath)
Definition: sysvol.c:551
#define RTL_CONSTANT_STRING(s)
Definition: tunneltest.c:14
uint16_t * PWSTR
Definition: typedefs.h:56
uint32_t * PULONG
Definition: typedefs.h:59
#define NTAPI
Definition: typedefs.h:36
void * PVOID
Definition: typedefs.h:50
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
uint32_t ULONG_PTR
Definition: typedefs.h:65
#define IN
Definition: typedefs.h:39
uint16_t * PWCHAR
Definition: typedefs.h:56
#define CONTAINING_RECORD(address, type, field)
Definition: typedefs.h:260
uint32_t ULONG
Definition: typedefs.h:59
#define OUT
Definition: typedefs.h:40
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
#define STATUS_IO_TIMEOUT
Definition: udferr_usr.h:163
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
LONGLONG QuadPart
Definition: typedefs.h:114
ULONG LowPart
Definition: typedefs.h:106
_In_ PDEVICE_OBJECT DeviceObject
Definition: wdfdevice.h:2055
_In_ WDFREQUEST _In_ WDFFILEOBJECT FileObject
Definition: wdfdevice.h:550
_Must_inspect_result_ _In_ WDFDEVICE _In_ PWDF_DEVICE_PROPERTY_DATA _In_ DEVPROPTYPE _In_ ULONG Size
Definition: wdfdevice.h:4533
_In_ WDFDEVICE AssociatedDevice
Definition: wdfinterrupt.h:173
_Must_inspect_result_ _In_ WDFKEY _In_ PCUNICODE_STRING _In_ ULONG _Out_opt_ PULONG _Out_opt_ PULONG ValueType
Definition: wdfregistry.h:282
_Must_inspect_result_ _In_ WDFKEY _In_ PCUNICODE_STRING ValueName
Definition: wdfregistry.h:243
_Must_inspect_result_ _In_ WDFKEY _In_ PCUNICODE_STRING _In_ ULONG ValueLength
Definition: wdfregistry.h:275
_Must_inspect_result_ _In_ PWDF_WORKITEM_CONFIG _In_ PWDF_OBJECT_ATTRIBUTES _Out_ WDFWORKITEM * WorkItem
Definition: wdfworkitem.h:115
Allocation
Definition: exfuncs.h:598
@ DelayedWorkQueue
Definition: extypes.h:190
_In_ UCHAR EntrySize
Definition: iofuncs.h:642
#define IO_NO_PARAMETER_CHECKING
Definition: iotypes.h:541
#define IO_NO_INCREMENT
Definition: iotypes.h:598
* PFILE_OBJECT
Definition: iotypes.h:1998
#define MAXIMUM_REPARSE_DATA_BUFFER_SIZE
Definition: iotypes.h:7213
@ CreateFileTypeNone
Definition: iotypes.h:535
#define IO_STOP_ON_SYMLINK
Definition: iotypes.h:7353
#define IO_REPARSE_TAG_MOUNT_POINT
Definition: iotypes.h:7231
_Requires_lock_held_ Interrupt _Releases_lock_ Interrupt _In_ _IRQL_restores_ KIRQL OldIrql
Definition: kefuncs.h:778
@ Executive
Definition: ketypes.h:415
#define ObDereferenceObject
Definition: obfuncs.h:203
_Inout_opt_ PVOID Parameter
Definition: rtltypes.h:336
_In_ KPROCESSOR_MODE PreviousMode
Definition: sefuncs.h:103
__wchar_t WCHAR
Definition: xmlstorage.h:180