summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock67
-rw-r--r--Cargo.toml1
-rw-r--r--ignore/Cargo.toml2
-rw-r--r--ignore/src/walk.rs71
-rw-r--r--src/args.rs36
-rw-r--r--src/atty.rs53
-rw-r--r--src/main.rs80
7 files changed, 241 insertions, 69 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 3fcef67f..d3e9bcf5 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2,19 +2,20 @@
name = "ripgrep"
version = "0.3.2"
dependencies = [
- "bytecount 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bytecount 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"clap 2.19.3 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
"grep 0.1.4",
"ignore 0.1.6",
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "memchr 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"memmap 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "num_cpus 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num_cpus 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "same-file 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"termcolor 0.1.1",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -24,7 +25,7 @@ name = "aho-corasick"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "memchr 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -39,7 +40,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "bytecount"
-version = "0.1.4"
+version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"simd 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -52,7 +53,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)",
"strsim 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
"term_size 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-segmentation 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -84,7 +85,7 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -96,7 +97,7 @@ dependencies = [
"fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "memchr 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -105,7 +106,7 @@ name = "grep"
version = "0.1.4"
dependencies = [
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "memchr 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"regex-syntax 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -118,10 +119,10 @@ dependencies = [
"globset 0.1.2",
"lazy_static 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "memchr 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"thread_local 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "walkdir 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -140,7 +141,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "libc"
-version = "0.2.18"
+version = "0.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@@ -150,10 +151,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "memchr"
-version = "1.0.0"
+version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "libc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -163,16 +164,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"fs2 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num_cpus"
-version = "1.2.0"
+version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "libc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -181,7 +182,7 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"aho-corasick 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "memchr 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"regex-syntax 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"simd 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"thread_local 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -194,6 +195,16 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
+name = "same-file"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "simd"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -209,7 +220,7 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -226,7 +237,7 @@ version = "3.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -273,10 +284,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "walkdir"
-version = "1.0.3"
+version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "same-file 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -302,7 +314,7 @@ dependencies = [
"checksum aho-corasick 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4f660b942762979b56c9f07b4b36bb559776fbad102f05d6771e1b629e8fd5bf"
"checksum ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "23ac7c30002a5accbf7e8987d0632fa6de155b7c3d39d0067317a391e00a2ef6"
"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d"
-"checksum bytecount 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49e3c21915578e2300b08d3c174a8ac887e0c6421dff86fdc4d741dc29e5d413"
+"checksum bytecount 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "289e7bdb4fb98f273dd0628a8be7ffe76aa9b944464f074b9c4f82000a580aed"
"checksum clap 2.19.3 (registry+https://github.com/rust-lang/crates.io-index)" = "95b78f3fe0fc94c13c731714363260e04b557a637166f33a4570d3189d642374"
"checksum crossbeam 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "0c5ea215664ca264da8a9d9c3be80d2eaf30923c259d03e870388eb927508f97"
"checksum env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "15abd780e45b3ea4f76b4e9a26ff4843258dd8a3eed2775a0e7368c2e7936c2f"
@@ -310,13 +322,14 @@ dependencies = [
"checksum fs2 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "640001e1bd865c7c32806292822445af576a6866175b5225aa2087ca5e3de551"
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
"checksum lazy_static 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6abe0ee2e758cd6bc8a2cd56726359007748fbf4128da998b65d0b70f881e19b"
-"checksum libc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "a51822fc847e7a8101514d1d44e354ba2ffa7d4c194dcab48870740e327cac70"
+"checksum libc 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)" = "9e030dc72013ed68994d1b2cbf36a94dd0e58418ba949c4b0db7eeb70a7a6352"
"checksum log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ab83497bf8bf4ed2a74259c1c802351fcd67a65baa86394b6ba73c36f4838054"
-"checksum memchr 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7492849298f0731c393b1f34ce03a7c84c00bead2e7057db9342907c8fdcae28"
+"checksum memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1dbccc0e46f1ea47b9f17e6d67c5a96bd27030519c519c9c91327e31275a47b4"
"checksum memmap 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "065ce59af31c18ea2c419100bda6247dd4ec3099423202b12f0bd32e529fabd2"
-"checksum num_cpus 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "55aabf4e2d6271a2e4e4c0f2ea1f5b07cc589cc1a9e9213013b54a76678ca4f3"
+"checksum num_cpus 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a225d1e2717567599c24f88e49f00856c6e825a12125181ee42c4257e3688d39"
"checksum regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4278c17d0f6d62dfef0ab00028feb45bd7d2102843f80763474eeb1be8a10c01"
"checksum regex-syntax 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9191b1f57603095f105d317e375d19b1c9c5c3185ea9633a99a6dcbed04457"
+"checksum same-file 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05f5dc7680f4bdc74fa0df5f32fcbaf1174a92e65bf3d69e0288248604306875"
"checksum simd 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "63b5847c2d766ca7ce7227672850955802fabd779ba616aeabead4c2c3877023"
"checksum strsim 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "67f84c44fbb2f91db7fef94554e6b2ac05909c9c0b0bc23bb98d3a1aebfe7f7c"
"checksum term_size 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3f7f5f3f71b0040cecc71af239414c23fd3c73570f5ff54cf50e03cef637f2a0"
@@ -328,6 +341,6 @@ dependencies = [
"checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122"
"checksum vec_map 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cac5efe5cb0fa14ec2f84f83c701c562ee63f6dcc680861b21d65c682adfb05f"
"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
-"checksum walkdir 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "dd7c16466ecc507c7cb5988db03e6eab4aaeab89a5c37a29251fcfd3ac9b7afe"
+"checksum walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "bb08f9e670fab86099470b97cd2b252d6527f0b3cc1401acdb595ffc9dd288ff"
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
diff --git a/Cargo.toml b/Cargo.toml
index ce497a11..d671cbba 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -37,6 +37,7 @@ memchr = "1"
memmap = "0.5"
num_cpus = "1"
regex = "0.2.0"
+same-file = "0.1.1"
termcolor = { version = "0.1.0", path = "termcolor" }
[target.'cfg(windows)'.dependencies]
diff --git a/ignore/Cargo.toml b/ignore/Cargo.toml
index dc903783..238fe44e 100644
--- a/ignore/Cargo.toml
+++ b/ignore/Cargo.toml
@@ -25,7 +25,7 @@ log = "0.3"
memchr = "1"
regex = "0.2.0"
thread_local = "0.3.2"
-walkdir = "1"
+walkdir = "1.0.7"
[dev-dependencies]
tempdir = "0.3.5"
diff --git a/ignore/src/walk.rs b/ignore/src/walk.rs
index e1dd2052..860f26d8 100644
--- a/ignore/src/walk.rs
+++ b/ignore/src/walk.rs
@@ -72,6 +72,14 @@ impl DirEntry {
self.dent.depth()
}
+ /// Returns the underlying inode number if one exists.
+ ///
+ /// If this entry doesn't have an inode number, then `None` is returned.
+ #[cfg(unix)]
+ pub fn ino(&self) -> Option<u64> {
+ self.dent.ino()
+ }
+
/// Returns an error, if one exists, associated with processing this entry.
///
/// An example of an error is one that occurred while parsing an ignore
@@ -188,6 +196,16 @@ impl DirEntryInner {
Raw(ref x) => x.depth(),
}
}
+
+ #[cfg(unix)]
+ fn ino(&self) -> Option<u64> {
+ use self::DirEntryInner::*;
+ match *self {
+ Stdin => None,
+ Walkdir(ref x) => Some(x.ino()),
+ Raw(ref x) => Some(x.ino()),
+ }
+ }
}
/// DirEntryRaw is essentially copied from the walkdir crate so that we can
@@ -203,6 +221,9 @@ struct DirEntryRaw {
follow_link: bool,
/// The depth at which this entry was generated relative to the root.
depth: usize,
+ /// The underlying inode number (Unix only).
+ #[cfg(unix)]
+ ino: u64,
}
impl fmt::Debug for DirEntryRaw {
@@ -247,6 +268,11 @@ impl DirEntryRaw {
self.depth
}
+ #[cfg(unix)]
+ fn ino(&self) -> u64 {
+ self.ino
+ }
+
fn from_entry(
depth: usize,
ent: &fs::DirEntry,
@@ -258,15 +284,57 @@ impl DirEntryRaw {
err: Box::new(err),
}
}));
- Ok(DirEntryRaw {
+ Ok(DirEntryRaw::from_entry_os(depth, ent, ty))
+ }
+
+ #[cfg(not(unix))]
+ fn from_entry_os(
+ depth: usize,
+ ent: &fs::DirEntry,
+ ty: fs::FileType,
+ ) -> DirEntryRaw {
+ DirEntryRaw {
path: ent.path(),
ty: ty,
follow_link: false,
depth: depth,
+ }
+ }
+
+ #[cfg(unix)]
+ fn from_entry_os(
+ depth: usize,
+ ent: &fs::DirEntry,
+ ty: fs::FileType,
+ ) -> DirEntryRaw {
+ use std::os::unix::fs::DirEntryExt;
+
+ DirEntryRaw {
+ path: ent.path(),
+ ty: ty,
+ follow_link: false,
+ depth: depth,
+ ino: ent.ino(),
+ }
+ }
+
+ #[cfg(not(unix))]
+ fn from_link(depth: usize, pb: PathBuf) -> Result<DirEntryRaw, Error> {
+ let md = try!(fs::metadata(&pb).map_err(|err| {
+ Error::Io(err).with_path(&pb)
+ }));
+ Ok(DirEntryRaw {
+ path: pb,
+ ty: md.file_type(),
+ follow_link: true,
+ depth: depth,
})
}
+ #[cfg(unix)]
fn from_link(depth: usize, pb: PathBuf) -> Result<DirEntryRaw, Error> {
+ use std::os::unix::fs::MetadataExt;
+
let md = try!(fs::metadata(&pb).map_err(|err| {
Error::Io(err).with_path(&pb)
}));
@@ -275,6 +343,7 @@ impl DirEntryRaw {
ty: md.file_type(),
follow_link: true,
depth: depth,
+ ino: md.ino(),
})
}
}
diff --git a/src/args.rs b/src/args.rs
index 6aec396b..29a7fa81 100644
--- a/src/args.rs
+++ b/src/args.rs
@@ -15,6 +15,7 @@ use grep::{Grep, GrepBuilder};
use log;
use num_cpus;
use regex;
+use same_file;
use termcolor;
use app;
@@ -65,6 +66,7 @@ pub struct Args {
quiet_matched: QuietMatched,
replace: Option<Vec<u8>>,
sort_files: bool,
+ stdout_handle: Option<same_file::Handle>,
text: bool,
threads: usize,
type_list: bool,
@@ -182,6 +184,17 @@ impl Args {
termcolor::Stdout::new(self.color_choice)
}
+ /// Returns a handle to stdout for filtering search.
+ ///
+ /// A handle is returned if and only if ripgrep's stdout is being
+ /// redirected to a file. The handle returned corresponds to that file.
+ ///
+ /// This can be used to ensure that we do not attempt to search a file
+ /// that ripgrep is writing to.
+ pub fn stdout_handle(&self) -> Option<&same_file::Handle> {
+ self.stdout_handle.as_ref()
+ }
+
/// Create a new buffer writer for multi-threaded searching with color
/// support.
pub fn buffer_writer(&self) -> termcolor::BufferWriter {
@@ -338,6 +351,7 @@ impl<'a> ArgMatches<'a> {
quiet_matched: QuietMatched::new(quiet),
replace: self.replace(),
sort_files: self.is_present("sort-files"),
+ stdout_handle: self.stdout_handle(),
text: self.text(),
threads: try!(self.threads()),
type_list: self.is_present("type-list"),
@@ -518,6 +532,28 @@ impl<'a> ArgMatches<'a> {
}
}
+ /// Returns a handle to stdout for filtering search.
+ ///
+ /// A handle is returned if and only if ripgrep's stdout is being
+ /// redirected to a file. The handle returned corresponds to that file.
+ ///
+ /// This can be used to ensure that we do not attempt to search a file
+ /// that ripgrep is writing to.
+ fn stdout_handle(&self) -> Option<same_file::Handle> {
+ let h = match same_file::Handle::stdout() {
+ Err(_) => return None,
+ Ok(h) => h,
+ };
+ let md = match h.as_file().metadata() {
+ Err(_) => return None,
+ Ok(md) => md,
+ };
+ if !md.is_file() {
+ return None;
+ }
+ Some(h)
+ }
+
/// Returns true if and only if memory map searching should be tried.
///
/// `paths` should be a slice of all top-level file paths that ripgrep
diff --git a/src/atty.rs b/src/atty.rs
index 9e96fe6e..cb10c1dc 100644
--- a/src/atty.rs
+++ b/src/atty.rs
@@ -11,15 +11,10 @@ use winapi::winnt::HANDLE;
#[cfg(unix)]
pub fn stdin_is_readable() -> bool {
- use std::fs::File;
use std::os::unix::fs::FileTypeExt;
- use std::os::unix::io::{FromRawFd, IntoRawFd};
- use libc;
+ use same_file::Handle;
- let file = unsafe { File::from_raw_fd(libc::STDIN_FILENO) };
- let md = file.metadata();
- let _ = file.into_raw_fd();
- let ft = match md {
+ let ft = match Handle::stdin().and_then(|h| h.as_file().metadata()) {
Err(_) => return false,
Ok(md) => md.file_type(),
};
@@ -101,7 +96,7 @@ pub fn on_stdout() -> bool {
/// Returns true if there is an MSYS tty on the given handle.
#[cfg(windows)]
-fn msys_tty_on_handle(handle: HANDLE) -> bool {
+unsafe fn msys_tty_on_handle(handle: HANDLE) -> bool {
use std::ffi::OsString;
use std::mem;
use std::os::raw::c_void;
@@ -113,27 +108,25 @@ fn msys_tty_on_handle(handle: HANDLE) -> bool {
use winapi::minwinbase::FileNameInfo;
use winapi::minwindef::MAX_PATH;
- unsafe {
- let size = mem::size_of::<FILE_NAME_INFO>();
- let mut name_info_bytes = vec![0u8; size + MAX_PATH];
- let res = GetFileInformationByHandleEx(
- handle,
- FileNameInfo,
- &mut *name_info_bytes as *mut _ as *mut c_void,
- name_info_bytes.len() as u32);
- if res == 0 {
- return true;
- }
- let name_info: FILE_NAME_INFO =
- *(name_info_bytes[0..size].as_ptr() as *const FILE_NAME_INFO);
- let name_bytes =
- &name_info_bytes[size..size + name_info.FileNameLength as usize];
- let name_u16 = slice::from_raw_parts(
- name_bytes.as_ptr() as *const u16, name_bytes.len() / 2);
- let name = OsString::from_wide(name_u16)
- .as_os_str().to_string_lossy().into_owned();
- name.contains("msys-") || name.contains("-pty")
+ let size = mem::size_of::<FILE_NAME_INFO>();
+ let mut name_info_bytes = vec![0u8; size + MAX_PATH];
+ let res = GetFileInformationByHandleEx(
+ handle,
+ FileNameInfo,
+ &mut *name_info_bytes as *mut _ as *mut c_void,
+ name_info_bytes.len() as u32);
+ if res == 0 {
+ return true;
}
+ let name_info: FILE_NAME_INFO =
+ *(name_info_bytes[0..size].as_ptr() as *const FILE_NAME_INFO);
+ let name_bytes =
+ &name_info_bytes[size..size + name_info.FileNameLength as usize];
+ let name_u16 = slice::from_raw_parts(
+ name_bytes.as_ptr() as *const u16, name_bytes.len() / 2);
+ let name = OsString::from_wide(name_u16)
+ .as_os_str().to_string_lossy().into_owned();
+ name.contains("msys-") || name.contains("-pty")
}
/// Returns true if there is a console on the given file descriptor.
@@ -145,8 +138,8 @@ unsafe fn console_on_fd(fd: DWORD) -> bool {
/// Returns true if there is a console on the given handle.
#[cfg(windows)]
-fn console_on_handle(handle: HANDLE) -> bool {
+unsafe fn console_on_handle(handle: HANDLE) -> bool {
use kernel32::GetConsoleMode;
let mut out = 0;
- unsafe { GetConsoleMode(handle, &mut out) != 0 }
+ GetConsoleMode(handle, &mut out) != 0
}
diff --git a/src/main.rs b/src/main.rs
index 236c093e..735298f9 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -15,6 +15,7 @@ extern crate memchr;
extern crate memmap;
extern crate num_cpus;
extern crate regex;
+extern crate same_file;
extern crate termcolor;
#[cfg(windows)]
extern crate winapi;
@@ -106,7 +107,11 @@ fn run_parallel(args: Arc<Args>) -> Result<u64> {
if quiet_matched.has_match() {
return Quit;
}
- let dent = match get_or_log_dir_entry(result, args.no_messages()) {
+ let dent = match get_or_log_dir_entry(
+ result,
+ args.stdout_handle(),
+ args.no_messages(),
+ ) {
None => return Continue,
Some(dent) => dent,
};
@@ -148,7 +153,11 @@ fn run_one_thread(args: Arc<Args>) -> Result<u64> {
let mut paths_searched: u64 = 0;
let mut match_count = 0;
for result in args.walker() {
- let dent = match get_or_log_dir_entry(result, args.no_messages()) {
+ let dent = match get_or_log_dir_entry(
+ result,
+ args.stdout_handle(),
+ args.no_messages(),
+ ) {
None => continue,
Some(dent) => dent,
};
@@ -190,11 +199,15 @@ fn run_files_parallel(args: Arc<Args>) -> Result<u64> {
}
file_count
});
- let no_messages = args.no_messages();
args.walker_parallel().run(move || {
+ let args = args.clone();
let tx = tx.clone();
Box::new(move |result| {
- if let Some(dent) = get_or_log_dir_entry(result, no_messages) {
+ if let Some(dent) = get_or_log_dir_entry(
+ result,
+ args.stdout_handle(),
+ args.no_messages(),
+ ) {
tx.send(dent).unwrap();
}
ignore::WalkState::Continue
@@ -208,7 +221,11 @@ fn run_files_one_thread(args: Arc<Args>) -> Result<u64> {
let mut printer = args.printer(stdout.lock());
let mut file_count = 0;
for result in args.walker() {
- let dent = match get_or_log_dir_entry(result, args.no_messages()) {
+ let dent = match get_or_log_dir_entry(
+ result,
+ args.stdout_handle(),
+ args.no_messages(),
+ ) {
None => continue,
Some(dent) => dent,
};
@@ -231,6 +248,7 @@ fn run_types(args: Arc<Args>) -> Result<u64> {
fn get_or_log_dir_entry(
result: result::Result<ignore::DirEntry, ignore::Error>,
+ stdout_handle: Option<&same_file::Handle>,
no_messages: bool,
) -> Option<ignore::DirEntry> {
match result {
@@ -253,16 +271,58 @@ fn get_or_log_dir_entry(
// A depth of 0 means the user gave the path explicitly, so we
// should always try to search it.
if dent.depth() == 0 && !ft.is_dir() {
- Some(dent)
- } else if ft.is_file() {
- Some(dent)
- } else {
- None
+ return Some(dent);
+ } else if !ft.is_file() {
+ return None;
+ }
+ // If we are redirecting stdout to a file, then don't search that
+ // file.
+ if is_stdout_file(&dent, stdout_handle, no_messages) {
+ return None;
+ }
+ Some(dent)
+ }
+ }
+}
+
+fn is_stdout_file(
+ dent: &ignore::DirEntry,
+ stdout_handle: Option<&same_file::Handle>,
+ no_messages: bool,
+) -> bool {
+ let stdout_handle = match stdout_handle {
+ None => return false,
+ Some(stdout_handle) => stdout_handle,
+ };
+ // If we know for sure that these two things aren't equal, then avoid
+ // the costly extra stat call to determine equality.
+ if !maybe_dent_eq_handle(dent, stdout_handle) {
+ return false;
+ }
+ match same_file::Handle::from_path(dent.path()) {
+ Ok(h) => stdout_handle == &h,
+ Err(err) => {
+ if !no_messages {
+ eprintln!("{}: {}", dent.path().display(), err);
}
+ false
}
}
}
+#[cfg(unix)]
+fn maybe_dent_eq_handle(
+ dent: &ignore::DirEntry,
+ handle: &same_file::Handle,
+) -> bool {
+ dent.ino() == Some(handle.ino())
+}
+
+#[cfg(not(unix))]
+fn maybe_dent_eq_handle(_: &ignore::DirEntry, _: &same_file::Handle) -> bool {
+ true
+}
+
fn eprint_nothing_searched() {
eprintln!("No files were searched, which means ripgrep probably \
applied a filter you didn't expect. \