Source File
buffer.go
Belonging Package
github.com/pkg/sftp/internal/encoding/ssh/filexfer
package sshfximport ()// 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-8type Buffer struct {b []byteoff intErr error}// 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 ( []byte) *Buffer {return &Buffer{b: ,}}// 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 ( int) *Buffer {return NewBuffer(make([]byte, 4+1+4+))}// 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 ( *Buffer) () []byte {return .b[.off:]}// Len returns the number of unconsumed bytes in the buffer.func ( *Buffer) () int { return len(.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 ( *Buffer) () int { return cap(.b) }// Reset resets the buffer to be empty, but it retains the underlying storage for use by future Appends.func ( *Buffer) () {* = Buffer{b: .b[: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 ( *Buffer) ( PacketType, uint32) {* = Buffer{b: append(.b[:0], make([]byte, 4)...),}.AppendUint8(uint8()).AppendUint32()}// 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 ( *Buffer) ( []byte) (, []byte, error) {.PutLength(len(.b) - 4 + len())return .b, , nil}// ConsumeUint8 consumes a single byte from the buffer.// If the buffer does not have enough data, it will set Err to ErrShortPacket.func ( *Buffer) () uint8 {if .Err != nil {return 0}if .Len() < 1 {.off = len(.b).Err = ErrShortPacketreturn 0}var uint8, .off = .b[.off], .off+1return}// AppendUint8 appends a single byte into the buffer.func ( *Buffer) ( uint8) {.b = append(.b, )}// 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 set Err to ErrShortPacket.func ( *Buffer) () bool {return .ConsumeUint8() != 0}// AppendBool appends a single bool into the buffer.// It encodes it as a single byte, with false as 0, and true as 1.func ( *Buffer) ( bool) {if {.AppendUint8(1)} else {.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 set Err to ErrShortPacket.func ( *Buffer) () uint16 {if .Err != nil {return 0}if .Len() < 2 {.off = len(.b).Err = ErrShortPacketreturn 0}:= binary.BigEndian.Uint16(.b[.off:]).off += 2return}// AppendUint16 appends single uint16 into the buffer, in network byte order (big-endian).func ( *Buffer) ( uint16) {.b = append(.b,byte(>>8),byte(>>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( []byte) uint32 {return binary.BigEndian.Uint32([: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 set Err to ErrShortPacket.func ( *Buffer) () uint32 {if .Err != nil {return 0}if .Len() < 4 {.off = len(.b).Err = ErrShortPacketreturn 0}:= binary.BigEndian.Uint32(.b[.off:]).off += 4return}// AppendUint32 appends a single uint32 into the buffer, in network byte order (big-endian).func ( *Buffer) ( uint32) {.b = append(.b,byte(>>24),byte(>>16),byte(>>8),byte(>>0),)}// ConsumeCount consumes a single uint32 count from the buffer, in network byte order (big-endian) as an int.// If the buffer does not have enough data, it will set Err to ErrShortPacket.func ( *Buffer) () int {return int(.ConsumeUint32())}// AppendCount appends a single int length as a uint32 into the buffer, in network byte order (big-endian).func ( *Buffer) ( int) {.AppendUint32(uint32())}// ConsumeUint64 consumes a single uint64 from the buffer, in network byte order (big-endian).// If the buffer does not have enough data, it will set Err to ErrShortPacket.func ( *Buffer) () uint64 {if .Err != nil {return 0}if .Len() < 8 {.off = len(.b).Err = ErrShortPacketreturn 0}:= binary.BigEndian.Uint64(.b[.off:]).off += 8return}// AppendUint64 appends a single uint64 into the buffer, in network byte order (big-endian).func ( *Buffer) ( uint64) {.b = append(.b,byte(>>56),byte(>>48),byte(>>40),byte(>>32),byte(>>24),byte(>>16),byte(>>8),byte(>>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 set Err to ErrShortPacket.func ( *Buffer) () int64 {return int64(.ConsumeUint64())}// AppendInt64 appends a single int64 into the buffer, in network byte order (big-endian) with two’s complement.func ( *Buffer) ( int64) {.AppendUint64(uint64())}// 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 set Err to 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 ( *Buffer) () []byte {:= int(.ConsumeUint32())if .Err != nil {return nil}if .Len() < || < 0 {.off = len(.b).Err = ErrShortPacketreturn nil}:= .b[.off:]if len() > || cap() > {= [::]}.off += int()return}// ConsumeByteSliceCopy consumes a single string of raw binary data as a copy 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 set Err to ErrShortPacket.//// The returned slice does not alias any buffer contents,// and will therefore be valid even if the buffer is later reused.//// If hint has sufficient capacity to hold the data, it will be reused and overwritten,// otherwise a new backing slice will be allocated and returned.func ( *Buffer) ( []byte) []byte {:= .ConsumeByteSlice()if := len() - len(); > 0 {= append(, make([]byte, )...)}:= copy(, )= [:]return}// 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 ( *Buffer) ( []byte) {.AppendUint32(uint32(len())).b = append(.b, ...)}// 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 set Err to ErrShortPacket.//// NOTE: Go implicitly assumes that strings contain UTF-8 encoded data.// All caveats on using arbitrary binary data in Go strings applies.func ( *Buffer) () string {return string(.ConsumeByteSlice())}// 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 ( *Buffer) ( string) {.AppendByteSlice([]byte())}// PutLength writes the given size into the first four bytes of the buffer in network byte order (big endian).func ( *Buffer) ( int) {if len(.b) < 4 {.b = append(.b, make([]byte, 4-len(.b))...)}binary.BigEndian.PutUint32(.b, uint32())}// MarshalBinary returns a clone of the full internal buffer.func ( *Buffer) () ([]byte, error) {:= make([]byte, len(.b)):= copy(, .b)return [:], nil}// UnmarshalBinary sets the internal buffer of b to be a clone of data, and zeros the internal offset.func ( *Buffer) ( []byte) error {if := len() - len(.b); > 0 {.b = append(.b, make([]byte, )...)}:= copy(.b, ).b = .b[:].off = 0return nil}
![]() |
The pages are generated with Golds v0.6.7. (GOOS=linux GOARCH=amd64) Golds is a Go 101 project developed by Tapir Liu. PR and bug reports are welcome and can be submitted to the issue list. Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds. |