pub mod cache; pub mod compression; pub mod dedup; pub mod local_fs; pub mod open_flags; pub mod raid; pub mod s3_fs; pub mod smb_fs; #[cfg(feature = "smb-server")] pub mod smb_server_backend; pub mod util; #[cfg(feature = "async-vfs")] pub mod async_fs; #[cfg(feature = "async-vfs")] pub mod async_s3_fs; #[cfg(feature = "async-vfs")] pub mod async_smb_fs; use std::path::{Path, PathBuf}; use std::time::SystemTime; /// VFS 错误类型 #[derive(Debug, Clone)] pub enum VfsError { NotFound(String), PermissionDenied(String), AlreadyExists(String), NotEmpty(String), NotADirectory(String), IsADirectory(String), Unsupported(String), Io(String), UnexpectedEof, } impl std::fmt::Display for VfsError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { VfsError::NotFound(p) => write!(f, "No such file or directory: {}", p), VfsError::PermissionDenied(p) => write!(f, "Permission denied: {}", p), VfsError::AlreadyExists(p) => write!(f, "File already exists: {}", p), VfsError::NotEmpty(p) => write!(f, "Directory not empty: {}", p), VfsError::NotADirectory(p) => write!(f, "Not a directory: {}", p), VfsError::IsADirectory(p) => write!(f, "Is a directory: {}", p), VfsError::Unsupported(msg) => write!(f, "Unsupported: {}", msg), VfsError::Io(msg) => write!(f, "IO error: {}", msg), VfsError::UnexpectedEof => write!(f, "Unexpected end of file"), } } } impl std::error::Error for VfsError {} /// 文件统计信息(类似 libc::stat) #[derive(Debug, Clone)] pub struct VfsStat { pub size: u64, pub mode: u32, pub uid: u32, pub gid: u32, pub atime: SystemTime, pub mtime: SystemTime, pub is_dir: bool, pub is_symlink: bool, } impl VfsStat { pub fn new() -> Self { Self { size: 0, mode: 0, uid: 0, gid: 0, atime: SystemTime::UNIX_EPOCH, mtime: SystemTime::UNIX_EPOCH, is_dir: false, is_symlink: false, } } } impl Default for VfsStat { fn default() -> Self { Self::new() } } /// 目录条目 #[derive(Debug, Clone)] pub struct VfsDirEntry { pub name: String, pub long_name: String, pub stat: VfsStat, } /// 打开文件的抽象 pub trait VfsFile: Send { fn read(&mut self, buf: &mut [u8]) -> Result; fn write(&mut self, buf: &[u8]) -> Result; fn seek(&mut self, pos: std::io::SeekFrom) -> Result; fn flush(&mut self) -> Result<(), VfsError>; fn stat(&mut self) -> Result; fn set_len(&mut self, size: u64) -> Result<(), VfsError>; /// Write all bytes (convenience, default loops write() until done) fn write_all(&mut self, mut buf: &[u8]) -> Result<(), VfsError> { while !buf.is_empty() { let n = self.write(buf)?; if n == 0 { return Err(VfsError::Io("write returned 0".to_string())); } buf = &buf[n..]; } Ok(()) } /// Read exactly `buf.len()` bytes (convenience, loops read() until done) fn read_exact(&mut self, mut buf: &mut [u8]) -> Result<(), VfsError> { while !buf.is_empty() { let n = self.read(buf)?; if n == 0 { return Err(VfsError::UnexpectedEof); } buf = &mut buf[n..]; } Ok(()) } } /// VFS 后端 trait(所有文件系统操作) pub trait VfsBackend: Send + Sync { /// Clone boxed fn clone_boxed(&self) -> Box; /// 读取目录内容 fn read_dir(&self, path: &Path) -> Result, VfsError>; /// 打开文件(读/写) fn open_file( &self, path: &Path, flags: &open_flags::OpenFlags, ) -> Result, VfsError>; /// 获取文件/目录元数据 fn stat(&self, path: &Path) -> Result; fn lstat(&self, path: &Path) -> Result; /// 创建目录 fn create_dir(&self, path: &Path, mode: u32) -> Result<(), VfsError>; /// 递归创建目录 fn create_dir_all(&self, path: &Path, mode: u32) -> Result<(), VfsError>; /// 删除空目录 fn remove_dir(&self, path: &Path) -> Result<(), VfsError>; /// 递归删除目录及其所有内容 fn remove_dir_all(&self, path: &Path) -> Result<(), VfsError> { // Default: read entries and remove one by one let entries = self.read_dir(path)?; for entry in entries { let child = path.join(&entry.name); if entry.stat.is_dir { self.remove_dir_all(&child)?; } else { self.remove_file(&child)?; } } self.remove_dir(path) } /// 删除文件 fn remove_file(&self, path: &Path) -> Result<(), VfsError>; /// 重命名 fn rename(&self, from: &Path, to: &Path) -> Result<(), VfsError>; /// 设置文件属性 fn set_stat(&self, path: &Path, stat: &VfsStat) -> Result<(), VfsError>; /// 原子性设置 atime 和 mtime(默认实现调用 stat + set_stat,有 race condition) fn set_times(&self, path: &Path, atime: SystemTime, mtime: SystemTime) -> Result<(), VfsError> { let mut stat = self.stat(path)?; stat.atime = atime; stat.mtime = mtime; self.set_stat(path, &stat) } /// 原子性设置 atime(默认实现调用 stat + set_stat,有 race condition) fn set_atime(&self, path: &Path, atime: SystemTime) -> Result<(), VfsError> { let mut stat = self.stat(path)?; stat.atime = atime; self.set_stat(path, &stat) } /// 原子性设置 mtime(默认实现调用 stat + set_stat,有 race condition) fn set_mtime(&self, path: &Path, mtime: SystemTime) -> Result<(), VfsError> { let mut stat = self.stat(path)?; stat.mtime = mtime; self.set_stat(path, &stat) } /// 读取符号链接目标 fn read_link(&self, path: &Path) -> Result; /// 创建符号链接 fn create_symlink(&self, target: &Path, link: &Path) -> Result<(), VfsError>; /// 规范化路径 fn real_path(&self, path: &Path) -> Result; /// 检查路径是否存在 fn exists(&self, path: &Path) -> bool; /// 创建硬链接 fn hard_link(&self, original: &Path, link: &Path) -> Result<(), VfsError>; /// 复制文件(高效实现,fallback 到 read+write) fn copy(&self, from: &Path, to: &Path) -> Result<(), VfsError> { let flags = open_flags::OpenFlags::new().read(); let mut src = self.open_file(from, &flags)?; let write_flags = open_flags::OpenFlags::new().write().create().truncate().mode(0o644); let mut dst = self.open_file(to, &write_flags)?; let mut buf = vec![0u8; 65536]; loop { match src.read(&mut buf) { Ok(0) => break, Ok(n) => dst.write_all(&buf[..n])?, Err(e) => return Err(e), } } dst.flush()?; Ok(()) } // ===== Snapshot support (ZFS-style) ===== /// 创建快照 fn create_snapshot(&self, _path: &Path, _name: &str) -> Result<(), VfsError> { Err(VfsError::Unsupported("create_snapshot".to_string())) } /// 列出快照 fn list_snapshots(&self, _path: &Path) -> Result, VfsError> { Err(VfsError::Unsupported("list_snapshots".to_string())) } /// 删除快照 fn delete_snapshot(&self, _path: &Path, _name: &str) -> Result<(), VfsError> { Err(VfsError::Unsupported("delete_snapshot".to_string())) } /// 从快照恢复 fn restore_snapshot(&self, _path: &Path, _name: &str) -> Result<(), VfsError> { Err(VfsError::Unsupported("restore_snapshot".to_string())) } /// 获取快照信息 fn snapshot_info(&self, _path: &Path, _name: &str) -> Result { Err(VfsError::Unsupported("snapshot_info".to_string())) } // ===== Quota support ===== /// 设置配额限制(字节) fn set_quota(&self, _path: &Path, _quota: &VfsQuota) -> Result<(), VfsError> { Err(VfsError::Unsupported("set_quota".to_string())) } /// 获取配额信息 fn get_quota(&self, _path: &Path) -> Result { Err(VfsError::Unsupported("get_quota".to_string())) } /// 获取配额使用情况 fn get_quota_usage(&self, _path: &Path) -> Result { Err(VfsError::Unsupported("get_quota_usage".to_string())) } /// 检查配额(写入前检查) fn check_quota(&self, _path: &Path, _size: u64) -> Result { Ok(true) // Default: no quota, always allow } // ===== Previous versions (shadow copy) ===== /// 列出文件的所有历史版本 fn list_previous_versions(&self, _path: &Path) -> Result, VfsError> { Err(VfsError::Unsupported("list_previous_versions".to_string())) } /// 打开历史版本文件(通过 @GMT- token) fn open_previous_version(&self, _path: &Path, _gmt_token: &str) -> Result, VfsError> { Err(VfsError::Unsupported("open_previous_version".to_string())) } /// 从历史版本恢复文件 fn restore_previous_version(&self, _path: &Path, _gmt_token: &str) -> Result<(), VfsError> { Err(VfsError::Unsupported("restore_previous_version".to_string())) } // ===== ACL support (NFSv4/SMB) ===== /// 获取文件ACL fn get_acl(&self, _path: &Path) -> Result { Err(VfsError::Unsupported("get_acl".to_string())) } /// 设置文件ACL fn set_acl(&self, _path: &Path, _acl: &VfsAcl) -> Result<(), VfsError> { Err(VfsError::Unsupported("set_acl".to_string())) } /// 检查ACL权限 fn check_acl(&self, _path: &Path, _principal: &str, _mask: VfsAceMask) -> Result { Ok(true) // Default: no ACL, always allow } /// 添加ACE fn add_ace(&self, _path: &Path, _ace: &VfsAce) -> Result<(), VfsError> { Err(VfsError::Unsupported("add_ace".to_string())) } /// 移除ACE fn remove_ace(&self, _path: &Path, _ace_index: usize) -> Result<(), VfsError> { Err(VfsError::Unsupported("remove_ace".to_string())) } } /// 快照信息 #[derive(Debug, Clone)] pub struct VfsSnapshotInfo { /// 快照名称 pub name: String, /// 创建时间 pub created: SystemTime, /// 快照大小(字节) pub size: u64, /// 是否只读 pub read_only: bool, } /// 配额设置 #[derive(Debug, Clone)] pub struct VfsQuota { /// 空间限制(字节),0表示无限制 pub space_limit: u64, /// 文件数量限制,0表示无限制 pub file_limit: u64, /// 用户ID(可选) pub user_id: Option, /// 软限制(字节),超过时警告 pub soft_limit: u64, /// 宽限期(秒) pub grace_period: u64, } /// 配额使用情况 #[derive(Debug, Clone)] pub struct VfsQuotaUsage { /// 已使用空间(字节) pub space_used: u64, /// 文件数量 pub files_used: u64, /// 是否超过软限制 pub over_soft_limit: bool, /// 是否超过硬限制 pub over_hard_limit: bool, } /// 历史版本信息(SMB shadow copy) #[derive(Debug, Clone)] pub struct VfsPreviousVersion { /// 快照名称 pub snapshot_name: String, /// GMT token (@GMT-YYYY.MM.DD-HH.MM.SS) pub gmt_token: String, /// 创建时间 pub created: SystemTime, /// 版本大小(字节) pub size: u64, } /// ACL访问控制条目类型(NFSv4/SMB) #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum VfsAceType { /// 允许访问 Allow, /// 拒绝访问 Deny, /// 审计(SMB) Audit, /// 警报(SMB) Alarm, } /// ACL继承标志(NFSv4/SMB) #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum VfsAceFlag { /// 文件继承 FileInherit, /// 目录继承 DirectoryInherit, /// 无继承(仅当前对象) NoPropagateInherit, /// 仅继承(不应用于当前对象) InheritOnly, /// 已继承 Inherited, /// 成功审计(SMB) SuccessfulAccess, /// 失败审计(SMB) FailedAccess, } /// ACL权限掩码(NFSv4) #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum VfsAceMask { /// 读数据 ReadData, /// 写数据 WriteData, /// 执行 Execute, /// 列目录(读数据+目录) ListDirectory, /// 添加文件(写数据+目录) AddFile, /// 添加子目录 AddSubdirectory, /// 删除子项 DeleteChild, /// 删除 Delete, /// 读属性 ReadAttributes, /// 写属性 WriteAttributes, /// 读ACL ReadNfsAcl, /// 写ACL WriteNfsAcl, /// 读取所有权 ReadOwner, /// 写入所有权 WriteOwner, /// 同步 Synchronize, /// 完全控制(所有权限) FullControl, } /// ACL访问控制条目(ACE) #[derive(Debug, Clone)] pub struct VfsAce { /// ACE类型 pub ace_type: VfsAceType, /// ACE标志 pub flags: Vec, /// 权限掩码 pub mask: Vec, /// 主体(用户/组SID或名称) pub principal: String, } /// ACL列表(NFSv4/SMB) #[derive(Debug, Clone, Default)] pub struct VfsAcl { /// ACE列表 pub aces: Vec, /// 默认ACL(仅目录) pub default_acl: Option>, } /// 压缩算法类型 #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum VfsCompression { /// 无压缩 None, /// LZ4压缩(快速) Lz4, /// ZSTD压缩(高压缩率) Zstd, } /// 压缩配置 #[derive(Debug, Clone)] pub struct VfsCompressionConfig { /// 压缩算法 pub algorithm: VfsCompression, /// 压缩级别(1-22 for ZSTD, 1-12 for LZ4) pub level: u32, /// 最小压缩大小(字节),小于此大小不压缩 pub min_size: u64, } /// 去重配置 #[derive(Debug, Clone)] pub struct VfsDedupConfig { /// 块大小(字节),默认4KB pub block_size: usize, /// 最小文件大小(字节),小于此大小不去重 pub min_file_size: u64, /// 去重存储路径 pub store_path: PathBuf, } impl Default for VfsDedupConfig { fn default() -> Self { Self { block_size: 4096, min_file_size: 1024, store_path: PathBuf::from(".dedup"), } } } /// RAID级别(ZFS RAID-Z) #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum VfsRaidLevel { /// 单磁盘(无RAID) Single, /// RAID-Z1(单奇偶校验,类似RAID 5) RaidZ1, /// RAID-Z2(双奇偶校验,类似RAID 6) RaidZ2, /// RAID-Z3(三奇偶校验) RaidZ3, } impl std::fmt::Display for VfsRaidLevel { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { VfsRaidLevel::Single => write!(f, "Single"), VfsRaidLevel::RaidZ1 => write!(f, "RAID-Z1"), VfsRaidLevel::RaidZ2 => write!(f, "RAID-Z2"), VfsRaidLevel::RaidZ3 => write!(f, "RAID-Z3"), } } } /// RAID配置 #[derive(Debug, Clone)] pub struct VfsRaidConfig { /// RAID级别 pub level: VfsRaidLevel, /// 条带大小(字节),默认64KB pub stripe_size: usize, /// 磁盘列表路径 pub disk_paths: Vec, } impl Default for VfsRaidConfig { fn default() -> Self { Self { level: VfsRaidLevel::Single, stripe_size: 65536, disk_paths: Vec::new(), } } } // ===== Async VfsBackend Design (Phase 1 - Framework) ===== /// Async VFS 文件 trait(用于异步操作) /// /// 设计要点: /// 1. 使用 `async fn` in traits (Rust 1.75+) /// 2. 所有方法返回 `Pin>` /// 3. 与 VfsFile 保持一致的接口 #[cfg(feature = "async-vfs")] pub trait AsyncVfsFile: Send + Sync { fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> std::pin::Pin> + Send + 'a>>; fn write<'a>(&'a mut self, buf: &'a [u8]) -> std::pin::Pin> + Send + 'a>>; fn seek<'a>(&'a mut self, pos: std::io::SeekFrom) -> std::pin::Pin> + Send + 'a>>; fn flush<'a>(&'a mut self) -> std::pin::Pin> + Send + 'a>>; } /// Async VFS 后端 trait(用于异步文件系统操作) /// /// 设计要点: /// 1. 使用 `async fn` in traits (Rust 1.75+) /// 2. 所有方法返回 `Pin>` /// 3. 与 VfsBackend 保持一致的接口 /// 4. 用于 WebDAV/SMB/SSH 异步处理 #[cfg(feature = "async-vfs")] pub trait AsyncVfsBackend: Send + Sync { fn clone_boxed(&self) -> Box; fn read_dir<'a>(&'a self, path: &'a Path) -> std::pin::Pin, VfsError>> + Send + 'a>>; fn open_file<'a>(&'a self, path: &'a Path, flags: &'a open_flags::OpenFlags) -> std::pin::Pin, VfsError>> + Send + 'a>>; fn stat<'a>(&'a self, path: &'a Path) -> std::pin::Pin> + Send + 'a>>; fn create_dir<'a>(&'a self, path: &'a Path, mode: u32) -> std::pin::Pin> + Send + 'a>>; fn remove_dir<'a>(&'a self, path: &'a Path) -> std::pin::Pin> + Send + 'a>>; fn remove_file<'a>(&'a self, path: &'a Path) -> std::pin::Pin> + Send + 'a>>; fn rename<'a>(&'a self, from: &'a Path, to: &'a Path) -> std::pin::Pin> + Send + 'a>>; fn exists<'a>(&'a self, path: &'a Path) -> std::pin::Pin + Send + 'a>>; } // ===== Async VfsBackend Implementation Notes ===== // // Phase 2: AsyncLocalFs (tokio::fs) // - 使用 tokio::fs::File 替代 std::fs::File // - 使用 tokio::fs::read_dir 替代 std::fs::read_dir // - 使用 tokio::fs::create_dir 替代 std::fs::create_dir // // Phase 3: AsyncS3Vfs (ureq is blocking, need async client) // - 使用 async-s3 或 rusoto // - 或者使用 spawn_blocking 包装现有 ureq 调用 // // Phase 4: AsyncSmbVfs // - smb-server crate 使用 async internally // - 需要 async wrapper // // Phase 5: WebDAV Integration // - VfsDavFs 改为 AsyncVfsBackend // - dav-server 已经是 async // - 直接使用 async 方法 // // 预估工作量: // - AsyncVfsBackend trait: 1 hour // - AsyncLocalFs: 3 hours // - AsyncS3Vfs: 2 hours // - AsyncSmbVfs: 2 hours // - WebDAV integration: 3 hours // - Tests: 2 hours // Total: ~13 hours (multi-day project) // // ===== Phase 5 WebDAV Async Integration Design ===== // // 现状分析: // 1. dav-server DavFileSystem trait 方法返回 Pin> // 2. 当前 VfsDavFs::open() 返回 Box::pin(ready(...)) // 3. 这是 "同步包装为 Future",不是真正的 async // 4. DavFileSystem trait API 已变化(2026-06-21 session发现) // - read_dir(path, ReadDirMeta) 而非 read_dir(path, depth) // - have_props(path) 返回 Pin> // - get_props/get_prop/patch_props 新方法 // - get_quota/set_accessed/set_modified 新方法 // - DavFile 需要 write_buf 方法 // - DavMetaData modified()/is_dir() 返回 Pin> // - DavDirEntry name()/is_dir()/metadata() 返回 Pin> // // Phase 5 阻塞因素: // 1. dav-server API 签名与预期不匹配(20+ 编译错误) // 2. 需要 match 完整 DavFileSystem trait 所有方法(~30个) // 3. AsyncVfsFile trait 方法签名需调整 // 4. 估算工作量:~8小时(而非原估计3小时) // // 实现方案选择: // 方案A:spawn_blocking wrapper(推荐) // - 创建 AsyncVfsDavFs 包装现有 VfsDavFs // - 所有 DavFileSystem 方法使用 spawn_blocking 调用同步版本 // - 工作量:~2小时 // - 优点:快速实现,兼容现有 API // - 缺点:仍为伪异步(阻塞线程池) // // 方案B:完整重写 DavFileSystem(长期) // - 完全匹配 dav-server API // - 使用真正的 AsyncVfsBackend async 方法 // - 工作量:~8小时 // - 优点:真正的异步 // - 缺点:需要完全理解 dav-server API // // 推荐方案A(spawn_blocking wrapper) // // 预估工作量:Phase 5 方案A ~2小时,方案B ~8小时