diff --git a/core/commands/object/patch.go b/core/commands/object/patch.go index c98f12506..78f927032 100644 --- a/core/commands/object/patch.go +++ b/core/commands/object/patch.go @@ -4,13 +4,20 @@ import ( "fmt" "io" + "github.com/ipfs/go-cid" cmds "github.com/ipfs/go-ipfs-cmds" "github.com/ipfs/go-ipfs/core/commands/cmdenv" + coreiface "github.com/ipfs/interface-go-ipfs-core" "github.com/ipfs/interface-go-ipfs-core/options" "github.com/ipfs/interface-go-ipfs-core/path" ) +const ( + softBlockLimit = 1024 * 1024 // https://github.com/ipfs/go-ipfs/issues/7421#issuecomment-910833499 + allowBigBlock = "allow-big-block" +) + var ObjectPatchCmd = &cmds.Command{ Helptext: cmds.HelpText{ Tagline: "Deprecated way to create a new merkledag object based on an existing one. Use MFS with 'files cp|rm' instead.", @@ -41,6 +48,9 @@ For modern use cases, use MFS with 'files' commands: 'ipfs files --help'. "rm-link": patchRmLinkCmd, "set-data": patchSetDataCmd, }, + Options: []cmds.Option{ + cmds.BoolOption(allowBigBlock, "Disable block size check and allow creation of blocks bigger than 1MB. WARNING: such blocks won't be transferable over the standard bitswap.").WithDefault(false), + }, } var patchAppendDataCmd = &cmds.Command{ @@ -82,6 +92,10 @@ DEPRECATED and provided for legacy reasons. Use 'ipfs add' or 'ipfs files' inste return err } + if err := checkBlockSize(req, p.Cid(), api.Dag()); err != nil { + return err + } + return cmds.EmitOnce(res, &Object{Hash: p.Cid().String()}) }, Type: &Object{}, @@ -128,6 +142,10 @@ DEPRECATED and provided for legacy reasons. Use 'files cp' and 'dag put' instead return err } + if err := checkBlockSize(req, p.Cid(), api.Dag()); err != nil { + return err + } + return cmds.EmitOnce(res, &Object{Hash: p.Cid().String()}) }, Type: Object{}, @@ -166,6 +184,10 @@ DEPRECATED and provided for legacy reasons. Use 'files rm' instead. return err } + if err := checkBlockSize(req, p.Cid(), api.Dag()); err != nil { + return err + } + return cmds.EmitOnce(res, &Object{Hash: p.Cid().String()}) }, Type: Object{}, @@ -232,6 +254,10 @@ Use MFS and 'files' commands instead: return err } + if err := checkBlockSize(req, p.Cid(), api.Dag()); err != nil { + return err + } + return cmds.EmitOnce(res, &Object{Hash: p.Cid().String()}) }, Type: Object{}, @@ -242,3 +268,26 @@ Use MFS and 'files' commands instead: }), }, } + +func checkBlockSize(req *cmds.Request, c cid.Cid, dagAPI coreiface.APIDagService) error { + allowAnyBlockSize, _ := req.Options[allowBigBlock].(bool) + if allowAnyBlockSize { + return nil + } + + // We do not allow producing blocks bigger than 1 MiB to avoid errors + // when transmitting them over BitSwap. The 1 MiB constant is an + // unenforced and undeclared rule of thumb hard-coded here. + modifiedNode, err := dagAPI.Get(req.Context, c) + if err != nil { + return err + } + modifiedNodeSize, err := modifiedNode.Size() + if err != nil { + return err + } + if modifiedNodeSize > softBlockLimit { + return fmt.Errorf("produced block is over 1MB, object API is deprecated and does not support HAMT-sharding: to create big directories, please use the files API (MFS)") + } + return nil +} diff --git a/test/sharness/t0051-object.sh b/test/sharness/t0051-object.sh index 95de4fda7..875548411 100755 --- a/test/sharness/t0051-object.sh +++ b/test/sharness/t0051-object.sh @@ -223,6 +223,24 @@ test_object_cmd() { ipfs object stat $OUTPUT ' + test_expect_success "'ipfs object patch' check output block size" ' + DIR=$(ipfs object new unixfs-dir) + for i in {1..13} + do + DIR=$(ipfs object patch "$DIR" add-link "$DIR.jpg" "$DIR") + done + # Fail when new block goes over the BS limit of 1MB, but allow manual override + test_expect_code 1 ipfs object patch "$DIR" add-link "$DIR.jpg" "$DIR" >patch_out 2>&1 + ' + + test_expect_success "ipfs object patch add-link output has the correct error" ' + grep "produced block is over 1MB, object API is deprecated and does not support HAMT-sharding: to create big directories, please use the files API (MFS)" patch_out + ' + + test_expect_success "ipfs object patch --allow-big-block=true add-link works" ' + test_expect_code 0 ipfs object patch --allow-big-block=true "$DIR" add-link "$DIR.jpg" "$DIR" + ' + test_expect_success "'ipfs object new foo' shouldn't crash" ' test_expect_code 1 ipfs object new foo '