mirror of
https://github.com/jkcoxson/idevice.git
synced 2026-03-02 06:26:15 +01:00
Compare commits
3 Commits
rppairing-
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c752ee92c5 | ||
|
|
76d847664b | ||
|
|
1f7924b773 |
@@ -76,6 +76,7 @@ To keep dependency bloat and compile time down, everything is contained in featu
|
|||||||
| `tunneld` | Interface with [pymobiledevice3](https://github.com/doronz88/pymobiledevice3)'s tunneld. |
|
| `tunneld` | Interface with [pymobiledevice3](https://github.com/doronz88/pymobiledevice3)'s tunneld. |
|
||||||
| `usbmuxd` | Connect using the usbmuxd daemon.|
|
| `usbmuxd` | Connect using the usbmuxd daemon.|
|
||||||
| `xpc` | Access protected services via XPC over RSD. |
|
| `xpc` | Access protected services via XPC over RSD. |
|
||||||
|
| `notification_proxy` | Post and observe iOS notifications. |
|
||||||
|
|
||||||
### Planned/TODO
|
### Planned/TODO
|
||||||
|
|
||||||
@@ -85,7 +86,7 @@ Finish the following:
|
|||||||
|
|
||||||
Implement the following:
|
Implement the following:
|
||||||
|
|
||||||
- notification_proxy
|
- file_relay
|
||||||
|
|
||||||
As this project is done in my free time within my busy schedule, there
|
As this project is done in my free time within my busy schedule, there
|
||||||
is no ETA for any of these. Feel free to contribute or donate!
|
is no ETA for any of these. Feel free to contribute or donate!
|
||||||
|
|||||||
50
cpp/include/idevice++/crashreportcopymobile.hpp
Normal file
50
cpp/include/idevice++/crashreportcopymobile.hpp
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
// Jackson Coxson
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <idevice++/bindings.hpp>
|
||||||
|
#include <idevice++/ffi.hpp>
|
||||||
|
#include <idevice++/provider.hpp>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace IdeviceFFI {
|
||||||
|
|
||||||
|
using CrashReportCopyMobilePtr =
|
||||||
|
std::unique_ptr<CrashReportCopyMobileHandle,
|
||||||
|
FnDeleter<CrashReportCopyMobileHandle, crash_report_client_free>>;
|
||||||
|
|
||||||
|
class CrashReportCopyMobile {
|
||||||
|
public:
|
||||||
|
// Factory: connect via Provider
|
||||||
|
static Result<CrashReportCopyMobile, FfiError> connect(Provider& provider);
|
||||||
|
|
||||||
|
// Factory: wrap an existing Idevice socket (consumes it on success)
|
||||||
|
static Result<CrashReportCopyMobile, FfiError> from_socket(Idevice&& socket);
|
||||||
|
|
||||||
|
// Static: flush crash reports from system storage
|
||||||
|
static Result<void, FfiError> flush(Provider& provider);
|
||||||
|
|
||||||
|
// Ops
|
||||||
|
Result<std::vector<std::string>, FfiError> ls(const char* dir_path = nullptr);
|
||||||
|
Result<std::vector<char>, FfiError> pull(const std::string& log_name);
|
||||||
|
Result<void, FfiError> remove(const std::string& log_name);
|
||||||
|
|
||||||
|
// RAII / moves
|
||||||
|
~CrashReportCopyMobile() noexcept = default;
|
||||||
|
CrashReportCopyMobile(CrashReportCopyMobile&&) noexcept = default;
|
||||||
|
CrashReportCopyMobile& operator=(CrashReportCopyMobile&&) noexcept = default;
|
||||||
|
CrashReportCopyMobile(const CrashReportCopyMobile&) = delete;
|
||||||
|
CrashReportCopyMobile& operator=(const CrashReportCopyMobile&) = delete;
|
||||||
|
|
||||||
|
CrashReportCopyMobileHandle* raw() const noexcept { return handle_.get(); }
|
||||||
|
static CrashReportCopyMobile adopt(CrashReportCopyMobileHandle* h) noexcept {
|
||||||
|
return CrashReportCopyMobile(h);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
explicit CrashReportCopyMobile(CrashReportCopyMobileHandle* h) noexcept : handle_(h) {}
|
||||||
|
CrashReportCopyMobilePtr handle_{};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace IdeviceFFI
|
||||||
94
cpp/src/crashreportcopymobile.cpp
Normal file
94
cpp/src/crashreportcopymobile.cpp
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
// Jackson Coxson
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
#include <idevice++/bindings.hpp>
|
||||||
|
#include <idevice++/crashreportcopymobile.hpp>
|
||||||
|
#include <idevice++/ffi.hpp>
|
||||||
|
#include <idevice++/provider.hpp>
|
||||||
|
|
||||||
|
namespace IdeviceFFI {
|
||||||
|
|
||||||
|
// -------- Factory Methods --------
|
||||||
|
|
||||||
|
Result<CrashReportCopyMobile, FfiError> CrashReportCopyMobile::connect(Provider& provider) {
|
||||||
|
CrashReportCopyMobileHandle* out = nullptr;
|
||||||
|
FfiError e(::crash_report_client_connect(provider.raw(), &out));
|
||||||
|
if (e) {
|
||||||
|
return Err(e);
|
||||||
|
}
|
||||||
|
return Ok(CrashReportCopyMobile::adopt(out));
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<CrashReportCopyMobile, FfiError> CrashReportCopyMobile::from_socket(Idevice&& socket) {
|
||||||
|
CrashReportCopyMobileHandle* out = nullptr;
|
||||||
|
FfiError e(::crash_report_client_new(socket.raw(), &out));
|
||||||
|
if (e) {
|
||||||
|
return Err(e);
|
||||||
|
}
|
||||||
|
socket.release();
|
||||||
|
return Ok(CrashReportCopyMobile::adopt(out));
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<void, FfiError> CrashReportCopyMobile::flush(Provider& provider) {
|
||||||
|
FfiError e(::crash_report_flush(provider.raw()));
|
||||||
|
if (e) {
|
||||||
|
return Err(e);
|
||||||
|
}
|
||||||
|
return Ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------- Ops --------
|
||||||
|
|
||||||
|
Result<std::vector<std::string>, FfiError>
|
||||||
|
CrashReportCopyMobile::ls(const char* dir_path) {
|
||||||
|
char** entries_raw = nullptr;
|
||||||
|
size_t count = 0;
|
||||||
|
|
||||||
|
FfiError e(::crash_report_client_ls(handle_.get(), dir_path, &entries_raw, &count));
|
||||||
|
if (e) {
|
||||||
|
return Err(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> result;
|
||||||
|
if (entries_raw) {
|
||||||
|
result.reserve(count);
|
||||||
|
for (size_t i = 0; i < count; ++i) {
|
||||||
|
if (entries_raw[i]) {
|
||||||
|
result.emplace_back(entries_raw[i]);
|
||||||
|
::idevice_string_free(entries_raw[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::free(entries_raw);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(std::move(result));
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<std::vector<char>, FfiError>
|
||||||
|
CrashReportCopyMobile::pull(const std::string& log_name) {
|
||||||
|
uint8_t* data = nullptr;
|
||||||
|
size_t length = 0;
|
||||||
|
|
||||||
|
FfiError e(::crash_report_client_pull(handle_.get(), log_name.c_str(), &data, &length));
|
||||||
|
if (e) {
|
||||||
|
return Err(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<char> result;
|
||||||
|
if (data && length > 0) {
|
||||||
|
result.assign(reinterpret_cast<char*>(data), reinterpret_cast<char*>(data) + length);
|
||||||
|
::idevice_data_free(data, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(std::move(result));
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<void, FfiError> CrashReportCopyMobile::remove(const std::string& log_name) {
|
||||||
|
FfiError e(::crash_report_client_remove(handle_.get(), log_name.c_str()));
|
||||||
|
if (e) {
|
||||||
|
return Err(e);
|
||||||
|
}
|
||||||
|
return Ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace IdeviceFFI
|
||||||
325
ffi/src/crashreportcopymobile.rs
Normal file
325
ffi/src/crashreportcopymobile.rs
Normal file
@@ -0,0 +1,325 @@
|
|||||||
|
// Jackson Coxson
|
||||||
|
|
||||||
|
use std::{
|
||||||
|
ffi::{CStr, c_char},
|
||||||
|
ptr::null_mut,
|
||||||
|
};
|
||||||
|
|
||||||
|
use idevice::{
|
||||||
|
IdeviceError, IdeviceService,
|
||||||
|
provider::IdeviceProvider,
|
||||||
|
services::crashreportcopymobile::{CrashReportCopyMobileClient, flush_reports},
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
IdeviceFfiError, IdeviceHandle, afc::AfcClientHandle, ffi_err, provider::IdeviceProviderHandle,
|
||||||
|
run_sync_local,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct CrashReportCopyMobileHandle(pub CrashReportCopyMobileClient);
|
||||||
|
|
||||||
|
/// Automatically creates and connects to the crash report copy mobile service,
|
||||||
|
/// returning a client handle
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
/// * [`provider`] - An IdeviceProvider
|
||||||
|
/// * [`client`] - On success, will be set to point to a newly allocated handle
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
/// An IdeviceFfiError on error, null on success
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
/// `provider` must be a valid pointer to a handle allocated by this library
|
||||||
|
/// `client` must be a valid, non-null pointer to a location where the handle will be stored
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
pub unsafe extern "C" fn crash_report_client_connect(
|
||||||
|
provider: *mut IdeviceProviderHandle,
|
||||||
|
client: *mut *mut CrashReportCopyMobileHandle,
|
||||||
|
) -> *mut IdeviceFfiError {
|
||||||
|
if provider.is_null() || client.is_null() {
|
||||||
|
tracing::error!("Null pointer provided");
|
||||||
|
return ffi_err!(IdeviceError::FfiInvalidArg);
|
||||||
|
}
|
||||||
|
|
||||||
|
let res: Result<CrashReportCopyMobileClient, IdeviceError> = run_sync_local(async move {
|
||||||
|
let provider_ref: &dyn IdeviceProvider = unsafe { &*(*provider).0 };
|
||||||
|
CrashReportCopyMobileClient::connect(provider_ref).await
|
||||||
|
});
|
||||||
|
|
||||||
|
match res {
|
||||||
|
Ok(r) => {
|
||||||
|
let boxed = Box::new(CrashReportCopyMobileHandle(r));
|
||||||
|
unsafe { *client = Box::into_raw(boxed) };
|
||||||
|
null_mut()
|
||||||
|
}
|
||||||
|
Err(e) => ffi_err!(e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new CrashReportCopyMobile client from an existing Idevice connection
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
/// * [`socket`] - An IdeviceSocket handle
|
||||||
|
/// * [`client`] - On success, will be set to point to a newly allocated handle
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
/// An IdeviceFfiError on error, null on success
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
/// `socket` must be a valid pointer to a handle allocated by this library
|
||||||
|
/// `client` must be a valid, non-null pointer to a location where the handle will be stored
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
pub unsafe extern "C" fn crash_report_client_new(
|
||||||
|
socket: *mut IdeviceHandle,
|
||||||
|
client: *mut *mut CrashReportCopyMobileHandle,
|
||||||
|
) -> *mut IdeviceFfiError {
|
||||||
|
if socket.is_null() || client.is_null() {
|
||||||
|
return ffi_err!(IdeviceError::FfiInvalidArg);
|
||||||
|
}
|
||||||
|
let socket = unsafe { Box::from_raw(socket) }.0;
|
||||||
|
let r = CrashReportCopyMobileClient::new(socket);
|
||||||
|
let boxed = Box::new(CrashReportCopyMobileHandle(r));
|
||||||
|
unsafe { *client = Box::into_raw(boxed) };
|
||||||
|
null_mut()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Lists crash report files in the specified directory
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
/// * [`client`] - A valid CrashReportCopyMobile handle
|
||||||
|
/// * [`dir_path`] - Optional directory path (NULL for root "/")
|
||||||
|
/// * [`entries`] - Will be set to point to an array of C strings
|
||||||
|
/// * [`count`] - Will be set to the number of entries
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
/// An IdeviceFfiError on error, null on success
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
/// All pointers must be valid and non-null
|
||||||
|
/// `dir_path` may be NULL (defaults to root)
|
||||||
|
/// Caller must free the returned array with `afc_free_directory_entries`
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
pub unsafe extern "C" fn crash_report_client_ls(
|
||||||
|
client: *mut CrashReportCopyMobileHandle,
|
||||||
|
dir_path: *const c_char,
|
||||||
|
entries: *mut *mut *mut c_char,
|
||||||
|
count: *mut libc::size_t,
|
||||||
|
) -> *mut IdeviceFfiError {
|
||||||
|
if client.is_null() || entries.is_null() || count.is_null() {
|
||||||
|
return ffi_err!(IdeviceError::FfiInvalidArg);
|
||||||
|
}
|
||||||
|
|
||||||
|
let path = if dir_path.is_null() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
match unsafe { CStr::from_ptr(dir_path) }.to_str() {
|
||||||
|
Ok(s) => Some(s),
|
||||||
|
Err(_) => return ffi_err!(IdeviceError::FfiInvalidString),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let res: Result<Vec<String>, IdeviceError> = run_sync_local(async {
|
||||||
|
let client_ref = unsafe { &mut (*client).0 };
|
||||||
|
client_ref.ls(path).await
|
||||||
|
});
|
||||||
|
|
||||||
|
match res {
|
||||||
|
Ok(items) => {
|
||||||
|
let c_strings = items
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|s| std::ffi::CString::new(s).ok())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let string_count = c_strings.len();
|
||||||
|
|
||||||
|
// Allocate array for char pointers (with NULL terminator)
|
||||||
|
let layout = std::alloc::Layout::array::<*mut c_char>(string_count + 1).unwrap();
|
||||||
|
let ptr = unsafe { std::alloc::alloc(layout) as *mut *mut c_char };
|
||||||
|
if ptr.is_null() {
|
||||||
|
return ffi_err!(IdeviceError::FfiInvalidArg);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i, cstring) in c_strings.into_iter().enumerate() {
|
||||||
|
let string_ptr = cstring.into_raw();
|
||||||
|
unsafe { *ptr.add(i) = string_ptr };
|
||||||
|
}
|
||||||
|
|
||||||
|
// NULL terminator
|
||||||
|
unsafe { *ptr.add(string_count) = std::ptr::null_mut() };
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
*entries = ptr;
|
||||||
|
*count = string_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
null_mut()
|
||||||
|
}
|
||||||
|
Err(e) => ffi_err!(e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Downloads a crash report file from the device
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
/// * [`client`] - A valid CrashReportCopyMobile handle
|
||||||
|
/// * [`log_name`] - Name of the log file to download (C string)
|
||||||
|
/// * [`data`] - Will be set to point to the file contents
|
||||||
|
/// * [`length`] - Will be set to the size of the data
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
/// An IdeviceFfiError on error, null on success
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
/// All pointers must be valid and non-null
|
||||||
|
/// `log_name` must be a valid C string
|
||||||
|
/// Caller must free the returned data with `idevice_data_free`
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
pub unsafe extern "C" fn crash_report_client_pull(
|
||||||
|
client: *mut CrashReportCopyMobileHandle,
|
||||||
|
log_name: *const c_char,
|
||||||
|
data: *mut *mut u8,
|
||||||
|
length: *mut libc::size_t,
|
||||||
|
) -> *mut IdeviceFfiError {
|
||||||
|
if client.is_null() || log_name.is_null() || data.is_null() || length.is_null() {
|
||||||
|
return ffi_err!(IdeviceError::FfiInvalidArg);
|
||||||
|
}
|
||||||
|
|
||||||
|
let name = match unsafe { CStr::from_ptr(log_name) }.to_str() {
|
||||||
|
Ok(s) => s.to_string(),
|
||||||
|
Err(_) => return ffi_err!(IdeviceError::FfiInvalidString),
|
||||||
|
};
|
||||||
|
|
||||||
|
let res: Result<Vec<u8>, IdeviceError> = run_sync_local(async {
|
||||||
|
let client_ref = unsafe { &mut (*client).0 };
|
||||||
|
client_ref.pull(name).await
|
||||||
|
});
|
||||||
|
|
||||||
|
match res {
|
||||||
|
Ok(file_data) => {
|
||||||
|
let len = file_data.len();
|
||||||
|
let mut boxed = file_data.into_boxed_slice();
|
||||||
|
unsafe {
|
||||||
|
*data = boxed.as_mut_ptr();
|
||||||
|
*length = len;
|
||||||
|
}
|
||||||
|
std::mem::forget(boxed);
|
||||||
|
null_mut()
|
||||||
|
}
|
||||||
|
Err(e) => ffi_err!(e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Removes a crash report file from the device
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
/// * [`client`] - A valid CrashReportCopyMobile handle
|
||||||
|
/// * [`log_name`] - Name of the log file to remove (C string)
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
/// An IdeviceFfiError on error, null on success
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
/// `client` must be a valid pointer to a handle allocated by this library
|
||||||
|
/// `log_name` must be a valid C string
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
pub unsafe extern "C" fn crash_report_client_remove(
|
||||||
|
client: *mut CrashReportCopyMobileHandle,
|
||||||
|
log_name: *const c_char,
|
||||||
|
) -> *mut IdeviceFfiError {
|
||||||
|
if client.is_null() || log_name.is_null() {
|
||||||
|
return ffi_err!(IdeviceError::FfiInvalidArg);
|
||||||
|
}
|
||||||
|
|
||||||
|
let name = match unsafe { CStr::from_ptr(log_name) }.to_str() {
|
||||||
|
Ok(s) => s.to_string(),
|
||||||
|
Err(_) => return ffi_err!(IdeviceError::FfiInvalidString),
|
||||||
|
};
|
||||||
|
|
||||||
|
let res = run_sync_local(async {
|
||||||
|
let client_ref = unsafe { &mut (*client).0 };
|
||||||
|
client_ref.remove(name).await
|
||||||
|
});
|
||||||
|
|
||||||
|
match res {
|
||||||
|
Ok(_) => null_mut(),
|
||||||
|
Err(e) => ffi_err!(e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Converts this client to an AFC client for advanced file operations
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
/// * [`client`] - A valid CrashReportCopyMobile handle (will be consumed)
|
||||||
|
/// * [`afc_client`] - On success, will be set to an AFC client handle
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
/// An IdeviceFfiError on error, null on success
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
/// `client` must be a valid pointer (will be freed after this call)
|
||||||
|
/// `afc_client` must be a valid, non-null pointer where the new AFC client will be stored
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
pub unsafe extern "C" fn crash_report_client_to_afc(
|
||||||
|
client: *mut CrashReportCopyMobileHandle,
|
||||||
|
afc_client: *mut *mut AfcClientHandle,
|
||||||
|
) -> *mut IdeviceFfiError {
|
||||||
|
if client.is_null() || afc_client.is_null() {
|
||||||
|
return ffi_err!(IdeviceError::FfiInvalidArg);
|
||||||
|
}
|
||||||
|
|
||||||
|
let crash_client = unsafe { Box::from_raw(client) }.0;
|
||||||
|
let afc = crash_client.to_afc_client();
|
||||||
|
|
||||||
|
let a = Box::into_raw(Box::new(AfcClientHandle(afc)));
|
||||||
|
unsafe { *afc_client = a };
|
||||||
|
|
||||||
|
null_mut()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Triggers a flush of crash logs from system storage
|
||||||
|
///
|
||||||
|
/// This connects to the crashreportmover service to move crash logs
|
||||||
|
/// into the AFC-accessible directory. Should be called before listing logs.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
/// * [`provider`] - An IdeviceProvider
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
/// An IdeviceFfiError on error, null on success
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
/// `provider` must be a valid pointer to a handle allocated by this library
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
pub unsafe extern "C" fn crash_report_flush(
|
||||||
|
provider: *mut IdeviceProviderHandle,
|
||||||
|
) -> *mut IdeviceFfiError {
|
||||||
|
if provider.is_null() {
|
||||||
|
return ffi_err!(IdeviceError::FfiInvalidArg);
|
||||||
|
}
|
||||||
|
|
||||||
|
let res = run_sync_local(async {
|
||||||
|
let provider_ref: &dyn IdeviceProvider = unsafe { &*(*provider).0 };
|
||||||
|
flush_reports(provider_ref).await
|
||||||
|
});
|
||||||
|
|
||||||
|
match res {
|
||||||
|
Ok(_) => null_mut(),
|
||||||
|
Err(e) => ffi_err!(e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Frees a CrashReportCopyMobile client handle
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
/// * [`handle`] - The handle to free
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
/// `handle` must be a valid pointer to the handle that was allocated by this library,
|
||||||
|
/// or NULL (in which case this function does nothing)
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
pub unsafe extern "C" fn crash_report_client_free(handle: *mut CrashReportCopyMobileHandle) {
|
||||||
|
if !handle.is_null() {
|
||||||
|
tracing::debug!("Freeing crash_report_client");
|
||||||
|
let _ = unsafe { Box::from_raw(handle) };
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,6 +10,8 @@ pub mod amfi;
|
|||||||
pub mod core_device;
|
pub mod core_device;
|
||||||
#[cfg(feature = "core_device_proxy")]
|
#[cfg(feature = "core_device_proxy")]
|
||||||
pub mod core_device_proxy;
|
pub mod core_device_proxy;
|
||||||
|
#[cfg(feature = "crashreportcopymobile")]
|
||||||
|
pub mod crashreportcopymobile;
|
||||||
#[cfg(feature = "debug_proxy")]
|
#[cfg(feature = "debug_proxy")]
|
||||||
pub mod debug_proxy;
|
pub mod debug_proxy;
|
||||||
#[cfg(feature = "diagnostics_relay")]
|
#[cfg(feature = "diagnostics_relay")]
|
||||||
|
|||||||
@@ -157,6 +157,74 @@ pub unsafe extern "C" fn lockdownd_start_service(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Pairs with the device using lockdownd
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
/// * `client` - A valid LockdowndClient handle
|
||||||
|
/// * `host_id` - The host ID (null-terminated string)
|
||||||
|
/// * `system_buid` - The system BUID (null-terminated string)
|
||||||
|
/// * `pairing_file` - On success, will be set to point to a newly allocated IdevicePairingFile handle
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
/// An IdeviceFfiError on error, null on success
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
/// `client` must be a valid pointer to a handle allocated by this library
|
||||||
|
/// `host_id` must be a valid null-terminated string
|
||||||
|
/// `system_buid` must be a valid null-terminated string
|
||||||
|
/// `pairing_file` must be a valid, non-null pointer to a location where the handle will be stored
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
pub unsafe extern "C" fn lockdownd_pair(
|
||||||
|
client: *mut LockdowndClientHandle,
|
||||||
|
host_id: *const libc::c_char,
|
||||||
|
system_buid: *const libc::c_char,
|
||||||
|
host_name: *const libc::c_char,
|
||||||
|
pairing_file: *mut *mut IdevicePairingFile,
|
||||||
|
) -> *mut IdeviceFfiError {
|
||||||
|
if client.is_null() || host_id.is_null() || system_buid.is_null() {
|
||||||
|
return ffi_err!(IdeviceError::FfiInvalidArg);
|
||||||
|
}
|
||||||
|
|
||||||
|
let host_id = unsafe {
|
||||||
|
std::ffi::CStr::from_ptr(host_id)
|
||||||
|
.to_string_lossy()
|
||||||
|
.into_owned()
|
||||||
|
};
|
||||||
|
let system_buid = unsafe {
|
||||||
|
std::ffi::CStr::from_ptr(system_buid)
|
||||||
|
.to_string_lossy()
|
||||||
|
.into_owned()
|
||||||
|
};
|
||||||
|
|
||||||
|
let host_name = if host_name.is_null() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(
|
||||||
|
match unsafe { std::ffi::CStr::from_ptr(host_name) }.to_str() {
|
||||||
|
Ok(v) => v,
|
||||||
|
Err(_) => {
|
||||||
|
return ffi_err!(IdeviceError::InvalidCString);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
let res = run_sync_local(async move {
|
||||||
|
let client_ref = unsafe { &mut (*client).0 };
|
||||||
|
|
||||||
|
client_ref.pair(host_id, system_buid, host_name).await
|
||||||
|
});
|
||||||
|
|
||||||
|
match res {
|
||||||
|
Ok(pairing_file_res) => {
|
||||||
|
let boxed_pairing_file = Box::new(IdevicePairingFile(pairing_file_res));
|
||||||
|
unsafe { *pairing_file = Box::into_raw(boxed_pairing_file) };
|
||||||
|
null_mut()
|
||||||
|
}
|
||||||
|
Err(e) => ffi_err!(e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Gets a value from lockdownd
|
/// Gets a value from lockdownd
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
|
|||||||
@@ -869,6 +869,10 @@ pub enum IdeviceError {
|
|||||||
#[cfg(feature = "notification_proxy")]
|
#[cfg(feature = "notification_proxy")]
|
||||||
#[error("notification proxy died")]
|
#[error("notification proxy died")]
|
||||||
NotificationProxyDeath = -69,
|
NotificationProxyDeath = -69,
|
||||||
|
|
||||||
|
#[cfg(feature = "installation_proxy")]
|
||||||
|
#[error("Application verification failed: {0}")]
|
||||||
|
ApplicationVerificationFailed(String) = -70,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IdeviceError {
|
impl IdeviceError {
|
||||||
@@ -912,6 +916,15 @@ impl IdeviceError {
|
|||||||
Some(Self::InternalError(detailed_error))
|
Some(Self::InternalError(detailed_error))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#[cfg(feature = "installation_proxy")]
|
||||||
|
"ApplicationVerificationFailed" => {
|
||||||
|
let msg = context
|
||||||
|
.get("ErrorDescription")
|
||||||
|
.and_then(|x| x.as_string())
|
||||||
|
.unwrap_or("No context")
|
||||||
|
.to_string();
|
||||||
|
Some(Self::ApplicationVerificationFailed(msg))
|
||||||
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1037,6 +1050,9 @@ impl IdeviceError {
|
|||||||
|
|
||||||
#[cfg(feature = "notification_proxy")]
|
#[cfg(feature = "notification_proxy")]
|
||||||
IdeviceError::NotificationProxyDeath => -69,
|
IdeviceError::NotificationProxyDeath => -69,
|
||||||
|
|
||||||
|
#[cfg(feature = "installation_proxy")]
|
||||||
|
IdeviceError::ApplicationVerificationFailed(_) => -70,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user