mirror of
https://github.com/BurntSushi/ripgrep.git
synced 2025-05-19 09:40:22 -07:00
ignore: treat symbolic links to directories as directories
Due to how walkdir works if symlinks are not followed, symlinks to directories are seen as simple files by ripgrep. This caused a panic in some cases due to receiving a WalkEvent::Exit event without a corresponding WalkEvent::Dir event. This is fixed by looking at the metadata of the file in the case of a symlink to determine if it's a directory. We are careful to only do this stat check when the depth of the entry is 0, as this bug only impacts us when 1) we aren't following symlinks generally and 2) the user provides a symlinked directory that we do follow as a top-level path to search. Fixes #1389, Closes #1397
This commit is contained in:
parent
75cbe88fa2
commit
52d7f47420
@ -49,6 +49,8 @@ Bug fixes:
|
|||||||
This was a serious performance regression in some cases.
|
This was a serious performance regression in some cases.
|
||||||
* [BUG #1344](https://github.com/BurntSushi/ripgrep/issues/1344):
|
* [BUG #1344](https://github.com/BurntSushi/ripgrep/issues/1344):
|
||||||
Document usage of `--type all`.
|
Document usage of `--type all`.
|
||||||
|
* [BUG #1389](https://github.com/BurntSushi/ripgrep/issues/1389):
|
||||||
|
Fixes a bug where ripgrep would panic when searching a symlinked directory.
|
||||||
* [BUG #1445](https://github.com/BurntSushi/ripgrep/issues/1445):
|
* [BUG #1445](https://github.com/BurntSushi/ripgrep/issues/1445):
|
||||||
ripgrep now respects ignore rules from .git/info/exclude in worktrees.
|
ripgrep now respects ignore rules from .git/info/exclude in worktrees.
|
||||||
* [BUG #1485](https://github.com/BurntSushi/ripgrep/issues/1485):
|
* [BUG #1485](https://github.com/BurntSushi/ripgrep/issues/1485):
|
||||||
|
@ -1043,7 +1043,7 @@ impl Iterator for WalkEventIter {
|
|||||||
None => None,
|
None => None,
|
||||||
Some(Err(err)) => Some(Err(err)),
|
Some(Err(err)) => Some(Err(err)),
|
||||||
Some(Ok(dent)) => {
|
Some(Ok(dent)) => {
|
||||||
if dent.file_type().is_dir() {
|
if walkdir_is_dir(&dent) {
|
||||||
self.depth += 1;
|
self.depth += 1;
|
||||||
Some(Ok(WalkEvent::Dir(dent)))
|
Some(Ok(WalkEvent::Dir(dent)))
|
||||||
} else {
|
} else {
|
||||||
@ -1791,6 +1791,24 @@ fn path_equals(dent: &DirEntry, handle: &Handle) -> Result<bool, Error> {
|
|||||||
.map_err(|err| Error::Io(err).with_path(dent.path()))
|
.map_err(|err| Error::Io(err).with_path(dent.path()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns true if the given walkdir entry corresponds to a directory.
|
||||||
|
///
|
||||||
|
/// This is normally just `dent.file_type().is_dir()`, but when we aren't
|
||||||
|
/// following symlinks, the root directory entry may be a symlink to a
|
||||||
|
/// directory that we *do* follow---by virtue of it being specified by the user
|
||||||
|
/// explicitly. In that case, we need to follow the symlink and query whether
|
||||||
|
/// it's a directory or not. But we only do this for root entries to avoid an
|
||||||
|
/// additional stat check in most cases.
|
||||||
|
fn walkdir_is_dir(dent: &walkdir::DirEntry) -> bool {
|
||||||
|
if dent.file_type().is_dir() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if !dent.file_type().is_symlink() || dent.depth() > 0 {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
dent.path().metadata().ok().map_or(false, |md| md.file_type().is_dir())
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns true if and only if the given path is on the same device as the
|
/// Returns true if and only if the given path is on the same device as the
|
||||||
/// given root device.
|
/// given root device.
|
||||||
fn is_same_file_system(root_device: u64, path: &Path) -> Result<bool, Error> {
|
fn is_same_file_system(root_device: u64, path: &Path) -> Result<bool, Error> {
|
||||||
|
@ -747,6 +747,21 @@ rgtest!(r1334_crazy_literals, |dir: Dir, mut cmd: TestCommand| {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// See: https://github.com/BurntSushi/ripgrep/issues/1389
|
||||||
|
rgtest!(r1389_bad_symlinks_no_biscuit, |dir: Dir, mut cmd: TestCommand| {
|
||||||
|
dir.create_dir("mydir");
|
||||||
|
dir.create("mydir/file.txt", "test");
|
||||||
|
dir.link_dir("mydir", "mylink");
|
||||||
|
|
||||||
|
let stdout = cmd.args(&[
|
||||||
|
"test",
|
||||||
|
"--no-ignore",
|
||||||
|
"--sort", "path",
|
||||||
|
"mylink",
|
||||||
|
]).stdout();
|
||||||
|
eqnice!("mylink/file.txt:test\n", stdout);
|
||||||
|
});
|
||||||
|
|
||||||
// See: https://github.com/BurntSushi/ripgrep/pull/1446
|
// See: https://github.com/BurntSushi/ripgrep/pull/1446
|
||||||
rgtest!(r1446_respect_excludes_in_worktree, |dir: Dir, mut cmd: TestCommand| {
|
rgtest!(r1446_respect_excludes_in_worktree, |dir: Dir, mut cmd: TestCommand| {
|
||||||
dir.create_dir("repo/.git/info");
|
dir.create_dir("repo/.git/info");
|
||||||
|
Loading…
x
Reference in New Issue
Block a user