# HG changeset patch # User Simon Sapin # Date 1619458136 -7200 # Node ID 1b4f0f819f925088312c8a60bd2c9cc785ffdc5a # Parent aeb03758f37aa460fd238492925a29add5ef8313 dirstate-tree: Handle I/O errors in status Errors such as insufficient permissions when listing a directory are logged, and the algorithm continues without considering that directory. Differential Revision: https://phab.mercurial-scm.org/D10549 diff -r aeb03758f37a -r 1b4f0f819f92 rust/hg-core/src/dirstate_tree/status.rs --- a/rust/hg-core/src/dirstate_tree/status.rs Mon Apr 26 19:16:23 2021 +0200 +++ b/rust/hg-core/src/dirstate_tree/status.rs Mon Apr 26 19:28:56 2021 +0200 @@ -6,6 +6,7 @@ use crate::matchers::Matcher; use crate::utils::files::get_bytes_from_os_string; use crate::utils::hg_path::HgPath; +use crate::BadMatch; use crate::DirstateStatus; use crate::EntryState; use crate::HgPathBuf; @@ -69,17 +70,37 @@ } impl<'tree, 'a> StatusCommon<'tree, 'a> { + fn read_dir( + &mut self, + hg_path: &HgPath, + fs_path: &Path, + is_at_repo_root: bool, + ) -> Result, ()> { + DirEntry::read_dir(fs_path, is_at_repo_root).map_err(|error| { + let errno = error.raw_os_error().expect("expected real OS error"); + self.outcome + .bad + .push((hg_path.to_owned().into(), BadMatch::OsError(errno))) + }) + } + fn traverse_fs_directory_and_dirstate( &mut self, has_ignored_ancestor: bool, dirstate_nodes: &'tree mut ChildNodes, - directory_hg_path: &HgPath, - fs_path: &Path, + directory_hg_path: &'tree HgPath, + directory_fs_path: &Path, is_at_repo_root: bool, ) { - // TODO: handle I/O errors - let mut fs_entries = - DirEntry::read_dir(fs_path, is_at_repo_root).unwrap(); + let mut fs_entries = if let Ok(entries) = self.read_dir( + directory_hg_path, + directory_fs_path, + is_at_repo_root, + ) { + entries + } else { + return; + }; // `merge_join_by` requires both its input iterators to be sorted: @@ -295,16 +316,18 @@ }; if traverse_children { let is_at_repo_root = false; - // TODO: handle I/O errors - let children_fs_entries = - DirEntry::read_dir(&fs_entry.full_path, is_at_repo_root) - .unwrap(); - for child_fs_entry in children_fs_entries { - self.traverse_fs_only( - is_ignored, - &hg_path, - &child_fs_entry, - ) + if let Ok(children_fs_entries) = self.read_dir( + &hg_path, + &fs_entry.full_path, + is_at_repo_root, + ) { + for child_fs_entry in children_fs_entries { + self.traverse_fs_only( + is_ignored, + &hg_path, + &child_fs_entry, + ) + } } } if self.options.collect_traversed_dirs {