Преглед изворни кода

Started implementing the setattr method.

Matthew Carr пре 2 година
родитељ
комит
b20315d385
4 измењених фајлова са 98 додато и 36 уклоњено
  1. 1 0
      Cargo.lock
  2. 1 0
      crates/btfuse/Cargo.toml
  3. 31 1
      crates/btfuse/src/main.rs
  4. 65 35
      crates/btlib/src/blocktree.rs

+ 1 - 0
Cargo.lock

@@ -145,6 +145,7 @@ dependencies = [
  "btlib",
  "env_logger",
  "fuse-backend-rs",
+ "libc",
  "log",
  "swtpm-harness",
  "tempdir",

+ 1 - 0
crates/btfuse/Cargo.toml

@@ -15,3 +15,4 @@ env_logger = "0.9.0"
 
 [dev-dependencies]
 tempdir = "0.3.7"
+libc = "0.2.137"

+ 31 - 1
crates/btfuse/src/main.rs

@@ -179,7 +179,11 @@ fn main() {
 mod test {
     use std::{
         ffi::{OsStr, OsString},
-        fs::{hard_link, read, read_dir, remove_file, write, ReadDir},
+        fs::{
+            hard_link, metadata, read, read_dir, remove_file, set_permissions, write, Permissions,
+            ReadDir,
+        },
+        os::unix::fs::PermissionsExt,
         sync::mpsc::{channel, Receiver},
         thread::JoinHandle,
         time::Duration,
@@ -279,6 +283,9 @@ mod test {
         }
 
         fn unmount_and_wait(&mut self) {
+            if self.handle.is_none() {
+                return;
+            }
             let mnt_path = self.mnt_path();
             unmount(mnt_path);
             self.wait();
@@ -300,6 +307,7 @@ mod test {
         env_logger::Builder::from_default_env().btformat().init();
         let mut case = TestCase::new();
         case.wait();
+
     }
 
     /// Tests if the file system can be mount then unmounted successfully.
@@ -389,4 +397,26 @@ mod test {
         let expected: [&OsStr; 0] = [];
         assert!(file_names(read_dir(&mnt_path).expect("read_dir failed")).eq(expected));
     }
+
+    #[test]
+    fn set_permissions_bits() {
+        const EXPECTED: u32 = libc::S_IFREG | 0o777;
+        let mut case = TestCase::new();
+        let file_path = case.mnt_path().join("bagobits");
+        write(&file_path, []).expect("write failed");
+        let original = metadata(&file_path)
+            .expect("metadata failed")
+            .permissions()
+            .mode();
+        assert_ne!(EXPECTED, original);
+
+        set_permissions(&file_path, Permissions::from_mode(EXPECTED))
+            .expect("set_permissions failed");
+
+        let actual = metadata(&file_path)
+            .expect("metadata failed")
+            .permissions()
+            .mode();
+        assert_eq!(EXPECTED, actual);
+    }
 }

+ 65 - 35
crates/btlib/src/blocktree.rs

@@ -5,7 +5,7 @@ mod private {
     use fuse_backend_rs::{
         abi::fuse_abi::{stat64, statvfs64, CreateIn},
         api::filesystem::{
-            Context, DirEntry as FuseDirEntry, Entry, FileSystem, FsOptions, OpenOptions,
+            Context, DirEntry as FuseDirEntry, Entry, FileSystem, FsOptions, OpenOptions, SetattrValid,
         },
     };
     use log::{debug, error, warn};
@@ -439,9 +439,9 @@ mod private {
             write_to(&sb, &mut sb_block)?;
             sb_block.mut_meta_body().access_secrets(|secrets| {
                 secrets.inode = SpecInodes::Sb.into();
-                secrets.mode = Self::default_file_mode();
-                secrets.uid = Self::uid();
-                secrets.gid = Self::gid();
+                secrets.mode = FileType::Reg.value() | 0o666;
+                secrets.uid = 0;
+                secrets.gid = 0;
                 secrets.nlink = 1;
                 Ok(())
             })?;
@@ -457,9 +457,9 @@ mod private {
             write_to(&Directory::new(), &mut root_block)?;
             root_block.mut_meta_body().access_secrets(|secrets| {
                 secrets.inode = SpecInodes::RootDir.into();
-                secrets.mode = Self::default_dir_mode();
-                secrets.uid = Self::uid();
-                secrets.gid = Self::gid();
+                secrets.mode = FileType::Dir.value() | 0o777;
+                secrets.uid = 0;
+                secrets.gid = 0;
                 secrets.nlink = 1;
                 Ok(())
             })?;
@@ -559,22 +559,6 @@ mod private {
                 .open()
         }
 
-        fn default_dir_mode() -> u32 {
-            FileType::Dir.value() | 0o755
-        }
-
-        fn default_file_mode() -> u32 {
-            FileType::Reg.value() | 0o644
-        }
-
-        fn uid() -> u32 {
-            unsafe { libc::getuid() }
-        }
-
-        fn gid() -> u32 {
-            unsafe { libc::getgid() }
-        }
-
         /// Returns the [Err] variant containing the [io::Error] corresponding to [libc::ENOSYS].
         fn not_supported<T>() -> io::Result<T> {
             let err = io::Error::from_raw_os_error(libc::ENOSYS);
@@ -1279,6 +1263,64 @@ mod private {
             })
         }
 
+        fn setattr(
+            &self,
+            ctx: &Context,
+            inode: Self::Inode,
+            attr: stat64,
+            _handle: Option<Self::Handle>,
+            valid: SetattrValid,
+        ) -> io::Result<(stat64, Duration)> {
+            debug!("Blocktree::setattr called for inode {inode}");
+            let stat = self.borrow_block(inode, |block| {
+                let ctx = AuthzContext::new(ctx, block.meta());
+                self.authorizer.can_write(&ctx)?;
+
+                let stat = block.mut_meta_body().access_secrets(|secrets| {
+                    if valid.intersects(SetattrValid::MODE) {
+                        secrets.mode = attr.st_mode;
+                    }
+                    if valid.intersects(SetattrValid::UID) {
+                        secrets.uid = attr.st_uid;
+                    }
+                    if valid.intersects(SetattrValid::GID) {
+                        secrets.gid = attr.st_gid;
+                    }
+                    if valid.intersects(SetattrValid::SIZE) {
+                        warn!("modifying file size with setattr is not supported");
+                        return Err(io::Error::from_raw_os_error(libc::EINVAL).into());
+                    }
+                    if valid.intersects(SetattrValid::ATIME) {
+                        secrets.atime = (attr.st_atime as u64).into();
+                    }
+                    if valid.intersects(SetattrValid::MTIME) {
+                        secrets.mtime = (attr.st_mtime as u64).into();
+                    }
+                    if valid.intersects(SetattrValid::CTIME) {
+                        secrets.ctime = (attr.st_ctime as u64).into();
+                    }
+                    let atime_now = valid.intersects(SetattrValid::ATIME_NOW);
+                    let mtime_now = valid.intersects(SetattrValid::MTIME_NOW);
+                    if atime_now || mtime_now {
+                        let now = Epoch::now();
+                        if atime_now {
+                            secrets.atime = now;
+                        }
+                        if mtime_now {
+                            secrets.mtime = now;
+                        }
+                    }
+                    if valid.intersects(SetattrValid::KILL_SUIDGID) {
+                        secrets.mode &= !(libc::S_ISUID | libc::S_ISGID)
+                    }
+                    Ok(secrets.stat())
+                })?;
+                block.flush_meta()?;
+                Ok(stat)
+            })?;
+            Ok((stat, self.attr_timeout()))
+        }
+
         //////////////////////////////////
         // METHODS WHICH ARE NOT SUPPORTED
         //////////////////////////////////
@@ -1474,18 +1516,6 @@ mod private {
             Self::not_supported()
         }
 
-        fn setattr(
-            &self,
-            _ctx: &Context,
-            inode: Self::Inode,
-            _attr: stat64,
-            _handle: Option<Self::Handle>,
-            _valid: fuse_backend_rs::api::filesystem::SetattrValid,
-        ) -> io::Result<(stat64, Duration)> {
-            debug!("Blocktree::setattr called for inode {inode}");
-            Self::not_supported()
-        }
-
         fn setlk(
             &self,
             _ctx: &Context,