1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
use std::fs::File;
use std::io::*;
use std::path::{Path, PathBuf};
use crate::*;
#[derive(Debug)]
pub struct FilesystemVfs {
root_path: PathBuf,
}
fn conv_path(path: impl AsRef<Path>) -> Result<relative_path::RelativePathBuf> {
relative_path::RelativePathBuf::from_path(path)
.map_err(|_| Error::new(ErrorKind::Other, "Invalid path"))
}
impl FilesystemVfs {
pub fn new(root_path: &Path) -> std::io::Result<FilesystemVfs> {
Ok(FilesystemVfs {
root_path: root_path.to_path_buf(),
})
}
pub fn open_file(&self, path: &Path) -> std::io::Result<File> {
let absolute = conv_path(path)?.to_logical_path(&self.root_path);
if !absolute.starts_with(&self.root_path) {
return Err(Error::new(
ErrorKind::Other,
"path is outside the vfs root directory",
));
}
File::open(absolute)
}
}
impl Vfs for FilesystemVfs {
type Reader = File;
fn open(&self, key: &str) -> std::io::Result<File> {
self.open_file(Path::new(key))
}
}
impl VfsReader for File {
fn get_size(&self) -> Result<u64> {
let meta = self.metadata()?;
Ok(meta.len())
}
}
#[cfg(test)]
mod tests {
use super::*;
struct StringDecoder;
impl Decoder for StringDecoder {
type Output = String;
type Error = Error;
fn decode<R: Read>(&self, mut reader: R) -> Result<String> {
let mut out = String::new();
reader.read_to_string(&mut out)?;
Ok(out)
}
fn estimate_cost(&self, item: &String) -> Result<u64> {
Ok(item.len() as u64)
}
}
#[test]
fn test_filesystem_vfs() {
let cache_config = AssetCacheConfig {
max_single_object_bytes_cost: 100,
max_bytes_cost: 1000,
max_decoded_cost: 1000,
max_single_object_decoded_cost: 1000,
};
let tmp_dir = tempfile::tempdir().unwrap();
let mut vfs_path = tmp_dir.path().to_path_buf();
vfs_path.push("actual_dir");
std::fs::create_dir(&vfs_path).unwrap();
let vfs = FilesystemVfs::new(&vfs_path).unwrap();
let cache =
AssetCache::<FilesystemVfs, StringDecoder>::new(vfs, StringDecoder, cache_config);
std::fs::write(&vfs_path.join("a"), "aaaa").unwrap();
std::fs::write(vfs_path.join("b"), "bbbb").unwrap();
std::fs::write(vfs_path.join("c"), "cccc").unwrap();
std::fs::write(vfs_path.parent().unwrap().join("d"), "dddd").unwrap();
assert_eq!(&*cache.get("a").unwrap(), "aaaa");
assert_eq!(&*cache.get("b").unwrap(), "bbbb");
assert_eq!(&*cache.get("c").unwrap(), "cccc");
if let Err(AssetCacheError::<Error>::Vfs(e)) = cache.get("../d") {
if e.kind() != ErrorKind::Other {
panic!(
"Should get an other error for paths outside the vfs root: {:?}",
e
);
}
} else {
panic!("Should error when getting files outside the vfs directory");
}
}
}