From c53154cd2bcfe0a33a231e04da32dd0366484ace Mon Sep 17 00:00:00 2001 From: Jeromy Date: Thu, 30 Jun 2016 18:09:15 -0700 Subject: [PATCH 1/2] add repo verify command License: MIT Signed-off-by: Jeromy --- core/commands/repo.go | 95 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 89 insertions(+), 6 deletions(-) diff --git a/core/commands/repo.go b/core/commands/repo.go index 40147c0df..13428c988 100644 --- a/core/commands/repo.go +++ b/core/commands/repo.go @@ -3,15 +3,18 @@ package commands import ( "bytes" "fmt" + "io" + "os" + "path/filepath" + + bstore "github.com/ipfs/go-ipfs/blocks/blockstore" cmds "github.com/ipfs/go-ipfs/commands" corerepo "github.com/ipfs/go-ipfs/core/corerepo" config "github.com/ipfs/go-ipfs/repo/config" fsrepo "github.com/ipfs/go-ipfs/repo/fsrepo" lockfile "github.com/ipfs/go-ipfs/repo/fsrepo/lock" + u "gx/ipfs/QmZNVWh8LLjAavuQ2JXuFmuYH3C11xo988vSgp7UQrTRj1/go-ipfs-util" - "io" - "os" - "path/filepath" ) type RepoVersion struct { @@ -31,6 +34,7 @@ var RepoCmd = &cmds.Command{ "stat": repoStatCmd, "fsck": RepoFsckCmd, "version": repoVersionCmd, + "verify": repoVerifyCmd, }, } @@ -207,9 +211,7 @@ daemons are running. return } - s := "Lockfiles have been removed." - log.Info(s) - res.SetOutput(&MessageOutput{s + "\n"}) + res.SetOutput(&MessageOutput{"Lockfiles have been removed.\n"}) }, Type: MessageOutput{}, Marshalers: cmds.MarshalerMap{ @@ -217,6 +219,87 @@ daemons are running. }, } +type VerifyProgress struct { + Message string + Progress int +} + +var repoVerifyCmd = &cmds.Command{ + Helptext: cmds.HelpText{ + Tagline: "Verify all blocks in repo are not corrupted.", + }, + Run: func(req cmds.Request, res cmds.Response) { + nd, err := req.InvocContext().GetNode() + if err != nil { + res.SetError(err, cmds.ErrNormal) + return + } + + out := make(chan interface{}) + go func() { + defer close(out) + bs := bstore.NewBlockstore(nd.Repo.Datastore()) + + bs.RuntimeHashing(true) + + keys, err := bs.AllKeysChan(req.Context()) + if err != nil { + log.Error(err) + return + } + + var fails int + var i int + for k := range keys { + _, err := bs.Get(k) + if err != nil { + out <- &VerifyProgress{ + Message: fmt.Sprintf("block %s was corrupt (%s)", k, err), + } + fails++ + } + i++ + out <- &VerifyProgress{Progress: i} + } + if fails == 0 { + out <- &VerifyProgress{Message: "verify complete, all blocks validated."} + } + }() + + res.SetOutput((<-chan interface{})(out)) + }, + Marshalers: cmds.MarshalerMap{ + cmds.Text: func(res cmds.Response) (io.Reader, error) { + out := res.Output().(<-chan interface{}) + + marshal := func(v interface{}) (io.Reader, error) { + obj, ok := v.(*VerifyProgress) + if !ok { + return nil, u.ErrCast() + } + + buf := new(bytes.Buffer) + if obj.Message != "" { + if len(obj.Message) < 20 { + obj.Message += " " + } + fmt.Fprintln(buf, obj.Message) + return buf, nil + } + + fmt.Fprintf(buf, "%d blocks processed.\r", obj.Progress) + return buf, nil + } + + return &cmds.ChannelMarshaler{ + Channel: out, + Marshaler: marshal, + Res: res, + }, nil + }, + }, +} + var repoVersionCmd = &cmds.Command{ Helptext: cmds.HelpText{ Tagline: "Show the repo version.", From d13befe9ef7fcdd62b523e7a677bed258121c474 Mon Sep 17 00:00:00 2001 From: Jeromy Date: Tue, 5 Jul 2016 14:58:14 -0700 Subject: [PATCH 2/2] add a test for repo verify, and make it return non-zero code on failure License: MIT Signed-off-by: Jeromy --- core/commands/repo.go | 6 ++++++ test/sharness/t0084-repo-read-rehash.sh | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/core/commands/repo.go b/core/commands/repo.go index 13428c988..6afd533f4 100644 --- a/core/commands/repo.go +++ b/core/commands/repo.go @@ -6,6 +6,7 @@ import ( "io" "os" "path/filepath" + "strings" bstore "github.com/ipfs/go-ipfs/blocks/blockstore" cmds "github.com/ipfs/go-ipfs/commands" @@ -263,6 +264,8 @@ var repoVerifyCmd = &cmds.Command{ } if fails == 0 { out <- &VerifyProgress{Message: "verify complete, all blocks validated."} + } else { + out <- &VerifyProgress{Message: "verify complete, some blocks were corrupt."} } }() @@ -280,6 +283,9 @@ var repoVerifyCmd = &cmds.Command{ buf := new(bytes.Buffer) if obj.Message != "" { + if strings.Contains(obj.Message, "blocks were corrupt") { + return nil, fmt.Errorf(obj.Message) + } if len(obj.Message) < 20 { obj.Message += " " } diff --git a/test/sharness/t0084-repo-read-rehash.sh b/test/sharness/t0084-repo-read-rehash.sh index 9f4e7641f..a4831f0f0 100755 --- a/test/sharness/t0084-repo-read-rehash.sh +++ b/test/sharness/t0084-repo-read-rehash.sh @@ -34,4 +34,9 @@ test_expect_success 'getting modified block fails' ' grep "block in storage has different hash than requested" err_msg ' +test_expect_success "block shows up in repo verify" ' + test_expect_code 1 ipfs repo verify > verify_out && + grep "$H_BLOCK2" verify_out +' + test_done