From 126429227ec83e6b9410d85aa4f1d84b3fb5ae61 Mon Sep 17 00:00:00 2001 From: Gus Date: Sun, 28 Jul 2019 10:27:08 +0200 Subject: [PATCH] Added ability to backup device provisioned partitions --- ViewModels/BackupTargetSelectionViewModel.cs | 35 ++++- ViewModels/BackupViewModel.cs | 150 ++++++++++++++++++- Views/BackupView.xaml | 38 ++++- 3 files changed, 220 insertions(+), 3 deletions(-) diff --git a/ViewModels/BackupTargetSelectionViewModel.cs b/ViewModels/BackupTargetSelectionViewModel.cs index 8364f0a..d915981 100644 --- a/ViewModels/BackupTargetSelectionViewModel.cs +++ b/ViewModels/BackupTargetSelectionViewModel.cs @@ -28,14 +28,16 @@ namespace WPinternals private PhoneNotifierViewModel PhoneNotifier; private Action BackupCallback; private Action BackupArchiveCallback; + private Action BackupArchiveProvisioningCallback; internal Action SwitchToUnlockBoot; - internal BackupTargetSelectionViewModel(PhoneNotifierViewModel PhoneNotifier, Action SwitchToUnlockBoot, Action BackupArchiveCallback, Action BackupCallback) + internal BackupTargetSelectionViewModel(PhoneNotifierViewModel PhoneNotifier, Action SwitchToUnlockBoot, Action BackupArchiveCallback, Action BackupCallback, Action BackupArchiveProvisioningCallback) : base() { this.PhoneNotifier = PhoneNotifier; this.BackupCallback = BackupCallback; this.BackupArchiveCallback = BackupArchiveCallback; + this.BackupArchiveProvisioningCallback = BackupArchiveProvisioningCallback; this.SwitchToUnlockBoot = SwitchToUnlockBoot; this.PhoneNotifier.NewDeviceArrived += NewDeviceArrived; @@ -112,6 +114,23 @@ namespace WPinternals } } + private string _ArchiveProvisioningPath; + public string ArchiveProvisioningPath + { + get + { + return _ArchiveProvisioningPath; + } + set + { + if (value != _ArchiveProvisioningPath) + { + _ArchiveProvisioningPath = value; + OnPropertyChanged("ArchiveProvisioningPath"); + } + } + } + private bool _IsPhoneDisconnected; public bool IsPhoneDisconnected { @@ -189,6 +208,19 @@ namespace WPinternals } } + private DelegateCommand _BackupArchiveProvisioningCommand; + public DelegateCommand BackupArchiveProvisioningCommand + { + get + { + if (_BackupArchiveProvisioningCommand == null) + { + _BackupArchiveProvisioningCommand = new DelegateCommand(() => { BackupArchiveProvisioningCallback(ArchiveProvisioningPath); }, () => ((ArchiveProvisioningPath != null) && (PhoneNotifier.CurrentInterface != null))); + } + return _BackupArchiveProvisioningCommand; + } + } + ~BackupTargetSelectionViewModel() { PhoneNotifier.NewDeviceArrived -= NewDeviceArrived; @@ -211,6 +243,7 @@ namespace WPinternals IsPhoneInOtherMode = (!IsPhoneDisconnected && !IsPhoneInMassStorage); BackupCommand.RaiseCanExecuteChanged(); BackupArchiveCommand.RaiseCanExecuteChanged(); + BackupArchiveProvisioningCommand.RaiseCanExecuteChanged(); } } } diff --git a/ViewModels/BackupViewModel.cs b/ViewModels/BackupViewModel.cs index cc4ae37..cb96677 100644 --- a/ViewModels/BackupViewModel.cs +++ b/ViewModels/BackupViewModel.cs @@ -49,7 +49,7 @@ namespace WPinternals if (SubContextViewModel == null) { - ActivateSubContext(new BackupTargetSelectionViewModel(PhoneNotifier, SwitchToUnlockBoot, DoBackupArchive, DoBackup)); + ActivateSubContext(new BackupTargetSelectionViewModel(PhoneNotifier, SwitchToUnlockBoot, DoBackupArchive, DoBackup, DoBackupArchiveProvisioning)); IsSwitchingInterface = false; } @@ -87,6 +87,21 @@ namespace WPinternals } } + internal async void DoBackupArchiveProvisioning(string ArchiveProvisioningPath) + { + try + { + IsSwitchingInterface = true; + await SwitchModeViewModel.SwitchToWithProgress(PhoneNotifier, PhoneInterfaces.Lumia_MassStorage, + (msg, sub) => ActivateSubContext(new BusyViewModel(msg, sub))); + BackupArchiveProvisioningTask(ArchiveProvisioningPath); + } + catch (Exception Ex) + { + ActivateSubContext(new MessageViewModel(Ex.Message, Callback)); + } + } + internal void BackupTask(string EFIESPPath, string MainOSPath, string DataPath) { IsSwitchingInterface = false; @@ -343,6 +358,139 @@ namespace WPinternals }).Start(); } + private readonly static string[] ProvisioningPartitions = new string[] + { + "DPP", + "MODEM_FSG", + "MODEM_FS1", + "MODEM_FS2", + "MODEM_FSC", + "DDR", + "SEC", + "APDP", + "MSADP", + "DPO", + "SSD", + "DBI", + "UEFI_BS_NV", + "UEFI_NV", + "UEFI_RT_NV", + "UEFI_RT_NV_RPMB", + "BOOTMODE", + "LIMITS" + }; + + internal void BackupArchiveProvisioningTask(string ArchiveProvisioningPath) + { + IsSwitchingInterface = false; + new Thread(() => + { + bool Result = true; + + ActivateSubContext(new BusyViewModel("Initializing backup...")); + + ulong TotalSizeSectors = 0; + int PartitionCount = 0; + + MassStorage Phone = (MassStorage)PhoneNotifier.CurrentModel; + + try + { + Phone.OpenVolume(false); + byte[] GPTBuffer = Phone.ReadSectors(1, 33); + GPT GPT = new WPinternals.GPT(GPTBuffer); + + Partition Partition; + + try + { + foreach (string PartitionName in ProvisioningPartitions) + { + if (GPT.Partitions.Any(p => p.Name == PartitionName)) + { + Partition = GPT.Partitions.Where(p => p.Name == PartitionName).First(); + if (PartitionName == "UEFI_BS_NV" && GPT.Partitions.Any(p => p.Name == "BACKUP_BS_NV")) + { + Partition = GPT.Partitions.Where(p => p.Name == "BACKUP_BS_NV").First(); + } + + TotalSizeSectors += Partition.SizeInSectors; + PartitionCount++; + } + } + } + catch (Exception Ex) + { + LogFile.LogException(Ex); + Result = false; + } + + BusyViewModel Busy = new BusyViewModel("Create backup...", MaxProgressValue: TotalSizeSectors, UIContext: UIContext); + ProgressUpdater Updater = Busy.ProgressUpdater; + ActivateSubContext(Busy); + ZipArchiveEntry Entry; + Stream EntryStream = null; + + using (FileStream FileStream = new FileStream(ArchiveProvisioningPath, FileMode.Create)) + { + using (ZipArchive Archive = new ZipArchive(FileStream, ZipArchiveMode.Create)) + { + int i = 0; + + foreach (string PartitionName in ProvisioningPartitions) + { + if (GPT.Partitions.Any(p => p.Name == PartitionName)) + { + if (Result) + { + try + { + Entry = Archive.CreateEntry(PartitionName + ".bin", CompressionLevel.Optimal); + EntryStream = Entry.Open(); + i++; + Busy.Message = "Create backup of partition " + PartitionName + " (" + i.ToString() + @"/" + PartitionCount.ToString() + ")"; + if (PartitionName == "UEFI_BS_NV" && GPT.Partitions.Any(p => p.Name == "BACKUP_BS_NV")) + { + Phone.BackupPartition("BACKUP_BS_NV", EntryStream, Updater); + } + else + { + Phone.BackupPartition(PartitionName, EntryStream, Updater); + } + } + catch (Exception Ex) + { + LogFile.LogException(Ex); + Result = false; + } + finally + { + if (EntryStream != null) + EntryStream.Close(); + EntryStream = null; + } + } + } + } + } + } + } + catch { } + finally + { + Phone.CloseVolume(); + } + + if (!Result) + { + ActivateSubContext(new MessageViewModel("Failed to create backup!", Exit)); + return; + } + + ActivateSubContext(new MessageViewModel("Successfully created a backup!", Exit)); + }).Start(); + } + private void Exit() { IsSwitchingInterface = false; diff --git a/Views/BackupView.xaml b/Views/BackupView.xaml index 7979ef5..564223a 100644 --- a/Views/BackupView.xaml +++ b/Views/BackupView.xaml @@ -68,7 +68,7 @@ DEALINGS IN THE SOFTWARE. - + @@ -108,5 +108,41 @@ DEALINGS IN THE SOFTWARE. + + + + + + + + + + + + + + + unlocked + + + + + + + + + + + + + +