| 
									
										
										
										
											2023-03-28 01:05:24 +08:00
										 |  |  | package sshfx | 
					
						
							| 
									
										
										
										
											2021-03-20 02:29:35 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-22 23:00:04 +08:00
										 |  |  | import ( | 
					
						
							|  |  |  | 	"fmt" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-20 02:29:35 +08:00
										 |  |  | // StatusPacket defines the SSH_FXP_STATUS packet.
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2023-03-28 01:05:24 +08:00
										 |  |  | // Specified in https://filezilla-project.org/specs/draft-ietf-secsh-filexfer-02.txt#section-7
 | 
					
						
							| 
									
										
										
										
											2021-03-20 02:29:35 +08:00
										 |  |  | type StatusPacket struct { | 
					
						
							|  |  |  | 	StatusCode   Status | 
					
						
							|  |  |  | 	ErrorMessage string | 
					
						
							|  |  |  | 	LanguageTag  string | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-22 23:00:04 +08:00
										 |  |  | // Error makes StatusPacket an error type.
 | 
					
						
							|  |  |  | func (p *StatusPacket) Error() string { | 
					
						
							|  |  |  | 	if p.ErrorMessage == "" { | 
					
						
							|  |  |  | 		return "sftp: " + p.StatusCode.String() | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-28 01:05:24 +08:00
										 |  |  | 	return fmt.Sprintf("sftp: %s: %q", p.StatusCode, p.ErrorMessage) | 
					
						
							| 
									
										
										
										
											2021-05-22 23:00:04 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // 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 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-20 02:29:35 +08:00
										 |  |  | // MarshalPacket returns p as a two-part binary encoding of p.
 | 
					
						
							| 
									
										
										
										
											2021-03-23 00:12:42 +08:00
										 |  |  | 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) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-03-20 02:29:35 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-23 00:12:42 +08:00
										 |  |  | 	buf.StartPacket(PacketTypeStatus, reqid) | 
					
						
							|  |  |  | 	buf.AppendUint32(uint32(p.StatusCode)) | 
					
						
							|  |  |  | 	buf.AppendString(p.ErrorMessage) | 
					
						
							|  |  |  | 	buf.AppendString(p.LanguageTag) | 
					
						
							| 
									
										
										
										
											2021-03-20 02:29:35 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-23 00:12:42 +08:00
										 |  |  | 	return buf.Packet(payload) | 
					
						
							| 
									
										
										
										
											2021-03-20 02:29:35 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // 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) { | 
					
						
							| 
									
										
										
										
											2023-03-28 01:05:24 +08:00
										 |  |  | 	*p = StatusPacket{ | 
					
						
							|  |  |  | 		StatusCode:   Status(buf.ConsumeUint32()), | 
					
						
							|  |  |  | 		ErrorMessage: buf.ConsumeString(), | 
					
						
							|  |  |  | 		LanguageTag:  buf.ConsumeString(), | 
					
						
							| 
									
										
										
										
											2021-03-20 02:29:35 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-28 01:05:24 +08:00
										 |  |  | 	return buf.Err | 
					
						
							| 
									
										
										
										
											2021-03-20 02:29:35 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // HandlePacket defines the SSH_FXP_HANDLE packet.
 | 
					
						
							|  |  |  | type HandlePacket struct { | 
					
						
							| 
									
										
										
										
											2021-03-21 22:11:23 +08:00
										 |  |  | 	Handle string | 
					
						
							| 
									
										
										
										
											2021-03-20 02:29:35 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-22 23:00:04 +08:00
										 |  |  | // Type returns the SSH_FXP_xy value associated with this packet type.
 | 
					
						
							|  |  |  | func (p *HandlePacket) Type() PacketType { | 
					
						
							|  |  |  | 	return PacketTypeHandle | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-20 02:29:35 +08:00
										 |  |  | // MarshalPacket returns p as a two-part binary encoding of p.
 | 
					
						
							| 
									
										
										
										
											2021-03-23 00:12:42 +08:00
										 |  |  | 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) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-03-20 02:29:35 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-23 00:12:42 +08:00
										 |  |  | 	buf.StartPacket(PacketTypeHandle, reqid) | 
					
						
							|  |  |  | 	buf.AppendString(p.Handle) | 
					
						
							| 
									
										
										
										
											2021-03-20 02:29:35 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-23 00:12:42 +08:00
										 |  |  | 	return buf.Packet(payload) | 
					
						
							| 
									
										
										
										
											2021-03-20 02:29:35 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // 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) { | 
					
						
							| 
									
										
										
										
											2023-03-28 01:05:24 +08:00
										 |  |  | 	*p = HandlePacket{ | 
					
						
							|  |  |  | 		Handle: buf.ConsumeString(), | 
					
						
							| 
									
										
										
										
											2021-03-20 02:29:35 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-28 01:05:24 +08:00
										 |  |  | 	return buf.Err | 
					
						
							| 
									
										
										
										
											2021-03-20 02:29:35 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // DataPacket defines the SSH_FXP_DATA packet.
 | 
					
						
							|  |  |  | type DataPacket struct { | 
					
						
							| 
									
										
										
										
											2021-03-21 22:11:23 +08:00
										 |  |  | 	Data []byte | 
					
						
							| 
									
										
										
										
											2021-03-20 02:29:35 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-22 23:00:04 +08:00
										 |  |  | // Type returns the SSH_FXP_xy value associated with this packet type.
 | 
					
						
							|  |  |  | func (p *DataPacket) Type() PacketType { | 
					
						
							|  |  |  | 	return PacketTypeData | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-20 02:29:35 +08:00
										 |  |  | // MarshalPacket returns p as a two-part binary encoding of p.
 | 
					
						
							| 
									
										
										
										
											2021-03-23 00:12:42 +08:00
										 |  |  | 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) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-03-20 02:29:35 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-23 00:12:42 +08:00
										 |  |  | 	buf.StartPacket(PacketTypeData, reqid) | 
					
						
							|  |  |  | 	buf.AppendUint32(uint32(len(p.Data))) | 
					
						
							| 
									
										
										
										
											2021-03-20 02:29:35 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-23 00:12:42 +08:00
										 |  |  | 	return buf.Packet(p.Data) | 
					
						
							| 
									
										
										
										
											2021-03-20 02:29:35 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // UnmarshalPacketBody unmarshals the packet body from the given Buffer.
 | 
					
						
							|  |  |  | // It is assumed that the uint32(request-id) has already been consumed.
 | 
					
						
							| 
									
										
										
										
											2021-05-22 23:00:04 +08:00
										 |  |  | //
 | 
					
						
							|  |  |  | // 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.
 | 
					
						
							| 
									
										
										
										
											2021-03-20 02:29:35 +08:00
										 |  |  | func (p *DataPacket) UnmarshalPacketBody(buf *Buffer) (err error) { | 
					
						
							| 
									
										
										
										
											2023-03-28 01:05:24 +08:00
										 |  |  | 	*p = DataPacket{ | 
					
						
							|  |  |  | 		Data: buf.ConsumeByteSliceCopy(p.Data), | 
					
						
							| 
									
										
										
										
											2021-05-22 23:00:04 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-28 01:05:24 +08:00
										 |  |  | 	return buf.Err | 
					
						
							| 
									
										
										
										
											2021-03-20 02:29:35 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // NamePacket defines the SSH_FXP_NAME packet.
 | 
					
						
							|  |  |  | type NamePacket struct { | 
					
						
							| 
									
										
										
										
											2021-03-21 22:11:23 +08:00
										 |  |  | 	Entries []*NameEntry | 
					
						
							| 
									
										
										
										
											2021-03-20 02:29:35 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-22 23:00:04 +08:00
										 |  |  | // Type returns the SSH_FXP_xy value associated with this packet type.
 | 
					
						
							|  |  |  | func (p *NamePacket) Type() PacketType { | 
					
						
							|  |  |  | 	return PacketTypeName | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-20 02:29:35 +08:00
										 |  |  | // MarshalPacket returns p as a two-part binary encoding of p.
 | 
					
						
							| 
									
										
										
										
											2021-03-23 00:12:42 +08:00
										 |  |  | 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))
 | 
					
						
							| 
									
										
										
										
											2021-03-20 05:19:45 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-23 00:12:42 +08:00
										 |  |  | 		for _, e := range p.Entries { | 
					
						
							|  |  |  | 			size += e.Len() | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-03-20 02:29:35 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-23 00:12:42 +08:00
										 |  |  | 		buf = NewMarshalBuffer(size) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-03-20 02:29:35 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-23 00:12:42 +08:00
										 |  |  | 	buf.StartPacket(PacketTypeName, reqid) | 
					
						
							|  |  |  | 	buf.AppendUint32(uint32(len(p.Entries))) | 
					
						
							| 
									
										
										
										
											2021-03-20 02:29:35 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	for _, e := range p.Entries { | 
					
						
							| 
									
										
										
										
											2021-03-23 00:12:42 +08:00
										 |  |  | 		e.MarshalInto(buf) | 
					
						
							| 
									
										
										
										
											2021-03-20 02:29:35 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-23 00:12:42 +08:00
										 |  |  | 	return buf.Packet(payload) | 
					
						
							| 
									
										
										
										
											2021-03-20 02:29:35 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // 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) { | 
					
						
							| 
									
										
										
										
											2023-03-28 01:05:24 +08:00
										 |  |  | 	count := buf.ConsumeCount() | 
					
						
							|  |  |  | 	if buf.Err != nil { | 
					
						
							|  |  |  | 		return buf.Err | 
					
						
							| 
									
										
										
										
											2021-03-20 02:29:35 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-28 01:05:24 +08:00
										 |  |  | 	*p = NamePacket{ | 
					
						
							|  |  |  | 		Entries: make([]*NameEntry, 0, count), | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-03-20 02:29:35 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-28 01:05:24 +08:00
										 |  |  | 	for i := 0; i < count; i++ { | 
					
						
							| 
									
										
										
										
											2021-03-20 02:29:35 +08:00
										 |  |  | 		var e NameEntry | 
					
						
							|  |  |  | 		if err := e.UnmarshalFrom(buf); err != nil { | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		p.Entries = append(p.Entries, &e) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-28 01:25:27 +08:00
										 |  |  | 	return buf.Err | 
					
						
							| 
									
										
										
										
											2021-03-20 02:29:35 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // AttrsPacket defines the SSH_FXP_ATTRS packet.
 | 
					
						
							|  |  |  | type AttrsPacket struct { | 
					
						
							| 
									
										
										
										
											2021-03-21 22:11:23 +08:00
										 |  |  | 	Attrs Attributes | 
					
						
							| 
									
										
										
										
											2021-03-20 02:29:35 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-22 23:00:04 +08:00
										 |  |  | // Type returns the SSH_FXP_xy value associated with this packet type.
 | 
					
						
							|  |  |  | func (p *AttrsPacket) Type() PacketType { | 
					
						
							|  |  |  | 	return PacketTypeAttrs | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-20 02:29:35 +08:00
										 |  |  | // MarshalPacket returns p as a two-part binary encoding of p.
 | 
					
						
							| 
									
										
										
										
											2021-03-23 00:12:42 +08:00
										 |  |  | 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) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-03-20 02:29:35 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-23 00:12:42 +08:00
										 |  |  | 	buf.StartPacket(PacketTypeAttrs, reqid) | 
					
						
							|  |  |  | 	p.Attrs.MarshalInto(buf) | 
					
						
							| 
									
										
										
										
											2021-03-20 02:29:35 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-23 00:12:42 +08:00
										 |  |  | 	return buf.Packet(payload) | 
					
						
							| 
									
										
										
										
											2021-03-20 02:29:35 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // 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) | 
					
						
							|  |  |  | } |