use typed_builder::TypedBuilder;
use std::fs::File;
use std::path::PathBuf;
use crate::core::device::Usage;
use crate::core::partition::FileSystem;
use crate::core::partition::PartitionTableType;
use crate::probe::Filter;
use crate::probe::FsProperty;
use crate::probe::PartitionScanningOption;
use crate::probe::Probe;
use crate::probe::ProbeBuilderError;
#[derive(Debug, TypedBuilder)]
#[builder(builder_type(name = ProbeBuilder, vis = "pub", doc ="Configures and creates a new
[`Probe`] instance.\n\nFor usage, see [`ProbeBuilder::build`] or the overview of the
[`probe`](crate::probe#overview) module."),
build_method(vis = "", name = __build))]
pub(crate) struct PrbBuilder {
#[builder(
default,
setter(into, strip_option),
setter(doc = "Sets the path to the device to associate with a [`Probe`].")
)]
scan_device: Option<PathBuf>,
#[builder(
default,
setter(
strip_option,
doc = "Sets the [`File`] object, providing access to an open device, as the device to
associate with a [`Probe`]."
)
)]
scan_file: Option<File>,
#[builder(
setter(strip_bool),
setter(
doc = "Sets a [`Probe`] to read/write mode.\n\n**Note:** Calling `allow_writes`
automatically adds [`FsProperty::Magic`](crate::probe::flag::FsProperty::Magic) to the
list of properties to collect."
)
)]
allow_writes: bool,
#[builder(
default = 512,
setter(doc = "Sets the number of bytes per sector on the device.")
)]
bytes_per_sector: u32,
#[builder(default = (0,0),
setter(transform = |location: u64, size: u64| (location, size),
doc = "Sets the region to scan on the [`Probe`]'s associated device.\n\n# Arguments\n\n-
`location` -- offset in bytes.\n- `size` -- region's size in bytes."))]
scan_device_segment: (u64, u64),
#[builder(
default = true,
setter(
doc = "Deactivates file system search functions when set to `false`. By default, set to
`true`."
)
)]
scan_device_superblocks: bool,
#[builder(default = None,
setter(transform = |criterion: Filter, fs_types: impl AsRef<[FileSystem]>| Some((criterion,
fs_types.as_ref().to_vec())),
doc = "Specifies which file systems to search for/exclude when scanning a device. By
default, a [`Probe`] will try to identify any of the supported [`FileSystem`]s,")) ]
scan_superblocks_for_file_systems: Option<(Filter, Vec<FileSystem>)>,
#[builder(default = None, setter(transform = |criterion: Filter, usage: impl AsRef<[Usage]>|
Some((criterion, usage.as_ref().to_vec())), doc = "Limits file system scanning to
superblocks with particular [`Usage`](crate::core::device::Usage) flags."))]
scan_superblocks_with_usage_flags: Option<(Filter, Vec<Usage>)>,
#[builder(default = None, setter(transform = |fs_properties: impl AsRef<[FsProperty]>|
Some(fs_properties.as_ref().to_vec()),
doc = "Sets the list of file system properties ([`FsProperty`](flag::FsProperty)) to
collect."))]
collect_fs_properties: Option<Vec<FsProperty>>,
#[builder(
default = false,
setter(
doc = "Activates partitions search functions when set to `true`. By default, set to `false`."
)
)]
scan_device_partitions: bool,
#[builder(default = None,
setter(transform = |criterion: Filter, pt_types: impl AsRef<[PartitionTableType]>|
Some((criterion, pt_types.as_ref().to_vec())),
doc = "Sets which partition table types to search for/exclude when scanning a device. By
default, a [`Probe`] will try to identify any of the supported [`PartitionTableType`]s."))]
scan_partitions_for_partition_tables: Option<(Filter, Vec<PartitionTableType>)>,
#[builder(default = None, setter(transform = |options: impl AsRef<[PartitionScanningOption]>|
Some(options.as_ref().to_vec()),
doc = "Sets optional scanning criteria for partition search functions."))]
partitions_scanning_options: Option<Vec<PartitionScanningOption>>,
#[builder(default = false)]
scan_device_topology: bool,
}
#[allow(non_camel_case_types)]
impl<
__scan_device: ::typed_builder::Optional<Option<PathBuf>>,
__scan_file: ::typed_builder::Optional<Option<File>>,
__allow_writes: ::typed_builder::Optional<bool>,
__bytes_per_sector: ::typed_builder::Optional<u32>,
__scan_device_segment: ::typed_builder::Optional<(u64, u64)>,
__scan_device_superblocks: ::typed_builder::Optional<bool>,
__scan_superblocks_for_file_systems: ::typed_builder::Optional<Option<(Filter, Vec<FileSystem>)>>,
__scan_superblocks_with_usage_flags: ::typed_builder::Optional<Option<(Filter, Vec<Usage>)>>,
__collect_fs_properties: ::typed_builder::Optional<Option<Vec<FsProperty>>>,
__scan_device_partitions: ::typed_builder::Optional<bool>,
__scan_partitions_for_partition_tables: ::typed_builder::Optional<Option<(Filter, Vec<PartitionTableType>)>>,
__partitions_scanning_options: ::typed_builder::Optional<Option<Vec<PartitionScanningOption>>>,
__scan_device_topology: ::typed_builder::Optional<bool>,
>
ProbeBuilder<(
__scan_device,
__scan_file,
__allow_writes,
__bytes_per_sector,
__scan_device_segment,
__scan_device_superblocks,
__scan_superblocks_for_file_systems,
__scan_superblocks_with_usage_flags,
__collect_fs_properties,
__scan_device_partitions,
__scan_partitions_for_partition_tables,
__partitions_scanning_options,
__scan_device_topology,
)>
{
pub fn build(self) -> Result<Probe, ProbeBuilderError> {
let builder = self.__build();
let mut probe = match (builder.scan_device, builder.scan_file, builder.allow_writes) {
(None, None, _) => Err(ProbeBuilderError::Required(
"one of the options `scan_device` or `scan_file` must be set".to_string(),
)),
(Some(_), Some(_), _) => Err(ProbeBuilderError::MutuallyExclusive(
"can not set `scan_device` and `scan_file` simultaneously".to_string(),
)),
(Some(path), None, false) => Probe::new_read_only(path, builder.scan_device_segment)
.map_err(ProbeBuilderError::from),
(Some(path), None, true) => Probe::new_read_write(path, builder.scan_device_segment)
.map_err(ProbeBuilderError::from),
(None, Some(file), false) => Probe::new_from_file(file, builder.scan_device_segment)
.map_err(ProbeBuilderError::from),
(None, Some(file), true) => {
Probe::new_from_file_read_write(file, builder.scan_device_segment)
.map_err(ProbeBuilderError::from)
}
}?;
probe.set_bytes_per_sector(builder.bytes_per_sector)?;
if builder.scan_device_superblocks {
probe.enable_chain_superblocks()?
} else {
probe.disable_chain_superblocks()?
}
if let Some((criterion, fs_types)) = builder.scan_superblocks_for_file_systems {
probe.scan_superblocks_for_file_systems(criterion, fs_types.as_slice())?
}
if let Some((criterion, usage)) = builder.scan_superblocks_with_usage_flags {
probe.scan_superblocks_with_usage_flags(criterion, usage.as_slice())?
}
if let Some(mut sb_flags) = builder.collect_fs_properties {
if builder.allow_writes {
sb_flags.push(FsProperty::Magic);
}
probe.collect_fs_properties(sb_flags.as_slice())?
}
if builder.scan_device_partitions {
probe.enable_chain_partitions()?
} else {
probe.disable_chain_partitions()?
}
if let Some((criterion, pt_types)) = builder.scan_partitions_for_partition_tables {
probe.scan_partitions_for_partition_tables(criterion, pt_types.as_slice())?
}
if let Some(mut part_flags) = builder.partitions_scanning_options {
if builder.allow_writes {
part_flags.push(PartitionScanningOption::Magic);
}
probe.set_partitions_scanning_options(part_flags.as_slice())?
}
if builder.scan_device_topology {
probe.enable_chain_topology()?
} else {
probe.disable_chain_topology()?
}
Ok(probe)
}
}