spb/drive Public
SPB Drive — self-hosted personal cloud drive (files, previews, sharing) on the MacLustr cluster.
JavaScript 82.7%
CSS 10.6%
Nunjucks 3.6%
Shell 1.8%
SQL 1.3%
1#!/usr/bin/env bash2# ─────────────────────────────────────────────3# SPB Drive — Personal Cloud Drive4# ─────────────────────────────────────────────5# Author : Simon-Pierre Boucher6# Contact : contact@spboucher.ai7# File : deploy/backup.sh8# Purpose : Nightly backup — sqlite snapshot + hardlink-incremental blobs;9# retention 14 dailies + 8 weeklies; verify + log10# License : MIT © Simon-Pierre Boucher11# ─────────────────────────────────────────────12#13# Restore procedure: see README.md § Backups & restore.1415set -euo pipefail1617DATA_DIR="$HOME/srv/drive"18BACKUP_ROOT="$DATA_DIR/backups"19TODAY="$(date +%Y-%m-%d)"20DEST="$BACKUP_ROOT/$TODAY"21LAST="$(ls -1d "$BACKUP_ROOT"/20* 2>/dev/null | tail -1 || true)"2223log() { printf '%s %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$*"; }2425mkdir -p "$DEST"2627# 1 ── SQLite online snapshot (safe under WAL).28log "sqlite backup → $DEST/drive.sqlite"29sqlite3 "$DATA_DIR/db/drive.sqlite" ".backup '$DEST/drive.sqlite'"3031# 2 ── Blob store: rsync with hardlinks against the previous backup —32# unchanged blobs cost zero extra bytes (content-addressed, immutable).33log "files rsync (link-dest: ${LAST:-none})"34if [ -n "$LAST" ] && [ -d "$LAST/files" ] && [ "$LAST" != "$DEST" ]; then35 rsync -a --delete --link-dest="$LAST/files" "$DATA_DIR/files/" "$DEST/files/"36else37 rsync -a --delete "$DATA_DIR/files/" "$DEST/files/"38fi3940# 3 ── Auth + keys (chmod 600 preserved).41cp -p "$DATA_DIR/auth.json" "$DATA_DIR/keys.json" "$DEST/" 2>/dev/null || true4243# 4 ── Verify: DB integrity + blob count matches.44log "verifying"45sqlite3 "$DEST/drive.sqlite" 'PRAGMA integrity_check;' | grep -q '^ok$' || { log "✗ DB integrity failed"; exit 1; }46SRC_COUNT=$(find "$DATA_DIR/files" -type f | wc -l | tr -d ' ')47DST_COUNT=$(find "$DEST/files" -type f | wc -l | tr -d ' ')48if [ "$SRC_COUNT" != "$DST_COUNT" ]; then49 log "✗ blob count mismatch (src=$SRC_COUNT dst=$DST_COUNT)"; exit 150fi5152# 5 ── Retention: keep 14 dailies; keep Sunday backups 8 weeks.53log "pruning old backups"54for dir in "$BACKUP_ROOT"/20*; do55 [ -d "$dir" ] || continue56 day="$(basename "$dir")"57 age_days=$(( ( $(date +%s) - $(date -j -f %Y-%m-%d "$day" +%s 2>/dev/null || date -d "$day" +%s) ) / 86400 ))58 weekday=$(date -j -f %Y-%m-%d "$day" +%u 2>/dev/null || date -d "$day" +%u)59 if [ "$age_days" -gt 56 ]; then60 rm -rf "$dir"; log "pruned $day (older than 8 weeks)"61 elif [ "$age_days" -gt 14 ] && [ "$weekday" != 7 ]; then62 rm -rf "$dir"; log "pruned $day (daily beyond 14 days)"63 fi64done6566log "✓ backup complete: $DEST ($SRC_COUNT blobs, $(du -sh "$DEST" | cut -f1))"67