summaryrefslogtreecommitdiff
path: root/vendor/github.com/pkg/sftp/internal/encoding/ssh/filexfer
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/pkg/sftp/internal/encoding/ssh/filexfer')
-rw-r--r--vendor/github.com/pkg/sftp/internal/encoding/ssh/filexfer/attrs.go325
-rw-r--r--vendor/github.com/pkg/sftp/internal/encoding/ssh/filexfer/buffer.go293
-rw-r--r--vendor/github.com/pkg/sftp/internal/encoding/ssh/filexfer/extended_packets.go142
-rw-r--r--vendor/github.com/pkg/sftp/internal/encoding/ssh/filexfer/extensions.go46
-rw-r--r--vendor/github.com/pkg/sftp/internal/encoding/ssh/filexfer/filexfer.go54
-rw-r--r--vendor/github.com/pkg/sftp/internal/encoding/ssh/filexfer/fx.go147
-rw-r--r--vendor/github.com/pkg/sftp/internal/encoding/ssh/filexfer/fxp.go124
-rw-r--r--vendor/github.com/pkg/sftp/internal/encoding/ssh/filexfer/handle_packets.go249
-rw-r--r--vendor/github.com/pkg/sftp/internal/encoding/ssh/filexfer/init_packets.go99
-rw-r--r--vendor/github.com/pkg/sftp/internal/encoding/ssh/filexfer/open_packets.go89
-rw-r--r--vendor/github.com/pkg/sftp/internal/encoding/ssh/filexfer/packets.go323
-rw-r--r--vendor/github.com/pkg/sftp/internal/encoding/ssh/filexfer/path_packets.go368
-rw-r--r--vendor/github.com/pkg/sftp/internal/encoding/ssh/filexfer/permissions.go114
-rw-r--r--vendor/github.com/pkg/sftp/internal/encoding/ssh/filexfer/response_packets.go243
14 files changed, 2616 insertions, 0 deletions
diff --git a/vendor/github.com/pkg/sftp/internal/encoding/ssh/filexfer/attrs.go b/vendor/github.com/pkg/sftp/internal/encoding/ssh/filexfer/attrs.go
new file mode 100644
index 000000000..eed61bfc6
--- /dev/null
+++ b/vendor/github.com/pkg/sftp/internal/encoding/ssh/filexfer/attrs.go
@@ -0,0 +1,325 @@
+package filexfer
+
+// Attributes related flags.
+const (
+ AttrSize = 1 << iota // SSH_FILEXFER_ATTR_SIZE
+ AttrUIDGID // SSH_FILEXFER_ATTR_UIDGID
+ AttrPermissions // SSH_FILEXFER_ATTR_PERMISSIONS
+ AttrACModTime // SSH_FILEXFER_ACMODTIME
+
+ AttrExtended = 1 << 31 // SSH_FILEXFER_ATTR_EXTENDED
+)
+
+// Attributes defines the file attributes type defined in draft-ietf-secsh-filexfer-02
+//
+// Defined in: https://tools.ietf.org/html/draft-ietf-secsh-filexfer-02#section-5
+type Attributes struct {
+ Flags uint32
+
+ // AttrSize
+ Size uint64
+
+ // AttrUIDGID
+ UID uint32
+ GID uint32
+
+ // AttrPermissions
+ Permissions FileMode
+
+ // AttrACmodTime
+ ATime uint32
+ MTime uint32
+
+ // AttrExtended
+ ExtendedAttributes []ExtendedAttribute
+}
+
+// GetSize returns the Size field and a bool that is true if and only if the value is valid/defined.
+func (a *Attributes) GetSize() (size uint64, ok bool) {
+ return a.Size, a.Flags&AttrSize != 0
+}
+
+// SetSize is a convenience function that sets the Size field,
+// and marks the field as valid/defined in Flags.
+func (a *Attributes) SetSize(size uint64) {
+ a.Flags |= AttrSize
+ a.Size = size
+}
+
+// GetUIDGID returns the UID and GID fields and a bool that is true if and only if the values are valid/defined.
+func (a *Attributes) GetUIDGID() (uid, gid uint32, ok bool) {
+ return a.UID, a.GID, a.Flags&AttrUIDGID != 0
+}
+
+// SetUIDGID is a convenience function that sets the UID and GID fields,
+// and marks the fields as valid/defined in Flags.
+func (a *Attributes) SetUIDGID(uid, gid uint32) {
+ a.Flags |= AttrUIDGID
+ a.UID = uid
+ a.GID = gid
+}
+
+// GetPermissions returns the Permissions field and a bool that is true if and only if the value is valid/defined.
+func (a *Attributes) GetPermissions() (perms FileMode, ok bool) {
+ return a.Permissions, a.Flags&AttrPermissions != 0
+}
+
+// SetPermissions is a convenience function that sets the Permissions field,
+// and marks the field as valid/defined in Flags.
+func (a *Attributes) SetPermissions(perms FileMode) {
+ a.Flags |= AttrPermissions
+ a.Permissions = perms
+}
+
+// GetACModTime returns the ATime and MTime fields and a bool that is true if and only if the values are valid/defined.
+func (a *Attributes) GetACModTime() (atime, mtime uint32, ok bool) {
+ return a.ATime, a.MTime, a.Flags&AttrACModTime != 0
+}
+
+// SetACModTime is a convenience function that sets the ATime and MTime fields,
+// and marks the fields as valid/defined in Flags.
+func (a *Attributes) SetACModTime(atime, mtime uint32) {
+ a.Flags |= AttrACModTime
+ a.ATime = atime
+ a.MTime = mtime
+}
+
+// Len returns the number of bytes a would marshal into.
+func (a *Attributes) Len() int {
+ length := 4
+
+ if a.Flags&AttrSize != 0 {
+ length += 8
+ }
+
+ if a.Flags&AttrUIDGID != 0 {
+ length += 4 + 4
+ }
+
+ if a.Flags&AttrPermissions != 0 {
+ length += 4
+ }
+
+ if a.Flags&AttrACModTime != 0 {
+ length += 4 + 4
+ }
+
+ if a.Flags&AttrExtended != 0 {
+ length += 4
+
+ for _, ext := range a.ExtendedAttributes {
+ length += ext.Len()
+ }
+ }
+
+ return length
+}
+
+// MarshalInto marshals e onto the end of the given Buffer.
+func (a *Attributes) MarshalInto(b *Buffer) {
+ b.AppendUint32(a.Flags)
+
+ if a.Flags&AttrSize != 0 {
+ b.AppendUint64(a.Size)
+ }
+
+ if a.Flags&AttrUIDGID != 0 {
+ b.AppendUint32(a.UID)
+ b.AppendUint32(a.GID)
+ }
+
+ if a.Flags&AttrPermissions != 0 {
+ b.AppendUint32(uint32(a.Permissions))
+ }
+
+ if a.Flags&AttrACModTime != 0 {
+ b.AppendUint32(a.ATime)
+ b.AppendUint32(a.MTime)
+ }
+
+ if a.Flags&AttrExtended != 0 {
+ b.AppendUint32(uint32(len(a.ExtendedAttributes)))
+
+ for _, ext := range a.ExtendedAttributes {
+ ext.MarshalInto(b)
+ }
+ }
+}
+
+// MarshalBinary returns a as the binary encoding of a.
+func (a *Attributes) MarshalBinary() ([]byte, error) {
+ buf := NewBuffer(make([]byte, 0, a.Len()))
+ a.MarshalInto(buf)
+ return buf.Bytes(), nil
+}
+
+// UnmarshalFrom unmarshals an Attributes from the given Buffer into e.
+//
+// NOTE: The values of fields not covered in the a.Flags are explicitly undefined.
+func (a *Attributes) UnmarshalFrom(b *Buffer) (err error) {
+ flags, err := b.ConsumeUint32()
+ if err != nil {
+ return err
+ }
+
+ return a.XXX_UnmarshalByFlags(flags, b)
+}
+
+// XXX_UnmarshalByFlags uses the pre-existing a.Flags field to determine which fields to decode.
+// DO NOT USE THIS: it is an anti-corruption function to implement existing internal usage in pkg/sftp.
+// This function is not a part of any compatibility promise.
+func (a *Attributes) XXX_UnmarshalByFlags(flags uint32, b *Buffer) (err error) {
+ a.Flags = flags
+
+ // Short-circuit dummy attributes.
+ if a.Flags == 0 {
+ return nil
+ }
+
+ if a.Flags&AttrSize != 0 {
+ if a.Size, err = b.ConsumeUint64(); err != nil {
+ return err
+ }
+ }
+
+ if a.Flags&AttrUIDGID != 0 {
+ if a.UID, err = b.ConsumeUint32(); err != nil {
+ return err
+ }
+
+ if a.GID, err = b.ConsumeUint32(); err != nil {
+ return err
+ }
+ }
+
+ if a.Flags&AttrPermissions != 0 {
+ m, err := b.ConsumeUint32()
+ if err != nil {
+ return err
+ }
+
+ a.Permissions = FileMode(m)
+ }
+
+ if a.Flags&AttrACModTime != 0 {
+ if a.ATime, err = b.ConsumeUint32(); err != nil {
+ return err
+ }
+
+ if a.MTime, err = b.ConsumeUint32(); err != nil {
+ return err
+ }
+ }
+
+ if a.Flags&AttrExtended != 0 {
+ count, err := b.ConsumeUint32()
+ if err != nil {
+ return err
+ }
+
+ a.ExtendedAttributes = make([]ExtendedAttribute, count)
+ for i := range a.ExtendedAttributes {
+ a.ExtendedAttributes[i].UnmarshalFrom(b)
+ }
+ }
+
+ return nil
+}
+
+// UnmarshalBinary decodes the binary encoding of Attributes into e.
+func (a *Attributes) UnmarshalBinary(data []byte) error {
+ return a.UnmarshalFrom(NewBuffer(data))
+}
+
+// ExtendedAttribute defines the extended file attribute type defined in draft-ietf-secsh-filexfer-02
+//
+// Defined in: https://tools.ietf.org/html/draft-ietf-secsh-filexfer-02#section-5
+type ExtendedAttribute struct {
+ Type string
+ Data string
+}
+
+// Len returns the number of bytes e would marshal into.
+func (e *ExtendedAttribute) Len() int {
+ return 4 + len(e.Type) + 4 + len(e.Data)
+}
+
+// MarshalInto marshals e onto the end of the given Buffer.
+func (e *ExtendedAttribute) MarshalInto(b *Buffer) {
+ b.AppendString(e.Type)
+ b.AppendString(e.Data)
+}
+
+// MarshalBinary returns e as the binary encoding of e.
+func (e *ExtendedAttribute) MarshalBinary() ([]byte, error) {
+ buf := NewBuffer(make([]byte, 0, e.Len()))
+ e.MarshalInto(buf)
+ return buf.Bytes(), nil
+}
+
+// UnmarshalFrom unmarshals an ExtendedAattribute from the given Buffer into e.
+func (e *ExtendedAttribute) UnmarshalFrom(b *Buffer) (err error) {
+ if e.Type, err = b.ConsumeString(); err != nil {
+ return err
+ }
+
+ if e.Data, err = b.ConsumeString(); err != nil {
+ return err
+ }
+
+ return nil
+}
+
+// UnmarshalBinary decodes the binary encoding of ExtendedAttribute into e.
+func (e *ExtendedAttribute) UnmarshalBinary(data []byte) error {
+ return e.UnmarshalFrom(NewBuffer(data))
+}
+
+// NameEntry implements the SSH_FXP_NAME repeated data type from draft-ietf-secsh-filexfer-02
+//
+// This type is incompatible with versions 4 or higher.
+type NameEntry struct {
+ Filename string
+ Longname string
+ Attrs Attributes
+}
+
+// Len returns the number of bytes e would marshal into.
+func (e *NameEntry) Len() int {
+ return 4 + len(e.Filename) + 4 + len(e.Longname) + e.Attrs.Len()
+}
+
+// MarshalInto marshals e onto the end of the given Buffer.
+func (e *NameEntry) MarshalInto(b *Buffer) {
+ b.AppendString(e.Filename)
+ b.AppendString(e.Longname)
+
+ e.Attrs.MarshalInto(b)
+}
+
+// MarshalBinary returns e as the binary encoding of e.
+func (e *NameEntry) MarshalBinary() ([]byte, error) {
+ buf := NewBuffer(make([]byte, 0, e.Len()))
+ e.MarshalInto(buf)
+ return buf.Bytes(), nil
+}
+
+// UnmarshalFrom unmarshals an NameEntry from the given Buffer into e.
+//
+// NOTE: The values of fields not covered in the a.Flags are explicitly undefined.
+func (e *NameEntry) UnmarshalFrom(b *Buffer) (err error) {
+ if e.Filename, err = b.ConsumeString(); err != nil {
+ return err
+ }
+
+ if e.Longname, err = b.ConsumeString(); err != nil {
+ return err
+ }
+
+ return e.Attrs.UnmarshalFrom(b)
+}
+
+// UnmarshalBinary decodes the binary encoding of NameEntry into e.
+func (e *NameEntry) UnmarshalBinary(data []byte) error {
+ return e.UnmarshalFrom(NewBuffer(data))
+}
diff --git a/vendor/github.com/pkg/sftp/internal/encoding/ssh/filexfer/buffer.go b/vendor/github.com/pkg/sftp/internal/encoding/ssh/filexfer/buffer.go
new file mode 100644
index 000000000..a6086036e
--- /dev/null
+++ b/vendor/github.com/pkg/sftp/internal/encoding/ssh/filexfer/buffer.go
@@ -0,0 +1,293 @@
+package filexfer
+
+import (
+ "encoding/binary"
+ "errors"
+)
+
+// Various encoding errors.
+var (
+ ErrShortPacket = errors.New("packet too short")
+ ErrLongPacket = errors.New("packet too long")
+)
+
+// Buffer wraps up the various encoding details of the SSH format.
+//
+// Data types are encoded as per section 4 from https://tools.ietf.org/html/draft-ietf-secsh-architecture-09#page-8
+type Buffer struct {
+ b []byte
+ off int
+}
+
+// NewBuffer creates and initializes a new buffer using buf as its initial contents.
+// The new buffer takes ownership of buf, and the caller should not use buf after this call.
+//
+// In most cases, new(Buffer) (or just declaring a Buffer variable) is sufficient to initialize a Buffer.
+func NewBuffer(buf []byte) *Buffer {
+ return &Buffer{
+ b: buf,
+ }
+}
+
+// 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))
+}
+
+// Bytes returns a slice of length b.Len() holding the unconsumed bytes in the Buffer.
+// The slice is valid for use only until the next buffer modification
+// (that is, only until the next call to an Append or Consume method).
+func (b *Buffer) Bytes() []byte {
+ return b.b[b.off:]
+}
+
+// Len returns the number of unconsumed bytes in the buffer.
+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) }
+
+// Reset resets the buffer to be empty, but it retains the underlying storage for use by future Appends.
+func (b *Buffer) Reset() {
+ b.b = b.b[:0]
+ b.off = 0
+}
+
+// StartPacket resets and initializes the buffer to be ready to start marshaling a packet into.
+// It truncates the buffer, reserves space for uint32(length), then appends the given packetType and requestID.
+func (b *Buffer) StartPacket(packetType PacketType, requestID uint32) {
+ b.b, b.off = append(b.b[:0], make([]byte, 4)...), 0
+
+ b.AppendUint8(uint8(packetType))
+ b.AppendUint32(requestID)
+}
+
+// Packet finalizes the packet started from StartPacket.
+// It is expected that this will end the ownership of the underlying byte-slice,
+// and so the returned byte-slices may be reused the same as any other byte-slice,
+// the caller should not use this buffer after this call.
+//
+// It writes the packet body length into the first four bytes of the buffer in network byte order (big endian).
+// The packet body length is the length of this buffer less the 4-byte length itself, plus the length of payload.
+//
+// It is assumed that no Consume methods have been called on this buffer,
+// and so it returns the whole underlying slice.
+func (b *Buffer) Packet(payload []byte) (header, payloadPassThru []byte, err error) {
+ b.PutLength(len(b.b) - 4 + len(payload))
+
+ return b.b, payload, nil
+}
+
+// ConsumeUint8 consumes a single byte from the buffer.
+// If the buffer does not have enough data, it will return ErrShortPacket.
+func (b *Buffer) ConsumeUint8() (uint8, error) {
+ if b.Len() < 1 {
+ return 0, ErrShortPacket
+ }
+
+ var v uint8
+ v, b.off = b.b[b.off], b.off+1
+ return v, nil
+}
+
+// AppendUint8 appends a single byte into the buffer.
+func (b *Buffer) AppendUint8(v uint8) {
+ b.b = append(b.b, v)
+}
+
+// ConsumeBool consumes a single byte from the buffer, and returns true if that byte is non-zero.
+// If the buffer does not have enough data, it will return ErrShortPacket.
+func (b *Buffer) ConsumeBool() (bool, error) {
+ v, err := b.ConsumeUint8()
+ if err != nil {
+ return false, err
+ }
+
+ return v != 0, nil
+}
+
+// AppendBool appends a single bool into the buffer.
+// It encodes it as a single byte, with false as 0, and true as 1.
+func (b *Buffer) AppendBool(v bool) {
+ if v {
+ b.AppendUint8(1)
+ } else {
+ b.AppendUint8(0)
+ }
+}
+
+// ConsumeUint16 consumes a single uint16 from the buffer, in network byte order (big-endian).
+// If the buffer does not have enough data, it will return ErrShortPacket.
+func (b *Buffer) ConsumeUint16() (uint16, error) {
+ if b.Len() < 2 {
+ return 0, ErrShortPacket
+ }
+
+ v := binary.BigEndian.Uint16(b.b[b.off:])
+ b.off += 2
+ return v, nil
+}
+
+// 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),
+ )
+}
+
+// unmarshalUint32 is used internally to read the packet length.
+// It is unsafe, and so not exported.
+// Even within this package, its use should be avoided.
+func unmarshalUint32(b []byte) uint32 {
+ return binary.BigEndian.Uint32(b[:4])
+}
+
+// ConsumeUint32 consumes a single uint32 from the buffer, in network byte order (big-endian).
+// If the buffer does not have enough data, it will return ErrShortPacket.
+func (b *Buffer) ConsumeUint32() (uint32, error) {
+ if b.Len() < 4 {
+ return 0, ErrShortPacket
+ }
+
+ v := binary.BigEndian.Uint32(b.b[b.off:])
+ b.off += 4
+ return v, nil
+}
+
+// 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),
+ )
+}
+
+// ConsumeUint64 consumes a single uint64 from the buffer, in network byte order (big-endian).
+// If the buffer does not have enough data, it will return ErrShortPacket.
+func (b *Buffer) ConsumeUint64() (uint64, error) {
+ if b.Len() < 8 {
+ return 0, ErrShortPacket
+ }
+
+ v := binary.BigEndian.Uint64(b.b[b.off:])
+ b.off += 8
+ return v, nil
+}
+
+// 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),
+ )
+}
+
+// ConsumeInt64 consumes a single int64 from the buffer, in network byte order (big-endian) with two’s complement.
+// If the buffer does not have enough data, it will return ErrShortPacket.
+func (b *Buffer) ConsumeInt64() (int64, error) {
+ u, err := b.ConsumeUint64()
+ if err != nil {
+ return 0, err
+ }
+
+ return int64(u), err
+}
+
+// AppendInt64 appends a single int64 into the buffer, in network byte order (big-endian) with two’s complement.
+func (b *Buffer) AppendInt64(v int64) {
+ b.AppendUint64(uint64(v))
+}
+
+// ConsumeByteSlice 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, or defines a length larger than available, it will return ErrShortPacket.
+//
+// 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).
+//
+// In no case will any Consume calls return overlapping slice aliases,
+// and Append calls are guaranteed to not disturb this slice alias.
+func (b *Buffer) ConsumeByteSlice() ([]byte, error) {
+ length, err := b.ConsumeUint32()
+ if err != nil {
+ return nil, err
+ }
+
+ if b.Len() < int(length) {
+ return nil, ErrShortPacket
+ }
+
+ v := b.b[b.off:]
+ if len(v) > int(length) {
+ v = v[:length:length]
+ }
+ b.off += int(length)
+ return v, nil
+}
+
+// AppendByteSlice appends a single string of raw binary data into the buffer.
+// A string is a uint32 length, followed by that number of raw bytes.
+func (b *Buffer) AppendByteSlice(v []byte) {
+ b.AppendUint32(uint32(len(v)))
+ b.b = append(b.b, v...)
+}
+
+// ConsumeString consumes a single string of 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, or defines a length larger than available, it will return ErrShortPacket.
+//
+// NOTE: Go implicitly assumes that strings contain UTF-8 encoded data.
+// All caveats on using arbitrary binary data in Go strings applies.
+func (b *Buffer) ConsumeString() (string, error) {
+ v, err := b.ConsumeByteSlice()
+ if err != nil {
+ return "", err
+ }
+
+ return string(v), nil
+}
+
+// AppendString appends a single string of binary data into the buffer.
+// A string is a uint32 length, followed by that number of raw bytes.
+func (b *Buffer) AppendString(v string) {
+ b.AppendByteSlice([]byte(v))
+}
+
+// PutLength writes the given size into the first four bytes of the buffer in network byte order (big endian).
+func (b *Buffer) PutLength(size int) {
+ if len(b.b) < 4 {
+ b.b = append(b.b, make([]byte, 4-len(b.b))...)
+ }
+
+ binary.BigEndian.PutUint32(b.b, uint32(size))
+}
+
+// MarshalBinary returns a clone of the full internal buffer.
+func (b *Buffer) MarshalBinary() ([]byte, error) {
+ clone := make([]byte, len(b.b))
+ n := copy(clone, b.b)
+ return clone[:n], nil
+}
+
+// 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 {
+ if grow := len(data) - len(b.b); grow > 0 {
+ b.b = append(b.b, make([]byte, grow)...)
+ }
+
+ n := copy(b.b, data)
+ b.b = b.b[:n]
+ b.off = 0
+ return nil
+}
diff --git a/vendor/github.com/pkg/sftp/internal/encoding/ssh/filexfer/extended_packets.go b/vendor/github.com/pkg/sftp/internal/encoding/ssh/filexfer/extended_packets.go
new file mode 100644
index 000000000..6b7b2cef4
--- /dev/null
+++ b/vendor/github.com/pkg/sftp/internal/encoding/ssh/filexfer/extended_packets.go
@@ -0,0 +1,142 @@
+package filexfer
+
+import (
+ "encoding"
+ "sync"
+)
+
+// ExtendedData aliases the untyped interface composition of encoding.BinaryMarshaler and encoding.BinaryUnmarshaler.
+type ExtendedData = interface {
+ encoding.BinaryMarshaler
+ encoding.BinaryUnmarshaler
+}
+
+// ExtendedDataConstructor defines a function that returns a new(ArbitraryExtendedPacket).
+type ExtendedDataConstructor func() ExtendedData
+
+var extendedPacketTypes = struct {
+ mu sync.RWMutex
+ constructors map[string]ExtendedDataConstructor
+}{
+ constructors: make(map[string]ExtendedDataConstructor),
+}
+
+// RegisterExtendedPacketType defines a specific ExtendedDataConstructor for the given extension string.
+func RegisterExtendedPacketType(extension string, constructor ExtendedDataConstructor) {
+ extendedPacketTypes.mu.Lock()
+ defer extendedPacketTypes.mu.Unlock()
+
+ if _, exist := extendedPacketTypes.constructors[extension]; exist {
+ panic("encoding/ssh/filexfer: multiple registration of extended packet type " + extension)
+ }
+
+ extendedPacketTypes.constructors[extension] = constructor
+}
+
+func newExtendedPacket(extension string) ExtendedData {
+ extendedPacketTypes.mu.RLock()
+ defer extendedPacketTypes.mu.RUnlock()
+
+ if f := extendedPacketTypes.constructors[extension]; f != nil {
+ return f()
+ }
+
+ return new(Buffer)
+}
+
+// ExtendedPacket defines the SSH_FXP_CLOSE packet.
+type ExtendedPacket struct {
+ ExtendedRequest string
+
+ Data ExtendedData
+}
+
+// Type returns the SSH_FXP_xy value associated with this packet type.
+func (p *ExtendedPacket) Type() PacketType {
+ return PacketTypeExtended
+}
+
+// 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, 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)
+ }
+
+ buf.StartPacket(PacketTypeExtended, reqid)
+ buf.AppendString(p.ExtendedRequest)
+
+ if p.Data != nil {
+ payload, err = p.Data.MarshalBinary()
+ if err != nil {
+ return nil, nil, err
+ }
+ }
+
+ return buf.Packet(payload)
+}
+
+// UnmarshalPacketBody unmarshals the packet body from the given Buffer.
+// It is assumed that the uint32(request-id) has already been consumed.
+//
+// If p.Data is nil, and the extension has been registered, a new type will be made from the registration.
+// If the extension has not been registered, then a new Buffer will be allocated.
+// Then the request-specific-data will be unmarshaled from the rest of the buffer.
+func (p *ExtendedPacket) UnmarshalPacketBody(buf *Buffer) (err error) {
+ if p.ExtendedRequest, err = buf.ConsumeString(); err != nil {
+ return err
+ }
+
+ if p.Data == nil {
+ p.Data = newExtendedPacket(p.ExtendedRequest)
+ }
+
+ return p.Data.UnmarshalBinary(buf.Bytes())
+}
+
+// ExtendedReplyPacket defines the SSH_FXP_CLOSE packet.
+type ExtendedReplyPacket struct {
+ Data ExtendedData
+}
+
+// Type returns the SSH_FXP_xy value associated with this packet type.
+func (p *ExtendedReplyPacket) Type() PacketType {
+ return PacketTypeExtendedReply
+}
+
+// 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, 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()
+ if err != nil {
+ return nil, nil, err
+ }
+ }
+
+ return buf.Packet(payload)
+}
+
+// UnmarshalPacketBody unmarshals the packet body from the given Buffer.
+// It is assumed that the uint32(request-id) has already been consumed.
+//
+// If p.Data is nil, and there is request-specific-data,
+// then the request-specific-data will be wrapped in a Buffer and assigned to p.Data.
+func (p *ExtendedReplyPacket) UnmarshalPacketBody(buf *Buffer) (err error) {
+ if p.Data == nil {
+ p.Data = new(Buffer)
+ }
+
+ return p.Data.UnmarshalBinary(buf.Bytes())
+}
diff --git a/vendor/github.com/pkg/sftp/internal/encoding/ssh/filexfer/extensions.go b/vendor/github.com/pkg/sftp/internal/encoding/ssh/filexfer/extensions.go
new file mode 100644
index 000000000..11c0b99c2
--- /dev/null
+++ b/vendor/github.com/pkg/sftp/internal/encoding/ssh/filexfer/extensions.go
@@ -0,0 +1,46 @@
+package filexfer
+
+// ExtensionPair defines the extension-pair type defined in draft-ietf-secsh-filexfer-13.
+// This type is backwards-compatible with how draft-ietf-secsh-filexfer-02 defines extensions.
+//
+// Defined in: https://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-4.2
+type ExtensionPair struct {
+ Name string
+ Data string
+}
+
+// Len returns the number of bytes e would marshal into.
+func (e *ExtensionPair) Len() int {
+ return 4 + len(e.Name) + 4 + len(e.Data)
+}
+
+// MarshalInto marshals e onto the end of the given Buffer.
+func (e *ExtensionPair) MarshalInto(buf *Buffer) {
+ buf.AppendString(e.Name)
+ buf.AppendString(e.Data)
+}
+
+// MarshalBinary returns e as the binary encoding of e.
+func (e *ExtensionPair) MarshalBinary() ([]byte, error) {
+ buf := NewBuffer(make([]byte, 0, e.Len()))
+ e.MarshalInto(buf)
+ return buf.Bytes(), nil
+}
+
+// UnmarshalFrom unmarshals an ExtensionPair from the given Buffer into e.
+func (e *ExtensionPair) UnmarshalFrom(buf *Buffer) (err error) {
+ if e.Name, err = buf.ConsumeString(); err != nil {
+ return err
+ }
+
+ if e.Data, err = buf.ConsumeString(); err != nil {
+ return err
+ }
+
+ return nil
+}
+
+// UnmarshalBinary decodes the binary encoding of ExtensionPair into e.
+func (e *ExtensionPair) UnmarshalBinary(data []byte) error {
+ return e.UnmarshalFrom(NewBuffer(data))
+}
diff --git a/vendor/github.com/pkg/sftp/internal/encoding/ssh/filexfer/filexfer.go b/vendor/github.com/pkg/sftp/internal/encoding/ssh/filexfer/filexfer.go
new file mode 100644
index 000000000..1e5abf746
--- /dev/null
+++ b/vendor/github.com/pkg/sftp/internal/encoding/ssh/filexfer/filexfer.go
@@ -0,0 +1,54 @@
+// Package filexfer implements the wire encoding for secsh-filexfer as described in https://tools.ietf.org/html/draft-ietf-secsh-filexfer-02
+package filexfer
+
+// PacketMarshaller narrowly defines packets that will only be transmitted.
+//
+// ExtendedPacket types will often only implement this interface,
+// since decoding the whole packet body of an ExtendedPacket can only be done dependent on the ExtendedRequest field.
+type PacketMarshaller interface {
+ // 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)
+}
+
+// Packet defines the behavior of a full generic SFTP packet.
+//
+// InitPacket, and VersionPacket are not generic SFTP packets, and instead implement (Un)MarshalBinary.
+//
+// ExtendedPacket types should not iplement this interface,
+// since decoding the whole packet body of an ExtendedPacket can only be done dependent on the ExtendedRequest field.
+type Packet interface {
+ PacketMarshaller
+
+ // Type returns the SSH_FXP_xy value associated with the specific packet.
+ Type() PacketType
+
+ // 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.
+ //
+ // Implementations should not alias the given Buffer,
+ // instead they can consider prepopulating an internal buffer as a hint,
+ // and copying into that buffer if it has sufficient length.
+ UnmarshalPacketBody(buf *Buffer) error
+}
+
+// ComposePacket converts returns from MarshalPacket into an equivalent call to MarshalBinary.
+func ComposePacket(header, payload []byte, err error) ([]byte, error) {
+ return append(header, payload...), err
+}
+
+// Default length values,
+// Defined in draft-ietf-secsh-filexfer-02 section 3.
+const (
+ DefaultMaxPacketLength = 34000
+ DefaultMaxDataLength = 32768
+)
diff --git a/vendor/github.com/pkg/sftp/internal/encoding/ssh/filexfer/fx.go b/vendor/github.com/pkg/sftp/internal/encoding/ssh/filexfer/fx.go
new file mode 100644
index 000000000..48f869861
--- /dev/null
+++ b/vendor/github.com/pkg/sftp/internal/encoding/ssh/filexfer/fx.go
@@ -0,0 +1,147 @@
+package filexfer
+
+import (
+ "fmt"
+)
+
+// Status defines the SFTP error codes used in SSH_FXP_STATUS response packets.
+type Status uint32
+
+// Defines the various SSH_FX_* values.
+const (
+ // see draft-ietf-secsh-filexfer-02
+ // https://tools.ietf.org/html/draft-ietf-secsh-filexfer-02#section-7
+ StatusOK = Status(iota)
+ StatusEOF
+ StatusNoSuchFile
+ StatusPermissionDenied
+ StatusFailure
+ StatusBadMessage
+ StatusNoConnection
+ StatusConnectionLost
+ StatusOPUnsupported
+
+ // https://tools.ietf.org/html/draft-ietf-secsh-filexfer-03#section-7
+ StatusV4InvalidHandle
+ StatusV4NoSuchPath
+ StatusV4FileAlreadyExists
+ StatusV4WriteProtect
+
+ // https://tools.ietf.org/html/draft-ietf-secsh-filexfer-04#section-7
+ StatusV4NoMedia
+
+ // https://tools.ietf.org/html/draft-ietf-secsh-filexfer-05#section-7
+ StatusV5NoSpaceOnFilesystem
+ StatusV5QuotaExceeded
+ StatusV5UnknownPrincipal
+ StatusV5LockConflict
+
+ // https://tools.ietf.org/html/draft-ietf-secsh-filexfer-06#section-8
+ StatusV6DirNotEmpty
+ StatusV6NotADirectory
+ StatusV6InvalidFilename
+ StatusV6LinkLoop
+
+ // https://tools.ietf.org/html/draft-ietf-secsh-filexfer-07#section-8
+ StatusV6CannotDelete
+ StatusV6InvalidParameter
+ StatusV6FileIsADirectory
+ StatusV6ByteRangeLockConflict
+ StatusV6ByteRangeLockRefused
+ StatusV6DeletePending
+
+ // https://tools.ietf.org/html/draft-ietf-secsh-filexfer-08#section-8.1
+ StatusV6FileCorrupt
+
+ // https://tools.ietf.org/html/draft-ietf-secsh-filexfer-10#section-9.1
+ StatusV6OwnerInvalid
+ StatusV6GroupInvalid
+
+ // https://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-9.1
+ StatusV6NoMatchingByteRangeLock
+)
+
+func (s Status) Error() string {
+ return s.String()
+}
+
+// Is returns true if the target is the same Status code,
+// or target is a StatusPacket with the same Status code.
+func (s Status) Is(target error) bool {
+ if target, ok := target.(*StatusPacket); ok {
+ return target.StatusCode == s
+ }
+
+ return s == target
+}
+
+func (s Status) String() string {
+ switch s {
+ case StatusOK:
+ return "SSH_FX_OK"
+ case StatusEOF:
+ return "SSH_FX_EOF"
+ case StatusNoSuchFile:
+ return "SSH_FX_NO_SUCH_FILE"
+ case StatusPermissionDenied:
+ return "SSH_FX_PERMISSION_DENIED"
+ case StatusFailure:
+ return "SSH_FX_FAILURE"
+ case StatusBadMessage:
+ return "SSH_FX_BAD_MESSAGE"
+ case StatusNoConnection:
+ return "SSH_FX_NO_CONNECTION"
+ case StatusConnectionLost:
+ return "SSH_FX_CONNECTION_LOST"
+ case StatusOPUnsupported:
+ return "SSH_FX_OP_UNSUPPORTED"
+ case StatusV4InvalidHandle:
+ return "SSH_FX_INVALID_HANDLE"
+ case StatusV4NoSuchPath:
+ return "SSH_FX_NO_SUCH_PATH"
+ case StatusV4FileAlreadyExists:
+ return "SSH_FX_FILE_ALREADY_EXISTS"
+ case StatusV4WriteProtect:
+ return "SSH_FX_WRITE_PROTECT"
+ case StatusV4NoMedia:
+ return "SSH_FX_NO_MEDIA"
+ case StatusV5NoSpaceOnFilesystem:
+ return "SSH_FX_NO_SPACE_ON_FILESYSTEM"
+ case StatusV5QuotaExceeded:
+ return "SSH_FX_QUOTA_EXCEEDED"
+ case StatusV5UnknownPrincipal:
+ return "SSH_FX_UNKNOWN_PRINCIPAL"
+ case StatusV5LockConflict:
+ return "SSH_FX_LOCK_CONFLICT"
+ case StatusV6DirNotEmpty:
+ return "SSH_FX_DIR_NOT_EMPTY"
+ case StatusV6NotADirectory:
+ return "SSH_FX_NOT_A_DIRECTORY"
+ case StatusV6InvalidFilename:
+ return "SSH_FX_INVALID_FILENAME"
+ case StatusV6LinkLoop:
+ return "SSH_FX_LINK_LOOP"
+ case StatusV6CannotDelete:
+ return "SSH_FX_CANNOT_DELETE"
+ case StatusV6InvalidParameter:
+ return "SSH_FX_INVALID_PARAMETER"
+ case StatusV6FileIsADirectory:
+ return "SSH_FX_FILE_IS_A_DIRECTORY"
+ case StatusV6ByteRangeLockConflict:
+ return "SSH_FX_BYTE_RANGE_LOCK_CONFLICT"
+ case StatusV6ByteRangeLockRefused:
+ return "SSH_FX_BYTE_RANGE_LOCK_REFUSED"
+ case StatusV6DeletePending:
+ return "SSH_FX_DELETE_PENDING"
+ case StatusV6FileCorrupt:
+ return "SSH_FX_FILE_CORRUPT"
+ case StatusV6OwnerInvalid:
+ return "SSH_FX_OWNER_INVALID"
+ case StatusV6GroupInvalid:
+ return "SSH_FX_GROUP_INVALID"
+ case StatusV6NoMatchingByteRangeLock:
+ return "SSH_FX_NO_MATCHING_BYTE_RANGE_LOCK"
+ default:
+ return fmt.Sprintf("SSH_FX_UNKNOWN(%d)", s)
+ }
+}
diff --git a/vendor/github.com/pkg/sftp/internal/encoding/ssh/filexfer/fxp.go b/vendor/github.com/pkg/sftp/internal/encoding/ssh/filexfer/fxp.go
new file mode 100644
index 000000000..15caf6d28
--- /dev/null
+++ b/vendor/github.com/pkg/sftp/internal/encoding/ssh/filexfer/fxp.go
@@ -0,0 +1,124 @@
+package filexfer
+
+import (
+ "fmt"
+)
+
+// PacketType defines the various SFTP packet types.
+type PacketType uint8
+
+// Request packet types.
+const (
+ // https://tools.ietf.org/html/draft-ietf-secsh-filexfer-02#section-3
+ PacketTypeInit = PacketType(iota + 1)
+ PacketTypeVersion
+ PacketTypeOpen
+ PacketTypeClose
+ PacketTypeRead
+ PacketTypeWrite
+ PacketTypeLStat
+ PacketTypeFStat
+ PacketTypeSetstat
+ PacketTypeFSetstat
+ PacketTypeOpenDir
+ PacketTypeReadDir
+ PacketTypeRemove
+ PacketTypeMkdir
+ PacketTypeRmdir
+ PacketTypeRealPath
+ PacketTypeStat
+ PacketTypeRename
+ PacketTypeReadLink
+ PacketTypeSymlink
+
+ // https://tools.ietf.org/html/draft-ietf-secsh-filexfer-07#section-3.3
+ PacketTypeV6Link
+
+ // https://tools.ietf.org/html/draft-ietf-secsh-filexfer-08#section-3.3
+ PacketTypeV6Block
+ PacketTypeV6Unblock
+)
+
+// Response packet types.
+const (
+ // https://tools.ietf.org/html/draft-ietf-secsh-filexfer-02#section-3
+ PacketTypeStatus = PacketType(iota + 101)
+ PacketTypeHandle
+ PacketTypeData
+ PacketTypeName
+ PacketTypeAttrs
+)
+
+// Extended packet types.
+const (
+ // https://tools.ietf.org/html/draft-ietf-secsh-filexfer-02#section-3
+ PacketTypeExtended = PacketType(iota + 200)
+ PacketTypeExtendedReply
+)
+
+func (f PacketType) String() string {
+ switch f {
+ case PacketTypeInit:
+ return "SSH_FXP_INIT"
+ case PacketTypeVersion:
+ return "SSH_FXP_VERSION"
+ case PacketTypeOpen:
+ return "SSH_FXP_OPEN"
+ case PacketTypeClose:
+ return "SSH_FXP_CLOSE"
+ case PacketTypeRead:
+ return "SSH_FXP_READ"
+ case PacketTypeWrite:
+ return "SSH_FXP_WRITE"
+ case PacketTypeLStat:
+ return "SSH_FXP_LSTAT"
+ case PacketTypeFStat:
+ return "SSH_FXP_FSTAT"
+ case PacketTypeSetstat:
+ return "SSH_FXP_SETSTAT"
+ case PacketTypeFSetstat:
+ return "SSH_FXP_FSETSTAT"
+ case PacketTypeOpenDir:
+ return "SSH_FXP_OPENDIR"
+ case PacketTypeReadDir:
+ return "SSH_FXP_READDIR"
+ case PacketTypeRemove:
+ return "SSH_FXP_REMOVE"
+ case PacketTypeMkdir:
+ return "SSH_FXP_MKDIR"
+ case PacketTypeRmdir:
+ return "SSH_FXP_RMDIR"
+ case PacketTypeRealPath:
+ return "SSH_FXP_REALPATH"
+ case PacketTypeStat:
+ return "SSH_FXP_STAT"
+ case PacketTypeRename:
+ return "SSH_FXP_RENAME"
+ case PacketTypeReadLink:
+ return "SSH_FXP_READLINK"
+ case PacketTypeSymlink:
+ return "SSH_FXP_SYMLINK"
+ case PacketTypeV6Link:
+ return "SSH_FXP_LINK"
+ case PacketTypeV6Block:
+ return "SSH_FXP_BLOCK"
+ case PacketTypeV6Unblock:
+ return "SSH_FXP_UNBLOCK"
+ case PacketTypeStatus:
+ return "SSH_FXP_STATUS"
+ case PacketTypeHandle:
+ return "SSH_FXP_HANDLE"
+ case PacketTypeData:
+ return "SSH_FXP_DATA"
+ case PacketTypeName:
+ return "SSH_FXP_NAME"
+ case PacketTypeAttrs:
+ return "SSH_FXP_ATTRS"
+ case PacketTypeExtended:
+ return "SSH_FXP_EXTENDED"
+ case PacketTypeExtendedReply:
+ return "SSH_FXP_EXTENDED_REPLY"
+ default:
+ return fmt.Sprintf("SSH_FXP_UNKNOWN(%d)", f)
+ }
+}
diff --git a/vendor/github.com/pkg/sftp/internal/encoding/ssh/filexfer/handle_packets.go b/vendor/github.com/pkg/sftp/internal/encoding/ssh/filexfer/handle_packets.go
new file mode 100644
index 000000000..a14277128
--- /dev/null
+++ b/vendor/github.com/pkg/sftp/internal/encoding/ssh/filexfer/handle_packets.go
@@ -0,0 +1,249 @@
+package filexfer
+
+// ClosePacket defines the SSH_FXP_CLOSE packet.
+type ClosePacket struct {
+ Handle string
+}
+
+// Type returns the SSH_FXP_xy value associated with this packet type.
+func (p *ClosePacket) Type() PacketType {
+ return PacketTypeClose
+}
+
+// MarshalPacket returns p as a two-part binary encoding of p.
+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)
+ }
+
+ buf.StartPacket(PacketTypeClose, reqid)
+ buf.AppendString(p.Handle)
+
+ return buf.Packet(payload)
+}
+
+// UnmarshalPacketBody unmarshals the packet body from the given Buffer.
+// It is assumed that the uint32(request-id) has already been consumed.
+func (p *ClosePacket) UnmarshalPacketBody(buf *Buffer) (err error) {
+ if p.Handle, err = buf.ConsumeString(); err != nil {
+ return err
+ }
+
+ return nil
+}
+
+// ReadPacket defines the SSH_FXP_READ packet.
+type ReadPacket struct {
+ Handle string
+ Offset uint64
+ Len uint32
+}
+
+// Type returns the SSH_FXP_xy value associated with this packet type.
+func (p *ReadPacket) Type() PacketType {
+ return PacketTypeRead
+}
+
+// MarshalPacket returns p as a two-part binary encoding of p.
+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)
+ }
+
+ buf.StartPacket(PacketTypeRead, reqid)
+ buf.AppendString(p.Handle)
+ buf.AppendUint64(p.Offset)
+ buf.AppendUint32(p.Len)
+
+ return buf.Packet(payload)
+}
+
+// UnmarshalPacketBody unmarshals the packet body from the given Buffer.
+// It is assumed that the uint32(request-id) has already been consumed.
+func (p *ReadPacket) UnmarshalPacketBody(buf *Buffer) (err error) {
+ if p.Handle, err = buf.ConsumeString(); err != nil {
+ return err
+ }
+
+ if p.Offset, err = buf.ConsumeUint64(); err != nil {
+ return err
+ }
+
+ if p.Len, err = buf.ConsumeUint32(); err != nil {
+ return err
+ }
+
+ return nil
+}
+
+// WritePacket defines the SSH_FXP_WRITE packet.
+type WritePacket struct {
+ Handle string
+ Offset uint64
+ Data []byte
+}
+
+// Type returns the SSH_FXP_xy value associated with this packet type.
+func (p *WritePacket) Type() PacketType {
+ return PacketTypeWrite
+}
+
+// MarshalPacket returns p as a two-part binary encoding of p.
+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)
+ }
+
+ buf.StartPacket(PacketTypeWrite, reqid)
+ buf.AppendString(p.Handle)
+ buf.AppendUint64(p.Offset)
+ buf.AppendUint32(uint32(len(p.Data)))
+
+ return buf.Packet(p.Data)
+}
+
+// UnmarshalPacketBody unmarshals the packet body from the given Buffer.
+// It is assumed that the uint32(request-id) has already been consumed.
+//
+// If p.Data is already populated, and of sufficient length to hold the data,
+// then this will copy the data into that byte slice.
+//
+// If p.Data has a length insufficient to hold the data,
+// then this will make a new slice of sufficient length, and copy the data into that.
+//
+// This means this _does not_ alias any of the data buffer that is passed in.
+func (p *WritePacket) UnmarshalPacketBody(buf *Buffer) (err error) {
+ if p.Handle, err = buf.ConsumeString(); err != nil {
+ return err
+ }
+
+ if p.Offset, err = buf.ConsumeUint64(); err != nil {
+ return err
+ }
+
+ data, err := buf.ConsumeByteSlice()
+ if err != nil {
+ return err
+ }
+
+ if len(p.Data) < len(data) {
+ p.Data = make([]byte, len(data))
+ }
+
+ n := copy(p.Data, data)
+ p.Data = p.Data[:n]
+ return nil
+}
+
+// FStatPacket defines the SSH_FXP_FSTAT packet.
+type FStatPacket struct {
+ Handle string
+}
+
+// Type returns the SSH_FXP_xy value associated with this packet type.
+func (p *FStatPacket) Type() PacketType {
+ return PacketTypeFStat
+}
+
+// MarshalPacket returns p as a two-part binary encoding of p.
+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)
+ }
+
+ buf.StartPacket(PacketTypeFStat, reqid)
+ buf.AppendString(p.Handle)
+
+ return buf.Packet(payload)
+}
+
+// UnmarshalPacketBody unmarshals the packet body from the given Buffer.
+// It is assumed that the uint32(request-id) has already been consumed.
+func (p *FStatPacket) UnmarshalPacketBody(buf *Buffer) (err error) {
+ if p.Handle, err = buf.ConsumeString(); err != nil {
+ return err
+ }
+
+ return nil
+}
+
+// FSetstatPacket defines the SSH_FXP_FSETSTAT packet.
+type FSetstatPacket struct {
+ Handle string
+ Attrs Attributes
+}
+
+// Type returns the SSH_FXP_xy value associated with this packet type.
+func (p *FSetstatPacket) Type() PacketType {
+ return PacketTypeFSetstat
+}
+
+// MarshalPacket returns p as a two-part binary encoding of p.
+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)
+ }
+
+ buf.StartPacket(PacketTypeFSetstat, reqid)
+ buf.AppendString(p.Handle)
+
+ p.Attrs.MarshalInto(buf)
+
+ return buf.Packet(payload)
+}
+
+// UnmarshalPacketBody unmarshals the packet body from the given Buffer.
+// It is assumed that the uint32(request-id) has already been consumed.
+func (p *FSetstatPacket) UnmarshalPacketBody(buf *Buffer) (err error) {
+ if p.Handle, err = buf.ConsumeString(); err != nil {
+ return err
+ }
+
+ return p.Attrs.UnmarshalFrom(buf)
+}
+
+// ReadDirPacket defines the SSH_FXP_READDIR packet.
+type ReadDirPacket struct {
+ Handle string
+}
+
+// Type returns the SSH_FXP_xy value associated with this packet type.
+func (p *ReadDirPacket) Type() PacketType {
+ return PacketTypeReadDir
+}
+
+// MarshalPacket returns p as a two-part binary encoding of p.
+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)
+ }
+
+ buf.StartPacket(PacketTypeReadDir, reqid)
+ buf.AppendString(p.Handle)
+
+ return buf.Packet(payload)
+}
+
+// UnmarshalPacketBody unmarshals the packet body from the given Buffer.
+// It is assumed that the uint32(request-id) has already been consumed.
+func (p *ReadDirPacket) UnmarshalPacketBody(buf *Buffer) (err error) {
+ if p.Handle, err = buf.ConsumeString(); err != nil {
+ return err
+ }
+
+ return nil
+}
diff --git a/vendor/github.com/pkg/sftp/internal/encoding/ssh/filexfer/init_packets.go b/vendor/github.com/pkg/sftp/internal/encoding/ssh/filexfer/init_packets.go
new file mode 100644
index 000000000..b0bc6f505
--- /dev/null
+++ b/vendor/github.com/pkg/sftp/internal/encoding/ssh/filexfer/init_packets.go
@@ -0,0 +1,99 @@
+package filexfer
+
+// InitPacket defines the SSH_FXP_INIT packet.
+type InitPacket struct {
+ Version uint32
+ Extensions []*ExtensionPair
+}
+
+// MarshalBinary returns p as the binary encoding of p.
+func (p *InitPacket) MarshalBinary() ([]byte, error) {
+ size := 1 + 4 // byte(type) + uint32(version)
+
+ for _, ext := range p.Extensions {
+ size += ext.Len()
+ }
+
+ b := NewBuffer(make([]byte, 4, 4+size))
+ b.AppendUint8(uint8(PacketTypeInit))
+ b.AppendUint32(p.Version)
+
+ for _, ext := range p.Extensions {
+ ext.MarshalInto(b)
+ }
+
+ b.PutLength(size)
+
+ return b.Bytes(), nil
+}
+
+// UnmarshalBinary unmarshals a full raw packet out of the given data.
+// It is assumed that the uint32(length) has already been consumed to receive the data.
+// It is also assumed that the uint8(type) has already been consumed to which packet to unmarshal into.
+func (p *InitPacket) UnmarshalBinary(data []byte) (err error) {
+ buf := NewBuffer(data)
+
+ if p.Version, err = buf.ConsumeUint32(); err != nil {
+ return err
+ }
+
+ for buf.Len() > 0 {
+ var ext ExtensionPair
+ if err := ext.UnmarshalFrom(buf); err != nil {
+ return err
+ }
+
+ p.Extensions = append(p.Extensions, &ext)
+ }
+
+ return nil
+}
+
+// VersionPacket defines the SSH_FXP_VERSION packet.
+type VersionPacket struct {
+ Version uint32
+ Extensions []*ExtensionPair
+}
+
+// MarshalBinary returns p as the binary encoding of p.
+func (p *VersionPacket) MarshalBinary() ([]byte, error) {
+ size := 1 + 4 // byte(type) + uint32(version)
+
+ for _, ext := range p.Extensions {
+ size += ext.Len()
+ }
+
+ b := NewBuffer(make([]byte, 4, 4+size))
+ b.AppendUint8(uint8(PacketTypeVersion))
+ b.AppendUint32(p.Version)
+
+ for _, ext := range p.Extensions {
+ ext.MarshalInto(b)
+ }
+
+ b.PutLength(size)
+
+ return b.Bytes(), nil
+}
+
+// UnmarshalBinary unmarshals a full raw packet out of the given data.
+// It is assumed that the uint32(length) has already been consumed to receive the data.
+// It is also assumed that the uint8(type) has already been consumed to which packet to unmarshal into.
+func (p *VersionPacket) UnmarshalBinary(data []byte) (err error) {
+ buf := NewBuffer(data)
+
+ if p.Version, err = buf.ConsumeUint32(); err != nil {
+ return err
+ }
+
+ for buf.Len() > 0 {
+ var ext ExtensionPair
+ if err := ext.UnmarshalFrom(buf); err != nil {
+ return err
+ }
+
+ p.Extensions = append(p.Extensions, &ext)
+ }
+
+ return nil
+}
diff --git a/vendor/github.com/pkg/sftp/internal/encoding/ssh/filexfer/open_packets.go b/vendor/github.com/pkg/sftp/internal/encoding/ssh/filexfer/open_packets.go
new file mode 100644
index 000000000..135871142
--- /dev/null
+++ b/vendor/github.com/pkg/sftp/internal/encoding/ssh/filexfer/open_packets.go
@@ -0,0 +1,89 @@
+package filexfer
+
+// SSH_FXF_* flags.
+const (
+ FlagRead = 1 << iota // SSH_FXF_READ
+ FlagWrite // SSH_FXF_WRITE
+ FlagAppend // SSH_FXF_APPEND
+ FlagCreate // SSH_FXF_CREAT
+ FlagTruncate // SSH_FXF_TRUNC
+ FlagExclusive // SSH_FXF_EXCL
+)
+
+// OpenPacket defines the SSH_FXP_OPEN packet.
+type OpenPacket struct {
+ Filename string
+ PFlags uint32
+ Attrs Attributes
+}
+
+// Type returns the SSH_FXP_xy value associated with this packet type.
+func (p *OpenPacket) Type() PacketType {
+ return PacketTypeOpen
+}
+
+// MarshalPacket returns p as a two-part binary encoding of p.
+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)
+ }
+
+ buf.StartPacket(PacketTypeOpen, reqid)
+ buf.AppendString(p.Filename)
+ buf.AppendUint32(p.PFlags)
+
+ p.Attrs.MarshalInto(buf)
+
+ return buf.Packet(payload)
+}
+
+// UnmarshalPacketBody unmarshals the packet body from the given Buffer.
+// It is assumed that the uint32(request-id) has already been consumed.
+func (p *OpenPacket) UnmarshalPacketBody(buf *Buffer) (err error) {
+ if p.Filename, err = buf.ConsumeString(); err != nil {
+ return err
+ }
+
+ if p.PFlags, err = buf.ConsumeUint32(); err != nil {
+ return err
+ }
+
+ return p.Attrs.UnmarshalFrom(buf)
+}
+
+// OpenDirPacket defines the SSH_FXP_OPENDIR packet.
+type OpenDirPacket struct {
+ Path string
+}
+
+// Type returns the SSH_FXP_xy value associated with this packet type.
+func (p *OpenDirPacket) Type() PacketType {
+ return PacketTypeOpenDir
+}
+
+// MarshalPacket returns p as a two-part binary encoding of p.
+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)
+ }
+
+ buf.StartPacket(PacketTypeOpenDir, reqid)
+ buf.AppendString(p.Path)
+
+ return buf.Packet(payload)
+}
+
+// UnmarshalPacketBody unmarshals the packet body from the given Buffer.
+// It is assumed that the uint32(request-id) has already been consumed.
+func (p *OpenDirPacket) UnmarshalPacketBody(buf *Buffer) (err error) {
+ if p.Path, err = buf.ConsumeString(); err != nil {
+ return err
+ }
+
+ return nil
+}
diff --git a/vendor/github.com/pkg/sftp/internal/encoding/ssh/filexfer/packets.go b/vendor/github.com/pkg/sftp/internal/encoding/ssh/filexfer/packets.go
new file mode 100644
index 000000000..3f24e9c22
--- /dev/null
+++ b/vendor/github.com/pkg/sftp/internal/encoding/ssh/filexfer/packets.go
@@ -0,0 +1,323 @@
+package filexfer
+
+import (
+ "errors"
+ "fmt"
+ "io"
+)
+
+// smallBufferSize is an initial allocation minimal capacity.
+const smallBufferSize = 64
+
+func newPacketFromType(typ PacketType) (Packet, error) {
+ switch typ {
+ case PacketTypeOpen:
+ return new(OpenPacket), nil
+ case PacketTypeClose:
+ return new(ClosePacket), nil
+ case PacketTypeRead:
+ return new(ReadPacket), nil
+ case PacketTypeWrite:
+ return new(WritePacket), nil
+ case PacketTypeLStat:
+ return new(LStatPacket), nil
+ case PacketTypeFStat:
+ return new(FStatPacket), nil
+ case PacketTypeSetstat:
+ return new(SetstatPacket), nil
+ case PacketTypeFSetstat:
+ return new(FSetstatPacket), nil
+ case PacketTypeOpenDir:
+ return new(OpenDirPacket), nil
+ case PacketTypeReadDir:
+ return new(ReadDirPacket), nil
+ case PacketTypeRemove:
+ return new(RemovePacket), nil
+ case PacketTypeMkdir:
+ return new(MkdirPacket), nil
+ case PacketTypeRmdir:
+ return new(RmdirPacket), nil
+ case PacketTypeRealPath:
+ return new(RealPathPacket), nil
+ case PacketTypeStat:
+ return new(StatPacket), nil
+ case PacketTypeRename:
+ return new(RenamePacket), nil
+ case PacketTypeReadLink:
+ return new(ReadLinkPacket), nil
+ case PacketTypeSymlink:
+ return new(SymlinkPacket), nil
+ case PacketTypeExtended:
+ return new(ExtendedPacket), nil
+ default:
+ return nil, fmt.Errorf("unexpected request packet type: %v", typ)
+ }
+}
+
+// RawPacket implements the general packet format from draft-ietf-secsh-filexfer-02
+//
+// RawPacket is intended for use in clients receiving responses,
+// where a response will be expected to be of a limited number of types,
+// and unmarshaling unknown/unexpected response packets is unnecessary.
+//
+// For servers expecting to receive arbitrary request packet types,
+// use RequestPacket.
+//
+// Defined in https://tools.ietf.org/html/draft-ietf-secsh-filexfer-02#section-3
+type RawPacket struct {
+ PacketType PacketType
+ RequestID uint32
+
+ Data Buffer
+}
+
+// Type returns the Type field defining the SSH_FXP_xy type for this packet.
+func (p *RawPacket) Type() PacketType {
+ return p.PacketType
+}
+
+// Reset clears the pointers and reference-semantic variables of RawPacket,
+// releasing underlying resources, and making them and the RawPacket suitable to be reused,
+// so long as no other references have been kept.
+func (p *RawPacket) Reset() {
+ p.Data = Buffer{}
+}
+
+// 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, b []byte) (header, payload []byte, err error) {
+ buf := NewBuffer(b)
+ if buf.Cap() < 9 {
+ buf = NewMarshalBuffer(0)
+ }
+
+ buf.StartPacket(p.PacketType, reqid)
+
+ return buf.Packet(p.Data.Bytes())
+}
+
+// MarshalBinary returns p as the binary encoding of p.
+//
+// This is a convenience implementation primarily intended for tests,
+// because it is inefficient with allocations.
+func (p *RawPacket) MarshalBinary() ([]byte, error) {
+ return ComposePacket(p.MarshalPacket(p.RequestID, nil))
+}
+
+// UnmarshalFrom decodes a RawPacket from the given Buffer into p.
+//
+// The Data field will alias the passed in Buffer,
+// so the buffer passed in should not be reused before RawPacket.Reset().
+func (p *RawPacket) UnmarshalFrom(buf *Buffer) error {
+ typ, err := buf.ConsumeUint8()
+ if err != nil {
+ return err
+ }
+
+ p.PacketType = PacketType(typ)
+
+ if p.RequestID, err = buf.ConsumeUint32(); err != nil {
+ return err
+ }
+
+ p.Data = *buf
+ return nil
+}
+
+// UnmarshalBinary decodes a full raw packet out of the given data.
+// It is assumed that the uint32(length) has already been consumed to receive the data.
+//
+// This is a convenience implementation primarily intended for tests,
+// because this must clone the given data byte slice,
+// as Data is not allowed to alias any part of the data byte slice.
+func (p *RawPacket) UnmarshalBinary(data []byte) error {
+ clone := make([]byte, len(data))
+ n := copy(clone, data)
+ return p.UnmarshalFrom(NewBuffer(clone[:n]))
+}
+
+// readPacket reads a uint32 length-prefixed binary data packet from r.
+// using the given byte slice as a backing array.
+//
+// If the packet length read from r is bigger than maxPacketLength,
+// or greater than math.MaxInt32 on a 32-bit implementation,
+// then a `ErrLongPacket` error will be returned.
+//
+// If the given byte slice is insufficient to hold the packet,
+// then it will be extended to fill the packet size.
+func readPacket(r io.Reader, b []byte, maxPacketLength uint32) ([]byte, error) {
+ if cap(b) < 4 {
+ // We will need allocate our own buffer just for reading the packet length.
+
+ // However, we don’t really want to allocate an extremely narrow buffer (4-bytes),
+ // and cause unnecessary allocation churn from both length reads and small packet reads,
+ // so we use smallBufferSize from the bytes package as a reasonable guess.
+
+ // But if callers really do want to force narrow throw-away allocation of every packet body,
+ // they can do so with a buffer of capacity 4.
+ b = make([]byte, smallBufferSize)
+ }
+
+ if _, err := io.ReadFull(r, b[:4]); err != nil {
+ return nil, err
+ }
+
+ length := unmarshalUint32(b)
+ if int(length) < 5 {
+ // Must have at least uint8(type) and uint32(request-id)
+
+ if int(length) < 0 {
+ // Only possible when strconv.IntSize == 32,
+ // the packet length is longer than math.MaxInt32,
+ // and thus longer than any possible slice.
+ return nil, ErrLongPacket
+ }
+
+ return nil, ErrShortPacket
+ }
+ if length > maxPacketLength {
+ return nil, ErrLongPacket
+ }
+
+ if int(length) > cap(b) {
+ // We know int(length) must be positive, because of tests above.
+ b = make([]byte, length)
+ }
+
+ n, err := io.ReadFull(r, b[:length])
+ return b[:n], err
+}
+
+// ReadFrom provides a simple functional packet reader,
+// using the given byte slice as a backing array.
+//
+// To protect against potential denial of service attacks,
+// if the read packet length is longer than maxPacketLength,
+// then no packet data will be read, and ErrLongPacket will be returned.
+// (On 32-bit int architectures, all packets >= 2^31 in length
+// will return ErrLongPacket regardless of maxPacketLength.)
+//
+// If the read packet length is longer than cap(b),
+// then a throw-away slice will allocated to meet the exact packet length.
+// This can be used to limit the length of reused buffers,
+// while still allowing reception of occasional large packets.
+//
+// The Data field may alias the passed in byte slice,
+// so the byte slice passed in should not be reused before RawPacket.Reset().
+func (p *RawPacket) ReadFrom(r io.Reader, b []byte, maxPacketLength uint32) error {
+ b, err := readPacket(r, b, maxPacketLength)
+ if err != nil {
+ return err
+ }
+
+ return p.UnmarshalFrom(NewBuffer(b))
+}
+
+// RequestPacket implements the general packet format from draft-ietf-secsh-filexfer-02
+// but also automatically decode/encodes valid request packets (2 < type < 100 || type == 200).
+//
+// RequestPacket is intended for use in servers receiving requests,
+// where any arbitrary request may be received, and so decoding them automatically
+// is useful.
+//
+// For clients expecting to receive specific response packet types,
+// where automatic unmarshaling of the packet body does not make sense,
+// use RawPacket.
+//
+// Defined in https://tools.ietf.org/html/draft-ietf-secsh-filexfer-02#section-3
+type RequestPacket struct {
+ RequestID uint32
+
+ Request Packet
+}
+
+// Type returns the SSH_FXP_xy value associated with the underlying packet.
+func (p *RequestPacket) Type() PacketType {
+ return p.Request.Type()
+}
+
+// Reset clears the pointers and reference-semantic variables in RequestPacket,
+// releasing underlying resources, and making them and the RequestPacket suitable to be reused,
+// so long as no other references have been kept.
+func (p *RequestPacket) Reset() {
+ p.Request = nil
+}
+
+// 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, b []byte) (header, payload []byte, err error) {
+ if p.Request == nil {
+ return nil, nil, errors.New("empty request packet")
+ }
+
+ return p.Request.MarshalPacket(reqid, b)
+}
+
+// MarshalBinary returns p as the binary encoding of p.
+//
+// This is a convenience implementation primarily intended for tests,
+// because it is inefficient with allocations.
+func (p *RequestPacket) MarshalBinary() ([]byte, error) {
+ return ComposePacket(p.MarshalPacket(p.RequestID, nil))
+}
+
+// UnmarshalFrom decodes a RequestPacket from the given Buffer into p.
+//
+// The Request field may alias the passed in Buffer, (e.g. SSH_FXP_WRITE),
+// so the buffer passed in should not be reused before RequestPacket.Reset().
+func (p *RequestPacket) UnmarshalFrom(buf *Buffer) error {
+ typ, err := buf.ConsumeUint8()
+ if err != nil {
+ return err
+ }
+
+ p.Request, err = newPacketFromType(PacketType(typ))
+ if err != nil {
+ return err
+ }
+
+ if p.RequestID, err = buf.ConsumeUint32(); err != nil {
+ return err
+ }
+
+ return p.Request.UnmarshalPacketBody(buf)
+}
+
+// UnmarshalBinary decodes a full request packet out of the given data.
+// It is assumed that the uint32(length) has already been consumed to receive the data.
+//
+// This is a convenience implementation primarily intended for tests,
+// because this must clone the given data byte slice,
+// as Request is not allowed to alias any part of the data byte slice.
+func (p *RequestPacket) UnmarshalBinary(data []byte) error {
+ clone := make([]byte, len(data))
+ n := copy(clone, data)
+ return p.UnmarshalFrom(NewBuffer(clone[:n]))
+}
+
+// ReadFrom provides a simple functional packet reader,
+// using the given byte slice as a backing array.
+//
+// To protect against potential denial of service attacks,
+// if the read packet length is longer than maxPacketLength,
+// then no packet data will be read, and ErrLongPacket will be returned.
+// (On 32-bit int architectures, all packets >= 2^31 in length
+// will return ErrLongPacket regardless of maxPacketLength.)
+//
+// If the read packet length is longer than cap(b),
+// then a throw-away slice will allocated to meet the exact packet length.
+// This can be used to limit the length of reused buffers,
+// while still allowing reception of occasional large packets.
+//
+// The Request field may alias the passed in byte slice,
+// so the byte slice passed in should not be reused before RawPacket.Reset().
+func (p *RequestPacket) ReadFrom(r io.Reader, b []byte, maxPacketLength uint32) error {
+ b, err := readPacket(r, b, maxPacketLength)
+ if err != nil {
+ return err
+ }
+
+ return p.UnmarshalFrom(NewBuffer(b))
+}
diff --git a/vendor/github.com/pkg/sftp/internal/encoding/ssh/filexfer/path_packets.go b/vendor/github.com/pkg/sftp/internal/encoding/ssh/filexfer/path_packets.go
new file mode 100644
index 000000000..e6f692d9f
--- /dev/null
+++ b/vendor/github.com/pkg/sftp/internal/encoding/ssh/filexfer/path_packets.go
@@ -0,0 +1,368 @@
+package filexfer
+
+// LStatPacket defines the SSH_FXP_LSTAT packet.
+type LStatPacket struct {
+ Path string
+}
+
+// Type returns the SSH_FXP_xy value associated with this packet type.
+func (p *LStatPacket) Type() PacketType {
+ return PacketTypeLStat
+}
+
+// MarshalPacket returns p as a two-part binary encoding of p.
+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)
+ }
+
+ buf.StartPacket(PacketTypeLStat, reqid)
+ buf.AppendString(p.Path)
+
+ return buf.Packet(payload)
+}
+
+// UnmarshalPacketBody unmarshals the packet body from the given Buffer.
+// It is assumed that the uint32(request-id) has already been consumed.
+func (p *LStatPacket) UnmarshalPacketBody(buf *Buffer) (err error) {
+ if p.Path, err = buf.ConsumeString(); err != nil {
+ return err
+ }
+
+ return nil
+}
+
+// SetstatPacket defines the SSH_FXP_SETSTAT packet.
+type SetstatPacket struct {
+ Path string
+ Attrs Attributes
+}
+
+// Type returns the SSH_FXP_xy value associated with this packet type.
+func (p *SetstatPacket) Type() PacketType {
+ return PacketTypeSetstat
+}
+
+// MarshalPacket returns p as a two-part binary encoding of p.
+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)
+ }
+
+ buf.StartPacket(PacketTypeSetstat, reqid)
+ buf.AppendString(p.Path)
+
+ p.Attrs.MarshalInto(buf)
+
+ return buf.Packet(payload)
+}
+
+// UnmarshalPacketBody unmarshals the packet body from the given Buffer.
+// It is assumed that the uint32(request-id) has already been consumed.
+func (p *SetstatPacket) UnmarshalPacketBody(buf *Buffer) (err error) {
+ if p.Path, err = buf.ConsumeString(); err != nil {
+ return err
+ }
+
+ return p.Attrs.UnmarshalFrom(buf)
+}
+
+// RemovePacket defines the SSH_FXP_REMOVE packet.
+type RemovePacket struct {
+ Path string
+}
+
+// Type returns the SSH_FXP_xy value associated with this packet type.
+func (p *RemovePacket) Type() PacketType {
+ return PacketTypeRemove
+}
+
+// MarshalPacket returns p as a two-part binary encoding of p.
+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)
+ }
+
+ buf.StartPacket(PacketTypeRemove, reqid)
+ buf.AppendString(p.Path)
+
+ return buf.Packet(payload)
+}
+
+// UnmarshalPacketBody unmarshals the packet body from the given Buffer.
+// It is assumed that the uint32(request-id) has already been consumed.
+func (p *RemovePacket) UnmarshalPacketBody(buf *Buffer) (err error) {
+ if p.Path, err = buf.ConsumeString(); err != nil {
+ return err
+ }
+
+ return nil
+}
+
+// MkdirPacket defines the SSH_FXP_MKDIR packet.
+type MkdirPacket struct {
+ Path string
+ Attrs Attributes
+}
+
+// Type returns the SSH_FXP_xy value associated with this packet type.
+func (p *MkdirPacket) Type() PacketType {
+ return PacketTypeMkdir
+}
+
+// MarshalPacket returns p as a two-part binary encoding of p.
+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)
+ }
+
+ buf.StartPacket(PacketTypeMkdir, reqid)
+ buf.AppendString(p.Path)
+
+ p.Attrs.MarshalInto(buf)
+
+ return buf.Packet(payload)
+}
+
+// UnmarshalPacketBody unmarshals the packet body from the given Buffer.
+// It is assumed that the uint32(request-id) has already been consumed.
+func (p *MkdirPacket) UnmarshalPacketBody(buf *Buffer) (err error) {
+ if p.Path, err = buf.ConsumeString(); err != nil {
+ return err
+ }
+
+ return p.Attrs.UnmarshalFrom(buf)
+}
+
+// RmdirPacket defines the SSH_FXP_RMDIR packet.
+type RmdirPacket struct {
+ Path string
+}
+
+// Type returns the SSH_FXP_xy value associated with this packet type.
+func (p *RmdirPacket) Type() PacketType {
+ return PacketTypeRmdir
+}
+
+// MarshalPacket returns p as a two-part binary encoding of p.
+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)
+ }
+
+ buf.StartPacket(PacketTypeRmdir, reqid)
+ buf.AppendString(p.Path)
+
+ return buf.Packet(payload)
+}
+
+// UnmarshalPacketBody unmarshals the packet body from the given Buffer.
+// It is assumed that the uint32(request-id) has already been consumed.
+func (p *RmdirPacket) UnmarshalPacketBody(buf *Buffer) (err error) {
+ if p.Path, err = buf.ConsumeString(); err != nil {
+ return err
+ }
+
+ return nil
+}
+
+// RealPathPacket defines the SSH_FXP_REALPATH packet.
+type RealPathPacket struct {
+ Path string
+}
+
+// Type returns the SSH_FXP_xy value associated with this packet type.
+func (p *RealPathPacket) Type() PacketType {
+ return PacketTypeRealPath
+}
+
+// MarshalPacket returns p as a two-part binary encoding of p.
+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)
+ }
+
+ buf.StartPacket(PacketTypeRealPath, reqid)
+ buf.AppendString(p.Path)
+
+ return buf.Packet(payload)
+}
+
+// UnmarshalPacketBody unmarshals the packet body from the given Buffer.
+// It is assumed that the uint32(request-id) has already been consumed.
+func (p *RealPathPacket) UnmarshalPacketBody(buf *Buffer) (err error) {
+ if p.Path, err = buf.ConsumeString(); err != nil {
+ return err
+ }
+
+ return nil
+}
+
+// StatPacket defines the SSH_FXP_STAT packet.
+type StatPacket struct {
+ Path string
+}
+
+// Type returns the SSH_FXP_xy value associated with this packet type.
+func (p *StatPacket) Type() PacketType {
+ return PacketTypeStat
+}
+
+// MarshalPacket returns p as a two-part binary encoding of p.
+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)
+ }
+
+ buf.StartPacket(PacketTypeStat, reqid)
+ buf.AppendString(p.Path)
+
+ return buf.Packet(payload)
+}
+
+// UnmarshalPacketBody unmarshals the packet body from the given Buffer.
+// It is assumed that the uint32(request-id) has already been consumed.
+func (p *StatPacket) UnmarshalPacketBody(buf *Buffer) (err error) {
+ if p.Path, err = buf.ConsumeString(); err != nil {
+ return err
+ }
+
+ return nil
+}
+
+// RenamePacket defines the SSH_FXP_RENAME packet.
+type RenamePacket struct {
+ OldPath string
+ NewPath string
+}
+
+// Type returns the SSH_FXP_xy value associated with this packet type.
+func (p *RenamePacket) Type() PacketType {
+ return PacketTypeRename
+}
+
+// MarshalPacket returns p as a two-part binary encoding of p.
+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)
+ }
+
+ buf.StartPacket(PacketTypeRename, reqid)
+ buf.AppendString(p.OldPath)
+ buf.AppendString(p.NewPath)
+
+ return buf.Packet(payload)
+}
+
+// UnmarshalPacketBody unmarshals the packet body from the given Buffer.
+// It is assumed that the uint32(request-id) has already been consumed.
+func (p *RenamePacket) UnmarshalPacketBody(buf *Buffer) (err error) {
+ if p.OldPath, err = buf.ConsumeString(); err != nil {
+ return err
+ }
+
+ if p.NewPath, err = buf.ConsumeString(); err != nil {
+ return err
+ }
+
+ return nil
+}
+
+// ReadLinkPacket defines the SSH_FXP_READLINK packet.
+type ReadLinkPacket struct {
+ Path string
+}
+
+// Type returns the SSH_FXP_xy value associated with this packet type.
+func (p *ReadLinkPacket) Type() PacketType {
+ return PacketTypeReadLink
+}
+
+// MarshalPacket returns p as a two-part binary encoding of p.
+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)
+ }
+
+ buf.StartPacket(PacketTypeReadLink, reqid)
+ buf.AppendString(p.Path)
+
+ return buf.Packet(payload)
+}
+
+// UnmarshalPacketBody unmarshals the packet body from the given Buffer.
+// It is assumed that the uint32(request-id) has already been consumed.
+func (p *ReadLinkPacket) UnmarshalPacketBody(buf *Buffer) (err error) {
+ if p.Path, err = buf.ConsumeString(); err != nil {
+ return err
+ }
+
+ return nil
+}
+
+// SymlinkPacket defines the SSH_FXP_SYMLINK packet.
+//
+// The order of the arguments to the SSH_FXP_SYMLINK method was inadvertently reversed.
+// Unfortunately, the reversal was not noticed until the server was widely deployed.
+// Covered in Section 3.1 of https://github.com/openssh/openssh-portable/blob/master/PROTOCOL
+type SymlinkPacket struct {
+ LinkPath string
+ TargetPath string
+}
+
+// Type returns the SSH_FXP_xy value associated with this packet type.
+func (p *SymlinkPacket) Type() PacketType {
+ return PacketTypeSymlink
+}
+
+// MarshalPacket returns p as a two-part binary encoding of p.
+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)
+ }
+
+ buf.StartPacket(PacketTypeSymlink, reqid)
+
+ // Arguments were inadvertently reversed.
+ buf.AppendString(p.TargetPath)
+ buf.AppendString(p.LinkPath)
+
+ return buf.Packet(payload)
+}
+
+// UnmarshalPacketBody unmarshals the packet body from the given Buffer.
+// It is assumed that the uint32(request-id) has already been consumed.
+func (p *SymlinkPacket) UnmarshalPacketBody(buf *Buffer) (err error) {
+ // Arguments were inadvertently reversed.
+ if p.TargetPath, err = buf.ConsumeString(); err != nil {
+ return err
+ }
+
+ if p.LinkPath, err = buf.ConsumeString(); err != nil {
+ return err
+ }
+
+ return nil
+}
diff --git a/vendor/github.com/pkg/sftp/internal/encoding/ssh/filexfer/permissions.go b/vendor/github.com/pkg/sftp/internal/encoding/ssh/filexfer/permissions.go
new file mode 100644
index 000000000..2fe63d591
--- /dev/null
+++ b/vendor/github.com/pkg/sftp/internal/encoding/ssh/filexfer/permissions.go
@@ -0,0 +1,114 @@
+package filexfer
+
+// FileMode represents a file’s mode and permission bits.
+// The bits are defined according to POSIX standards,
+// and may not apply to the OS being built for.
+type FileMode uint32
+
+// Permission flags, defined here to avoid potential inconsistencies in individual OS implementations.
+const (
+ ModePerm FileMode = 0o0777 // S_IRWXU | S_IRWXG | S_IRWXO
+ ModeUserRead FileMode = 0o0400 // S_IRUSR
+ ModeUserWrite FileMode = 0o0200 // S_IWUSR
+ ModeUserExec FileMode = 0o0100 // S_IXUSR
+ ModeGroupRead FileMode = 0o0040 // S_IRGRP
+ ModeGroupWrite FileMode = 0o0020 // S_IWGRP
+ ModeGroupExec FileMode = 0o0010 // S_IXGRP
+ ModeOtherRead FileMode = 0o0004 // S_IROTH
+ ModeOtherWrite FileMode = 0o0002 // S_IWOTH
+ ModeOtherExec FileMode = 0o0001 // S_IXOTH
+
+ ModeSetUID FileMode = 0o4000 // S_ISUID
+ ModeSetGID FileMode = 0o2000 // S_ISGID
+ ModeSticky FileMode = 0o1000 // S_ISVTX
+
+ ModeType FileMode = 0xF000 // S_IFMT
+ ModeNamedPipe FileMode = 0x1000 // S_IFIFO
+ ModeCharDevice FileMode = 0x2000 // S_IFCHR
+ ModeDir FileMode = 0x4000 // S_IFDIR
+ ModeDevice FileMode = 0x6000 // S_IFBLK
+ ModeRegular FileMode = 0x8000 // S_IFREG
+ ModeSymlink FileMode = 0xA000 // S_IFLNK
+ ModeSocket FileMode = 0xC000 // S_IFSOCK
+)
+
+// IsDir reports whether m describes a directory.
+// That is, it tests for m.Type() == ModeDir.
+func (m FileMode) IsDir() bool {
+ return (m & ModeType) == ModeDir
+}
+
+// IsRegular reports whether m describes a regular file.
+// That is, it tests for m.Type() == ModeRegular
+func (m FileMode) IsRegular() bool {
+ return (m & ModeType) == ModeRegular
+}
+
+// Perm returns the POSIX permission bits in m (m & ModePerm).
+func (m FileMode) Perm() FileMode {
+ return (m & ModePerm)
+}
+
+// Type returns the type bits in m (m & ModeType).
+func (m FileMode) Type() FileMode {
+ return (m & ModeType)
+}
+
+// String returns a `-rwxrwxrwx` style string representing the `ls -l` POSIX permissions string.
+func (m FileMode) String() string {
+ var buf [10]byte
+
+ switch m.Type() {
+ case ModeRegular:
+ buf[0] = '-'
+ case ModeDir:
+ buf[0] = 'd'
+ case ModeSymlink:
+ buf[0] = 'l'
+ case ModeDevice:
+ buf[0] = 'b'
+ case ModeCharDevice:
+ buf[0] = 'c'
+ case ModeNamedPipe:
+ buf[0] = 'p'
+ case ModeSocket:
+ buf[0] = 's'
+ default:
+ buf[0] = '?'
+ }
+
+ const rwx = "rwxrwxrwx"
+ for i, c := range rwx {
+ if m&(1<<uint(9-1-i)) != 0 {
+ buf[i+1] = byte(c)
+ } else {
+ buf[i+1] = '-'
+ }
+ }
+
+ if m&ModeSetUID != 0 {
+ if buf[3] == 'x' {
+ buf[3] = 's'
+ } else {
+ buf[3] = 'S'
+ }
+ }
+
+ if m&ModeSetGID != 0 {
+ if buf[6] == 'x' {
+ buf[6] = 's'
+ } else {
+ buf[6] = 'S'
+ }
+ }
+
+ if m&ModeSticky != 0 {
+ if buf[9] == 'x' {
+ buf[9] = 't'
+ } else {
+ buf[9] = 'T'
+ }
+ }
+
+ return string(buf[:])
+}
diff --git a/vendor/github.com/pkg/sftp/internal/encoding/ssh/filexfer/response_packets.go b/vendor/github.com/pkg/sftp/internal/encoding/ssh/filexfer/response_packets.go
new file mode 100644
index 000000000..7a9b3eae8
--- /dev/null
+++ b/vendor/github.com/pkg/sftp/internal/encoding/ssh/filexfer/response_packets.go
@@ -0,0 +1,243 @@
+package filexfer
+
+import (
+ "fmt"
+)
+
+// StatusPacket defines the SSH_FXP_STATUS packet.
+//
+// Specified in https://tools.ietf.org/html/draft-ietf-secsh-filexfer-02#section-7
+type StatusPacket struct {
+ StatusCode Status
+ ErrorMessage string
+ LanguageTag string
+}
+
+// Error makes StatusPacket an error type.
+func (p *StatusPacket) Error() string {
+ if p.ErrorMessage == "" {
+ return "sftp: " + p.StatusCode.String()
+ }
+
+ return fmt.Sprintf("sftp: %q (%s)", p.ErrorMessage, p.StatusCode)
+}
+
+// Is returns true if target is a StatusPacket with the same StatusCode,
+// or target is a Status code which is the same as SatusCode.
+func (p *StatusPacket) Is(target error) bool {
+ if target, ok := target.(*StatusPacket); ok {
+ return p.StatusCode == target.StatusCode
+ }
+
+ return p.StatusCode == target
+}
+
+// Type returns the SSH_FXP_xy value associated with this packet type.
+func (p *StatusPacket) Type() PacketType {
+ return PacketTypeStatus
+}
+
+// MarshalPacket returns p as a two-part binary encoding of p.
+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)
+ }
+
+ buf.StartPacket(PacketTypeStatus, reqid)
+ buf.AppendUint32(uint32(p.StatusCode))
+ buf.AppendString(p.ErrorMessage)
+ buf.AppendString(p.LanguageTag)
+
+ return buf.Packet(payload)
+}
+
+// UnmarshalPacketBody unmarshals the packet body from the given Buffer.
+// It is assumed that the uint32(request-id) has already been consumed.
+func (p *StatusPacket) UnmarshalPacketBody(buf *Buffer) (err error) {
+ statusCode, err := buf.ConsumeUint32()
+ if err != nil {
+ return err
+ }
+ p.StatusCode = Status(statusCode)
+
+ if p.ErrorMessage, err = buf.ConsumeString(); err != nil {
+ return err
+ }
+
+ if p.LanguageTag, err = buf.ConsumeString(); err != nil {
+ return err
+ }
+
+ return nil
+}
+
+// HandlePacket defines the SSH_FXP_HANDLE packet.
+type HandlePacket struct {
+ Handle string
+}
+
+// Type returns the SSH_FXP_xy value associated with this packet type.
+func (p *HandlePacket) Type() PacketType {
+ return PacketTypeHandle
+}
+
+// MarshalPacket returns p as a two-part binary encoding of p.
+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)
+ }
+
+ buf.StartPacket(PacketTypeHandle, reqid)
+ buf.AppendString(p.Handle)
+
+ return buf.Packet(payload)
+}
+
+// UnmarshalPacketBody unmarshals the packet body from the given Buffer.
+// It is assumed that the uint32(request-id) has already been consumed.
+func (p *HandlePacket) UnmarshalPacketBody(buf *Buffer) (err error) {
+ if p.Handle, err = buf.ConsumeString(); err != nil {
+ return err
+ }
+
+ return nil
+}
+
+// DataPacket defines the SSH_FXP_DATA packet.
+type DataPacket struct {
+ Data []byte
+}
+
+// Type returns the SSH_FXP_xy value associated with this packet type.
+func (p *DataPacket) Type() PacketType {
+ return PacketTypeData
+}
+
+// MarshalPacket returns p as a two-part binary encoding of p.
+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)
+ }
+
+ buf.StartPacket(PacketTypeData, reqid)
+ buf.AppendUint32(uint32(len(p.Data)))
+
+ return buf.Packet(p.Data)
+}
+
+// UnmarshalPacketBody unmarshals the packet body from the given Buffer.
+// It is assumed that the uint32(request-id) has already been consumed.
+//
+// If p.Data is already populated, and of sufficient length to hold the data,
+// then this will copy the data into that byte slice.
+//
+// If p.Data has a length insufficient to hold the data,
+// then this will make a new slice of sufficient length, and copy the data into that.
+//
+// This means this _does not_ alias any of the data buffer that is passed in.
+func (p *DataPacket) UnmarshalPacketBody(buf *Buffer) (err error) {
+ data, err := buf.ConsumeByteSlice()
+ if err != nil {
+ return err
+ }
+
+ if len(p.Data) < len(data) {
+ p.Data = make([]byte, len(data))
+ }
+
+ n := copy(p.Data, data)
+ p.Data = p.Data[:n]
+ return nil
+}
+
+// NamePacket defines the SSH_FXP_NAME packet.
+type NamePacket struct {
+ Entries []*NameEntry
+}
+
+// Type returns the SSH_FXP_xy value associated with this packet type.
+func (p *NamePacket) Type() PacketType {
+ return PacketTypeName
+}
+
+// MarshalPacket returns p as a two-part binary encoding of p.
+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()
+ }
+
+ buf = NewMarshalBuffer(size)
+ }
+
+ buf.StartPacket(PacketTypeName, reqid)
+ buf.AppendUint32(uint32(len(p.Entries)))
+
+ for _, e := range p.Entries {
+ e.MarshalInto(buf)
+ }
+
+ return buf.Packet(payload)
+}
+
+// UnmarshalPacketBody unmarshals the packet body from the given Buffer.
+// It is assumed that the uint32(request-id) has already been consumed.
+func (p *NamePacket) UnmarshalPacketBody(buf *Buffer) (err error) {
+ count, err := buf.ConsumeUint32()
+ if err != nil {
+ return err
+ }
+
+ p.Entries = make([]*NameEntry, 0, count)
+
+ for i := uint32(0); i < count; i++ {
+ var e NameEntry
+ if err := e.UnmarshalFrom(buf); err != nil {
+ return err
+ }
+
+ p.Entries = append(p.Entries, &e)
+ }
+
+ return nil
+}
+
+// AttrsPacket defines the SSH_FXP_ATTRS packet.
+type AttrsPacket struct {
+ Attrs Attributes
+}
+
+// Type returns the SSH_FXP_xy value associated with this packet type.
+func (p *AttrsPacket) Type() PacketType {
+ return PacketTypeAttrs
+}
+
+// MarshalPacket returns p as a two-part binary encoding of p.
+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)
+ }
+
+ buf.StartPacket(PacketTypeAttrs, reqid)
+ p.Attrs.MarshalInto(buf)
+
+ return buf.Packet(payload)
+}
+
+// UnmarshalPacketBody unmarshals the packet body from the given Buffer.
+// It is assumed that the uint32(request-id) has already been consumed.
+func (p *AttrsPacket) UnmarshalPacketBody(buf *Buffer) (err error) {
+ return p.Attrs.UnmarshalFrom(buf)
+}