Fix: drive remove/add - kein blockierender Unmount, kein stiller Fallback

`drive remove` brach bei einem Unmount-Fehler (z. B. fehlende Rechte,
weil das Paar in einem anderen Kontext gemountet wurde) komplett ab,
bevor das Paar aus der Konfiguration entfernt wurde - der Nutzer kam
dann nicht mehr an sein eigenes `drive remove` heran. Der Unmount
läuft jetzt best-effort (wie das bereits bestehende
cleanup_credentials), ein Fehler wird geloggt statt zu blockieren.

`drive add` fiel bei einem fehlgeschlagenen Konfigurations-Laden
(z. B. korrupte Datei - eine fehlende Datei liefert bereits
Standardwerte) still auf GlobalSettings::default() zurück. Das hätte
nicht nur einen abweichenden mount_base_dir ignoriert, sondern auch
das nachfolgende add_pair() (das intern selbst neu lädt) auf
denselben kaputten Zustand treffen lassen - mit dem Risiko, dass alle
bestehenden Paare durch die eine neue Konfiguration ersetzt werden.
Ein Ladefehler bricht jetzt früh mit einer klaren Fehlermeldung ab.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LjyzpGWECyKSBWz5DtkTGz
This commit is contained in:
2026-09-15 23:06:03 +02:00
co-authored by Claude Sonnet 5
parent bb9290c113
commit bc324dd4b7
+20 -3
View File
@@ -127,6 +127,17 @@ async fn remove(id: &str) -> anyhow::Result<()> {
let cfg = config::pairs::load()?; let cfg = config::pairs::load()?;
let pair = config::pairs::find_pair(&cfg, id)?; let pair = config::pairs::find_pair(&cfg, id)?;
// Best-effort wie `cleanup_credentials` weiter unten: ein Unmount-Fehler (z. B. weil das
// Paar von einem anderen Nutzer/Kontext gemountet wurde und wir keine Berechtigung haben)
// darf das Entfernen aus der Konfiguration nicht blockieren - sonst käme der Nutzer nicht
// mehr an sein eigenes `drive remove` heran, ohne vorher erst als root/mit den richtigen
// Rechten manuell auszuhängen.
if let Err(e) = smart_mount::reconcile::unmount_pair(&pair, &cfg.settings).await {
logger_ctdra::warn(
"drive",
&format!("could not unmount drive pair '{id}' before removal: {e}"),
);
}
config::pairs::remove_pair(id)?; config::pairs::remove_pair(id)?;
let creds = CredentialStore::open().await?; let creds = CredentialStore::open().await?;
creds.delete(id, None).await?; creds.delete(id, None).await?;
@@ -173,9 +184,15 @@ async fn add(args: DriveArgs) -> anyhow::Result<()> {
)?; )?;
let id = uuid::Uuid::new_v4().to_string(); let id = uuid::Uuid::new_v4().to_string();
let settings = config::pairs::load() // Bewusst KEIN `unwrap_or_default()`: ein Ladefehler bedeutet eine kaputte/korrupte
.map(|c| c.settings) // Konfigurationsdatei (eine fehlende Datei liefert bereits Standardwerte, siehe
.unwrap_or_default(); // `config_ctdra::load`), nicht "noch keine Konfiguration vorhanden". Stillschweigend mit
// `GlobalSettings::default()` weiterzumachen würde nicht nur einen ggf. abweichenden
// `mount_base_dir` ignorieren, sondern - schwerwiegender - auch das nachfolgende
// `add_pair()` (das intern selbst frisch lädt) auf denselben kaputten Zustand treffen
// lassen, was dort ALLE bestehenden Paare durch die eine neue Konfiguration ersetzen
// würde. Besser früh mit einem klaren Fehler abbrechen.
let settings = config::pairs::load()?.settings;
let mount_point = settings.mount_base_dir.join(&id); let mount_point = settings.mount_base_dir.join(&id);
let pair = DrivePair { let pair = DrivePair {