Added ability to backup device provisioned partitions

This commit is contained in:
Gus
2019-07-28 10:27:08 +02:00
parent bf7b09d551
commit 126429227e
3 changed files with 220 additions and 3 deletions
+34 -1
View File
@@ -28,14 +28,16 @@ namespace WPinternals
private PhoneNotifierViewModel PhoneNotifier;
private Action<string, string, string> BackupCallback;
private Action<string> BackupArchiveCallback;
private Action<string> BackupArchiveProvisioningCallback;
internal Action SwitchToUnlockBoot;
internal BackupTargetSelectionViewModel(PhoneNotifierViewModel PhoneNotifier, Action SwitchToUnlockBoot, Action<string> BackupArchiveCallback, Action<string, string, string> BackupCallback)
internal BackupTargetSelectionViewModel(PhoneNotifierViewModel PhoneNotifier, Action SwitchToUnlockBoot, Action<string> BackupArchiveCallback, Action<string, string, string> BackupCallback, Action<string> 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();
}
}
}
+149 -1
View File
@@ -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;