summaryrefslogtreecommitdiffstats
path: root/libimagref
diff options
context:
space:
mode:
authorMatthias Beyer <mail@beyermatthias.de>2016-06-25 16:55:49 +0200
committerMatthias Beyer <mail@beyermatthias.de>2016-07-04 19:29:02 +0200
commit757d69f41a2f0114061fb8b8dd2e9880c959151d (patch)
tree480b5c26effdf0a60a7ec89401cd2edb20f5bfef /libimagref
parentcc8048ea24fa4034f0e22cb5a78b45ce06bedd13 (diff)
Impl: Ref::refind()
Diffstat (limited to 'libimagref')
-rw-r--r--libimagref/src/reference.rs49
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())
+ })
}
}