diff --git a/src/internal/mod.rs b/src/internal/mod.rs index 250f419..1f09b44 100644 --- a/src/internal/mod.rs +++ b/src/internal/mod.rs @@ -6,9 +6,11 @@ // notice may not be copied, modified, or distributed except // according to those terms. +use std::borrow::Cow; +use std::ffi::{OsStr, OsString}; + use regex_syntax::hir::Hir; use regex_syntax::Parser; -use std::ffi::OsString; pub use self::file_types::FileTypes; @@ -27,6 +29,22 @@ macro_rules! print_error_and_exit { }; } +#[cfg(any(unix, target_os = "redox"))] +pub fn osstr_to_bytes(input: &OsStr) -> Cow<[u8]> { + use std::os::unix::ffi::OsStrExt; + Cow::Borrowed(input.as_bytes()) +} + +#[cfg(windows)] +pub fn osstr_to_bytes(input: &OsStr) -> Cow<[u8]> { + let string = input.to_string_lossy(); + + match string { + Cow::Owned(string) => Cow::Owned(string.into_bytes()), + Cow::Borrowed(string) => Cow::Borrowed(string.as_bytes()), + } +} + /// Determine if a regex pattern contains a literal uppercase character. pub fn pattern_has_uppercase_char(pattern: &str) -> bool { Parser::new() diff --git a/src/internal/opts.rs b/src/internal/opts.rs index 9775c3b..1673129 100644 --- a/src/internal/opts.rs +++ b/src/internal/opts.rs @@ -4,7 +4,7 @@ use crate::internal::{ FileTypes, }; use lscolors::LsColors; -use regex::RegexSet; +use regex::bytes::RegexSet; use std::{path::PathBuf, sync::Arc, time::Duration}; /// Configuration options for *fd*. diff --git a/src/main.rs b/src/main.rs index eb55665..8b01327 100644 --- a/src/main.rs +++ b/src/main.rs @@ -25,7 +25,7 @@ use std::time; use atty::Stream; use lscolors::LsColors; -use regex::{RegexBuilder, RegexSetBuilder}; +use regex::bytes::{RegexBuilder, RegexSetBuilder}; use crate::exec::CommandTemplate; use crate::internal::{ diff --git a/src/walk.rs b/src/walk.rs index 72101f2..8c28189 100644 --- a/src/walk.rs +++ b/src/walk.rs @@ -9,10 +9,12 @@ use crate::exec; use crate::exit_codes::ExitCode; use crate::fshelper; -use crate::internal::{opts::FdOptions, MAX_BUFFER_LENGTH}; +use crate::internal::{opts::FdOptions, osstr_to_bytes, MAX_BUFFER_LENGTH}; use crate::output; +use std::borrow::Cow; use std::error::Error; +use std::ffi::OsStr; use std::io; use std::path::PathBuf; use std::process; @@ -24,7 +26,7 @@ use std::time; use ignore::overrides::OverrideBuilder; use ignore::{self, WalkBuilder}; -use regex::Regex; +use regex::bytes::Regex; /// The receiver thread can either be buffering results or directly streaming to the console. enum ReceiverMode { @@ -279,30 +281,34 @@ fn spawn_senders( } // Check the name first, since it doesn't require metadata - let entry_path = entry.path(); - let search_str_o = if config.search_full_path { + let search_str: Cow = if config.search_full_path { match fshelper::path_absolute_form(entry_path) { - Ok(path_abs_buf) => Some(path_abs_buf.to_string_lossy().into_owned().into()), + Ok(path_abs_buf) => Cow::Owned(path_abs_buf.as_os_str().to_os_string()), Err(_) => { print_error_and_exit!("Unable to retrieve absolute path."); } } } else { - entry_path.file_name().map(|f| f.to_string_lossy()) + match entry_path.file_name() { + Some(filename) => Cow::Borrowed(filename), + None => unreachable!( + "Encountered file system entry without a file name. This should only \ + happen for paths like 'foo/bar/..' or '/' which are not supposed to \ + appear in a file system traversal." + ), + } }; - if let Some(search_str) = search_str_o { - if !pattern.is_match(&*search_str) { - return ignore::WalkState::Continue; - } + if !pattern.is_match(&osstr_to_bytes(search_str.as_ref())) { + return ignore::WalkState::Continue; } // Filter out unwanted extensions. if let Some(ref exts_regex) = config.extensions { - if let Some(path_str) = entry_path.file_name().and_then(|s| s.to_str()) { - if !exts_regex.is_match(path_str) { + if let Some(path_str) = entry_path.file_name() { + if !exts_regex.is_match(&osstr_to_bytes(path_str)) { return ignore::WalkState::Continue; } } else { @@ -311,7 +317,6 @@ fn spawn_senders( } // Filter out unwanted file types. - if let Some(ref file_types) = config.file_types { if let Some(ref entry_type) = entry.file_type() { if (!file_types.files && entry_type.is_file())