[MOUNTMGR]

Implement ReconcileThisDatabaseWithMasterWorker() which was the last missing bit of our MountMgr :-)

svn path=/trunk/; revision=69292
This commit is contained in:
Pierre Schweitzer 2015-09-19 20:37:09 +00:00
parent 88648de586
commit 582d858bfd
3 changed files with 752 additions and 165 deletions

View file

@ -394,11 +394,750 @@ ReleaseRemoteDatabaseSemaphore(IN PDEVICE_EXTENSION DeviceExtension)
KeReleaseSemaphore(&(DeviceExtension->RemoteDatabaseLock), IO_NO_INCREMENT, 1, FALSE);
}
/*
* @implemented
*/
NTSTATUS
NTAPI
QueryUniqueIdQueryRoutine(IN PWSTR ValueName,
IN ULONG ValueType,
IN PVOID ValueData,
IN ULONG ValueLength,
IN PVOID Context,
IN PVOID EntryContext)
{
PMOUNTDEV_UNIQUE_ID IntUniqueId;
PMOUNTDEV_UNIQUE_ID * UniqueId;
UNREFERENCED_PARAMETER(ValueName);
UNREFERENCED_PARAMETER(ValueType);
UNREFERENCED_PARAMETER(EntryContext);
/* Sanity check */
if (ValueLength >= 0x10000)
{
return STATUS_SUCCESS;
}
/* Allocate the Unique ID */
IntUniqueId = AllocatePool(sizeof(UniqueId) + ValueLength);
if (IntUniqueId)
{
/* Copy data & return */
IntUniqueId->UniqueIdLength = (USHORT)ValueLength;
RtlCopyMemory(&(IntUniqueId->UniqueId), ValueData, ValueLength);
UniqueId = Context;
*UniqueId = IntUniqueId;
}
return STATUS_SUCCESS;
}
/*
* @implemented
*/
NTSTATUS
QueryUniqueIdFromMaster(IN PDEVICE_EXTENSION DeviceExtension,
IN PUNICODE_STRING SymbolicName,
OUT PMOUNTDEV_UNIQUE_ID * UniqueId)
{
NTSTATUS Status;
PDEVICE_INFORMATION DeviceInformation;
RTL_QUERY_REGISTRY_TABLE QueryTable[2];
/* Query the unique ID */
RtlZeroMemory(QueryTable, sizeof(QueryTable));
QueryTable[0].QueryRoutine = QueryUniqueIdQueryRoutine;
QueryTable[0].Name = SymbolicName->Buffer;
*UniqueId = NULL;
RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
DatabasePath,
QueryTable,
UniqueId,
NULL);
/* Unique ID found, no need to go farther */
if (*UniqueId)
{
return STATUS_SUCCESS;
}
/* Otherwise, find associate device information */
Status = FindDeviceInfo(DeviceExtension, SymbolicName, FALSE, &DeviceInformation);
if (!NT_SUCCESS(Status))
{
return Status;
}
*UniqueId = AllocatePool(DeviceInformation->UniqueId->UniqueIdLength + sizeof(MOUNTDEV_UNIQUE_ID));
if (!*UniqueId)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
/* Return this unique ID (better than nothing) */
(*UniqueId)->UniqueIdLength = DeviceInformation->UniqueId->UniqueIdLength;
RtlCopyMemory(&((*UniqueId)->UniqueId), &(DeviceInformation->UniqueId->UniqueId), (*UniqueId)->UniqueIdLength);
return STATUS_SUCCESS;
}
/*
* @implemented
*/
NTSTATUS
WriteUniqueIdToMaster(IN PDEVICE_EXTENSION DeviceExtension,
IN PDATABASE_ENTRY DatabaseEntry)
{
NTSTATUS Status;
PWCHAR SymbolicName;
PLIST_ENTRY NextEntry;
UNICODE_STRING SymbolicString;
PDEVICE_INFORMATION DeviceInformation;
/* Create symbolic name from database entry */
SymbolicName = AllocatePool(DatabaseEntry->SymbolicNameLength + sizeof(WCHAR));
if (!SymbolicName)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlCopyMemory(SymbolicName,
(PVOID)((ULONG_PTR)DatabaseEntry + DatabaseEntry->SymbolicNameOffset),
DatabaseEntry->SymbolicNameLength);
SymbolicName[DatabaseEntry->SymbolicNameLength / sizeof(WCHAR)] = UNICODE_NULL;
/* Associate the unique ID with the name from remote database */
Status = RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE,
DatabasePath,
SymbolicName,
REG_BINARY,
(PVOID)((ULONG_PTR)DatabaseEntry + DatabaseEntry->UniqueIdOffset),
DatabaseEntry->UniqueIdLength);
FreePool(SymbolicName);
/* Reget symbolic name */
SymbolicString.Length = DatabaseEntry->SymbolicNameLength;
SymbolicString.MaximumLength = DatabaseEntry->SymbolicNameLength;
SymbolicString.Buffer = (PVOID)((ULONG_PTR)DatabaseEntry + DatabaseEntry->SymbolicNameOffset);
/* Find the device using this unique ID */
for (NextEntry = DeviceExtension->DeviceListHead.Flink;
NextEntry != &(DeviceExtension->DeviceListHead);
NextEntry = NextEntry->Flink)
{
DeviceInformation = CONTAINING_RECORD(NextEntry,
DEVICE_INFORMATION,
DeviceListEntry);
if (DeviceInformation->UniqueId->UniqueIdLength != DatabaseEntry->UniqueIdLength)
{
continue;
}
if (RtlCompareMemory((PVOID)((ULONG_PTR)DatabaseEntry + DatabaseEntry->UniqueIdOffset),
DeviceInformation->UniqueId->UniqueId,
DatabaseEntry->UniqueIdLength) == DatabaseEntry->UniqueIdLength)
{
break;
}
}
/* If found, create a mount point */
if (NextEntry != &(DeviceExtension->DeviceListHead))
{
MountMgrCreatePointWorker(DeviceExtension, &SymbolicString, &(DeviceInformation->DeviceName));
}
return Status;
}
/*
* @implemented
*/
VOID
NTAPI
ReconcileThisDatabaseWithMasterWorker(IN PVOID Parameter)
{
UNREFERENCED_PARAMETER(Parameter);
ULONG Offset;
NTSTATUS Status;
PFILE_OBJECT FileObject;
PDEVICE_OBJECT DeviceObject;
PMOUNTDEV_UNIQUE_ID UniqueId;
PDATABASE_ENTRY DatabaseEntry;
HANDLE DatabaseHandle, Handle;
IO_STATUS_BLOCK IoStatusBlock;
OBJECT_ATTRIBUTES ObjectAttributes;
PDEVICE_INFORMATION ListDeviceInfo;
PLIST_ENTRY Entry, EntryInfo, NextEntry;
PASSOCIATED_DEVICE_ENTRY AssociatedDevice;
BOOLEAN HardwareErrors, Restart, FailedFinding;
WCHAR FileNameBuffer[0x8], SymbolicNameBuffer[100];
UNICODE_STRING ReparseFile, FileName, SymbolicName, VolumeName;
FILE_REPARSE_POINT_INFORMATION ReparsePointInformation, SavedReparsePointInformation;
PDEVICE_EXTENSION DeviceExtension = ((PRECONCILE_WORK_ITEM_CONTEXT)Parameter)->DeviceExtension;
PDEVICE_INFORMATION DeviceInformation = ((PRECONCILE_WORK_ITEM_CONTEXT)Parameter)->DeviceInformation;
/* We're unloading, do nothing */
if (Unloading)
{
return;
}
/* Lock remote DB */
if (!NT_SUCCESS(WaitForRemoteDatabaseSemaphore(DeviceExtension)))
{
return;
}
/* Recheck for unloading */
if (Unloading)
{
goto ReleaseRDS;
}
/* Find the DB to reconcile */
KeWaitForSingleObject(&DeviceExtension->DeviceLock, Executive, KernelMode, FALSE, NULL);
for (Entry = DeviceExtension->DeviceListHead.Flink;
Entry != &DeviceExtension->DeviceListHead;
Entry = Entry->Flink)
{
ListDeviceInfo = CONTAINING_RECORD(Entry, DEVICE_INFORMATION, DeviceListEntry);
if (ListDeviceInfo == DeviceInformation)
{
break;
}
}
/* If not found, or if removable, bail out */
if (Entry == &DeviceExtension->DeviceListHead || DeviceInformation->Removable)
{
KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
goto ReleaseRDS;
}
/* Get our device object */
Status = IoGetDeviceObjectPointer(&ListDeviceInfo->DeviceName, FILE_READ_ATTRIBUTES, &FileObject, &DeviceObject);
if (!NT_SUCCESS(Status))
{
KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
goto ReleaseRDS;
}
if (DeviceObject->Flags & 1)
{
_InterlockedExchangeAdd(&ListDeviceInfo->MountState, 1u);
}
ObDereferenceObject(FileObject);
/* Force default: no DB, and need for reconcile */
DeviceInformation->NeedsReconcile = TRUE;
DeviceInformation->NoDatabase = TRUE;
FailedFinding = FALSE;
/* Remove any associated device that refers to the DB to reconcile */
for (Entry = DeviceExtension->DeviceListHead.Flink;
Entry != &DeviceExtension->DeviceListHead;
Entry = Entry->Flink)
{
ListDeviceInfo = CONTAINING_RECORD(Entry, DEVICE_INFORMATION, DeviceListEntry);
EntryInfo = ListDeviceInfo->AssociatedDevicesHead.Flink;
while (EntryInfo != &ListDeviceInfo->AssociatedDevicesHead)
{
AssociatedDevice = CONTAINING_RECORD(EntryInfo, ASSOCIATED_DEVICE_ENTRY, AssociatedDevicesEntry);
NextEntry = EntryInfo->Flink;
if (AssociatedDevice->DeviceInformation == DeviceInformation)
{
RemoveEntryList(&AssociatedDevice->AssociatedDevicesEntry);
FreePool(AssociatedDevice->String.Buffer);
FreePool(AssociatedDevice);
}
EntryInfo = NextEntry;
}
}
/* Open the remote database */
DatabaseHandle = OpenRemoteDatabase(DeviceInformation, FALSE);
/* Prepare a string with reparse point index */
ReparseFile.Length = DeviceInformation->DeviceName.Length + ReparseIndex.Length;
ReparseFile.MaximumLength = ReparseFile.Length + sizeof(UNICODE_NULL);
ReparseFile.Buffer = AllocatePool(ReparseFile.MaximumLength);
if (ReparseFile.Buffer == NULL)
{
if (DatabaseHandle != 0)
{
CloseRemoteDatabase(DatabaseHandle);
}
KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
goto ReleaseRDS;
}
RtlCopyMemory(ReparseFile.Buffer, DeviceInformation->DeviceName.Buffer,
DeviceInformation->DeviceName.Length);
RtlCopyMemory((PVOID)((ULONG_PTR)ReparseFile.Buffer + DeviceInformation->DeviceName.Length),
ReparseFile.Buffer, ReparseFile.Length);
ReparseFile.Buffer[ReparseFile.Length / sizeof(WCHAR)] = UNICODE_NULL;
InitializeObjectAttributes(&ObjectAttributes,
&ReparseFile,
OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
NULL,
NULL);
/* Open reparse point directory */
HardwareErrors = IoSetThreadHardErrorMode(FALSE);
Status = ZwOpenFile(&Handle,
FILE_GENERIC_READ,
&ObjectAttributes,
&IoStatusBlock,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_SYNCHRONOUS_IO_ALERT);
IoSetThreadHardErrorMode(HardwareErrors);
FreePool(ReparseFile.Buffer);
if (!NT_SUCCESS(Status))
{
if (DatabaseHandle != 0)
{
TruncateRemoteDatabase(DatabaseHandle, 0);
CloseRemoteDatabase(DatabaseHandle);
}
KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
goto ReleaseRDS;
}
/* Query reparse point information
* We only pay attention to mout point
*/
RtlZeroMemory(FileNameBuffer, sizeof(FileNameBuffer));
FileName.Buffer = FileNameBuffer;
FileName.Length = sizeof(FileNameBuffer);
FileName.MaximumLength = sizeof(FileNameBuffer);
((PULONG)FileNameBuffer)[0] = IO_REPARSE_TAG_MOUNT_POINT;
Status = ZwQueryDirectoryFile(Handle,
NULL,
NULL,
NULL,
&IoStatusBlock,
&ReparsePointInformation,
sizeof(FILE_REPARSE_POINT_INFORMATION),
FileReparsePointInformation,
TRUE,
&FileName,
FALSE);
if (!NT_SUCCESS(Status))
{
ZwClose(Handle);
if (DatabaseHandle != 0)
{
TruncateRemoteDatabase(DatabaseHandle, 0);
CloseRemoteDatabase(DatabaseHandle);
}
KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
goto ReleaseRDS;
}
/* If we failed to open the remote DB previously,
* retry this time allowing migration (and thus, creation if required)
*/
if (DatabaseHandle == 0)
{
DatabaseHandle = OpenRemoteDatabase(DeviceInformation, TRUE);
if (DatabaseHandle == 0)
{
KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
goto ReleaseRDS;
}
}
KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
/* Reset all the references to our DB entries */
Offset = 0;
for (;;)
{
DatabaseEntry = GetRemoteDatabaseEntry(DatabaseHandle, Offset);
if (DatabaseEntry == NULL)
{
break;
}
DatabaseEntry->EntryReferences = 0;
Status = WriteRemoteDatabaseEntry(DatabaseHandle, Offset, DatabaseEntry);
if (!NT_SUCCESS(Status))
{
FreePool(DatabaseEntry);
goto CloseReparse;
}
Offset += DatabaseEntry->EntrySize;
FreePool(DatabaseEntry);
}
/* Init string for QueryVolumeName call */
SymbolicName.MaximumLength = sizeof(SymbolicNameBuffer);
SymbolicName.Length = 0;
SymbolicName.Buffer = SymbolicNameBuffer;
Restart = TRUE;
/* Start looping on reparse points */
for (;;)
{
RtlCopyMemory(&SavedReparsePointInformation, &ReparsePointInformation, sizeof(FILE_REPARSE_POINT_INFORMATION));
Status = ZwQueryDirectoryFile(Handle,
NULL,
NULL,
NULL,
&IoStatusBlock,
&ReparsePointInformation,
sizeof(FILE_REPARSE_POINT_INFORMATION),
FileReparsePointInformation,
TRUE,
Restart ? &FileName : NULL,
Restart);
/* Restart only once */
if (Restart)
{
Restart = FALSE;
}
else
{
/* If we get the same one, we're done, bail out */
if (ReparsePointInformation.FileReference == SavedReparsePointInformation.FileReference &&
ReparsePointInformation.Tag == SavedReparsePointInformation.Tag)
{
break;
}
}
/* If querying failed, or if onloading, or if not returning mount points, bail out */
if (!NT_SUCCESS(Status) || Unloading || ReparsePointInformation.Tag != IO_REPARSE_TAG_MOUNT_POINT)
{
break;
}
/* Get the volume name associated to the mount point */
Status = QueryVolumeName(Handle, &ReparsePointInformation, 0, &SymbolicName, &VolumeName);
if (!NT_SUCCESS(Status))
{
continue;
}
/* Browse the DB to find the name */
Offset = 0;
for (;;)
{
UNICODE_STRING DbName;
DatabaseEntry = GetRemoteDatabaseEntry(DatabaseHandle, Offset);
if (DatabaseEntry == NULL)
{
break;
}
DbName.MaximumLength = DatabaseEntry->SymbolicNameLength;
DbName.Length = DbName.MaximumLength;
DbName.Buffer = (PWSTR)((ULONG_PTR)DatabaseEntry + DatabaseEntry->SymbolicNameOffset);
/* Found, we're done! */
if (RtlEqualUnicodeString(&DbName, &SymbolicName, TRUE))
{
break;
}
Offset += DatabaseEntry->EntrySize;
FreePool(DatabaseEntry);
}
/* If we found the mount point.... */
if (DatabaseEntry != NULL)
{
/* If it was referenced, reference it once more and update to remote */
if (DatabaseEntry->EntryReferences)
{
++DatabaseEntry->EntryReferences;
Status = WriteRemoteDatabaseEntry(DatabaseHandle, Offset, DatabaseEntry);
if (!NT_SUCCESS(Status))
{
goto FreeDBEntry;
}
FreePool(DatabaseEntry);
}
else
{
/* Query the Unique ID associated to that mount point in case it changed */
KeWaitForSingleObject(&DeviceExtension->DeviceLock, Executive, KernelMode, FALSE, NULL);
Status = QueryUniqueIdFromMaster(DeviceExtension, &SymbolicName, &UniqueId);
if (!NT_SUCCESS(Status))
{
/* If we failed doing so, reuse the old Unique ID and push it to master */
Status = WriteUniqueIdToMaster(DeviceExtension, DatabaseEntry);
if (!NT_SUCCESS(Status))
{
goto ReleaseDeviceLock;
}
/* And then, reference & write the entry */
++DatabaseEntry->EntryReferences;
Status = WriteRemoteDatabaseEntry(DatabaseHandle, Offset, DatabaseEntry);
if (!NT_SUCCESS(Status))
{
goto ReleaseDeviceLock;
}
KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
FreePool(DatabaseEntry);
}
/* If the Unique ID didn't change */
else if (UniqueId->UniqueIdLength == DatabaseEntry->UniqueIdLength &&
RtlCompareMemory(UniqueId->UniqueId,
(PVOID)((ULONG_PTR)DatabaseEntry + DatabaseEntry->UniqueIdOffset),
UniqueId->UniqueIdLength) == UniqueId->UniqueIdLength)
{
/* Reference the entry, and update to remote */
++DatabaseEntry->EntryReferences;
Status = WriteRemoteDatabaseEntry(DatabaseHandle, Offset, DatabaseEntry);
if (!NT_SUCCESS(Status))
{
goto FreeUniqueId;
}
FreePool(UniqueId);
KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
FreePool(DatabaseEntry);
}
/* Would, by chance, the Unique ID be present elsewhere? */
else if (IsUniqueIdPresent(DeviceExtension, DatabaseEntry))
{
/* Push the ID to master */
Status = WriteUniqueIdToMaster(DeviceExtension, DatabaseEntry);
if (!NT_SUCCESS(Status))
{
goto FreeUniqueId;
}
/* And then, reference & write the entry */
++DatabaseEntry->EntryReferences;
Status = WriteRemoteDatabaseEntry(DatabaseHandle, Offset, DatabaseEntry);
if (!NT_SUCCESS(Status))
{
goto FreeUniqueId;
}
FreePool(UniqueId);
KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
FreePool(DatabaseEntry);
}
else
{
/* OK, at that point, we're facing a totally unknown unique ID
* So, get rid of the old entry, and recreate a new one with
* the know unique ID
*/
Status = DeleteRemoteDatabaseEntry(DatabaseHandle, Offset);
if (!NT_SUCCESS(Status))
{
goto FreeUniqueId;
}
FreePool(DatabaseEntry);
/* Allocate a new entry big enough */
DatabaseEntry = AllocatePool(UniqueId->UniqueIdLength + SymbolicName.Length + sizeof(DATABASE_ENTRY));
if (DatabaseEntry == NULL)
{
goto FreeUniqueId;
}
/* Configure it */
DatabaseEntry->EntrySize = UniqueId->UniqueIdLength + SymbolicName.Length + sizeof(DATABASE_ENTRY);
DatabaseEntry->EntryReferences = 1;
DatabaseEntry->SymbolicNameOffset = sizeof(DATABASE_ENTRY);
DatabaseEntry->SymbolicNameLength = SymbolicName.Length;
DatabaseEntry->UniqueIdOffset = SymbolicName.Length + sizeof(DATABASE_ENTRY);
DatabaseEntry->UniqueIdLength = UniqueId->UniqueIdLength;
RtlCopyMemory((PVOID)((ULONG_PTR)DatabaseEntry + DatabaseEntry->SymbolicNameOffset), SymbolicName.Buffer, DatabaseEntry->SymbolicNameLength);
RtlCopyMemory((PVOID)((ULONG_PTR)DatabaseEntry + DatabaseEntry->UniqueIdOffset), UniqueId->UniqueId, UniqueId->UniqueIdLength);
/* And write it remotely */
Status = AddRemoteDatabaseEntry(DatabaseHandle, DatabaseEntry);
if (!NT_SUCCESS(Status))
{
FreePool(DatabaseEntry);
goto FreeUniqueId;
}
FreePool(UniqueId);
FreePool(DatabaseEntry);
KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
}
}
}
else
{
/* We failed finding it remotely
* So, let's allocate a new remote DB entry
*/
KeWaitForSingleObject(&DeviceExtension->DeviceLock, Executive, KernelMode, FALSE, NULL);
/* To be able to do so, we need the device Unique ID, ask master */
Status = QueryUniqueIdFromMaster(DeviceExtension, &SymbolicName, &UniqueId);
KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
if (NT_SUCCESS(Status))
{
/* Allocate a new entry big enough */
DatabaseEntry = AllocatePool(UniqueId->UniqueIdLength + SymbolicName.Length + sizeof(DATABASE_ENTRY));
if (DatabaseEntry != NULL)
{
/* Configure it */
DatabaseEntry->EntrySize = UniqueId->UniqueIdLength + SymbolicName.Length + sizeof(DATABASE_ENTRY);
DatabaseEntry->EntryReferences = 1;
DatabaseEntry->SymbolicNameOffset = sizeof(DATABASE_ENTRY);
DatabaseEntry->SymbolicNameLength = SymbolicName.Length;
DatabaseEntry->UniqueIdOffset = SymbolicName.Length + sizeof(DATABASE_ENTRY);
DatabaseEntry->UniqueIdLength = UniqueId->UniqueIdLength;
RtlCopyMemory((PVOID)((ULONG_PTR)DatabaseEntry + DatabaseEntry->SymbolicNameOffset), SymbolicName.Buffer, DatabaseEntry->SymbolicNameLength);
RtlCopyMemory((PVOID)((ULONG_PTR)DatabaseEntry + DatabaseEntry->UniqueIdOffset), UniqueId->UniqueId, UniqueId->UniqueIdLength);
/* And write it remotely */
Status = AddRemoteDatabaseEntry(DatabaseHandle, DatabaseEntry);
FreePool(DatabaseEntry);
FreePool(UniqueId);
if (!NT_SUCCESS(Status))
{
goto FreeVolume;
}
}
else
{
FreePool(UniqueId);
}
}
}
/* Find info about the device associated associated with the mount point */
KeWaitForSingleObject(&DeviceExtension->DeviceLock, Executive, KernelMode, FALSE, NULL);
Status = FindDeviceInfo(DeviceExtension, &SymbolicName, FALSE, &ListDeviceInfo);
if (!NT_SUCCESS(Status))
{
FailedFinding = TRUE;
FreePool(VolumeName.Buffer);
}
else
{
/* Associate the device with the currrent DB */
AssociatedDevice = AllocatePool(sizeof(ASSOCIATED_DEVICE_ENTRY));
if (AssociatedDevice == NULL)
{
FreePool(VolumeName.Buffer);
}
else
{
AssociatedDevice->DeviceInformation = DeviceInformation;
AssociatedDevice->String.Length = VolumeName.Length;
AssociatedDevice->String.MaximumLength = VolumeName.MaximumLength;
AssociatedDevice->String.Buffer = VolumeName.Buffer;
InsertTailList(&ListDeviceInfo->AssociatedDevicesHead, &AssociatedDevice->AssociatedDevicesEntry);
}
/* If we don't have to skip notifications, notify */
if (!ListDeviceInfo->SkipNotifications)
{
PostOnlineNotification(DeviceExtension, &ListDeviceInfo->SymbolicName);
}
}
KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
}
/* We don't need mount points any longer */
ZwClose(Handle);
/* Look for the DB again */
KeWaitForSingleObject(&DeviceExtension->DeviceLock, Executive, KernelMode, FALSE, NULL);
for (Entry = DeviceExtension->DeviceListHead.Flink;
Entry != &DeviceExtension->DeviceListHead;
Entry = Entry->Flink)
{
ListDeviceInfo = CONTAINING_RECORD(Entry, DEVICE_INFORMATION, DeviceListEntry);
if (ListDeviceInfo == DeviceInformation)
{
break;
}
}
if (Entry == &DeviceExtension->DeviceListHead)
{
ListDeviceInfo = NULL;
}
/* Start the pruning loop */
Offset = 0;
for (;;)
{
/* Get the entry */
DatabaseEntry = GetRemoteDatabaseEntry(DatabaseHandle, Offset);
if (DatabaseEntry == NULL)
{
break;
}
/* It's not referenced anylonger? Prune it */
if (DatabaseEntry->EntryReferences == 0)
{
Status = DeleteRemoteDatabaseEntry(DatabaseHandle, Offset);
if (!NT_SUCCESS(Status))
{
FreePool(DatabaseEntry);
KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
goto CloseRDB;
}
}
/* Update the Unique IDs to reflect the changes we might have done previously */
else
{
if (ListDeviceInfo != NULL)
{
UpdateReplicatedUniqueIds(ListDeviceInfo, DatabaseEntry);
}
Offset += DatabaseEntry->EntrySize;
}
FreePool(DatabaseEntry);
}
/* We do have a DB now :-) */
if (ListDeviceInfo != NULL && !FailedFinding)
{
DeviceInformation->NoDatabase = FALSE;
}
KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
goto CloseRDB;
FreeUniqueId:
FreePool(UniqueId);
ReleaseDeviceLock:
KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
FreeDBEntry:
FreePool(DatabaseEntry);
FreeVolume:
FreePool(VolumeName.Buffer);
CloseReparse:
ZwClose(Handle);
CloseRDB:
CloseRemoteDatabase(DatabaseHandle);
ReleaseRDS:
ReleaseRemoteDatabaseSemaphore(DeviceExtension);
return;
}
@ -1247,165 +1986,6 @@ OpenRemoteDatabase(IN PDEVICE_INFORMATION DeviceInformation,
return Database;
}
/*
* @implemented
*/
NTSTATUS
NTAPI
QueryUniqueIdQueryRoutine(IN PWSTR ValueName,
IN ULONG ValueType,
IN PVOID ValueData,
IN ULONG ValueLength,
IN PVOID Context,
IN PVOID EntryContext)
{
PMOUNTDEV_UNIQUE_ID IntUniqueId;
PMOUNTDEV_UNIQUE_ID * UniqueId;
UNREFERENCED_PARAMETER(ValueName);
UNREFERENCED_PARAMETER(ValueType);
UNREFERENCED_PARAMETER(EntryContext);
/* Sanity check */
if (ValueLength >= 0x10000)
{
return STATUS_SUCCESS;
}
/* Allocate the Unique ID */
IntUniqueId = AllocatePool(sizeof(UniqueId) + ValueLength);
if (IntUniqueId)
{
/* Copy data & return */
IntUniqueId->UniqueIdLength = (USHORT)ValueLength;
RtlCopyMemory(&(IntUniqueId->UniqueId), ValueData, ValueLength);
UniqueId = Context;
*UniqueId = IntUniqueId;
}
return STATUS_SUCCESS;
}
/*
* @implemented
*/
NTSTATUS
QueryUniqueIdFromMaster(IN PDEVICE_EXTENSION DeviceExtension,
IN PUNICODE_STRING SymbolicName,
OUT PMOUNTDEV_UNIQUE_ID * UniqueId)
{
NTSTATUS Status;
PDEVICE_INFORMATION DeviceInformation;
RTL_QUERY_REGISTRY_TABLE QueryTable[2];
/* Query the unique ID */
RtlZeroMemory(QueryTable, sizeof(QueryTable));
QueryTable[0].QueryRoutine = QueryUniqueIdQueryRoutine;
QueryTable[0].Name = SymbolicName->Buffer;
*UniqueId = NULL;
RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
DatabasePath,
QueryTable,
UniqueId,
NULL);
/* Unique ID found, no need to go farther */
if (*UniqueId)
{
return STATUS_SUCCESS;
}
/* Otherwise, find associate device information */
Status = FindDeviceInfo(DeviceExtension, SymbolicName, FALSE, &DeviceInformation);
if (!NT_SUCCESS(Status))
{
return Status;
}
*UniqueId = AllocatePool(DeviceInformation->UniqueId->UniqueIdLength + sizeof(MOUNTDEV_UNIQUE_ID));
if (!*UniqueId)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
/* Return this unique ID (better than nothing) */
(*UniqueId)->UniqueIdLength = DeviceInformation->UniqueId->UniqueIdLength;
RtlCopyMemory(&((*UniqueId)->UniqueId), &(DeviceInformation->UniqueId->UniqueId), (*UniqueId)->UniqueIdLength);
return STATUS_SUCCESS;
}
/*
* @implemented
*/
NTSTATUS
WriteUniqueIdToMaster(IN PDEVICE_EXTENSION DeviceExtension,
IN PDATABASE_ENTRY DatabaseEntry)
{
NTSTATUS Status;
PWCHAR SymbolicName;
PLIST_ENTRY NextEntry;
UNICODE_STRING SymbolicString;
PDEVICE_INFORMATION DeviceInformation;
/* Create symbolic name from database entry */
SymbolicName = AllocatePool(DatabaseEntry->SymbolicNameLength + sizeof(WCHAR));
if (!SymbolicName)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlCopyMemory(SymbolicName,
(PVOID)((ULONG_PTR)DatabaseEntry + DatabaseEntry->SymbolicNameOffset),
DatabaseEntry->SymbolicNameLength);
SymbolicName[DatabaseEntry->SymbolicNameLength / sizeof(WCHAR)] = UNICODE_NULL;
/* Associate the unique ID with the name from remote database */
Status = RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE,
DatabasePath,
SymbolicName,
REG_BINARY,
(PVOID)((ULONG_PTR)DatabaseEntry + DatabaseEntry->UniqueIdOffset),
DatabaseEntry->UniqueIdLength);
FreePool(SymbolicName);
/* Reget symbolic name */
SymbolicString.Length = DatabaseEntry->SymbolicNameLength;
SymbolicString.MaximumLength = DatabaseEntry->SymbolicNameLength;
SymbolicString.Buffer = (PVOID)((ULONG_PTR)DatabaseEntry + DatabaseEntry->SymbolicNameOffset);
/* Find the device using this unique ID */
for (NextEntry = DeviceExtension->DeviceListHead.Flink;
NextEntry != &(DeviceExtension->DeviceListHead);
NextEntry = NextEntry->Flink)
{
DeviceInformation = CONTAINING_RECORD(NextEntry,
DEVICE_INFORMATION,
DeviceListEntry);
if (DeviceInformation->UniqueId->UniqueIdLength != DatabaseEntry->UniqueIdLength)
{
continue;
}
if (RtlCompareMemory((PVOID)((ULONG_PTR)DatabaseEntry + DatabaseEntry->UniqueIdOffset),
DeviceInformation->UniqueId->UniqueId,
DatabaseEntry->UniqueIdLength) == DatabaseEntry->UniqueIdLength)
{
break;
}
}
/* If found, create a mount point */
if (NextEntry != &(DeviceExtension->DeviceListHead))
{
MountMgrCreatePointWorker(DeviceExtension, &SymbolicString, &(DeviceInformation->DeviceName));
}
return Status;
}
/*
* @implemented
*/

View file

@ -420,6 +420,18 @@ HasNoDriveLetterEntry(
IN PMOUNTDEV_UNIQUE_ID UniqueId
);
VOID
UpdateReplicatedUniqueIds(
IN PDEVICE_INFORMATION DeviceInformation,
IN PDATABASE_ENTRY DatabaseEntry
);
BOOLEAN
IsUniqueIdPresent(
IN PDEVICE_EXTENSION DeviceExtension,
IN PDATABASE_ENTRY DatabaseEntry
);
/* point.c */
NTSTATUS
MountMgrCreatePointWorker(

View file

@ -43,11 +43,6 @@ LONG Unloading;
static const WCHAR Cunc[] = L"\\??\\C:";
/*
* TODO:
* - ReconcileThisDatabaseWithMasterWorker
*/
/*
* @implemented
*/