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

     1  package sshfx
     2  
     3  import (
     4  	"fmt"
     5  )
     6  
     7  // StatusPacket defines the SSH_FXP_STATUS packet.
     8  //
     9  // Specified in https://filezilla-project.org/specs/draft-ietf-secsh-filexfer-02.txt#section-7
    10  type StatusPacket struct {
    11  	StatusCode   Status
    12  	ErrorMessage string
    13  	LanguageTag  string
    14  }
    15  
    16  // Error makes StatusPacket an error type.
    17  func (p *StatusPacket) Error() string {
    18  	if p.ErrorMessage == "" {
    19  		return "sftp: " + p.StatusCode.String()
    20  	}
    21  
    22  	return fmt.Sprintf("sftp: %s: %q", p.StatusCode, p.ErrorMessage)
    23  }
    24  
    25  // Is returns true if target is a StatusPacket with the same StatusCode,
    26  // or target is a Status code which is the same as SatusCode.
    27  func (p *StatusPacket) Is(target error) bool {
    28  	if target, ok := target.(*StatusPacket); ok {
    29  		return p.StatusCode == target.StatusCode
    30  	}
    31  
    32  	return p.StatusCode == target
    33  }
    34  
    35  // Type returns the SSH_FXP_xy value associated with this packet type.
    36  func (p *StatusPacket) Type() PacketType {
    37  	return PacketTypeStatus
    38  }
    39  
    40  // MarshalPacket returns p as a two-part binary encoding of p.
    41  func (p *StatusPacket) MarshalPacket(reqid uint32, b []byte) (header, payload []byte, err error) {
    42  	buf := NewBuffer(b)
    43  	if buf.Cap() < 9 {
    44  		// uint32(error/status code) + string(error message) + string(language tag)
    45  		size := 4 + 4 + len(p.ErrorMessage) + 4 + len(p.LanguageTag)
    46  		buf = NewMarshalBuffer(size)
    47  	}
    48  
    49  	buf.StartPacket(PacketTypeStatus, reqid)
    50  	buf.AppendUint32(uint32(p.StatusCode))
    51  	buf.AppendString(p.ErrorMessage)
    52  	buf.AppendString(p.LanguageTag)
    53  
    54  	return buf.Packet(payload)
    55  }
    56  
    57  // UnmarshalPacketBody unmarshals the packet body from the given Buffer.
    58  // It is assumed that the uint32(request-id) has already been consumed.
    59  func (p *StatusPacket) UnmarshalPacketBody(buf *Buffer) (err error) {
    60  	*p = StatusPacket{
    61  		StatusCode:   Status(buf.ConsumeUint32()),
    62  		ErrorMessage: buf.ConsumeString(),
    63  		LanguageTag:  buf.ConsumeString(),
    64  	}
    65  
    66  	return buf.Err
    67  }
    68  
    69  // HandlePacket defines the SSH_FXP_HANDLE packet.
    70  type HandlePacket struct {
    71  	Handle string
    72  }
    73  
    74  // Type returns the SSH_FXP_xy value associated with this packet type.
    75  func (p *HandlePacket) Type() PacketType {
    76  	return PacketTypeHandle
    77  }
    78  
    79  // MarshalPacket returns p as a two-part binary encoding of p.
    80  func (p *HandlePacket) MarshalPacket(reqid uint32, b []byte) (header, payload []byte, err error) {
    81  	buf := NewBuffer(b)
    82  	if buf.Cap() < 9 {
    83  		size := 4 + len(p.Handle) // string(handle)
    84  		buf = NewMarshalBuffer(size)
    85  	}
    86  
    87  	buf.StartPacket(PacketTypeHandle, reqid)
    88  	buf.AppendString(p.Handle)
    89  
    90  	return buf.Packet(payload)
    91  }
    92  
    93  // UnmarshalPacketBody unmarshals the packet body from the given Buffer.
    94  // It is assumed that the uint32(request-id) has already been consumed.
    95  func (p *HandlePacket) UnmarshalPacketBody(buf *Buffer) (err error) {
    96  	*p = HandlePacket{
    97  		Handle: buf.ConsumeString(),
    98  	}
    99  
   100  	return buf.Err
   101  }
   102  
   103  // DataPacket defines the SSH_FXP_DATA packet.
   104  type DataPacket struct {
   105  	Data []byte
   106  }
   107  
   108  // Type returns the SSH_FXP_xy value associated with this packet type.
   109  func (p *DataPacket) Type() PacketType {
   110  	return PacketTypeData
   111  }
   112  
   113  // MarshalPacket returns p as a two-part binary encoding of p.
   114  func (p *DataPacket) MarshalPacket(reqid uint32, b []byte) (header, payload []byte, err error) {
   115  	buf := NewBuffer(b)
   116  	if buf.Cap() < 9 {
   117  		size := 4 // uint32(len(data)); data content in payload
   118  		buf = NewMarshalBuffer(size)
   119  	}
   120  
   121  	buf.StartPacket(PacketTypeData, reqid)
   122  	buf.AppendUint32(uint32(len(p.Data)))
   123  
   124  	return buf.Packet(p.Data)
   125  }
   126  
   127  // UnmarshalPacketBody unmarshals the packet body from the given Buffer.
   128  // It is assumed that the uint32(request-id) has already been consumed.
   129  //
   130  // If p.Data is already populated, and of sufficient length to hold the data,
   131  // then this will copy the data into that byte slice.
   132  //
   133  // If p.Data has a length insufficient to hold the data,
   134  // then this will make a new slice of sufficient length, and copy the data into that.
   135  //
   136  // This means this _does not_ alias any of the data buffer that is passed in.
   137  func (p *DataPacket) UnmarshalPacketBody(buf *Buffer) (err error) {
   138  	*p = DataPacket{
   139  		Data: buf.ConsumeByteSliceCopy(p.Data),
   140  	}
   141  
   142  	return buf.Err
   143  }
   144  
   145  // NamePacket defines the SSH_FXP_NAME packet.
   146  type NamePacket struct {
   147  	Entries []*NameEntry
   148  }
   149  
   150  // Type returns the SSH_FXP_xy value associated with this packet type.
   151  func (p *NamePacket) Type() PacketType {
   152  	return PacketTypeName
   153  }
   154  
   155  // MarshalPacket returns p as a two-part binary encoding of p.
   156  func (p *NamePacket) MarshalPacket(reqid uint32, b []byte) (header, payload []byte, err error) {
   157  	buf := NewBuffer(b)
   158  	if buf.Cap() < 9 {
   159  		size := 4 // uint32(len(entries))
   160  
   161  		for _, e := range p.Entries {
   162  			size += e.Len()
   163  		}
   164  
   165  		buf = NewMarshalBuffer(size)
   166  	}
   167  
   168  	buf.StartPacket(PacketTypeName, reqid)
   169  	buf.AppendUint32(uint32(len(p.Entries)))
   170  
   171  	for _, e := range p.Entries {
   172  		e.MarshalInto(buf)
   173  	}
   174  
   175  	return buf.Packet(payload)
   176  }
   177  
   178  // UnmarshalPacketBody unmarshals the packet body from the given Buffer.
   179  // It is assumed that the uint32(request-id) has already been consumed.
   180  func (p *NamePacket) UnmarshalPacketBody(buf *Buffer) (err error) {
   181  	count := buf.ConsumeCount()
   182  	if buf.Err != nil {
   183  		return buf.Err
   184  	}
   185  
   186  	*p = NamePacket{
   187  		Entries: make([]*NameEntry, 0, count),
   188  	}
   189  
   190  	for i := 0; i < count; i++ {
   191  		var e NameEntry
   192  		if err := e.UnmarshalFrom(buf); err != nil {
   193  			return err
   194  		}
   195  
   196  		p.Entries = append(p.Entries, &e)
   197  	}
   198  
   199  	return buf.Err
   200  }
   201  
   202  // AttrsPacket defines the SSH_FXP_ATTRS packet.
   203  type AttrsPacket struct {
   204  	Attrs Attributes
   205  }
   206  
   207  // Type returns the SSH_FXP_xy value associated with this packet type.
   208  func (p *AttrsPacket) Type() PacketType {
   209  	return PacketTypeAttrs
   210  }
   211  
   212  // MarshalPacket returns p as a two-part binary encoding of p.
   213  func (p *AttrsPacket) MarshalPacket(reqid uint32, b []byte) (header, payload []byte, err error) {
   214  	buf := NewBuffer(b)
   215  	if buf.Cap() < 9 {
   216  		size := p.Attrs.Len() // ATTRS(attrs)
   217  		buf = NewMarshalBuffer(size)
   218  	}
   219  
   220  	buf.StartPacket(PacketTypeAttrs, reqid)
   221  	p.Attrs.MarshalInto(buf)
   222  
   223  	return buf.Packet(payload)
   224  }
   225  
   226  // UnmarshalPacketBody unmarshals the packet body from the given Buffer.
   227  // It is assumed that the uint32(request-id) has already been consumed.
   228  func (p *AttrsPacket) UnmarshalPacketBody(buf *Buffer) (err error) {
   229  	return p.Attrs.UnmarshalFrom(buf)
   230  }