Skip to main content

ext4_mkfs_sys/
lib.rs

1//! Low-level FFI bindings to lwext4 library.
2//!
3//! This crate provides raw FFI bindings for the mkfs functionality of lwext4.
4
5#![allow(non_camel_case_types)]
6#![allow(non_snake_case)]
7#![allow(dead_code)]
8
9use std::os::raw::{c_char, c_int, c_void};
10
11/// UUID size constant
12pub const UUID_SIZE: usize = 16;
13
14/// Filesystem type constants
15pub const F_SET_EXT2: c_int = 2;
16pub const F_SET_EXT3: c_int = 3;
17pub const F_SET_EXT4: c_int = 4;
18
19/// Block cache descriptor (opaque)
20#[repr(C)]
21pub struct ext4_bcache {
22    _opaque: [u8; 0],
23}
24
25/// Filesystem descriptor (opaque, large structure)
26#[repr(C)]
27pub struct ext4_fs {
28    _opaque: [u8; 0],
29}
30
31/// Block device interface with callbacks
32#[repr(C)]
33pub struct ext4_blockdev_iface {
34    /// Open device function
35    pub open: Option<unsafe extern "C" fn(bdev: *mut ext4_blockdev) -> c_int>,
36
37    /// Block read function
38    pub bread: Option<
39        unsafe extern "C" fn(
40            bdev: *mut ext4_blockdev,
41            buf: *mut c_void,
42            blk_id: u64,
43            blk_cnt: u32,
44        ) -> c_int,
45    >,
46
47    /// Block write function
48    pub bwrite: Option<
49        unsafe extern "C" fn(
50            bdev: *mut ext4_blockdev,
51            buf: *const c_void,
52            blk_id: u64,
53            blk_cnt: u32,
54        ) -> c_int,
55    >,
56
57    /// Close device function
58    pub close: Option<unsafe extern "C" fn(bdev: *mut ext4_blockdev) -> c_int>,
59
60    /// Lock block device (optional)
61    pub lock: Option<unsafe extern "C" fn(bdev: *mut ext4_blockdev) -> c_int>,
62
63    /// Unlock block device (optional)
64    pub unlock: Option<unsafe extern "C" fn(bdev: *mut ext4_blockdev) -> c_int>,
65
66    /// Physical block size (bytes)
67    pub ph_bsize: u32,
68
69    /// Physical block count
70    pub ph_bcnt: u64,
71
72    /// Physical block buffer
73    pub ph_bbuf: *mut u8,
74
75    /// Reference counter
76    pub ph_refctr: u32,
77
78    /// Physical read counter
79    pub bread_ctr: u32,
80
81    /// Physical write counter
82    pub bwrite_ctr: u32,
83
84    /// User data pointer
85    pub p_user: *mut c_void,
86}
87
88/// Block device descriptor
89#[repr(C)]
90pub struct ext4_blockdev {
91    /// Block device interface
92    pub bdif: *mut ext4_blockdev_iface,
93
94    /// Offset in bdif (for multi partition mode)
95    pub part_offset: u64,
96
97    /// Part size in bdif (for multi partition mode)
98    pub part_size: u64,
99
100    /// Block cache
101    pub bc: *mut ext4_bcache,
102
103    /// Logical block size (bytes)
104    pub lg_bsize: u32,
105
106    /// Logical block count
107    pub lg_bcnt: u64,
108
109    /// Cache write back mode reference counter
110    pub cache_write_back: u32,
111
112    /// The filesystem this block device belongs to
113    pub fs: *mut ext4_fs,
114
115    /// Journal (opaque)
116    pub journal: *mut c_void,
117}
118
119/// mkfs configuration info
120#[repr(C)]
121pub struct ext4_mkfs_info {
122    /// Total length in bytes
123    pub len: u64,
124
125    /// Block size in bytes
126    pub block_size: u32,
127
128    /// Blocks per group
129    pub blocks_per_group: u32,
130
131    /// Inodes per group
132    pub inodes_per_group: u32,
133
134    /// Inode size
135    pub inode_size: u32,
136
137    /// Total inodes
138    pub inodes: u32,
139
140    /// Journal blocks
141    pub journal_blocks: u32,
142
143    /// Read-only compatible features
144    pub feat_ro_compat: u32,
145
146    /// Compatible features
147    pub feat_compat: u32,
148
149    /// Incompatible features
150    pub feat_incompat: u32,
151
152    /// Block group descriptor reserve blocks
153    pub bg_desc_reserve_blocks: u32,
154
155    /// Descriptor size
156    pub dsc_size: u16,
157
158    /// UUID (128-bit)
159    pub uuid: [u8; UUID_SIZE],
160
161    /// Enable journal
162    pub journal: bool,
163
164    /// Volume label
165    pub label: *const c_char,
166}
167
168extern "C" {
169    /// Initialize block device
170    pub fn ext4_block_init(bdev: *mut ext4_blockdev) -> c_int;
171
172    /// Finalize block device
173    pub fn ext4_block_fini(bdev: *mut ext4_blockdev) -> c_int;
174
175    /// Bind block cache to block device
176    pub fn ext4_block_bind_bcache(bdev: *mut ext4_blockdev, bc: *mut ext4_bcache) -> c_int;
177
178    /// Initialize block cache dynamically
179    pub fn ext4_bcache_init_dynamic(bc: *mut ext4_bcache, cnt: u32, itemsize: u32) -> c_int;
180
181    /// Finalize block cache
182    pub fn ext4_bcache_fini_dynamic(bc: *mut ext4_bcache) -> c_int;
183
184    /// Read mkfs info from existing filesystem
185    pub fn ext4_mkfs_read_info(bdev: *mut ext4_blockdev, info: *mut ext4_mkfs_info) -> c_int;
186
187    /// Create ext2/3/4 filesystem
188    pub fn ext4_mkfs(
189        fs: *mut ext4_fs,
190        bd: *mut ext4_blockdev,
191        info: *mut ext4_mkfs_info,
192        fs_type: c_int,
193    ) -> c_int;
194}
195
196impl Default for ext4_blockdev_iface {
197    fn default() -> Self {
198        Self {
199            open: None,
200            bread: None,
201            bwrite: None,
202            close: None,
203            lock: None,
204            unlock: None,
205            ph_bsize: 0,
206            ph_bcnt: 0,
207            ph_bbuf: std::ptr::null_mut(),
208            ph_refctr: 0,
209            bread_ctr: 0,
210            bwrite_ctr: 0,
211            p_user: std::ptr::null_mut(),
212        }
213    }
214}
215
216impl Default for ext4_blockdev {
217    fn default() -> Self {
218        Self {
219            bdif: std::ptr::null_mut(),
220            part_offset: 0,
221            part_size: 0,
222            bc: std::ptr::null_mut(),
223            lg_bsize: 0,
224            lg_bcnt: 0,
225            cache_write_back: 0,
226            fs: std::ptr::null_mut(),
227            journal: std::ptr::null_mut(),
228        }
229    }
230}
231
232impl Default for ext4_mkfs_info {
233    fn default() -> Self {
234        Self {
235            len: 0,
236            block_size: 4096,
237            blocks_per_group: 0,
238            inodes_per_group: 0,
239            inode_size: 256,
240            inodes: 0,
241            journal_blocks: 0,
242            feat_ro_compat: 0,
243            feat_compat: 0,
244            feat_incompat: 0,
245            bg_desc_reserve_blocks: 0,
246            dsc_size: 0,
247            uuid: [0u8; UUID_SIZE],
248            journal: false,
249            label: std::ptr::null(),
250        }
251    }
252}
253
254#[cfg(test)]
255mod tests {
256    use super::*;
257
258    #[test]
259    fn test_struct_default_construction() {
260        // Verify we can construct the types with default values
261        let _iface = ext4_blockdev_iface::default();
262        let _bdev = ext4_blockdev::default();
263        let _info = ext4_mkfs_info::default();
264    }
265
266    #[test]
267    fn test_constants() {
268        assert_eq!(UUID_SIZE, 16);
269        assert_eq!(F_SET_EXT2, 2);
270        assert_eq!(F_SET_EXT3, 3);
271        assert_eq!(F_SET_EXT4, 4);
272    }
273
274    #[test]
275    fn test_blockdev_iface_default_values() {
276        let iface = ext4_blockdev_iface::default();
277
278        assert!(iface.open.is_none());
279        assert!(iface.bread.is_none());
280        assert!(iface.bwrite.is_none());
281        assert!(iface.close.is_none());
282        assert!(iface.lock.is_none());
283        assert!(iface.unlock.is_none());
284        assert_eq!(iface.ph_bsize, 0);
285        assert_eq!(iface.ph_bcnt, 0);
286        assert!(iface.ph_bbuf.is_null());
287        assert_eq!(iface.ph_refctr, 0);
288        assert_eq!(iface.bread_ctr, 0);
289        assert_eq!(iface.bwrite_ctr, 0);
290        assert!(iface.p_user.is_null());
291    }
292
293    #[test]
294    fn test_blockdev_default_values() {
295        let bdev = ext4_blockdev::default();
296
297        assert!(bdev.bdif.is_null());
298        assert_eq!(bdev.part_offset, 0);
299        assert_eq!(bdev.part_size, 0);
300        assert!(bdev.bc.is_null());
301        assert_eq!(bdev.lg_bsize, 0);
302        assert_eq!(bdev.lg_bcnt, 0);
303        assert_eq!(bdev.cache_write_back, 0);
304        assert!(bdev.fs.is_null());
305        assert!(bdev.journal.is_null());
306    }
307
308    #[test]
309    fn test_mkfs_info_default_values() {
310        let info = ext4_mkfs_info::default();
311
312        assert_eq!(info.len, 0);
313        assert_eq!(info.block_size, 4096);
314        assert_eq!(info.blocks_per_group, 0);
315        assert_eq!(info.inodes_per_group, 0);
316        assert_eq!(info.inode_size, 256);
317        assert_eq!(info.inodes, 0);
318        assert_eq!(info.journal_blocks, 0);
319        assert_eq!(info.feat_ro_compat, 0);
320        assert_eq!(info.feat_compat, 0);
321        assert_eq!(info.feat_incompat, 0);
322        assert_eq!(info.bg_desc_reserve_blocks, 0);
323        assert_eq!(info.dsc_size, 0);
324        assert_eq!(info.uuid, [0u8; UUID_SIZE]);
325        assert!(!info.journal);
326        assert!(info.label.is_null());
327    }
328
329    #[test]
330    fn test_blockdev_iface_custom_values() {
331        let mut buffer = vec![0u8; 512];
332        let mut iface = ext4_blockdev_iface::default();
333
334        iface.ph_bsize = 512;
335        iface.ph_bcnt = 1024;
336        iface.ph_bbuf = buffer.as_mut_ptr();
337
338        assert_eq!(iface.ph_bsize, 512);
339        assert_eq!(iface.ph_bcnt, 1024);
340        assert!(!iface.ph_bbuf.is_null());
341    }
342
343    #[test]
344    fn test_mkfs_info_custom_values() {
345        let mut info = ext4_mkfs_info::default();
346
347        info.len = 10 * 1024 * 1024; // 10MB
348        info.block_size = 1024;
349        info.inode_size = 128;
350        info.uuid = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
351        info.journal = true;
352
353        assert_eq!(info.len, 10 * 1024 * 1024);
354        assert_eq!(info.block_size, 1024);
355        assert_eq!(info.inode_size, 128);
356        assert_eq!(info.uuid[0], 1);
357        assert_eq!(info.uuid[15], 16);
358        assert!(info.journal);
359    }
360}