github.com/pkg/sftp@v1.13.6/internal/encoding/ssh/filexfer/buffer.go (about)

     1  package sshfx
     2  
     3  import (
     4  	"encoding/binary"
     5  	"errors"
     6  )
     7  
     8  // Various encoding errors.
     9  var (
    10  	ErrShortPacket = errors.New("packet too short")
    11  	ErrLongPacket  = errors.New("packet too long")
    12  )
    13  
    14  // Buffer wraps up the various encoding details of the SSH format.
    15  //
    16  // Data types are encoded as per section 4 from https://tools.ietf.org/html/draft-ietf-secsh-architecture-09#page-8
    17  type Buffer struct {
    18  	b   []byte
    19  	off int
    20  	Err error
    21  }
    22  
    23  // NewBuffer creates and initializes a new buffer using buf as its initial contents.
    24  // The new buffer takes ownership of buf, and the caller should not use buf after this call.
    25  //
    26  // In most cases, new(Buffer) (or just declaring a Buffer variable) is sufficient to initialize a Buffer.
    27  func NewBuffer(buf []byte) *Buffer {
    28  	return &Buffer{
    29  		b: buf,
    30  	}
    31  }
    32  
    33  // NewMarshalBuffer creates a new Buffer ready to start marshaling a Packet into.
    34  // It preallocates enough space for uint32(length), uint8(type), uint32(request-id) and size more bytes.
    35  func NewMarshalBuffer(size int) *Buffer {
    36  	return NewBuffer(make([]byte, 4+1+4+size))
    37  }
    38  
    39  // Bytes returns a slice of length b.Len() holding the unconsumed bytes in the Buffer.
    40  // The slice is valid for use only until the next buffer modification
    41  // (that is, only until the next call to an Append or Consume method).
    42  func (b *Buffer) Bytes() []byte {
    43  	return b.b[b.off:]
    44  }
    45  
    46  // Len returns the number of unconsumed bytes in the buffer.
    47  func (b *Buffer) Len() int { return len(b.b) - b.off }
    48  
    49  // Cap returns the capacity of the buffer’s underlying byte slice,
    50  // that is, the total space allocated for the buffer’s data.
    51  func (b *Buffer) Cap() int { return cap(b.b) }
    52  
    53  // Reset resets the buffer to be empty, but it retains the underlying storage for use by future Appends.
    54  func (b *Buffer) Reset() {
    55  	*b = Buffer{
    56  		b: b.b[:0],
    57  	}
    58  }
    59  
    60  // StartPacket resets and initializes the buffer to be ready to start marshaling a packet into.
    61  // It truncates the buffer, reserves space for uint32(length), then appends the given packetType and requestID.
    62  func (b *Buffer) StartPacket(packetType PacketType, requestID uint32) {
    63  	*b = Buffer{
    64  		b: append(b.b[:0], make([]byte, 4)...),
    65  	}
    66  
    67  	b.AppendUint8(uint8(packetType))
    68  	b.AppendUint32(requestID)
    69  }
    70  
    71  // Packet finalizes the packet started from StartPacket.
    72  // It is expected that this will end the ownership of the underlying byte-slice,
    73  // and so the returned byte-slices may be reused the same as any other byte-slice,
    74  // the caller should not use this buffer after this call.
    75  //
    76  // It writes the packet body length into the first four bytes of the buffer in network byte order (big endian).
    77  // The packet body length is the length of this buffer less the 4-byte length itself, plus the length of payload.
    78  //
    79  // It is assumed that no Consume methods have been called on this buffer,
    80  // and so it returns the whole underlying slice.
    81  func (b *Buffer) Packet(payload []byte) (header, payloadPassThru []byte, err error) {
    82  	b.PutLength(len(b.b) - 4 + len(payload))
    83  
    84  	return b.b, payload, nil
    85  }
    86  
    87  // ConsumeUint8 consumes a single byte from the buffer.
    88  // If the buffer does not have enough data, it will set Err to ErrShortPacket.
    89  func (b *Buffer) ConsumeUint8() uint8 {
    90  	if b.Err != nil {
    91  		return 0
    92  	}
    93  
    94  	if b.Len() < 1 {
    95  		b.off = len(b.b)
    96  		b.Err = ErrShortPacket
    97  		return 0
    98  	}
    99  
   100  	var v uint8
   101  	v, b.off = b.b[b.off], b.off+1
   102  	return v
   103  }
   104  
   105  // AppendUint8 appends a single byte into the buffer.
   106  func (b *Buffer) AppendUint8(v uint8) {
   107  	b.b = append(b.b, v)
   108  }
   109  
   110  // ConsumeBool consumes a single byte from the buffer, and returns true if that byte is non-zero.
   111  // If the buffer does not have enough data, it will set Err to ErrShortPacket.
   112  func (b *Buffer) ConsumeBool() bool {
   113  	return b.ConsumeUint8() != 0
   114  }
   115  
   116  // AppendBool appends a single bool into the buffer.
   117  // It encodes it as a single byte, with false as 0, and true as 1.
   118  func (b *Buffer) AppendBool(v bool) {
   119  	if v {
   120  		b.AppendUint8(1)
   121  	} else {
   122  		b.AppendUint8(0)
   123  	}
   124  }
   125  
   126  // ConsumeUint16 consumes a single uint16 from the buffer, in network byte order (big-endian).
   127  // If the buffer does not have enough data, it will set Err to ErrShortPacket.
   128  func (b *Buffer) ConsumeUint16() uint16 {
   129  	if b.Err != nil {
   130  		return 0
   131  	}
   132  
   133  	if b.Len() < 2 {
   134  		b.off = len(b.b)
   135  		b.Err = ErrShortPacket
   136  		return 0
   137  	}
   138  
   139  	v := binary.BigEndian.Uint16(b.b[b.off:])
   140  	b.off += 2
   141  	return v
   142  }
   143  
   144  // AppendUint16 appends single uint16 into the buffer, in network byte order (big-endian).
   145  func (b *Buffer) AppendUint16(v uint16) {
   146  	b.b = append(b.b,
   147  		byte(v>>8),
   148  		byte(v>>0),
   149  	)
   150  }
   151  
   152  // unmarshalUint32 is used internally to read the packet length.
   153  // It is unsafe, and so not exported.
   154  // Even within this package, its use should be avoided.
   155  func unmarshalUint32(b []byte) uint32 {
   156  	return binary.BigEndian.Uint32(b[:4])
   157  }
   158  
   159  // ConsumeUint32 consumes a single uint32 from the buffer, in network byte order (big-endian).
   160  // If the buffer does not have enough data, it will set Err to ErrShortPacket.
   161  func (b *Buffer) ConsumeUint32() uint32 {
   162  	if b.Err != nil {
   163  		return 0
   164  	}
   165  
   166  	if b.Len() < 4 {
   167  		b.off = len(b.b)
   168  		b.Err = ErrShortPacket
   169  		return 0
   170  	}
   171  
   172  	v := binary.BigEndian.Uint32(b.b[b.off:])
   173  	b.off += 4
   174  	return v
   175  }
   176  
   177  // AppendUint32 appends a single uint32 into the buffer, in network byte order (big-endian).
   178  func (b *Buffer) AppendUint32(v uint32) {
   179  	b.b = append(b.b,
   180  		byte(v>>24),
   181  		byte(v>>16),
   182  		byte(v>>8),
   183  		byte(v>>0),
   184  	)
   185  }
   186  
   187  // ConsumeCount consumes a single uint32 count from the buffer, in network byte order (big-endian) as an int.
   188  // If the buffer does not have enough data, it will set Err to ErrShortPacket.
   189  func (b *Buffer) ConsumeCount() int {
   190  	return int(b.ConsumeUint32())
   191  }
   192  
   193  // AppendCount appends a single int length as a uint32 into the buffer, in network byte order (big-endian).
   194  func (b *Buffer) AppendCount(v int) {
   195  	b.AppendUint32(uint32(v))
   196  }
   197  
   198  // ConsumeUint64 consumes a single uint64 from the buffer, in network byte order (big-endian).
   199  // If the buffer does not have enough data, it will set Err to ErrShortPacket.
   200  func (b *Buffer) ConsumeUint64() uint64 {
   201  	if b.Err != nil {
   202  		return 0
   203  	}
   204  
   205  	if b.Len() < 8 {
   206  		b.off = len(b.b)
   207  		b.Err = ErrShortPacket
   208  		return 0
   209  	}
   210  
   211  	v := binary.BigEndian.Uint64(b.b[b.off:])
   212  	b.off += 8
   213  	return v
   214  }
   215  
   216  // AppendUint64 appends a single uint64 into the buffer, in network byte order (big-endian).
   217  func (b *Buffer) AppendUint64(v uint64) {
   218  	b.b = append(b.b,
   219  		byte(v>>56),
   220  		byte(v>>48),
   221  		byte(v>>40),
   222  		byte(v>>32),
   223  		byte(v>>24),
   224  		byte(v>>16),
   225  		byte(v>>8),
   226  		byte(v>>0),
   227  	)
   228  }
   229  
   230  // ConsumeInt64 consumes a single int64 from the buffer, in network byte order (big-endian) with two’s complement.
   231  // If the buffer does not have enough data, it will set Err to ErrShortPacket.
   232  func (b *Buffer) ConsumeInt64() int64 {
   233  	return int64(b.ConsumeUint64())
   234  }
   235  
   236  // AppendInt64 appends a single int64 into the buffer, in network byte order (big-endian) with two’s complement.
   237  func (b *Buffer) AppendInt64(v int64) {
   238  	b.AppendUint64(uint64(v))
   239  }
   240  
   241  // ConsumeByteSlice consumes a single string of raw binary data from the buffer.
   242  // A string is a uint32 length, followed by that number of raw bytes.
   243  // If the buffer does not have enough data, or defines a length larger than available, it will set Err to ErrShortPacket.
   244  //
   245  // The returned slice aliases the buffer contents, and is valid only as long as the buffer is not reused
   246  // (that is, only until the next call to Reset, PutLength, StartPacket, or UnmarshalBinary).
   247  //
   248  // In no case will any Consume calls return overlapping slice aliases,
   249  // and Append calls are guaranteed to not disturb this slice alias.
   250  func (b *Buffer) ConsumeByteSlice() []byte {
   251  	length := int(b.ConsumeUint32())
   252  	if b.Err != nil {
   253  		return nil
   254  	}
   255  
   256  	if b.Len() < length || length < 0 {
   257  		b.off = len(b.b)
   258  		b.Err = ErrShortPacket
   259  		return nil
   260  	}
   261  
   262  	v := b.b[b.off:]
   263  	if len(v) > length || cap(v) > length {
   264  		v = v[:length:length]
   265  	}
   266  	b.off += int(length)
   267  	return v
   268  }
   269  
   270  // ConsumeByteSliceCopy consumes a single string of raw binary data as a copy from the buffer.
   271  // A string is a uint32 length, followed by that number of raw bytes.
   272  // If the buffer does not have enough data, or defines a length larger than available, it will set Err to ErrShortPacket.
   273  //
   274  // The returned slice does not alias any buffer contents,
   275  // and will therefore be valid even if the buffer is later reused.
   276  //
   277  // If hint has sufficient capacity to hold the data, it will be reused and overwritten,
   278  // otherwise a new backing slice will be allocated and returned.
   279  func (b *Buffer) ConsumeByteSliceCopy(hint []byte) []byte {
   280  	data := b.ConsumeByteSlice()
   281  
   282  	if grow := len(data) - len(hint); grow > 0 {
   283  		hint = append(hint, make([]byte, grow)...)
   284  	}
   285  
   286  	n := copy(hint, data)
   287  	hint = hint[:n]
   288  	return hint
   289  }
   290  
   291  // AppendByteSlice appends a single string of raw binary data into the buffer.
   292  // A string is a uint32 length, followed by that number of raw bytes.
   293  func (b *Buffer) AppendByteSlice(v []byte) {
   294  	b.AppendUint32(uint32(len(v)))
   295  	b.b = append(b.b, v...)
   296  }
   297  
   298  // ConsumeString consumes a single string of binary data from the buffer.
   299  // A string is a uint32 length, followed by that number of raw bytes.
   300  // If the buffer does not have enough data, or defines a length larger than available, it will set Err to ErrShortPacket.
   301  //
   302  // NOTE: Go implicitly assumes that strings contain UTF-8 encoded data.
   303  // All caveats on using arbitrary binary data in Go strings applies.
   304  func (b *Buffer) ConsumeString() string {
   305  	return string(b.ConsumeByteSlice())
   306  }
   307  
   308  // AppendString appends a single string of binary data into the buffer.
   309  // A string is a uint32 length, followed by that number of raw bytes.
   310  func (b *Buffer) AppendString(v string) {
   311  	b.AppendByteSlice([]byte(v))
   312  }
   313  
   314  // PutLength writes the given size into the first four bytes of the buffer in network byte order (big endian).
   315  func (b *Buffer) PutLength(size int) {
   316  	if len(b.b) < 4 {
   317  		b.b = append(b.b, make([]byte, 4-len(b.b))...)
   318  	}
   319  
   320  	binary.BigEndian.PutUint32(b.b, uint32(size))
   321  }
   322  
   323  // MarshalBinary returns a clone of the full internal buffer.
   324  func (b *Buffer) MarshalBinary() ([]byte, error) {
   325  	clone := make([]byte, len(b.b))
   326  	n := copy(clone, b.b)
   327  	return clone[:n], nil
   328  }
   329  
   330  // UnmarshalBinary sets the internal buffer of b to be a clone of data, and zeros the internal offset.
   331  func (b *Buffer) UnmarshalBinary(data []byte) error {
   332  	if grow := len(data) - len(b.b); grow > 0 {
   333  		b.b = append(b.b, make([]byte, grow)...)
   334  	}
   335  
   336  	n := copy(b.b, data)
   337  	b.b = b.b[:n]
   338  	b.off = 0
   339  	return nil
   340  }