//! Re-identifies and reconnects a session's source disk when unplugged and reattached //! under a different OS device node (e.g. `/dev/sda` becoming `/dev/sdb`). use crate::device; use crate::source::{fingerprint, open_path, Source}; use std::path::Path; use std::sync::Arc; /// Checks whether `src` matches the size and fingerprint expected by the session. /// `size == 0` or `fp == None` mean unknown (legacy session) and do not reject the source. pub fn matches(src: &dyn Source, size: u64, fp: Option<&str>) -> bool { (size == 0 || src.size() == size) && fp.map_or(true, |f| fingerprint(src).as_deref() == Some(f)) } /// Searches attached storage devices for the disk matching the session's fingerprint. /// Requires an exact fingerprint match when present; otherwise accepts a unique size match. pub fn find_matching_source( size: u64, fp: Option<&str>, exclude: &[String], ) -> Option<(String, Arc)> { if size == 0 && fp.is_none() { return None; } let mut found: Vec<(String, Arc)> = vec![]; for d in device::list_devices() { if !d.readable || exclude.contains(&d.path) || (size != 0 && d.size != size) { continue; } let Ok(src) = open_path(Path::new(&d.path)) else { continue; }; if matches(src.as_ref(), size, fp) { found.push((d.path, src)); } } if fp.is_some() { found.into_iter().next() } else if found.len() == 1 { found.pop() } else { None } }