summaryrefslogtreecommitdiffstats
path: root/ignore/src/pathutil.rs
diff options
context:
space:
mode:
Diffstat (limited to 'ignore/src/pathutil.rs')
-rw-r--r--ignore/src/pathutil.rs48
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