2025-09-21 13:03:18 +00:00
|
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
|
|
|
|
|
|
use aster_systree::SysPerms;
|
|
|
|
|
|
|
|
|
|
use crate::prelude::*;
|
|
|
|
|
|
|
|
|
|
bitflags! {
|
|
|
|
|
pub struct InodeMode: u16 {
|
|
|
|
|
/// set-user-ID
|
|
|
|
|
const S_ISUID = 0o4000;
|
|
|
|
|
/// set-group-ID
|
|
|
|
|
const S_ISGID = 0o2000;
|
|
|
|
|
/// sticky bit
|
|
|
|
|
const S_ISVTX = 0o1000;
|
|
|
|
|
/// read by owner
|
|
|
|
|
const S_IRUSR = 0o0400;
|
|
|
|
|
/// write by owner
|
|
|
|
|
const S_IWUSR = 0o0200;
|
|
|
|
|
/// execute/search by owner
|
|
|
|
|
const S_IXUSR = 0o0100;
|
|
|
|
|
/// read by group
|
|
|
|
|
const S_IRGRP = 0o0040;
|
|
|
|
|
/// write by group
|
|
|
|
|
const S_IWGRP = 0o0020;
|
|
|
|
|
/// execute/search by group
|
|
|
|
|
const S_IXGRP = 0o0010;
|
|
|
|
|
/// read by others
|
|
|
|
|
const S_IROTH = 0o0004;
|
|
|
|
|
/// write by others
|
|
|
|
|
const S_IWOTH = 0o0002;
|
|
|
|
|
/// execute/search by others
|
|
|
|
|
const S_IXOTH = 0o0001;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl InodeMode {
|
|
|
|
|
pub fn is_owner_readable(&self) -> bool {
|
|
|
|
|
self.contains(Self::S_IRUSR)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn is_owner_writable(&self) -> bool {
|
|
|
|
|
self.contains(Self::S_IWUSR)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn is_owner_executable(&self) -> bool {
|
|
|
|
|
self.contains(Self::S_IXUSR)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn is_group_readable(&self) -> bool {
|
|
|
|
|
self.contains(Self::S_IRGRP)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn is_group_writable(&self) -> bool {
|
|
|
|
|
self.contains(Self::S_IWGRP)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn is_group_executable(&self) -> bool {
|
|
|
|
|
self.contains(Self::S_IXGRP)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn is_other_readable(&self) -> bool {
|
|
|
|
|
self.contains(Self::S_IROTH)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn is_other_writable(&self) -> bool {
|
|
|
|
|
self.contains(Self::S_IWOTH)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn is_other_executable(&self) -> bool {
|
|
|
|
|
self.contains(Self::S_IXOTH)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[expect(dead_code)]
|
|
|
|
|
pub fn has_sticky_bit(&self) -> bool {
|
|
|
|
|
self.contains(Self::S_ISVTX)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn has_set_uid(&self) -> bool {
|
|
|
|
|
self.contains(Self::S_ISUID)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn has_set_gid(&self) -> bool {
|
|
|
|
|
self.contains(Self::S_ISGID)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl From<SysPerms> for InodeMode {
|
|
|
|
|
fn from(value: SysPerms) -> Self {
|
|
|
|
|
InodeMode::from_bits_truncate(value.bits())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Changes an inode mode.
|
|
|
|
|
///
|
|
|
|
|
/// # Syntax
|
|
|
|
|
///
|
|
|
|
|
/// If you are familiar with the `chmod` tool, the syntax of the `chmod` macro
|
|
|
|
|
/// should appear natural and self-explaining.
|
|
|
|
|
///
|
|
|
|
|
/// The `chmod` macro takes two or more arguments. The first argument is an
|
|
|
|
|
/// initial value of the inode mode. The rest arguments are one or more
|
|
|
|
|
/// symbolic mode, each of which dictates how the current value of the inode
|
|
|
|
|
/// mode shall be changed.
|
|
|
|
|
///
|
|
|
|
|
/// The format of a symbolic mode is as follows:
|
|
|
|
|
///
|
|
|
|
|
/// ```
|
|
|
|
|
/// [ugoa][+-=][perms]
|
|
|
|
|
/// ```
|
|
|
|
|
///
|
|
|
|
|
/// where `[perms]` is either zero or more letters from `rwx`.
|
|
|
|
|
///
|
|
|
|
|
/// The user part, `[ugoa]`,
|
|
|
|
|
/// controls the target users whose access to the file will be changed:
|
|
|
|
|
/// * `u`: the user who owns it;
|
|
|
|
|
/// * `g`: other users in the file owner's group;
|
|
|
|
|
/// * `o`: other users not in the file owner's group;
|
|
|
|
|
/// * `a`: all users.
|
|
|
|
|
///
|
|
|
|
|
/// The operator part, `[+-=]`,
|
|
|
|
|
/// indicates how the file permission bits are changed:
|
|
|
|
|
/// * `+`: `[perms]` are added to the target users' permissions;
|
|
|
|
|
/// * `-`: `[perms]` are removed from the target users' permissions;
|
|
|
|
|
/// * `=`: `[perms]` are set to the target users' permissions.
|
|
|
|
|
///
|
|
|
|
|
/// The permission part, `[perms]`, is a combination of `rwx`.
|
|
|
|
|
/// * `r`: the read permission;
|
|
|
|
|
/// * `w`: the write permission;
|
|
|
|
|
/// * `x`: the execute/search permission.
|
|
|
|
|
///
|
|
|
|
|
/// # Examples
|
|
|
|
|
///
|
|
|
|
|
/// ```
|
|
|
|
|
/// // Add the read and write permissions to everyone
|
|
|
|
|
/// let mode0 = mkmod!(a+rw);
|
|
|
|
|
/// assert!(mode0.bits() == 0o666);
|
|
|
|
|
///
|
|
|
|
|
/// // Add the execute permissions to the owner user
|
|
|
|
|
/// let mode1 = chmod!(mode0, u+x);
|
|
|
|
|
/// assert!(mode1.bits() == 0o766);
|
|
|
|
|
///
|
|
|
|
|
/// // Combine the above two steps into one invocation
|
|
|
|
|
/// let mode2 = mkmod!(a+rw, u+x);
|
|
|
|
|
/// assert!(mode2.bits() == 0o766);
|
|
|
|
|
/// ```
|
|
|
|
|
macro_rules! chmod {
|
|
|
|
|
($mode:expr) => { $mode };
|
|
|
|
|
|
|
|
|
|
($mode:expr, $who:ident + $perms:ident $(, $($rest:tt)*)?) => {
|
|
|
|
|
$crate::fs::utils::chmod!(@apply $mode, $who, '+', $perms $(, $($rest)*)?)
|
|
|
|
|
};
|
|
|
|
|
($mode:expr, $who:ident - $perms:ident $(, $($rest:tt)*)?) => {
|
|
|
|
|
$crate::fs::utils::chmod!(@apply $mode, $who, '-', $perms $(, $($rest)*)?)
|
|
|
|
|
};
|
|
|
|
|
($mode:expr, $who:ident = $perms:ident $(, $($rest:tt)*)?) => {
|
|
|
|
|
$crate::fs::utils::chmod!(@apply $mode, $who, '=', $perms $(, $($rest)*)?)
|
|
|
|
|
};
|
|
|
|
|
($mode:expr, $who:ident = $(, $($rest:tt)*)?) => {
|
|
|
|
|
$crate::fs::utils::chmod!(@apply $mode, $who, '=', none $(, $($rest)*)?)
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
(@apply $mode:expr, $who:ident, $op:expr, $perms:ident $(, $($rest:tt)*)?) => {{
|
2025-12-08 15:29:12 +00:00
|
|
|
let mask = $crate::fs::utils::who_and_perms_to_mask!($who, $perms);
|
2025-09-21 13:03:18 +00:00
|
|
|
let new_mode = match $op {
|
|
|
|
|
'+' => $mode | mask,
|
|
|
|
|
'-' => $mode & !mask,
|
2025-12-08 15:29:12 +00:00
|
|
|
'=' => ($mode & !$crate::fs::utils::who_and_perms_to_mask!($who, rwx)) | mask,
|
2025-09-21 13:03:18 +00:00
|
|
|
_ => unreachable!(),
|
|
|
|
|
};
|
2025-12-08 15:29:12 +00:00
|
|
|
$crate::fs::utils::chmod!(new_mode $(, $($rest)*)?)
|
2025-09-21 13:03:18 +00:00
|
|
|
}};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Makes an inode mode.
|
|
|
|
|
///
|
|
|
|
|
/// `mkmod` is equivalent to `chmod` with the first argument set to
|
|
|
|
|
/// `InodeMode::empty()`. See [`chmod`] for details.
|
|
|
|
|
macro_rules! mkmod {
|
|
|
|
|
($($args:tt)*) => {
|
2025-12-08 15:29:12 +00:00
|
|
|
$crate::fs::utils::chmod!($crate::fs::utils::InodeMode::empty(), $($args)*)
|
2025-09-21 13:03:18 +00:00
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
macro_rules! who_and_perms_to_mask {
|
|
|
|
|
($who:ident, $perms:ident) => {
|
2025-12-08 15:29:12 +00:00
|
|
|
$crate::fs::utils::InodeMode::from_bits_truncate(
|
|
|
|
|
$crate::fs::utils::who_to_mask!($who) & $crate::fs::utils::perms_to_mask!($perms),
|
|
|
|
|
)
|
2025-09-21 13:03:18 +00:00
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
macro_rules! who_to_mask {
|
|
|
|
|
(u) => {
|
|
|
|
|
0o700
|
|
|
|
|
};
|
|
|
|
|
(g) => {
|
|
|
|
|
0o070
|
|
|
|
|
};
|
|
|
|
|
(o) => {
|
|
|
|
|
0o007
|
|
|
|
|
};
|
|
|
|
|
(ug) => {
|
|
|
|
|
0o770
|
|
|
|
|
};
|
|
|
|
|
(uo) => {
|
|
|
|
|
0o707
|
|
|
|
|
};
|
|
|
|
|
(go) => {
|
|
|
|
|
0o077
|
|
|
|
|
};
|
|
|
|
|
(a) => {
|
|
|
|
|
0o777
|
|
|
|
|
};
|
|
|
|
|
(ugo) => {
|
|
|
|
|
0o777
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
macro_rules! perms_to_mask {
|
|
|
|
|
(none) => {
|
|
|
|
|
0
|
|
|
|
|
};
|
|
|
|
|
(r) => {
|
|
|
|
|
0o444
|
|
|
|
|
};
|
|
|
|
|
(w) => {
|
|
|
|
|
0o222
|
|
|
|
|
};
|
|
|
|
|
(x) => {
|
|
|
|
|
0o111
|
|
|
|
|
};
|
|
|
|
|
(rw) => {
|
|
|
|
|
0o666
|
|
|
|
|
};
|
|
|
|
|
(rx) => {
|
|
|
|
|
0o555
|
|
|
|
|
};
|
|
|
|
|
(wx) => {
|
|
|
|
|
0o333
|
|
|
|
|
};
|
|
|
|
|
(rwx) => {
|
|
|
|
|
0o777
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) use chmod;
|
|
|
|
|
pub(crate) use mkmod;
|
|
|
|
|
pub(crate) use perms_to_mask;
|
|
|
|
|
pub(crate) use who_and_perms_to_mask;
|
|
|
|
|
pub(crate) use who_to_mask;
|
|
|
|
|
|
|
|
|
|
#[cfg(ktest)]
|
|
|
|
|
mod test {
|
|
|
|
|
use ostd::prelude::*;
|
|
|
|
|
|
|
|
|
|
#[ktest]
|
|
|
|
|
fn test_mkmod_and_chmod() {
|
|
|
|
|
let mode0 = mkmod!(a+rw);
|
|
|
|
|
assert!(mode0.bits() == 0o666);
|
|
|
|
|
|
|
|
|
|
let mode1 = chmod!(mode0, u+x);
|
|
|
|
|
assert!(mode1.bits() == 0o766);
|
|
|
|
|
|
|
|
|
|
let mode2 = mkmod!(a+rw, u+x);
|
|
|
|
|
assert!(mode2.bits() == 0o766);
|
|
|
|
|
|
|
|
|
|
let mode3 = chmod!(mode2, ug-wx);
|
|
|
|
|
assert!(mode3.bits() == 0o446);
|
|
|
|
|
|
|
|
|
|
let mode4 = chmod!(mode3, o=rx);
|
|
|
|
|
assert!(mode4.bits() == 0o445);
|
|
|
|
|
|
|
|
|
|
let mode5 = chmod!(mode4, u=, g=, o=);
|
|
|
|
|
assert!(mode5.bits() == 0o000);
|
|
|
|
|
}
|
|
|
|
|
}
|