1
0
mirror of https://github.com/ipfs/kubo.git synced 2025-05-17 23:16:11 +08:00
Files
kubo/core/commands/filestore.go
Łukasz Magiera 7c2aa0e9a9 gx: update go-unixfs to propagate archive changes
License: MIT
Signed-off-by: Łukasz Magiera <magik6k@gmail.com>
2019-01-30 20:58:32 +01:00

260 lines
5.8 KiB
Go

package commands
import (
"fmt"
"io"
"os"
core "github.com/ipfs/go-ipfs/core"
cmdenv "github.com/ipfs/go-ipfs/core/commands/cmdenv"
e "github.com/ipfs/go-ipfs/core/commands/e"
filestore "github.com/ipfs/go-ipfs/filestore"
cmds "gx/ipfs/QmR77mMvvh8mJBBWQmBfQBu8oD38NUN4KE9SL2gDgAQNc6/go-ipfs-cmds"
cid "gx/ipfs/QmR8BauakNcBa3RbE4nbQu76PDiJgoQgz8AJdhJuiU4TAw/go-cid"
"gx/ipfs/Qmde5VP1qUkyQXKCfmEUA7bP64V2HAptbJ7phuPp7jXWwg/go-ipfs-cmdkit"
)
var FileStoreCmd = &cmds.Command{
Helptext: cmdkit.HelpText{
Tagline: "Interact with filestore objects.",
},
Subcommands: map[string]*cmds.Command{
"ls": lsFileStore,
"verify": verifyFileStore,
"dups": dupsFileStore,
},
}
const (
fileOrderOptionName = "file-order"
)
var lsFileStore = &cmds.Command{
Helptext: cmdkit.HelpText{
Tagline: "List objects in filestore.",
LongDescription: `
List objects in the filestore.
If one or more <obj> is specified only list those specific objects,
otherwise list all objects.
The output is:
<hash> <size> <path> <offset>
`,
},
Arguments: []cmdkit.Argument{
cmdkit.StringArg("obj", false, true, "Cid of objects to list."),
},
Options: []cmdkit.Option{
cmdkit.BoolOption(fileOrderOptionName, "sort the results based on the path of the backing file"),
},
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
_, fs, err := getFilestore(env)
if err != nil {
return err
}
args := req.Arguments
if len(args) > 0 {
return listByArgs(res, fs, args)
}
fileOrder, _ := req.Options[fileOrderOptionName].(bool)
next, err := filestore.ListAll(fs, fileOrder)
if err != nil {
return err
}
for {
r := next()
if r == nil {
break
}
if err := res.Emit(r); err != nil {
return err
}
}
return nil
},
PostRun: cmds.PostRunMap{
cmds.CLI: func(res cmds.Response, re cmds.ResponseEmitter) error {
enc, err := cmdenv.GetCidEncoder(res.Request())
if err != nil {
return err
}
return streamResult(func(v interface{}, out io.Writer) nonFatalError {
r := v.(*filestore.ListRes)
if r.ErrorMsg != "" {
return nonFatalError(r.ErrorMsg)
}
fmt.Fprintf(out, "%s\n", r.FormatLong(enc.Encode))
return ""
})(res, re)
},
},
Type: filestore.ListRes{},
}
var verifyFileStore = &cmds.Command{
Helptext: cmdkit.HelpText{
Tagline: "Verify objects in filestore.",
LongDescription: `
Verify objects in the filestore.
If one or more <obj> is specified only verify those specific objects,
otherwise verify all objects.
The output is:
<status> <hash> <size> <path> <offset>
Where <status> is one of:
ok: the block can be reconstructed
changed: the contents of the backing file have changed
no-file: the backing file could not be found
error: there was some other problem reading the file
missing: <obj> could not be found in the filestore
ERROR: internal error, most likely due to a corrupt database
For ERROR entries the error will also be printed to stderr.
`,
},
Arguments: []cmdkit.Argument{
cmdkit.StringArg("obj", false, true, "Cid of objects to verify."),
},
Options: []cmdkit.Option{
cmdkit.BoolOption(fileOrderOptionName, "verify the objects based on the order of the backing file"),
},
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
_, fs, err := getFilestore(env)
if err != nil {
return err
}
args := req.Arguments
if len(args) > 0 {
return listByArgs(res, fs, args)
}
fileOrder, _ := req.Options[fileOrderOptionName].(bool)
next, err := filestore.VerifyAll(fs, fileOrder)
if err != nil {
return err
}
for {
r := next()
if r == nil {
break
}
if err := res.Emit(r); err != nil {
return err
}
}
return nil
},
PostRun: cmds.PostRunMap{
cmds.CLI: func(res cmds.Response, re cmds.ResponseEmitter) error {
enc, err := cmdenv.GetCidEncoder(res.Request())
if err != nil {
return err
}
for {
v, err := res.Next()
if err != nil {
if err == io.EOF {
return nil
}
return err
}
list, ok := v.(*filestore.ListRes)
if !ok {
return e.TypeErr(list, v)
}
if list.Status == filestore.StatusOtherError {
fmt.Fprintf(os.Stderr, "%s\n", list.ErrorMsg)
}
fmt.Fprintf(os.Stdout, "%s %s\n", list.Status.Format(), list.FormatLong(enc.Encode))
}
},
},
Type: filestore.ListRes{},
}
var dupsFileStore = &cmds.Command{
Helptext: cmdkit.HelpText{
Tagline: "List blocks that are both in the filestore and standard block storage.",
},
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
_, fs, err := getFilestore(env)
if err != nil {
return err
}
enc, err := cmdenv.GetCidEncoder(req)
if err != nil {
return err
}
ch, err := fs.FileManager().AllKeysChan(req.Context)
if err != nil {
return err
}
for cid := range ch {
have, err := fs.MainBlockstore().Has(cid)
if err != nil {
return res.Emit(&RefWrapper{Err: err.Error()})
}
if have {
if err := res.Emit(&RefWrapper{Ref: enc.Encode(cid)}); err != nil {
return err
}
}
}
return nil
},
Encoders: refsEncoderMap,
Type: RefWrapper{},
}
func getFilestore(env cmds.Environment) (*core.IpfsNode, *filestore.Filestore, error) {
n, err := cmdenv.GetNode(env)
if err != nil {
return nil, nil, err
}
fs := n.Filestore
if fs == nil {
return n, nil, filestore.ErrFilestoreNotEnabled
}
return n, fs, err
}
func listByArgs(res cmds.ResponseEmitter, fs *filestore.Filestore, args []string) error {
for _, arg := range args {
c, err := cid.Decode(arg)
if err != nil {
ret := &filestore.ListRes{
Status: filestore.StatusOtherError,
ErrorMsg: fmt.Sprintf("%s: %v", arg, err),
}
if err := res.Emit(ret); err != nil {
return err
}
continue
}
r := filestore.Verify(fs, c)
if err := res.Emit(r); err != nil {
return err
}
}
return nil
}