/* * @implemented */ BOOLEAN RedirectSavedLink(IN PSAVED_LINK_INFORMATION SavedLinkInformation, IN PUNICODE_STRING DosName, IN PUNICODE_STRING NewLink) { PLIST_ENTRY NextEntry; PSYMLINK_INFORMATION SymlinkInformation; /* Find the link */ for (NextEntry = SavedLinkInformation->SymbolicLinksListHead.Flink; NextEntry != &(SavedLinkInformation->SymbolicLinksListHead); NextEntry = NextEntry->Flink) { SymlinkInformation = CONTAINING_RECORD(NextEntry, SYMLINK_INFORMATION, SymbolicLinksListEntry); if (!RtlEqualUnicodeString(DosName, &(SymlinkInformation->Name), TRUE)) { /* Delete old link */ GlobalDeleteSymbolicLink(DosName); /* Set its new location */ GlobalCreateSymbolicLink(DosName, NewLink); /* And remove it from the list (not valid any more) */ RemoveEntryList(&(SymlinkInformation->SymbolicLinksListEntry)); FreePool(SymlinkInformation->Name.Buffer); FreePool(SymlinkInformation); return TRUE; } } return FALSE; }
/* * @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; }