ReactOS  0.4.14-dev-49-gfb4591c
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 
31 PWSTR DatabasePath = L"\\Registry\\Machine\\System\\MountedDevices";
32 PWSTR OfflinePath = L"\\Registry\\Machine\\System\\MountedDevices\\Offline";
33 
34 UNICODE_STRING RemoteDatabase = RTL_CONSTANT_STRING(L"\\System Volume Information\\MountPointManagerRemoteDatabase");
35 
36 /*
37  * @implemented
38  */
39 LONG
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  */
92  IN LONG NewSize)
93 {
97  FILE_ALLOCATION_INFORMATION Allocation;
98 
99  EndOfFile.EndOfFile.QuadPart = NewSize;
100  Allocation.AllocationSize.QuadPart = NewSize;
101 
102  /* First set EOF */
103  Status = ZwSetInformationFile(Database,
104  &IoStatusBlock,
105  &EndOfFile,
108  if (NT_SUCCESS(Status))
109  {
110  /* And then, properly set allocation information */
111  Status = ZwSetInformationFile(Database,
112  &IoStatusBlock,
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,
140  &IoStatusBlock,
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,
169  &IoStatusBlock,
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  {
180  FreePool(Entry);
181  return NULL;
182  }
183 
184  /* Validate entry */
185  if (MAX(Entry->SymbolicNameOffset + Entry->SymbolicNameLength,
186  Entry->UniqueIdOffset + Entry->UniqueIdLength) > (LONG)EntrySize)
187  {
189  FreePool(Entry);
190  return NULL;
191  }
192 
193  return Entry;
194 }
195 
196 /*
197  * @implemented
198  */
199 NTSTATUS
201  IN LONG Offset,
203 {
207 
208  ByteOffset.QuadPart = Offset;
209  Status = ZwWriteFile(Database,
210  NULL,
211  NULL,
212  NULL,
213  &IoStatusBlock,
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  */
232 NTSTATUS
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  */
264  FreePool(Entry);
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  {
274  FreePool(Entry);
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 */
281  FreePool(Entry);
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  */
320 NTSTATUS
321 NTAPI
326  IN PVOID Context,
328 {
329  PMOUNTDEV_UNIQUE_ID UniqueId = Context;
330 
333 
334  /* Ensure it matches, and delete */
335  if ((UniqueId->UniqueIdLength == ValueLength) &&
337  ValueLength))
338  {
340  DatabasePath,
341  ValueName);
342  }
343 
344  return STATUS_SUCCESS;
345 }
346 
347 /*
348  * @implemented
349  */
350 VOID
352  IN PMOUNTDEV_UNIQUE_ID UniqueId)
353 {
355 
358  QueryTable[0].Name = SymbolicLink->Buffer;
359 
361  DatabasePath,
362  QueryTable,
363  UniqueId,
364  NULL);
365 }
366 
367 /*
368  * @implemented
369  */
370 NTSTATUS
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  */
390 VOID
392 {
393  KeReleaseSemaphore(&(DeviceExtension->RemoteDatabaseLock), IO_NO_INCREMENT, 1, FALSE);
394 }
395 
396 /*
397  * @implemented
398  */
399 NTSTATUS
400 NTAPI
405  IN PVOID Context,
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  */
439 NTSTATUS
442  OUT PMOUNTDEV_UNIQUE_ID * UniqueId)
443 {
445  PDEVICE_INFORMATION DeviceInformation;
447 
448  /* Query the unique ID */
452 
453  *UniqueId = NULL;
455  DatabasePath,
456  QueryTable,
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  */
488 NTSTATUS
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 */
512  DatabasePath,
513  SymbolicName,
514  REG_BINARY,
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  */
558 VOID
559 NTAPI
561 {
562  ULONG Offset;
566  PMOUNTDEV_UNIQUE_ID UniqueId;
567  PDATABASE_ENTRY DatabaseEntry;
568  HANDLE DatabaseHandle, Handle;
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];
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 */
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);
657  FreePool(AssociatedDevice);
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 = DeviceInformation->DeviceName.Length + ReparseIndex.Length;
669  ReparseFile.MaximumLength = ReparseFile.Length + sizeof(UNICODE_NULL);
670  ReparseFile.Buffer = AllocatePool(ReparseFile.MaximumLength);
671  if (ReparseFile.Buffer == NULL)
672  {
673  if (DatabaseHandle != 0)
674  {
675  CloseRemoteDatabase(DatabaseHandle);
676  }
677  KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
678  goto ReleaseRDS;
679  }
680 
681 
682  RtlCopyMemory(ReparseFile.Buffer, DeviceInformation->DeviceName.Buffer,
683  DeviceInformation->DeviceName.Length);
684  RtlCopyMemory((PVOID)((ULONG_PTR)ReparseFile.Buffer + DeviceInformation->DeviceName.Length),
685  ReparseFile.Buffer, ReparseFile.Length);
686  ReparseFile.Buffer[ReparseFile.Length / sizeof(WCHAR)] = UNICODE_NULL;
687 
689  &ReparseFile,
691  NULL,
692  NULL);
693 
694  /* Open reparse point directory */
695  HardwareErrors = IoSetThreadHardErrorMode(FALSE);
699  &IoStatusBlock,
702  IoSetThreadHardErrorMode(HardwareErrors);
703 
704  FreePool(ReparseFile.Buffer);
705 
706  if (!NT_SUCCESS(Status))
707  {
708  if (DatabaseHandle != 0)
709  {
710  TruncateRemoteDatabase(DatabaseHandle, 0);
711  CloseRemoteDatabase(DatabaseHandle);
712  }
713  KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
714  goto ReleaseRDS;
715  }
716 
717  /* Query reparse point information
718  * We only pay attention to mout point
719  */
721  FileName.Buffer = FileNameBuffer;
722  FileName.Length = sizeof(FileNameBuffer);
723  FileName.MaximumLength = sizeof(FileNameBuffer);
725  Status = ZwQueryDirectoryFile(Handle,
726  NULL,
727  NULL,
728  NULL,
729  &IoStatusBlock,
730  &ReparsePointInformation,
733  TRUE,
734  &FileName,
735  FALSE);
736  if (!NT_SUCCESS(Status))
737  {
738  ZwClose(Handle);
739  if (DatabaseHandle != 0)
740  {
741  TruncateRemoteDatabase(DatabaseHandle, 0);
742  CloseRemoteDatabase(DatabaseHandle);
743  }
744  KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
745  goto ReleaseRDS;
746  }
747 
748  /* If we failed to open the remote DB previously,
749  * retry this time allowing migration (and thus, creation if required)
750  */
751  if (DatabaseHandle == 0)
752  {
753  DatabaseHandle = OpenRemoteDatabase(DeviceInformation, TRUE);
754  if (DatabaseHandle == 0)
755  {
756  KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
757  goto ReleaseRDS;
758  }
759  }
760 
761  KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
762 
763  /* Reset all the references to our DB entries */
764  Offset = 0;
765  for (;;)
766  {
767  DatabaseEntry = GetRemoteDatabaseEntry(DatabaseHandle, Offset);
768  if (DatabaseEntry == NULL)
769  {
770  break;
771  }
772 
773  DatabaseEntry->EntryReferences = 0;
774  Status = WriteRemoteDatabaseEntry(DatabaseHandle, Offset, DatabaseEntry);
775  if (!NT_SUCCESS(Status))
776  {
777  FreePool(DatabaseEntry);
778  goto CloseReparse;
779  }
780 
781  Offset += DatabaseEntry->EntrySize;
782  FreePool(DatabaseEntry);
783  }
784 
785  /* Init string for QueryVolumeName call */
786  SymbolicName.MaximumLength = sizeof(SymbolicNameBuffer);
787  SymbolicName.Length = 0;
788  SymbolicName.Buffer = SymbolicNameBuffer;
789  Restart = TRUE;
790 
791  /* Start looping on reparse points */
792  for (;;)
793  {
794  RtlCopyMemory(&SavedReparsePointInformation, &ReparsePointInformation, sizeof(FILE_REPARSE_POINT_INFORMATION));
795  Status = ZwQueryDirectoryFile(Handle,
796  NULL,
797  NULL,
798  NULL,
799  &IoStatusBlock,
800  &ReparsePointInformation,
803  TRUE,
804  Restart ? &FileName : NULL,
805  Restart);
806  /* Restart only once */
807  if (Restart)
808  {
809  Restart = FALSE;
810  }
811  else
812  {
813  /* If we get the same one, we're done, bail out */
814  if (ReparsePointInformation.FileReference == SavedReparsePointInformation.FileReference &&
815  ReparsePointInformation.Tag == SavedReparsePointInformation.Tag)
816  {
817  break;
818  }
819  }
820 
821  /* If querying failed, or if onloading, or if not returning mount points, bail out */
822  if (!NT_SUCCESS(Status) || Unloading || ReparsePointInformation.Tag != IO_REPARSE_TAG_MOUNT_POINT)
823  {
824  break;
825  }
826 
827  /* Get the volume name associated to the mount point */
828  Status = QueryVolumeName(Handle, &ReparsePointInformation, 0, &SymbolicName, &VolumeName);
829  if (!NT_SUCCESS(Status))
830  {
831  continue;
832  }
833 
834  /* Browse the DB to find the name */
835  Offset = 0;
836  for (;;)
837  {
838  UNICODE_STRING DbName;
839 
840  DatabaseEntry = GetRemoteDatabaseEntry(DatabaseHandle, Offset);
841  if (DatabaseEntry == NULL)
842  {
843  break;
844  }
845 
846  DbName.MaximumLength = DatabaseEntry->SymbolicNameLength;
847  DbName.Length = DbName.MaximumLength;
848  DbName.Buffer = (PWSTR)((ULONG_PTR)DatabaseEntry + DatabaseEntry->SymbolicNameOffset);
849  /* Found, we're done! */
850  if (RtlEqualUnicodeString(&DbName, &SymbolicName, TRUE))
851  {
852  break;
853  }
854 
855  Offset += DatabaseEntry->EntrySize;
856  FreePool(DatabaseEntry);
857  }
858 
859  /* If we found the mount point.... */
860  if (DatabaseEntry != NULL)
861  {
862  /* If it was referenced, reference it once more and update to remote */
863  if (DatabaseEntry->EntryReferences)
864  {
865  ++DatabaseEntry->EntryReferences;
866  Status = WriteRemoteDatabaseEntry(DatabaseHandle, Offset, DatabaseEntry);
867  if (!NT_SUCCESS(Status))
868  {
869  goto FreeDBEntry;
870  }
871 
872  FreePool(DatabaseEntry);
873  }
874  else
875  {
876  /* Query the Unique ID associated to that mount point in case it changed */
877  KeWaitForSingleObject(&DeviceExtension->DeviceLock, Executive, KernelMode, FALSE, NULL);
878  Status = QueryUniqueIdFromMaster(DeviceExtension, &SymbolicName, &UniqueId);
879  if (!NT_SUCCESS(Status))
880  {
881  /* If we failed doing so, reuse the old Unique ID and push it to master */
882  Status = WriteUniqueIdToMaster(DeviceExtension, DatabaseEntry);
883  if (!NT_SUCCESS(Status))
884  {
885  goto ReleaseDeviceLock;
886  }
887 
888  /* And then, reference & write the entry */
889  ++DatabaseEntry->EntryReferences;
890  Status = WriteRemoteDatabaseEntry(DatabaseHandle, Offset, DatabaseEntry);
891  if (!NT_SUCCESS(Status))
892  {
893  goto ReleaseDeviceLock;
894  }
895 
896  KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
897  FreePool(DatabaseEntry);
898  }
899  /* If the Unique ID didn't change */
900  else if (UniqueId->UniqueIdLength == DatabaseEntry->UniqueIdLength &&
901  RtlCompareMemory(UniqueId->UniqueId,
902  (PVOID)((ULONG_PTR)DatabaseEntry + DatabaseEntry->UniqueIdOffset),
903  UniqueId->UniqueIdLength) == UniqueId->UniqueIdLength)
904  {
905  /* Reference the entry, and update to remote */
906  ++DatabaseEntry->EntryReferences;
907  Status = WriteRemoteDatabaseEntry(DatabaseHandle, Offset, DatabaseEntry);
908  if (!NT_SUCCESS(Status))
909  {
910  goto FreeUniqueId;
911  }
912 
913  FreePool(UniqueId);
914  KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
915  FreePool(DatabaseEntry);
916  }
917  /* Would, by chance, the Unique ID be present elsewhere? */
918  else if (IsUniqueIdPresent(DeviceExtension, DatabaseEntry))
919  {
920  /* Push the ID to master */
921  Status = WriteUniqueIdToMaster(DeviceExtension, DatabaseEntry);
922  if (!NT_SUCCESS(Status))
923  {
924  goto FreeUniqueId;
925  }
926 
927  /* And then, reference & write the entry */
928  ++DatabaseEntry->EntryReferences;
929  Status = WriteRemoteDatabaseEntry(DatabaseHandle, Offset, DatabaseEntry);
930  if (!NT_SUCCESS(Status))
931  {
932  goto FreeUniqueId;
933  }
934 
935  FreePool(UniqueId);
936  KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
937  FreePool(DatabaseEntry);
938  }
939  else
940  {
941  /* OK, at that point, we're facing a totally unknown unique ID
942  * So, get rid of the old entry, and recreate a new one with
943  * the know unique ID
944  */
945  Status = DeleteRemoteDatabaseEntry(DatabaseHandle, Offset);
946  if (!NT_SUCCESS(Status))
947  {
948  goto FreeUniqueId;
949  }
950 
951  FreePool(DatabaseEntry);
952  /* Allocate a new entry big enough */
953  DatabaseEntry = AllocatePool(UniqueId->UniqueIdLength + SymbolicName.Length + sizeof(DATABASE_ENTRY));
954  if (DatabaseEntry == NULL)
955  {
956  goto FreeUniqueId;
957  }
958 
959  /* Configure it */
960  DatabaseEntry->EntrySize = UniqueId->UniqueIdLength + SymbolicName.Length + sizeof(DATABASE_ENTRY);
961  DatabaseEntry->EntryReferences = 1;
962  DatabaseEntry->SymbolicNameOffset = sizeof(DATABASE_ENTRY);
963  DatabaseEntry->SymbolicNameLength = SymbolicName.Length;
964  DatabaseEntry->UniqueIdOffset = SymbolicName.Length + sizeof(DATABASE_ENTRY);
965  DatabaseEntry->UniqueIdLength = UniqueId->UniqueIdLength;
966  RtlCopyMemory((PVOID)((ULONG_PTR)DatabaseEntry + DatabaseEntry->SymbolicNameOffset), SymbolicName.Buffer, DatabaseEntry->SymbolicNameLength);
967  RtlCopyMemory((PVOID)((ULONG_PTR)DatabaseEntry + DatabaseEntry->UniqueIdOffset), UniqueId->UniqueId, UniqueId->UniqueIdLength);
968 
969  /* And write it remotely */
970  Status = AddRemoteDatabaseEntry(DatabaseHandle, DatabaseEntry);
971  if (!NT_SUCCESS(Status))
972  {
973  FreePool(DatabaseEntry);
974  goto FreeUniqueId;
975  }
976 
977  FreePool(UniqueId);
978  FreePool(DatabaseEntry);
979  KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
980  }
981  }
982  }
983  else
984  {
985  /* We failed finding it remotely
986  * So, let's allocate a new remote DB entry
987  */
988  KeWaitForSingleObject(&DeviceExtension->DeviceLock, Executive, KernelMode, FALSE, NULL);
989  /* To be able to do so, we need the device Unique ID, ask master */
990  Status = QueryUniqueIdFromMaster(DeviceExtension, &SymbolicName, &UniqueId);
991  KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
992  if (NT_SUCCESS(Status))
993  {
994  /* Allocate a new entry big enough */
995  DatabaseEntry = AllocatePool(UniqueId->UniqueIdLength + SymbolicName.Length + sizeof(DATABASE_ENTRY));
996  if (DatabaseEntry != NULL)
997  {
998  /* Configure it */
999  DatabaseEntry->EntrySize = UniqueId->UniqueIdLength + SymbolicName.Length + sizeof(DATABASE_ENTRY);
1000  DatabaseEntry->EntryReferences = 1;
1001  DatabaseEntry->SymbolicNameOffset = sizeof(DATABASE_ENTRY);
1002  DatabaseEntry->SymbolicNameLength = SymbolicName.Length;
1003  DatabaseEntry->UniqueIdOffset = SymbolicName.Length + sizeof(DATABASE_ENTRY);
1004  DatabaseEntry->UniqueIdLength = UniqueId->UniqueIdLength;
1005  RtlCopyMemory((PVOID)((ULONG_PTR)DatabaseEntry + DatabaseEntry->SymbolicNameOffset), SymbolicName.Buffer, DatabaseEntry->SymbolicNameLength);
1006  RtlCopyMemory((PVOID)((ULONG_PTR)DatabaseEntry + DatabaseEntry->UniqueIdOffset), UniqueId->UniqueId, UniqueId->UniqueIdLength);
1007 
1008  /* And write it remotely */
1009  Status = AddRemoteDatabaseEntry(DatabaseHandle, DatabaseEntry);
1010  FreePool(DatabaseEntry);
1011  FreePool(UniqueId);
1012 
1013  if (!NT_SUCCESS(Status))
1014  {
1015  goto FreeVolume;
1016  }
1017  }
1018  else
1019  {
1020  FreePool(UniqueId);
1021  }
1022  }
1023  }
1024 
1025  /* Find info about the device associated associated with the mount point */
1026  KeWaitForSingleObject(&DeviceExtension->DeviceLock, Executive, KernelMode, FALSE, NULL);
1027  Status = FindDeviceInfo(DeviceExtension, &SymbolicName, FALSE, &ListDeviceInfo);
1028  if (!NT_SUCCESS(Status))
1029  {
1030  FailedFinding = TRUE;
1032  }
1033  else
1034  {
1035  /* Associate the device with the currrent DB */
1036  AssociatedDevice = AllocatePool(sizeof(ASSOCIATED_DEVICE_ENTRY));
1037  if (AssociatedDevice == NULL)
1038  {
1040  }
1041  else
1042  {
1043  AssociatedDevice->DeviceInformation = DeviceInformation;
1044  AssociatedDevice->String.Length = VolumeName.Length;
1045  AssociatedDevice->String.MaximumLength = VolumeName.MaximumLength;
1046  AssociatedDevice->String.Buffer = VolumeName.Buffer;
1047  InsertTailList(&ListDeviceInfo->AssociatedDevicesHead, &AssociatedDevice->AssociatedDevicesEntry);
1048  }
1049 
1050  /* If we don't have to skip notifications, notify */
1051  if (!ListDeviceInfo->SkipNotifications)
1052  {
1053  PostOnlineNotification(DeviceExtension, &ListDeviceInfo->SymbolicName);
1054  }
1055  }
1056 
1057  KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
1058  }
1059 
1060  /* We don't need mount points any longer */
1061  ZwClose(Handle);
1062 
1063  /* Look for the DB again */
1064  KeWaitForSingleObject(&DeviceExtension->DeviceLock, Executive, KernelMode, FALSE, NULL);
1065  for (Entry = DeviceExtension->DeviceListHead.Flink;
1066  Entry != &DeviceExtension->DeviceListHead;
1067  Entry = Entry->Flink)
1068  {
1069  ListDeviceInfo = CONTAINING_RECORD(Entry, DEVICE_INFORMATION, DeviceListEntry);
1070  if (ListDeviceInfo == DeviceInformation)
1071  {
1072  break;
1073  }
1074  }
1075 
1076  if (Entry == &DeviceExtension->DeviceListHead)
1077  {
1078  ListDeviceInfo = NULL;
1079  }
1080 
1081  /* Start the pruning loop */
1082  Offset = 0;
1083  for (;;)
1084  {
1085  /* Get the entry */
1086  DatabaseEntry = GetRemoteDatabaseEntry(DatabaseHandle, Offset);
1087  if (DatabaseEntry == NULL)
1088  {
1089  break;
1090  }
1091 
1092  /* It's not referenced anylonger? Prune it */
1093  if (DatabaseEntry->EntryReferences == 0)
1094  {
1095  Status = DeleteRemoteDatabaseEntry(DatabaseHandle, Offset);
1096  if (!NT_SUCCESS(Status))
1097  {
1098  FreePool(DatabaseEntry);
1099  KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
1100  goto CloseRDB;
1101  }
1102  }
1103  /* Update the Unique IDs to reflect the changes we might have done previously */
1104  else
1105  {
1106  if (ListDeviceInfo != NULL)
1107  {
1108  UpdateReplicatedUniqueIds(ListDeviceInfo, DatabaseEntry);
1109  }
1110 
1111  Offset += DatabaseEntry->EntrySize;
1112  }
1113 
1114  FreePool(DatabaseEntry);
1115  }
1116 
1117  /* We do have a DB now :-) */
1118  if (ListDeviceInfo != NULL && !FailedFinding)
1119  {
1120  DeviceInformation->NoDatabase = FALSE;
1121  }
1122 
1123  KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
1124 
1125  goto CloseRDB;
1126 
1127 FreeUniqueId:
1128  FreePool(UniqueId);
1129 ReleaseDeviceLock:
1130  KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
1131 FreeDBEntry:
1132  FreePool(DatabaseEntry);
1133 FreeVolume:
1135 CloseReparse:
1136  ZwClose(Handle);
1137 CloseRDB:
1138  CloseRemoteDatabase(DatabaseHandle);
1139 ReleaseRDS:
1140  ReleaseRemoteDatabaseSemaphore(DeviceExtension);
1141  return;
1142 }
1143 
1144 /*
1145  * @implemented
1146  */
1147 VOID
1148 NTAPI
1150  IN PVOID Context)
1151 {
1152  ULONG i;
1153  KEVENT Event;
1154  KIRQL OldIrql;
1155  NTSTATUS Status;
1156  HANDLE SafeEvent;
1159  PRECONCILE_WORK_ITEM WorkItem;
1160  PDEVICE_EXTENSION DeviceExtension;
1162 
1164 
1166  &SafeVolumes,
1168  NULL,
1169  NULL);
1171  Timeout.LowPart = 0xFFFFFFFF;
1172  Timeout.HighPart = 0xFF676980;
1173 
1174  /* Try to wait as long as possible */
1175  for (i = (Unloading ? 999 : 0); i < 1000; i++)
1176  {
1178  if (NT_SUCCESS(Status))
1179  {
1180  break;
1181  }
1182 
1184  }
1185 
1186  if (i < 1000)
1187  {
1188  do
1189  {
1190  Status = ZwWaitForSingleObject(SafeEvent, FALSE, &Timeout);
1191  }
1192  while (Status == STATUS_TIMEOUT && !Unloading);
1193 
1194  ZwClose(SafeEvent);
1195  }
1196 
1197  DeviceExtension = Context;
1198 
1199  InterlockedExchange(&(DeviceExtension->WorkerThreadStatus), 1);
1200 
1201  /* Acquire workers lock */
1202  KeWaitForSingleObject(&(DeviceExtension->WorkerSemaphore), Executive, KernelMode, FALSE, NULL);
1203 
1204  KeAcquireSpinLock(&(DeviceExtension->WorkerLock), &OldIrql);
1205 
1206  /* Ensure there are workers */
1207  while (!IsListEmpty(&(DeviceExtension->WorkerQueueListHead)))
1208  {
1209  /* Unqueue a worker */
1210  Entry = RemoveHeadList(&(DeviceExtension->WorkerQueueListHead));
1211  WorkItem = CONTAINING_RECORD(Entry,
1213  WorkerQueueListEntry);
1214 
1215  KeReleaseSpinLock(&(DeviceExtension->WorkerLock), OldIrql);
1216 
1217  /* Call it */
1218  WorkItem->WorkerRoutine(WorkItem->Context);
1219 
1220  IoFreeWorkItem(WorkItem->WorkItem);
1221  FreePool(WorkItem);
1222 
1223  if (InterlockedDecrement(&(DeviceExtension->WorkerReferences)) == 0)
1224  {
1225  return;
1226  }
1227 
1228  KeWaitForSingleObject(&(DeviceExtension->WorkerSemaphore), Executive, KernelMode, FALSE, NULL);
1229  KeAcquireSpinLock(&(DeviceExtension->WorkerLock), &OldIrql);
1230  }
1231  KeReleaseSpinLock(&(DeviceExtension->WorkerLock), OldIrql);
1232 
1233  InterlockedDecrement(&(DeviceExtension->WorkerReferences));
1234 
1235  /* Reset event */
1237 }
1238 
1239 /*
1240  * @implemented
1241  */
1242 NTSTATUS
1244  IN PRECONCILE_WORK_ITEM WorkItem,
1245  IN PVOID Context)
1246 {
1247  KIRQL OldIrql;
1248 
1249  WorkItem->Context = Context;
1250 
1251  /* When called, lock is already acquired */
1252 
1253  /* If noone, start to work */
1254  if (InterlockedIncrement(&(DeviceExtension->WorkerReferences)))
1255  {
1256  IoQueueWorkItem(WorkItem->WorkItem, WorkerThread, DelayedWorkQueue, DeviceExtension);
1257  }
1258 
1259  /* Otherwise queue worker for delayed execution */
1260  KeAcquireSpinLock(&(DeviceExtension->WorkerLock), &OldIrql);
1261  InsertTailList(&(DeviceExtension->WorkerQueueListHead),
1262  &(WorkItem->WorkerQueueListEntry));
1263  KeReleaseSpinLock(&(DeviceExtension->WorkerLock), OldIrql);
1264 
1265  KeReleaseSemaphore(&(DeviceExtension->WorkerSemaphore), IO_NO_INCREMENT, 1, FALSE);
1266 
1267  return STATUS_SUCCESS;
1268 }
1269 
1270 /*
1271  * @implemented
1272  */
1273 NTSTATUS
1275  IN PFILE_REPARSE_POINT_INFORMATION ReparsePointInformation,
1279 {
1280  HANDLE Handle;
1281  NTSTATUS Status;
1282  ULONG NeededLength;
1285  PFILE_NAME_INFORMATION FileNameInfo;
1286  PREPARSE_DATA_BUFFER ReparseDataBuffer;
1287 
1288  UNREFERENCED_PARAMETER(ReparsePointInformation);
1289 
1290  if (!FileName)
1291  {
1293  NULL,
1295  RootDirectory,
1296  NULL);
1297  }
1298  else
1299  {
1301  FileName,
1303  NULL,
1304  NULL);
1305  }
1306 
1307  /* Open volume */
1311  &IoStatusBlock,
1315  if (!NT_SUCCESS(Status))
1316  {
1317  return Status;
1318  }
1319 
1320  /* Get the reparse point data */
1321  ReparseDataBuffer = AllocatePool(MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
1322  if (!ReparseDataBuffer)
1323  {
1324  ZwClose(Handle);
1326  }
1327 
1329  0,
1330  NULL,
1331  NULL,
1332  &IoStatusBlock,
1334  NULL,
1335  0,
1336  ReparseDataBuffer,
1338  if (!NT_SUCCESS(Status))
1339  {
1340  FreePool(ReparseDataBuffer);
1341  ZwClose(Handle);
1342  return Status;
1343  }
1344 
1345  /* Check that name can fit in buffer */
1346  if (ReparseDataBuffer->MountPointReparseBuffer.SubstituteNameLength + sizeof(UNICODE_NULL) > SymbolicName->MaximumLength)
1347  {
1348  FreePool(ReparseDataBuffer);
1349  ZwClose(Handle);
1350  return STATUS_BUFFER_TOO_SMALL;
1351  }
1352 
1353  /* Copy symbolic name */
1354  SymbolicName->Length = ReparseDataBuffer->MountPointReparseBuffer.SubstituteNameLength;
1356  (PWSTR)((ULONG_PTR)ReparseDataBuffer->MountPointReparseBuffer.PathBuffer +
1357  ReparseDataBuffer->MountPointReparseBuffer.SubstituteNameOffset),
1358  ReparseDataBuffer->MountPointReparseBuffer.SubstituteNameLength);
1359 
1360  FreePool(ReparseDataBuffer);
1361 
1362  /* Name has to \ terminated */
1363  if (SymbolicName->Buffer[SymbolicName->Length / sizeof(WCHAR) - 1] != L'\\')
1364  {
1365  ZwClose(Handle);
1366  return STATUS_INVALID_PARAMETER;
1367  }
1368 
1369  /* So that we can delete it, and match mountmgr requirements */
1370  SymbolicName->Length -= sizeof(WCHAR);
1372 
1373  /* Also ensure it's really a volume name... */
1375  {
1376  ZwClose(Handle);
1377  return STATUS_INVALID_PARAMETER;
1378  }
1379 
1380  /* Now prepare to really get the name */
1381  FileNameInfo = AllocatePool(sizeof(FILE_NAME_INFORMATION) + 2 * sizeof(WCHAR));
1382  if (!FileNameInfo)
1383  {
1384  ZwClose(Handle);
1386  }
1387 
1388  Status = ZwQueryInformationFile(Handle,
1389  &IoStatusBlock,
1390  FileNameInfo,
1391  sizeof(FILE_NAME_INFORMATION) + 2 * sizeof(WCHAR),
1394  {
1395  /* As expected... Reallocate with proper size */
1396  NeededLength = FileNameInfo->FileNameLength;
1397  FreePool(FileNameInfo);
1398 
1399  FileNameInfo = AllocatePool(sizeof(FILE_NAME_INFORMATION) + NeededLength);
1400  if (!FileNameInfo)
1401  {
1402  ZwClose(Handle);
1404  }
1405 
1406  /* And query name */
1407  Status = ZwQueryInformationFile(Handle,
1408  &IoStatusBlock,
1409  FileNameInfo,
1410  sizeof(FILE_NAME_INFORMATION) + NeededLength,
1412  }
1413 
1414  ZwClose(Handle);
1415 
1416  if (!NT_SUCCESS(Status))
1417  {
1418  return Status;
1419  }
1420 
1421  /* Return the volume name */
1422  VolumeName->Length = (USHORT)FileNameInfo->FileNameLength;
1423  VolumeName->MaximumLength = (USHORT)FileNameInfo->FileNameLength + sizeof(WCHAR);
1425  if (!VolumeName->Buffer)
1426  {
1428  }
1429 
1430  RtlCopyMemory(VolumeName->Buffer, FileNameInfo->FileName, FileNameInfo->FileNameLength);
1431  VolumeName->Buffer[FileNameInfo->FileNameLength / sizeof(WCHAR)] = UNICODE_NULL;
1432 
1433  FreePool(FileNameInfo);
1434 
1435  return STATUS_SUCCESS;
1436 }
1437 
1438 /*
1439  * @implemented
1440  */
1441 VOID
1443  IN PDEVICE_INFORMATION DeviceInformation)
1444 {
1445  HANDLE Handle;
1446  NTSTATUS Status;
1450  PDEVICE_INFORMATION VolumeDeviceInformation;
1451  WCHAR FileNameBuffer[0x8], SymbolicNameBuffer[0x64];
1453  FILE_REPARSE_POINT_INFORMATION ReparsePointInformation, SavedReparsePointInformation;
1454 
1455  /* Removable devices don't have remote database on them */
1456  if (DeviceInformation->Removable)
1457  {
1458  return;
1459  }
1460 
1461  /* Prepare a string with reparse point index */
1462  ReparseFile.Length = DeviceInformation->DeviceName.Length + ReparseIndex.Length;
1463  ReparseFile.MaximumLength = ReparseFile.Length + sizeof(UNICODE_NULL);
1464  ReparseFile.Buffer = AllocatePool(ReparseFile.MaximumLength);
1465  if (!ReparseFile.Buffer)
1466  {
1467  return;
1468  }
1469 
1470  RtlCopyMemory(ReparseFile.Buffer, DeviceInformation->DeviceName.Buffer,
1471  DeviceInformation->DeviceName.Length);
1472  RtlCopyMemory((PVOID)((ULONG_PTR)ReparseFile.Buffer + DeviceInformation->DeviceName.Length),
1473  ReparseFile.Buffer, ReparseFile.Length);
1474  ReparseFile.Buffer[ReparseFile.Length / sizeof(WCHAR)] = UNICODE_NULL;
1475 
1477  &ReparseFile,
1479  NULL,
1480  NULL);
1481 
1482  /* Open reparse point */
1486  &IoStatusBlock,
1489  FreePool(ReparseFile.Buffer);
1490  if (!NT_SUCCESS(Status))
1491  {
1492  DeviceInformation->NoDatabase = FALSE;
1493  return;
1494  }
1495 
1496  /* Query reparse point information
1497  * We only pay attention to mout point
1498  */
1500  FileName.Buffer = FileNameBuffer;
1501  FileName.Length = sizeof(FileNameBuffer);
1502  FileName.MaximumLength = sizeof(FileNameBuffer);
1504  Status = ZwQueryDirectoryFile(Handle,
1505  NULL,
1506  NULL,
1507  NULL,
1508  &IoStatusBlock,
1509  &ReparsePointInformation,
1512  TRUE,
1513  &FileName,
1514  FALSE);
1515  if (!NT_SUCCESS(Status))
1516  {
1517  ZwClose(Handle);
1518  return;
1519  }
1520 
1521  RestartScan = TRUE;
1522 
1523  /* Query mount points */
1524  while (TRUE)
1525  {
1526  SymbolicName.Length = 0;
1527  SymbolicName.MaximumLength = sizeof(SymbolicNameBuffer);
1528  SymbolicName.Buffer = SymbolicNameBuffer;
1529  RtlCopyMemory(&SavedReparsePointInformation, &ReparsePointInformation, sizeof(FILE_REPARSE_POINT_INFORMATION));
1530 
1531  Status = ZwQueryDirectoryFile(Handle,
1532  NULL,
1533  NULL,
1534  NULL,
1535  &IoStatusBlock,
1536  &ReparsePointInformation,
1539  TRUE,
1540  (RestartScan) ? &FileName : NULL,
1541  RestartScan);
1542  if (!RestartScan)
1543  {
1544  if (ReparsePointInformation.FileReference == SavedReparsePointInformation.FileReference &&
1545  ReparsePointInformation.Tag == SavedReparsePointInformation.Tag)
1546  {
1547  break;
1548  }
1549  }
1550  else
1551  {
1552  RestartScan = FALSE;
1553  }
1554 
1555  if (!NT_SUCCESS(Status) || ReparsePointInformation.Tag != IO_REPARSE_TAG_MOUNT_POINT)
1556  {
1557  break;
1558  }
1559 
1560  /* Get the volume name associated to the mount point */
1562  &ReparsePointInformation,
1563  NULL, &SymbolicName,
1564  &VolumeName);
1565  if (!NT_SUCCESS(Status))
1566  {
1567  continue;
1568  }
1569 
1571 
1572  /* Get its information */
1573  Status = FindDeviceInfo(DeviceExtension, &SymbolicName,
1574  FALSE, &VolumeDeviceInformation);
1575  if (!NT_SUCCESS(Status))
1576  {
1577  DeviceInformation->NoDatabase = TRUE;
1578  continue;
1579  }
1580 
1581  /* If notification are enabled, mark it online */
1582  if (!DeviceInformation->SkipNotifications)
1583  {
1584  PostOnlineNotification(DeviceExtension, &VolumeDeviceInformation->SymbolicName);
1585  }
1586  }
1587 
1588  ZwClose(Handle);
1589 }
1590 
1591 /*
1592  * @implemented
1593  */
1594 VOID
1596  IN PDEVICE_INFORMATION DeviceInformation)
1597 {
1598  PRECONCILE_WORK_ITEM WorkItem;
1599 
1600  /* Removable devices don't have remote database */
1601  if (DeviceInformation->Removable)
1602  {
1603  return;
1604  }
1605 
1606  /* Allocate a work item */
1607  WorkItem = AllocatePool(sizeof(RECONCILE_WORK_ITEM));
1608  if (!WorkItem)
1609  {
1610  return;
1611  }
1612 
1613  WorkItem->WorkItem = IoAllocateWorkItem(DeviceExtension->DeviceObject);
1614  if (!WorkItem->WorkItem)
1615  {
1616  FreePool(WorkItem);
1617  return;
1618  }
1619 
1620  /* And queue it */
1622  WorkItem->DeviceExtension = DeviceExtension;
1623  WorkItem->DeviceInformation = DeviceInformation;
1624  QueueWorkItem(DeviceExtension, WorkItem, &(WorkItem->DeviceExtension));
1625 
1626  /* If there's no automount, and automatic letters
1627  * all volumes to find those online and notify there presence
1628  */
1629  if (DeviceExtension->WorkerThreadStatus == 0 &&
1630  DeviceExtension->AutomaticDriveLetter == 1 &&
1631  DeviceExtension->NoAutoMount == FALSE)
1632  {
1633  OnlineMountedVolumes(DeviceExtension, DeviceInformation);
1634  }
1635 }
1636 
1637 /*
1638  * @implemented
1639  */
1640 VOID
1642 {
1643  PLIST_ENTRY NextEntry;
1644  PDEVICE_INFORMATION DeviceInformation;
1645 
1646  /* Browse all the devices */
1647  for (NextEntry = DeviceExtension->DeviceListHead.Flink;
1648  NextEntry != &(DeviceExtension->DeviceListHead);
1649  NextEntry = NextEntry->Flink)
1650  {
1651  DeviceInformation = CONTAINING_RECORD(NextEntry,
1653  DeviceListEntry);
1654  /* If it's not removable, then, it might have a database to sync */
1655  if (!DeviceInformation->Removable)
1656  {
1657  ReconcileThisDatabaseWithMaster(DeviceExtension, DeviceInformation);
1658  }
1659  }
1660 }
1661 
1662 /*
1663  * @implemented
1664  */
1665 VOID
1666 NTAPI
1668  IN PVOID Context)
1669 {
1670  NTSTATUS Status;
1671  HANDLE Database = 0;
1672  UNICODE_STRING DatabaseName;
1673  PMIGRATE_WORK_ITEM WorkItem;
1676  PDEVICE_INFORMATION DeviceInformation;
1677 
1679 
1680  /* Extract context */
1681  WorkItem = Context;
1682  DeviceInformation = WorkItem->DeviceInformation;
1683 
1684  /* Reconstruct appropriate string */
1685  DatabaseName.Length = DeviceInformation->DeviceName.Length + RemoteDatabase.Length;
1686  DatabaseName.MaximumLength = DatabaseName.Length + sizeof(WCHAR);
1687  DatabaseName.Buffer = AllocatePool(DatabaseName.MaximumLength);
1688  if (DatabaseName.Buffer == NULL)
1689  {
1691  goto Cleanup;
1692  }
1693 
1694  /* Create the required folder (in which the database will be stored
1695  * \System Volume Information at root of the volume
1696  */
1697  Status = RtlCreateSystemVolumeInformationFolder(&(DeviceInformation->DeviceName));
1698  if (!NT_SUCCESS(Status))
1699  {
1700  goto Cleanup;
1701  }
1702 
1703  /* Finish initiating strings */
1704  RtlCopyMemory(DatabaseName.Buffer, DeviceInformation->DeviceName.Buffer, DeviceInformation->DeviceName.Length);
1705  RtlCopyMemory(DatabaseName.Buffer + (DeviceInformation->DeviceName.Length / sizeof(WCHAR)),
1707  DatabaseName.Buffer[DatabaseName.Length / sizeof(WCHAR)] = UNICODE_NULL;
1708 
1709  /* Create database */
1711  &DatabaseName,
1713  NULL,
1714  NULL);
1715 
1721  &IoStatusBlock,
1722  NULL,
1724  0,
1725  FILE_CREATE,
1727  NULL,
1728  0,
1730  NULL,
1732  if (!NT_SUCCESS(Status))
1733  {
1735  {
1736  DPRINT1("Attempt to exploit CVE-2015-1769. See CORE-10216\n");
1737  }
1738 
1739  Database = 0;
1740  goto Cleanup;
1741  }
1742 
1743 Cleanup:
1744  if (DatabaseName.Buffer)
1745  {
1746  FreePool(DatabaseName.Buffer);
1747  }
1748 
1749  if (NT_SUCCESS(Status))
1750  {
1751  DeviceInformation->Migrated = 1;
1752  }
1753  else if (Database != 0)
1754  {
1755  ZwClose(Database);
1756  }
1757 
1758  IoFreeWorkItem(WorkItem->WorkItem);
1759 
1760  WorkItem->WorkItem = NULL;
1761  WorkItem->Status = Status;
1762  WorkItem->Database = Database;
1763 
1764  KeSetEvent(WorkItem->Event, 0, FALSE);
1765 }
1766 
1767 /*
1768  * @implemented
1769  */
1770 NTSTATUS
1773 {
1774  KEVENT Event;
1775  NTSTATUS Status;
1776  PMIGRATE_WORK_ITEM WorkItem;
1777 
1779 
1780  /* Allocate a work item dedicated to migration */
1781  WorkItem = AllocatePool(sizeof(MIGRATE_WORK_ITEM));
1782  if (!WorkItem)
1783  {
1784  *Database = 0;
1786  }
1787 
1788  RtlZeroMemory(WorkItem, sizeof(MIGRATE_WORK_ITEM));
1789  WorkItem->Event = &Event;
1790  WorkItem->DeviceInformation = DeviceInformation;
1791  WorkItem->WorkItem = IoAllocateWorkItem(DeviceInformation->DeviceExtension->DeviceObject);
1792  if (!WorkItem->WorkItem)
1793  {
1794  FreePool(WorkItem);
1795  *Database = 0;
1797  }
1798 
1799  /* And queue it */
1800  IoQueueWorkItem(WorkItem->WorkItem,
1803  WorkItem);
1804 
1806  Status = WorkItem->Status;
1807 
1808  *Database = (NT_SUCCESS(Status) ? WorkItem->Database : 0);
1809 
1810  FreePool(WorkItem);
1811  return Status;
1812 }
1813 
1814 /*
1815  * @implemented
1816  */
1817 HANDLE
1819  IN BOOLEAN MigrateDatabase)
1820 {
1821  HANDLE Database;
1822  NTSTATUS Status;
1826  UNICODE_STRING DeviceRemoteDatabase;
1827 
1828  Database = 0;
1829 
1830  /* Get database name */
1831  DeviceRemoteDatabase.Length = DeviceInformation->DeviceName.Length + RemoteDatabase.Length;
1832  DeviceRemoteDatabase.MaximumLength = DeviceRemoteDatabase.Length + sizeof(WCHAR);
1833  DeviceRemoteDatabase.Buffer = AllocatePool(DeviceRemoteDatabase.MaximumLength);
1834  if (!DeviceRemoteDatabase.Buffer)
1835  {
1836  return 0;
1837  }
1838 
1839  RtlCopyMemory(DeviceRemoteDatabase.Buffer, DeviceInformation->DeviceName.Buffer, DeviceInformation->DeviceName.Length);
1840  RtlCopyMemory(DeviceRemoteDatabase.Buffer + (DeviceInformation->DeviceName.Length / sizeof(WCHAR)),
1842  DeviceRemoteDatabase.Buffer[DeviceRemoteDatabase.Length / sizeof(WCHAR)] = UNICODE_NULL;
1843 
1844  /* Open database */
1846  &DeviceRemoteDatabase,
1848  NULL,
1849  NULL);
1850 
1851  /* Disable hard errors */
1853 
1859  &IoStatusBlock,
1860  NULL,
1862  0,
1863  (!MigrateDatabase || DeviceInformation->Migrated == 0) ? FILE_OPEN_IF : FILE_OPEN,
1865  NULL,
1866  0,
1868  NULL,
1871  {
1872  DPRINT1("Attempt to exploit CVE-2015-1769. See CORE-10216\n");
1873  }
1874 
1875  /* If base it to be migrated and was opened successfully, go ahead */
1876  if (MigrateDatabase && NT_SUCCESS(Status))
1877  {
1878  CreateRemoteDatabase(DeviceInformation, &Database);
1879  }
1880 
1882  FreePool(DeviceRemoteDatabase.Buffer);
1883 
1884  return Database;
1885 }
1886 
1887 /*
1888  * @implemented
1889  */
1890 VOID
1892  IN PMOUNTDEV_UNIQUE_ID OldUniqueId,
1893  IN PMOUNTDEV_UNIQUE_ID NewUniqueId)
1894 {
1895  LONG Offset = 0;
1896  HANDLE Database;
1897  PDATABASE_ENTRY Entry, NewEntry;
1899 
1900  /* Open the remote database */
1901  Database = OpenRemoteDatabase(DeviceInformation, FALSE);
1902  if (!Database)
1903  {
1904  return;
1905  }
1906 
1907  /* Get all the entries */
1908  do
1909  {
1911  if (!Entry)
1912  {
1913  break;
1914  }
1915 
1916  /* Not the correct entry, skip it */
1917  if (Entry->UniqueIdLength != OldUniqueId->UniqueIdLength)
1918  {
1919  Offset += Entry->EntrySize;
1920  FreePool(Entry);
1921  continue;
1922  }
1923 
1924  /* Not the correct entry, skip it */
1925  if (RtlCompareMemory(OldUniqueId->UniqueId,
1926  (PVOID)((ULONG_PTR)Entry + Entry->UniqueIdOffset),
1927  Entry->UniqueIdLength) != Entry->UniqueIdLength)
1928  {
1929  Offset += Entry->EntrySize;
1930  FreePool(Entry);
1931  continue;
1932  }
1933 
1934  /* Here, we have the correct entry */
1935  NewEntry = AllocatePool(Entry->EntrySize + NewUniqueId->UniqueIdLength - OldUniqueId->UniqueIdLength);
1936  if (!NewEntry)
1937  {
1938  Offset += Entry->EntrySize;
1939  FreePool(Entry);
1940  continue;
1941  }
1942 
1943  /* Recreate the entry from the previous one */
1944  NewEntry->EntrySize = Entry->EntrySize + NewUniqueId->UniqueIdLength - OldUniqueId->UniqueIdLength;
1945  NewEntry->EntryReferences = Entry->EntryReferences;
1946  NewEntry->SymbolicNameOffset = sizeof(DATABASE_ENTRY);
1947  NewEntry->SymbolicNameLength = Entry->SymbolicNameLength;
1948  NewEntry->UniqueIdOffset = Entry->SymbolicNameLength + sizeof(DATABASE_ENTRY);
1949  NewEntry->UniqueIdLength = NewUniqueId->UniqueIdLength;
1950  RtlCopyMemory((PVOID)((ULONG_PTR)NewEntry + NewEntry->SymbolicNameOffset),
1951  (PVOID)((ULONG_PTR)Entry + Entry->SymbolicNameOffset),
1952  NewEntry->SymbolicNameLength);
1953  RtlCopyMemory((PVOID)((ULONG_PTR)NewEntry + NewEntry->UniqueIdOffset),
1954  NewUniqueId->UniqueId, NewEntry->UniqueIdLength);
1955 
1956  /* Delete old entry */
1958  if (!NT_SUCCESS(Status))
1959  {
1960  FreePool(Entry);
1961  FreePool(NewEntry);
1962  break;
1963  }
1964 
1965  /* And replace with new one */
1966  Status = AddRemoteDatabaseEntry(Database, NewEntry);
1967  FreePool(Entry);
1968  FreePool(NewEntry);
1969  } while (NT_SUCCESS(Status));
1970 
1972 
1973  return;
1974 }
1975 
1976 /*
1977  * @implemented
1978  */
1979 NTSTATUS
1980 NTAPI
1982  IN ULONG ValueType,
1983  IN PVOID ValueData,
1985  IN PVOID Context,
1987 {
1988  PMOUNTDEV_UNIQUE_ID UniqueId;
1989  UNICODE_STRING RegistryEntry;
1990 
1992 
1993  if (ValueType != REG_BINARY)
1994  {
1995  return STATUS_SUCCESS;
1996  }
1997 
1998  UniqueId = Context;
1999 
2000  /* First ensure we have the correct data */
2001  if (UniqueId->UniqueIdLength != ValueLength)
2002  {
2003  return STATUS_SUCCESS;
2004  }
2005 
2007  {
2008  return STATUS_SUCCESS;
2009  }
2010 
2011  RtlInitUnicodeString(&RegistryEntry, ValueName);
2012 
2013  /* Then, it's a drive letter, erase it */
2014  if (IsDriveLetter(&RegistryEntry))
2015  {
2017  DatabasePath,
2018  ValueName);
2019  }
2020 
2021  return STATUS_SUCCESS;
2022 }
2023 
2024 /*
2025  * @implemented
2026  */
2027 VOID
2029 {
2031 
2034 
2036  DatabasePath,
2037  QueryTable,
2038  UniqueId,
2039  NULL);
2040 }
2041 
2042 /*
2043  * @implemented
2044  */
2045 NTSTATUS
2046 NTAPI
2048  IN ULONG ValueType,
2049  IN PVOID ValueData,
2051  IN PVOID Context,
2053 {
2054  PMOUNTDEV_UNIQUE_ID UniqueId = Context;
2055 
2057 
2058  /* Ensure we have correct input */
2059  if (ValueName[0] != L'#' || ValueType != REG_BINARY ||
2060  UniqueId->UniqueIdLength != ValueLength)
2061  {
2062  return STATUS_SUCCESS;
2063  }
2064 
2065  /* And then, if unique ID matching, delete entry */
2067  {
2069  DatabasePath,
2070  ValueName);
2071  }
2072 
2073  return STATUS_SUCCESS;
2074 }
2075 
2076 /*
2077  * @implemented
2078  */
2079 VOID
2081 {
2083 
2086 
2088  DatabasePath,
2089  QueryTable,
2090  UniqueId,
2091  NULL);
2092 }
#define FILE_GENERIC_READ
Definition: nt_native.h:653
IN PUNICODE_STRING IN POBJECT_ATTRIBUTES ObjectAttributes
Definition: conport.c:35
USHORT UniqueIdOffset
Definition: mntmgr.h:91
VOID DeleteRegistryDriveLetter(IN PMOUNTDEV_UNIQUE_ID UniqueId)
Definition: database.c:2028
#define FILE_WRITE_EA
Definition: nt_native.h:640
_In_ PCWSTR _Inout_ _At_ QueryTable _Pre_unknown_ PRTL_QUERY_REGISTRY_TABLE QueryTable
Definition: rtlfuncs.h:4004
#define IN
Definition: typedefs.h:38
VOID NTAPI ReconcileThisDatabaseWithMasterWorker(IN PVOID Parameter)
Definition: database.c:560
#define TRUE
Definition: types.h:120
NTSYSAPI VOID NTAPI RtlCopyMemory(VOID UNALIGNED *Destination, CONST VOID UNALIGNED *Source, ULONG Length)
NTSTATUS QueueWorkItem(IN PDEVICE_EXTENSION DeviceExtension, IN PRECONCILE_WORK_ITEM WorkItem, IN PVOID Context)
Definition: database.c:1243
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
#define FILE_OPEN_IF
Definition: from_kernel.h:56
VOID DeleteFromLocalDatabase(IN PUNICODE_STRING SymbolicLink, IN PMOUNTDEV_UNIQUE_ID UniqueId)
Definition: database.c:351
NTSTATUS DeleteRemoteDatabaseEntry(IN HANDLE Database, IN LONG StartingOffset)
Definition: database.c:233
NTSYSAPI NTSTATUS WINAPI RtlDeleteRegistryValue(ULONG, PCWSTR, PCWSTR)
_Must_inspect_result_ _In_ PFILE_OBJECT _In_ ULONG _In_ BOOLEAN _In_ ULONG _In_opt_ PULONG _In_ BOOLEAN RestartScan
Definition: fltkernel.h:2298
WCHAR RootDirectory[MAX_PATH]
Definition: format.c:74
_In_ PFCB _In_ LONGLONG StartingOffset
Definition: cdprocs.h:282
NTSTATUS TruncateRemoteDatabase(IN HANDLE Database, IN LONG NewSize)
Definition: database.c:91
struct _Entry Entry
Definition: kefuncs.h:640
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
ULONG EntryReferences
Definition: mntmgr.h:88
USHORT MaximumLength
Definition: env_spec_w32.h:370
ULONG EntrySize
Definition: mntmgr.h:87
#define REG_BINARY
Definition: nt_native.h:1496
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:323
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
#define FILE_ATTRIBUTE_SYSTEM
Definition: nt_native.h:704
NTSYSAPI NTSTATUS NTAPI ZwClose(_In_ HANDLE Handle)
uint16_t * PWSTR
Definition: typedefs.h:54
PDEVICE_INFORMATION DeviceInformation
Definition: mntmgr.h:98
_In_ PCWSTR _In_z_ PCWSTR _In_ ULONG ValueType
Definition: rtlfuncs.h:4016
_In_ PNDIS_STRING _In_ PNDIS_STRING SymbolicName
Definition: ndis.h:4676
LONG NTSTATUS
Definition: precomp.h:26
USHORT UniqueIdLength
Definition: imports.h:138
PKEVENT Event
Definition: mntmgr.h:134
#define FILE_CREATE
Definition: from_kernel.h:55
BOOLEAN IsUniqueIdPresent(IN PDEVICE_EXTENSION DeviceExtension, IN PDATABASE_ENTRY DatabaseEntry)
Definition: uniqueid.c:221
BOOLEAN IsDriveLetter(PUNICODE_STRING SymbolicName)
Definition: symlink.c:922
UNICODE_STRING RemoteDatabase
Definition: database.c:34
#define DO_UNLOAD_PENDING
Definition: env_spec_w32.h:392
NTSYSCALLAPI NTSTATUS NTAPI ZwOpenEvent(_Out_ PHANDLE EventHandle, _In_ ACCESS_MASK DesiredAccess, _In_ POBJECT_ATTRIBUTES ObjectAttributes)
NTSTATUS NTAPI IoGetDeviceObjectPointer(IN PUNICODE_STRING ObjectName, IN ACCESS_MASK DesiredAccess, OUT PFILE_OBJECT *FileObject, OUT PDEVICE_OBJECT *DeviceObject)
Definition: device.c:1435
VOID NTAPI CreateRemoteDatabaseWorker(IN PDEVICE_OBJECT DeviceObject, IN PVOID Context)
Definition: database.c:1667
VOID NTAPI ObDereferenceObject(IN PVOID Object)
Definition: obref.c:375
UNICODE_STRING SafeVolumes
Definition: symlink.c:38
NTSTATUS WriteUniqueIdToMaster(IN PDEVICE_EXTENSION DeviceExtension, IN PDATABASE_ENTRY DatabaseEntry)
Definition: database.c:489
uint16_t * PWCHAR
Definition: typedefs.h:54
#define FILE_SHARE_WRITE
Definition: nt_native.h:681
_In_ PVOID Parameter
Definition: ldrtypes.h:241
#define FSCTL_GET_REPARSE_POINT
Definition: winioctl.h:97
#define InsertTailList(ListHead, Entry)
USHORT SymbolicNameLength
Definition: mntmgr.h:90
#define FILE_APPEND_DATA
Definition: nt_native.h:634
VOID DeleteNoDriveLetterEntry(IN PMOUNTDEV_UNIQUE_ID UniqueId)
Definition: database.c:2080
NTSTATUS MountMgrCreatePointWorker(IN PDEVICE_EXTENSION DeviceExtension, IN PUNICODE_STRING SymbolicLinkName, IN PUNICODE_STRING DeviceName)
Definition: point.c:35
PIO_WORKITEM NTAPI IoAllocateWorkItem(IN PDEVICE_OBJECT DeviceObject)
Definition: iowork.c:75
_In_ UCHAR EntrySize
Definition: iofuncs.h:640
LONG NTAPI KeSetEvent(IN PKEVENT Event, IN KPRIORITY Increment, IN BOOLEAN Wait)
Definition: eventobj.c:159
#define FreePool(P)
Definition: mntmgr.h:154
NTSTATUS NTAPI KeWaitForSingleObject(IN PVOID Object, IN KWAIT_REASON WaitReason, IN KPROCESSOR_MODE WaitMode, IN BOOLEAN Alertable, IN PLARGE_INTEGER Timeout OPTIONAL)
Definition: wait.c:416
VOID NTAPI IoFreeWorkItem(IN PIO_WORKITEM IoWorkItem)
Definition: iowork.c:64
_Must_inspect_result_ FORCEINLINE BOOLEAN IsListEmpty(_In_ const LIST_ENTRY *ListHead)
Definition: rtlfuncs.h:57
UNICODE_STRING SymbolicName
Definition: mntmgr.h:48
#define FILE_WRITE_ATTRIBUTES
Definition: nt_native.h:649
#define STATUS_STOPPED_ON_SYMLINK
Definition: ntstatus.h:212
LIST_ENTRY AssociatedDevicesEntry
Definition: mntmgr.h:97
#define FILE_SHARE_READ
Definition: compat.h:125
#define FILE_OPEN_BY_FILE_ID
Definition: from_kernel.h:41
LARGE_INTEGER AllocationSize
Definition: winternl.h:688
VOID OnlineMountedVolumes(IN PDEVICE_EXTENSION DeviceExtension, IN PDEVICE_INFORMATION DeviceInformation)
Definition: database.c:1442
#define STATUS_BUFFER_TOO_SMALL
Definition: shellext.h:64
#define IO_STOP_ON_SYMLINK
Definition: iotypes.h:6997
HANDLE Database
Definition: mntmgr.h:136
uint32_t ULONG_PTR
Definition: typedefs.h:63
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
FORCEINLINE BOOLEAN RemoveEntryList(_In_ PLIST_ENTRY Entry)
Definition: rtlfuncs.h:105
#define IO_REPARSE_TAG_MOUNT_POINT
Definition: iotypes.h:6875
#define STATUS_TIMEOUT
Definition: ntstatus.h:81
UCHAR KIRQL
Definition: env_spec_w32.h:591
_In_ PUNICODE_STRING ValueName
Definition: cmfuncs.h:264
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
#define FILE_SYNCHRONOUS_IO_ALERT
Definition: from_kernel.h:30
VOID ReconcileThisDatabaseWithMaster(IN PDEVICE_EXTENSION DeviceExtension, IN PDEVICE_INFORMATION DeviceInformation)
Definition: database.c:1595
HANDLE OpenRemoteDatabase(IN PDEVICE_INFORMATION DeviceInformation, IN BOOLEAN MigrateDatabase)
Definition: database.c:1818
PRTL_QUERY_REGISTRY_ROUTINE QueryRoutine
Definition: nt_native.h:109
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
_In_ ULONG _In_ ULONG Offset
Definition: ntddpcm.h:101
#define UNICODE_NULL
long LONG
Definition: pedump.c:60
#define IO_NO_PARAMETER_CHECKING
Definition: iotypes.h:509
BOOLEAN NeedsReconcile
Definition: mntmgr.h:56
#define EVENT_ALL_ACCESS
Definition: isotest.c:82
#define FILE_READ_DATA
Definition: nt_native.h:628
#define MOUNTMGR_IS_VOLUME_NAME(s)
Definition: mountmgr.h:61
_In_ PVOID _In_ ULONG Event
Definition: iotypes.h:435
BOOLEAN NoDatabase
Definition: mntmgr.h:57
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)
unsigned char BOOLEAN
_In_ PCWSTR _Inout_ _At_ QueryTable EntryContext
Definition: rtlfuncs.h:4004
smooth NULL
Definition: ftsmooth.c:416
FORCEINLINE PLIST_ENTRY RemoveHeadList(_Inout_ PLIST_ENTRY ListHead)
Definition: rtlfuncs.h:128
USHORT UniqueIdLength
Definition: mntmgr.h:92
NTSTATUS FindDeviceInfo(IN PDEVICE_EXTENSION DeviceExtension, IN PUNICODE_STRING SymbolicName, IN BOOLEAN DeviceNameGiven, OUT PDEVICE_INFORMATION *DeviceInformation)
Definition: mountmgr.c:641
void * PVOID
Definition: retypes.h:9
_Inout_ PFILE_OBJECT FileObject
Definition: cdprocs.h:593
UNICODE_STRING ReparseIndex
Definition: symlink.c:40
#define InterlockedExchangeAdd
Definition: interlocked.h:181
#define FILE_WRITE_DATA
Definition: nt_native.h:631
PFLT_MESSAGE_WAITER_QUEUE CONTAINING_RECORD(Csq, DEVICE_EXTENSION, IrpQueue)) -> WaiterQ.mLock) _IRQL_raises_(DISPATCH_LEVEL) VOID NTAPI FltpAcquireMessageWaiterLock(_In_ PIO_CSQ Csq, _Out_ PKIRQL Irql)
Definition: Messaging.c:560
NTSTATUS CloseRemoteDatabase(IN HANDLE Database)
Definition: database.c:82
struct _DATABASE_ENTRY DATABASE_ENTRY
struct _LIST_ENTRY * Flink
Definition: typedefs.h:119
_In_ HANDLE Handle
Definition: extypes.h:390
_In_ KPROCESSOR_MODE PreviousMode
Definition: sefuncs.h:103
VOID ChangeRemoteDatabaseUniqueId(IN PDEVICE_INFORMATION DeviceInformation, IN PMOUNTDEV_UNIQUE_ID OldUniqueId, IN PMOUNTDEV_UNIQUE_ID NewUniqueId)
Definition: database.c:1891
BOOLEAN SkipNotifications
Definition: mntmgr.h:58
NTSTATUS NTAPI RtlCreateSystemVolumeInformationFolder(IN PUNICODE_STRING VolumeRootPath)
Definition: sysvol.c:545
__wchar_t WCHAR
Definition: xmlstorage.h:180
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
struct _RECONCILE_WORK_ITEM_CONTEXT * PRECONCILE_WORK_ITEM_CONTEXT
PDEVICE_INFORMATION DeviceInformation
Definition: mntmgr.h:133
PIO_WORKITEM WorkItem
Definition: mntmgr.h:132
VOID NTAPI WorkerThread(IN PDEVICE_OBJECT DeviceObject, IN PVOID Context)
Definition: database.c:1149
Definition: mntmgr.h:95
#define KeAcquireSpinLock(sl, irql)
Definition: env_spec_w32.h:609
_In_ GUID _In_ PVOID ValueData
Definition: hubbusif.h:311
NTSTATUS Status
Definition: mntmgr.h:135
USHORT SymbolicNameOffset
Definition: mntmgr.h:89
NTSYSAPI NTSTATUS WINAPI RtlQueryRegistryValues(ULONG, PCWSTR, PRTL_QUERY_REGISTRY_TABLE, PVOID, PVOID)
* PFILE_OBJECT
Definition: iotypes.h:1955
#define OBJ_CASE_INSENSITIVE
Definition: winternl.h:228
#define READ_CONTROL
Definition: nt_native.h:58
#define FILE_READ_ATTRIBUTES
Definition: nt_native.h:647
Definition: mntmgr.h:85
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)
#define FILE_ATTRIBUTE_NORMAL
Definition: compat.h:126
NTSYSAPI NTSTATUS WINAPI RtlWriteRegistryValue(ULONG, PCWSTR, PCWSTR, ULONG, PVOID, ULONG)
#define FILE_SHARE_DELETE
Definition: nt_native.h:682
static const WCHAR L[]
Definition: oid.c:1250
#define InterlockedDecrement
Definition: armddk.h:52
_Requires_lock_held_ Interrupt _Releases_lock_ Interrupt _In_ _IRQL_restores_ KIRQL OldIrql
Definition: kefuncs.h:803
_In_ GUID _In_ PVOID _In_ ULONG ValueLength
Definition: hubbusif.h:311
PVOID *typedef PHANDLE
Definition: ntsecpkg.h:414
BOOLEAN NTAPI IoSetThreadHardErrorMode(IN BOOLEAN HardErrorEnabled)
Definition: error.c:707
#define FILE_NON_DIRECTORY_FILE
Definition: constants.h:492
ULONG LowPart
Definition: typedefs.h:104
_Must_inspect_result_ _In_ USHORT NewSize
Definition: fltkernel.h:975
Definition: typedefs.h:117
IN PVOID IN PVOID IN USHORT IN USHORT Size
Definition: pci.h:359
static const WCHAR Cleanup[]
Definition: register.c:80
#define SYNCHRONIZE
Definition: nt_native.h:61
#define RTL_REGISTRY_ABSOLUTE
Definition: nt_native.h:161
UNICODE_STRING String
Definition: mntmgr.h:99
#define AllocatePool(Size)
Definition: mntmgr.h:153
#define InterlockedExchange
Definition: armddk.h:54
PWSTR DatabasePath
Definition: database.c:31
Status
Definition: gdiplustypes.h:24
T MAX(T a, T b)
Definition: polytest.cpp:85
VOID PostOnlineNotification(IN PDEVICE_EXTENSION DeviceExtension, IN PUNICODE_STRING SymbolicName)
Definition: notify.c:145
#define FILE_OPEN
Definition: from_kernel.h:54
VOID NTAPI IoQueueWorkItem(IN PIO_WORKITEM IoWorkItem, IN PIO_WORKITEM_ROUTINE WorkerRoutine, IN WORK_QUEUE_TYPE QueueType, IN PVOID Context)
Definition: iowork.c:40
IN PDEVICE_OBJECT DeviceObject
Definition: fatprocs.h:1560
struct _FileName FileName
Definition: fatprocs.h:884
NTSTATUS NTAPI DeleteDriveLetterRoutine(IN PWSTR ValueName, IN ULONG ValueType, IN PVOID ValueData, IN ULONG ValueLength, IN PVOID Context, IN PVOID EntryContext)
Definition: database.c:1981
static ULONG Timeout
Definition: ping.c:61
#define KeInitializeEvent(pEvt, foo, foo2)
Definition: env_spec_w32.h:477
NTSTATUS WriteRemoteDatabaseEntry(IN HANDLE Database, IN LONG Offset, IN PDATABASE_ENTRY Entry)
Definition: database.c:200
#define InterlockedIncrement
Definition: armddk.h:53
#define STATUS_BUFFER_OVERFLOW
Definition: shellext.h:61
LONG NTAPI KeReleaseSemaphore(IN PKSEMAPHORE Semaphore, IN KPRIORITY Increment, IN LONG Adjustment, IN BOOLEAN Wait)
Definition: semphobj.c:54
unsigned short USHORT
Definition: pedump.c:61
BOOLEAN Removable
Definition: mntmgr.h:54
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:1274
#define FILE_READ_EA
Definition: nt_native.h:638
static OUT PIO_STATUS_BLOCK IoStatusBlock
Definition: pipe.c:75
#define FILE_ATTRIBUTE_HIDDEN
Definition: nt_native.h:703
unsigned int * PULONG
Definition: retypes.h:1
VOID UpdateReplicatedUniqueIds(IN PDEVICE_INFORMATION DeviceInformation, IN PDATABASE_ENTRY DatabaseEntry)
Definition: uniqueid.c:376
#define KeReleaseSpinLock(sl, irql)
Definition: env_spec_w32.h:627
#define STATUS_IO_TIMEOUT
Definition: udferr_usr.h:163
NTSTATUS CreateRemoteDatabase(IN PDEVICE_INFORMATION DeviceInformation, IN OUT PHANDLE Database)
Definition: database.c:1771
#define DPRINT1
Definition: precomp.h:8
#define FileStandardInformation
Definition: propsheet.cpp:61
UNICODE_STRING DeviceName
Definition: mntmgr.h:50
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:3009
NTSTATUS WaitForRemoteDatabaseSemaphore(IN PDEVICE_EXTENSION DeviceExtension)
Definition: database.c:371
#define FILE_SYNCHRONOUS_IO_NONALERT
Definition: from_kernel.h:31
PIO_WORKITEM WorkItem
Definition: mntmgr.h:124
_Must_inspect_result_ _Inout_opt_ PUNICODE_STRING VolumeName
Definition: fltkernel.h:1117
WCHAR FileNameBuffer[_MAX_PATH]
Definition: framewnd.c:239
PDATABASE_ENTRY GetRemoteDatabaseEntry(IN HANDLE Database, IN LONG StartingOffset)
Definition: database.c:125
#define OUT
Definition: typedefs.h:39
struct tagContext Context
Definition: acpixf.h:1024
unsigned int ULONG
Definition: retypes.h:1
#define IO_NO_INCREMENT
Definition: iotypes.h:566
LIST_ENTRY AssociatedDevicesHead
Definition: mntmgr.h:47
NTSYSAPI VOID NTAPI RtlInitUnicodeString(PUNICODE_STRING DestinationString, PCWSTR SourceString)
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:261
#define InitializeObjectAttributes(p, n, a, r, s)
Definition: reg.c:106
NTSTATUS NTAPI DeleteNoDriveLetterEntryRoutine(IN PWSTR ValueName, IN ULONG ValueType, IN PVOID ValueData, IN ULONG ValueLength, IN PVOID Context, IN PVOID EntryContext)
Definition: database.c:2047
NTSTATUS QueryUniqueIdFromMaster(IN PDEVICE_EXTENSION DeviceExtension, IN PUNICODE_STRING SymbolicName, OUT PMOUNTDEV_UNIQUE_ID *UniqueId)
Definition: database.c:440
PWSTR OfflinePath
Definition: database.c:32
NTSTATUS AddRemoteDatabaseEntry(IN HANDLE Database, IN PDATABASE_ENTRY Entry)
Definition: database.c:64
VOID ReleaseRemoteDatabaseSemaphore(IN PDEVICE_EXTENSION DeviceExtension)
Definition: database.c:391
VOID ReconcileAllDatabasesWithMaster(IN PDEVICE_EXTENSION DeviceExtension)
Definition: database.c:1641
return STATUS_SUCCESS
Definition: btrfs.c:2966
#define MAXIMUM_REPARSE_DATA_BUFFER_SIZE
Definition: iotypes.h:6857
PMOUNTDEV_UNIQUE_ID UniqueId
Definition: mntmgr.h:49
PWORKER_THREAD_ROUTINE WorkerRoutine
Definition: mntmgr.h:125
#define OBJ_KERNEL_HANDLE
Definition: winternl.h:231
#define FILE_OPEN_REPARSE_POINT
Definition: from_kernel.h:46
NTSYSAPI BOOLEAN NTAPI RtlEqualUnicodeString(PUNICODE_STRING String1, PUNICODE_STRING String2, BOOLEAN CaseInSensitive)
UCHAR UniqueId[1]
Definition: imports.h:139
base of all file and directory entries
Definition: entries.h:82
static const WCHAR SymbolicLink[]
Definition: interface.c:31
#define RtlCompareMemory(s1, s2, l)
Definition: env_spec_w32.h:465
LONGLONG QuadPart
Definition: typedefs.h:112
IN PDCB IN PCCB IN VBO IN OUT PULONG OUT PDIRENT OUT PBCB OUT PVBO ByteOffset
Definition: fatprocs.h:716
struct _REPARSE_DATA_BUFFER::@301::@304 MountPointReparseBuffer
LONG GetRemoteDatabaseSize(IN HANDLE Database)
Definition: database.c:40
#define RTL_CONSTANT_STRING(s)
Definition: tunneltest.c:14
KEVENT UnloadEvent
Definition: mountmgr.c:41
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68