walk: catch ignore NotFound error in the case of a broken symlink

This commit is contained in:
Tom Milligan 2019-10-09 13:22:10 +01:00 committed by David Peter
parent 06434f229b
commit 9d73402ef2
1 changed files with 39 additions and 3 deletions

View File

@ -13,8 +13,10 @@ use crate::internal::{opts::FdOptions, osstr_to_bytes, MAX_BUFFER_LENGTH};
use crate::output;
use std::borrow::Cow;
use std::convert::TryFrom;
use std::error::Error;
use std::ffi::OsStr;
use std::fs;
use std::io;
use std::path::PathBuf;
use std::process;
@ -44,6 +46,40 @@ pub enum WorkerResult {
Error(ignore::Error),
}
/// Converts a WorkerResult to a PathBuf. This is required as in some cases,
/// the underlying `ignore` libary will return an error when we actually
/// still want to show the path.
///
/// Currently, the cases supported are:
/// - a broken symlink should still be found and the path returned
impl TryFrom<WorkerResult> for PathBuf {
type Error = ignore::Error;
fn try_from(worker_result: WorkerResult) -> Result<PathBuf, Self::Error> {
match worker_result {
WorkerResult::Entry(value) => return Ok(value),
WorkerResult::Error(err) => {
if let ignore::Error::WithPath {
path,
err: path_err,
} = &err
{
if let ignore::Error::Io(io_err) = &**path_err {
if io_err.kind() == io::ErrorKind::NotFound {
if let Ok(metadata) = fs::symlink_metadata(&path) {
if metadata.file_type().is_symlink() {
return Ok(path.to_path_buf());
}
}
}
}
}
return Err(err);
}
}
}
}
/// Recursively scan the given search path for files / pathnames matching the pattern.
///
/// If the `--exec` argument was supplied, this will create a thread pool for executing
@ -201,8 +237,8 @@ fn spawn_receiver(
let mut stdout = stdout.lock();
for worker_result in rx {
match worker_result {
WorkerResult::Entry(value) => {
match PathBuf::try_from(worker_result) {
Ok(value) => {
match mode {
ReceiverMode::Buffering => {
buffer.push(value);
@ -231,7 +267,7 @@ fn spawn_receiver(
}
}
}
WorkerResult::Error(err) => {
Err(err) => {
if show_filesystem_errors {
print_error!("{}", err);
}