1use 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
18pub struct Ext4Inode {
20 fs: Arc<Mutex<ext4_rs::Ext4>>,
22
23 ino: u32,
25
26 dentry: SpinLock<Weak<Dentry>>,
29}
30
31impl Ext4Inode {
32 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 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 fn convert_inode_type(ft: ext4_rs::InodeFileType) -> InodeType {
51 use ext4_rs::InodeFileType;
52 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, }
63 }
64
65 fn convert_dir_entry_type(dentry_type: u8) -> InodeType {
67 match dentry_type {
68 1 => InodeType::File, 2 => InodeType::Directory, 3 => InodeType::CharDevice, 4 => InodeType::BlockDevice, 5 => InodeType::Fifo, 6 => InodeType::Socket, 7 => InodeType::Symlink, _ => 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 let size = (inode.size as u64) | ((inode.size_hi as u64) << 32);
89
90 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 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 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 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 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 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 let metadata = self.metadata()?;
167 if metadata.inode_type != InodeType::Directory {
168 return Err(FsError::NotDirectory);
169 }
170
171 let mut fs = self.fs.lock();
174 let mut parent = self.ino;
175 let mut name_off = 0;
176
177 let child_ino = fs
179 .generic_open(name, &mut parent, false, 0, &mut name_off)
180 .map_err(|_| FsError::NotFound)?;
181
182 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 let metadata = self.metadata()?;
189 if metadata.inode_type != InodeType::Directory {
190 return Err(FsError::NotDirectory);
191 }
192
193 if self.lookup(name).is_ok() {
195 return Err(FsError::AlreadyExists);
196 }
197
198 let fs = self.fs.lock();
200 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 let metadata = self.metadata()?;
217 if metadata.inode_type != InodeType::Directory {
218 return Err(FsError::NotDirectory);
219 }
220
221 if self.lookup(name).is_ok() {
223 return Err(FsError::AlreadyExists);
224 }
225
226 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 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 let metadata = self.metadata()?;
270 if metadata.inode_type != InodeType::Directory {
271 return Err(FsError::NotDirectory);
272 }
273
274 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 let metadata = self.metadata()?;
295 if metadata.inode_type != InodeType::Directory {
296 return Err(FsError::NotDirectory);
297 }
298
299 let child = self.lookup(name)?;
301 let child_metadata = child.metadata()?;
302
303 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 if child_metadata.inode_type == InodeType::Directory {
316 fs.dir_remove(self.ino, name)
318 .map_err(|_| FsError::IoError)?;
319 } else {
320 let mut parent_ref = fs.get_inode_ref(self.ino);
322 let mut child_ref = fs.get_inode_ref(child_ext4.ino);
323
324 fs.unlink(&mut parent_ref, &mut child_ref, name)
328 .map_err(|_| FsError::IoError)?;
329
330 fs.write_back_inode(&mut parent_ref);
332 }
333
334 Ok(())
335 }
336
337 fn rmdir(&self, name: &str) -> Result<(), FsError> {
338 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 fn rename(
370 &self,
371 old_name: &str,
372 new_parent: Arc<dyn Inode>,
373 new_name: &str,
374 ) -> Result<(), FsError> {
375 let metadata = self.metadata()?;
389 if metadata.inode_type != InodeType::Directory {
390 return Err(FsError::NotDirectory);
391 }
392
393 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 let new_parent_ext4 = new_parent
403 .as_any()
404 .downcast_ref::<Ext4Inode>()
405 .ok_or(FsError::InvalidArgument)?;
406
407 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 if !Arc::ptr_eq(&self.fs, &new_parent_ext4.fs) {
415 return Err(FsError::InvalidArgument);
416 }
417
418 if old_child_metadata.inode_type == InodeType::Directory {
420 if old_child_ext4.ino == new_parent_ext4.ino {
422 return Err(FsError::InvalidArgument);
423 }
424 }
426
427 let fs = self.fs.lock();
429
430 let mut replaced_inode: Option<u32> = None;
433
434 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 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 if fs.dir_has_entry(existing_ino) {
450 return Err(FsError::DirectoryNotEmpty);
451 }
452
453 fs.dir_remove(new_parent_ext4.ino, new_name)
455 .map_err(|_| FsError::IoError)?;
456 } else {
457 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 replaced_inode = Some(existing_ino);
469 }
470
471 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 if let Err(_e) = fs.dir_add_entry(&mut new_parent_ref, &child_ref, new_name) {
479 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 if let Err(_e) = fs.dir_remove_entry(&mut old_parent_ref, old_name) {
490 let _ = fs.dir_remove_entry(&mut new_parent_ref, new_name);
492
493 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 if old_child_metadata.inode_type == InodeType::Directory && self.ino != new_parent_ext4.ino
507 {
508 let mut child_ref = fs.get_inode_ref(old_child_ext4.ino);
510
511 if let Err(_e) = fs.dir_remove_entry(&mut child_ref, "..") {
513 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 if let Err(_e) = fs.dir_add_entry(&mut child_ref, &new_parent_ref, "..") {
530 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 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 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 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 let entries = fs.dir_get_entries(self.ino);
578
579 let vfs_entries = entries
581 .iter()
582 .map(|e| {
583 let name_len = e.name_len as usize;
585 let name = String::from_utf8_lossy(&e.name[..name_len]).into_owned();
586
587 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 return Ok(());
608 }
609
610 if size < old_size {
611 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 let extend_size = size - old_size;
624 let zero_buf = alloc::vec![0u8; extend_size.min(4096)]; 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 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 let mut inode_ref = fs.get_inode_ref(self.ino);
661 let inode = &mut inode_ref.inode;
662
663 if let Some(at) = atime {
665 inode.atime = at.tv_sec as u32;
666 inode.i_atime_extra = ((at.tv_nsec as u32) << 2) & 0xFFFFFFFC;
669 }
670
671 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 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 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 let mut inode_ref = fs.get_inode_ref(self.ino);
693 let inode = &mut inode_ref.inode;
694
695 if uid != u32::MAX {
697 inode.uid = uid as u16;
698 }
700 if gid != u32::MAX {
701 inode.gid = gid as u16;
702 }
704
705 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 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 let mut inode_ref = fs.get_inode_ref(self.ino);
721 let inode = &mut inode_ref.inode;
722
723 let file_type = inode.mode & 0xF000;
725 let permission_bits = (mode.bits() & 0x0FFF) as u16;
726 inode.mode = file_type | permission_bits;
727
728 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 fs.write_back_inode(&mut inode_ref);
735
736 Ok(())
737 }
738
739 fn readlink(&self) -> Result<String, FsError> {
740 let metadata = self.metadata()?;
742 if metadata.inode_type != InodeType::Symlink {
743 return Err(FsError::InvalidArgument);
744 }
745
746 let size = metadata.size;
748 if size == 0 {
749 return Ok(String::new());
750 }
751
752 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 buf.truncate(bytes_read);
763
764 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 Err(FsError::NotSupported)
771 }
772}