use BigEndian.Append funcs and change MarshalSize semantics to include the whole packet
diff --git a/encoding/ssh/filexfer/attrs.go b/encoding/ssh/filexfer/attrs.go index a1aec30..5054d6d 100644 --- a/encoding/ssh/filexfer/attrs.go +++ b/encoding/ssh/filexfer/attrs.go
@@ -2,6 +2,7 @@ import ( "io/fs" + "iter" "path" "time" ) @@ -212,29 +213,30 @@ // MarshalSize returns the number of bytes the attributes would marshal into. func (a *Attributes) MarshalSize() int { - length := 4 + // uint32(flags) + size := 4 if a.HasSize() { - length += 8 + size += 8 // uint64(size) } if a.HasUserGroup() { - length += 4 + 4 + size += 4 + 4 // uint32(uid) + uint32(gid) } if a.HasPermissions() { - length += 4 + size += 4 // uint32(permissions) } if a.HasACModTime() { - length += 4 + 4 + size += 4 + 4 // uint32(atime) + uint32(mtime) } if a.HasExtended() { - length += a.Extended.MarshalSize() + size += a.Extended.MarshalSize() } - return length + return size } // MarshalInto marshals the attributes onto the end of the buffer. @@ -266,7 +268,7 @@ // MarshalBinary returns the binary encoding of attributes. func (a *Attributes) MarshalBinary() ([]byte, error) { - buf := NewBuffer(make([]byte, 0, a.MarshalSize())) + buf := NewMarshalBuffer(a.MarshalSize()) a.MarshalInto(buf) return buf.Bytes(), nil } @@ -319,18 +321,19 @@ // MarshalSize returns the number of bytes the extended attributes would marshal into. func (a ExtendedAttributes) MarshalSize() int { - length := 4 + // uint32(extended_count) + size := 4 for _, ext := range a { - length += ext.MarshalSize() + size += ext.MarshalSize() } - return length + return size } // MarshalInto marshals the extended attributes onto the end of the buffer. func (a ExtendedAttributes) MarshalInto(buf *Buffer) { - buf.AppendUint32(uint32(len(a))) + buf.AppendCount(len(a)) for _, ext := range a { ext.MarshalInto(buf) @@ -339,7 +342,7 @@ // MarshalBinary returns the binary encoding of the extended attributes. func (a ExtendedAttributes) MarshalBinary() ([]byte, error) { - buf := NewBuffer(make([]byte, 0, a.MarshalSize())) + buf := NewMarshalBuffer(a.MarshalSize()) a.MarshalInto(buf) return buf.Bytes(), nil } @@ -411,20 +414,24 @@ return "", false } -// Seq is an iterator that yields the type field from each extended attribute. -func (a ExtendedAttributes) Seq(yield func(string) bool) { - for _, ext := range a { - if !yield(ext.Type) { - return +// Types returns an iterator that yields the type field from each extended attribute. +func (a ExtendedAttributes) Types() iter.Seq[string] { + return func(yield func(string) bool) { + for _, ext := range a { + if !yield(ext.Type) { + return + } } } } -// Seq2 is an iterator that yields the type and data fields from each extended attribute. -func (a ExtendedAttributes) Seq2(yield func(string, string) bool) { - for _, ext := range a { - if !yield(ext.Type, ext.Data) { - return +// All returns an iterator that yields the type and data fields from each extended attribute. +func (a ExtendedAttributes) All() iter.Seq2[string, string] { + return func(yield func(string, string) bool) { + for _, ext := range a { + if !yield(ext.Type, ext.Data) { + return + } } } } @@ -451,7 +458,7 @@ // MarshalBinary returns the binary encoding of the extended attribute. func (e *ExtendedAttribute) MarshalBinary() ([]byte, error) { - buf := NewBuffer(make([]byte, 0, e.MarshalSize())) + buf := NewMarshalBuffer(e.MarshalSize()) e.MarshalInto(buf) return buf.Bytes(), nil } @@ -539,7 +546,7 @@ // MarshalBinary returns the binary encoding of the name entry. func (e *NameEntry) MarshalBinary() ([]byte, error) { - buf := NewBuffer(make([]byte, 0, e.MarshalSize())) + buf := NewMarshalBuffer(e.MarshalSize()) e.MarshalInto(buf) return buf.Bytes(), nil }
diff --git a/encoding/ssh/filexfer/buffer.go b/encoding/ssh/filexfer/buffer.go index d2450a6..0d8cec1 100644 --- a/encoding/ssh/filexfer/buffer.go +++ b/encoding/ssh/filexfer/buffer.go
@@ -38,9 +38,9 @@ } // NewMarshalBuffer creates a new buffer ready to start marshaling a Packet into. -// It preallocates enough space for uint32(length), and size more bytes. +// It preallocates enough capacity for size bytes. func NewMarshalBuffer(size int) *Buffer { - return NewBuffer(make([]byte, 4+size)) + return NewBuffer(make([]byte, 0, size)) } // Bytes returns a slice of length b.Len() holding the unconsumed bytes in the buffer. @@ -131,8 +131,8 @@ return 0 } - var v uint8 - v, b.off = b.b[b.off], b.off+1 + v := b.b[b.off] + b.off++ return v } @@ -171,10 +171,7 @@ // AppendUint16 appends single uint16 into the buffer, in network byte order (big-endian). func (b *Buffer) AppendUint16(v uint16) { - b.b = append(b.b, - byte(v>>8), - byte(v>>0), - ) + b.b = binary.BigEndian.AppendUint16(b.b, v) } // unmarshalPacketLength is used internally to read the packet length. @@ -198,14 +195,9 @@ // AppendUint32 appends a single uint32 into the buffer, in network byte order (big-endian). func (b *Buffer) AppendUint32(v uint32) { - b.b = append(b.b, - byte(v>>24), - byte(v>>16), - byte(v>>8), - byte(v>>0), - ) + b.b = binary.BigEndian.AppendUint32(b.b, v) } - +//*/ // ConsumeCount consumes a single uint32 count from the buffer, in network byte order (big-endian) as an int. // If the buffer does not have enough data, it will set Err to ErrShortPacket. func (b *Buffer) ConsumeCount() (int, error) { @@ -232,16 +224,7 @@ // AppendUint64 appends a single uint64 into the buffer, in network byte order (big-endian). func (b *Buffer) AppendUint64(v uint64) { - b.b = append(b.b, - byte(v>>56), - byte(v>>48), - byte(v>>40), - byte(v>>32), - byte(v>>24), - byte(v>>16), - byte(v>>8), - byte(v>>0), - ) + b.b = binary.BigEndian.AppendUint64(b.b, v) } // ConsumeInt64 consumes a single int64 from the buffer, in network byte order (big-endian) with two’s complement. @@ -257,7 +240,8 @@ // ConsumeBytes consumes a single string of raw binary data from the buffer. // A string is a uint32 length, followed by that number of raw bytes. -// If the buffer does not have enough data, it will set Err to ErrShortPacket. +// If the buffer does not have enough data, it will set Err to ErrShortPacket, +// and return as much data as is available. // // The returned slice aliases the buffer contents, and is valid only as long as the buffer is not reused; // that is, only until the next call to [Reset], [PutLength], [StartPacket], or [UnmarshalBinary]. @@ -265,18 +249,20 @@ // In no case will consuming calls return overlapping slice aliases, // and append calls are guaranteed to not disturb this slice alias. func (b *Buffer) ConsumeBytes() []byte { - length := int(b.ConsumeUint32()) + length, _ := b.ConsumeCount() if length == 0 { - // Short-circuit empty strings. - return nil - } - - if !b.checkLen(length) { + // Short-circuit empty strings, or errors from ConsumeCount. return nil } v := b.b[b.off:] + + if !b.checkLen(length) { + // Return whatever was left, this might possibly help with debugging. + return slices.Clip(v) + } + if len(v) > length || cap(v) > length { v = slices.Clip(v[:length]) } @@ -311,7 +297,7 @@ // uint32(length) + raw(data) b.Grow(4 + len(v)) // ensure at most one allocation - b.AppendUint32(uint32(len(v))) + b.AppendCount(len(v)) b.b = append(b.b, v...) } @@ -342,8 +328,8 @@ binary.BigEndian.PutUint32(b.b, uint32(size)) } -// MarshalSize returns the number of bytes that the packet would marshal into. -// This excludes the uint32(length). +// MarshalSize returns the number of bytes that the buffer would marshal into. +// This is the whole size of the buffer, including any uint32(length) that might exist. func (b *Buffer) MarshalSize() int { // raw(data) return len(b.b) @@ -356,7 +342,8 @@ // UnmarshalBinary sets the internal buffer of b to be a clone of data, and zeros the internal offset. func (b *Buffer) UnmarshalBinary(data []byte) error { - b.b = append(b.b[:0], data...) - b.off = 0 + *b = Buffer{ + b: append(b.b[:0], data...), + } return nil }
diff --git a/encoding/ssh/filexfer/buffer_test.go b/encoding/ssh/filexfer/buffer_test.go new file mode 100644 index 0000000..9f35dc7 --- /dev/null +++ b/encoding/ssh/filexfer/buffer_test.go
@@ -0,0 +1,21 @@ +package sshfx + +import ( + "testing" +) + +func BenchmarkAppendCount(b *testing.B) { + buf := NewBuffer(make([]byte, 0, b.N*4)) + + for i := range b.N { + buf.AppendCount(i) + } +} + +func BenchmarkAppendString(b *testing.B) { + buf := NewBuffer(make([]byte, 0, b.N*(4+3))) + + for range b.N { + buf.AppendString("foo") + } +}
diff --git a/encoding/ssh/filexfer/extended_packets.go b/encoding/ssh/filexfer/extended_packets.go index b44b202..d80fb03 100644 --- a/encoding/ssh/filexfer/extended_packets.go +++ b/encoding/ssh/filexfer/extended_packets.go
@@ -96,10 +96,9 @@ } // MarshalSize returns the number of bytes that the packet would marshal into. -// This excludes the uint32(length). func (p *ExtendedPacket) MarshalSize() int { - // uint8(type) + uint32(request-id) + string(extended-request) - size := 1 + 4 + 4 + len(p.ExtendedRequest) + // uint32(length) + uint8(type) + uint32(request-id) + string(extended-request) + size := 4 + 1 + 4 + 4 + len(p.ExtendedRequest) if p.Data != nil { size += p.Data.MarshalSize() } @@ -158,10 +157,9 @@ } // MarshalSize returns the number of bytes that the packet would marshal into. -// This excludes the uint32(length). func (p *ExtendedReplyPacket) MarshalSize() int { - // uint8(type) + uint32(request-id) - size := 1 + 4 + // uint32(length) + uint8(type) + uint32(request-id) + size := 4 + 1 + 4 if p.Data != nil { size += p.Data.MarshalSize() }
diff --git a/encoding/ssh/filexfer/extended_packets_test.go b/encoding/ssh/filexfer/extended_packets_test.go index 9d564fb..e097e5b 100644 --- a/encoding/ssh/filexfer/extended_packets_test.go +++ b/encoding/ssh/filexfer/extended_packets_test.go
@@ -9,10 +9,18 @@ value uint8 } +func (d *testExtendedData) Type() PacketType { + return PacketTypeExtended +} + func (d *testExtendedData) MarshalSize() int { return 1 } +func (d *testExtendedData) ExtendedRequest() string { + return "bar@example" +} + func (d *testExtendedData) MarshalBinary() ([]byte, error) { buf := NewBuffer(make([]byte, 0, d.MarshalSize())) @@ -34,6 +42,8 @@ return nil } +var _ ExtendedData = &testExtendedData{} + var _ Packet = &ExtendedPacket{} func TestExtendedPacketNoData(t *testing.T) { @@ -81,7 +91,7 @@ func TestExtendedPacketTestData(t *testing.T) { const ( id = 42 - extendedRequest = "foo@example" + extendedRequest = "bar@example" textValue = 13 ) @@ -109,7 +119,7 @@ 0x00, 0x00, 0x00, 21, 200, 0x00, 0x00, 0x00, 42, - 0x00, 0x00, 0x00, 11, 'f', 'o', 'o', '@', 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x00, 0x00, 0x00, 11, 'b', 'a', 'r', '@', 'e', 'x', 'a', 'm', 'p', 'l', 'e', 0x27, } @@ -117,6 +127,7 @@ t.Fatalf("MarshalPacket() = %X, but wanted %X", buf, want) } + // Even when unregistered, if we give a hint type, it should work. *p = ExtendedPacket{ Data: new(testExtendedData), } @@ -137,6 +148,9 @@ t.Errorf("UnmarshalPacketBody(): Data.value was %#x, but expected %#x", buf.value, value) } + // Test that when rregistered without a hint type, it should work. + RegisterExtendedPacketType[testExtendedData]() + *p = ExtendedPacket{} // UnmarshalPacketBody assumes the (length, type, request-id) have already been consumed. @@ -148,7 +162,88 @@ t.Errorf("UnmarshalPacketBody(): ExtendedRequest was %q, but expected %q", p.ExtendedRequest, extendedRequest) } - wantBuffer := []byte{0x27} + if buf, ok := p.Data.(*testExtendedData); !ok { + t.Errorf("UnmarshalPacketBody(): Data was type %T, but expected %T", p.Data, buf) + + } else if buf.value != value { + t.Errorf("UnmarshalPacketBody(): Data.value was %#x, but expected %#x", buf.value, value) + } + + // Test that even registered, a specified data hint will override it. + *p = ExtendedPacket{ + Data: new(Buffer), + } + + // UnmarshalPacketBody assumes the (length, type, request-id) have already been consumed. + if err := p.UnmarshalPacketBody(NewBuffer(buf[9:])); err != nil { + t.Fatal("unexpected error:", err) + } + + if p.ExtendedRequest != extendedRequest { + t.Errorf("UnmarshalPacketBody(): ExtendedRequest was %q, but expected %q", p.ExtendedRequest, extendedRequest) + } + + wantBuffer := []byte{ textValue^0x2a } + + if buf, ok := p.Data.(*Buffer); !ok { + t.Errorf("UnmarshalPacketBody(): Data was type %T, but expected %T", p.Data, buf) + + } else if !bytes.Equal(buf.b, wantBuffer) { + t.Errorf("UnmarshalPacketBody(): Data was %X, but expected %X", buf.b, wantBuffer) + } +} + +func TestExtendedPacketTestBuffer(t *testing.T) { + const ( + id = 42 + extendedRequest = "undef@example" + textValue = 13 + ) + + const value = 13 + + p := &ExtendedPacket{ + ExtendedRequest: extendedRequest, + Data: &Buffer{ + b: []byte("\x00\x00\x00\x03bar"), + }, + } + + expectAllocs(t, 2, func() { + // header should be allocated with enough space to cover the test data, + // but test data will still be separately allocated. + _, _ = ComposePacket(p.MarshalPacket(id, nil)) + }) + + buf, err := ComposePacket(p.MarshalPacket(id, nil)) + if err != nil { + t.Fatal("unexpected error:", err) + } + + want := []byte{ + 0x00, 0x00, 0x00, 29, + 200, + 0x00, 0x00, 0x00, 42, + 0x00, 0x00, 0x00, 13, 'u', 'n', 'd', 'e', 'f', '@', 'e', 'x', 'a', 'm', 'p', 'l', 'e', + 0x00, 0x00, 0x00, 0x03, 'b', 'a', 'r', + } + + if !bytes.Equal(buf, want) { + t.Fatalf("MarshalPacket() = %X, but wanted %X", buf, want) + } + + *p = ExtendedPacket{} + + // UnmarshalPacketBody assumes the (length, type, request-id) have already been consumed. + if err := p.UnmarshalPacketBody(NewBuffer(buf[9:])); err != nil { + t.Fatal("unexpected error:", err) + } + + if p.ExtendedRequest != extendedRequest { + t.Errorf("UnmarshalPacketBody(): ExtendedRequest was %q, but expected %q", p.ExtendedRequest, extendedRequest) + } + + wantBuffer := []byte{ 0x00, 0x00, 0x00, 0x03, 'b', 'a', 'r' } if buf, ok := p.Data.(*Buffer); !ok { t.Errorf("UnmarshalPacketBody(): Data was type %T, but expected %T", p.Data, buf)
diff --git a/encoding/ssh/filexfer/extensions.go b/encoding/ssh/filexfer/extensions.go index ccc6765..1c22ff8 100644 --- a/encoding/ssh/filexfer/extensions.go +++ b/encoding/ssh/filexfer/extensions.go
@@ -11,6 +11,7 @@ // MarshalSize returns the number of bytes e would marshal into. func (e *ExtensionPair) MarshalSize() int { + // string(name) + string(data) return 4 + len(e.Name) + 4 + len(e.Data) }
diff --git a/encoding/ssh/filexfer/handle_packets.go b/encoding/ssh/filexfer/handle_packets.go index c041eda..79458c2 100644 --- a/encoding/ssh/filexfer/handle_packets.go +++ b/encoding/ssh/filexfer/handle_packets.go
@@ -11,10 +11,9 @@ } // MarshalSize returns the number of bytes that the packet would marshal into. -// This excludes the uint32(length). func (p *ClosePacket) MarshalSize() int { - // uint8(type) + uint32(request-id) + string(handle) - return 1 + 4 + 4 + len(p.Handle) + // uint32(length) + uint8(type) + uint32(request-id) + string(handle) + return 4 + 1 + 4 + 4 + len(p.Handle) } // GetHandle returns the handle field of the packet. @@ -58,10 +57,9 @@ } // MarshalSize returns the number of bytes that the packet would marshal into. -// This excludes the uint32(length). func (p *ReadPacket) MarshalSize() int { - // uint8(type) + uint32(request-id) + string(handle) + uint64(offset) + uint32(len) - return 1 + 4 + 4 + len(p.Handle) + 8 + 4 + // uint32(length) + uint8(type) + uint32(request-id) + string(handle) + uint64(offset) + uint32(len) + return 4 + 1 + 4 + 4 + len(p.Handle) + 8 + 4 } // GetHandle returns the handle field of the packet. @@ -109,10 +107,9 @@ } // MarshalSize returns the number of bytes that the packet would marshal into. -// This excludes the uint32(length). func (p *WritePacket) MarshalSize() int { - // uint8(type) + uint32(request-id) + string(handle) + uint64(offset) + bytes(data) - return 1 + 4 + 4 + len(p.Handle) + 8 + 4 + len(p.Data) + // uint32(length) + uint8(type) + uint32(request-id) + string(handle) + uint64(offset) + bytes(data) + return 4 + 1 + 4 + 4 + len(p.Handle) + 8 + 4 + len(p.Data) } // GetHandle returns the handle field of the packet. @@ -169,10 +166,9 @@ } // MarshalSize returns the number of bytes that the packet would marshal into. -// This excludes the uint32(length). func (p *FStatPacket) MarshalSize() int { - // uint8(type) + uint32(request-id) + string(handle) - return 1 + 4 + 4 + len(p.Handle) + // uint32(length) + uint8(type) + uint32(request-id) + string(handle) + return 4 + 1 + 4 + 4 + len(p.Handle) } // GetHandle returns the handle field of the packet. @@ -215,10 +211,9 @@ } // MarshalSize returns the number of bytes that the packet would marshal into. -// This excludes the uint32(length). func (p *FSetStatPacket) MarshalSize() int { - // uint8(type) + uint32(request-id) + string(handle) ATTRS(attrs) - return 1 + 4 + 4 + len(p.Handle) + p.Attrs.MarshalSize() + // uint32(length) + uint8(type) + uint32(request-id) + string(handle) ATTRS(attrs) + return 4 + 1 + 4 + 4 + len(p.Handle) + p.Attrs.MarshalSize() } // GetHandle returns the handle field of the packet. @@ -262,10 +257,9 @@ } // MarshalSize returns the number of bytes that the packet would marshal into. -// This excludes the uint32(length). func (p *ReadDirPacket) MarshalSize() int { - // uint8(type) + uint32(request-id) + string(handle) - return 1 + 4 + 4 + len(p.Handle) + // uint32(length) + uint8(type) + uint32(request-id) + string(handle) + return 4 + 1 + 4 + 4 + len(p.Handle) } // GetHandle returns the handle field of the packet.
diff --git a/encoding/ssh/filexfer/init_packets.go b/encoding/ssh/filexfer/init_packets.go index d3fc578..8cd739d 100644 --- a/encoding/ssh/filexfer/init_packets.go +++ b/encoding/ssh/filexfer/init_packets.go
@@ -11,15 +11,25 @@ Extensions []*ExtensionPair } -// MarshalBinary returns p as the binary encoding of p. -func (p *InitPacket) MarshalBinary() ([]byte, error) { - size := 1 + 4 // byte(type) + uint32(version) +// MarshalSize returns the number of bytes that the packet would marshal into. +func (p *InitPacket) MarshalSize() int { + // uint32(length) + byte(type) + uint32(version) + size := 4 + 1 + 4 for _, ext := range p.Extensions { size += ext.MarshalSize() } - b := NewBuffer(make([]byte, 4, 4+size)) + return size +} + +// MarshalBinary returns p as the binary encoding of p. +func (p *InitPacket) MarshalBinary() ([]byte, error) { + b := NewMarshalBuffer(p.MarshalSize()) + + b.Reset() + + b.AppendUint32(uint32(0)) // will be overwritten with size. b.AppendUint8(uint8(PacketTypeInit)) b.AppendUint32(p.Version) @@ -27,9 +37,8 @@ ext.MarshalInto(b) } - b.PutLength(size) - - return b.Bytes(), nil + data, _, _ := b.Packet(nil) + return data, nil } // UnmarshalBinary unmarshals a full raw packet out of the given data. @@ -99,15 +108,25 @@ Extensions []*ExtensionPair } -// MarshalBinary returns p as the binary encoding of p. -func (p *VersionPacket) MarshalBinary() ([]byte, error) { - size := 1 + 4 // byte(type) + uint32(version) +// MarshalSize returns the number of bytes that the packet would marshal into. +func (p *VersionPacket) MarshalSize() int { + // uint32(length) + byte(type) + uint32(version) + size := 4 + 1 + 4 for _, ext := range p.Extensions { size += ext.MarshalSize() } - b := NewBuffer(make([]byte, 4, 4+size)) + return size +} + +// MarshalBinary returns p as the binary encoding of p. +func (p *VersionPacket) MarshalBinary() ([]byte, error) { + b := NewMarshalBuffer(p.MarshalSize()) + + b.Reset() + + b.AppendUint32(uint32(0)) // will be overwritten with size. b.AppendUint8(uint8(PacketTypeVersion)) b.AppendUint32(p.Version) @@ -115,9 +134,8 @@ ext.MarshalInto(b) } - b.PutLength(size) - - return b.Bytes(), nil + data, _, _ := b.Packet(nil) + return data, nil } // UnmarshalBinary unmarshals a full raw packet out of the given data.
diff --git a/encoding/ssh/filexfer/open_packets.go b/encoding/ssh/filexfer/open_packets.go index 2cc64bf..ab9f1b5 100644 --- a/encoding/ssh/filexfer/open_packets.go +++ b/encoding/ssh/filexfer/open_packets.go
@@ -23,10 +23,9 @@ } // MarshalSize returns the number of bytes that the packet would marshal into. -// This excludes the uint32(length). func (p *OpenPacket) MarshalSize() int { - // uint8(type) + uint32(request-id) + string(filename) + uint32(pflags) + ATTRS(attrs) - return 1 + 4 + 4 + len(p.Filename) + 4 + p.Attrs.MarshalSize() + // uint32(length) + uint8(type) + uint32(request-id) + string(filename) + uint32(pflags) + ATTRS(attrs) + return 4 + 1 + 4 + 4 + len(p.Filename) + 4 + p.Attrs.MarshalSize() } // MarshalPacket returns p as a two-part binary encoding of p. @@ -67,10 +66,9 @@ } // MarshalSize returns the number of bytes that the packet would marshal into. -// This excludes the uint32(length). func (p *OpenDirPacket) MarshalSize() int { - // uint8(type) + uint32(path) string(filename) - return 1 + 4 + 4 + len(p.Path) + // uint32(length) + uint8(type) + uint32(path) string(filename) + return 4 + 1 + 4 + 4 + len(p.Path) } // MarshalPacket returns p as a two-part binary encoding of p.
diff --git a/encoding/ssh/filexfer/openssh/fsync.go b/encoding/ssh/filexfer/openssh/fsync.go index 2446afa..d314f1f 100644 --- a/encoding/ssh/filexfer/openssh/fsync.go +++ b/encoding/ssh/filexfer/openssh/fsync.go
@@ -24,8 +24,7 @@ return sshfx.PacketTypeExtended } -// MarshalSize returns the number of bytes that the packet would marshal into. -// This excludes the uint32(length). +// MarshalSize returns the number of bytes that the extended request data would marshal into. func (ep *FSyncExtendedPacket) MarshalSize() int { // string(handle) return 4 + len(ep.Handle) @@ -60,8 +59,7 @@ // // NOTE: This _only_ encodes the packet-specific data, it does not encode the full extended packet. func (ep *FSyncExtendedPacket) MarshalBinary() ([]byte, error) { - - buf := sshfx.NewBuffer(make([]byte, 0, ep.MarshalSize())) + buf := sshfx.NewMarshalBuffer(ep.MarshalSize()) ep.MarshalInto(buf) return buf.Bytes(), nil }
diff --git a/encoding/ssh/filexfer/openssh/hardlink.go b/encoding/ssh/filexfer/openssh/hardlink.go index 65b2850..ece8085 100644 --- a/encoding/ssh/filexfer/openssh/hardlink.go +++ b/encoding/ssh/filexfer/openssh/hardlink.go
@@ -25,8 +25,7 @@ return sshfx.PacketTypeExtended } -// MarshalSize returns the number of bytes that the packet would marshal into. -// This excludes the uint32(length). +// MarshalSize returns the number of bytes that the extended request data would marshal into. func (ep *HardlinkExtendedPacket) MarshalSize() int { // string(oldpath) + string(newpath) return 4 + len(ep.OldPath) + 4 + len(ep.NewPath) @@ -57,7 +56,7 @@ // // NOTE: This _only_ encodes the packet-specific data, it does not encode the full extended packet. func (ep *HardlinkExtendedPacket) MarshalBinary() ([]byte, error) { - buf := sshfx.NewBuffer(make([]byte, 0, ep.MarshalSize())) + buf := sshfx.NewMarshalBuffer(ep.MarshalSize()) ep.MarshalInto(buf) return buf.Bytes(), nil }
diff --git a/encoding/ssh/filexfer/openssh/posix-rename.go b/encoding/ssh/filexfer/openssh/posix-rename.go index ad67ef6..fd1d074 100644 --- a/encoding/ssh/filexfer/openssh/posix-rename.go +++ b/encoding/ssh/filexfer/openssh/posix-rename.go
@@ -25,8 +25,7 @@ return sshfx.PacketTypeExtended } -// MarshalSize returns the number of bytes that the packet would marshal into. -// This excludes the uint32(length). +// MarshalSize returns the number of bytes that the extended request data would marshal into. func (ep *POSIXRenameExtendedPacket) MarshalSize() int { // string(oldpath) + string(newpath) return 4 + len(ep.OldPath) + 4 + len(ep.NewPath) @@ -57,7 +56,7 @@ // // NOTE: This _only_ encodes the packet-specific data, it does not encode the full extended packet. func (ep *POSIXRenameExtendedPacket) MarshalBinary() ([]byte, error) { - buf := sshfx.NewBuffer(make([]byte, 0, ep.MarshalSize())) + buf := sshfx.NewMarshalBuffer(ep.MarshalSize()) ep.MarshalInto(buf) return buf.Bytes(), nil }
diff --git a/encoding/ssh/filexfer/openssh/statvfs.go b/encoding/ssh/filexfer/openssh/statvfs.go index a2d23a9..33f2dcc 100644 --- a/encoding/ssh/filexfer/openssh/statvfs.go +++ b/encoding/ssh/filexfer/openssh/statvfs.go
@@ -24,8 +24,7 @@ return sshfx.PacketTypeExtended } -// MarshalSize returns the number of bytes that the packet would marshal into. -// This excludes the uint32(length). +// MarshalSize returns the number of bytes that the extended request data would marshal into. func (ep *StatVFSExtendedPacket) MarshalSize() int { // string(path) return 4 + len(ep.Path) @@ -55,10 +54,8 @@ // // NOTE: This _only_ encodes the packet-specific data, it does not encode the full extended packet. func (ep *StatVFSExtendedPacket) MarshalBinary() ([]byte, error) { - buf := sshfx.NewBuffer(make([]byte, 0, ep.MarshalSize())) - + buf := sshfx.NewMarshalBuffer(ep.MarshalSize()) ep.MarshalInto(buf) - return buf.Bytes(), nil } @@ -96,8 +93,7 @@ return sshfx.PacketTypeExtended } -// MarshalSize returns the number of bytes that the packet would marshal into. -// This excludes the uint32(length). +// MarshalSize returns the number of bytes that the extended request data would marshal into. func (ep *FStatVFSExtendedPacket) MarshalSize() int { // string(handle) return 4 + len(ep.Handle) @@ -132,10 +128,8 @@ // // NOTE: This _only_ encodes the packet-specific data, it does not encode the full extended packet. func (ep *FStatVFSExtendedPacket) MarshalBinary() ([]byte, error) { - buf := sshfx.NewBuffer(make([]byte, 0, ep.MarshalSize())) - + buf := sshfx.NewMarshalBuffer(ep.MarshalSize()) ep.MarshalInto(buf) - return buf.Bytes(), nil } @@ -180,8 +174,7 @@ return sshfx.PacketTypeExtendedReply } -// MarshalSize returns the number of bytes that the packet would marshal into. -// This excludes the uint32(length). +// MarshalSize returns the number of bytes that the extended request data would marshal into. func (ep *StatVFSExtendedReplyPacket) MarshalSize() int { // 11 times uint64(fields) return 11 * 8 @@ -222,9 +215,9 @@ // // NOTE: This _only_ encodes the packet-specific data, it does not encode the full extended reply packet. func (ep *StatVFSExtendedReplyPacket) MarshalBinary() ([]byte, error) { - b := sshfx.NewBuffer(make([]byte, 0, ep.MarshalSize())) - ep.MarshalInto(b) - return b.Bytes(), nil + buf := sshfx.NewMarshalBuffer(ep.MarshalSize()) + ep.MarshalInto(buf) + return buf.Bytes(), nil } // UnmarshalFrom decodes the fstatvfs@openssh.com extended reply packet-specific data into ep.
diff --git a/encoding/ssh/filexfer/packets.go b/encoding/ssh/filexfer/packets.go index 101d826..344b0bc 100644 --- a/encoding/ssh/filexfer/packets.go +++ b/encoding/ssh/filexfer/packets.go
@@ -32,10 +32,9 @@ } // MarshalSize returns the number of bytes that the packet would marshal into. -// This excludes the uint32(length). func (p *RawPacket) MarshalSize() int { - // uint8(type) + uint32(request-id) + raw(buffer) - return 1 + 4 + p.Data.MarshalSize() + // uint32(length) + uint8(type) + uint32(request-id) + raw(buffer) + return 4 + 1 + 4 + p.Data.MarshalSize() } // Reset clears the pointers and reference-semantic variables of RawPacket, @@ -231,14 +230,13 @@ } // MarshalSize returns the number of bytes that the packet would marshal into. -// This excludes the uint32(length). func (p *RequestPacket) MarshalSize() int { if p.Request == nil { - // uint8(type) + uint32(request-id) - return 1 + 4 + // uint32(length) + uint8(type) + uint32(request-id) + return 4 + 1 + 4 } - return 5 // p.Request.MarshalSize() TODO + return p.Request.MarshalSize() } // Reset clears the pointers and reference-semantic variables in RequestPacket,
diff --git a/encoding/ssh/filexfer/path_packets.go b/encoding/ssh/filexfer/path_packets.go index 70b9a38..7cee10e 100644 --- a/encoding/ssh/filexfer/path_packets.go +++ b/encoding/ssh/filexfer/path_packets.go
@@ -11,10 +11,9 @@ } // MarshalSize returns the number of bytes that the packet would marshal into. -// This excludes the uint32(length). func (p *LStatPacket) MarshalSize() int { - // uint8(type) + uint32(request-id) + string(path) - return 1 + 4 + 4 + len(p.Path) + // uint32(length) + uint8(type) + uint32(request-id) + string(path) + return 4 + 1 + 4 + 4 + len(p.Path) } // MarshalPacket returns p as a two-part binary encoding of p. @@ -52,10 +51,9 @@ } // MarshalSize returns the number of bytes that the packet would marshal into. -// This excludes the uint32(length). func (p *SetStatPacket) MarshalSize() int { - // uint8(type) + uint32(request-id) + string(path) + ATTRS(attrs) - return 1 + 4 + 4 + len(p.Path) + p.Attrs.MarshalSize() + // uint32(length) + uint8(type) + uint32(request-id) + string(path) + ATTRS(attrs) + return 4 + 1 + 4 + 4 + len(p.Path) + p.Attrs.MarshalSize() } // MarshalPacket returns p as a two-part binary encoding of p. @@ -94,10 +92,9 @@ } // MarshalSize returns the number of bytes that the packet would marshal into. -// This excludes the uint32(length). func (p *RemovePacket) MarshalSize() int { - // uint8(type) + uint32(request-id) + string(path) - return 1 + 4 + 4 + len(p.Path) + // uint32(length) + uint8(type) + uint32(request-id) + string(path) + return 4 + 1 + 4 + 4 + len(p.Path) } // MarshalPacket returns p as a two-part binary encoding of p. @@ -135,10 +132,9 @@ } // MarshalSize returns the number of bytes that the packet would marshal into. -// This excludes the uint32(length). func (p *MkdirPacket) MarshalSize() int { - // uint8(type) + uint32(request-id) + string(path) + ATTRS(attrs) - return 1 + 4 + 4 + len(p.Path) + p.Attrs.MarshalSize() + // uint32(length) + uint8(type) + uint32(request-id) + string(path) + ATTRS(attrs) + return 4 + 1 + 4 + 4 + len(p.Path) + p.Attrs.MarshalSize() } // MarshalPacket returns p as a two-part binary encoding of p. @@ -177,10 +173,9 @@ } // MarshalSize returns the number of bytes that the packet would marshal into. -// This excludes the uint32(length). func (p *RmdirPacket) MarshalSize() int { - // uint8(type) + uint32(request-id) + string(path) - return 1 + 4 + 4 + len(p.Path) + // uint32(length) + uint8(type) + uint32(request-id) + string(path) + return 4 + 1 + 4 + 4 + len(p.Path) } // MarshalPacket returns p as a two-part binary encoding of p. @@ -217,10 +212,9 @@ } // MarshalSize returns the number of bytes that the packet would marshal into. -// This excludes the uint32(length). func (p *RealPathPacket) MarshalSize() int { - // uint8(type) + uint32(request-id) + string(path) - return 1 + 4 + 4 + len(p.Path) + // uint32(length) + uint8(type) + uint32(request-id) + string(path) + return 4 + 1 + 4 + 4 + len(p.Path) } // MarshalPacket returns p as a two-part binary encoding of p. @@ -257,10 +251,9 @@ } // MarshalSize returns the number of bytes that the packet would marshal into. -// This excludes the uint32(length). func (p *StatPacket) MarshalSize() int { - // uint8(type) + uint32(request-id) + string(path) - return 1 + 4 + 4 + len(p.Path) + // uint32(length) + uint8(type) + uint32(request-id) + string(path) + return 4 + 1 + 4 + 4 + len(p.Path) } // MarshalPacket returns p as a two-part binary encoding of p. @@ -298,10 +291,9 @@ } // MarshalSize returns the number of bytes that the packet would marshal into. -// This excludes the uint32(length). func (p *RenamePacket) MarshalSize() int { - // uint8(type) + uint32(request-id) + string(oldpath) + string(newpath) - return 1 + 4 + 4 + len(p.OldPath) + 4 + len(p.NewPath) + // uint32(length) + uint8(type) + uint32(request-id) + string(oldpath) + string(newpath) + return 4 + 1 + 4 + 4 + len(p.OldPath) + 4 + len(p.NewPath) } // MarshalPacket returns p as a two-part binary encoding of p. @@ -340,10 +332,9 @@ } // MarshalSize returns the number of bytes that the packet would marshal into. -// This excludes the uint32(length). func (p *ReadLinkPacket) MarshalSize() int { - // uint8(type) + uint32(request-id) + string(path) - return 1 + 4 + 4 + len(p.Path) + // uint32(length) + uint8(type) + uint32(request-id) + string(path) + return 4 + 1 + 4 + 4 + len(p.Path) } // MarshalPacket returns p as a two-part binary encoding of p. @@ -385,10 +376,9 @@ } // MarshalSize returns the number of bytes that the packet would marshal into. -// This excludes the uint32(length). func (p *SymlinkPacket) MarshalSize() int { - // uint8(type) + uint32(request-id) + string(linkpath) + string(targetpath) - return 1 + 4 + 4 + len(p.LinkPath) + 4 + len(p.TargetPath) + // uint32(length) + uint8(type) + uint32(request-id) + string(linkpath) + string(targetpath) + return 4 + 1 + 4 + 4 + len(p.LinkPath) + 4 + len(p.TargetPath) } // MarshalPacket returns p as a two-part binary encoding of p.
diff --git a/encoding/ssh/filexfer/response_packets.go b/encoding/ssh/filexfer/response_packets.go index afa07ba..60ec6d0 100644 --- a/encoding/ssh/filexfer/response_packets.go +++ b/encoding/ssh/filexfer/response_packets.go
@@ -40,10 +40,12 @@ } // MarshalSize returns the number of bytes that the packet would marshal into. -// This excludes the uint32(length). func (p *StatusPacket) MarshalSize() int { - // uint8(type) + uint32(request-id) + uint32(error/status code) + string(error message) + string(language tag) - return 1 + 4 + 4 + 4 + len(p.ErrorMessage) + 4 + len(p.LanguageTag) + // uint32(length) + uint8(type) + uint32(request-id) + const size = 4 + 1 + 4 + + // uint32(error/status code) + string(error message) + string(language tag) + return size + 4 + 4 + len(p.ErrorMessage) + 4 + len(p.LanguageTag) } // MarshalPacket returns p as a two-part binary encoding of p. @@ -84,10 +86,9 @@ } // MarshalSize returns the number of bytes that the packet would marshal into. -// This excludes the uint32(length). func (p *HandlePacket) MarshalSize() int { - // uint8(type) + uint32(request-id) + string(handle) - return 1 + 4 + 4 + len(p.Handle) + // uint32(length) + uint8(type) + uint32(request-id) + string(handle) + return 4 + 1 + 4 + 4 + len(p.Handle) } // MarshalPacket returns p as a two-part binary encoding of p. @@ -124,10 +125,9 @@ } // MarshalSize returns the number of bytes that the packet would marshal into. -// This excludes the uint32(length). func (p *DataPacket) MarshalSize() int { - // uint8(type) + uint32(request-id) + bytes(data) - return 1 + 4 + 4 + len(p.Data) + // uint32(length) + uint8(type) + uint32(request-id) + bytes(data) + return 4 + 1 + 4 + 4 + len(p.Data) } // MarshalPacket returns p as a two-part binary encoding of p. @@ -173,10 +173,9 @@ } // MarshalSize returns the number of bytes that the packet would marshal into. -// This excludes the uint32(length). func (p *NamePacket) MarshalSize() int { - // uint8(type) + uint32(request-id) + uint32(len(entries)) - size := 1 + 4 + 4 + // uint32(length) + uint8(type) + uint32(request-id) + uint32(len(entries)) + size := 4 + 1 + 4 + 4 for _, e := range p.Entries { size += e.MarshalSize() @@ -237,10 +236,9 @@ } // MarshalSize returns the number of bytes that the packet would marshal into. -// This excludes the uint32(length). func (p *PathPseudoPacket) MarshalSize() int { - // uint8(type) + uint32(request-id) + - size := 1 + 4 + 4 // uint32(count = 1) + // uint32(length) + uint8(type) + uint32(request-id) + + size := 4 + 1 + 4 + 4 // uint32(count = 1) size += 4 + len(p.Path) // string(path) @@ -310,10 +308,9 @@ } // MarshalSize returns the number of bytes that the packet would marshal into. -// This excludes the uint32(length). func (p *AttrsPacket) MarshalSize() int { - // uint8(type) + uint32(request-id) + ATTRS(attrs) - return 1 + 4 + p.Attrs.MarshalSize() + // uint32(length) + uint8(type) + uint32(request-id) + ATTRS(attrs) + return 4 + 1 + 4 + p.Attrs.MarshalSize() } // MarshalPacket returns p as a two-part binary encoding of p.