mirror of
https://github.com/BurntSushi/ripgrep.git
synced 2024-12-12 19:18:24 +02:00
ignore: make walker visit untraversable directories
This commit fixes an inconsistency between the serial and the parallel directory walkers around visiting a directory for which the user holds insufficient permissions to descend into. The serial walker does produce a successful entry for a directory that it cannot descend into due to insufficient permissions. However, before this change that has not been the case for the parallel walker, which would produce an `Err` item not only when descending into a directory that it cannot read from but also for the directory entry itself. This change brings the behaviour of the parallel variant in line with that of the serial one. Fixes #1346, Closes #1365
This commit is contained in:
parent
b435eaafc8
commit
322fc75a3d
@ -1409,16 +1409,7 @@ impl<'s> Worker<'s> {
|
||||
return;
|
||||
}
|
||||
}
|
||||
let readdir = match work.read_dir() {
|
||||
Ok(readdir) => readdir,
|
||||
Err(err) => {
|
||||
if self.visitor.visit(Err(err)).is_quit() {
|
||||
self.quit_now();
|
||||
return;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
let descend = if let Some(root_device) = work.root_device {
|
||||
match is_same_file_system(root_device, work.dent.path()) {
|
||||
Ok(true) => true,
|
||||
@ -1435,6 +1426,13 @@ impl<'s> Worker<'s> {
|
||||
true
|
||||
};
|
||||
|
||||
// Try to read the directory first before we transfer ownership
|
||||
// to the provided closure. Do not unwrap it immediately, though,
|
||||
// as we may receive an `Err` value e.g. in the case when we do not
|
||||
// have sufficient read permissions to list the directory.
|
||||
// In that case we still want to provide the closure with a valid
|
||||
// entry before passing the error value.
|
||||
let readdir = work.read_dir();
|
||||
let depth = work.dent.depth();
|
||||
match self.visitor.visit(Ok(work.dent)) {
|
||||
WalkState::Continue => {}
|
||||
@ -1447,11 +1445,28 @@ impl<'s> Worker<'s> {
|
||||
if !descend {
|
||||
continue;
|
||||
}
|
||||
|
||||
let readdir = match readdir {
|
||||
Ok(readdir) => readdir,
|
||||
Err(err) => {
|
||||
if self.visitor.visit(Err(err)).is_quit() {
|
||||
self.quit_now();
|
||||
return;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
if self.max_depth.map_or(false, |max| depth >= max) {
|
||||
continue;
|
||||
}
|
||||
for result in readdir {
|
||||
let state = self.run_one(&work.ignore, depth + 1, work.root_device, result);
|
||||
let state = self.run_one(
|
||||
&work.ignore,
|
||||
depth + 1,
|
||||
work.root_device,
|
||||
result,
|
||||
);
|
||||
if state.is_quit() {
|
||||
self.quit_now();
|
||||
return;
|
||||
@ -2155,4 +2170,23 @@ mod tests {
|
||||
builder.follow_links(true).same_file_system(true);
|
||||
assert_paths(td.path(), &builder, &["same_file", "same_file/alink"]);
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[test]
|
||||
fn no_read_permissions() {
|
||||
let dir_path = Path::new("/root");
|
||||
|
||||
// There's no /etc/sudoers.d, skip the test.
|
||||
if !dir_path.is_dir() {
|
||||
return;
|
||||
}
|
||||
// We're the root, so the test won't check what we want it to.
|
||||
if fs::read_dir(&dir_path).is_ok() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check that we can't descend but get an entry for the parent dir.
|
||||
let builder = WalkBuilder::new(&dir_path);
|
||||
assert_paths(dir_path.parent().unwrap(), &builder, &["root"]);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user