135 lines
3 KiB
Rust
135 lines
3 KiB
Rust
#[macro_use]
|
|
extern crate anyhow;
|
|
#[macro_use]
|
|
extern crate log;
|
|
|
|
mod fs;
|
|
mod utils;
|
|
|
|
use std::fs::File;
|
|
use std::io::{BufRead, BufReader};
|
|
use std::path::{Path, PathBuf};
|
|
use std::sync::atomic::{AtomicBool, Ordering};
|
|
use std::sync::Arc;
|
|
|
|
use anyhow::Result;
|
|
use clap::Parser;
|
|
use fuse::{BackgroundSession, FileType};
|
|
|
|
use crate::fs::FakeFs;
|
|
|
|
#[derive(Debug, Parser)]
|
|
struct Opt {
|
|
input: PathBuf,
|
|
mountpoint: PathBuf,
|
|
}
|
|
|
|
fn main() -> Result<()> {
|
|
let opt = Opt::parse();
|
|
|
|
setup_logger()?;
|
|
|
|
let fs = read_input(&opt.input)?;
|
|
|
|
run_with_ctrlc(move || -> Result<BackgroundSession> {
|
|
let x = unsafe { fuse::spawn_mount(fs, &opt.mountpoint, &[])? };
|
|
Ok(x)
|
|
})?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn read_input(input: impl AsRef<Path>) -> Result<FakeFs> {
|
|
let mut fs = FakeFs::new();
|
|
|
|
// Read input
|
|
{
|
|
let file = File::open(input.as_ref())?;
|
|
let reader = BufReader::new(file);
|
|
let mut it = reader.lines().peekable();
|
|
let mut current_dir = PathBuf::from("/");
|
|
|
|
loop {
|
|
let line = match it.next() {
|
|
Some(Ok(v)) => v,
|
|
Some(Err(e)) => return Err(e.into()),
|
|
None => break,
|
|
};
|
|
|
|
// Assume line starts with $
|
|
let line = line.strip_prefix("$ ").unwrap();
|
|
let parts = line.split(" ").collect::<Vec<_>>();
|
|
let command = parts[0];
|
|
|
|
match command {
|
|
"cd" => {
|
|
let move_path = PathBuf::from(parts[1]);
|
|
let dst_path = utils::into_absolute(&move_path, ¤t_dir);
|
|
info!("Moving to {dst_path:?}");
|
|
current_dir = dst_path;
|
|
}
|
|
"ls" => loop {
|
|
let line = match it.peek() {
|
|
Some(Ok(v)) if !v.starts_with("$") => it.next().unwrap()?,
|
|
_ => break,
|
|
};
|
|
|
|
let parts = line.split(" ").collect::<Vec<_>>();
|
|
let filename = parts[1];
|
|
let (ty, size) = match parts[0] {
|
|
"dir" => (FileType::Directory, 0),
|
|
s => (FileType::RegularFile, s.parse::<u64>().unwrap()),
|
|
};
|
|
|
|
let ino = fs.ensure_path(current_dir.join(filename), ty)?;
|
|
if size > 0 {
|
|
fs.set_size(ino, size);
|
|
}
|
|
},
|
|
_ => panic!("Don't know command {command}"),
|
|
}
|
|
}
|
|
}
|
|
|
|
debug!("Fs contents: {fs:?}");
|
|
Ok(fs)
|
|
}
|
|
|
|
fn run_with_ctrlc<F, R>(f: F) -> R
|
|
where
|
|
F: FnOnce() -> R,
|
|
{
|
|
let running = Arc::new(AtomicBool::new(true));
|
|
let r = running.clone();
|
|
|
|
ctrlc::set_handler(move || {
|
|
r.store(false, Ordering::SeqCst);
|
|
})
|
|
.expect("Error setting Ctrl-C handler");
|
|
|
|
debug!("Waiting for Ctrl-C...");
|
|
let res = f();
|
|
while running.load(Ordering::SeqCst) {}
|
|
debug!("Got it! Exiting...");
|
|
|
|
res
|
|
}
|
|
|
|
fn setup_logger() -> Result<()> {
|
|
fern::Dispatch::new()
|
|
.format(|out, message, record| {
|
|
out.finish(format_args!(
|
|
"{}[{}][{}] {}",
|
|
chrono::Local::now().format("[%Y-%m-%d][%H:%M:%S]"),
|
|
record.target(),
|
|
record.level(),
|
|
message
|
|
))
|
|
})
|
|
.level(log::LevelFilter::Debug)
|
|
.chain(std::io::stdout())
|
|
.chain(fern::log_file("output.log")?)
|
|
.apply()
|
|
.map_err(|e| e.into())
|
|
}
|