From 2937082ba2370bd9715fea3c91763f1f694a4011 Mon Sep 17 00:00:00 2001 From: Stefan Hacker Date: Thu, 16 Apr 2026 12:29:11 +0200 Subject: [PATCH] fix(cloud-files): Sauberes Re-Register + FETCH_PLACEHOLDERS-Stub + mehr Log - CfUnregisterSyncRoot VOR CfRegisterSyncRoot, damit alte Policies (z.B. PARTIAL) nicht durch UPDATE-Flag kleben bleiben - FETCH_PLACEHOLDERS-Stub registriert, der mit leerer Antwort und DISABLE_ON_DEMAND_POPULATION-Flag antwortet. Safety-Net falls Windows trotz FULL-Policy doch danach fragt - log_msg an kritischen Stellen (register, connect, populate), damit wir beim naechsten Timeout sehen wo es haengt Co-Authored-By: Claude Opus 4.6 (1M context) --- .../src-tauri/src/cloud_files/windows.rs | 70 ++++++++++++++----- 1 file changed, 54 insertions(+), 16 deletions(-) diff --git a/clients/desktop/src-tauri/src/cloud_files/windows.rs b/clients/desktop/src-tauri/src/cloud_files/windows.rs index 9bdb415..5d9c9f7 100644 --- a/clients/desktop/src-tauri/src/cloud_files/windows.rs +++ b/clients/desktop/src-tauri/src/cloud_files/windows.rs @@ -102,9 +102,18 @@ pub fn register_sync_root( // struct einbauen koennen. windows-rs verlangt hier nichts weiter. let _ = display_wide; - // Erst versuchen ohne UPDATE-Flag (frische Registrierung). Bei "schon - // registriert"-Fehler nochmal mit UPDATE-Flag. So laeuft es beim ersten - // Aktivieren UND bei Folgestarts. + // Erst eine eventuell vorhandene Registrierung wegraeumen. Sonst + // uebernimmt UPDATE nur einen Teil der Policies und alte PARTIAL- + // Population-Einstellungen bleiben aktiv -> Explorer-Timeout. + unsafe { + let _ = CF::CfUnregisterSyncRoot(PCWSTR(path_wide.as_ptr())); + } + + log_msg(mount_point, &format!( + "register_sync_root path={} provider={} account={}", + mount_point.display(), provider_name, account_id + )); + unsafe { if let Err(e) = CF::CfRegisterSyncRoot( PCWSTR(path_wide.as_ptr()), @@ -112,23 +121,21 @@ pub fn register_sync_root( &policies, CF::CF_REGISTER_FLAG_NONE, ) { - let already = e.code().0 == 0x80070091u32 as i32 // DIR_NOT_EMPTY - || e.code().0 == 0x800710D1u32 as i32; // Already registered - if already { - CF::CfRegisterSyncRoot( - PCWSTR(path_wide.as_ptr()), - &info, - &policies, - CF::CF_REGISTER_FLAG_UPDATE, - ) - .map_err(|e| format!("CfRegisterSyncRoot(UPDATE): {e}"))?; - } else { - return Err(format!("CfRegisterSyncRoot: {e}")); - } + log_err(mount_point, &format!("CfRegisterSyncRoot FAILED: {e:?}")); + // Als Fallback mit UPDATE-Flag + CF::CfRegisterSyncRoot( + PCWSTR(path_wide.as_ptr()), + &info, + &policies, + CF::CF_REGISTER_FLAG_UPDATE, + ) + .map_err(|e| format!("CfRegisterSyncRoot(UPDATE): {e}"))?; } } + log_msg(mount_point, "CfRegisterSyncRoot OK"); connect_callbacks(mount_point)?; + log_msg(mount_point, "callbacks connected"); Ok(()) } @@ -308,12 +315,40 @@ fn complete_transfer( Ok(()) } +unsafe extern "system" fn on_fetch_placeholders( + info: *const CF::CF_CALLBACK_INFO, + _params: *const CF::CF_CALLBACK_PARAMETERS, +) { + // Safety-Net: wir populieren schon ueber populate_placeholders, + // aber falls Windows trotzdem ruft, geben wir leere Antwort. + let info = &*info; + let mut op_info = CF::CF_OPERATION_INFO::default(); + op_info.StructSize = std::mem::size_of::() as u32; + op_info.Type = CF::CF_OPERATION_TYPE_TRANSFER_PLACEHOLDERS; + op_info.ConnectionKey = info.ConnectionKey; + op_info.TransferKey = info.TransferKey; + let mut params = CF::CF_OPERATION_PARAMETERS::default(); + params.ParamSize = std::mem::size_of::() as u32; + let transfer = &mut params.Anonymous.TransferPlaceholders; + transfer.CompletionStatus = windows::Win32::Foundation::NTSTATUS(0); + transfer.PlaceholderTotalCount = 0; + transfer.PlaceholderArray = std::ptr::null_mut(); + transfer.PlaceholderCount = 0; + transfer.EntriesProcessed = 0; + transfer.Flags = CF::CF_OPERATION_TRANSFER_PLACEHOLDERS_FLAG_DISABLE_ON_DEMAND_POPULATION; + let _ = CF::CfExecute(&op_info, &mut params); +} + fn connect_callbacks(mount_point: &Path) -> Result<(), String> { let callbacks = [ CF::CF_CALLBACK_REGISTRATION { Type: CF::CF_CALLBACK_TYPE_FETCH_DATA, Callback: Some(on_fetch_data), }, + CF::CF_CALLBACK_REGISTRATION { + Type: CF::CF_CALLBACK_TYPE_FETCH_PLACEHOLDERS, + Callback: Some(on_fetch_placeholders), + }, // Sentinel: Type = INVALID beendet die Tabelle. CF::CF_CALLBACK_REGISTRATION { Type: CF::CF_CALLBACK_TYPE_NONE, @@ -357,6 +392,9 @@ pub fn populate_placeholders( entries: &[RemoteEntry], ) -> Result<(), String> { use std::collections::HashMap; + log_msg(mount_point, &format!( + "populate_placeholders: {} Eintraege", entries.len() + )); let by_id: HashMap = entries.iter().map(|e| (e.id, e)).collect(); fn rel_path<'a>(