mirror of
https://github.com/jkcoxson/idevice.git
synced 2026-03-02 06:26:15 +01:00
open an owned file in AFC (#44)
* ability to open an owned file Signed-off-by: Abdullah Al-Banna <abdu.albanna@proton.me> * get the inner afc of an owned file without closing the file Signed-off-by: Abdullah Al-Banna <abdu.albanna@proton.me> --------- Signed-off-by: Abdullah Al-Banna <abdu.albanna@proton.me>
This commit is contained in:
committed by
GitHub
parent
c60f0d102b
commit
9e8abb7d37
@@ -4,21 +4,31 @@ use std::{io::SeekFrom, marker::PhantomPinned, pin::Pin};
|
|||||||
|
|
||||||
use tokio::io::{AsyncRead, AsyncSeek, AsyncWrite};
|
use tokio::io::{AsyncRead, AsyncSeek, AsyncWrite};
|
||||||
|
|
||||||
use super::inner_file::InnerFileDescriptor;
|
use crate::{
|
||||||
use crate::IdeviceError;
|
IdeviceError,
|
||||||
|
afc::{
|
||||||
|
AfcClient,
|
||||||
|
inner_file::{InnerFileDescriptor, OwnedInnerFileDescriptor},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct FileDescriptor<'a> {
|
pub struct FileDescriptor<'a> {
|
||||||
inner: Pin<Box<InnerFileDescriptor<'a>>>,
|
inner: Pin<Box<InnerFileDescriptor<'a>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct OwnedFileDescriptor {
|
||||||
|
inner: Pin<Box<OwnedInnerFileDescriptor>>,
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> FileDescriptor<'a> {
|
impl<'a> FileDescriptor<'a> {
|
||||||
/// create a new FileDescriptor from a raw fd
|
/// create a new FileDescriptor from a raw fd
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
/// make sure the fd is an opened file, and that you got it from a previous
|
/// make sure the fd is an opened file, and that you got it from a previous
|
||||||
/// FileDescriptor via `as_raw_fd()` method
|
/// FileDescriptor via `as_raw_fd()` method
|
||||||
pub unsafe fn new(client: &'a mut super::AfcClient, fd: u64, path: String) -> Self {
|
pub unsafe fn new(client: &'a mut AfcClient, fd: u64, path: String) -> Self {
|
||||||
Self {
|
Self {
|
||||||
inner: Box::pin(InnerFileDescriptor {
|
inner: Box::pin(InnerFileDescriptor {
|
||||||
client,
|
client,
|
||||||
@@ -30,20 +40,54 @@ impl<'a> FileDescriptor<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_raw_fd(&self) -> u64 {
|
|
||||||
self.inner.fd
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl FileDescriptor<'_> {
|
|
||||||
/// Returns the current cursor position for the file
|
|
||||||
pub async fn seek_tell(&mut self) -> Result<u64, IdeviceError> {
|
|
||||||
self.inner.as_mut().seek_tell().await
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Closes the file descriptor
|
/// Closes the file descriptor
|
||||||
pub async fn close(self) -> Result<(), IdeviceError> {
|
pub async fn close(self) -> Result<(), IdeviceError> {
|
||||||
self.inner.close().await
|
self.inner.close().await
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl OwnedFileDescriptor {
|
||||||
|
/// create a new OwnedFileDescriptor from a raw fd
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
/// make sure the fd is an opened file, and that you got it from a previous
|
||||||
|
/// OwnedFileDescriptor via `as_raw_fd()` method
|
||||||
|
pub unsafe fn new(client: AfcClient, fd: u64, path: String) -> Self {
|
||||||
|
Self {
|
||||||
|
inner: Box::pin(OwnedInnerFileDescriptor {
|
||||||
|
client,
|
||||||
|
fd,
|
||||||
|
path,
|
||||||
|
pending_fut: None,
|
||||||
|
_m: PhantomPinned,
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Closes the file descriptor
|
||||||
|
pub async fn close(self) -> Result<AfcClient, IdeviceError> {
|
||||||
|
self.inner.close().await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// gets the owned afc
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
/// this get's the afc out without closing, if you want to get the afc and close the file, use
|
||||||
|
/// `.close()`
|
||||||
|
pub unsafe fn get_inner_afc(self) -> AfcClient {
|
||||||
|
self.inner.get_inner_afc()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
crate::impl_to_structs!(FileDescriptor<'_>, OwnedFileDescriptor; {
|
||||||
|
pub fn as_raw_fd(&self) -> u64 {
|
||||||
|
self.inner.fd
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the current cursor position for the file
|
||||||
|
pub async fn seek_tell(&mut self) -> Result<u64, IdeviceError> {
|
||||||
|
self.inner.as_mut().seek_tell().await
|
||||||
|
}
|
||||||
|
|
||||||
/// Reads the entire contents of the file
|
/// Reads the entire contents of the file
|
||||||
///
|
///
|
||||||
@@ -60,9 +104,9 @@ impl FileDescriptor<'_> {
|
|||||||
pub async fn write_entire(&mut self, bytes: &[u8]) -> Result<(), IdeviceError> {
|
pub async fn write_entire(&mut self, bytes: &[u8]) -> Result<(), IdeviceError> {
|
||||||
self.inner.as_mut().write(bytes).await
|
self.inner.as_mut().write(bytes).await
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
impl AsyncRead for FileDescriptor<'_> {
|
crate::impl_trait_to_structs!(AsyncRead for FileDescriptor<'_>, OwnedFileDescriptor; {
|
||||||
fn poll_read(
|
fn poll_read(
|
||||||
mut self: std::pin::Pin<&mut Self>,
|
mut self: std::pin::Pin<&mut Self>,
|
||||||
cx: &mut std::task::Context<'_>,
|
cx: &mut std::task::Context<'_>,
|
||||||
@@ -71,9 +115,9 @@ impl AsyncRead for FileDescriptor<'_> {
|
|||||||
let inner = self.inner.as_mut();
|
let inner = self.inner.as_mut();
|
||||||
inner.poll_read(cx, buf)
|
inner.poll_read(cx, buf)
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
impl AsyncWrite for FileDescriptor<'_> {
|
crate::impl_trait_to_structs!(AsyncWrite for FileDescriptor<'_>, OwnedFileDescriptor; {
|
||||||
fn poll_write(
|
fn poll_write(
|
||||||
mut self: std::pin::Pin<&mut Self>,
|
mut self: std::pin::Pin<&mut Self>,
|
||||||
cx: &mut std::task::Context<'_>,
|
cx: &mut std::task::Context<'_>,
|
||||||
@@ -98,9 +142,9 @@ impl AsyncWrite for FileDescriptor<'_> {
|
|||||||
let inner = self.inner.as_mut();
|
let inner = self.inner.as_mut();
|
||||||
inner.poll_shutdown(cx)
|
inner.poll_shutdown(cx)
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
impl AsyncSeek for FileDescriptor<'_> {
|
crate::impl_trait_to_structs!(AsyncSeek for FileDescriptor<'_>, OwnedFileDescriptor; {
|
||||||
fn start_seek(mut self: Pin<&mut Self>, position: SeekFrom) -> std::io::Result<()> {
|
fn start_seek(mut self: Pin<&mut Self>, position: SeekFrom) -> std::io::Result<()> {
|
||||||
let this = self.inner.as_mut();
|
let this = self.inner.as_mut();
|
||||||
this.start_seek(position)
|
this.start_seek(position)
|
||||||
@@ -113,4 +157,4 @@ impl AsyncSeek for FileDescriptor<'_> {
|
|||||||
let this = self.inner.as_mut();
|
let this = self.inner.as_mut();
|
||||||
this.poll_complete(cx)
|
this.poll_complete(cx)
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
|||||||
@@ -5,11 +5,13 @@ use std::{io::SeekFrom, pin::Pin};
|
|||||||
use futures::{FutureExt, future::BoxFuture};
|
use futures::{FutureExt, future::BoxFuture};
|
||||||
use tokio::io::{AsyncRead, AsyncSeek, AsyncWrite};
|
use tokio::io::{AsyncRead, AsyncSeek, AsyncWrite};
|
||||||
|
|
||||||
use crate::IdeviceError;
|
use crate::{
|
||||||
|
IdeviceError,
|
||||||
use super::{
|
afc::{
|
||||||
opcode::AfcOpcode,
|
AfcClient, MAGIC,
|
||||||
packet::{AfcPacket, AfcPacketHeader},
|
opcode::AfcOpcode,
|
||||||
|
packet::{AfcPacket, AfcPacketHeader},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Maximum transfer size for file operations (1MB)
|
/// Maximum transfer size for file operations (1MB)
|
||||||
@@ -32,19 +34,31 @@ pub(crate) enum PendingResult {
|
|||||||
Bytes(Vec<u8>),
|
Bytes(Vec<u8>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type OwnedBoxFuture = Pin<Box<dyn Future<Output = Result<PendingResult, IdeviceError>> + Send>>;
|
||||||
|
|
||||||
/// Handle for an open file on the device.
|
/// Handle for an open file on the device.
|
||||||
/// Call close before dropping
|
/// Call close before dropping
|
||||||
pub(crate) struct InnerFileDescriptor<'a> {
|
pub(crate) struct InnerFileDescriptor<'a> {
|
||||||
pub(crate) client: &'a mut super::AfcClient,
|
pub(crate) client: &'a mut AfcClient,
|
||||||
pub(crate) fd: u64,
|
pub(crate) fd: u64,
|
||||||
pub(crate) path: String,
|
pub(crate) path: String,
|
||||||
|
|
||||||
pub(crate) pending_fut: Option<BoxFuture<'a, Result<PendingResult, IdeviceError>>>,
|
pub(crate) pending_fut: Option<BoxFuture<'a, Result<PendingResult, IdeviceError>>>,
|
||||||
|
|
||||||
pub(crate) _m: std::marker::PhantomPinned,
|
pub(crate) _m: std::marker::PhantomPinned,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InnerFileDescriptor<'_> {
|
/// Handle for an owned open file on the device.
|
||||||
|
/// Call close before dropping
|
||||||
|
pub(crate) struct OwnedInnerFileDescriptor {
|
||||||
|
pub(crate) client: AfcClient,
|
||||||
|
pub(crate) fd: u64,
|
||||||
|
pub(crate) path: String,
|
||||||
|
|
||||||
|
pub(crate) pending_fut: Option<OwnedBoxFuture>,
|
||||||
|
pub(crate) _m: std::marker::PhantomPinned,
|
||||||
|
}
|
||||||
|
|
||||||
|
crate::impl_to_structs!(InnerFileDescriptor<'_>, OwnedInnerFileDescriptor; {
|
||||||
/// Generic helper to send an AFC packet and read the response
|
/// Generic helper to send an AFC packet and read the response
|
||||||
pub async fn send_packet(
|
pub async fn send_packet(
|
||||||
self: Pin<&mut Self>,
|
self: Pin<&mut Self>,
|
||||||
@@ -57,7 +71,7 @@ impl InnerFileDescriptor<'_> {
|
|||||||
|
|
||||||
let header_len = header_payload.len() as u64 + AfcPacketHeader::LEN;
|
let header_len = header_payload.len() as u64 + AfcPacketHeader::LEN;
|
||||||
let header = AfcPacketHeader {
|
let header = AfcPacketHeader {
|
||||||
magic: super::MAGIC,
|
magic: MAGIC,
|
||||||
entire_len: header_len + payload.len() as u64,
|
entire_len: header_len + payload.len() as u64,
|
||||||
header_payload_len: header_len,
|
header_payload_len: header_len,
|
||||||
packet_num: this.client.package_number,
|
packet_num: this.client.package_number,
|
||||||
@@ -115,15 +129,6 @@ impl InnerFileDescriptor<'_> {
|
|||||||
self.as_mut().seek_tell().await
|
self.as_mut().seek_tell().await
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Closes the file descriptor
|
|
||||||
pub async fn close(mut self: Pin<Box<Self>>) -> Result<(), IdeviceError> {
|
|
||||||
let header_payload = self.fd.to_le_bytes().to_vec();
|
|
||||||
|
|
||||||
self.as_mut()
|
|
||||||
.send_packet(AfcOpcode::FileClose, header_payload, Vec::new())
|
|
||||||
.await?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Reads n size of contents from the file
|
/// Reads n size of contents from the file
|
||||||
///
|
///
|
||||||
@@ -188,7 +193,7 @@ impl InnerFileDescriptor<'_> {
|
|||||||
|
|
||||||
fn store_pending_read(mut self: Pin<&mut Self>, buf_rem: usize) {
|
fn store_pending_read(mut self: Pin<&mut Self>, buf_rem: usize) {
|
||||||
unsafe {
|
unsafe {
|
||||||
let this = self.as_mut().get_unchecked_mut() as *mut InnerFileDescriptor;
|
let this = self.as_mut().get_unchecked_mut() as *mut Self;
|
||||||
|
|
||||||
let fut = Some(
|
let fut = Some(
|
||||||
// SAFETY: we already know that self is pinned
|
// SAFETY: we already know that self is pinned
|
||||||
@@ -204,7 +209,7 @@ impl InnerFileDescriptor<'_> {
|
|||||||
|
|
||||||
fn store_pending_seek(mut self: Pin<&mut Self>, position: std::io::SeekFrom) {
|
fn store_pending_seek(mut self: Pin<&mut Self>, position: std::io::SeekFrom) {
|
||||||
unsafe {
|
unsafe {
|
||||||
let this = self.as_mut().get_unchecked_mut() as *mut InnerFileDescriptor;
|
let this = self.as_mut().get_unchecked_mut() as *mut Self;
|
||||||
|
|
||||||
let fut = Some(
|
let fut = Some(
|
||||||
Pin::new_unchecked(&mut *this)
|
Pin::new_unchecked(&mut *this)
|
||||||
@@ -221,7 +226,7 @@ impl InnerFileDescriptor<'_> {
|
|||||||
unsafe {
|
unsafe {
|
||||||
let this = self.as_mut().get_unchecked_mut();
|
let this = self.as_mut().get_unchecked_mut();
|
||||||
|
|
||||||
let this = this as *mut InnerFileDescriptor;
|
let this = this as *mut Self;
|
||||||
|
|
||||||
// move the entire buffer into the future so we don't have to store it somewhere
|
// move the entire buffer into the future so we don't have to store it somewhere
|
||||||
let pined_this = Pin::new_unchecked(&mut *this);
|
let pined_this = Pin::new_unchecked(&mut *this);
|
||||||
@@ -232,7 +237,7 @@ impl InnerFileDescriptor<'_> {
|
|||||||
(&mut *this).pending_fut = Some(fut);
|
(&mut *this).pending_fut = Some(fut);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
impl<'a> InnerFileDescriptor<'a> {
|
impl<'a> InnerFileDescriptor<'a> {
|
||||||
fn get_or_init_read_fut(
|
fn get_or_init_read_fut(
|
||||||
@@ -268,9 +273,63 @@ impl<'a> InnerFileDescriptor<'a> {
|
|||||||
self.as_mut().get_unchecked_mut().pending_fut.take();
|
self.as_mut().get_unchecked_mut().pending_fut.take();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Closes the file descriptor
|
||||||
|
pub async fn close(mut self: Pin<Box<Self>>) -> Result<(), IdeviceError> {
|
||||||
|
let header_payload = self.fd.to_le_bytes().to_vec();
|
||||||
|
|
||||||
|
self.as_mut()
|
||||||
|
.send_packet(AfcOpcode::FileClose, header_payload, Vec::new())
|
||||||
|
.await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AsyncRead for InnerFileDescriptor<'_> {
|
impl OwnedInnerFileDescriptor {
|
||||||
|
fn get_or_init_read_fut(mut self: Pin<&mut Self>, buf_rem: usize) -> &mut OwnedBoxFuture {
|
||||||
|
if self.as_ref().pending_fut.is_none() {
|
||||||
|
self.as_mut().store_pending_read(buf_rem);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe { self.get_unchecked_mut().pending_fut.as_mut().unwrap() }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_or_init_write_fut(mut self: Pin<&mut Self>, buf: &'_ [u8]) -> &mut OwnedBoxFuture {
|
||||||
|
if self.as_ref().pending_fut.is_none() {
|
||||||
|
self.as_mut().store_pending_write(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe { self.get_unchecked_mut().pending_fut.as_mut().unwrap() }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_seek_fut(self: Pin<&mut Self>) -> Option<&mut OwnedBoxFuture> {
|
||||||
|
unsafe { self.get_unchecked_mut().pending_fut.as_mut() }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn remove_pending_fut(mut self: Pin<&mut Self>) {
|
||||||
|
unsafe {
|
||||||
|
self.as_mut().get_unchecked_mut().pending_fut.take();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Closes the file descriptor
|
||||||
|
pub async fn close(mut self: Pin<Box<Self>>) -> Result<AfcClient, IdeviceError> {
|
||||||
|
let header_payload = self.fd.to_le_bytes().to_vec();
|
||||||
|
|
||||||
|
self.as_mut()
|
||||||
|
.send_packet(AfcOpcode::FileClose, header_payload, Vec::new())
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
// we don't need it to be pinned anymore
|
||||||
|
Ok(unsafe { Pin::into_inner_unchecked(self) }.client)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_inner_afc(self: Pin<Box<Self>>) -> AfcClient {
|
||||||
|
unsafe { Pin::into_inner_unchecked(self).client }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
crate::impl_trait_to_structs!(AsyncRead for InnerFileDescriptor<'_>, OwnedInnerFileDescriptor; {
|
||||||
fn poll_read(
|
fn poll_read(
|
||||||
mut self: std::pin::Pin<&mut Self>,
|
mut self: std::pin::Pin<&mut Self>,
|
||||||
cx: &mut std::task::Context<'_>,
|
cx: &mut std::task::Context<'_>,
|
||||||
@@ -293,9 +352,9 @@ impl AsyncRead for InnerFileDescriptor<'_> {
|
|||||||
|
|
||||||
std::task::Poll::Ready(Ok(()))
|
std::task::Poll::Ready(Ok(()))
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
impl AsyncWrite for InnerFileDescriptor<'_> {
|
crate::impl_trait_to_structs!(AsyncWrite for InnerFileDescriptor<'_>, OwnedInnerFileDescriptor; {
|
||||||
fn poll_write(
|
fn poll_write(
|
||||||
mut self: std::pin::Pin<&mut Self>,
|
mut self: std::pin::Pin<&mut Self>,
|
||||||
cx: &mut std::task::Context<'_>,
|
cx: &mut std::task::Context<'_>,
|
||||||
@@ -329,9 +388,10 @@ impl AsyncWrite for InnerFileDescriptor<'_> {
|
|||||||
) -> std::task::Poll<Result<(), std::io::Error>> {
|
) -> std::task::Poll<Result<(), std::io::Error>> {
|
||||||
std::task::Poll::Ready(Ok(()))
|
std::task::Poll::Ready(Ok(()))
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl AsyncSeek for InnerFileDescriptor<'_> {
|
});
|
||||||
|
|
||||||
|
crate::impl_trait_to_structs!(AsyncSeek for InnerFileDescriptor<'_>, OwnedInnerFileDescriptor; {
|
||||||
fn start_seek(self: Pin<&mut Self>, position: SeekFrom) -> std::io::Result<()> {
|
fn start_seek(self: Pin<&mut Self>, position: SeekFrom) -> std::io::Result<()> {
|
||||||
self.store_pending_seek(position);
|
self.store_pending_seek(position);
|
||||||
|
|
||||||
@@ -356,7 +416,7 @@ impl AsyncSeek for InnerFileDescriptor<'_> {
|
|||||||
_ => unreachable!("a non seek future was stored, this shouldn't happen"),
|
_ => unreachable!("a non seek future was stored, this shouldn't happen"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
impl std::fmt::Debug for InnerFileDescriptor<'_> {
|
impl std::fmt::Debug for InnerFileDescriptor<'_> {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
@@ -368,18 +428,31 @@ impl std::fmt::Debug for InnerFileDescriptor<'_> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Debug for OwnedInnerFileDescriptor {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
f.debug_struct("OwnedInnerFileDescriptor")
|
||||||
|
.field("client", &self.client)
|
||||||
|
.field("fd", &self.fd)
|
||||||
|
.field("path", &self.path)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use tokio::io::{AsyncReadExt, AsyncSeekExt, AsyncWriteExt};
|
use tokio::io::{AsyncReadExt, AsyncSeekExt, AsyncWriteExt};
|
||||||
|
|
||||||
use crate::usbmuxd::{UsbmuxdAddr, UsbmuxdConnection};
|
use crate::{
|
||||||
|
IdeviceService as _,
|
||||||
|
afc::opcode::AfcFopenMode,
|
||||||
|
usbmuxd::{UsbmuxdAddr, UsbmuxdConnection},
|
||||||
|
};
|
||||||
|
|
||||||
use super::super::*;
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
async fn make_client() -> super::super::AfcClient {
|
async fn make_client() -> AfcClient {
|
||||||
let mut u = UsbmuxdConnection::default()
|
let mut u = UsbmuxdConnection::default()
|
||||||
.await
|
.await
|
||||||
.expect("failed to connect to usbmuxd");
|
.expect("failed to connect to usbmuxd");
|
||||||
|
|||||||
23
idevice/src/services/afc/inner_file_impl_macro.rs
Normal file
23
idevice/src/services/afc/inner_file_impl_macro.rs
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
#[macro_export]
|
||||||
|
macro_rules! impl_to_structs {
|
||||||
|
(
|
||||||
|
$( $name:ident $(<$li:lifetime>)? ),+;
|
||||||
|
$body:tt
|
||||||
|
) => {
|
||||||
|
$(
|
||||||
|
impl $name $(<$li>)? $body
|
||||||
|
)+
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! impl_trait_to_structs {
|
||||||
|
(
|
||||||
|
$trit:ident for $( $name:ident $(<$li:lifetime>)? ),+;
|
||||||
|
$body:tt
|
||||||
|
) => {
|
||||||
|
$(
|
||||||
|
impl $trit for $name $(<$li>)? $body
|
||||||
|
)+
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -6,16 +6,20 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use errors::AfcError;
|
use errors::AfcError;
|
||||||
use file::FileDescriptor;
|
|
||||||
use opcode::{AfcFopenMode, AfcOpcode};
|
use opcode::{AfcFopenMode, AfcOpcode};
|
||||||
use packet::{AfcPacket, AfcPacketHeader};
|
use packet::{AfcPacket, AfcPacketHeader};
|
||||||
use tracing::warn;
|
use tracing::warn;
|
||||||
|
|
||||||
use crate::{Idevice, IdeviceError, IdeviceService, obf};
|
use crate::{
|
||||||
|
Idevice, IdeviceError, IdeviceService,
|
||||||
|
afc::file::{FileDescriptor, OwnedFileDescriptor},
|
||||||
|
obf,
|
||||||
|
};
|
||||||
|
|
||||||
pub mod errors;
|
pub mod errors;
|
||||||
pub mod file;
|
pub mod file;
|
||||||
mod inner_file;
|
mod inner_file;
|
||||||
|
mod inner_file_impl_macro;
|
||||||
pub mod opcode;
|
pub mod opcode;
|
||||||
pub mod packet;
|
pub mod packet;
|
||||||
|
|
||||||
@@ -415,6 +419,51 @@ impl AfcClient {
|
|||||||
Ok(unsafe { FileDescriptor::new(self, fd, path) })
|
Ok(unsafe { FileDescriptor::new(self, fd, path) })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Opens an owned file on the device
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
/// * `path` - Path to the file to open
|
||||||
|
/// * `mode` - Opening mode (read, write, etc.)
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
/// A `OwnedFileDescriptor` struct for the opened file
|
||||||
|
pub async fn open_owned(
|
||||||
|
mut self,
|
||||||
|
path: impl Into<String>,
|
||||||
|
mode: AfcFopenMode,
|
||||||
|
) -> Result<OwnedFileDescriptor, IdeviceError> {
|
||||||
|
let path = path.into();
|
||||||
|
let mut header_payload = (mode as u64).to_le_bytes().to_vec();
|
||||||
|
header_payload.extend(path.as_bytes());
|
||||||
|
let header_len = header_payload.len() as u64 + AfcPacketHeader::LEN;
|
||||||
|
|
||||||
|
let header = AfcPacketHeader {
|
||||||
|
magic: MAGIC,
|
||||||
|
entire_len: header_len, // it's the same since the payload is empty for this
|
||||||
|
header_payload_len: header_len,
|
||||||
|
packet_num: self.package_number,
|
||||||
|
operation: AfcOpcode::FileOpen,
|
||||||
|
};
|
||||||
|
self.package_number += 1;
|
||||||
|
|
||||||
|
let packet = AfcPacket {
|
||||||
|
header,
|
||||||
|
header_payload,
|
||||||
|
payload: Vec::new(),
|
||||||
|
};
|
||||||
|
|
||||||
|
self.send(packet).await?;
|
||||||
|
let res = self.read().await?;
|
||||||
|
if res.header_payload.len() < 8 {
|
||||||
|
warn!("Header payload fd is less than 8 bytes");
|
||||||
|
return Err(IdeviceError::UnexpectedResponse);
|
||||||
|
}
|
||||||
|
let fd = u64::from_le_bytes(res.header_payload[..8].try_into().unwrap());
|
||||||
|
|
||||||
|
// we know it's a valid fd
|
||||||
|
Ok(unsafe { OwnedFileDescriptor::new(self, fd, path) })
|
||||||
|
}
|
||||||
|
|
||||||
/// Creates a hard or symbolic link
|
/// Creates a hard or symbolic link
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
|
|||||||
Reference in New Issue
Block a user