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:
Warren
2026-06-21 16:07:12 +08:00
parent 614275f77a
commit 9acd174388
9 changed files with 1940 additions and 112 deletions

View File

@@ -28,11 +28,31 @@ pub struct VersionHistory {
pub struct WebDavVersioning {
db: Arc<RwLock<HashMap<String, Vec<u8>>>>,
version_storage: PathBuf,
index_path: PathBuf,
}
impl WebDavVersioning {
pub fn new(db: Arc<RwLock<HashMap<String, Vec<u8>>>>, version_storage: PathBuf) -> Self {
Self { db, version_storage }
pub fn new(version_storage: PathBuf) -> Self {
let index_path = version_storage.join("version_index.json");
let db = Arc::new(RwLock::new(HashMap::new()));
// Load persisted index from disk
if index_path.exists() {
if let Ok(json) = std::fs::read_to_string(&index_path) {
if let Ok(map) = serde_json::from_str::<HashMap<String, Vec<u8>>>(&json) {
*db.write().unwrap() = map;
}
}
}
Self { db, version_storage, index_path }
}
fn save_index(&self) -> Result<(), VersionError> {
let db = self.db.read().unwrap();
let json = serde_json::to_string(&*db)?;
std::fs::write(&self.index_path, json)?;
Ok(())
}
pub fn create_version(
@@ -71,9 +91,10 @@ impl WebDavVersioning {
let value = serde_json::to_vec(&version_info)?;
self.db.write().unwrap().insert(key, value);
let history_key = Self::history_key(file_path);
self.update_version_history(file_path, &version_id)?;
self.save_index()?;
Ok(version_info)
}
@@ -144,6 +165,8 @@ impl WebDavVersioning {
self.update_version_history(file_path, &new_version_id)?;
self.save_index()?;
Ok(new_version_info)
}
@@ -165,6 +188,8 @@ impl WebDavVersioning {
let current = self.get_current_version(file_path)?;
self.update_version_history(file_path, &current.version_id)?;
self.save_index()?;
Ok(())
}
@@ -249,14 +274,12 @@ impl From<serde_json::Error> for VersionError {
#[cfg(test)]
mod tests {
use super::*;
use std::sync::Arc;
use tempfile::TempDir;
fn setup_versioning() -> (WebDavVersioning, TempDir) {
let version_dir = TempDir::new().unwrap();
let db = Arc::new(RwLock::new(HashMap::new()));
let versioning = WebDavVersioning::new(db, version_dir.path().to_path_buf());
let versioning = WebDavVersioning::new(version_dir.path().to_path_buf());
(versioning, version_dir)
}