diff --git a/libimagstore/src/error.rs b/libimagstore/src/error.rs index 3a61a58a..f6067ccb 100644 --- a/libimagstore/src/error.rs +++ b/libimagstore/src/error.rs @@ -16,6 +16,10 @@ generate_custom_error_types!(StoreError, StoreErrorKind, CustomErrorData, FileNotCreated => "File corresponding to ID could not be created", FileNotWritten => "File corresponding to ID could not be written to", FileNotSeeked => "File corresponding to ID could not be seeked", + FileNotRemoved => "File corresponding to ID could not be removed", + FileNotRenamed => "File corresponding to ID could not be renamed", + FileNotCopied => "File could not be copied", + DirNotCreated => "Directory/Directories could not be created", StorePathExists => "Store path exists", StorePathCreate => "Store path create", LockError => "Error locking datastructure", diff --git a/libimagstore/src/lazyfile.rs b/libimagstore/src/lazyfile.rs index 515e4b24..a8eb2feb 100644 --- a/libimagstore/src/lazyfile.rs +++ b/libimagstore/src/lazyfile.rs @@ -1,4 +1,8 @@ -pub use self::fs::LazyFile; +pub use self::fs::FileAbstraction; + +// TODO: +// This whole thing can be written better with a trait based mechanism that is embedded into the +// store. However it would mean rewriting most things to be generic which can be a pain in the ass. #[cfg(test)] mod fs { @@ -15,23 +19,23 @@ mod fs { }; } - /// `LazyFile` type, this is the Test version! + /// `FileAbstraction` type, this is the Test version! /// /// A lazy file is either absent, but a path to it is available, or it is present. #[derive(Debug)] - pub enum LazyFile { + pub enum FileAbstraction { Absent(PathBuf), } - impl LazyFile { + impl FileAbstraction { /** - * Get the mutable file behind a LazyFile object + * Get the mutable file behind a FileAbstraction object */ pub fn get_file_content(&mut self) -> Result>, SE> { debug!("Getting lazy file: {:?}", self); match *self { - LazyFile::Absent(ref f) => { + FileAbstraction::Absent(ref f) => { let map = MAP.lock().unwrap(); return Ok(map.get(f).unwrap().clone()); }, @@ -40,7 +44,7 @@ mod fs { pub fn write_file_content(&mut self, buf: &[u8]) -> Result<(), SE> { match *self { - LazyFile::Absent(ref f) => { + FileAbstraction::Absent(ref f) => { let mut map = MAP.lock().unwrap(); if let Some(ref mut cur) = map.get_mut(f) { let mut vec = cur.get_mut(); @@ -54,6 +58,28 @@ mod fs { }, }; } + + pub fn remove_file(_: &PathBuf) -> Result<(), SE> { + Ok(()) + } + + pub fn copy(from: &PathBuf, to: &PathBuf) -> Result<(), SE> { + let mut map = MAP.lock().unwrap(); + let a = map.get(from).unwrap().clone(); + map.insert(to.clone(), a); + Ok(()) + } + + pub fn rename(from: &PathBuf, to: &PathBuf) -> Result<(), SE> { + let mut map = MAP.lock().unwrap(); + let a = map.get(from).unwrap().clone(); + map.insert(to.clone(), a); + Ok(()) + } + + pub fn create_dir_all(_: &PathBuf) -> Result<(), SE> { + Ok(()) + } } } @@ -62,15 +88,15 @@ mod fs { use error::{MapErrInto, StoreError as SE, StoreErrorKind as SEK}; use std::io::{Seek, SeekFrom, Read}; use std::path::{Path, PathBuf}; - use std::fs::{File, OpenOptions, create_dir_all}; + use std::fs::{File, OpenOptions, create_dir_all, remove_file, copy, rename}; - /// `LazyFile` type + /// `FileAbstraction` type /// /// A lazy file is either absent, but a path to it is available, or it is present. #[derive(Debug)] - pub enum LazyFile { + pub enum FileAbstraction { Absent(PathBuf), - File(File) + File(File, PathBuf) } fn open_file>(p: A) -> ::std::io::Result { @@ -87,25 +113,26 @@ mod fs { OpenOptions::new().write(true).read(true).create(true).open(p) } - impl LazyFile { + impl FileAbstraction { /** * Get the content behind this file */ pub fn get_file_content(&mut self) -> Result<&mut Read, SE> { debug!("Getting lazy file: {:?}", self); - let file = match *self { - LazyFile::File(ref mut f) => return { + let (file, path) = match *self { + FileAbstraction::File(ref mut f, _) => return { // We seek to the beginning of the file since we expect each // access to the file to be in a different context try!(f.seek(SeekFrom::Start(0)) .map_err_into(SEK::FileNotSeeked)); Ok(f) }, - LazyFile::Absent(ref p) => try!(open_file(p).map_err_into(SEK::FileNotFound)), + FileAbstraction::Absent(ref p) => (try!(open_file(p).map_err_into(SEK::FileNotFound)), + p.clone()), }; - *self = LazyFile::File(file); - if let LazyFile::File(ref mut f) = *self { + *self = FileAbstraction::File(file, path); + if let FileAbstraction::File(ref mut f, _) = *self { return Ok(f); } unreachable!() @@ -116,28 +143,45 @@ mod fs { */ pub fn write_file_content(&mut self, buf: &[u8]) -> Result<(), SE> { use std::io::Write; - let file = match *self { - LazyFile::File(ref mut f) => return { + let (file, path) = match *self { + FileAbstraction::File(ref mut f, _) => return { // We seek to the beginning of the file since we expect each // access to the file to be in a different context try!(f.seek(SeekFrom::Start(0)) .map_err_into(SEK::FileNotCreated)); f.write_all(buf).map_err_into(SEK::FileNotWritten) }, - LazyFile::Absent(ref p) => try!(create_file(p).map_err_into(SEK::FileNotCreated)), + FileAbstraction::Absent(ref p) => (try!(create_file(p).map_err_into(SEK::FileNotCreated)), + p.clone()), }; - *self = LazyFile::File(file); - if let LazyFile::File(ref mut f) = *self { + *self = FileAbstraction::File(file, path); + if let FileAbstraction::File(ref mut f, _) = *self { return f.write_all(buf).map_err_into(SEK::FileNotWritten); } unreachable!(); } + + pub fn remove_file(path: &PathBuf) -> Result<(), SE> { + remove_file(path).map_err_into(SEK::FileNotRemoved) + } + + pub fn copy(from: &PathBuf, to: &PathBuf) -> Result<(), SE> { + copy(from, to).map_err_into(SEK::FileNotCopied).map(|_| ()) + } + + pub fn rename(from: &PathBuf, to: &PathBuf) -> Result<(), SE> { + rename(from, to).map_err_into(SEK::FileNotRenamed) + } + + pub fn create_dir_all(path: &PathBuf) -> Result<(), SE> { + create_dir_all(path).map_err_into(SEK::DirNotCreated) + } } } #[cfg(test)] mod test { - use super::LazyFile; + use super::FileAbstraction; use std::io::Read; use std::path::PathBuf; @@ -145,7 +189,7 @@ mod test { fn lazy_file() { let mut path = PathBuf::from("/tests"); path.set_file_name("test1"); - let mut lf = LazyFile::Absent(path); + let mut lf = FileAbstraction::Absent(path); lf.write_file_content(b"Hello World").unwrap(); let mut bah = Vec::new(); lf.get_file_content().unwrap().read_to_end(&mut bah).unwrap(); diff --git a/libimagstore/src/store.rs b/libimagstore/src/store.rs index 4fd24c4f..229a6913 100644 --- a/libimagstore/src/store.rs +++ b/libimagstore/src/store.rs @@ -1,5 +1,4 @@ use std::collections::HashMap; -use std::fs::remove_file; use std::ops::Drop; use std::path::PathBuf; use std::result::Result as RResult; @@ -26,7 +25,7 @@ use error::{ParserErrorKind, ParserError}; use error::{StoreError as SE, StoreErrorKind as SEK}; use error::MapErrInto; use storeid::{IntoStoreId, StoreId, StoreIdIterator}; -use lazyfile::LazyFile; +use lazyfile::FileAbstraction; use hook::aspect::Aspect; use hook::error::HookErrorKind; @@ -56,7 +55,7 @@ enum StoreEntryStatus { #[derive(Debug)] struct StoreEntry { id: StoreId, - file: LazyFile, + file: FileAbstraction, status: StoreEntryStatus, } @@ -116,7 +115,7 @@ impl StoreEntry { fn new(id: StoreId) -> StoreEntry { StoreEntry { id: id.clone(), - file: LazyFile::Absent(id.into()), + file: FileAbstraction::Absent(id.into()), status: StoreEntryStatus::Present, } } @@ -198,7 +197,6 @@ impl Store { /// Create a new Store object pub fn new(location: PathBuf, store_config: Option) -> Result { - use std::fs::create_dir_all; use configuration::*; debug!("Validating Store configuration"); @@ -218,7 +216,7 @@ impl Store { } debug!("Creating store path"); - let c = create_dir_all(location.clone()); + let c = FileAbstraction::create_dir_all(&location); if c.is_err() { debug!("Failed"); return Err(SEK::StorePathCreate.into_error_with_cause(Box::new(c.unwrap_err()))); @@ -639,9 +637,6 @@ impl Store { fn save_to_other_location(&self, entry: &FileLockEntry, new_id: StoreId, remove_old: bool) -> Result<()> { - use std::fs::copy; - use std::fs::remove_file; - let new_id = new_id.storified(self); let hsmap = self.entries.write(); if hsmap.is_err() { @@ -653,10 +648,10 @@ impl Store { let old_id = entry.get_location().clone(); - copy(old_id.clone(), new_id.clone()) + FileAbstraction::copy(&old_id.clone().into(), &new_id.clone().into()) .and_then(|_| { if remove_old { - remove_file(old_id) + FileAbstraction::remove_file(&old_id.clone().into()) } else { Ok(()) } @@ -670,7 +665,6 @@ impl Store { /// Move an entry without loading pub fn move_by_id(&self, old_id: StoreId, new_id: StoreId) -> Result<()> { - use std::fs::rename; let new_id = new_id.storified(self); let old_id = old_id.storified(self); @@ -690,13 +684,23 @@ impl Store { if hsmap.unwrap().contains_key(&old_id) { return Err(SE::new(SEK::EntryAlreadyBorrowed, None)); } else { - match rename(old_id, new_id.clone()) { + match FileAbstraction::rename(&old_id.clone(), &new_id) { Err(e) => return Err(SEK::EntryRenameError.into_error_with_cause(Box::new(e))), _ => { debug!("Rename worked"); }, } - } + if hsmap.unwrap().contains_key(&old_id) { + return Err(SE::new(SEK::EntryAlreadyBorrowed, None)); + } else { + match rename(old_id, new_id.clone()) { + Err(e) => return Err(SEK::EntryRenameError.into_error_with_cause(Box::new(e))), + _ => { + debug!("Rename worked"); + }, + } + } + } }