diff options
Diffstat (limited to 'ignore/src/pathutil.rs')
-rw-r--r-- | ignore/src/pathutil.rs | 48 |
1 files changed, 41 insertions, 7 deletions
diff --git a/ignore/src/pathutil.rs b/ignore/src/pathutil.rs index bfd43de3..fbbc0f89 100644 --- a/ignore/src/pathutil.rs +++ b/ignore/src/pathutil.rs @@ -1,22 +1,56 @@ use std::ffi::OsStr; use std::path::Path; -/// Returns true if and only if this file path is considered to be hidden. +use walk::DirEntry; + +/// Returns true if and only if this entry is considered to be hidden. +/// +/// This only returns true if the base name of the path starts with a `.`. +/// +/// On Unix, this implements a more optimized check. #[cfg(unix)] -pub fn is_hidden<P: AsRef<Path>>(path: P) -> bool { +pub fn is_hidden(dent: &DirEntry) -> bool { use std::os::unix::ffi::OsStrExt; - if let Some(name) = file_name(path.as_ref()) { + if let Some(name) = file_name(dent.path()) { name.as_bytes().get(0) == Some(&b'.') } else { false } } -/// Returns true if and only if this file path is considered to be hidden. -#[cfg(not(unix))] -pub fn is_hidden<P: AsRef<Path>>(path: P) -> bool { - if let Some(name) = file_name(path.as_ref()) { +/// Returns true if and only if this entry is considered to be hidden. +/// +/// On Windows, this returns true if one of the following is true: +/// +/// * The base name of the path starts with a `.`. +/// * The file attributes have the `HIDDEN` property set. +#[cfg(windows)] +pub fn is_hidden(dent: &DirEntry) -> bool { + use std::os::windows::fs::MetadataExt; + use winapi_util::file; + + // This looks like we're doing an extra stat call, but on Windows, the + // directory traverser reuses the metadata retrieved from each directory + // entry and stores it on the DirEntry itself. So this is "free." + if let Ok(md) = dent.metadata() { + if file::is_hidden(md.file_attributes() as u64) { + return true; + } + } + if let Some(name) = file_name(dent.path()) { + name.to_str().map(|s| s.starts_with(".")).unwrap_or(false) + } else { + false + } +} + +/// Returns true if and only if this entry is considered to be hidden. +/// +/// This only returns true if the base name of the path starts with a `.`. +#[cfg(not(any(unix, windows)))] +pub fn is_hidden(dent: &DirEntry) -> bool { + if let Some(name) = file_name(dent.path()) { name.to_str().map(|s| s.starts_with(".")).unwrap_or(false) } else { false |