diff --git a/TODO.md b/TODO.md index cb92805..d67394e 100644 --- a/TODO.md +++ b/TODO.md @@ -4,11 +4,11 @@ * Detach bundle upload * XAttrs in fuse * XAttrs in tar +* `check --repair` ## Stability / Reliability * Lock the local repository to avoid index corruption * Recover from missing index, bundle cache and bundle map by rebuilding those -* Relative path in bundle cache ## Usability * Verbosity control @@ -23,6 +23,7 @@ * Benchmarks * Full fuse method coverage * Clippy +* Do not estimate meta size ## Other * Homepage diff --git a/src/bundledb/cache.rs b/src/bundledb/cache.rs index 52c27bc..47c8951 100644 --- a/src/bundledb/cache.rs +++ b/src/bundledb/cache.rs @@ -62,21 +62,23 @@ impl StoredBundle { self.info.id.clone() } - pub fn move_to>(mut self, path: P) -> Result { - let path = path.as_ref(); - if fs::rename(&self.path, path).is_err() { - try!(fs::copy(&self.path, path).context(path)); - try!(fs::remove_file(&self.path).context(&self.path as &Path)); + pub fn move_to>(mut self, base_path: &Path, path: P) -> Result { + let src_path = base_path.join(&self.path); + let dst_path = path.as_ref(); + if fs::rename(&src_path, dst_path).is_err() { + try!(fs::copy(&src_path, dst_path).context(dst_path)); + try!(fs::remove_file(&src_path).context(&src_path as &Path)); } - self.path = path.to_path_buf(); + self.path = dst_path.strip_prefix(base_path).unwrap().to_path_buf(); Ok(self) } - pub fn copy_to>(&self, path: P) -> Result { - let path = path.as_ref(); - try!(fs::copy(&self.path, path).context(path)); + pub fn copy_to>(&self, base_path: &Path, path: P) -> Result { + let src_path = base_path.join(&self.path); + let dst_path = path.as_ref(); + try!(fs::copy(&src_path, dst_path).context(dst_path)); let mut bundle = self.clone(); - bundle.path = path.to_path_buf(); + bundle.path = dst_path.strip_prefix(base_path).unwrap().to_path_buf(); Ok(bundle) } diff --git a/src/bundledb/db.rs b/src/bundledb/db.rs index 39636a3..a275c85 100644 --- a/src/bundledb/db.rs +++ b/src/bundledb/db.rs @@ -66,7 +66,8 @@ pub fn bundle_path(bundle: &BundleId, mut folder: PathBuf, mut count: usize) -> (folder, file.into()) } -pub fn load_bundles>(path: P, bundles: &mut HashMap, crypto: Arc>) -> Result<(Vec, Vec), BundleDbError> { +pub fn load_bundles>(path: P, base: P, bundles: &mut HashMap, crypto: Arc>) -> Result<(Vec, Vec), BundleDbError> { + let base = base.as_ref(); let mut paths = vec![path.as_ref().to_path_buf()]; let mut bundle_paths = HashSet::new(); while let Some(path) = paths.pop() { @@ -76,7 +77,7 @@ pub fn load_bundles>(path: P, bundles: &mut HashMap>(path: P, bundles: &mut HashMap>(path: P, bundles: &mut HashMap>) -> Self { + fn new(repo_path: PathBuf, remote_path: PathBuf, local_path: PathBuf, crypto: Arc>) -> Self { BundleDb { + repo_path: repo_path, remote_cache_path: local_path.join("remote.cache"), local_cache_path: local_path.join("local.cache"), local_bundles_path: local_path.join("cached"), @@ -149,12 +152,12 @@ impl BundleDb { self.remote_bundles.insert(bundle.id(), bundle); } } - let (new, gone) = try!(load_bundles(&self.local_bundles_path, &mut self.local_bundles, self.crypto.clone())); + let (new, gone) = try!(load_bundles(&self.local_bundles_path, &self.repo_path, &mut self.local_bundles, self.crypto.clone())); if !new.is_empty() || !gone.is_empty() { let bundles: Vec<_> = self.local_bundles.values().cloned().collect(); try!(StoredBundle::save_list_to(&bundles, &local_cache_path)); } - let (new, gone) = try!(load_bundles(&self.remote_path, &mut self.remote_bundles, self.crypto.clone())); + let (new, gone) = try!(load_bundles(&self.remote_path, &self.repo_path, &mut self.remote_bundles, self.crypto.clone())); if !new.is_empty() || !gone.is_empty() { let bundles: Vec<_> = self.remote_bundles.values().cloned().collect(); try!(StoredBundle::save_list_to(&bundles, &remote_cache_path)); @@ -178,7 +181,7 @@ impl BundleDb { } for bundle in gone { if let Some(bundle) = self.local_bundles.remove(&bundle.id()) { - try!(fs::remove_file(&bundle.path).map_err(|e| BundleDbError::Remove(e, bundle.id()))) + try!(fs::remove_file(self.repo_path.join(&bundle.path)).map_err(|e| BundleDbError::Remove(e, bundle.id()))) } } Ok(()) @@ -189,10 +192,10 @@ impl BundleDb { } #[inline] - pub fn open, L: AsRef>(remote_path: R, local_path: L, crypto: Arc>) -> Result<(Self, Vec, Vec), BundleDbError> { + pub fn open, L: AsRef>(repo_path: PathBuf, remote_path: R, local_path: L, crypto: Arc>) -> Result<(Self, Vec, Vec), BundleDbError> { let remote_path = remote_path.as_ref().to_owned(); let local_path = local_path.as_ref().to_owned(); - let mut self_ = Self::new(remote_path, local_path, crypto); + let mut self_ = Self::new(repo_path, remote_path, local_path, crypto); let (new, gone) = try!(self_.load_bundle_list()); try!(self_.update_cache(&new, &gone)); let new = new.into_iter().map(|s| s.info).collect(); @@ -201,10 +204,10 @@ impl BundleDb { } #[inline] - pub fn create, L: AsRef>(remote_path: R, local_path: L, crypto: Arc>) -> Result { + pub fn create, L: AsRef>(repo_path: PathBuf, remote_path: R, local_path: L, crypto: Arc>) -> Result { let remote_path = remote_path.as_ref().to_owned(); let local_path = local_path.as_ref().to_owned(); - let self_ = Self::new(remote_path, local_path, crypto); + let self_ = Self::new(repo_path, remote_path, local_path, crypto); try!(fs::create_dir_all(&self_.remote_path).context(&self_.remote_path as &Path)); try!(fs::create_dir_all(&self_.local_bundles_path).context(&self_.local_bundles_path as &Path)); try!(fs::create_dir_all(&self_.temp_path).context(&self_.temp_path as &Path)); @@ -225,7 +228,7 @@ impl BundleDb { } fn get_bundle(&self, stored: &StoredBundle) -> Result { - Ok(try!(BundleReader::load(stored.path.clone(), self.crypto.clone()))) + Ok(try!(BundleReader::load(self.repo_path.join(&stored.path), self.crypto.clone()))) } pub fn get_chunk(&mut self, bundle_id: &BundleId, id: usize) -> Result, BundleDbError> { @@ -248,7 +251,7 @@ impl BundleDb { let id = bundle.id(); let (folder, filename) = bundle_path(&id, self.local_bundles_path.clone(), self.local_bundles.len()); try!(fs::create_dir_all(&folder).context(&folder as &Path)); - let bundle = try!(bundle.copy_to(folder.join(filename))); + let bundle = try!(bundle.copy_to(&self.repo_path, folder.join(filename))); self.local_bundles.insert(id, bundle); Ok(()) } @@ -262,7 +265,7 @@ impl BundleDb { } let (folder, filename) = bundle_path(&random_id, self.remote_path.clone(), self.remote_bundles.len()); try!(fs::create_dir_all(&folder).context(&folder as &Path)); - let bundle = try!(bundle.move_to(folder.join(filename))); + let bundle = try!(bundle.move_to(&self.repo_path, folder.join(filename))); self.remote_bundles.insert(bundle.id(), bundle.clone()); Ok(bundle.info) } @@ -286,7 +289,7 @@ impl BundleDb { #[inline] pub fn delete_local_bundle(&mut self, bundle: &BundleId) -> Result<(), BundleDbError> { if let Some(bundle) = self.local_bundles.remove(bundle) { - try!(fs::remove_file(&bundle.path).map_err(|e| BundleDbError::Remove(e, bundle.id()))) + try!(fs::remove_file(self.repo_path.join(&bundle.path)).map_err(|e| BundleDbError::Remove(e, bundle.id()))) } Ok(()) } @@ -295,7 +298,7 @@ impl BundleDb { pub fn delete_bundle(&mut self, bundle: &BundleId) -> Result<(), BundleDbError> { try!(self.delete_local_bundle(bundle)); if let Some(bundle) = self.remote_bundles.remove(bundle) { - fs::remove_file(&bundle.path).map_err(|e| BundleDbError::Remove(e, bundle.id())) + fs::remove_file(self.repo_path.join(&bundle.path)).map_err(|e| BundleDbError::Remove(e, bundle.id())) } else { Err(BundleDbError::NoSuchBundle(bundle.clone())) } diff --git a/src/repository/mod.rs b/src/repository/mod.rs index 267d8a6..0ebe1d8 100644 --- a/src/repository/mod.rs +++ b/src/repository/mod.rs @@ -66,6 +66,7 @@ impl Repository { try!(fs::create_dir_all(path.join("remote/locks"))); let locks = LockFolder::new(path.join("remote/locks")); let bundles = try!(BundleDb::create( + path.to_path_buf(), path.join("remote/bundles"), path.join("bundles"), crypto.clone() @@ -99,6 +100,7 @@ impl Repository { let locks = LockFolder::new(path.join("remote/locks")); let crypto = Arc::new(Mutex::new(try!(Crypto::open(path.join("keys"))))); let (bundles, new, gone) = try!(BundleDb::open( + path.to_path_buf(), path.join("remote/bundles"), path.join("bundles"), crypto.clone()