ソースを参照

test: simple test and fuse test

liujingx 10 ヶ月 前
コミット
7ce6d56ce2

+ 1 - 1
ext4_fuse/src/block_file.rs

@@ -29,7 +29,7 @@ impl BlockDevice for BlockFile {
     fn write_block(&self, block: &Block) {
         let mut file = &self.0;
         // warn!("write_block {}", block.block_id);
-        let _r = file.seek(SeekFrom::Start(block.block_id * BLOCK_SIZE as u64));
+        let _r = file.seek(SeekFrom::Start(block.id * BLOCK_SIZE as u64));
         let _r = file.write_all(&block.data);
     }
 }

+ 37 - 31
ext4_fuse/src/common.rs

@@ -1,33 +1,8 @@
 use ext4_rs::{
-    DirEntry, FileType as Ext4FileType, InodeRef, OpenFlags, INODE_BLOCK_SIZE,
+    DirEntry, FileAttr as Ext4FileAttr, FileType as Ext4FileType, OpenFlags, INODE_BLOCK_SIZE,
 };
-use fuser::{FileAttr, FileType};
-use std::time::{Duration, SystemTime};
-
-/// A wrapper of ext4_rs::InodeRef
-pub struct FuseInode(pub InodeRef);
-
-impl FuseInode {
-    pub fn get_attr(&self) -> FileAttr {
-        FileAttr {
-            ino: self.0.id as u64,
-            size: self.0.inode.size(),
-            blocks: self.0.inode.blocks_count(),
-            atime: get_time(self.0.inode.atime as u64),
-            mtime: get_time(self.0.inode.mtime as u64),
-            ctime: get_time(self.0.inode.ctime as u64),
-            crtime: SystemTime::UNIX_EPOCH,
-            kind: translate_ftype(self.0.inode.file_type()),
-            perm: self.0.inode.mode().perm_bits(),
-            nlink: self.0.inode.links_cnt() as u32,
-            uid: self.0.inode.uid as u32,
-            gid: self.0.inode.gid as u32,
-            rdev: 0,
-            blksize: INODE_BLOCK_SIZE as u32,
-            flags: 0,
-        }
-    }
-}
+use fuser::{FileAttr, FileType, TimeOrNow};
+use std::time::{Duration, SystemTime, UNIX_EPOCH};
 
 /// File handler for fuse filesystem
 pub struct FileHandler {
@@ -79,15 +54,46 @@ pub fn translate_ftype(file_type: Ext4FileType) -> FileType {
     match file_type {
         Ext4FileType::RegularFile => FileType::RegularFile,
         Ext4FileType::Directory => FileType::Directory,
-        Ext4FileType::SymLink => FileType::Symlink,
         Ext4FileType::CharacterDev => FileType::CharDevice,
         Ext4FileType::BlockDev => FileType::BlockDevice,
         Ext4FileType::Fifo => FileType::NamedPipe,
         Ext4FileType::Socket => FileType::Socket,
+        Ext4FileType::SymLink => FileType::Symlink,
         Ext4FileType::Unknown => FileType::RegularFile,
     }
 }
 
-fn get_time(time: u64) -> SystemTime {
-    SystemTime::UNIX_EPOCH + Duration::from_secs(time)
+pub fn translate_attr(attr: Ext4FileAttr) -> FileAttr {
+    FileAttr {
+        ino: attr.ino as u64,
+        size: attr.size,
+        blocks: attr.blocks,
+        atime: second2sys_time(attr.atime),
+        mtime: second2sys_time(attr.mtime),
+        ctime: second2sys_time(attr.ctime),
+        crtime: second2sys_time(attr.crtime),
+        kind: translate_ftype(attr.ftype),
+        perm: attr.perm.bits(),
+        nlink: attr.links as u32,
+        uid: attr.uid,
+        gid: attr.gid,
+        rdev: 0,
+        blksize: INODE_BLOCK_SIZE as u32,
+        flags: 0,
+    }
+}
+
+pub fn sys_time2second(time: SystemTime) -> u32 {
+    time.duration_since(UNIX_EPOCH).unwrap().as_secs() as u32
 }
+
+pub fn second2sys_time(time: u32) -> SystemTime {
+    SystemTime::UNIX_EPOCH + Duration::from_secs(time as u64)
+}
+
+pub fn time_or_now2second(time_or_now: TimeOrNow) -> u32 {
+    match time_or_now {
+        fuser::TimeOrNow::Now => sys_time2second(SystemTime::now()),
+        fuser::TimeOrNow::SpecificTime(time) => sys_time2second(time),
+    }
+}

+ 89 - 23
ext4_fuse/src/fuse_fs.rs

@@ -10,11 +10,13 @@
 //! See `fuse_lowlevel_ops` in C FUSE library for details.
 //! https://libfuse.github.io/doxygen/structfuse__lowlevel__ops.html
 
-use super::common::{translate_ftype, DirHandler, FileHandler, FuseInode};
-use ext4_rs::{DirEntry, ErrCode, Ext4, InodeMode, OpenFlags};
+use super::common::{
+    sys_time2second, time_or_now2second, translate_attr, translate_ftype, DirHandler, FileHandler,
+};
+use ext4_rs::{DirEntry, ErrCode, Ext4, Ext4Error, InodeMode, OpenFlags};
 use fuser::{
-    Filesystem, ReplyAttr, ReplyCreate, ReplyData, ReplyEmpty, ReplyEntry, ReplyOpen, ReplyWrite,
-    Request,
+    FileAttr, FileType, Filesystem, ReplyAttr, ReplyCreate, ReplyData, ReplyEmpty, ReplyEntry,
+    ReplyOpen, ReplyWrite, Request,
 };
 use std::ffi::OsStr;
 use std::time::Duration;
@@ -41,43 +43,83 @@ impl Ext4FuseFs {
     }
 
     /// Add a file handler to file list
-    pub fn add_file(&mut self, inode: u32, flags: OpenFlags) -> FId {
+    fn add_file(&mut self, inode: u32, flags: OpenFlags) -> FId {
         self.files
             .push(FileHandler::new(self.next_did, inode, flags));
         self.next_fid += 1;
         self.next_fid - 1
     }
 
-    pub fn release_file(&mut self, fh: FId) {
+    fn release_file(&mut self, fh: FId) {
         self.files.retain(|f| f.id != fh);
     }
 
     /// Add a directory handler to directory list
-    pub fn add_dir(&mut self, entries: Vec<DirEntry>) -> FId {
+    fn add_dir(&mut self, entries: Vec<DirEntry>) -> FId {
         self.dirs.push(DirHandler::new(self.next_did, entries));
         self.next_did += 1;
         self.next_did - 1
     }
 
-    pub fn release_dir(&mut self, did: FId) {
+    fn release_dir(&mut self, did: FId) {
         self.dirs.retain(|d| d.id != did);
     }
+
+    fn get_attr(&self, inode: u32) -> Result<FileAttr, Ext4Error> {
+        match self.fs.getattr(inode) {
+            Ok(attr) => Ok(translate_attr(attr)),
+            Err(e) => Err(e),
+        }
+    }
 }
 
 impl Filesystem for Ext4FuseFs {
     fn lookup(&mut self, _req: &Request<'_>, parent: u64, name: &OsStr, reply: ReplyEntry) {
         match self.fs.lookup(parent as u32, name.to_str().unwrap()) {
-            Ok(inode_id) => {
-                let inode = self.fs.inode(inode_id);
-                reply.entry(&get_ttl(), &FuseInode(inode).get_attr(), 0)
-            }
+            Ok(inode_id) => reply.entry(&get_ttl(), &self.get_attr(inode_id).unwrap(), 0),
             Err(e) => reply.error(e.code() as i32),
         }
     }
 
     fn getattr(&mut self, _req: &Request<'_>, ino: u64, reply: ReplyAttr) {
-        let inode = self.fs.inode(ino as u32);
-        reply.attr(&get_ttl(), &FuseInode(inode).get_attr())
+        match self.get_attr(ino as u32) {
+            Ok(attr) => reply.attr(&get_ttl(), &attr),
+            Err(e) => reply.error(e.code() as i32),
+        }
+    }
+
+    fn setattr(
+        &mut self,
+        _req: &Request<'_>,
+        ino: u64,
+        mode: Option<u32>,
+        uid: Option<u32>,
+        gid: Option<u32>,
+        size: Option<u64>,
+        atime: Option<fuser::TimeOrNow>,
+        mtime: Option<fuser::TimeOrNow>,
+        ctime: Option<std::time::SystemTime>,
+        _fh: Option<u64>,
+        crtime: Option<std::time::SystemTime>,
+        _chgtime: Option<std::time::SystemTime>,
+        _bkuptime: Option<std::time::SystemTime>,
+        _flags: Option<u32>,
+        reply: ReplyAttr,
+    ) {
+        match self.fs.setattr(
+            ino as u32,
+            mode.map(|m| InodeMode::from_bits_truncate(m as u16)),
+            uid,
+            gid,
+            size,
+            atime.map(|t| time_or_now2second(t)),
+            mtime.map(|t| time_or_now2second(t)),
+            ctime.map(|t| sys_time2second(t)),
+            crtime.map(|t| sys_time2second(t)),
+        ) {
+            Ok(_) => reply.attr(&get_ttl(), &self.get_attr(ino as u32).unwrap()),
+            Err(e) => reply.error(e.code() as i32),
+        }
     }
 
     fn create(
@@ -97,17 +139,21 @@ impl Filesystem for Ext4FuseFs {
         ) {
             Ok(ino) => {
                 let fid = self.add_file(ino, OpenFlags::from_bits_truncate(flags as u32));
-                let inode = self.fs.inode(ino);
-                reply.created(&get_ttl(), &FuseInode(inode).get_attr(), 0, fid, 0);
+                reply.created(&get_ttl(), &self.get_attr(ino).unwrap(), 0, fid, 0);
             }
             Err(e) => reply.error(e.code() as i32),
         }
     }
 
     fn open(&mut self, _req: &Request<'_>, ino: u64, flags: i32, reply: ReplyOpen) {
-        let inode = self.fs.inode(ino as u32);
-        if !inode.inode.is_file() {
-            return reply.error(ErrCode::EISDIR as i32);
+        let attr = self.get_attr(ino as u32);
+        match attr {
+            Ok(attr) => {
+                if attr.kind != FileType::RegularFile {
+                    return reply.error(ErrCode::EISDIR as i32);
+                }
+            }
+            Err(e) => return reply.error(e.code() as i32),
         }
         let fid = self.add_file(ino as u32, OpenFlags::from_bits_truncate(flags as u32));
         reply.opened(fid, 0);
@@ -179,7 +225,7 @@ impl Filesystem for Ext4FuseFs {
             .fs
             .link(ino as u32, newparent as u32, newname.to_str().unwrap())
         {
-            Ok(inode) => reply.entry(&get_ttl(), &FuseInode(inode).get_attr(), 0),
+            Ok(_) => reply.entry(&get_ttl(), &self.get_attr(ino as u32).unwrap(), 0),
             Err(e) => reply.error(e.code() as i32),
         }
     }
@@ -191,6 +237,27 @@ impl Filesystem for Ext4FuseFs {
         }
     }
 
+    fn rename(
+        &mut self,
+        _req: &Request<'_>,
+        parent: u64,
+        name: &OsStr,
+        newparent: u64,
+        newname: &OsStr,
+        _flags: u32,
+        reply: ReplyEmpty,
+    ) {
+        match self.fs.rename(
+            parent as u32,
+            name.to_str().unwrap(),
+            newparent as u32,
+            newname.to_str().unwrap(),
+        ) {
+            Ok(_) => reply.ok(),
+            Err(e) => reply.error(e.code() as i32),
+        }
+    }
+
     fn mkdir(
         &mut self,
         _req: &Request<'_>,
@@ -205,7 +272,7 @@ impl Filesystem for Ext4FuseFs {
             name.to_str().unwrap(),
             InodeMode::from_bits_truncate(mode as u16),
         ) {
-            Ok(inode) => reply.entry(&get_ttl(), &FuseInode(inode).get_attr(), 0),
+            Ok(ino) => reply.entry(&get_ttl(), &self.get_attr(ino).unwrap(), 0),
             Err(e) => reply.error(e.code() as i32),
         }
     }
@@ -237,11 +304,10 @@ impl Filesystem for Ext4FuseFs {
                         break;
                     }
                     let entry = entry.unwrap();
-                    let inode = self.fs.inode(entry.inode());
                     if reply.add(
                         ino,
                         dir.cur as i64,
-                        translate_ftype(inode.inode.file_type()),
+                        translate_ftype(self.fs.getattr(entry.inode()).unwrap().ftype),
                         entry.name().unwrap(),
                     ) {
                         break;

+ 1 - 1
ext4_test/src/block_file.rs

@@ -29,7 +29,7 @@ impl BlockDevice for BlockFile {
     fn write_block(&self, block: &Block) {
         let mut file = &self.0;
         // warn!("write_block {}", block.block_id);
-        let _r = file.seek(SeekFrom::Start(block.block_id * BLOCK_SIZE as u64));
+        let _r = file.seek(SeekFrom::Start(block.id * BLOCK_SIZE as u64));
         let _r = file.write_all(&block.data);
     }
 }

+ 5 - 5
ext4_test/src/main.rs

@@ -64,13 +64,13 @@ fn read_write_test(ext4: &mut Ext4) {
         .expect("open failed");
     ext4.write(wfile.inode, 0, wbuffer).expect("write failed");
 
-    let mut rbuffer = vec![0u8; wbuffer.len()];
+    let mut rbuffer = vec![0u8; wbuffer.len() + 100]; // Test end of file
     let rfile = ext4
         .generic_open(ROOT_INO, "d3/f0", OpenFlags::O_RDONLY)
         .expect("open failed");
-    ext4.read(wfile.inode, 0, &mut rbuffer).expect("read failed");
+    let rcount = ext4.read(rfile.inode, 0, &mut rbuffer).expect("read failed");
 
-    assert_eq!(wbuffer, rbuffer);
+    assert_eq!(wbuffer, &rbuffer[..rcount]);
 }
 
 fn large_read_write_test(ext4: &mut Ext4) {
@@ -84,9 +84,9 @@ fn large_read_write_test(ext4: &mut Ext4) {
         .generic_open(ROOT_INO, "d3/f1", OpenFlags::O_RDONLY)
         .expect("open failed");
     let mut rbuffer = vec![0u8; wbuffer.len()];
-    ext4.read(rfile.inode, 0,&mut rbuffer).expect("read failed");
+    let rcount = ext4.read(rfile.inode, 0,&mut rbuffer).expect("read failed");
 
-    assert_eq!(wbuffer, rbuffer);
+    assert_eq!(wbuffer, &rbuffer[..rcount]);
 }
 
 fn remove_file_test(ext4: &mut Ext4) {