| 
									
										
										
										
											2016-07-09 03:38:35 +08:00
										 |  |  | package sftp | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-09 08:22:52 +08:00
										 |  |  | import ( | 
					
						
							| 
									
										
										
										
											2018-01-23 00:26:46 +08:00
										 |  |  | 	"context" | 
					
						
							| 
									
										
										
										
											2016-07-09 08:22:52 +08:00
										 |  |  | 	"io" | 
					
						
							|  |  |  | 	"os" | 
					
						
							|  |  |  | 	"path" | 
					
						
							| 
									
										
										
										
											2016-07-15 12:11:34 +08:00
										 |  |  | 	"path/filepath" | 
					
						
							| 
									
										
										
										
											2020-09-06 14:26:58 +08:00
										 |  |  | 	"strings" | 
					
						
							| 
									
										
										
										
											2016-07-30 06:57:06 +08:00
										 |  |  | 	"sync" | 
					
						
							| 
									
										
										
										
											2016-07-09 08:22:52 +08:00
										 |  |  | 	"syscall" | 
					
						
							| 
									
										
										
										
											2016-08-04 01:52:04 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/pkg/errors" | 
					
						
							| 
									
										
										
										
											2016-07-09 08:22:52 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-28 09:22:11 +08:00
										 |  |  | // MaxFilelist is the max number of files to return in a readdir batch.
 | 
					
						
							|  |  |  | var MaxFilelist int64 = 100 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-26 02:42:18 +08:00
										 |  |  | // Request contains the data and state for the incoming service request.
 | 
					
						
							| 
									
										
										
										
											2016-07-09 03:38:35 +08:00
										 |  |  | type Request struct { | 
					
						
							| 
									
										
										
										
											2017-04-25 12:36:09 +08:00
										 |  |  | 	// Get, Put, Setstat, Stat, Rename, Remove
 | 
					
						
							| 
									
										
										
										
											2019-05-25 03:23:18 +08:00
										 |  |  | 	// Rmdir, Mkdir, List, Readlink, Link, Symlink
 | 
					
						
							| 
									
										
										
										
											2016-07-09 03:38:35 +08:00
										 |  |  | 	Method   string | 
					
						
							|  |  |  | 	Filepath string | 
					
						
							| 
									
										
										
										
											2017-04-25 12:51:06 +08:00
										 |  |  | 	Flags    uint32 | 
					
						
							| 
									
										
										
										
											2016-07-09 03:38:35 +08:00
										 |  |  | 	Attrs    []byte // convert to sub-struct
 | 
					
						
							|  |  |  | 	Target   string // for renames and sym-links
 | 
					
						
							| 
									
										
										
										
											2018-11-21 08:34:41 +08:00
										 |  |  | 	handle   string | 
					
						
							| 
									
										
										
										
											2016-08-03 10:37:23 +08:00
										 |  |  | 	// reader/writer/readdir from handlers
 | 
					
						
							| 
									
										
										
										
											2018-02-07 03:59:15 +08:00
										 |  |  | 	state state | 
					
						
							| 
									
										
										
										
											2018-01-23 00:26:46 +08:00
										 |  |  | 	// context lasts duration of request
 | 
					
						
							|  |  |  | 	ctx       context.Context | 
					
						
							|  |  |  | 	cancelCtx context.CancelFunc | 
					
						
							| 
									
										
										
										
											2016-08-03 10:37:23 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type state struct { | 
					
						
							| 
									
										
										
										
											2018-02-07 03:59:15 +08:00
										 |  |  | 	*sync.RWMutex | 
					
						
							| 
									
										
										
										
											2020-08-30 16:40:22 +08:00
										 |  |  | 	writerAt       io.WriterAt | 
					
						
							|  |  |  | 	readerAt       io.ReaderAt | 
					
						
							|  |  |  | 	writerReaderAt WriterAtReaderAt | 
					
						
							|  |  |  | 	listerAt       ListerAt | 
					
						
							|  |  |  | 	lsoffset       int64 | 
					
						
							| 
									
										
										
										
											2016-07-09 03:38:35 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-04 01:52:04 +08:00
										 |  |  | // New Request initialized based on packet data
 | 
					
						
							| 
									
										
										
										
											2018-02-02 03:32:59 +08:00
										 |  |  | func requestFromPacket(ctx context.Context, pkt hasPath) *Request { | 
					
						
							| 
									
										
										
										
											2016-10-21 09:42:47 +08:00
										 |  |  | 	method := requestMethod(pkt) | 
					
						
							|  |  |  | 	request := NewRequest(method, pkt.getPath()) | 
					
						
							| 
									
										
										
										
											2018-02-02 03:32:59 +08:00
										 |  |  | 	request.ctx, request.cancelCtx = context.WithCancel(ctx) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-21 09:42:47 +08:00
										 |  |  | 	switch p := pkt.(type) { | 
					
						
							| 
									
										
										
										
											2018-01-06 09:55:57 +08:00
										 |  |  | 	case *sshFxpOpenPacket: | 
					
						
							| 
									
										
										
										
											2018-01-07 08:12:05 +08:00
										 |  |  | 		request.Flags = p.Pflags | 
					
						
							| 
									
										
										
										
											2016-10-21 09:42:47 +08:00
										 |  |  | 	case *sshFxpSetstatPacket: | 
					
						
							| 
									
										
										
										
											2017-04-25 12:51:06 +08:00
										 |  |  | 		request.Flags = p.Flags | 
					
						
							| 
									
										
										
										
											2016-10-21 09:42:47 +08:00
										 |  |  | 		request.Attrs = p.Attrs.([]byte) | 
					
						
							|  |  |  | 	case *sshFxpRenamePacket: | 
					
						
							| 
									
										
										
										
											2017-08-13 20:00:08 +08:00
										 |  |  | 		request.Target = cleanPath(p.Newpath) | 
					
						
							| 
									
										
										
										
											2016-10-21 09:42:47 +08:00
										 |  |  | 	case *sshFxpSymlinkPacket: | 
					
						
							| 
									
										
										
										
											2017-08-13 20:00:08 +08:00
										 |  |  | 		request.Target = cleanPath(p.Linkpath) | 
					
						
							| 
									
										
										
										
											2019-05-25 03:23:18 +08:00
										 |  |  | 	case *sshFxpExtendedPacketHardlink: | 
					
						
							|  |  |  | 		request.Target = cleanPath(p.Newpath) | 
					
						
							| 
									
										
										
										
											2016-10-21 09:42:47 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-08-04 01:52:04 +08:00
										 |  |  | 	return request | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-14 05:09:14 +08:00
										 |  |  | // NewRequest creates a new Request object.
 | 
					
						
							| 
									
										
										
										
											2017-08-21 08:03:15 +08:00
										 |  |  | func NewRequest(method, path string) *Request { | 
					
						
							| 
									
										
										
										
											2018-02-07 03:59:15 +08:00
										 |  |  | 	return &Request{Method: method, Filepath: cleanPath(path), | 
					
						
							|  |  |  | 		state: state{RWMutex: new(sync.RWMutex)}} | 
					
						
							| 
									
										
										
										
											2018-01-23 00:26:46 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-07 04:22:08 +08:00
										 |  |  | // shallow copy of existing request
 | 
					
						
							|  |  |  | func (r *Request) copy() *Request { | 
					
						
							|  |  |  | 	r.state.Lock() | 
					
						
							|  |  |  | 	defer r.state.Unlock() | 
					
						
							|  |  |  | 	r2 := new(Request) | 
					
						
							|  |  |  | 	*r2 = *r | 
					
						
							|  |  |  | 	return r2 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-23 00:26:46 +08:00
										 |  |  | // Context returns the request's context. To change the context,
 | 
					
						
							|  |  |  | // use WithContext.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // The returned context is always non-nil; it defaults to the
 | 
					
						
							|  |  |  | // background context.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // For incoming server requests, the context is canceled when the
 | 
					
						
							|  |  |  | // request is complete or the client's connection closes.
 | 
					
						
							|  |  |  | func (r *Request) Context() context.Context { | 
					
						
							|  |  |  | 	if r.ctx != nil { | 
					
						
							|  |  |  | 		return r.ctx | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return context.Background() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // WithContext returns a copy of r with its context changed to ctx.
 | 
					
						
							|  |  |  | // The provided ctx must be non-nil.
 | 
					
						
							|  |  |  | func (r *Request) WithContext(ctx context.Context) *Request { | 
					
						
							|  |  |  | 	if ctx == nil { | 
					
						
							|  |  |  | 		panic("nil context") | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-02-07 04:22:08 +08:00
										 |  |  | 	r2 := r.copy() | 
					
						
							|  |  |  | 	r2.ctx = ctx | 
					
						
							|  |  |  | 	r2.cancelCtx = nil | 
					
						
							| 
									
										
										
										
											2018-01-23 00:26:46 +08:00
										 |  |  | 	return r2 | 
					
						
							| 
									
										
										
										
											2016-07-09 03:38:35 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-16 22:53:40 +08:00
										 |  |  | // Returns current offset for file list
 | 
					
						
							| 
									
										
										
										
											2017-08-21 08:18:07 +08:00
										 |  |  | func (r *Request) lsNext() int64 { | 
					
						
							| 
									
										
										
										
											2018-02-07 03:59:15 +08:00
										 |  |  | 	r.state.RLock() | 
					
						
							|  |  |  | 	defer r.state.RUnlock() | 
					
						
							| 
									
										
										
										
											2017-08-16 22:53:40 +08:00
										 |  |  | 	return r.state.lsoffset | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Increases next offset
 | 
					
						
							| 
									
										
										
										
											2017-08-21 08:18:07 +08:00
										 |  |  | func (r *Request) lsInc(offset int64) { | 
					
						
							| 
									
										
										
										
											2018-02-07 03:59:15 +08:00
										 |  |  | 	r.state.Lock() | 
					
						
							|  |  |  | 	defer r.state.Unlock() | 
					
						
							| 
									
										
										
										
											2017-07-28 09:22:11 +08:00
										 |  |  | 	r.state.lsoffset = r.state.lsoffset + offset | 
					
						
							| 
									
										
										
										
											2017-07-11 07:43:58 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // manage file read/write state
 | 
					
						
							| 
									
										
										
										
											2017-12-24 08:50:46 +08:00
										 |  |  | func (r *Request) setListerState(la ListerAt) { | 
					
						
							| 
									
										
										
										
											2018-02-07 03:59:15 +08:00
										 |  |  | 	r.state.Lock() | 
					
						
							|  |  |  | 	defer r.state.Unlock() | 
					
						
							| 
									
										
										
										
											2017-12-24 08:50:46 +08:00
										 |  |  | 	r.state.listerAt = la | 
					
						
							| 
									
										
										
										
											2016-08-03 10:37:23 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-21 08:03:15 +08:00
										 |  |  | func (r *Request) getLister() ListerAt { | 
					
						
							| 
									
										
										
										
											2018-02-07 03:59:15 +08:00
										 |  |  | 	r.state.RLock() | 
					
						
							|  |  |  | 	defer r.state.RUnlock() | 
					
						
							| 
									
										
										
										
											2017-07-28 09:22:11 +08:00
										 |  |  | 	return r.state.listerAt | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-20 02:52:43 +08:00
										 |  |  | // Close reader/writer if possible
 | 
					
						
							| 
									
										
										
										
											2017-12-13 02:05:18 +08:00
										 |  |  | func (r *Request) close() error { | 
					
						
							| 
									
										
										
										
											2018-05-27 04:55:29 +08:00
										 |  |  | 	defer func() { | 
					
						
							|  |  |  | 		if r.cancelCtx != nil { | 
					
						
							|  |  |  | 			r.cancelCtx() | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}() | 
					
						
							| 
									
										
										
										
											2020-07-19 03:45:27 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-15 05:10:32 +08:00
										 |  |  | 	r.state.RLock() | 
					
						
							| 
									
										
										
										
											2020-07-19 03:45:27 +08:00
										 |  |  | 	wr := r.state.writerAt | 
					
						
							| 
									
										
										
										
											2020-07-24 15:23:55 +08:00
										 |  |  | 	rd := r.state.readerAt | 
					
						
							| 
									
										
										
										
											2020-09-03 01:21:12 +08:00
										 |  |  | 	rw := r.state.writerReaderAt | 
					
						
							| 
									
										
										
										
											2018-09-15 05:10:32 +08:00
										 |  |  | 	r.state.RUnlock() | 
					
						
							| 
									
										
										
										
											2020-07-19 03:45:27 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	var err error | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-24 15:23:55 +08:00
										 |  |  | 	// Close errors on a Writer are far more likely to be the important one.
 | 
					
						
							|  |  |  | 	// As they can be information that there was a loss of data.
 | 
					
						
							| 
									
										
										
										
											2020-09-03 22:40:14 +08:00
										 |  |  | 	if c, ok := wr.(io.Closer); ok { | 
					
						
							| 
									
										
										
										
											2020-07-19 03:45:27 +08:00
										 |  |  | 		if err2 := c.Close(); err == nil { | 
					
						
							|  |  |  | 			// update error if it is still nil
 | 
					
						
							|  |  |  | 			err = err2 | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-08-20 02:52:43 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-07-19 03:45:27 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-03 22:40:14 +08:00
										 |  |  | 	if c, ok := rw.(io.Closer); ok { | 
					
						
							| 
									
										
										
										
											2020-08-30 16:40:22 +08:00
										 |  |  | 		if err2 := c.Close(); err == nil { | 
					
						
							|  |  |  | 			// update error if it is still nil
 | 
					
						
							|  |  |  | 			err = err2 | 
					
						
							|  |  |  | 			r.state.writerReaderAt = nil | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-03 22:40:14 +08:00
										 |  |  | 	if c, ok := rd.(io.Closer); ok { | 
					
						
							| 
									
										
										
										
											2020-07-19 03:45:27 +08:00
										 |  |  | 		if err2 := c.Close(); err == nil { | 
					
						
							|  |  |  | 			// update error if it is still nil
 | 
					
						
							|  |  |  | 			err = err2 | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return err | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-30 16:40:22 +08:00
										 |  |  | // Notify transfer error if any
 | 
					
						
							| 
									
										
										
										
											2020-07-19 03:45:27 +08:00
										 |  |  | func (r *Request) transferError(err error) { | 
					
						
							|  |  |  | 	if err == nil { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-15 05:10:32 +08:00
										 |  |  | 	r.state.RLock() | 
					
						
							| 
									
										
										
										
											2020-07-19 03:45:27 +08:00
										 |  |  | 	wr := r.state.writerAt | 
					
						
							| 
									
										
										
										
											2020-07-24 15:23:55 +08:00
										 |  |  | 	rd := r.state.readerAt | 
					
						
							| 
									
										
										
										
											2020-09-03 01:21:12 +08:00
										 |  |  | 	rw := r.state.writerReaderAt | 
					
						
							| 
									
										
										
										
											2018-09-15 05:10:32 +08:00
										 |  |  | 	r.state.RUnlock() | 
					
						
							| 
									
										
										
										
											2020-07-19 03:45:27 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-03 22:40:14 +08:00
										 |  |  | 	if t, ok := wr.(TransferError); ok { | 
					
						
							| 
									
										
										
										
											2020-08-30 16:40:22 +08:00
										 |  |  | 		t.TransferError(err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-03 22:40:14 +08:00
										 |  |  | 	if t, ok := rw.(TransferError); ok { | 
					
						
							| 
									
										
										
										
											2020-07-19 03:45:27 +08:00
										 |  |  | 		t.TransferError(err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-03 22:40:14 +08:00
										 |  |  | 	if t, ok := rd.(TransferError); ok { | 
					
						
							| 
									
										
										
										
											2020-07-19 03:45:27 +08:00
										 |  |  | 		t.TransferError(err) | 
					
						
							| 
									
										
										
										
											2016-08-20 02:52:43 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-13 02:23:03 +08:00
										 |  |  | // called from worker to handle packet/request
 | 
					
						
							| 
									
										
										
										
											2020-03-15 02:42:19 +08:00
										 |  |  | func (r *Request) call(handlers Handlers, pkt requestPacket, alloc *allocator, orderID uint32) responsePacket { | 
					
						
							| 
									
										
										
										
											2016-07-12 11:19:49 +08:00
										 |  |  | 	switch r.Method { | 
					
						
							|  |  |  | 	case "Get": | 
					
						
							| 
									
										
										
										
											2020-03-15 02:42:19 +08:00
										 |  |  | 		return fileget(handlers.FileGet, r, pkt, alloc, orderID) | 
					
						
							| 
									
										
										
										
											2018-11-21 08:34:41 +08:00
										 |  |  | 	case "Put": | 
					
						
							| 
									
										
										
										
											2020-03-15 02:42:19 +08:00
										 |  |  | 		return fileput(handlers.FilePut, r, pkt, alloc, orderID) | 
					
						
							| 
									
										
										
										
											2020-08-30 16:40:22 +08:00
										 |  |  | 	case "Open": | 
					
						
							|  |  |  | 		return fileputget(handlers.FilePut, r, pkt, alloc, orderID) | 
					
						
							| 
									
										
										
										
											2019-05-25 03:23:18 +08:00
										 |  |  | 	case "Setstat", "Rename", "Rmdir", "Mkdir", "Link", "Symlink", "Remove": | 
					
						
							| 
									
										
										
										
											2018-01-07 08:12:05 +08:00
										 |  |  | 		return filecmd(handlers.FileCmd, r, pkt) | 
					
						
							| 
									
										
										
										
											2018-06-06 09:34:17 +08:00
										 |  |  | 	case "List": | 
					
						
							| 
									
										
										
										
											2018-01-07 08:12:05 +08:00
										 |  |  | 		return filelist(handlers.FileList, r, pkt) | 
					
						
							| 
									
										
										
										
											2020-09-06 14:26:58 +08:00
										 |  |  | 	case "Stat", "Lstat", "Readlink": | 
					
						
							| 
									
										
										
										
											2018-06-06 09:34:17 +08:00
										 |  |  | 		return filestat(handlers.FileList, r, pkt) | 
					
						
							| 
									
										
										
										
											2017-04-25 12:36:09 +08:00
										 |  |  | 	default: | 
					
						
							| 
									
										
										
										
											2017-08-23 10:24:14 +08:00
										 |  |  | 		return statusFromError(pkt, | 
					
						
							| 
									
										
										
										
											2017-08-21 06:51:26 +08:00
										 |  |  | 			errors.Errorf("unexpected method: %s", r.Method)) | 
					
						
							| 
									
										
										
										
											2016-07-09 03:38:35 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-29 10:20:55 +08:00
										 |  |  | // Additional initialization for Open packets
 | 
					
						
							|  |  |  | func (r *Request) open(h Handlers, pkt requestPacket) responsePacket { | 
					
						
							| 
									
										
										
										
											2018-11-21 08:34:41 +08:00
										 |  |  | 	flags := r.Pflags() | 
					
						
							| 
									
										
										
										
											2020-09-03 22:40:14 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-21 08:34:41 +08:00
										 |  |  | 	switch { | 
					
						
							|  |  |  | 	case flags.Write, flags.Append, flags.Creat, flags.Trunc: | 
					
						
							| 
									
										
										
										
											2020-09-03 01:21:12 +08:00
										 |  |  | 		if flags.Read { | 
					
						
							| 
									
										
										
										
											2020-09-03 22:40:14 +08:00
										 |  |  | 			if openFileWriter, ok := h.FilePut.(OpenFileWriter); ok { | 
					
						
							| 
									
										
										
										
											2020-09-03 01:21:12 +08:00
										 |  |  | 				r.Method = "Open" | 
					
						
							| 
									
										
										
										
											2020-09-03 22:40:14 +08:00
										 |  |  | 				rw, err := openFileWriter.OpenFile(r) | 
					
						
							|  |  |  | 				if err != nil { | 
					
						
							|  |  |  | 					return statusFromError(pkt, err) | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				r.state.writerReaderAt = rw | 
					
						
							| 
									
										
										
										
											2020-09-04 00:17:31 +08:00
										 |  |  | 				return &sshFxpHandlePacket{ID: pkt.id(), Handle: r.handle} | 
					
						
							| 
									
										
										
										
											2020-09-03 01:21:12 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-09-04 00:17:31 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		r.Method = "Put" | 
					
						
							|  |  |  | 		wr, err := h.FilePut.Filewrite(r) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return statusFromError(pkt, err) | 
					
						
							| 
									
										
										
										
											2020-08-30 16:40:22 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-09-04 00:17:31 +08:00
										 |  |  | 		r.state.writerAt = wr | 
					
						
							| 
									
										
										
										
											2018-11-21 08:34:41 +08:00
										 |  |  | 	case flags.Read: | 
					
						
							| 
									
										
										
										
											2019-01-29 10:20:55 +08:00
										 |  |  | 		r.Method = "Get" | 
					
						
							| 
									
										
										
										
											2020-09-03 22:40:14 +08:00
										 |  |  | 		rd, err := h.FileGet.Fileread(r) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return statusFromError(pkt, err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		r.state.readerAt = rd | 
					
						
							| 
									
										
										
										
											2019-01-29 10:20:55 +08:00
										 |  |  | 	default: | 
					
						
							|  |  |  | 		return statusFromError(pkt, errors.New("bad file flags")) | 
					
						
							| 
									
										
										
										
											2017-08-23 10:24:14 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-01-29 10:20:55 +08:00
										 |  |  | 	return &sshFxpHandlePacket{ID: pkt.id(), Handle: r.handle} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | func (r *Request) opendir(h Handlers, pkt requestPacket) responsePacket { | 
					
						
							|  |  |  | 	r.Method = "List" | 
					
						
							| 
									
										
										
										
											2020-09-03 22:40:14 +08:00
										 |  |  | 	la, err := h.FileList.Filelist(r) | 
					
						
							| 
									
										
										
										
											2019-01-29 10:20:55 +08:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2020-09-11 00:11:47 +08:00
										 |  |  | 		return statusFromError(pkt, wrapPathError(r.Filepath, err)) | 
					
						
							| 
									
										
										
										
											2019-01-29 10:20:55 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-09-03 22:40:14 +08:00
										 |  |  | 	r.state.listerAt = la | 
					
						
							| 
									
										
										
										
											2019-01-29 10:20:55 +08:00
										 |  |  | 	return &sshFxpHandlePacket{ID: pkt.id(), Handle: r.handle} | 
					
						
							| 
									
										
										
										
											2017-08-23 10:24:14 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-13 02:23:03 +08:00
										 |  |  | // wrap FileReader handler
 | 
					
						
							| 
									
										
										
										
											2020-03-15 02:42:19 +08:00
										 |  |  | func fileget(h FileReader, r *Request, pkt requestPacket, alloc *allocator, orderID uint32) responsePacket { | 
					
						
							| 
									
										
										
										
											2018-09-15 05:10:32 +08:00
										 |  |  | 	r.state.RLock() | 
					
						
							|  |  |  | 	reader := r.state.readerAt | 
					
						
							|  |  |  | 	r.state.RUnlock() | 
					
						
							| 
									
										
										
										
											2016-08-03 10:37:23 +08:00
										 |  |  | 	if reader == nil { | 
					
						
							| 
									
										
										
										
											2018-11-21 08:34:41 +08:00
										 |  |  | 		return statusFromError(pkt, errors.New("unexpected read packet")) | 
					
						
							| 
									
										
										
										
											2016-07-12 11:19:49 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-07-30 06:57:06 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-15 02:42:19 +08:00
										 |  |  | 	data, offset, _ := packetData(pkt, alloc, orderID) | 
					
						
							| 
									
										
										
										
											2018-01-07 08:12:05 +08:00
										 |  |  | 	n, err := reader.ReadAt(data, offset) | 
					
						
							| 
									
										
										
										
											2020-08-30 16:40:22 +08:00
										 |  |  | 	// only return EOF error if no data left to read
 | 
					
						
							| 
									
										
										
										
											2016-07-26 02:42:18 +08:00
										 |  |  | 	if err != nil && (err != io.EOF || n == 0) { | 
					
						
							| 
									
										
										
										
											2018-01-07 08:12:05 +08:00
										 |  |  | 		return statusFromError(pkt, err) | 
					
						
							| 
									
										
										
										
											2016-07-26 02:42:18 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-07-12 04:56:47 +08:00
										 |  |  | 	return &sshFxpDataPacket{ | 
					
						
							| 
									
										
										
										
											2018-01-07 08:12:05 +08:00
										 |  |  | 		ID:     pkt.id(), | 
					
						
							| 
									
										
										
										
											2016-07-09 08:22:52 +08:00
										 |  |  | 		Length: uint32(n), | 
					
						
							| 
									
										
										
										
											2016-07-13 05:56:24 +08:00
										 |  |  | 		Data:   data[:n], | 
					
						
							| 
									
										
										
										
											2017-08-21 06:51:26 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-07-09 08:22:52 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2016-07-13 02:23:03 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | // wrap FileWriter handler
 | 
					
						
							| 
									
										
										
										
											2020-03-15 02:42:19 +08:00
										 |  |  | func fileput(h FileWriter, r *Request, pkt requestPacket, alloc *allocator, orderID uint32) responsePacket { | 
					
						
							| 
									
										
										
										
											2018-09-15 05:10:32 +08:00
										 |  |  | 	r.state.RLock() | 
					
						
							|  |  |  | 	writer := r.state.writerAt | 
					
						
							|  |  |  | 	r.state.RUnlock() | 
					
						
							| 
									
										
										
										
											2016-08-03 10:37:23 +08:00
										 |  |  | 	if writer == nil { | 
					
						
							| 
									
										
										
										
											2018-11-21 08:34:41 +08:00
										 |  |  | 		return statusFromError(pkt, errors.New("unexpected write packet")) | 
					
						
							| 
									
										
										
										
											2016-07-12 11:19:49 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-15 02:42:19 +08:00
										 |  |  | 	data, offset, _ := packetData(pkt, alloc, orderID) | 
					
						
							| 
									
										
										
										
											2019-01-29 10:23:54 +08:00
										 |  |  | 	_, err := writer.WriteAt(data, offset) | 
					
						
							| 
									
										
										
										
											2018-01-08 09:34:08 +08:00
										 |  |  | 	return statusFromError(pkt, err) | 
					
						
							| 
									
										
										
										
											2016-07-09 08:22:52 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2016-07-13 02:23:03 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-30 16:40:22 +08:00
										 |  |  | // wrap OpenFileWriter handler
 | 
					
						
							|  |  |  | func fileputget(h FileWriter, r *Request, pkt requestPacket, alloc *allocator, orderID uint32) responsePacket { | 
					
						
							|  |  |  | 	r.state.RLock() | 
					
						
							|  |  |  | 	writerReader := r.state.writerReaderAt | 
					
						
							|  |  |  | 	r.state.RUnlock() | 
					
						
							|  |  |  | 	if writerReader == nil { | 
					
						
							|  |  |  | 		return statusFromError(pkt, errors.New("unexpected write and read packet")) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	switch pkt.(type) { | 
					
						
							|  |  |  | 	case *sshFxpReadPacket: | 
					
						
							|  |  |  | 		data, offset, _ := packetData(pkt, alloc, orderID) | 
					
						
							|  |  |  | 		n, err := writerReader.ReadAt(data, offset) | 
					
						
							|  |  |  | 		// only return EOF error if no data left to read
 | 
					
						
							|  |  |  | 		if err != nil && (err != io.EOF || n == 0) { | 
					
						
							|  |  |  | 			return statusFromError(pkt, err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return &sshFxpDataPacket{ | 
					
						
							|  |  |  | 			ID:     pkt.id(), | 
					
						
							|  |  |  | 			Length: uint32(n), | 
					
						
							|  |  |  | 			Data:   data[:n], | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	case *sshFxpWritePacket: | 
					
						
							|  |  |  | 		data, offset, _ := packetData(pkt, alloc, orderID) | 
					
						
							|  |  |  | 		_, err := writerReader.WriteAt(data, offset) | 
					
						
							|  |  |  | 		return statusFromError(pkt, err) | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		return statusFromError(pkt, errors.New("unexpected packet type for read or write")) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-21 08:34:41 +08:00
										 |  |  | // file data for additional read/write packets
 | 
					
						
							| 
									
										
										
										
											2020-03-15 02:42:19 +08:00
										 |  |  | func packetData(p requestPacket, alloc *allocator, orderID uint32) (data []byte, offset int64, length uint32) { | 
					
						
							| 
									
										
										
										
											2018-11-21 08:34:41 +08:00
										 |  |  | 	switch p := p.(type) { | 
					
						
							|  |  |  | 	case *sshFxpReadPacket: | 
					
						
							|  |  |  | 		length = p.Len | 
					
						
							|  |  |  | 		offset = int64(p.Offset) | 
					
						
							| 
									
										
										
										
											2020-03-15 02:42:19 +08:00
										 |  |  | 		data = p.getDataSlice(alloc, orderID) | 
					
						
							| 
									
										
										
										
											2018-11-21 08:34:41 +08:00
										 |  |  | 	case *sshFxpWritePacket: | 
					
						
							|  |  |  | 		data = p.Data | 
					
						
							|  |  |  | 		length = p.Length | 
					
						
							|  |  |  | 		offset = int64(p.Offset) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-13 02:23:03 +08:00
										 |  |  | // wrap FileCmder handler
 | 
					
						
							| 
									
										
										
										
											2018-01-07 08:12:05 +08:00
										 |  |  | func filecmd(h FileCmder, r *Request, pkt requestPacket) responsePacket { | 
					
						
							| 
									
										
										
										
											2018-05-11 00:04:34 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	switch p := pkt.(type) { | 
					
						
							|  |  |  | 	case *sshFxpFsetstatPacket: | 
					
						
							|  |  |  | 		r.Flags = p.Flags | 
					
						
							|  |  |  | 		r.Attrs = p.Attrs.([]byte) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-07-09 08:22:52 +08:00
										 |  |  | 	err := h.Filecmd(r) | 
					
						
							| 
									
										
										
										
											2018-01-08 09:34:08 +08:00
										 |  |  | 	return statusFromError(pkt, err) | 
					
						
							| 
									
										
										
										
											2016-07-09 08:22:52 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2016-07-13 02:23:03 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-28 09:22:11 +08:00
										 |  |  | // wrap FileLister handler
 | 
					
						
							| 
									
										
										
										
											2018-01-07 08:12:05 +08:00
										 |  |  | func filelist(h FileLister, r *Request, pkt requestPacket) responsePacket { | 
					
						
							| 
									
										
										
										
											2017-07-28 09:22:11 +08:00
										 |  |  | 	var err error | 
					
						
							|  |  |  | 	lister := r.getLister() | 
					
						
							|  |  |  | 	if lister == nil { | 
					
						
							| 
									
										
										
										
											2019-01-29 10:20:55 +08:00
										 |  |  | 		return statusFromError(pkt, errors.New("unexpected dir packet")) | 
					
						
							| 
									
										
										
										
											2016-07-26 02:42:18 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-07-28 09:22:11 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-16 22:53:40 +08:00
										 |  |  | 	offset := r.lsNext() | 
					
						
							| 
									
										
										
										
											2017-07-28 09:22:11 +08:00
										 |  |  | 	finfo := make([]os.FileInfo, MaxFilelist) | 
					
						
							|  |  |  | 	n, err := lister.ListAt(finfo, offset) | 
					
						
							| 
									
										
										
										
											2017-08-16 22:53:40 +08:00
										 |  |  | 	r.lsInc(int64(n)) | 
					
						
							| 
									
										
										
										
											2017-07-28 09:22:11 +08:00
										 |  |  | 	// ignore EOF as we only return it when there are no results
 | 
					
						
							|  |  |  | 	finfo = finfo[:n] // avoid need for nil tests below
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-09 08:22:52 +08:00
										 |  |  | 	switch r.Method { | 
					
						
							|  |  |  | 	case "List": | 
					
						
							| 
									
										
										
										
											2017-08-21 06:51:26 +08:00
										 |  |  | 		if err != nil && err != io.EOF { | 
					
						
							| 
									
										
										
										
											2018-01-07 08:12:05 +08:00
										 |  |  | 			return statusFromError(pkt, err) | 
					
						
							| 
									
										
										
										
											2017-08-21 06:51:26 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-05-11 01:54:29 +08:00
										 |  |  | 		if err == io.EOF && n == 0 { | 
					
						
							| 
									
										
										
										
											2018-01-07 08:12:05 +08:00
										 |  |  | 			return statusFromError(pkt, io.EOF) | 
					
						
							| 
									
										
										
										
											2017-08-21 06:51:26 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-08-09 23:25:44 +08:00
										 |  |  | 		dirname := filepath.ToSlash(path.Base(r.Filepath)) | 
					
						
							| 
									
										
										
										
											2018-01-07 08:12:05 +08:00
										 |  |  | 		ret := &sshFxpNamePacket{ID: pkt.id()} | 
					
						
							| 
									
										
										
										
											2017-07-28 09:22:11 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-09 08:22:52 +08:00
										 |  |  | 		for _, fi := range finfo { | 
					
						
							|  |  |  | 			ret.NameAttrs = append(ret.NameAttrs, sshFxpNameAttr{ | 
					
						
							|  |  |  | 				Name:     fi.Name(), | 
					
						
							|  |  |  | 				LongName: runLs(dirname, fi), | 
					
						
							|  |  |  | 				Attrs:    []interface{}{fi}, | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-08-21 06:51:26 +08:00
										 |  |  | 		return ret | 
					
						
							| 
									
										
										
										
											2018-06-06 09:34:17 +08:00
										 |  |  | 	default: | 
					
						
							|  |  |  | 		err = errors.Errorf("unexpected method: %s", r.Method) | 
					
						
							|  |  |  | 		return statusFromError(pkt, err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func filestat(h FileLister, r *Request, pkt requestPacket) responsePacket { | 
					
						
							| 
									
										
										
										
											2020-09-06 14:26:58 +08:00
										 |  |  | 	var lister ListerAt | 
					
						
							|  |  |  | 	var err error | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if r.Method == "Lstat" { | 
					
						
							|  |  |  | 		if lstatFileLister, ok := h.(LstatFileLister); ok { | 
					
						
							|  |  |  | 			lister, err = lstatFileLister.Lstat(r) | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			// LstatFileLister not implemented handle this request as a Stat
 | 
					
						
							|  |  |  | 			r.Method = "Stat" | 
					
						
							|  |  |  | 			lister, err = h.Filelist(r) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		lister, err = h.Filelist(r) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-06-06 09:34:17 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return statusFromError(pkt, err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	finfo := make([]os.FileInfo, 1) | 
					
						
							|  |  |  | 	n, err := lister.ListAt(finfo, 0) | 
					
						
							|  |  |  | 	finfo = finfo[:n] // avoid need for nil tests below
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	switch r.Method { | 
					
						
							| 
									
										
										
										
											2020-09-06 14:26:58 +08:00
										 |  |  | 	case "Stat", "Lstat": | 
					
						
							| 
									
										
										
										
											2017-08-21 06:51:26 +08:00
										 |  |  | 		if err != nil && err != io.EOF { | 
					
						
							| 
									
										
										
										
											2018-01-07 08:12:05 +08:00
										 |  |  | 			return statusFromError(pkt, err) | 
					
						
							| 
									
										
										
										
											2017-08-21 06:51:26 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		if n == 0 { | 
					
						
							| 
									
										
										
										
											2020-09-06 14:26:58 +08:00
										 |  |  | 			err = &os.PathError{Op: strings.ToLower(r.Method), Path: r.Filepath, | 
					
						
							| 
									
										
										
										
											2017-08-21 06:51:26 +08:00
										 |  |  | 				Err: syscall.ENOENT} | 
					
						
							| 
									
										
										
										
											2018-01-07 08:12:05 +08:00
										 |  |  | 			return statusFromError(pkt, err) | 
					
						
							| 
									
										
										
										
											2017-08-21 06:51:26 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-07-12 04:56:47 +08:00
										 |  |  | 		return &sshFxpStatResponse{ | 
					
						
							| 
									
										
										
										
											2018-01-07 08:12:05 +08:00
										 |  |  | 			ID:   pkt.id(), | 
					
						
							| 
									
										
										
										
											2016-07-09 08:22:52 +08:00
										 |  |  | 			info: finfo[0], | 
					
						
							| 
									
										
										
										
											2017-08-21 06:51:26 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-07-15 12:11:34 +08:00
										 |  |  | 	case "Readlink": | 
					
						
							| 
									
										
										
										
											2017-08-21 06:51:26 +08:00
										 |  |  | 		if err != nil && err != io.EOF { | 
					
						
							| 
									
										
										
										
											2018-01-07 08:12:05 +08:00
										 |  |  | 			return statusFromError(pkt, err) | 
					
						
							| 
									
										
										
										
											2017-08-21 06:51:26 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		if n == 0 { | 
					
						
							|  |  |  | 			err = &os.PathError{Op: "readlink", Path: r.Filepath, | 
					
						
							|  |  |  | 				Err: syscall.ENOENT} | 
					
						
							| 
									
										
										
										
											2018-01-07 08:12:05 +08:00
										 |  |  | 			return statusFromError(pkt, err) | 
					
						
							| 
									
										
										
										
											2017-08-21 06:51:26 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-07-23 08:11:09 +08:00
										 |  |  | 		filename := finfo[0].Name() | 
					
						
							| 
									
										
										
										
											2016-07-13 05:56:24 +08:00
										 |  |  | 		return &sshFxpNamePacket{ | 
					
						
							| 
									
										
										
										
											2018-01-07 08:12:05 +08:00
										 |  |  | 			ID: pkt.id(), | 
					
						
							| 
									
										
										
										
											2016-07-09 08:22:52 +08:00
										 |  |  | 			NameAttrs: []sshFxpNameAttr{{ | 
					
						
							| 
									
										
										
										
											2016-07-15 12:11:34 +08:00
										 |  |  | 				Name:     filename, | 
					
						
							|  |  |  | 				LongName: filename, | 
					
						
							| 
									
										
										
										
											2016-07-09 08:22:52 +08:00
										 |  |  | 				Attrs:    emptyFileStat, | 
					
						
							|  |  |  | 			}}, | 
					
						
							| 
									
										
										
										
											2017-08-21 06:51:26 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-07-28 09:22:11 +08:00
										 |  |  | 	default: | 
					
						
							| 
									
										
										
										
											2017-08-21 06:51:26 +08:00
										 |  |  | 		err = errors.Errorf("unexpected method: %s", r.Method) | 
					
						
							| 
									
										
										
										
											2018-01-07 08:12:05 +08:00
										 |  |  | 		return statusFromError(pkt, err) | 
					
						
							| 
									
										
										
										
											2016-07-09 08:22:52 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-24 08:34:22 +08:00
										 |  |  | // init attributes of request object from packet data
 | 
					
						
							|  |  |  | func requestMethod(p requestPacket) (method string) { | 
					
						
							|  |  |  | 	switch p.(type) { | 
					
						
							| 
									
										
										
										
											2019-01-29 10:20:55 +08:00
										 |  |  | 	case *sshFxpReadPacket, *sshFxpWritePacket, *sshFxpOpenPacket: | 
					
						
							|  |  |  | 		// set in open() above
 | 
					
						
							|  |  |  | 	case *sshFxpOpendirPacket, *sshFxpReaddirPacket: | 
					
						
							|  |  |  | 		// set in opendir() above
 | 
					
						
							| 
									
										
										
										
											2017-12-24 08:34:22 +08:00
										 |  |  | 	case *sshFxpSetstatPacket, *sshFxpFsetstatPacket: | 
					
						
							| 
									
										
										
										
											2016-10-21 09:42:47 +08:00
										 |  |  | 		method = "Setstat" | 
					
						
							| 
									
										
										
										
											2016-08-04 01:52:04 +08:00
										 |  |  | 	case *sshFxpRenamePacket: | 
					
						
							| 
									
										
										
										
											2016-10-21 09:42:47 +08:00
										 |  |  | 		method = "Rename" | 
					
						
							| 
									
										
										
										
											2016-08-04 01:52:04 +08:00
										 |  |  | 	case *sshFxpSymlinkPacket: | 
					
						
							| 
									
										
										
										
											2016-10-21 09:42:47 +08:00
										 |  |  | 		method = "Symlink" | 
					
						
							| 
									
										
										
										
											2016-07-15 05:12:46 +08:00
										 |  |  | 	case *sshFxpRemovePacket: | 
					
						
							| 
									
										
										
										
											2016-10-21 09:42:47 +08:00
										 |  |  | 		method = "Remove" | 
					
						
							| 
									
										
										
										
											2020-09-06 14:26:58 +08:00
										 |  |  | 	case *sshFxpStatPacket, *sshFxpFstatPacket: | 
					
						
							| 
									
										
										
										
											2016-10-21 09:42:47 +08:00
										 |  |  | 		method = "Stat" | 
					
						
							| 
									
										
										
										
											2020-09-06 14:26:58 +08:00
										 |  |  | 	case *sshFxpLstatPacket: | 
					
						
							|  |  |  | 		method = "Lstat" | 
					
						
							| 
									
										
										
										
											2016-07-09 03:38:35 +08:00
										 |  |  | 	case *sshFxpRmdirPacket: | 
					
						
							| 
									
										
										
										
											2016-10-21 09:42:47 +08:00
										 |  |  | 		method = "Rmdir" | 
					
						
							| 
									
										
										
										
											2016-07-09 03:38:35 +08:00
										 |  |  | 	case *sshFxpReadlinkPacket: | 
					
						
							| 
									
										
										
										
											2016-10-21 09:42:47 +08:00
										 |  |  | 		method = "Readlink" | 
					
						
							| 
									
										
										
										
											2016-07-09 03:38:35 +08:00
										 |  |  | 	case *sshFxpMkdirPacket: | 
					
						
							| 
									
										
										
										
											2016-10-21 09:42:47 +08:00
										 |  |  | 		method = "Mkdir" | 
					
						
							| 
									
										
										
										
											2019-05-25 03:23:18 +08:00
										 |  |  | 	case *sshFxpExtendedPacketHardlink: | 
					
						
							|  |  |  | 		method = "Link" | 
					
						
							| 
									
										
										
										
											2016-07-09 03:38:35 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-10-21 09:42:47 +08:00
										 |  |  | 	return method | 
					
						
							| 
									
										
										
										
											2016-07-09 03:38:35 +08:00
										 |  |  | } |