From 1014f58cfcc2090ee72b1fc43088e0b78fb5e474 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Tue, 13 Feb 2018 21:11:45 +0100 Subject: [PATCH] Rewrite interface --- lib/entry/libimagentryref/Cargo.toml | 2 - lib/entry/libimagentryref/src/error.rs | 68 +---- lib/entry/libimagentryref/src/lib.rs | 4 +- lib/entry/libimagentryref/src/reference.rs | 308 +++----------------- lib/entry/libimagentryref/src/refstore.rs | 311 +++++---------------- lib/entry/libimagentryref/src/util.rs | 52 ---- 6 files changed, 110 insertions(+), 635 deletions(-) delete mode 100644 lib/entry/libimagentryref/src/util.rs diff --git a/lib/entry/libimagentryref/Cargo.toml b/lib/entry/libimagentryref/Cargo.toml index e46d2103..5e1f7f9a 100644 --- a/lib/entry/libimagentryref/Cargo.toml +++ b/lib/entry/libimagentryref/Cargo.toml @@ -22,11 +22,9 @@ maintenance = { status = "actively-developed" } [dependencies] itertools = "0.7" log = "0.4.0" -rust-crypto = "0.2" toml = "0.4" toml-query = "0.6" error-chain = "0.11" -walkdir = "1" libimagstore = { version = "0.7.0", path = "../../../lib/core/libimagstore" } libimagerror = { version = "0.7.0", path = "../../../lib/core/libimagerror" } diff --git a/lib/entry/libimagentryref/src/error.rs b/lib/entry/libimagentryref/src/error.rs index 3c75c202..1a76aea0 100644 --- a/lib/entry/libimagentryref/src/error.rs +++ b/lib/entry/libimagentryref/src/error.rs @@ -23,7 +23,6 @@ error_chain! { } links { - ListError(::libimagentrylist::error::ListError, ::libimagentrylist::error::ListErrorKind); StoreError(::libimagstore::error::StoreError, ::libimagstore::error::StoreErrorKind); TomlQueryError(::toml_query::error::Error, ::toml_query::error::ErrorKind); EntryUtilError(::libimagentryutil::error::EntryUtilError, ::libimagentryutil::error::EntryUtilErrorKind); @@ -34,16 +33,10 @@ error_chain! { Utf8Error(::std::string::FromUtf8Error); TomlDeError(::toml::de::Error); TomlSerError(::toml::ser::Error); - WalkDirError(::walkdir::Error); } errors { - UTF8Error { - description("UTF8 Error") - display("UTF8 Error") - } - - HeaderTypeError { + HeaderTypeError { description("Header type error") display("Header type error") } @@ -53,12 +46,12 @@ error_chain! { display("Header field missing error") } - HeaderFieldWriteError { + HeaderFieldWriteError { description("Header field cannot be written") display("Header field cannot be written") } - HeaderFieldReadError { + HeaderFieldReadError { description("Header field cannot be read") display("Header field cannot be read") } @@ -73,61 +66,6 @@ error_chain! { display("Path cannot be converted because of UTF8 Error") } - PathHashingError { - description("Path cannot be hashed") - display("Path cannot be hashed") - } - - PathCanonicalizationError { - description("Path cannot be canonicalized") - display("Path cannot be canonicalized") - } - - TypeConversionError { - description("Couldn't convert types") - display("Couldn't convert types") - } - - RefToDisplayError { - description("Cannot convert Ref to string to show it to user") - display("Cannot convert Ref to string to show it to user") - } - - RefNotInStore { - description("Ref/StoreId does not exist in store") - display("Ref/StoreId does not exist in store") - } - - RefTargetDoesNotExist { - description("Ref Target does not exist") - display("Ref Target does not exist") - } - - RefTargetPermissionError { - description("Ref Target permissions insufficient for referencing") - display("Ref Target permissions insufficient for referencing") - } - - RefTargetCannotBeHashed { - description("Ref Target cannot be hashed (is it a directory?)") - display("Ref Target cannot be hashed (is it a directory?)") - } - - RefTargetFileCannotBeOpened { - description("Ref Target File cannot be open()ed") - display("Ref Target File cannot be open()ed") - } - - RefTargetCannotReadPermissions { - description("Ref Target: Cannot read permissions") - display("Ref Target: Cannot read permissions") - } - - RefHashingError { - description("Error while hashing") - display("Error while hashing") - } - } } diff --git a/lib/entry/libimagentryref/src/lib.rs b/lib/entry/libimagentryref/src/lib.rs index ea0824d3..7311d13b 100644 --- a/lib/entry/libimagentryref/src/lib.rs +++ b/lib/entry/libimagentryref/src/lib.rs @@ -36,11 +36,9 @@ )] #[macro_use] extern crate log; -extern crate crypto; extern crate itertools; extern crate toml; extern crate toml_query; -extern crate walkdir; #[macro_use] extern crate libimagstore; extern crate libimagerror; @@ -53,4 +51,4 @@ module_entry_path_mod!("ref"); pub mod error; pub mod reference; pub mod refstore; -mod util; + diff --git a/lib/entry/libimagentryref/src/reference.rs b/lib/entry/libimagentryref/src/reference.rs index dcfc9a1a..43222a86 100644 --- a/lib/entry/libimagentryref/src/reference.rs +++ b/lib/entry/libimagentryref/src/reference.rs @@ -21,101 +21,57 @@ //! files outside of the imag store. use std::path::PathBuf; -use std::fs::File; -use std::fs::Permissions; +use std::result::Result as RResult; -use libimagstore::store::Entry; use libimagentryutil::isa::Is; use libimagentryutil::isa::IsKindHeaderPathProvider; +use libimagstore::store::Entry; -use toml::Value; -use toml_query::read::TomlValueReadTypeExt; -use toml_query::set::TomlValueSetExt; +use toml_query::read::TomlValueReadExt; +use refstore::UniqueRefPathGenerator; -use error::RefErrorKind as REK; -use error::RefError as RE; -use error::ResultExt; use error::Result; -use hasher::*; +use error::RefError as RE; +use error::RefErrorKind as REK; pub trait Ref { /// Check whether the underlying object is actually a ref fn is_ref(&self) -> Result; - /// Get the hash from the path of the ref - fn get_path_hash(&self) -> Result; + /// Get the stored hash. + /// + /// Does not need a `UniqueRefPathGenerator` as it reads the hash stored in the header + fn get_hash(&self) -> Result; - /// Get the hash of the link target which is stored in the ref object - fn get_stored_hash(&self) -> Result; + /// Get the referenced path. + /// + /// Does not need a `UniqueRefPathGenerator` as it reads the path stored in the header. + fn get_path(&self) -> Result; - /// Get the hahs of the link target which is stored in the ref object, which is hashed with a - /// custom Hasher instance. - fn get_stored_hash_with_hasher(&self, h: &H) -> Result; + /// Check whether the referenced file still matches its hash + fn hash_valid(&self) -> Result; - /// Get the hash of the link target by reading the link target and hashing the contents - fn get_current_hash(&self) -> Result; - - /// Get the hash of the link target by reading the link target and hashing the contents with the - /// custom hasher - fn get_current_hash_with_hasher(&self, h: H) -> Result; - - /// check whether the pointer the Ref represents still points to a file which exists - fn fs_link_exists(&self) -> Result; + /// Update the stored hash + /// + /// This updates the hash in the header and moves the entry to the appropriate location + fn update_hash(&mut self, store: &Store) -> Result; /// Alias for `r.fs_link_exists() && r.deref().is_file()` - fn is_ref_to_file(&self) -> Result; + fn is_ref_to_file(&self) -> Result { + self.get_path().map(|p| p.is_file()) + } /// Alias for `r.fs_link_exists() && r.deref().is_dir()` - fn is_ref_to_dir(&self) -> Result; + fn is_ref_to_dir(&self) -> Result { + self.get_path().map(|p| p.is_dir()) + } /// Alias for `!Ref::fs_link_exists()` - fn is_dangling(&self) -> Result; + fn is_dangling(&self) -> Result { + self.get_path().map(|p| !p.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 - /// - file permissions are still valid - fn fs_link_valid(&self) -> Result; - - /// Check whether the file permissions of the referenced file are equal to the stored - /// permissions - fn fs_link_valid_permissions(&self) -> Result; - - /// Check whether the Hashsum of the referenced file is equal to the stored hashsum - fn fs_link_valid_hash(&self) -> Result; - - /// Update the Ref by re-checking the file from FS - /// This errors if the file is not present or cannot be read() - fn update_ref(&mut self) -> Result<()>; - - /// Update the Ref by re-checking the file from FS using the passed Hasher instance - /// This errors if the file is not present or cannot be read() - fn update_ref_with_hasher(&mut self, h: &H) -> Result<()>; - - /// Get the path of the file which is reffered to by this Ref - fn fs_file(&self) -> Result; - - /// 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. - /// - /// 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. - fn refind(&self, search_roots: Option>) -> Result; - - /// See documentation of `Ref::refind()` - fn refind_with_hasher(&self, search_roots: Option>, h: H) - -> Result; - - /// Get the permissions of the file which are present - fn get_current_permissions(&self) -> Result; } provide_kindflag_path!(pub IsRef, "ref.is_ref"); @@ -127,210 +83,20 @@ impl Ref for Entry { self.is::().map_err(From::from) } - /// Get the hash from the path of the ref - fn get_path_hash(&self) -> Result { - self.get_location() - .clone() - .into_pathbuf() - .map_err(From::from) - .and_then(|pb| { - pb.file_name() - .and_then(|osstr| osstr.to_str()) - .and_then(|s| s.split("~").next()) - .map(String::from) - .ok_or(String::from("String splitting error")) - .map_err(From::from) - }) + fn get_hash(&self) -> Result { + unimplemented!() } - /// Get the hash of the link target which is stored in the ref object - fn get_stored_hash(&self) -> Result { - self.get_stored_hash_with_hasher(&DefaultHasher::new()) + fn get_path(&self) -> Result { + unimplemented!() } - /// Get the hahs of the link target which is stored in the ref object, which is hashed with a - /// custom Hasher instance. - fn get_stored_hash_with_hasher(&self, h: &H) -> Result { - self.get_header() - .read_string(&format!("ref.content_hash.{}", h.hash_name())[..])? - .ok_or(RE::from_kind(REK::HeaderFieldMissingError)) + fn hash_valid(&self) -> Result { + unimplemented!() } - /// Get the hash of the link target by reading the link target and hashing the contents - fn get_current_hash(&self) -> Result { - self.get_current_hash_with_hasher(DefaultHasher::new()) - } - - /// Get the hash of the link target by reading the link target and hashing the contents with the - /// custom hasher - fn get_current_hash_with_hasher(&self, mut h: H) -> Result { - self.fs_file() - .and_then(|pb| File::open(pb.clone()).map(|f| (pb, f)).map_err(From::from)) - .and_then(|(path, mut file)| h.create_hash(&path, &mut file)) - } - - /// check whether the pointer the Ref represents still points to a file which exists - fn fs_link_exists(&self) -> Result { - self.fs_file().map(|pathbuf| pathbuf.exists()) - } - - /// Alias for `r.fs_link_exists() && r.deref().is_file()` - 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()` - fn is_ref_to_dir(&self) -> Result { - self.fs_file().map(|pathbuf| pathbuf.is_dir()) - } - - /// Alias for `!Ref::fs_link_exists()` - fn is_dangling(&self) -> Result { - self.fs_link_exists().map(|b| !b) - } - - /// 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 - 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 - /// permissions - fn fs_link_valid_permissions(&self) -> Result { - self - .get_header() - .read_bool("ref.permissions.ro") - .chain_err(|| REK::HeaderFieldReadError)? - .ok_or(RE::from_kind(REK::HeaderFieldMissingError)) - .and_then(|ro| self.get_current_permissions().map(|perm| ro == perm.readonly())) - .chain_err(|| REK::RefTargetCannotReadPermissions) - } - - /// Check whether the Hashsum of the referenced file is equal to the stored hashsum - fn fs_link_valid_hash(&self) -> Result { - let stored_hash = self.get_stored_hash()?; - let current_hash = self.get_current_hash()?; - Ok(stored_hash == current_hash) - } - - /// Update the Ref by re-checking the file from FS - /// This errors if the file is not present or cannot be read() - fn update_ref(&mut self) -> Result<()> { - self.update_ref_with_hasher(&DefaultHasher::new()) - } - - /// Update the Ref by re-checking the file from FS using the passed Hasher instance - /// This errors if the file is not present or cannot be read() - fn update_ref_with_hasher(&mut self, h: &H) -> Result<()> { - let current_hash = self.get_current_hash()?; // uses the default hasher - let current_perm = self.get_current_permissions()?; - - self - .get_header_mut() - .set("ref.permissions.ro", Value::Boolean(current_perm.readonly())) - ?; - - self - .get_header_mut() - .set(&format!("ref.content_hash.{}", h.hash_name())[..], Value::String(current_hash)) - ?; - - Ok(()) - } - - /// Get the path of the file which is reffered to by this Ref - fn fs_file(&self) -> Result { - self.get_header() - .read_string("ref.path")? - .ok_or(RE::from_kind(REK::HeaderFieldMissingError)) - .map(PathBuf::from) - } - - /// 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. - /// - /// 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. - fn refind(&self, search_roots: Option>) -> Result { - self.refind_with_hasher(search_roots, DefaultHasher::new()) - } - - /// See documentation of `Ref::refind()` - fn refind_with_hasher(&self, search_roots: Option>, mut h: H) - -> 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(From::from) - .and_then(|entry| { - let pb = PathBuf::from(entry.path()); - File::open(entry.path()) - .map(|f| (pb, f)) - .map_err(From::from) - }) - .and_then(|(p, mut f)| { - h.create_hash(&p, &mut f) - .map(|h| (p, h)) - .map_err(From::from) - }) - .map(|(path, hash)| { - if hash == stored_hash { - Some(path) - } else { - None - } - }) - }) - .filter_map(Result::ok) - .filter_map(|e| e) - .next() - }) - .flatten() - .next() - .ok_or(RE::from_kind(REK::RefTargetDoesNotExist)) - }) - } - - /// Get the permissions of the file which are present - fn get_current_permissions(&self) -> Result { - self.fs_file() - .and_then(|pb| { - File::open(pb) - .chain_err(|| REK::HeaderFieldReadError) - }) - .and_then(|file| { - file - .metadata() - .map(|md| md.permissions()) - .chain_err(|| REK::RefTargetCannotReadPermissions) - }) + fn update_hash(&mut self, store: &Store) -> Result { + unimplemented!() } } diff --git a/lib/entry/libimagentryref/src/refstore.rs b/lib/entry/libimagentryref/src/refstore.rs index 7248bbe8..5f1c780d 100644 --- a/lib/entry/libimagentryref/src/refstore.rs +++ b/lib/entry/libimagentryref/src/refstore.rs @@ -17,280 +17,107 @@ // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA // +use std::path::Path; use std::path::PathBuf; -use std::collections::BTreeMap; -use std::fs::File; use libimagstore::store::FileLockEntry; -use libimagstore::storeid::IntoStoreId; -use libimagstore::storeid::StoreId; -use libimagstore::storeid::StoreIdIterator; use libimagstore::store::Store; +use libimagstore::storeid::StoreId; use libimagentryutil::isa::Is; +use toml_query::insert::TomlValueInsertExt; use toml::Value; -use error::RefErrorKind as REK; use error::RefError as RE; -use error::ResultExt; -use error::Result; -use flags::RefFlags; +use error::RefErrorKind as REK; use reference::IsRef; -use hasher::*; -use module_path::ModuleEntryPath; -use util::*; -pub trait RefStore { +/// A UniqueRefPathGenerator generates unique Pathes +/// +/// It is basically a functor which generates a StoreId from a &Path. +/// For more information have a look at the documentation of RefStore. +pub trait UniqueRefPathGenerator { + type Error: From; - /// Check whether there is a reference to the file at `pb` - fn exists(&self, pb: PathBuf) -> Result; + /// The collection the `StoreId` should be created for + fn collection() -> &'static str { + "ref" + } - /// Get a Ref object from the store by hash. - /// - /// Returns None if the hash cannot be found. - fn get_by_hash<'a>(&'a self, hash: String) -> Result>>; + /// A function which should generate a unique string for a Path + fn unique_hash>(path: A) -> Result; - /// Find a store id by partial ref (also see documentation for - /// `RefStore::get_by_partitial_hash()`. - fn find_storeid_by_partial_hash(&self, hash: &String) -> Result>; + /// Postprocess the generated `StoreId` object + fn postprocess_storeid(sid: StoreId) -> Result { + Ok(sid) + } +} - /// Get a Ref object from the store by (eventually partial) hash. - /// - /// If the hash is complete, `RefStore::get_by_hash()` should be used as it is cheaper. - /// If the hash comes from user input and thus might be abbreviated, this function can be used. - fn get_by_partitial_hash<'a>(&'a self, hash: &String) -> Result>>; +/// A extensions for the `Store` to handle `Ref` objects +/// +/// The RefStore handles refs using a `UniqueRefPathGenerator`. The `UniqueRefPathGenerator`, as it +/// name suggests, generates unique `StoreId`s for a `&Path`. It is a functor `&Path -> StoreId`. +/// +/// It provides three functions which are called in the following sequence: +/// +/// * The `UniqueRefPathGenerator::collection()` function is used for get the collection a `StoreId` +/// should be in (The first element of the `StoreId` path) +/// * The `UniqueRefPathGenerator::unique_hash()` gets the `&Path` which it then should generate a +/// unique String for. How this is done does not matter. It can hash the Path itself, read the +/// file and hash that or something else. It should be reproduceable, though. +/// * These two parts are joined and put into a `StoreId` which the +/// `UniqueRefPathGenerator::postprocess_storeid()` function is then allowed to postprocess (for +/// example add more parts to the StoreId). The default implementation does nothing. +/// +/// The StoreId which is generated is then used to carry out the actual action (reading, creating +/// ...). +/// If a entry is created, header information is set (that it is a ref, the hash which was just +/// generated and the path of the referenced file) +/// +/// # Details +/// +/// The `UniqueRefPathGenerator` is passed as type parameter to enforce some semantics: +/// +/// * The used `UniqueRefPathGenerator` is defined by the implementation rather than by the runtime +/// of the program or some environment. Of course this is only a small hurdle to enforce this, but +/// a hint. +/// * The `UniqueRefPathGenerator` is a functor which does not carry state. +/// +pub trait RefStore<'a> { - /// Delete a ref by hash - /// - /// If the returned Result contains an error, the ref might not be deleted. - fn delete_by_hash(&self, hash: String) -> Result<()>; - - /// Create a Ref object which refers to `pb` - fn create<'a>(&'a self, pb: PathBuf, flags: RefFlags) -> Result>; - - fn create_with_hasher<'a, H: Hasher>(&'a self, pb: PathBuf, flags: RefFlags, h: H) - -> Result>; - - /// Get all reference objects - fn all_references(&self) -> Result; + fn get_ref(&'a self, hash: &String) -> Result>, RPG::Error>; + fn create_ref>(&'a self, path: A) -> Result, RPG::Error>; + fn retrieve_ref>(&'a self, path: A) -> Result, RPG::Error>; } -impl RefStore for Store { +impl<'a> RefStore<'a> for Store { - /// Check whether there is a reference to the file at `pb` - fn exists(&self, pb: PathBuf) -> Result { - pb.canonicalize() - .chain_err(|| REK::PathCanonicalizationError) - .and_then(|c| hash_path(&c)) - .chain_err(|| REK::PathHashingError) - .and_then(|hash| { - self.retrieve_for_module("ref").map(|iter| (hash, iter)).map_err(From::from) - }) - .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 = r.to_str() - .chain_err(|| REK::TypeConversionError) - .map(|s| s.contains(&hash[..])) - ?; - - if !contains_hash { - continue; - } - - match self.get(r.clone())? { - Some(fle) => { - if read_reference(&fle).map(|path| path == pb).unwrap_or(false) { - return Ok(true) - } - }, - - None => { - let e = format!("Failed to get from store: {}", r); - return Err(e).map_err(From::from) - }, - } - } - - Ok(false) - }) + fn get_ref(&self) -> Result>, RPG::Error> { + unimplemented!() } - /// Get a Ref object from the store by hash. - /// - /// Returns None if the hash cannot be found. - fn get_by_hash<'a>(&'a self, hash: String) -> Result>> { - ModuleEntryPath::new(hash) - .into_storeid() - .and_then(|id| self.get(id)) - .map_err(From::from) + fn create_ref(&self) -> Result, RPG::Error> { + unimplemented!() } - fn find_storeid_by_partial_hash(&self, hash: &String) -> Result> { - debug!("Trying to find '{}' in store...", hash); - for id in self.retrieve_for_module("ref")? { - let components_have_hash = id - .components() - .any(|c| c.as_os_str().to_str().map(|s| s.contains(hash)).unwrap_or(false)); - - if components_have_hash { - debug!("Found hash '{}' in {:?}", hash, id); - return Ok(Some(id)) - } - } - Ok(None) + fn retrieve_ref(&self) Result, RPG::Error> { + unimplemented!() } - /// Get a Ref object from the store by (eventually partial) hash. - /// - /// If the hash is complete, `RefStore::get_by_hash()` should be used as it is cheaper. - /// If the hash comes from user input and thus might be abbreviated, this function can be used. - fn get_by_partitial_hash<'a>(&'a self, hash: &String) -> Result>> { - match self.find_storeid_by_partial_hash(hash)? { - Some(id) => self.get(id).map_err(From::from), - None => Ok(None), - } + fn delete_ref(&self) -> Result<(), RPG::Error> { + unimplemented!() } - /// Delete a ref by hash - /// - /// If the returned Result contains an error, the ref might not be deleted. - fn delete_by_hash(&self, hash: String) -> Result<()> { - ModuleEntryPath::new(hash) - .into_storeid() - .and_then(|id| self.delete(id)) - .map_err(From::from) + fn ref_exists(&self) -> Result { + unimplemented!() } - /// Create a Ref object which refers to `pb` - fn create<'a>(&'a self, pb: PathBuf, flags: RefFlags) -> Result> { - self.create_with_hasher(pb, flags, DefaultHasher::new()) - } - - fn create_with_hasher<'a, H: Hasher>(&'a self, pb: PathBuf, flags: RefFlags, mut h: H) - -> Result> + fn move_ref_by_id(&self) + -> Result<(), Either> { - use toml_query::insert::TomlValueInsertExt; - - if !pb.exists() { - return Err(RE::from_kind(REK::RefTargetDoesNotExist)); - } - if flags.get_content_hashing() && pb.is_dir() { - return Err(RE::from_kind(REK::RefTargetCannotBeHashed)); - } - - let (mut fle, content_hash, permissions, canonical_path) = { // scope to be able to fold - File::open(pb.clone()) - .chain_err(|| REK::RefTargetFileCannotBeOpened) - - // 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() { - Some(h.create_hash(&pb, &mut file)?) - } 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(file.metadata() - .map(|md| md.permissions()) - .chain_err(|| REK::RefTargetCannotReadPermissions)?) - } else { - None - }; - - Ok((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(|(opt_contenthash, opt_permissions)| { - pb.canonicalize() - .map(|can| (opt_contenthash, opt_permissions, can)) - // if PathBuf::canonicalize() failed, build an error from the return value - .chain_err(|| REK::PathCanonicalizationError) - }) - - // and then we hash the canonicalized path - // and return (file, content hash, permissions, canonicalized path, path hash) - .and_then(|(opt_contenthash, opt_permissions, can)| { - let path_hash = hash_path(&can).chain_err(|| REK::PathHashingError)?; - - Ok((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(|(opt_conhash, opt_perm, can, path_hash)| { - match can.to_str().map(String::from) { - // UTF convert error in PathBuf::to_str(), - None => Err(RE::from_kind(REK::PathUTF8Error)), - Some(can) => Ok((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(|(opt_conhash, opt_perm, can, path_hash)| { - let fle = self.create(ModuleEntryPath::new(path_hash))?; - Ok((fle, opt_conhash, opt_perm, can)) - })? - }; - - for tpl in [ - Some((String::from("ref"), Value::Table(BTreeMap::new()))), - Some((String::from("ref.permissions"), Value::Table(BTreeMap::new()))), - Some((String::from("ref.path"), Value::String(canonical_path))), - Some((String::from("ref.content_hash"), Value::Table(BTreeMap::new()))), - - content_hash.map(|hash| { - (format!("ref.content_hash.{}", h.hash_name()), Value::String(hash)) - }), - permissions.map(|p| { - (String::from("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(Some(_)) => { - let e = RE::from_kind(REK::HeaderFieldAlreadyExistsError); - return Err(e).chain_err(|| REK::HeaderFieldWriteError); - }, - Ok(None) => { - // Okay, we just inserted a new header value... - }, - Err(e) => return Err(e).chain_err(|| REK::HeaderFieldWriteError), - } - } - &None => { - debug!("Not going to insert."); - } - } - } - - let _ = fle.set_isflag::()?; - - Ok(fle) + unimplemented!() } - fn all_references(&self) -> Result { - self.retrieve_for_module("ref").map_err(From::from) - } } diff --git a/lib/entry/libimagentryref/src/util.rs b/lib/entry/libimagentryref/src/util.rs deleted file mode 100644 index 878b98cd..00000000 --- a/lib/entry/libimagentryref/src/util.rs +++ /dev/null @@ -1,52 +0,0 @@ -// -// imag - the personal information management suite for the commandline -// Copyright (C) 2015-2018 Matthias Beyer and contributors -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; version -// 2.1 of the License. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -// - -use std::path::PathBuf; - -use error::RefErrorKind as REK; -use error::RefError as RE; -use error::Result; - -use libimagstore::store::Entry; - -use toml_query::read::TomlValueReadTypeExt; - -/// Creates a Hash from a PathBuf by making the PathBuf absolute and then running a hash -/// algorithm on it -pub fn hash_path(pb: &PathBuf) -> Result { - use crypto::sha1::Sha1; - use crypto::digest::Digest; - - pb.to_str() - .ok_or(RE::from_kind(REK::PathUTF8Error)) - .map(|s| { - let mut hasher = Sha1::new(); - hasher.input_str(s); - hasher.result_str() - }) -} - -/// Read the reference from a file -pub fn read_reference(refentry: &Entry) -> Result { - refentry.get_header() - .read_string("ref.path")? - .ok_or(RE::from_kind(REK::HeaderFieldMissingError)) - .map(PathBuf::from) -} -