WebDAV improvements: flush fix, RwLock recovery, expired lock cleanup, atomic set_times
P0 fixes: - flush(): add flushed flag, proper error logging, Drop warning for data loss - props_data RwLock: replace unwrap() with try_read/try_write recovery - PersistedLs: add is_expired() + cleanup_expired_locks() helper P1 improvements: - Props persistence via VFS (load_props/save_props/patch_props) - COPY/MOVE sync dead props (copy on COPY, move key on rename) - Atomic set_atime/set_mtime via filetime crate (no race condition) New files: - webdav_locks.rs: PersistedLs with lock persistence + expiry cleanup Tests: 288 passed, 0 failed
This commit is contained in:
@@ -148,6 +148,21 @@ pub trait VfsBackend: Send + Sync {
|
||||
/// 删除空目录
|
||||
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>;
|
||||
|
||||
@@ -157,6 +172,28 @@ pub trait VfsBackend: Send + Sync {
|
||||
/// 设置文件属性
|
||||
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<PathBuf, VfsError>;
|
||||
|
||||
@@ -172,6 +209,24 @@ pub trait VfsBackend: Send + Sync {
|
||||
/// 创建硬链接
|
||||
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) =====
|
||||
|
||||
/// 创建快照
|
||||
|
||||
Reference in New Issue
Block a user