ReactOS  0.4.15-dev-3324-gda4e15f
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 {
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;
574  BOOLEAN HardwareErrors, Restart, FailedFinding;
575  WCHAR FileNameBuffer[0x8], SymbolicNameBuffer[100];
577  FILE_REPARSE_POINT_INFORMATION ReparsePointInformation, SavedReparsePointInformation;
578  PDEVICE_EXTENSION DeviceExtension = ((PRECONCILE_WORK_ITEM_CONTEXT)Parameter)->DeviceExtension;
579  PDEVICE_INFORMATION DeviceInformation = ((PRECONCILE_WORK_ITEM_CONTEXT)Parameter)->DeviceInformation;
580 
581  /* We're unloading, do nothing */
582  if (Unloading)
583  {
584  return;
585  }
586 
587  /* Lock remote DB */
588  if (!NT_SUCCESS(WaitForRemoteDatabaseSemaphore(DeviceExtension)))
589  {
590  return;
591  }
592 
593  /* Recheck for unloading */
594  if (Unloading)
595  {
596  goto ReleaseRDS;
597  }
598 
599  /* Find the DB to reconcile */
600  KeWaitForSingleObject(&DeviceExtension->DeviceLock, Executive, KernelMode, FALSE, NULL);
601  for (Entry = DeviceExtension->DeviceListHead.Flink;
602  Entry != &DeviceExtension->DeviceListHead;
603  Entry = Entry->Flink)
604  {
605  ListDeviceInfo = CONTAINING_RECORD(Entry, DEVICE_INFORMATION, DeviceListEntry);
606  if (ListDeviceInfo == DeviceInformation)
607  {
608  break;
609  }
610  }
611 
612  /* If not found, or if removable, bail out */
613  if (Entry == &DeviceExtension->DeviceListHead || DeviceInformation->Removable)
614  {
615  KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
616  goto ReleaseRDS;
617  }
618 
619  /* Get our device object */
621  if (!NT_SUCCESS(Status))
622  {
623  KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
624  goto ReleaseRDS;
625  }
626 
627  /* Mark mounted only if not unloading */
628  if (!(DeviceObject->Flags & DO_UNLOAD_PENDING))
629  {
630  InterlockedExchangeAdd(&ListDeviceInfo->MountState, 1);
631  }
632 
634 
635  /* Force default: no DB, and need for reconcile */
636  DeviceInformation->NeedsReconcile = TRUE;
637  DeviceInformation->NoDatabase = TRUE;
638  FailedFinding = FALSE;
639 
640  /* Remove any associated device that refers to the DB to reconcile */
641  for (Entry = DeviceExtension->DeviceListHead.Flink;
642  Entry != &DeviceExtension->DeviceListHead;
643  Entry = Entry->Flink)
644  {
645  ListDeviceInfo = CONTAINING_RECORD(Entry, DEVICE_INFORMATION, DeviceListEntry);
646 
647  EntryInfo = ListDeviceInfo->AssociatedDevicesHead.Flink;
648  while (EntryInfo != &ListDeviceInfo->AssociatedDevicesHead)
649  {
650  AssociatedDevice = CONTAINING_RECORD(EntryInfo, ASSOCIATED_DEVICE_ENTRY, AssociatedDevicesEntry);
651  NextEntry = EntryInfo->Flink;
652 
653  if (AssociatedDevice->DeviceInformation == DeviceInformation)
654  {
655  RemoveEntryList(&AssociatedDevice->AssociatedDevicesEntry);
656  FreePool(AssociatedDevice->String.Buffer);
658  }
659 
660  EntryInfo = NextEntry;
661  }
662  }
663 
664  /* Open the remote database */
665  DatabaseHandle = OpenRemoteDatabase(DeviceInformation, FALSE);
666 
667  /* Prepare a string with reparse point index */
668  ReparseFile.Length = 0;
669  ReparseFile.MaximumLength = DeviceInformation->DeviceName.Length
671  + sizeof(UNICODE_NULL);
672  ReparseFile.Buffer = AllocatePool(ReparseFile.MaximumLength);
673  if (!ReparseFile.Buffer)
674  {
675  if (DatabaseHandle != 0)
676  {
677  CloseRemoteDatabase(DatabaseHandle);
678  }
679  KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
680  goto ReleaseRDS;
681  }
682 
683  RtlAppendUnicodeStringToString(&ReparseFile, &DeviceInformation->DeviceName);
685  ReparseFile.Buffer[ReparseFile.Length / sizeof(WCHAR)] = UNICODE_NULL;
686 
688  &ReparseFile,
690  NULL,
691  NULL);
692 
693  /* Open reparse point directory */
694  HardwareErrors = IoSetThreadHardErrorMode(FALSE);
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 */
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;
1159  PDEVICE_EXTENSION DeviceExtension;
1161 
1163 
1165  &SafeVolumes,
1167  NULL,
1168  NULL);
1170  Timeout.QuadPart = -10000000LL; /* Wait for 1 second */
1171 
1172  /* Wait as long as possible for clearance from autochk
1173  * We will write remote databases only if it is safe
1174  * to access volumes.
1175  * First, given we start before SMSS, wait for the
1176  * event creation.
1177  */
1178  i = 0;
1179  do
1180  {
1181  /* If we started to shutdown, stop waiting forever and jump to last attempt */
1182  if (Unloading)
1183  {
1184  i = 999;
1185  }
1186  else
1187  {
1188  /* Attempt to open the event */
1190  if (NT_SUCCESS(Status))
1191  {
1192  break;
1193  }
1194 
1195  /* Wait a bit to give SMSS a chance to create the event */
1197  }
1198 
1199  ++i;
1200  }
1201  while (i < 1000);
1202 
1203  /* We managed to open the event, wait until autochk signals it */
1204  if (i < 1000)
1205  {
1206  do
1207  {
1208  Status = ZwWaitForSingleObject(SafeEvent, FALSE, &Timeout);
1209  }
1210  while (Status == STATUS_TIMEOUT && !Unloading);
1211 
1212  ZwClose(SafeEvent);
1213  }
1214 
1215  DeviceExtension = Context;
1216 
1217  InterlockedExchange(&(DeviceExtension->WorkerThreadStatus), 1);
1218 
1219  /* Acquire workers lock */
1220  KeWaitForSingleObject(&(DeviceExtension->WorkerSemaphore), Executive, KernelMode, FALSE, NULL);
1221 
1222  KeAcquireSpinLock(&(DeviceExtension->WorkerLock), &OldIrql);
1223 
1224  /* Ensure there are workers */
1225  while (!IsListEmpty(&(DeviceExtension->WorkerQueueListHead)))
1226  {
1227  /* Unqueue a worker */
1228  Entry = RemoveHeadList(&(DeviceExtension->WorkerQueueListHead));
1231  WorkerQueueListEntry);
1232 
1233  KeReleaseSpinLock(&(DeviceExtension->WorkerLock), OldIrql);
1234 
1235  /* Call it */
1236  WorkItem->WorkerRoutine(WorkItem->Context);
1237 
1238  IoFreeWorkItem(WorkItem->WorkItem);
1239  FreePool(WorkItem);
1240 
1241  if (InterlockedDecrement(&(DeviceExtension->WorkerReferences)) < 0)
1242  {
1243  return;
1244  }
1245 
1246  KeWaitForSingleObject(&(DeviceExtension->WorkerSemaphore), Executive, KernelMode, FALSE, NULL);
1247  KeAcquireSpinLock(&(DeviceExtension->WorkerLock), &OldIrql);
1248  }
1249  KeReleaseSpinLock(&(DeviceExtension->WorkerLock), OldIrql);
1250 
1251  InterlockedDecrement(&(DeviceExtension->WorkerReferences));
1252 
1253  /* Reset event */
1255 }
1256 
1257 /*
1258  * @implemented
1259  */
1260 NTSTATUS
1263  IN PVOID Context)
1264 {
1265  KIRQL OldIrql;
1266 
1267  WorkItem->Context = Context;
1268 
1269  /* When called, lock is already acquired */
1270 
1271  /* If noone (-1 as references), start to work */
1272  if (InterlockedIncrement(&(DeviceExtension->WorkerReferences)) == 0)
1273  {
1274  IoQueueWorkItem(WorkItem->WorkItem, WorkerThread, DelayedWorkQueue, DeviceExtension);
1275  }
1276 
1277  /* Otherwise queue worker for delayed execution */
1278  KeAcquireSpinLock(&(DeviceExtension->WorkerLock), &OldIrql);
1279  InsertTailList(&(DeviceExtension->WorkerQueueListHead),
1280  &(WorkItem->WorkerQueueListEntry));
1281  KeReleaseSpinLock(&(DeviceExtension->WorkerLock), OldIrql);
1282 
1283  KeReleaseSemaphore(&(DeviceExtension->WorkerSemaphore), IO_NO_INCREMENT, 1, FALSE);
1284 
1285  return STATUS_SUCCESS;
1286 }
1287 
1288 /*
1289  * @implemented
1290  */
1291 NTSTATUS
1293  IN PFILE_REPARSE_POINT_INFORMATION ReparsePointInformation,
1297 {
1298  HANDLE Handle;
1299  NTSTATUS Status;
1300  ULONG NeededLength;
1303  PFILE_NAME_INFORMATION FileNameInfo;
1304  PREPARSE_DATA_BUFFER ReparseDataBuffer;
1305 
1306  UNREFERENCED_PARAMETER(ReparsePointInformation);
1307 
1308  if (!FileName)
1309  {
1311  NULL,
1313  RootDirectory,
1314  NULL);
1315  }
1316  else
1317  {
1319  FileName,
1321  NULL,
1322  NULL);
1323  }
1324 
1325  /* Open volume */
1329  &IoStatusBlock,
1333  if (!NT_SUCCESS(Status))
1334  {
1335  return Status;
1336  }
1337 
1338  /* Get the reparse point data */
1339  ReparseDataBuffer = AllocatePool(MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
1340  if (!ReparseDataBuffer)
1341  {
1342  ZwClose(Handle);
1344  }
1345 
1347  0,
1348  NULL,
1349  NULL,
1350  &IoStatusBlock,
1352  NULL,
1353  0,
1354  ReparseDataBuffer,
1356  if (!NT_SUCCESS(Status))
1357  {
1358  FreePool(ReparseDataBuffer);
1359  ZwClose(Handle);
1360  return Status;
1361  }
1362 
1363  /* Check that name can fit in buffer */
1364  if (ReparseDataBuffer->MountPointReparseBuffer.SubstituteNameLength + sizeof(UNICODE_NULL) > SymbolicName->MaximumLength)
1365  {
1366  FreePool(ReparseDataBuffer);
1367  ZwClose(Handle);
1368  return STATUS_BUFFER_TOO_SMALL;
1369  }
1370 
1371  /* Copy symbolic name */
1372  SymbolicName->Length = ReparseDataBuffer->MountPointReparseBuffer.SubstituteNameLength;
1374  (PWSTR)((ULONG_PTR)ReparseDataBuffer->MountPointReparseBuffer.PathBuffer +
1375  ReparseDataBuffer->MountPointReparseBuffer.SubstituteNameOffset),
1376  ReparseDataBuffer->MountPointReparseBuffer.SubstituteNameLength);
1377 
1378  FreePool(ReparseDataBuffer);
1379 
1380  /* Name has to \ terminated */
1381  if (SymbolicName->Buffer[SymbolicName->Length / sizeof(WCHAR) - 1] != L'\\')
1382  {
1383  ZwClose(Handle);
1384  return STATUS_INVALID_PARAMETER;
1385  }
1386 
1387  /* So that we can delete it, and match mountmgr requirements */
1388  SymbolicName->Length -= sizeof(WCHAR);
1390 
1391  /* Also ensure it's really a volume name... */
1393  {
1394  ZwClose(Handle);
1395  return STATUS_INVALID_PARAMETER;
1396  }
1397 
1398  /* Now prepare to really get the name */
1399  FileNameInfo = AllocatePool(sizeof(FILE_NAME_INFORMATION) + 2 * sizeof(WCHAR));
1400  if (!FileNameInfo)
1401  {
1402  ZwClose(Handle);
1404  }
1405 
1406  Status = ZwQueryInformationFile(Handle,
1407  &IoStatusBlock,
1408  FileNameInfo,
1409  sizeof(FILE_NAME_INFORMATION) + 2 * sizeof(WCHAR),
1412  {
1413  /* As expected... Reallocate with proper size */
1414  NeededLength = FileNameInfo->FileNameLength;
1415  FreePool(FileNameInfo);
1416 
1417  FileNameInfo = AllocatePool(sizeof(FILE_NAME_INFORMATION) + NeededLength);
1418  if (!FileNameInfo)
1419  {
1420  ZwClose(Handle);
1422  }
1423 
1424  /* And query name */
1425  Status = ZwQueryInformationFile(Handle,
1426  &IoStatusBlock,
1427  FileNameInfo,
1428  sizeof(FILE_NAME_INFORMATION) + NeededLength,
1430  }
1431 
1432  ZwClose(Handle);
1433 
1434  if (!NT_SUCCESS(Status))
1435  {
1436  return Status;
1437  }
1438 
1439  /* Return the volume name */
1440  VolumeName->Length = (USHORT)FileNameInfo->FileNameLength;
1441  VolumeName->MaximumLength = (USHORT)FileNameInfo->FileNameLength + sizeof(WCHAR);
1443  if (!VolumeName->Buffer)
1444  {
1446  }
1447 
1448  RtlCopyMemory(VolumeName->Buffer, FileNameInfo->FileName, FileNameInfo->FileNameLength);
1449  VolumeName->Buffer[FileNameInfo->FileNameLength / sizeof(WCHAR)] = UNICODE_NULL;
1450 
1451  FreePool(FileNameInfo);
1452 
1453  return STATUS_SUCCESS;
1454 }
1455 
1456 /*
1457  * @implemented
1458  */
1459 VOID
1461  IN PDEVICE_INFORMATION DeviceInformation)
1462 {
1463  HANDLE Handle;
1464  NTSTATUS Status;
1468  PDEVICE_INFORMATION VolumeDeviceInformation;
1469  WCHAR FileNameBuffer[0x8], SymbolicNameBuffer[0x64];
1471  FILE_REPARSE_POINT_INFORMATION ReparsePointInformation, SavedReparsePointInformation;
1472 
1473  /* Removable devices don't have remote database on them */
1474  if (DeviceInformation->Removable)
1475  {
1476  return;
1477  }
1478 
1479  /* Prepare a string with reparse point index */
1480  ReparseFile.Length = 0;
1481  ReparseFile.MaximumLength = DeviceInformation->DeviceName.Length
1483  + sizeof(UNICODE_NULL);
1484  ReparseFile.Buffer = AllocatePool(ReparseFile.MaximumLength);
1485  if (!ReparseFile.Buffer)
1486  {
1487  return;
1488  }
1489 
1490  RtlAppendUnicodeStringToString(&ReparseFile, &DeviceInformation->DeviceName);
1492  ReparseFile.Buffer[ReparseFile.Length / sizeof(WCHAR)] = UNICODE_NULL;
1493 
1495  &ReparseFile,
1497  NULL,
1498  NULL);
1499 
1500  /* Open reparse point */
1504  &IoStatusBlock,
1507  FreePool(ReparseFile.Buffer);
1508  if (!NT_SUCCESS(Status))
1509  {
1510  DeviceInformation->NoDatabase = FALSE;
1511  return;
1512  }
1513 
1514  /* Query reparse point information
1515  * We only pay attention to mout point
1516  */
1518  FileName.Buffer = FileNameBuffer;
1519  FileName.Length = sizeof(FileNameBuffer);
1520  FileName.MaximumLength = sizeof(FileNameBuffer);
1522  Status = ZwQueryDirectoryFile(Handle,
1523  NULL,
1524  NULL,
1525  NULL,
1526  &IoStatusBlock,
1527  &ReparsePointInformation,
1530  TRUE,
1531  &FileName,
1532  FALSE);
1533  if (!NT_SUCCESS(Status))
1534  {
1535  ZwClose(Handle);
1536  return;
1537  }
1538 
1539  RestartScan = TRUE;
1540 
1541  /* Query mount points */
1542  while (TRUE)
1543  {
1544  SymbolicName.Length = 0;
1545  SymbolicName.MaximumLength = sizeof(SymbolicNameBuffer);
1546  SymbolicName.Buffer = SymbolicNameBuffer;
1547  RtlCopyMemory(&SavedReparsePointInformation, &ReparsePointInformation, sizeof(FILE_REPARSE_POINT_INFORMATION));
1548 
1549  Status = ZwQueryDirectoryFile(Handle,
1550  NULL,
1551  NULL,
1552  NULL,
1553  &IoStatusBlock,
1554  &ReparsePointInformation,
1557  TRUE,
1558  (RestartScan) ? &FileName : NULL,
1559  RestartScan);
1560  if (!RestartScan)
1561  {
1562  if (ReparsePointInformation.FileReference == SavedReparsePointInformation.FileReference &&
1563  ReparsePointInformation.Tag == SavedReparsePointInformation.Tag)
1564  {
1565  break;
1566  }
1567  }
1568  else
1569  {
1570  RestartScan = FALSE;
1571  }
1572 
1573  if (!NT_SUCCESS(Status) || ReparsePointInformation.Tag != IO_REPARSE_TAG_MOUNT_POINT)
1574  {
1575  break;
1576  }
1577 
1578  /* Get the volume name associated to the mount point */
1580  &ReparsePointInformation,
1581  NULL, &SymbolicName,
1582  &VolumeName);
1583  if (!NT_SUCCESS(Status))
1584  {
1585  continue;
1586  }
1587 
1589 
1590  /* Get its information */
1591  Status = FindDeviceInfo(DeviceExtension, &SymbolicName,
1592  FALSE, &VolumeDeviceInformation);
1593  if (!NT_SUCCESS(Status))
1594  {
1595  DeviceInformation->NoDatabase = TRUE;
1596  continue;
1597  }
1598 
1599  /* If notification are enabled, mark it online */
1600  if (!DeviceInformation->SkipNotifications)
1601  {
1602  PostOnlineNotification(DeviceExtension, &VolumeDeviceInformation->SymbolicName);
1603  }
1604  }
1605 
1606  ZwClose(Handle);
1607 }
1608 
1609 /*
1610  * @implemented
1611  */
1612 VOID
1614  IN PDEVICE_INFORMATION DeviceInformation)
1615 {
1617 
1618  /* Removable devices don't have remote database */
1619  if (DeviceInformation->Removable)
1620  {
1621  return;
1622  }
1623 
1624  /* Allocate a work item */
1626  if (!WorkItem)
1627  {
1628  return;
1629  }
1630 
1631  WorkItem->WorkItem = IoAllocateWorkItem(DeviceExtension->DeviceObject);
1632  if (!WorkItem->WorkItem)
1633  {
1634  FreePool(WorkItem);
1635  return;
1636  }
1637 
1638  /* And queue it */
1640  WorkItem->DeviceExtension = DeviceExtension;
1641  WorkItem->DeviceInformation = DeviceInformation;
1642  QueueWorkItem(DeviceExtension, WorkItem, &(WorkItem->DeviceExtension));
1643 
1644  /* If there's no automount, and automatic letters
1645  * all volumes to find those online and notify there presence
1646  */
1647  if (DeviceExtension->WorkerThreadStatus == 0 &&
1648  DeviceExtension->AutomaticDriveLetter == 1 &&
1649  DeviceExtension->NoAutoMount == FALSE)
1650  {
1651  OnlineMountedVolumes(DeviceExtension, DeviceInformation);
1652  }
1653 }
1654 
1655 /*
1656  * @implemented
1657  */
1658 VOID
1660 {
1661  PLIST_ENTRY NextEntry;
1662  PDEVICE_INFORMATION DeviceInformation;
1663 
1664  /* Browse all the devices */
1665  for (NextEntry = DeviceExtension->DeviceListHead.Flink;
1666  NextEntry != &(DeviceExtension->DeviceListHead);
1667  NextEntry = NextEntry->Flink)
1668  {
1669  DeviceInformation = CONTAINING_RECORD(NextEntry,
1671  DeviceListEntry);
1672  /* If it's not removable, then, it might have a database to sync */
1673  if (!DeviceInformation->Removable)
1674  {
1675  ReconcileThisDatabaseWithMaster(DeviceExtension, DeviceInformation);
1676  }
1677  }
1678 }
1679 
1680 /*
1681  * @implemented
1682  */
1683 VOID
1684 NTAPI
1686  IN PVOID Context)
1687 {
1688  NTSTATUS Status;
1689  HANDLE Database = 0;
1690  UNICODE_STRING DatabaseName;
1694  PDEVICE_INFORMATION DeviceInformation;
1695 
1697 
1698  /* Extract context */
1699  WorkItem = Context;
1700  DeviceInformation = WorkItem->DeviceInformation;
1701 
1702  /* Reconstruct appropriate string */
1703  DatabaseName.Length = 0;
1704  DatabaseName.MaximumLength = DeviceInformation->DeviceName.Length
1706  + sizeof(UNICODE_NULL);
1707  DatabaseName.Buffer = AllocatePool(DatabaseName.MaximumLength);
1708  if (DatabaseName.Buffer == NULL)
1709  {
1711  goto Cleanup;
1712  }
1713 
1714  /* Create the required folder (in which the database will be stored
1715  * \System Volume Information at root of the volume
1716  */
1717  Status = RtlCreateSystemVolumeInformationFolder(&(DeviceInformation->DeviceName));
1718  if (!NT_SUCCESS(Status))
1719  {
1720  goto Cleanup;
1721  }
1722 
1723  /* Finish initiating strings */
1724  RtlAppendUnicodeStringToString(&DatabaseName, &DeviceInformation->DeviceName);
1726  DatabaseName.Buffer[DatabaseName.Length / sizeof(WCHAR)] = UNICODE_NULL;
1727 
1728  /* Create database */
1730  &DatabaseName,
1732  NULL,
1733  NULL);
1734 
1740  &IoStatusBlock,
1741  NULL,
1743  0,
1744  FILE_CREATE,
1746  NULL,
1747  0,
1749  NULL,
1751  if (!NT_SUCCESS(Status))
1752  {
1754  {
1755  DPRINT1("Attempt to exploit CVE-2015-1769. See CORE-10216\n");
1756  }
1757 
1758  Database = 0;
1759  goto Cleanup;
1760  }
1761 
1762 Cleanup:
1763  if (DatabaseName.Buffer)
1764  {
1765  FreePool(DatabaseName.Buffer);
1766  }
1767 
1768  if (NT_SUCCESS(Status))
1769  {
1770  DeviceInformation->Migrated = 1;
1771  }
1772  else if (Database != 0)
1773  {
1774  ZwClose(Database);
1775  }
1776 
1777  IoFreeWorkItem(WorkItem->WorkItem);
1778 
1779  WorkItem->WorkItem = NULL;
1780  WorkItem->Status = Status;
1781  WorkItem->Database = Database;
1782 
1783  KeSetEvent(WorkItem->Event, 0, FALSE);
1784 }
1785 
1786 /*
1787  * @implemented
1788  */
1789 NTSTATUS
1792 {
1793  KEVENT Event;
1794  NTSTATUS Status;
1796 
1798 
1799  /* Allocate a work item dedicated to migration */
1801  if (!WorkItem)
1802  {
1803  *Database = 0;
1805  }
1806 
1808  WorkItem->Event = &Event;
1809  WorkItem->DeviceInformation = DeviceInformation;
1810  WorkItem->WorkItem = IoAllocateWorkItem(DeviceInformation->DeviceExtension->DeviceObject);
1811  if (!WorkItem->WorkItem)
1812  {
1813  FreePool(WorkItem);
1814  *Database = 0;
1816  }
1817 
1818  /* And queue it */
1819  IoQueueWorkItem(WorkItem->WorkItem,
1822  WorkItem);
1823 
1825  Status = WorkItem->Status;
1826 
1827  *Database = (NT_SUCCESS(Status) ? WorkItem->Database : 0);
1828 
1829  FreePool(WorkItem);
1830  return Status;
1831 }
1832 
1833 /*
1834  * @implemented
1835  */
1836 HANDLE
1838  IN BOOLEAN MigrateDatabase)
1839 {
1840  HANDLE Database;
1841  NTSTATUS Status;
1845  UNICODE_STRING DeviceRemoteDatabase;
1846 
1847  Database = 0;
1848 
1849  /* Get database name */
1850  DeviceRemoteDatabase.Length = 0;
1851  DeviceRemoteDatabase.MaximumLength = DeviceInformation->DeviceName.Length
1853  + sizeof(UNICODE_NULL);
1854  DeviceRemoteDatabase.Buffer = AllocatePool(DeviceRemoteDatabase.MaximumLength);
1855  if (!DeviceRemoteDatabase.Buffer)
1856  {
1857  return 0;
1858  }
1859 
1860  RtlAppendUnicodeStringToString(&DeviceRemoteDatabase, &DeviceInformation->DeviceName);
1861  RtlAppendUnicodeStringToString(&DeviceRemoteDatabase, &RemoteDatabase);
1862  DeviceRemoteDatabase.Buffer[DeviceRemoteDatabase.Length / sizeof(WCHAR)] = UNICODE_NULL;
1863 
1864  /* Open database */
1866  &DeviceRemoteDatabase,
1868  NULL,
1869  NULL);
1870 
1871  /* Disable hard errors */
1873 
1879  &IoStatusBlock,
1880  NULL,
1882  0,
1883  (!MigrateDatabase || DeviceInformation->Migrated == 0) ? FILE_OPEN_IF : FILE_OPEN,
1885  NULL,
1886  0,
1888  NULL,
1891  {
1892  DPRINT1("Attempt to exploit CVE-2015-1769. See CORE-10216\n");
1893  }
1894 
1895  /* If base it to be migrated and was opened successfully, go ahead */
1896  if (MigrateDatabase && NT_SUCCESS(Status))
1897  {
1898  CreateRemoteDatabase(DeviceInformation, &Database);
1899  }
1900 
1902  FreePool(DeviceRemoteDatabase.Buffer);
1903 
1904  return Database;
1905 }
1906 
1907 /*
1908  * @implemented
1909  */
1910 VOID
1912  IN PMOUNTDEV_UNIQUE_ID OldUniqueId,
1913  IN PMOUNTDEV_UNIQUE_ID NewUniqueId)
1914 {
1915  LONG Offset = 0;
1916  HANDLE Database;
1917  PDATABASE_ENTRY Entry, NewEntry;
1919 
1920  /* Open the remote database */
1921  Database = OpenRemoteDatabase(DeviceInformation, FALSE);
1922  if (!Database)
1923  {
1924  return;
1925  }
1926 
1927  /* Get all the entries */
1928  do
1929  {
1931  if (!Entry)
1932  {
1933  break;
1934  }
1935 
1936  /* Not the correct entry, skip it */
1937  if (Entry->UniqueIdLength != OldUniqueId->UniqueIdLength)
1938  {
1939  Offset += Entry->EntrySize;
1940  FreePool(Entry);
1941  continue;
1942  }
1943 
1944  /* Not the correct entry, skip it */
1945  if (RtlCompareMemory(OldUniqueId->UniqueId,
1946  (PVOID)((ULONG_PTR)Entry + Entry->UniqueIdOffset),
1947  Entry->UniqueIdLength) != Entry->UniqueIdLength)
1948  {
1949  Offset += Entry->EntrySize;
1950  FreePool(Entry);
1951  continue;
1952  }
1953 
1954  /* Here, we have the correct entry */
1955  NewEntry = AllocatePool(Entry->EntrySize + NewUniqueId->UniqueIdLength - OldUniqueId->UniqueIdLength);
1956  if (!NewEntry)
1957  {
1958  Offset += Entry->EntrySize;
1959  FreePool(Entry);
1960  continue;
1961  }
1962 
1963  /* Recreate the entry from the previous one */
1964  NewEntry->EntrySize = Entry->EntrySize + NewUniqueId->UniqueIdLength - OldUniqueId->UniqueIdLength;
1965  NewEntry->EntryReferences = Entry->EntryReferences;
1966  NewEntry->SymbolicNameOffset = sizeof(DATABASE_ENTRY);
1967  NewEntry->SymbolicNameLength = Entry->SymbolicNameLength;
1968  NewEntry->UniqueIdOffset = Entry->SymbolicNameLength + sizeof(DATABASE_ENTRY);
1969  NewEntry->UniqueIdLength = NewUniqueId->UniqueIdLength;
1970  RtlCopyMemory((PVOID)((ULONG_PTR)NewEntry + NewEntry->SymbolicNameOffset),
1971  (PVOID)((ULONG_PTR)Entry + Entry->SymbolicNameOffset),
1972  NewEntry->SymbolicNameLength);
1973  RtlCopyMemory((PVOID)((ULONG_PTR)NewEntry + NewEntry->UniqueIdOffset),
1974  NewUniqueId->UniqueId, NewEntry->UniqueIdLength);
1975 
1976  /* Delete old entry */
1978  if (!NT_SUCCESS(Status))
1979  {
1980  FreePool(Entry);
1981  FreePool(NewEntry);
1982  break;
1983  }
1984 
1985  /* And replace with new one */
1986  Status = AddRemoteDatabaseEntry(Database, NewEntry);
1987  FreePool(Entry);
1988  FreePool(NewEntry);
1989  } while (NT_SUCCESS(Status));
1990 
1992 
1993  return;
1994 }
1995 
1996 /*
1997  * @implemented
1998  */
1999 NTSTATUS
2000 NTAPI
2002  IN ULONG ValueType,
2003  IN PVOID ValueData,
2005  IN PVOID Context,
2007 {
2008  PMOUNTDEV_UNIQUE_ID UniqueId;
2009  UNICODE_STRING RegistryEntry;
2010 
2012 
2013  if (ValueType != REG_BINARY)
2014  {
2015  return STATUS_SUCCESS;
2016  }
2017 
2018  UniqueId = Context;
2019 
2020  /* First ensure we have the correct data */
2021  if (UniqueId->UniqueIdLength != ValueLength)
2022  {
2023  return STATUS_SUCCESS;
2024  }
2025 
2027  {
2028  return STATUS_SUCCESS;
2029  }
2030 
2031  RtlInitUnicodeString(&RegistryEntry, ValueName);
2032 
2033  /* Then, it's a drive letter, erase it */
2034  if (IsDriveLetter(&RegistryEntry))
2035  {
2037  DatabasePath,
2038  ValueName);
2039  }
2040 
2041  return STATUS_SUCCESS;
2042 }
2043 
2044 /*
2045  * @implemented
2046  */
2047 VOID
2049 {
2051 
2054 
2056  DatabasePath,
2057  QueryTable,
2058  UniqueId,
2059  NULL);
2060 }
2061 
2062 /*
2063  * @implemented
2064  */
2065 NTSTATUS
2066 NTAPI
2068  IN ULONG ValueType,
2069  IN PVOID ValueData,
2071  IN PVOID Context,
2073 {
2074  PMOUNTDEV_UNIQUE_ID UniqueId = Context;
2075 
2077 
2078  /* Ensure we have correct input */
2079  if (ValueName[0] != L'#' || ValueType != REG_BINARY ||
2080  UniqueId->UniqueIdLength != ValueLength)
2081  {
2082  return STATUS_SUCCESS;
2083  }
2084 
2085  /* And then, if unique ID matching, delete entry */
2087  {
2089  DatabasePath,
2090  ValueName);
2091  }
2092 
2093  return STATUS_SUCCESS;
2094 }
2095 
2096 /*
2097  * @implemented
2098  */
2099 VOID
2101 {
2103 
2106 
2108  DatabasePath,
2109  QueryTable,
2110  UniqueId,
2111  NULL);
2112 }
#define FILE_GENERIC_READ
Definition: nt_native.h:653
VOID OnlineMountedVolumes(IN PDEVICE_EXTENSION DeviceExtension, IN PDEVICE_INFORMATION DeviceInformation)
Definition: database.c:1460
IN PUNICODE_STRING IN POBJECT_ATTRIBUTES ObjectAttributes
Definition: conport.c:35
PWSTR DatabasePath
Definition: database.c:31
USHORT UniqueIdOffset
Definition: mntmgr.h:91
#define FILE_WRITE_EA
Definition: nt_native.h:640
_In_ PCWSTR _Inout_ _At_ QueryTable _Pre_unknown_ PRTL_QUERY_REGISTRY_TABLE QueryTable
Definition: rtlfuncs.h:4155
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
#define IN
Definition: typedefs.h:39
#define LL
Definition: tui.h:84
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
#define FILE_OPEN_IF
Definition: from_kernel.h:56
_Must_inspect_result_ _In_ PFILE_OBJECT _In_ ULONG _In_ BOOLEAN _In_ ULONG _In_opt_ PULONG _In_ BOOLEAN RestartScan
Definition: fltkernel.h:2297
WCHAR RootDirectory[MAX_PATH]
Definition: format.c:74
_In_ PFCB _In_ LONGLONG StartingOffset
Definition: cdprocs.h:290
NTSYSAPI NTSTATUS WINAPI RtlQueryRegistryValues(ULONG, PCWSTR, PRTL_QUERY_REGISTRY_TABLE, PVOID, PVOID)
struct _Entry Entry
Definition: kefuncs.h:627
#define OBJ_CASE_INSENSITIVE
Definition: winternl.h:228
ULONG EntryReferences
Definition: mntmgr.h:88
USHORT MaximumLength
Definition: env_spec_w32.h:370
VOID DeleteFromLocalDatabase(IN PUNICODE_STRING SymbolicLink, IN PMOUNTDEV_UNIQUE_ID UniqueId)
Definition: database.c:351
ULONG EntrySize
Definition: mntmgr.h:87
VOID ReleaseRemoteDatabaseSemaphore(IN PDEVICE_EXTENSION DeviceExtension)
Definition: database.c:391
#define REG_BINARY
Definition: nt_native.h:1496
#define TRUE
Definition: types.h:120
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:317
#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:56
_In_ PNDIS_STRING _In_ PNDIS_STRING SymbolicName
Definition: ndis.h:4676
PWSTR OfflinePath
Definition: database.c:32
LONG NTSTATUS
Definition: precomp.h:26
USHORT UniqueIdLength
Definition: imports.h:138
#define FILE_CREATE
Definition: from_kernel.h:55
BOOLEAN IsUniqueIdPresent(IN PDEVICE_EXTENSION DeviceExtension, IN PDATABASE_ENTRY DatabaseEntry)
Definition: uniqueid.c:221
HANDLE OpenRemoteDatabase(IN PDEVICE_INFORMATION DeviceInformation, IN BOOLEAN MigrateDatabase)
Definition: database.c:1837
BOOLEAN IsDriveLetter(PUNICODE_STRING SymbolicName)
Definition: symlink.c:922
VOID NTAPI KeAcquireSpinLock(PKSPIN_LOCK SpinLock, PKIRQL OldIrql)
Definition: spinlock.c:50
IN PVOID IN PVOID IN USHORT IN USHORT Size
Definition: pci.h:361
#define DO_UNLOAD_PENDING
Definition: env_spec_w32.h:392
NTSTATUS QueryUniqueIdFromMaster(IN PDEVICE_EXTENSION DeviceExtension, IN PUNICODE_STRING SymbolicName, OUT PMOUNTDEV_UNIQUE_ID *UniqueId)
Definition: database.c:440
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
UNICODE_STRING SafeVolumes
Definition: symlink.c:38
VOID DeleteRegistryDriveLetter(IN PMOUNTDEV_UNIQUE_ID UniqueId)
Definition: database.c:2048
uint16_t * PWCHAR
Definition: typedefs.h:56
#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
Allocation
Definition: exfuncs.h:598
#define FILE_APPEND_DATA
Definition: nt_native.h:634
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:642
LONG NTAPI KeSetEvent(IN PKEVENT Event, IN KPRIORITY Increment, IN BOOLEAN Wait)
Definition: eventobj.c:159
_Must_inspect_result_ _In_ WDFKEY _In_ PCUNICODE_STRING _In_ ULONG _Out_opt_ PULONG _Out_opt_ PULONG ValueType
Definition: wdfregistry.h:279
#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
#define OBJ_KERNEL_HANDLE
Definition: winternl.h:231
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:224
#define FILE_SHARE_READ
Definition: compat.h:136
#define FILE_OPEN_BY_FILE_ID
Definition: from_kernel.h:41
#define STATUS_BUFFER_TOO_SMALL
Definition: shellext.h:69
#define IO_STOP_ON_SYMLINK
Definition: iotypes.h:7353
uint32_t ULONG_PTR
Definition: typedefs.h:65
FORCEINLINE BOOLEAN RemoveEntryList(_In_ PLIST_ENTRY Entry)
Definition: rtlfuncs.h:105
#define IO_REPARSE_TAG_MOUNT_POINT
Definition: iotypes.h:7231
#define STATUS_TIMEOUT
Definition: ntstatus.h:81
UNICODE_STRING RemoteDatabase
Definition: database.c:34
UCHAR KIRQL
Definition: env_spec_w32.h:591
_In_ PDEVICE_OBJECT DeviceObject
Definition: wdfdevice.h:2055
#define FILE_SYNCHRONOUS_IO_ALERT
Definition: from_kernel.h:30
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
#define FALSE
Definition: types.h:117
#define UNICODE_NULL
VOID DeleteNoDriveLetterEntry(IN PMOUNTDEV_UNIQUE_ID UniqueId)
Definition: database.c:2100
NTSYSAPI NTSTATUS WINAPI RtlWriteRegistryValue(ULONG, PCWSTR, PCWSTR, ULONG, PVOID, ULONG)
long LONG
Definition: pedump.c:60
#define IO_NO_PARAMETER_CHECKING
Definition: iotypes.h:541
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:467
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:4155
VOID ChangeRemoteDatabaseUniqueId(IN PDEVICE_INFORMATION DeviceInformation, IN PMOUNTDEV_UNIQUE_ID OldUniqueId, IN PMOUNTDEV_UNIQUE_ID NewUniqueId)
Definition: database.c:1911
VOID NTAPI WorkerThread(IN PDEVICE_OBJECT DeviceObject, IN PVOID Context)
Definition: database.c:1148
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:636
void * PVOID
Definition: retypes.h:9
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
_In_ WDFREQUEST _In_ WDFFILEOBJECT FileObject
Definition: wdfdevice.h:547
struct _DATABASE_ENTRY DATABASE_ENTRY
KIRQL OldIrql
Definition: mm.h:1502
Status
Definition: gdiplustypes.h:24
struct _LIST_ENTRY * Flink
Definition: typedefs.h:121
_In_ KPROCESSOR_MODE PreviousMode
Definition: sefuncs.h:103
NTSTATUS CreateRemoteDatabase(IN PDEVICE_INFORMATION DeviceInformation, IN OUT PHANDLE Database)
Definition: database.c:1790
LONG GetRemoteDatabaseSize(IN HANDLE Database)
Definition: database.c:40
BOOLEAN SkipNotifications
Definition: mntmgr.h:58
NTSTATUS WaitForRemoteDatabaseSemaphore(IN PDEVICE_EXTENSION DeviceExtension)
Definition: database.c:371
NTSTATUS NTAPI RtlCreateSystemVolumeInformationFolder(IN PUNICODE_STRING VolumeRootPath)
Definition: sysvol.c:551
__wchar_t WCHAR
Definition: xmlstorage.h:180
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
struct _RECONCILE_WORK_ITEM_CONTEXT * PRECONCILE_WORK_ITEM_CONTEXT
Definition: mntmgr.h:95
#define ObDereferenceObject
Definition: obfuncs.h:203
NTSTATUS WriteUniqueIdToMaster(IN PDEVICE_EXTENSION DeviceExtension, IN PDATABASE_ENTRY DatabaseEntry)
Definition: database.c:489
_In_ GUID _In_ PVOID ValueData
Definition: hubbusif.h:311
USHORT SymbolicNameOffset
Definition: mntmgr.h:89
* PFILE_OBJECT
Definition: iotypes.h:1998
#define READ_CONTROL
Definition: nt_native.h:58
#define FILE_READ_ATTRIBUTES
Definition: nt_native.h:647
NTSTATUS NTAPI DeleteNoDriveLetterEntryRoutine(IN PWSTR ValueName, IN ULONG ValueType, IN PVOID ValueData, IN ULONG ValueLength, IN PVOID Context, IN PVOID EntryContext)
Definition: database.c:2067
Definition: mntmgr.h:85
NTSTATUS AddRemoteDatabaseEntry(IN HANDLE Database, IN PDATABASE_ENTRY Entry)
Definition: database.c:64
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)
_Must_inspect_result_ _In_ WDFKEY _In_ PCUNICODE_STRING ValueName
Definition: wdfregistry.h:240
VOID NTAPI CreateRemoteDatabaseWorker(IN PDEVICE_OBJECT DeviceObject, IN PVOID Context)
Definition: database.c:1685
_In_ WDFDEVICE AssociatedDevice
Definition: wdfinterrupt.h:173
#define FILE_ATTRIBUTE_NORMAL
Definition: compat.h:137
#define FILE_SHARE_DELETE
Definition: nt_native.h:682
static const WCHAR L[]
Definition: oid.c:1250
#define InterlockedDecrement
Definition: armddk.h:52
NTSYSAPI NTSTATUS WINAPI RtlDeleteRegistryValue(ULONG, PCWSTR, PCWSTR)
NTSTATUS TruncateRemoteDatabase(IN HANDLE Database, IN LONG NewSize)
Definition: database.c:91
PVOID *typedef PHANDLE
Definition: ntsecpkg.h:454
BOOLEAN NTAPI IoSetThreadHardErrorMode(IN BOOLEAN HardErrorEnabled)
Definition: error.c:726
#define FILE_NON_DIRECTORY_FILE
Definition: constants.h:492
ULONG LowPart
Definition: typedefs.h:106
_Must_inspect_result_ _In_ USHORT NewSize
Definition: fltkernel.h:975
Definition: typedefs.h:119
static const WCHAR Cleanup[]
Definition: register.c:80
#define SYNCHRONIZE
Definition: nt_native.h:61
#define RTL_REGISTRY_ABSOLUTE
Definition: nt_native.h:161
#define AllocatePool(Size)
Definition: mntmgr.h:153
#define InterlockedExchange
Definition: armddk.h:54
VOID ReconcileThisDatabaseWithMaster(IN PDEVICE_EXTENSION DeviceExtension, IN PDEVICE_INFORMATION DeviceInformation)
Definition: database.c:1613
NTSTATUS DeleteRemoteDatabaseEntry(IN HANDLE Database, IN LONG StartingOffset)
Definition: database.c:233
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
_In_ ULONG _In_ ULONG Offset
Definition: ntddpcm.h:101
VOID NTAPI IoQueueWorkItem(IN PIO_WORKITEM IoWorkItem, IN PIO_WORKITEM_ROUTINE WorkerRoutine, IN WORK_QUEUE_TYPE QueueType, IN PVOID Context)
Definition: iowork.c:40
NTSTATUS CloseRemoteDatabase(IN HANDLE Database)
Definition: database.c:82
struct _FileName FileName
Definition: fatprocs.h:893
NTSTATUS QueueWorkItem(IN PDEVICE_EXTENSION DeviceExtension, IN PRECONCILE_WORK_ITEM WorkItem, IN PVOID Context)
Definition: database.c:1261
static ULONG Timeout
Definition: ping.c:61
#define KeInitializeEvent(pEvt, foo, foo2)
Definition: env_spec_w32.h:477
#define InterlockedIncrement
Definition: armddk.h:53
#define STATUS_BUFFER_OVERFLOW
Definition: shellext.h:66
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
NTSTATUS QueryVolumeName(IN HANDLE RootDirectory, IN PFILE_REPARSE_POINT_INFORMATION ReparsePointInformation, IN PUNICODE_STRING FileName OPTIONAL, OUT PUNICODE_STRING SymbolicName, OUT PUNICODE_STRING VolumeName)
Definition: database.c:1292
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
PDATABASE_ENTRY GetRemoteDatabaseEntry(IN HANDLE Database, IN LONG StartingOffset)
Definition: database.c:125
NTSYSAPI NTSTATUS NTAPI RtlAppendUnicodeStringToString(PUNICODE_STRING Destination, PUNICODE_STRING Source)
#define FILE_READ_EA
Definition: nt_native.h:638
static OUT PIO_STATUS_BLOCK IoStatusBlock
Definition: pipe.c:75
VOID ReconcileAllDatabasesWithMaster(IN PDEVICE_EXTENSION DeviceExtension)
Definition: database.c:1659
#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 NULL
Definition: types.h:112
#define KeReleaseSpinLock(sl, irql)
Definition: env_spec_w32.h:627
#define STATUS_IO_TIMEOUT
Definition: udferr_usr.h:163
#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
VOID NTAPI ReconcileThisDatabaseWithMasterWorker(IN PVOID Parameter)
Definition: database.c:560
#define FILE_SYNCHRONOUS_IO_NONALERT
Definition: from_kernel.h:31
_Must_inspect_result_ _Inout_opt_ PUNICODE_STRING VolumeName
Definition: fltkernel.h:1117
WCHAR FileNameBuffer[_MAX_PATH]
Definition: framewnd.c:240
_In_ HANDLE Handle
Definition: extypes.h:390
struct tagContext Context
Definition: acpixf.h:1034
#define OUT
Definition: typedefs.h:40
NTSTATUS NTAPI DeleteDriveLetterRoutine(IN PWSTR ValueName, IN ULONG ValueType, IN PVOID ValueData, IN ULONG ValueLength, IN PVOID Context, IN PVOID EntryContext)
Definition: database.c:2001
unsigned int ULONG
Definition: retypes.h:1
#define IO_NO_INCREMENT
Definition: iotypes.h:598
LIST_ENTRY AssociatedDevicesHead
Definition: mntmgr.h:47
NTSYSAPI VOID NTAPI RtlInitUnicodeString(PUNICODE_STRING DestinationString, PCWSTR SourceString)
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
#define InitializeObjectAttributes(p, n, a, r, s)
Definition: reg.c:106
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
#define STATUS_SUCCESS
Definition: shellext.h:65
_Must_inspect_result_ _In_ PWDF_WORKITEM_CONFIG _In_ PWDF_OBJECT_ATTRIBUTES _Out_ WDFWORKITEM * WorkItem
Definition: wdfworkitem.h:110
#define MAXIMUM_REPARSE_DATA_BUFFER_SIZE
Definition: iotypes.h:7213
PMOUNTDEV_UNIQUE_ID UniqueId
Definition: mntmgr.h:49
NTSTATUS WriteRemoteDatabaseEntry(IN HANDLE Database, IN LONG Offset, IN PDATABASE_ENTRY Entry)
Definition: database.c:200
#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
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
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:114
IN PDCB IN PCCB IN VBO IN OUT PULONG OUT PDIRENT OUT PBCB OUT PVBO ByteOffset
Definition: fatprocs.h:725
struct _REPARSE_DATA_BUFFER::@301::@304 MountPointReparseBuffer
#define RTL_CONSTANT_STRING(s)
Definition: tunneltest.c:14
KEVENT UnloadEvent
Definition: mountmgr.c:36
_Must_inspect_result_ _In_ WDFKEY _In_ PCUNICODE_STRING _In_ ULONG ValueLength
Definition: wdfregistry.h:271
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68