mirror of
https://github.com/ipfs/kubo.git
synced 2025-06-27 07:57:30 +08:00
Merge pull request #5098 from schomatis/feat/unixfs/fsnode-include-pb
unixfs: integrate `pb.Data` into `FSNode` to avoid duplicating fields
This commit is contained in:
@ -116,7 +116,7 @@ func (db *DagBuilderHelper) GetDagServ() ipld.DAGService {
|
||||
func (db *DagBuilderHelper) NewUnixfsNode() *UnixfsNode {
|
||||
n := &UnixfsNode{
|
||||
node: new(dag.ProtoNode),
|
||||
ufmt: &ft.FSNode{Type: ft.TFile},
|
||||
ufmt: ft.NewFSNode(ft.TFile),
|
||||
}
|
||||
n.SetPrefix(db.prefix)
|
||||
return n
|
||||
@ -161,7 +161,7 @@ func (db *DagBuilderHelper) NewLeaf(data []byte) (*UnixfsNode, error) {
|
||||
func (db *DagBuilderHelper) newUnixfsBlock() *UnixfsNode {
|
||||
n := &UnixfsNode{
|
||||
node: new(dag.ProtoNode),
|
||||
ufmt: &ft.FSNode{Type: ft.TRaw},
|
||||
ufmt: ft.NewFSNode(ft.TRaw),
|
||||
}
|
||||
n.SetPrefix(db.prefix)
|
||||
return n
|
||||
|
@ -77,7 +77,7 @@ func (n *UnixfsNode) Set(other *UnixfsNode) {
|
||||
n.raw = other.raw
|
||||
n.rawnode = other.rawnode
|
||||
if other.ufmt != nil {
|
||||
n.ufmt.Data = other.ufmt.Data
|
||||
n.ufmt.SetData(other.ufmt.GetData())
|
||||
}
|
||||
}
|
||||
|
||||
@ -127,7 +127,7 @@ func (n *UnixfsNode) RemoveChild(index int, dbh *DagBuilderHelper) {
|
||||
|
||||
// SetData stores data in this node.
|
||||
func (n *UnixfsNode) SetData(data []byte) {
|
||||
n.ufmt.Data = data
|
||||
n.ufmt.SetData(data)
|
||||
}
|
||||
|
||||
// FileSize returns the total file size of this tree (including children)
|
||||
|
@ -60,7 +60,7 @@ func (fi *File) Open(flags int, sync bool) (FileDescriptor, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch fsn.Type {
|
||||
switch fsn.GetType() {
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported fsnode type for 'file'")
|
||||
case ft.TSymlink:
|
||||
|
@ -852,7 +852,7 @@ func TestFlushing(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if fsnode.Type != ft.TDirectory {
|
||||
if fsnode.GetType() != ft.TDirectory {
|
||||
t.Fatal("root wasnt a directory")
|
||||
}
|
||||
|
||||
|
@ -526,7 +526,7 @@ func dagTruncate(ctx context.Context, n ipld.Node, size uint64, ds ipld.DAGServi
|
||||
var cur uint64
|
||||
end := 0
|
||||
var modified ipld.Node
|
||||
ndata := new(ft.FSNode)
|
||||
ndata := ft.NewFSNode(ft.TRaw)
|
||||
for i, lnk := range nd.Links() {
|
||||
child, err := lnk.GetNode(ctx, ds)
|
||||
if err != nil {
|
||||
|
@ -139,67 +139,101 @@ func DataSize(data []byte) (uint64, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// An FSNode represents a filesystem object.
|
||||
// An FSNode represents a filesystem object using the UnixFS specification.
|
||||
//
|
||||
// The `NewFSNode` constructor should be used instead of just calling `new(FSNode)`
|
||||
// to guarantee that the required (`Type` and `Filesize`) fields in the `format`
|
||||
// structure are initialized before marshaling (in `GetBytes()`).
|
||||
type FSNode struct {
|
||||
Data []byte
|
||||
|
||||
// total data size for each child
|
||||
blocksizes []uint64
|
||||
|
||||
// running sum of blocksizes
|
||||
subtotal uint64
|
||||
|
||||
// node type of this node
|
||||
Type pb.Data_DataType
|
||||
// UnixFS format defined as a protocol buffers message.
|
||||
format pb.Data
|
||||
}
|
||||
|
||||
// FSNodeFromBytes unmarshal a protobuf message onto an FSNode.
|
||||
func FSNodeFromBytes(b []byte) (*FSNode, error) {
|
||||
pbn := new(pb.Data)
|
||||
err := proto.Unmarshal(b, pbn)
|
||||
n := new(FSNode)
|
||||
err := proto.Unmarshal(b, &n.format)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
n := new(FSNode)
|
||||
n.Data = pbn.Data
|
||||
n.blocksizes = pbn.Blocksizes
|
||||
n.subtotal = pbn.GetFilesize() - uint64(len(n.Data))
|
||||
n.Type = pbn.GetType()
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// NewFSNode creates a new FSNode structure with the given `dataType`.
|
||||
//
|
||||
// It initializes the (required) `Type` field (that doesn't have a `Set()`
|
||||
// accessor so it must be specified at creation), otherwise the `Marshal()`
|
||||
// method in `GetBytes()` would fail (`required field "Type" not set`).
|
||||
//
|
||||
// It also initializes the `Filesize` pointer field to ensure its value
|
||||
// is never nil before marshaling, this is not a required field but it is
|
||||
// done to be backwards compatible with previous `go-ipfs` versions hash.
|
||||
// (If it wasn't initialized there could be cases where `Filesize` could
|
||||
// have been left at nil, when the `FSNode` was created but no data or
|
||||
// child nodes were set to adjust it, as is the case in `NewLeaf()`.)
|
||||
func NewFSNode(dataType pb.Data_DataType) *FSNode {
|
||||
n := new(FSNode)
|
||||
n.format.Type = &dataType
|
||||
|
||||
// Initialize by `Filesize` by updating it with a dummy (zero) value.
|
||||
n.UpdateFilesize(0)
|
||||
|
||||
return n
|
||||
}
|
||||
|
||||
// AddBlockSize adds the size of the next child block of this node
|
||||
func (n *FSNode) AddBlockSize(s uint64) {
|
||||
n.subtotal += s
|
||||
n.blocksizes = append(n.blocksizes, s)
|
||||
n.UpdateFilesize(int64(s))
|
||||
n.format.Blocksizes = append(n.format.Blocksizes, s)
|
||||
}
|
||||
|
||||
// RemoveBlockSize removes the given child block's size.
|
||||
func (n *FSNode) RemoveBlockSize(i int) {
|
||||
n.subtotal -= n.blocksizes[i]
|
||||
n.blocksizes = append(n.blocksizes[:i], n.blocksizes[i+1:]...)
|
||||
n.UpdateFilesize(-int64(n.format.Blocksizes[i]))
|
||||
n.format.Blocksizes = append(n.format.Blocksizes[:i], n.format.Blocksizes[i+1:]...)
|
||||
}
|
||||
|
||||
// GetBytes marshals this node as a protobuf message.
|
||||
func (n *FSNode) GetBytes() ([]byte, error) {
|
||||
pbn := new(pb.Data)
|
||||
pbn.Type = &n.Type
|
||||
pbn.Filesize = proto.Uint64(uint64(len(n.Data)) + n.subtotal)
|
||||
pbn.Blocksizes = n.blocksizes
|
||||
pbn.Data = n.Data
|
||||
return proto.Marshal(pbn)
|
||||
return proto.Marshal(&n.format)
|
||||
}
|
||||
|
||||
// FileSize returns the total size of this tree. That is, the size of
|
||||
// the data in this node plus the size of all its children.
|
||||
func (n *FSNode) FileSize() uint64 {
|
||||
return uint64(len(n.Data)) + n.subtotal
|
||||
return n.format.GetFilesize()
|
||||
}
|
||||
|
||||
// NumChildren returns the number of child blocks of this node
|
||||
func (n *FSNode) NumChildren() int {
|
||||
return len(n.blocksizes)
|
||||
return len(n.format.Blocksizes)
|
||||
}
|
||||
|
||||
// GetData retrieves the `Data` field from the internal `format`.
|
||||
func (n *FSNode) GetData() []byte {
|
||||
return n.format.GetData()
|
||||
}
|
||||
|
||||
// SetData sets the `Data` field from the internal `format`
|
||||
// updating its `Filesize`.
|
||||
func (n *FSNode) SetData(newData []byte) {
|
||||
n.UpdateFilesize(int64(len(newData) - len(n.GetData())))
|
||||
n.format.Data = newData
|
||||
}
|
||||
|
||||
// UpdateFilesize updates the `Filesize` field from the internal `format`
|
||||
// by a signed difference (`filesizeDiff`).
|
||||
// TODO: Add assert to check for `Filesize` > 0?
|
||||
func (n *FSNode) UpdateFilesize(filesizeDiff int64) {
|
||||
n.format.Filesize = proto.Uint64(uint64(
|
||||
int64(n.format.GetFilesize()) + filesizeDiff))
|
||||
}
|
||||
|
||||
// GetType retrieves the `Type` field from the internal `format`.
|
||||
func (n *FSNode) GetType() pb.Data_DataType {
|
||||
return n.format.GetType()
|
||||
}
|
||||
|
||||
// Metadata is used to store additional FSNode information.
|
||||
|
@ -10,14 +10,13 @@ import (
|
||||
)
|
||||
|
||||
func TestFSNode(t *testing.T) {
|
||||
fsn := new(FSNode)
|
||||
fsn.Type = TFile
|
||||
fsn := NewFSNode(TFile)
|
||||
for i := 0; i < 16; i++ {
|
||||
fsn.AddBlockSize(100)
|
||||
}
|
||||
fsn.RemoveBlockSize(15)
|
||||
|
||||
fsn.Data = make([]byte, 128)
|
||||
fsn.SetData(make([]byte, 128))
|
||||
|
||||
b, err := fsn.GetBytes()
|
||||
if err != nil {
|
||||
|
Reference in New Issue
Block a user