/* * @implemented */ NTSTATUS NTAPI MountMgrTargetDeviceNotification(IN PVOID NotificationStructure, IN PVOID Context) { PDEVICE_EXTENSION DeviceExtension; PDEVICE_INFORMATION DeviceInformation; PDEVICE_INTERFACE_CHANGE_NOTIFICATION Notification; DeviceInformation = Context; DeviceExtension = DeviceInformation->DeviceExtension; Notification = NotificationStructure; /* If it's to signal that removal is complete, then, execute the function */ if (IsEqualGUID(&(Notification->Event), &GUID_TARGET_DEVICE_REMOVE_COMPLETE)) { MountMgrMountedDeviceRemoval(DeviceExtension, Notification->SymbolicLinkName); } /* It it's to signal that a volume has been mounted * Verify if a database sync is required and execute it */ else if (IsEqualGUID(&(Notification->Event), &GUID_IO_VOLUME_MOUNT)) { if (InterlockedCompareExchange(&(DeviceInformation->MountState), FALSE, TRUE) == TRUE) { InterlockedDecrement(&(DeviceInformation->MountState)); } else { if (DeviceInformation->NeedsReconcile) { DeviceInformation->NeedsReconcile = FALSE; ReconcileThisDatabaseWithMaster(DeviceExtension, DeviceInformation); } } } return STATUS_SUCCESS; }
/* * @implemented */ NTSTATUS MountMgrCreatePointWorker(IN PDEVICE_EXTENSION DeviceExtension, IN PUNICODE_STRING SymbolicLinkName, IN PUNICODE_STRING DeviceName) { NTSTATUS Status; PLIST_ENTRY DeviceEntry; PMOUNTDEV_UNIQUE_ID UniqueId; PSYMLINK_INFORMATION SymlinkInformation; UNICODE_STRING SymLink, TargetDeviceName; PDEVICE_INFORMATION DeviceInformation = NULL, DeviceInfo; /* Get device name */ Status = QueryDeviceInformation(SymbolicLinkName, &TargetDeviceName, NULL, NULL, NULL, NULL, NULL, NULL); if (!NT_SUCCESS(Status)) { return Status; } /* First of all, try to find device */ for (DeviceEntry = DeviceExtension->DeviceListHead.Flink; DeviceEntry != &(DeviceExtension->DeviceListHead); DeviceEntry = DeviceEntry->Flink) { DeviceInformation = CONTAINING_RECORD(DeviceEntry, DEVICE_INFORMATION, DeviceListEntry); if (RtlCompareUnicodeString(&TargetDeviceName, &(DeviceInformation->DeviceName), TRUE) == 0) { break; } } /* Copy symbolic link name and null terminate it */ SymLink.Buffer = AllocatePool(SymbolicLinkName->Length + sizeof(UNICODE_NULL)); if (!SymLink.Buffer) { FreePool(TargetDeviceName.Buffer); return STATUS_INSUFFICIENT_RESOURCES; } RtlCopyMemory(SymLink.Buffer, SymbolicLinkName->Buffer, SymbolicLinkName->Length); SymLink.Buffer[SymbolicLinkName->Length / sizeof(WCHAR)] = UNICODE_NULL; SymLink.Length = SymbolicLinkName->Length; SymLink.MaximumLength = SymbolicLinkName->Length + sizeof(UNICODE_NULL); /* If we didn't find device */ if (DeviceEntry == &(DeviceExtension->DeviceListHead)) { /* Then, try with unique ID */ Status = QueryDeviceInformation(SymbolicLinkName, NULL, &UniqueId, NULL, NULL, NULL, NULL, NULL); if (!NT_SUCCESS(Status)) { FreePool(TargetDeviceName.Buffer); FreePool(SymLink.Buffer); return Status; } /* Create a link to the device */ Status = GlobalCreateSymbolicLink(&SymLink, &TargetDeviceName); if (!NT_SUCCESS(Status)) { FreePool(UniqueId); FreePool(TargetDeviceName.Buffer); FreePool(SymLink.Buffer); return Status; } /* If caller provided driver letter, delete it */ if (IsDriveLetter(&SymLink)) { DeleteRegistryDriveLetter(UniqueId); } /* Device will be identified with its unique ID */ Status = RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE, DatabasePath, SymLink.Buffer, REG_BINARY, UniqueId->UniqueId, UniqueId->UniqueIdLength); FreePool(UniqueId); FreePool(TargetDeviceName.Buffer); FreePool(SymLink.Buffer); return Status; } /* If call provided a driver letter whereas device already has one * fail, this is not doable */ if (IsDriveLetter(&SymLink) && HasDriveLetter(DeviceInformation)) { FreePool(TargetDeviceName.Buffer); FreePool(SymLink.Buffer); return STATUS_INVALID_PARAMETER; } /* Now, create a link */ Status = GlobalCreateSymbolicLink(&SymLink, &TargetDeviceName); FreePool(TargetDeviceName.Buffer); if (!NT_SUCCESS(Status)) { FreePool(SymLink.Buffer); return Status; } /* Associate Unique ID <-> symbolic name */ UniqueId = DeviceInformation->UniqueId; Status = RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE, DatabasePath, SymLink.Buffer, REG_BINARY, UniqueId->UniqueId, UniqueId->UniqueIdLength); if (!NT_SUCCESS(Status)) { GlobalDeleteSymbolicLink(&SymLink); FreePool(SymLink.Buffer); return Status; } /* Now, prepare to save the link with the device */ SymlinkInformation = AllocatePool(sizeof(SYMLINK_INFORMATION)); if (!SymlinkInformation) { Status = STATUS_INSUFFICIENT_RESOURCES; GlobalDeleteSymbolicLink(&SymLink); FreePool(SymLink.Buffer); return Status; } SymlinkInformation->Name.Length = SymLink.Length; SymlinkInformation->Name.MaximumLength = SymLink.Length + sizeof(UNICODE_NULL); SymlinkInformation->Name.Buffer = AllocatePool(SymlinkInformation->Name.MaximumLength); if (!SymlinkInformation->Name.Buffer) { Status = STATUS_INSUFFICIENT_RESOURCES; FreePool(SymlinkInformation); GlobalDeleteSymbolicLink(&SymLink); FreePool(SymLink.Buffer); return Status; } /* Save the link and mark it online */ RtlCopyMemory(SymlinkInformation->Name.Buffer, SymLink.Buffer, SymlinkInformation->Name.Length); SymlinkInformation->Name.Buffer[SymlinkInformation->Name.Length / sizeof(WCHAR)] = UNICODE_NULL; SymlinkInformation->Online = TRUE; InsertTailList(&DeviceInformation->SymbolicLinksListHead, &SymlinkInformation->SymbolicLinksListEntry); SendLinkCreated(&(SymlinkInformation->Name)); /* If we have a drive letter */ if (IsDriveLetter(&SymLink)) { /* Then, delete the no drive letter entry */ DeleteNoDriveLetterEntry(UniqueId); /* And post online notification if asked */ if (!DeviceInformation->SkipNotifications) { PostOnlineNotification(DeviceExtension, &DeviceInformation->SymbolicName); } } /* If that's a volume with automatic drive letter, it's now time to resync databases */ if (MOUNTMGR_IS_VOLUME_NAME(&SymLink) && DeviceExtension->AutomaticDriveLetter) { for (DeviceEntry = DeviceExtension->DeviceListHead.Flink; DeviceEntry != &(DeviceExtension->DeviceListHead); DeviceEntry = DeviceEntry->Flink) { DeviceInfo = CONTAINING_RECORD(DeviceEntry, DEVICE_INFORMATION, DeviceListEntry); /* If there's one, ofc! */ if (!DeviceInfo->NoDatabase) { ReconcileThisDatabaseWithMaster(DeviceExtension, DeviceInfo); } } } /* Notify & quit */ FreePool(SymLink.Buffer); MountMgrNotify(DeviceExtension); if (!DeviceInformation->Volume) { MountMgrNotifyNameChange(DeviceExtension, DeviceName, FALSE); } return Status; }
/* * @implemented */ VOID MountMgrUniqueIdChangeRoutine(IN PDEVICE_EXTENSION DeviceExtension, IN PMOUNTDEV_UNIQUE_ID OldUniqueId, IN PMOUNTDEV_UNIQUE_ID NewUniqueId) { NTSTATUS Status; BOOLEAN ResyncNeeded; PUNIQUE_ID_REPLICATE DuplicateId; PDEVICE_INFORMATION DeviceInformation; RTL_QUERY_REGISTRY_TABLE QueryTable[2]; PMOUNTDEV_UNIQUE_ID UniqueId, NewDuplicateId; PLIST_ENTRY ListHead, NextEntry, ReplicatedHead, NextReplicated; /* Synchronise with remote databases */ Status = WaitForRemoteDatabaseSemaphore(DeviceExtension); KeWaitForSingleObject(&(DeviceExtension->DeviceLock), Executive, KernelMode, FALSE, NULL); RtlZeroMemory(QueryTable, sizeof(QueryTable)); QueryTable[0].QueryRoutine = ChangeUniqueIdRoutine; QueryTable[0].EntryContext = NewUniqueId; /* Write new data */ RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE, DatabasePath, QueryTable, OldUniqueId, NULL); /* Browse all the devices to find the one that * owns the old unique ID */ ListHead = &(DeviceExtension->DeviceListHead); NextEntry = ListHead->Flink; while (ListHead != NextEntry) { DeviceInformation = CONTAINING_RECORD(NextEntry, DEVICE_INFORMATION, DeviceListEntry); if (DeviceInformation->UniqueId->UniqueIdLength == OldUniqueId->UniqueIdLength && RtlCompareMemory(OldUniqueId->UniqueId, DeviceInformation->UniqueId->UniqueId, OldUniqueId->UniqueIdLength) == OldUniqueId->UniqueIdLength) { break; } NextEntry = NextEntry->Flink; } /* If we didn't find any release everything and quit */ if (ListHead == NextEntry) { KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE); if (NT_SUCCESS(Status)) { ReleaseRemoteDatabaseSemaphore(DeviceExtension); } return; } /* If lock failed, then, just update this database */ if (!NT_SUCCESS(Status)) { ReconcileThisDatabaseWithMaster(DeviceExtension, DeviceInformation); KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE); return; } /* Allocate new unique ID */ UniqueId = AllocatePool(NewUniqueId->UniqueIdLength + sizeof(MOUNTDEV_UNIQUE_ID)); if (!UniqueId) { KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE); ReleaseRemoteDatabaseSemaphore(DeviceExtension); return; } /* Release old one */ FreePool(DeviceInformation->UniqueId); /* And set new one */ DeviceInformation->UniqueId = UniqueId; UniqueId->UniqueIdLength = NewUniqueId->UniqueIdLength; RtlCopyMemory(UniqueId->UniqueId, NewUniqueId->UniqueId, NewUniqueId->UniqueIdLength); /* Now, check if it's required to update replicated unique IDs as well */ ListHead = &(DeviceExtension->DeviceListHead); NextEntry = ListHead->Flink; while (ListHead != NextEntry) { DeviceInformation = CONTAINING_RECORD(NextEntry, DEVICE_INFORMATION, DeviceListEntry); ResyncNeeded = FALSE; ReplicatedHead = &(DeviceInformation->ReplicatedUniqueIdsListHead); NextReplicated = ReplicatedHead->Flink; while (ReplicatedHead != NextReplicated) { DuplicateId = CONTAINING_RECORD(NextReplicated, UNIQUE_ID_REPLICATE, ReplicatedUniqueIdsListEntry); if (DuplicateId->UniqueId->UniqueIdLength == OldUniqueId->UniqueIdLength) { if (RtlCompareMemory(DuplicateId->UniqueId->UniqueId, OldUniqueId->UniqueId, OldUniqueId->UniqueIdLength) == OldUniqueId->UniqueIdLength) { /* It was our old unique ID */ NewDuplicateId = AllocatePool(NewUniqueId->UniqueIdLength + sizeof(MOUNTDEV_UNIQUE_ID)); if (NewDuplicateId) { /* Update it */ ResyncNeeded = TRUE; FreePool(DuplicateId->UniqueId); DuplicateId->UniqueId = NewDuplicateId; DuplicateId->UniqueId->UniqueIdLength = NewUniqueId->UniqueIdLength; RtlCopyMemory(NewDuplicateId->UniqueId, NewUniqueId->UniqueId, NewUniqueId->UniqueIdLength); } } } NextReplicated = NextReplicated->Flink; } /* If resync is required on this device, do it */ if (ResyncNeeded) { ChangeRemoteDatabaseUniqueId(DeviceInformation, OldUniqueId, NewUniqueId); } NextEntry = NextEntry->Flink; } KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE); ReleaseRemoteDatabaseSemaphore(DeviceExtension); return; }