Skip to main content

hadris_cpio/
mode.rs

1use core::fmt;
2
3/// Bitmask for extracting the file type from a Unix mode value.
4const S_IFMT: u32 = 0o170000;
5const S_IFSOCK: u32 = 0o140000;
6const S_IFLNK: u32 = 0o120000;
7const S_IFREG: u32 = 0o100000;
8const S_IFBLK: u32 = 0o060000;
9const S_IFDIR: u32 = 0o040000;
10const S_IFCHR: u32 = 0o020000;
11const S_IFIFO: u32 = 0o010000;
12
13/// Unix file type extracted from the upper bits of a CPIO mode field.
14///
15/// The file type occupies bits 12-15 of the mode value (`mode & 0o170000`).
16/// Use [`FileType::from_mode`] to extract the type from a raw mode value,
17/// and [`make_mode`] to combine a file type with permission bits.
18#[derive(Debug, Clone, Copy, PartialEq, Eq)]
19pub enum FileType {
20    /// Unix-domain or network socket.
21    Socket,
22    /// Symbolic link.
23    Symlink,
24    /// Regular file.
25    Regular,
26    /// Block device node.
27    BlockDevice,
28    /// Directory.
29    Directory,
30    /// Character device node.
31    CharDevice,
32    /// Named pipe.
33    Fifo,
34    /// Unrecognized file-type mode bits.
35    Unknown(u32),
36}
37
38impl FileType {
39    /// Extract the file type from a raw Unix mode value.
40    pub fn from_mode(mode: u32) -> Self {
41        match mode & S_IFMT {
42            S_IFSOCK => FileType::Socket,
43            S_IFLNK => FileType::Symlink,
44            S_IFREG => FileType::Regular,
45            S_IFBLK => FileType::BlockDevice,
46            S_IFDIR => FileType::Directory,
47            S_IFCHR => FileType::CharDevice,
48            S_IFIFO => FileType::Fifo,
49            other => FileType::Unknown(other),
50        }
51    }
52
53    /// Convert this file type back to the upper mode bits.
54    pub fn to_mode_bits(self) -> u32 {
55        match self {
56            FileType::Socket => S_IFSOCK,
57            FileType::Symlink => S_IFLNK,
58            FileType::Regular => S_IFREG,
59            FileType::BlockDevice => S_IFBLK,
60            FileType::Directory => S_IFDIR,
61            FileType::CharDevice => S_IFCHR,
62            FileType::Fifo => S_IFIFO,
63            FileType::Unknown(v) => v,
64        }
65    }
66}
67
68impl fmt::Display for FileType {
69    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
70        match self {
71            FileType::Socket => write!(f, "socket"),
72            FileType::Symlink => write!(f, "symlink"),
73            FileType::Regular => write!(f, "regular file"),
74            FileType::BlockDevice => write!(f, "block device"),
75            FileType::Directory => write!(f, "directory"),
76            FileType::CharDevice => write!(f, "char device"),
77            FileType::Fifo => write!(f, "fifo"),
78            FileType::Unknown(v) => write!(f, "unknown({v:#o})"),
79        }
80    }
81}
82
83/// Combine a [`FileType`] and permission bits into a complete mode value.
84///
85/// The permission bits are masked to the lower 12 bits (`0o7777`).
86pub fn make_mode(file_type: FileType, permissions: u32) -> u32 {
87    file_type.to_mode_bits() | (permissions & 0o7777)
88}