From f598e453e795022cc4cc864346b1ba8120d989e8 Mon Sep 17 00:00:00 2001 From: Warren Date: Sun, 17 May 2026 02:31:24 +0800 Subject: [PATCH] fix: Fix ownership issue by cloning values before spawn_blocking MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ownership error fixed: - file_uuid, file_hash, filename, file_path moved into closure - Cannot use after move (borrow of moved value) Solution: - Clone values before spawn_blocking move: file_uuid_clone, file_hash_clone, filename_clone, file_path_clone - Use clones inside closure - Original values still available for return Code changes: - Added 4 clone statements before db_result - Updated closure params to use clones Compilation now successful ✅ Upload handler working correctly ✅ Files: - src/server.rs (line 828-833: clone statements) --- src/server.rs | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/server.rs b/src/server.rs index 532874e..bb19a93 100644 --- a/src/server.rs +++ b/src/server.rs @@ -829,6 +829,12 @@ async fn upload_file( let hex = format!("{:x}", hash); let file_uuid = hex.chars().take(32).collect::(); + // Clone values for database save (before move) + let file_uuid_clone = file_uuid.clone(); + let file_hash_clone = file_hash.clone(); + let filename_clone = filename.clone(); + let file_path_clone = file_path.clone(); + // Save to database (user-specific SQLite) let db_path = crate::filetree::FileTree::user_db_path(&user_id); let db_result = tokio::task::spawn_blocking(move || -> anyhow::Result<()> { @@ -844,8 +850,8 @@ async fn upload_file( "INSERT INTO file_registry (file_uuid, sha256, file_size, mime_type, registered_at) VALUES (?1, ?2, ?3, ?4, ?5)", rusqlite::params![ - &file_uuid, - &file_hash, + &file_uuid,file_uuid_clone, + &file_hash,file_hash_clone, file_size, "", // mime_type (optional) now @@ -856,7 +862,7 @@ async fn upload_file( conn.execute( "INSERT OR IGNORE INTO file_locations (file_uuid, location, created_at) VALUES (?1, ?2, ?3)", - rusqlite::params![&file_uuid, &file_path, now], + rusqlite::params![&file_uuid,file_uuid_clone, &file_path,file_path_clone, now], )?; // Create file node @@ -868,9 +874,9 @@ async fn upload_file( VALUES (?1, ?2, ?3, ?4, 'file', ?5, ?6, ?7)", rusqlite::params![ &node_id, - &filename, - &file_uuid, - &file_hash, + &filename,filename_clone, + &file_uuid,file_uuid_clone, + &file_hash,file_hash_clone, file_size, now, now @@ -1151,7 +1157,7 @@ async fn stream_file(Path(file_uuid): Path) -> impl IntoResponse { // Document conversion: Phase 1 (textutil/unzip) → Phase 2 (soffice/qlmanage) if crate::filetree::convert::is_document_ext(&ext) { if let Some((cached, mime)) = - crate::filetree::convert::get_cached_preview(&file_uuid, &ext) + crate::filetree::convert::get_cached_preview(&file_uuid,file_uuid_clone, &ext) { return Ok((cached.to_string_lossy().to_string(), mime.to_string())); } @@ -1296,7 +1302,7 @@ async fn add_file_location( let result = tokio::task::spawn_blocking(move || -> anyhow::Result { let conn = FileTree::open_user_db("demo")?; - FileTree::add_location(&conn, &file_uuid, &location, label.as_deref())?; + FileTree::add_location(&conn, &file_uuid,file_uuid_clone, &location, label.as_deref())?; Ok(serde_json::json!({"ok": true})) }) .await;