Skip to main content

ext4_lwext4/
types.rs

1//! Common types used throughout ext4-rs.
2
3use bitflags::bitflags;
4use ext4_lwext4_sys;
5
6/// Filesystem type for creation.
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
8pub enum FsType {
9    /// ext2 filesystem (no journaling)
10    Ext2,
11    /// ext3 filesystem (with journaling)
12    Ext3,
13    /// ext4 filesystem (with extents and journaling)
14    #[default]
15    Ext4,
16}
17
18impl FsType {
19    /// Convert to lwext4 filesystem type constant
20    pub(crate) fn to_raw(self) -> i32 {
21        match self {
22            FsType::Ext2 => ext4_lwext4_sys::F_SET_EXT2,
23            FsType::Ext3 => ext4_lwext4_sys::F_SET_EXT3,
24            FsType::Ext4 => ext4_lwext4_sys::F_SET_EXT4,
25        }
26    }
27}
28
29/// File type enumeration.
30#[derive(Debug, Clone, Copy, PartialEq, Eq)]
31pub enum FileType {
32    /// Regular file
33    RegularFile,
34    /// Directory
35    Directory,
36    /// Symbolic link
37    Symlink,
38    /// Block device
39    BlockDevice,
40    /// Character device
41    CharDevice,
42    /// FIFO (named pipe)
43    Fifo,
44    /// Socket
45    Socket,
46    /// Unknown file type
47    Unknown,
48}
49
50impl FileType {
51    /// Convert from lwext4 directory entry type
52    pub(crate) fn from_raw(raw: u8) -> Self {
53        match raw {
54            ext4_lwext4_sys::EXT4_DE_REG_FILE => FileType::RegularFile,
55            ext4_lwext4_sys::EXT4_DE_DIR => FileType::Directory,
56            ext4_lwext4_sys::EXT4_DE_SYMLINK => FileType::Symlink,
57            ext4_lwext4_sys::EXT4_DE_BLKDEV => FileType::BlockDevice,
58            ext4_lwext4_sys::EXT4_DE_CHRDEV => FileType::CharDevice,
59            ext4_lwext4_sys::EXT4_DE_FIFO => FileType::Fifo,
60            ext4_lwext4_sys::EXT4_DE_SOCK => FileType::Socket,
61            _ => FileType::Unknown,
62        }
63    }
64
65    /// Convert to lwext4 directory entry type
66    pub(crate) fn to_raw(self) -> u8 {
67        match self {
68            FileType::RegularFile => ext4_lwext4_sys::EXT4_DE_REG_FILE,
69            FileType::Directory => ext4_lwext4_sys::EXT4_DE_DIR,
70            FileType::Symlink => ext4_lwext4_sys::EXT4_DE_SYMLINK,
71            FileType::BlockDevice => ext4_lwext4_sys::EXT4_DE_BLKDEV,
72            FileType::CharDevice => ext4_lwext4_sys::EXT4_DE_CHRDEV,
73            FileType::Fifo => ext4_lwext4_sys::EXT4_DE_FIFO,
74            FileType::Socket => ext4_lwext4_sys::EXT4_DE_SOCK,
75            FileType::Unknown => ext4_lwext4_sys::EXT4_DE_UNKNOWN,
76        }
77    }
78
79    /// Check if this is a regular file
80    pub fn is_file(&self) -> bool {
81        matches!(self, FileType::RegularFile)
82    }
83
84    /// Check if this is a directory
85    pub fn is_dir(&self) -> bool {
86        matches!(self, FileType::Directory)
87    }
88
89    /// Check if this is a symbolic link
90    pub fn is_symlink(&self) -> bool {
91        matches!(self, FileType::Symlink)
92    }
93}
94
95bitflags! {
96    /// Flags for opening files.
97    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
98    pub struct OpenFlags: u32 {
99        /// Open for reading only
100        const READ = 0b0000_0001;
101        /// Open for writing only
102        const WRITE = 0b0000_0010;
103        /// Create file if it doesn't exist
104        const CREATE = 0b0000_0100;
105        /// Truncate file to zero length
106        const TRUNCATE = 0b0000_1000;
107        /// Append to end of file
108        const APPEND = 0b0001_0000;
109        /// Fail if file already exists (requires CREATE)
110        const EXCLUSIVE = 0b0010_0000;
111    }
112}
113
114impl OpenFlags {
115    /// Convert to lwext4 open flags
116    pub(crate) fn to_raw(self) -> i32 {
117        let mut flags = 0i32;
118
119        if self.contains(OpenFlags::READ) && self.contains(OpenFlags::WRITE) {
120            flags |= ext4_lwext4_sys::O_RDWR;
121        } else if self.contains(OpenFlags::WRITE) {
122            flags |= ext4_lwext4_sys::O_WRONLY;
123        } else {
124            flags |= ext4_lwext4_sys::O_RDONLY;
125        }
126
127        if self.contains(OpenFlags::CREATE) {
128            flags |= ext4_lwext4_sys::O_CREAT;
129        }
130        if self.contains(OpenFlags::TRUNCATE) {
131            flags |= ext4_lwext4_sys::O_TRUNC;
132        }
133        if self.contains(OpenFlags::APPEND) {
134            flags |= ext4_lwext4_sys::O_APPEND;
135        }
136        if self.contains(OpenFlags::EXCLUSIVE) {
137            flags |= ext4_lwext4_sys::O_EXCL;
138        }
139
140        flags
141    }
142}
143
144/// Seek position for file operations.
145#[derive(Debug, Clone, Copy, PartialEq, Eq)]
146pub enum SeekFrom {
147    /// Seek from the beginning of the file
148    Start(u64),
149    /// Seek from the end of the file
150    End(i64),
151    /// Seek from the current position
152    Current(i64),
153}
154
155impl SeekFrom {
156    /// Convert to lwext4 seek origin and offset
157    pub(crate) fn to_raw(self) -> (i64, u32) {
158        match self {
159            SeekFrom::Start(pos) => (pos as i64, ext4_lwext4_sys::SEEK_SET),
160            SeekFrom::End(pos) => (pos, ext4_lwext4_sys::SEEK_END),
161            SeekFrom::Current(pos) => (pos, ext4_lwext4_sys::SEEK_CUR),
162        }
163    }
164}
165
166/// File metadata.
167#[derive(Debug, Clone)]
168pub struct Metadata {
169    /// File type
170    pub file_type: FileType,
171    /// File size in bytes
172    pub size: u64,
173    /// Number of blocks allocated
174    pub blocks: u64,
175    /// File mode (permissions)
176    pub mode: u32,
177    /// Owner user ID
178    pub uid: u32,
179    /// Owner group ID
180    pub gid: u32,
181    /// Access time (Unix timestamp)
182    pub atime: u64,
183    /// Modification time (Unix timestamp)
184    pub mtime: u64,
185    /// Change time (Unix timestamp)
186    pub ctime: u64,
187    /// Number of hard links
188    pub nlink: u32,
189}
190
191impl Metadata {
192    /// Check if this is a regular file
193    pub fn is_file(&self) -> bool {
194        self.file_type.is_file()
195    }
196
197    /// Check if this is a directory
198    pub fn is_dir(&self) -> bool {
199        self.file_type.is_dir()
200    }
201
202    /// Check if this is a symbolic link
203    pub fn is_symlink(&self) -> bool {
204        self.file_type.is_symlink()
205    }
206
207    /// Get the file size
208    pub fn len(&self) -> u64 {
209        self.size
210    }
211
212    /// Check if the file is empty
213    pub fn is_empty(&self) -> bool {
214        self.size == 0
215    }
216}
217
218/// Filesystem statistics.
219#[derive(Debug, Clone)]
220pub struct FsStats {
221    /// Block size in bytes
222    pub block_size: u32,
223    /// Total number of blocks
224    pub total_blocks: u64,
225    /// Number of free blocks
226    pub free_blocks: u64,
227    /// Total number of inodes
228    pub total_inodes: u64,
229    /// Number of free inodes
230    pub free_inodes: u64,
231    /// Number of block groups
232    pub block_group_count: u32,
233    /// Blocks per group
234    pub blocks_per_group: u32,
235    /// Inodes per group
236    pub inodes_per_group: u32,
237    /// Volume name
238    pub volume_name: String,
239}
240
241impl FsStats {
242    /// Calculate total filesystem size in bytes
243    pub fn total_size(&self) -> u64 {
244        self.total_blocks * self.block_size as u64
245    }
246
247    /// Calculate free space in bytes
248    pub fn free_size(&self) -> u64 {
249        self.free_blocks * self.block_size as u64
250    }
251
252    /// Calculate used space in bytes
253    pub fn used_size(&self) -> u64 {
254        (self.total_blocks - self.free_blocks) * self.block_size as u64
255    }
256}