microsandbox_core/utils/
conversion.rs

1//! Utility functions for converting between different data types.
2
3use std::{
4    ffi::{c_char, CString},
5    ops::{Bound, RangeBounds},
6};
7
8//--------------------------------------------------------------------------------------------------
9// Functions
10//--------------------------------------------------------------------------------------------------
11
12/// Converts a range bound to a u64 start and end value.
13///
14/// ## Examples
15///
16/// ```
17/// use microsandbox_core::utils::convert_bounds;
18///
19/// let (start, end) = convert_bounds(1..10);
20/// assert_eq!(start, 1);
21/// assert_eq!(end, 9);
22///
23/// let (start, end) = convert_bounds(..10);
24/// assert_eq!(start, 0);
25/// assert_eq!(end, 9);
26///
27/// let (start, end) = convert_bounds(1..);
28/// assert_eq!(start, 1);
29/// assert_eq!(end, u64::MAX);
30///
31/// let (start, end) = convert_bounds(..=10);
32/// assert_eq!(start, 0);
33/// assert_eq!(end, 10);
34/// ```
35pub fn convert_bounds(range: impl RangeBounds<u64>) -> (u64, u64) {
36    let start = match range.start_bound() {
37        Bound::Included(&start) => start,
38        Bound::Excluded(&start) => start + 1,
39        Bound::Unbounded => 0,
40    };
41
42    let end = match range.end_bound() {
43        Bound::Included(&end) => end,
44        Bound::Excluded(&end) => end - 1,
45        Bound::Unbounded => u64::MAX,
46    };
47
48    (start, end)
49}
50
51/// Creates a null-terminated array of pointers from a slice of strings.
52///
53/// This function is useful for FFI calls that expect a null-terminated array of C-style strings.
54///
55/// ## Arguments
56///
57/// * `strings` - A slice of strings to convert
58///
59/// ## Returns
60///
61/// A vector of pointers to null-terminated C strings, with a null pointer appended at the end.
62///
63/// ## Safety
64///
65/// The returned vector must be kept alive as long as the pointers are in use.
66pub fn to_null_terminated_c_array(strings: &[CString]) -> Vec<*const c_char> {
67    let mut ptrs: Vec<*const c_char> = strings.iter().map(|s| s.as_ptr()).collect();
68    ptrs.push(std::ptr::null());
69
70    ptrs
71}
72
73/// Converts a file mode to a string representation similar to ls -l
74///
75/// # Examples
76/// ```
77/// use microsandbox_core::utils::format_mode;
78/// assert_eq!(format_mode(0o755), "-rwxr-xr-x");
79/// assert_eq!(format_mode(0o644), "-rw-r--r--");
80/// assert_eq!(format_mode(0o40755), "drwxr-xr-x");
81/// ```
82pub fn format_mode(mode: u32) -> String {
83    let file_type = match mode & 0o170000 {
84        0o040000 => 'd', // directory
85        0o120000 => 'l', // symbolic link
86        0o010000 => 'p', // named pipe (FIFO)
87        0o140000 => 's', // socket
88        0o060000 => 'b', // block device
89        0o020000 => 'c', // character device
90        _ => '-',        // regular file
91    };
92
93    let user = format_triplet((mode >> 6) & 0o7);
94    let group = format_triplet((mode >> 3) & 0o7);
95    let other = format_triplet(mode & 0o7);
96
97    format!("{}{}{}{}", file_type, user, group, other)
98}
99
100/// Helper function to convert a permission triplet (3 bits) to rwx format
101fn format_triplet(mode: u32) -> String {
102    let r = if mode & 0o4 != 0 { 'r' } else { '-' };
103    let w = if mode & 0o2 != 0 { 'w' } else { '-' };
104    let x = if mode & 0o1 != 0 { 'x' } else { '-' };
105    format!("{}{}{}", r, w, x)
106}
107
108//--------------------------------------------------------------------------------------------------
109// Tests
110//--------------------------------------------------------------------------------------------------
111
112#[cfg(test)]
113mod tests {
114    use super::*;
115
116    #[test]
117    fn test_format_mode() {
118        assert_eq!(format_mode(0o755), "-rwxr-xr-x");
119        assert_eq!(format_mode(0o644), "-rw-r--r--");
120        assert_eq!(format_mode(0o40755), "drwxr-xr-x");
121        assert_eq!(format_mode(0o100644), "-rw-r--r--");
122        assert_eq!(format_mode(0o120777), "lrwxrwxrwx");
123        assert_eq!(format_mode(0o010644), "prw-r--r--");
124    }
125}