From 6d41747fdb112d0aa730da5d5805547fe3f29330 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Thu, 9 Jun 2016 19:34:18 +0200 Subject: [PATCH 01/38] Initial import --- libimagref/Cargo.toml | 23 +++++++++++++++++++++++ libimagref/src/lib.rs | 15 +++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 libimagref/Cargo.toml create mode 100644 libimagref/src/lib.rs diff --git a/libimagref/Cargo.toml b/libimagref/Cargo.toml new file mode 100644 index 00000000..a21494ad --- /dev/null +++ b/libimagref/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "libimagref" +version = "0.1.0" +authors = ["Matthias Beyer "] + +[dependencies] +itertools = "0.4" +log = "0.3" +rust-crypto = "0.2" +semver = "0.2" +toml = "0.1.27" +version = "2.0.1" +walkdir = "0.1.5" + +[dependencies.libimagstore] +path = "../libimagstore" + +[dependencies.libimagerror] +path = "../libimagerror" + +[dependencies.libimagutil] +path = "../libimagutil" + diff --git a/libimagref/src/lib.rs b/libimagref/src/lib.rs new file mode 100644 index 00000000..c62abbd0 --- /dev/null +++ b/libimagref/src/lib.rs @@ -0,0 +1,15 @@ +#[macro_use] extern crate log; +extern crate crypto; +extern crate itertools; +extern crate semver; +extern crate toml; +extern crate version; +extern crate walkdir; + +#[macro_use] extern crate libimagstore; +#[macro_use] extern crate libimagerror; +#[macro_use] extern crate libimagutil; + +module_entry_path_mod!("ref", "0.1.0"); + +pub mod ref; From a3b35205913f018cfbf3cfe6defafe503dddae68 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Thu, 9 Jun 2016 19:34:25 +0200 Subject: [PATCH 02/38] Add Ref type --- libimagref/src/lib.rs | 6 +- libimagref/src/reference.rs | 106 ++++++++++++++++++++++++++++++++++++ 2 files changed, 111 insertions(+), 1 deletion(-) create mode 100644 libimagref/src/reference.rs diff --git a/libimagref/src/lib.rs b/libimagref/src/lib.rs index c62abbd0..e9fca89f 100644 --- a/libimagref/src/lib.rs +++ b/libimagref/src/lib.rs @@ -12,4 +12,8 @@ extern crate walkdir; module_entry_path_mod!("ref", "0.1.0"); -pub mod ref; +pub mod reference; +pub mod flags; +pub mod error; +pub mod result; + diff --git a/libimagref/src/reference.rs b/libimagref/src/reference.rs new file mode 100644 index 00000000..67c210bd --- /dev/null +++ b/libimagref/src/reference.rs @@ -0,0 +1,106 @@ +//! The Ref object is a helper over the link functionality, so one is able to create references to +//! files outside of the imag store. + +use std::path::PathBuf; +use std::ops::Deref; +use std::ops::DerefMut; + +use libimagstore::store::FileLockEntry; +use libimagstore::storeid::StoreId; +use libimagstore::store::Store; + +use result::Result; +use flags::RefFlags; + +pub struct Ref<'a>(FileLockEntry<'a>); + +impl<'a> Ref<'a> { + + /// Try to open `si` as Ref object from the store + pub fn open(store: &Store, si: StoreId) -> Result> { + unimplemented!() + } + + /// Create a Ref object which refers to `pb` + pub fn create(store: &Store, pb: PathBuf, flags: RefFlags) -> Result> { + unimplemented!() + } + + /// Creates a Hash from a PathBuf by making the PathBuf absolute and then running a hash + /// algorithm on it + fn hash_path(pb: &PathBuf) -> String { + unimplemented!() + } + + /// check whether the pointer the Ref represents still points to a file which exists + pub fn fs_link_exists(&self) -> bool { + unimplemented!() + } + + /// check whether the pointer the Ref represents is valid + /// This includes: + /// - Hashsum of the file is still the same as stored in the Ref + /// - file permissions are still valid + pub fn fs_link_valid(&self) -> bool { + unimplemented!() + } + + /// Check whether the file permissions of the referenced file are equal to the stored + /// permissions + pub fn fs_link_valid_permissions(&self) -> bool { + unimplemented!() + } + + /// Check whether the Hashsum of the referenced file is equal to the stored hashsum + pub fn fs_link_valid_hash(&self) -> bool { + unimplemented!() + } + + /// Update the Ref by re-checking the file from FS + /// This errors if the file is not present or cannot be read() + pub fn update_ref(&mut self) -> Result<()> { + unimplemented!() + } + + /// Get the path of the file which is reffered to by this Ref + pub fn fs_file(&self) -> &PathBuf { + unimplemented!() + } + + /// Check whether there is a reference to the file at `pb` + pub fn exists(store: &Store, pb: PathBuf) -> Result { + unimplemented!() + } + + /// 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`. + /// + /// If `search_roots` is `None`, it starts at the filesystem root `/`. + /// + /// # Warning + /// + /// This option causes heavy I/O as it recursively searches the Filesystem. + pub fn refind(&self, search_roots: Option>) -> Option { + unimplemented!() + } + +} + +impl<'a> Deref for Ref<'a> { + type Target = FileLockEntry<'a>; + + fn deref(&self) -> &FileLockEntry<'a> { + &self.0 + } + +} + +impl<'a> DerefMut for Ref<'a> { + + fn deref_mut(&mut self) -> &mut FileLockEntry<'a> { + &mut self.0 + } + +} From f6ff7752493d1e6c032ba57c46cde143ac916e50 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Thu, 9 Jun 2016 16:49:46 +0200 Subject: [PATCH 03/38] Add concept of RefFlags --- libimagref/src/flags.rs | 55 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 libimagref/src/flags.rs diff --git a/libimagref/src/flags.rs b/libimagref/src/flags.rs new file mode 100644 index 00000000..9d7a1a3b --- /dev/null +++ b/libimagref/src/flags.rs @@ -0,0 +1,55 @@ +use std::collections::BTreeMap; + +use toml::Value; + +use error::RefErrorKind as REK; +use result::Result; + +#[derive(Default)] +pub struct RefFlags { + content_hashing: bool, + permission_tracking: bool, +} + +impl RefFlags { + + /// Read the RefFlags from a TOML document + /// + /// Assumes that the whole TOML tree is passed. So this looks up `ref.flags` to get the flags. + /// It assumes that this is a Map with Key = and Value = boolean. + pub fn read(v: &Value) -> Result { + unimplemented!() + } + + /// Build a TOML::Value from this RefFlags object. + /// + /// Returns a Map which should be set in `ref.flags` in the header. + pub fn into_toml(self) -> Result { + unimplemented!() + } + + /// Alias for `RefFlags::content_hashing()` + pub fn is_often_moving(mut self, b: bool) -> RefFlags { + self.with_content_hashing(b) + } + + pub fn with_content_hashing(self, b: bool) -> RefFlags { + unimplemented!() + } + + pub fn with_permission_tracking(mut self, b: bool) -> RefFlags { + self.permission_tracking = b; + self + } + + + pub fn get_content_hashing(&self) -> bool { + unimplemented!() + } + + pub fn get_permission_tracking(&self) -> bool { + unimplemented!() + } + +} + From e19a30d22785168f4348299c805a992eab42f211 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Thu, 9 Jun 2016 19:26:51 +0200 Subject: [PATCH 04/38] Add error module --- libimagref/src/error.rs | 28 ++++++++++++++++++++++++++++ libimagref/src/lib.rs | 4 ++-- 2 files changed, 30 insertions(+), 2 deletions(-) create mode 100644 libimagref/src/error.rs diff --git a/libimagref/src/error.rs b/libimagref/src/error.rs new file mode 100644 index 00000000..50c0723a --- /dev/null +++ b/libimagref/src/error.rs @@ -0,0 +1,28 @@ +generate_error_module!( + generate_error_types!(RefError, RefErrorKind, + StoreReadError => "Store read error", + StoreWriteError => "Store write error", + HeaderTypeError => "Header type error", + HeaderFieldMissingError => "Header field missing error", + HeaderFieldWriteError => "Header field cannot be written", + HeaderFieldReadError => "Header field cannot be read", + HeaderFieldAlreadyExistsError => "Header field already exists, cannot override", + PathUTF8Error => "Path cannot be converted because of UTF8 Error", + PathHashingError => "Path cannot be hashed", + PathCanonicalizationError => "Path cannot be canonicalized", + + TypeConversionError => "Couldn't convert types", + + RefNotInStore => "Ref/StoreId does not exist in store", + + RefTargetDoesNotExist => "Ref Target does not exist", + RefTargetPermissionError => "Ref Target permissions insufficient for referencing", + RefTargetCannotBeHashed => "Ref Target cannot be hashed (is it a directory?)", + RefTargetFileCannotBeOpened => "Ref Target File cannot be open()ed", + RefTargetCannotReadPermissions => "Ref Target: Cannot read permissions" + ); +); + +pub use self::error::RefError; +pub use self::error::RefErrorKind; + diff --git a/libimagref/src/lib.rs b/libimagref/src/lib.rs index e9fca89f..1cafe6a5 100644 --- a/libimagref/src/lib.rs +++ b/libimagref/src/lib.rs @@ -12,8 +12,8 @@ extern crate walkdir; module_entry_path_mod!("ref", "0.1.0"); -pub mod reference; -pub mod flags; pub mod error; +pub mod flags; +pub mod reference; pub mod result; From 6a701d9646138b7c10d53700db7df18091a3c6fb Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Thu, 9 Jun 2016 19:33:25 +0200 Subject: [PATCH 05/38] Add result type --- libimagref/src/result.rs | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 libimagref/src/result.rs diff --git a/libimagref/src/result.rs b/libimagref/src/result.rs new file mode 100644 index 00000000..097232d5 --- /dev/null +++ b/libimagref/src/result.rs @@ -0,0 +1,6 @@ +use std::result::Result as RResult; + +use error::RefError; + +pub type Result = RResult; + From 14cd99f5f2099571bd989c771fd4fc6cd9208176 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Thu, 9 Jun 2016 19:31:12 +0200 Subject: [PATCH 06/38] Impl RefFlags::read() --- libimagref/src/flags.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/libimagref/src/flags.rs b/libimagref/src/flags.rs index 9d7a1a3b..1dbbbd3f 100644 --- a/libimagref/src/flags.rs +++ b/libimagref/src/flags.rs @@ -18,7 +18,18 @@ impl RefFlags { /// Assumes that the whole TOML tree is passed. So this looks up `ref.flags` to get the flags. /// It assumes that this is a Map with Key = and Value = boolean. pub fn read(v: &Value) -> Result { - unimplemented!() + fn get_field(v: &Value, key: &str) -> Result { + match v.lookup(key) { + Some(&Value::Boolean(b)) => Ok(b), + Some(_) => Err(REK::HeaderTypeError.into()), + None => Err(REK::HeaderFieldMissingError.into()), + } + } + + Ok(RefFlags { + content_hashing: try!(get_field(v, "ref.flags.content_hashing")), + permission_tracking: try!(get_field(v, "ref.flags.permission_tracking")), + }) } /// Build a TOML::Value from this RefFlags object. From 57e653e384f5c588eb6c512b967b9e3f22ac12a1 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Thu, 9 Jun 2016 19:39:17 +0200 Subject: [PATCH 07/38] Impl RefFlags::into_toml() as Into for RefFlags --- libimagref/src/flags.rs | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/libimagref/src/flags.rs b/libimagref/src/flags.rs index 1dbbbd3f..17ff9fc7 100644 --- a/libimagref/src/flags.rs +++ b/libimagref/src/flags.rs @@ -32,13 +32,6 @@ impl RefFlags { }) } - /// Build a TOML::Value from this RefFlags object. - /// - /// Returns a Map which should be set in `ref.flags` in the header. - pub fn into_toml(self) -> Result { - unimplemented!() - } - /// Alias for `RefFlags::content_hashing()` pub fn is_often_moving(mut self, b: bool) -> RefFlags { self.with_content_hashing(b) @@ -64,3 +57,17 @@ impl RefFlags { } +impl Into for RefFlags { + + /// Build a TOML::Value from this RefFlags object. + /// + /// Returns a Map which should be set in `ref.flags` in the header. + fn into(self) -> Value { + let mut btm = BTreeMap::new(); + btm.insert(String::from("content_hashing"), Value::Boolean(self.content_hashing)); + btm.insert(String::from("permission_tracking"), Value::Boolean(self.permission_tracking)); + return Value::Table(btm) + } + +} + From 303a0c2bf8fdd7a0fa73fe9c3f8025641e2d7315 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Thu, 9 Jun 2016 19:42:08 +0200 Subject: [PATCH 08/38] Impl RefFlags::with_content_hashing() --- libimagref/src/flags.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libimagref/src/flags.rs b/libimagref/src/flags.rs index 17ff9fc7..5a51b0c4 100644 --- a/libimagref/src/flags.rs +++ b/libimagref/src/flags.rs @@ -37,8 +37,9 @@ impl RefFlags { self.with_content_hashing(b) } - pub fn with_content_hashing(self, b: bool) -> RefFlags { - unimplemented!() + pub fn with_content_hashing(mut self, b: bool) -> RefFlags { + self.content_hashing = b; + self } pub fn with_permission_tracking(mut self, b: bool) -> RefFlags { From 7a11588ec245d0a49a5da3f7965121bcd70e4da0 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Thu, 9 Jun 2016 19:42:20 +0200 Subject: [PATCH 09/38] Impl RefFlags::with_permission_tracking() --- libimagref/src/flags.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libimagref/src/flags.rs b/libimagref/src/flags.rs index 5a51b0c4..584a35f8 100644 --- a/libimagref/src/flags.rs +++ b/libimagref/src/flags.rs @@ -42,7 +42,7 @@ impl RefFlags { self } - pub fn with_permission_tracking(mut self, b: bool) -> RefFlags { + pub fn with_permission_tracking(self, b: bool) -> RefFlags { self.permission_tracking = b; self } From d00af36700654f5313d036518558942929335b59 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Thu, 9 Jun 2016 19:42:20 +0200 Subject: [PATCH 10/38] Impl RefFlags::with_permission_tracking() --- libimagref/src/flags.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libimagref/src/flags.rs b/libimagref/src/flags.rs index 584a35f8..5a51b0c4 100644 --- a/libimagref/src/flags.rs +++ b/libimagref/src/flags.rs @@ -42,7 +42,7 @@ impl RefFlags { self } - pub fn with_permission_tracking(self, b: bool) -> RefFlags { + pub fn with_permission_tracking(mut self, b: bool) -> RefFlags { self.permission_tracking = b; self } From 8989791c7a4234363071f45d8d10e27e98e45491 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Thu, 9 Jun 2016 19:43:24 +0200 Subject: [PATCH 11/38] Impl RefFlags::get_content_hashing() --- libimagref/src/flags.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libimagref/src/flags.rs b/libimagref/src/flags.rs index 5a51b0c4..865c34a6 100644 --- a/libimagref/src/flags.rs +++ b/libimagref/src/flags.rs @@ -49,7 +49,7 @@ impl RefFlags { pub fn get_content_hashing(&self) -> bool { - unimplemented!() + self.content_hashing } pub fn get_permission_tracking(&self) -> bool { From 5cfedf35700009cacc2346366aced4cd22a3da28 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Thu, 9 Jun 2016 19:43:43 +0200 Subject: [PATCH 12/38] Impl RefFlags::get_permission_tracking() --- libimagref/src/flags.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libimagref/src/flags.rs b/libimagref/src/flags.rs index 865c34a6..083403af 100644 --- a/libimagref/src/flags.rs +++ b/libimagref/src/flags.rs @@ -53,7 +53,7 @@ impl RefFlags { } pub fn get_permission_tracking(&self) -> bool { - unimplemented!() + self.permission_tracking } } From b219f06a6595638efaef745b715c23ae35eb8e6e Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Tue, 14 Jun 2016 11:05:38 +0200 Subject: [PATCH 13/38] Impl Ref::open() --- libimagref/src/reference.rs | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/libimagref/src/reference.rs b/libimagref/src/reference.rs index 67c210bd..6b994441 100644 --- a/libimagref/src/reference.rs +++ b/libimagref/src/reference.rs @@ -8,17 +8,34 @@ use std::ops::DerefMut; use libimagstore::store::FileLockEntry; use libimagstore::storeid::StoreId; use libimagstore::store::Store; +use libimagerror::into::IntoError; -use result::Result; +use toml::Value; + +use error::RefErrorKind as REK; use flags::RefFlags; +use result::Result; pub struct Ref<'a>(FileLockEntry<'a>); impl<'a> Ref<'a> { - /// Try to open `si` as Ref object from the store - pub fn open(store: &Store, si: StoreId) -> Result> { - unimplemented!() + /// Try to get `si` as Ref object from the store + pub fn get(store: &'a Store, si: StoreId) -> Result> { + match store.get(si) { + Err(e) => return Err(REK::StoreReadError.into_error_with_cause(Box::new(e))), + Ok(None) => return Err(REK::RefNotInStore.into_error()), + Ok(Some(fle)) => Ref::read_reference(&fle).map(|_| Ref(fle)), + } + } + + fn read_reference(fle: &FileLockEntry<'a>) -> Result { + match fle.get_header().read("ref.reference") { + Ok(Some(Value::String(s))) => Ok(PathBuf::from(s)), + Ok(Some(_)) => Err(REK::HeaderTypeError.into_error()), + Ok(None) => Err(REK::HeaderFieldMissingError.into_error()), + Err(e) => Err(REK::StoreReadError.into_error_with_cause(Box::new(e))), + } } /// Create a Ref object which refers to `pb` From 19f273db4533e8a1f148cc8d61e0f2db087427ad Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Tue, 14 Jun 2016 11:07:18 +0200 Subject: [PATCH 14/38] Impl Ref::is_dangling() --- libimagref/src/reference.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/libimagref/src/reference.rs b/libimagref/src/reference.rs index 6b994441..1066e53c 100644 --- a/libimagref/src/reference.rs +++ b/libimagref/src/reference.rs @@ -54,6 +54,11 @@ impl<'a> Ref<'a> { unimplemented!() } + /// Alias for `!Ref::fs_link_exists()` + pub fn is_dangling(&self) -> bool { + !self.fs_link_exists() + } + /// check whether the pointer the Ref represents is valid /// This includes: /// - Hashsum of the file is still the same as stored in the Ref From 682acfcf81a39d2157744319f9baac600754dcff Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Tue, 14 Jun 2016 11:08:58 +0200 Subject: [PATCH 15/38] Impl Ref::is_ref_to_file() --- libimagref/src/reference.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/libimagref/src/reference.rs b/libimagref/src/reference.rs index 1066e53c..151afe4c 100644 --- a/libimagref/src/reference.rs +++ b/libimagref/src/reference.rs @@ -54,6 +54,11 @@ impl<'a> Ref<'a> { unimplemented!() } + /// Alias for `r.fs_link_exists() && r.deref().is_file()` + pub fn is_ref_to_file(&self) -> bool { + unimplemented!() + } + /// Alias for `!Ref::fs_link_exists()` pub fn is_dangling(&self) -> bool { !self.fs_link_exists() From ca86f3c6ad90ea7b72404176b7dffb7e9305cddb Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Tue, 14 Jun 2016 11:09:19 +0200 Subject: [PATCH 16/38] Impl Ref::is_ref_to_dir() --- libimagref/src/reference.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/libimagref/src/reference.rs b/libimagref/src/reference.rs index 151afe4c..f79f01b4 100644 --- a/libimagref/src/reference.rs +++ b/libimagref/src/reference.rs @@ -59,6 +59,11 @@ impl<'a> Ref<'a> { unimplemented!() } + /// Alias for `r.fs_link_exists() && r.deref().is_dir()` + pub fn is_ref_to_dir(&self) -> bool { + unimplemented!() + } + /// Alias for `!Ref::fs_link_exists()` pub fn is_dangling(&self) -> bool { !self.fs_link_exists() From 4ccbb174fa0b4ee95b91c343c8953c95f3601cf6 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Tue, 14 Jun 2016 11:33:29 +0200 Subject: [PATCH 17/38] Impl Ref::create() --- libimagref/src/reference.rs | 137 +++++++++++++++++++++++++++++++++++- 1 file changed, 135 insertions(+), 2 deletions(-) diff --git a/libimagref/src/reference.rs b/libimagref/src/reference.rs index f79f01b4..602708ff 100644 --- a/libimagref/src/reference.rs +++ b/libimagref/src/reference.rs @@ -4,9 +4,11 @@ use std::path::PathBuf; use std::ops::Deref; use std::ops::DerefMut; +use std::collections::BTreeMap; use libimagstore::store::FileLockEntry; use libimagstore::storeid::StoreId; +use libimagstore::storeid::IntoStoreId; use libimagstore::store::Store; use libimagerror::into::IntoError; @@ -15,6 +17,7 @@ use toml::Value; use error::RefErrorKind as REK; use flags::RefFlags; use result::Result; +use module_path::ModuleEntryPath; pub struct Ref<'a>(FileLockEntry<'a>); @@ -39,8 +42,138 @@ impl<'a> Ref<'a> { } /// Create a Ref object which refers to `pb` - pub fn create(store: &Store, pb: PathBuf, flags: RefFlags) -> Result> { - unimplemented!() + pub fn create(store: &'a Store, pb: PathBuf, flags: RefFlags) -> Result> { + use std::fs::File; + use std::io::Read; + use crypto::sha1::Sha1; + use crypto::digest::Digest; + + if !pb.exists() { + return Err(REK::RefTargetDoesNotExist.into_error()); + } + if flags.get_content_hashing() && pb.is_dir() { + return Err(REK::RefTargetCannotBeHashed.into_error()); + } + + let (mut fle, content_hash, permissions, canonical_path) = { // scope to be able to fold + try!(File::open(pb.clone()) + .map_err(Box::new) + .map_err(|e| REK::RefTargetFileCannotBeOpened.into_error_with_cause(e)) + + // If we were able to open this file, + // we hash the contents of the file and return (file, hash) + .and_then(|mut file| { + let opt_contenthash = if flags.get_content_hashing() { + let mut hasher = Sha1::new(); + let mut s = String::new(); + file.read_to_string(&mut s); + hasher.input_str(&s[..]); + Some(hasher.result_str()) + } else { + None + }; + + Ok((file, opt_contenthash)) + }) + + // and then we get the permissions if we have to + // and return (file, content hash, permissions) + .and_then(|(file, opt_contenthash)| { + let opt_permissions = if flags.get_permission_tracking() { + Some(try!(file + .metadata() + .map(|md| md.permissions()) + .map_err(Box::new) + .map_err(|e| REK::RefTargetCannotReadPermissions.into_error_with_cause(e)) + )) + } else { + None + }; + + Ok((file, opt_contenthash, opt_permissions)) + }) + + // and then we try to canonicalize the PathBuf, because we want to store a + // canonicalized path + // and return (file, content hash, permissions, canonicalized path) + .and_then(|(file, opt_contenthash, opt_permissions)| { + pb.canonicalize() + .map(|can| (file, opt_contenthash, opt_permissions, can)) + // if PathBuf::canonicalize() failed, build an error from the return value + .map_err(|e| REK::PathCanonicalizationError.into_error_with_cause(Box::new(e))) + }) + + // and then we hash the canonicalized path + // and return (file, content hash, permissions, canonicalized path, path hash) + .and_then(|(file, opt_contenthash, opt_permissions, can)| { + let path_hash = try!(Ref::hash_path(&can) + .map_err(Box::new) + .map_err(|e| REK::PathHashingError.into_error_with_cause(e)) + ); + + Ok((file, opt_contenthash, opt_permissions, can, path_hash)) + }) + + // and then we convert the PathBuf of the canonicalized path to a String to be able + // to save it in the Ref FileLockEntry obj + // and return + // (file, content hash, permissions, canonicalized path as String, path hash) + .and_then(|(file, opt_conhash, opt_perm, can, path_hash)| { + match can.to_str().map(String::from) { + // UTF convert error in PathBuf::to_str(), + None => Err(REK::PathUTF8Error.into_error()), + Some(can) => Ok((file, opt_conhash, opt_perm, can, path_hash)) + } + }) + + // and then we create the FileLockEntry in the Store + // and return (filelockentry, content hash, permissions, canonicalized path) + .and_then(|(file, opt_conhash, opt_perm, can, path_hash)| { + let fle = try!(store + .create(ModuleEntryPath::new(path_hash)) + .map_err(Box::new) + .map_err(|e| REK::StoreWriteError.into_error_with_cause(e)) + ); + + Ok((fle, opt_conhash, opt_perm, can)) + }) + ) + }; + + for tpl in [ + Some(("ref", Value::Table(BTreeMap::new()))), + Some(("ref.permissions", Value::Table(BTreeMap::new()))), + + Some(("ref.path", Value::String(canonical_path))), + + content_hash.map(|h| ("ref.content_hash", Value::String(h))), + permissions.map(|p| ("ref.permissions.ro", Value::Boolean(p.readonly()))), + ].into_iter() + { + match tpl { + &Some((ref s, ref v)) => { + match fle.get_header_mut().insert(s, v.clone()) { + Ok(false) => { + let e = REK::HeaderFieldAlreadyExistsError.into_error(); + let e = Box::new(e); + let e = REK::HeaderFieldWriteError.into_error_with_cause(e); + return Err(e); + }, + Err(e) => { + let e = Box::new(e); + let e = REK::HeaderFieldWriteError.into_error_with_cause(e); + return Err(e); + }, + _ => (), + } + } + &None => { + debug!("Not going to insert."); + } + } + } + + Ok(Ref(fle)) } /// Creates a Hash from a PathBuf by making the PathBuf absolute and then running a hash From 130ea0db1381c6c0ae12f11c4f4fb53d72937cfa Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Tue, 21 Jun 2016 22:30:53 +0200 Subject: [PATCH 18/38] Impl Ref::hash_path() (changes returntype) --- libimagref/src/reference.rs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/libimagref/src/reference.rs b/libimagref/src/reference.rs index 602708ff..084464b8 100644 --- a/libimagref/src/reference.rs +++ b/libimagref/src/reference.rs @@ -178,8 +178,19 @@ impl<'a> Ref<'a> { /// Creates a Hash from a PathBuf by making the PathBuf absolute and then running a hash /// algorithm on it - fn hash_path(pb: &PathBuf) -> String { - unimplemented!() + fn hash_path(pb: &PathBuf) -> Result { + use std::io::Read; + use crypto::sha1::Sha1; + use crypto::digest::Digest; + + match pb.to_str() { + Some(s) => { + let mut hasher = Sha1::new(); + hasher.input_str(s); + Ok(hasher.result_str()) + }, + None => return Err(REK::PathUTF8Error.into_error()), + } } /// check whether the pointer the Ref represents still points to a file which exists From ac0d22e4799d4f0baa43b833f02b16b3e58ee1b8 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Thu, 23 Jun 2016 14:14:39 +0200 Subject: [PATCH 19/38] Impl Ref::fs_link_exists() --- libimagref/src/reference.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libimagref/src/reference.rs b/libimagref/src/reference.rs index 084464b8..1301d19a 100644 --- a/libimagref/src/reference.rs +++ b/libimagref/src/reference.rs @@ -194,8 +194,8 @@ impl<'a> Ref<'a> { } /// check whether the pointer the Ref represents still points to a file which exists - pub fn fs_link_exists(&self) -> bool { - unimplemented!() + pub fn fs_link_exists(&self) -> Result { + self.fs_file().map(|pathbuf| pathbuf.exists()) } /// Alias for `r.fs_link_exists() && r.deref().is_file()` @@ -209,8 +209,8 @@ impl<'a> Ref<'a> { } /// Alias for `!Ref::fs_link_exists()` - pub fn is_dangling(&self) -> bool { - !self.fs_link_exists() + pub fn is_dangling(&self) -> Result { + self.fs_link_exists().map(|b| !b) } /// check whether the pointer the Ref represents is valid From 904d81595bbad52135164f3e05cfc10d78b7ec89 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Thu, 23 Jun 2016 14:16:05 +0200 Subject: [PATCH 20/38] Impl Ref::fs_file() --- libimagref/src/reference.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/libimagref/src/reference.rs b/libimagref/src/reference.rs index 1301d19a..7655cc1b 100644 --- a/libimagref/src/reference.rs +++ b/libimagref/src/reference.rs @@ -239,8 +239,13 @@ impl<'a> Ref<'a> { } /// Get the path of the file which is reffered to by this Ref - pub fn fs_file(&self) -> &PathBuf { - unimplemented!() + pub fn fs_file(&self) -> Result { + match self.0.get_header().read("ref.path") { + Ok(Some(Value::String(ref s))) => Ok(PathBuf::from(s)), + Ok(Some(_)) => Err(REK::HeaderTypeError.into_error()), + Ok(None) => Err(REK::HeaderFieldMissingError.into_error()), + Err(e) => Err(REK::StoreReadError.into_error_with_cause(Box::new(e))), + } } /// Check whether there is a reference to the file at `pb` From ca48e2ac39b63b55e4a274e8d712ed024f132e78 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Thu, 23 Jun 2016 14:17:48 +0200 Subject: [PATCH 21/38] Impl Ref::is_ref_to_file() --- libimagref/src/reference.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libimagref/src/reference.rs b/libimagref/src/reference.rs index 7655cc1b..7121fcec 100644 --- a/libimagref/src/reference.rs +++ b/libimagref/src/reference.rs @@ -199,8 +199,8 @@ impl<'a> Ref<'a> { } /// Alias for `r.fs_link_exists() && r.deref().is_file()` - pub fn is_ref_to_file(&self) -> bool { - unimplemented!() + pub fn is_ref_to_file(&self) -> Result { + self.fs_file().map(|pathbuf| pathbuf.is_file()) } /// Alias for `r.fs_link_exists() && r.deref().is_dir()` From 7613526aff7a23a15986620d60d49891de739bf6 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Thu, 23 Jun 2016 14:18:16 +0200 Subject: [PATCH 22/38] Impl Ref::is_ref_to_dir() --- libimagref/src/reference.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libimagref/src/reference.rs b/libimagref/src/reference.rs index 7121fcec..ca8ca190 100644 --- a/libimagref/src/reference.rs +++ b/libimagref/src/reference.rs @@ -204,8 +204,8 @@ impl<'a> Ref<'a> { } /// Alias for `r.fs_link_exists() && r.deref().is_dir()` - pub fn is_ref_to_dir(&self) -> bool { - unimplemented!() + pub fn is_ref_to_dir(&self) -> Result { + self.fs_file().map(|pathbuf| pathbuf.is_dir()) } /// Alias for `!Ref::fs_link_exists()` From 6757c673c4307299c7fa7ddd249dbd8564ad15c8 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Thu, 23 Jun 2016 15:26:18 +0200 Subject: [PATCH 23/38] Extract file-content-hashing functionality to new private function --- libimagref/src/reference.rs | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/libimagref/src/reference.rs b/libimagref/src/reference.rs index ca8ca190..9d15dfd6 100644 --- a/libimagref/src/reference.rs +++ b/libimagref/src/reference.rs @@ -5,6 +5,8 @@ use std::path::PathBuf; use std::ops::Deref; use std::ops::DerefMut; use std::collections::BTreeMap; +use std::fs::File; +use std::io::Read; use libimagstore::store::FileLockEntry; use libimagstore::storeid::StoreId; @@ -13,6 +15,8 @@ use libimagstore::store::Store; use libimagerror::into::IntoError; use toml::Value; +use crypto::sha1::Sha1; +use crypto::digest::Digest; use error::RefErrorKind as REK; use flags::RefFlags; @@ -43,11 +47,6 @@ impl<'a> Ref<'a> { /// Create a Ref object which refers to `pb` pub fn create(store: &'a Store, pb: PathBuf, flags: RefFlags) -> Result> { - use std::fs::File; - use std::io::Read; - use crypto::sha1::Sha1; - use crypto::digest::Digest; - if !pb.exists() { return Err(REK::RefTargetDoesNotExist.into_error()); } @@ -64,11 +63,7 @@ impl<'a> Ref<'a> { // we hash the contents of the file and return (file, hash) .and_then(|mut file| { let opt_contenthash = if flags.get_content_hashing() { - let mut hasher = Sha1::new(); - let mut s = String::new(); - file.read_to_string(&mut s); - hasher.input_str(&s[..]); - Some(hasher.result_str()) + Some(hash_file_contents(&mut file)) } else { None }; @@ -285,3 +280,12 @@ impl<'a> DerefMut for Ref<'a> { } } + +fn hash_file_contents(f: &mut File) -> String { + let mut hasher = Sha1::new(); + let mut s = String::new(); + f.read_to_string(&mut s); + hasher.input_str(&s[..]); + hasher.result_str() +} + From 079675c4f07f6435d03d93e6061d3cb6258cabf3 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Thu, 23 Jun 2016 15:26:28 +0200 Subject: [PATCH 24/38] Impl Ref::fs_link_valid_hash() --- libimagref/src/error.rs | 1 + libimagref/src/reference.rs | 27 +++++++++++++++++++++++++-- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/libimagref/src/error.rs b/libimagref/src/error.rs index 50c0723a..4fee1429 100644 --- a/libimagref/src/error.rs +++ b/libimagref/src/error.rs @@ -2,6 +2,7 @@ generate_error_module!( generate_error_types!(RefError, RefErrorKind, StoreReadError => "Store read error", StoreWriteError => "Store write error", + IOError => "IO Error", HeaderTypeError => "Header type error", HeaderFieldMissingError => "Header field missing error", HeaderFieldWriteError => "Header field cannot be written", diff --git a/libimagref/src/reference.rs b/libimagref/src/reference.rs index 9d15dfd6..fb0d34eb 100644 --- a/libimagref/src/reference.rs +++ b/libimagref/src/reference.rs @@ -223,8 +223,31 @@ impl<'a> Ref<'a> { } /// Check whether the Hashsum of the referenced file is equal to the stored hashsum - pub fn fs_link_valid_hash(&self) -> bool { - unimplemented!() + pub fn fs_link_valid_hash(&self) -> Result { + let stored_hash = try!(match self.0.get_header().read("ref.content_hash") { + // content hash stored... + Ok(Some(Value::String(s))) => Ok(s), + + // content hash header field has wrong type + Ok(Some(_)) => Err(REK::HeaderTypeError.into_error()), + + // content hash not stored + Ok(None) => Err(REK::HeaderFieldMissingError.into_error()), + + // Error + Err(e) => Err(REK::StoreReadError.into_error_with_cause(Box::new(e))), + }); + + let current_hash = try!(self.fs_file() + .and_then(|pb| { + File::open(pb) + .map_err(Box::new) + .map_err(|e| REK::IOError.into_error_with_cause(e)) + }) + .map(|mut file| hash_file_contents(&mut file)) + ); + + Ok(stored_hash == current_hash) } /// Update the Ref by re-checking the file from FS From 4b98b168e58383755952cf7fa59b146a91932e89 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Thu, 23 Jun 2016 23:00:34 +0200 Subject: [PATCH 25/38] Impl Ref::exists() --- libimagref/src/reference.rs | 51 ++++++++++++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/libimagref/src/reference.rs b/libimagref/src/reference.rs index fb0d34eb..aadec161 100644 --- a/libimagref/src/reference.rs +++ b/libimagref/src/reference.rs @@ -268,7 +268,56 @@ impl<'a> Ref<'a> { /// Check whether there is a reference to the file at `pb` pub fn exists(store: &Store, pb: PathBuf) -> Result { - unimplemented!() + pb.canonicalize() + .map_err(Box::new) + .map_err(|e| REK::PathCanonicalizationError.into_error_with_cause(e)) + .and_then(|can| { + Ref::hash_path(&can) + .map_err(Box::new) + .map_err(|e| REK::PathHashingError.into_error_with_cause(e)) + }) + .and_then(|hash| { + store.retrieve_for_module("ref").map(|iter| (hash, iter)) + .map_err(Box::new) + .map_err(|e| REK::StoreReadError.into_error_with_cause(e)) + }) + .and_then(|(hash, possible_refs)| { + // This is kind of a manual Iterator::filter() call what we do here, but with the + // actual ::filter method we cannot return the error in a nice way, so we do it + // manually here. If you can come up with a better version of this, feel free to + // take this note as a todo. + for r in possible_refs { + let contains_hash = match r.to_str() { + None => { // couldn't parse StoreId -> PathBuf -> &str + // TODO: How to report this? + return Err(REK::TypeConversionError.into_error()); + }, + Some(s) => s.contains(&hash[..]), + }; + + if !contains_hash { + continue; + } + + match store.get(r) { + Ok(Some(fle)) => { + if Ref::read_reference(&fle).map(|path| path == pb).unwrap_or(false) { + return Ok(true) + } + }, + + Ok(None) => { // Something weird just happened + return Err(REK::StoreReadError.into_error()); + }, + + Err(e) => { + return Err(REK::StoreReadError.into_error_with_cause(Box::new(e))); + }, + } + } + + Ok(false) + }) } /// Re-find a referenced file From 5bf11af82c7497f73a13a3e1a8c3b731beeb2dfb Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 24 Jun 2016 16:58:41 +0200 Subject: [PATCH 26/38] Impl Ref::fs_link_valid_permissions() --- libimagref/src/reference.rs | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/libimagref/src/reference.rs b/libimagref/src/reference.rs index aadec161..9340632a 100644 --- a/libimagref/src/reference.rs +++ b/libimagref/src/reference.rs @@ -218,8 +218,36 @@ impl<'a> Ref<'a> { /// Check whether the file permissions of the referenced file are equal to the stored /// permissions - pub fn fs_link_valid_permissions(&self) -> bool { - unimplemented!() + pub fn fs_link_valid_permissions(&self) -> Result { + self.0 + .get_header() + .read("ref.permissions.ro") + .map_err(Box::new) + .map_err(|e| REK::HeaderFieldReadError.into_error_with_cause(e)) + .and_then(|ro| { + match ro { + Some(Value::Boolean(b)) => Ok(b), + Some(_) => Err(REK::HeaderTypeError.into_error()), + None => Err(REK::HeaderFieldMissingError.into_error()), + } + }) + .and_then(|ro| self.fs_file().map(|pb| (ro, pb))) + .and_then(|(ro, pb)| { + File::open(pb) + .map(|file| (ro, file)) + .map_err(Box::new) + .map_err(|e| REK::HeaderFieldReadError.into_error_with_cause(e)) + }) + .and_then(|(ro, file)| { + file + .metadata() + .map(|md| md.permissions()) + .map(|perm| perm.readonly() == ro) + .map_err(Box::new) + .map_err(|e| REK::RefTargetCannotReadPermissions.into_error_with_cause(e)) + }) + .map_err(Box::new) + .map_err(|e| REK::RefTargetCannotReadPermissions.into_error_with_cause(e)) } /// Check whether the Hashsum of the referenced file is equal to the stored hashsum From 9604f94f178ae609def7e5187f49ff2872e98b9e Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 24 Jun 2016 17:01:40 +0200 Subject: [PATCH 27/38] Impl Ref::fs_link_valid() --- libimagref/src/reference.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/libimagref/src/reference.rs b/libimagref/src/reference.rs index 9340632a..6a647aba 100644 --- a/libimagref/src/reference.rs +++ b/libimagref/src/reference.rs @@ -212,8 +212,13 @@ impl<'a> Ref<'a> { /// This includes: /// - Hashsum of the file is still the same as stored in the Ref /// - file permissions are still valid - pub fn fs_link_valid(&self) -> bool { - unimplemented!() + pub fn fs_link_valid(&self) -> Result { + match (self.fs_link_valid_permissions(), self.fs_link_valid_hash()) { + (Ok(true) , Ok(true)) => Ok(true), + (Ok(_) , Ok(_)) => Ok(false), + (Err(e) , _) => Err(e), + (_ , Err(e)) => Err(e), + } } /// Check whether the file permissions of the referenced file are equal to the stored From 6a24fcb7e4e0569d0571ef52a8aa24b82b020277 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 24 Jun 2016 17:31:28 +0200 Subject: [PATCH 28/38] Outsource hash getter functions into new (pub) functions --- libimagref/src/reference.rs | 53 +++++++++++++++++++++---------------- 1 file changed, 30 insertions(+), 23 deletions(-) diff --git a/libimagref/src/reference.rs b/libimagref/src/reference.rs index 6a647aba..a9aefd50 100644 --- a/libimagref/src/reference.rs +++ b/libimagref/src/reference.rs @@ -188,6 +188,34 @@ impl<'a> Ref<'a> { } } + /// Get the hash of the link target which is stored in the ref object + pub fn get_stored_hash(&self) -> Result { + match self.0.get_header().read("ref.content_hash") { + // content hash stored... + Ok(Some(Value::String(s))) => Ok(s), + + // content hash header field has wrong type + Ok(Some(_)) => Err(REK::HeaderTypeError.into_error()), + + // content hash not stored + Ok(None) => Err(REK::HeaderFieldMissingError.into_error()), + + // Error + Err(e) => Err(REK::StoreReadError.into_error_with_cause(Box::new(e))), + } + } + + /// Get the hash of the link target by reading the link target and hashing the contents + pub fn get_current_hash(&self) -> Result { + self.fs_file() + .and_then(|pb| { + File::open(pb) + .map_err(Box::new) + .map_err(|e| REK::IOError.into_error_with_cause(e)) + }) + .map(|mut file| hash_file_contents(&mut file)) + } + /// check whether the pointer the Ref represents still points to a file which exists pub fn fs_link_exists(&self) -> Result { self.fs_file().map(|pathbuf| pathbuf.exists()) @@ -257,29 +285,8 @@ impl<'a> Ref<'a> { /// Check whether the Hashsum of the referenced file is equal to the stored hashsum pub fn fs_link_valid_hash(&self) -> Result { - let stored_hash = try!(match self.0.get_header().read("ref.content_hash") { - // content hash stored... - Ok(Some(Value::String(s))) => Ok(s), - - // content hash header field has wrong type - Ok(Some(_)) => Err(REK::HeaderTypeError.into_error()), - - // content hash not stored - Ok(None) => Err(REK::HeaderFieldMissingError.into_error()), - - // Error - Err(e) => Err(REK::StoreReadError.into_error_with_cause(Box::new(e))), - }); - - let current_hash = try!(self.fs_file() - .and_then(|pb| { - File::open(pb) - .map_err(Box::new) - .map_err(|e| REK::IOError.into_error_with_cause(e)) - }) - .map(|mut file| hash_file_contents(&mut file)) - ); - + let stored_hash = try!(self.get_stored_hash()); + let current_hash = try!(self.get_current_hash()); Ok(stored_hash == current_hash) } From 72a125ab62c633eea81688ad1787fdabc107c7b1 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 24 Jun 2016 17:36:55 +0200 Subject: [PATCH 29/38] Extract permissions getting into helper function --- libimagref/src/reference.rs | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/libimagref/src/reference.rs b/libimagref/src/reference.rs index a9aefd50..546b1dec 100644 --- a/libimagref/src/reference.rs +++ b/libimagref/src/reference.rs @@ -7,6 +7,7 @@ use std::ops::DerefMut; use std::collections::BTreeMap; use std::fs::File; use std::io::Read; +use std::fs::Permissions; use libimagstore::store::FileLockEntry; use libimagstore::storeid::StoreId; @@ -216,6 +217,23 @@ impl<'a> Ref<'a> { .map(|mut file| hash_file_contents(&mut file)) } + /// Get the permissions of the file which are present + fn get_current_permissions(&self) -> Result { + self.fs_file() + .and_then(|pb| { + File::open(pb) + .map_err(Box::new) + .map_err(|e| REK::HeaderFieldReadError.into_error_with_cause(e)) + }) + .and_then(|file| { + file + .metadata() + .map(|md| md.permissions()) + .map_err(Box::new) + .map_err(|e| REK::RefTargetCannotReadPermissions.into_error_with_cause(e)) + }) + } + /// check whether the pointer the Ref represents still points to a file which exists pub fn fs_link_exists(&self) -> Result { self.fs_file().map(|pathbuf| pathbuf.exists()) @@ -264,21 +282,7 @@ impl<'a> Ref<'a> { None => Err(REK::HeaderFieldMissingError.into_error()), } }) - .and_then(|ro| self.fs_file().map(|pb| (ro, pb))) - .and_then(|(ro, pb)| { - File::open(pb) - .map(|file| (ro, file)) - .map_err(Box::new) - .map_err(|e| REK::HeaderFieldReadError.into_error_with_cause(e)) - }) - .and_then(|(ro, file)| { - file - .metadata() - .map(|md| md.permissions()) - .map(|perm| perm.readonly() == ro) - .map_err(Box::new) - .map_err(|e| REK::RefTargetCannotReadPermissions.into_error_with_cause(e)) - }) + .and_then(|ro| self.get_current_permissions().map(|perm| ro == perm.readonly())) .map_err(Box::new) .map_err(|e| REK::RefTargetCannotReadPermissions.into_error_with_cause(e)) } From cc8048ea24fa4034f0e22cb5a78b45ce06bedd13 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 24 Jun 2016 17:39:58 +0200 Subject: [PATCH 30/38] Impl Ref::update_ref() --- libimagref/src/reference.rs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/libimagref/src/reference.rs b/libimagref/src/reference.rs index 546b1dec..1d807b61 100644 --- a/libimagref/src/reference.rs +++ b/libimagref/src/reference.rs @@ -297,7 +297,24 @@ impl<'a> Ref<'a> { /// Update the Ref by re-checking the file from FS /// This errors if the file is not present or cannot be read() pub fn update_ref(&mut self) -> Result<()> { - unimplemented!() + let current_hash = try!(self.get_current_hash()); + let current_perm = try!(self.get_current_permissions()); + + try!(self.0 + .get_header_mut() + .set("ref.permissions.ro", Value::Boolean(current_perm.readonly())) + .map_err(Box::new) + .map_err(|e| REK::StoreWriteError.into_error_with_cause(e)) + ); + + try!(self.0 + .get_header_mut() + .set("ref.content_hash", Value::String(current_hash)) + .map_err(Box::new) + .map_err(|e| REK::StoreWriteError.into_error_with_cause(e)) + ); + + Ok(()) } /// Get the path of the file which is reffered to by this Ref From 757d69f41a2f0114061fb8b8dd2e9880c959151d Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Sat, 25 Jun 2016 16:55:49 +0200 Subject: [PATCH 31/38] Impl: Ref::refind() --- libimagref/src/reference.rs | 49 ++++++++++++++++++++++++++++++++++--- 1 file 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>) -> Option { - unimplemented!() + pub fn refind(&self, search_roots: Option>) -> Result { + 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()) + }) } } From bb4b705816e6eccf9b282ef4d2eb9bc599501a11 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Sun, 26 Jun 2016 11:35:16 +0200 Subject: [PATCH 32/38] Impl Default for RefFlags --- libimagref/src/flags.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/libimagref/src/flags.rs b/libimagref/src/flags.rs index 083403af..211aee7c 100644 --- a/libimagref/src/flags.rs +++ b/libimagref/src/flags.rs @@ -5,7 +5,6 @@ use toml::Value; use error::RefErrorKind as REK; use result::Result; -#[derive(Default)] pub struct RefFlags { content_hashing: bool, permission_tracking: bool, @@ -72,3 +71,13 @@ impl Into for RefFlags { } +impl Default for RefFlags { + + fn default() -> RefFlags { + RefFlags { + content_hashing: false, + permission_tracking: false, + } + } +} + From 31f32a4e59e4b53ae45f976a9558a5b15cea9e1a Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Sun, 26 Jun 2016 11:38:07 +0200 Subject: [PATCH 33/38] Ref: derive Debug --- libimagref/src/reference.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/libimagref/src/reference.rs b/libimagref/src/reference.rs index 6041cca3..8000e403 100644 --- a/libimagref/src/reference.rs +++ b/libimagref/src/reference.rs @@ -24,6 +24,7 @@ use flags::RefFlags; use result::Result; use module_path::ModuleEntryPath; +#[derive(Debug)] pub struct Ref<'a>(FileLockEntry<'a>); impl<'a> Ref<'a> { From 38557e9a9b3288fd57d49b41c9512f9ead7a4d1a Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Tue, 28 Jun 2016 22:54:43 +0200 Subject: [PATCH 34/38] impl Ref::delete() --- libimagref/src/reference.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/libimagref/src/reference.rs b/libimagref/src/reference.rs index 8000e403..d10953e5 100644 --- a/libimagref/src/reference.rs +++ b/libimagref/src/reference.rs @@ -38,6 +38,16 @@ impl<'a> Ref<'a> { } } + /// Delete this ref + /// + /// If the returned Result contains an error, the ref might not be deleted. + pub fn delete(self, store: &'a Store) -> Result<()> { + store + .delete(self.0.get_location().clone()) + .map_err(Box::new) + .map_err(|e| REK::StoreWriteError.into_error_with_cause(e)) + } + fn read_reference(fle: &FileLockEntry<'a>) -> Result { match fle.get_header().read("ref.reference") { Ok(Some(Value::String(s))) => Ok(PathBuf::from(s)), From a240b997734671c57bfa59429c2ea8376b40c976 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Tue, 28 Jun 2016 23:01:42 +0200 Subject: [PATCH 35/38] Impl Ref::get_by_hash() --- libimagref/src/reference.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/libimagref/src/reference.rs b/libimagref/src/reference.rs index d10953e5..e1ed79b9 100644 --- a/libimagref/src/reference.rs +++ b/libimagref/src/reference.rs @@ -38,6 +38,17 @@ impl<'a> Ref<'a> { } } + /// Get a Ref object from the store by hash. + /// + /// Returns None if the hash cannot be found. + pub fn get_by_hash(store: &'a Store, hash: String) -> Result>> { + store + .get(ModuleEntryPath::new(hash).into_storeid()) + .map(|opt_fle| opt_fle.map(|fle| Ref(fle))) + .map_err(Box::new) + .map_err(|e| REK::StoreReadError.into_error_with_cause(e)) + } + /// Delete this ref /// /// If the returned Result contains an error, the ref might not be deleted. From 617cb97ddfab49229e67238c3c7da3cf79b3dc9a Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Thu, 30 Jun 2016 11:10:38 +0200 Subject: [PATCH 36/38] Add Ref::get_path_hash() --- libimagref/src/reference.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/libimagref/src/reference.rs b/libimagref/src/reference.rs index e1ed79b9..8bdbbb6f 100644 --- a/libimagref/src/reference.rs +++ b/libimagref/src/reference.rs @@ -211,6 +211,17 @@ impl<'a> Ref<'a> { } } + /// Get the hash from the path of the ref + pub fn get_path_hash(&self) -> Option { + self.0 + .get_location() + .as_path() + .file_name() + .and_then(|osstr| osstr.to_str()) + .and_then(|s| s.split("~").next()) + .map(String::from) + } + /// Get the hash of the link target which is stored in the ref object pub fn get_stored_hash(&self) -> Result { match self.0.get_header().read("ref.content_hash") { From ebf185fd29b822715fe1e05a29de72adc239463f Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Thu, 30 Jun 2016 10:57:10 +0200 Subject: [PATCH 37/38] Add Ref::from_filelockentry() --- libimagref/src/reference.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/libimagref/src/reference.rs b/libimagref/src/reference.rs index 8bdbbb6f..5c83e35c 100644 --- a/libimagref/src/reference.rs +++ b/libimagref/src/reference.rs @@ -29,12 +29,17 @@ pub struct Ref<'a>(FileLockEntry<'a>); impl<'a> Ref<'a> { + /// Try to build a Ref object based on an existing FileLockEntry object + pub fn from_filelockentry(fle: FileLockEntry<'a>) -> Result> { + Ref::read_reference(&fle).map(|_| Ref(fle)) + } + /// Try to get `si` as Ref object from the store pub fn get(store: &'a Store, si: StoreId) -> Result> { match store.get(si) { Err(e) => return Err(REK::StoreReadError.into_error_with_cause(Box::new(e))), Ok(None) => return Err(REK::RefNotInStore.into_error()), - Ok(Some(fle)) => Ref::read_reference(&fle).map(|_| Ref(fle)), + Ok(Some(fle)) => Ref::from_filelockentry(fle), } } From a29242c586a6e75438e7e6fc70f67a31ff23da88 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Mon, 4 Jul 2016 19:41:21 +0200 Subject: [PATCH 38/38] Impl Display for Ref --- libimagref/src/reference.rs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/libimagref/src/reference.rs b/libimagref/src/reference.rs index 5c83e35c..465ca105 100644 --- a/libimagref/src/reference.rs +++ b/libimagref/src/reference.rs @@ -6,8 +6,10 @@ use std::ops::Deref; use std::ops::DerefMut; use std::collections::BTreeMap; use std::fs::File; -use std::io::Read; +use std::io::{Read, Write}; +use std::fmt::{Display, Error as FmtError, Formatter}; use std::fs::Permissions; +use std::result::Result as RResult; use libimagstore::store::FileLockEntry; use libimagstore::storeid::StoreId; @@ -495,6 +497,20 @@ impl<'a> DerefMut for Ref<'a> { } +impl<'a> Display for Ref<'a> { + + fn fmt(&self, fmt: &mut Formatter) -> RResult<(), FmtError> { + let path = self.fs_file() + .map(|pb| String::from(pb.to_str().unwrap_or(""))) + .unwrap_or(String::from("Could not read Path from reference object")); + + let hash = self.get_stored_hash().unwrap_or(String::from("")); + + write!(fmt, "Ref({} -> {})", hash, path) + } + +} + fn hash_file_contents(f: &mut File) -> String { let mut hasher = Sha1::new(); let mut s = String::new();