Просмотр исходного кода

perf: reuse filetype from DirEntry

Terts Diepraam 2 лет назад
Родитель
Сommit
d1df86e969
7 измененных файлов с 149 добавлено и 126 удалено
  1. 21 23
      src/fs/dir.rs
  2. 98 67
      src/fs/file.rs
  3. 4 1
      src/fs/filter.rs
  4. 23 24
      src/main.rs
  5. 0 1
      src/output/color_scale.rs
  6. 2 9
      src/output/details.rs
  7. 1 1
      src/output/table.rs

+ 21 - 23
src/fs/dir.rs

@@ -7,6 +7,7 @@
 use crate::fs::feature::git::GitCache;
 use crate::fs::fields::GitStatus;
 use std::fs;
+use std::fs::DirEntry;
 use std::io;
 use std::path::{Path, PathBuf};
 use std::slice::Iter as SliceIter;
@@ -23,7 +24,7 @@ use crate::fs::File;
 /// accordingly. (See `File#get_source_files`)
 pub struct Dir {
     /// A vector of the files that have been read from this directory.
-    contents: Vec<PathBuf>,
+    contents: Vec<DirEntry>,
 
     /// The path that was read.
     pub path: PathBuf,
@@ -41,9 +42,7 @@ impl Dir {
     pub fn read_dir(path: PathBuf) -> io::Result<Self> {
         info!("Reading directory {:?}", &path);
 
-        let contents = fs::read_dir(&path)?
-            .map(|result| result.map(|entry| entry.path()))
-            .collect::<Result<_, _>>()?;
+        let contents = fs::read_dir(&path)?.collect::<Result<Vec<_>, _>>()?;
 
         info!("Read directory success {:?}", &path);
         Ok(Self { contents, path })
@@ -73,7 +72,7 @@ impl Dir {
 
     /// Whether this directory contains a file with the given path.
     pub fn contains(&self, path: &Path) -> bool {
-        self.contents.iter().any(|p| p.as_path() == path)
+        self.contents.iter().any(|p| p.path().as_path() == path)
     }
 
     /// Append a path onto the path specified by this directory.
@@ -86,7 +85,7 @@ impl Dir {
 #[allow(clippy::struct_excessive_bools)]
 pub struct Files<'dir, 'ig> {
     /// The internal iterator over the paths that have been read already.
-    inner: SliceIter<'dir, PathBuf>,
+    inner: SliceIter<'dir, DirEntry>,
 
     /// The directory that begat those paths.
     dir: &'dir Dir,
@@ -121,10 +120,11 @@ impl<'dir, 'ig> Files<'dir, 'ig> {
 
     /// Go through the directory until we encounter a file we can list (which
     /// varies depending on the dotfile visibility flag)
-    fn next_visible_file(&mut self) -> Option<Result<File<'dir>, (PathBuf, io::Error)>> {
+    fn next_visible_file(&mut self) -> Option<File<'dir>> {
         loop {
-            if let Some(path) = self.inner.next() {
-                let filename = File::filename(path);
+            if let Some(entry) = self.inner.next() {
+                let path = entry.path();
+                let filename = File::filename(&path);
                 if !self.dotfiles && filename.starts_with('.') {
                     continue;
                 }
@@ -137,25 +137,25 @@ impl<'dir, 'ig> Files<'dir, 'ig> {
                 }
 
                 if self.git_ignoring {
-                    let git_status = self.git.map(|g| g.get(path, false)).unwrap_or_default();
+                    let git_status = self.git.map(|g| g.get(&path, false)).unwrap_or_default();
                     if git_status.unstaged == GitStatus::Ignored {
                         continue;
                     }
                 }
 
                 let file = File::from_args(
-                    path.clone(),
+                    path,
                     self.dir,
                     filename,
                     self.deref_links,
                     self.total_size,
-                )
-                .map_err(|e| (path.clone(), e));
+                    entry.file_type().ok(),
+                );
 
                 // Windows has its own concept of hidden files, when dotfiles are
                 // hidden Windows hidden files should also be filtered out
                 #[cfg(windows)]
-                if !self.dotfiles && file.as_ref().is_ok_and(|f| f.attributes().hidden) {
+                if !self.dotfiles && file.attributes().map_or(false, |a| a.hidden) {
                     continue;
                 }
 
@@ -181,24 +181,22 @@ enum DotsNext {
 }
 
 impl<'dir, 'ig> Iterator for Files<'dir, 'ig> {
-    type Item = Result<File<'dir>, (PathBuf, io::Error)>;
+    type Item = File<'dir>;
 
     fn next(&mut self) -> Option<Self::Item> {
         match self.dots {
             DotsNext::Dot => {
                 self.dots = DotsNext::DotDot;
-                Some(
-                    File::new_aa_current(self.dir, self.total_size)
-                        .map_err(|e| (Path::new(".").to_path_buf(), e)),
-                )
+                Some(File::new_aa_current(self.dir, self.total_size))
             }
 
             DotsNext::DotDot => {
                 self.dots = DotsNext::Files;
-                Some(
-                    File::new_aa_parent(self.parent(), self.dir, self.total_size)
-                        .map_err(|e| (self.parent(), e)),
-                )
+                Some(File::new_aa_parent(
+                    self.parent(),
+                    self.dir,
+                    self.total_size,
+                ))
             }
 
             DotsNext::Files => self.next_visible_file(),

+ 98 - 67
src/fs/file.rs

@@ -8,6 +8,7 @@
 
 #[cfg(unix)]
 use std::collections::HashMap;
+use std::fs::FileType;
 use std::io;
 #[cfg(unix)]
 use std::os::unix::fs::{FileTypeExt, MetadataExt, PermissionsExt};
@@ -74,12 +75,15 @@ pub struct File<'dir> {
     /// path (following a symlink).
     pub path: PathBuf,
 
+    /// The cached filetype for this file
+    pub filetype: OnceLock<Option<std::fs::FileType>>,
+
     /// A cached `metadata` (`stat`) call for this file.
     ///
     /// This too is queried multiple times, and is *not* cached by the OS, as
     /// it could easily change between invocations — but exa is so short-lived
     /// it’s better to just cache it.
-    pub metadata: std::fs::Metadata,
+    pub metadata: OnceLock<io::Result<std::fs::Metadata>>,
 
     /// A reference to the directory that contains this file, if any.
     ///
@@ -122,7 +126,8 @@ impl<'dir> File<'dir> {
         filename: FN,
         deref_links: bool,
         total_size: bool,
-    ) -> io::Result<File<'dir>>
+        filetype: Option<std::fs::FileType>,
+    ) -> File<'dir>
     where
         PD: Into<Option<&'dir Dir>>,
         FN: Into<Option<String>>,
@@ -131,11 +136,7 @@ impl<'dir> File<'dir> {
         let name = filename.into().unwrap_or_else(|| File::filename(&path));
         let ext = File::ext(&path);
 
-        debug!("Statting file {:?}", &path);
-        let metadata = std::fs::symlink_metadata(&path)?;
         let is_all_all = false;
-        let extended_attributes = OnceLock::new();
-        let absolute_path = OnceLock::new();
         let recursive_size = if total_size {
             RecursiveSize::Unknown
         } else {
@@ -144,24 +145,32 @@ impl<'dir> File<'dir> {
 
         debug!("deref_links {}", deref_links);
 
+        let filetype = match filetype {
+            Some(f) => OnceLock::from(Some(f)),
+            None => OnceLock::new(),
+        };
+
+        debug!("deref_links {}", deref_links);
+
         let mut file = File {
             name,
             ext,
             path,
-            metadata,
             parent_dir,
             is_all_all,
             deref_links,
             recursive_size,
-            extended_attributes,
-            absolute_path,
+            filetype,
+            metadata: OnceLock::new(),
+            extended_attributes: OnceLock::new(),
+            absolute_path: OnceLock::new(),
         };
 
         if total_size {
             file.recursive_size = file.recursive_directory_size();
         }
 
-        Ok(file)
+        file
     }
 
     fn new_aa(
@@ -169,15 +178,11 @@ impl<'dir> File<'dir> {
         parent_dir: &'dir Dir,
         name: &'static str,
         total_size: bool,
-    ) -> io::Result<File<'dir>> {
+    ) -> File<'dir> {
         let ext = File::ext(&path);
 
-        debug!("Statting file {:?}", &path);
-        let metadata = std::fs::symlink_metadata(&path)?;
         let is_all_all = true;
         let parent_dir = Some(parent_dir);
-        let extended_attributes = OnceLock::new();
-        let absolute_path = OnceLock::new();
         let recursive_size = if total_size {
             RecursiveSize::Unknown
         } else {
@@ -188,31 +193,28 @@ impl<'dir> File<'dir> {
             name: name.into(),
             ext,
             path,
-            metadata,
             parent_dir,
             is_all_all,
             deref_links: false,
-            extended_attributes,
-            absolute_path,
             recursive_size,
+            metadata: OnceLock::new(),
+            absolute_path: OnceLock::new(),
+            extended_attributes: OnceLock::new(),
+            filetype: OnceLock::new(),
         };
 
         if total_size {
             file.recursive_size = file.recursive_directory_size();
         }
 
-        Ok(file)
+        file
     }
 
-    pub fn new_aa_current(parent_dir: &'dir Dir, total_size: bool) -> io::Result<File<'dir>> {
+    pub fn new_aa_current(parent_dir: &'dir Dir, total_size: bool) -> File<'dir> {
         File::new_aa(parent_dir.path.clone(), parent_dir, ".", total_size)
     }
 
-    pub fn new_aa_parent(
-        path: PathBuf,
-        parent_dir: &'dir Dir,
-        total_size: bool,
-    ) -> io::Result<File<'dir>> {
+    pub fn new_aa_parent(path: PathBuf, parent_dir: &'dir Dir, total_size: bool) -> File<'dir> {
         File::new_aa(path, parent_dir, "..", total_size)
     }
 
@@ -267,6 +269,21 @@ impl<'dir> File<'dir> {
         }
     }
 
+    fn filetype(&self) -> Option<&std::fs::FileType> {
+        self.filetype
+            .get_or_init(|| self.metadata().as_ref().ok().map(|md| md.file_type()))
+            .as_ref()
+    }
+
+    pub fn metadata(&self) -> Result<&std::fs::Metadata, &io::Error> {
+        self.metadata
+            .get_or_init(|| {
+                debug!("Statting file {:?}", &self.path);
+                std::fs::symlink_metadata(&self.path)
+            })
+            .as_ref()
+    }
+
     /// Get the extended attributes of a file path on demand.
     pub fn extended_attributes(&self) -> &Vec<Attribute> {
         self.extended_attributes
@@ -275,7 +292,7 @@ impl<'dir> File<'dir> {
 
     /// Whether this file is a directory on the filesystem.
     pub fn is_directory(&self) -> bool {
-        self.metadata.is_dir()
+        self.filetype().map_or(false, std::fs::FileType::is_dir)
     }
 
     /// Whether this file is a directory, or a symlink pointing to a directory.
@@ -308,7 +325,7 @@ impl<'dir> File<'dir> {
     /// Whether this file is a regular file on the filesystem — that is, not a
     /// directory, a link, or anything else treated specially.
     pub fn is_file(&self) -> bool {
-        self.metadata.is_file()
+        self.filetype().map_or(false, std::fs::FileType::is_file)
     }
 
     /// Whether this file is both a regular file *and* executable for the
@@ -317,36 +334,42 @@ impl<'dir> File<'dir> {
     #[cfg(unix)]
     pub fn is_executable_file(&self) -> bool {
         let bit = modes::USER_EXECUTE;
-        self.is_file() && (self.metadata.permissions().mode() & bit) == bit
+        if self.is_file() {
+            return false;
+        }
+        let Ok(md) = self.metadata() else {
+            return false;
+        };
+        (md.permissions().mode() & bit) == bit
     }
 
     /// Whether this file is a symlink on the filesystem.
     pub fn is_link(&self) -> bool {
-        self.metadata.file_type().is_symlink()
+        self.filetype().map_or(false, FileType::is_symlink)
     }
 
     /// Whether this file is a named pipe on the filesystem.
     #[cfg(unix)]
     pub fn is_pipe(&self) -> bool {
-        self.metadata.file_type().is_fifo()
+        self.filetype().map_or(false, FileTypeExt::is_fifo)
     }
 
     /// Whether this file is a char device on the filesystem.
     #[cfg(unix)]
     pub fn is_char_device(&self) -> bool {
-        self.metadata.file_type().is_char_device()
+        self.filetype().map_or(false, FileTypeExt::is_char_device)
     }
 
     /// Whether this file is a block device on the filesystem.
     #[cfg(unix)]
     pub fn is_block_device(&self) -> bool {
-        self.metadata.file_type().is_block_device()
+        self.filetype().map_or(false, FileTypeExt::is_block_device)
     }
 
     /// Whether this file is a socket on the filesystem.
     #[cfg(unix)]
     pub fn is_socket(&self) -> bool {
-        self.metadata.file_type().is_socket()
+        self.filetype().map_or(false, FileTypeExt::is_socket)
     }
 
     /// Determine the full path resolving all symbolic links on demand.
@@ -435,7 +458,8 @@ impl<'dir> File<'dir> {
                     parent_dir: None,
                     path,
                     ext,
-                    metadata,
+                    filetype: OnceLock::from(Some(metadata.file_type())),
+                    metadata: OnceLock::from(Ok(metadata)),
                     name,
                     is_all_all: false,
                     deref_links: self.deref_links,
@@ -482,7 +506,7 @@ impl<'dir> File<'dir> {
     /// more attentively.
     #[cfg(unix)]
     pub fn links(&self) -> f::Links {
-        let count = self.metadata.nlink();
+        let count = self.metadata().map_or(0, MetadataExt::nlink);
 
         f::Links {
             count,
@@ -493,7 +517,7 @@ impl<'dir> File<'dir> {
     /// This file’s inode.
     #[cfg(unix)]
     pub fn inode(&self) -> f::Inode {
-        f::Inode(self.metadata.ino())
+        f::Inode(self.metadata().map_or(0, MetadataExt::ino))
     }
 
     /// This actual size the file takes up on disk, in bytes.
@@ -512,7 +536,7 @@ impl<'dir> File<'dir> {
             // Note that metadata.blocks returns the number of blocks
             // for 512 byte blocks according to the POSIX standard
             // even though the physical block size may be different.
-            f::Blocksize::Some(self.metadata.blocks() * 512)
+            f::Blocksize::Some(self.metadata().map_or(0, |md| md.blocks() * 512))
         } else {
             // directory or symlinks
             f::Blocksize::None
@@ -529,7 +553,7 @@ impl<'dir> File<'dir> {
                 _ => None,
             };
         }
-        Some(f::User(self.metadata.uid()))
+        Some(f::User(self.metadata().map_or(0, MetadataExt::uid)))
     }
 
     /// The ID of the group that owns this file.
@@ -541,7 +565,7 @@ impl<'dir> File<'dir> {
                 _ => None,
             };
         }
-        Some(f::Group(self.metadata.gid()))
+        Some(f::Group(self.metadata().map_or(0, MetadataExt::gid)))
     }
 
     /// This file’s size, if it’s a regular file.
@@ -566,7 +590,7 @@ impl<'dir> File<'dir> {
             self.recursive_size
                 .map_or(f::Size::None, |bytes, _| f::Size::Some(bytes))
         } else if self.is_char_device() || self.is_block_device() {
-            let device_id = self.metadata.rdev();
+            let device_id = self.metadata().map_or(0, MetadataExt::rdev);
 
             // MacOS and Linux have different arguments and return types for the
             // functions major and minor.  On Linux the try_into().unwrap() and
@@ -580,7 +604,7 @@ impl<'dir> File<'dir> {
                 minor: unsafe { libc::minor(device_id.try_into().unwrap()) } as u32,
             })
         } else if self.is_file() {
-            f::Size::Some(self.metadata.len())
+            f::Size::Some(self.metadata().map_or(0, std::fs::Metadata::len))
         } else {
             // symlink
             f::Size::None
@@ -596,7 +620,7 @@ impl<'dir> File<'dir> {
         if self.is_directory() {
             f::Size::None
         } else {
-            f::Size::Some(self.metadata.len())
+            f::Size::Some(self.metadata().map_or(0, std::fs::Metadata::len))
         }
     }
 
@@ -606,17 +630,17 @@ impl<'dir> File<'dir> {
     #[cfg(unix)]
     fn recursive_directory_size(&self) -> RecursiveSize {
         if self.is_directory() {
-            let key = (self.metadata.dev(), self.metadata.ino());
+            let key = (
+                self.metadata().map_or(0, MetadataExt::dev),
+                self.metadata().map_or(0, MetadataExt::ino),
+            );
             if let Some(size) = DIRECTORY_SIZE_CACHE.lock().unwrap().get(&key) {
                 return RecursiveSize::Some(size.0, size.1);
             }
             Dir::read_dir(self.path.clone()).map_or(RecursiveSize::Unknown, |dir| {
                 let mut size = 0;
                 let mut blocks = 0;
-                for file in dir
-                    .files(super::DotFilter::Dotfiles, None, false, false, true)
-                    .flatten()
-                {
+                for file in dir.files(super::DotFilter::Dotfiles, None, false, false, true) {
                     match file.recursive_directory_size() {
                         RecursiveSize::Some(bytes, blks) => {
                             size += bytes;
@@ -624,8 +648,8 @@ impl<'dir> File<'dir> {
                         }
                         RecursiveSize::Unknown => {}
                         RecursiveSize::None => {
-                            size += file.metadata.size();
-                            blocks += file.metadata.blocks();
+                            size += file.metadata().map_or(0, MetadataExt::size);
+                            blocks += file.metadata().map_or(0, MetadataExt::blocks);
                         }
                     }
                 }
@@ -653,7 +677,8 @@ impl<'dir> File<'dir> {
     /// of a directory when `total_size` is used.
     #[inline]
     pub fn length(&self) -> u64 {
-        self.recursive_size.unwrap_bytes_or(self.metadata.len())
+        self.recursive_size
+            .unwrap_bytes_or(self.metadata().map_or(0, std::fs::Metadata::len))
     }
 
     /// Is the file is using recursive size calculation
@@ -674,7 +699,7 @@ impl<'dir> File<'dir> {
     #[cfg(unix)]
     pub fn is_empty_dir(&self) -> bool {
         if self.is_directory() {
-            if self.metadata.nlink() > 2 {
+            if self.metadata().map_or(0, MetadataExt::nlink) > 2 {
                 // Directories will have a link count of two if they do not have any subdirectories.
                 // The '.' entry is a link to itself and the '..' is a link to the parent directory.
                 // A subdirectory will have a link to its parent directory increasing the link count
@@ -745,9 +770,9 @@ impl<'dir> File<'dir> {
                 _ => None,
             };
         }
-        self.metadata
-            .modified()
+        self.metadata()
             .ok()
+            .and_then(|md| md.modified().ok())
             .and_then(Self::systemtime_to_naivedatetime)
     }
 
@@ -760,7 +785,11 @@ impl<'dir> File<'dir> {
                 _ => None,
             };
         }
-        NaiveDateTime::from_timestamp_opt(self.metadata.ctime(), self.metadata.ctime_nsec() as u32)
+        let md = self.metadata();
+        NaiveDateTime::from_timestamp_opt(
+            md.map_or(0, MetadataExt::ctime),
+            md.map_or(0, |md| md.ctime_nsec() as u32),
+        )
     }
 
     #[cfg(windows)]
@@ -776,9 +805,9 @@ impl<'dir> File<'dir> {
                 _ => None,
             };
         }
-        self.metadata
-            .accessed()
+        self.metadata()
             .ok()
+            .and_then(|md| md.accessed().ok())
             .and_then(Self::systemtime_to_naivedatetime)
     }
 
@@ -790,10 +819,8 @@ impl<'dir> File<'dir> {
                 _ => None,
             };
         }
-        self.metadata
-            .created()
-            .ok()
-            .and_then(Self::systemtime_to_naivedatetime)
+        let btime = self.metadata().ok()?.created().ok()?;
+        Self::systemtime_to_naivedatetime(btime)
     }
 
     /// This file’s ‘type’.
@@ -845,7 +872,7 @@ impl<'dir> File<'dir> {
                 _ => None,
             };
         }
-        let bits = self.metadata.mode();
+        let bits = self.metadata().map_or(0, MetadataExt::mode);
         let has_bit = |bit| bits & bit == bit;
 
         Some(f::Permissions {
@@ -868,19 +895,19 @@ impl<'dir> File<'dir> {
     }
 
     #[cfg(windows)]
-    pub fn attributes(&self) -> f::Attributes {
-        let bits = self.metadata.file_attributes();
+    pub fn attributes(&self) -> Option<f::Attributes> {
+        let bits = self.metadata().ok()?.file_attributes();
         let has_bit = |bit| bits & bit == bit;
 
         // https://docs.microsoft.com/en-us/windows/win32/fileio/file-attribute-constants
-        f::Attributes {
+        Some(f::Attributes {
             directory: has_bit(0x10),
             archive: has_bit(0x20),
             readonly: has_bit(0x1),
             hidden: has_bit(0x2),
             system: has_bit(0x4),
             reparse_point: has_bit(0x400),
-        }
+        })
     }
 
     /// This file’s security context field.
@@ -930,12 +957,16 @@ impl<'dir> File<'dir> {
         use std::os::netbsd::fs::MetadataExt;
         #[cfg(target_os = "openbsd")]
         use std::os::openbsd::fs::MetadataExt;
-        f::Flags(self.metadata.st_flags())
+        f::Flags(
+            self.metadata()
+                .map(MetadataExt::st_flags)
+                .unwrap_or_default(),
+        )
     }
 
     #[cfg(windows)]
     pub fn flags(&self) -> f::Flags {
-        f::Flags(self.metadata.file_attributes())
+        f::Flags(self.metadata().map_or(0, |md| md.file_attributes()))
     }
 
     #[cfg(not(any(

+ 4 - 1
src/fs/filter.rs

@@ -274,7 +274,10 @@ impl SortField {
             Self::Size          => a.length().cmp(&b.length()),
 
             #[cfg(unix)]
-            Self::FileInode     => a.metadata.ino().cmp(&b.metadata.ino()),
+            Self::FileInode     => {
+                a.metadata().map_or(0, MetadataExt::ino)
+                    .cmp(&b.metadata().map_or(0, MetadataExt::ino))
+            }
             Self::ModifiedDate  => a.modified_time().cmp(&b.modified_time()),
             Self::AccessedDate  => a.accessed_time().cmp(&b.accessed_time()),
             Self::ChangedDate   => a.changed_time().cmp(&b.changed_time()),

+ 23 - 24
src/main.rs

@@ -106,7 +106,7 @@ fn main() {
             info!("matching on exa.run");
             match exa.run() {
                 Ok(exit_status) => {
-                    trace!("exa.run: exit Ok(exit_status)");
+                    trace!("exa.run: exit Ok({exit_status})");
                     exit(exit_status);
                 }
 
@@ -260,33 +260,35 @@ impl<'args> Exa<'args> {
         let mut exit_status = 0;
 
         for file_path in &self.input_paths {
-            match File::from_args(
+            let f = File::from_args(
                 PathBuf::from(file_path),
                 None,
                 None,
                 self.options.view.deref_links,
                 self.options.view.total_size,
-            ) {
-                Err(e) => {
-                    exit_status = 2;
-                    writeln!(io::stderr(), "{file_path:?}: {e}")?;
-                }
+                None,
+            );
+
+            // We don't know whether this file exists, so we have to try to get
+            // the metadata to verify.
+            if let Err(e) = f.metadata() {
+                exit_status = 2;
+                writeln!(io::stderr(), "{file_path:?}: {e}")?;
+                continue;
+            }
 
-                Ok(f) => {
-                    if f.points_to_directory() && !self.options.dir_action.treat_dirs_as_files() {
-                        trace!("matching on to_dir");
-                        match f.to_dir() {
-                            Ok(d) => dirs.push(d),
-                            Err(e) if e.kind() == ErrorKind::PermissionDenied => {
-                                eprintln!("{file_path:?}: {e}");
-                                exit(exits::PERMISSION_DENIED);
-                            }
-                            Err(e) => writeln!(io::stderr(), "{file_path:?}: {e}")?,
-                        }
-                    } else {
-                        files.push(f);
+            if f.points_to_directory() && !self.options.dir_action.treat_dirs_as_files() {
+                trace!("matching on to_dir");
+                match f.to_dir() {
+                    Ok(d) => dirs.push(d),
+                    Err(e) if e.kind() == ErrorKind::PermissionDenied => {
+                        eprintln!("{file_path:?}: {e}");
+                        exit(exits::PERMISSION_DENIED);
                     }
+                    Err(e) => writeln!(io::stderr(), "{file_path:?}: {e}")?,
                 }
+            } else {
+                files.push(f);
             }
         }
 
@@ -344,10 +346,7 @@ impl<'args> Exa<'args> {
                 self.options.view.deref_links,
                 self.options.view.total_size,
             ) {
-                match file {
-                    Ok(file) => children.push(file),
-                    Err((path, e)) => writeln!(io::stderr(), "[{}: {}]", path.display(), e)?,
-                }
+                children.push(file);
             }
             let recursing = self.options.dir_action.recurse_options().is_some();
             self.options

+ 0 - 1
src/output/color_scale.rs

@@ -170,7 +170,6 @@ fn update_information_recursively(
                 Ok(dir) => {
                     let files: Vec<File<'_>> = dir
                         .files(dot_filter, git, git_ignoring, false, false)
-                        .flatten()
                         .collect();
 
                     update_information_recursively(

+ 2 - 9
src/output/details.rs

@@ -330,7 +330,7 @@ impl<'a> Render<'a> {
 
         for (tree_params, egg) in depth.iterate_over(file_eggs.into_iter()) {
             let mut files = Vec::new();
-            let mut errors = egg.errors;
+            let errors = egg.errors;
 
             if let (Some(ref mut t), Some(row)) = (table.as_mut(), egg.table_row.as_ref()) {
                 t.add_widths(row);
@@ -362,14 +362,7 @@ impl<'a> Render<'a> {
                     egg.file.deref_links,
                     egg.file.is_recursive_size(),
                 ) {
-                    match file_to_add {
-                        Ok(f) => {
-                            files.push(f);
-                        }
-                        Err((path, e)) => {
-                            errors.push((e, Some(path)));
-                        }
-                    }
+                    files.push(file_to_add);
                 }
 
                 self.filter

+ 1 - 1
src/output/table.rs

@@ -497,7 +497,7 @@ impl<'a> Table<'a> {
         Some(f::PermissionsPlus {
             file_type: file.type_char(),
             #[cfg(windows)]
-            attributes: file.attributes(),
+            attributes: file.attributes()?,
             xattrs,
         })
     }