From 221a2c8f6d33451b093b1346cf85b1a12688c512 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20M=C3=BCller?= Date: Sun, 17 Jan 2016 18:27:19 +0100 Subject: [PATCH 1/5] Add file creation --- libimagstore/src/error.rs | 4 ++ libimagstore/src/lazyfile.rs | 107 +++++++++++++++++++++++++++++++++++ libimagstore/src/lib.rs | 1 + 3 files changed, 112 insertions(+) create mode 100644 libimagstore/src/lazyfile.rs diff --git a/libimagstore/src/error.rs b/libimagstore/src/error.rs index e4c86619..83cb825e 100644 --- a/libimagstore/src/error.rs +++ b/libimagstore/src/error.rs @@ -10,6 +10,8 @@ pub enum StoreErrorKind { IdLocked, IdNotFound, OutOfMemory, + FileNotFound, + FileNotCreated, // maybe more } @@ -19,6 +21,8 @@ fn store_error_type_as_str(e: &StoreErrorKind) -> &'static str { &StoreErrorKind::IdLocked => "ID locked", &StoreErrorKind::IdNotFound => "ID not found", &StoreErrorKind::OutOfMemory => "Out of Memory", + &StoreErrorKind::FileNotFound => "File corresponding to ID not found", + &StoreErrorKind::FileNotCreated => "File corresponding to ID could not be created", } } diff --git a/libimagstore/src/lazyfile.rs b/libimagstore/src/lazyfile.rs new file mode 100644 index 00000000..29a598b6 --- /dev/null +++ b/libimagstore/src/lazyfile.rs @@ -0,0 +1,107 @@ + +use error::{StoreError, StoreErrorKind}; +use std::path::{Path, PathBuf}; +use std::fs::{File, OpenOptions}; + +pub enum LazyFile { + Absent(PathBuf), + File(File) +} + +fn open_file>(p: A) -> ::std::io::Result { + OpenOptions::new().write(true).read(true).open(p) +} + +fn create_file>(p: A) -> ::std::io::Result { + OpenOptions::new().write(true).read(true).create(true).open(p) +} + +impl LazyFile { + pub fn new(p: PathBuf) -> LazyFile { + LazyFile::Absent(p) + } + pub fn new_with_file(f: File) -> LazyFile { + LazyFile::File(f) + } + + pub fn get_file(&mut self) -> Result<&File, StoreError> { + let file = match *self { + LazyFile::File(ref f) => return Ok(f), + LazyFile::Absent(ref p) => { + try!(open_file(p).map_err(|e| { + StoreError::new(StoreErrorKind::FileNotFound, + Some(Box::new(e))) + })) + + } + }; + *self = LazyFile::File(file); + if let LazyFile::File(ref f) = *self { + return Ok(f); + } + unreachable!() + } + + pub fn get_file_mut(&mut self) -> Result<&mut File, StoreError> { + let file = match *self { + LazyFile::File(ref mut f) => return Ok(f), + LazyFile::Absent(ref p) => { + try!(open_file(p).map_err(|e| { + StoreError::new(StoreErrorKind::FileNotFound, + Some(Box::new(e))) + })) + } + }; + *self = LazyFile::File(file); + if let LazyFile::File(ref mut f) = *self { + return Ok(f); + } + unreachable!() + } + + pub fn create_file(&mut self) -> Result<&mut File, StoreError> { + let file = match *self { + LazyFile::File(ref mut f) => return Ok(f), + LazyFile::Absent(ref p) => { + try!(create_file(p).map_err(|e| { + StoreError::new(StoreErrorKind::FileNotFound, + Some(Box::new(e))) + })) + } + }; + *self = LazyFile::File(file); + if let LazyFile::File(ref mut f) = *self { + return Ok(f); + } + unreachable!() + } +} + +#[cfg(test)] +mod test { + use super::LazyFile; + use std::io::{Read, Write}; + use std::path::PathBuf; + use std::fs::File; + + #[test] + fn lazy_file() { + let path = PathBuf::from("/tmp/test"); + let mut lf = LazyFile::new(path); + + write!(lf.create_file().unwrap(), "Hello World").unwrap(); + } + + #[test] + fn lazy_file_with_file() { + let path = PathBuf::from("/tmp/test2"); + let mut lf = LazyFile::new_with_file(File::create(path).unwrap()); + let mut file = lf.get_file_mut().unwrap(); + + write!(file, "Hello World").unwrap(); + file.sync_all().unwrap(); + let mut s = String::new(); + file.read_to_string(&mut s).unwrap(); + assert_eq!(s, "Hello World"); + } +} diff --git a/libimagstore/src/lib.rs b/libimagstore/src/lib.rs index 12c0e09d..1296d6dd 100644 --- a/libimagstore/src/lib.rs +++ b/libimagstore/src/lib.rs @@ -6,4 +6,5 @@ pub mod entry; pub mod error; pub mod header; pub mod store; +mod lazyfile; From be0bb6d0adeb3dfea0a154c5dee1f8e7f186806f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20M=C3=BCller?= Date: Mon, 18 Jan 2016 17:59:57 +0100 Subject: [PATCH 2/5] Add tempdir to Cargo.toml --- libimagstore/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libimagstore/Cargo.toml b/libimagstore/Cargo.toml index d8582775..6285e2d9 100644 --- a/libimagstore/Cargo.toml +++ b/libimagstore/Cargo.toml @@ -7,4 +7,4 @@ authors = ["Matthias Beyer "] fs2 = "0.2.2" toml = "0.1.25" - +tempdir = "0.3.4" From c122c3cf370e2d07874e1393d852e79bfbd00043 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20M=C3=BCller?= Date: Mon, 18 Jan 2016 18:20:50 +0100 Subject: [PATCH 3/5] Use tempdir in tests --- libimagstore/Cargo.lock | 28 ++++++++++++++++++++++++++++ libimagstore/src/lazyfile.rs | 28 ++++++++++++++++++++-------- libimagstore/src/lib.rs | 1 + 3 files changed, 49 insertions(+), 8 deletions(-) diff --git a/libimagstore/Cargo.lock b/libimagstore/Cargo.lock index 1d5c3264..6eb4a715 100644 --- a/libimagstore/Cargo.lock +++ b/libimagstore/Cargo.lock @@ -3,9 +3,19 @@ name = "libimagstore" version = "0.1.0" dependencies = [ "fs2 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "tempdir 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "advapi32-sys" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "fs2" version = "0.2.2" @@ -30,11 +40,29 @@ name = "libc" version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "rand" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "advapi32-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rustc-serialize" version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "tempdir" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "toml" version = "0.1.25" diff --git a/libimagstore/src/lazyfile.rs b/libimagstore/src/lazyfile.rs index 29a598b6..777b7aff 100644 --- a/libimagstore/src/lazyfile.rs +++ b/libimagstore/src/lazyfile.rs @@ -83,25 +83,37 @@ mod test { use std::io::{Read, Write}; use std::path::PathBuf; use std::fs::File; + use tempdir::TempDir; + + fn get_dir() -> TempDir { + TempDir::new("test-image").unwrap() + } #[test] fn lazy_file() { - let path = PathBuf::from("/tmp/test"); + let dir = get_dir(); + let mut path = PathBuf::from(dir.path()); + path.set_file_name("test1"); let mut lf = LazyFile::new(path); write!(lf.create_file().unwrap(), "Hello World").unwrap(); + dir.close().unwrap(); } #[test] fn lazy_file_with_file() { - let path = PathBuf::from("/tmp/test2"); - let mut lf = LazyFile::new_with_file(File::create(path).unwrap()); - let mut file = lf.get_file_mut().unwrap(); + let dir = get_dir(); + let mut path = PathBuf::from(dir.path()); + path.set_file_name("test2"); + let mut lf = LazyFile::new(path); + let mut file = lf.create_file().unwrap(); - write!(file, "Hello World").unwrap(); + file.write(b"Hello World").unwrap(); file.sync_all().unwrap(); - let mut s = String::new(); - file.read_to_string(&mut s).unwrap(); - assert_eq!(s, "Hello World"); + let mut s = Vec::new(); + file.read_to_end(&mut s).unwrap(); + assert_eq!(s, "Hello World".to_string().into_bytes()); + + dir.close().unwrap(); } } diff --git a/libimagstore/src/lib.rs b/libimagstore/src/lib.rs index 1296d6dd..30a7f999 100644 --- a/libimagstore/src/lib.rs +++ b/libimagstore/src/lib.rs @@ -1,5 +1,6 @@ extern crate fs2; extern crate toml; +extern crate tempdir; pub mod content; pub mod entry; From 4e0e80c0b83ea385f71e3da49a9f8cbb3077c6c6 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Mon, 18 Jan 2016 18:30:55 +0100 Subject: [PATCH 4/5] Fix test: lazy_file_with_file --- libimagstore/src/lazyfile.rs | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/libimagstore/src/lazyfile.rs b/libimagstore/src/lazyfile.rs index 777b7aff..48971371 100644 --- a/libimagstore/src/lazyfile.rs +++ b/libimagstore/src/lazyfile.rs @@ -105,14 +105,23 @@ mod test { let dir = get_dir(); let mut path = PathBuf::from(dir.path()); path.set_file_name("test2"); - let mut lf = LazyFile::new(path); - let mut file = lf.create_file().unwrap(); - file.write(b"Hello World").unwrap(); - file.sync_all().unwrap(); - let mut s = Vec::new(); - file.read_to_end(&mut s).unwrap(); - assert_eq!(s, "Hello World".to_string().into_bytes()); + { + let mut lf = LazyFile::new(path.clone()); + let mut file = lf.create_file().unwrap(); + + file.write(b"Hello World").unwrap(); + file.sync_all().unwrap(); + } + + { + let mut lf = LazyFile::new(path); + let mut file = lf.create_file().unwrap(); + + let mut s = Vec::new(); + file.read_to_end(&mut s).unwrap(); + assert_eq!(s, "Hello World".to_string().into_bytes()); + } dir.close().unwrap(); } From 1c73fcfae1f763b8260f065e32f9c6d3037ba206 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20M=C3=BCller?= Date: Mon, 18 Jan 2016 18:43:36 +0100 Subject: [PATCH 5/5] Seek to beginning of file before reading --- libimagstore/src/lazyfile.rs | 35 +++++++++++++++-------------------- 1 file changed, 15 insertions(+), 20 deletions(-) diff --git a/libimagstore/src/lazyfile.rs b/libimagstore/src/lazyfile.rs index 48971371..2d4f3cf4 100644 --- a/libimagstore/src/lazyfile.rs +++ b/libimagstore/src/lazyfile.rs @@ -1,5 +1,6 @@ use error::{StoreError, StoreErrorKind}; +use std::io::{Seek, SeekFrom}; use std::path::{Path, PathBuf}; use std::fs::{File, OpenOptions}; @@ -25,26 +26,22 @@ impl LazyFile { } pub fn get_file(&mut self) -> Result<&File, StoreError> { - let file = match *self { - LazyFile::File(ref f) => return Ok(f), - LazyFile::Absent(ref p) => { - try!(open_file(p).map_err(|e| { - StoreError::new(StoreErrorKind::FileNotFound, - Some(Box::new(e))) - })) - - } - }; - *self = LazyFile::File(file); - if let LazyFile::File(ref f) = *self { - return Ok(f); + match self.get_file_mut() { + Ok(file) => Ok(&*file), + Err(e) => Err(e) } - unreachable!() } pub fn get_file_mut(&mut self) -> Result<&mut File, StoreError> { let file = match *self { - LazyFile::File(ref mut f) => return Ok(f), + LazyFile::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 + f.seek(SeekFrom::Start(0)).map_err(|e| + StoreError::new( + StoreErrorKind::FileNotCreated, Some(Box::new(e)))); + Ok(f) + }, LazyFile::Absent(ref p) => { try!(open_file(p).map_err(|e| { StoreError::new(StoreErrorKind::FileNotFound, @@ -80,7 +77,7 @@ impl LazyFile { #[cfg(test)] mod test { use super::LazyFile; - use std::io::{Read, Write}; + use std::io::{Read, Write, Seek, SeekFrom}; use std::path::PathBuf; use std::fs::File; use tempdir::TempDir; @@ -105,9 +102,9 @@ mod test { let dir = get_dir(); let mut path = PathBuf::from(dir.path()); path.set_file_name("test2"); + let mut lf = LazyFile::new(path.clone()); { - let mut lf = LazyFile::new(path.clone()); let mut file = lf.create_file().unwrap(); file.write(b"Hello World").unwrap(); @@ -115,9 +112,7 @@ mod test { } { - let mut lf = LazyFile::new(path); - let mut file = lf.create_file().unwrap(); - + let mut file = lf.get_file().unwrap(); let mut s = Vec::new(); file.read_to_end(&mut s).unwrap(); assert_eq!(s, "Hello World".to_string().into_bytes());