comparison rust/hg-core/src/dirstate_tree/status.rs @ 47115:1b4f0f819f92

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
author Simon Sapin <simon.sapin@octobus.net>
date Mon, 26 Apr 2021 19:28:56 +0200
parents aeb03758f37a
children 60d852ae7e7b
comparison
equal deleted inserted replaced
47114:aeb03758f37a 47115:1b4f0f819f92
4 use crate::dirstate_tree::dirstate_map::Node; 4 use crate::dirstate_tree::dirstate_map::Node;
5 use crate::matchers::get_ignore_function; 5 use crate::matchers::get_ignore_function;
6 use crate::matchers::Matcher; 6 use crate::matchers::Matcher;
7 use crate::utils::files::get_bytes_from_os_string; 7 use crate::utils::files::get_bytes_from_os_string;
8 use crate::utils::hg_path::HgPath; 8 use crate::utils::hg_path::HgPath;
9 use crate::BadMatch;
9 use crate::DirstateStatus; 10 use crate::DirstateStatus;
10 use crate::EntryState; 11 use crate::EntryState;
11 use crate::HgPathBuf; 12 use crate::HgPathBuf;
12 use crate::PatternFileWarning; 13 use crate::PatternFileWarning;
13 use crate::StatusError; 14 use crate::StatusError;
67 ignore_fn: IgnoreFnType<'a>, 68 ignore_fn: IgnoreFnType<'a>,
68 outcome: DirstateStatus<'tree>, 69 outcome: DirstateStatus<'tree>,
69 } 70 }
70 71
71 impl<'tree, 'a> StatusCommon<'tree, 'a> { 72 impl<'tree, 'a> StatusCommon<'tree, 'a> {
73 fn read_dir(
74 &mut self,
75 hg_path: &HgPath,
76 fs_path: &Path,
77 is_at_repo_root: bool,
78 ) -> Result<Vec<DirEntry>, ()> {
79 DirEntry::read_dir(fs_path, is_at_repo_root).map_err(|error| {
80 let errno = error.raw_os_error().expect("expected real OS error");
81 self.outcome
82 .bad
83 .push((hg_path.to_owned().into(), BadMatch::OsError(errno)))
84 })
85 }
86
72 fn traverse_fs_directory_and_dirstate( 87 fn traverse_fs_directory_and_dirstate(
73 &mut self, 88 &mut self,
74 has_ignored_ancestor: bool, 89 has_ignored_ancestor: bool,
75 dirstate_nodes: &'tree mut ChildNodes, 90 dirstate_nodes: &'tree mut ChildNodes,
76 directory_hg_path: &HgPath, 91 directory_hg_path: &'tree HgPath,
77 fs_path: &Path, 92 directory_fs_path: &Path,
78 is_at_repo_root: bool, 93 is_at_repo_root: bool,
79 ) { 94 ) {
80 // TODO: handle I/O errors 95 let mut fs_entries = if let Ok(entries) = self.read_dir(
81 let mut fs_entries = 96 directory_hg_path,
82 DirEntry::read_dir(fs_path, is_at_repo_root).unwrap(); 97 directory_fs_path,
98 is_at_repo_root,
99 ) {
100 entries
101 } else {
102 return;
103 };
83 104
84 // `merge_join_by` requires both its input iterators to be sorted: 105 // `merge_join_by` requires both its input iterators to be sorted:
85 106
86 // * `BTreeMap` iterates according to keys’ ordering by definition 107 // * `BTreeMap` iterates according to keys’ ordering by definition
87 108
293 // ignored 314 // ignored
294 self.options.list_unknown || self.options.list_ignored 315 self.options.list_unknown || self.options.list_ignored
295 }; 316 };
296 if traverse_children { 317 if traverse_children {
297 let is_at_repo_root = false; 318 let is_at_repo_root = false;
298 // TODO: handle I/O errors 319 if let Ok(children_fs_entries) = self.read_dir(
299 let children_fs_entries = 320 &hg_path,
300 DirEntry::read_dir(&fs_entry.full_path, is_at_repo_root) 321 &fs_entry.full_path,
301 .unwrap(); 322 is_at_repo_root,
302 for child_fs_entry in children_fs_entries { 323 ) {
303 self.traverse_fs_only( 324 for child_fs_entry in children_fs_entries {
304 is_ignored, 325 self.traverse_fs_only(
305 &hg_path, 326 is_ignored,
306 &child_fs_entry, 327 &hg_path,
307 ) 328 &child_fs_entry,
329 )
330 }
308 } 331 }
309 } 332 }
310 if self.options.collect_traversed_dirs { 333 if self.options.collect_traversed_dirs {
311 self.outcome.traversed.push(hg_path.into()) 334 self.outcome.traversed.push(hg_path.into())
312 } 335 }