os/uapi/
fcntl.rs

1//! fcntl 相关的用户空间 API 定义
2
3use bitflags::bitflags;
4
5/// fcntl 命令
6///
7/// 使用枚举避免魔数,提供类型安全
8/// 参考:include/uapi/asm-generic/fcntl.h
9#[derive(Debug, Clone, Copy, PartialEq, Eq)]
10#[repr(i32)]
11pub enum FcntlCmd {
12    // === 文件描述符操作 ===
13    /// 复制文件描述符,新 fd >= arg (F_DUPFD)
14    DupFd = 0,
15
16    /// 获取文件描述符标志 (F_GETFD)
17    GetFd = 1,
18
19    /// 设置文件描述符标志 (F_SETFD)
20    SetFd = 2,
21
22    /// 获取文件状态标志 (F_GETFL)
23    GetFl = 3,
24
25    /// 设置文件状态标志 (F_SETFL)
26    SetFl = 4,
27
28    // === 文件锁操作 ===
29    /// 获取锁信息 (F_GETLK)
30    GetLk = 5,
31
32    /// 设置锁(非阻塞)(F_SETLK)
33    SetLk = 6,
34
35    /// 设置锁(阻塞)(F_SETLKW)
36    SetLkW = 7,
37
38    // === 信号相关 ===
39    /// 设置异步 I/O 所有者 (F_SETOWN)
40    SetOwn = 8,
41
42    /// 获取异步 I/O 所有者 (F_GETOWN)
43    GetOwn = 9,
44
45    /// 设置信号 (F_SETSIG)
46    SetSig = 10,
47
48    /// 获取信号 (F_GETSIG)
49    GetSig = 11,
50
51    // === 扩展命令 (Linux 特有) ===
52    /// 复制 fd 并设置 CLOEXEC (F_DUPFD_CLOEXEC)
53    DupFdCloexec = 1030,
54
55    /// 设置管道大小 (F_SETPIPE_SZ)
56    SetPipeSz = 1031,
57
58    /// 获取管道大小 (F_GETPIPE_SZ)
59    GetPipeSz = 1032,
60}
61
62impl FcntlCmd {
63    /// 从 i32 转换为 FcntlCmd
64    ///
65    /// # 返回值
66    /// - `Some(cmd)`: 识别的命令
67    /// - `None`: 未知命令
68    pub fn from_raw(cmd: i32) -> Option<Self> {
69        match cmd {
70            0 => Some(Self::DupFd),
71            1 => Some(Self::GetFd),
72            2 => Some(Self::SetFd),
73            3 => Some(Self::GetFl),
74            4 => Some(Self::SetFl),
75            5 => Some(Self::GetLk),
76            6 => Some(Self::SetLk),
77            7 => Some(Self::SetLkW),
78            8 => Some(Self::SetOwn),
79            9 => Some(Self::GetOwn),
80            10 => Some(Self::SetSig),
81            11 => Some(Self::GetSig),
82            1030 => Some(Self::DupFdCloexec),
83            1031 => Some(Self::SetPipeSz),
84            1032 => Some(Self::GetPipeSz),
85            _ => None,
86        }
87    }
88}
89
90bitflags! {
91    /// 文件描述符标志
92    ///
93    /// 用于 F_GETFD/F_SETFD
94    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
95    pub struct FdFlags: u32 {
96        /// close-on-exec 标志 (FD_CLOEXEC)
97        const CLOEXEC = 1;
98    }
99}
100
101bitflags! {
102    /// 文件状态标志
103    ///
104    /// 可通过 F_SETFL 修改的标志
105    /// 参考:include/uapi/asm-generic/fcntl.h
106    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
107    pub struct FileStatusFlags: u32 {
108        /// 追加模式 (O_APPEND)
109        const APPEND = 0o2000;
110
111        /// 非阻塞模式 (O_NONBLOCK)
112        const NONBLOCK = 0o4000;
113
114        /// 异步 I/O - 信号驱动 (O_ASYNC)
115        const ASYNC = 0o20000;
116
117        /// 直接 I/O - 绕过缓存 (O_DIRECT)
118        const DIRECT = 0o40000;
119
120        /// 不更新访问时间 (O_NOATIME)
121        const NOATIME = 0o1000000;
122    }
123}
124
125impl FileStatusFlags {
126    /// 检查标志是否可以通过 F_SETFL 修改
127    ///
128    /// F_SETFL 只能修改特定标志,不能修改访问模式等
129    pub fn is_modifiable(self) -> bool {
130        // 只有这些标志可以被 F_SETFL 修改
131        let modifiable = Self::APPEND | Self::NONBLOCK | Self::ASYNC | Self::DIRECT | Self::NOATIME;
132        (self & !modifiable).is_empty()
133    }
134}
135
136/// 锁类型枚举
137#[derive(Debug, Clone, Copy, PartialEq, Eq)]
138#[repr(i16)]
139pub enum LockType {
140    /// 共享或读锁 (F_RDLCK)
141    Read = 0,
142
143    /// 独占或写锁 (F_WRLCK)
144    Write = 1,
145
146    /// 解锁 (F_UNLCK)
147    Unlock = 2,
148}
149
150impl LockType {
151    pub fn from_raw(val: i16) -> Option<Self> {
152        match val {
153            0 => Some(Self::Read),
154            1 => Some(Self::Write),
155            2 => Some(Self::Unlock),
156            _ => None,
157        }
158    }
159}
160
161/// 文件锁结构(对应 POSIX struct flock)
162///
163/// 用于 F_GETLK / F_SETLK / F_SETLKW 系统调用
164#[repr(C)]
165#[derive(Debug, Clone, Copy)]
166pub struct Flock {
167    /// 锁类型:F_RDLCK, F_WRLCK, F_UNLCK
168    pub l_type: i16,
169
170    /// 起始偏移的参考位置:SEEK_SET, SEEK_CUR, SEEK_END
171    pub l_whence: i16,
172
173    /// 锁的起始偏移量
174    pub l_start: i64,
175
176    /// 锁的长度(0 表示到文件末尾)
177    pub l_len: i64,
178
179    /// 持有锁的进程 PID(仅用于 F_GETLK)
180    pub l_pid: i32,
181
182    /// 填充以保持 C 结构对齐
183    _pad: i32,
184}
185
186impl Flock {
187    /// 创建新的锁结构
188    pub fn new(lock_type: LockType, whence: i16, start: i64, len: i64) -> Self {
189        Self {
190            l_type: lock_type as i16,
191            l_whence: whence,
192            l_start: start,
193            l_len: len,
194            l_pid: 0,
195            _pad: 0,
196        }
197    }
198
199    /// 将相对偏移转换为绝对偏移
200    ///
201    /// # 参数
202    /// - `current_offset`: 当前文件偏移量(用于 SEEK_CUR)
203    /// - `file_size`: 文件大小(用于 SEEK_END)
204    pub fn to_absolute_range(
205        &self,
206        current_offset: usize,
207        file_size: usize,
208    ) -> Result<(usize, usize), ()> {
209        let start = match self.l_whence as i32 {
210            SEEK_SET => self.l_start,
211            SEEK_CUR => current_offset as i64 + self.l_start,
212            SEEK_END => file_size as i64 + self.l_start,
213            _ => return Err(()),
214        };
215
216        if start < 0 {
217            return Err(());
218        }
219
220        let start = start as usize;
221        let len = if self.l_len == 0 {
222            // 0 表示锁定到文件末尾
223            usize::MAX - start
224        } else if self.l_len > 0 {
225            self.l_len as usize
226        } else {
227            return Err(());
228        };
229
230        Ok((start, len))
231    }
232}
233
234bitflags! {
235    /// 文件打开标志(与 POSIX 兼容)
236    ///
237    /// 用于 open()/openat() 系统调用
238    /// 参考:include/uapi/asm-generic/fcntl.h
239    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
240    pub struct OpenFlags: u32 {
241        /// 只读模式 (O_RDONLY)
242        const O_RDONLY    = 0o0;
243
244        /// 只写模式 (O_WRONLY)
245        const O_WRONLY    = 0o1;
246
247        /// 读写模式 (O_RDWR)
248        const O_RDWR      = 0o2;
249
250        /// 访问模式掩码 (O_ACCMODE)
251        const O_ACCMODE   = 0o3;
252
253        /// 文件不存在则创建 (O_CREAT)
254        const O_CREAT     = 0o100;
255
256        /// 与 O_CREAT 配合,文件必须不存在 (O_EXCL)
257        const O_EXCL      = 0o200;
258
259        /// 截断文件到 0 (O_TRUNC)
260        const O_TRUNC     = 0o1000;
261
262        /// 追加模式 (O_APPEND)
263        const O_APPEND    = 0o2000;
264
265        /// 非阻塞 I/O (O_NONBLOCK)
266        const O_NONBLOCK  = 0o4000;
267
268        /// 必须是目录 (O_DIRECTORY)
269        const O_DIRECTORY = 0o200000;
270
271        /// exec 时关闭 (O_CLOEXEC)
272        const O_CLOEXEC   = 0o2000000;
273
274        /// 大文件 (O_LARGEFILE) (空操作)
275        const O_LARGEFILE = 0o100000;
276    }
277}
278
279impl OpenFlags {
280    /// 检查是否可读(O_RDONLY 或 O_RDWR)
281    pub fn readable(&self) -> bool {
282        let mode = self.bits() & Self::O_ACCMODE.bits();
283        mode == Self::O_RDONLY.bits() || mode == Self::O_RDWR.bits()
284    }
285
286    /// 检查是否可写(O_WRONLY 或 O_RDWR)
287    pub fn writable(&self) -> bool {
288        let mode = self.bits() & Self::O_ACCMODE.bits();
289        mode == Self::O_WRONLY.bits() || mode == Self::O_RDWR.bits()
290    }
291}
292
293/// 文件偏移量设置模式
294///
295/// 用于 lseek() 系统调用
296/// 对应 POSIX 的 `SEEK_SET`、`SEEK_CUR`、`SEEK_END`
297/// 参考:include/uapi/linux/fs.h
298#[derive(Debug, Clone, Copy, PartialEq, Eq)]
299#[repr(i32)]
300pub enum SeekWhence {
301    /// 从文件开头计算 (SEEK_SET)
302    Set = 0,
303
304    /// 从当前位置计算 (SEEK_CUR)
305    Cur = 1,
306
307    /// 从文件末尾计算 (SEEK_END)
308    End = 2,
309}
310
311impl SeekWhence {
312    /// 从 i32 转换(用于系统调用参数解析)
313    ///
314    /// # 参数
315    /// - `value`: 用户空间传入的 whence 值(0/1/2)
316    ///
317    /// # 返回值
318    /// - `Some(whence)`: 有效的 whence 值
319    /// - `None`: 无效值
320    pub fn from_i32(value: i32) -> Option<Self> {
321        match value {
322            0 => Some(Self::Set),
323            1 => Some(Self::Cur),
324            2 => Some(Self::End),
325            _ => None,
326        }
327    }
328
329    /// 从 usize 转换(兼容旧代码)
330    pub fn from_usize(value: usize) -> Option<Self> {
331        Self::from_i32(value as i32)
332    }
333}
334
335// 兼容性常量(供 C 代码和文档参考)
336pub const SEEK_SET: i32 = 0;
337pub const SEEK_CUR: i32 = 1;
338pub const SEEK_END: i32 = 2;