os/vfs/file.rs
1//! 文件抽象层 - VFS 会话层接口
2//!
3//! 该模块定义了统一的文件操作接口 [`File`] trait,支持普通文件、管道、字符设备等多种文件类型。
4//! 所有打开的文件以 `Arc<dyn File>` 形式存储在进程的文件描述符表中。
5//!
6//! # 架构定位
7//!
8//! VFS 采用两层设计:
9//! - **会话层**: [`File`] trait - 维护会话状态(offset、flags),有状态操作
10//! - **存储层**: [`Inode`] trait - 提供无状态的随机访问
11//!
12//! ## 为什么分离会话层和存储层?
13//!
14//! 同一个文件可以被多次打开或 dup,每次打开都需要独立的会话状态(如 offset),
15//! 但它们共享相同的底层存储(Inode)。这种设计支持:
16//!
17//! - **dup 语义**: 复制的文件描述符共享 offset
18//! - **硬链接**: 多个路径指向同一个 Inode
19//! - **fork 继承**: 父子进程共享文件表
20//!
21//! ```text
22//! 进程 A: fd[3] ──┐
23//! ├──> Arc<RegFile> { offset: 100 }
24//! 进程 A: fd[4] ──┘ │
25//! ▼
26//! Arc<Dentry>
27//! │
28//! ▼
29//! Arc<Inode> ←─── 进程 B: fd[5] -> Arc<RegFile> { offset: 200 }
30//! ```
31//!
32//! # 实现类型
33//!
34//! - [`RegFile`](crate::vfs::RegFile) - 普通文件,基于 Inode,支持 seek
35//! - [`PipeFile`](crate::vfs::PipeFile) - 管道,环形缓冲区,流式设备
36//! - [`StdinFile`](crate::vfs::StdinFile) / [`StdoutFile`](crate::vfs::StdoutFile) / [`StderrFile`](crate::vfs::StderrFile) - 标准 I/O
37//! - `CharDevFile` - 字符设备文件(串口、终端等)
38//! - `BlkDevFile` - 块设备文件(磁盘等)
39//!
40//! # 设计特点
41//!
42//! ## 可选方法
43//!
44//! File trait 中的许多方法提供了默认实现(返回 `NotSupported`),
45//! 允许不同文件类型只实现自己支持的功能:
46//!
47//! - `lseek()`: 仅 RegFile 和 BlkDevFile 支持
48//! - `get_pipe_size()`: 仅 PipeFile 支持
49//! - `ioctl()`: 仅设备文件支持
50//!
51//! ## 原子操作
52//!
53//! RegFile 使用 `AtomicUsize` 管理 offset,支持无锁并发读写:
54//!
55//! ```text
56//! 线程 1: read() -> fetch_add(n)
57//! 线程 2: read() -> fetch_add(m) // 并发安全
58//! ```
59//!
60//! # 使用示例
61//!
62//! ```rust
63//! use vfs::{vfs_lookup, RegFile, OpenFlags, File};
64//! use alloc::sync::Arc;
65//!
66//! // 1. 创建 File 对象
67//! let dentry = vfs_lookup("/etc/passwd")?;
68//! let file: Arc<dyn File> = Arc::new(
69//! RegFile::new(dentry, OpenFlags::O_RDONLY)
70//! );
71//!
72//! // 2. 读取数据
73//! let mut buf = [0u8; 1024];
74//! let n = file.read(&mut buf)?;
75//!
76//! // 3. 检查文件属性
77//! assert!(file.readable());
78//! assert!(!file.writable());
79//!
80//! // 4. 获取元数据
81//! let metadata = file.metadata()?;
82//! println!("文件大小: {}", metadata.size);
83//! ```
84
85use crate::uapi::fcntl::{OpenFlags, SeekWhence};
86use crate::vfs::{Dentry, FsError, Inode, InodeMetadata};
87use alloc::sync::Arc;
88
89/// 文件操作的统一接口
90///
91/// 所有打开的文件以 `Arc<dyn File>` 形式存储在进程的文件描述符表中。
92///
93/// # 设计要点
94///
95/// - 方法不携带 offset 参数,由实现者内部维护
96/// - 支持可 seek 文件(RegFile)和流式设备(PipeFile)
97/// - 可选方法提供默认实现(如 `lseek` 默认返回 `NotSupported`)
98pub trait File: Send + Sync {
99 /// 检查文件是否可读
100 fn readable(&self) -> bool;
101
102 /// 检查文件是否可写
103 fn writable(&self) -> bool;
104
105 /// 从文件读取数据
106 ///
107 /// RegFile 从当前 offset 读取并更新 offset;
108 /// PipeFile 从管道缓冲区读取,无 offset 概念。
109 fn read(&self, buf: &mut [u8]) -> Result<usize, FsError>;
110
111 /// 向文件写入数据
112 ///
113 /// RegFile 在 `O_APPEND` 模式下总是写到文件末尾。
114 fn write(&self, buf: &[u8]) -> Result<usize, FsError>;
115
116 /// 获取文件元数据
117 fn metadata(&self) -> Result<InodeMetadata, FsError>;
118
119 /// 设置文件偏移量(可选方法)
120 ///
121 /// 默认返回 `NotSupported`,适用于流式设备。
122 fn lseek(&self, _offset: isize, _whence: SeekWhence) -> Result<usize, FsError> {
123 Err(FsError::NotSupported)
124 }
125
126 /// 获取当前偏移量(可选方法)
127 ///
128 /// 默认返回 0,适用于流式设备。
129 fn offset(&self) -> usize {
130 0
131 }
132
133 /// 获取打开标志(可选方法)
134 ///
135 /// 用于 exec 时关闭 `O_CLOEXEC` 文件。
136 fn flags(&self) -> OpenFlags {
137 OpenFlags::empty()
138 }
139
140 /// 获取目录项(可选方法)
141 ///
142 /// 默认返回`FsError::NotSupported`,适用于RegFile
143 fn dentry(&self) -> Result<Arc<Dentry>, FsError> {
144 Err(FsError::NotSupported)
145 }
146
147 /// 获取Inode(可选方法)
148 ///
149 /// 默认返回`FsError::NotSupported`,适用于RegFile
150 fn inode(&self) -> Result<Arc<dyn Inode>, FsError> {
151 Err(FsError::NotSupported)
152 }
153
154 /// 设置文件状态标志(可选方法,用于 F_SETFL)
155 ///
156 /// 默认返回 `NotSupported`,适用于不支持动态修改标志的文件类型
157 fn set_status_flags(&self, _flags: OpenFlags) -> Result<(), FsError> {
158 Err(FsError::NotSupported)
159 }
160
161 /// 获取管道大小(可选方法,用于 F_GETPIPE_SZ)
162 ///
163 /// 默认返回 `NotSupported`,仅适用于 PipeFile
164 fn get_pipe_size(&self) -> Result<usize, FsError> {
165 Err(FsError::NotSupported)
166 }
167
168 /// 设置管道大小(可选方法,用于 F_SETPIPE_SZ)
169 ///
170 /// 默认返回 `NotSupported`,仅适用于 PipeFile
171 fn set_pipe_size(&self, _size: usize) -> Result<(), FsError> {
172 Err(FsError::NotSupported)
173 }
174
175 /// 获取异步 I/O 所有者(可选方法,用于 F_GETOWN)
176 ///
177 /// 返回接收 SIGIO 信号的进程 PID
178 /// 默认返回 `NotSupported`
179 fn get_owner(&self) -> Result<i32, FsError> {
180 Err(FsError::NotSupported)
181 }
182
183 /// 设置异步 I/O 所有者(可选方法,用于 F_SETOWN)
184 ///
185 /// 设置接收 SIGIO 信号的进程 PID
186 /// 默认返回 `NotSupported`
187 fn set_owner(&self, _pid: i32) -> Result<(), FsError> {
188 Err(FsError::NotSupported)
189 }
190
191 /// 从指定位置读取数据(可选方法,用于 pread64/preadv)
192 ///
193 /// 不改变文件偏移量,默认返回 `NotSupported`,适用于非 seekable 文件
194 fn read_at(&self, _offset: usize, _buf: &mut [u8]) -> Result<usize, FsError> {
195 Err(FsError::NotSupported)
196 }
197
198 /// 向指定位置写入数据(可选方法,用于 pwrite64/pwritev)
199 ///
200 /// 不改变文件偏移量,默认返回 `NotSupported`,适用于非 seekable 文件
201 fn write_at(&self, _offset: usize, _buf: &[u8]) -> Result<usize, FsError> {
202 Err(FsError::NotSupported)
203 }
204
205 /// 执行设备特定的控制操作(可选方法,用于 ioctl)
206 ///
207 /// 用于设备驱动程序特定的控制命令。
208 /// - `request`: ioctl 请求码
209 /// - `arg`: 参数指针(作为 usize 传递)
210 ///
211 /// 默认返回 `NotSupported`,仅由支持 ioctl 的设备类型实现
212 fn ioctl(&self, _request: u32, _arg: usize) -> Result<isize, FsError> {
213 Err(FsError::NotSupported)
214 }
215
216 /// 获取 Any trait 引用,用于安全的类型转换
217 fn as_any(&self) -> &dyn core::any::Any;
218
219 /// 从socket接收数据并获取源地址(可选方法,用于recvfrom)
220 ///
221 /// 返回(读取字节数, 源地址)
222 /// 默认返回NotSupported,仅socket实现
223 fn recvfrom(&self, _buf: &mut [u8]) -> Result<(usize, Option<alloc::vec::Vec<u8>>), FsError> {
224 Err(FsError::NotSupported)
225 }
226}