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) <noreply@anthropic.com>
This commit is contained in:
Stefan Hacker 2026-04-16 12:29:11 +02:00
parent e55ce106d4
commit 2937082ba2
1 changed files with 54 additions and 16 deletions

View File

@ -102,9 +102,18 @@ pub fn register_sync_root(
// struct einbauen koennen. windows-rs verlangt hier nichts weiter. // struct einbauen koennen. windows-rs verlangt hier nichts weiter.
let _ = display_wide; let _ = display_wide;
// Erst versuchen ohne UPDATE-Flag (frische Registrierung). Bei "schon // Erst eine eventuell vorhandene Registrierung wegraeumen. Sonst
// registriert"-Fehler nochmal mit UPDATE-Flag. So laeuft es beim ersten // uebernimmt UPDATE nur einen Teil der Policies und alte PARTIAL-
// Aktivieren UND bei Folgestarts. // 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 { unsafe {
if let Err(e) = CF::CfRegisterSyncRoot( if let Err(e) = CF::CfRegisterSyncRoot(
PCWSTR(path_wide.as_ptr()), PCWSTR(path_wide.as_ptr()),
@ -112,9 +121,8 @@ pub fn register_sync_root(
&policies, &policies,
CF::CF_REGISTER_FLAG_NONE, CF::CF_REGISTER_FLAG_NONE,
) { ) {
let already = e.code().0 == 0x80070091u32 as i32 // DIR_NOT_EMPTY log_err(mount_point, &format!("CfRegisterSyncRoot FAILED: {e:?}"));
|| e.code().0 == 0x800710D1u32 as i32; // Already registered // Als Fallback mit UPDATE-Flag
if already {
CF::CfRegisterSyncRoot( CF::CfRegisterSyncRoot(
PCWSTR(path_wide.as_ptr()), PCWSTR(path_wide.as_ptr()),
&info, &info,
@ -122,13 +130,12 @@ pub fn register_sync_root(
CF::CF_REGISTER_FLAG_UPDATE, CF::CF_REGISTER_FLAG_UPDATE,
) )
.map_err(|e| format!("CfRegisterSyncRoot(UPDATE): {e}"))?; .map_err(|e| format!("CfRegisterSyncRoot(UPDATE): {e}"))?;
} else {
return Err(format!("CfRegisterSyncRoot: {e}"));
}
} }
} }
log_msg(mount_point, "CfRegisterSyncRoot OK");
connect_callbacks(mount_point)?; connect_callbacks(mount_point)?;
log_msg(mount_point, "callbacks connected");
Ok(()) Ok(())
} }
@ -308,12 +315,40 @@ fn complete_transfer(
Ok(()) 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::<CF::CF_OPERATION_INFO>() 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::<CF::CF_OPERATION_PARAMETERS>() 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> { fn connect_callbacks(mount_point: &Path) -> Result<(), String> {
let callbacks = [ let callbacks = [
CF::CF_CALLBACK_REGISTRATION { CF::CF_CALLBACK_REGISTRATION {
Type: CF::CF_CALLBACK_TYPE_FETCH_DATA, Type: CF::CF_CALLBACK_TYPE_FETCH_DATA,
Callback: Some(on_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. // Sentinel: Type = INVALID beendet die Tabelle.
CF::CF_CALLBACK_REGISTRATION { CF::CF_CALLBACK_REGISTRATION {
Type: CF::CF_CALLBACK_TYPE_NONE, Type: CF::CF_CALLBACK_TYPE_NONE,
@ -357,6 +392,9 @@ pub fn populate_placeholders(
entries: &[RemoteEntry], entries: &[RemoteEntry],
) -> Result<(), String> { ) -> Result<(), String> {
use std::collections::HashMap; use std::collections::HashMap;
log_msg(mount_point, &format!(
"populate_placeholders: {} Eintraege", entries.len()
));
let by_id: HashMap<i64, &RemoteEntry> = entries.iter().map(|e| (e.id, e)).collect(); let by_id: HashMap<i64, &RemoteEntry> = entries.iter().map(|e| (e.id, e)).collect();
fn rel_path<'a>( fn rel_path<'a>(