use std::{ffi::CString, path::Path, ptr};
use either::Either;
use libc::{c_char, c_int, c_void};
use libcryptsetup_rs_sys::crypt_device;
use crate::{
activate::CryptActivation, backup::CryptBackup, context::CryptContext, debug::CryptDebug,
err::LibcryptErr, format::CryptFormat, key::CryptVolumeKey, keyfile::CryptKeyfile,
keyslot::CryptKeyslot, log::CryptLog, luks2_flags::CryptLuks2Flags,
luks2_reencrypt::CryptLuks2Reencrypt, luks2_token::CryptLuks2Token, runtime::CryptRuntime,
settings::CryptSettings, status::CryptDeviceStatus, wipe::CryptWipe,
};
type ConfirmCallback = unsafe extern "C" fn(msg: *const c_char, usrptr: *mut c_void) -> c_int;
pub struct CryptInit;
impl CryptInit {
pub fn init(device_path: &Path) -> Result<CryptDevice, LibcryptErr> {
let mut cdevice: *mut crypt_device = ptr::null_mut();
let device_path_cstring = path_to_cstring!(device_path)?;
errno!(unsafe {
libcryptsetup_rs_sys::crypt_init(
&mut cdevice as *mut *mut crypt_device,
device_path_cstring.as_ptr(),
)
})?;
Ok(CryptDevice { ptr: cdevice })
}
pub fn init_with_data_device(
device_paths: Either<&Path, (&Path, &Path)>,
) -> Result<CryptDevice, LibcryptErr> {
let mut cdevice: *mut crypt_device = ptr::null_mut();
let (device_path_cstring, data_device_option) = match device_paths {
Either::Left(device) => (path_to_cstring!(device)?, None),
Either::Right((header_device, data_device)) => (
path_to_cstring!(header_device)?,
Some(path_to_cstring!(data_device)?),
),
};
errno!(unsafe {
libcryptsetup_rs_sys::crypt_init_data_device(
&mut cdevice as *mut *mut crypt_device,
device_path_cstring.as_ptr(),
match data_device_option {
Some(ref d) => d.as_ptr(),
None => ptr::null(),
},
)
})?;
Ok(CryptDevice { ptr: cdevice })
}
pub fn init_by_name_and_header(
name: &str,
header_device_path: Option<&Path>,
) -> Result<CryptDevice, LibcryptErr> {
let mut cdevice: *mut crypt_device = ptr::null_mut();
let name_cstring = to_cstring!(name)?;
let mut header_device_path_cstring = CString::default();
if let Some(path) = header_device_path {
header_device_path_cstring = path_to_cstring!(path)?;
}
errno!(unsafe {
libcryptsetup_rs_sys::crypt_init_by_name_and_header(
&mut cdevice as *mut *mut crypt_device,
name_cstring.as_ptr(),
if header_device_path.is_some() {
header_device_path_cstring.as_ptr()
} else {
ptr::null()
},
)
})?;
Ok(CryptDevice { ptr: cdevice })
}
}
pub struct CryptDevice {
ptr: *mut crypt_device,
}
impl CryptDevice {
pub fn from_ptr(ptr: *mut crypt_device) -> Self {
CryptDevice { ptr }
}
pub fn logging_handle(&mut self) -> CryptLog {
CryptLog::new(self)
}
pub fn settings_handle(&mut self) -> CryptSettings {
CryptSettings::new(self)
}
pub fn format_handle(&mut self) -> CryptFormat {
CryptFormat::new(self)
}
pub fn context_handle(&mut self) -> CryptContext {
CryptContext::new(self)
}
pub fn keyslot_handle(&mut self) -> CryptKeyslot {
CryptKeyslot::new(self)
}
pub fn runtime_handle<'a>(&'a mut self, name: &'a str) -> CryptRuntime<'a> {
CryptRuntime::new(self, name)
}
pub fn luks2_flag_handle<T>(&mut self) -> CryptLuks2Flags<T> {
CryptLuks2Flags::new(self)
}
pub fn activate_handle(&mut self) -> CryptActivation {
CryptActivation::new(self)
}
pub fn volume_key_handle(&mut self) -> CryptVolumeKey {
CryptVolumeKey::new(self)
}
pub fn status_handle(&mut self) -> CryptDeviceStatus {
CryptDeviceStatus::new(self)
}
pub fn backup_handle(&mut self) -> CryptBackup {
CryptBackup::new(self)
}
pub fn debug_handle() -> CryptDebug {
CryptDebug
}
pub fn keyfile_handle(&mut self) -> CryptKeyfile {
CryptKeyfile::new(self)
}
pub fn wipe_handle(&mut self) -> CryptWipe {
CryptWipe::new(self)
}
pub fn token_handle(&mut self) -> CryptLuks2Token {
CryptLuks2Token::new(self)
}
pub fn reencrypt_handle(&mut self) -> CryptLuks2Reencrypt {
CryptLuks2Reencrypt::new(self)
}
pub fn set_confirm_callback<T>(
&mut self,
confirm: Option<ConfirmCallback>,
usrdata: Option<&mut T>,
) {
unsafe {
libcryptsetup_rs_sys::crypt_set_confirm_callback(
self.ptr,
confirm,
match usrdata {
Some(ud) => ud as *mut _ as *mut c_void,
None => ptr::null_mut(),
},
)
}
}
pub fn set_data_device(&mut self, device_path: &Path) -> Result<(), LibcryptErr> {
let device_path_cstring = path_to_cstring!(device_path)?;
errno!(unsafe {
libcryptsetup_rs_sys::crypt_set_data_device(self.ptr, device_path_cstring.as_ptr())
})
}
pub fn set_data_offset(&mut self, offset: u64) -> Result<(), LibcryptErr> {
errno!(unsafe { libcryptsetup_rs_sys::crypt_set_data_offset(self.ptr, offset * 8) })
}
pub(crate) fn as_ptr(&mut self) -> *mut crypt_device {
self.ptr
}
}
impl Drop for CryptDevice {
fn drop(&mut self) {
unsafe { libcryptsetup_rs_sys::crypt_free(self.ptr) }
}
}