mirror of
https://github.com/jkcoxson/idevice.git
synced 2026-03-02 06:26:15 +01:00
Implement AFC file seek (#28)
* Implement AFC file seek * refactored to be more readable
This commit is contained in:
committed by
GitHub
parent
23c8808ae7
commit
224fabfa69
@@ -1,5 +1,7 @@
|
|||||||
// Jackson Coxson
|
// Jackson Coxson
|
||||||
|
|
||||||
|
use std::io::SeekFrom;
|
||||||
|
|
||||||
use crate::IdeviceError;
|
use crate::IdeviceError;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
@@ -19,28 +21,76 @@ pub struct FileDescriptor<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl FileDescriptor<'_> {
|
impl FileDescriptor<'_> {
|
||||||
/// Closes the file descriptor
|
/// Generic helper to send an AFC packet and read the response
|
||||||
pub async fn close(self) -> Result<(), IdeviceError> {
|
async fn send_packet(
|
||||||
let header_payload = self.fd.to_le_bytes().to_vec();
|
&mut self,
|
||||||
|
opcode: AfcOpcode,
|
||||||
|
header_payload: Vec<u8>,
|
||||||
|
payload: Vec<u8>,
|
||||||
|
) -> Result<AfcPacket, IdeviceError> {
|
||||||
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: super::MAGIC,
|
||||||
entire_len: header_len,
|
entire_len: header_len + payload.len() as u64,
|
||||||
header_payload_len: header_len,
|
header_payload_len: header_len,
|
||||||
packet_num: self.client.package_number,
|
packet_num: self.client.package_number,
|
||||||
operation: AfcOpcode::FileClose,
|
operation: opcode,
|
||||||
};
|
};
|
||||||
self.client.package_number += 1;
|
self.client.package_number += 1;
|
||||||
|
|
||||||
let packet = AfcPacket {
|
let packet = AfcPacket {
|
||||||
header,
|
header,
|
||||||
header_payload,
|
header_payload,
|
||||||
payload: Vec::new(),
|
payload,
|
||||||
};
|
};
|
||||||
|
|
||||||
self.client.send(packet).await?;
|
self.client.send(packet).await?;
|
||||||
self.client.read().await?;
|
self.client.read().await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the current cursor position for the file
|
||||||
|
pub async fn seek_tell(&mut self) -> Result<u64, IdeviceError> {
|
||||||
|
let header_payload = self.fd.to_le_bytes().to_vec();
|
||||||
|
let res = self
|
||||||
|
.send_packet(AfcOpcode::FileTell, header_payload, Vec::new())
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
let cur_pos = res
|
||||||
|
.header_payload
|
||||||
|
.get(..8)
|
||||||
|
.ok_or(IdeviceError::UnexpectedResponse)?
|
||||||
|
.try_into()
|
||||||
|
.map(u64::from_le_bytes)
|
||||||
|
.map_err(|_| IdeviceError::UnexpectedResponse)?;
|
||||||
|
|
||||||
|
Ok(cur_pos)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Moves the file cursor
|
||||||
|
pub async fn seek(&mut self, pos: SeekFrom) -> Result<(), IdeviceError> {
|
||||||
|
let (offset, whence) = match pos {
|
||||||
|
SeekFrom::Start(off) => (off as i64, 0),
|
||||||
|
SeekFrom::Current(off) => (off, 1),
|
||||||
|
SeekFrom::End(off) => (off, 2),
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut header_payload = Vec::new();
|
||||||
|
header_payload.extend(self.fd.to_le_bytes());
|
||||||
|
header_payload.extend((whence as u64).to_le_bytes());
|
||||||
|
header_payload.extend(offset.to_le_bytes());
|
||||||
|
|
||||||
|
self.send_packet(AfcOpcode::FileSeek, header_payload, Vec::new())
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Closes the file descriptor
|
||||||
|
pub async fn close(mut self) -> Result<(), IdeviceError> {
|
||||||
|
let header_payload = self.fd.to_le_bytes().to_vec();
|
||||||
|
|
||||||
|
self.send_packet(AfcOpcode::FileClose, header_payload, Vec::new())
|
||||||
|
.await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,32 +99,18 @@ impl FileDescriptor<'_> {
|
|||||||
/// # Returns
|
/// # Returns
|
||||||
/// A vector containing the file's data
|
/// A vector containing the file's data
|
||||||
pub async fn read(&mut self) -> Result<Vec<u8>, IdeviceError> {
|
pub async fn read(&mut self) -> Result<Vec<u8>, IdeviceError> {
|
||||||
// Get the file size first
|
let seek_pos = self.seek_tell().await? as usize;
|
||||||
let mut bytes_left = self.client.get_file_info(&self.path).await?.size;
|
let file_info = self.client.get_file_info(&self.path).await?;
|
||||||
|
let mut bytes_left = file_info.size.saturating_sub(seek_pos);
|
||||||
let mut collected_bytes = Vec::with_capacity(bytes_left);
|
let mut collected_bytes = Vec::with_capacity(bytes_left);
|
||||||
|
|
||||||
while bytes_left > 0 {
|
while bytes_left > 0 {
|
||||||
let mut header_payload = self.fd.to_le_bytes().to_vec();
|
let mut header_payload = self.fd.to_le_bytes().to_vec();
|
||||||
header_payload.extend_from_slice(&MAX_TRANSFER.to_le_bytes());
|
header_payload.extend_from_slice(&MAX_TRANSFER.to_le_bytes());
|
||||||
let header_len = header_payload.len() as u64 + AfcPacketHeader::LEN;
|
let res = self
|
||||||
|
.send_packet(AfcOpcode::Read, header_payload, Vec::new())
|
||||||
|
.await?;
|
||||||
|
|
||||||
let header = AfcPacketHeader {
|
|
||||||
magic: super::MAGIC,
|
|
||||||
entire_len: header_len,
|
|
||||||
header_payload_len: header_len,
|
|
||||||
packet_num: self.client.package_number,
|
|
||||||
operation: AfcOpcode::Read,
|
|
||||||
};
|
|
||||||
self.client.package_number += 1;
|
|
||||||
|
|
||||||
let packet = AfcPacket {
|
|
||||||
header,
|
|
||||||
header_payload,
|
|
||||||
payload: Vec::new(),
|
|
||||||
};
|
|
||||||
|
|
||||||
self.client.send(packet).await?;
|
|
||||||
let res = self.client.read().await?;
|
|
||||||
bytes_left -= res.payload.len();
|
bytes_left -= res.payload.len();
|
||||||
collected_bytes.extend(res.payload);
|
collected_bytes.extend(res.payload);
|
||||||
}
|
}
|
||||||
@@ -87,29 +123,10 @@ impl FileDescriptor<'_> {
|
|||||||
/// # Arguments
|
/// # Arguments
|
||||||
/// * `bytes` - Data to write to the file
|
/// * `bytes` - Data to write to the file
|
||||||
pub async fn write(&mut self, bytes: &[u8]) -> Result<(), IdeviceError> {
|
pub async fn write(&mut self, bytes: &[u8]) -> Result<(), IdeviceError> {
|
||||||
let chunks = bytes.chunks(MAX_TRANSFER as usize);
|
for chunk in bytes.chunks(MAX_TRANSFER as usize) {
|
||||||
|
|
||||||
for chunk in chunks {
|
|
||||||
let header_payload = self.fd.to_le_bytes().to_vec();
|
let header_payload = self.fd.to_le_bytes().to_vec();
|
||||||
let header_len = header_payload.len() as u64 + AfcPacketHeader::LEN;
|
self.send_packet(AfcOpcode::Write, header_payload, chunk.to_vec())
|
||||||
|
.await?;
|
||||||
let header = AfcPacketHeader {
|
|
||||||
magic: super::MAGIC,
|
|
||||||
entire_len: header_len + chunk.len() as u64,
|
|
||||||
header_payload_len: header_len,
|
|
||||||
packet_num: self.client.package_number,
|
|
||||||
operation: AfcOpcode::Write,
|
|
||||||
};
|
|
||||||
self.client.package_number += 1;
|
|
||||||
|
|
||||||
let packet = AfcPacket {
|
|
||||||
header,
|
|
||||||
header_payload,
|
|
||||||
payload: chunk.to_vec(),
|
|
||||||
};
|
|
||||||
|
|
||||||
self.client.send(packet).await?;
|
|
||||||
self.client.read().await?;
|
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user