This commit is contained in:
AB
2020-06-04 00:43:55 +03:00
parent 7b3b955caf
commit 29eacf8302
4 changed files with 142 additions and 164 deletions

View File

@ -4,7 +4,6 @@ use std::process;
extern crate chrono; extern crate chrono;
extern crate config; extern crate config;
#[derive(Default, Debug, Clone, PartialEq)] #[derive(Default, Debug, Clone, PartialEq)]
pub struct Config { pub struct Config {
pub server: String, pub server: String,
@ -14,7 +13,6 @@ pub struct Config {
pub conf_file: String, pub conf_file: String,
} }
pub fn read() -> Config { pub fn read() -> Config {
// Parse opts and args // Parse opts and args
let cli_args = App::new(env!("CARGO_PKG_NAME")) let cli_args = App::new(env!("CARGO_PKG_NAME"))
@ -32,7 +30,11 @@ pub fn read() -> Config {
.get_matches(); .get_matches();
info!("Logger initialized. Set RUST_LOG=[debug,error,info,warn,trace] Default: info"); info!("Logger initialized. Set RUST_LOG=[debug,error,info,warn,trace] Default: info");
info!("Starting {} {}", env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION")); info!(
"Starting {} {}",
env!("CARGO_PKG_NAME"),
env!("CARGO_PKG_VERSION")
);
// Read config file and env vars // Read config file and env vars
let config_file = cli_args.value_of("conf").unwrap(); let config_file = cli_args.value_of("conf").unwrap();
@ -64,15 +66,11 @@ pub fn read() -> Config {
let username = match settings.get_str("username") { let username = match settings.get_str("username") {
Ok(username) => Some(username), Ok(username) => Some(username),
Err(_) => { Err(_) => None,
None
}
}; };
let password = match settings.get_str("password") { let password = match settings.get_str("password") {
Ok(password) => Some(password), Ok(password) => Some(password),
Err(_) => { Err(_) => None,
None
}
}; };
if password == None || username == None { if password == None || username == None {
warn!("Insecure server detected. Set `username` and `password` directives to use auth."); warn!("Insecure server detected. Set `username` and `password` directives to use auth.");

View File

@ -4,7 +4,6 @@
use crate::config; use crate::config;
use crate::http; use crate::http;
use polyfuse::{ use polyfuse::{
io::{Reader, Writer}, io::{Reader, Writer},
op, op,
@ -12,6 +11,9 @@ use polyfuse::{
Context, DirEntry, FileAttr, Filesystem, Forget, Operation, Context, DirEntry, FileAttr, Filesystem, Forget, Operation,
}; };
use slab::Slab; use slab::Slab;
use std::error::Error;
use std::mem::swap;
use std::path::{Path, PathBuf};
use std::{ use std::{
collections::hash_map::{Entry, HashMap}, collections::hash_map::{Entry, HashMap},
ffi::{OsStr, OsString}, ffi::{OsStr, OsString},
@ -22,10 +24,6 @@ use std::{
}; };
use tokio::sync::Mutex; use tokio::sync::Mutex;
use tracing_futures::Instrument; use tracing_futures::Instrument;
use std::path::{Path, PathBuf};
use std::mem::swap;
use std::error::Error;
type Ino = u64; type Ino = u64;
@ -194,8 +192,8 @@ impl MemFS {
} }
async fn make_node<F>(&self, parent: Ino, name: &OsStr, f: F) -> io::Result<ReplyEntry> async fn make_node<F>(&self, parent: Ino, name: &OsStr, f: F) -> io::Result<ReplyEntry>
where where
F: FnOnce(&VacantEntry<'_>) -> INode, F: FnOnce(&VacantEntry<'_>) -> INode,
{ {
debug!("make_node: parent: {:?}, name: {:?}", parent, name); debug!("make_node: parent: {:?}, name: {:?}", parent, name);
let mut inodes = self.inodes.lock().await; let mut inodes = self.inodes.lock().await;
@ -348,7 +346,6 @@ impl MemFS {
let mut full_uri: PathBuf = PathBuf::new(); let mut full_uri: PathBuf = PathBuf::new();
if parent_ino == 1 { if parent_ino == 1 {
full_uri = PathBuf::from("/"); full_uri = PathBuf::from("/");
} else { } else {
let mut vec_full_uri: Vec<PathBuf> = Vec::new(); let mut vec_full_uri: Vec<PathBuf> = Vec::new();
let mut inode = parent_ino; let mut inode = parent_ino;
@ -357,8 +354,7 @@ impl MemFS {
if p.1 != 0 { if p.1 != 0 {
vec_full_uri.push(p.0); vec_full_uri.push(p.0);
inode = p.1; inode = p.1;
} } else {
else {
break; break;
} }
} }
@ -372,7 +368,7 @@ impl MemFS {
Ok(full_uri) Ok(full_uri)
} }
async fn name_to_inode(&self, p_inode: u64, name: &OsStr) -> Option<u64>{ async fn name_to_inode(&self, p_inode: u64, name: &OsStr) -> Option<u64> {
let inodes = self.inodes.lock().await; let inodes = self.inodes.lock().await;
match inodes.get(p_inode).ok_or_else(no_entry) { match inodes.get(p_inode).ok_or_else(no_entry) {
Ok(inode) => { Ok(inode) => {
@ -380,16 +376,14 @@ impl MemFS {
warn!("name_to_inode p_inode - {:?} name - {:?}", p_inode, name); warn!("name_to_inode p_inode - {:?} name - {:?}", p_inode, name);
match &inode.kind { match &inode.kind {
INodeKind::Directory(ref dir) => { INodeKind::Directory(ref dir) => match dir.children.get(name) {
match dir.children.get(name) { Some(name) => Some(name.clone()),
Some(name) => Some(name.clone()), None => None,
None => None
}
}, },
_ => None _ => None,
} }
}, }
Err(e) => None Err(e) => None,
} }
} }
@ -398,8 +392,7 @@ impl MemFS {
//warn!("do_lookup f_inode {:?}", f_inode); //warn!("do_lookup f_inode {:?}", f_inode);
match self.name_to_inode( match self.name_to_inode(op.parent(), op.name()).await {
op.parent(), op.name()).await {
Some(f_inode) => { Some(f_inode) => {
warn!("do_lookup f_inode {:?}", f_inode); warn!("do_lookup f_inode {:?}", f_inode);
let inodes = self.inodes.lock().await; let inodes = self.inodes.lock().await;
@ -414,13 +407,16 @@ impl MemFS {
file_path.push(op.name()); file_path.push(op.name());
file_path file_path
} }
_ => {drop(inode); _ => {
drop(inode);
drop(inodes); drop(inodes);
PathBuf::new()} PathBuf::new()
}
}; };
warn!("{:?}", file_path); warn!("{:?}", file_path);
self.fetch_remote(file_path, f_inode).await;} self.fetch_remote(file_path, f_inode).await;
None => warn!("Cant find inode for {:?}", op.name()) }
None => warn!("Cant find inode for {:?}", op.name()),
} }
self.lookup_inode(op.parent(), op.name()).await self.lookup_inode(op.parent(), op.name()).await
@ -499,63 +495,62 @@ impl MemFS {
} }
} }
pub async fn fetch_remote(&self, path: PathBuf, parent: u64) -> io::Result<()> { pub async fn fetch_remote(&self, path: PathBuf, parent: u64) -> io::Result<()> {
let remote_entries = http::list_directory( let remote_entries = http::list_directory(
&self.cfg.server, &self.cfg.username, &self.cfg.password, path).await.unwrap(); &self.cfg.server,
for r_entry in remote_entries.iter(){ &self.cfg.username,
&self.cfg.password,
path,
)
.await
.unwrap();
for r_entry in remote_entries.iter() {
match &r_entry.r#type { match &r_entry.r#type {
Some(r#type) => { Some(r#type) => match r#type.as_str() {
match r#type.as_str() { "file" => {
"file" => { let f_name = r_entry.name.as_ref().unwrap();
let f_name = r_entry.name.as_ref().unwrap(); self.make_node(parent, OsStr::new(f_name.as_str()), |entry| INode {
self.make_node( attr: {
parent, OsStr::new(f_name.as_str()), |entry| { info!("Adding file {:?} - {:?}", f_name, parent);
INode { let mut attr = FileAttr::default();
attr: { attr.set_ino(entry.ino());
info!("Adding file {:?} - {:?}", f_name, parent); attr.set_mtime(r_entry.parse_rfc2822());
let mut attr = FileAttr::default(); attr.set_size(r_entry.size.unwrap());
attr.set_ino(entry.ino()); attr.set_nlink(1);
attr.set_mtime(r_entry.parse_rfc2822()); attr.set_mode(libc::S_IFREG | 0o444);
attr.set_size(r_entry.size.unwrap()); attr
attr.set_nlink(1); },
attr.set_mode(libc::S_IFREG | 0o444); xattrs: HashMap::new(),
attr refcount: 1,
}, links: 1,
xattrs: HashMap::new(), kind: INodeKind::RegularFile(vec![]),
refcount: 1, })
links: 1, .await;
kind: INodeKind::RegularFile(vec![]),
}
})
.await;
}
"directory" => {
let f_name = r_entry.name.as_ref().unwrap();
self.make_node(
parent, OsStr::new(f_name.as_str()), |entry| {
INode {
attr: {
info!("Adding directory {:?} - {:?}", f_name, parent);
let mut attr = FileAttr::default();
attr.set_ino(entry.ino());
attr.set_mtime(r_entry.parse_rfc2822());
attr.set_nlink(1);
attr.set_mode(libc::S_IFDIR | 0o755);
attr
},
xattrs: HashMap::new(),
refcount: u64::max_value() / 2,
links: u64::max_value() / 2,
kind: INodeKind::Directory(Directory {
children: HashMap::new(),
parent: Some(parent),
}),
}
}).await;
}
&_ => {}
} }
} "directory" => {
let f_name = r_entry.name.as_ref().unwrap();
self.make_node(parent, OsStr::new(f_name.as_str()), |entry| INode {
attr: {
info!("Adding directory {:?} - {:?}", f_name, parent);
let mut attr = FileAttr::default();
attr.set_ino(entry.ino());
attr.set_mtime(r_entry.parse_rfc2822());
attr.set_nlink(1);
attr.set_mode(libc::S_IFDIR | 0o755);
attr
},
xattrs: HashMap::new(),
refcount: u64::max_value() / 2,
links: u64::max_value() / 2,
kind: INodeKind::Directory(Directory {
children: HashMap::new(),
parent: Some(parent),
}),
})
.await;
}
&_ => {}
},
None => {} None => {}
} }
} }
@ -572,28 +567,24 @@ impl MemFS {
// let clos = async || -> io::Result<HashMap<OsString, u64>> { // let clos = async || -> io::Result<HashMap<OsString, u64>> {
// let clos = || -> io::Result<HashMap<OsString, u64>> { // let clos = || -> io::Result<HashMap<OsString, u64>> {
let mut parent_ino: u64 = 0; let mut parent_ino: u64 = 0;
let children = match &inode.kind { let children = match &inode.kind {
INodeKind::Directory(dir) => { INodeKind::Directory(dir) => match dir.parent {
match dir.parent { Some(parent) => {
Some(parent) => { let par_inode = inodes.get(parent).ok_or_else(no_entry).unwrap();
let par_inode = inodes.get(parent).ok_or_else(no_entry).unwrap(); let par_inode = par_inode.lock().await;
let par_inode = par_inode.lock().await;
parent_ino = par_inode.attr.ino(); parent_ino = par_inode.attr.ino();
let _uri = match &par_inode.kind { let _uri = match &par_inode.kind {
INodeKind::Directory(dir) => { INodeKind::Directory(dir) => dir.children.clone(),
dir.children.clone() _ => HashMap::new(),
} };
_ => HashMap::new() _uri
};
_uri
}
None => HashMap::new()
}
} }
_ => {HashMap::new()} None => HashMap::new(),
}; },
_ => HashMap::new(),
};
// }; // };
// let children = clos().await.unwrap(); // let children = clos().await.unwrap();
@ -604,7 +595,6 @@ impl MemFS {
} }
} }
Some((uri, parent_ino)) Some((uri, parent_ino))
} }
async fn do_opendir(&self, op: &op::Opendir<'_>) -> io::Result<ReplyOpen> { async fn do_opendir(&self, op: &op::Opendir<'_>) -> io::Result<ReplyOpen> {
@ -617,7 +607,6 @@ impl MemFS {
let inode = inode.lock().await; let inode = inode.lock().await;
if inode.attr.nlink() == 0 { if inode.attr.nlink() == 0 {
return Err(no_entry()); return Err(no_entry());
} }
@ -688,7 +677,7 @@ impl MemFS {
links: 1, links: 1,
kind: INodeKind::RegularFile(vec![]), kind: INodeKind::RegularFile(vec![]),
}) })
.await .await
} }
async fn do_mkdir(&self, op: &op::Mkdir<'_>) -> io::Result<ReplyEntry> { async fn do_mkdir(&self, op: &op::Mkdir<'_>) -> io::Result<ReplyEntry> {
@ -709,7 +698,7 @@ impl MemFS {
parent: Some(op.parent()), parent: Some(op.parent()),
}), }),
}) })
.await .await
} }
async fn do_symlink(&self, op: &op::Symlink<'_>) -> io::Result<ReplyEntry> { async fn do_symlink(&self, op: &op::Symlink<'_>) -> io::Result<ReplyEntry> {
@ -726,7 +715,7 @@ impl MemFS {
links: 1, links: 1,
kind: INodeKind::Symlink(Arc::new(op.link().into())), kind: INodeKind::Symlink(Arc::new(op.link().into())),
}) })
.await .await
} }
async fn do_link(&self, op: &op::Link<'_>) -> io::Result<ReplyEntry> { async fn do_link(&self, op: &op::Link<'_>) -> io::Result<ReplyEntry> {
@ -881,8 +870,8 @@ impl MemFS {
op: &op::Write<'_>, op: &op::Write<'_>,
reader: &mut R, reader: &mut R,
) -> io::Result<ReplyWrite> ) -> io::Result<ReplyWrite>
where where
R: Reader + Unpin, R: Reader + Unpin,
{ {
let inodes = self.inodes.lock().await; let inodes = self.inodes.lock().await;
@ -919,8 +908,8 @@ impl Filesystem for MemFS {
cx: &'a mut Context<'cx, T>, cx: &'a mut Context<'cx, T>,
op: Operation<'cx>, op: Operation<'cx>,
) -> io::Result<()> ) -> io::Result<()>
where where
T: Reader + Writer + Send + Unpin, T: Reader + Writer + Send + Unpin,
{ {
let span = tracing::debug_span!("MemFS::call", unique = cx.unique()); let span = tracing::debug_span!("MemFS::call", unique = cx.unique());
span.in_scope(|| tracing::debug!(?op)); span.in_scope(|| tracing::debug!(?op));
@ -1001,14 +990,14 @@ enum Either<L, R> {
} }
impl<L, R> Reply for Either<L, R> impl<L, R> Reply for Either<L, R>
where where
L: Reply, L: Reply,
R: Reply, R: Reply,
{ {
#[inline] #[inline]
fn collect_bytes<'a, C: ?Sized>(&'a self, collector: &mut C) fn collect_bytes<'a, C: ?Sized>(&'a self, collector: &mut C)
where where
C: Collector<'a>, C: Collector<'a>,
{ {
match self { match self {
Either::Left(l) => l.collect_bytes(collector), Either::Left(l) => l.collect_bytes(collector),

View File

@ -9,10 +9,9 @@ use std::{
path::PathBuf, path::PathBuf,
process, process,
thread::sleep, thread::sleep,
time::{Duration,SystemTime}, time::{Duration, SystemTime},
}; };
#[derive(Default, Debug, Clone, PartialEq, Deserialize)] #[derive(Default, Debug, Clone, PartialEq, Deserialize)]
pub struct RemoteEntry { pub struct RemoteEntry {
pub name: Option<String>, pub name: Option<String>,
@ -21,49 +20,42 @@ pub struct RemoteEntry {
pub size: Option<u64>, pub size: Option<u64>,
} }
impl RemoteEntry{ impl RemoteEntry {
pub fn parse_rfc2822(&self) -> SystemTime{ pub fn parse_rfc2822(&self) -> SystemTime {
let rfc2822 = DateTime::parse_from_rfc2822(&self.mtime.as_ref().unwrap()).unwrap(); let rfc2822 = DateTime::parse_from_rfc2822(&self.mtime.as_ref().unwrap()).unwrap();
SystemTime::from(rfc2822) SystemTime::from(rfc2822)
} }
} }
use chrono::{DateTime, NaiveDate, NaiveDateTime, NaiveTime};
use chrono::format::ParseError; use chrono::format::ParseError;
use chrono::{DateTime, NaiveDate, NaiveDateTime, NaiveTime};
pub async fn list_directory( pub async fn list_directory(
server: &std::string::String, server: &std::string::String,
username: &Option<String>, username: &Option<String>,
password: &Option<String>, password: &Option<String>,
path: PathBuf) -> path: PathBuf,
Result<Vec<RemoteEntry>, reqwest::Error> { ) -> Result<Vec<RemoteEntry>, reqwest::Error> {
info!("Fetching path '{}/{}'", server, path.display()); info!("Fetching path '{}/{}'", server, path.display());
let client = reqwest::Client::new(); let client = reqwest::Client::new();
let http_auth = match username { let http_auth = match username {
Some(username) => { Some(username) => {
// info!("Using Basic Auth"); // info!("Using Basic Auth");
let mut _buf = String::new(); let mut _buf = String::new();
_buf.push_str( _buf.push_str(format!("{}:{}", username, password.as_ref().unwrap()).as_str());
format!(
"{}:{}",
username,
password.as_ref().unwrap()
).as_str()
);
base64::encode(_buf) base64::encode(_buf)
} }
None => {String::new()} None => String::new(),
}; };
//info!("AUTH: {:?}", http_auth); //info!("AUTH: {:?}", http_auth);
let resp = client let resp = client
.get(format!("{}/{}", server, path.display()).as_str()) .get(format!("{}/{}", server, path.display()).as_str())
.header("Authorization", format!("Basic {}", http_auth)) .header("Authorization", format!("Basic {}", http_auth))
.send() .send()
.await? .await?
.json::<Vec<RemoteEntry>>() .json::<Vec<RemoteEntry>>()
.await?; .await?;
info!("Found {} entries into '{}'", resp.len(), path.display()); info!("Found {} entries into '{}'", resp.len(), path.display());
Ok(resp) Ok(resp)
} }

View File

@ -2,13 +2,12 @@ use std::path::PathBuf;
#[macro_use] #[macro_use]
extern crate log; extern crate log;
use env_logger::Env; use env_logger::Env;
use std::{process,path::Path}; use std::{path::Path, process};
mod config; mod config;
mod filesystem; mod filesystem;
mod http; mod http;
#[tokio::main] #[tokio::main]
async fn main() -> Result<(), std::io::Error> { async fn main() -> Result<(), std::io::Error> {
env_logger::from_env(Env::default().default_filter_or("info")).init(); env_logger::from_env(Env::default().default_filter_or("info")).init();