ls: Lazily obtain FileType, eagerly obtain Metadata when Metadata is available (#8753)

Improves the ls perf by +10% in some cases
This commit is contained in:
kimono-koans
2025-09-29 10:24:08 +02:00
committed by GitHub
parent 4cab890676
commit 5c15d7939b
4 changed files with 244 additions and 213 deletions
Generated
+1
View File
@@ -3608,6 +3608,7 @@ dependencies = [
"clap",
"codspeed-divan-compat",
"fluent",
"fnv",
"glob",
"hostname",
"lscolors",
+1
View File
@@ -24,6 +24,7 @@ ansi-width = { workspace = true }
clap = { workspace = true, features = ["env"] }
glob = { workspace = true }
hostname = { workspace = true }
fnv = { workspace = true }
lscolors = { workspace = true }
selinux = { workspace = true, optional = true }
terminal_size = { workspace = true }
+15 -22
View File
@@ -3,11 +3,9 @@
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.
use super::PathData;
use super::get_metadata_with_deref_opt;
use lscolors::{Indicator, LsColors, Style};
use lscolors::{Colorable, Indicator, LsColors, Style};
use std::ffi::OsString;
use std::fs::{DirEntry, Metadata};
use std::io::{BufWriter, Stdout};
use std::fs::Metadata;
/// We need this struct to be able to store the previous style.
/// This because we need to check the previous value in case we don't need
@@ -135,25 +133,22 @@ impl<'a> StyleManager<'a> {
self.apply_style(style, name, wrap)
}
pub(crate) fn apply_style_based_on_dir_entry(
pub(crate) fn apply_style_based_on_colorable<T: Colorable>(
&mut self,
dir_entry: &DirEntry,
path: &T,
name: OsString,
wrap: bool,
) -> OsString {
let style = self.colors.style_for(dir_entry);
let style = self.colors.style_for(path);
self.apply_style(style, name, wrap)
}
}
/// Colors the provided name based on the style determined for the given path
/// This function is quite long because it tries to leverage [`DirEntry`] to avoid
/// unnecessary calls to stat and manages the symlink errors
pub(crate) fn color_name(
name: OsString,
path: &PathData,
style_manager: &mut StyleManager,
out: &mut BufWriter<Stdout>,
target_symlink: Option<&PathData>,
wrap: bool,
) -> OsString {
@@ -179,23 +174,21 @@ pub(crate) fn color_name(
if !path.must_dereference {
// If we need to dereference (follow) a symlink, we will need to get the metadata
if let Some(de) = &path.de {
// There is a DirEntry, we don't need to get the metadata for the color
return style_manager.apply_style_based_on_dir_entry(de, name, wrap);
}
// There is a DirEntry, we don't need to get the metadata for the color
return style_manager.apply_style_based_on_colorable(path, name, wrap);
}
if let Some(target) = target_symlink {
// use the optional target_symlink
// Use fn get_metadata_with_deref_opt instead of get_metadata() here because ls
// Use fn symlink_metadata directly instead of get_metadata() here because ls
// should not exit with an err, if we are unable to obtain the target_metadata
let md_res = get_metadata_with_deref_opt(&target.p_buf, path.must_dereference);
let md = md_res.or_else(|_| path.p_buf.symlink_metadata());
style_manager.apply_style_based_on_metadata(path, md.ok().as_ref(), name, wrap)
style_manager.apply_style_based_on_colorable(target, name, wrap)
} else {
let md_option = path.get_metadata(out);
let symlink_metadata = path.p_buf.symlink_metadata().ok();
let md = md_option.or(symlink_metadata.as_ref());
style_manager.apply_style_based_on_metadata(path, md, name, wrap)
let md_option: Option<Metadata> = path
.metadata()
.cloned()
.or_else(|| path.p_buf.symlink_metadata().ok());
style_manager.apply_style_based_on_metadata(path, md_option.as_ref(), name, wrap)
}
}
+227 -191
View File
File diff suppressed because it is too large Load Diff