@@ -66,7 +66,7 @@ func (svr *Server) getHandle(handle string) (*os.File, bool) {
66
66
type serverRespondablePacket interface {
67
67
encoding.BinaryUnmarshaler
68
68
id () uint32
69
- respond (svr * Server ) error
69
+ respond (svr * Server ) responsePacket
70
70
}
71
71
72
72
// NewServer creates a new Server instance around the provided streams, serving
@@ -140,7 +140,7 @@ func (svr *Server) sftpServerWorker(pktChan chan requestPacket) error {
140
140
// If server is operating read-only and a write operation is requested,
141
141
// return permission denied
142
142
if ! readonly && svr .readOnly {
143
- svr .sendError ( pkt , syscall .EPERM )
143
+ svr .sendPacket ( statusFromError ( pkt , syscall .EPERM ) )
144
144
continue
145
145
}
146
146
@@ -152,133 +152,138 @@ func (svr *Server) sftpServerWorker(pktChan chan requestPacket) error {
152
152
}
153
153
154
154
func handlePacket (s * Server , p requestPacket ) error {
155
+ var rpkt responsePacket
155
156
switch p := p .(type ) {
156
157
case * sshFxInitPacket :
157
- return s . sendPacket ( sshFxVersionPacket {Version : sftpProtocolVersion })
158
+ rpkt = sshFxVersionPacket {Version : sftpProtocolVersion }
158
159
case * sshFxpStatPacket :
159
160
// stat the requested file
160
161
info , err := os .Stat (p .Path )
161
- if err != nil {
162
- return s .sendError (p , err )
163
- }
164
- return s .sendPacket (sshFxpStatResponse {
162
+ rpkt = sshFxpStatResponse {
165
163
ID : p .ID ,
166
164
info : info ,
167
- })
165
+ }
166
+ if err != nil {
167
+ rpkt = statusFromError (p , err )
168
+ }
168
169
case * sshFxpLstatPacket :
169
170
// stat the requested file
170
171
info , err := os .Lstat (p .Path )
171
- if err != nil {
172
- return s .sendError (p , err )
173
- }
174
- return s .sendPacket (sshFxpStatResponse {
172
+ rpkt = sshFxpStatResponse {
175
173
ID : p .ID ,
176
174
info : info ,
177
- })
175
+ }
176
+ if err != nil {
177
+ rpkt = statusFromError (p , err )
178
+ }
178
179
case * sshFxpFstatPacket :
180
+ fmt .Println ("fstat" )
179
181
f , ok := s .getHandle (p .Handle )
180
- if ! ok {
181
- return s .sendError (p , syscall .EBADF )
182
+ var err error = syscall .EBADF
183
+ var info os.FileInfo
184
+ if ok {
185
+ info , err = f .Stat ()
186
+ rpkt = sshFxpStatResponse {
187
+ ID : p .ID ,
188
+ info : info ,
189
+ }
182
190
}
183
-
184
- info , err := f .Stat ()
185
191
if err != nil {
186
- return s . sendError (p , err )
192
+ rpkt = statusFromError (p , err )
187
193
}
188
-
189
- return s .sendPacket (sshFxpStatResponse {
190
- ID : p .ID ,
191
- info : info ,
192
- })
193
194
case * sshFxpMkdirPacket :
194
195
// TODO FIXME: ignore flags field
195
196
err := os .Mkdir (p .Path , 0755 )
196
- return s . sendError (p , err )
197
+ rpkt = statusFromError (p , err )
197
198
case * sshFxpRmdirPacket :
198
199
err := os .Remove (p .Path )
199
- return s . sendError (p , err )
200
+ rpkt = statusFromError (p , err )
200
201
case * sshFxpRemovePacket :
201
202
err := os .Remove (p .Filename )
202
- return s . sendError (p , err )
203
+ rpkt = statusFromError (p , err )
203
204
case * sshFxpRenamePacket :
204
205
err := os .Rename (p .Oldpath , p .Newpath )
205
- return s . sendError (p , err )
206
+ rpkt = statusFromError (p , err )
206
207
case * sshFxpSymlinkPacket :
207
208
err := os .Symlink (p .Targetpath , p .Linkpath )
208
- return s . sendError (p , err )
209
+ rpkt = statusFromError (p , err )
209
210
case * sshFxpClosePacket :
210
- return s . sendError (p , s .closeHandle (p .Handle ))
211
+ rpkt = statusFromError (p , s .closeHandle (p .Handle ))
211
212
case * sshFxpReadlinkPacket :
212
213
f , err := os .Readlink (p .Path )
213
- if err != nil {
214
- return s .sendError (p , err )
215
- }
216
-
217
- return s .sendPacket (sshFxpNamePacket {
214
+ rpkt = sshFxpNamePacket {
218
215
ID : p .ID ,
219
216
NameAttrs : []sshFxpNameAttr {{
220
217
Name : f ,
221
218
LongName : f ,
222
219
Attrs : emptyFileStat ,
223
220
}},
224
- })
225
-
226
- case * sshFxpRealpathPacket :
227
- f , err := filepath .Abs (p .Path )
221
+ }
228
222
if err != nil {
229
- return s . sendError (p , err )
223
+ rpkt = statusFromError (p , err )
230
224
}
225
+ case * sshFxpRealpathPacket :
226
+ f , err := filepath .Abs (p .Path )
231
227
f = cleanPath (f )
232
- return s . sendPacket ( sshFxpNamePacket {
228
+ rpkt = sshFxpNamePacket {
233
229
ID : p .ID ,
234
230
NameAttrs : []sshFxpNameAttr {{
235
231
Name : f ,
236
232
LongName : f ,
237
233
Attrs : emptyFileStat ,
238
234
}},
239
- })
235
+ }
236
+ if err != nil {
237
+ rpkt = statusFromError (p , err )
238
+ }
240
239
case * sshFxpOpendirPacket :
241
240
if stat , err := os .Stat (p .Path ); err != nil {
242
- return s . sendError (p , err )
241
+ rpkt = statusFromError (p , err )
243
242
} else if ! stat .IsDir () {
244
- return s . sendError (p , & os.PathError {
243
+ rpkt = statusFromError (p , & os.PathError {
245
244
Path : p .Path , Err : syscall .ENOTDIR })
245
+ } else {
246
+ rpkt = sshFxpOpenPacket {
247
+ ID : p .ID ,
248
+ Path : p .Path ,
249
+ Pflags : ssh_FXF_READ ,
250
+ }.respond (s )
246
251
}
247
- return sshFxpOpenPacket {
248
- ID : p .ID ,
249
- Path : p .Path ,
250
- Pflags : ssh_FXF_READ ,
251
- }.respond (s )
252
252
case * sshFxpReadPacket :
253
+ var err error = syscall .EBADF
253
254
f , ok := s .getHandle (p .Handle )
254
- if ! ok {
255
- return s .sendError (p , syscall .EBADF )
255
+ if ok {
256
+ err = nil
257
+ data := make ([]byte , clamp (p .Len , s .maxTxPacket ))
258
+ n , _err := f .ReadAt (data , int64 (p .Offset ))
259
+ if _err != nil && (_err != io .EOF || n == 0 ) {
260
+ err = _err
261
+ }
262
+ rpkt = sshFxpDataPacket {
263
+ ID : p .ID ,
264
+ Length : uint32 (n ),
265
+ Data : data [:n ],
266
+ }
256
267
}
257
-
258
- data := make ([]byte , clamp (p .Len , s .maxTxPacket ))
259
- n , err := f .ReadAt (data , int64 (p .Offset ))
260
- if err != nil && (err != io .EOF || n == 0 ) {
261
- return s .sendError (p , err )
268
+ if err != nil {
269
+ rpkt = statusFromError (p , err )
262
270
}
263
- return s .sendPacket (sshFxpDataPacket {
264
- ID : p .ID ,
265
- Length : uint32 (n ),
266
- Data : data [:n ],
267
- })
271
+
268
272
case * sshFxpWritePacket :
269
273
f , ok := s .getHandle (p .Handle )
270
- if ! ok {
271
- return s .sendError (p , syscall .EBADF )
274
+ var err error = syscall .EBADF
275
+ if ok {
276
+ _ , err = f .WriteAt (p .Data , int64 (p .Offset ))
272
277
}
273
-
274
- _ , err := f .WriteAt (p .Data , int64 (p .Offset ))
275
- return s .sendError (p , err )
278
+ rpkt = statusFromError (p , err )
276
279
case serverRespondablePacket :
277
- err := p .respond (s )
278
- return errors .Wrap (err , "pkt.respond failed" )
280
+ rpkt = p .respond (s )
279
281
default :
280
282
return errors .Errorf ("unexpected packet type %T" , p )
281
283
}
284
+
285
+ s .sendPacket (rpkt )
286
+ return nil
282
287
}
283
288
284
289
// Serve serves SFTP connections until the streams stop or the SFTP subsystem
@@ -342,10 +347,6 @@ func (svr *Server) sendPacket(pkt responsePacket) error {
342
347
return nil
343
348
}
344
349
345
- func (svr * Server ) sendError (p requestPacket , err error ) error {
346
- return svr .sendPacket (statusFromError (p , err ))
347
- }
348
-
349
350
type ider interface {
350
351
id () uint32
351
352
}
@@ -380,7 +381,7 @@ func (p sshFxpOpenPacket) hasPflags(flags ...uint32) bool {
380
381
return true
381
382
}
382
383
383
- func (p sshFxpOpenPacket ) respond (svr * Server ) error {
384
+ func (p sshFxpOpenPacket ) respond (svr * Server ) responsePacket {
384
385
var osFlags int
385
386
if p .hasPflags (ssh_FXF_READ , ssh_FXF_WRITE ) {
386
387
osFlags |= os .O_RDWR
@@ -390,7 +391,7 @@ func (p sshFxpOpenPacket) respond(svr *Server) error {
390
391
osFlags |= os .O_RDONLY
391
392
} else {
392
393
// how are they opening?
393
- return svr . sendError ( & p , syscall .EINVAL )
394
+ return statusFromError ( p , syscall .EINVAL )
394
395
}
395
396
396
397
if p .hasPflags (ssh_FXF_APPEND ) {
@@ -408,23 +409,23 @@ func (p sshFxpOpenPacket) respond(svr *Server) error {
408
409
409
410
f , err := os .OpenFile (p .Path , osFlags , 0644 )
410
411
if err != nil {
411
- return svr . sendError ( & p , err )
412
+ return statusFromError ( p , err )
412
413
}
413
414
414
415
handle := svr .nextHandle (f )
415
- return svr . sendPacket ( sshFxpHandlePacket {ID : p .id (), Handle : handle })
416
+ return sshFxpHandlePacket {ID : p .id (), Handle : handle }
416
417
}
417
418
418
- func (p sshFxpReaddirPacket ) respond (svr * Server ) error {
419
+ func (p sshFxpReaddirPacket ) respond (svr * Server ) responsePacket {
419
420
f , ok := svr .getHandle (p .Handle )
420
421
if ! ok {
421
- return svr . sendError ( & p , syscall .EBADF )
422
+ return statusFromError ( p , syscall .EBADF )
422
423
}
423
424
424
425
dirname := f .Name ()
425
426
dirents , err := f .Readdir (128 )
426
427
if err != nil {
427
- return svr . sendError ( & p , err )
428
+ return statusFromError ( p , err )
428
429
}
429
430
430
431
ret := sshFxpNamePacket {ID : p .ID }
@@ -435,10 +436,10 @@ func (p sshFxpReaddirPacket) respond(svr *Server) error {
435
436
Attrs : []interface {}{dirent },
436
437
})
437
438
}
438
- return svr . sendPacket ( ret )
439
+ return ret
439
440
}
440
441
441
- func (p sshFxpSetstatPacket ) respond (svr * Server ) error {
442
+ func (p sshFxpSetstatPacket ) respond (svr * Server ) responsePacket {
442
443
// additional unmarshalling is required for each possibility here
443
444
b := p .Attrs .([]byte )
444
445
var err error
@@ -477,13 +478,13 @@ func (p sshFxpSetstatPacket) respond(svr *Server) error {
477
478
}
478
479
}
479
480
480
- return svr . sendError ( & p , err )
481
+ return statusFromError ( p , err )
481
482
}
482
483
483
- func (p sshFxpFsetstatPacket ) respond (svr * Server ) error {
484
+ func (p sshFxpFsetstatPacket ) respond (svr * Server ) responsePacket {
484
485
f , ok := svr .getHandle (p .Handle )
485
486
if ! ok {
486
- return svr . sendError ( & p , syscall .EBADF )
487
+ return statusFromError ( p , syscall .EBADF )
487
488
}
488
489
489
490
// additional unmarshalling is required for each possibility here
@@ -524,7 +525,7 @@ func (p sshFxpFsetstatPacket) respond(svr *Server) error {
524
525
}
525
526
}
526
527
527
- return svr . sendError ( & p , err )
528
+ return statusFromError ( p , err )
528
529
}
529
530
530
531
// translateErrno translates a syscall error number to a SFTP error code.
0 commit comments