From ac041950078310e325e5a22e50a73f647b84c972 Mon Sep 17 00:00:00 2001 From: Manos Pitsidianakis Date: Thu, 1 Aug 2019 12:04:38 +0300 Subject: [PATCH] maildir: mark removed paths Remove events almost always come immediately before Rename events, showing that the previous name of a file is removed and then renamed. Keep proper tabs by marking removed paths instead of actually removing them. --- melib/src/backends/maildir.rs | 11 ++++--- melib/src/backends/maildir/backend.rs | 41 +++++++++++++++++++++------ 2 files changed, 39 insertions(+), 13 deletions(-) diff --git a/melib/src/backends/maildir.rs b/melib/src/backends/maildir.rs index 9dd3c8ccf..be6de086a 100644 --- a/melib/src/backends/maildir.rs +++ b/melib/src/backends/maildir.rs @@ -73,10 +73,13 @@ impl MaildirOp { debug!("{:#?}", e); } } - if let Some(path) = &map[&self.hash].modified { - path.clone() + if let Some(modif) = &map[&self.hash].modified { + match modif { + PathMod::Path(ref path) => path.clone(), + PathMod::Hash(hash) => map[&hash].to_path_buf(), + } } else { - map.get(&self.hash).unwrap().buf.to_path_buf() + map.get(&self.hash).unwrap().to_path_buf() } } } @@ -161,7 +164,7 @@ impl<'a> BackendOp for MaildirOp { let hash_index = self.hash_index.clone(); let mut map = hash_index.lock().unwrap(); let map = map.entry(self.folder_hash).or_default(); - map.entry(old_hash).or_default().modified = Some(new_name.clone()); + map.entry(old_hash).or_default().modified = Some(PathMod::Path(new_name.clone())); debug!("renaming {:?} to {:?}", path, new_name); fs::rename(&path, &new_name)?; diff --git a/melib/src/backends/maildir/backend.rs b/melib/src/backends/maildir/backend.rs index 41d818744..2c5c053c4 100644 --- a/melib/src/backends/maildir/backend.rs +++ b/melib/src/backends/maildir/backend.rs @@ -49,21 +49,30 @@ use std::result; use std::sync::{Arc, Mutex}; use std::thread; +#[derive(Clone, Debug, PartialEq)] +pub(super) enum PathMod { + Path(PathBuf), + Hash(EnvelopeHash), +} + #[derive(Debug, Default)] pub struct MaildirPath { pub(super) buf: PathBuf, - pub(super) modified: Option, + pub(super) modified: Option, + pub(super) removed: bool, } impl Deref for MaildirPath { type Target = PathBuf; fn deref(&self) -> &PathBuf { + assert!(!(self.removed && self.modified.is_none())); &self.buf } } impl DerefMut for MaildirPath { fn deref_mut(&mut self) -> &mut PathBuf { + assert!(!(self.removed && self.modified.is_none())); &mut self.buf } } @@ -73,6 +82,7 @@ impl From for MaildirPath { MaildirPath { buf: val, modified: None, + removed: false, } } } @@ -321,16 +331,25 @@ impl MailBackend for MaildirType { debug!("removed but not contained in index"); continue; }; - if let Some(path) = &index_lock[&hash].modified { - debug!( - "envelope {} has modified path set {}", - hash, - path.display() - ); + if let Some(ref modif) = &index_lock[&hash].modified { + match modif { + PathMod::Path(path) => debug!( + "envelope {} has modified path set {}", + hash, + path.display() + ), + PathMod::Hash(hash) => debug!( + "envelope {} has modified path set {}", + hash, + &index_lock[&hash].buf.display() + ), + } continue; } - index_lock.remove(&hash); + index_lock.entry(hash).and_modify(|e| { + e.removed = true; + }); sender.send(RefreshEvent { hash: folder_hash, @@ -356,7 +375,11 @@ impl MailBackend for MaildirType { hash: get_path_hash!(dest), kind: Rename(old_hash, new_hash), }); - index_lock.remove(&old_hash); + index_lock.entry(old_hash).and_modify(|e| { + debug!(&e.modified); + e.modified = Some(PathMod::Hash(new_hash)); + e.removed = false; + }); index_lock.insert(new_hash, dest.into()); continue; } else if !index_lock.contains_key(&new_hash) {