changeset 47129: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 04bcba539c96
files rust/hg-core/src/dirstate_tree/status.rs
diffstat 1 files changed, 38 insertions(+), 15 deletions(-) [+]
line wrap: on
line diff
--- 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<Vec<DirEntry>, ()> {
+        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 {