Skip to content

Commit

Permalink
Merge branch 'tools-ux'
Browse files Browse the repository at this point in the history
  • Loading branch information
Demindiro committed Feb 2, 2023
2 parents 56f91fe + 99ab96a commit d5e4099
Show file tree
Hide file tree
Showing 24 changed files with 963 additions and 430 deletions.
4 changes: 4 additions & 0 deletions fuse/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ parallel = ["nrfs/parallel"]
[dependencies.async-channel]
version = "1.8"

[dependencies.clap]
version = "4.1"
features = ["derive"]

[dependencies.fuser]
version = "0.11"
features = ["abi-7-28"]
Expand Down
6 changes: 5 additions & 1 deletion fuse/src/fs/channel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use {
async_channel::Sender,
fuser::{
Filesystem, KernelConfig, ReplyAttr, ReplyCreate, ReplyData, ReplyDirectory, ReplyEmpty,
ReplyEntry, ReplyWrite, Request, TimeOrNow,
ReplyEntry, ReplyStatfs, ReplyWrite, Request, TimeOrNow,
},
std::{ffi::OsStr, path::Path, time::SystemTime},
};
Expand Down Expand Up @@ -236,6 +236,10 @@ impl Filesystem for FsChannel {
self.send(Job::FSync(FSync { reply }));
}

fn statfs(&mut self, _: &Request<'_>, _: u64, reply: ReplyStatfs) {
self.send(Job::StatFs(StatFs { reply }))
}

fn destroy(&mut self) {
self.send(Job::Destroy);
}
Expand Down
9 changes: 6 additions & 3 deletions fuse/src/fs/inode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,12 @@ macro_rules! impl_ty {
}

impl InodeStore {
/// Create a new inode store with the given uid and gid as defaults.
pub fn new(uid: u32, gid: u32) -> Self {
Self { unix_default: ext::unix::Entry::new(0o700, uid, gid), ..Default::default() }
/// Create a new inode store with the given permissions, uid and gid as defaults.
pub fn new(permissions: u16, uid: u32, gid: u32) -> Self {
Self {
unix_default: ext::unix::Entry::new(permissions, uid, gid),
..Default::default()
}
}

fn add<'a, 'b, T: RawRef<'a, 'b, FileDev>>(
Expand Down
44 changes: 26 additions & 18 deletions fuse/src/fs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,30 +35,32 @@ pub struct Fs {
}

impl Fs {
pub async fn new(io: fs::File) -> (Self, FsChannel) {
pub async fn new(
permissions: u16,
io: impl Iterator<Item = fs::File>,
key: Option<[u8; 32]>,
cache_size: usize,
) -> (Self, FsChannel) {
let retrieve_key = &mut |use_password| {
if use_password {
rpassword::prompt_password("Password: ")
.expect("failed to ask password")
.into_bytes()
if let Some(key) = key {
Some(nrfs::KeyPassword::Key(key))
} else if use_password {
let pwd = rpassword::prompt_password("Password: ").expect("failed to ask password");
Some(nrfs::KeyPassword::Password(pwd.into_bytes()))
} else {
todo!("ask for key file")
None
}
};

let fs = FileDev::new(io, nrfs::BlockSize::K4);
let conf = nrfs::LoadConfig {
key_password: nrfs::KeyPassword::Key(&[0; 32]),
retrieve_key,
devices: vec![fs],
cache_size: 1 << 24,
allow_repair: true,
};
let devices = io.map(|f| FileDev::new(f, nrfs::BlockSize::K4)).collect();
let conf = nrfs::LoadConfig { retrieve_key, devices, cache_size, allow_repair: true };
eprintln!("Mounting filesystem");
let fs = Nrfs::load(conf).await.unwrap();

// Add root dir now so it's always at ino 1.
let mut ino = InodeStore::new(unsafe { libc::getuid() }, unsafe { libc::getgid() });
let mut ino = InodeStore::new(permissions, unsafe { libc::getuid() }, unsafe {
libc::getgid()
});

let bg = Background::default();
let root = bg.run(fs.root_dir(&bg)).await.unwrap();
Expand Down Expand Up @@ -108,6 +110,7 @@ impl Fs {
Unlink unlink
RmDir rmdir
FSync fsync
StatFs statfs
}
}
Ok::<_, nrfs::Error<_>>(())
Expand Down Expand Up @@ -135,6 +138,13 @@ impl Fs {
});

let blksize = 1u32 << self.fs.block_size().to_raw();

// "Number of 512B blocks allocated"
let blocks =
u64::try_from((u128::from(len) + u128::from(blksize) - 1) / u128::from(blksize))
.unwrap();
let blocks = blocks << (self.fs.block_size().to_raw() - 9);

FileAttr {
atime: UNIX_EPOCH,
mtime,
Expand All @@ -148,9 +158,7 @@ impl Fs {
flags: 0,
kind: ty,
size: len,
blocks: ((u128::from(len) + u128::from(blksize) - 1) / u128::from(blksize))
.try_into()
.unwrap_or(u64::MAX),
blocks,
ino,
blksize,
}
Expand Down
1 change: 1 addition & 0 deletions fuse/src/fs/ops/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ mod readlink;
mod rename;
mod rmdir;
mod setattr;
mod statfs;
mod symlink;
mod unlink;
mod write;
Expand Down
19 changes: 19 additions & 0 deletions fuse/src/fs/ops/statfs.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
use super::*;

impl Fs {
pub async fn statfs<'a>(&'a self, _: &Background<'a, FileDev>, job: crate::job::StatFs) {
let stat = self.fs.statistics();
let store = &stat.object_store.storage;
let alloc = &store.allocation;
job.reply.statfs(
alloc.total_blocks,
alloc.total_blocks - alloc.used_blocks,
alloc.total_blocks - alloc.used_blocks,
u64::MAX,
u64::MAX - stat.object_store.used_objects,
1 << store.block_size.to_raw(),
255,
0,
);
}
}
10 changes: 8 additions & 2 deletions fuse/src/job.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use {
fuser::{
ReplyAttr, ReplyCreate, ReplyData, ReplyDirectory, ReplyEmpty, ReplyEntry, ReplyWrite,
TimeOrNow,
ReplyAttr, ReplyCreate, ReplyData, ReplyDirectory, ReplyEmpty, ReplyEntry, ReplyStatfs,
ReplyWrite, TimeOrNow,
},
std::{ffi::OsStr, path::Path},
};
Expand All @@ -25,6 +25,7 @@ pub enum Job {
Unlink(Unlink),
RmDir(RmDir),
FSync(FSync),
StatFs(StatFs),
Destroy,
}

Expand Down Expand Up @@ -151,3 +152,8 @@ pub struct RmDir {
pub struct FSync {
pub reply: ReplyEmpty,
}

#[derive(Debug)]
pub struct StatFs {
pub reply: ReplyStatfs,
}
73 changes: 54 additions & 19 deletions fuse/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,31 +1,66 @@
#![forbid(unused_must_use)]
#![forbid(rust_2018_idioms)]
#![feature(iterator_try_collect)]

mod fs;
mod job;

use fuser::MountOption;
use {clap::Parser, fuser::MountOption, std::error::Error};

fn main() -> Result<(), Box<dyn std::error::Error>> {
/// FUSE driver for NRFS.
#[derive(Parser)]
struct Args {
/// Path to mount filesystem on.
mount: String,
/// Paths to filesystem images.
images: Vec<String>,
/// File to load key from.
#[arg(short = 'K', long)]
key_file: Option<String>,
/// Soft limit on the cache size.
#[arg(long, default_value_t = 1 << 27)]
cache_size: usize,
}

fn main() -> Result<(), Box<dyn Error>> {
env_logger::init();

let mut a = std::env::args().skip(1);
let f = a.next().ok_or("expected file path")?;
let m = a.next().ok_or("expected mount path")?;

let f = std::fs::OpenOptions::new()
.read(true)
.write(true)
.open(&f)?;
let (f, channel) = futures_executor::block_on(fs::Fs::new(f));
let session = fuser::spawn_mount2(
channel,
m,
&[
MountOption::FSName("nrfs".into()),
MountOption::DefaultPermissions,
],
)?;
let args = Args::parse();

let key = args
.key_file
.map(|key_file| {
let key = std::fs::read(key_file)?;
let key: [u8; 32] = key.try_into().map_err(|_| "key is not 32 bytes long")?;
Ok::<_, Box<dyn Error>>(key)
})
.transpose()?;

let f = args
.images
.into_iter()
.map(|path| {
std::fs::OpenOptions::new()
.read(true)
.write(true)
.open(&path)
})
.try_collect::<Vec<_>>()?;

let (f, channel) =
futures_executor::block_on(fs::Fs::new(0o755, f.into_iter(), key, args.cache_size));

let mut opts = vec![
MountOption::FSName("nrfs".into()),
MountOption::DefaultPermissions,
];

if unsafe { libc::getuid() } == 0 {
eprintln!("Enabling allow_other");
opts.extend_from_slice(&[MountOption::AllowOther]);
}

let session = fuser::spawn_mount2(channel, args.mount, &opts)?;

futures_executor::block_on(f.run()).unwrap();

Expand Down
8 changes: 4 additions & 4 deletions nrfs/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,6 @@ pub struct NewConfig<'a, D: Dev> {
pub struct LoadConfig<'a, D: Dev> {
/// Devices.
pub devices: Vec<D>,
/// Key or password
pub key_password: KeyPassword<'a>,
/// Size of the cache.
///
/// This is a soft limit.
Expand All @@ -43,6 +41,8 @@ pub struct LoadConfig<'a, D: Dev> {
pub allow_repair: bool,
/// Method to retrieve either a key directly or get a password.
///
/// If the passed parameter is `true` a password is expected.
pub retrieve_key: &'a mut dyn FnMut(bool) -> Vec<u8>,
/// If the passed parameter is `true` a password can be provided.
///
/// On failure, return `None`.
pub retrieve_key: &'a mut dyn FnMut(bool) -> Option<KeyPassword>,
}
16 changes: 16 additions & 0 deletions nrfs/src/dir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1167,6 +1167,22 @@ impl<'a, 'b, D: Dev> DirRef<'a, 'b, D> {
Ok(self.fs.dir_data(self.id).item_count)
}

/// Get the amount of allocated but unused item slots in this directory.
pub async fn capacity(&self) -> Result<u32, Error<D>> {
Ok(self.fs.dir_data(self.id).item_capacity)
}

/// Get the total size of the heap.
pub async fn heap_size(&self) -> Result<u64, Error<D>> {
Ok(self
.fs
.storage
.get(self.bg, self.id + HEAP_OFFT)
.await?
.len()
.await?)
}

/// Create a [`Dir`] helper structure.
pub(crate) fn dir(&self) -> Dir<'a, 'b, D> {
Dir::new(self.bg, self.fs, self.id)
Expand Down
33 changes: 31 additions & 2 deletions nrfs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#![feature(cell_update)]
#![feature(pin_macro)]
#![feature(split_array)]
#![feature(error_in_core)]

/// Tracing in debug mode only.
macro_rules! trace {
Expand Down Expand Up @@ -148,10 +149,9 @@ impl<D: Dev> Nrfs<D> {
/// `read_only` guarantees no modifications will be made.
// TODO read_only is a sham.
pub async fn load(config: LoadConfig<'_, D>) -> Result<Self, Error<D>> {
let LoadConfig { devices, key_password, cache_size, allow_repair, retrieve_key } = config;
let LoadConfig { devices, cache_size, allow_repair, retrieve_key } = config;
let conf = nros::LoadConfig {
devices,
key_password,
cache_size,
allow_repair,
retrieve_key,
Expand Down Expand Up @@ -199,6 +199,18 @@ impl<D: Dev> Nrfs<D> {
Statistics { object_store: self.storage.statistics() }
}

/// Get the key used to encrypt the header.
pub fn header_key(&self) -> [u8; 32] {
self.storage.header_key()
}

/// Set a new key derivation function.
///
/// This replaces the header key.
pub fn set_key_deriver(&self, kdf: KeyDeriver<'_>) {
self.storage.set_key_deriver(kdf)
}

/// Get a reference to a [`FileData`] structure.
fn file_data(&self, idx: Idx) -> RefMut<'_, FileData> {
RefMut::map(self.data.borrow_mut(), |fs| &mut fs.files[idx])
Expand Down Expand Up @@ -458,6 +470,23 @@ where
}
}

impl<D> fmt::Display for Error<D>
where
D: Dev,
D::Error: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(self, f)
}
}

impl<D> core::error::Error for Error<D>
where
D: Dev,
D::Error: fmt::Debug,
{
}

impl<D: Dev> From<nros::Error<D>> for Error<D> {
fn from(err: nros::Error<D>) -> Self {
Self::Nros(err)
Expand Down
6 changes: 6 additions & 0 deletions nros/src/block_size.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,9 @@ impl BlockSize {
(n + mask) & !mask
}
}

impl Default for BlockSize {
fn default() -> Self {
Self::K4
}
}
Loading

0 comments on commit d5e4099

Please sign in to comment.