use crate::passthrough::file_handle::{FileOrHandle, SerializableFileHandle};
use crate::passthrough::inode_store::{InodeData, StrongInodeReference};
use crate::passthrough::{self, MigrationMode};
use crate::util::ResultErrorContext;
use std::convert::TryInto;
use std::ffi::CStr;
use std::fmt::{self, Display};
use std::io;
pub mod file_handles;
pub mod find_paths;
pub mod proc_paths;
pub(in crate::passthrough) struct InodeMigrationInfo {
pub location: InodeLocation,
pub file_handle: Option<SerializableFileHandle>,
}
pub(in crate::passthrough) enum InodeLocation {
RootNode,
Path(find_paths::InodePath),
FileHandle(file_handles::FileHandle),
}
pub(in crate::passthrough) enum HandleMigrationInfo {
OpenInode { flags: i32 },
}
impl InodeMigrationInfo {
pub fn new(
fs_cfg: &passthrough::Config,
parent_ref: StrongInodeReference,
filename: &CStr,
file_or_handle: &FileOrHandle,
) -> io::Result<Self> {
let location: InodeLocation = match fs_cfg.migration_mode {
MigrationMode::FindPaths => {
find_paths::InodePath::new_with_cstr(parent_ref, filename)?.into()
}
MigrationMode::FileHandles => {
let handle = file_or_handle.try_into().err_context(|| {
format!(
"(inode {})/{filename:?}: Failed to generate file handle",
parent_ref.get().inode,
)
})?;
file_handles::FileHandle::new(handle).into()
}
};
Self::new_internal(fs_cfg, location, || file_or_handle.try_into())
}
fn new_internal<L: Into<InodeLocation>, F: FnOnce() -> io::Result<SerializableFileHandle>>(
fs_cfg: &passthrough::Config,
inode_location: L,
file_handle_fn: F,
) -> io::Result<Self> {
let file_handle: Option<SerializableFileHandle> = if fs_cfg.migration_verify_handles {
Some(file_handle_fn()?)
} else {
None
};
Ok(InodeMigrationInfo {
location: inode_location.into(),
file_handle,
})
}
pub(in crate::passthrough) fn new_root(
fs_cfg: &passthrough::Config,
file_or_handle: &FileOrHandle,
) -> io::Result<Self> {
Self::new_internal(fs_cfg, InodeLocation::RootNode, || {
file_or_handle.try_into()
})
}
pub fn for_each_strong_reference<F: FnMut(StrongInodeReference)>(self, f: F) {
match self.location {
InodeLocation::RootNode => (),
InodeLocation::Path(p) => p.for_each_strong_reference(f),
InodeLocation::FileHandle(fh) => fh.for_each_strong_reference(f),
}
}
pub fn has_path(&self) -> bool {
match &self.location {
InodeLocation::RootNode => false,
InodeLocation::Path(_) => true,
InodeLocation::FileHandle(_) => false,
}
}
pub fn check_path_presence(&self, inode_data: &InodeData) -> io::Result<()> {
match &self.location {
InodeLocation::RootNode => Ok(()),
InodeLocation::Path(p) => p.check_presence(inode_data, self),
InodeLocation::FileHandle(_) => Ok(()),
}
}
}
impl Display for InodeLocation {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
InodeLocation::RootNode => write!(f, "[shared directory root]"),
InodeLocation::Path(p) => write!(f, "{p}"),
InodeLocation::FileHandle(fh) => write!(f, "{fh}"),
}
}
}
impl HandleMigrationInfo {
pub fn new(flags: i32) -> Self {
HandleMigrationInfo::OpenInode {
flags: flags & !(libc::O_CREAT | libc::O_EXCL | libc::O_TRUNC),
}
}
}