rencfs 0.14.11

WARNING! UNDER ACTIVE DEVELOPMENT. An encrypted file system that is mounted with FUSE on Linux. It can be used to create encrypted directories.
Documentation
#![cfg(target_os = "linux")]
use std::fs;
use std::path::Path;
use std::str::FromStr;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::{Arc, Mutex, Once};
use std::thread::sleep;
use std::time::Duration;

use rencfs::crypto::Cipher;
use rencfs::encryptedfs::PasswordProvider;
use rencfs::mount::{create_mount_point, MountHandle, MountPoint};
use shush_rs::SecretString;
use tokio::runtime::Runtime;

struct TestResource {
    mount_handle: Option<MountHandle>,
    runtime: Runtime,
}

pub const MOUNT_PATH: &str = "/tmp/rencfs/mnt";
pub const DATA_PATH: &str = "/tmp/rencfs/data";

impl TestResource {
    fn new() -> Self {
        let mount_point = create_mount_point(
            Path::new(&MOUNT_PATH),
            Path::new(&DATA_PATH),
            get_password_provider(),
            Cipher::ChaCha20Poly1305,
            false,
            false,
            false,
        );
        let runtime = tokio::runtime::Builder::new_multi_thread()
            .worker_threads(1)
            .enable_all()
            .build()
            .unwrap();
        let mh = runtime.block_on(async {
            let mh = mount_point.mount().await;
            sleep(Duration::from_millis(100));
            mh
        });

        Self {
            mount_handle: match mh {
                Ok(mh) => Some(mh),
                Err(e) => panic!("Encountered an error mounting {}", e),
            },
            runtime,
        }
    }
}

impl Drop for TestResource {
    fn drop(&mut self) {
        let mh = self
            .mount_handle
            .take()
            .expect("MountHandle should be some");
        let res = self.runtime.block_on(async { mh.umount().await });
        match res {
            Ok(_) => println!("Succesfully unmounted"),
            Err(e) => {
                panic!(
                    "Something went wrong when unmounting {}.You may need to manually unmount",
                    e
                )
            }
        }
    }
}

static mut TEST_RESOURCES: Option<Arc<Mutex<TestResource>>> = None;
static INIT: Once = Once::new();
static TEARDOWN: Once = Once::new();
static RESOURCE_COUNT: AtomicUsize = AtomicUsize::new(0);

pub struct TestGuard;

impl TestGuard {
    pub fn setup() -> Self {
        unsafe {
            INIT.call_once(|| {
                println!("Initializing the mount");
                TEST_RESOURCES = Some(Arc::new(Mutex::new(TestResource::new())));
            });
        }
        RESOURCE_COUNT.fetch_add(1, Ordering::SeqCst);
        Self
    }
}

#[allow(static_mut_refs)]
impl Drop for TestGuard {
    fn drop(&mut self) {
        if RESOURCE_COUNT.fetch_sub(1, Ordering::SeqCst) == 1 {
            TEARDOWN.call_once(|| unsafe {
                if let Some(resources) = TEST_RESOURCES.take() {
                    println!("Deinitializing the mount");
                    drop(resources);
                }
            });
        }
    }
}

struct TestPasswordProvider {}
impl PasswordProvider for TestPasswordProvider {
    fn get_password(&self) -> Option<SecretString> {
        Some(SecretString::from_str("test").unwrap())
    }
}

pub fn get_password_provider() -> Box<dyn PasswordProvider> {
    Box::new(TestPasswordProvider {})
}

pub fn count_files(folder_path: &str) -> u32 {
    println!("<<<[{}]>>>", &folder_path);
    let path = Path::new(folder_path);
    let mut file_count = 0;
    if let Ok(dir_iterator) = fs::read_dir(path) {
        for _entry in dir_iterator {
            let _ = _entry.inspect(|e| println!("[{:?}]", e.file_name()));
            file_count += 1;
        }
    }
    println!("<<< File count [{}] >>>", &file_count);
    file_count
}