diff options
author | Matthias Beyer <mail@beyermatthias.de> | 2016-06-25 16:55:49 +0200 |
---|---|---|
committer | Matthias Beyer <mail@beyermatthias.de> | 2016-07-04 19:29:02 +0200 |
commit | 757d69f41a2f0114061fb8b8dd2e9880c959151d (patch) | |
tree | 480b5c26effdf0a60a7ec89401cd2edb20f5bfef /libimagref | |
parent | cc8048ea24fa4034f0e22cb5a78b45ce06bedd13 (diff) |
Impl: Ref::refind()
Diffstat (limited to 'libimagref')
-rw-r--r-- | libimagref/src/reference.rs | 49 |
1 files changed, 46 insertions, 3 deletions
diff --git a/libimagref/src/reference.rs b/libimagref/src/reference.rs index 1d807b61..6041cca3 100644 --- a/libimagref/src/reference.rs +++ b/libimagref/src/reference.rs @@ -384,15 +384,58 @@ impl<'a> Ref<'a> { /// Re-find a referenced file /// /// This function tries to re-find a ref by searching all directories in `search_roots` recursively - /// for a file which matches the hash of the Ref `ref`. + /// for a file which matches the hash of the Ref. /// /// If `search_roots` is `None`, it starts at the filesystem root `/`. /// + /// If the target cannot be found, this yields a RefTargetDoesNotExist error kind. + /// /// # Warning /// /// This option causes heavy I/O as it recursively searches the Filesystem. - pub fn refind(&self, search_roots: Option<Vec<PathBuf>>) -> Option<PathBuf> { - unimplemented!() + pub fn refind(&self, search_roots: Option<Vec<PathBuf>>) -> Result<PathBuf> { + use itertools::Itertools; + use walkdir::WalkDir; + + self.get_stored_hash() + .and_then(|stored_hash| { + search_roots + .unwrap_or(vec![PathBuf::from("/")]) + .into_iter() + .map(|root| { + WalkDir::new(root) + .follow_links(false) + .into_iter() + .map(|entry| { + entry + .map_err(Box::new) + .map_err(|e| REK::IOError.into_error_with_cause(e)) + .and_then(|entry| { + let pb = PathBuf::from(entry.path()); + File::open(entry.path()) + .map_err(Box::new) + .map_err(|e| REK::IOError.into_error_with_cause(e)) + .map(|f| (pb, f)) + }) + .map(|(path, mut file)| (path, hash_file_contents(&mut file))) + .map(|(path, hash)| { + if hash == stored_hash { + Some(path) + } else { + None + } + }) + .map_err(Box::new) + .map_err(|e| REK::IOError.into_error_with_cause(e)) + }) + .filter_map(|e| e.ok()) + .filter_map(|e| e) + .next() + }) + .flatten() + .next() + .ok_or(REK::RefTargetDoesNotExist.into_error()) + }) } } |