os/fs/ext4/
inode.rs

1//! Ext4 Inode 包装
2//!
3//! 将 ext4_rs 的 inode 操作包装为 VFS Inode trait
4//!
5//! 设计要点:
6//! - 使用 Dentry 引用而非存储路径,消除与 VFS 的冗余
7//! - 需要路径时动态从 Dentry.full_path() 获取
8
9use crate::sync::{Mutex, SpinLock};
10use crate::uapi::time::TimeSpec;
11use alloc::string::String;
12use alloc::sync::{Arc, Weak};
13use alloc::vec::Vec;
14use ext4_rs::InodeFileType;
15
16use crate::vfs::{Dentry, DirEntry, FileMode, FsError, Inode, InodeMetadata, InodeType};
17
18/// Ext4 Inode 包装
19pub struct Ext4Inode {
20    /// ext4_rs 文件系统对象
21    fs: Arc<Mutex<ext4_rs::Ext4>>,
22
23    /// Inode 号
24    ino: u32,
25
26    /// 关联的 Dentry(弱引用,避免循环引用)
27    /// 用于获取完整路径,而不是在 Inode 中重复存储
28    dentry: SpinLock<Weak<Dentry>>,
29}
30
31impl Ext4Inode {
32    /// 创建新的 Ext4Inode
33    ///
34    /// 注意:初始创建时 dentry 为空,VFS 会在创建 Dentry 后调用 set_dentry()
35    pub fn new(fs: Arc<Mutex<ext4_rs::Ext4>>, ino: u32) -> Self {
36        Self {
37            fs,
38            ino,
39            dentry: SpinLock::new(Weak::new()),
40        }
41    }
42
43    /// 辅助方法:获取完整路径(从 Dentry 动态获取)
44    fn get_full_path(&self) -> Result<String, FsError> {
45        let dentry = self.dentry.lock().upgrade().ok_or(FsError::IoError)?;
46        Ok(dentry.full_path())
47    }
48
49    /// 辅助方法:将 ext4_rs 的 InodeFileType 转换为 VFS InodeType
50    fn convert_inode_type(ft: ext4_rs::InodeFileType) -> InodeType {
51        use ext4_rs::InodeFileType;
52        // InodeFileType 是 bitflags,需要比较 bits()
53        match ft {
54            InodeFileType::S_IFREG => InodeType::File,
55            InodeFileType::S_IFDIR => InodeType::Directory,
56            InodeFileType::S_IFLNK => InodeType::Symlink,
57            InodeFileType::S_IFCHR => InodeType::CharDevice,
58            InodeFileType::S_IFBLK => InodeType::BlockDevice,
59            InodeFileType::S_IFIFO => InodeType::Fifo,
60            InodeFileType::S_IFSOCK => InodeType::Socket,
61            _ => InodeType::File, // 默认为普通文件
62        }
63    }
64
65    /// 辅助方法:将ext4_rs的DirEntryType转换为VFS InodeType
66    fn convert_dir_entry_type(dentry_type: u8) -> InodeType {
67        match dentry_type {
68            1 => InodeType::File,        // EXT4_DE_REG_FILE
69            2 => InodeType::Directory,   // EXT4_DE_DIR
70            3 => InodeType::CharDevice,  // EXT4_DE_CHRDEV
71            4 => InodeType::BlockDevice, // EXT4_DE_BLKDEV
72            5 => InodeType::Fifo,        // EXT4_DE_FIFO
73            6 => InodeType::Socket,      // EXT4_DE_SOCK
74            7 => InodeType::Symlink,     // EXT4_DE_SYMLINK
75            _ => InodeType::File,
76        }
77    }
78}
79
80impl Inode for Ext4Inode {
81    fn metadata(&self) -> Result<InodeMetadata, FsError> {
82        let fs = self.fs.lock();
83
84        let inode_ref = fs.get_inode_ref(self.ino);
85        let inode = &inode_ref.inode;
86
87        // 计算文件大小(64位)
88        let size = (inode.size as u64) | ((inode.size_hi as u64) << 32);
89
90        // 提取 inode 类型和权限
91        let mode = inode.mode;
92        let file_type = (mode & 0xF000) >> 12;
93        let inode_type = match file_type {
94            0x8 => InodeType::File,
95            0x4 => InodeType::Directory,
96            0xA => InodeType::Symlink,
97            0x2 => InodeType::CharDevice,
98            0x6 => InodeType::BlockDevice,
99            0x1 => InodeType::Fifo,
100            0xC => InodeType::Socket,
101            _ => InodeType::File,
102        };
103
104        // 解析时间戳(包含纳秒精度)
105        // extra 字段格式: (nanosec << 2) | epoch_bits
106        // 我们只需要纳秒部分: extra >> 2
107        let atime_nsec = (inode.i_atime_extra >> 2) as i64;
108        let mtime_nsec = (inode.i_mtime_extra >> 2) as i64;
109        let ctime_nsec = (inode.i_ctime_extra >> 2) as i64;
110
111        Ok(InodeMetadata {
112            inode_no: self.ino as usize,
113            size: size as usize,
114            blocks: inode.blocks as usize,
115            atime: TimeSpec {
116                tv_sec: inode.atime as i64,
117                tv_nsec: atime_nsec,
118            },
119            mtime: TimeSpec {
120                tv_sec: inode.mtime as i64,
121                tv_nsec: mtime_nsec,
122            },
123            ctime: TimeSpec {
124                tv_sec: inode.ctime as i64,
125                tv_nsec: ctime_nsec,
126            },
127            inode_type,
128            mode: FileMode::from_bits_truncate(mode as u32),
129            nlinks: inode.links_count as usize,
130            uid: inode.uid as u32,
131            gid: inode.gid as u32,
132            rdev: 0,
133        })
134    }
135
136    fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize, FsError> {
137        // Check if this is a directory
138        let metadata = self.metadata()?;
139        if metadata.inode_type == InodeType::Directory {
140            return Err(FsError::IsDirectory);
141        }
142
143        let fs = self.fs.lock();
144
145        // ext4_rs 的 read_at 签名: pub fn read_at(&self, inode: u32, offset: usize, read_buf: &mut [u8])
146        fs.read_at(self.ino, offset, buf)
147            .map_err(|_| FsError::IoError)
148    }
149
150    fn write_at(&self, offset: usize, buf: &[u8]) -> Result<usize, FsError> {
151        // Check if this is a directory
152        let metadata = self.metadata()?;
153        if metadata.inode_type == InodeType::Directory {
154            return Err(FsError::IsDirectory);
155        }
156
157        let fs = self.fs.lock();
158
159        // ext4_rs 的 write_at 签名: pub fn write_at(&self, inode: u32, offset: usize, write_buf: &[u8])
160        fs.write_at(self.ino, offset, buf)
161            .map_err(|_| FsError::IoError)
162    }
163
164    fn lookup(&self, name: &str) -> Result<Arc<dyn Inode>, FsError> {
165        // Check if current inode is a directory
166        let metadata = self.metadata()?;
167        if metadata.inode_type != InodeType::Directory {
168            return Err(FsError::NotDirectory);
169        }
170
171        // 类似 create,lookup 也应该使用相对路径
172        // 直接在当前目录下查找指定名称的文件
173        let mut fs = self.fs.lock();
174        let mut parent = self.ino;
175        let mut name_off = 0;
176
177        // 直接使用文件名作为路径
178        let child_ino = fs
179            .generic_open(name, &mut parent, false, 0, &mut name_off)
180            .map_err(|_| FsError::NotFound)?;
181
182        // 创建子 Inode(暂时没有 dentry,VFS 会调用 set_dentry)
183        Ok(Arc::new(Ext4Inode::new(self.fs.clone(), child_ino)))
184    }
185
186    fn create(&self, name: &str, _mode: FileMode) -> Result<Arc<dyn Inode>, FsError> {
187        // Check if current inode is a directory
188        let metadata = self.metadata()?;
189        if metadata.inode_type != InodeType::Directory {
190            return Err(FsError::NotDirectory);
191        }
192
193        // Check if file already exists
194        if self.lookup(name).is_ok() {
195            return Err(FsError::AlreadyExists);
196        }
197
198        // create() only creates regular files (not directories)
199        let fs = self.fs.lock();
200        // ext4_rs 的 create_inode 内部会强制设置 mode |= 0o777
201        // 所以这里直接使用 0o777
202        let ftype = ext4_rs::InodeFileType::S_IFREG.bits() | 0o777;
203
204        let child_inode = fs
205            .create(self.ino, name, ftype)
206            .map_err(|_| FsError::IoError)?;
207
208        Ok(Arc::new(Ext4Inode::new(
209            self.fs.clone(),
210            child_inode.inode_num,
211        )))
212    }
213
214    fn mkdir(&self, name: &str, _mode: FileMode) -> Result<Arc<dyn Inode>, FsError> {
215        // Check if current inode is a directory
216        let metadata = self.metadata()?;
217        if metadata.inode_type != InodeType::Directory {
218            return Err(FsError::NotDirectory);
219        }
220
221        // Check if directory already exists
222        if self.lookup(name).is_ok() {
223            return Err(FsError::AlreadyExists);
224        }
225
226        // mkdir() creates directories using S_IFDIR | 0o755
227        let fs = self.fs.lock();
228        let ftype = ext4_rs::InodeFileType::S_IFDIR.bits() | 0o755;
229
230        let mut parent = self.ino;
231        let mut name_off = 0;
232
233        let inode_id = fs
234            .generic_open(name, &mut parent, true, ftype, &mut name_off)
235            .map_err(|e| {
236                crate::println!("[Ext4Inode::mkdir] generic_open failed: {:?}", e);
237                FsError::NoSpace
238            })?;
239
240        Ok(Arc::new(Ext4Inode::new(self.fs.clone(), inode_id)))
241    }
242
243    fn symlink(&self, name: &str, target: &str) -> Result<Arc<dyn Inode>, FsError> {
244        // Check if current inode is a directory
245        let metadata = self.metadata()?;
246        if metadata.inode_type != InodeType::Directory {
247            return Err(FsError::NotDirectory);
248        }
249
250        let parent = self.ino;
251        let inode_mod = InodeFileType::S_IFLNK.bits() | 0o777;
252        let fs = self.fs.lock();
253
254        let new_inode = fs
255            .create(parent, name, inode_mod)
256            .map_err(|_| FsError::NoSpace)?;
257
258        fs.write_at(new_inode.inode_num, 0, target.as_bytes())
259            .map_err(|_| FsError::IoError)?;
260
261        Ok(Arc::new(Ext4Inode::new(
262            self.fs.clone(),
263            new_inode.inode_num,
264        )))
265    }
266
267    fn link(&self, name: &str, target: &Arc<dyn Inode>) -> Result<(), FsError> {
268        // Check if current inode is a directory
269        let metadata = self.metadata()?;
270        if metadata.inode_type != InodeType::Directory {
271            return Err(FsError::NotDirectory);
272        }
273
274        // 向下转型为 Ext4Inode 以获取 inode 号
275        let ext4_inode = target
276            .downcast_ref::<Ext4Inode>()
277            .ok_or(FsError::InvalidArgument)?;
278
279        if !Arc::ptr_eq(&self.fs, &ext4_inode.fs) {
280            return Err(FsError::InvalidArgument);
281        }
282
283        let fs = self.fs.lock();
284        let mut self_ref = fs.get_inode_ref(self.ino);
285        let mut target_ref = fs.get_inode_ref(ext4_inode.ino);
286        fs.link(&mut self_ref, &mut target_ref, name)
287            .map_err(|_| FsError::NoSpace)?;
288
289        Ok(())
290    }
291
292    fn unlink(&self, name: &str) -> Result<(), FsError> {
293        // Check if current inode is a directory
294        let metadata = self.metadata()?;
295        if metadata.inode_type != InodeType::Directory {
296            return Err(FsError::NotDirectory);
297        }
298
299        // 查找要删除的项
300        let child = self.lookup(name)?;
301        let child_metadata = child.metadata()?;
302
303        // 获取 child 的 inode 号
304        let child_ext4 = child
305            .as_any()
306            .downcast_ref::<Ext4Inode>()
307            .ok_or(FsError::InvalidArgument)?;
308
309        let fs = self.fs.lock();
310
311        // Workaround for ext4_rs bug: dir_remove() 无条件调用 dir_has_entry()
312        // 但 dir_has_entry() 内部 assert child 必须是目录
313        // 所以对于普通文件,我们需要使用底层的 API 绕过这个 bug
314
315        if child_metadata.inode_type == InodeType::Directory {
316            // 对于目录,使用 dir_remove(它会检查目录是否为空)
317            fs.dir_remove(self.ino, name)
318                .map_err(|_| FsError::IoError)?;
319        } else {
320            // 对于普通文件,使用底层 API 手动删除
321            let mut parent_ref = fs.get_inode_ref(self.ino);
322            let mut child_ref = fs.get_inode_ref(child_ext4.ino);
323
324            // 调用底层的 unlink,它会:
325            // 1. 删除目录项(dir_remove_entry)
326            // 2. 释放 inode(ialloc_free_inode)
327            fs.unlink(&mut parent_ref, &mut child_ref, name)
328                .map_err(|_| FsError::IoError)?;
329
330            // 写回 parent inode
331            fs.write_back_inode(&mut parent_ref);
332        }
333
334        Ok(())
335    }
336
337    fn rmdir(&self, name: &str) -> Result<(), FsError> {
338        // Check if current inode is a directory
339        let metadata = self.metadata()?;
340        if metadata.inode_type != InodeType::Directory {
341            return Err(FsError::NotDirectory);
342        }
343
344        let fs = self.fs.lock();
345        let parent = self.ino;
346
347        fs.dir_remove(parent, name)
348            .map(|_| ())
349            .map_err(|_| FsError::NotFound)
350    }
351
352    /// 重命名或移动文件/目录
353    ///
354    /// # 安全性保证
355    /// - **并发安全**:持有文件系统锁直到操作完成,防止竞态条件
356    /// - **失败回滚**:关键操作失败时会尝试恢复到原始状态
357    /// - **参数验证**:严格检查所有前置条件
358    ///
359    /// # 安全性限制 ⚠️
360    /// - **非崩溃安全**:由于 ext4_rs 没有事务日志支持,系统崩溃时可能导致文件系统不一致
361    ///   - 最坏情况:文件可能同时出现在两个位置,或完全丢失
362    ///   - 建议:关键操作后调用 `sync()` 确保数据写入磁盘
363    /// - **回滚非原子**:回滚操作本身也可能失败(如磁盘已满)
364    /// - **简化的循环检测**:只检查是否移动到自身,未实现完整的祖先链遍历
365    ///
366    /// # 注意事项
367    /// - 操作持有全局文件系统锁,可能影响并发性能
368    /// - 跨目录移动目录比简单重命名更耗时(需要更新 ".." 引用)
369    fn rename(
370        &self,
371        old_name: &str,
372        new_parent: Arc<dyn Inode>,
373        new_name: &str,
374    ) -> Result<(), FsError> {
375        // 重命名实现:使用 "添加新条目 + 删除旧条目" 的方式
376        //
377        // 操作顺序(最小化中间不一致状态):
378        // 1. 验证所有参数和前置条件
379        // 2. 备份需要删除的目标(如果存在)
380        // 3. 在新位置添加条目
381        // 4. 从旧位置删除条目
382        // 5. 如果是目录,更新 ".." 引用
383        // 6. 失败时回滚
384
385        // ========== 阶段 1: 验证 ==========
386
387        // 检查当前 inode(旧父目录)是否为目录
388        let metadata = self.metadata()?;
389        if metadata.inode_type != InodeType::Directory {
390            return Err(FsError::NotDirectory);
391        }
392
393        // 查找要重命名的子项
394        let old_child = self.lookup(old_name)?;
395        let old_child_metadata = old_child.metadata()?;
396        let old_child_ext4 = old_child
397            .as_any()
398            .downcast_ref::<Ext4Inode>()
399            .ok_or(FsError::InvalidArgument)?;
400
401        // 转换新父目录
402        let new_parent_ext4 = new_parent
403            .as_any()
404            .downcast_ref::<Ext4Inode>()
405            .ok_or(FsError::InvalidArgument)?;
406
407        // 检查新父目录是否为目录
408        let new_parent_metadata = new_parent_ext4.metadata()?;
409        if new_parent_metadata.inode_type != InodeType::Directory {
410            return Err(FsError::NotDirectory);
411        }
412
413        // 确保在同一个文件系统中
414        if !Arc::ptr_eq(&self.fs, &new_parent_ext4.fs) {
415            return Err(FsError::InvalidArgument);
416        }
417
418        // 防止将目录移动到其子目录中(会造成循环)
419        if old_child_metadata.inode_type == InodeType::Directory {
420            // 简单检查:如果新父目录就是被移动的目录本身
421            if old_child_ext4.ino == new_parent_ext4.ino {
422                return Err(FsError::InvalidArgument);
423            }
424            // TODO: 完整的循环检查需要遍历新父目录的祖先链
425        }
426
427        // 持有锁直到操作完成
428        let fs = self.fs.lock();
429
430        // ========== 阶段 2: 检查目标是否存在 ==========
431
432        let mut replaced_inode: Option<u32> = None;
433
434        // 检查目标位置是否已有文件/目录
435        let target_exists = {
436            let mut parent = new_parent_ext4.ino;
437            let mut name_off = 0;
438            fs.generic_open(new_name, &mut parent, false, 0, &mut name_off)
439                .ok()
440        };
441
442        if let Some(existing_ino) = target_exists {
443            // 如果目标已存在,需要先删除它
444            let existing_ref = fs.get_inode_ref(existing_ino);
445            let replaced_is_dir = existing_ref.inode.is_dir();
446
447            if replaced_is_dir {
448                // 如果目标是目录,必须为空
449                if fs.dir_has_entry(existing_ino) {
450                    return Err(FsError::DirectoryNotEmpty);
451                }
452
453                // 删除空目录
454                fs.dir_remove(new_parent_ext4.ino, new_name)
455                    .map_err(|_| FsError::IoError)?;
456            } else {
457                // 删除普通文件
458                let mut new_parent_ref = fs.get_inode_ref(new_parent_ext4.ino);
459                let mut existing_ref = fs.get_inode_ref(existing_ino);
460
461                fs.unlink(&mut new_parent_ref, &mut existing_ref, new_name)
462                    .map_err(|_| FsError::IoError)?;
463
464                fs.write_back_inode(&mut new_parent_ref);
465            }
466
467            // 记录被替换的 inode,以便回滚
468            replaced_inode = Some(existing_ino);
469        }
470
471        // ========== 阶段 3: 执行重命名(关键部分)==========
472
473        let mut old_parent_ref = fs.get_inode_ref(self.ino);
474        let mut new_parent_ref = fs.get_inode_ref(new_parent_ext4.ino);
475        let child_ref = fs.get_inode_ref(old_child_ext4.ino);
476
477        // 步骤 3a: 在新位置添加条目
478        if let Err(_e) = fs.dir_add_entry(&mut new_parent_ref, &child_ref, new_name) {
479            // 失败:尝试恢复被删除的目标文件
480            if let Some(replaced_ino) = replaced_inode {
481                let replaced_ref = fs.get_inode_ref(replaced_ino);
482                let _ = fs.dir_add_entry(&mut new_parent_ref, &replaced_ref, new_name);
483                fs.write_back_inode(&mut new_parent_ref);
484            }
485            return Err(FsError::NoSpace);
486        }
487
488        // 步骤 3b: 从旧位置删除条目
489        if let Err(_e) = fs.dir_remove_entry(&mut old_parent_ref, old_name) {
490            // 回滚:删除刚添加的新条目
491            let _ = fs.dir_remove_entry(&mut new_parent_ref, new_name);
492
493            // 尝试恢复被删除的目标文件
494            if let Some(replaced_ino) = replaced_inode {
495                let replaced_ref = fs.get_inode_ref(replaced_ino);
496                let _ = fs.dir_add_entry(&mut new_parent_ref, &replaced_ref, new_name);
497            }
498
499            fs.write_back_inode(&mut old_parent_ref);
500            fs.write_back_inode(&mut new_parent_ref);
501            return Err(FsError::IoError);
502        }
503
504        // ========== 阶段 4: 更新目录的 ".." 引用(如果需要)==========
505
506        if old_child_metadata.inode_type == InodeType::Directory && self.ino != new_parent_ext4.ino
507        {
508            // 只有跨目录移动时才需要更新 ".."
509            let mut child_ref = fs.get_inode_ref(old_child_ext4.ino);
510
511            // 步骤 4a: 删除旧的 ".." 条目
512            if let Err(_e) = fs.dir_remove_entry(&mut child_ref, "..") {
513                // 回滚:恢复旧位置的条目,删除新位置的条目
514                let _ = fs.dir_add_entry(&mut old_parent_ref, &child_ref, old_name);
515                let _ = fs.dir_remove_entry(&mut new_parent_ref, new_name);
516
517                if let Some(replaced_ino) = replaced_inode {
518                    let replaced_ref = fs.get_inode_ref(replaced_ino);
519                    let _ = fs.dir_add_entry(&mut new_parent_ref, &replaced_ref, new_name);
520                }
521
522                fs.write_back_inode(&mut old_parent_ref);
523                fs.write_back_inode(&mut new_parent_ref);
524                fs.write_back_inode(&mut child_ref);
525                return Err(FsError::IoError);
526            }
527
528            // 步骤 4b: 添加新的 ".." 条目
529            if let Err(_e) = fs.dir_add_entry(&mut child_ref, &new_parent_ref, "..") {
530                // 回滚:恢复 ".." 条目,恢复旧位置条目,删除新位置条目
531                let _ = fs.dir_add_entry(&mut child_ref, &old_parent_ref, "..");
532                let _ = fs.dir_add_entry(&mut old_parent_ref, &child_ref, old_name);
533                let _ = fs.dir_remove_entry(&mut new_parent_ref, new_name);
534
535                if let Some(replaced_ino) = replaced_inode {
536                    let replaced_ref = fs.get_inode_ref(replaced_ino);
537                    let _ = fs.dir_add_entry(&mut new_parent_ref, &replaced_ref, new_name);
538                }
539
540                fs.write_back_inode(&mut old_parent_ref);
541                fs.write_back_inode(&mut new_parent_ref);
542                fs.write_back_inode(&mut child_ref);
543                return Err(FsError::NoSpace);
544            }
545
546            // 步骤 4c: 更新链接计数
547            let old_parent_links = old_parent_ref.inode.links_count();
548            if old_parent_links > 0 {
549                old_parent_ref.inode.set_links_count(old_parent_links - 1);
550            }
551
552            let new_parent_links = new_parent_ref.inode.links_count();
553            new_parent_ref.inode.set_links_count(new_parent_links + 1);
554
555            fs.write_back_inode(&mut child_ref);
556        }
557
558        // ========== 阶段 5: 提交更改 ==========
559
560        fs.write_back_inode(&mut old_parent_ref);
561        fs.write_back_inode(&mut new_parent_ref);
562
563        Ok(())
564    }
565
566    fn readdir(&self) -> Result<Vec<DirEntry>, FsError> {
567        // Check if current inode is a directory
568        let metadata = self.metadata()?;
569        if metadata.inode_type != InodeType::Directory {
570            return Err(FsError::NotDirectory);
571        }
572
573        let fs = self.fs.lock();
574
575        // ext4_rs 的 dir_get_entries 签名: pub fn dir_get_entries(&self, inode: u32) -> Vec<Ext4DirEntry>
576        // 直接返回 Vec,不需要 map_err
577        let entries = fs.dir_get_entries(self.ino);
578
579        // 转换为 VFS 的 DirEntry 格式
580        let vfs_entries = entries
581            .iter()
582            .map(|e| {
583                // Ext4DirEntry 的 name 字段是 [u8; 255],需要转换为 String
584                let name_len = e.name_len as usize;
585                let name = String::from_utf8_lossy(&e.name[..name_len]).into_owned();
586
587                // inner 是 union,需要 unsafe 访问 inode_type 字段
588                let inode_type = unsafe { Self::convert_dir_entry_type(e.inner.inode_type) };
589
590                DirEntry {
591                    name,
592                    inode_type,
593                    inode_no: e.inode as usize,
594                }
595            })
596            .collect();
597
598        Ok(vfs_entries)
599    }
600
601    fn truncate(&self, size: usize) -> Result<(), FsError> {
602        let metadata = self.metadata()?;
603        let old_size = metadata.size;
604
605        if size == old_size {
606            // 大小不变,直接返回
607            return Ok(());
608        }
609
610        if size < old_size {
611            // 缩小文件:使用 ext4_rs 的 truncate_inode
612            let fs = self.fs.lock();
613            let mut inode_ref = fs.get_inode_ref(self.ino);
614            fs.truncate_inode(&mut inode_ref, size as u64)
615                .map_err(|_| FsError::IoError)?;
616        } else {
617            // 扩展文件:ext4_rs 的 truncate_inode 不支持扩展(有 assert)
618            // Workaround: 在文件末尾写入零字节来扩展
619            // 这是安全的,因为:
620            // 1. 写入位置从 old_size 开始,在现有数据之后
621            // 2. write_at 会分配新块并更新文件大小
622            // 3. 符合 POSIX truncate 语义(新增部分填充零)
623            let extend_size = size - old_size;
624            let zero_buf = alloc::vec![0u8; extend_size.min(4096)]; // 使用 4KB 缓冲区
625
626            let fs = self.fs.lock();
627            let mut written = 0;
628            while written < extend_size {
629                let to_write = (extend_size - written).min(zero_buf.len());
630                fs.write_at(self.ino, old_size + written, &zero_buf[..to_write])
631                    .map_err(|_| FsError::IoError)?;
632                written += to_write;
633            }
634        }
635
636        Ok(())
637    }
638
639    fn sync(&self) -> Result<(), FsError> {
640        // ext4_rs 会自动同步数据到 BlockDevice
641        Ok(())
642    }
643
644    fn set_dentry(&self, dentry: Weak<Dentry>) {
645        *self.dentry.lock() = dentry;
646    }
647
648    fn get_dentry(&self) -> Option<Arc<Dentry>> {
649        self.dentry.lock().upgrade()
650    }
651
652    fn as_any(&self) -> &dyn core::any::Any {
653        self
654    }
655
656    fn set_times(&self, atime: Option<TimeSpec>, mtime: Option<TimeSpec>) -> Result<(), FsError> {
657        let mut fs = self.fs.lock();
658
659        // 获取 inode 引用(可变)
660        let mut inode_ref = fs.get_inode_ref(self.ino);
661        let inode = &mut inode_ref.inode;
662
663        // 更新访问时间
664        if let Some(at) = atime {
665            inode.atime = at.tv_sec as u32;
666            // 设置纳秒精度: (nanosec << 2) | epoch_bits
667            // epoch_bits 通常为 0,所以直接左移 2 位
668            inode.i_atime_extra = ((at.tv_nsec as u32) << 2) & 0xFFFFFFFC;
669        }
670
671        // 更新修改时间
672        if let Some(mt) = mtime {
673            inode.mtime = mt.tv_sec as u32;
674            inode.i_mtime_extra = ((mt.tv_nsec as u32) << 2) & 0xFFFFFFFC;
675
676            // 修改时间改变时,也更新 ctime
677            let now = TimeSpec::now();
678            inode.ctime = now.tv_sec as u32;
679            inode.i_ctime_extra = ((now.tv_nsec as u32) << 2) & 0xFFFFFFFC;
680        }
681
682        // 写回 inode 到磁盘
683        fs.write_back_inode(&mut inode_ref);
684
685        Ok(())
686    }
687
688    fn chown(&self, uid: u32, gid: u32) -> Result<(), FsError> {
689        let mut fs = self.fs.lock();
690
691        // 获取 inode 引用(可变)
692        let mut inode_ref = fs.get_inode_ref(self.ino);
693        let inode = &mut inode_ref.inode;
694
695        // 更新 uid/gid(u32::MAX 表示不改变)
696        if uid != u32::MAX {
697            inode.uid = uid as u16;
698            // 如果将来需要支持 32 位 UID,需要更新 i_uid_high
699        }
700        if gid != u32::MAX {
701            inode.gid = gid as u16;
702            // 如果将来需要支持 32 位 GID,需要更新 i_gid_high
703        }
704
705        // 更新 ctime(状态改变时间)
706        let now = TimeSpec::now();
707        inode.ctime = now.tv_sec as u32;
708        inode.i_ctime_extra = ((now.tv_nsec as u32) << 2) & 0xFFFFFFFC;
709
710        // 写回 inode 到磁盘
711        fs.write_back_inode(&mut inode_ref);
712
713        Ok(())
714    }
715
716    fn chmod(&self, mode: FileMode) -> Result<(), FsError> {
717        let mut fs = self.fs.lock();
718
719        // 获取 inode 引用(可变)
720        let mut inode_ref = fs.get_inode_ref(self.ino);
721        let inode = &mut inode_ref.inode;
722
723        // 保留文件类型位(高 4 位),只修改权限位(低 12 位)
724        let file_type = inode.mode & 0xF000;
725        let permission_bits = (mode.bits() & 0x0FFF) as u16;
726        inode.mode = file_type | permission_bits;
727
728        // 更新 ctime(状态改变时间)
729        let now = TimeSpec::now();
730        inode.ctime = now.tv_sec as u32;
731        inode.i_ctime_extra = ((now.tv_nsec as u32) << 2) & 0xFFFFFFFC;
732
733        // 写回 inode 到磁盘
734        fs.write_back_inode(&mut inode_ref);
735
736        Ok(())
737    }
738
739    fn readlink(&self) -> Result<String, FsError> {
740        // 检查是否为符号链接
741        let metadata = self.metadata()?;
742        if metadata.inode_type != InodeType::Symlink {
743            return Err(FsError::InvalidArgument);
744        }
745
746        // 获取符号链接的大小(即目标路径的长度)
747        let size = metadata.size;
748        if size == 0 {
749            return Ok(String::new());
750        }
751
752        // 读取符号链接目标
753        // 符号链接的目标存储在inode的数据区(与普通文件相同的方式)
754        let fs = self.fs.lock();
755        let mut buf = alloc::vec![0u8; size];
756
757        let bytes_read = fs
758            .read_at(self.ino, 0, &mut buf)
759            .map_err(|_| FsError::IoError)?;
760
761        // 截断到实际读取的长度
762        buf.truncate(bytes_read);
763
764        // 转换为UTF-8字符串
765        String::from_utf8(buf).map_err(|_| FsError::InvalidArgument)
766    }
767
768    fn mknod(&self, _name: &str, _mode: FileMode, _dev: u64) -> Result<Arc<dyn Inode>, FsError> {
769        // TODO: 实现 ext4 创建文件节点
770        Err(FsError::NotSupported)
771    }
772}