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}