os/fs/sysfs/
inode.rs

1//! Sysfs Inode 实现
2//!
3//! 提供三种类型的 Inode:
4//! - 目录 (Directory)
5//! - 属性文件 (Attribute) - 动态生成内容
6//! - 符号链接 (Symlink)
7
8use alloc::collections::BTreeMap;
9use alloc::string::{String, ToString};
10use alloc::sync::Arc;
11use alloc::vec::Vec;
12use core::any::Any;
13use core::sync::atomic::{AtomicUsize, Ordering};
14use spin::Mutex;
15
16use crate::uapi::time::TimeSpec;
17use crate::vfs::{DirEntry, FileMode, FsError, Inode, InodeMetadata, InodeType};
18
19/// Sysfs 属性生成器
20///
21/// 用于动态生成属性文件的内容
22pub type AttrShowFn = dyn Fn() -> Result<String, FsError> + Send + Sync;
23pub type AttrStoreFn = dyn Fn(&str) -> Result<(), FsError> + Send + Sync;
24
25/// Sysfs 属性
26pub struct SysfsAttr {
27    pub name: String,
28    pub mode: FileMode,
29    pub show: Arc<AttrShowFn>,
30    pub store: Option<Arc<AttrStoreFn>>,
31}
32
33/// Sysfs Inode 内容类型
34pub enum SysfsInodeContent {
35    /// 目录 (子节点)
36    Directory(Mutex<BTreeMap<String, Arc<SysfsInode>>>),
37
38    /// 属性文件 (动态生成)
39    Attribute(SysfsAttr),
40
41    /// 符号链接
42    Symlink(String),
43}
44
45/// Sysfs Inode
46pub struct SysfsInode {
47    inode_no: usize,
48    inode_type: InodeType,
49    metadata: Mutex<InodeMetadata>,
50    content: SysfsInodeContent,
51}
52
53static NEXT_INODE_NO: AtomicUsize = AtomicUsize::new(1);
54
55impl SysfsInode {
56    /// 创建目录 inode
57    pub fn new_directory(mode: FileMode) -> Arc<Self> {
58        let inode_no = NEXT_INODE_NO.fetch_add(1, Ordering::Relaxed);
59        let now = TimeSpec::now();
60        Arc::new(Self {
61            inode_no,
62            inode_type: InodeType::Directory,
63            metadata: Mutex::new(InodeMetadata {
64                inode_no,
65                inode_type: InodeType::Directory,
66                size: 0,
67                mode,
68                nlinks: 2,
69                uid: 0,
70                gid: 0,
71                atime: now,
72                mtime: now,
73                ctime: now,
74                blocks: 0,
75                rdev: 0,
76            }),
77            content: SysfsInodeContent::Directory(Mutex::new(BTreeMap::new())),
78        })
79    }
80
81    /// 创建属性文件 inode
82    pub fn new_attribute(attr: SysfsAttr) -> Arc<Self> {
83        let inode_no = NEXT_INODE_NO.fetch_add(1, Ordering::Relaxed);
84        let mode = attr.mode.clone();
85        let now = TimeSpec::now();
86        Arc::new(Self {
87            inode_no,
88            inode_type: InodeType::File,
89            metadata: Mutex::new(InodeMetadata {
90                inode_no,
91                inode_type: InodeType::File,
92                size: 0, // sysfs 文件大小总是 0
93                mode,
94                nlinks: 1,
95                uid: 0,
96                gid: 0,
97                atime: now,
98                mtime: now,
99                ctime: now,
100                blocks: 0,
101                rdev: 0,
102            }),
103            content: SysfsInodeContent::Attribute(attr),
104        })
105    }
106
107    /// 创建符号链接 inode
108    pub fn new_symlink(target: String) -> Arc<Self> {
109        let inode_no = NEXT_INODE_NO.fetch_add(1, Ordering::Relaxed);
110        let now = TimeSpec::now();
111        Arc::new(Self {
112            inode_no,
113            inode_type: InodeType::Symlink,
114            metadata: Mutex::new(InodeMetadata {
115                inode_no,
116                inode_type: InodeType::Symlink,
117                size: target.len(),
118                mode: FileMode::from_bits_truncate(0o777),
119                nlinks: 1,
120                uid: 0,
121                gid: 0,
122                atime: now,
123                mtime: now,
124                ctime: now,
125                blocks: 0,
126                rdev: 0,
127            }),
128            content: SysfsInodeContent::Symlink(target),
129        })
130    }
131
132    /// 向目录添加子节点
133    pub fn add_child(&self, name: &str, child: Arc<SysfsInode>) -> Result<(), FsError> {
134        match &self.content {
135            SysfsInodeContent::Directory(children) => {
136                children.lock().insert(name.to_string(), child);
137                Ok(())
138            }
139            _ => Err(FsError::NotDirectory),
140        }
141    }
142
143    /// 读取符号链接目标
144    pub fn readlink(&self) -> Result<String, FsError> {
145        match &self.content {
146            SysfsInodeContent::Symlink(target) => Ok(target.clone()),
147            _ => Err(FsError::InvalidArgument),
148        }
149    }
150}
151
152impl Inode for SysfsInode {
153    fn metadata(&self) -> Result<InodeMetadata, FsError> {
154        Ok(self.metadata.lock().clone())
155    }
156
157    fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize, FsError> {
158        match &self.content {
159            SysfsInodeContent::Attribute(attr) => {
160                // 调用 show 函数生成内容
161                let content = (attr.show)()?;
162                let data = content.as_bytes();
163
164                if offset >= data.len() {
165                    return Ok(0);
166                }
167
168                let to_read = (data.len() - offset).min(buf.len());
169                buf[..to_read].copy_from_slice(&data[offset..offset + to_read]);
170                Ok(to_read)
171            }
172            _ => Err(FsError::IsDirectory),
173        }
174    }
175
176    fn write_at(&self, offset: usize, buf: &[u8]) -> Result<usize, FsError> {
177        match &self.content {
178            SysfsInodeContent::Attribute(attr) => {
179                // 检查是否支持写入
180                if let Some(store) = &attr.store {
181                    if offset != 0 {
182                        return Err(FsError::InvalidArgument);
183                    }
184
185                    // 转换为字符串并调用 store 函数
186                    let content =
187                        core::str::from_utf8(buf).map_err(|_| FsError::InvalidArgument)?;
188
189                    (store)(content)?;
190                    Ok(buf.len())
191                } else {
192                    Err(FsError::PermissionDenied)
193                }
194            }
195            _ => Err(FsError::IsDirectory),
196        }
197    }
198
199    fn readdir(&self) -> Result<Vec<DirEntry>, FsError> {
200        match &self.content {
201            SysfsInodeContent::Directory(children) => {
202                let mut entries = Vec::new();
203
204                entries.push(DirEntry {
205                    name: ".".to_string(),
206                    inode_no: self.inode_no,
207                    inode_type: InodeType::Directory,
208                });
209
210                entries.push(DirEntry {
211                    name: "..".to_string(),
212                    inode_no: self.inode_no,
213                    inode_type: InodeType::Directory,
214                });
215
216                for (name, child) in children.lock().iter() {
217                    entries.push(DirEntry {
218                        name: name.clone(),
219                        inode_no: child.inode_no,
220                        inode_type: child.inode_type,
221                    });
222                }
223
224                Ok(entries)
225            }
226            _ => Err(FsError::NotDirectory),
227        }
228    }
229
230    fn lookup(&self, name: &str) -> Result<Arc<dyn Inode>, FsError> {
231        match &self.content {
232            SysfsInodeContent::Directory(children) => children
233                .lock()
234                .get(name)
235                .cloned()
236                .map(|inode| inode as Arc<dyn Inode>)
237                .ok_or(FsError::NotFound),
238            _ => Err(FsError::NotDirectory),
239        }
240    }
241
242    fn create(&self, _name: &str, _mode: FileMode) -> Result<Arc<dyn Inode>, FsError> {
243        // sysfs 是只读文件系统
244        Err(FsError::ReadOnlyFs)
245    }
246
247    fn mkdir(&self, _name: &str, _mode: FileMode) -> Result<Arc<dyn Inode>, FsError> {
248        // sysfs 是只读文件系统
249        Err(FsError::ReadOnlyFs)
250    }
251
252    fn truncate(&self, _size: usize) -> Result<(), FsError> {
253        // sysfs 是只读文件系统
254        Err(FsError::ReadOnlyFs)
255    }
256
257    fn sync(&self) -> Result<(), FsError> {
258        // sysfs 是纯虚拟文件系统,无需同步
259        Ok(())
260    }
261
262    fn symlink(&self, _name: &str, _target: &str) -> Result<Arc<dyn Inode>, FsError> {
263        Err(FsError::PermissionDenied)
264    }
265
266    fn link(&self, _name: &str, _target: &Arc<dyn Inode>) -> Result<(), FsError> {
267        Err(FsError::PermissionDenied)
268    }
269
270    fn unlink(&self, _name: &str) -> Result<(), FsError> {
271        Err(FsError::PermissionDenied)
272    }
273
274    fn rmdir(&self, _name: &str) -> Result<(), FsError> {
275        Err(FsError::PermissionDenied)
276    }
277
278    fn rename(
279        &self,
280        _old_name: &str,
281        _new_parent: Arc<dyn Inode>,
282        _new_name: &str,
283    ) -> Result<(), FsError> {
284        Err(FsError::PermissionDenied)
285    }
286
287    fn set_times(&self, _atime: Option<TimeSpec>, _mtime: Option<TimeSpec>) -> Result<(), FsError> {
288        Err(FsError::PermissionDenied)
289    }
290
291    fn readlink(&self) -> Result<String, FsError> {
292        match &self.content {
293            SysfsInodeContent::Symlink(target) => Ok(target.clone()),
294            _ => Err(FsError::InvalidArgument),
295        }
296    }
297
298    fn as_any(&self) -> &dyn Any {
299        self
300    }
301
302    fn mknod(&self, _name: &str, _mode: FileMode, _dev: u64) -> Result<Arc<dyn Inode>, FsError> {
303        Err(FsError::NotSupported)
304    }
305
306    fn chmod(&self, _mode: FileMode) -> Result<(), FsError> {
307        Err(FsError::NotSupported)
308    }
309
310    fn chown(&self, _uid: u32, _gid: u32) -> Result<(), FsError> {
311        Err(FsError::NotSupported)
312    }
313}