use std::io;
use std::path::Path;
use std::path::PathBuf;
use normalize_path::NormalizePath;
pub struct GrassFs {
root_dir: PathBuf,
}
impl std::fmt::Debug for GrassFs {
fn fmt(
&self,
f: &mut std::fmt::Formatter<'_>,
) -> std::fmt::Result {
f.debug_tuple("GrassFs").finish()
}
}
impl GrassFs {
pub fn new(root_dir: &Path) -> Self {
Self {
root_dir: root_dir.to_path_buf(),
}
}
fn is_allowed(
&self,
path: &Path,
) -> bool {
path.normalize().starts_with(&self.root_dir)
}
fn guard(
&self,
path: &Path,
) -> io::Result<()> {
if self.is_allowed(path) {
return Ok(());
}
Err(io::Error::new(
io::ErrorKind::NotFound,
format!("{} is outside of the served directory", path.display()),
))
}
}
impl grass::Fs for GrassFs {
fn is_dir(
&self,
path: &Path,
) -> bool {
self.is_allowed(path) && path.is_dir()
}
fn is_file(
&self,
path: &Path,
) -> bool {
self.is_allowed(path) && path.is_file()
}
fn read(
&self,
path: &Path,
) -> io::Result<Vec<u8>> {
self.guard(path)?;
std::fs::read(path)
}
fn canonicalize(
&self,
path: &Path,
) -> io::Result<PathBuf> {
self.guard(path)?;
std::fs::canonicalize(path)
}
}