distinguish between file permissions and file mode

This commit is contained in:
Ashwin Naren
2026-03-02 11:49:58 -08:00
parent d164e06558
commit edca499714
16 changed files with 80 additions and 31 deletions

View File

@@ -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()
}
}

View File

@@ -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,

View File

@@ -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(

View File

@@ -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,