use std::path::Path;
const ILLEGAL: &[char] = &['"', '*', ':', '<', '>', '?', '|', '\\'];
fn bad_component(comp: &str, strict: bool) -> bool {
comp.chars().any(|c| c.is_control())
|| (strict
&& (comp.chars().any(|c| ILLEGAL.contains(&c)) || comp.ends_with([' ', '.'])))
}
pub fn unportable(path: &str, strict: bool) -> bool {
path.split('/').any(|c| bad_component(c, strict))
}
pub fn display(path: &str) -> String {
path.chars()
.map(|c| match c {
'\n' => "⏎".to_string(),
'\t' => "⇥".to_string(),
'\r' => "␍".to_string(),
c if c.is_control() => format!("\\u{{{:x}}}", c as u32),
c => c.to_string(),
})
.collect()
}
pub fn sanitize(path: &str, strict: bool) -> String {
path.split('/')
.map(|comp| {
let mut s: String = comp
.chars()
.filter(|c| !c.is_control())
.map(|c| if strict && ILLEGAL.contains(&c) { '_' } else { c })
.collect();
if strict {
while s.ends_with([' ', '.']) {
s.pop();
}
}
let s = s.trim().to_string();
if s.is_empty() { "_".to_string() } else { s }
})
.collect::<Vec<_>>()
.join("/")
}
pub fn probe_restrictive(root: &Path) -> bool {
let dir = root.join(".stowe");
if std::fs::create_dir_all(&dir).is_err() {
return true;
}
let probe = dir.join(".probe:*?");
match std::fs::write(&probe, b"") {
Ok(()) => {
let _ = std::fs::remove_file(&probe);
false
}
Err(_) => true,
}
}