mirror of
https://github.com/Llewellynvdm/exa.git
synced 2024-11-29 15:13:54 +00:00
Prevent infinite loop with -aaR
This happened because exa would recurse into `.` over and over again. There was nothing distinguishing the pseudo-entry for `.` that was being added by `--a` from a `.` passed in on the command-line, so it was looping forever. It gets fixed by having the File value keep track of whether it’s an --all --all entry, and not recursing into directories with this field set. Fixes #515
This commit is contained in:
parent
7dada93c3e
commit
e936d7e09f
@ -191,7 +191,7 @@ impl<'args, 'w, W: Write + 'w> Exa<'args, 'w, W> {
|
||||
if !recurse_opts.tree && !recurse_opts.is_too_deep(depth) {
|
||||
|
||||
let mut child_dirs = Vec::new();
|
||||
for child_dir in children.iter().filter(|f| f.is_directory()) {
|
||||
for child_dir in children.iter().filter(|f| f.is_directory() && !f.is_all_all) {
|
||||
match child_dir.to_dir() {
|
||||
Ok(d) => child_dirs.push(d),
|
||||
Err(e) => writeln!(stderr(), "{}: {}", child_dir.path.display(), e)?,
|
||||
|
@ -140,12 +140,12 @@ impl<'dir, 'ig> Iterator for Files<'dir, 'ig> {
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if let Dots::DotNext = self.dots {
|
||||
self.dots = Dots::DotDotNext;
|
||||
Some(File::new(self.dir.path.to_path_buf(), self.dir, String::from("."))
|
||||
Some(File::new_aa_current(self.dir)
|
||||
.map_err(|e| (Path::new(".").to_path_buf(), e)))
|
||||
}
|
||||
else if let Dots::DotDotNext = self.dots {
|
||||
self.dots = Dots::FilesNext;
|
||||
Some(File::new(self.parent(), self.dir, String::from(".."))
|
||||
Some(File::new_aa_parent(self.parent(), self.dir)
|
||||
.map_err(|e| (self.parent(), e)))
|
||||
}
|
||||
else {
|
||||
|
@ -55,6 +55,13 @@ pub struct File<'dir> {
|
||||
/// contain a reference to it, which is used in certain operations (such
|
||||
/// as looking up compiled files).
|
||||
pub parent_dir: Option<&'dir Dir>,
|
||||
|
||||
/// Whether this is one of the two `--all all` directories, `.` and `..`.
|
||||
///
|
||||
/// Unlike all other entries, these are not returned as part of the
|
||||
/// directory's children, and are in fact added specifically by exa; this
|
||||
/// means that they should be skipped when recursing.
|
||||
pub is_all_all: bool,
|
||||
}
|
||||
|
||||
impl<'dir> File<'dir> {
|
||||
@ -68,8 +75,30 @@ impl<'dir> File<'dir> {
|
||||
|
||||
debug!("Statting file {:?}", &path);
|
||||
let metadata = fs::symlink_metadata(&path)?;
|
||||
let is_all_all = false;
|
||||
|
||||
Ok(File { path, parent_dir, metadata, ext, name })
|
||||
Ok(File { path, parent_dir, metadata, ext, name, is_all_all })
|
||||
}
|
||||
|
||||
pub fn new_aa_current(parent_dir: &'dir Dir) -> IOResult<File<'dir>> {
|
||||
let path = parent_dir.path.to_path_buf();
|
||||
let ext = File::ext(&path);
|
||||
|
||||
debug!("Statting file {:?}", &path);
|
||||
let metadata = fs::symlink_metadata(&path)?;
|
||||
let is_all_all = true;
|
||||
|
||||
Ok(File { path, parent_dir: Some(parent_dir), metadata, ext, name: ".".to_string(), is_all_all })
|
||||
}
|
||||
|
||||
pub fn new_aa_parent(path: PathBuf, parent_dir: &'dir Dir) -> IOResult<File<'dir>> {
|
||||
let ext = File::ext(&path);
|
||||
|
||||
debug!("Statting file {:?}", &path);
|
||||
let metadata = fs::symlink_metadata(&path)?;
|
||||
let is_all_all = true;
|
||||
|
||||
Ok(File { path, parent_dir: Some(parent_dir), metadata, ext, name: "..".to_string(), is_all_all })
|
||||
}
|
||||
|
||||
/// A file’s name is derived from its string. This needs to handle directories
|
||||
@ -219,7 +248,7 @@ impl<'dir> File<'dir> {
|
||||
Ok(metadata) => {
|
||||
let ext = File::ext(&path);
|
||||
let name = File::filename(&path);
|
||||
FileTarget::Ok(Box::new(File { parent_dir: None, path, ext, metadata, name }))
|
||||
FileTarget::Ok(Box::new(File { parent_dir: None, path, ext, metadata, name, is_all_all: false }))
|
||||
}
|
||||
Err(e) => {
|
||||
error!("Error following link {:?}: {:#?}", &path, e);
|
||||
|
Loading…
Reference in New Issue
Block a user