1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-29 12:07:46 +00:00

Move more logic into md function, make enter_directory function clearer

This commit is contained in:
electricboogie 2022-01-26 16:41:52 -06:00
parent 0b53cd8c4a
commit 1d629d8d66

View file

@ -1283,6 +1283,7 @@ struct PathData {
md: OnceCell<Option<Metadata>>, md: OnceCell<Option<Metadata>>,
ft: OnceCell<Option<FileType>>, ft: OnceCell<Option<FileType>>,
// Name of the file - will be empty for . or .. // Name of the file - will be empty for . or ..
de: OnceCell<Option<DirEntry>>,
display_name: OsString, display_name: OsString,
// PathBuf that all above data corresponds to // PathBuf that all above data corresponds to
p_buf: PathBuf, p_buf: PathBuf,
@ -1295,6 +1296,7 @@ impl PathData {
p_buf: PathBuf, p_buf: PathBuf,
file_type: Option<std::io::Result<FileType>>, file_type: Option<std::io::Result<FileType>>,
metadata: Option<std::io::Result<Metadata>>, metadata: Option<std::io::Result<Metadata>>,
dir_entry: Option<std::io::Result<DirEntry>>,
file_name: Option<OsString>, file_name: Option<OsString>,
config: &Config, config: &Config,
command_line: bool, command_line: bool,
@ -1328,6 +1330,11 @@ impl PathData {
Dereference::None => false, Dereference::None => false,
}; };
let de = match dir_entry {
Some(de) => OnceCell::from(de.ok()),
None => OnceCell::new(),
};
let ft = match file_type { let ft = match file_type {
Some(ft) => OnceCell::from(ft.ok()), Some(ft) => OnceCell::from(ft.ok()),
None => OnceCell::new(), None => OnceCell::new(),
@ -1353,6 +1360,7 @@ impl PathData {
Self { Self {
ft, ft,
md, md,
de,
display_name, display_name,
p_buf, p_buf,
must_dereference, must_dereference,
@ -1362,33 +1370,30 @@ impl PathData {
fn md(&self, out: &mut BufWriter<Stdout>) -> Option<&Metadata> { fn md(&self, out: &mut BufWriter<Stdout>) -> Option<&Metadata> {
self.md self.md
.get_or_init( .get_or_init(|| {
|| match get_metadata(self.p_buf.as_path(), self.must_dereference) { // check if we can use DirEntry metadata
if !self.must_dereference {
if let Some(Some(dir_entry)) = self.de.get() {
return dir_entry.metadata().ok();
}
}
// if not, check if we can use path metadata
match get_metadata(self.p_buf.as_path(), self.must_dereference) {
Err(err) => { Err(err) => {
let _ = out.flush(); let _ = out.flush();
let errno = err.raw_os_error().unwrap_or(1i32); let errno = err.raw_os_error().unwrap_or(1i32);
// Wait to enter "directory" to print error for any bad fd
if self.must_dereference && errno.eq(&9i32) { if self.must_dereference && errno.eq(&9i32) {
if let Some(parent) = self.p_buf.parent() { if let Some(Some(dir_entry)) = self.de.get() {
if let Ok(read_dir) = fs::read_dir(parent) { return dir_entry.metadata().ok();
// this dir_entry metadata is different from the metadata call on the path
let res = read_dir
.filter_map(|x| x.ok())
.filter(|x| self.p_buf.eq(&x.path()))
.filter_map(|x| x.metadata().ok())
.next();
if let Some(md) = res {
return Some(md);
}
}
} }
} }
show!(LsError::IOErrorContext(err, self.p_buf.clone(),)); show!(LsError::IOErrorContext(err, self.p_buf.clone(),));
None None
} }
Ok(md) => Some(md), Ok(md) => Some(md),
}, }
) })
.as_ref() .as_ref()
} }
@ -1406,7 +1411,7 @@ fn list(locs: Vec<&Path>, config: Config) -> UResult<()> {
let initial_locs_len = locs.len(); let initial_locs_len = locs.len();
for loc in locs { for loc in locs {
let path_data = PathData::new(PathBuf::from(loc), None, None, None, &config, true); let path_data = PathData::new(PathBuf::from(loc), None, None, None, None, &config, true);
// Getting metadata here is no big deal as it's just the CWD // Getting metadata here is no big deal as it's just the CWD
// and we really just want to know if the strings exist as files/dirs // and we really just want to know if the strings exist as files/dirs
@ -1541,6 +1546,7 @@ fn enter_directory(
path_data.p_buf.clone(), path_data.p_buf.clone(),
None, None,
None, None,
None,
Some(".".into()), Some(".".into()),
config, config,
false, false,
@ -1549,6 +1555,7 @@ fn enter_directory(
path_data.p_buf.join(".."), path_data.p_buf.join(".."),
None, None,
None, None,
None,
Some("..".into()), Some("..".into()),
config, config,
false, false,
@ -1579,58 +1586,37 @@ fn enter_directory(
// certain we print the error once. This also seems to match GNU behavior. // certain we print the error once. This also seems to match GNU behavior.
let entry_path_data = match dir_entry.file_type() { let entry_path_data = match dir_entry.file_type() {
Ok(ft) => { Ok(ft) => {
// metadata returned from a DirEntry matches GNU metadata for if let Ok(md) = dir_entry.metadata() {
// non-dereferenced files, and is *different* from the PathData::new(
// metadata call on the path, see, for example, bad fds, dir_entry.path(),
// so we use dir_entry metadata here when we know we Some(Ok(ft)),
// will need metadata later anyway Some(Ok(md)),
#[cfg(unix)] Some(Ok(dir_entry)),
{ None,
if (config.format == Format::Long) config,
|| (config.sort == Sort::Name) false,
|| (config.sort == Sort::None) )
|| config.inode } else {
{ PathData::new(
if let Ok(md) = dir_entry.metadata() { dir_entry.path(),
PathData::new( Some(Ok(ft)),
dir_entry.path(), None,
Some(Ok(ft)), Some(Ok(dir_entry)),
Some(Ok(md)), None,
None, config,
config, false,
false, )
)
} else {
PathData::new(dir_entry.path(), None, None, None, config, false)
}
} else {
PathData::new(dir_entry.path(), None, None, None, config, false)
}
}
#[cfg(not(unix))]
{
if (config.format == Format::Long)
|| (config.sort == Sort::Name)
|| (config.sort == Sort::None)
{
if let Ok(md) = dir_entry.metadata() {
PathData::new(
dir_entry.path(),
Some(Ok(ft)),
Some(Ok(md)),
None,
config,
false,
)
} else {
PathData::new(dir_entry.path(), None, None, None, config, false)
}
} else {
PathData::new(dir_entry.path(), None, None, None, config, false)
}
} }
} }
Err(_) => PathData::new(dir_entry.path(), None, None, None, config, false), Err(_) => PathData::new(
dir_entry.path(),
None,
None,
Some(Ok(dir_entry)),
None,
config,
false,
),
}; };
vec_path_data.push(entry_path_data); vec_path_data.push(entry_path_data);
}; };
@ -2494,7 +2480,8 @@ fn display_file_name(
} }
} }
let target_data = PathData::new(absolute_target, None, None, None, config, false); let target_data =
PathData::new(absolute_target, None, None, None, None, config, false);
// If we have a symlink to a valid file, we use the metadata of said file. // If we have a symlink to a valid file, we use the metadata of said file.
// Because we use an absolute path, we can assume this is guaranteed to exist. // Because we use an absolute path, we can assume this is guaranteed to exist.