diff --git a/cmd/khepri/cmd_fsck.go b/cmd/khepri/cmd_fsck.go new file mode 100644 index 000000000..f85a380c5 --- /dev/null +++ b/cmd/khepri/cmd_fsck.go @@ -0,0 +1,86 @@ +package main + +import ( + "crypto/sha256" + "encoding/json" + "log" + + "github.com/fd0/khepri" +) + +func fsck_tree(repo *khepri.Repository, id khepri.ID) (bool, error) { + log.Printf(" checking dir %s", id) + + rd, err := repo.Get(khepri.TYPE_BLOB, id) + if err != nil { + return false, err + } + + hr := khepri.NewHashingReader(rd, sha256.New) + dec := json.NewDecoder(hr) + + tree := &khepri.Tree{} + err = dec.Decode(tree) + + if err != nil { + return false, err + } + + if !id.Equal(hr.Hash()) { + return false, nil + } + + return true, nil +} + +func fsck_snapshot(repo *khepri.Repository, id khepri.ID) (bool, error) { + log.Printf("checking snapshot %s", id) + + sn, err := khepri.LoadSnapshot(repo, id) + if err != nil { + return false, err + } + + return fsck_tree(repo, sn.TreeID) +} + +func commandFsck(repo *khepri.Repository, args []string) error { + var snapshots khepri.IDs + var err error + + if len(args) != 0 { + snapshots = make(khepri.IDs, 0, len(args)) + + for _, arg := range args { + id, err := khepri.ParseID(arg) + if err != nil { + log.Fatal(err) + } + + snapshots = append(snapshots, id) + } + } else { + snapshots, err = repo.List(khepri.TYPE_REF) + + if err != nil { + log.Fatalf("error reading list of snapshot IDs: %v", err) + } + } + + log.Printf("checking %d snapshots", len(snapshots)) + + for _, id := range snapshots { + ok, err := fsck_snapshot(repo, id) + + if err != nil { + log.Printf("error checking snapshot %s: %v", id, err) + continue + } + + if !ok { + log.Printf("snapshot %s failed", id) + } + } + + return nil +} diff --git a/cmd/khepri/main.go b/cmd/khepri/main.go index 7aeac74f4..6288b317b 100644 --- a/cmd/khepri/main.go +++ b/cmd/khepri/main.go @@ -32,6 +32,7 @@ func init() { commands["restore"] = commandRestore commands["list"] = commandList commands["snapshots"] = commandSnapshots + commands["fsck"] = commandFsck } func main() { diff --git a/snapshot.go b/snapshot.go index 555ebcf1e..c35bdcda7 100644 --- a/snapshot.go +++ b/snapshot.go @@ -68,6 +68,8 @@ func LoadSnapshot(repo *Repository, id ID) (*Snapshot, error) { return nil, err } + // TODO: maybe inject a hashing reader here and test if the given id is correct + dec := json.NewDecoder(rd) sn := &Snapshot{} err = dec.Decode(sn)