feat: Lösch-Synchronisation mit lokalem Backup und Bereinigung

Gelöschte Dateien werden beim Download ins Backup-Verzeichnis verschoben
(${LOCAL_PHOTO_DIR}-bak, ${LOCAL_DARKTABLE_DB_DIR}-bak) statt permanent
gelöscht. Upload verwendet --delete ohne Backup. Backups älter als 2 Jahre
werden automatisch bereinigt. Safeguard verhindert --delete bei leerem
Quellverzeichnis. validate_path prüft jetzt auch lokale Pfade.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-21 07:04:06 +02:00
parent d714f95cb7
commit faa65dde2f
7 changed files with 166 additions and 9 deletions
+31 -6
View File
@@ -180,6 +180,13 @@ TMPFILES+=("$DOWNLOAD_LOG_DB")
DOWNLOAD_LOG_PHOTOS=$(mktemp)
TMPFILES+=("$DOWNLOAD_LOG_PHOTOS")
BACKUP_PHOTO_DIR="${LOCAL_PHOTO_DIR}-bak"
BACKUP_DB_DIR="${LOCAL_DARKTABLE_DB_DIR}-bak"
if [ "$DRY_RUN" = false ]; then
mkdir -p "$BACKUP_PHOTO_DIR" "$BACKUP_DB_DIR"
fi
RSYNC_DRY_FLAG=()
[ "$DRY_RUN" = true ] && RSYNC_DRY_FLAG=(--dry-run)
[ "$DRY_RUN" = true ] && DRY_SUFFIX=" (Trockenlauf)" || DRY_SUFFIX=""
@@ -191,7 +198,12 @@ if [ "$UPLOAD_ALLOWED" = true ]; then
log_step "Upload: Datenbank${DRY_SUFFIX}"
log " Quelle: $LOCAL_DARKTABLE_DB_DIR/"
log " Ziel: $SERVER_USER@$SERVER_IP:$SERVER_DB_DIR/"
if ! rsync -uavh --itemize-changes \
if [ -z "$(ls -A "$LOCAL_DARKTABLE_DB_DIR" 2>/dev/null)" ]; then
log_error "Upload abgebrochen: Quellverzeichnis leer ($LOCAL_DARKTABLE_DB_DIR). Falscher Mount?"
touch "$CONFIG_DIR/sync_pending"
exit 1
fi
if ! rsync -uavh --itemize-changes --delete \
"${RSYNC_DRY_FLAG[@]}" \
--exclude '*.lock' \
--exclude 'darktable_version' \
@@ -208,7 +220,12 @@ if [ "$UPLOAD_ALLOWED" = true ]; then
log_step "Upload: Fotos${DRY_SUFFIX}"
log " Quelle: $LOCAL_PHOTO_DIR/"
log " Ziel: $SERVER_USER@$SERVER_IP:$SERVER_PHOTO_DIR/"
if ! rsync -uavh --itemize-changes \
if [ -z "$(ls -A "$LOCAL_PHOTO_DIR" 2>/dev/null)" ]; then
log_error "Upload abgebrochen: Quellverzeichnis leer ($LOCAL_PHOTO_DIR). Falscher Mount?"
touch "$CONFIG_DIR/sync_pending"
exit 1
fi
if ! rsync -uavh --itemize-changes --delete \
"${RSYNC_DRY_FLAG[@]}" \
--exclude '*.lock' \
-e "ssh -p $SERVER_SSH_PORT" \
@@ -227,7 +244,9 @@ fi
log_step "Download: Datenbank${DRY_SUFFIX}"
log " Quelle: $SERVER_USER@$SERVER_IP:$SERVER_DB_DIR/"
log " Ziel: $LOCAL_DARKTABLE_DB_DIR/"
if ! rsync -uavh --itemize-changes \
log " Backup: $BACKUP_DB_DIR/"
if ! rsync -uavh --itemize-changes --delete \
--backup --backup-dir="$BACKUP_DB_DIR" \
"${RSYNC_DRY_FLAG[@]}" \
--exclude '*.lock' \
-e "ssh -p $SERVER_SSH_PORT" \
@@ -243,7 +262,9 @@ log "Datenbank-Download abgeschlossen: $RECEIVED_DB Datei(en) empfangen."
log_step "Download: Fotos${DRY_SUFFIX}"
log " Quelle: $SERVER_USER@$SERVER_IP:$SERVER_PHOTO_DIR/"
log " Ziel: $LOCAL_PHOTO_DIR/"
if ! rsync -uavh --itemize-changes \
log " Backup: $BACKUP_PHOTO_DIR/"
if ! rsync -uavh --itemize-changes --delete \
--backup --backup-dir="$BACKUP_PHOTO_DIR" \
"${RSYNC_DRY_FLAG[@]}" \
--exclude '*.lock' \
-e "ssh -p $SERVER_SSH_PORT" \
@@ -266,6 +287,10 @@ if [ "$DRY_RUN" = false ]; then
rm -f "$CONFIG_DIR/sync_pending"
log "sync_pending entfernt."
log_step "Backup-Bereinigung (älter als 2 Jahre)"
cleanup_old_backups "$BACKUP_PHOTO_DIR"
cleanup_old_backups "$BACKUP_DB_DIR"
fi
TOTAL_SENT=$((SENT_DB + SENT_PHOTOS))
@@ -283,8 +308,8 @@ if [ "$DRY_RUN" = true ]; then
DN_DEL=$( echo "$download_log" | grep -cE '^\*deleting' || echo 0)
log_step "Trockenlauf-Ergebnis"
log " Upload: $UP_NEW neu | $UP_UPD aktualisiert | $UP_DEL gelöscht"
log " Download: $DN_NEW neu | $DN_UPD aktualisiert | $DN_DEL gelöscht"
log " Upload: $UP_NEW neu | $UP_UPD aktualisiert | $UP_DEL gelöscht (Server)"
log " Download: $DN_NEW neu | $DN_UPD aktualisiert | $DN_DEL gelöscht → Backup: $BACKUP_PHOTO_DIR"
if [ "$((TOTAL_SENT + TOTAL_RECEIVED))" -gt 0 ]; then
if ask_user "Details" "Details der zu übertragenden Dateien anzeigen?"; then