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
|
use super::{DirEntry, FileSystem, Inode, InodeKind};
use crate::errno::Errno;
use alloc::{collections::BTreeMap, string::String, sync::Arc, vec::Vec};
use spin::Mutex;
pub struct RamFs {
root: Arc<RamInode>,
}
impl RamFs {
pub fn new() -> Arc<Self> {
Arc::new(RamFs { root: Arc::new(RamInode::Dir(Mutex::new(BTreeMap::new()))) })
}
}
impl FileSystem for RamFs {
fn name(&self) -> &'static str {
"ramfs"
}
fn root(&self) -> Arc<dyn Inode> {
self.root.clone()
}
}
pub enum RamInode {
File(Mutex<Vec<u8>>),
Dir(Mutex<BTreeMap<String, Arc<RamInode>>>),
}
impl Inode for RamInode {
fn kind(&self) -> InodeKind {
match self {
RamInode::File(_) => InodeKind::File,
RamInode::Dir(_) => InodeKind::Directory,
}
}
fn size(&self) -> usize {
match self {
RamInode::File(data) => data.lock().len(),
RamInode::Dir(entries) => entries.lock().len(),
}
}
fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize, Errno> {
let RamInode::File(data) = self else { return Err(Errno::EISDIR) };
let data = data.lock();
if offset >= data.len() {
return Ok(0); }
let n = buf.len().min(data.len() - offset);
buf[..n].copy_from_slice(&data[offset..offset + n]);
Ok(n)
}
fn write_at(&self, offset: usize, buf: &[u8]) -> Result<usize, Errno> {
let RamInode::File(data) = self else { return Err(Errno::EISDIR) };
let mut data = data.lock();
let end = offset.checked_add(buf.len()).ok_or(Errno::EINVAL)?;
if data.len() < end {
data.resize(end, 0); }
data[offset..end].copy_from_slice(buf);
Ok(buf.len())
}
fn lookup(&self, name: &str) -> Result<Arc<dyn Inode>, Errno> {
let RamInode::Dir(entries) = self else { return Err(Errno::ENOTDIR) };
let node = entries.lock().get(name).cloned().ok_or(Errno::ENOENT)?;
Ok(node)
}
fn create(&self, name: &str, kind: InodeKind) -> Result<Arc<dyn Inode>, Errno> {
let RamInode::Dir(entries) = self else { return Err(Errno::ENOTDIR) };
if name.is_empty() || name.contains('/') || name.len() > 255 {
return Err(Errno::EINVAL);
}
let mut entries = entries.lock();
if entries.contains_key(name) {
return Err(Errno::EEXIST);
}
let node = Arc::new(match kind {
InodeKind::File => RamInode::File(Mutex::new(Vec::new())),
InodeKind::Directory => RamInode::Dir(Mutex::new(BTreeMap::new())),
InodeKind::Symlink | InodeKind::Device => return Err(Errno::EOPNOTSUPP), });
entries.insert(String::from(name), node.clone());
Ok(node)
}
fn list(&self) -> Result<Vec<DirEntry>, Errno> {
let RamInode::Dir(entries) = self else { return Err(Errno::ENOTDIR) };
let entries = entries.lock();
Ok(entries.iter().map(|(name, node)| DirEntry { name: name.clone(), kind: node.kind() }).collect())
}
fn truncate(&self) -> Result<(), Errno> {
let RamInode::File(data) = self else { return Err(Errno::EISDIR) };
data.lock().clear();
Ok(())
}
fn remove(&self, name: &str) -> Result<(), Errno> {
let RamInode::Dir(entries) = self else { return Err(Errno::ENOTDIR) };
let mut entries = entries.lock();
let node = entries.get(name).ok_or(Errno::ENOENT)?;
if let RamInode::Dir(children) = &**node {
if !children.lock().is_empty() {
return Err(Errno::ENOTEMPTY);
}
}
entries.remove(name);
Ok(())
}
}
|