liujingx 10 mēneši atpakaļ
vecāks
revīzija
932ffc4f37
4 mainītis faili ar 152 papildinājumiem un 50 dzēšanām
  1. 1 1
      src/ext4/high_level.rs
  2. 95 24
      src/ext4/low_level.rs
  3. 54 24
      src/ext4_defs/inode.rs
  4. 2 1
      src/lib.rs

+ 1 - 1
src/ext4/high_level.rs

@@ -54,7 +54,7 @@ impl Ext4 {
         flags: OpenFlags,
     ) -> Result<FileHandler> {
         let inode_id = self.generic_lookup(root, path)?;
-        let inode = self.inode(inode_id);
+        let inode = self.read_inode(inode_id);
         // Check file type
         if !inode.inode.is_file() {
             return_error!(ErrCode::EISDIR, "File {} is not a regular file", path);

+ 95 - 24
src/ext4/low_level.rs

@@ -11,7 +11,7 @@ use crate::return_error;
 use core::cmp::min;
 
 impl Ext4 {
-    /// Read an indoe
+    /// Get file attributes.
     ///
     /// # Params
     ///
@@ -19,9 +19,91 @@ impl Ext4 {
     ///
     /// # Return
     ///
-    /// An inode reference, combing id and the inode itself
-    pub fn inode(&self, id: InodeId) -> InodeRef {
-        self.read_inode(id)
+    /// A file attribute struct.
+    ///
+    /// # Error
+    ///
+    /// `EINVAL` if the inode is invalid (mode == 0).
+    pub fn getattr(&self, id: InodeId) -> Result<FileAttr> {
+        let inode = self.read_inode(id);
+        if inode.inode.mode().bits() == 0 {
+            return_error!(ErrCode::EINVAL, "Invalid inode");
+        }
+        Ok(FileAttr {
+            ino: id,
+            size: inode.inode.size(),
+            blocks: inode.inode.block_count(),
+            atime: inode.inode.atime(),
+            mtime: inode.inode.mtime(),
+            ctime: inode.inode.ctime(),
+            crtime: inode.inode.crtime(),
+            ftype: inode.inode.file_type(),
+            perm: inode.inode.perm(),
+            links: inode.inode.link_count(),
+            uid: inode.inode.uid(),
+            gid: inode.inode.gid(),
+        })
+    }
+
+    /// Set file attributes.
+    ///
+    /// # Params
+    ///
+    /// * `id` - inode id
+    /// * `mode` - file mode
+    /// * `uid` - 32-bit user id
+    /// * `gid` - 32-bit group id
+    /// * `size` - 64-bit file size
+    /// * `atime` - 32-bit access time in seconds
+    /// * `mtime` - 32-bit modify time in seconds
+    /// * `ctime` - 32-bit change time in seconds
+    /// * `crtime` - 32-bit create time in seconds
+    ///
+    /// # Error
+    ///
+    /// `EINVAL` if the inode is invalid (mode == 0).
+    pub fn setattr(
+        &mut self,
+        id: InodeId,
+        mode: Option<InodeMode>,
+        uid: Option<u32>,
+        gid: Option<u32>,
+        size: Option<u64>,
+        atime: Option<u32>,
+        mtime: Option<u32>,
+        ctime: Option<u32>,
+        crtime: Option<u32>,
+    ) -> Result<()> {
+        let mut inode = self.read_inode(id);
+        if inode.inode.mode().bits() == 0 {
+            return_error!(ErrCode::EINVAL, "Invalid inode");
+        }
+        if let Some(mode) = mode {
+            inode.inode.set_mode(mode);
+        }
+        if let Some(uid) = uid {
+            inode.inode.set_uid(uid);
+        }
+        if let Some(gid) = gid {
+            inode.inode.set_gid(gid);
+        }
+        if let Some(size) = size {
+            inode.inode.set_size(size);
+        }
+        if let Some(atime) = atime {
+            inode.inode.set_atime(atime);
+        }
+        if let Some(mtime) = mtime {
+            inode.inode.set_mtime(mtime);
+        }
+        if let Some(ctime) = ctime {
+            inode.inode.set_ctime(ctime);
+        }
+        if let Some(crtime) = crtime {
+            inode.inode.set_crtime(crtime);
+        }
+        self.write_inode_with_csum(&mut inode);
+        Ok(())
     }
 
     /// Create and open a file. This function will not check the existence
@@ -71,8 +153,6 @@ impl Ext4 {
     /// # Error
     ///
     /// * `EISDIR` - `file` is not a regular file
-    ///
-    /// 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 file = self.read_inode(file);
@@ -96,9 +176,7 @@ impl Ext4 {
         // Read first block
         if misaligned > 0 {
             let read_len = min(BLOCK_SIZE - misaligned, read_size);
-            let fblock = self
-                .extent_get_pblock(&mut file, start_iblock)
-                .unwrap();
+            let fblock = self.extent_get_pblock(&mut file, start_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(misaligned, read_len));
@@ -134,9 +212,7 @@ impl Ext4 {
     /// # Error
     ///
     /// * `EISDIR` - `file` is not a regular file
-    /// `ENOSPC` - no space left on device
-    ///
-    /// TODO: handle EOF
+    /// * `ENOSPC` - no space left on device
     pub fn write(&mut self, file: InodeId, offset: usize, data: &[u8]) -> Result<usize> {
         // Get the inode of the file
         let mut file = self.read_inode(file);
@@ -183,15 +259,11 @@ impl Ext4 {
     /// * `child` - the inode of the file to link
     /// * `parent` - the inode of the directory to link to
     ///
-    /// # Return
-    ///
-    /// `Ok(child)` - An inode reference to the child inode.
-    ///
     /// # Error
     ///
     /// * `ENOTDIR` - `parent` is not a directory
     /// * `ENOSPC` - no space left on device
-    pub fn link(&mut self, child: InodeId, parent: InodeId, name: &str) -> Result<InodeRef> {
+    pub fn link(&mut self, child: InodeId, parent: InodeId, name: &str) -> Result<()> {
         let mut parent = self.read_inode(parent);
         // Can only link to a directory
         if !parent.inode.is_dir() {
@@ -199,7 +271,7 @@ impl Ext4 {
         }
         let mut child = self.read_inode(child);
         self.link_inode(&mut parent, &mut child, name)?;
-        Ok(child)
+        Ok(())
     }
 
     /// Unlink a file.
@@ -277,13 +349,13 @@ impl Ext4 {
     ///
     /// # Return
     ///
-    /// `Ok(child)` - An inode reference to the new directory.
+    /// `Ok(child)` - the inode id of the created directory
     ///
     /// # Error
     ///
     /// * `ENOTDIR` - `parent` is not a directory
     /// * `ENOSPC` - no space left on device
-    pub fn mkdir(&mut self, parent: InodeId, name: &str, mode: InodeMode) -> Result<InodeRef> {
+    pub fn mkdir(&mut self, parent: InodeId, name: &str, mode: InodeMode) -> Result<InodeId> {
         let mut parent = self.read_inode(parent);
         // Can only create a directory in a directory
         if !parent.inode.is_dir() {
@@ -294,8 +366,7 @@ impl Ext4 {
         let mut child = self.create_inode(mode)?;
         // Link the new inode
         self.link_inode(&mut parent, &mut child, name)?;
-
-        Ok(child)
+        Ok(child.id)
     }
 
     /// Look up a directory entry by name.
@@ -307,7 +378,7 @@ impl Ext4 {
     ///
     /// # Return
     ///
-    /// `Ok(child)`: The inode id to which the directory entry points.
+    /// `Ok(child)`- the inode id to which the directory entry points.
     ///
     /// # Error
     ///
@@ -331,7 +402,7 @@ impl Ext4 {
     ///
     /// # Return
     ///
-    /// `Ok(entries)` - A vector of directory entries in the directory.
+    /// `Ok(entries)` - a vector of directory entries in the directory.
     ///
     /// # Error
     ///

+ 54 - 24
src/ext4_defs/inode.rs

@@ -63,8 +63,8 @@ impl InodeMode {
         }) | (perm & InodeMode::PERM_MASK)
     }
     /// Get permission bits of an inode mode.
-    pub fn perm_bits(&self) -> u16 {
-        (*self & InodeMode::PERM_MASK).bits() as u16
+    pub fn perm(&self) -> InodeMode {
+        *self & InodeMode::PERM_MASK
     }
     /// Get the file type of an inode mode.
     pub fn file_type(&self) -> FileType {
@@ -81,8 +81,24 @@ impl InodeMode {
     }
 }
 
+#[derive(Debug, Clone)]
+pub struct FileAttr {
+    pub ino: InodeId,
+    pub size: u64,
+    pub atime: u32,
+    pub mtime: u32,
+    pub ctime: u32,
+    pub crtime: u32,
+    pub blocks: u64,
+    pub ftype: FileType,
+    pub perm: InodeMode,
+    pub links: u16,
+    pub uid: u32,
+    pub gid: u32,
+}
+
 #[repr(C)]
-#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
+#[derive(Debug, Clone)]
 pub struct Linux2 {
     /// Upper 16-bits of the block count. See the note attached to i_blocks_lo.
     pub l_blocks_hi: u16,
@@ -99,7 +115,7 @@ pub struct Linux2 {
 }
 
 #[repr(C)]
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+#[derive(Debug, Clone)]
 pub struct Inode {
     /// File mode.
     mode: u16,
@@ -195,6 +211,10 @@ impl Inode {
         self.file_type() == FileType::SymLink
     }
 
+    pub fn perm(&self) -> InodeMode {
+        self.mode().perm()
+    }
+
     pub fn link_count(&self) -> u16 {
         self.link_count
     }
@@ -203,20 +223,22 @@ impl Inode {
         self.link_count = cnt;
     }
 
-    pub fn uid(&self) -> u16 {
-        self.uid
+    pub fn uid(&self) -> u32 {
+        self.uid as u32 | ((self.osd2.l_uid_hi as u32) << 16)
     }
 
-    pub fn set_uid(&mut self, uid: u16) {
-        self.uid = uid;
+    pub fn set_uid(&mut self, uid: u32) {
+        self.uid = uid as u16;
+        self.osd2.l_uid_hi = (uid >> 16) as u16;
     }
 
-    pub fn gid(&self) -> u16 {
-        self.gid
+    pub fn gid(&self) -> u32 {
+        self.gid as u32 | ((self.osd2.l_gid_hi as u32) << 16)
     }
 
-    pub fn set_gid(&mut self, gid: u16) {
-        self.gid = gid;
+    pub fn set_gid(&mut self, gid: u32) {
+        self.gid = gid as u16;
+        self.osd2.l_gid_hi = (gid >> 16) as u16;
     }
 
     pub fn size(&self) -> u64 {
@@ -228,36 +250,44 @@ impl Inode {
         self.size_hi = (size >> 32) as u32;
     }
 
-    pub fn access_time(&self) -> u32 {
+    pub fn atime(&self) -> u32 {
         self.atime
     }
 
-    pub fn set_access_time(&mut self, access_time: u32) {
-        self.atime = access_time;
+    pub fn set_atime(&mut self, atime: u32) {
+        self.atime = atime;
     }
 
-    pub fn change_time(&self) -> u32 {
+    pub fn ctime(&self) -> u32 {
         self.ctime
     }
 
-    pub fn set_change_time(&mut self, change_time: u32) {
-        self.ctime = change_time;
+    pub fn set_ctime(&mut self, ctime: u32) {
+        self.ctime = ctime;
     }
 
-    pub fn modify_time(&self) -> u32 {
+    pub fn mtime(&self) -> u32 {
         self.mtime
     }
 
-    pub fn set_modify_time(&mut self, modif_time: u32) {
-        self.mtime = modif_time;
+    pub fn set_mtime(&mut self, mtime: u32) {
+        self.mtime = mtime;
     }
 
-    pub fn delete_time(&self) -> u32 {
+    pub fn dtime(&self) -> u32 {
         self.dtime
     }
 
-    pub fn set_delete_time(&mut self, del_time: u32) {
-        self.dtime = del_time;
+    pub fn set_dtime(&mut self, dtime: u32) {
+        self.dtime = dtime;
+    }
+
+    pub fn crtime(&self) -> u32 {
+        self.crtime
+    }
+
+    pub fn set_crtime(&mut self, crtime: u32) {
+        self.crtime = crtime;
     }
 
     pub fn block_count(&self) -> u64 {

+ 2 - 1
src/lib.rs

@@ -12,5 +12,6 @@ pub use constants::{BLOCK_SIZE, EXT4_ROOT_INO, INODE_BLOCK_SIZE};
 pub use error::{ErrCode, Ext4Error};
 pub use ext4::Ext4;
 pub use ext4_defs::{
-    Block, BlockDevice, DirEntry, FileHandler, FileType, Inode, InodeMode, InodeRef, OpenFlags,
+    Block, BlockDevice, DirEntry, FileAttr, FileHandler, FileType, Inode, InodeMode, InodeRef,
+    OpenFlags,
 };