初次提交代码
1. 完成基本的rpc的调用回调 2. 支持了config的解析 3. 支持了file handle的管理
This commit is contained in:
parent
5e1e42504c
commit
6b9433f756
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -13,4 +13,3 @@ Cargo.lock
|
||||||
|
|
||||||
# MSVC Windows builds of rustc generate these, which store debugging information
|
# MSVC Windows builds of rustc generate these, which store debugging information
|
||||||
*.pdb
|
*.pdb
|
||||||
|
|
||||||
|
|
1222
Cargo.lock
generated
Normal file
1222
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
28
Cargo.toml
Normal file
28
Cargo.toml
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
[package]
|
||||||
|
name = "lws_vfs"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[[bin]] # Bin to run the HelloWorld gRPC server
|
||||||
|
name = "lws_vfs-server"
|
||||||
|
path = "src/server.rs"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
tonic = "0.11"
|
||||||
|
prost = "0.12"
|
||||||
|
tokio = { version = "1.0", features = ["macros", "rt-multi-thread"] }
|
||||||
|
winapi = { version = "0.3", features = [
|
||||||
|
"fileapi",
|
||||||
|
"minwinbase",
|
||||||
|
"minwindef",
|
||||||
|
"timezoneapi",
|
||||||
|
"winnt",
|
||||||
|
] }
|
||||||
|
windows = "0.28"
|
||||||
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
serde_json = "1.0"
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
tonic-build = "0.11"
|
4
build.rs
Normal file
4
build.rs
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
tonic_build::compile_protos("proto/lws.proto")?;
|
||||||
|
Ok(())
|
||||||
|
}
|
163
proto/lws.proto
Normal file
163
proto/lws.proto
Normal file
|
@ -0,0 +1,163 @@
|
||||||
|
// Copyright 2015 gRPC authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
package lws_vfs;
|
||||||
|
|
||||||
|
service LwsVfs {
|
||||||
|
// Sends a greeting
|
||||||
|
rpc SayHello(HelloRequest) returns (HelloReply) {}
|
||||||
|
|
||||||
|
rpc fgetattr(getattr) returns (getattr) {}
|
||||||
|
rpc fsetxattr(setxattr) returns (setxattr) {}
|
||||||
|
rpc faccess(access) returns (access) {}
|
||||||
|
rpc freaddir(readdir) returns (readdir) {}
|
||||||
|
rpc fread(read) returns (read) {}
|
||||||
|
rpc fopen(open) returns (open) {}
|
||||||
|
rpc fwrite(write) returns (write) {}
|
||||||
|
rpc fgetxattr(getxattr) returns (getxattr) {}
|
||||||
|
rpc ftruncate(truncate) returns (truncate) {}
|
||||||
|
rpc futimens(utimens) returns (utimens) {}
|
||||||
|
rpc fchown(chown) returns (chown) {}
|
||||||
|
rpc frelease(release) returns (release) {}
|
||||||
|
rpc fmkdir(mkdir) returns (mkdir) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The request message containing the user's name.
|
||||||
|
message HelloRequest { string name = 1; }
|
||||||
|
|
||||||
|
// The response message containing the greetings
|
||||||
|
message HelloReply { string message = 1; }
|
||||||
|
|
||||||
|
message file_info {
|
||||||
|
int32 flags = 1;
|
||||||
|
uint32 fh_old = 2;
|
||||||
|
bool direct_io = 3;
|
||||||
|
uint64 fh = 10;
|
||||||
|
uint64 lock_owner = 11;
|
||||||
|
}
|
||||||
|
|
||||||
|
message fstat {
|
||||||
|
uint64 fst_mode = 1;
|
||||||
|
uint64 fst_ino = 2;
|
||||||
|
uint64 fst_dev = 3;
|
||||||
|
uint64 fst_rdev = 4;
|
||||||
|
uint64 fst_nlink = 5;
|
||||||
|
uint64 fst_uid = 6;
|
||||||
|
uint64 fst_gid = 7;
|
||||||
|
uint64 fst_size = 8;
|
||||||
|
uint64 fst_atime = 9;
|
||||||
|
uint64 fst_mtime = 10;
|
||||||
|
uint64 fst_ctime = 11;
|
||||||
|
uint64 fst_blksize = 12;
|
||||||
|
uint64 fst_blocks = 13;
|
||||||
|
}
|
||||||
|
|
||||||
|
// fuse api function message define:
|
||||||
|
message getattr {
|
||||||
|
string path = 1;
|
||||||
|
fstat stat = 2;
|
||||||
|
int32 ret = 15;
|
||||||
|
}
|
||||||
|
|
||||||
|
message setxattr {
|
||||||
|
string path = 1;
|
||||||
|
string name = 2;
|
||||||
|
bytes value = 3;
|
||||||
|
int64 size = 4;
|
||||||
|
uint32 flags = 5;
|
||||||
|
int32 ret = 15;
|
||||||
|
}
|
||||||
|
message getxattr {
|
||||||
|
string path = 1;
|
||||||
|
string name = 2;
|
||||||
|
bytes value = 3;
|
||||||
|
int64 size = 4;
|
||||||
|
int32 ret = 15;
|
||||||
|
}
|
||||||
|
|
||||||
|
message access {
|
||||||
|
string path = 1;
|
||||||
|
uint32 mask = 2;
|
||||||
|
int32 ret = 15;
|
||||||
|
}
|
||||||
|
|
||||||
|
message readdir {
|
||||||
|
string path = 1;
|
||||||
|
repeated string dirs = 2;
|
||||||
|
uint32 offset = 3;
|
||||||
|
file_info fi = 4;
|
||||||
|
int32 ret = 15;
|
||||||
|
}
|
||||||
|
|
||||||
|
message open {
|
||||||
|
string path = 1;
|
||||||
|
file_info fi = 2;
|
||||||
|
int32 ret = 15;
|
||||||
|
}
|
||||||
|
|
||||||
|
message read {
|
||||||
|
string path = 1;
|
||||||
|
bytes buff = 2;
|
||||||
|
int64 size = 3;
|
||||||
|
int64 offset = 4;
|
||||||
|
file_info fi = 5;
|
||||||
|
int32 ret = 15;
|
||||||
|
}
|
||||||
|
|
||||||
|
message write {
|
||||||
|
string path = 1;
|
||||||
|
bytes buff = 2;
|
||||||
|
int64 size = 3;
|
||||||
|
int64 offset = 4;
|
||||||
|
file_info fi = 5;
|
||||||
|
int32 ret = 15;
|
||||||
|
}
|
||||||
|
|
||||||
|
message truncate {
|
||||||
|
string path = 1;
|
||||||
|
int64 size = 3;
|
||||||
|
int32 ret = 15;
|
||||||
|
}
|
||||||
|
|
||||||
|
message timespec {
|
||||||
|
int32 tv_sec = 1;
|
||||||
|
int64 tv_nsec = 2;
|
||||||
|
}
|
||||||
|
message utimens {
|
||||||
|
string path = 1;
|
||||||
|
repeated timespec ts = 2; // const struct timespec ts[2]
|
||||||
|
int32 ret = 15;
|
||||||
|
}
|
||||||
|
|
||||||
|
message chown {
|
||||||
|
string path = 1;
|
||||||
|
int32 uid = 2;
|
||||||
|
int32 gid = 3;
|
||||||
|
int32 ret = 15;
|
||||||
|
}
|
||||||
|
|
||||||
|
message release {
|
||||||
|
string path = 1;
|
||||||
|
file_info fi = 2;
|
||||||
|
int32 ret = 15;
|
||||||
|
}
|
||||||
|
|
||||||
|
message mkdir {
|
||||||
|
string path = 1;
|
||||||
|
file_info fi = 2;
|
||||||
|
uint32 mode = 3;
|
||||||
|
int32 ret = 15;
|
||||||
|
}
|
154
src/fs_impl/mod.rs
Normal file
154
src/fs_impl/mod.rs
Normal file
|
@ -0,0 +1,154 @@
|
||||||
|
use std::fs;
|
||||||
|
|
||||||
|
use std::io::{self, Seek as ioSeek};
|
||||||
|
use std::error::Error;
|
||||||
|
|
||||||
|
use crate::lws_vfs::{Fstat, FileInfo};
|
||||||
|
|
||||||
|
extern crate winapi;
|
||||||
|
use winapi::um::winnt::{FILE_ATTRIBUTE_READONLY};
|
||||||
|
use std::os::windows::fs::MetadataExt;
|
||||||
|
use std::os::windows::prelude::*;
|
||||||
|
|
||||||
|
fn from_metadata(sta: &mut Fstat, metadata: &fs::Metadata) -> Result<(), Box<dyn Error>> {
|
||||||
|
sta.fst_size = metadata.len();
|
||||||
|
// sta.fst_mtime = metadata
|
||||||
|
// .modified()?.duration_since(SystemTime::UNIX_EPOCH)
|
||||||
|
// .map(|d| d.as_secs() as u64)?;
|
||||||
|
sta.fst_mtime = metadata.last_write_time();
|
||||||
|
sta.fst_ctime = metadata.creation_time();
|
||||||
|
sta.fst_atime = metadata.last_access_time();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
pub fn fgetattr(path: &String, sta: &mut Fstat, _fi: &mut FileInfo) -> Result<i32, Box<dyn Error>> {
|
||||||
|
let metadata = fs::metadata(path)?;
|
||||||
|
from_metadata(sta, &metadata)?;
|
||||||
|
let perm = get_file_mode_mask(path);
|
||||||
|
sta.fst_mode = perm as u64;
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fopen(path: &String, _fi: &mut FileInfo) -> Result<fs::File, Box<dyn Error>>{
|
||||||
|
return Ok(fs::File::open(path)?);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fread(path: &String, buffer:&mut Vec<u8>, _size:&mut usize, offsize: usize, _fi: &mut FileInfo) -> Result<i32, Box<dyn Error>> {
|
||||||
|
let mut file = fs::File::open(path)?;
|
||||||
|
match file.seek_read(buffer,offsize as u64){
|
||||||
|
Ok(_) =>{},
|
||||||
|
Err(_) => {
|
||||||
|
buffer.resize(file.stream_position()? as usize - offsize, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fwrite(path: &String, buffer: &Vec<u8>, size: &mut usize, offsize: usize, _fi: &mut FileInfo,
|
||||||
|
) -> Result<i32, Box<dyn Error>> {
|
||||||
|
let mut file = fs::File::open(path)?;
|
||||||
|
match file.seek_write(buffer,offsize as u64){
|
||||||
|
Ok(_) =>{},
|
||||||
|
Err(_) => {
|
||||||
|
*size = file.stream_position()? as usize - offsize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
|
pub fn freaddir(path: &String, buffer: &mut Vec<String>, _size: usize, _offset: usize, _fi: &mut FileInfo,
|
||||||
|
) -> Result<i32, Box<dyn Error>> {
|
||||||
|
let mut readed = fs::read_dir(path)?;
|
||||||
|
loop {
|
||||||
|
match readed.next() {
|
||||||
|
Some(Ok(entry)) => {
|
||||||
|
let name = entry.file_name().into_string().unwrap();
|
||||||
|
buffer.push(name);
|
||||||
|
}
|
||||||
|
Some(Err(e)) => {
|
||||||
|
return Err(Box::new(e));
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
|
pub fn fmkdir(path: &String, _mode: u32) -> Result<i32, Box<dyn Error>> {
|
||||||
|
fs::create_dir(path)?;
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
|
pub fn fchown(_path: &String, _uid: u32, _gid: u32) -> Result<i32, Box<dyn Error>> {
|
||||||
|
Ok(-1)
|
||||||
|
}
|
||||||
|
pub fn ftruncate(path: &String, _size: usize) -> Result<i32, Box<dyn Error>> {
|
||||||
|
fs::OpenOptions::new().write(true).truncate(true).open(path)?;
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
use std::fs::OpenOptions;
|
||||||
|
use winapi::um::fileapi::SetFileTime;
|
||||||
|
use winapi::shared::minwindef::FILETIME;
|
||||||
|
use winapi::shared::minwindef::DWORD;
|
||||||
|
use std::ptr::null_mut;
|
||||||
|
use winapi::ctypes::c_void;
|
||||||
|
fn system_time_to_file_time(seconds: u64, nanoseconds: u32) -> FILETIME {
|
||||||
|
let total_nanoseconds = (seconds * 1_000_000_000) + nanoseconds as u64;
|
||||||
|
let total_100_nanoseconds = total_nanoseconds / 100;
|
||||||
|
FILETIME {
|
||||||
|
dwLowDateTime: total_100_nanoseconds as DWORD,
|
||||||
|
dwHighDateTime: (total_100_nanoseconds >> 32) as DWORD,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn futimens(path: &String, a:& Vec<u64>, m: & Vec<u64>) -> Result<i32, Box<dyn Error>> {
|
||||||
|
let file = OpenOptions::new().write(true).open(path)?;
|
||||||
|
let handle = file.as_raw_handle();
|
||||||
|
|
||||||
|
let atime = system_time_to_file_time(a[0], a[1] as u32);
|
||||||
|
let mtime = system_time_to_file_time(m[0], m[1] as u32);
|
||||||
|
|
||||||
|
let result = unsafe {
|
||||||
|
SetFileTime(handle as *mut c_void, null_mut(), &atime, &mtime)
|
||||||
|
};
|
||||||
|
|
||||||
|
if result != 0 {
|
||||||
|
Ok(0)
|
||||||
|
} else {
|
||||||
|
Err(Box::new(io::Error::last_os_error()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn frelease(_path: &String, _fi: &mut FileInfo) -> Result<i32, Box<dyn Error>> {
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
|
pub fn fsetxattr(_path: &String,_name: &str,_value:&Vec<u8>,_size: usize,_flags: u32
|
||||||
|
) -> Result<i32, Box<dyn Error>> {
|
||||||
|
Ok(-1)
|
||||||
|
}
|
||||||
|
pub fn fgetxattr(_path: &String, _name: &str, _size: usize) -> Result<i32, Box<dyn Error>> {
|
||||||
|
Ok(-1)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_file_mode_mask(path:&str) -> u32{
|
||||||
|
let mut permissions = 0;
|
||||||
|
let metadata = match fs::metadata(path){
|
||||||
|
Ok(metadata) => metadata,
|
||||||
|
Err(_) => {
|
||||||
|
println!("get {} metadata fail", path);
|
||||||
|
return permissions;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let attributes = metadata.file_attributes();
|
||||||
|
// let permissions = metadata.permissions();
|
||||||
|
if attributes & FILE_ATTRIBUTE_READONLY != 0 {
|
||||||
|
permissions |= 0o222;
|
||||||
|
} else {
|
||||||
|
permissions |= 0o444 | 0o222;
|
||||||
|
}
|
||||||
|
if metadata.is_dir() {
|
||||||
|
permissions |= 0o111;
|
||||||
|
}
|
||||||
|
permissions
|
||||||
|
}
|
||||||
|
pub fn faccess(path: &String, mask: u32) -> Result<i32, Box<dyn Error>> {
|
||||||
|
let permissions = get_file_mode_mask(path);
|
||||||
|
Ok(if permissions & mask != 0 {0} else {-1})
|
||||||
|
}
|
423
src/lib.rs
Normal file
423
src/lib.rs
Normal file
|
@ -0,0 +1,423 @@
|
||||||
|
use lws_vfs::lws_vfs_server::LwsVfs;
|
||||||
|
use lws_vfs::{HelloReply, HelloRequest, Getattr, Setxattr, Access, Readdir, Read, Open,Write,Getxattr,Truncate,Utimens,Chown, Release, Fstat, FileInfo, Mkdir};
|
||||||
|
use tonic::{Request, Response, Status};
|
||||||
|
use serde_json::{self, Value};
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::{BufReader, Read as _};
|
||||||
|
use std::error::Error;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::sync::{Arc,Mutex};
|
||||||
|
mod fs_impl;
|
||||||
|
pub mod lws_vfs {
|
||||||
|
tonic::include_proto!("lws_vfs");
|
||||||
|
}
|
||||||
|
|
||||||
|
// config
|
||||||
|
//
|
||||||
|
// {
|
||||||
|
// "mount": {
|
||||||
|
// "c:\\": "/l3c",
|
||||||
|
// "w:\\": "/l0e",
|
||||||
|
// "y:\\": "/l0d"
|
||||||
|
// },
|
||||||
|
// "port":5001
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
pub struct Config{
|
||||||
|
port:u16,
|
||||||
|
mount_map:HashMap<String,String>,
|
||||||
|
}
|
||||||
|
impl Config{
|
||||||
|
pub fn new(json:&str) -> Result<Config, Box<dyn Error>> {
|
||||||
|
let mut file = File::open(json)?;
|
||||||
|
let mut buffer = String::new();
|
||||||
|
file.read_to_string(&mut buffer)?;
|
||||||
|
let json:Value = serde_json::from_str(buffer.as_ref())?;
|
||||||
|
let port:u16 = match json.get("port"){
|
||||||
|
Some(port) => port.as_u64().expect("expect port is a number but its not") as u16,
|
||||||
|
None => {
|
||||||
|
5001
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let mounts = match json.get("mount"){
|
||||||
|
Some(mounts) => mounts.as_object().unwrap(),
|
||||||
|
None => {
|
||||||
|
return Err(Box::new(std::io::Error::new(std::io::ErrorKind::Other, "no mount map")))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let mount_map = mounts.iter().map(|(key,value)|{
|
||||||
|
(key.as_str().to_string(),value.as_str().unwrap().to_string())
|
||||||
|
}).collect();
|
||||||
|
Ok(Config{
|
||||||
|
port,
|
||||||
|
mount_map
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_port(&self) -> u16 {
|
||||||
|
self.port
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
struct FileFdMgnt {
|
||||||
|
// key is fd, value is FileHandle
|
||||||
|
files:HashMap<u64,File>,
|
||||||
|
curr_fd:u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FileFdMgnt {
|
||||||
|
pub fn new() -> FileFdMgnt {
|
||||||
|
FileFdMgnt{
|
||||||
|
curr_fd:3,
|
||||||
|
files:HashMap::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn gen_fd(&mut self) -> Result<u64, Box<dyn Error>> {
|
||||||
|
let refd = self.curr_fd;
|
||||||
|
loop{
|
||||||
|
self.curr_fd += 1;
|
||||||
|
match self.files.get(&self.curr_fd){
|
||||||
|
Some(_) => {}
|
||||||
|
None => {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if refd == self.curr_fd {
|
||||||
|
return Err(Box::new(std::io::Error::new(std::io::ErrorKind::Other, "no fd")))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(self.curr_fd)
|
||||||
|
}
|
||||||
|
pub fn push(&mut self, handle:File) -> Result<u64, Box<dyn Error>> {
|
||||||
|
let fd = self.gen_fd()?;
|
||||||
|
self.files.insert(fd, handle);
|
||||||
|
Ok(fd)
|
||||||
|
}
|
||||||
|
pub fn pop(&mut self, fd:u64){
|
||||||
|
if let Some(handle) = self.files.remove(&fd){
|
||||||
|
drop(handle);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
println!("not found fd:{}", fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// server 的基础结构
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
pub struct LwsVfsIns {
|
||||||
|
pub config: Config,
|
||||||
|
file_fds: Arc<Mutex<FileFdMgnt>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LwsVfsIns {
|
||||||
|
pub fn new(json:&str) -> Result<LwsVfsIns, Box<dyn Error>> {
|
||||||
|
Ok(LwsVfsIns{
|
||||||
|
config:Config::new(json)?,
|
||||||
|
file_fds:Arc::new(Mutex::new(FileFdMgnt::new())),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
fn lpath(&self, path:&String) -> String {
|
||||||
|
let mut ret = String::new();
|
||||||
|
for (k,v) in &self.config.mount_map{
|
||||||
|
if path.starts_with(v){
|
||||||
|
ret = path.replace(v, k);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tonic::async_trait]
|
||||||
|
impl LwsVfs for LwsVfsIns {
|
||||||
|
async fn say_hello(&self, request: Request<HelloRequest>) -> Result<Response<HelloReply>, Status> {
|
||||||
|
println!("Got a request: {:?}", request);
|
||||||
|
|
||||||
|
let reply = HelloReply {
|
||||||
|
message: format!("Hello {}!", request.into_inner().name),
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Response::new(reply))
|
||||||
|
}
|
||||||
|
async fn fgetattr(&self, request: Request<Getattr>) -> Result<Response<Getattr>, Status> {
|
||||||
|
println!("Got a request: {:?}", request);
|
||||||
|
|
||||||
|
let request = request.into_inner();
|
||||||
|
let path = &self.lpath(&request.path);
|
||||||
|
let mut fstat = Fstat::default();
|
||||||
|
let mut fi = FileInfo::default();
|
||||||
|
let ret = match fs_impl::fgetattr(path, & mut fstat, &mut fi){
|
||||||
|
Ok(ret) => ret,
|
||||||
|
Err(e) => {
|
||||||
|
println!("Error getting file metadata: {:?}", e);
|
||||||
|
-1
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let reply = Getattr {
|
||||||
|
path:path.to_string(),
|
||||||
|
stat:Some(fstat),
|
||||||
|
ret,
|
||||||
|
};
|
||||||
|
Ok(Response::new(reply))
|
||||||
|
}
|
||||||
|
async fn fopen(&self, request: Request<Open>) -> Result<Response<Open>, Status> {
|
||||||
|
println!("Got a request: {:?}", request);
|
||||||
|
let request = request.into_inner();
|
||||||
|
let path = &self.lpath(&request.path);
|
||||||
|
let mut fi =request.fi.unwrap();
|
||||||
|
let ret = match fs_impl::fopen(path, &mut fi){
|
||||||
|
Ok(file) => {
|
||||||
|
match self.file_fds.lock().unwrap().push(file){
|
||||||
|
Ok(fd) => fi.fh = fd,
|
||||||
|
Err(e) => {
|
||||||
|
println!("Error pushing file[{}]: {:?}", path, e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
0
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
println!("Error opening file[{}]: {:?}", path, e);
|
||||||
|
-1
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let reply = Open {
|
||||||
|
path: path.to_string(),
|
||||||
|
fi:Some(fi),
|
||||||
|
ret,
|
||||||
|
};
|
||||||
|
Ok(Response::new(reply))
|
||||||
|
}
|
||||||
|
async fn fread(&self, request: Request<Read>) -> Result<Response<Read>, Status> {
|
||||||
|
println!("Got a request: {:?}", request);
|
||||||
|
let request = request.into_inner();
|
||||||
|
let mut fi = request.fi.unwrap();
|
||||||
|
let path = &self.lpath(&request.path);
|
||||||
|
let mut size:usize = request.size.try_into().unwrap();
|
||||||
|
let offset:usize = request.offset.try_into().unwrap();
|
||||||
|
let mut buff: Vec<u8> = Vec::with_capacity(size);
|
||||||
|
unsafe { buff.set_len(size); }
|
||||||
|
match fs_impl::fread(path, &mut buff, &mut size, offset, &mut fi){
|
||||||
|
Ok(ret) => {
|
||||||
|
let reply = Read {
|
||||||
|
path: request.path,
|
||||||
|
size: buff.len() as i64,
|
||||||
|
buff,
|
||||||
|
offset: offset as i64,
|
||||||
|
fi: Some(fi),
|
||||||
|
ret,
|
||||||
|
};
|
||||||
|
Ok(Response::new(reply))
|
||||||
|
},
|
||||||
|
Err(e) => {
|
||||||
|
println!("Error reading file[{}]: {:?}", path, e);
|
||||||
|
let reply = Read {
|
||||||
|
path: request.path,
|
||||||
|
buff: Vec::new(),
|
||||||
|
size: 0,
|
||||||
|
offset: 0,
|
||||||
|
fi: Some(fi),
|
||||||
|
ret: -1,
|
||||||
|
};
|
||||||
|
Ok(Response::new(reply))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async fn fwrite(&self, request: Request<Write>) -> Result<Response<Write>, Status> {
|
||||||
|
let request = request.into_inner();
|
||||||
|
let mut fi = request.fi.unwrap();
|
||||||
|
let path = &self.lpath(&request.path);
|
||||||
|
let buff = request.buff;
|
||||||
|
let mut size = request.size as usize;
|
||||||
|
let offset = request.offset as usize;
|
||||||
|
let ret = match fs_impl::fwrite(path, &buff, &mut size, offset, &mut fi) {
|
||||||
|
Ok(ret) => {
|
||||||
|
ret
|
||||||
|
},
|
||||||
|
Err(e) => {
|
||||||
|
println!("Error fwrite file[{}]: {:?}", path, e);
|
||||||
|
-1
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let reply = Write {
|
||||||
|
ret,
|
||||||
|
size:size as i64,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
Ok(Response::new(reply))
|
||||||
|
|
||||||
|
}
|
||||||
|
async fn faccess( &self, request: Request<Access>,) -> Result<Response<Access>, Status> {
|
||||||
|
let request = request.into_inner();
|
||||||
|
let path = &self.lpath(&request.path);
|
||||||
|
let mask = request.mask;
|
||||||
|
let ret = match fs_impl::faccess(path, mask) {
|
||||||
|
Ok(ret) => {
|
||||||
|
ret
|
||||||
|
},
|
||||||
|
Err(e) => {
|
||||||
|
println!("Error access file[{}]: {:?}", path, e);
|
||||||
|
-1
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let reply = Access {
|
||||||
|
ret,
|
||||||
|
path:path.to_string(),
|
||||||
|
mask,
|
||||||
|
};
|
||||||
|
Ok(Response::new(reply))
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn fsetxattr(&self, request: Request<Setxattr>) -> Result<Response<Setxattr>, Status> {
|
||||||
|
let req = request.into_inner();
|
||||||
|
let path = &self.lpath(&req.path);
|
||||||
|
let name = req.name.as_ref();
|
||||||
|
let value = req.value;
|
||||||
|
let size = req.size as usize;
|
||||||
|
let flags = req.flags;
|
||||||
|
let ret = match fs_impl::fsetxattr(path, name, &value, size, flags) {
|
||||||
|
Ok(ret) => ret,
|
||||||
|
Err(e) => {
|
||||||
|
println!("Error: setxattr file[{}]: {:?}", path, e);
|
||||||
|
-1
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let reply = Setxattr{
|
||||||
|
ret: ret,
|
||||||
|
..Setxattr::default()
|
||||||
|
};
|
||||||
|
Ok(Response::new(reply))
|
||||||
|
}
|
||||||
|
async fn fgetxattr(&self, request: Request<Getxattr>) -> Result<Response<Getxattr>, Status> {
|
||||||
|
let req = request.into_inner();
|
||||||
|
let path = &self.lpath(&req.path);
|
||||||
|
let name = req.name.as_ref();
|
||||||
|
let size = req.size as usize;
|
||||||
|
let ret = match fs_impl::fgetxattr(path, name, size) {
|
||||||
|
Ok(ret) => ret,
|
||||||
|
Err(e) => {
|
||||||
|
println!("Error: getxattr file[{}]: {:?}", path, e);
|
||||||
|
-1
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let reply = Getxattr{
|
||||||
|
ret,
|
||||||
|
..Getxattr::default()
|
||||||
|
};
|
||||||
|
Ok(Response::new(reply))
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn freaddir(&self, request: Request<Readdir>) -> Result<Response<Readdir>, Status> {
|
||||||
|
let request = request.into_inner();
|
||||||
|
let mut fi = request.fi.unwrap();
|
||||||
|
let path = &self.lpath(&request.path);
|
||||||
|
let offset = request.offset as usize;
|
||||||
|
let mut dirs: Vec<String> = Vec::new();
|
||||||
|
let size = 0;
|
||||||
|
let ret = match fs_impl::freaddir(path, &mut dirs, size, offset, &mut fi) {
|
||||||
|
Ok(ret) => ret,
|
||||||
|
Err(e) => {
|
||||||
|
println!("Error: readdir file[{}]: {:?}", path, e);
|
||||||
|
-1
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let reply = Readdir{
|
||||||
|
ret,
|
||||||
|
dirs,
|
||||||
|
..Readdir::default()
|
||||||
|
};
|
||||||
|
Ok(Response::new(reply))
|
||||||
|
}
|
||||||
|
async fn fmkdir(&self, request: Request<Mkdir>) -> Result<Response<Mkdir>, Status> {
|
||||||
|
let request = request.into_inner();
|
||||||
|
let path = &self.lpath(&request.path);
|
||||||
|
let mode = request.mode;
|
||||||
|
let ret = match fs_impl::fmkdir(&path, mode) {
|
||||||
|
Ok(ret) => ret,
|
||||||
|
Err(e) => {
|
||||||
|
println!("Error: mkdir [{}]: {:?}", path, e);
|
||||||
|
-1
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let reply = Mkdir{
|
||||||
|
ret,
|
||||||
|
..Mkdir::default()
|
||||||
|
};
|
||||||
|
Ok(Response::new(reply))
|
||||||
|
}
|
||||||
|
async fn ftruncate(&self, request: Request<Truncate>) -> Result<Response<Truncate>, Status> {
|
||||||
|
let request= request.into_inner();
|
||||||
|
let path = &self.lpath(&request.path);
|
||||||
|
let size = request.size as usize;
|
||||||
|
let ret = match fs_impl::ftruncate(path, size) {
|
||||||
|
Ok(ret) => ret,
|
||||||
|
Err(e) => {
|
||||||
|
println!("Error: truncate file[{}]: {:?}", path, e);
|
||||||
|
-1
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let reply = Truncate{
|
||||||
|
ret,
|
||||||
|
..Truncate::default()
|
||||||
|
};
|
||||||
|
Ok(Response::new(reply))
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn futimens(&self, request: Request<Utimens>) -> Result<Response<Utimens>, Status> {
|
||||||
|
let request = request.into_inner();
|
||||||
|
let path = &self.lpath(&request.path);
|
||||||
|
let a_time = vec![request.ts[0].tv_sec as u64, request.ts[0].tv_nsec as u64];
|
||||||
|
let m_time = vec![request.ts[1].tv_sec as u64, request.ts[1].tv_nsec as u64];
|
||||||
|
let ret = match fs_impl::futimens(path, &a_time, &m_time) {
|
||||||
|
Ok(ret) => ret,
|
||||||
|
Err(e) => {
|
||||||
|
println!("Error: futimens file[{}]: {:?}", path, e);
|
||||||
|
-1
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let reply = Utimens{
|
||||||
|
ret,
|
||||||
|
..Utimens::default()
|
||||||
|
};
|
||||||
|
Ok(Response::new(reply))
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn fchown(&self, request: Request<Chown>) -> Result<Response<Chown>, Status> {
|
||||||
|
let request = request.into_inner();
|
||||||
|
let path = &self.lpath(&request.path);
|
||||||
|
let uid = request.uid as u32;
|
||||||
|
let gid = request.gid as u32;
|
||||||
|
let ret = match fs_impl::fchown(path, uid, gid) {
|
||||||
|
Ok(ret) => ret,
|
||||||
|
Err(e) => {
|
||||||
|
println!("Error: chown file[{}]: {:?}", path, e);
|
||||||
|
-1
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let reply = Chown{
|
||||||
|
ret,
|
||||||
|
..Chown::default()
|
||||||
|
};
|
||||||
|
Ok(Response::new(reply))
|
||||||
|
}
|
||||||
|
async fn frelease(&self, request: Request<Release>) -> Result<Response<Release>, Status> {
|
||||||
|
let request = request.into_inner();
|
||||||
|
let path = &self.lpath(&request.path);
|
||||||
|
let mut fi = request.fi.unwrap();
|
||||||
|
self.file_fds.lock().unwrap().pop(fi.fh);
|
||||||
|
let ret = match fs_impl::frelease(path, &mut fi) {
|
||||||
|
Ok(ret) => ret,
|
||||||
|
Err(e) => {
|
||||||
|
println!("Error: release file[{}]: {:?}", path, e);
|
||||||
|
-1
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let reply = Release{
|
||||||
|
ret,
|
||||||
|
..Release::default()
|
||||||
|
};
|
||||||
|
Ok(Response::new(reply))
|
||||||
|
}
|
||||||
|
}
|
3
src/main.rs
Normal file
3
src/main.rs
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
fn main() {
|
||||||
|
println!("Hello, world!");
|
||||||
|
}
|
33
src/server.rs
Normal file
33
src/server.rs
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
use tonic::transport;
|
||||||
|
|
||||||
|
use lws_vfs::LwsVfsIns;
|
||||||
|
use lws_vfs::lws_vfs::lws_vfs_server::LwsVfsServer;
|
||||||
|
|
||||||
|
// fn main() {
|
||||||
|
// println!("Hello, world!");
|
||||||
|
// let file = "test.txt";
|
||||||
|
// let mut sta = Stat {
|
||||||
|
// st_size: 0,
|
||||||
|
// st_mode: 0,
|
||||||
|
// };
|
||||||
|
// let mut fi = FuseFileInfo {};
|
||||||
|
// getattr(file, &mut sta, &mut fi);
|
||||||
|
// }
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let instance = match LwsVfsIns::new("config.json"){
|
||||||
|
Ok(greeter) => greeter,
|
||||||
|
Err(e) => {
|
||||||
|
println!("Error creating lws server instance: {:?}", e);
|
||||||
|
return Err(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let addr = format!("[::1]:{}", instance.config.get_port());
|
||||||
|
println!("Listening on {}", addr);
|
||||||
|
transport::Server::builder()
|
||||||
|
.add_service(LwsVfsServer::new(instance))
|
||||||
|
.serve(addr.parse()?)
|
||||||
|
.await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user