pnafs 0.0.10

PNA(Portable-Network-Archive) file system
use crate::{
    cli::PasswordArgs,
    command::{Command, ask_password},
    filesystem::PnaFS,
};
use clap::{Args, ValueHint};
use fuser::{Config, MountOption, SessionACL, mount2};
use std::fs::create_dir_all;
use std::io;
use std::path::{Path, PathBuf};

#[derive(Args)]
pub(crate) struct MountArgs {
    #[command(flatten)]
    password: PasswordArgs,
    #[command(flatten)]
    mount_options: MountOptions,
    #[arg(value_hint = ValueHint::FilePath)]
    archive: PathBuf,
    #[arg(value_hint = ValueHint::DirPath)]
    mount_point: PathBuf,
}

#[derive(Args)]
struct MountOptions {
    #[arg(
        long,
        help = "Allow the root user to access this filesystem, in addition to the user who mounted it"
    )]
    allow_root: bool,
    #[arg(
        long,
        help = "Allow all users to access files on this filesystem. By default access is restricted to the user who mounted it"
    )]
    allow_other: bool,
}

impl Command for MountArgs {
    #[inline]
    fn execute(self) -> io::Result<()> {
        let password = ask_password(self.password)?;
        mount_archive(self.mount_point, self.archive, password, self.mount_options)
    }
}

fn mount_archive(
    mount_point: impl AsRef<Path>,
    archive: impl Into<PathBuf>,
    password: Option<String>,
    mount_options: MountOptions,
) -> io::Result<()> {
    let fs = PnaFS::new(archive.into(), password);
    create_dir_all(&mount_point)?;

    let acl = if mount_options.allow_other {
        SessionACL::All
    } else if mount_options.allow_root {
        SessionACL::RootAndOwner
    } else {
        SessionACL::Owner
    };

    let mut config = Config::default();
    config.mount_options = vec![MountOption::FSName("pnafs".to_owned()), MountOption::RO];
    config.acl = acl;

    mount2(fs, mount_point, &config)?;
    Ok(())
}