mirror of
https://github.com/hexagonal-sun/moss-kernel.git
synced 2026-04-17 21:58:54 -04:00
distinguish between file permissions and file mode
This commit is contained in:
@@ -41,6 +41,28 @@ bitflags! {
|
||||
|
||||
const S_ISGID = 0x0400;
|
||||
const S_ISUID = 0x0800;
|
||||
}
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct FileMode: u16 {
|
||||
const S_IXOTH = 0x0001;
|
||||
const S_IWOTH = 0x0002;
|
||||
const S_IROTH = 0x0004;
|
||||
|
||||
const S_IXGRP = 0x0008;
|
||||
const S_IWGRP = 0x0010;
|
||||
const S_IRGRP = 0x0020;
|
||||
|
||||
const S_IXUSR = 0x0040;
|
||||
const S_IWUSR = 0x0080;
|
||||
const S_IRUSR = 0x0100;
|
||||
|
||||
const S_ISVTX = 0x0200;
|
||||
|
||||
const S_ISGID = 0x0400;
|
||||
const S_ISUID = 0x0800;
|
||||
|
||||
// Mutually-exclusive file types:
|
||||
const S_IFIFO = 0x1000;
|
||||
@@ -53,6 +75,28 @@ bitflags! {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<FileMode> for FilePermissions {
|
||||
fn from(mode: FileMode) -> Self {
|
||||
FilePermissions::from_bits_truncate(mode.bits())
|
||||
}
|
||||
}
|
||||
|
||||
impl FileMode {
|
||||
pub fn new(file_type: FileType, permissions: FilePermissions) -> Self {
|
||||
let mut mode = FileMode::from_bits_truncate(permissions.bits());
|
||||
mode |= match file_type {
|
||||
FileType::Directory => FileMode::S_IFDIR,
|
||||
FileType::File => FileMode::S_IFREG,
|
||||
FileType::Symlink => FileMode::S_IFLNK,
|
||||
FileType::BlockDevice(_) => FileMode::S_IFBLK,
|
||||
FileType::CharDevice(_) => FileMode::S_IFCHR,
|
||||
FileType::Fifo => FileMode::S_IFIFO,
|
||||
FileType::Socket => FileMode::S_IFSOCK,
|
||||
};
|
||||
mode
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents file metadata, similar to `stat`.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct FileAttr {
|
||||
@@ -65,12 +109,18 @@ pub struct FileAttr {
|
||||
pub mtime: Duration, // Modification time
|
||||
pub ctime: Duration, // Change time
|
||||
pub file_type: FileType,
|
||||
pub mode: FilePermissions,
|
||||
pub permissions: FilePermissions,
|
||||
pub nlinks: u32,
|
||||
pub uid: Uid,
|
||||
pub gid: Gid,
|
||||
}
|
||||
|
||||
impl FileAttr {
|
||||
pub fn mode(&self) -> FileMode {
|
||||
FileMode::new(self.file_type, self.permissions)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for FileAttr {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
@@ -83,7 +133,7 @@ impl Default for FileAttr {
|
||||
mtime: Duration::new(0, 0),
|
||||
ctime: Duration::new(0, 0),
|
||||
file_type: FileType::File,
|
||||
mode: FilePermissions::empty(),
|
||||
permissions: FilePermissions::empty(),
|
||||
nlinks: 1,
|
||||
uid: Uid::new_root(),
|
||||
gid: Gid::new_root_group(),
|
||||
@@ -116,7 +166,7 @@ impl FileAttr {
|
||||
if uid.is_root() {
|
||||
if requested_mode.contains(AccessMode::X_OK) {
|
||||
// Root still needs at least one execute bit to be set for X_OK
|
||||
if self.mode.intersects(
|
||||
if self.permissions.intersects(
|
||||
FilePermissions::S_IXUSR | FilePermissions::S_IXGRP | FilePermissions::S_IXOTH,
|
||||
) {
|
||||
return Ok(());
|
||||
@@ -129,13 +179,13 @@ impl FileAttr {
|
||||
// Determine which set of permission bits to use (owner, group, or other)
|
||||
let perms_to_check = if self.uid == uid {
|
||||
// User is the owner
|
||||
self.mode
|
||||
self.permissions
|
||||
} else if self.gid == gid {
|
||||
// User is in the file's group. Shift group bits to align with owner bits for easier checking.
|
||||
FilePermissions::from_bits_truncate(self.mode.bits() << 3)
|
||||
FilePermissions::from_bits_truncate(self.permissions.bits() << 3)
|
||||
} else {
|
||||
// Others. Shift other bits to align with owner bits.
|
||||
FilePermissions::from_bits_truncate(self.mode.bits() << 6)
|
||||
FilePermissions::from_bits_truncate(self.permissions.bits() << 6)
|
||||
};
|
||||
|
||||
if requested_mode.contains(AccessMode::R_OK)
|
||||
@@ -175,11 +225,11 @@ mod tests {
|
||||
const OTHER_UID: Uid = Uid::new(1002);
|
||||
const OTHER_GID: Gid = Gid::new(3000);
|
||||
|
||||
fn setup_file(mode: FilePermissions) -> FileAttr {
|
||||
fn setup_file(permissions: FilePermissions) -> FileAttr {
|
||||
FileAttr {
|
||||
uid: OWNER_UID,
|
||||
gid: FILE_GROUP_GID,
|
||||
mode,
|
||||
permissions,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,8 +96,7 @@ impl From<Metadata> for FileAttr {
|
||||
FileAttr {
|
||||
size: meta.size_in_bytes,
|
||||
file_type: meta.file_type.into(),
|
||||
// Infallible, since they are identical
|
||||
mode: FilePermissions::from_bits(meta.mode.bits()).unwrap(),
|
||||
permissions: FilePermissions::from_bits_truncate(meta.mode.bits()),
|
||||
uid: Uid::new(meta.uid),
|
||||
gid: Gid::new(meta.gid),
|
||||
atime: meta.atime,
|
||||
|
||||
@@ -221,7 +221,7 @@ impl<T: Fat32Operations> Fat32DirStream<T> {
|
||||
let attr = FileAttr {
|
||||
size: dir_entry.size as u64,
|
||||
file_type,
|
||||
mode: FilePermissions::from_bits_retain(0o755),
|
||||
permissions: FilePermissions::from_bits_retain(0o755),
|
||||
atime: fat_date_to_duration(dir_entry.adate),
|
||||
mtime: fat_datetime_to_duration(dir_entry.mdate, dir_entry.mtime, 0),
|
||||
ctime: fat_datetime_to_duration(
|
||||
|
||||
@@ -126,14 +126,14 @@ where
|
||||
G: PageAllocGetter<C>,
|
||||
T: AddressTranslator<()>,
|
||||
{
|
||||
fn new(id: InodeId, mode: FilePermissions) -> Result<Self> {
|
||||
fn new(id: InodeId, permissions: FilePermissions) -> Result<Self> {
|
||||
Ok(Self {
|
||||
id,
|
||||
attr: SpinLockIrq::new(FileAttr {
|
||||
file_type: FileType::File,
|
||||
size: 0,
|
||||
nlinks: 1,
|
||||
mode,
|
||||
permissions,
|
||||
..Default::default()
|
||||
}),
|
||||
inner: SpinLockIrq::new(TmpFsRegInner {
|
||||
@@ -666,14 +666,14 @@ where
|
||||
G: PageAllocGetter<C>,
|
||||
T: AddressTranslator<()>,
|
||||
{
|
||||
pub fn new(id: u64, fs: Weak<TmpFs<C, G, T>>, mode: FilePermissions) -> Arc<Self> {
|
||||
pub fn new(id: u64, fs: Weak<TmpFs<C, G, T>>, permissions: FilePermissions) -> Arc<Self> {
|
||||
Arc::new_cyclic(|weak_this| Self {
|
||||
entries: SpinLockIrq::new(Vec::new()),
|
||||
attrs: SpinLockIrq::new(FileAttr {
|
||||
size: 0,
|
||||
file_type: FileType::Directory,
|
||||
block_size: BLOCK_SZ as _,
|
||||
mode,
|
||||
permissions,
|
||||
..Default::default()
|
||||
}),
|
||||
id,
|
||||
|
||||
@@ -28,7 +28,7 @@ impl DevFs {
|
||||
id: InodeId::from_fsid_and_inodeid(DEVFS_ID, 0),
|
||||
attr: SpinLock::new(FileAttr {
|
||||
file_type: FileType::Directory,
|
||||
mode: FilePermissions::from_bits_retain(0o755),
|
||||
permissions: FilePermissions::from_bits_retain(0o755),
|
||||
..FileAttr::default()
|
||||
}),
|
||||
kind: InodeKind::Directory(SpinLock::new(BTreeMap::new())),
|
||||
@@ -44,7 +44,7 @@ impl DevFs {
|
||||
&self,
|
||||
name: String,
|
||||
device_id: CharDevDescriptor,
|
||||
mode: FilePermissions,
|
||||
permissions: FilePermissions,
|
||||
) -> Result<()> {
|
||||
let InodeKind::Directory(ref children) = self.root.kind else {
|
||||
// This should be impossible as the root is always a directory.
|
||||
@@ -66,7 +66,7 @@ impl DevFs {
|
||||
attr: SpinLock::new(FileAttr {
|
||||
id,
|
||||
file_type: FileType::CharDevice(device_id),
|
||||
mode,
|
||||
permissions,
|
||||
..FileAttr::default()
|
||||
}),
|
||||
// This is the crucial part: we store the device handle.
|
||||
|
||||
@@ -16,7 +16,7 @@ impl ProcCmdlineInode {
|
||||
id,
|
||||
attr: FileAttr {
|
||||
file_type: libkernel::fs::FileType::File,
|
||||
mode: libkernel::fs::attr::FilePermissions::from_bits_retain(0o444),
|
||||
permissions: libkernel::fs::attr::FilePermissions::from_bits_retain(0o444),
|
||||
..FileAttr::default()
|
||||
},
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ impl ProcRootInode {
|
||||
id: InodeId::from_fsid_and_inodeid(PROCFS_ID, 0),
|
||||
attr: FileAttr {
|
||||
file_type: FileType::Directory,
|
||||
mode: FilePermissions::from_bits_retain(0o555),
|
||||
permissions: FilePermissions::from_bits_retain(0o555),
|
||||
..FileAttr::default()
|
||||
},
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ impl ProcTaskInode {
|
||||
id: inode_id,
|
||||
attr: FileAttr {
|
||||
file_type: FileType::Directory,
|
||||
mode: FilePermissions::from_bits_retain(0o555),
|
||||
permissions: FilePermissions::from_bits_retain(0o555),
|
||||
..FileAttr::default()
|
||||
},
|
||||
desc,
|
||||
|
||||
@@ -58,7 +58,7 @@ impl ProcTaskFileInode {
|
||||
| TaskFileType::Stat => FileType::File,
|
||||
TaskFileType::Cwd | TaskFileType::Root => FileType::Symlink,
|
||||
},
|
||||
mode: FilePermissions::from_bits_retain(0o444),
|
||||
permissions: FilePermissions::from_bits_retain(0o444),
|
||||
..FileAttr::default()
|
||||
},
|
||||
process_stats,
|
||||
|
||||
@@ -507,7 +507,7 @@ impl VFS {
|
||||
{
|
||||
let creds = task.creds.lock_save_irq();
|
||||
|
||||
if attr.mode.contains(FilePermissions::S_ISVTX)
|
||||
if attr.permissions.contains(FilePermissions::S_ISVTX)
|
||||
&& attr.uid != creds.euid()
|
||||
&& parent_attr.uid != creds.euid()
|
||||
{
|
||||
|
||||
@@ -62,7 +62,7 @@ impl Inode for PipeInode {
|
||||
mtime: self.time,
|
||||
ctime: self.time,
|
||||
file_type: FileType::Fifo,
|
||||
mode: FilePermissions::from_bits_retain(0o0600),
|
||||
permissions: FilePermissions::from_bits_retain(0o0600),
|
||||
nlinks: 1,
|
||||
uid: self.uid,
|
||||
gid: self.gid,
|
||||
|
||||
@@ -37,7 +37,7 @@ pub async fn sys_fchmodat(dirfd: Fd, path: TUA<c_char>, mode: u16, flags: i32) -
|
||||
return Err(KernelError::NotPermitted);
|
||||
}
|
||||
|
||||
attr.mode = mode;
|
||||
attr.permissions = mode;
|
||||
node.setattr(attr).await?;
|
||||
|
||||
Ok(0)
|
||||
|
||||
@@ -103,14 +103,14 @@ pub async fn sys_renameat2(
|
||||
|
||||
let creds = task.creds.lock_save_irq();
|
||||
|
||||
if (old_attr.mode.contains(FilePermissions::S_ISVTX)
|
||||
if (old_attr.permissions.contains(FilePermissions::S_ISVTX)
|
||||
&& old_attr.uid != creds.euid()
|
||||
&& old_parent_attr.uid != creds.euid())
|
||||
|| new_parent_attr.uid != creds.euid()
|
||||
{
|
||||
creds.caps().check_capable(CapabilitiesFlags::CAP_FOWNER)?;
|
||||
} else if let Some(new_attr) = new_attr
|
||||
&& new_attr.mode.contains(FilePermissions::S_ISVTX)
|
||||
&& new_attr.permissions.contains(FilePermissions::S_ISVTX)
|
||||
&& new_attr.uid != creds.euid()
|
||||
{
|
||||
creds.caps().check_capable(CapabilitiesFlags::CAP_FOWNER)?;
|
||||
|
||||
@@ -45,7 +45,7 @@ impl From<FileAttr> for Stat {
|
||||
Self {
|
||||
st_dev: value.id.fs_id(),
|
||||
st_ino: value.id.inode_id(),
|
||||
st_mode: value.mode.bits() as u32 | u32::from(value.file_type),
|
||||
st_mode: value.mode().bits() as u32 | u32::from(value.file_type),
|
||||
st_nlink: value.nlinks,
|
||||
st_uid: value.uid.into(),
|
||||
st_gid: value.gid.into(),
|
||||
|
||||
@@ -146,7 +146,7 @@ pub async fn sys_statx(
|
||||
|
||||
if mask.contains(StatXMask::STATX_MODE) {
|
||||
stat_x.stx_mask |= StatXMask::STATX_MODE.bits();
|
||||
stat_x.stx_mode |= attr.mode.bits() as u16;
|
||||
stat_x.stx_mode |= attr.mode().bits() as u16;
|
||||
}
|
||||
|
||||
if mask.contains(StatXMask::STATX_NLINK) {
|
||||
|
||||
@@ -13,7 +13,7 @@ pub async fn sys_fchmod(fd: Fd, mode: u16) -> Result<usize> {
|
||||
.lock_save_irq()
|
||||
.get(fd)
|
||||
.ok_or(KernelError::BadFd)?;
|
||||
let mode = FilePermissions::from_bits_retain(mode);
|
||||
let permissions = FilePermissions::from_bits_retain(mode);
|
||||
|
||||
let inode = file.inode().ok_or(KernelError::BadFd)?;
|
||||
let mut attr = inode.getattr().await?;
|
||||
@@ -22,7 +22,7 @@ pub async fn sys_fchmod(fd: Fd, mode: u16) -> Result<usize> {
|
||||
return Err(KernelError::NotPermitted);
|
||||
}
|
||||
|
||||
attr.mode = mode;
|
||||
attr.permissions = permissions;
|
||||
inode.setattr(attr).await?;
|
||||
|
||||
Ok(0)
|
||||
|
||||
Reference in New Issue
Block a user