diff --git a/idevice/src/afc/errors.rs b/idevice/src/afc/errors.rs index 41c4037..7aa9fc3 100644 --- a/idevice/src/afc/errors.rs +++ b/idevice/src/afc/errors.rs @@ -1,6 +1,6 @@ // Jackson Coxson -#[derive(thiserror::Error, Debug)] +#[derive(thiserror::Error, Debug, PartialEq)] #[non_exhaustive] #[repr(C)] pub enum AfcError { diff --git a/idevice/src/afc/mod.rs b/idevice/src/afc/mod.rs index fab3e0f..0840b39 100644 --- a/idevice/src/afc/mod.rs +++ b/idevice/src/afc/mod.rs @@ -100,6 +100,32 @@ impl AfcClient { Ok(strings) } + pub async fn mk_dir(&mut self, path: impl Into) -> Result<(), IdeviceError> { + let path = path.into(); + let header_payload = path.as_bytes().to_vec(); + 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::MakeDir, + }; + self.package_number += 1; + + let packet = AfcPacket { + header, + header_payload, + payload: Vec::new(), + }; + + self.send(packet).await?; + self.read().await?; // read a response to check for errors + + Ok(()) + } + pub async fn get_file_info( &mut self, path: impl Into, @@ -190,7 +216,12 @@ impl AfcClient { return Err(IdeviceError::UnexpectedResponse); } let code = u64::from_le_bytes(res.header_payload[..8].try_into().unwrap()); - return Err(IdeviceError::Afc(AfcError::from(code))); + let e = AfcError::from(code); + if e == AfcError::Success { + return Ok(res); + } else { + return Err(IdeviceError::Afc(e)); + } } Ok(res) } diff --git a/tools/src/afc.rs b/tools/src/afc.rs index c9a7810..219361a 100644 --- a/tools/src/afc.rs +++ b/tools/src/afc.rs @@ -41,6 +41,11 @@ async fn main() { .about("Lists the items in the directory") .arg(Arg::new("path").required(true).index(1)), ) + .subcommand( + Command::new("mkdir") + .about("Creates a directory") + .arg(Arg::new("path").required(true).index(1)), + ) .subcommand( Command::new("remove") .about("Remove a provisioning profile") @@ -78,6 +83,9 @@ async fn main() { let path = matches.get_one::("path").expect("No path passed"); let res = afc_client.list_dir(path).await.expect("Failed to read dir"); println!("{path}\n{res:#?}"); + } else if let Some(matches) = matches.subcommand_matches("mkdir") { + let path = matches.get_one::("path").expect("No path passed"); + afc_client.mk_dir(path).await.expect("Failed to mkdir"); } else if let Some(matches) = matches.subcommand_matches("remove") { let path = matches.get_one::("id").expect("No path passed"); } else if let Some(matches) = matches.subcommand_matches("info") {