diff options
-rw-r--r-- | Cargo.lock | 67 | ||||
-rw-r--r-- | Cargo.toml | 1 | ||||
-rw-r--r-- | ignore/Cargo.toml | 2 | ||||
-rw-r--r-- | ignore/src/walk.rs | 71 | ||||
-rw-r--r-- | src/args.rs | 36 | ||||
-rw-r--r-- | src/atty.rs | 53 | ||||
-rw-r--r-- | src/main.rs | 80 |
7 files changed, 241 insertions, 69 deletions
@@ -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" @@ -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. \ |