This is why I was so intent on clearing the PR queue. This will effectively invalidate all existing patches, so I wanted to start from a clean slate. We do make one little tweak: we put the default type definitions in their own file and tell rustfmt to keep its grubby mits off of it. We also sort it lexicographically and hopefully will enforce that from here on.
143 lines
4.2 KiB
Rust
143 lines
4.2 KiB
Rust
use std::ffi::OsStr;
|
|
use std::path::Path;
|
|
|
|
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(dent: &DirEntry) -> bool {
|
|
use std::os::unix::ffi::OsStrExt;
|
|
|
|
if let Some(name) = file_name(dent.path()) {
|
|
name.as_bytes().get(0) == Some(&b'.')
|
|
} else {
|
|
false
|
|
}
|
|
}
|
|
|
|
/// 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
|
|
}
|
|
}
|
|
|
|
/// Strip `prefix` from the `path` and return the remainder.
|
|
///
|
|
/// If `path` doesn't have a prefix `prefix`, then return `None`.
|
|
#[cfg(unix)]
|
|
pub fn strip_prefix<'a, P: AsRef<Path> + ?Sized>(
|
|
prefix: &'a P,
|
|
path: &'a Path,
|
|
) -> Option<&'a Path> {
|
|
use std::os::unix::ffi::OsStrExt;
|
|
|
|
let prefix = prefix.as_ref().as_os_str().as_bytes();
|
|
let path = path.as_os_str().as_bytes();
|
|
if prefix.len() > path.len() || prefix != &path[0..prefix.len()] {
|
|
None
|
|
} else {
|
|
Some(&Path::new(OsStr::from_bytes(&path[prefix.len()..])))
|
|
}
|
|
}
|
|
|
|
/// Strip `prefix` from the `path` and return the remainder.
|
|
///
|
|
/// If `path` doesn't have a prefix `prefix`, then return `None`.
|
|
#[cfg(not(unix))]
|
|
pub fn strip_prefix<'a, P: AsRef<Path> + ?Sized>(
|
|
prefix: &'a P,
|
|
path: &'a Path,
|
|
) -> Option<&'a Path> {
|
|
path.strip_prefix(prefix).ok()
|
|
}
|
|
|
|
/// Returns true if this file path is just a file name. i.e., Its parent is
|
|
/// the empty string.
|
|
#[cfg(unix)]
|
|
pub fn is_file_name<P: AsRef<Path>>(path: P) -> bool {
|
|
use memchr::memchr;
|
|
use std::os::unix::ffi::OsStrExt;
|
|
|
|
let path = path.as_ref().as_os_str().as_bytes();
|
|
memchr(b'/', path).is_none()
|
|
}
|
|
|
|
/// Returns true if this file path is just a file name. i.e., Its parent is
|
|
/// the empty string.
|
|
#[cfg(not(unix))]
|
|
pub fn is_file_name<P: AsRef<Path>>(path: P) -> bool {
|
|
path.as_ref().parent().map(|p| p.as_os_str().is_empty()).unwrap_or(false)
|
|
}
|
|
|
|
/// The final component of the path, if it is a normal file.
|
|
///
|
|
/// If the path terminates in ., .., or consists solely of a root of prefix,
|
|
/// file_name will return None.
|
|
#[cfg(unix)]
|
|
pub fn file_name<'a, P: AsRef<Path> + ?Sized>(
|
|
path: &'a P,
|
|
) -> Option<&'a OsStr> {
|
|
use memchr::memrchr;
|
|
use std::os::unix::ffi::OsStrExt;
|
|
|
|
let path = path.as_ref().as_os_str().as_bytes();
|
|
if path.is_empty() {
|
|
return None;
|
|
} else if path.len() == 1 && path[0] == b'.' {
|
|
return None;
|
|
} else if path.last() == Some(&b'.') {
|
|
return None;
|
|
} else if path.len() >= 2 && &path[path.len() - 2..] == &b".."[..] {
|
|
return None;
|
|
}
|
|
let last_slash = memrchr(b'/', path).map(|i| i + 1).unwrap_or(0);
|
|
Some(OsStr::from_bytes(&path[last_slash..]))
|
|
}
|
|
|
|
/// The final component of the path, if it is a normal file.
|
|
///
|
|
/// If the path terminates in ., .., or consists solely of a root of prefix,
|
|
/// file_name will return None.
|
|
#[cfg(not(unix))]
|
|
pub fn file_name<'a, P: AsRef<Path> + ?Sized>(
|
|
path: &'a P,
|
|
) -> Option<&'a OsStr> {
|
|
path.as_ref().file_name()
|
|
}
|