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 [email protected] 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.