| 
									
										
										
										
											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" | 
					
						
							| 
									
										
										
										
											2021-06-05 05:18:41 +08:00
										 |  |  | 	"errors" | 
					
						
							|  |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2016-07-09 08:22:52 +08:00
										 |  |  | 	"io" | 
					
						
							|  |  |  | 	"os" | 
					
						
							| 
									
										
										
										
											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" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-02 19:23:37 +08:00
										 |  |  | // state encapsulates the reader/writer/readdir from handlers.
 | 
					
						
							|  |  |  | type state struct { | 
					
						
							|  |  |  | 	mu sync.RWMutex | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	writerAt         io.WriterAt | 
					
						
							|  |  |  | 	readerAt         io.ReaderAt | 
					
						
							|  |  |  | 	writerAtReaderAt WriterAtReaderAt | 
					
						
							|  |  |  | 	listerAt         ListerAt | 
					
						
							|  |  |  | 	lsoffset         int64 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // copy returns a shallow copy the state.
 | 
					
						
							|  |  |  | // This is broken out to specific fields,
 | 
					
						
							|  |  |  | // because we have to copy around the mutex in state.
 | 
					
						
							|  |  |  | func (s *state) copy() state { | 
					
						
							|  |  |  | 	s.mu.RLock() | 
					
						
							|  |  |  | 	defer s.mu.RUnlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return state{ | 
					
						
							|  |  |  | 		writerAt:         s.writerAt, | 
					
						
							|  |  |  | 		readerAt:         s.readerAt, | 
					
						
							|  |  |  | 		writerAtReaderAt: s.writerAtReaderAt, | 
					
						
							|  |  |  | 		listerAt:         s.listerAt, | 
					
						
							|  |  |  | 		lsoffset:         s.lsoffset, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (s *state) setReaderAt(rd io.ReaderAt) { | 
					
						
							|  |  |  | 	s.mu.Lock() | 
					
						
							|  |  |  | 	defer s.mu.Unlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	s.readerAt = rd | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (s *state) getReaderAt() io.ReaderAt { | 
					
						
							|  |  |  | 	s.mu.RLock() | 
					
						
							|  |  |  | 	defer s.mu.RUnlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return s.readerAt | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (s *state) setWriterAt(rd io.WriterAt) { | 
					
						
							|  |  |  | 	s.mu.Lock() | 
					
						
							|  |  |  | 	defer s.mu.Unlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	s.writerAt = rd | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (s *state) getWriterAt() io.WriterAt { | 
					
						
							|  |  |  | 	s.mu.RLock() | 
					
						
							|  |  |  | 	defer s.mu.RUnlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return s.writerAt | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (s *state) setWriterAtReaderAt(rw WriterAtReaderAt) { | 
					
						
							|  |  |  | 	s.mu.Lock() | 
					
						
							|  |  |  | 	defer s.mu.Unlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	s.writerAtReaderAt = rw | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (s *state) getWriterAtReaderAt() WriterAtReaderAt { | 
					
						
							|  |  |  | 	s.mu.RLock() | 
					
						
							|  |  |  | 	defer s.mu.RUnlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return s.writerAtReaderAt | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (s *state) getAllReaderWriters() (io.ReaderAt, io.WriterAt, WriterAtReaderAt) { | 
					
						
							|  |  |  | 	s.mu.RLock() | 
					
						
							|  |  |  | 	defer s.mu.RUnlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return s.readerAt, s.writerAt, s.writerAtReaderAt | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Returns current offset for file list
 | 
					
						
							|  |  |  | func (s *state) lsNext() int64 { | 
					
						
							|  |  |  | 	s.mu.RLock() | 
					
						
							|  |  |  | 	defer s.mu.RUnlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return s.lsoffset | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Increases next offset
 | 
					
						
							|  |  |  | func (s *state) lsInc(offset int64) { | 
					
						
							|  |  |  | 	s.mu.Lock() | 
					
						
							|  |  |  | 	defer s.mu.Unlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	s.lsoffset += offset | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // manage file read/write state
 | 
					
						
							|  |  |  | func (s *state) setListerAt(la ListerAt) { | 
					
						
							|  |  |  | 	s.mu.Lock() | 
					
						
							|  |  |  | 	defer s.mu.Unlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	s.listerAt = la | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (s *state) getListerAt() ListerAt { | 
					
						
							|  |  |  | 	s.mu.RLock() | 
					
						
							|  |  |  | 	defer s.mu.RUnlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return s.listerAt | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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 | 
					
						
							| 
									
										
										
										
											2021-08-02 19:23:37 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-03 10:37:23 +08:00
										 |  |  | 	// reader/writer/readdir from handlers
 | 
					
						
							| 
									
										
										
										
											2021-08-02 19:23:37 +08:00
										 |  |  | 	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
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-02 19:23:37 +08:00
										 |  |  | // NewRequest creates a new Request object.
 | 
					
						
							|  |  |  | func NewRequest(method, path string) *Request { | 
					
						
							|  |  |  | 	return &Request{ | 
					
						
							|  |  |  | 		Method:   method, | 
					
						
							|  |  |  | 		Filepath: cleanPath(path), | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // copy returns a shallow copy of existing request.
 | 
					
						
							|  |  |  | // This is broken out to specific fields,
 | 
					
						
							|  |  |  | // because we have to copy around the mutex in state.
 | 
					
						
							|  |  |  | func (r *Request) copy() *Request { | 
					
						
							|  |  |  | 	return &Request{ | 
					
						
							|  |  |  | 		Method:   r.Method, | 
					
						
							|  |  |  | 		Filepath: r.Filepath, | 
					
						
							|  |  |  | 		Flags:    r.Flags, | 
					
						
							|  |  |  | 		Attrs:    r.Attrs, | 
					
						
							|  |  |  | 		Target:   r.Target, | 
					
						
							|  |  |  | 		handle:   r.handle, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		state: r.state.copy(), | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		ctx:       r.ctx, | 
					
						
							|  |  |  | 		cancelCtx: r.cancelCtx, | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											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: | 
					
						
							| 
									
										
										
										
											2020-09-24 23:20:10 +08:00
										 |  |  | 		// NOTE: given a POSIX compliant signature: symlink(target, linkpath string)
 | 
					
						
							|  |  |  | 		// this makes Request.Target the linkpath, and Request.Filepath the target.
 | 
					
						
							| 
									
										
										
										
											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 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-02 19:23:37 +08:00
										 |  |  | 	rd, wr, rw := r.getAllReaderWriters() | 
					
						
							| 
									
										
										
										
											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 | 
					
						
							| 
									
										
										
										
											2021-08-02 19:23:37 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			r.setWriterAtReaderAt(nil) | 
					
						
							| 
									
										
										
										
											2020-08-30 16:40:22 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-02 19:23:37 +08:00
										 |  |  | 	rd, wr, rw := r.getAllReaderWriters() | 
					
						
							| 
									
										
										
										
											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) | 
					
						
							| 
									
										
										
										
											2021-02-11 02:13:19 +08:00
										 |  |  | 	case "Setstat", "Rename", "Rmdir", "Mkdir", "Link", "Symlink", "Remove", "PosixRename", "StatVFS": | 
					
						
							| 
									
										
										
										
											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: | 
					
						
							| 
									
										
										
										
											2021-08-02 19:23:37 +08:00
										 |  |  | 		return statusFromError(pkt.id(), fmt.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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-22 20:00:27 +08:00
										 |  |  | 	id := pkt.id() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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 { | 
					
						
							| 
									
										
										
										
											2021-02-22 20:00:27 +08:00
										 |  |  | 					return statusFromError(id, err) | 
					
						
							| 
									
										
										
										
											2020-09-03 22:40:14 +08:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2021-08-02 19:23:37 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				r.setWriterAtReaderAt(rw) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				return &sshFxpHandlePacket{ | 
					
						
							|  |  |  | 					ID:     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 { | 
					
						
							| 
									
										
										
										
											2021-02-22 20:00:27 +08:00
										 |  |  | 			return statusFromError(id, err) | 
					
						
							| 
									
										
										
										
											2020-08-30 16:40:22 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-08-02 19:23:37 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		r.setWriterAt(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 { | 
					
						
							| 
									
										
										
										
											2021-02-22 20:00:27 +08:00
										 |  |  | 			return statusFromError(id, err) | 
					
						
							| 
									
										
										
										
											2020-09-03 22:40:14 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-08-02 19:23:37 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		r.setReaderAt(rd) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-29 10:20:55 +08:00
										 |  |  | 	default: | 
					
						
							| 
									
										
										
										
											2021-02-22 20:00:27 +08:00
										 |  |  | 		return statusFromError(id, errors.New("bad file flags")) | 
					
						
							| 
									
										
										
										
											2017-08-23 10:24:14 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-08-02 19:23:37 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return &sshFxpHandlePacket{ | 
					
						
							|  |  |  | 		ID:     id, | 
					
						
							|  |  |  | 		Handle: r.handle, | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-01-29 10:20:55 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2021-02-22 20:00:27 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-29 10:20:55 +08:00
										 |  |  | 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 { | 
					
						
							| 
									
										
										
										
											2021-02-22 20:00:27 +08:00
										 |  |  | 		return statusFromError(pkt.id(), wrapPathError(r.Filepath, err)) | 
					
						
							| 
									
										
										
										
											2019-01-29 10:20:55 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-08-02 19:23:37 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	r.setListerAt(la) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	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 { | 
					
						
							| 
									
										
										
										
											2021-08-02 19:23:37 +08:00
										 |  |  | 	rd := r.getReaderAt() | 
					
						
							|  |  |  | 	if rd == nil { | 
					
						
							| 
									
										
										
										
											2021-02-22 20:00:27 +08:00
										 |  |  | 		return statusFromError(pkt.id(), 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) | 
					
						
							| 
									
										
										
										
											2021-08-02 19:23:37 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	n, err := rd.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) { | 
					
						
							| 
									
										
										
										
											2021-02-22 20:00:27 +08:00
										 |  |  | 		return statusFromError(pkt.id(), err) | 
					
						
							| 
									
										
										
										
											2016-07-26 02:42:18 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-08-02 19:23:37 +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 { | 
					
						
							| 
									
										
										
										
											2021-08-02 19:23:37 +08:00
										 |  |  | 	wr := r.getWriterAt() | 
					
						
							|  |  |  | 	if wr == nil { | 
					
						
							| 
									
										
										
										
											2021-02-22 20:00:27 +08:00
										 |  |  | 		return statusFromError(pkt.id(), 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) | 
					
						
							| 
									
										
										
										
											2021-08-02 19:23:37 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	_, err := wr.WriteAt(data, offset) | 
					
						
							| 
									
										
										
										
											2021-02-22 20:00:27 +08:00
										 |  |  | 	return statusFromError(pkt.id(), 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 { | 
					
						
							| 
									
										
										
										
											2021-08-02 19:23:37 +08:00
										 |  |  | 	rw := r.getWriterAtReaderAt() | 
					
						
							|  |  |  | 	if rw == nil { | 
					
						
							| 
									
										
										
										
											2021-02-22 20:00:27 +08:00
										 |  |  | 		return statusFromError(pkt.id(), errors.New("unexpected write and read packet")) | 
					
						
							| 
									
										
										
										
											2020-08-30 16:40:22 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-08-02 19:23:37 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-29 04:40:52 +08:00
										 |  |  | 	switch p := pkt.(type) { | 
					
						
							| 
									
										
										
										
											2020-08-30 16:40:22 +08:00
										 |  |  | 	case *sshFxpReadPacket: | 
					
						
							| 
									
										
										
										
											2020-10-29 04:40:52 +08:00
										 |  |  | 		data, offset := p.getDataSlice(alloc, orderID), int64(p.Offset) | 
					
						
							| 
									
										
										
										
											2021-08-02 19:23:37 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		n, err := rw.ReadAt(data, offset) | 
					
						
							| 
									
										
										
										
											2020-08-30 16:40:22 +08:00
										 |  |  | 		// only return EOF error if no data left to read
 | 
					
						
							|  |  |  | 		if err != nil && (err != io.EOF || n == 0) { | 
					
						
							| 
									
										
										
										
											2021-02-22 20:00:27 +08:00
										 |  |  | 			return statusFromError(pkt.id(), err) | 
					
						
							| 
									
										
										
										
											2020-08-30 16:40:22 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-08-02 19:23:37 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-30 16:40:22 +08:00
										 |  |  | 		return &sshFxpDataPacket{ | 
					
						
							|  |  |  | 			ID:     pkt.id(), | 
					
						
							|  |  |  | 			Length: uint32(n), | 
					
						
							|  |  |  | 			Data:   data[:n], | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-08-02 19:23:37 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-30 16:40:22 +08:00
										 |  |  | 	case *sshFxpWritePacket: | 
					
						
							| 
									
										
										
										
											2020-10-29 04:40:52 +08:00
										 |  |  | 		data, offset := p.Data, int64(p.Offset) | 
					
						
							| 
									
										
										
										
											2021-08-02 19:23:37 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		_, err := rw.WriteAt(data, offset) | 
					
						
							| 
									
										
										
										
											2021-02-22 20:00:27 +08:00
										 |  |  | 		return statusFromError(pkt.id(), err) | 
					
						
							| 
									
										
										
										
											2021-08-02 19:23:37 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-30 16:40:22 +08:00
										 |  |  | 	default: | 
					
						
							| 
									
										
										
										
											2021-02-22 20:00:27 +08:00
										 |  |  | 		return statusFromError(pkt.id(), errors.New("unexpected packet type for read or write")) | 
					
						
							| 
									
										
										
										
											2020-08-30 16:40:22 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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: | 
					
						
							| 
									
										
										
										
											2020-10-29 04:40:52 +08:00
										 |  |  | 		return p.getDataSlice(alloc, orderID), int64(p.Offset), p.Len | 
					
						
							| 
									
										
										
										
											2018-11-21 08:34:41 +08:00
										 |  |  | 	case *sshFxpWritePacket: | 
					
						
							| 
									
										
										
										
											2020-10-29 04:40:52 +08:00
										 |  |  | 		return p.Data, int64(p.Offset), p.Length | 
					
						
							| 
									
										
										
										
											2018-11-21 08:34:41 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	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) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-09-26 00:16:01 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-02 19:23:37 +08:00
										 |  |  | 	switch r.Method { | 
					
						
							|  |  |  | 	case "PosixRename": | 
					
						
							| 
									
										
										
										
											2020-09-26 00:16:01 +08:00
										 |  |  | 		if posixRenamer, ok := h.(PosixRenameFileCmder); ok { | 
					
						
							|  |  |  | 			err := posixRenamer.PosixRename(r) | 
					
						
							| 
									
										
										
										
											2021-02-22 20:00:27 +08:00
										 |  |  | 			return statusFromError(pkt.id(), err) | 
					
						
							| 
									
										
										
										
											2020-09-26 00:16:01 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// PosixRenameFileCmder not implemented handle this request as a Rename
 | 
					
						
							|  |  |  | 		r.Method = "Rename" | 
					
						
							|  |  |  | 		err := h.Filecmd(r) | 
					
						
							| 
									
										
										
										
											2021-02-22 20:00:27 +08:00
										 |  |  | 		return statusFromError(pkt.id(), err) | 
					
						
							| 
									
										
										
										
											2020-09-26 00:16:01 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-02 19:23:37 +08:00
										 |  |  | 	case "StatVFS": | 
					
						
							| 
									
										
										
										
											2021-02-11 02:13:19 +08:00
										 |  |  | 		if statVFSCmdr, ok := h.(StatVFSFileCmder); ok { | 
					
						
							|  |  |  | 			stat, err := statVFSCmdr.StatVFS(r) | 
					
						
							|  |  |  | 			if err != nil { | 
					
						
							| 
									
										
										
										
											2021-02-22 20:00:27 +08:00
										 |  |  | 				return statusFromError(pkt.id(), err) | 
					
						
							| 
									
										
										
										
											2021-02-11 02:13:19 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 			stat.ID = pkt.id() | 
					
						
							|  |  |  | 			return stat | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-22 20:00:27 +08:00
										 |  |  | 		return statusFromError(pkt.id(), ErrSSHFxOpUnsupported) | 
					
						
							| 
									
										
										
										
											2021-02-11 02:13:19 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-09 08:22:52 +08:00
										 |  |  | 	err := h.Filecmd(r) | 
					
						
							| 
									
										
										
										
											2021-02-22 20:00:27 +08:00
										 |  |  | 	return statusFromError(pkt.id(), 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 { | 
					
						
							| 
									
										
										
										
											2021-08-02 19:23:37 +08:00
										 |  |  | 	lister := r.getListerAt() | 
					
						
							| 
									
										
										
										
											2017-07-28 09:22:11 +08:00
										 |  |  | 	if lister == nil { | 
					
						
							| 
									
										
										
										
											2021-02-22 20:00:27 +08:00
										 |  |  | 		return statusFromError(pkt.id(), 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": | 
					
						
							| 
									
										
										
										
											2021-08-02 19:23:37 +08:00
										 |  |  | 		if err != nil && (err != io.EOF || n == 0) { | 
					
						
							| 
									
										
										
										
											2021-02-22 20:00:27 +08:00
										 |  |  | 			return statusFromError(pkt.id(), err) | 
					
						
							| 
									
										
										
										
											2017-08-21 06:51:26 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-08-02 19:23:37 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-02 19:58:16 +08:00
										 |  |  | 		nameAttrs := make([]*sshFxpNameAttr, 0, len(finfo)) | 
					
						
							| 
									
										
										
										
											2017-07-28 09:22:11 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-17 19:40:30 +08:00
										 |  |  | 		// If the type conversion fails, we get untyped `nil`,
 | 
					
						
							|  |  |  | 		// which is handled by not looking up any names.
 | 
					
						
							|  |  |  | 		idLookup, _ := h.(NameLookupFileLister) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-09 08:22:52 +08:00
										 |  |  | 		for _, fi := range finfo { | 
					
						
							| 
									
										
										
										
											2021-08-02 19:55:34 +08:00
										 |  |  | 			nameAttrs = append(nameAttrs, &sshFxpNameAttr{ | 
					
						
							| 
									
										
										
										
											2016-07-09 08:22:52 +08:00
										 |  |  | 				Name:     fi.Name(), | 
					
						
							| 
									
										
										
										
											2021-08-17 19:40:30 +08:00
										 |  |  | 				LongName: runLs(idLookup, fi), | 
					
						
							| 
									
										
										
										
											2016-07-09 08:22:52 +08:00
										 |  |  | 				Attrs:    []interface{}{fi}, | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-08-02 19:55:34 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		return &sshFxpNamePacket{ | 
					
						
							|  |  |  | 			ID:        pkt.id(), | 
					
						
							|  |  |  | 			NameAttrs: nameAttrs, | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-08-02 19:23:37 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-06 09:34:17 +08:00
										 |  |  | 	default: | 
					
						
							| 
									
										
										
										
											2021-06-05 05:18:41 +08:00
										 |  |  | 		err = fmt.Errorf("unexpected method: %s", r.Method) | 
					
						
							| 
									
										
										
										
											2021-02-22 20:00:27 +08:00
										 |  |  | 		return statusFromError(pkt.id(), err) | 
					
						
							| 
									
										
										
										
											2018-06-06 09:34:17 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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 { | 
					
						
							| 
									
										
										
										
											2021-02-22 20:00:27 +08:00
										 |  |  | 		return statusFromError(pkt.id(), err) | 
					
						
							| 
									
										
										
										
											2018-06-06 09:34:17 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	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 { | 
					
						
							| 
									
										
										
										
											2021-02-22 20:00:27 +08:00
										 |  |  | 			return statusFromError(pkt.id(), err) | 
					
						
							| 
									
										
										
										
											2017-08-21 06:51:26 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		if n == 0 { | 
					
						
							| 
									
										
										
										
											2021-08-02 19:23:37 +08:00
										 |  |  | 			err = &os.PathError{ | 
					
						
							|  |  |  | 				Op:   strings.ToLower(r.Method), | 
					
						
							|  |  |  | 				Path: r.Filepath, | 
					
						
							|  |  |  | 				Err:  syscall.ENOENT, | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2021-02-22 20:00:27 +08:00
										 |  |  | 			return statusFromError(pkt.id(), 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 { | 
					
						
							| 
									
										
										
										
											2021-02-22 20:00:27 +08:00
										 |  |  | 			return statusFromError(pkt.id(), err) | 
					
						
							| 
									
										
										
										
											2017-08-21 06:51:26 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		if n == 0 { | 
					
						
							| 
									
										
										
										
											2021-08-02 19:23:37 +08:00
										 |  |  | 			err = &os.PathError{ | 
					
						
							|  |  |  | 				Op:   "readlink", | 
					
						
							|  |  |  | 				Path: r.Filepath, | 
					
						
							|  |  |  | 				Err:  syscall.ENOENT, | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2021-02-22 20:00:27 +08:00
										 |  |  | 			return statusFromError(pkt.id(), 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(), | 
					
						
							| 
									
										
										
										
											2021-02-22 20:00:27 +08:00
										 |  |  | 			NameAttrs: []*sshFxpNameAttr{ | 
					
						
							| 
									
										
										
										
											2021-02-23 05:29:35 +08:00
										 |  |  | 				{ | 
					
						
							| 
									
										
										
										
											2021-02-22 20:00:27 +08:00
										 |  |  | 					Name:     filename, | 
					
						
							|  |  |  | 					LongName: filename, | 
					
						
							|  |  |  | 					Attrs:    emptyFileStat, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			}, | 
					
						
							| 
									
										
										
										
											2017-08-21 06:51:26 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-07-28 09:22:11 +08:00
										 |  |  | 	default: | 
					
						
							| 
									
										
										
										
											2021-06-05 05:18:41 +08:00
										 |  |  | 		err = fmt.Errorf("unexpected method: %s", r.Method) | 
					
						
							| 
									
										
										
										
											2021-02-22 20:00:27 +08:00
										 |  |  | 		return statusFromError(pkt.id(), 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
										 |  |  | } |