mirror of
https://github.com/philmmanjaro/alma.git
synced 2025-12-06 19:39:20 +01:00
Uber refactoring
This commit is contained in:
80
src/storage/crypt.rs
Normal file
80
src/storage/crypt.rs
Normal file
@@ -0,0 +1,80 @@
|
||||
use super::markers::BlockDevice;
|
||||
use crate::error::{Error, ErrorKind};
|
||||
use crate::process::CommandExt;
|
||||
use crate::tool::Tool;
|
||||
use log::{debug, warn};
|
||||
use std::marker::PhantomData;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct EncryptedDevice<'t, 'o> {
|
||||
cryptsetup: &'t Tool,
|
||||
name: String,
|
||||
path: PathBuf,
|
||||
origin: PhantomData<&'o BlockDevice>,
|
||||
}
|
||||
|
||||
impl<'t, 'o> EncryptedDevice<'t, 'o> {
|
||||
pub fn prepare(cryptsetup: &Tool, device: &BlockDevice) -> Result<(), Error> {
|
||||
debug!("Preparing encrypted device in {}", device.path().display());
|
||||
cryptsetup
|
||||
.execute()
|
||||
.arg("luksFormat")
|
||||
.arg("-q")
|
||||
.arg(device.path())
|
||||
.run(ErrorKind::LuksSetup)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn open(
|
||||
cryptsetup: &'t Tool,
|
||||
device: &'o BlockDevice,
|
||||
name: String,
|
||||
) -> Result<EncryptedDevice<'t, 'o>, Error> {
|
||||
debug!(
|
||||
"Opening encrypted device {} as {}",
|
||||
device.path().display(),
|
||||
name
|
||||
);
|
||||
cryptsetup
|
||||
.execute()
|
||||
.arg("open")
|
||||
.arg(device.path())
|
||||
.arg(&name)
|
||||
.run(ErrorKind::LuksOpen)?;
|
||||
|
||||
let path = PathBuf::from("/dev/mapper").join(&name);
|
||||
Ok(Self {
|
||||
cryptsetup,
|
||||
name,
|
||||
path,
|
||||
origin: PhantomData,
|
||||
})
|
||||
}
|
||||
|
||||
fn _close(&mut self) -> Result<(), Error> {
|
||||
debug!("Closing encrypted device {}", self.name);
|
||||
self.cryptsetup
|
||||
.execute()
|
||||
.arg("close")
|
||||
.arg(&self.name)
|
||||
.run(ErrorKind::LuksClose)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'t, 'o> Drop for EncryptedDevice<'t, 'o> {
|
||||
fn drop(&mut self) {
|
||||
if self._close().is_err() {
|
||||
warn!("Error closing {}", self.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'t, 'o> BlockDevice for EncryptedDevice<'t, 'o> {
|
||||
fn path(&self) -> &Path {
|
||||
&self.path
|
||||
}
|
||||
}
|
||||
57
src/storage/filesystem.rs
Normal file
57
src/storage/filesystem.rs
Normal file
@@ -0,0 +1,57 @@
|
||||
use super::markers::BlockDevice;
|
||||
use crate::{
|
||||
error::{Error, ErrorKind},
|
||||
process::CommandExt,
|
||||
tool::Tool,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum FilesystemType {
|
||||
Ext4,
|
||||
Vfat,
|
||||
}
|
||||
|
||||
impl FilesystemType {
|
||||
pub fn to_mount_type(self) -> &'static str {
|
||||
match self {
|
||||
FilesystemType::Ext4 => "ext4",
|
||||
FilesystemType::Vfat => "vfat",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Filesystem<'a> {
|
||||
fs_type: FilesystemType,
|
||||
block: &'a BlockDevice,
|
||||
}
|
||||
|
||||
impl<'a> Filesystem<'a> {
|
||||
pub fn format(
|
||||
block: &'a BlockDevice,
|
||||
fs_type: FilesystemType,
|
||||
mkfs: &Tool,
|
||||
) -> Result<Self, Error> {
|
||||
let mut command = mkfs.execute();
|
||||
match fs_type {
|
||||
FilesystemType::Ext4 => command.arg("-F").arg(block.path()),
|
||||
FilesystemType::Vfat => command.arg("-F32").arg(block.path()),
|
||||
};
|
||||
|
||||
command.run(ErrorKind::Formatting)?;
|
||||
|
||||
Ok(Self { fs_type, block })
|
||||
}
|
||||
|
||||
pub fn from_partition(block: &'a BlockDevice, fs_type: FilesystemType) -> Self {
|
||||
Self { fs_type, block }
|
||||
}
|
||||
|
||||
pub fn block(&self) -> &BlockDevice {
|
||||
self.block
|
||||
}
|
||||
|
||||
pub fn fs_type(&self) -> FilesystemType {
|
||||
self.fs_type
|
||||
}
|
||||
}
|
||||
7
src/storage/markers.rs
Normal file
7
src/storage/markers.rs
Normal file
@@ -0,0 +1,7 @@
|
||||
use std::path::Path;
|
||||
|
||||
pub trait BlockDevice: std::fmt::Debug {
|
||||
fn path(&self) -> &Path;
|
||||
}
|
||||
|
||||
pub trait Origin {}
|
||||
12
src/storage/mod.rs
Normal file
12
src/storage/mod.rs
Normal file
@@ -0,0 +1,12 @@
|
||||
mod crypt;
|
||||
mod filesystem;
|
||||
mod markers;
|
||||
mod mount_stack;
|
||||
mod partition;
|
||||
mod storage_device;
|
||||
|
||||
pub use crypt::EncryptedDevice;
|
||||
pub use filesystem::{Filesystem, FilesystemType};
|
||||
pub use markers::BlockDevice;
|
||||
pub use mount_stack::MountStack;
|
||||
pub use storage_device::StorageDevice;
|
||||
66
src/storage/mount_stack.rs
Normal file
66
src/storage/mount_stack.rs
Normal file
@@ -0,0 +1,66 @@
|
||||
use super::Filesystem;
|
||||
use crate::error::{Error, ErrorKind};
|
||||
use failure::Fail;
|
||||
use log::{debug, warn};
|
||||
use nix;
|
||||
use nix::mount::{mount, umount, MsFlags};
|
||||
use std::marker::PhantomData;
|
||||
use std::path::PathBuf;
|
||||
|
||||
pub struct MountStack<'a> {
|
||||
targets: Vec<PathBuf>,
|
||||
filesystems: PhantomData<Filesystem<'a>>,
|
||||
}
|
||||
|
||||
impl<'a> MountStack<'a> {
|
||||
pub fn new() -> Self {
|
||||
MountStack {
|
||||
targets: Vec::new(),
|
||||
filesystems: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn mount(
|
||||
&mut self,
|
||||
filesystem: &'a Filesystem,
|
||||
target: PathBuf,
|
||||
options: Option<&str>,
|
||||
) -> nix::Result<()> {
|
||||
let source = filesystem.block().path();
|
||||
debug!("Mounting {:?} to {:?}", filesystem, target);
|
||||
mount(
|
||||
Some(source),
|
||||
&target,
|
||||
Some(filesystem.fs_type().to_mount_type()),
|
||||
MsFlags::MS_NOATIME,
|
||||
options,
|
||||
)?;
|
||||
self.targets.push(target);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn _umount(&mut self) -> Result<(), Error> {
|
||||
let mut result = Ok(());
|
||||
|
||||
while let Some(target) = self.targets.pop() {
|
||||
debug!("Unmounting {}", target.display());
|
||||
if let Err(e) = umount(&target) {
|
||||
warn!("Unable to umount {}: {}", target.display(), e);
|
||||
result = Err(Error::from(e.context(ErrorKind::UmountFailure)));
|
||||
};
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
pub fn umount(mut self) -> Result<(), Error> {
|
||||
self._umount()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Drop for MountStack<'a> {
|
||||
fn drop(&mut self) {
|
||||
self._umount().ok();
|
||||
}
|
||||
}
|
||||
24
src/storage/partition.rs
Normal file
24
src/storage/partition.rs
Normal file
@@ -0,0 +1,24 @@
|
||||
use super::markers::{BlockDevice, Origin};
|
||||
use std::marker::PhantomData;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Partition<'a> {
|
||||
path: PathBuf,
|
||||
origin: PhantomData<&'a Origin>,
|
||||
}
|
||||
|
||||
impl<'a> Partition<'a> {
|
||||
pub fn new<T: Origin + 'a>(path: PathBuf) -> Self {
|
||||
Self {
|
||||
path,
|
||||
origin: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> BlockDevice for Partition<'a> {
|
||||
fn path(&self) -> &Path {
|
||||
&self.path
|
||||
}
|
||||
}
|
||||
87
src/storage/storage_device.rs
Normal file
87
src/storage/storage_device.rs
Normal file
@@ -0,0 +1,87 @@
|
||||
use super::markers::{BlockDevice, Origin};
|
||||
use super::partition::Partition;
|
||||
use crate::error::{Error, ErrorKind};
|
||||
use failure::ResultExt;
|
||||
use log::debug;
|
||||
use std::fs::read_to_string;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct StorageDevice {
|
||||
name: String,
|
||||
path: PathBuf,
|
||||
}
|
||||
|
||||
impl StorageDevice {
|
||||
pub fn from_path(path: PathBuf) -> Result<Self, Error> {
|
||||
let real_path = path.canonicalize().context(ErrorKind::DeviceQuery)?;
|
||||
let device_name = real_path
|
||||
.file_name()
|
||||
.and_then(|s| s.to_str())
|
||||
.map(String::from)
|
||||
.ok_or_else(|| Error::from(ErrorKind::InvalidDeviceName))?;
|
||||
|
||||
debug!(
|
||||
"path: {:?}, real path: {:?}, device name: {:?}",
|
||||
path, real_path, device_name
|
||||
);
|
||||
|
||||
drop(path);
|
||||
let _self = Self {
|
||||
name: device_name,
|
||||
path: real_path,
|
||||
};
|
||||
if !(_self.is_removable_device()? || _self.is_loop_device()) {
|
||||
return Err(ErrorKind::DangerousDevice)?;
|
||||
}
|
||||
|
||||
Ok(_self)
|
||||
}
|
||||
|
||||
fn sys_path(&self) -> PathBuf {
|
||||
let mut path = PathBuf::from("/sys/block");
|
||||
path.push(self.name.clone());
|
||||
path
|
||||
}
|
||||
|
||||
fn is_removable_device(&self) -> Result<bool, Error> {
|
||||
let mut path = self.sys_path();
|
||||
path.push("removable");
|
||||
|
||||
debug!("Reading: {:?}", path);
|
||||
let result = read_to_string(&path).context(ErrorKind::DeviceQuery)?;
|
||||
debug!("{:?} -> {}", path, result);
|
||||
|
||||
Ok(result == "1\n")
|
||||
}
|
||||
|
||||
fn is_loop_device(&self) -> bool {
|
||||
let mut path = self.sys_path();
|
||||
path.push("loop");
|
||||
path.exists()
|
||||
}
|
||||
|
||||
pub fn get_partition(&self, index: u8) -> Result<Partition, Error> {
|
||||
let name = if self.name.chars().rev().next().unwrap().is_digit(10) {
|
||||
format!("{}p{}", self.name, index)
|
||||
} else {
|
||||
format!("{}{}", self.name, index)
|
||||
};
|
||||
let mut path = PathBuf::from("/dev");
|
||||
path.push(name);
|
||||
|
||||
debug!("Partition {} for {} is in {:?}", index, self.name, path);
|
||||
if !path.exists() {
|
||||
return Err(ErrorKind::NoSuchPartition(index).into());
|
||||
}
|
||||
Ok(Partition::new::<Self>(path))
|
||||
}
|
||||
}
|
||||
|
||||
impl BlockDevice for StorageDevice {
|
||||
fn path(&self) -> &Path {
|
||||
&self.path
|
||||
}
|
||||
}
|
||||
|
||||
impl Origin for StorageDevice {}
|
||||
Reference in New Issue
Block a user