#![cfg(feature = "virtual-path")]
use strict_path::{VirtualPath, VirtualRoot};
#[derive(Clone, Copy)]
struct UserSpace;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let tmp = tempfile::tempdir()?;
let user_id = "user_42";
let user_dir = tmp.path().join(user_id);
let vroot: VirtualRoot<UserSpace> = VirtualRoot::try_new_create(&user_dir)?;
let doc: VirtualPath<UserSpace> = vroot.virtual_join("docs/welcome.txt")?;
doc.create_parent_dir_all()?;
doc.write("hello, virtual user space\n")?;
let body = doc.read_to_string()?;
let display = doc.virtualpath_display();
println!("user_id={user_id}, path={}, bytes={} ", display, body.len());
let docs_dir: VirtualPath<UserSpace> = vroot.virtual_join("docs")?;
if docs_dir.exists() && docs_dir.is_dir() {
let mut names = Vec::new();
for entry in docs_dir.virtual_read_dir()? {
let child = entry?;
names.push(child.virtualpath_display().to_string());
}
names.sort();
println!("docs: {}", names.join(", "));
}
println!("\nValidating untrusted upload filenames (HTTP request / form field):");
let upload_requests: &[&str] = &[
"notes/meeting.txt",
"../../etc/shadow", "../other_user/secret.txt", "reports/2024/q4.csv", ];
for uploaded_filename in upload_requests {
match vroot.virtual_join(uploaded_filename) {
Ok(safe_upload_path) => {
safe_upload_path.create_parent_dir_all()?;
safe_upload_path.write(b"file content")?;
println!(
" OK '{}' -> {}",
uploaded_filename,
safe_upload_path.virtualpath_display()
);
}
Err(e) => {
println!(" ERROR '{}': {e}", uploaded_filename);
}
}
}
Ok(())
}
#[cfg(not(feature = "virtual-path"))]
fn main() {
eprintln!("This example requires the 'virtual-path' feature.");
eprintln!("Run with: cargo run --example user_virtual_root --features virtual-path");
}