From 6b72672d29f0cde481fc1c582c41e0231725bd3b Mon Sep 17 00:00:00 2001 From: Olivier Date: Fri, 11 Aug 2023 20:24:59 +0100 Subject: [PATCH] Fix bug in path iteration leading to bug in gradual scans --- yama/src/scan.rs | 38 ++++++++++++++++++++------------------ yama_pile/src/tree.rs | 4 +++- 2 files changed, 23 insertions(+), 19 deletions(-) diff --git a/yama/src/scan.rs b/yama/src/scan.rs index eca4209..370bfbb 100644 --- a/yama/src/scan.rs +++ b/yama/src/scan.rs @@ -265,15 +265,7 @@ pub fn prepopulate_unmodified( ); // Pull out parent directories so our subset always contains the parents for their children. - let mut path_fragment = path.as_bytes(); - while let Some((index, _)) = path_fragment - .iter() - .enumerate() - .rev() - .find(|(_idx, char_byte)| **char_byte == b'/') - { - path_fragment = &path_fragment[0..index]; - + for path_fragment in iterate_dirs_upwards(path.as_bytes()) { if let Some(directory) = pruned_scan_entry_map.remove(path_fragment) { prepopulated_scan_entry_map.insert(path_fragment, directory); @@ -345,15 +337,7 @@ pub fn limit_scan_entry_map_to_size( accum_size += size_of_entry; // Pull out parent directories so our subset always contains the parents for their children. - let mut path_fragment = &path_bytes[..]; - while let Some((index, _)) = path_fragment - .iter() - .enumerate() - .rev() - .find(|(_idx, char_byte)| **char_byte == b'/') - { - path_fragment = &path_bytes[0..index]; - + for path_fragment in iterate_dirs_upwards(&path_bytes) { if let Some(directory) = unincluded_directories.remove(path_fragment) { result.insert(path_fragment, directory); accum_size += 4096; @@ -375,6 +359,24 @@ pub fn limit_scan_entry_map_to_size( result } +/// Returns a list of all the parent paths of the given path (in bytes), +/// including the root, in order from leaf to root. +pub fn iterate_dirs_upwards(path_bytes: &[u8]) -> Vec<&[u8]> { + let mut result = Vec::new(); + let mut path_fragment = &path_bytes[..]; + while let Some((index, _)) = path_fragment + .iter() + .enumerate() + .rev() + .find(|(_idx, char_byte)| **char_byte == b'/') + { + path_fragment = &path_bytes[0..index]; + result.push(path_fragment); + } + result.push(&path_bytes[0..0]); + result +} + #[cfg(test)] mod tests { use crate::scan::limit_scan_entry_map_to_size; diff --git a/yama_pile/src/tree.rs b/yama_pile/src/tree.rs index e908990..cda68ca 100644 --- a/yama_pile/src/tree.rs +++ b/yama_pile/src/tree.rs @@ -417,7 +417,9 @@ pub fn assemble_tree_from_scan_entries( // note: for the root, this inserts the root file entry as a child called "" within a fake root 'directory'. // That's fine. We'll patch this up later. dirs.get_mut(parent_dir_name) - .context("bad PMap: parent not seen first")? + .with_context(|| { + format!("bad PMap: parent {parent_dir_name} not seen first") + })? .insert( child_name.to_owned(), TreeNode::NormalFile {