feat(backup): 归档先写 .partial 再 fsync 改名并记录 sha256,删除原件前回读校验,reaper 抽样巡检与清扫半截归档,保留权限与 mtime,面板标出损坏与已校验

This commit is contained in:
Lemon-miaow committed 2026-09-25 03:16:06 +08:00
1 parent 489eff4494
commit 89a0134707
25 files changed
+1489 -125

No files matched your search

+10 -1
View File
@@ -7,6 +7,7 @@ import (
"flag"
"fmt"
"io"
"strings"
"time"
"felis.lolicon.best/internal/backup"
@@ -91,11 +92,16 @@ func cmdBackup(args []string, stdout, stderr io.Writer) int {
return 1
}
ref, size, err := archiver.Archive(ctx, *server, naming.WorldPVCName(*server))
a, err := archiver.Archive(ctx, *server, naming.WorldPVCName(*server))
if err != nil {
fmt.Fprintf(stderr, "felis backup: archive: %v\n", err)
return 1
}
ref, size := a.Ref, a.Size
if len(a.Skipped) > 0 {
fmt.Fprintf(stderr, "felis backup: %d entries are not plain files or directories and are not in the archive: %s\n",
len(a.Skipped), strings.Join(a.Skipped[:min(len(a.Skipped), 10)], ", "))
}
drv, err := store.Open(ctx, cfg.Database.URL)
if err != nil {
@@ -112,6 +118,9 @@ func cmdBackup(args []string, stdout, stderr io.Writer) int {
SizeBytes: size,
Reason: *reason,
ExpiresAt: time.Now().Add(rcfg.ManualRetention),
SHA256: a.SHA256,
SkippedEntries: len(a.Skipped),
}
st := reaper.NewPGStore(drv.DB())
if err := st.InsertBackup(ctx, rec); err != nil {