use crate::error::{VZError, VZResult};
use crate::shim_ffi;
use std::ffi::{CString, c_void};
use std::path::Path;
use std::ptr;
pub struct SharedDirectory {
inner: *mut c_void,
}
unsafe impl Send for SharedDirectory {}
impl SharedDirectory {
pub fn new(path: impl AsRef<Path>, read_only: bool) -> VZResult<Self> {
let path = path.as_ref();
if !path.exists() {
return Err(VZError::NotFound(path.display().to_string()));
}
if !path.is_dir() {
return Err(VZError::InvalidConfiguration(format!(
"Path is not a directory: {}",
path.display()
)));
}
let c_path = CString::new(path.to_string_lossy().as_bytes()).map_err(|_| {
VZError::InvalidConfiguration(format!("path contains NUL: {}", path.display()))
})?;
let obj = unsafe { shim_ffi::abx_shared_directory_new(c_path.as_ptr(), read_only) };
tracing::debug!(
"Created SharedDirectory for {:?} (read_only={})",
path,
read_only
);
Ok(Self { inner: obj })
}
}
impl Drop for SharedDirectory {
fn drop(&mut self) {
if !self.inner.is_null() {
unsafe { shim_ffi::abx_object_release(self.inner.cast()) };
}
}
}
pub trait DirectoryShare {
fn as_ptr(&self) -> *mut c_void;
}
pub struct SingleDirectoryShare {
inner: *mut c_void,
}
unsafe impl Send for SingleDirectoryShare {}
impl SingleDirectoryShare {
pub fn new(directory: SharedDirectory) -> VZResult<Self> {
let obj = unsafe { shim_ffi::abx_single_share_new(directory.inner.cast()) };
tracing::debug!("Created SingleDirectoryShare");
Ok(Self { inner: obj })
}
}
impl DirectoryShare for SingleDirectoryShare {
fn as_ptr(&self) -> *mut c_void {
self.inner
}
}
impl Drop for SingleDirectoryShare {
fn drop(&mut self) {
if !self.inner.is_null() {
unsafe { shim_ffi::abx_object_release(self.inner.cast()) };
}
}
}
pub struct VirtioFileSystemDeviceConfiguration {
inner: *mut c_void,
tag: String,
}
unsafe impl Send for VirtioFileSystemDeviceConfiguration {}
impl VirtioFileSystemDeviceConfiguration {
pub fn new(tag: &str) -> VZResult<Self> {
if tag.is_empty() {
return Err(VZError::InvalidConfiguration(
"VirtioFS tag cannot be empty".into(),
));
}
let c_tag = CString::new(tag)
.map_err(|_| VZError::InvalidConfiguration(format!("tag contains NUL: {tag}")))?;
unsafe {
let mut error: *mut std::ffi::c_char = ptr::null_mut();
let obj = shim_ffi::abx_virtiofs_new(c_tag.as_ptr(), &raw mut error);
if obj.is_null() {
return Err(VZError::InvalidConfiguration(shim_ffi::take_error_string(
error,
)));
}
tracing::debug!("Created VirtioFileSystemDeviceConfiguration with tag '{tag}'");
Ok(Self {
inner: obj,
tag: tag.to_string(),
})
}
}
pub fn set_share<S: DirectoryShare>(&mut self, share: S) -> &mut Self {
unsafe {
shim_ffi::abx_virtiofs_set_share(self.inner.cast(), share.as_ptr().cast());
}
tracing::debug!("Set share for VirtioFS device '{}'", self.tag);
self
}
#[must_use]
pub fn tag(&self) -> &str {
&self.tag
}
#[must_use]
pub(crate) fn into_ptr(self) -> *mut c_void {
let ptr = self.inner;
std::mem::forget(self);
ptr
}
}
impl Drop for VirtioFileSystemDeviceConfiguration {
fn drop(&mut self) {
if !self.inner.is_null() {
unsafe { shim_ffi::abx_object_release(self.inner.cast()) };
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RosettaAvailability {
NotSupported,
Supported,
NotInstalled,
}
pub struct LinuxRosettaDirectoryShare {
inner: *mut c_void,
}
unsafe impl Send for LinuxRosettaDirectoryShare {}
impl LinuxRosettaDirectoryShare {
pub fn availability() -> RosettaAvailability {
match unsafe { shim_ffi::abx_rosetta_availability() } {
2 => RosettaAvailability::Supported,
1 => RosettaAvailability::NotInstalled,
_ => RosettaAvailability::NotSupported,
}
}
pub fn new() -> VZResult<Self> {
let avail = Self::availability();
if avail != RosettaAvailability::Supported {
return Err(VZError::OperationFailed(format!(
"Rosetta is not available: {avail:?}"
)));
}
unsafe {
let mut error: *mut std::ffi::c_char = ptr::null_mut();
let obj = shim_ffi::abx_rosetta_share_new(&raw mut error);
if obj.is_null() {
return Err(VZError::OperationFailed(shim_ffi::take_error_string(error)));
}
tracing::debug!("Created LinuxRosettaDirectoryShare");
Ok(Self { inner: obj })
}
}
}
impl DirectoryShare for LinuxRosettaDirectoryShare {
fn as_ptr(&self) -> *mut c_void {
self.inner
}
}
impl Drop for LinuxRosettaDirectoryShare {
fn drop(&mut self) {
if !self.inner.is_null() {
unsafe { shim_ffi::abx_object_release(self.inner.cast()) };
}
}
}