From 76ac602c3d79bb39c133c81a38425a77bc0b8b1f Mon Sep 17 00:00:00 2001
From: Chuyan Zhang <me@zcy.moe>
Date: Sat, 25 Nov 2023 02:13:22 -0800
Subject: Some FUSE callbacks, some POSIX interface implementation

---
 src/utils/constants.rs   |  1 +
 src/utils/mod.rs         | 61 ++++++++++++++++++++++++++++++++++++++++++++++-
 src/utils/permissions.rs | 62 ++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 123 insertions(+), 1 deletion(-)
 create mode 100644 src/utils/constants.rs
 create mode 100644 src/utils/permissions.rs

(limited to 'src/utils')

diff --git a/src/utils/constants.rs b/src/utils/constants.rs
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/src/utils/constants.rs
@@ -0,0 +1 @@
+
diff --git a/src/utils/mod.rs b/src/utils/mod.rs
index 60b09f2..0a9b825 100644
--- a/src/utils/mod.rs
+++ b/src/utils/mod.rs
@@ -1,7 +1,10 @@
+mod constants;
+pub mod permissions;
+
 use crate::block_device::BLOCK_SIZE;
 use crate::disk::inode::{Inode, INODE_SIZE};
 use crate::{AyaFS, INODE_PER_BLOCK};
-use fuser::FileAttr;
+use fuser::{FileAttr, FileType};
 use std::time::{Duration, SystemTime, UNIX_EPOCH};
 
 pub(crate) fn time_now() -> u32 {
@@ -42,6 +45,62 @@ pub(crate) fn to_systime(time: u32) -> SystemTime {
     UNIX_EPOCH + Duration::from_secs(time as u64)
 }
 
+// File type code, one of:
+// 0x0 	Unknown.
+// 0x1 	Regular file.
+// 0x2 	Directory.
+// 0x3 	Character device file.
+// 0x4 	Block device file.
+// 0x5 	FIFO.
+// 0x6 	Socket.
+// 0x7 	Symbolic link.
+
+pub(crate) fn from_filetype(file_type: FileType) -> u8 {
+    match file_type {
+        FileType::NamedPipe => 0x5,
+        FileType::CharDevice => 0x3,
+        FileType::BlockDevice => 0x4,
+        FileType::Directory => 0x2,
+        FileType::RegularFile => 0x1,
+        FileType::Symlink => 0x7,
+        FileType::Socket => 0x6,
+    }
+}
+
+pub(crate) fn to_filetype(file_type: u8) -> Option<FileType> {
+    match file_type {
+        0x0 => None,
+        0x1 => Some(FileType::RegularFile),
+        0x2 => Some(FileType::Directory),
+        0x3 => Some(FileType::CharDevice),
+        0x4 => Some(FileType::BlockDevice),
+        0x5 => Some(FileType::NamedPipe),
+        0x6 => Some(FileType::Socket),
+        0x7 => Some(FileType::Symlink),
+        _ => panic!("bad filetype"),
+    }
+}
+
+pub(crate) fn to_fileattr(inode_index: usize, inode: &Inode) -> FileAttr {
+    FileAttr {
+        ino: inode_index as u64,
+        size: inode.size as u64,
+        blocks: inode.n_blocks as u64,
+        atime: to_systime(inode.atime),
+        mtime: to_systime(inode.mtime),
+        ctime: to_systime(inode.ctime),
+        crtime: to_systime(inode.crtime),
+        kind: inode.mode.into(),
+        perm: inode.mode.perm(),
+        nlink: inode.n_links as u32,
+        uid: inode.uid,
+        gid: inode.gid,
+        rdev: 0,
+        blksize: BLOCK_SIZE as u32,
+        flags: inode.flags,
+    }
+}
+
 impl AyaFS {
     /// 输入 inode 编号, 返回它对应的 block number 和 block 内 offset
     pub(crate) fn locate_inode(&self, inode_index: usize) -> (usize, usize) {
diff --git a/src/utils/permissions.rs b/src/utils/permissions.rs
new file mode 100644
index 0000000..a3afe77
--- /dev/null
+++ b/src/utils/permissions.rs
@@ -0,0 +1,62 @@
+use std::fs::File;
+use std::io::BufRead;
+use libc::{F_OK, S_ISGID, S_ISUID, S_IXGRP, X_OK};
+use crate::disk::inode::InodeMode;
+
+pub(crate) fn get_groups(pid: u32) -> Vec<u32> {
+    let file = File::open(format!("/proc/{pid}/task/{pid}/status"))
+        .expect(format!("pid {pid} incorrect!").as_str());
+    for line in std::io::BufReader::new(file).lines() {
+        let line = line.unwrap();
+        if line.starts_with("Groups:") {
+            return line["Groups: ".len()..]
+                .split(' ')
+                .filter(|x| !x.trim().is_empty())
+                .map(|x| x.parse::<u32>().unwrap())
+                .collect();
+        }
+    }
+
+    Vec::new()
+}
+
+pub(crate) fn clear_suid_sgid(mut mode: InodeMode) -> InodeMode {
+    mode.0 &= !S_ISUID as u16;
+    if mode.0 & S_IXGRP as u16 != 0 {
+        mode.0 &= !S_ISGID as u16;
+    }
+    mode
+}
+
+pub(crate) fn check_access(
+    incoming_uid: u32,
+    incoming_gid: u32,
+    uid: u32,
+    gid: u32,
+    perm: InodeMode,
+    mut mask: i32,
+) -> bool {
+    if mask == F_OK {
+        return true;
+    }
+
+    let perm = i32::from(perm.0);
+    // root
+    if incoming_uid == 0 {
+        // 读写任何东西都是可以的, 执行只有 IXOTH/IXGRP/IXUSR 之一设置才可以
+        mask &= X_OK;
+        mask -= mask & (perm >> 6);
+        mask -= mask & (perm >> 3);
+        mask -= mask & perm;
+        return mask == 0;
+    }
+
+    if incoming_uid == uid {
+        mask -= mask & (perm >> 6);
+    } else if incoming_gid == gid {
+        mask -= mask & (perm >> 3);
+    } else {
+        mask -= mask & perm;
+    }
+    mask == 0
+}
\ No newline at end of file
-- 
cgit v1.2.3-70-g09d2