package backup import ( "archive/tar" "compress/gzip" "fmt" "io" "os" "path/filepath" ) // ErrCorrupted wird geliefert, wenn eine Sicherungsdatei nicht lesbar ist // (Akzeptanzkriterium 2: Verifikation, nicht nur Erstellungs-Prüfung). var ErrCorrupted = fmt.Errorf("backup: sicherungsdatei ist beschaedigt oder unvollstaendig") // Verify prüft, dass base.tar.gz im gegebenen Sicherungsverzeichnis // vollständig lesbar ist — öffnet gzip- UND tar-Stream und liest JEDEN // Eintrag bis zum Ende durch (nicht nur die Kopfdaten), damit ein // abgeschnittener oder mit kaputten Bytes überschriebener Inhalt // zuverlässig auffällt, nicht nur ein defekter Tar-Header. func Verify(backupDir string) error { path := filepath.Join(backupDir, BaseTarGzFile) f, err := os.Open(path) if err != nil { return fmt.Errorf("%w: %s nicht lesbar: %v", ErrCorrupted, path, err) } defer func() { _ = f.Close() }() gz, err := gzip.NewReader(f) if err != nil { return fmt.Errorf("%w: gzip-header ungueltig: %v", ErrCorrupted, err) } defer func() { _ = gz.Close() }() tr := tar.NewReader(gz) entries := 0 for { hdr, err := tr.Next() if err == io.EOF { break } if err != nil { return fmt.Errorf("%w: tar-eintrag ungueltig: %v", ErrCorrupted, err) } if _, err := io.Copy(io.Discard, tr); err != nil { return fmt.Errorf("%w: inhalt von %q nicht vollstaendig lesbar: %v", ErrCorrupted, hdr.Name, err) } entries++ } if entries == 0 { return fmt.Errorf("%w: archiv enthaelt keine eintraege", ErrCorrupted) } return nil }