mirror of
https://github.com/jkcoxson/idevice.git
synced 2026-03-02 14:36:16 +01:00
cargofmt
This commit is contained in:
@@ -5,10 +5,10 @@
|
|||||||
|
|
||||||
use log::{debug, warn};
|
use log::{debug, warn};
|
||||||
use plist::Dictionary;
|
use plist::Dictionary;
|
||||||
use tokio::io::AsyncReadExt;
|
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::io::{Read, Write};
|
use std::io::{Read, Write};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
use tokio::io::AsyncReadExt;
|
||||||
|
|
||||||
use crate::{Idevice, IdeviceError, IdeviceService, obf};
|
use crate::{Idevice, IdeviceError, IdeviceService, obf};
|
||||||
|
|
||||||
@@ -156,21 +156,56 @@ impl Default for RestoreOptions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl RestoreOptions {
|
impl RestoreOptions {
|
||||||
pub fn new() -> Self { Self::default() }
|
pub fn new() -> Self {
|
||||||
pub fn with_reboot(mut self, reboot: bool) -> Self { self.reboot = reboot; self }
|
Self::default()
|
||||||
pub fn with_copy(mut self, copy: bool) -> Self { self.copy = copy; self }
|
}
|
||||||
pub fn with_preserve_settings(mut self, preserve: bool) -> Self { self.preserve_settings = preserve; self }
|
pub fn with_reboot(mut self, reboot: bool) -> Self {
|
||||||
pub fn with_system_files(mut self, system: bool) -> Self { self.system_files = system; self }
|
self.reboot = reboot;
|
||||||
pub fn with_remove_items_not_restored(mut self, remove: bool) -> Self { self.remove_items_not_restored = remove; self }
|
self
|
||||||
pub fn with_password(mut self, password: impl Into<String>) -> Self { self.password = Some(password.into()); self }
|
}
|
||||||
|
pub fn with_copy(mut self, copy: bool) -> Self {
|
||||||
|
self.copy = copy;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
pub fn with_preserve_settings(mut self, preserve: bool) -> Self {
|
||||||
|
self.preserve_settings = preserve;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
pub fn with_system_files(mut self, system: bool) -> Self {
|
||||||
|
self.system_files = system;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
pub fn with_remove_items_not_restored(mut self, remove: bool) -> Self {
|
||||||
|
self.remove_items_not_restored = remove;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
pub fn with_password(mut self, password: impl Into<String>) -> Self {
|
||||||
|
self.password = Some(password.into());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
pub fn to_plist(&self) -> Dictionary {
|
pub fn to_plist(&self) -> Dictionary {
|
||||||
let mut opts = Dictionary::new();
|
let mut opts = Dictionary::new();
|
||||||
opts.insert("RestoreShouldReboot".into(), plist::Value::Boolean(self.reboot));
|
opts.insert(
|
||||||
opts.insert("RestoreDontCopyBackup".into(), plist::Value::Boolean(!self.copy));
|
"RestoreShouldReboot".into(),
|
||||||
opts.insert("RestorePreserveSettings".into(), plist::Value::Boolean(self.preserve_settings));
|
plist::Value::Boolean(self.reboot),
|
||||||
opts.insert("RestoreSystemFiles".into(), plist::Value::Boolean(self.system_files));
|
);
|
||||||
opts.insert("RemoveItemsNotRestored".into(), plist::Value::Boolean(self.remove_items_not_restored));
|
opts.insert(
|
||||||
|
"RestoreDontCopyBackup".into(),
|
||||||
|
plist::Value::Boolean(!self.copy),
|
||||||
|
);
|
||||||
|
opts.insert(
|
||||||
|
"RestorePreserveSettings".into(),
|
||||||
|
plist::Value::Boolean(self.preserve_settings),
|
||||||
|
);
|
||||||
|
opts.insert(
|
||||||
|
"RestoreSystemFiles".into(),
|
||||||
|
plist::Value::Boolean(self.system_files),
|
||||||
|
);
|
||||||
|
opts.insert(
|
||||||
|
"RemoveItemsNotRestored".into(),
|
||||||
|
plist::Value::Boolean(self.remove_items_not_restored),
|
||||||
|
);
|
||||||
if let Some(pw) = &self.password {
|
if let Some(pw) = &self.password {
|
||||||
opts.insert("Password".into(), plist::Value::String(pw.clone()));
|
opts.insert("Password".into(), plist::Value::String(pw.clone()));
|
||||||
}
|
}
|
||||||
@@ -184,7 +219,7 @@ impl MobileBackup2Client {
|
|||||||
/// # Arguments
|
/// # Arguments
|
||||||
/// * `idevice` - Pre-established device connection
|
/// * `idevice` - Pre-established device connection
|
||||||
pub fn new(idevice: Idevice) -> Self {
|
pub fn new(idevice: Idevice) -> Self {
|
||||||
Self {
|
Self {
|
||||||
idevice,
|
idevice,
|
||||||
protocol_version: 0.0,
|
protocol_version: 0.0,
|
||||||
}
|
}
|
||||||
@@ -224,9 +259,7 @@ impl MobileBackup2Client {
|
|||||||
|
|
||||||
/// Sends a raw DL array as binary plist
|
/// Sends a raw DL array as binary plist
|
||||||
async fn send_dl_array(&mut self, array: Vec<plist::Value>) -> Result<(), IdeviceError> {
|
async fn send_dl_array(&mut self, array: Vec<plist::Value>) -> Result<(), IdeviceError> {
|
||||||
self.idevice
|
self.idevice.send_bplist(plist::Value::Array(array)).await
|
||||||
.send_bplist(plist::Value::Array(array))
|
|
||||||
.await
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Receives any DL* message and returns (message_tag, full_array_value)
|
/// Receives any DL* message and returns (message_tag, full_array_value)
|
||||||
@@ -262,17 +295,21 @@ impl MobileBackup2Client {
|
|||||||
/// Returns `IdeviceError` if version exchange fails
|
/// Returns `IdeviceError` if version exchange fails
|
||||||
async fn version_exchange(&mut self) -> Result<(), IdeviceError> {
|
async fn version_exchange(&mut self) -> Result<(), IdeviceError> {
|
||||||
debug!("Starting mobilebackup2 version exchange");
|
debug!("Starting mobilebackup2 version exchange");
|
||||||
|
|
||||||
// Send supported protocol versions (matching libimobiledevice)
|
// Send supported protocol versions (matching libimobiledevice)
|
||||||
let mut hello_dict = Dictionary::new();
|
let mut hello_dict = Dictionary::new();
|
||||||
let versions = vec![plist::Value::Real(2.0), plist::Value::Real(2.1)];
|
let versions = vec![plist::Value::Real(2.0), plist::Value::Real(2.1)];
|
||||||
hello_dict.insert("SupportedProtocolVersions".into(), plist::Value::Array(versions));
|
hello_dict.insert(
|
||||||
|
"SupportedProtocolVersions".into(),
|
||||||
self.send_device_link_message("Hello", Some(hello_dict)).await?;
|
plist::Value::Array(versions),
|
||||||
|
);
|
||||||
|
|
||||||
|
self.send_device_link_message("Hello", Some(hello_dict))
|
||||||
|
.await?;
|
||||||
|
|
||||||
// Receive response
|
// Receive response
|
||||||
let response = self.receive_device_link_message("Response").await?;
|
let response = self.receive_device_link_message("Response").await?;
|
||||||
|
|
||||||
// Check for error
|
// Check for error
|
||||||
if let Some(error_code) = response.get("ErrorCode")
|
if let Some(error_code) = response.get("ErrorCode")
|
||||||
&& let Some(code) = error_code.as_unsigned_integer()
|
&& let Some(code) = error_code.as_unsigned_integer()
|
||||||
@@ -281,7 +318,7 @@ impl MobileBackup2Client {
|
|||||||
warn!("Version exchange failed with error code: {code}");
|
warn!("Version exchange failed with error code: {code}");
|
||||||
return Err(IdeviceError::UnexpectedResponse);
|
return Err(IdeviceError::UnexpectedResponse);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get negotiated protocol version
|
// Get negotiated protocol version
|
||||||
if let Some(version) = response.get("ProtocolVersion").and_then(|v| v.as_real()) {
|
if let Some(version) = response.get("ProtocolVersion").and_then(|v| v.as_real()) {
|
||||||
self.protocol_version = version;
|
self.protocol_version = version;
|
||||||
@@ -290,7 +327,7 @@ impl MobileBackup2Client {
|
|||||||
warn!("No protocol version in response");
|
warn!("No protocol version in response");
|
||||||
return Err(IdeviceError::UnexpectedResponse);
|
return Err(IdeviceError::UnexpectedResponse);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -315,19 +352,19 @@ impl MobileBackup2Client {
|
|||||||
// Create DLMessageProcessMessage array format
|
// Create DLMessageProcessMessage array format
|
||||||
let mut message_array = Vec::new();
|
let mut message_array = Vec::new();
|
||||||
message_array.push(plist::Value::String("DLMessageProcessMessage".into()));
|
message_array.push(plist::Value::String("DLMessageProcessMessage".into()));
|
||||||
|
|
||||||
// Create the actual message dictionary
|
// Create the actual message dictionary
|
||||||
let mut message_dict = Dictionary::new();
|
let mut message_dict = Dictionary::new();
|
||||||
message_dict.insert("MessageName".into(), message_name.into());
|
message_dict.insert("MessageName".into(), message_name.into());
|
||||||
|
|
||||||
if let Some(opts) = options {
|
if let Some(opts) = options {
|
||||||
for (key, value) in opts {
|
for (key, value) in opts {
|
||||||
message_dict.insert(key, value);
|
message_dict.insert(key, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
message_array.push(plist::Value::Dictionary(message_dict));
|
message_array.push(plist::Value::Dictionary(message_dict));
|
||||||
|
|
||||||
debug!("Sending device link message: {message_name}");
|
debug!("Sending device link message: {message_name}");
|
||||||
self.idevice
|
self.idevice
|
||||||
.send_bplist(plist::Value::Array(message_array))
|
.send_bplist(plist::Value::Array(message_array))
|
||||||
@@ -344,7 +381,10 @@ impl MobileBackup2Client {
|
|||||||
///
|
///
|
||||||
/// # Errors
|
/// # Errors
|
||||||
/// Returns `IdeviceError` if communication fails or message name doesn't match
|
/// Returns `IdeviceError` if communication fails or message name doesn't match
|
||||||
async fn receive_device_link_message(&mut self, expected_message: &str) -> Result<Dictionary, IdeviceError> {
|
async fn receive_device_link_message(
|
||||||
|
&mut self,
|
||||||
|
expected_message: &str,
|
||||||
|
) -> Result<Dictionary, IdeviceError> {
|
||||||
// Read raw bytes and parse as plist::Value to handle array format
|
// Read raw bytes and parse as plist::Value to handle array format
|
||||||
if let Some(socket) = &mut self.idevice.socket {
|
if let Some(socket) = &mut self.idevice.socket {
|
||||||
debug!("Reading response size");
|
debug!("Reading response size");
|
||||||
@@ -354,7 +394,7 @@ impl MobileBackup2Client {
|
|||||||
let mut buf = vec![0; len as usize];
|
let mut buf = vec![0; len as usize];
|
||||||
socket.read_exact(&mut buf).await?;
|
socket.read_exact(&mut buf).await?;
|
||||||
let response_value: plist::Value = plist::from_bytes(&buf)?;
|
let response_value: plist::Value = plist::from_bytes(&buf)?;
|
||||||
|
|
||||||
// Parse DLMessageProcessMessage format
|
// Parse DLMessageProcessMessage format
|
||||||
if let plist::Value::Array(array) = response_value
|
if let plist::Value::Array(array) = response_value
|
||||||
&& array.len() >= 2
|
&& array.len() >= 2
|
||||||
@@ -364,7 +404,8 @@ impl MobileBackup2Client {
|
|||||||
{
|
{
|
||||||
// Check MessageName if expected
|
// Check MessageName if expected
|
||||||
if !expected_message.is_empty() {
|
if !expected_message.is_empty() {
|
||||||
if let Some(message_name) = dict.get("MessageName").and_then(|v| v.as_string()) {
|
if let Some(message_name) = dict.get("MessageName").and_then(|v| v.as_string())
|
||||||
|
{
|
||||||
if message_name != expected_message {
|
if message_name != expected_message {
|
||||||
warn!("Expected message '{expected_message}', got '{message_name}'");
|
warn!("Expected message '{expected_message}', got '{message_name}'");
|
||||||
return Err(IdeviceError::UnexpectedResponse);
|
return Err(IdeviceError::UnexpectedResponse);
|
||||||
@@ -376,7 +417,7 @@ impl MobileBackup2Client {
|
|||||||
}
|
}
|
||||||
return Ok(dict.clone());
|
return Ok(dict.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
warn!("Invalid device link message format");
|
warn!("Invalid device link message format");
|
||||||
Err(IdeviceError::UnexpectedResponse)
|
Err(IdeviceError::UnexpectedResponse)
|
||||||
} else {
|
} else {
|
||||||
@@ -400,7 +441,8 @@ impl MobileBackup2Client {
|
|||||||
message_type: BackupMessageType,
|
message_type: BackupMessageType,
|
||||||
options: Option<Dictionary>,
|
options: Option<Dictionary>,
|
||||||
) -> Result<(), IdeviceError> {
|
) -> Result<(), IdeviceError> {
|
||||||
self.send_device_link_message(message_type.as_str(), options).await
|
self.send_device_link_message(message_type.as_str(), options)
|
||||||
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sends a MobileBackup2 request with proper envelope and identifiers
|
/// Sends a MobileBackup2 request with proper envelope and identifiers
|
||||||
@@ -463,15 +505,15 @@ impl MobileBackup2Client {
|
|||||||
// Per protocol use MessageName "Info"
|
// Per protocol use MessageName "Info"
|
||||||
self.send_backup_message(BackupMessageType::BackupMessageTypeInfo, None)
|
self.send_backup_message(BackupMessageType::BackupMessageTypeInfo, None)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let response = self.receive_backup_response().await?;
|
let response = self.receive_backup_response().await?;
|
||||||
|
|
||||||
// Check for error in response
|
// Check for error in response
|
||||||
if let Some(error) = response.get("ErrorCode") {
|
if let Some(error) = response.get("ErrorCode") {
|
||||||
warn!("Backup info request failed with error: {error:?}");
|
warn!("Backup info request failed with error: {error:?}");
|
||||||
return Err(IdeviceError::UnexpectedResponse);
|
return Err(IdeviceError::UnexpectedResponse);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(response)
|
Ok(response)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -485,17 +527,17 @@ impl MobileBackup2Client {
|
|||||||
pub async fn list_backups(&mut self) -> Result<Vec<BackupInfo>, IdeviceError> {
|
pub async fn list_backups(&mut self) -> Result<Vec<BackupInfo>, IdeviceError> {
|
||||||
self.send_backup_message(BackupMessageType::BackupMessageTypeList, None)
|
self.send_backup_message(BackupMessageType::BackupMessageTypeList, None)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let response = self.receive_backup_response().await?;
|
let response = self.receive_backup_response().await?;
|
||||||
|
|
||||||
// Check for error in response
|
// Check for error in response
|
||||||
if let Some(error) = response.get("ErrorCode") {
|
if let Some(error) = response.get("ErrorCode") {
|
||||||
warn!("List backups request failed with error: {error:?}");
|
warn!("List backups request failed with error: {error:?}");
|
||||||
return Err(IdeviceError::UnexpectedResponse);
|
return Err(IdeviceError::UnexpectedResponse);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut backups = Vec::new();
|
let mut backups = Vec::new();
|
||||||
|
|
||||||
if let Some(plist::Value::Array(backup_list)) = response.get("BackupList") {
|
if let Some(plist::Value::Array(backup_list)) = response.get("BackupList") {
|
||||||
for backup_item in backup_list {
|
for backup_item in backup_list {
|
||||||
if let plist::Value::Dictionary(backup_dict) = backup_item {
|
if let plist::Value::Dictionary(backup_dict) = backup_item {
|
||||||
@@ -504,35 +546,35 @@ impl MobileBackup2Client {
|
|||||||
.and_then(|v| v.as_string())
|
.and_then(|v| v.as_string())
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
.to_string();
|
.to_string();
|
||||||
|
|
||||||
let device_name = backup_dict
|
let device_name = backup_dict
|
||||||
.get("DeviceName")
|
.get("DeviceName")
|
||||||
.and_then(|v| v.as_string())
|
.and_then(|v| v.as_string())
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
.to_string();
|
.to_string();
|
||||||
|
|
||||||
let display_name = backup_dict
|
let display_name = backup_dict
|
||||||
.get("DisplayName")
|
.get("DisplayName")
|
||||||
.and_then(|v| v.as_string())
|
.and_then(|v| v.as_string())
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
.to_string();
|
.to_string();
|
||||||
|
|
||||||
let last_backup_date = backup_dict
|
let last_backup_date = backup_dict
|
||||||
.get("LastBackupDate")
|
.get("LastBackupDate")
|
||||||
.and_then(|v| v.as_string())
|
.and_then(|v| v.as_string())
|
||||||
.map(|s| s.to_string());
|
.map(|s| s.to_string());
|
||||||
|
|
||||||
let version = backup_dict
|
let version = backup_dict
|
||||||
.get("Version")
|
.get("Version")
|
||||||
.and_then(|v| v.as_string())
|
.and_then(|v| v.as_string())
|
||||||
.unwrap_or("Unknown")
|
.unwrap_or("Unknown")
|
||||||
.to_string();
|
.to_string();
|
||||||
|
|
||||||
let is_encrypted = backup_dict
|
let is_encrypted = backup_dict
|
||||||
.get("IsEncrypted")
|
.get("IsEncrypted")
|
||||||
.and_then(|v| v.as_boolean())
|
.and_then(|v| v.as_boolean())
|
||||||
.unwrap_or(false);
|
.unwrap_or(false);
|
||||||
|
|
||||||
backups.push(BackupInfo {
|
backups.push(BackupInfo {
|
||||||
uuid,
|
uuid,
|
||||||
device_name,
|
device_name,
|
||||||
@@ -544,7 +586,7 @@ impl MobileBackup2Client {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(backups)
|
Ok(backups)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -573,15 +615,15 @@ impl MobileBackup2Client {
|
|||||||
options,
|
options,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let response = self.receive_backup_response().await?;
|
let response = self.receive_backup_response().await?;
|
||||||
|
|
||||||
// Check for error in response
|
// Check for error in response
|
||||||
if let Some(error) = response.get("ErrorCode") {
|
if let Some(error) = response.get("ErrorCode") {
|
||||||
warn!("Backup start failed with error: {error:?}");
|
warn!("Backup start failed with error: {error:?}");
|
||||||
return Err(IdeviceError::UnexpectedResponse);
|
return Err(IdeviceError::UnexpectedResponse);
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!("Backup started successfully");
|
debug!("Backup started successfully");
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -597,7 +639,9 @@ impl MobileBackup2Client {
|
|||||||
///
|
///
|
||||||
/// # Errors
|
/// # Errors
|
||||||
/// Returns `IdeviceError` if the restore fails to start
|
/// Returns `IdeviceError` if the restore fails to start
|
||||||
#[deprecated(note = "Use restore_from_path; restore via BackupUUID is not supported by device/mobilebackup2")]
|
#[deprecated(
|
||||||
|
note = "Use restore_from_path; restore via BackupUUID is not supported by device/mobilebackup2"
|
||||||
|
)]
|
||||||
pub async fn start_restore(
|
pub async fn start_restore(
|
||||||
&mut self,
|
&mut self,
|
||||||
_backup_uuid: &str,
|
_backup_uuid: &str,
|
||||||
@@ -614,13 +658,19 @@ impl MobileBackup2Client {
|
|||||||
opts.insert("RestoreDontCopyBackup".into(), plist::Value::Boolean(false));
|
opts.insert("RestoreDontCopyBackup".into(), plist::Value::Boolean(false));
|
||||||
}
|
}
|
||||||
if !opts.contains_key("RestorePreserveSettings") {
|
if !opts.contains_key("RestorePreserveSettings") {
|
||||||
opts.insert("RestorePreserveSettings".into(), plist::Value::Boolean(true));
|
opts.insert(
|
||||||
|
"RestorePreserveSettings".into(),
|
||||||
|
plist::Value::Boolean(true),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if !opts.contains_key("RestoreSystemFiles") {
|
if !opts.contains_key("RestoreSystemFiles") {
|
||||||
opts.insert("RestoreSystemFiles".into(), plist::Value::Boolean(false));
|
opts.insert("RestoreSystemFiles".into(), plist::Value::Boolean(false));
|
||||||
}
|
}
|
||||||
if !opts.contains_key("RemoveItemsNotRestored") {
|
if !opts.contains_key("RemoveItemsNotRestored") {
|
||||||
opts.insert("RemoveItemsNotRestored".into(), plist::Value::Boolean(false));
|
opts.insert(
|
||||||
|
"RemoveItemsNotRestored".into(),
|
||||||
|
plist::Value::Boolean(false),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
// Avoid borrowing self while sending request
|
// Avoid borrowing self while sending request
|
||||||
let target_udid_owned = self.idevice.udid().map(|s| s.to_string());
|
let target_udid_owned = self.idevice.udid().map(|s| s.to_string());
|
||||||
@@ -633,15 +683,15 @@ impl MobileBackup2Client {
|
|||||||
Some(opts),
|
Some(opts),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let response = self.receive_backup_response().await?;
|
let response = self.receive_backup_response().await?;
|
||||||
|
|
||||||
// Check for error in response
|
// Check for error in response
|
||||||
if let Some(error) = response.get("ErrorCode") {
|
if let Some(error) = response.get("ErrorCode") {
|
||||||
warn!("Restore start failed with error: {error:?}");
|
warn!("Restore start failed with error: {error:?}");
|
||||||
return Err(IdeviceError::UnexpectedResponse);
|
return Err(IdeviceError::UnexpectedResponse);
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!("Restore started successfully");
|
debug!("Restore started successfully");
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -677,14 +727,18 @@ impl MobileBackup2Client {
|
|||||||
target_udid,
|
target_udid,
|
||||||
Some(source),
|
Some(source),
|
||||||
Some(opts),
|
Some(opts),
|
||||||
).await?;
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
// 进入 DeviceLink 文件交换循环,根目录传入 backup_root(协议请求包含 source 前缀)
|
// 进入 DeviceLink 文件交换循环,根目录传入 backup_root(协议请求包含 source 前缀)
|
||||||
let _ = self.process_restore_dl_loop(backup_root).await?;
|
let _ = self.process_restore_dl_loop(backup_root).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn process_restore_dl_loop(&mut self, host_dir: &Path) -> Result<Option<Dictionary>, IdeviceError> {
|
async fn process_restore_dl_loop(
|
||||||
|
&mut self,
|
||||||
|
host_dir: &Path,
|
||||||
|
) -> Result<Option<Dictionary>, IdeviceError> {
|
||||||
loop {
|
loop {
|
||||||
let (tag, value) = self.receive_dl_message().await?;
|
let (tag, value) = self.receive_dl_message().await?;
|
||||||
match tag.as_str() {
|
match tag.as_str() {
|
||||||
@@ -696,7 +750,8 @@ impl MobileBackup2Client {
|
|||||||
}
|
}
|
||||||
"DLMessageGetFreeDiskSpace" => {
|
"DLMessageGetFreeDiskSpace" => {
|
||||||
// Minimal implementation: report 0 with success
|
// Minimal implementation: report 0 with success
|
||||||
self.send_status_response(0, None, Some(plist::Value::Integer(0u64.into()))).await?;
|
self.send_status_response(0, None, Some(plist::Value::Integer(0u64.into())))
|
||||||
|
.await?;
|
||||||
}
|
}
|
||||||
"DLContentsOfDirectory" => {
|
"DLContentsOfDirectory" => {
|
||||||
let empty = plist::Value::Dictionary(Dictionary::new());
|
let empty = plist::Value::Dictionary(Dictionary::new());
|
||||||
@@ -708,15 +763,30 @@ impl MobileBackup2Client {
|
|||||||
}
|
}
|
||||||
"DLMessageMoveFiles" | "DLMessageMoveItems" => {
|
"DLMessageMoveFiles" | "DLMessageMoveItems" => {
|
||||||
let status = Self::move_files_from_message(&value, host_dir);
|
let status = Self::move_files_from_message(&value, host_dir);
|
||||||
self.send_status_response(status, None, Some(plist::Value::Dictionary(Dictionary::new()))).await?;
|
self.send_status_response(
|
||||||
|
status,
|
||||||
|
None,
|
||||||
|
Some(plist::Value::Dictionary(Dictionary::new())),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
}
|
}
|
||||||
"DLMessageRemoveFiles" | "DLMessageRemoveItems" => {
|
"DLMessageRemoveFiles" | "DLMessageRemoveItems" => {
|
||||||
let status = Self::remove_files_from_message(&value, host_dir);
|
let status = Self::remove_files_from_message(&value, host_dir);
|
||||||
self.send_status_response(status, None, Some(plist::Value::Dictionary(Dictionary::new()))).await?;
|
self.send_status_response(
|
||||||
|
status,
|
||||||
|
None,
|
||||||
|
Some(plist::Value::Dictionary(Dictionary::new())),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
}
|
}
|
||||||
"DLMessageCopyItem" => {
|
"DLMessageCopyItem" => {
|
||||||
let status = Self::copy_item_from_message(&value, host_dir);
|
let status = Self::copy_item_from_message(&value, host_dir);
|
||||||
self.send_status_response(status, None, Some(plist::Value::Dictionary(Dictionary::new()))).await?;
|
self.send_status_response(
|
||||||
|
status,
|
||||||
|
None,
|
||||||
|
Some(plist::Value::Dictionary(Dictionary::new())),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
}
|
}
|
||||||
"DLMessageProcessMessage" => {
|
"DLMessageProcessMessage" => {
|
||||||
if let plist::Value::Array(arr) = value
|
if let plist::Value::Array(arr) = value
|
||||||
@@ -731,13 +801,18 @@ impl MobileBackup2Client {
|
|||||||
}
|
}
|
||||||
other => {
|
other => {
|
||||||
warn!("Unsupported DL message: {other}");
|
warn!("Unsupported DL message: {other}");
|
||||||
self.send_status_response(-1, Some("Operation not supported"), None).await?;
|
self.send_status_response(-1, Some("Operation not supported"), None)
|
||||||
|
.await?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_download_files(&mut self, dl_value: &plist::Value, host_dir: &Path) -> Result<(), IdeviceError> {
|
async fn handle_download_files(
|
||||||
|
&mut self,
|
||||||
|
dl_value: &plist::Value,
|
||||||
|
host_dir: &Path,
|
||||||
|
) -> Result<(), IdeviceError> {
|
||||||
let mut err_any = false;
|
let mut err_any = false;
|
||||||
if let plist::Value::Array(arr) = dl_value
|
if let plist::Value::Array(arr) = dl_value
|
||||||
&& arr.len() >= 2
|
&& arr.len() >= 2
|
||||||
@@ -755,13 +830,23 @@ impl MobileBackup2Client {
|
|||||||
// terminating zero dword
|
// terminating zero dword
|
||||||
self.idevice.send_raw(&0u32.to_be_bytes()).await?;
|
self.idevice.send_raw(&0u32.to_be_bytes()).await?;
|
||||||
if err_any {
|
if err_any {
|
||||||
self.send_status_response(-13, Some("Multi status"), Some(plist::Value::Dictionary(Dictionary::new()))).await
|
self.send_status_response(
|
||||||
|
-13,
|
||||||
|
Some("Multi status"),
|
||||||
|
Some(plist::Value::Dictionary(Dictionary::new())),
|
||||||
|
)
|
||||||
|
.await
|
||||||
} else {
|
} else {
|
||||||
self.send_status_response(0, None, Some(plist::Value::Dictionary(Dictionary::new()))).await
|
self.send_status_response(0, None, Some(plist::Value::Dictionary(Dictionary::new())))
|
||||||
|
.await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn send_single_file(&mut self, host_dir: &Path, rel_path: &str) -> Result<(), IdeviceError> {
|
async fn send_single_file(
|
||||||
|
&mut self,
|
||||||
|
host_dir: &Path,
|
||||||
|
rel_path: &str,
|
||||||
|
) -> Result<(), IdeviceError> {
|
||||||
let full = host_dir.join(rel_path);
|
let full = host_dir.join(rel_path);
|
||||||
let path_bytes = rel_path.as_bytes().to_vec();
|
let path_bytes = rel_path.as_bytes().to_vec();
|
||||||
let nlen = (path_bytes.len() as u32).to_be_bytes();
|
let nlen = (path_bytes.len() as u32).to_be_bytes();
|
||||||
@@ -785,7 +870,9 @@ impl MobileBackup2Client {
|
|||||||
let mut buf = [0u8; 32768];
|
let mut buf = [0u8; 32768];
|
||||||
loop {
|
loop {
|
||||||
let read = f.read(&mut buf).unwrap_or(0);
|
let read = f.read(&mut buf).unwrap_or(0);
|
||||||
if read == 0 { break; }
|
if read == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
let size = ((read as u32) + 1).to_be_bytes();
|
let size = ((read as u32) + 1).to_be_bytes();
|
||||||
let mut hdr = Vec::with_capacity(5);
|
let mut hdr = Vec::with_capacity(5);
|
||||||
hdr.extend_from_slice(&size);
|
hdr.extend_from_slice(&size);
|
||||||
@@ -801,32 +888,47 @@ impl MobileBackup2Client {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_upload_files(&mut self, _dl_value: &plist::Value, host_dir: &Path) -> Result<(), IdeviceError> {
|
async fn handle_upload_files(
|
||||||
|
&mut self,
|
||||||
|
_dl_value: &plist::Value,
|
||||||
|
host_dir: &Path,
|
||||||
|
) -> Result<(), IdeviceError> {
|
||||||
loop {
|
loop {
|
||||||
let dlen = self.read_be_u32().await?;
|
let dlen = self.read_be_u32().await?;
|
||||||
if dlen == 0 { break; }
|
if dlen == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
let dname = self.read_exact_string(dlen as usize).await?;
|
let dname = self.read_exact_string(dlen as usize).await?;
|
||||||
let flen = self.read_be_u32().await?;
|
let flen = self.read_be_u32().await?;
|
||||||
if flen == 0 { break; }
|
if flen == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
let fname = self.read_exact_string(flen as usize).await?;
|
let fname = self.read_exact_string(flen as usize).await?;
|
||||||
let dst = host_dir.join(&fname);
|
let dst = host_dir.join(&fname);
|
||||||
if let Some(parent) = dst.parent() { let _ = fs::create_dir_all(parent); }
|
if let Some(parent) = dst.parent() {
|
||||||
let mut file = std::fs::File::create(&dst).map_err(|e| IdeviceError::InternalError(e.to_string()))?;
|
let _ = fs::create_dir_all(parent);
|
||||||
|
}
|
||||||
|
let mut file = std::fs::File::create(&dst)
|
||||||
|
.map_err(|e| IdeviceError::InternalError(e.to_string()))?;
|
||||||
loop {
|
loop {
|
||||||
let nlen = self.read_be_u32().await?;
|
let nlen = self.read_be_u32().await?;
|
||||||
if nlen == 0 { break; }
|
if nlen == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
let code = self.read_one().await?;
|
let code = self.read_one().await?;
|
||||||
if code == DL_CODE_FILE_DATA {
|
if code == DL_CODE_FILE_DATA {
|
||||||
let size = (nlen - 1) as usize;
|
let size = (nlen - 1) as usize;
|
||||||
let data = self.read_exact(size).await?;
|
let data = self.read_exact(size).await?;
|
||||||
file.write_all(&data).map_err(|e| IdeviceError::InternalError(e.to_string()))?;
|
file.write_all(&data)
|
||||||
|
.map_err(|e| IdeviceError::InternalError(e.to_string()))?;
|
||||||
} else {
|
} else {
|
||||||
let _ = self.read_exact((nlen - 1) as usize).await?;
|
let _ = self.read_exact((nlen - 1) as usize).await?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let _ = dname; // unused
|
let _ = dname; // unused
|
||||||
}
|
}
|
||||||
self.send_status_response(0, None, Some(plist::Value::Dictionary(Dictionary::new()))).await
|
self.send_status_response(0, None, Some(plist::Value::Dictionary(Dictionary::new())))
|
||||||
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn read_be_u32(&mut self) -> Result<u32, IdeviceError> {
|
async fn read_be_u32(&mut self) -> Result<u32, IdeviceError> {
|
||||||
@@ -854,7 +956,10 @@ impl MobileBackup2Client {
|
|||||||
&& let Some(plist::Value::String(dir)) = arr.get(1)
|
&& let Some(plist::Value::String(dir)) = arr.get(1)
|
||||||
{
|
{
|
||||||
let path = host_dir.join(dir);
|
let path = host_dir.join(dir);
|
||||||
return match fs::create_dir_all(&path) { Ok(_) => 0, Err(_) => -1 };
|
return match fs::create_dir_all(&path) {
|
||||||
|
Ok(_) => 0,
|
||||||
|
Err(_) => -1,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
-1
|
-1
|
||||||
}
|
}
|
||||||
@@ -868,8 +973,12 @@ impl MobileBackup2Client {
|
|||||||
if let Some(to) = to_v.as_string() {
|
if let Some(to) = to_v.as_string() {
|
||||||
let old = host_dir.join(from);
|
let old = host_dir.join(from);
|
||||||
let newp = host_dir.join(to);
|
let newp = host_dir.join(to);
|
||||||
if let Some(parent) = newp.parent() { let _ = fs::create_dir_all(parent); }
|
if let Some(parent) = newp.parent() {
|
||||||
if fs::rename(&old, &newp).is_err() { return -1; }
|
let _ = fs::create_dir_all(parent);
|
||||||
|
}
|
||||||
|
if fs::rename(&old, &newp).is_err() {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@@ -886,8 +995,12 @@ impl MobileBackup2Client {
|
|||||||
if let Some(p) = it.as_string() {
|
if let Some(p) = it.as_string() {
|
||||||
let path = host_dir.join(p);
|
let path = host_dir.join(p);
|
||||||
if path.is_dir() {
|
if path.is_dir() {
|
||||||
if fs::remove_dir_all(&path).is_err() { return -1; }
|
if fs::remove_dir_all(&path).is_err() {
|
||||||
} else if path.exists() && fs::remove_file(&path).is_err() { return -1; }
|
return -1;
|
||||||
|
}
|
||||||
|
} else if path.exists() && fs::remove_file(&path).is_err() {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@@ -898,22 +1011,33 @@ impl MobileBackup2Client {
|
|||||||
fn copy_item_from_message(dl_value: &plist::Value, host_dir: &Path) -> i64 {
|
fn copy_item_from_message(dl_value: &plist::Value, host_dir: &Path) -> i64 {
|
||||||
if let plist::Value::Array(arr) = dl_value
|
if let plist::Value::Array(arr) = dl_value
|
||||||
&& arr.len() >= 3
|
&& arr.len() >= 3
|
||||||
&& let (Some(plist::Value::String(src)), Some(plist::Value::String(dst))) = (arr.get(1), arr.get(2))
|
&& let (Some(plist::Value::String(src)), Some(plist::Value::String(dst))) =
|
||||||
|
(arr.get(1), arr.get(2))
|
||||||
{
|
{
|
||||||
let from = host_dir.join(src);
|
let from = host_dir.join(src);
|
||||||
let to = host_dir.join(dst);
|
let to = host_dir.join(dst);
|
||||||
if let Some(parent) = to.parent() { let _ = fs::create_dir_all(parent); }
|
if let Some(parent) = to.parent() {
|
||||||
|
let _ = fs::create_dir_all(parent);
|
||||||
|
}
|
||||||
if from.is_dir() {
|
if from.is_dir() {
|
||||||
return match fs::create_dir_all(&to) { Ok(_) => 0, Err(_) => -1 };
|
return match fs::create_dir_all(&to) {
|
||||||
|
Ok(_) => 0,
|
||||||
|
Err(_) => -1,
|
||||||
|
};
|
||||||
} else {
|
} else {
|
||||||
return match fs::copy(&from, &to) { Ok(_) => 0, Err(_) => -1 };
|
return match fs::copy(&from, &to) {
|
||||||
|
Ok(_) => 0,
|
||||||
|
Err(_) => -1,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
-1
|
-1
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Starts a restore using the typed RestoreOptions builder
|
/// Starts a restore using the typed RestoreOptions builder
|
||||||
#[deprecated(note = "Use restore_from_path; restore via BackupUUID is not supported by device/mobilebackup2")]
|
#[deprecated(
|
||||||
|
note = "Use restore_from_path; restore via BackupUUID is not supported by device/mobilebackup2"
|
||||||
|
)]
|
||||||
pub async fn start_restore_with(
|
pub async fn start_restore_with(
|
||||||
&mut self,
|
&mut self,
|
||||||
_backup_uuid: &str,
|
_backup_uuid: &str,
|
||||||
@@ -960,12 +1084,22 @@ impl MobileBackup2Client {
|
|||||||
source_identifier: Option<&str>,
|
source_identifier: Option<&str>,
|
||||||
) -> Result<Dictionary, IdeviceError> {
|
) -> Result<Dictionary, IdeviceError> {
|
||||||
let target_udid = self.idevice.udid();
|
let target_udid = self.idevice.udid();
|
||||||
let source = source_identifier.or(target_udid).ok_or(IdeviceError::InvalidHostID)?;
|
let source = source_identifier
|
||||||
|
.or(target_udid)
|
||||||
|
.ok_or(IdeviceError::InvalidHostID)?;
|
||||||
self.assert_backup_exists(backup_root, source)?;
|
self.assert_backup_exists(backup_root, source)?;
|
||||||
|
|
||||||
let mut dict = Dictionary::new();
|
let mut dict = Dictionary::new();
|
||||||
dict.insert("TargetIdentifier".into(), plist::Value::String(target_udid.unwrap().to_string()));
|
dict.insert(
|
||||||
if let Some(src) = source_identifier { dict.insert("SourceIdentifier".into(), plist::Value::String(src.to_string())); }
|
"TargetIdentifier".into(),
|
||||||
|
plist::Value::String(target_udid.unwrap().to_string()),
|
||||||
|
);
|
||||||
|
if let Some(src) = source_identifier {
|
||||||
|
dict.insert(
|
||||||
|
"SourceIdentifier".into(),
|
||||||
|
plist::Value::String(src.to_string()),
|
||||||
|
);
|
||||||
|
}
|
||||||
self.send_device_link_message("Info", Some(dict)).await?;
|
self.send_device_link_message("Info", Some(dict)).await?;
|
||||||
|
|
||||||
match self.process_restore_dl_loop(backup_root).await? {
|
match self.process_restore_dl_loop(backup_root).await? {
|
||||||
@@ -981,13 +1115,21 @@ impl MobileBackup2Client {
|
|||||||
source_identifier: Option<&str>,
|
source_identifier: Option<&str>,
|
||||||
) -> Result<Dictionary, IdeviceError> {
|
) -> Result<Dictionary, IdeviceError> {
|
||||||
let target_udid = self.idevice.udid();
|
let target_udid = self.idevice.udid();
|
||||||
let source = source_identifier.or(target_udid).ok_or(IdeviceError::InvalidHostID)?;
|
let source = source_identifier
|
||||||
|
.or(target_udid)
|
||||||
|
.ok_or(IdeviceError::InvalidHostID)?;
|
||||||
self.assert_backup_exists(backup_root, source)?;
|
self.assert_backup_exists(backup_root, source)?;
|
||||||
|
|
||||||
let mut dict = Dictionary::new();
|
let mut dict = Dictionary::new();
|
||||||
dict.insert("MessageName".into(), plist::Value::String("List".into()));
|
dict.insert("MessageName".into(), plist::Value::String("List".into()));
|
||||||
dict.insert("TargetIdentifier".into(), plist::Value::String(target_udid.unwrap().to_string()));
|
dict.insert(
|
||||||
dict.insert("SourceIdentifier".into(), plist::Value::String(source.to_string()));
|
"TargetIdentifier".into(),
|
||||||
|
plist::Value::String(target_udid.unwrap().to_string()),
|
||||||
|
);
|
||||||
|
dict.insert(
|
||||||
|
"SourceIdentifier".into(),
|
||||||
|
plist::Value::String(source.to_string()),
|
||||||
|
);
|
||||||
self.send_device_link_message("List", Some(dict)).await?;
|
self.send_device_link_message("List", Some(dict)).await?;
|
||||||
|
|
||||||
match self.process_restore_dl_loop(backup_root).await? {
|
match self.process_restore_dl_loop(backup_root).await? {
|
||||||
@@ -1004,14 +1146,24 @@ impl MobileBackup2Client {
|
|||||||
source_identifier: Option<&str>,
|
source_identifier: Option<&str>,
|
||||||
) -> Result<(), IdeviceError> {
|
) -> Result<(), IdeviceError> {
|
||||||
let target_udid = self.idevice.udid();
|
let target_udid = self.idevice.udid();
|
||||||
let source = source_identifier.or(target_udid).ok_or(IdeviceError::InvalidHostID)?;
|
let source = source_identifier
|
||||||
|
.or(target_udid)
|
||||||
|
.ok_or(IdeviceError::InvalidHostID)?;
|
||||||
self.assert_backup_exists(backup_root, source)?;
|
self.assert_backup_exists(backup_root, source)?;
|
||||||
|
|
||||||
let mut dict = Dictionary::new();
|
let mut dict = Dictionary::new();
|
||||||
dict.insert("TargetIdentifier".into(), plist::Value::String(target_udid.unwrap().to_string()));
|
dict.insert(
|
||||||
|
"TargetIdentifier".into(),
|
||||||
|
plist::Value::String(target_udid.unwrap().to_string()),
|
||||||
|
);
|
||||||
dict.insert("MessageName".into(), plist::Value::String("Unback".into()));
|
dict.insert("MessageName".into(), plist::Value::String("Unback".into()));
|
||||||
dict.insert("SourceIdentifier".into(), plist::Value::String(source.to_string()));
|
dict.insert(
|
||||||
if let Some(pw) = password { dict.insert("Password".into(), plist::Value::String(pw.to_string())); }
|
"SourceIdentifier".into(),
|
||||||
|
plist::Value::String(source.to_string()),
|
||||||
|
);
|
||||||
|
if let Some(pw) = password {
|
||||||
|
dict.insert("Password".into(), plist::Value::String(pw.to_string()));
|
||||||
|
}
|
||||||
self.send_device_link_message("Unback", Some(dict)).await?;
|
self.send_device_link_message("Unback", Some(dict)).await?;
|
||||||
let _ = self.process_restore_dl_loop(backup_root).await?;
|
let _ = self.process_restore_dl_loop(backup_root).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -1027,16 +1179,32 @@ impl MobileBackup2Client {
|
|||||||
source_identifier: Option<&str>,
|
source_identifier: Option<&str>,
|
||||||
) -> Result<(), IdeviceError> {
|
) -> Result<(), IdeviceError> {
|
||||||
let target_udid = self.idevice.udid();
|
let target_udid = self.idevice.udid();
|
||||||
let source = source_identifier.or(target_udid).ok_or(IdeviceError::InvalidHostID)?;
|
let source = source_identifier
|
||||||
|
.or(target_udid)
|
||||||
|
.ok_or(IdeviceError::InvalidHostID)?;
|
||||||
self.assert_backup_exists(backup_root, source)?;
|
self.assert_backup_exists(backup_root, source)?;
|
||||||
|
|
||||||
let mut dict = Dictionary::new();
|
let mut dict = Dictionary::new();
|
||||||
dict.insert("MessageName".into(), plist::Value::String("Extract".into()));
|
dict.insert("MessageName".into(), plist::Value::String("Extract".into()));
|
||||||
dict.insert("TargetIdentifier".into(), plist::Value::String(target_udid.unwrap().to_string()));
|
dict.insert(
|
||||||
dict.insert("DomainName".into(), plist::Value::String(domain_name.to_string()));
|
"TargetIdentifier".into(),
|
||||||
dict.insert("RelativePath".into(), plist::Value::String(relative_path.to_string()));
|
plist::Value::String(target_udid.unwrap().to_string()),
|
||||||
dict.insert("SourceIdentifier".into(), plist::Value::String(source.to_string()));
|
);
|
||||||
if let Some(pw) = password { dict.insert("Password".into(), plist::Value::String(pw.to_string())); }
|
dict.insert(
|
||||||
|
"DomainName".into(),
|
||||||
|
plist::Value::String(domain_name.to_string()),
|
||||||
|
);
|
||||||
|
dict.insert(
|
||||||
|
"RelativePath".into(),
|
||||||
|
plist::Value::String(relative_path.to_string()),
|
||||||
|
);
|
||||||
|
dict.insert(
|
||||||
|
"SourceIdentifier".into(),
|
||||||
|
plist::Value::String(source.to_string()),
|
||||||
|
);
|
||||||
|
if let Some(pw) = password {
|
||||||
|
dict.insert("Password".into(), plist::Value::String(pw.to_string()));
|
||||||
|
}
|
||||||
self.send_device_link_message("Extract", Some(dict)).await?;
|
self.send_device_link_message("Extract", Some(dict)).await?;
|
||||||
let _ = self.process_restore_dl_loop(backup_root).await?;
|
let _ = self.process_restore_dl_loop(backup_root).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -1051,11 +1219,22 @@ impl MobileBackup2Client {
|
|||||||
) -> Result<(), IdeviceError> {
|
) -> Result<(), IdeviceError> {
|
||||||
let target_udid = self.idevice.udid();
|
let target_udid = self.idevice.udid();
|
||||||
let mut dict = Dictionary::new();
|
let mut dict = Dictionary::new();
|
||||||
dict.insert("MessageName".into(), plist::Value::String("ChangePassword".into()));
|
dict.insert(
|
||||||
dict.insert("TargetIdentifier".into(), plist::Value::String(target_udid.ok_or(IdeviceError::InvalidHostID)?.to_string()));
|
"MessageName".into(),
|
||||||
if let Some(o) = old { dict.insert("OldPassword".into(), plist::Value::String(o.to_string())); }
|
plist::Value::String("ChangePassword".into()),
|
||||||
if let Some(n) = new { dict.insert("NewPassword".into(), plist::Value::String(n.to_string())); }
|
);
|
||||||
self.send_device_link_message("ChangePassword", Some(dict)).await?;
|
dict.insert(
|
||||||
|
"TargetIdentifier".into(),
|
||||||
|
plist::Value::String(target_udid.ok_or(IdeviceError::InvalidHostID)?.to_string()),
|
||||||
|
);
|
||||||
|
if let Some(o) = old {
|
||||||
|
dict.insert("OldPassword".into(), plist::Value::String(o.to_string()));
|
||||||
|
}
|
||||||
|
if let Some(n) = new {
|
||||||
|
dict.insert("NewPassword".into(), plist::Value::String(n.to_string()));
|
||||||
|
}
|
||||||
|
self.send_device_link_message("ChangePassword", Some(dict))
|
||||||
|
.await?;
|
||||||
let _ = self.process_restore_dl_loop(backup_root).await?;
|
let _ = self.process_restore_dl_loop(backup_root).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -1064,9 +1243,16 @@ impl MobileBackup2Client {
|
|||||||
pub async fn erase_device_from_path(&mut self, backup_root: &Path) -> Result<(), IdeviceError> {
|
pub async fn erase_device_from_path(&mut self, backup_root: &Path) -> Result<(), IdeviceError> {
|
||||||
let target_udid = self.idevice.udid();
|
let target_udid = self.idevice.udid();
|
||||||
let mut dict = Dictionary::new();
|
let mut dict = Dictionary::new();
|
||||||
dict.insert("MessageName".into(), plist::Value::String("EraseDevice".into()));
|
dict.insert(
|
||||||
dict.insert("TargetIdentifier".into(), plist::Value::String(target_udid.ok_or(IdeviceError::InvalidHostID)?.to_string()));
|
"MessageName".into(),
|
||||||
self.send_device_link_message("EraseDevice", Some(dict)).await?;
|
plist::Value::String("EraseDevice".into()),
|
||||||
|
);
|
||||||
|
dict.insert(
|
||||||
|
"TargetIdentifier".into(),
|
||||||
|
plist::Value::String(target_udid.ok_or(IdeviceError::InvalidHostID)?.to_string()),
|
||||||
|
);
|
||||||
|
self.send_device_link_message("EraseDevice", Some(dict))
|
||||||
|
.await?;
|
||||||
let _ = self.process_restore_dl_loop(backup_root).await?;
|
let _ = self.process_restore_dl_loop(backup_root).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -1112,4 +1298,5 @@ impl MobileBackup2Client {
|
|||||||
debug!("Disconnected from backup service");
|
debug!("Disconnected from backup service");
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user