132 lines
3.2 KiB
Rust
132 lines
3.2 KiB
Rust
use core::ops::Deref;
|
|
use diesel::prelude::*;
|
|
use std::collections::HashMap;
|
|
use std::path::Path;
|
|
use std::path::PathBuf;
|
|
|
|
use db::mount_points;
|
|
use db::{ConnectionSource, DB};
|
|
use errors::*;
|
|
|
|
pub trait VFSSource {
|
|
fn get_vfs(&self) -> Result<VFS>;
|
|
}
|
|
|
|
impl VFSSource for DB {
|
|
fn get_vfs(&self) -> Result<VFS> {
|
|
use self::mount_points::dsl::*;
|
|
let mut vfs = VFS::new();
|
|
let connection = self.get_connection();
|
|
let points: Vec<MountPoint> = mount_points
|
|
.select((source, name))
|
|
.get_results(connection.deref())?;
|
|
for point in points {
|
|
vfs.mount(&Path::new(&point.source), &point.name)?;
|
|
}
|
|
Ok(vfs)
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Debug, Deserialize, Insertable, PartialEq, Queryable, Serialize)]
|
|
#[table_name = "mount_points"]
|
|
pub struct MountPoint {
|
|
pub source: String,
|
|
pub name: String,
|
|
}
|
|
|
|
pub struct VFS {
|
|
mount_points: HashMap<String, PathBuf>,
|
|
}
|
|
|
|
impl VFS {
|
|
pub fn new() -> VFS {
|
|
VFS {
|
|
mount_points: HashMap::new(),
|
|
}
|
|
}
|
|
|
|
pub fn mount(&mut self, real_path: &Path, name: &str) -> Result<()> {
|
|
self.mount_points
|
|
.insert(name.to_owned(), real_path.to_path_buf());
|
|
Ok(())
|
|
}
|
|
|
|
pub fn real_to_virtual<P: AsRef<Path>>(&self, real_path: P) -> Result<PathBuf> {
|
|
for (name, target) in &self.mount_points {
|
|
if let Ok(p) = real_path.as_ref().strip_prefix(target) {
|
|
let mount_path = Path::new(&name);
|
|
return if p.components().count() == 0 {
|
|
Ok(mount_path.to_path_buf())
|
|
} else {
|
|
Ok(mount_path.join(p))
|
|
};
|
|
}
|
|
}
|
|
bail!("Real path has no match in VFS")
|
|
}
|
|
|
|
pub fn virtual_to_real<P: AsRef<Path>>(&self, virtual_path: P) -> Result<PathBuf> {
|
|
for (name, target) in &self.mount_points {
|
|
let mount_path = Path::new(&name);
|
|
if let Ok(p) = virtual_path.as_ref().strip_prefix(mount_path) {
|
|
return if p.components().count() == 0 {
|
|
Ok(target.clone())
|
|
} else {
|
|
Ok(target.join(p))
|
|
};
|
|
}
|
|
}
|
|
bail!("Virtual path has no match in VFS")
|
|
}
|
|
|
|
pub fn get_mount_points(&self) -> &HashMap<String, PathBuf> {
|
|
&self.mount_points
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_virtual_to_real() {
|
|
let mut vfs = VFS::new();
|
|
vfs.mount(Path::new("test_dir"), "root").unwrap();
|
|
|
|
let mut correct_path = PathBuf::new();
|
|
correct_path.push("test_dir");
|
|
correct_path.push("somewhere");
|
|
correct_path.push("something.png");
|
|
|
|
let mut virtual_path = PathBuf::new();
|
|
virtual_path.push("root");
|
|
virtual_path.push("somewhere");
|
|
virtual_path.push("something.png");
|
|
|
|
let found_path = vfs.virtual_to_real(virtual_path.as_path()).unwrap();
|
|
assert!(found_path.to_str() == correct_path.to_str());
|
|
}
|
|
|
|
#[test]
|
|
fn test_virtual_to_real_no_trail() {
|
|
let mut vfs = VFS::new();
|
|
vfs.mount(Path::new("test_dir"), "root").unwrap();
|
|
let correct_path = Path::new("test_dir");
|
|
let found_path = vfs.virtual_to_real(Path::new("root")).unwrap();
|
|
assert!(found_path.to_str() == correct_path.to_str());
|
|
}
|
|
|
|
#[test]
|
|
fn test_real_to_virtual() {
|
|
let mut vfs = VFS::new();
|
|
vfs.mount(Path::new("test_dir"), "root").unwrap();
|
|
|
|
let mut correct_path = PathBuf::new();
|
|
correct_path.push("root");
|
|
correct_path.push("somewhere");
|
|
correct_path.push("something.png");
|
|
|
|
let mut real_path = PathBuf::new();
|
|
real_path.push("test_dir");
|
|
real_path.push("somewhere");
|
|
real_path.push("something.png");
|
|
|
|
let found_path = vfs.real_to_virtual(real_path.as_path()).unwrap();
|
|
assert!(found_path == correct_path);
|
|
}
|