From 1a7534a106805231b19a25976bd1ad1aa46dd274 Mon Sep 17 00:00:00 2001 From: Jackson Coxson Date: Sun, 6 Apr 2025 11:53:45 -0600 Subject: [PATCH] afc write file --- idevice/src/afc/file.rs | 32 ++++++++++++++++++++++++++++++-- tools/src/afc.rs | 26 +++++++++++++++++++++++++- 2 files changed, 55 insertions(+), 3 deletions(-) diff --git a/idevice/src/afc/file.rs b/idevice/src/afc/file.rs index 43798e7..11897ee 100644 --- a/idevice/src/afc/file.rs +++ b/idevice/src/afc/file.rs @@ -22,7 +22,7 @@ impl FileDescriptor<'_> { let header = AfcPacketHeader { magic: super::MAGIC, - entire_len: header_len, // it's the same since the payload is empty for this + entire_len: header_len, header_payload_len: header_len, packet_num: self.client.package_number, operation: AfcOpcode::FileClose, @@ -52,7 +52,7 @@ impl FileDescriptor<'_> { let header = AfcPacketHeader { magic: super::MAGIC, - entire_len: header_len, // it's the same since the payload is empty for this + entire_len: header_len, header_payload_len: header_len, packet_num: self.client.package_number, operation: AfcOpcode::Read, @@ -73,4 +73,32 @@ impl FileDescriptor<'_> { Ok(collected_bytes) } + + pub async fn write(&mut self, bytes: &[u8]) -> Result<(), IdeviceError> { + let chunks = bytes.chunks(MAX_TRANSFER as usize); + + for chunk in chunks { + 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?; + } + Ok(()) + } } diff --git a/tools/src/afc.rs b/tools/src/afc.rs index 276718f..c38b7f6 100644 --- a/tools/src/afc.rs +++ b/tools/src/afc.rs @@ -1,6 +1,8 @@ // Jackson Coxson -use clap::{Arg, Command}; +use std::path::PathBuf; + +use clap::{value_parser, Arg, Command}; use idevice::{ afc::{opcode::AfcFopenMode, AfcClient}, IdeviceService, @@ -48,6 +50,17 @@ async fn main() { .arg(Arg::new("path").required(true).index(1)) .arg(Arg::new("save").required(true).index(2)), ) + .subcommand( + Command::new("upload") + .about("Creates a directory") + .arg( + Arg::new("file") + .required(true) + .index(1) + .value_parser(value_parser!(PathBuf)), + ) + .arg(Arg::new("path").required(true).index(2)), + ) .subcommand( Command::new("mkdir") .about("Creates a directory") @@ -112,6 +125,17 @@ async fn main() { tokio::fs::write(save, res) .await .expect("Failed to write to file"); + } else if let Some(matches) = matches.subcommand_matches("upload") { + let file = matches.get_one::("file").expect("No path passed"); + let path = matches.get_one::("path").expect("No path passed"); + + let bytes = tokio::fs::read(file).await.expect("Failed to read file"); + let mut file = afc_client + .open(path, AfcFopenMode::WrOnly) + .await + .expect("Failed to open"); + + file.write(&bytes).await.expect("Failed to upload bytes"); } else if let Some(matches) = matches.subcommand_matches("remove") { let path = matches.get_one::("path").expect("No path passed"); afc_client.remove(path).await.expect("Failed to remove");