encoding: MarshalPacket shall take a buffer hint now
diff --git a/encoding/ssh/filexfer/buffer.go b/encoding/ssh/filexfer/buffer.go
index 4091e13..d8e9d97 100644
--- a/encoding/ssh/filexfer/buffer.go
+++ b/encoding/ssh/filexfer/buffer.go
@@ -29,16 +29,19 @@
}
}
-// NewMarshalBuffer creates an initializes a new Buffer ready to start marshaling a Packet into.
-// It prepopulates 4 bytes for length, the 1-byte packetType, and the 4-byte requestID.
-// It preallocates enough space for an additional size bytes of data above the prepopulated values.
-func NewMarshalBuffer(packetType PacketType, requestID uint32, size int) *Buffer {
- buf := NewBuffer(make([]byte, 4, 4+1+4+size))
+// NewMarshalBuffer creates a new Buffer ready to start marshaling a Packet into.
+// It preallocates enough space for uint32(length), uint8(type), uint32(request-id) and size more bytes.
+func NewMarshalBuffer(size int) *Buffer {
+ return NewBuffer(make([]byte, 4+1+4+size))
+}
- buf.AppendUint8(uint8(packetType))
- buf.AppendUint32(requestID)
+// StartPacket resets and initializes the Buffer to be ready to start marshaling a Packet body into.
+// It truncates the buffer, reserves space for uint32(length), then appends the packetType and requestID.
+func (b *Buffer) StartPacket(packetType PacketType, requestID uint32) {
+ b.b = append(b.b[:0], make([]byte, 4)...)
- return buf
+ b.AppendUint8(uint8(packetType))
+ b.AppendUint32(requestID)
}
// Bytes returns a slice of length b.Len() holding the unconsumed bytes in the Buffer.
@@ -65,9 +68,11 @@
}
// Len returns the number of unconsumed bytes in the Buffer.
-func (b *Buffer) Len() int {
- return len(b.b) - b.off
-}
+func (b *Buffer) Len() int { return len(b.b) - b.off }
+
+// Cap returns the capacity of the Buffer’s underlying byte slice,
+// that is, the total space allocated for the buffer’s data.
+func (b *Buffer) Cap() int { return cap(b.b) }
// ConsumeUint8 consumes a single byte from the Buffer.
// If Buffer does not have enough data, it will return ErrShortPacket.
diff --git a/encoding/ssh/filexfer/extended_packets.go b/encoding/ssh/filexfer/extended_packets.go
index 94c6310..de04c39 100644
--- a/encoding/ssh/filexfer/extended_packets.go
+++ b/encoding/ssh/filexfer/extended_packets.go
@@ -50,12 +50,15 @@
// MarshalPacket returns p as a two-part binary encoding of p.
//
// The Data is marshaled into binary, and returned as the payload.
-func (p *ExtendedPacket) MarshalPacket(reqid uint32) (header, payload []byte, err error) {
- size := 4 + len(p.ExtendedRequest) // string(extended-request)
+func (p *ExtendedPacket) MarshalPacket(reqid uint32, b []byte) (header, payload []byte, err error) {
+ buf := NewBuffer(b)
+ if buf.Cap() < 9 {
+ size := 4 + len(p.ExtendedRequest) // string(extended-request)
+ buf = NewMarshalBuffer(size)
+ }
- b := NewMarshalBuffer(PacketTypeExtended, reqid, size)
-
- b.AppendString(p.ExtendedRequest)
+ buf.StartPacket(PacketTypeExtended, reqid)
+ buf.AppendString(p.ExtendedRequest)
if p.Data != nil {
payload, err = p.Data.MarshalBinary()
@@ -64,7 +67,7 @@
}
}
- return b.Packet(payload)
+ return buf.Packet(payload)
}
// UnmarshalPacketBody unmarshals the packet body from the given Buffer.
@@ -93,8 +96,13 @@
// MarshalPacket returns p as a two-part binary encoding of p.
//
// The Data is marshaled into binary, and returned as the payload.
-func (p *ExtendedReplyPacket) MarshalPacket(reqid uint32) (header, payload []byte, err error) {
- b := NewMarshalBuffer(PacketTypeExtendedReply, reqid, 0)
+func (p *ExtendedReplyPacket) MarshalPacket(reqid uint32, b []byte) (header, payload []byte, err error) {
+ buf := NewBuffer(b)
+ if buf.Cap() < 9 {
+ buf = NewMarshalBuffer(0)
+ }
+
+ buf.StartPacket(PacketTypeExtendedReply, reqid)
if p.Data != nil {
payload, err = p.Data.MarshalBinary()
@@ -103,7 +111,7 @@
}
}
- return b.Packet(payload)
+ return buf.Packet(payload)
}
// UnmarshalPacketBody unmarshals the packet body from the given Buffer.
diff --git a/encoding/ssh/filexfer/extended_packets_test.go b/encoding/ssh/filexfer/extended_packets_test.go
index a362774..668ef57 100644
--- a/encoding/ssh/filexfer/extended_packets_test.go
+++ b/encoding/ssh/filexfer/extended_packets_test.go
@@ -42,7 +42,7 @@
ExtendedRequest: extendedRequest,
}
- data, err := ComposePacket(p.MarshalPacket(id))
+ data, err := ComposePacket(p.MarshalPacket(id, nil))
if err != nil {
t.Fatal("unexpected error:", err)
}
@@ -86,7 +86,7 @@
},
}
- data, err := ComposePacket(p.MarshalPacket(id))
+ data, err := ComposePacket(p.MarshalPacket(id, nil))
if err != nil {
t.Fatal("unexpected error:", err)
}
@@ -153,7 +153,7 @@
p := &ExtendedReplyPacket{}
- data, err := ComposePacket(p.MarshalPacket(id))
+ data, err := ComposePacket(p.MarshalPacket(id, nil))
if err != nil {
t.Fatal("unexpected error:", err)
}
@@ -190,7 +190,7 @@
},
}
- data, err := ComposePacket(p.MarshalPacket(id))
+ data, err := ComposePacket(p.MarshalPacket(id, nil))
if err != nil {
t.Fatal("unexpected error:", err)
}
diff --git a/encoding/ssh/filexfer/filexfer.go b/encoding/ssh/filexfer/filexfer.go
index d45fd35..0b26169 100644
--- a/encoding/ssh/filexfer/filexfer.go
+++ b/encoding/ssh/filexfer/filexfer.go
@@ -1,8 +1,23 @@
+// Package filexfer implements the wire encoding for secsh-filexfer as described in https://tools.ietf.org/html/draft-ietf-secsh-filexfer-02
package filexfer
// Packet defines the behavior of an SFTP packet.
type Packet interface {
- MarshalPacket(reqid uint32) (header, payload []byte, err error)
+ // MarshalPacket is the primary intended way to encode a packet.
+ // The request-id for the packet is set from reqid.
+ //
+ // An optional buffer may be given in b.
+ // If the buffer has a minimum capacity, it shall be truncated and used to marshal the header into.
+ // The minimum capacity for the packet must be a constant expression, and should be at least 9.
+ //
+ // It shall return the main body of the encoded packet in header,
+ // and may optionally return an additional payload to be written immediately after the header.
+ //
+ // It shall encode in the first 4-bytes of the header the proper length of the rest of the header+payload.
+ MarshalPacket(reqid uint32, b []byte) (header, payload []byte, err error)
+
+ // UnmarshalPacketBody decodes a packet body from the given Buffer.
+ // It is assumed that the common header values of the length, type and request-id have already been consumed.
UnmarshalPacketBody(buf *Buffer) error
}
diff --git a/encoding/ssh/filexfer/handle_packets.go b/encoding/ssh/filexfer/handle_packets.go
index 4841bce..33670dc 100644
--- a/encoding/ssh/filexfer/handle_packets.go
+++ b/encoding/ssh/filexfer/handle_packets.go
@@ -6,14 +6,17 @@
}
// MarshalPacket returns p as a two-part binary encoding of p.
-func (p *ClosePacket) MarshalPacket(reqid uint32) (header, payload []byte, err error) {
- size := 4 + len(p.Handle) // string(handle)
+func (p *ClosePacket) MarshalPacket(reqid uint32, b []byte) (header, payload []byte, err error) {
+ buf := NewBuffer(b)
+ if buf.Cap() < 9 {
+ size := 4 + len(p.Handle) // string(handle)
+ buf = NewMarshalBuffer(size)
+ }
- b := NewMarshalBuffer(PacketTypeClose, reqid, size)
+ buf.StartPacket(PacketTypeClose, reqid)
+ buf.AppendString(p.Handle)
- b.AppendString(p.Handle)
-
- return b.Packet(payload)
+ return buf.Packet(payload)
}
// UnmarshalPacketBody unmarshals the packet body from the given Buffer.
@@ -34,17 +37,20 @@
}
// MarshalPacket returns p as a two-part binary encoding of p.
-func (p *ReadPacket) MarshalPacket(reqid uint32) (header, payload []byte, err error) {
- // string(handle) + uint64(offset) + uint32(len)
- size := 4 + len(p.Handle) + 8 + 4
+func (p *ReadPacket) MarshalPacket(reqid uint32, b []byte) (header, payload []byte, err error) {
+ buf := NewBuffer(b)
+ if buf.Cap() < 9 {
+ // string(handle) + uint64(offset) + uint32(len)
+ size := 4 + len(p.Handle) + 8 + 4
+ buf = NewMarshalBuffer(size)
+ }
- b := NewMarshalBuffer(PacketTypeRead, reqid, size)
+ buf.StartPacket(PacketTypeRead, reqid)
+ buf.AppendString(p.Handle)
+ buf.AppendUint64(p.Offset)
+ buf.AppendUint32(p.Len)
- b.AppendString(p.Handle)
- b.AppendUint64(p.Offset)
- b.AppendUint32(p.Len)
-
- return b.Packet(payload)
+ return buf.Packet(payload)
}
// UnmarshalPacketBody unmarshals the packet body from the given Buffer.
@@ -73,17 +79,20 @@
}
// MarshalPacket returns p as a two-part binary encoding of p.
-func (p *WritePacket) MarshalPacket(reqid uint32) (header, payload []byte, err error) {
- // string(handle) + uint64(offset) + uint32(len(data)); data content in payload
- size := 4 + len(p.Handle) + 8 + 4
+func (p *WritePacket) MarshalPacket(reqid uint32, b []byte) (header, payload []byte, err error) {
+ buf := NewBuffer(b)
+ if buf.Cap() < 9 {
+ // string(handle) + uint64(offset) + uint32(len(data)); data content in payload
+ size := 4 + len(p.Handle) + 8 + 4
+ buf = NewMarshalBuffer(size)
+ }
- b := NewMarshalBuffer(PacketTypeWrite, reqid, size)
+ buf.StartPacket(PacketTypeWrite, reqid)
+ buf.AppendString(p.Handle)
+ buf.AppendUint64(p.Offset)
+ buf.AppendUint32(uint32(len(p.Data)))
- b.AppendString(p.Handle)
- b.AppendUint64(p.Offset)
- b.AppendUint32(uint32(len(p.Data)))
-
- return b.Packet(p.Data)
+ return buf.Packet(p.Data)
}
// UnmarshalPacketBody unmarshals the packet body from the given Buffer.
@@ -110,14 +119,17 @@
}
// MarshalPacket returns p as a two-part binary encoding of p.
-func (p *FStatPacket) MarshalPacket(reqid uint32) (header, payload []byte, err error) {
- size := 4 + len(p.Handle) // string(handle)
+func (p *FStatPacket) MarshalPacket(reqid uint32, b []byte) (header, payload []byte, err error) {
+ buf := NewBuffer(b)
+ if buf.Cap() < 9 {
+ size := 4 + len(p.Handle) // string(handle)
+ buf = NewMarshalBuffer(size)
+ }
- b := NewMarshalBuffer(PacketTypeFStat, reqid, size)
+ buf.StartPacket(PacketTypeFStat, reqid)
+ buf.AppendString(p.Handle)
- b.AppendString(p.Handle)
-
- return b.Packet(payload)
+ return buf.Packet(payload)
}
// UnmarshalPacketBody unmarshals the packet body from the given Buffer.
@@ -137,16 +149,19 @@
}
// MarshalPacket returns p as a two-part binary encoding of p.
-func (p *FSetstatPacket) MarshalPacket(reqid uint32) (header, payload []byte, err error) {
- size := 4 + len(p.Handle) + p.Attrs.Len() // string(handle) + ATTRS(attrs)
+func (p *FSetstatPacket) MarshalPacket(reqid uint32, b []byte) (header, payload []byte, err error) {
+ buf := NewBuffer(b)
+ if buf.Cap() < 9 {
+ size := 4 + len(p.Handle) + p.Attrs.Len() // string(handle) + ATTRS(attrs)
+ buf = NewMarshalBuffer(size)
+ }
- b := NewMarshalBuffer(PacketTypeFSetstat, reqid, size)
+ buf.StartPacket(PacketTypeFSetstat, reqid)
+ buf.AppendString(p.Handle)
- b.AppendString(p.Handle)
+ p.Attrs.MarshalInto(buf)
- p.Attrs.MarshalInto(b)
-
- return b.Packet(payload)
+ return buf.Packet(payload)
}
// UnmarshalPacketBody unmarshals the packet body from the given Buffer.
@@ -165,14 +180,17 @@
}
// MarshalPacket returns p as a two-part binary encoding of p.
-func (p *ReadDirPacket) MarshalPacket(reqid uint32) (header, payload []byte, err error) {
- size := 4 + len(p.Handle) // string(handle)
+func (p *ReadDirPacket) MarshalPacket(reqid uint32, b []byte) (header, payload []byte, err error) {
+ buf := NewBuffer(b)
+ if buf.Cap() < 9 {
+ size := 4 + len(p.Handle) // string(handle)
+ buf = NewMarshalBuffer(size)
+ }
- b := NewMarshalBuffer(PacketTypeReadDir, reqid, size)
+ buf.StartPacket(PacketTypeReadDir, reqid)
+ buf.AppendString(p.Handle)
- b.AppendString(p.Handle)
-
- return b.Packet(payload)
+ return buf.Packet(payload)
}
// UnmarshalPacketBody unmarshals the packet body from the given Buffer.
diff --git a/encoding/ssh/filexfer/handle_packets_test.go b/encoding/ssh/filexfer/handle_packets_test.go
index b8599ad..10fdc53 100644
--- a/encoding/ssh/filexfer/handle_packets_test.go
+++ b/encoding/ssh/filexfer/handle_packets_test.go
@@ -17,7 +17,7 @@
Handle: "somehandle",
}
- data, err := ComposePacket(p.MarshalPacket(id))
+ data, err := ComposePacket(p.MarshalPacket(id, nil))
if err != nil {
t.Fatal("unexpected error:", err)
}
@@ -61,7 +61,7 @@
Len: length,
}
- data, err := ComposePacket(p.MarshalPacket(id))
+ data, err := ComposePacket(p.MarshalPacket(id, nil))
if err != nil {
t.Fatal("unexpected error:", err)
}
@@ -116,7 +116,7 @@
Data: payload,
}
- data, err := ComposePacket(p.MarshalPacket(id))
+ data, err := ComposePacket(p.MarshalPacket(id, nil))
if err != nil {
t.Fatal("unexpected error:", err)
}
@@ -166,7 +166,7 @@
Handle: "somehandle",
}
- data, err := ComposePacket(p.MarshalPacket(id))
+ data, err := ComposePacket(p.MarshalPacket(id, nil))
if err != nil {
t.Fatal("unexpected error:", err)
}
@@ -211,7 +211,7 @@
},
}
- data, err := ComposePacket(p.MarshalPacket(id))
+ data, err := ComposePacket(p.MarshalPacket(id, nil))
if err != nil {
t.Fatal("unexpected error:", err)
}
@@ -253,7 +253,7 @@
Handle: "somehandle",
}
- data, err := ComposePacket(p.MarshalPacket(id))
+ data, err := ComposePacket(p.MarshalPacket(id, nil))
if err != nil {
t.Fatal("unexpected error:", err)
}
diff --git a/encoding/ssh/filexfer/open_packets.go b/encoding/ssh/filexfer/open_packets.go
index 4284d0f..b0e25c2 100644
--- a/encoding/ssh/filexfer/open_packets.go
+++ b/encoding/ssh/filexfer/open_packets.go
@@ -18,18 +18,21 @@
}
// MarshalPacket returns p as a two-part binary encoding of p.
-func (p *OpenPacket) MarshalPacket(reqid uint32) (header, payload []byte, err error) {
- // string(filename) + uint32(pflags) + ATTRS(attrs)
- size := 4 + len(p.Filename) + 4 + p.Attrs.Len()
+func (p *OpenPacket) MarshalPacket(reqid uint32, b []byte) (header, payload []byte, err error) {
+ buf := NewBuffer(b)
+ if buf.Cap() < 9 {
+ // string(filename) + uint32(pflags) + ATTRS(attrs)
+ size := 4 + len(p.Filename) + 4 + p.Attrs.Len()
+ buf = NewMarshalBuffer(size)
+ }
- b := NewMarshalBuffer(PacketTypeOpen, reqid, size)
+ buf.StartPacket(PacketTypeOpen, reqid)
+ buf.AppendString(p.Filename)
+ buf.AppendUint32(p.PFlags)
- b.AppendString(p.Filename)
- b.AppendUint32(p.PFlags)
+ p.Attrs.MarshalInto(buf)
- p.Attrs.MarshalInto(b)
-
- return b.Packet(payload)
+ return buf.Packet(payload)
}
// UnmarshalPacketBody unmarshals the packet body from the given Buffer.
@@ -52,14 +55,17 @@
}
// MarshalPacket returns p as a two-part binary encoding of p.
-func (p *OpenDirPacket) MarshalPacket(reqid uint32) (header, payload []byte, err error) {
- size := 4 + len(p.Path) // string(path)
+func (p *OpenDirPacket) MarshalPacket(reqid uint32, b []byte) (header, payload []byte, err error) {
+ buf := NewBuffer(b)
+ if buf.Cap() < 9 {
+ size := 4 + len(p.Path) // string(path)
+ buf = NewMarshalBuffer(size)
+ }
- b := NewMarshalBuffer(PacketTypeOpenDir, reqid, size)
+ buf.StartPacket(PacketTypeOpenDir, reqid)
+ buf.AppendString(p.Path)
- b.AppendString(p.Path)
-
- return b.Packet(payload)
+ return buf.Packet(payload)
}
// UnmarshalPacketBody unmarshals the packet body from the given Buffer.
diff --git a/encoding/ssh/filexfer/open_packets_test.go b/encoding/ssh/filexfer/open_packets_test.go
index f4b0a44..8637cd0 100644
--- a/encoding/ssh/filexfer/open_packets_test.go
+++ b/encoding/ssh/filexfer/open_packets_test.go
@@ -23,7 +23,7 @@
},
}
- data, err := ComposePacket(p.MarshalPacket(id))
+ data, err := ComposePacket(p.MarshalPacket(id, nil))
if err != nil {
t.Fatal("unexpected error:", err)
}
@@ -78,7 +78,7 @@
Path: path,
}
- data, err := ComposePacket(p.MarshalPacket(id))
+ data, err := ComposePacket(p.MarshalPacket(id, nil))
if err != nil {
t.Fatal("unexpected error:", err)
}
diff --git a/encoding/ssh/filexfer/openssh/hardlink.go b/encoding/ssh/filexfer/openssh/hardlink.go
index f279f52..838ff2d 100644
--- a/encoding/ssh/filexfer/openssh/hardlink.go
+++ b/encoding/ssh/filexfer/openssh/hardlink.go
@@ -27,13 +27,13 @@
}
// MarshalPacket returns ep as a two-part binary encoding of the full extended packet.
-func (ep *HardlinkExtendedPacket) MarshalPacket(reqid uint32) (header, payload []byte, err error) {
+func (ep *HardlinkExtendedPacket) MarshalPacket(reqid uint32, b []byte) (header, payload []byte, err error) {
p := &sshfx.ExtendedPacket{
ExtendedRequest: extensionHardlink,
Data: ep,
}
- return p.MarshalPacket(reqid)
+ return p.MarshalPacket(reqid, b)
}
// MarshalInto encodes ep into the binary encoding of the hardlink@openssh.com extended packet-specific data.
diff --git a/encoding/ssh/filexfer/openssh/openssh.go b/encoding/ssh/filexfer/openssh/openssh.go
new file mode 100644
index 0000000..f93ff17
--- /dev/null
+++ b/encoding/ssh/filexfer/openssh/openssh.go
@@ -0,0 +1,2 @@
+// Package openssh implements the openssh secsh-filexfer extensions as described in https://github.com/openssh/openssh-portable/blob/master/PROTOCOL
+package openssh
diff --git a/encoding/ssh/filexfer/openssh/posix-rename.go b/encoding/ssh/filexfer/openssh/posix-rename.go
index b4c45c4..8c8313a 100644
--- a/encoding/ssh/filexfer/openssh/posix-rename.go
+++ b/encoding/ssh/filexfer/openssh/posix-rename.go
@@ -27,13 +27,13 @@
}
// MarshalPacket returns ep as a two-part binary encoding of the full extended packet.
-func (ep *PosixRenameExtendedPacket) MarshalPacket(reqid uint32) (header, payload []byte, err error) {
+func (ep *PosixRenameExtendedPacket) MarshalPacket(reqid uint32, b []byte) (header, payload []byte, err error) {
p := &sshfx.ExtendedPacket{
ExtendedRequest: extensionPosixRename,
Data: ep,
}
- return p.MarshalPacket(reqid)
+ return p.MarshalPacket(reqid, b)
}
// MarshalInto encodes ep into the binary encoding of the hardlink@openssh.com extended packet-specific data.
diff --git a/encoding/ssh/filexfer/openssh/statvfs.go b/encoding/ssh/filexfer/openssh/statvfs.go
index cf41cc3..5a723d4 100644
--- a/encoding/ssh/filexfer/openssh/statvfs.go
+++ b/encoding/ssh/filexfer/openssh/statvfs.go
@@ -26,13 +26,13 @@
}
// MarshalPacket returns ep as a two-part binary encoding of the full extended packet.
-func (ep *StatVFSExtendedPacket) MarshalPacket(reqid uint32) (header, payload []byte, err error) {
+func (ep *StatVFSExtendedPacket) MarshalPacket(reqid uint32, b []byte) (header, payload []byte, err error) {
p := &sshfx.ExtendedPacket{
ExtendedRequest: extensionStatVFS,
Data: ep,
}
- return p.MarshalPacket(reqid)
+ return p.MarshalPacket(reqid, b)
}
// MarshalInto encodes ep into the binary encoding of the statvfs@openssh.com extended packet-specific data.
@@ -89,13 +89,13 @@
}
// MarshalPacket returns ep as a two-part binary encoding of the full extended packet.
-func (ep *FStatVFSExtendedPacket) MarshalPacket(reqid uint32) (header, payload []byte, err error) {
+func (ep *FStatVFSExtendedPacket) MarshalPacket(reqid uint32, b []byte) (header, payload []byte, err error) {
p := &sshfx.ExtendedPacket{
ExtendedRequest: extensionFStatVFS,
Data: ep,
}
- return p.MarshalPacket(reqid)
+ return p.MarshalPacket(reqid, b)
}
// MarshalInto encodes ep into the binary encoding of the statvfs@openssh.com extended packet-specific data.
@@ -153,11 +153,11 @@
}
// MarshalPacket returns ep as a two-part binary encoding of the full extended reply packet.
-func (ep *StatVFSExtendedReplyPacket) MarshalPacket(reqid uint32) (header, payload []byte, err error) {
+func (ep *StatVFSExtendedReplyPacket) MarshalPacket(reqid uint32, b []byte) (header, payload []byte, err error) {
p := &sshfx.ExtendedReplyPacket{
Data: ep,
}
- return p.MarshalPacket(reqid)
+ return p.MarshalPacket(reqid, b)
}
// MarshalInto encodes ep into the binary encoding of the (f)statvfs@openssh.com extended reply packet-specific data.
diff --git a/encoding/ssh/filexfer/packets.go b/encoding/ssh/filexfer/packets.go
index e32f1c4..baa2af4 100644
--- a/encoding/ssh/filexfer/packets.go
+++ b/encoding/ssh/filexfer/packets.go
@@ -64,15 +64,20 @@
// MarshalPacket returns p as a two-part binary encoding of p.
//
// The internal p.RequestID is overridden by the reqid argument.
-func (p *RawPacket) MarshalPacket(reqid uint32) (header, payload []byte, err error) {
- b := NewMarshalBuffer(p.Type, reqid, 0)
+func (p *RawPacket) MarshalPacket(reqid uint32, b []byte) (header, payload []byte, err error) {
+ buf := NewBuffer(b)
+ if buf.Cap() < 9 {
+ buf = NewMarshalBuffer(0)
+ }
- return b.Packet(p.Data.Bytes())
+ buf.StartPacket(p.Type, reqid)
+
+ return buf.Packet(p.Data.Bytes())
}
// MarshalBinary returns p as the binary encoding of p.
func (p *RawPacket) MarshalBinary() ([]byte, error) {
- return ComposePacket(p.MarshalPacket(p.RequestID))
+ return ComposePacket(p.MarshalPacket(p.RequestID, nil))
}
// UnmarshalFrom decodes a RawPacket from the given Buffer into p.
@@ -139,7 +144,8 @@
return p.UnmarshalBinary(b)
}
-// RequestPacket decodes a full request packet from the internal Data based on the Type.
+// RequestPacket decodes a full RequestPacket from the internal Data based on the Type.
+// Prefer using a RequestPacket directly, rather than going indirectly through RawPacket.
func (p *RawPacket) RequestPacket() (*RequestPacket, error) {
packet, err := newPacketFromType(p.Type)
if err != nil {
@@ -173,17 +179,17 @@
// MarshalPacket returns p as a two-part binary encoding of p.
//
// The internal p.RequestID is overridden by the reqid argument.
-func (p *RequestPacket) MarshalPacket(reqid uint32) (header, payload []byte, err error) {
+func (p *RequestPacket) MarshalPacket(reqid uint32, b []byte) (header, payload []byte, err error) {
if p.Request == nil {
return nil, nil, errors.New("empty request packet")
}
- return p.Request.MarshalPacket(reqid)
+ return p.Request.MarshalPacket(reqid, b)
}
// MarshalBinary returns p as the binary encoding of p.
func (p *RequestPacket) MarshalBinary() ([]byte, error) {
- return ComposePacket(p.MarshalPacket(p.RequestID))
+ return ComposePacket(p.MarshalPacket(p.RequestID, nil))
}
// UnmarshalFrom decodes a RequestPacket from the given Buffer into p.
diff --git a/encoding/ssh/filexfer/path_packets.go b/encoding/ssh/filexfer/path_packets.go
index 45ec5a5..f7085f3 100644
--- a/encoding/ssh/filexfer/path_packets.go
+++ b/encoding/ssh/filexfer/path_packets.go
@@ -6,14 +6,17 @@
}
// MarshalPacket returns p as a two-part binary encoding of p.
-func (p *LStatPacket) MarshalPacket(reqid uint32) (header, payload []byte, err error) {
- size := 4 + len(p.Path) // string(path)
+func (p *LStatPacket) MarshalPacket(reqid uint32, b []byte) (header, payload []byte, err error) {
+ buf := NewBuffer(b)
+ if buf.Cap() < 9 {
+ size := 4 + len(p.Path) // string(path)
+ buf = NewMarshalBuffer(size)
+ }
- b := NewMarshalBuffer(PacketTypeLStat, reqid, size)
+ buf.StartPacket(PacketTypeLStat, reqid)
+ buf.AppendString(p.Path)
- b.AppendString(p.Path)
-
- return b.Packet(payload)
+ return buf.Packet(payload)
}
// UnmarshalPacketBody unmarshals the packet body from the given Buffer.
@@ -33,16 +36,19 @@
}
// MarshalPacket returns p as a two-part binary encoding of p.
-func (p *SetstatPacket) MarshalPacket(reqid uint32) (header, payload []byte, err error) {
- size := 4 + len(p.Path) + p.Attrs.Len() // string(path) + ATTRS(attrs)
+func (p *SetstatPacket) MarshalPacket(reqid uint32, b []byte) (header, payload []byte, err error) {
+ buf := NewBuffer(b)
+ if buf.Cap() < 9 {
+ size := 4 + len(p.Path) + p.Attrs.Len() // string(path) + ATTRS(attrs)
+ buf = NewMarshalBuffer(size)
+ }
- b := NewMarshalBuffer(PacketTypeSetstat, reqid, size)
+ buf.StartPacket(PacketTypeSetstat, reqid)
+ buf.AppendString(p.Path)
- b.AppendString(p.Path)
+ p.Attrs.MarshalInto(buf)
- p.Attrs.MarshalInto(b)
-
- return b.Packet(payload)
+ return buf.Packet(payload)
}
// UnmarshalPacketBody unmarshals the packet body from the given Buffer.
@@ -61,14 +67,17 @@
}
// MarshalPacket returns p as a two-part binary encoding of p.
-func (p *RemovePacket) MarshalPacket(reqid uint32) (header, payload []byte, err error) {
- size := 4 + len(p.Path) // string(path)
+func (p *RemovePacket) MarshalPacket(reqid uint32, b []byte) (header, payload []byte, err error) {
+ buf := NewBuffer(b)
+ if buf.Cap() < 9 {
+ size := 4 + len(p.Path) // string(path)
+ buf = NewMarshalBuffer(size)
+ }
- b := NewMarshalBuffer(PacketTypeRemove, reqid, size)
+ buf.StartPacket(PacketTypeRemove, reqid)
+ buf.AppendString(p.Path)
- b.AppendString(p.Path)
-
- return b.Packet(payload)
+ return buf.Packet(payload)
}
// UnmarshalPacketBody unmarshals the packet body from the given Buffer.
@@ -88,16 +97,19 @@
}
// MarshalPacket returns p as a two-part binary encoding of p.
-func (p *MkdirPacket) MarshalPacket(reqid uint32) (header, payload []byte, err error) {
- size := 4 + len(p.Path) + p.Attrs.Len() // string(path) + ATTRS(attrs)
+func (p *MkdirPacket) MarshalPacket(reqid uint32, b []byte) (header, payload []byte, err error) {
+ buf := NewBuffer(b)
+ if buf.Cap() < 9 {
+ size := 4 + len(p.Path) + p.Attrs.Len() // string(path) + ATTRS(attrs)
+ buf = NewMarshalBuffer(size)
+ }
- b := NewMarshalBuffer(PacketTypeMkdir, reqid, size)
+ buf.StartPacket(PacketTypeMkdir, reqid)
+ buf.AppendString(p.Path)
- b.AppendString(p.Path)
+ p.Attrs.MarshalInto(buf)
- p.Attrs.MarshalInto(b)
-
- return b.Packet(payload)
+ return buf.Packet(payload)
}
// UnmarshalPacketBody unmarshals the packet body from the given Buffer.
@@ -116,14 +128,17 @@
}
// MarshalPacket returns p as a two-part binary encoding of p.
-func (p *RmdirPacket) MarshalPacket(reqid uint32) (header, payload []byte, err error) {
- size := 4 + len(p.Path) // string(path)
+func (p *RmdirPacket) MarshalPacket(reqid uint32, b []byte) (header, payload []byte, err error) {
+ buf := NewBuffer(b)
+ if buf.Cap() < 9 {
+ size := 4 + len(p.Path) // string(path)
+ buf = NewMarshalBuffer(size)
+ }
- b := NewMarshalBuffer(PacketTypeRmdir, reqid, size)
+ buf.StartPacket(PacketTypeRmdir, reqid)
+ buf.AppendString(p.Path)
- b.AppendString(p.Path)
-
- return b.Packet(payload)
+ return buf.Packet(payload)
}
// UnmarshalPacketBody unmarshals the packet body from the given Buffer.
@@ -142,14 +157,17 @@
}
// MarshalPacket returns p as a two-part binary encoding of p.
-func (p *RealPathPacket) MarshalPacket(reqid uint32) (header, payload []byte, err error) {
- size := 4 + len(p.Path) // string(path)
+func (p *RealPathPacket) MarshalPacket(reqid uint32, b []byte) (header, payload []byte, err error) {
+ buf := NewBuffer(b)
+ if buf.Cap() < 9 {
+ size := 4 + len(p.Path) // string(path)
+ buf = NewMarshalBuffer(size)
+ }
- b := NewMarshalBuffer(PacketTypeRealPath, reqid, size)
+ buf.StartPacket(PacketTypeRealPath, reqid)
+ buf.AppendString(p.Path)
- b.AppendString(p.Path)
-
- return b.Packet(payload)
+ return buf.Packet(payload)
}
// UnmarshalPacketBody unmarshals the packet body from the given Buffer.
@@ -168,14 +186,17 @@
}
// MarshalPacket returns p as a two-part binary encoding of p.
-func (p *StatPacket) MarshalPacket(reqid uint32) (header, payload []byte, err error) {
- size := 4 + len(p.Path) // string(path)
+func (p *StatPacket) MarshalPacket(reqid uint32, b []byte) (header, payload []byte, err error) {
+ buf := NewBuffer(b)
+ if buf.Cap() < 9 {
+ size := 4 + len(p.Path) // string(path)
+ buf = NewMarshalBuffer(size)
+ }
- b := NewMarshalBuffer(PacketTypeStat, reqid, size)
+ buf.StartPacket(PacketTypeStat, reqid)
+ buf.AppendString(p.Path)
- b.AppendString(p.Path)
-
- return b.Packet(payload)
+ return buf.Packet(payload)
}
// UnmarshalPacketBody unmarshals the packet body from the given Buffer.
@@ -195,16 +216,19 @@
}
// MarshalPacket returns p as a two-part binary encoding of p.
-func (p *RenamePacket) MarshalPacket(reqid uint32) (header, payload []byte, err error) {
- // string(oldpath) + string(newpath)
- size := 4 + len(p.OldPath) + 4 + len(p.NewPath)
+func (p *RenamePacket) MarshalPacket(reqid uint32, b []byte) (header, payload []byte, err error) {
+ buf := NewBuffer(b)
+ if buf.Cap() < 9 {
+ // string(oldpath) + string(newpath)
+ size := 4 + len(p.OldPath) + 4 + len(p.NewPath)
+ buf = NewMarshalBuffer(size)
+ }
- b := NewMarshalBuffer(PacketTypeRename, reqid, size)
+ buf.StartPacket(PacketTypeRename, reqid)
+ buf.AppendString(p.OldPath)
+ buf.AppendString(p.NewPath)
- b.AppendString(p.OldPath)
- b.AppendString(p.NewPath)
-
- return b.Packet(payload)
+ return buf.Packet(payload)
}
// UnmarshalPacketBody unmarshals the packet body from the given Buffer.
@@ -227,14 +251,17 @@
}
// MarshalPacket returns p as a two-part binary encoding of p.
-func (p *ReadLinkPacket) MarshalPacket(reqid uint32) (header, payload []byte, err error) {
- size := 4 + len(p.Path) // string(path)
+func (p *ReadLinkPacket) MarshalPacket(reqid uint32, b []byte) (header, payload []byte, err error) {
+ buf := NewBuffer(b)
+ if buf.Cap() < 9 {
+ size := 4 + len(p.Path) // string(path)
+ buf = NewMarshalBuffer(size)
+ }
- b := NewMarshalBuffer(PacketTypeReadLink, reqid, size)
+ buf.StartPacket(PacketTypeReadLink, reqid)
+ buf.AppendString(p.Path)
- b.AppendString(p.Path)
-
- return b.Packet(payload)
+ return buf.Packet(payload)
}
// UnmarshalPacketBody unmarshals the packet body from the given Buffer.
@@ -258,17 +285,21 @@
}
// MarshalPacket returns p as a two-part binary encoding of p.
-func (p *SymlinkPacket) MarshalPacket(reqid uint32) (header, payload []byte, err error) {
- // string(targetpath) + string(linkpath)
- size := 4 + len(p.TargetPath) + 4 + len(p.LinkPath)
+func (p *SymlinkPacket) MarshalPacket(reqid uint32, b []byte) (header, payload []byte, err error) {
+ buf := NewBuffer(b)
+ if buf.Cap() < 9 {
+ // string(targetpath) + string(linkpath)
+ size := 4 + len(p.TargetPath) + 4 + len(p.LinkPath)
+ buf = NewMarshalBuffer(size)
+ }
- b := NewMarshalBuffer(PacketTypeSymlink, reqid, size)
+ buf.StartPacket(PacketTypeSymlink, reqid)
// Arguments were inadvertently reversed.
- b.AppendString(p.TargetPath)
- b.AppendString(p.LinkPath)
+ buf.AppendString(p.TargetPath)
+ buf.AppendString(p.LinkPath)
- return b.Packet(payload)
+ return buf.Packet(payload)
}
// UnmarshalPacketBody unmarshals the packet body from the given Buffer.
diff --git a/encoding/ssh/filexfer/path_packets_test.go b/encoding/ssh/filexfer/path_packets_test.go
index aba3200..852145e 100644
--- a/encoding/ssh/filexfer/path_packets_test.go
+++ b/encoding/ssh/filexfer/path_packets_test.go
@@ -17,7 +17,7 @@
Path: path,
}
- data, err := ComposePacket(p.MarshalPacket(id))
+ data, err := ComposePacket(p.MarshalPacket(id, nil))
if err != nil {
t.Fatal("unexpected error:", err)
}
@@ -62,7 +62,7 @@
},
}
- data, err := ComposePacket(p.MarshalPacket(id))
+ data, err := ComposePacket(p.MarshalPacket(id, nil))
if err != nil {
t.Fatal("unexpected error:", err)
}
@@ -112,7 +112,7 @@
Path: path,
}
- data, err := ComposePacket(p.MarshalPacket(id))
+ data, err := ComposePacket(p.MarshalPacket(id, nil))
if err != nil {
t.Fatal("unexpected error:", err)
}
@@ -157,7 +157,7 @@
},
}
- data, err := ComposePacket(p.MarshalPacket(id))
+ data, err := ComposePacket(p.MarshalPacket(id, nil))
if err != nil {
t.Fatal("unexpected error:", err)
}
@@ -207,7 +207,7 @@
Path: path,
}
- data, err := ComposePacket(p.MarshalPacket(id))
+ data, err := ComposePacket(p.MarshalPacket(id, nil))
if err != nil {
t.Fatal("unexpected error:", err)
}
@@ -247,7 +247,7 @@
Path: path,
}
- data, err := ComposePacket(p.MarshalPacket(id))
+ data, err := ComposePacket(p.MarshalPacket(id, nil))
if err != nil {
t.Fatal("unexpected error:", err)
}
@@ -287,7 +287,7 @@
Path: path,
}
- data, err := ComposePacket(p.MarshalPacket(id))
+ data, err := ComposePacket(p.MarshalPacket(id, nil))
if err != nil {
t.Fatal("unexpected error:", err)
}
@@ -329,7 +329,7 @@
NewPath: newpath,
}
- data, err := ComposePacket(p.MarshalPacket(id))
+ data, err := ComposePacket(p.MarshalPacket(id, nil))
if err != nil {
t.Fatal("unexpected error:", err)
}
@@ -374,7 +374,7 @@
Path: path,
}
- data, err := ComposePacket(p.MarshalPacket(id))
+ data, err := ComposePacket(p.MarshalPacket(id, nil))
if err != nil {
t.Fatal("unexpected error:", err)
}
@@ -416,7 +416,7 @@
TargetPath: targetpath,
}
- data, err := ComposePacket(p.MarshalPacket(id))
+ data, err := ComposePacket(p.MarshalPacket(id, nil))
if err != nil {
t.Fatal("unexpected error:", err)
}
diff --git a/encoding/ssh/filexfer/response_packets.go b/encoding/ssh/filexfer/response_packets.go
index 7c4b116..831b443 100644
--- a/encoding/ssh/filexfer/response_packets.go
+++ b/encoding/ssh/filexfer/response_packets.go
@@ -10,17 +10,20 @@
}
// MarshalPacket returns p as a two-part binary encoding of p.
-func (p *StatusPacket) MarshalPacket(reqid uint32) (header, payload []byte, err error) {
- // uint32(error/status code) + string(error message) + string(language tag)
- size := 4 + 4 + len(p.ErrorMessage) + 4 + len(p.LanguageTag)
+func (p *StatusPacket) MarshalPacket(reqid uint32, b []byte) (header, payload []byte, err error) {
+ buf := NewBuffer(b)
+ if buf.Cap() < 9 {
+ // uint32(error/status code) + string(error message) + string(language tag)
+ size := 4 + 4 + len(p.ErrorMessage) + 4 + len(p.LanguageTag)
+ buf = NewMarshalBuffer(size)
+ }
- b := NewMarshalBuffer(PacketTypeStatus, reqid, size)
+ buf.StartPacket(PacketTypeStatus, reqid)
+ buf.AppendUint32(uint32(p.StatusCode))
+ buf.AppendString(p.ErrorMessage)
+ buf.AppendString(p.LanguageTag)
- b.AppendUint32(uint32(p.StatusCode))
- b.AppendString(p.ErrorMessage)
- b.AppendString(p.LanguageTag)
-
- return b.Packet(payload)
+ return buf.Packet(payload)
}
// UnmarshalPacketBody unmarshals the packet body from the given Buffer.
@@ -49,14 +52,17 @@
}
// MarshalPacket returns p as a two-part binary encoding of p.
-func (p *HandlePacket) MarshalPacket(reqid uint32) (header, payload []byte, err error) {
- size := 4 + len(p.Handle) // string(handle)
+func (p *HandlePacket) MarshalPacket(reqid uint32, b []byte) (header, payload []byte, err error) {
+ buf := NewBuffer(b)
+ if buf.Cap() < 9 {
+ size := 4 + len(p.Handle) // string(handle)
+ buf = NewMarshalBuffer(size)
+ }
- b := NewMarshalBuffer(PacketTypeHandle, reqid, size)
+ buf.StartPacket(PacketTypeHandle, reqid)
+ buf.AppendString(p.Handle)
- b.AppendString(p.Handle)
-
- return b.Packet(payload)
+ return buf.Packet(payload)
}
// UnmarshalPacketBody unmarshals the packet body from the given Buffer.
@@ -75,14 +81,17 @@
}
// MarshalPacket returns p as a two-part binary encoding of p.
-func (p *DataPacket) MarshalPacket(reqid uint32) (header, payload []byte, err error) {
- size := 4 // uint32(len(data)); data content in payload
+func (p *DataPacket) MarshalPacket(reqid uint32, b []byte) (header, payload []byte, err error) {
+ buf := NewBuffer(b)
+ if buf.Cap() < 9 {
+ size := 4 // uint32(len(data)); data content in payload
+ buf = NewMarshalBuffer(size)
+ }
- b := NewMarshalBuffer(PacketTypeData, reqid, size)
+ buf.StartPacket(PacketTypeData, reqid)
+ buf.AppendUint32(uint32(len(p.Data)))
- b.AppendUint32(uint32(len(p.Data)))
-
- return b.Packet(p.Data)
+ return buf.Packet(p.Data)
}
// UnmarshalPacketBody unmarshals the packet body from the given Buffer.
@@ -101,22 +110,26 @@
}
// MarshalPacket returns p as a two-part binary encoding of p.
-func (p *NamePacket) MarshalPacket(reqid uint32) (header, payload []byte, err error) {
- size := 4 // uint32(len(entries))
+func (p *NamePacket) MarshalPacket(reqid uint32, b []byte) (header, payload []byte, err error) {
+ buf := NewBuffer(b)
+ if buf.Cap() < 9 {
+ size := 4 // uint32(len(entries))
- for _, e := range p.Entries {
- size += e.Len()
+ for _, e := range p.Entries {
+ size += e.Len()
+ }
+
+ buf = NewMarshalBuffer(size)
}
- b := NewMarshalBuffer(PacketTypeName, reqid, size)
-
- b.AppendUint32(uint32(len(p.Entries)))
+ buf.StartPacket(PacketTypeName, reqid)
+ buf.AppendUint32(uint32(len(p.Entries)))
for _, e := range p.Entries {
- e.MarshalInto(b)
+ e.MarshalInto(buf)
}
- return b.Packet(payload)
+ return buf.Packet(payload)
}
// UnmarshalPacketBody unmarshals the packet body from the given Buffer.
@@ -147,14 +160,17 @@
}
// MarshalPacket returns p as a two-part binary encoding of p.
-func (p *AttrsPacket) MarshalPacket(reqid uint32) (header, payload []byte, err error) {
- size := p.Attrs.Len() // ATTRS(attrs)
+func (p *AttrsPacket) MarshalPacket(reqid uint32, b []byte) (header, payload []byte, err error) {
+ buf := NewBuffer(b)
+ if buf.Cap() < 9 {
+ size := p.Attrs.Len() // ATTRS(attrs)
+ buf = NewMarshalBuffer(size)
+ }
- b := NewMarshalBuffer(PacketTypeAttrs, reqid, size)
+ buf.StartPacket(PacketTypeAttrs, reqid)
+ p.Attrs.MarshalInto(buf)
- p.Attrs.MarshalInto(b)
-
- return b.Packet(payload)
+ return buf.Packet(payload)
}
// UnmarshalPacketBody unmarshals the packet body from the given Buffer.
diff --git a/encoding/ssh/filexfer/response_packets_test.go b/encoding/ssh/filexfer/response_packets_test.go
index e39d709..23e42bb 100644
--- a/encoding/ssh/filexfer/response_packets_test.go
+++ b/encoding/ssh/filexfer/response_packets_test.go
@@ -21,7 +21,7 @@
LanguageTag: languageTag,
}
- data, err := ComposePacket(p.MarshalPacket(id))
+ data, err := ComposePacket(p.MarshalPacket(id, nil))
if err != nil {
t.Fatal("unexpected error:", err)
}
@@ -71,7 +71,7 @@
Handle: "somehandle",
}
- data, err := ComposePacket(p.MarshalPacket(id))
+ data, err := ComposePacket(p.MarshalPacket(id, nil))
if err != nil {
t.Fatal("unexpected error:", err)
}
@@ -112,7 +112,7 @@
Data: payload,
}
- data, err := ComposePacket(p.MarshalPacket(id))
+ data, err := ComposePacket(p.MarshalPacket(id, nil))
if err != nil {
t.Fatal("unexpected error:", err)
}
@@ -171,7 +171,7 @@
},
}
- data, err := ComposePacket(p.MarshalPacket(id))
+ data, err := ComposePacket(p.MarshalPacket(id, nil))
if err != nil {
t.Fatal("unexpected error:", err)
}
@@ -240,7 +240,7 @@
},
}
- data, err := ComposePacket(p.MarshalPacket(id))
+ data, err := ComposePacket(p.MarshalPacket(id, nil))
if err != nil {
t.Fatal("unexpected error:", err)
}