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 }