mirror of
https://github.com/sharkdp/fd
synced 2024-11-05 16:58:21 +00:00
New implementation of broken-symlink handling
This commit is contained in:
parent
bfc8c42444
commit
bbf0f1cc1f
2 changed files with 56 additions and 8 deletions
|
@ -13,7 +13,7 @@ use std::io;
|
|||
use std::os::unix::fs::PermissionsExt;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use ignore::DirEntry;
|
||||
use crate::walk;
|
||||
|
||||
pub fn path_absolute_form(path: &Path) -> io::Result<PathBuf> {
|
||||
if path.is_absolute() {
|
||||
|
@ -55,7 +55,7 @@ pub fn is_executable(_: &fs::Metadata) -> bool {
|
|||
false
|
||||
}
|
||||
|
||||
pub fn is_empty(entry: &DirEntry) -> bool {
|
||||
pub fn is_empty(entry: &walk::DirEntry) -> bool {
|
||||
if let Some(file_type) = entry.file_type() {
|
||||
if file_type.is_dir() {
|
||||
if let Ok(mut entries) = fs::read_dir(entry.path()) {
|
||||
|
|
60
src/walk.rs
60
src/walk.rs
|
@ -15,8 +15,9 @@ use crate::output;
|
|||
use std::borrow::Cow;
|
||||
use std::error::Error;
|
||||
use std::ffi::OsStr;
|
||||
use std::fs::{FileType, Metadata};
|
||||
use std::io;
|
||||
use std::path::PathBuf;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::mpsc::{channel, Receiver, Sender};
|
||||
|
@ -253,6 +254,36 @@ fn spawn_receiver(
|
|||
})
|
||||
}
|
||||
|
||||
pub enum DirEntry {
|
||||
Normal(ignore::DirEntry),
|
||||
BrokenSymlink(PathBuf),
|
||||
}
|
||||
|
||||
impl DirEntry {
|
||||
pub fn path(&self) -> &Path {
|
||||
match self {
|
||||
DirEntry::Normal(e) => e.path(),
|
||||
DirEntry::BrokenSymlink(pathbuf) => pathbuf.as_path(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn file_type(&self) -> Option<FileType> {
|
||||
match self {
|
||||
DirEntry::Normal(e) => e.file_type(),
|
||||
DirEntry::BrokenSymlink(pathbuf) => {
|
||||
pathbuf.symlink_metadata().map(|m| m.file_type()).ok()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn metadata(&self) -> Option<Metadata> {
|
||||
match self {
|
||||
DirEntry::Normal(e) => e.metadata().ok(),
|
||||
DirEntry::BrokenSymlink(_) => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn spawn_senders(
|
||||
config: &Arc<FdOptions>,
|
||||
wants_to_quit: &Arc<AtomicBool>,
|
||||
|
@ -272,17 +303,34 @@ fn spawn_senders(
|
|||
}
|
||||
|
||||
let entry = match entry_o {
|
||||
Ok(e) => e,
|
||||
Ok(e) if e.depth() == 0 => {
|
||||
// Skip the root directory entry.
|
||||
return ignore::WalkState::Continue;
|
||||
}
|
||||
Ok(e) => DirEntry::Normal(e),
|
||||
Err(ignore::Error::WithPath {
|
||||
path,
|
||||
err: inner_err,
|
||||
}) => match inner_err.as_ref() {
|
||||
ignore::Error::Io(io_error) if io_error.kind() == io::ErrorKind::NotFound => {
|
||||
DirEntry::BrokenSymlink(path.to_owned())
|
||||
}
|
||||
_ => {
|
||||
tx_thread
|
||||
.send(WorkerResult::Error(ignore::Error::WithPath {
|
||||
path,
|
||||
err: inner_err,
|
||||
}))
|
||||
.unwrap();
|
||||
return ignore::WalkState::Continue;
|
||||
}
|
||||
},
|
||||
Err(err) => {
|
||||
tx_thread.send(WorkerResult::Error(err)).unwrap();
|
||||
return ignore::WalkState::Continue;
|
||||
}
|
||||
};
|
||||
|
||||
if entry.depth() == 0 {
|
||||
return ignore::WalkState::Continue;
|
||||
}
|
||||
|
||||
// Check the name first, since it doesn't require metadata
|
||||
let entry_path = entry.path();
|
||||
|
||||
|
|
Loading…
Reference in a new issue