1use std::ffi::CString;
5use std::path::Path;
6
7use ni_syscfg_sys::*;
8
9use crate::error::{api_status, NiSystemConfigurationError, Result};
10use crate::types::FfiBoolean;
11use crate::Session;
12
13type Uuid = String;
14
15pub struct ImageInfo {
17 pub title: String,
19 pub id: Uuid,
22 pub description: String,
24 pub version: String,
26}
27
28#[repr(i32)]
36pub enum NetworkInterfaceSettings {
37 ResetPrimaryResetOthers = NISysCfgNetworkInterfaceSettings_NISysCfgResetPrimaryResetOthers,
38 PreservePrimaryResetOthers =
39 NISysCfgNetworkInterfaceSettings_NISysCfgPreservePrimaryResetOthers,
40 PreservePrimaryPreserveOthers =
41 NISysCfgNetworkInterfaceSettings_NISysCfgPreservePrimaryPreserveOthers,
42 PreservePrimaryApplyOthers =
43 NISysCfgNetworkInterfaceSettings_NISysCfgPreservePrimaryApplyOthers,
44 ApplyPrimaryResetOthers = NISysCfgNetworkInterfaceSettings_NISysCfgApplyPrimaryResetOthers,
45 ApplyPrimaryPreserveOthers =
46 NISysCfgNetworkInterfaceSettings_NISysCfgApplyPrimaryPreserveOthers,
47 ApplyPrimaryApplyOthers = NISysCfgNetworkInterfaceSettings_NISysCfgApplyPrimaryApplyOthers,
48}
49
50impl Session {
51 pub fn get_system_image(
65 &self,
66 image: &Path,
67 image_info: &ImageInfo,
68 encryption_passphrase: Option<&str>,
69 excluded_files_folders: &[&str],
70 auto_restart: bool,
71 overwrite_if_exists: bool,
72 ) -> Result<()> {
73 let handle = self.handle();
74 let path = CString::new(image.as_os_str().to_string_lossy().as_ref())?;
75 let password = encryption_passphrase.map(|password| CString::new(password));
76 let password_ptr = if let Some(actual_password) = password {
77 actual_password?.as_ptr()
78 } else {
79 std::ptr::null()
80 };
81
82 let title = CString::new(image_info.title.as_str())?;
83 let id = CString::new(image_info.id.as_str())?;
84 let version = CString::new(image_info.version.as_str())?;
85 let description = CString::new(image_info.description.as_str())?;
86
87 let excluded_c = str_slice_to_cstring(excluded_files_folders)?;
90 let mut excluded_ptrs = cstring_vec_to_ptr_array(&excluded_c[..]);
91
92 unsafe {
93 api_status(NISysCfgCreateSystemImageAsFolder(
94 *handle,
95 title.as_ptr(),
96 id.as_ptr(),
97 version.as_ptr(),
98 description.as_ptr(),
99 FfiBoolean::from(auto_restart) as i32,
100 path.as_ptr(),
101 password_ptr,
102 excluded_ptrs.len() as u32,
103 excluded_ptrs.as_mut_ptr(),
104 FfiBoolean::from(overwrite_if_exists) as i32,
105 ))?;
106 }
107 Ok(())
108 }
109
110 pub fn set_system_image(
124 &self,
125 image: &Path,
126 encryption_passphrase: Option<&str>,
127 excluded_files_folders: &[&str],
128 auto_restart: bool,
129 original_system_only: bool,
130 network_settings: NetworkInterfaceSettings,
131 ) -> Result<()> {
132 let handle = self.handle();
133 let path = CString::new(image.as_os_str().to_string_lossy().as_ref())?;
134 let password = encryption_passphrase.map(|password| CString::new(password));
135 let password_ptr = if let Some(actual_password) = password {
136 actual_password?.as_ptr()
137 } else {
138 std::ptr::null()
139 };
140
141 let excluded_c = str_slice_to_cstring(excluded_files_folders)?;
144 let mut excluded_ptrs = cstring_vec_to_ptr_array(&excluded_c[..]);
145
146 unsafe {
147 api_status(NISysCfgSetSystemImageFromFolder2(
148 *handle,
149 FfiBoolean::from(auto_restart) as i32,
150 path.as_ptr(),
151 password_ptr,
152 excluded_ptrs.len() as u32,
153 excluded_ptrs.as_mut_ptr(),
154 FfiBoolean::from(original_system_only) as i32,
155 network_settings as i32,
156 ))?;
157 }
158 Ok(())
159 }
160}
161
162fn str_slice_to_cstring(slice: &[&str]) -> Result<Vec<CString>> {
163 slice
164 .iter()
165 .map(|&item| CString::new(item))
166 .map(|item| item.map_err(|e| NiSystemConfigurationError::NulStringError(e)))
167 .collect::<Result<Vec<CString>>>()
168}
169
170fn cstring_vec_to_ptr_array(list: &[CString]) -> Vec<*const i8> {
171 list.iter().map(|cstring| cstring.as_ptr()).collect()
172}
173
174#[cfg(test)]
175mod test {
176 use std::ffi::CStr;
177
178 use super::{cstring_vec_to_ptr_array, str_slice_to_cstring};
179
180 #[test]
182 fn test_string_list_conversion() {
183 let original = ["test1", "test2", "test3"];
184
185 let cstring = str_slice_to_cstring(&original).unwrap();
188 let mut pointers = cstring_vec_to_ptr_array(&cstring);
189
190 let length = pointers.len() as u32;
191 let ptr = pointers.as_mut_ptr();
192
193 let new_strings: Vec<&CStr> = unsafe {
195 let new_pointers = std::slice::from_raw_parts(ptr, length as usize);
196 new_pointers
197 .iter()
198 .map(|&ptr| CStr::from_ptr(ptr))
199 .collect()
200 };
201
202 for (&new, original) in new_strings.iter().zip(original) {
203 let new_string = new.to_str().unwrap();
204 assert_eq!(new_string, original);
205 }
206 }
207}