sftp-server 0.1.0

Library providing a pure Rust implementation of an SFTP server; can operate standalone with an embedded SSH server, or can provide the SFTP backend for an external SSH server (e.g. openssh). Binary crates should pull in this library and provide their own storage back-end.
Documentation
use std::borrow::Cow;
use std::collections::VecDeque;

use camino::Utf8Path;
use camino::Utf8PathBuf;
use lexiclean_cow::Lexiclean;

use sftp_protocol::common::Metadata;
use crate::Error;
use super::file::OpenFile;

pub type Result<T> = std::result::Result<T, Error>;
pub trait PathRef: AsRef<Utf8Path> + Send + Sync {}
impl<T> PathRef for T where T: AsRef<Utf8Path> + Send + Sync {}

#[async_trait]
pub trait Backend : Clone + Send + Sync {
	async fn metadata(&self, path: impl PathRef + 'async_trait) -> Result<Metadata>;
	async fn list(&self, path: impl PathRef + 'async_trait) -> Result<VecDeque<Metadata>>;
	#[allow(clippy::too_many_arguments)]
	async fn open(&self, path: impl PathRef + 'async_trait, read: bool, write: bool, append: bool, create: bool, truncate: bool, create_new: bool) -> Result<OpenFile>;
	async fn set_metadata(&self, path: impl PathRef + 'async_trait, uid_and_gid: Option<(u32, u32)>, permissions: Option<u32>, atime_and_mtime: Option<(u32, u32)>) -> Result<()>;
	async fn delete_file(&self, path: impl PathRef + 'async_trait) -> Result<()>;
	async fn mkdir(&self, path: impl PathRef + 'async_trait) -> Result<()>;
	async fn rmdir(&self, path: impl PathRef + 'async_trait) -> Result<()>;
	async fn rename(&self, from: impl PathRef + 'async_trait, to: impl PathRef + 'async_trait) -> Result<()>;
	async fn readlink(&self, path: impl PathRef + 'async_trait) -> Result<Option<Utf8PathBuf>>;
	async fn mklink(&self, link_path: impl PathRef + 'async_trait, target_path: impl PathRef + 'async_trait, link_type: crate::LinkType) -> Result<()>;

	fn normalize_path<'a, 'path>(&'a self, path: &'path Utf8Path) -> Result<Cow<'path, Utf8Path>> {
		let path = path.lexiclean();
		if let Some(first) = path.ancestors().next() {
			if(first == "..") {
				return Err(Error::InvalidPath);
			}
		}
		Ok(path)
	}
}