diff --git a/src/fs/mod.rs b/src/fs/mod.rs index 2dea947..0234ebb 100644 --- a/src/fs/mod.rs +++ b/src/fs/mod.rs @@ -28,6 +28,8 @@ use tokio::{ const CHUNK_SIZE: usize = 512 * 1024; // 512k and is hardcoded in the hub. the block_size value is not used const TTL: Duration = Duration::from_secs(60 * 60 * 24 * 365); const LRU_CAP: usize = 5; // Least Recently Used File Capacity +const FS_BLOCK_SIZE: u32 = 4 * 1024; + type FHash = [u8; 32]; type BlockSize = u64; @@ -109,7 +111,9 @@ where } async fn statfs(&self, req: &Request, _op: op::Statfs<'_>) -> Result<()> { - let out = StatfsOut::default(); + let mut out = StatfsOut::default(); + let stats = out.statfs(); + stats.bsize(FS_BLOCK_SIZE); req.reply(out)?; Ok(()) } @@ -371,7 +375,19 @@ impl AttributeFiller for Inode { attr.ino(self.ino); attr.ctime(Duration::from_secs(self.ctime as u64)); attr.mtime(Duration::from_secs(self.mtime as u64)); + attr.uid(self.uid); + attr.gid(self.gid); attr.size(self.size); + attr.rdev(self.rdev as u32); + attr.blksize(FS_BLOCK_SIZE); + + let mut blocks = self.size / 512; + blocks += match self.size % 512 { + 0 => 0, + _ => 1, + }; + + attr.blocks(blocks); match self.mode.file_type() { FileType::Dir => attr.nlink(2), diff --git a/src/main.rs b/src/main.rs index 6fa7bfe..5ecd55e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,7 +5,7 @@ use nix::unistd::Pid; use std::io::Read; use anyhow::{Context, Result}; -use clap::{ArgAction, Parser}; +use clap::{ArgAction, Args, Parser, Subcommand}; use rfs::cache; use rfs::fungi; @@ -16,6 +16,24 @@ mod fs; #[derive(Parser, Debug)] #[clap(name ="rfs", author, version = env!("GIT_VERSION"), about, long_about = None)] struct Options { + /// enable debugging logs + #[clap(long, action=ArgAction::Count)] + debug: u8, + + #[command(subcommand)] + command: Commands, +} + +#[derive(Subcommand, Debug)] +enum Commands { + /// mount an FL + Mount(MountOptions), + /// create an FL and upload blocks + Create(CreateOptions), +} + +#[derive(Args, Debug)] +struct MountOptions { /// path to metadata file (flist) #[clap(short, long)] meta: String, @@ -27,10 +45,6 @@ struct Options { #[clap(short, long)] daemon: bool, - /// enable debugging logs - #[clap(long, action=ArgAction::Count)] - debug: u8, - /// log file only used with daemon mode #[clap(short, long)] log: Option, @@ -43,6 +57,20 @@ struct Options { target: String, } +#[derive(Args, Debug)] +struct CreateOptions { + /// path to metadata file (flist) + #[clap(short, long)] + meta: String, + + /// store url + #[clap(short, long)] + store: String, + + /// target directory to upload + target: String, +} + fn main() -> Result<()> { let opts = Options::parse(); @@ -60,6 +88,25 @@ fn main() -> Result<()> { log::debug!("options: {:#?}", opts); + match opts.command { + Commands::Mount(opts) => mount(opts), + Commands::Create(opts) => create(opts), + } +} + +fn create(opts: CreateOptions) -> Result<()> { + let rt = tokio::runtime::Runtime::new()?; + + rt.block_on(async move { + let store = store::make(opts.store).await?; + let meta = fungi::Writer::new(opts.meta).await?; + rfs::pack(meta, store, opts.target).await?; + + Ok(()) + }) +} + +fn mount(opts: MountOptions) -> Result<()> { if is_mountpoint(&opts.target)? { eprintln!("target {} is already a mount point", opts.target); std::process::exit(1); @@ -89,7 +136,7 @@ fn main() -> Result<()> { let rt = tokio::runtime::Runtime::new()?; - rt.block_on(app(opts)) + rt.block_on(fuse(opts)) } fn is_mountpoint>(target: S) -> Result { @@ -128,7 +175,7 @@ fn wait_child(target: String, mut pid_file: tempfile::NamedTempFile) { std::process::exit(1); } -async fn app(opts: Options) -> Result<()> { +async fn fuse(opts: MountOptions) -> Result<()> { let meta = fungi::Reader::new(opts.meta) .await .context("failed to initialize metadata database")?;