替换为fuser_mt 使用high——level的接口进行实现。

处理好了同步和异步的code
This commit is contained in:
Ekko.bao 2024-07-17 08:49:01 +08:00
parent 24573524a6
commit 2f34dd807d
5 changed files with 411 additions and 33 deletions

42
Cargo.lock generated
View File

@ -214,10 +214,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
name = "fuser"
version = "0.14.0"
name = "fuse_mt"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2e697f6f62c20b6fad1ba0f84ae909f25971cf16e735273524e3977c94604cf8"
checksum = "e098b8dc4cd32e9ba31d9c8cdfef11271d8191233c64c2a671432ff19d354948"
dependencies = [
"fuser",
"libc",
"log",
"threadpool",
]
[[package]]
name = "fuser"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "21370f84640642c8ea36dfb2a6bfc4c55941f476fcf431f6fef25a5ddcf0169b"
dependencies = [
"libc",
"log",
@ -454,7 +466,8 @@ checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
name = "lws_client"
version = "0.1.0"
dependencies = [
"fuser",
"fuse_mt",
"libc",
"prost",
"serde",
"serde_json",
@ -534,9 +547,9 @@ checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
[[package]]
name = "page_size"
version = "0.6.0"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "30d5b2194ed13191c1999ae0704b7839fb18384fa22e49b57eeaa97d79ce40da"
checksum = "1b7663cbd190cfd818d08efa8497f6cd383076688c49a391ef7c0d03cd12b561"
dependencies = [
"libc",
"winapi",
@ -858,6 +871,15 @@ dependencies = [
"windows-sys 0.52.0",
]
[[package]]
name = "threadpool"
version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa"
dependencies = [
"num_cpus",
]
[[package]]
name = "tokio"
version = "1.38.0"
@ -1213,9 +1235,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]]
name = "zerocopy"
version = "0.7.35"
version = "0.6.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
checksum = "854e949ac82d619ee9a14c66a1b674ac730422372ccb759ce0c39cabcf2bf8e6"
dependencies = [
"byteorder",
"zerocopy-derive",
@ -1223,9 +1245,9 @@ dependencies = [
[[package]]
name = "zerocopy-derive"
version = "0.7.35"
version = "0.6.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
checksum = "125139de3f6b9d625c39e2efdd73d41bdac468ccd556556440e322be0e1bbd91"
dependencies = [
"proc-macro2",
"quote",

View File

@ -13,7 +13,8 @@ prost = "0.12"
tokio = { version = "1.0", features = ["macros", "rt-multi-thread"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
fuser = "0.14.0"
fuse_mt = "0.6.1"
libc = "0.2"
[build-dependencies]
tonic-build = "0.11"

View File

@ -76,6 +76,7 @@ message fstat {
message getattr {
string path = 1;
fstat stat = 2;
file_info fi = 3;
int32 ret = 15;
}

View File

@ -8,7 +8,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
return Err(e);
}
};
match lws_ins.hello().await{
match lws_ins.hello(){
Err(e) => {
println!("lws client instance hello err {:?}", e);
return Err(e);

View File

@ -1,16 +1,14 @@
use lws_client::HelloRequest;
use lws_client::{Getattr, HelloRequest, FileInfo};
use std::borrow::BorrowMut;
use std::cell::RefCell;
use std::{io::Read as _};
use std::fs::File;
use std::error::Error;
use std::collections::HashMap;
use serde_json::{self, Value};
use lws_client::lws_vfs_client::LwsVfsClient;
use std::os::raw::c_int;
use std::ffi::{OsStr, OsString};
use fuser::{
KernelConfig, FileAttr, FileType, Filesystem, MountOption, ReplyAttr, ReplyData, ReplyDirectory, ReplyEntry,
Request,
};
pub mod lws_client {
tonic::include_proto!("lws_vfs"); //导入lws vfs proto buffer
@ -66,43 +64,399 @@ impl Config {
}
}
struct vir_fs {
name: String,
}
pub struct LwsVfsIns {
pub config: Config,
rpc: LwsVfsClient<tonic::transport::Channel>
rpc: RefCell<LwsVfsClient<tonic::transport::Channel>>,
async_rt: tokio::runtime::Runtime,
}
impl Filesystem for LwsVfsIns {
fn init(&mut self, _req: &Request, #[allow(unused_variables)] config: &mut KernelConfig,
) -> Result<(), c_int> {
use fuse_mt::*;
use std::path::{Path, PathBuf};
use std::time::{Duration, SystemTime};
impl FilesystemMT for LwsVfsIns {
/// Called on mount, before any other function.
fn init(&self, _req: RequestInfo) -> ResultEmpty {
match self.hello() {
Ok(()) => {
Ok(())
},
Err(e) =>{
Err(libc::ENOSYS)
}
}
}
/// Called on filesystem unmount.
fn destroy(&self) {
// Nothing.
}
/// Get the attributes of a filesystem entry.
///
/// * `fh`: a file handle if this is called on an open file.
fn getattr(&self, _req: RequestInfo, path: &Path, _fh: Option<u64>) -> ResultEntry {
let request = tonic::Request::new(Getattr {
path : path.to_str().unwrap().into(),
fi : FileInfo {
},
..Getattr::default()
});
let response = self.async_rt.block_on(self.rpc.borrow_mut().fgetattr(request));
Err(libc::ENOSYS)
}
// The following operations in the FUSE C API are all one kernel call: setattr
// We split them out to match the C API's behavior.
/// Change the mode of a filesystem entry.
///
/// * `fh`: a file handle if this is called on an open file.
/// * `mode`: the mode to change the file to.
fn chmod(&self, _req: RequestInfo, _path: &Path, _fh: Option<u64>, _mode: u32) -> ResultEmpty {
Err(libc::ENOSYS)
}
/// Change the owner UID and/or group GID of a filesystem entry.
///
/// * `fh`: a file handle if this is called on an open file.
/// * `uid`: user ID to change the file's owner to. If `None`, leave the UID unchanged.
/// * `gid`: group ID to change the file's group to. If `None`, leave the GID unchanged.
fn chown(&self, _req: RequestInfo, _path: &Path, _fh: Option<u64>, _uid: Option<u32>, _gid: Option<u32>) -> ResultEmpty {
Err(libc::ENOSYS)
}
/// Set the length of a file.
///
/// * `fh`: a file handle if this is called on an open file.
/// * `size`: size in bytes to set as the file's length.
fn truncate(&self, _req: RequestInfo, _path: &Path, _fh: Option<u64>, _size: u64) -> ResultEmpty {
Err(libc::ENOSYS)
}
/// Set timestamps of a filesystem entry.
///
/// * `fh`: a file handle if this is called on an open file.
/// * `atime`: the time of last access.
/// * `mtime`: the time of last modification.
fn utimens(&self, _req: RequestInfo, _path: &Path, _fh: Option<u64>, _atime: Option<SystemTime>, _mtime: Option<SystemTime>) -> ResultEmpty {
Err(libc::ENOSYS)
}
/// Set timestamps of a filesystem entry (with extra options only used on MacOS).
#[allow(clippy::too_many_arguments)]
fn utimens_macos(&self, _req: RequestInfo, _path: &Path, _fh: Option<u64>, _crtime: Option<SystemTime>, _chgtime: Option<SystemTime>, _bkuptime: Option<SystemTime>, _flags: Option<u32>) -> ResultEmpty {
Err(libc::ENOSYS)
}
// END OF SETATTR FUNCTIONS
/// Read a symbolic link.
fn readlink(&self, _req: RequestInfo, _path: &Path) -> ResultData {
Err(libc::ENOSYS)
}
/// Create a special file.
///
/// * `parent`: path to the directory to make the entry under.
/// * `name`: name of the entry.
/// * `mode`: mode for the new entry.
/// * `rdev`: if mode has the bits `S_IFCHR` or `S_IFBLK` set, this is the major and minor numbers for the device file. Otherwise it should be ignored.
fn mknod(&self, _req: RequestInfo, _parent: &Path, _name: &OsStr, _mode: u32, _rdev: u32) -> ResultEntry {
Err(libc::ENOSYS)
}
/// Create a directory.
///
/// * `parent`: path to the directory to make the directory under.
/// * `name`: name of the directory.
/// * `mode`: permissions for the new directory.
fn mkdir(&self, _req: RequestInfo, _parent: &Path, _name: &OsStr, _mode: u32) -> ResultEntry {
Err(libc::ENOSYS)
}
/// Remove a file.
///
/// * `parent`: path to the directory containing the file to delete.
/// * `name`: name of the file to delete.
fn unlink(&self, _req: RequestInfo, _parent: &Path, _name: &OsStr) -> ResultEmpty {
Err(libc::ENOSYS)
}
/// Remove a directory.
///
/// * `parent`: path to the directory containing the directory to delete.
/// * `name`: name of the directory to delete.
fn rmdir(&self, _req: RequestInfo, _parent: &Path, _name: &OsStr) -> ResultEmpty {
Err(libc::ENOSYS)
}
/// Create a symbolic link.
///
/// * `parent`: path to the directory to make the link in.
/// * `name`: name of the symbolic link.
/// * `target`: path (may be relative or absolute) to the target of the link.
fn symlink(&self, _req: RequestInfo, _parent: &Path, _name: &OsStr, _target: &Path) -> ResultEntry {
Err(libc::ENOSYS)
}
/// Rename a filesystem entry.
///
/// * `parent`: path to the directory containing the existing entry.
/// * `name`: name of the existing entry.
/// * `newparent`: path to the directory it should be renamed into (may be the same as `parent`).
/// * `newname`: name of the new entry.
fn rename(&self, _req: RequestInfo, _parent: &Path, _name: &OsStr, _newparent: &Path, _newname: &OsStr) -> ResultEmpty {
Err(libc::ENOSYS)
}
/// Create a hard link.
///
/// * `path`: path to an existing file.
/// * `newparent`: path to the directory for the new link.
/// * `newname`: name for the new link.
fn link(&self, _req: RequestInfo, _path: &Path, _newparent: &Path, _newname: &OsStr) -> ResultEntry {
Err(libc::ENOSYS)
}
/// Open a file.
///
/// * `path`: path to the file.
/// * `flags`: one of `O_RDONLY`, `O_WRONLY`, or `O_RDWR`, plus maybe additional flags.
///
/// Return a tuple of (file handle, flags). The file handle will be passed to any subsequent
/// calls that operate on the file, and can be any value you choose, though it should allow
/// your filesystem to identify the file opened even without any path info.
fn open(&self, _req: RequestInfo, _path: &Path, _flags: u32) -> ResultOpen {
Err(libc::ENOSYS)
}
/// Read from a file.
///
/// Note that it is not an error for this call to request to read past the end of the file, and
/// you should only return data up to the end of the file (i.e. the number of bytes returned
/// will be fewer than requested; possibly even zero). Do not extend the file in this case.
///
/// * `path`: path to the file.
/// * `fh`: file handle returned from the `open` call.
/// * `offset`: offset into the file to stasync_rt reading.
/// * `size`: number of bytes to read.
/// * `callback`: a callback that must be invoked to return the result of the operation: either
/// the result data as a slice, or an error code.
///
/// Return the return value from the `callback` function.
fn read(&self, _req: RequestInfo, _path: &Path, _fh: u64, _offset: u64, _size: u32, callback: impl FnOnce(ResultSlice<'_>) -> CallbackResult) -> CallbackResult {
callback(Err(libc::ENOSYS))
}
/// Write to a file.
///
/// * `path`: path to the file.
/// * `fh`: file handle returned from the `open` call.
/// * `offset`: offset into the file to stasync_rt writing.
/// * `data`: the data to write
/// * `flags`:
///
/// Return the number of bytes written.
fn write(&self, _req: RequestInfo, _path: &Path, _fh: u64, _offset: u64, _data: Vec<u8>, _flags: u32) -> ResultWrite {
Err(libc::ENOSYS)
}
/// Called each time a program calls `close` on an open file.
///
/// Note that because file descriptors can be duplicated (by `dup`, `dup2`, `fork`) this may be
/// called multiple times for a given file handle. The main use of this function is if the
/// filesystem would like to return an error to the `close` call. Note that most programs
/// ignore the return value of `close`, though.
///
/// * `path`: path to the file.
/// * `fh`: file handle returned from the `open` call.
/// * `lock_owner`: if the filesystem supports locking (`setlk`, `getlk`), remove all locks
/// belonging to this lock owner.
fn flush(&self, _req: RequestInfo, _path: &Path, _fh: u64, _lock_owner: u64) -> ResultEmpty {
Err(libc::ENOSYS)
}
/// Called when an open file is closed.
///
/// There will be one of these for each `open` call. After `release`, no more calls will be
/// made with the given file handle.
///
/// * `path`: path to the file.
/// * `fh`: file handle returned from the `open` call.
/// * `flags`: the flags passed when the file was opened.
/// * `lock_owner`: if the filesystem supports locking (`setlk`, `getlk`), remove all locks
/// belonging to this lock owner.
/// * `flush`: whether pending data must be flushed or not.
fn release(&self, _req: RequestInfo, _path: &Path, _fh: u64, _flags: u32, _lock_owner: u64, _flush: bool) -> ResultEmpty {
Err(libc::ENOSYS)
}
/// Write out any pending changes of a file.
///
/// When this returns, data should be written to persistent storage.
///
/// * `path`: path to the file.
/// * `fh`: file handle returned from the `open` call.
/// * `datasync`: if `false`, also write metadata, otherwise just write file data.
fn fsync(&self, _req: RequestInfo, _path: &Path, _fh: u64, _datasync: bool) -> ResultEmpty {
Err(libc::ENOSYS)
}
/// Open a directory.
///
/// Analogous to the `opend` call.
///
/// * `path`: path to the directory.
/// * `flags`: file access flags. Will contain `O_DIRECTORY` at least.
///
/// Return a tuple of (file handle, flags). The file handle will be passed to any subsequent
/// calls that operate on the directory, and can be any value you choose, though it should
/// allow your filesystem to identify the directory opened even without any path info.
fn opendir(&self, _req: RequestInfo, _path: &Path, _flags: u32) -> ResultOpen {
Err(libc::ENOSYS)
}
/// Get the entries of a directory.
///
/// * `path`: path to the directory.
/// * `fh`: file handle returned from the `opendir` call.
///
/// Return all the entries of the directory.
fn readdir(&self, _req: RequestInfo, _path: &Path, _fh: u64) -> ResultReaddir {
Err(libc::ENOSYS)
}
/// Close an open directory.
///
/// This will be called exactly once for each `opendir` call.
///
/// * `path`: path to the directory.
/// * `fh`: file handle returned from the `opendir` call.
/// * `flags`: the file access flags passed to the `opendir` call.
fn releasedir(&self, _req: RequestInfo, _path: &Path, _fh: u64, _flags: u32) -> ResultEmpty {
Err(libc::ENOSYS)
}
/// Write out any pending changes to a directory.
///
/// Analogous to the `fsync` call.
fn fsyncdir(&self, _req: RequestInfo, _path: &Path, _fh: u64, _datasync: bool) -> ResultEmpty {
Err(libc::ENOSYS)
}
/// Get filesystem statistics.
///
/// * `path`: path to some folder in the filesystem.
///
/// See the `Statfs` struct for more details.
fn statfs(&self, _req: RequestInfo, _path: &Path) -> ResultStatfs {
Err(libc::ENOSYS)
}
/// Set a file extended attribute.
///
/// * `path`: path to the file.
/// * `name`: attribute name.
/// * `value`: the data to set the value to.
/// * `flags`: can be either `XATTR_CREATE` or `XATTR_REPLACE`.
/// * `position`: offset into the attribute value to write data.
fn setxattr(&self, _req: RequestInfo, _path: &Path, _name: &OsStr, _value: &[u8], _flags: u32, _position: u32) -> ResultEmpty {
Err(libc::ENOSYS)
}
/// Get a file extended attribute.
///
/// * `path`: path to the file
/// * `name`: attribute name.
/// * `size`: the maximum number of bytes to read.
///
/// If `size` is 0, return `Xattr::Size(n)` where `n` is the size of the attribute data.
/// Otherwise, return `Xattr::Data(data)` with the requested data.
fn getxattr(&self, _req: RequestInfo, _path: &Path, _name: &OsStr, _size: u32) -> ResultXattr {
Err(libc::ENOSYS)
}
/// List extended attributes for a file.
///
/// * `path`: path to the file.
/// * `size`: maximum number of bytes to return.
///
/// If `size` is 0, return `Xattr::Size(n)` where `n` is the size required for the list of
/// attribute names.
/// Otherwise, return `Xattr::Data(data)` where `data` is all the null-terminated attribute
/// names.
fn listxattr(&self, _req: RequestInfo, _path: &Path, _size: u32) -> ResultXattr {
Err(libc::ENOSYS)
}
/// Remove an extended attribute for a file.
///
/// * `path`: path to the file.
/// * `name`: name of the attribute to remove.
fn removexattr(&self, _req: RequestInfo, _path: &Path, _name: &OsStr) -> ResultEmpty {
Err(libc::ENOSYS)
}
/// Check for access to a file.
///
/// * `path`: path to the file.
/// * `mask`: mode bits to check for access to.
///
/// Return `Ok(())` if all requested permissions are allowed, otherwise return `Err(EACCES)`
/// or other error code as appropriate (e.g. `ENOENT` if the file doesn't exist).
fn access(&self, _req: RequestInfo, _path: &Path, _mask: u32) -> ResultEmpty {
Err(libc::ENOSYS)
}
/// Create and open a new file.
///
/// * `parent`: path to the directory to create the file in.
/// * `name`: name of the file to be created.
/// * `mode`: the mode to set on the new file.
/// * `flags`: flags like would be passed to `open`.
///
/// Return a `CreatedEntry` (which contains the new file's attributes as well as a file handle
/// -- see documentation on `open` for more info on that).
fn create(&self, _req: RequestInfo, _parent: &Path, _name: &OsStr, _mode: u32, _flags: u32) -> ResultCreate {
Err(libc::ENOSYS)
}
}
use std::env;
impl LwsVfsIns {
pub async fn new(json: &str) -> Result<LwsVfsIns, Box<dyn Error>> {
let config = Config::new(json)?;
let addr = format!("http://{}:{}", config.get_addr(), config.get_port());
//connect to server
let rpc = LwsVfsClient::connect(addr).await?;
let rpc = RefCell::new(LwsVfsClient::connect(addr).await?);
let async_rt = tokio::runtime::Runtime::new().unwrap();
Ok(LwsVfsIns {
config,
rpc,
async_rt,
})
}
pub async fn hello(&mut self) -> Result<(), Box<dyn Error>> {
pub fn hello(&self) -> Result<(), Box<dyn Error>> {
let request = tonic::Request::new(HelloRequest {
name: "Ekko lws hello".into(),
});
let response = &self.rpc.say_hello(request).await?;
let response = self.async_rt.block_on(self.rpc.borrow_mut().say_hello(request))?;
println!("RESPONSE={:?}", response);
Ok(())
}
pub fn mount<FS:Filesystem>(file_system:FS) -> Result<(), Box<dyn Error>> {
let mountpoint = "/mnt";
let options = vec![MountOption::RO, MountOption::FSName("lws_fs".to_string())];
fuser::mount2(file_system, mountpoint, &options).unwrap();
pub fn mount<F>(file_system:F) -> Result<(), Box<dyn Error>>
where
F: FilesystemMT + Sync + Send + 'static
{
let args: Vec<OsString> = env::args_os().collect();
let fuse_args = [OsStr::new("-o"), OsStr::new("fsname=passthrufs")];
fuse_mt::mount(fuse_mt::FuseMT::new(file_system, 1), &args[2], &fuse_args[..])?;
Ok(())
}
}