master
go 122 lines 2.96 KB
Raw
1 package harness
2
3 import (
4 "bytes"
5 "encoding/json"
6
7 mdag "github.com/ipfs/boxo/ipld/merkledag"
8 ft "github.com/ipfs/boxo/ipld/unixfs"
9 pb "github.com/ipfs/boxo/ipld/unixfs/pb"
10 )
11
12 // UnixFSDataType returns the UnixFS DataType for the given CID by fetching the
13 // raw block and parsing the protobuf. This directly checks the Type field in
14 // the UnixFS Data message (https://specs.ipfs.tech/unixfs/#data).
15 //
16 // Common types:
17 // - ft.TDirectory (1) = basic flat directory
18 // - ft.THAMTShard (5) = HAMT sharded directory
19 func (n *Node) UnixFSDataType(cid string) (pb.Data_DataType, error) {
20 log.Debugf("node %d block get %s", n.ID, cid)
21
22 var blockData bytes.Buffer
23 res := n.Runner.MustRun(RunRequest{
24 Path: n.IPFSBin,
25 Args: []string{"block", "get", cid},
26 CmdOpts: []CmdOpt{RunWithStdout(&blockData)},
27 })
28 if res.Err != nil {
29 return 0, res.Err
30 }
31
32 // Parse dag-pb block
33 protoNode, err := mdag.DecodeProtobuf(blockData.Bytes())
34 if err != nil {
35 return 0, err
36 }
37
38 // Parse UnixFS data
39 fsNode, err := ft.FSNodeFromBytes(protoNode.Data())
40 if err != nil {
41 return 0, err
42 }
43
44 return fsNode.Type(), nil
45 }
46
47 // UnixFSHAMTFanout returns the fanout value for a HAMT shard directory.
48 // This is only valid for HAMT shards (THAMTShard type).
49 func (n *Node) UnixFSHAMTFanout(cid string) (uint64, error) {
50 log.Debugf("node %d block get %s for fanout", n.ID, cid)
51
52 var blockData bytes.Buffer
53 res := n.Runner.MustRun(RunRequest{
54 Path: n.IPFSBin,
55 Args: []string{"block", "get", cid},
56 CmdOpts: []CmdOpt{RunWithStdout(&blockData)},
57 })
58 if res.Err != nil {
59 return 0, res.Err
60 }
61
62 // Parse dag-pb block
63 protoNode, err := mdag.DecodeProtobuf(blockData.Bytes())
64 if err != nil {
65 return 0, err
66 }
67
68 // Parse UnixFS data
69 fsNode, err := ft.FSNodeFromBytes(protoNode.Data())
70 if err != nil {
71 return 0, err
72 }
73
74 return fsNode.Fanout(), nil
75 }
76
77 // InspectPBNode uses dag-json output of 'ipfs dag get' to inspect
78 // "Logical Format" of DAG-PB as defined in
79 // https://web.archive.org/web/20250403194752/https://ipld.io/specs/codecs/dag-pb/spec/#logical-format
80 // (mainly used for inspecting Links without depending on any libraries)
81 func (n *Node) InspectPBNode(cid string) (PBNode, error) {
82 log.Debugf("node %d dag get %s as dag-json", n.ID, cid)
83
84 var root PBNode
85 var dagJsonOutput bytes.Buffer
86 res := n.Runner.MustRun(RunRequest{
87 Path: n.IPFSBin,
88 Args: []string{"dag", "get", "--output-codec=dag-json", cid},
89 CmdOpts: []CmdOpt{RunWithStdout(&dagJsonOutput)},
90 })
91 if res.Err != nil {
92 return root, res.Err
93 }
94
95 err := json.Unmarshal(dagJsonOutput.Bytes(), &root)
96 if err != nil {
97 return root, err
98 }
99 return root, nil
100 }
101
102 // Define structs to match the JSON for
103 type PBHash struct {
104 Slash string `json:"/"`
105 }
106
107 type PBLink struct {
108 Hash PBHash `json:"Hash"`
109 Name string `json:"Name"`
110 Tsize int `json:"Tsize"`
111 }
112
113 type PBData struct {
114 Slash struct {
115 Bytes string `json:"bytes"`
116 } `json:"/"`
117 }
118
119 type PBNode struct {
120 Data PBData `json:"Data"`
121 Links []PBLink `json:"Links"`
122 }