ReactOS  0.4.13-dev-92-gf251225
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  if (DeviceObject->Flags & 1)
628  {
629  _InterlockedExchangeAdd(&ListDeviceInfo->MountState, 1u);
630  }
631 
633 
634  /* Force default: no DB, and need for reconcile */
635  DeviceInformation->NeedsReconcile = TRUE;
636  DeviceInformation->NoDatabase = TRUE;
637  FailedFinding = FALSE;
638 
639  /* Remove any associated device that refers to the DB to reconcile */
640  for (Entry = DeviceExtension->DeviceListHead.Flink;
641  Entry != &DeviceExtension->DeviceListHead;
642  Entry = Entry->Flink)
643  {
644  ListDeviceInfo = CONTAINING_RECORD(Entry, DEVICE_INFORMATION, DeviceListEntry);
645 
646  EntryInfo = ListDeviceInfo->AssociatedDevicesHead.Flink;
647  while (EntryInfo != &ListDeviceInfo->AssociatedDevicesHead)
648  {
649  AssociatedDevice = CONTAINING_RECORD(EntryInfo, ASSOCIATED_DEVICE_ENTRY, AssociatedDevicesEntry);
650  NextEntry = EntryInfo->Flink;
651 
652  if (AssociatedDevice->DeviceInformation == DeviceInformation)
653  {
654  RemoveEntryList(&AssociatedDevice->AssociatedDevicesEntry);
655  FreePool(AssociatedDevice->String.Buffer);
656  FreePool(AssociatedDevice);
657  }
658 
659  EntryInfo = NextEntry;
660  }
661  }
662 
663  /* Open the remote database */
664  DatabaseHandle = OpenRemoteDatabase(DeviceInformation, FALSE);
665 
666  /* Prepare a string with reparse point index */
667  ReparseFile.Length = DeviceInformation->DeviceName.Length + ReparseIndex.Length;
668  ReparseFile.MaximumLength = ReparseFile.Length + sizeof(UNICODE_NULL);
669  ReparseFile.Buffer = AllocatePool(ReparseFile.MaximumLength);
670  if (ReparseFile.Buffer == NULL)
671  {
672  if (DatabaseHandle != 0)
673  {
674  CloseRemoteDatabase(DatabaseHandle);
675  }
676  KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
677  goto ReleaseRDS;
678  }
679 
680 
681  RtlCopyMemory(ReparseFile.Buffer, DeviceInformation->DeviceName.Buffer,
682  DeviceInformation->DeviceName.Length);
683  RtlCopyMemory((PVOID)((ULONG_PTR)ReparseFile.Buffer + DeviceInformation->DeviceName.Length),
684  ReparseFile.Buffer, ReparseFile.Length);
685  ReparseFile.Buffer[ReparseFile.Length / sizeof(WCHAR)] = UNICODE_NULL;
686 
688  &ReparseFile,
690  NULL,
691  NULL);
692 
693  /* Open reparse point directory */
694  HardwareErrors = IoSetThreadHardErrorMode(FALSE);
698  &IoStatusBlock,
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,
728  &IoStatusBlock,
729  &ReparsePointInformation,
732  TRUE,
733  &FileName,
734  FALSE);
735  if (!NT_SUCCESS(Status))
736  {
737  ZwClose(Handle);
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);
786  SymbolicName.Length = 0;
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,
798  &IoStatusBlock,
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! */
849  if (RtlEqualUnicodeString(&DbName, &SymbolicName, TRUE))
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 */
1035  AssociatedDevice = AllocatePool(sizeof(ASSOCIATED_DEVICE_ENTRY));
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 
1126 FreeUniqueId:
1127  FreePool(UniqueId);
1128 ReleaseDeviceLock:
1129  KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
1130 FreeDBEntry:
1131  FreePool(DatabaseEntry);
1132 FreeVolume:
1134 CloseReparse:
1135  ZwClose(Handle);
1136 CloseRDB:
1137  CloseRemoteDatabase(DatabaseHandle);
1138 ReleaseRDS:
1139  ReleaseRemoteDatabaseSemaphore(DeviceExtension);
1140  return;
1141 }
1142 
1143 /*
1144  * @implemented
1145  */
1146 VOID
1147 NTAPI
1149  IN PVOID Context)
1150 {
1151  ULONG i;
1152  KEVENT Event;
1153  KIRQL OldIrql;
1154  NTSTATUS Status;
1155  HANDLE SafeEvent;
1158  PRECONCILE_WORK_ITEM WorkItem;
1159  PDEVICE_EXTENSION DeviceExtension;
1161 
1163 
1165  &SafeVolumes,
1167  NULL,
1168  NULL);
1170  Timeout.LowPart = 0xFFFFFFFF;
1171  Timeout.HighPart = 0xFF676980;
1172 
1173  /* Try to wait as long as possible */
1174  for (i = (Unloading ? 999 : 0); i < 1000; i++)
1175  {
1177  if (NT_SUCCESS(Status))
1178  {
1179  break;
1180  }
1181 
1183  }
1184 
1185  if (i < 1000)
1186  {
1187  do
1188  {
1189  Status = ZwWaitForSingleObject(SafeEvent, FALSE, &Timeout);
1190  }
1191  while (Status == STATUS_TIMEOUT && !Unloading);
1192 
1193  ZwClose(SafeEvent);
1194  }
1195 
1196  DeviceExtension = Context;
1197 
1198  InterlockedExchange(&(DeviceExtension->WorkerThreadStatus), 1);
1199 
1200  /* Acquire workers lock */
1201  KeWaitForSingleObject(&(DeviceExtension->WorkerSemaphore), Executive, KernelMode, FALSE, NULL);
1202 
1203  KeAcquireSpinLock(&(DeviceExtension->WorkerLock), &OldIrql);
1204 
1205  /* Ensure there are workers */
1206  while (!IsListEmpty(&(DeviceExtension->WorkerQueueListHead)))
1207  {
1208  /* Unqueue a worker */
1209  Entry = RemoveHeadList(&(DeviceExtension->WorkerQueueListHead));
1210  WorkItem = CONTAINING_RECORD(Entry,
1212  WorkerQueueListEntry);
1213 
1214  KeReleaseSpinLock(&(DeviceExtension->WorkerLock), OldIrql);
1215 
1216  /* Call it */
1217  WorkItem->WorkerRoutine(WorkItem->Context);
1218 
1219  IoFreeWorkItem(WorkItem->WorkItem);
1220  FreePool(WorkItem);
1221 
1222  if (InterlockedDecrement(&(DeviceExtension->WorkerReferences)) == 0)
1223  {
1224  return;
1225  }
1226 
1227  KeWaitForSingleObject(&(DeviceExtension->WorkerSemaphore), Executive, KernelMode, FALSE, NULL);
1228  KeAcquireSpinLock(&(DeviceExtension->WorkerLock), &OldIrql);
1229  }
1230  KeReleaseSpinLock(&(DeviceExtension->WorkerLock), OldIrql);
1231 
1232  InterlockedDecrement(&(DeviceExtension->WorkerReferences));
1233 
1234  /* Reset event */
1236 }
1237 
1238 /*
1239  * @implemented
1240  */
1241 NTSTATUS
1243  IN PRECONCILE_WORK_ITEM WorkItem,
1244  IN PVOID Context)
1245 {
1246  KIRQL OldIrql;
1247 
1248  WorkItem->Context = Context;
1249 
1250  /* When called, lock is already acquired */
1251 
1252  /* If noone, start to work */
1253  if (InterlockedIncrement(&(DeviceExtension->WorkerReferences)))
1254  {
1255  IoQueueWorkItem(WorkItem->WorkItem, WorkerThread, DelayedWorkQueue, DeviceExtension);
1256  }
1257 
1258  /* Otherwise queue worker for delayed execution */
1259  KeAcquireSpinLock(&(DeviceExtension->WorkerLock), &OldIrql);
1260  InsertTailList(&(DeviceExtension->WorkerQueueListHead),
1261  &(WorkItem->WorkerQueueListEntry));
1262  KeReleaseSpinLock(&(DeviceExtension->WorkerLock), OldIrql);
1263 
1264  KeReleaseSemaphore(&(DeviceExtension->WorkerSemaphore), IO_NO_INCREMENT, 1, FALSE);
1265 
1266  return STATUS_SUCCESS;
1267 }
1268 
1269 /*
1270  * @implemented
1271  */
1272 NTSTATUS
1274  IN PFILE_REPARSE_POINT_INFORMATION ReparsePointInformation,
1278 {
1279  HANDLE Handle;
1280  NTSTATUS Status;
1281  ULONG NeededLength;
1284  PFILE_NAME_INFORMATION FileNameInfo;
1285  PREPARSE_DATA_BUFFER ReparseDataBuffer;
1286 
1287  UNREFERENCED_PARAMETER(ReparsePointInformation);
1288 
1289  if (!FileName)
1290  {
1292  NULL,
1294  RootDirectory,
1295  NULL);
1296  }
1297  else
1298  {
1300  FileName,
1302  NULL,
1303  NULL);
1304  }
1305 
1306  /* Open volume */
1310  &IoStatusBlock,
1314  if (!NT_SUCCESS(Status))
1315  {
1316  return Status;
1317  }
1318 
1319  /* Get the reparse point data */
1320  ReparseDataBuffer = AllocatePool(MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
1321  if (!ReparseDataBuffer)
1322  {
1323  ZwClose(Handle);
1325  }
1326 
1328  0,
1329  NULL,
1330  NULL,
1331  &IoStatusBlock,
1333  NULL,
1334  0,
1335  ReparseDataBuffer,
1337  if (!NT_SUCCESS(Status))
1338  {
1339  FreePool(ReparseDataBuffer);
1340  ZwClose(Handle);
1341  return Status;
1342  }
1343 
1344  /* Check that name can fit in buffer */
1345  if (ReparseDataBuffer->MountPointReparseBuffer.SubstituteNameLength + sizeof(UNICODE_NULL) > SymbolicName->MaximumLength)
1346  {
1347  FreePool(ReparseDataBuffer);
1348  ZwClose(Handle);
1349  return STATUS_BUFFER_TOO_SMALL;
1350  }
1351 
1352  /* Copy symbolic name */
1353  SymbolicName->Length = ReparseDataBuffer->MountPointReparseBuffer.SubstituteNameLength;
1355  (PWSTR)((ULONG_PTR)ReparseDataBuffer->MountPointReparseBuffer.PathBuffer +
1356  ReparseDataBuffer->MountPointReparseBuffer.SubstituteNameOffset),
1357  ReparseDataBuffer->MountPointReparseBuffer.SubstituteNameLength);
1358 
1359  FreePool(ReparseDataBuffer);
1360 
1361  /* Name has to \ terminated */
1362  if (SymbolicName->Buffer[SymbolicName->Length / sizeof(WCHAR) - 1] != L'\\')
1363  {
1364  ZwClose(Handle);
1365  return STATUS_INVALID_PARAMETER;
1366  }
1367 
1368  /* So that we can delete it, and match mountmgr requirements */
1369  SymbolicName->Length -= sizeof(WCHAR);
1371 
1372  /* Also ensure it's really a volume name... */
1374  {
1375  ZwClose(Handle);
1376  return STATUS_INVALID_PARAMETER;
1377  }
1378 
1379  /* Now prepare to really get the name */
1380  FileNameInfo = AllocatePool(sizeof(FILE_NAME_INFORMATION) + 2 * sizeof(WCHAR));
1381  if (!FileNameInfo)
1382  {
1383  ZwClose(Handle);
1385  }
1386 
1387  Status = ZwQueryInformationFile(Handle,
1388  &IoStatusBlock,
1389  FileNameInfo,
1390  sizeof(FILE_NAME_INFORMATION) + 2 * sizeof(WCHAR),
1393  {
1394  /* As expected... Reallocate with proper size */
1395  NeededLength = FileNameInfo->FileNameLength;
1396  FreePool(FileNameInfo);
1397 
1398  FileNameInfo = AllocatePool(sizeof(FILE_NAME_INFORMATION) + NeededLength);
1399  if (!FileNameInfo)
1400  {
1401  ZwClose(Handle);
1403  }
1404 
1405  /* And query name */
1406  Status = ZwQueryInformationFile(Handle,
1407  &IoStatusBlock,
1408  FileNameInfo,
1409  sizeof(FILE_NAME_INFORMATION) + NeededLength,
1411  }
1412 
1413  ZwClose(Handle);
1414 
1415  if (!NT_SUCCESS(Status))
1416  {
1417  return Status;
1418  }
1419 
1420  /* Return the volume name */
1421  VolumeName->Length = (USHORT)FileNameInfo->FileNameLength;
1422  VolumeName->MaximumLength = (USHORT)FileNameInfo->FileNameLength + sizeof(WCHAR);
1424  if (!VolumeName->Buffer)
1425  {
1427  }
1428 
1429  RtlCopyMemory(VolumeName->Buffer, FileNameInfo->FileName, FileNameInfo->FileNameLength);
1430  VolumeName->Buffer[FileNameInfo->FileNameLength / sizeof(WCHAR)] = UNICODE_NULL;
1431 
1432  FreePool(FileNameInfo);
1433 
1434  return STATUS_SUCCESS;
1435 }
1436 
1437 /*
1438  * @implemented
1439  */
1440 VOID
1442  IN PDEVICE_INFORMATION DeviceInformation)
1443 {
1444  HANDLE Handle;
1445  NTSTATUS Status;
1449  PDEVICE_INFORMATION VolumeDeviceInformation;
1450  WCHAR FileNameBuffer[0x8], SymbolicNameBuffer[0x64];
1452  FILE_REPARSE_POINT_INFORMATION ReparsePointInformation, SavedReparsePointInformation;
1453 
1454  /* Removable devices don't have remote database on them */
1455  if (DeviceInformation->Removable)
1456  {
1457  return;
1458  }
1459 
1460  /* Prepare a string with reparse point index */
1461  ReparseFile.Length = DeviceInformation->DeviceName.Length + ReparseIndex.Length;
1462  ReparseFile.MaximumLength = ReparseFile.Length + sizeof(UNICODE_NULL);
1463  ReparseFile.Buffer = AllocatePool(ReparseFile.MaximumLength);
1464  if (!ReparseFile.Buffer)
1465  {
1466  return;
1467  }
1468 
1469  RtlCopyMemory(ReparseFile.Buffer, DeviceInformation->DeviceName.Buffer,
1470  DeviceInformation->DeviceName.Length);
1471  RtlCopyMemory((PVOID)((ULONG_PTR)ReparseFile.Buffer + DeviceInformation->DeviceName.Length),
1472  ReparseFile.Buffer, ReparseFile.Length);
1473  ReparseFile.Buffer[ReparseFile.Length / sizeof(WCHAR)] = UNICODE_NULL;
1474 
1476  &ReparseFile,
1478  NULL,
1479  NULL);
1480 
1481  /* Open reparse point */
1485  &IoStatusBlock,
1488  FreePool(ReparseFile.Buffer);
1489  if (!NT_SUCCESS(Status))
1490  {
1491  DeviceInformation->NoDatabase = FALSE;
1492  return;
1493  }
1494 
1495  /* Query reparse point information
1496  * We only pay attention to mout point
1497  */
1499  FileName.Buffer = FileNameBuffer;
1500  FileName.Length = sizeof(FileNameBuffer);
1501  FileName.MaximumLength = sizeof(FileNameBuffer);
1503  Status = ZwQueryDirectoryFile(Handle,
1504  NULL,
1505  NULL,
1506  NULL,
1507  &IoStatusBlock,
1508  &ReparsePointInformation,
1511  TRUE,
1512  &FileName,
1513  FALSE);
1514  if (!NT_SUCCESS(Status))
1515  {
1516  ZwClose(Handle);
1517  return;
1518  }
1519 
1520  RestartScan = TRUE;
1521 
1522  /* Query mount points */
1523  while (TRUE)
1524  {
1525  SymbolicName.Length = 0;
1526  SymbolicName.MaximumLength = sizeof(SymbolicNameBuffer);
1527  SymbolicName.Buffer = SymbolicNameBuffer;
1528  RtlCopyMemory(&SavedReparsePointInformation, &ReparsePointInformation, sizeof(FILE_REPARSE_POINT_INFORMATION));
1529 
1530  Status = ZwQueryDirectoryFile(Handle,
1531  NULL,
1532  NULL,
1533  NULL,
1534  &IoStatusBlock,
1535  &ReparsePointInformation,
1538  TRUE,
1539  (RestartScan) ? &FileName : NULL,
1540  RestartScan);
1541  if (!RestartScan)
1542  {
1543  if (ReparsePointInformation.FileReference == SavedReparsePointInformation.FileReference &&
1544  ReparsePointInformation.Tag == SavedReparsePointInformation.Tag)
1545  {
1546  break;
1547  }
1548  }
1549  else
1550  {
1551  RestartScan = FALSE;
1552  }
1553 
1554  if (!NT_SUCCESS(Status) || ReparsePointInformation.Tag != IO_REPARSE_TAG_MOUNT_POINT)
1555  {
1556  break;
1557  }
1558 
1559  /* Get the volume name associated to the mount point */
1561  &ReparsePointInformation,
1562  NULL, &SymbolicName,
1563  &VolumeName);
1564  if (!NT_SUCCESS(Status))
1565  {
1566  continue;
1567  }
1568 
1570 
1571  /* Get its information */
1572  Status = FindDeviceInfo(DeviceExtension, &SymbolicName,
1573  FALSE, &VolumeDeviceInformation);
1574  if (!NT_SUCCESS(Status))
1575  {
1576  DeviceInformation->NoDatabase = TRUE;
1577  continue;
1578  }
1579 
1580  /* If notification are enabled, mark it online */
1581  if (!DeviceInformation->SkipNotifications)
1582  {
1583  PostOnlineNotification(DeviceExtension, &VolumeDeviceInformation->SymbolicName);
1584  }
1585  }
1586 
1587  ZwClose(Handle);
1588 }
1589 
1590 /*
1591  * @implemented
1592  */
1593 VOID
1595  IN PDEVICE_INFORMATION DeviceInformation)
1596 {
1597  PRECONCILE_WORK_ITEM WorkItem;
1598 
1599  /* Removable devices don't have remote database */
1600  if (DeviceInformation->Removable)
1601  {
1602  return;
1603  }
1604 
1605  /* Allocate a work item */
1606  WorkItem = AllocatePool(sizeof(RECONCILE_WORK_ITEM));
1607  if (!WorkItem)
1608  {
1609  return;
1610  }
1611 
1612  WorkItem->WorkItem = IoAllocateWorkItem(DeviceExtension->DeviceObject);
1613  if (!WorkItem->WorkItem)
1614  {
1615  FreePool(WorkItem);
1616  return;
1617  }
1618 
1619  /* And queue it */
1621  WorkItem->DeviceExtension = DeviceExtension;
1622  WorkItem->DeviceInformation = DeviceInformation;
1623  QueueWorkItem(DeviceExtension, WorkItem, &(WorkItem->DeviceExtension));
1624 
1625  /* If there's no automount, and automatic letters
1626  * all volumes to find those online and notify there presence
1627  */
1628  if (DeviceExtension->WorkerThreadStatus == 0 &&
1629  DeviceExtension->AutomaticDriveLetter == 1 &&
1630  DeviceExtension->NoAutoMount == FALSE)
1631  {
1632  OnlineMountedVolumes(DeviceExtension, DeviceInformation);
1633  }
1634 }
1635 
1636 /*
1637  * @implemented
1638  */
1639 VOID
1641 {
1642  PLIST_ENTRY NextEntry;
1643  PDEVICE_INFORMATION DeviceInformation;
1644 
1645  /* Browse all the devices */
1646  for (NextEntry = DeviceExtension->DeviceListHead.Flink;
1647  NextEntry != &(DeviceExtension->DeviceListHead);
1648  NextEntry = NextEntry->Flink)
1649  {
1650  DeviceInformation = CONTAINING_RECORD(NextEntry,
1652  DeviceListEntry);
1653  /* If it's not removable, then, it might have a database to sync */
1654  if (!DeviceInformation->Removable)
1655  {
1656  ReconcileThisDatabaseWithMaster(DeviceExtension, DeviceInformation);
1657  }
1658  }
1659 }
1660 
1661 /*
1662  * @implemented
1663  */
1664 VOID
1665 NTAPI
1667  IN PVOID Context)
1668 {
1669  NTSTATUS Status;
1670  HANDLE Database = 0;
1671  UNICODE_STRING DatabaseName;
1672  PMIGRATE_WORK_ITEM WorkItem;
1675  PDEVICE_INFORMATION DeviceInformation;
1676 
1678 
1679  /* Extract context */
1680  WorkItem = Context;
1681  DeviceInformation = WorkItem->DeviceInformation;
1682 
1683  /* Reconstruct appropriate string */
1684  DatabaseName.Length = DeviceInformation->DeviceName.Length + RemoteDatabase.Length;
1685  DatabaseName.MaximumLength = DatabaseName.Length + sizeof(WCHAR);
1686  DatabaseName.Buffer = AllocatePool(DatabaseName.MaximumLength);
1687  if (DatabaseName.Buffer == NULL)
1688  {
1690  goto Cleanup;
1691  }
1692 
1693  /* Create the required folder (in which the database will be stored
1694  * \System Volume Information at root of the volume
1695  */
1696  Status = RtlCreateSystemVolumeInformationFolder(&(DeviceInformation->DeviceName));
1697  if (!NT_SUCCESS(Status))
1698  {
1699  goto Cleanup;
1700  }
1701 
1702  /* Finish initiating strings */
1703  RtlCopyMemory(DatabaseName.Buffer, DeviceInformation->DeviceName.Buffer, DeviceInformation->DeviceName.Length);
1704  RtlCopyMemory(DatabaseName.Buffer + (DeviceInformation->DeviceName.Length / sizeof(WCHAR)),
1706  DatabaseName.Buffer[DatabaseName.Length / sizeof(WCHAR)] = UNICODE_NULL;
1707 
1708  /* Create database */
1710  &DatabaseName,
1712  NULL,
1713  NULL);
1714 
1720  &IoStatusBlock,
1721  NULL,
1723  0,
1724  FILE_CREATE,
1726  NULL,
1727  0,
1729  NULL,
1731  if (!NT_SUCCESS(Status))
1732  {
1734  {
1735  DPRINT1("Attempt to exploit CVE-2015-1769. See CORE-10216\n");
1736  }
1737 
1738  Database = 0;
1739  goto Cleanup;
1740  }
1741 
1742 Cleanup:
1743  if (DatabaseName.Buffer)
1744  {
1745  FreePool(DatabaseName.Buffer);
1746  }
1747 
1748  if (NT_SUCCESS(Status))
1749  {
1750  DeviceInformation->Migrated = 1;
1751  }
1752  else if (Database != 0)
1753  {
1754  ZwClose(Database);
1755  }
1756 
1757  IoFreeWorkItem(WorkItem->WorkItem);
1758 
1759  WorkItem->WorkItem = NULL;
1760  WorkItem->Status = Status;
1761  WorkItem->Database = Database;
1762 
1763  KeSetEvent(WorkItem->Event, 0, FALSE);
1764 }
1765 
1766 /*
1767  * @implemented
1768  */
1769 NTSTATUS
1772 {
1773  KEVENT Event;
1774  NTSTATUS Status;
1775  PMIGRATE_WORK_ITEM WorkItem;
1776 
1778 
1779  /* Allocate a work item dedicated to migration */
1780  WorkItem = AllocatePool(sizeof(MIGRATE_WORK_ITEM));
1781  if (!WorkItem)
1782  {
1783  *Database = 0;
1785  }
1786 
1787  RtlZeroMemory(WorkItem, sizeof(MIGRATE_WORK_ITEM));
1788  WorkItem->Event = &Event;
1789  WorkItem->DeviceInformation = DeviceInformation;
1790  WorkItem->WorkItem = IoAllocateWorkItem(DeviceInformation->DeviceExtension->DeviceObject);
1791  if (!WorkItem->WorkItem)
1792  {
1793  FreePool(WorkItem);
1794  *Database = 0;
1796  }
1797 
1798  /* And queue it */
1799  IoQueueWorkItem(WorkItem->WorkItem,
1802  WorkItem);
1803 
1805  Status = WorkItem->Status;
1806 
1807  *Database = (NT_SUCCESS(Status) ? WorkItem->Database : 0);
1808 
1809  FreePool(WorkItem);
1810  return Status;
1811 }
1812 
1813 /*
1814  * @implemented
1815  */
1816 HANDLE
1818  IN BOOLEAN MigrateDatabase)
1819 {
1820  HANDLE Database;
1821  NTSTATUS Status;
1825  UNICODE_STRING DeviceRemoteDatabase;
1826 
1827  Database = 0;
1828 
1829  /* Get database name */
1830  DeviceRemoteDatabase.Length = DeviceInformation->DeviceName.Length + RemoteDatabase.Length;
1831  DeviceRemoteDatabase.MaximumLength = DeviceRemoteDatabase.Length + sizeof(WCHAR);
1832  DeviceRemoteDatabase.Buffer = AllocatePool(DeviceRemoteDatabase.MaximumLength);
1833  if (!DeviceRemoteDatabase.Buffer)
1834  {
1835  return 0;
1836  }
1837 
1838  RtlCopyMemory(DeviceRemoteDatabase.Buffer, DeviceInformation->DeviceName.Buffer, DeviceInformation->DeviceName.Length);
1839  RtlCopyMemory(DeviceRemoteDatabase.Buffer + (DeviceInformation->DeviceName.Length / sizeof(WCHAR)),
1841  DeviceRemoteDatabase.Buffer[DeviceRemoteDatabase.Length / sizeof(WCHAR)] = UNICODE_NULL;
1842 
1843  /* Open database */
1845  &DeviceRemoteDatabase,
1847  NULL,
1848  NULL);
1849 
1850  /* Disable hard errors */
1852 
1858  &IoStatusBlock,
1859  NULL,
1861  0,
1862  (!MigrateDatabase || DeviceInformation->Migrated == 0) ? FILE_OPEN_IF : FILE_OPEN,
1864  NULL,
1865  0,
1867  NULL,
1870  {
1871  DPRINT1("Attempt to exploit CVE-2015-1769. See CORE-10216\n");
1872  }
1873 
1874  /* If base it to be migrated and was opened successfully, go ahead */
1875  if (MigrateDatabase && NT_SUCCESS(Status))
1876  {
1877  CreateRemoteDatabase(DeviceInformation, &Database);
1878  }
1879 
1881  FreePool(DeviceRemoteDatabase.Buffer);
1882 
1883  return Database;
1884 }
1885 
1886 /*
1887  * @implemented
1888  */
1889 VOID
1891  IN PMOUNTDEV_UNIQUE_ID OldUniqueId,
1892  IN PMOUNTDEV_UNIQUE_ID NewUniqueId)
1893 {
1894  LONG Offset = 0;
1895  HANDLE Database;
1896  PDATABASE_ENTRY Entry, NewEntry;
1898 
1899  /* Open the remote database */
1900  Database = OpenRemoteDatabase(DeviceInformation, FALSE);
1901  if (!Database)
1902  {
1903  return;
1904  }
1905 
1906  /* Get all the entries */
1907  do
1908  {
1910  if (!Entry)
1911  {
1912  break;
1913  }
1914 
1915  /* Not the correct entry, skip it */
1916  if (Entry->UniqueIdLength != OldUniqueId->UniqueIdLength)
1917  {
1918  Offset += Entry->EntrySize;
1919  FreePool(Entry);
1920  continue;
1921  }
1922 
1923  /* Not the correct entry, skip it */
1924  if (RtlCompareMemory(OldUniqueId->UniqueId,
1925  (PVOID)((ULONG_PTR)Entry + Entry->UniqueIdOffset),
1926  Entry->UniqueIdLength) != Entry->UniqueIdLength)
1927  {
1928  Offset += Entry->EntrySize;
1929  FreePool(Entry);
1930  continue;
1931  }
1932 
1933  /* Here, we have the correct entry */
1934  NewEntry = AllocatePool(Entry->EntrySize + NewUniqueId->UniqueIdLength - OldUniqueId->UniqueIdLength);
1935  if (!NewEntry)
1936  {
1937  Offset += Entry->EntrySize;
1938  FreePool(Entry);
1939  continue;
1940  }
1941 
1942  /* Recreate the entry from the previous one */
1943  NewEntry->EntrySize = Entry->EntrySize + NewUniqueId->UniqueIdLength - OldUniqueId->UniqueIdLength;
1944  NewEntry->EntryReferences = Entry->EntryReferences;
1945  NewEntry->SymbolicNameOffset = sizeof(DATABASE_ENTRY);
1946  NewEntry->SymbolicNameLength = Entry->SymbolicNameLength;
1947  NewEntry->UniqueIdOffset = Entry->SymbolicNameLength + sizeof(DATABASE_ENTRY);
1948  NewEntry->UniqueIdLength = NewUniqueId->UniqueIdLength;
1949  RtlCopyMemory((PVOID)((ULONG_PTR)NewEntry + NewEntry->SymbolicNameOffset),
1950  (PVOID)((ULONG_PTR)Entry + Entry->SymbolicNameOffset),
1951  NewEntry->SymbolicNameLength);
1952  RtlCopyMemory((PVOID)((ULONG_PTR)NewEntry + NewEntry->UniqueIdOffset),
1953  NewUniqueId->UniqueId, NewEntry->UniqueIdLength);
1954 
1955  /* Delete old entry */
1957  if (!NT_SUCCESS(Status))
1958  {
1959  FreePool(Entry);
1960  FreePool(NewEntry);
1961  break;
1962  }
1963 
1964  /* And replace with new one */
1965  Status = AddRemoteDatabaseEntry(Database, NewEntry);
1966  FreePool(Entry);
1967  FreePool(NewEntry);
1968  } while (NT_SUCCESS(Status));
1969 
1971 
1972  return;
1973 }
1974 
1975 /*
1976  * @implemented
1977  */
1978 NTSTATUS
1979 NTAPI
1981  IN ULONG ValueType,
1982  IN PVOID ValueData,
1984  IN PVOID Context,
1986 {
1987  PMOUNTDEV_UNIQUE_ID UniqueId;
1988  UNICODE_STRING RegistryEntry;
1989 
1991 
1992  if (ValueType != REG_BINARY)
1993  {
1994  return STATUS_SUCCESS;
1995  }
1996 
1997  UniqueId = Context;
1998 
1999  /* First ensure we have the correct data */
2000  if (UniqueId->UniqueIdLength != ValueLength)
2001  {
2002  return STATUS_SUCCESS;
2003  }
2004 
2006  {
2007  return STATUS_SUCCESS;
2008  }
2009 
2010  RtlInitUnicodeString(&RegistryEntry, ValueName);
2011 
2012  /* Then, it's a drive letter, erase it */
2013  if (IsDriveLetter(&RegistryEntry))
2014  {
2016  DatabasePath,
2017  ValueName);
2018  }
2019 
2020  return STATUS_SUCCESS;
2021 }
2022 
2023 /*
2024  * @implemented
2025  */
2026 VOID
2028 {
2030 
2033 
2035  DatabasePath,
2036  QueryTable,
2037  UniqueId,
2038  NULL);
2039 }
2040 
2041 /*
2042  * @implemented
2043  */
2044 NTSTATUS
2045 NTAPI
2047  IN ULONG ValueType,
2048  IN PVOID ValueData,
2050  IN PVOID Context,
2052 {
2053  PMOUNTDEV_UNIQUE_ID UniqueId = Context;
2054 
2056 
2057  /* Ensure we have correct input */
2058  if (ValueName[0] != L'#' || ValueType != REG_BINARY ||
2059  UniqueId->UniqueIdLength != ValueLength)
2060  {
2061  return STATUS_SUCCESS;
2062  }
2063 
2064  /* And then, if unique ID matching, delete entry */
2066  {
2068  DatabasePath,
2069  ValueName);
2070  }
2071 
2072  return STATUS_SUCCESS;
2073 }
2074 
2075 /*
2076  * @implemented
2077  */
2078 VOID
2080 {
2082 
2085 
2087  DatabasePath,
2088  QueryTable,
2089  UniqueId,
2090  NULL);
2091 }
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 * u
Definition: glfuncs.h:240
#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:2027
#define FILE_WRITE_EA
Definition: nt_native.h:640
_In_ PCWSTR _Inout_ _At_ QueryTable _Pre_unknown_ PRTL_QUERY_REGISTRY_TABLE QueryTable
Definition: rtlfuncs.h:3988
#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:1242
#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:4000
_In_ PNDIS_STRING _In_ PNDIS_STRING SymbolicName
Definition: ndis.h:4658
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:924
struct _REPARSE_DATA_BUFFER::@300::@303 MountPointReparseBuffer
UNICODE_STRING RemoteDatabase
Definition: database.c:34
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:1434
VOID NTAPI CreateRemoteDatabaseWorker(IN PDEVICE_OBJECT DeviceObject, IN PVOID Context)
Definition: database.c:1666
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:240
#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:2079
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:1441
#define STATUS_BUFFER_TOO_SMALL
Definition: shellext.h:64
#define IO_STOP_ON_SYMLINK
Definition: iotypes.h:6996
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:6874
#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:1594
HANDLE OpenRemoteDatabase(IN PDEVICE_INFORMATION DeviceInformation, IN BOOLEAN MigrateDatabase)
Definition: database.c:1817
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:508
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:434
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:3988
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:651
void * PVOID
Definition: retypes.h:9
_Inout_ PFILE_OBJECT FileObject
Definition: cdprocs.h:593
UNICODE_STRING ReparseIndex
Definition: symlink.c:40
#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:1890
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:1148
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:1954
#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:1980
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:1273
#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:1770
#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:1012
unsigned int ULONG
Definition: retypes.h:1
#define IO_NO_INCREMENT
Definition: iotypes.h:565
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:2046
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:1640
return STATUS_SUCCESS
Definition: btrfs.c:2725
#define MAXIMUM_REPARSE_DATA_BUFFER_SIZE
Definition: iotypes.h:6856
PMOUNTDEV_UNIQUE_ID UniqueId
Definition: mntmgr.h:49
PWORKER_THREAD_ROUTINE WorkerRoutine
Definition: mntmgr.h:125
#define OBJ_KERNEL_HANDLE
Definition: winternl.h:231
long __cdecl _InterlockedExchangeAdd(_Interlocked_operand_ long volatile *_Addend, long _Value)
#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
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