1package filexfer
2
3// LStatPacket defines the SSH_FXP_LSTAT packet.
4type LStatPacket struct {
5	Path string
6}
7
8// Type returns the SSH_FXP_xy value associated with this packet type.
9func (p *LStatPacket) Type() PacketType {
10	return PacketTypeLStat
11}
12
13// MarshalPacket returns p as a two-part binary encoding of p.
14func (p *LStatPacket) MarshalPacket(reqid uint32, b []byte) (header, payload []byte, err error) {
15	buf := NewBuffer(b)
16	if buf.Cap() < 9 {
17		size := 4 + len(p.Path) // string(path)
18		buf = NewMarshalBuffer(size)
19	}
20
21	buf.StartPacket(PacketTypeLStat, reqid)
22	buf.AppendString(p.Path)
23
24	return buf.Packet(payload)
25}
26
27// UnmarshalPacketBody unmarshals the packet body from the given Buffer.
28// It is assumed that the uint32(request-id) has already been consumed.
29func (p *LStatPacket) UnmarshalPacketBody(buf *Buffer) (err error) {
30	if p.Path, err = buf.ConsumeString(); err != nil {
31		return err
32	}
33
34	return nil
35}
36
37// SetstatPacket defines the SSH_FXP_SETSTAT packet.
38type SetstatPacket struct {
39	Path  string
40	Attrs Attributes
41}
42
43// Type returns the SSH_FXP_xy value associated with this packet type.
44func (p *SetstatPacket) Type() PacketType {
45	return PacketTypeSetstat
46}
47
48// MarshalPacket returns p as a two-part binary encoding of p.
49func (p *SetstatPacket) MarshalPacket(reqid uint32, b []byte) (header, payload []byte, err error) {
50	buf := NewBuffer(b)
51	if buf.Cap() < 9 {
52		size := 4 + len(p.Path) + p.Attrs.Len() // string(path) + ATTRS(attrs)
53		buf = NewMarshalBuffer(size)
54	}
55
56	buf.StartPacket(PacketTypeSetstat, reqid)
57	buf.AppendString(p.Path)
58
59	p.Attrs.MarshalInto(buf)
60
61	return buf.Packet(payload)
62}
63
64// UnmarshalPacketBody unmarshals the packet body from the given Buffer.
65// It is assumed that the uint32(request-id) has already been consumed.
66func (p *SetstatPacket) UnmarshalPacketBody(buf *Buffer) (err error) {
67	if p.Path, err = buf.ConsumeString(); err != nil {
68		return err
69	}
70
71	return p.Attrs.UnmarshalFrom(buf)
72}
73
74// RemovePacket defines the SSH_FXP_REMOVE packet.
75type RemovePacket struct {
76	Path string
77}
78
79// Type returns the SSH_FXP_xy value associated with this packet type.
80func (p *RemovePacket) Type() PacketType {
81	return PacketTypeRemove
82}
83
84// MarshalPacket returns p as a two-part binary encoding of p.
85func (p *RemovePacket) MarshalPacket(reqid uint32, b []byte) (header, payload []byte, err error) {
86	buf := NewBuffer(b)
87	if buf.Cap() < 9 {
88		size := 4 + len(p.Path) // string(path)
89		buf = NewMarshalBuffer(size)
90	}
91
92	buf.StartPacket(PacketTypeRemove, reqid)
93	buf.AppendString(p.Path)
94
95	return buf.Packet(payload)
96}
97
98// UnmarshalPacketBody unmarshals the packet body from the given Buffer.
99// It is assumed that the uint32(request-id) has already been consumed.
100func (p *RemovePacket) UnmarshalPacketBody(buf *Buffer) (err error) {
101	if p.Path, err = buf.ConsumeString(); err != nil {
102		return err
103	}
104
105	return nil
106}
107
108// MkdirPacket defines the SSH_FXP_MKDIR packet.
109type MkdirPacket struct {
110	Path  string
111	Attrs Attributes
112}
113
114// Type returns the SSH_FXP_xy value associated with this packet type.
115func (p *MkdirPacket) Type() PacketType {
116	return PacketTypeMkdir
117}
118
119// MarshalPacket returns p as a two-part binary encoding of p.
120func (p *MkdirPacket) MarshalPacket(reqid uint32, b []byte) (header, payload []byte, err error) {
121	buf := NewBuffer(b)
122	if buf.Cap() < 9 {
123		size := 4 + len(p.Path) + p.Attrs.Len() // string(path) + ATTRS(attrs)
124		buf = NewMarshalBuffer(size)
125	}
126
127	buf.StartPacket(PacketTypeMkdir, reqid)
128	buf.AppendString(p.Path)
129
130	p.Attrs.MarshalInto(buf)
131
132	return buf.Packet(payload)
133}
134
135// UnmarshalPacketBody unmarshals the packet body from the given Buffer.
136// It is assumed that the uint32(request-id) has already been consumed.
137func (p *MkdirPacket) UnmarshalPacketBody(buf *Buffer) (err error) {
138	if p.Path, err = buf.ConsumeString(); err != nil {
139		return err
140	}
141
142	return p.Attrs.UnmarshalFrom(buf)
143}
144
145// RmdirPacket defines the SSH_FXP_RMDIR packet.
146type RmdirPacket struct {
147	Path string
148}
149
150// Type returns the SSH_FXP_xy value associated with this packet type.
151func (p *RmdirPacket) Type() PacketType {
152	return PacketTypeRmdir
153}
154
155// MarshalPacket returns p as a two-part binary encoding of p.
156func (p *RmdirPacket) MarshalPacket(reqid uint32, b []byte) (header, payload []byte, err error) {
157	buf := NewBuffer(b)
158	if buf.Cap() < 9 {
159		size := 4 + len(p.Path) // string(path)
160		buf = NewMarshalBuffer(size)
161	}
162
163	buf.StartPacket(PacketTypeRmdir, reqid)
164	buf.AppendString(p.Path)
165
166	return buf.Packet(payload)
167}
168
169// UnmarshalPacketBody unmarshals the packet body from the given Buffer.
170// It is assumed that the uint32(request-id) has already been consumed.
171func (p *RmdirPacket) UnmarshalPacketBody(buf *Buffer) (err error) {
172	if p.Path, err = buf.ConsumeString(); err != nil {
173		return err
174	}
175
176	return nil
177}
178
179// RealPathPacket defines the SSH_FXP_REALPATH packet.
180type RealPathPacket struct {
181	Path string
182}
183
184// Type returns the SSH_FXP_xy value associated with this packet type.
185func (p *RealPathPacket) Type() PacketType {
186	return PacketTypeRealPath
187}
188
189// MarshalPacket returns p as a two-part binary encoding of p.
190func (p *RealPathPacket) MarshalPacket(reqid uint32, b []byte) (header, payload []byte, err error) {
191	buf := NewBuffer(b)
192	if buf.Cap() < 9 {
193		size := 4 + len(p.Path) // string(path)
194		buf = NewMarshalBuffer(size)
195	}
196
197	buf.StartPacket(PacketTypeRealPath, reqid)
198	buf.AppendString(p.Path)
199
200	return buf.Packet(payload)
201}
202
203// UnmarshalPacketBody unmarshals the packet body from the given Buffer.
204// It is assumed that the uint32(request-id) has already been consumed.
205func (p *RealPathPacket) UnmarshalPacketBody(buf *Buffer) (err error) {
206	if p.Path, err = buf.ConsumeString(); err != nil {
207		return err
208	}
209
210	return nil
211}
212
213// StatPacket defines the SSH_FXP_STAT packet.
214type StatPacket struct {
215	Path string
216}
217
218// Type returns the SSH_FXP_xy value associated with this packet type.
219func (p *StatPacket) Type() PacketType {
220	return PacketTypeStat
221}
222
223// MarshalPacket returns p as a two-part binary encoding of p.
224func (p *StatPacket) MarshalPacket(reqid uint32, b []byte) (header, payload []byte, err error) {
225	buf := NewBuffer(b)
226	if buf.Cap() < 9 {
227		size := 4 + len(p.Path) // string(path)
228		buf = NewMarshalBuffer(size)
229	}
230
231	buf.StartPacket(PacketTypeStat, reqid)
232	buf.AppendString(p.Path)
233
234	return buf.Packet(payload)
235}
236
237// UnmarshalPacketBody unmarshals the packet body from the given Buffer.
238// It is assumed that the uint32(request-id) has already been consumed.
239func (p *StatPacket) UnmarshalPacketBody(buf *Buffer) (err error) {
240	if p.Path, err = buf.ConsumeString(); err != nil {
241		return err
242	}
243
244	return nil
245}
246
247// RenamePacket defines the SSH_FXP_RENAME packet.
248type RenamePacket struct {
249	OldPath string
250	NewPath string
251}
252
253// Type returns the SSH_FXP_xy value associated with this packet type.
254func (p *RenamePacket) Type() PacketType {
255	return PacketTypeRename
256}
257
258// MarshalPacket returns p as a two-part binary encoding of p.
259func (p *RenamePacket) MarshalPacket(reqid uint32, b []byte) (header, payload []byte, err error) {
260	buf := NewBuffer(b)
261	if buf.Cap() < 9 {
262		// string(oldpath) + string(newpath)
263		size := 4 + len(p.OldPath) + 4 + len(p.NewPath)
264		buf = NewMarshalBuffer(size)
265	}
266
267	buf.StartPacket(PacketTypeRename, reqid)
268	buf.AppendString(p.OldPath)
269	buf.AppendString(p.NewPath)
270
271	return buf.Packet(payload)
272}
273
274// UnmarshalPacketBody unmarshals the packet body from the given Buffer.
275// It is assumed that the uint32(request-id) has already been consumed.
276func (p *RenamePacket) UnmarshalPacketBody(buf *Buffer) (err error) {
277	if p.OldPath, err = buf.ConsumeString(); err != nil {
278		return err
279	}
280
281	if p.NewPath, err = buf.ConsumeString(); err != nil {
282		return err
283	}
284
285	return nil
286}
287
288// ReadLinkPacket defines the SSH_FXP_READLINK packet.
289type ReadLinkPacket struct {
290	Path string
291}
292
293// Type returns the SSH_FXP_xy value associated with this packet type.
294func (p *ReadLinkPacket) Type() PacketType {
295	return PacketTypeReadLink
296}
297
298// MarshalPacket returns p as a two-part binary encoding of p.
299func (p *ReadLinkPacket) MarshalPacket(reqid uint32, b []byte) (header, payload []byte, err error) {
300	buf := NewBuffer(b)
301	if buf.Cap() < 9 {
302		size := 4 + len(p.Path) // string(path)
303		buf = NewMarshalBuffer(size)
304	}
305
306	buf.StartPacket(PacketTypeReadLink, reqid)
307	buf.AppendString(p.Path)
308
309	return buf.Packet(payload)
310}
311
312// UnmarshalPacketBody unmarshals the packet body from the given Buffer.
313// It is assumed that the uint32(request-id) has already been consumed.
314func (p *ReadLinkPacket) UnmarshalPacketBody(buf *Buffer) (err error) {
315	if p.Path, err = buf.ConsumeString(); err != nil {
316		return err
317	}
318
319	return nil
320}
321
322// SymlinkPacket defines the SSH_FXP_SYMLINK packet.
323//
324// The order of the arguments to the SSH_FXP_SYMLINK method was inadvertently reversed.
325// Unfortunately, the reversal was not noticed until the server was widely deployed.
326// Covered in Section 3.1 of https://github.com/openssh/openssh-portable/blob/master/PROTOCOL
327type SymlinkPacket struct {
328	LinkPath   string
329	TargetPath string
330}
331
332// Type returns the SSH_FXP_xy value associated with this packet type.
333func (p *SymlinkPacket) Type() PacketType {
334	return PacketTypeSymlink
335}
336
337// MarshalPacket returns p as a two-part binary encoding of p.
338func (p *SymlinkPacket) MarshalPacket(reqid uint32, b []byte) (header, payload []byte, err error) {
339	buf := NewBuffer(b)
340	if buf.Cap() < 9 {
341		// string(targetpath) + string(linkpath)
342		size := 4 + len(p.TargetPath) + 4 + len(p.LinkPath)
343		buf = NewMarshalBuffer(size)
344	}
345
346	buf.StartPacket(PacketTypeSymlink, reqid)
347
348	// Arguments were inadvertently reversed.
349	buf.AppendString(p.TargetPath)
350	buf.AppendString(p.LinkPath)
351
352	return buf.Packet(payload)
353}
354
355// UnmarshalPacketBody unmarshals the packet body from the given Buffer.
356// It is assumed that the uint32(request-id) has already been consumed.
357func (p *SymlinkPacket) UnmarshalPacketBody(buf *Buffer) (err error) {
358	// Arguments were inadvertently reversed.
359	if p.TargetPath, err = buf.ConsumeString(); err != nil {
360		return err
361	}
362
363	if p.LinkPath, err = buf.ConsumeString(); err != nil {
364		return err
365	}
366
367	return nil
368}
369