feat(proto/server)!: 升级至协议 v2(统一错误模型);全面替换 Request/Response 并移除 ret
- Breaking change: 协议不向后兼容,旧客户端需同步升级 - Proto: 新增 FsOp/ErrorCause/FsError/RpcStatus;为所有 FS 接口定义 <Op>Request/<Op>Response;删除历史 ret 字段 - Server: 所有 RPC 返回统一的 RpcStatus;成功 ok=true,失败填充 FsError(operation/paths/sys_msg 等) - Open/Read/Write 对齐新字段(fi/data/written);Readdir/Opendir/Releasedir 等返回类型调整 - Rename 传回 from/to;OpendirRequest 不再输入 fi,服务端生成并回传 - Docs: 新增 docs/protocol_v2.md;README 标注 v2 破坏性升级与用法 - Build: 主要面向 Windows(winapi)。Linux 环境类型检查可能失败 后续:完善 errno 抽取与 context 填充;可选引入流式 read/write 以优化大文件传输。
This commit is contained in:
13
README.md
13
README.md
@ -1,4 +1,13 @@
|
||||
# wls_vfs
|
||||
|
||||
windows linux文件共享,使用fuse + grpc + protobuffer
|
||||
语言:rust
|
||||
Windows/Linux 文件共享服务端(gRPC + Protobuf)。
|
||||
|
||||
本仓库已升级至协议 v2(统一错误模型):
|
||||
|
||||
- 所有 RPC 使用显式的 `Request`/`Response` 类型;
|
||||
- 响应统一携带 `RpcStatus { ok, error }`;
|
||||
- 删除历史 `ret` 字段;失败信息通过 `FsError` 完整承载(`code`/`sys_msg`/`operation`/`paths`/`context` 等)。
|
||||
|
||||
协议详情见:`proto/lws.proto` 与 `docs/protocol_v2.md`。
|
||||
|
||||
注意:本项目主要在 Windows 上构建运行(依赖 `winapi`)。在非 Windows 平台构建仅用于类型检查,可能失败。
|
||||
|
14
docs/protocol_v2.md
Normal file
14
docs/protocol_v2.md
Normal file
@ -0,0 +1,14 @@
|
||||
# LWS 协议 v2(统一错误模型)
|
||||
|
||||
- RpcStatus { ok, error }
|
||||
- FsError { code, message, sys_msg, grpc_code, grpc_message, operation(FsOp), paths[], context{...}, causes[], server, timestamp_ms, retriable }
|
||||
|
||||
成功:ok = true;失败:ok = false 且 error.code 为正数 POSIX errno。
|
||||
|
||||
常用 context keys: flags, offset, size, uid, gid, mode, fh, mask, xattr_name, xattr_size。
|
||||
|
||||
FsOp 与 RPC 映射:与客户端 docs 相同(参见 proto/lws.proto 中的 service 定义)。
|
||||
|
||||
服务端返回建议:
|
||||
- 失败时设置 error.code 与 sys_msg,并补充 operation/paths/context。
|
||||
- 传输层错误由客户端据 gRPC `Status` 统一映射。
|
290
proto/lws.proto
290
proto/lws.proto
@ -16,43 +16,62 @@ syntax = "proto3";
|
||||
|
||||
package lws_vfs;
|
||||
|
||||
service LwsVfs {
|
||||
// Sends a greeting
|
||||
rpc SayHello(HelloRequest) returns (HelloReply) {}
|
||||
rpc GetConfig(get_config) returns (get_config) {}
|
||||
|
||||
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) {}
|
||||
rpc frmdir(rmdir) returns (rmdir) {}
|
||||
rpc fflush(flush) returns (flush) {}
|
||||
rpc fopendir(opendir) returns (opendir) {}
|
||||
rpc freleasedir(releasedir) returns (releasedir) {}
|
||||
rpc fcreate(create) returns (create) {}
|
||||
rpc funlink(unlink) returns (unlink) {}
|
||||
rpc frename(rename) returns (rename) {}
|
||||
// Filesystem operation types for diagnostics and observability.
|
||||
enum FsOp {
|
||||
FSOP_UNKNOWN = 0;
|
||||
FSOP_GETATTR = 1;
|
||||
FSOP_SETXATTR = 2;
|
||||
FSOP_ACCESS = 3;
|
||||
FSOP_READDIR = 4;
|
||||
FSOP_READ = 5;
|
||||
FSOP_OPEN = 6;
|
||||
FSOP_WRITE = 7;
|
||||
FSOP_GETXATTR = 8;
|
||||
FSOP_TRUNCATE = 9;
|
||||
FSOP_UTIMENS = 10;
|
||||
FSOP_CHOWN = 11;
|
||||
FSOP_RELEASE = 12;
|
||||
FSOP_MKDIR = 13;
|
||||
FSOP_RMDIR = 14;
|
||||
FSOP_FLUSH = 15;
|
||||
FSOP_OPENDIR = 16;
|
||||
FSOP_RELEASEDIR = 17;
|
||||
FSOP_CREATE = 18;
|
||||
FSOP_UNLINK = 19;
|
||||
FSOP_RENAME = 20;
|
||||
FSOP_HELLO = 21;
|
||||
FSOP_GET_CONFIG = 22;
|
||||
}
|
||||
|
||||
// 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 get_config {
|
||||
string config = 1;
|
||||
// Optional chained cause for nested errors.
|
||||
message ErrorCause {
|
||||
int32 code = 1; // POSIX errno if available
|
||||
string message = 2; // human-readable message
|
||||
string type = 3; // error type/category from server implementation
|
||||
}
|
||||
|
||||
// Rich error payload carried by all responses.
|
||||
message FsError {
|
||||
int32 code = 1; // POSIX errno (>0)
|
||||
string message = 2; // application error message
|
||||
string sys_msg = 3; // strerror(code) or OS message
|
||||
uint32 grpc_code = 4; // gRPC status code (if applicable)
|
||||
string grpc_message = 5; // gRPC status message
|
||||
FsOp operation = 6; // which fs op failed
|
||||
repeated string paths = 7; // involved paths (e.g. [from, to])
|
||||
map<string, string> context = 8; // flags/size/offset/uid/gid ...
|
||||
repeated ErrorCause causes = 9; // nested causes
|
||||
string server = 10; // server id/hostname
|
||||
uint64 timestamp_ms = 11; // server time when error occurred
|
||||
bool retriable = 12; // whether retry may succeed
|
||||
}
|
||||
|
||||
message RpcStatus {
|
||||
bool ok = 1; // true if the call succeeded
|
||||
FsError error = 2; // populated when ok == false
|
||||
}
|
||||
|
||||
// Common structs
|
||||
message file_info {
|
||||
uint32 flags = 1;
|
||||
uint32 fh_old = 2;
|
||||
@ -77,34 +96,9 @@ message fstat {
|
||||
uint64 fst_blocks = 13;
|
||||
}
|
||||
|
||||
// fuse api function message define:
|
||||
message getattr {
|
||||
string path = 1;
|
||||
fstat stat = 2;
|
||||
file_info fi = 3;
|
||||
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 timespec {
|
||||
int32 tv_sec = 1;
|
||||
int64 tv_nsec = 2;
|
||||
}
|
||||
|
||||
message direntry {
|
||||
@ -112,112 +106,100 @@ message direntry {
|
||||
uint32 kind = 2;
|
||||
}
|
||||
|
||||
message readdir {
|
||||
string path = 1;
|
||||
repeated direntry dirs = 2;
|
||||
uint32 offset = 3;
|
||||
file_info fi = 4;
|
||||
int32 ret = 15;
|
||||
// Service and RPCs
|
||||
service LwsVfs {
|
||||
rpc SayHello(HelloRequest) returns (HelloReply) {}
|
||||
rpc GetConfig(GetConfigRequest) returns (GetConfigResponse) {}
|
||||
|
||||
rpc fgetattr(GetattrRequest) returns (GetattrResponse) {}
|
||||
rpc fsetxattr(SetxattrRequest) returns (EmptyResponse) {}
|
||||
rpc faccess(AccessRequest) returns (EmptyResponse) {}
|
||||
rpc freaddir(ReaddirRequest) returns (ReaddirResponse) {}
|
||||
rpc fread(ReadRequest) returns (ReadResponse) {}
|
||||
rpc fopen(OpenRequest) returns (OpenResponse) {}
|
||||
rpc fwrite(WriteRequest) returns (WriteResponse) {}
|
||||
rpc fgetxattr(GetxattrRequest) returns (GetxattrResponse) {}
|
||||
rpc ftruncate(TruncateRequest) returns (EmptyResponse) {}
|
||||
rpc futimens(UtimensRequest) returns (EmptyResponse) {}
|
||||
rpc fchown(ChownRequest) returns (EmptyResponse) {}
|
||||
rpc frelease(ReleaseRequest) returns (EmptyResponse) {}
|
||||
rpc fmkdir(MkdirRequest) returns (EmptyResponse) {}
|
||||
rpc frmdir(RmdirRequest) returns (EmptyResponse) {}
|
||||
rpc fflush(FlushRequest) returns (EmptyResponse) {}
|
||||
rpc fopendir(OpendirRequest) returns (OpendirResponse) {}
|
||||
rpc freleasedir(ReleasedirRequest) returns (EmptyResponse) {}
|
||||
rpc fcreate(CreateRequest) returns (CreateResponse) {}
|
||||
rpc funlink(UnlinkRequest) returns (EmptyResponse) {}
|
||||
rpc frename(RenameRequest) returns (EmptyResponse) {}
|
||||
}
|
||||
|
||||
message open {
|
||||
string path = 1;
|
||||
file_info fi = 2;
|
||||
int32 ret = 15;
|
||||
}
|
||||
// Hello
|
||||
message HelloRequest { string name = 1; }
|
||||
message HelloReply { string message = 1; RpcStatus status = 2; }
|
||||
|
||||
message read {
|
||||
string path = 1;
|
||||
bytes buff = 2;
|
||||
int64 size = 3;
|
||||
uint64 offset = 4;
|
||||
file_info fi = 5;
|
||||
int32 ret = 15;
|
||||
}
|
||||
// Config
|
||||
message GetConfigRequest {}
|
||||
message GetConfigResponse { string config = 1; RpcStatus status = 2; }
|
||||
|
||||
message write {
|
||||
string path = 1;
|
||||
bytes buff = 2;
|
||||
uint64 size = 3;
|
||||
uint64 offset = 4;
|
||||
file_info fi = 5;
|
||||
int32 ret = 15;
|
||||
}
|
||||
// getattr
|
||||
message GetattrRequest { string path = 1; file_info fi = 2; }
|
||||
message GetattrResponse { fstat stat = 1; RpcStatus status = 2; }
|
||||
|
||||
message truncate {
|
||||
string path = 1;
|
||||
int64 size = 3;
|
||||
int32 ret = 15;
|
||||
}
|
||||
// xattr
|
||||
message SetxattrRequest { string path = 1; string name = 2; bytes value = 3; int64 size = 4; uint32 flags = 5; }
|
||||
message GetxattrRequest { string path = 1; string name = 2; int64 size = 3; }
|
||||
message GetxattrResponse { bytes value = 1; RpcStatus status = 2; }
|
||||
|
||||
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;
|
||||
}
|
||||
// access
|
||||
message AccessRequest { string path = 1; uint32 mask = 2; }
|
||||
|
||||
message chown {
|
||||
string path = 1;
|
||||
int32 uid = 2;
|
||||
int32 gid = 3;
|
||||
int32 ret = 15;
|
||||
}
|
||||
// readdir
|
||||
message ReaddirRequest { string path = 1; uint32 offset = 2; file_info fi = 3; }
|
||||
message ReaddirResponse { repeated direntry dirs = 1; RpcStatus status = 2; }
|
||||
|
||||
message release {
|
||||
string path = 1;
|
||||
file_info fi = 2;
|
||||
uint32 flush = 3;
|
||||
int32 ret = 15;
|
||||
}
|
||||
// open
|
||||
message OpenRequest { string path = 1; file_info fi = 2; }
|
||||
message OpenResponse { file_info fi = 1; RpcStatus status = 2; }
|
||||
|
||||
message mkdir {
|
||||
string path = 1;
|
||||
file_info fi = 2;
|
||||
uint32 mode = 3;
|
||||
int32 ret = 15;
|
||||
}
|
||||
// read
|
||||
message ReadRequest { string path = 1; uint64 offset = 2; int64 size = 3; file_info fi = 4; }
|
||||
message ReadResponse { bytes data = 1; RpcStatus status = 2; }
|
||||
|
||||
message rmdir {
|
||||
string path = 1;
|
||||
int32 ret = 15;
|
||||
}
|
||||
// write
|
||||
message WriteRequest { string path = 1; uint64 offset = 2; bytes data = 3; file_info fi = 4; }
|
||||
message WriteResponse { uint64 written = 1; RpcStatus status = 2; }
|
||||
|
||||
message flush {
|
||||
string path = 1;
|
||||
file_info fi = 2;
|
||||
int32 ret = 15;
|
||||
}
|
||||
// truncate
|
||||
message TruncateRequest { string path = 1; int64 size = 2; }
|
||||
|
||||
message opendir {
|
||||
string path = 1;
|
||||
file_info fi = 2;
|
||||
int32 ret = 15;
|
||||
}
|
||||
// utimens
|
||||
message UtimensRequest { string path = 1; repeated timespec ts = 2; }
|
||||
|
||||
message releasedir {
|
||||
string path = 1;
|
||||
file_info fi = 2;
|
||||
int32 ret = 15;
|
||||
}
|
||||
// chown
|
||||
message ChownRequest { string path = 1; int32 uid = 2; int32 gid = 3; }
|
||||
|
||||
message create {
|
||||
string path = 1;
|
||||
uint32 mode = 2;
|
||||
file_info fi = 3;
|
||||
int32 ret = 15;
|
||||
}
|
||||
// release/flush
|
||||
message ReleaseRequest { string path = 1; file_info fi = 2; uint32 flush = 3; }
|
||||
message FlushRequest { string path = 1; file_info fi = 2; }
|
||||
|
||||
message unlink {
|
||||
string path = 1;
|
||||
int32 ret = 15;
|
||||
}
|
||||
// mkdir/rmdir
|
||||
message MkdirRequest { string path = 1; uint32 mode = 2; }
|
||||
message RmdirRequest { string path = 1; }
|
||||
|
||||
message rename {
|
||||
string path = 1;
|
||||
string new = 2;
|
||||
int32 ret = 15;
|
||||
}
|
||||
// opendir/releasedir
|
||||
message OpendirRequest { string path = 1; }
|
||||
message OpendirResponse { file_info fi = 1; RpcStatus status = 2; }
|
||||
message ReleasedirRequest { string path = 1; file_info fi = 2; }
|
||||
|
||||
// create
|
||||
message CreateRequest { string path = 1; uint32 mode = 2; }
|
||||
message CreateResponse { file_info fi = 1; RpcStatus status = 2; }
|
||||
|
||||
// unlink
|
||||
message UnlinkRequest { string path = 1; }
|
||||
|
||||
// rename
|
||||
message RenameRequest { string path = 1; string new = 2; }
|
||||
|
||||
// Empty response with status only
|
||||
message EmptyResponse { RpcStatus status = 1; }
|
||||
|
541
src/lib.rs
541
src/lib.rs
@ -1,8 +1,10 @@
|
||||
|
||||
use lws_vfs::lws_vfs_server::LwsVfs;
|
||||
use lws_vfs::{
|
||||
Access, Chown, FileInfo, Flush, Fstat, Getattr, Getxattr, HelloReply, HelloRequest, Mkdir,
|
||||
Open, Read, Readdir, Release, Rmdir, Setxattr, Truncate, Utimens, Write, Create, Unlink, Opendir, Releasedir, Rename, GetConfig,
|
||||
AccessRequest, ChownRequest, CreateRequest, CreateResponse, Direntry, EmptyResponse, FileInfo,
|
||||
FlushRequest, FsError, FsOp, Fstat, GetConfigRequest, GetConfigResponse, GetattrRequest, GetattrResponse,
|
||||
GetxattrRequest, GetxattrResponse, HelloReply, HelloRequest, MkdirRequest, OpenRequest, OpenResponse,
|
||||
OpendirRequest, OpendirResponse, ReadRequest, ReadResponse, ReaddirRequest, ReaddirResponse, ReleaseRequest, ReleasedirRequest,
|
||||
RenameRequest, RpcStatus, RmdirRequest, SetxattrRequest, TruncateRequest, UnlinkRequest, UtimensRequest, WriteRequest, WriteResponse,
|
||||
};
|
||||
|
||||
use self::fs_impl::FSImpl;
|
||||
@ -16,6 +18,7 @@ use std::collections::HashMap;
|
||||
extern crate log;
|
||||
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
|
||||
mod fs_impl;
|
||||
mod disk;
|
||||
@ -58,53 +61,44 @@ impl Config {
|
||||
)))
|
||||
}
|
||||
};
|
||||
let mut mount_map: HashMap<String, String> = mounts.iter().filter(|(key, _)| {
|
||||
match disk::get_disk_info(&key) {
|
||||
let mut mount_map: HashMap<String, String> = mounts
|
||||
.iter()
|
||||
.filter(|(key, _)| match disk::get_disk_info(&key) {
|
||||
None => false,
|
||||
Some(_) => true,
|
||||
}
|
||||
}).map(|(key, value)| (key.to_string(), value.as_str().unwrap().to_string())).collect();
|
||||
})
|
||||
.map(|(key, value)| (key.to_string(), value.as_str().unwrap().to_string()))
|
||||
.collect();
|
||||
log::debug!("mounts is {:?}", mounts);
|
||||
|
||||
let mut volume_names = HashMap::new();
|
||||
|
||||
// 获取所有的盘符对应的卷标便于后续进行比对
|
||||
for drive in 'C'..='Z' {
|
||||
for drive in 'C'..='Z' {
|
||||
let drive = format!("{}:\\", drive);
|
||||
if let Some((volume, _, _)) = disk::get_disk_info(&drive) {
|
||||
//TODO: 这里如果存在同名的卷标会出现问题
|
||||
volume_names.insert(volume, drive);
|
||||
}
|
||||
}
|
||||
log::info!("local disk info: {:?}", volume_names);
|
||||
|
||||
// 遍历配置的盘符和卷标,将配置的盘符和卷标映射到实际盘符上
|
||||
for (key, value) in mounts.iter() {
|
||||
// 直接看下是不是盘符
|
||||
if let Some((drive, _, _)) = disk::get_disk_info(&key) {
|
||||
mount_map.insert(drive.to_string(), value.as_str().unwrap().to_string());
|
||||
} else if let Some(drive) = volume_names.get(key.as_str()) {
|
||||
mount_map.insert(drive.to_string(), value.as_str().unwrap().to_string());
|
||||
} else {
|
||||
// 看下是不是卷标
|
||||
if let Some(drive) = volume_names.get(key.as_str()) {
|
||||
// log::info!("value is {:?} {}", value, value.as_str().unwrap());
|
||||
mount_map.insert(drive.to_string(), value.as_str().unwrap().to_string());
|
||||
} else {
|
||||
log::error!("mount volume name [{}] not found in disk list", key);
|
||||
return Err(Box::new(std::io::Error::new(
|
||||
std::io::ErrorKind::Other,
|
||||
"mount map unavailable",
|
||||
)))
|
||||
}
|
||||
|
||||
log::error!("mount volume name [{}] not found in disk list", key);
|
||||
return Err(Box::new(std::io::Error::new(
|
||||
std::io::ErrorKind::Other,
|
||||
"mount map unavailable",
|
||||
)));
|
||||
}
|
||||
}
|
||||
log::info!("after local search&match: {:?}", mount_map);
|
||||
Ok(Config { port, mount_map })
|
||||
}
|
||||
|
||||
pub fn get_port(&self) -> u16 {
|
||||
self.port
|
||||
}
|
||||
pub fn get_port(&self) -> u16 { self.port }
|
||||
}
|
||||
|
||||
/// server 的基础结构
|
||||
@ -115,425 +109,330 @@ pub struct LwsVfsIns {
|
||||
}
|
||||
|
||||
fn linux_to_windows_path(linux_path: &str) -> String {
|
||||
let path: PathBuf = Path::new(linux_path)
|
||||
.components()
|
||||
// .filter(|component| component.as_os_str() != Component::RootDir.as_os_str())
|
||||
// .map(|component| component.as_os_str().to_string_lossy().into_owned())
|
||||
.collect();
|
||||
let path: PathBuf = Path::new(linux_path).components().collect();
|
||||
path.to_string_lossy().to_string()
|
||||
}
|
||||
|
||||
impl LwsVfsIns {
|
||||
pub fn new(json: &str) -> Result<LwsVfsIns, Box<dyn Error>> {
|
||||
Ok(LwsVfsIns {
|
||||
config: Config::new(json)?,
|
||||
fs: FSImpl::new(),
|
||||
})
|
||||
Ok(LwsVfsIns { config: Config::new(json)?, fs: FSImpl::new() })
|
||||
}
|
||||
fn lpath(&self, path: &String) -> String {
|
||||
let mut ret = String::new();
|
||||
// log::trace!("try to convert {}", path);
|
||||
// /l0e -> w:
|
||||
for (k, v) in &self.config.mount_map {
|
||||
if path.starts_with(v) {
|
||||
ret = path.replace(v, k);
|
||||
break;
|
||||
}
|
||||
if path.starts_with(v) { ret = path.replace(v, k); break; }
|
||||
}
|
||||
linux_to_windows_path(&ret)
|
||||
}
|
||||
}
|
||||
|
||||
/// 将result 转换成 i32返回给rpc使用
|
||||
macro_rules! result2ret {
|
||||
($fun_name:expr, $path:expr, $ret:expr) => {
|
||||
match $ret {
|
||||
Ok(ret) => ret,
|
||||
Err(e) => {
|
||||
log::error!("{} [{}]: {:?}", $fun_name, $path, e);
|
||||
if let Some(e) = e.downcast_ref::<std::io::Error>() {
|
||||
e.raw_os_error().unwrap_or(-1) as i32
|
||||
} else {
|
||||
-1
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
fn ok_status() -> Option<RpcStatus> { Some(RpcStatus{ ok: true, error: None }) }
|
||||
|
||||
fn now_ms() -> u64 {
|
||||
SystemTime::now().duration_since(UNIX_EPOCH).map(|d| d.as_millis() as u64).unwrap_or(0)
|
||||
}
|
||||
|
||||
fn err_status(op: FsOp, paths: Vec<String>, err: &(dyn std::error::Error)) -> Option<RpcStatus> {
|
||||
let (code, sys_msg) = (libc::EIO, format!("{}", err));
|
||||
Some(RpcStatus{
|
||||
ok: false,
|
||||
error: Some(FsError{
|
||||
code,
|
||||
message: String::new(),
|
||||
sys_msg,
|
||||
grpc_code: 0,
|
||||
grpc_message: String::new(),
|
||||
operation: op as i32,
|
||||
paths,
|
||||
context: Default::default(),
|
||||
causes: vec![],
|
||||
server: std::env::var("HOSTNAME").unwrap_or_default(),
|
||||
timestamp_ms: now_ms(),
|
||||
retriable: false,
|
||||
})
|
||||
})
|
||||
}
|
||||
// match e.downcast_ref::<std::io::Error>() {
|
||||
// Some(e) => match e.kind() {
|
||||
// std::io::ErrorKind::NotFound => libc::ENOENT,
|
||||
// std::io::ErrorKind::PermissionDenied => libc::EACCES,
|
||||
// std::io::ErrorKind::AlreadyExists => libc::EEXIST,
|
||||
// }
|
||||
// }
|
||||
|
||||
#[tonic::async_trait]
|
||||
impl LwsVfs for LwsVfsIns {
|
||||
async fn say_hello(
|
||||
&self,
|
||||
request: Request<HelloRequest>,
|
||||
) -> Result<Response<HelloReply>, Status> {
|
||||
async fn say_hello(&self, request: Request<HelloRequest>) -> Result<Response<HelloReply>, Status> {
|
||||
let request = request.into_inner();
|
||||
log::trace!("Got a request: {:?}", request);
|
||||
|
||||
let reply = HelloReply {
|
||||
message: format!("Hello {}!", request.name),
|
||||
};
|
||||
|
||||
let reply = HelloReply { message: format!("Hello {}!", request.name), status: ok_status() };
|
||||
Ok(Response::new(reply))
|
||||
}
|
||||
async fn get_config(&self, _req: Request<GetConfig>) -> Result<Response<GetConfig>, Status> {
|
||||
log::info!("{:?}",self.config);
|
||||
|
||||
async fn get_config(&self, _req: Request<GetConfigRequest>) -> Result<Response<GetConfigResponse>, Status> {
|
||||
log::info!("{:?}", self.config);
|
||||
let config = serde_json::to_string(&self.config).unwrap();
|
||||
log::info!("reply config: {}", config);
|
||||
let reply = GetConfig {
|
||||
config,
|
||||
};
|
||||
Ok(Response::new(reply))
|
||||
Ok(Response::new(GetConfigResponse{ config, status: ok_status() }))
|
||||
}
|
||||
async fn fgetattr(&self, request: Request<Getattr>) -> Result<Response<Getattr>, Status> {
|
||||
|
||||
async fn fgetattr(&self, request: Request<GetattrRequest>) -> Result<Response<GetattrResponse>, Status> {
|
||||
let request = request.into_inner();
|
||||
log::trace!("Got a request: {:?}", request);
|
||||
let path = &self.lpath(&request.path);
|
||||
let mut fstat = Fstat::default();
|
||||
let mut fi = FileInfo::default();
|
||||
let ret = self.fs.fgetattr(path, &mut fstat, &mut fi);
|
||||
let ret = result2ret!("fgetattr", path, ret);
|
||||
let reply = Getattr {
|
||||
path: path.to_string(),
|
||||
stat: Some(fstat),
|
||||
ret,
|
||||
..Getattr::default()
|
||||
let reply = match self.fs.fgetattr(path, &mut fstat, &mut fi) {
|
||||
Ok(0) => GetattrResponse { stat: Some(fstat), status: ok_status() },
|
||||
Ok(_) => GetattrResponse { stat: None, status: err_status(FsOp::FSOP_GETATTR, vec![path.to_string()], &std::io::Error::new(std::io::ErrorKind::Other, "op failed")) },
|
||||
Err(e) => GetattrResponse { stat: None, status: err_status(FsOp::FSOP_GETATTR, vec![path.to_string()], &*e) },
|
||||
};
|
||||
Ok(Response::new(reply))
|
||||
}
|
||||
async fn fopen(&self, request: Request<Open>) -> Result<Response<Open>, Status> {
|
||||
|
||||
async fn fopen(&self, request: Request<OpenRequest>) -> Result<Response<OpenResponse>, Status> {
|
||||
let request = request.into_inner();
|
||||
log::trace!("Got a request: {:?}", request);
|
||||
let path = &self.lpath(&request.path);
|
||||
let mut fi = match request.fi{
|
||||
Some(fi) => fi,
|
||||
None => FileInfo::default(),
|
||||
};
|
||||
let ret = self.fs.fopen(path, &mut fi);
|
||||
let ret = result2ret!("fopen", path, ret);
|
||||
let reply = Open {
|
||||
path: path.to_string(),
|
||||
fi: Some(fi),
|
||||
ret,
|
||||
let mut fi = FileInfo::default();
|
||||
let reply = match self.fs.fopen(path, &mut fi) {
|
||||
Ok(0) => OpenResponse{ fi: Some(fi), status: ok_status() },
|
||||
Ok(_) => OpenResponse{ fi: None, status: err_status(FsOp::FSOP_OPEN, vec![path.to_string()], &std::io::Error::new(std::io::ErrorKind::Other, "op failed")) },
|
||||
Err(e) => OpenResponse{ fi: None, status: err_status(FsOp::FSOP_OPEN, vec![path.to_string()], &*e) },
|
||||
};
|
||||
Ok(Response::new(reply))
|
||||
}
|
||||
async fn fread(&self, request: Request<Read>) -> Result<Response<Read>, Status> {
|
||||
|
||||
async fn fread(&self, request: Request<ReadRequest>) -> Result<Response<ReadResponse>, Status> {
|
||||
let request = request.into_inner();
|
||||
let mut fi = match request.fi{
|
||||
Some(fi) => fi,
|
||||
None => FileInfo::default(),
|
||||
};
|
||||
let mut fi = FileInfo::default();
|
||||
let path = &self.lpath(&request.path);
|
||||
let mut size: usize = request.size as usize;
|
||||
let mut offset: usize = request.offset as usize;
|
||||
let mut buff: Vec<u8> = Vec::with_capacity(size);
|
||||
unsafe {
|
||||
buff.set_len(size);
|
||||
}
|
||||
log::trace!("Got a request: fread {}, size {} offset {}", path, request.size, offset);
|
||||
let ret = self.fs.fread(path, &mut buff, &mut size, offset, &mut fi);
|
||||
let ret = result2ret!("fread", path, ret);
|
||||
if ret != 0 {
|
||||
buff = Vec::new();
|
||||
offset = 0;
|
||||
}
|
||||
Ok(Response::new(Read {
|
||||
path: request.path,
|
||||
size: buff.len() as i64,
|
||||
buff,
|
||||
offset: offset as u64,
|
||||
fi: None,
|
||||
ret,
|
||||
}))
|
||||
}
|
||||
|
||||
async fn fwrite(&self, request: Request<Write>) -> Result<Response<Write>, Status> {
|
||||
let request = request.into_inner();
|
||||
let mut fi = match request.fi{
|
||||
Some(fi) => fi,
|
||||
None => FileInfo::default(),
|
||||
};
|
||||
let path = &self.lpath(&request.path);
|
||||
let buff = request.buff;
|
||||
let mut size = request.size as usize;
|
||||
let offset = request.offset as usize;
|
||||
log::trace!("Got a request: Write {}, size {} offset {}", path, request.size, offset);
|
||||
let ret = self.fs.fwrite(path, &buff, &mut size, offset, &mut fi);
|
||||
let ret = result2ret!("fwrite", path, ret);
|
||||
let reply = Write {
|
||||
ret,
|
||||
path: path.to_string(),
|
||||
size: size as u64,
|
||||
..Default::default()
|
||||
let offset: usize = request.offset as usize;
|
||||
let mut buff: Vec<u8> = vec![0; size];
|
||||
let reply = match self.fs.fread(path, &mut buff, &mut size, offset, &mut fi) {
|
||||
Ok(0) => ReadResponse { data: buff, status: ok_status() },
|
||||
Ok(_) => ReadResponse { data: Vec::new(), status: err_status(FsOp::FSOP_READ, vec![path.to_string()], &std::io::Error::new(std::io::ErrorKind::Other, "op failed")) },
|
||||
Err(e) => ReadResponse { data: Vec::new(), status: err_status(FsOp::FSOP_READ, vec![path.to_string()], &*e) },
|
||||
};
|
||||
Ok(Response::new(reply))
|
||||
}
|
||||
async fn faccess(&self, request: Request<Access>) -> Result<Response<Access>, Status> {
|
||||
|
||||
async fn fwrite(&self, request: Request<WriteRequest>) -> Result<Response<WriteResponse>, Status> {
|
||||
let request = request.into_inner();
|
||||
let mut fi = FileInfo::default();
|
||||
let path = &self.lpath(&request.path);
|
||||
let buff = request.data;
|
||||
let mut size = buff.len();
|
||||
let offset = request.offset as usize;
|
||||
let reply = match self.fs.fwrite(path, &buff, &mut size, offset, &mut fi) {
|
||||
Ok(0) => WriteResponse { written: size as u64, status: ok_status() },
|
||||
Ok(_) => WriteResponse { written: 0, status: err_status(FsOp::FSOP_WRITE, vec![path.to_string()], &std::io::Error::new(std::io::ErrorKind::Other, "op failed")) },
|
||||
Err(e) => WriteResponse { written: 0, status: err_status(FsOp::FSOP_WRITE, vec![path.to_string()], &*e) },
|
||||
};
|
||||
Ok(Response::new(reply))
|
||||
}
|
||||
|
||||
async fn faccess(&self, request: Request<AccessRequest>) -> Result<Response<EmptyResponse>, Status> {
|
||||
let request = request.into_inner();
|
||||
log::trace!("Got a request: {:?}", request);
|
||||
let path = &self.lpath(&request.path);
|
||||
let mask = request.mask;
|
||||
let ret = self.fs.faccess(path, mask);
|
||||
let ret = result2ret!("faccess", path, ret);
|
||||
let reply = Access {
|
||||
ret,
|
||||
path: path.to_string(),
|
||||
mask,
|
||||
let reply = match self.fs.faccess(path, mask) {
|
||||
Ok(0) => EmptyResponse { status: ok_status() },
|
||||
Ok(_) => EmptyResponse { status: err_status(FsOp::FSOP_ACCESS, vec![path.to_string()], &std::io::Error::new(std::io::ErrorKind::Other, "op failed")) },
|
||||
Err(e) => EmptyResponse { status: err_status(FsOp::FSOP_ACCESS, vec![path.to_string()], &*e) },
|
||||
};
|
||||
Ok(Response::new(reply))
|
||||
}
|
||||
|
||||
async fn fsetxattr(&self, request: Request<Setxattr>) -> Result<Response<Setxattr>, Status> {
|
||||
async fn fsetxattr(&self, request: Request<SetxattrRequest>) -> Result<Response<EmptyResponse>, Status> {
|
||||
let request = request.into_inner();
|
||||
log::trace!("Got a request: {:?}", request);
|
||||
let path = &self.lpath(&request.path);
|
||||
let name = request.name.as_ref();
|
||||
let value = request.value;
|
||||
let size = request.size as usize;
|
||||
let flags = request.flags;
|
||||
let ret = self.fs.fsetxattr(path, name, &value, size, flags);
|
||||
let ret = result2ret!("fsetxattr", path, ret);
|
||||
let reply = Setxattr {
|
||||
ret: ret,
|
||||
..Setxattr::default()
|
||||
let reply = match self.fs.fsetxattr(path, name, &value, size, flags) {
|
||||
Ok(0) => EmptyResponse { status: ok_status() },
|
||||
Ok(_) => EmptyResponse { status: err_status(FsOp::FSOP_SETXATTR, vec![path.to_string()], &std::io::Error::from_raw_os_error(libc::ENOSYS)) },
|
||||
Err(e) => EmptyResponse { status: err_status(FsOp::FSOP_SETXATTR, vec![path.to_string()], &*e) },
|
||||
};
|
||||
Ok(Response::new(reply))
|
||||
}
|
||||
async fn fgetxattr(&self, request: Request<Getxattr>) -> Result<Response<Getxattr>, Status> {
|
||||
|
||||
async fn fgetxattr(&self, request: Request<GetxattrRequest>) -> Result<Response<GetxattrResponse>, Status> {
|
||||
let request = request.into_inner();
|
||||
log::trace!("Got a request: {:?}", request);
|
||||
let path = &self.lpath(&request.path);
|
||||
let name = request.name.as_ref();
|
||||
let size = request.size as usize;
|
||||
let ret = self.fs.fgetxattr(path, name, size);
|
||||
let ret = result2ret!("fgetxattr", path, ret);
|
||||
let reply = Getxattr {
|
||||
ret,
|
||||
..Getxattr::default()
|
||||
let reply = match self.fs.fgetxattr(path, name, size) {
|
||||
Ok(0) => GetxattrResponse { value: Vec::new(), status: ok_status() },
|
||||
Ok(_) => GetxattrResponse { value: Vec::new(), status: err_status(FsOp::FSOP_GETXATTR, vec![path.to_string()], &std::io::Error::from_raw_os_error(libc::ENOSYS)) },
|
||||
Err(e) => GetxattrResponse { value: Vec::new(), status: err_status(FsOp::FSOP_GETXATTR, vec![path.to_string()], &*e) },
|
||||
};
|
||||
Ok(Response::new(reply))
|
||||
}
|
||||
|
||||
async fn freaddir(&self, request: Request<Readdir>) -> Result<Response<Readdir>, Status> {
|
||||
async fn freaddir(&self, request: Request<ReaddirRequest>) -> Result<Response<ReaddirResponse>, Status> {
|
||||
let request = request.into_inner();
|
||||
log::trace!("Got a request: {:?}", request);
|
||||
let mut fi = match request.fi{
|
||||
Some(fi) => fi,
|
||||
None => FileInfo::default(),
|
||||
};
|
||||
let mut fi = FileInfo::default();
|
||||
let path = &self.lpath(&request.path);
|
||||
let offset = request.offset as usize;
|
||||
let mut dirs = vec![];
|
||||
let mut dirs: Vec<Direntry> = vec![];
|
||||
let size = 0;
|
||||
let ret = self.fs.freaddir(path, &mut dirs, size, offset, &mut fi);
|
||||
let ret = result2ret!("freaddir", path, ret);
|
||||
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();
|
||||
log::trace!("Got a request: {:?}", request);
|
||||
let path = &self.lpath(&request.path);
|
||||
let mode = request.mode;
|
||||
let ret = self.fs.fmkdir(&path, mode);
|
||||
let ret = result2ret!("fmkdir", path, ret);
|
||||
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();
|
||||
log::trace!("Got a request: {:?}", request);
|
||||
let path = &self.lpath(&request.path);
|
||||
let size = request.size as u64;
|
||||
let ret = self.fs.ftruncate(path, size);
|
||||
let ret = result2ret!("ftruncate", path, ret);
|
||||
let reply = Truncate {
|
||||
ret,
|
||||
..Truncate::default()
|
||||
let reply = match self.fs.freaddir(path, &mut dirs, size, offset, &mut fi) {
|
||||
Ok(0) => ReaddirResponse { dirs, status: ok_status() },
|
||||
Ok(_) => ReaddirResponse { dirs: vec![], status: err_status(FsOp::FSOP_READDIR, vec![path.to_string()], &std::io::Error::new(std::io::ErrorKind::Other, "op failed")) },
|
||||
Err(e) => ReaddirResponse { dirs: vec![], status: err_status(FsOp::FSOP_READDIR, vec![path.to_string()], &*e) },
|
||||
};
|
||||
Ok(Response::new(reply))
|
||||
}
|
||||
|
||||
async fn futimens(&self, request: Request<Utimens>) -> Result<Response<Utimens>, Status> {
|
||||
async fn fmkdir(&self, request: Request<MkdirRequest>) -> Result<Response<EmptyResponse>, Status> {
|
||||
let request = request.into_inner();
|
||||
let path = &self.lpath(&request.path);
|
||||
let mode = request.mode;
|
||||
let reply = match self.fs.fmkdir(&path, mode) {
|
||||
Ok(0) => EmptyResponse { status: ok_status() },
|
||||
Ok(_) => EmptyResponse { status: err_status(FsOp::FSOP_MKDIR, vec![path.to_string()], &std::io::Error::new(std::io::ErrorKind::Other, "op failed")) },
|
||||
Err(e) => EmptyResponse { status: err_status(FsOp::FSOP_MKDIR, vec![path.to_string()], &*e) },
|
||||
};
|
||||
Ok(Response::new(reply))
|
||||
}
|
||||
|
||||
async fn ftruncate(&self, request: Request<TruncateRequest>) -> Result<Response<EmptyResponse>, Status> {
|
||||
let request = request.into_inner();
|
||||
let path = &self.lpath(&request.path);
|
||||
let size = request.size as u64;
|
||||
let reply = match self.fs.ftruncate(path, size) {
|
||||
Ok(0) => EmptyResponse { status: ok_status() },
|
||||
Ok(_) => EmptyResponse { status: err_status(FsOp::FSOP_TRUNCATE, vec![path.to_string()], &std::io::Error::new(std::io::ErrorKind::Other, "op failed")) },
|
||||
Err(e) => EmptyResponse { status: err_status(FsOp::FSOP_TRUNCATE, vec![path.to_string()], &*e) },
|
||||
};
|
||||
Ok(Response::new(reply))
|
||||
}
|
||||
|
||||
async fn futimens(&self, request: Request<UtimensRequest>) -> Result<Response<EmptyResponse>, Status> {
|
||||
let request = request.into_inner();
|
||||
log::trace!("Got a request: {:?}", request);
|
||||
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 = self.fs.futimens(path, &a_time, &m_time);
|
||||
let ret = result2ret!("futimens", path, ret);
|
||||
let reply = Utimens {
|
||||
ret,
|
||||
..Utimens::default()
|
||||
let reply = match self.fs.futimens(path, &a_time, &m_time) {
|
||||
Ok(0) => EmptyResponse { status: ok_status() },
|
||||
Ok(_) => EmptyResponse { status: err_status(FsOp::FSOP_UTIMENS, vec![path.to_string()], &std::io::Error::new(std::io::ErrorKind::Other, "op failed")) },
|
||||
Err(e) => EmptyResponse { status: err_status(FsOp::FSOP_UTIMENS, vec![path.to_string()], &*e) },
|
||||
};
|
||||
Ok(Response::new(reply))
|
||||
}
|
||||
|
||||
async fn fchown(&self, request: Request<Chown>) -> Result<Response<Chown>, Status> {
|
||||
async fn fchown(&self, request: Request<ChownRequest>) -> Result<Response<EmptyResponse>, Status> {
|
||||
let request = request.into_inner();
|
||||
log::trace!("Got a request: {:?}", request);
|
||||
let path = &self.lpath(&request.path);
|
||||
let uid = request.uid as u32;
|
||||
let gid = request.gid as u32;
|
||||
let ret = self.fs.fchown(path, uid, gid);
|
||||
let ret = result2ret!("fchown", path, ret);
|
||||
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();
|
||||
log::trace!("Got a request: {:?}", request);
|
||||
let path = &self.lpath(&request.path);
|
||||
let mut fi = match request.fi{
|
||||
Some(fi) => fi,
|
||||
None => FileInfo::default(),
|
||||
};
|
||||
let ret = self.fs.frelease(path, &mut fi, request.flush != 0);
|
||||
let ret = result2ret!("frelease", path, ret);
|
||||
let reply = Release {
|
||||
ret,
|
||||
..Release::default()
|
||||
};
|
||||
Ok(Response::new(reply))
|
||||
}
|
||||
async fn frmdir(&self, request: Request<Rmdir>) -> Result<Response<Rmdir>, Status> {
|
||||
let request = request.into_inner();
|
||||
log::trace!("Got a request: {:?}", request);
|
||||
let path = &self.lpath(&request.path);
|
||||
let ret = self.fs.frmdir(path);
|
||||
let ret = result2ret!("frmdir", path, ret);
|
||||
let reply = Rmdir {
|
||||
ret,
|
||||
path: request.path,
|
||||
let reply = match self.fs.fchown(path, uid, gid) {
|
||||
Ok(0) => EmptyResponse { status: ok_status() },
|
||||
Ok(_) => EmptyResponse { status: err_status(FsOp::FSOP_CHOWN, vec![path.to_string()], &std::io::Error::from_raw_os_error(libc::ENOSYS)) },
|
||||
Err(e) => EmptyResponse { status: err_status(FsOp::FSOP_CHOWN, vec![path.to_string()], &*e) },
|
||||
};
|
||||
Ok(Response::new(reply))
|
||||
}
|
||||
|
||||
async fn fflush(&self, request: Request<Flush>) -> Result<Response<Flush>, Status> {
|
||||
async fn frelease(&self, request: Request<ReleaseRequest>) -> Result<Response<EmptyResponse>, Status> {
|
||||
let request = request.into_inner();
|
||||
log::trace!("Got a request: {:?}", request);
|
||||
let path = &self.lpath(&request.path);
|
||||
let mut fi = match request.fi{
|
||||
Some(fi) => fi,
|
||||
None => FileInfo::default(),
|
||||
};
|
||||
let ret = self.fs.fflush(path, &mut fi);
|
||||
let ret = result2ret!("fflush", path, ret);
|
||||
let reply = Flush {
|
||||
ret,
|
||||
..Flush::default()
|
||||
let mut fi = FileInfo::default();
|
||||
let reply = match self.fs.frelease(path, &mut fi, request.flush != 0) {
|
||||
Ok(0) => EmptyResponse { status: ok_status() },
|
||||
Ok(_) => EmptyResponse { status: err_status(FsOp::FSOP_RELEASE, vec![path.to_string()], &std::io::Error::new(std::io::ErrorKind::Other, "op failed")) },
|
||||
Err(e) => EmptyResponse { status: err_status(FsOp::FSOP_RELEASE, vec![path.to_string()], &*e) },
|
||||
};
|
||||
Ok(Response::new(reply))
|
||||
}
|
||||
|
||||
async fn fcreate(&self, request: Request<Create>) -> Result<Response<Create>, Status> {
|
||||
async fn frmdir(&self, request: Request<RmdirRequest>) -> Result<Response<EmptyResponse>, Status> {
|
||||
let request = request.into_inner();
|
||||
let path = &self.lpath(&request.path);
|
||||
let reply = match self.fs.frmdir(path) {
|
||||
Ok(0) => EmptyResponse { status: ok_status() },
|
||||
Ok(_) => EmptyResponse { status: err_status(FsOp::FSOP_RMDIR, vec![path.to_string()], &std::io::Error::new(std::io::ErrorKind::Other, "op failed")) },
|
||||
Err(e) => EmptyResponse { status: err_status(FsOp::FSOP_RMDIR, vec![path.to_string()], &*e) },
|
||||
};
|
||||
Ok(Response::new(reply))
|
||||
}
|
||||
|
||||
async fn fflush(&self, request: Request<FlushRequest>) -> Result<Response<EmptyResponse>, Status> {
|
||||
let request = request.into_inner();
|
||||
let path = &self.lpath(&request.path);
|
||||
let mut fi = FileInfo::default();
|
||||
let reply = match self.fs.fflush(path, &mut fi) {
|
||||
Ok(0) => EmptyResponse { status: ok_status() },
|
||||
Ok(_) => EmptyResponse { status: err_status(FsOp::FSOP_FLUSH, vec![path.to_string()], &std::io::Error::new(std::io::ErrorKind::Other, "op failed")) },
|
||||
Err(e) => EmptyResponse { status: err_status(FsOp::FSOP_FLUSH, vec![path.to_string()], &*e) },
|
||||
};
|
||||
Ok(Response::new(reply))
|
||||
}
|
||||
|
||||
async fn fcreate(&self, request: Request<CreateRequest>) -> Result<Response<CreateResponse>, Status> {
|
||||
let request = request.into_inner();
|
||||
log::trace!("Got a request: {:?}", request);
|
||||
let path = &self.lpath(&request.path);
|
||||
let mode = request.mode as u32;
|
||||
let mut fi = match request.fi{
|
||||
Some(fi) => fi,
|
||||
None => FileInfo::default(),
|
||||
};
|
||||
let ret = self.fs.fcreate(path, mode, &mut fi);
|
||||
let ret = result2ret!("fcreate", path, ret);
|
||||
let reply = Create {
|
||||
ret,
|
||||
fi:Some(fi),
|
||||
..Create::default()
|
||||
let mut fi = FileInfo::default();
|
||||
let reply = match self.fs.fcreate(path, mode, &mut fi) {
|
||||
Ok(0) => CreateResponse { fi: Some(fi), status: ok_status() },
|
||||
Ok(_) => CreateResponse { fi: None, status: err_status(FsOp::FSOP_CREATE, vec![path.to_string()], &std::io::Error::new(std::io::ErrorKind::Other, "op failed")) },
|
||||
Err(e) => CreateResponse { fi: None, status: err_status(FsOp::FSOP_CREATE, vec![path.to_string()], &*e) },
|
||||
};
|
||||
Ok(Response::new(reply))
|
||||
}
|
||||
|
||||
async fn funlink(&self, request: Request<Unlink>) -> Result<Response<Unlink>, Status> {
|
||||
async fn funlink(&self, request: Request<UnlinkRequest>) -> Result<Response<EmptyResponse>, Status> {
|
||||
let request = request.into_inner();
|
||||
log::trace!("Got a request: {:?}", request);
|
||||
let path = &self.lpath(&request.path);
|
||||
let ret = self.fs.funlink(path);
|
||||
let ret = result2ret!("funlink", path, ret);
|
||||
let reply = Unlink {
|
||||
ret,
|
||||
path: request.path,
|
||||
let reply = match self.fs.funlink(path) {
|
||||
Ok(0) => EmptyResponse { status: ok_status() },
|
||||
Ok(_) => EmptyResponse { status: err_status(FsOp::FSOP_UNLINK, vec![path.to_string()], &std::io::Error::new(std::io::ErrorKind::Other, "op failed")) },
|
||||
Err(e) => EmptyResponse { status: err_status(FsOp::FSOP_UNLINK, vec![path.to_string()], &*e) },
|
||||
};
|
||||
Ok(Response::new(reply))
|
||||
}
|
||||
|
||||
async fn fopendir(&self,request: Request<Opendir>) -> Result<Response<Opendir>, Status> {
|
||||
async fn fopendir(&self, request: Request<OpendirRequest>) -> Result<Response<OpendirResponse>, Status> {
|
||||
let request = request.into_inner();
|
||||
log::trace!("Got a request: {:?}", request);
|
||||
let path = &self.lpath(&request.path);
|
||||
let mut fi = match request.fi{
|
||||
Some(fi) => fi,
|
||||
None => FileInfo::default(),
|
||||
};
|
||||
let ret = self.fs.fopendir(path, &mut fi);
|
||||
let ret = result2ret!("fopendir", path, ret);
|
||||
let reply = Opendir {
|
||||
ret,
|
||||
fi: Some(fi),
|
||||
..Opendir::default()
|
||||
let mut fi = FileInfo::default();
|
||||
let reply = match self.fs.fopendir(path, &mut fi) {
|
||||
Ok(0) => OpendirResponse { fi: Some(fi), status: ok_status() },
|
||||
Ok(_) => OpendirResponse { fi: None, status: err_status(FsOp::FSOP_OPENDIR, vec![path.to_string()], &std::io::Error::new(std::io::ErrorKind::Other, "op failed")) },
|
||||
Err(e) => OpendirResponse { fi: None, status: err_status(FsOp::FSOP_OPENDIR, vec![path.to_string()], &*e) },
|
||||
};
|
||||
Ok(Response::new(reply))
|
||||
}
|
||||
|
||||
async fn freleasedir(&self, request: Request<Releasedir>) -> Result<Response<Releasedir>, Status> {
|
||||
async fn freleasedir(&self, request: Request<ReleasedirRequest>) -> Result<Response<EmptyResponse>, Status> {
|
||||
let request = request.into_inner();
|
||||
log::trace!("Got a request: {:?}", request);
|
||||
let path = &self.lpath(&request.path);
|
||||
let mut fi = match request.fi{
|
||||
Some(fi) => fi,
|
||||
None => FileInfo::default(),
|
||||
};
|
||||
let ret = self.fs.freleasedir(path, &mut fi);
|
||||
let ret = result2ret!("freleasedir", path, ret);
|
||||
let reply = Releasedir {
|
||||
ret,
|
||||
..Releasedir::default()
|
||||
let mut fi = FileInfo::default();
|
||||
let reply = match self.fs.freleasedir(path, &mut fi) {
|
||||
Ok(0) => EmptyResponse { status: ok_status() },
|
||||
Ok(_) => EmptyResponse { status: err_status(FsOp::FSOP_RELEASEDIR, vec![path.to_string()], &std::io::Error::new(std::io::ErrorKind::Other, "op failed")) },
|
||||
Err(e) => EmptyResponse { status: err_status(FsOp::FSOP_RELEASEDIR, vec![path.to_string()], &*e) },
|
||||
};
|
||||
Ok(Response::new(reply))
|
||||
}
|
||||
|
||||
async fn frename(&self, request: Request<Rename>) -> Result<Response<Rename>, Status> {
|
||||
async fn frename(&self, request: Request<RenameRequest>) -> Result<Response<EmptyResponse>, Status> {
|
||||
let request = request.into_inner();
|
||||
log::trace!("Got a request: {:?}", request);
|
||||
let from = &self.lpath(&request.path);
|
||||
let to = &self.lpath(&request.new);
|
||||
let ret = self.fs.frename(from, to);
|
||||
let ret = result2ret!("frename", from, ret);
|
||||
let reply = Rename {
|
||||
ret,
|
||||
..Rename::default()
|
||||
let reply = match self.fs.frename(from, to) {
|
||||
Ok(0) => EmptyResponse { status: ok_status() },
|
||||
Ok(_) => EmptyResponse { status: err_status(FsOp::FSOP_RENAME, vec![from.to_string(), to.to_string()], &std::io::Error::new(std::io::ErrorKind::Other, "op failed")) },
|
||||
Err(e) => EmptyResponse { status: err_status(FsOp::FSOP_RENAME, vec![from.to_string(), to.to_string()], &*e) },
|
||||
};
|
||||
Ok(Response::new(reply))
|
||||
}
|
||||
}
|
||||
|
||||
# [test]
|
||||
#[test]
|
||||
fn test_config_new() {
|
||||
env_logger::init();
|
||||
let _config = Config::new("config.json").unwrap();
|
||||
println!("Config: {:#?}", _config);
|
||||
let _ = env_logger::try_init();
|
||||
let _config = Config::new("config.json").unwrap();
|
||||
println!("Config: {:#?}", _config);
|
||||
}
|
||||
|
||||
# [cfg(test)]
|
||||
#[cfg(test)]
|
||||
mod test_macros {
|
||||
use std::error::Error;
|
||||
macro_rules! handle_result {
|
||||
@ -548,29 +447,21 @@ mod test_macros {
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
struct MyStruct;
|
||||
|
||||
impl MyStruct {
|
||||
fn example_function(&self, _:i32) -> Result<i32, Box<dyn Error>> {
|
||||
// 这里模拟一个可能的错误
|
||||
Err("模拟错误".into())
|
||||
}
|
||||
}
|
||||
impl MyStruct { fn example_function(&self, _:i32) -> Result<i32, Box<dyn Error>> { Err("模拟错误".into()) } }
|
||||
|
||||
#[test]
|
||||
fn test_() -> Result<(), Box<dyn Error>> {
|
||||
let _ = env_logger::try_init();
|
||||
let my_struct = MyStruct;
|
||||
|
||||
// 使用宏处理返回值
|
||||
assert_ne!(handle_result!(my_struct.example_function(32), "调用 example_function 时发生错误"), 32);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
# [test]
|
||||
#[test]
|
||||
fn test_path() {
|
||||
env_logger::init();
|
||||
let _ = env_logger::try_init();
|
||||
let path = linux_to_windows_path(r"p:\/test/dir/tree");
|
||||
assert_eq!(path, r"p:\test\dir\tree");
|
||||
let path = linux_to_windows_path(r"p:\/");
|
||||
|
Reference in New Issue
Block a user