forked from TrueCloudLab/restic
123 lines
2.2 KiB
Go
123 lines
2.2 KiB
Go
package main
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
|
|
"github.com/fd0/khepri"
|
|
"github.com/fd0/khepri/backend"
|
|
)
|
|
|
|
func init() {
|
|
commands["fsck"] = commandFsck
|
|
}
|
|
|
|
func fsckFile(ch *khepri.ContentHandler, IDs []backend.ID) error {
|
|
for _, id := range IDs {
|
|
debug("checking data blob %v\n", id)
|
|
|
|
// load content
|
|
_, err := ch.Load(backend.Data, id)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func fsckTree(ch *khepri.ContentHandler, id backend.ID) error {
|
|
debug("checking tree %v\n", id)
|
|
|
|
tree, err := khepri.LoadTree(ch, id)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for i, node := range tree {
|
|
if node.Name == "" {
|
|
return fmt.Errorf("node %v of tree %v has no name", i, id)
|
|
}
|
|
|
|
if node.Type == "" {
|
|
return fmt.Errorf("node %q of tree %v has no type", node.Name, id)
|
|
}
|
|
|
|
switch node.Type {
|
|
case "file":
|
|
if node.Content == nil {
|
|
return fmt.Errorf("file node %q of tree %v has no content", node.Name, id)
|
|
}
|
|
|
|
err := fsckFile(ch, node.Content)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
case "dir":
|
|
if node.Subtree == nil {
|
|
return fmt.Errorf("dir node %q of tree %v has no subtree", node.Name, id)
|
|
}
|
|
|
|
err := fsckTree(ch, node.Subtree)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func fsck_snapshot(be backend.Server, key *khepri.Key, id backend.ID) error {
|
|
debug("checking snapshot %v\n", id)
|
|
|
|
ch, err := khepri.NewContentHandler(be, key)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
sn, err := ch.LoadSnapshot(id)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if sn.Content == nil {
|
|
return fmt.Errorf("snapshot %v has no content", sn.ID)
|
|
}
|
|
|
|
if sn.Map == nil {
|
|
return fmt.Errorf("snapshot %v has no map", sn.ID)
|
|
}
|
|
|
|
return fsckTree(ch, sn.Content)
|
|
}
|
|
|
|
func commandFsck(be backend.Server, key *khepri.Key, args []string) error {
|
|
if len(args) == 0 {
|
|
return errors.New("usage: fsck [all|snapshot-id]")
|
|
}
|
|
|
|
if len(args) == 1 && args[0] != "all" {
|
|
snapshotID, err := backend.FindSnapshot(be, args[0])
|
|
if err != nil {
|
|
return fmt.Errorf("invalid id %q: %v", args[1], err)
|
|
}
|
|
|
|
return fsck_snapshot(be, key, snapshotID)
|
|
}
|
|
|
|
list, err := be.List(backend.Snapshot)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for _, snapshotID := range list {
|
|
err := fsck_snapshot(be, key, snapshotID)
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|