diff --git a/idevice/src/services/afc/file.rs b/idevice/src/services/afc/file.rs index 5727d97..49f771b 100644 --- a/idevice/src/services/afc/file.rs +++ b/idevice/src/services/afc/file.rs @@ -1,5 +1,7 @@ // Jackson Coxson +use std::io::SeekFrom; + use crate::IdeviceError; use super::{ @@ -19,28 +21,76 @@ pub struct FileDescriptor<'a> { } impl FileDescriptor<'_> { - /// Closes the file descriptor - pub async fn close(self) -> Result<(), IdeviceError> { - let header_payload = self.fd.to_le_bytes().to_vec(); + /// Generic helper to send an AFC packet and read the response + async fn send_packet( + &mut self, + opcode: AfcOpcode, + header_payload: Vec, + payload: Vec, + ) -> Result { let header_len = header_payload.len() as u64 + AfcPacketHeader::LEN; - let header = AfcPacketHeader { magic: super::MAGIC, - entire_len: header_len, + entire_len: header_len + payload.len() as u64, header_payload_len: header_len, packet_num: self.client.package_number, - operation: AfcOpcode::FileClose, + operation: opcode, }; self.client.package_number += 1; let packet = AfcPacket { header, header_payload, - payload: Vec::new(), + payload, }; 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 { + 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(()) } @@ -49,32 +99,18 @@ impl FileDescriptor<'_> { /// # Returns /// A vector containing the file's data pub async fn read(&mut self) -> Result, IdeviceError> { - // Get the file size first - let mut bytes_left = self.client.get_file_info(&self.path).await?.size; + let seek_pos = self.seek_tell().await? as usize; + 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); while bytes_left > 0 { let mut header_payload = self.fd.to_le_bytes().to_vec(); 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(); collected_bytes.extend(res.payload); } @@ -87,29 +123,10 @@ impl FileDescriptor<'_> { /// # Arguments /// * `bytes` - Data to write to the file pub async fn write(&mut self, bytes: &[u8]) -> Result<(), IdeviceError> { - let chunks = bytes.chunks(MAX_TRANSFER as usize); - - for chunk in chunks { + for chunk in bytes.chunks(MAX_TRANSFER as usize) { let header_payload = self.fd.to_le_bytes().to_vec(); - let header_len = header_payload.len() as u64 + AfcPacketHeader::LEN; - - 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?; + self.send_packet(AfcOpcode::Write, header_payload, chunk.to_vec()) + .await?; } Ok(()) }