1macro_rules! mutex {
9 ( $libcryptsetup_call:expr ) => {{
10 #[cfg(feature = "mutex")]
11 #[allow(unused_variables)]
12 let lock = $crate::MUTEX.acquire();
13
14 #[cfg(not(feature = "mutex"))]
15 if *$crate::THREAD_ID != std::thread::current().id() {
16 panic!("Enable the mutex feature for this crate to allow calling libcryptsetup methods from multiple threads");
17 }
18
19 unsafe { $libcryptsetup_call }
20 }};
21}
22
23macro_rules! errno {
25 ( $rc:expr ) => {
26 match $rc {
27 i if i < 0 => {
28 return Err($crate::err::LibcryptErr::IOError(
29 std::io::Error::from_raw_os_error(-i),
30 ))
31 }
32 i if i > 0 => panic!("Unexpected return value {}", i),
33 _ => Result::<(), $crate::err::LibcryptErr>::Ok(()),
34 }
35 };
36}
37
38macro_rules! errno_int_success {
40 ( $rc:expr ) => {
41 match $rc {
42 i if i < 0 => {
43 return Err($crate::err::LibcryptErr::IOError(
44 std::io::Error::from_raw_os_error(-i),
45 ))
46 }
47 i => Result::<_, $crate::err::LibcryptErr>::Ok(i),
48 }
49 };
50}
51
52macro_rules! int_to_return {
54 ( $rc:expr, $type:ty ) => {
55 <$type>::from($rc)
56 };
57}
58
59macro_rules! try_int_to_return {
61 ( $rc:expr, $type:ty ) => {
62 <$type>::try_from($rc)
63 };
64}
65
66macro_rules! ptr_to_option {
68 ( $ptr:expr ) => {{
69 let p = $ptr;
70 if p.is_null() {
71 None
72 } else {
73 Some(p)
74 }
75 }};
76}
77
78macro_rules! ptr_to_option_with_reference {
80 ( $ptr:expr ) => {{
81 let p = $ptr;
82 unsafe { p.as_ref() }
83 }};
84}
85
86macro_rules! ptr_to_result {
88 ( $ptr:expr ) => {{
89 ptr_to_option!($ptr).ok_or($crate::err::LibcryptErr::NullPtr)
90 }};
91}
92
93macro_rules! ptr_to_result_with_reference {
95 ( $ptr:expr ) => {{
96 let p = $ptr;
97 unsafe { p.as_ref() }.ok_or($crate::err::LibcryptErr::NullPtr)
98 }};
99}
100
101macro_rules! path_to_cstring {
103 ( $path:expr ) => {
104 match $path
105 .to_str()
106 .ok_or_else(|| LibcryptErr::InvalidConversion)
107 .and_then(|s| std::ffi::CString::new(s).map_err(LibcryptErr::NullError))
108 {
109 Ok(s) => Ok(s),
110 Err(e) => Err(e),
111 }
112 };
113}
114
115macro_rules! to_cstring {
117 ( $str:expr ) => {
118 match std::ffi::CString::new($str.as_bytes()) {
119 Ok(s) => Ok(s),
120 Err(e) => Err($crate::err::LibcryptErr::NullError(e)),
121 }
122 };
123}
124
125macro_rules! to_byte_ptr {
127 ( $bytes:expr ) => {
128 $bytes.as_ptr().cast::<std::os::raw::c_char>()
129 };
130}
131
132macro_rules! to_mut_byte_ptr {
134 ( $bytes:expr ) => {
135 $bytes.as_mut_ptr().cast::<std::os::raw::c_char>()
136 };
137}
138
139#[macro_export]
141macro_rules! from_str_ptr {
142 ( $str_ptr:expr ) => {{
143 let str_ptr = $str_ptr;
144 unsafe { ::std::ffi::CStr::from_ptr(str_ptr) }
145 .to_str()
146 .map_err($crate::LibcryptErr::Utf8Error)
147 }};
148}
149
150macro_rules! from_str_ptr_to_owned {
152 ( $str_ptr:expr ) => {
153 unsafe { ::std::ffi::CStr::from_ptr($str_ptr) }
154 .to_str()
155 .map_err($crate::err::LibcryptErr::Utf8Error)
156 .map(|s| s.to_string())
157 };
158}
159
160macro_rules! consts_to_from_enum {
162 ( #[$meta:meta] $flag_enum:ident, $flag_type:ty, $( $name:ident => $constant:expr ),* ) => {
163 #[$meta]
164 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
165 pub enum $flag_enum {
166 $(
167 #[allow(missing_docs)]
168 $name,
169 )*
170 }
171
172 #[allow(clippy::from_over_into)]
173 impl std::convert::Into<$flag_type> for $flag_enum {
174 fn into(self) -> $flag_type {
175 match self {
176 $(
177 $flag_enum::$name => $constant,
178 )*
179 }
180 }
181 }
182
183 impl std::convert::TryFrom<$flag_type> for $flag_enum {
184 type Error = $crate::err::LibcryptErr;
185
186 fn try_from(v: $flag_type) -> Result<Self, Self::Error> {
187 Ok(match v {
188 $(
189 i if i == $constant => $flag_enum::$name,
190 )*
191 _ => return Err($crate::err::LibcryptErr::InvalidConversion),
192 })
193 }
194 }
195 };
196}
197
198#[macro_export]
199macro_rules! c_str {
201 ( $str:tt ) => {
202 concat!($str, "\0")
203 };
204}
205
206#[macro_export]
207macro_rules! c_confirm_callback {
209 ( $fn_name:ident, $type:ty, $safe_fn_name:ident ) => {
210 extern "C" fn $fn_name(
211 msg: *const std::os::raw::c_char,
212 usrptr: *mut std::os::raw::c_void,
213 ) -> std::os::raw::c_int {
214 let msg_str =
215 $crate::from_str_ptr!(msg).expect("Invalid message string passed to cryptsetup-rs");
216 let generic_ptr = usrptr.cast::<$type>();
217 let generic_ref = unsafe { generic_ptr.as_mut() };
218
219 $safe_fn_name(msg_str, generic_ref) as std::os::raw::c_int
220 }
221 };
222}
223
224#[macro_export]
225macro_rules! c_logging_callback {
227 ( $fn_name:ident, $type:ty, $safe_fn_name:ident ) => {
228 extern "C" fn $fn_name(
229 level: std::os::raw::c_int,
230 msg: *const std::os::raw::c_char,
231 usrptr: *mut std::os::raw::c_void,
232 ) {
233 let level = <$crate::consts::vals::CryptLogLevel as std::convert::TryFrom<
234 std::os::raw::c_int,
235 >>::try_from(level)
236 .expect("Invalid logging level passed to cryptsetup-rs");
237 let msg_str = $crate::from_str_ptr!(msg)
238 .expect("Invalid message string passed to cryptsetup-rs")
239 .trim();
240 let generic_ptr = usrptr.cast::<$type>();
241 let generic_ref = unsafe { generic_ptr.as_mut() };
242
243 $safe_fn_name(level, msg_str, generic_ref);
244 }
245 };
246}
247
248#[macro_export]
249macro_rules! c_progress_callback {
251 ( $fn_name:ident, $type:ty, $safe_fn_name:ident ) => {
252 extern "C" fn $fn_name(
253 size: u64,
254 offset: u64,
255 usrptr: *mut std::os::raw::c_void,
256 ) -> std::os::raw::c_int {
257 let generic_ptr = usrptr.cast::<$type>();
258 let generic_ref = unsafe { generic_ptr.as_mut() };
259
260 $safe_fn_name(size, offset, generic_ref) as std::os::raw::c_int
261 }
262 };
263}
264
265#[macro_export]
266macro_rules! c_token_handler_open {
268 ( $fn_name:ident, $type:ty, $safe_fn_name:ident ) => {
269 extern "C" fn $fn_name(
270 cd: *mut libcryptsetup_rs_sys::crypt_device,
271 token_id: std::os::raw::c_int,
272 buffer: *mut *mut std::os::raw::c_char,
273 buffer_len: *mut $crate::SizeT,
274 usrptr: *mut std::os::raw::c_void,
275 ) -> std::os::raw::c_int {
276 let device = $crate::device::CryptDevice::from_ptr(cd);
277 let generic_ptr = usrptr as *mut $type;
278 let generic_ref = unsafe { generic_ptr.as_mut() };
279
280 let buffer: Result<Box<[u8]>, $crate::LibcryptErr> =
281 $safe_fn_name(device, token_id, generic_ref);
282 match buffer {
283 Ok(()) => {
284 *buffer = Box::into_raw(buffer) as *mut std::os::raw::c_char;
285 0
286 }
287 Err(_) => -1,
288 }
289 }
290 };
291}
292
293#[macro_export]
294macro_rules! c_token_handler_free {
296 ( $fn_name:ident, $safe_fn_name:ident ) => {
297 extern "C" fn $fn_name(buffer: *mut std::os::raw::c_void, buffer_len: $crate::SizeT) {
298 let boxed_slice = unsafe {
299 Box::from_raw(std::slice::from_raw_parts_mut(
300 buffer as *mut u8,
301 buffer_len as usize,
302 ))
303 };
304
305 $safe_fn_name(boxed_slice)
306 }
307 };
308}
309
310#[macro_export]
311macro_rules! c_token_handler_validate {
313 ( $fn_name:ident, $safe_fn_name:ident ) => {
314 extern "C" fn $fn_name(
315 cd: *mut libcryptsetup_rs_sys::crypt_device,
316 json: *mut std::os::raw::c_char,
317 ) -> std::os::raw::c_int {
318 let device = $crate::device::CryptDevice::from_ptr(cd);
319 let s = match $crate::from_str_ptr!(json) {
320 Ok(s) => s,
321 Err(_) => return -1,
322 };
323 let json_obj = match serde_json::from_str(s) {
324 Ok(j) => j,
325 Err(_) => return -1,
326 };
327
328 let rc: Result<(), $crate::LibcryptErr> = $safe_fn_name(device, json_obj);
329 match rc {
330 Ok(()) => 0,
331 Err(_) => -1,
332 }
333 }
334 };
335}
336
337#[macro_export]
338macro_rules! c_token_handler_dump {
340 ( $fn_name:ident, $safe_fn_name:ident ) => {
341 extern "C" fn $fn_name(
342 cd: *mut libcryptsetup_rs_sys::crypt_device,
343 json: *mut std::os::raw::c_char,
344 ) {
345 let device = $crate::device::CryptDevice::from_ptr(cd);
346 let s = match $crate::from_str_ptr!(json) {
347 Ok(s) => s,
348 Err(_) => return,
349 };
350 let json_obj = match serde_json::from_str(s) {
351 Ok(j) => j,
352 Err(_) => return,
353 };
354
355 $safe_fn_name(device, json_obj)
356 }
357 };
358}
359
360#[cfg(test)]
361mod test {
362 use crate::consts::vals::CryptLogLevel;
363
364 fn safe_confirm_callback(_msg: &str, usrdata: Option<&mut u32>) -> bool {
365 *usrdata.unwrap() != 0
366 }
367
368 c_confirm_callback!(confirm_callback, u32, safe_confirm_callback);
369
370 fn safe_logging_callback(_level: CryptLogLevel, _msg: &str, _usrdata: Option<&mut u32>) {}
371
372 c_logging_callback!(logging_callback, u32, safe_logging_callback);
373
374 fn safe_progress_callback(_size: u64, _offset: u64, usrdata: Option<&mut u32>) -> bool {
375 *usrdata.unwrap() != 0
376 }
377
378 c_progress_callback!(progress_callback, u32, safe_progress_callback);
379
380 #[test]
381 fn test_c_confirm_callback() {
382 let ret = confirm_callback(
383 "\0".as_ptr().cast::<std::os::raw::c_char>(),
384 (&mut 1u32 as *mut u32).cast::<std::os::raw::c_void>(),
385 );
386 assert_eq!(1, ret);
387
388 let ret = confirm_callback(
389 "\0".as_ptr().cast::<std::os::raw::c_char>(),
390 (&mut 0u32 as *mut u32).cast::<std::os::raw::c_void>(),
391 );
392 assert_eq!(0, ret);
393 }
394
395 #[test]
396 fn test_c_logging_callback() {
397 logging_callback(
398 libcryptsetup_rs_sys::CRYPT_LOG_ERROR as i32,
399 "\0".as_ptr().cast::<std::os::raw::c_char>(),
400 (&mut 1u32 as *mut u32).cast::<std::os::raw::c_void>(),
401 );
402
403 logging_callback(
404 libcryptsetup_rs_sys::CRYPT_LOG_DEBUG,
405 "\0".as_ptr().cast::<std::os::raw::c_char>(),
406 (&mut 0u32 as *mut u32).cast::<std::os::raw::c_void>(),
407 );
408 }
409
410 #[test]
411 fn test_c_progress_callback() {
412 let ret = progress_callback(0, 0, (&mut 1u32 as *mut u32).cast::<std::os::raw::c_void>());
413 assert_eq!(1, ret);
414
415 let ret = progress_callback(0, 0, (&mut 0u32 as *mut u32).cast::<std::os::raw::c_void>());
416 assert_eq!(0, ret);
417 }
418
419 consts_to_from_enum!(
420 PETestEnum,
422 u16,
423 This => 0,
424 Can => 1,
425 Use => 2,
426 PartialEq => 3
427 );
428
429 #[test]
430 fn test_enum_partial_eq() {
431 assert_eq!(PETestEnum::This, PETestEnum::try_from(0).unwrap());
432 assert_eq!(PETestEnum::Can, PETestEnum::try_from(1).unwrap());
433 assert_eq!(PETestEnum::Use, PETestEnum::try_from(2).unwrap());
434 assert_eq!(PETestEnum::PartialEq, PETestEnum::try_from(3).unwrap());
435 }
436
437 #[cfg(not(feature = "mutex"))]
438 #[test]
439 #[should_panic(expected = "Enable the mutex feature")]
440 fn test_multiple_threads_no_mutex_feature() {
441 std::thread::spawn(|| {
442 crate::get_sector_size(None);
443 })
444 .join()
445 .unwrap();
446 crate::get_sector_size(None);
447 }
448}