1 use std::{path::PathBuf, process::Command}; 2 3 use anyhow::{anyhow, Result}; 4 5 pub struct LoopDevice { 6 img_path: PathBuf, 7 loop_device_path: Option<String>, 8 } 9 impl LoopDevice { 10 pub fn attach(&mut self) -> Result<()> { 11 if self.loop_device_path.is_some() { 12 return Ok(()); 13 } 14 let output = Command::new("losetup") 15 .arg("-f") 16 .arg("--show") 17 .arg("-P") 18 .arg(&self.img_path) 19 .output()?; 20 21 if output.status.success() { 22 let loop_device = String::from_utf8(output.stdout)?.trim().to_string(); 23 self.loop_device_path = Some(loop_device); 24 log::trace!( 25 "Loop device attached: {}", 26 self.loop_device_path.as_ref().unwrap() 27 ); 28 Ok(()) 29 } else { 30 Err(anyhow::anyhow!( 31 "Failed to mount disk image: losetup command exited with status {}", 32 output.status 33 )) 34 } 35 } 36 /// 获取指定分区的路径 37 /// 38 /// # 参数 39 /// 40 /// * `nth` - 分区的编号 41 /// 42 /// # 返回值 43 /// 44 /// 返回一个 `Result<String>`,包含分区路径的字符串。如果循环设备未附加,则返回错误。 45 /// 46 /// # 错误 47 /// 48 /// 如果循环设备未附加,则返回 `anyhow!("Loop device not attached")` 错误。 49 pub fn partition_path(&self, nth: u8) -> Result<PathBuf> { 50 if self.loop_device_path.is_none() { 51 return Err(anyhow!("Loop device not attached")); 52 } 53 let s = format!("{}p{}", self.loop_device_path.as_ref().unwrap(), nth); 54 let s = PathBuf::from(s); 55 // 判断路径是否存在 56 if !s.exists() { 57 return Err(anyhow!("Partition not exist")); 58 } 59 Ok(s) 60 } 61 62 pub fn detach(&mut self) -> Result<()> { 63 if self.loop_device_path.is_none() { 64 return Ok(()); 65 } 66 let loop_device = self.loop_device_path.take().unwrap(); 67 let output = Command::new("losetup") 68 .arg("-d") 69 .arg(loop_device) 70 .output()?; 71 72 if output.status.success() { 73 self.loop_device_path = None; 74 Ok(()) 75 } else { 76 Err(anyhow::anyhow!("Failed to detach loop device")) 77 } 78 } 79 } 80 81 impl Drop for LoopDevice { 82 fn drop(&mut self) { 83 self.detach().expect("Failed to detach loop device"); 84 } 85 } 86 87 pub struct LoopDeviceBuilder { 88 img_path: Option<PathBuf>, 89 } 90 91 impl LoopDeviceBuilder { 92 pub fn new() -> Self { 93 LoopDeviceBuilder { img_path: None } 94 } 95 96 pub fn img_path(mut self, img_path: PathBuf) -> Self { 97 self.img_path = Some(img_path); 98 self 99 } 100 101 pub fn build(self) -> Result<LoopDevice> { 102 let mut loop_dev = LoopDevice { 103 img_path: self.img_path.unwrap(), 104 loop_device_path: None, 105 }; 106 loop_dev.attach()?; 107 Ok(loop_dev) 108 } 109 } 110