Przeglądaj źródła

refactor: inode fields

liujingx 10 miesięcy temu
rodzic
commit
4a4181775c

+ 0 - 1
src/ext4/alloc.rs

@@ -45,7 +45,6 @@ impl Ext4 {
         // Add `.` and `..` entries
         self.dir_add_entry(&mut root, &root_self, ".")?;
         self.dir_add_entry(&mut root, &root_self, "..")?;
-        root.inode.link_count += 2;
 
         self.write_inode_with_csum(&mut root);
         Ok(root)

+ 5 - 11
src/ext4/dir.rs

@@ -7,9 +7,7 @@ impl Ext4 {
     /// Find a directory entry that matches a given name under a parent directory
     pub(super) fn dir_find_entry(&self, dir: &InodeRef, name: &str) -> Result<DirEntry> {
         info!("Dir find entry: dir {}, name {}", dir.id, name);
-        let inode_size: u32 = dir.inode.size;
-        let total_blocks: u32 = inode_size / BLOCK_SIZE as u32;
-
+        let total_blocks: u32 = dir.inode.block_count() as u32;
         let mut iblock: LBlockId = 0;
         while iblock < total_blocks {
             // Get the fs block id
@@ -37,9 +35,8 @@ impl Ext4 {
             "Dir add entry: dir {}, child {}, name {}",
             dir.id, child.id, name
         );
-        let inode_size = dir.inode.size();
-        let total_blocks = inode_size as u32 / BLOCK_SIZE as u32;
-
+        let total_blocks: u32 = dir.inode.block_count() as u32;
+        
         // Try finding a block with enough space
         let mut iblock: LBlockId = 0;
         while iblock < total_blocks {
@@ -69,8 +66,7 @@ impl Ext4 {
     /// Remove a entry from a directory
     pub(super) fn dir_remove_entry(&mut self, dir: &mut InodeRef, name: &str) -> Result<()> {
         info!("Dir remove entry: dir {}, path {}", dir.id, name);
-        let inode_size = dir.inode.size();
-        let total_blocks = inode_size as u32 / BLOCK_SIZE as u32;
+        let total_blocks: u32 = dir.inode.block_count() as u32;
 
         // Check each block
         let mut iblock: LBlockId = 0;
@@ -95,10 +91,8 @@ impl Ext4 {
     /// Get all entries under a directory
     pub(super) fn dir_get_all_entries(&self, dir: &InodeRef) -> Vec<DirEntry> {
         info!("Dir get all entries: dir {}", dir.id);
-        let inode_size: u32 = dir.inode.size;
-        let total_blocks: u32 = inode_size / BLOCK_SIZE as u32;
+        let total_blocks = dir.inode.block_count() as u32;
         let mut entries: Vec<DirEntry> = Vec::new();
-
         let mut iblock: LBlockId = 0;
         while iblock < total_blocks {
             // Get the fs block id

+ 14 - 14
src/ext4/low_level.rs

@@ -75,9 +75,9 @@ impl Ext4 {
     /// TODO: handle EOF
     pub fn read(&mut self, file: InodeId, offset: usize, buf: &mut [u8]) -> Result<usize> {
         // Get the inode of the file
-        let mut inode_ref = self.read_inode(file);
-        if !inode_ref.inode.is_file() {
-            return_error!(ErrCode::EISDIR, "Inode {} is not a file", file);
+        let mut file = self.read_inode(file);
+        if !file.inode.is_file() {
+            return_error!(ErrCode::EISDIR, "Inode {} is not a file", file.id);
         }
 
         // Read no bytes
@@ -85,7 +85,7 @@ impl Ext4 {
             return Ok(0);
         }
         // Calc the actual size to read
-        let read_size = min(buf.len(), inode_ref.inode.size() as usize - offset);
+        let read_size = min(buf.len(), file.inode.size() as usize - offset);
         // Calc the start block of reading
         let start_iblock = (offset / BLOCK_SIZE) as LBlockId;
         // Calc the length that is not aligned to the block size
@@ -97,7 +97,7 @@ impl Ext4 {
         if misaligned > 0 {
             let read_len = min(BLOCK_SIZE - misaligned, read_size);
             let fblock = self
-                .extent_get_pblock(&mut inode_ref, start_iblock)
+                .extent_get_pblock(&mut file, start_iblock)
                 .unwrap();
             let block = self.read_block(fblock);
             // Copy data from block to the user buffer
@@ -108,7 +108,7 @@ impl Ext4 {
         // Continue with full block reads
         while cursor < read_size {
             let read_len = min(BLOCK_SIZE, read_size - cursor);
-            let fblock = self.extent_get_pblock(&mut inode_ref, iblock).unwrap();
+            let fblock = self.extent_get_pblock(&mut file, iblock).unwrap();
             let block = self.read_block(fblock);
             // Copy data from block to the user buffer
             buf[cursor..cursor + read_len].copy_from_slice(block.read_offset(0, read_len));
@@ -139,9 +139,9 @@ impl Ext4 {
     /// TODO: handle EOF
     pub fn write(&mut self, file: InodeId, offset: usize, data: &[u8]) -> Result<usize> {
         // Get the inode of the file
-        let mut inode = self.read_inode(file);
-        if !inode.inode.is_file() {
-            return_error!(ErrCode::EISDIR, "Inode {} is not a file", file);
+        let mut file = self.read_inode(file);
+        if !file.inode.is_file() {
+            return_error!(ErrCode::EISDIR, "Inode {} is not a file", file.id);
         }
 
         let write_size = data.len();
@@ -149,9 +149,9 @@ impl Ext4 {
         let start_iblock = (offset / BLOCK_SIZE) as LBlockId;
         let end_iblock = ((offset + write_size) / BLOCK_SIZE) as LBlockId;
         // Append enough block for writing
-        let append_block_count = (end_iblock + 1) as i64 - inode.inode.block_count() as i64;
+        let append_block_count = (end_iblock + 1) as i64 - file.inode.block_count() as i64;
         for _ in 0..append_block_count {
-            self.inode_append_block(&mut inode)?;
+            self.inode_append_block(&mut file)?;
         }
 
         // Write data
@@ -159,7 +159,7 @@ impl Ext4 {
         let mut iblock = start_iblock;
         while cursor < write_size {
             let write_len = min(BLOCK_SIZE, write_size - cursor);
-            let fblock = self.extent_get_pblock(&mut inode, iblock)?;
+            let fblock = self.extent_get_pblock(&mut file, iblock)?;
             let mut block = self.read_block(fblock);
             block.write_offset(
                 (offset + cursor) % BLOCK_SIZE,
@@ -169,8 +169,8 @@ impl Ext4 {
             cursor += write_len;
             iblock += 1;
         }
-        inode.inode.set_size((offset + cursor) as u64);
-        self.write_inode_with_csum(&mut inode);
+        file.inode.set_size((offset + cursor) as u64);
+        self.write_inode_with_csum(&mut file);
 
         Ok(cursor)
     }

+ 7 - 1
src/ext4_defs/block_device.rs

@@ -4,7 +4,13 @@ use core::any::Any;
 use core::fmt::Debug;
 
 /// Interface for serializing and deserializing objects to and from bytes.
-pub trait AsBytes
+/// 
+/// # Unsafe
+/// 
+/// This trait is unsafe because it allows arbitrary memory interpretation.
+/// Implementor should guarantee the object is saved in the way defined by
+/// functions `from_bytes` and `to_bytes`.
+pub unsafe trait AsBytes
 where
     Self: Sized,
 {

+ 1 - 1
src/ext4_defs/block_group.rs

@@ -44,7 +44,7 @@ pub struct BlockGroupDesc {
     reserved: u32,                   // 填充
 }
 
-impl AsBytes for BlockGroupDesc {}
+unsafe impl AsBytes for BlockGroupDesc {}
 
 impl BlockGroupDesc {
     pub fn block_bitmap_block(&self, s: &SuperBlock) -> PBlockId {

+ 3 - 3
src/ext4_defs/dir_entry.rs

@@ -56,7 +56,7 @@ impl Default for DirEntry {
 
 /// The actual size of the directory entry is determined by `name_len`.
 /// So we need to implement `AsBytes` methods specifically for `DirEntry`.
-impl AsBytes for DirEntry {
+unsafe impl AsBytes for DirEntry {
     fn from_bytes(bytes: &[u8]) -> Self {
         let fake_entry = FakeDirEntry::from_bytes(bytes);
         let mut entry = DirEntry {
@@ -192,7 +192,7 @@ pub struct DirEntryTail {
     pub checksum: u32, // crc32c(uuid+inum+dirblock)
 }
 
-impl AsBytes for DirEntryTail {}
+unsafe impl AsBytes for DirEntryTail {}
 
 impl DirEntryTail {
     pub fn set_csum(&mut self, s: &SuperBlock, diren: &DirEntry, blk_data: &[u8]) {
@@ -209,4 +209,4 @@ pub struct FakeDirEntry {
     inode_type: FileType,
 }
 
-impl AsBytes for FakeDirEntry {}
+unsafe impl AsBytes for FakeDirEntry {}

+ 109 - 51
src/ext4_defs/inode.rs

@@ -84,47 +84,81 @@ impl InodeMode {
 #[repr(C)]
 #[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
 pub struct Linux2 {
-    pub l_i_blocks_high: u16, // 原来是l_i_reserved1
-    pub l_i_file_acl_high: u16,
-    pub l_i_uid_high: u16,    // 这两个字段
-    pub l_i_gid_high: u16,    // 原来是reserved2[0]
-    pub l_i_checksum_lo: u16, // crc32c(uuid+inum+inode) LE
-    pub l_i_reserved: u16,
+    /// Upper 16-bits of the block count. See the note attached to i_blocks_lo.
+    pub l_blocks_hi: u16,
+    /// Upper 16-bits of the extended attribute block.
+    pub l_file_acl_hi: u16,
+    /// Upper 16-bits of the Owner UID.
+    pub l_uid_hi: u16,
+    /// Upper 16-bits of the GID.
+    pub l_gid_hi: u16,
+    /// Lower 16-bits of the inode checksum.
+    pub l_checksum_lo: u16,
+    /// Reserved.
+    pub l_reserved: u16,
 }
 
 #[repr(C)]
 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
 pub struct Inode {
-    pub mode: u16,
-    pub uid: u16,
-    pub size: u32,
-    pub atime: u32,
-    pub ctime: u32,
-    pub mtime: u32,
-    pub dtime: u32,
-    pub gid: u16,
-    pub link_count: u16,
+    /// File mode.
+    mode: u16,
+    /// Lower 16-bits of Owner UID.
+    uid: u16,
+    /// Lower 32-bits of size in bytes.
+    size: u32,
+    /// Last access time, in seconds since the epoch.
+    atime: u32,
+    /// Last inode change time, in seconds since the epoch.
+    ctime: u32,
+    /// Last data modification time, in seconds since the epoch.
+    mtime: u32,
+    /// Deletion Time, in seconds since the epoch.
+    dtime: u32,
+    /// Lower 16-bits of GID.
+    gid: u16,
+    /// Hard link count.
+    link_count: u16,
+    /// Lower 32-bits of "block" count.
     /// Note: this field is different from ext4 inode by now.
     /// Ext4 defines this as the count of 512-byte blocks.
     /// To simplify, we define this as the count of 4096-byte blocks.
-    pub block_count: u32,
-    pub flags: u32,
-    pub osd1: u32,
-    pub block: [u8; 60], // Block bitmap or extent tree
-    pub generation: u32,
-    pub file_acl: u32,
-    pub size_hi: u32,
-    pub faddr: u32,   /* Obsoleted fragment address */
-    pub osd2: Linux2, // 操作系统相关的字段2
-
-    pub extra_isize: u16,
-    pub checksum_hi: u16,  // crc32c(uuid+inum+inode) BE
-    pub ctime_extra: u32,  // 额外的修改时间(nsec << 2 | epoch)
-    pub mtime_extra: u32,  // 额外的文件修改时间(nsec << 2 | epoch)
-    pub atime_extra: u32,  // 额外的访问时间(nsec << 2 | epoch)
-    pub crtime: u32,       // 文件创建时间
-    pub crtime_extra: u32, // 额外的文件创建时间(nsec << 2 | epoch)
-    pub version_hi: u32,   // 64位版本的高32位
+    block_count: u32,
+    /// Inode flags.
+    flags: u32,
+    /// Os related fields 1.
+    osd1: u32,
+    /// Block map or extent tree.
+    block: [u8; 60],
+    /// File version (for NFS).
+    generation: u32,
+    /// Lower 32-bits of extended attribute block.
+    file_acl: u32,
+    /// Upper 32-bits of file/directory size.
+    size_hi: u32,
+    /// (Obsolete) fragment address.
+    faddr: u32,
+    /// Os related fields 2.
+    osd2: Linux2,
+    /// Size of this inode - 128. Alternately, the size of the extended inode
+    /// fields beyond the original ext2 inode, including this field.
+    extra_isize: u16,
+    /// Upper 16-bits of the inode checksum.
+    checksum_hi: u16,
+    /// Extra change time bits. This provides sub-second precision.
+    ctime_extra: u32,
+    /// Extra modification time bits. This provides sub-second precision.
+    mtime_extra: u32,
+    /// Extra access time bits. This provides sub-second precision.
+    atime_extra: u32,
+    /// File creation time, in seconds since the epoch.
+    crtime: u32,
+    /// Extra file creation time bits. This provides sub-second precision.
+    crtime_extra: u32,
+    /// Upper 32-bits for version number.
+    version_hi: u32,
+    /// Project id
+    projid: u32,
 }
 
 /// Because `[u8; 60]` cannot derive `Default`, we implement it manually.
@@ -134,17 +168,9 @@ impl Default for Inode {
     }
 }
 
-impl AsBytes for Inode {}
+unsafe impl AsBytes for Inode {}
 
 impl Inode {
-    pub fn flags(&self) -> u32 {
-        self.flags
-    }
-
-    pub fn set_flags(&mut self, f: u32) {
-        self.flags |= f;
-    }
-
     pub fn mode(&self) -> InodeMode {
         InodeMode::from_bits_truncate(self.mode)
     }
@@ -177,10 +203,18 @@ impl Inode {
         self.link_count = cnt;
     }
 
+    pub fn uid(&self) -> u16 {
+        self.uid
+    }
+
     pub fn set_uid(&mut self, uid: u16) {
         self.uid = uid;
     }
 
+    pub fn gid(&self) -> u16 {
+        self.gid
+    }
+
     pub fn set_gid(&mut self, gid: u16) {
         self.gid = gid;
     }
@@ -194,33 +228,49 @@ impl Inode {
         self.size_hi = (size >> 32) as u32;
     }
 
+    pub fn access_time(&self) -> u32 {
+        self.atime
+    }
+
     pub fn set_access_time(&mut self, access_time: u32) {
         self.atime = access_time;
     }
 
-    pub fn set_change_inode_time(&mut self, change_inode_time: u32) {
-        self.ctime = change_inode_time;
+    pub fn change_time(&self) -> u32 {
+        self.ctime
     }
 
-    pub fn set_modif_time(&mut self, modif_time: u32) {
+    pub fn set_change_time(&mut self, change_time: u32) {
+        self.ctime = change_time;
+    }
+
+    pub fn modify_time(&self) -> u32 {
+        self.mtime
+    }
+
+    pub fn set_modify_time(&mut self, modif_time: u32) {
         self.mtime = modif_time;
     }
 
-    pub fn set_del_time(&mut self, del_time: u32) {
+    pub fn delete_time(&self) -> u32 {
+        self.dtime
+    }
+
+    pub fn set_delete_time(&mut self, del_time: u32) {
         self.dtime = del_time;
     }
 
     pub fn block_count(&self) -> u64 {
         let mut blocks = self.block_count as u64;
-        if self.osd2.l_i_blocks_high != 0 {
-            blocks |= (self.osd2.l_i_blocks_high as u64) << 32;
+        if self.osd2.l_blocks_hi != 0 {
+            blocks |= (self.osd2.l_blocks_hi as u64) << 32;
         }
         blocks
     }
 
     pub fn set_block_count(&mut self, cnt: u64) {
         self.block_count = cnt as u32;
-        self.osd2.l_i_blocks_high = (cnt >> 32) as u16;
+        self.osd2.l_blocks_hi = (cnt >> 32) as u16;
     }
 
     pub fn set_generation(&mut self, generation: u32) {
@@ -231,6 +281,14 @@ impl Inode {
         self.extra_isize = extra_isize;
     }
 
+    pub fn flags(&self) -> u32 {
+        self.flags
+    }
+
+    pub fn set_flags(&mut self, f: u32) {
+        self.flags |= f;
+    }
+
     fn copy_to_byte_slice(&self, slice: &mut [u8]) {
         unsafe {
             let inode_ptr = self as *const Inode as *const u8;
@@ -345,7 +403,7 @@ impl InodeRef {
         let ino_gen = self.inode.generation;
 
         // Preparation: temporarily set bg checksum to 0
-        self.inode.osd2.l_i_checksum_lo = 0;
+        self.inode.osd2.l_checksum_lo = 0;
         self.inode.checksum_hi = 0;
 
         let mut checksum = ext4_crc32c(
@@ -366,7 +424,7 @@ impl InodeRef {
             checksum &= 0xFFFF;
         }
 
-        self.inode.osd2.l_i_checksum_lo = ((checksum << 16) >> 16) as u16;
+        self.inode.osd2.l_checksum_lo = ((checksum << 16) >> 16) as u16;
         if super_block.inode_size() > 128 {
             self.inode.checksum_hi = (checksum >> 16) as u16;
         }

+ 1 - 1
src/ext4_defs/super_block.rs

@@ -112,7 +112,7 @@ pub struct SuperBlock {
     checksum: u32,             // crc32c(superblock)
 }
 
-impl AsBytes for SuperBlock {}
+unsafe impl AsBytes for SuperBlock {}
 
 impl SuperBlock {
     pub fn load_from_disk(block_device: &dyn BlockDevice) -> Self {