blob: 144073003d66c03ffba116909235deb03caa8010 [file] [log] [blame]
//! Path validation for the purpose of the [`fs`] module. This is decoupled from
//! [`Path`] and [`PathBuf`], as the Rust standard library also does it this
//! way. Instead, the FS implementation is responsible for that.
//!
//! [`PathBuf`]: super::PathBuf
//! [`fs`]: crate::fs
use super::Path;
use crate::fs::CHARACTER_DENY_LIST;
use crate::Char16;
use core::fmt::{self, Display, Formatter};
/// Errors related to file paths.
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum PathError {
/// The path is empty / points to nothing.
Empty,
/// A component of the path is empty, i.e., two separators without content
/// in between were found.
EmptyComponent,
/// There are illegal characters in the path.
IllegalChar(Char16),
}
impl Display for PathError {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
Self::Empty => write!(f, "path is empty"),
Self::EmptyComponent => write!(f, "path contains an empty component"),
Self::IllegalChar(c) => {
write!(
f,
"path contains an illegal character (value {})",
u16::from(*c)
)
}
}
}
}
#[cfg(feature = "unstable")]
impl core::error::Error for PathError {}
/// Validates a path for the needs of the [`fs`] module.
///
/// [`fs`]: crate::fs
pub fn validate_path<P: AsRef<Path>>(path: P) -> Result<(), PathError> {
let path = path.as_ref();
if path.is_empty() {
return Err(PathError::Empty);
}
for component in path.components() {
if component.is_empty() {
return Err(PathError::EmptyComponent);
} else if let Some(char) = component
.as_slice()
.iter()
.find(|c| CHARACTER_DENY_LIST.contains(c))
{
return Err(PathError::IllegalChar(*char));
}
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
use crate::fs::PathBuf;
use crate::{cstr16, CString16};
#[test]
fn test_validate_path() {
validate_path(cstr16!("hello\\foo\\bar")).unwrap();
let err = validate_path(cstr16!("hello\\f>oo\\bar")).unwrap_err();
assert_eq!(err, PathError::IllegalChar(CHARACTER_DENY_LIST[6]));
let err = validate_path(cstr16!("hello\\\\bar")).unwrap_err();
assert_eq!(err, PathError::EmptyComponent);
let empty_cstring16 = CString16::try_from("").unwrap();
let path = PathBuf::from(empty_cstring16);
let err = validate_path(path).unwrap_err();
assert_eq!(err, PathError::Empty)
}
}