use std::os::unix::ffi::OsStrExt; use std::path::Path; use async_trait::async_trait; use digest::generic_array::GenericArray; use digest::{Digest, OutputSizeUser}; use serde::{Deserialize, Serialize}; use sha2::Sha256; use super::{FileSystem, MountType, ReadOnly}; use crate::util::Invoke; use crate::{Error, ResultExt}; pub async fn mount( logicalname: impl AsRef, mountpoint: impl AsRef, mount_type: MountType, ) -> Result<(), Error> { tokio::fs::create_dir_all(mountpoint.as_ref()).await?; let mut cmd = tokio::process::Command::new("mount"); cmd.arg(logicalname.as_ref()).arg(mountpoint.as_ref()); if mount_type == ReadOnly { cmd.arg("-o").arg("ro"); } cmd.invoke(crate::ErrorKind::Filesystem).await?; Ok(()) } #[derive(Debug, Deserialize, Serialize)] #[serde(rename_all = "kebab-case")] pub struct BlockDev> { logicalname: LogicalName, } impl> BlockDev { pub fn new(logicalname: LogicalName) -> Self { BlockDev { logicalname } } } #[async_trait] impl + Send + Sync> FileSystem for BlockDev { async fn mount + Send + Sync>( &self, mountpoint: P, mount_type: MountType, ) -> Result<(), Error> { mount(self.logicalname.as_ref(), mountpoint, mount_type).await } async fn source_hash( &self, ) -> Result::OutputSize>, Error> { let mut sha = Sha256::new(); sha.update("BlockDev"); sha.update( tokio::fs::canonicalize(self.logicalname.as_ref()) .await .with_ctx(|_| { ( crate::ErrorKind::Filesystem, self.logicalname.as_ref().display().to_string(), ) })? .as_os_str() .as_bytes(), ); Ok(sha.finalize()) } }