| 
									
										
										
										
											2015-07-25 16:19:29 +08:00
										 |  |  | package sftp | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // sftp server counterpart
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"encoding" | 
					
						
							|  |  |  | 	"fmt" | 
					
						
							|  |  |  | 	"io" | 
					
						
							| 
									
										
										
										
											2016-01-11 04:10:18 +08:00
										 |  |  | 	"io/ioutil" | 
					
						
							| 
									
										
										
										
											2015-07-25 16:19:29 +08:00
										 |  |  | 	"os" | 
					
						
							| 
									
										
										
										
											2015-08-06 03:57:28 +08:00
										 |  |  | 	"path/filepath" | 
					
						
							| 
									
										
										
										
											2016-01-08 06:27:37 +08:00
										 |  |  | 	"strconv" | 
					
						
							| 
									
										
										
										
											2015-07-25 16:19:29 +08:00
										 |  |  | 	"sync" | 
					
						
							|  |  |  | 	"syscall" | 
					
						
							| 
									
										
										
										
											2015-09-07 17:13:07 +08:00
										 |  |  | 	"time" | 
					
						
							| 
									
										
										
										
											2016-05-19 13:16:48 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/pkg/errors" | 
					
						
							| 
									
										
										
										
											2015-07-25 16:19:29 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-07 14:55:15 +08:00
										 |  |  | const ( | 
					
						
							|  |  |  | 	sftpServerWorkerCount = 8 | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Server is an SSH File Transfer Protocol (sftp) server.
 | 
					
						
							|  |  |  | // This is intended to provide the sftp subsystem to an ssh server daemon.
 | 
					
						
							|  |  |  | // This implementation currently supports most of sftp server protocol version 3,
 | 
					
						
							|  |  |  | // as specified at http://tools.ietf.org/html/draft-ietf-secsh-filexfer-02
 | 
					
						
							| 
									
										
										
										
											2015-07-25 16:19:29 +08:00
										 |  |  | type Server struct { | 
					
						
							|  |  |  | 	in            io.Reader | 
					
						
							| 
									
										
										
										
											2015-09-07 10:36:47 +08:00
										 |  |  | 	out           io.WriteCloser | 
					
						
							| 
									
										
										
										
											2016-05-29 14:32:05 +08:00
										 |  |  | 	outMutex      sync.Mutex | 
					
						
							| 
									
										
										
										
											2015-07-31 14:43:00 +08:00
										 |  |  | 	debugStream   io.Writer | 
					
						
							|  |  |  | 	readOnly      bool | 
					
						
							| 
									
										
										
										
											2016-01-05 05:15:21 +08:00
										 |  |  | 	lastID        uint32 | 
					
						
							| 
									
										
										
										
											2015-09-07 10:36:47 +08:00
										 |  |  | 	pktChan       chan rxPacket | 
					
						
							| 
									
										
										
										
											2015-09-08 13:50:46 +08:00
										 |  |  | 	openFiles     map[string]*os.File | 
					
						
							| 
									
										
										
										
											2016-05-29 14:32:05 +08:00
										 |  |  | 	openFilesLock sync.RWMutex | 
					
						
							| 
									
										
										
										
											2015-07-26 16:32:19 +08:00
										 |  |  | 	handleCount   int | 
					
						
							| 
									
										
										
										
											2015-08-05 12:11:01 +08:00
										 |  |  | 	maxTxPacket   uint32 | 
					
						
							| 
									
										
										
										
											2015-07-26 16:32:19 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-08 13:50:46 +08:00
										 |  |  | func (svr *Server) nextHandle(f *os.File) string { | 
					
						
							| 
									
										
										
										
											2015-07-26 16:32:19 +08:00
										 |  |  | 	svr.openFilesLock.Lock() | 
					
						
							|  |  |  | 	defer svr.openFilesLock.Unlock() | 
					
						
							|  |  |  | 	svr.handleCount++ | 
					
						
							| 
									
										
										
										
											2016-01-08 06:27:37 +08:00
										 |  |  | 	handle := strconv.Itoa(svr.handleCount) | 
					
						
							| 
									
										
										
										
											2015-09-08 13:50:46 +08:00
										 |  |  | 	svr.openFiles[handle] = f | 
					
						
							| 
									
										
										
										
											2015-07-26 16:32:19 +08:00
										 |  |  | 	return handle | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (svr *Server) closeHandle(handle string) error { | 
					
						
							|  |  |  | 	svr.openFilesLock.Lock() | 
					
						
							|  |  |  | 	defer svr.openFilesLock.Unlock() | 
					
						
							|  |  |  | 	if f, ok := svr.openFiles[handle]; ok { | 
					
						
							|  |  |  | 		delete(svr.openFiles, handle) | 
					
						
							|  |  |  | 		return f.Close() | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-12-31 01:56:52 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return syscall.EBADF | 
					
						
							| 
									
										
										
										
											2015-07-25 16:19:29 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-08 13:50:46 +08:00
										 |  |  | func (svr *Server) getHandle(handle string) (*os.File, bool) { | 
					
						
							| 
									
										
										
										
											2015-07-30 08:24:24 +08:00
										 |  |  | 	svr.openFilesLock.RLock() | 
					
						
							|  |  |  | 	defer svr.openFilesLock.RUnlock() | 
					
						
							|  |  |  | 	f, ok := svr.openFiles[handle] | 
					
						
							|  |  |  | 	return f, ok | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-25 16:19:29 +08:00
										 |  |  | type serverRespondablePacket interface { | 
					
						
							|  |  |  | 	encoding.BinaryUnmarshaler | 
					
						
							| 
									
										
										
										
											2016-01-08 06:27:37 +08:00
										 |  |  | 	id() uint32 | 
					
						
							| 
									
										
										
										
											2015-07-25 16:19:29 +08:00
										 |  |  | 	respond(svr *Server) error | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-11 04:10:18 +08:00
										 |  |  | // NewServer creates a new Server instance around the provided streams, serving
 | 
					
						
							| 
									
										
										
										
											2016-01-17 01:41:01 +08:00
										 |  |  | // content from the root of the filesystem.  Optionally, ServerOption
 | 
					
						
							| 
									
										
										
										
											2016-01-11 04:10:18 +08:00
										 |  |  | // functions may be specified to further configure the Server.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // A subsequent call to Serve() is required to begin serving files over SFTP.
 | 
					
						
							| 
									
										
										
										
											2016-05-29 14:32:05 +08:00
										 |  |  | func NewServer(rwc io.ReadWriteCloser, options ...ServerOption) (*Server, error) { | 
					
						
							| 
									
										
										
										
											2016-01-11 04:10:18 +08:00
										 |  |  | 	s := &Server{ | 
					
						
							| 
									
										
										
										
											2016-05-29 14:32:05 +08:00
										 |  |  | 		in:          rwc.(io.Reader), | 
					
						
							|  |  |  | 		out:         rwc.(io.WriteCloser), | 
					
						
							|  |  |  | 		debugStream: ioutil.Discard, | 
					
						
							|  |  |  | 		pktChan:     make(chan rxPacket, sftpServerWorkerCount), | 
					
						
							|  |  |  | 		openFiles:   make(map[string]*os.File), | 
					
						
							|  |  |  | 		maxTxPacket: 1 << 15, | 
					
						
							| 
									
										
										
										
											2016-01-11 04:10:18 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for _, o := range options { | 
					
						
							|  |  |  | 		if err := o(s); err != nil { | 
					
						
							|  |  |  | 			return nil, err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return s, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // A ServerOption is a function which applies configuration to a Server.
 | 
					
						
							|  |  |  | type ServerOption func(*Server) error | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // WithDebug enables Server debugging output to the supplied io.Writer.
 | 
					
						
							| 
									
										
										
										
											2016-01-12 01:21:15 +08:00
										 |  |  | func WithDebug(w io.Writer) ServerOption { | 
					
						
							| 
									
										
										
										
											2016-01-11 04:10:18 +08:00
										 |  |  | 	return func(s *Server) error { | 
					
						
							|  |  |  | 		s.debugStream = w | 
					
						
							|  |  |  | 		return nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // ReadOnly configures a Server to serve files in read-only mode.
 | 
					
						
							| 
									
										
										
										
											2016-01-12 01:21:15 +08:00
										 |  |  | func ReadOnly() ServerOption { | 
					
						
							| 
									
										
										
										
											2016-01-11 04:10:18 +08:00
										 |  |  | 	return func(s *Server) error { | 
					
						
							|  |  |  | 		s.readOnly = true | 
					
						
							|  |  |  | 		return nil | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-07-25 16:19:29 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-07 10:36:47 +08:00
										 |  |  | type rxPacket struct { | 
					
						
							|  |  |  | 	pktType  fxp | 
					
						
							|  |  |  | 	pktBytes []byte | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-25 16:19:29 +08:00
										 |  |  | // Unmarshal a single logical packet from the secure channel
 | 
					
						
							|  |  |  | func (svr *Server) rxPackets() error { | 
					
						
							|  |  |  | 	defer close(svr.pktChan) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for { | 
					
						
							|  |  |  | 		pktType, pktBytes, err := recvPacket(svr.in) | 
					
						
							| 
									
										
										
										
											2015-12-31 01:56:52 +08:00
										 |  |  | 		switch err { | 
					
						
							|  |  |  | 		case nil: | 
					
						
							| 
									
										
										
										
											2016-01-01 22:31:52 +08:00
										 |  |  | 			svr.pktChan <- rxPacket{fxp(pktType), pktBytes} | 
					
						
							| 
									
										
										
										
											2015-12-31 01:56:52 +08:00
										 |  |  | 		case io.EOF: | 
					
						
							| 
									
										
										
										
											2015-07-25 16:19:29 +08:00
										 |  |  | 			return nil | 
					
						
							| 
									
										
										
										
											2015-12-31 01:56:52 +08:00
										 |  |  | 		default: | 
					
						
							| 
									
										
										
										
											2016-05-19 13:16:48 +08:00
										 |  |  | 			return errors.Wrap(err, "revcPacket error") | 
					
						
							| 
									
										
										
										
											2015-07-25 16:19:29 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-09-07 10:36:47 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Up to N parallel servers
 | 
					
						
							|  |  |  | func (svr *Server) sftpServerWorker(doneChan chan error) { | 
					
						
							| 
									
										
										
										
											2016-05-19 12:49:23 +08:00
										 |  |  | 	for p := range svr.pktChan { | 
					
						
							|  |  |  | 		var pkt serverRespondablePacket | 
					
						
							|  |  |  | 		var readonly = true | 
					
						
							|  |  |  | 		switch p.pktType { | 
					
						
							|  |  |  | 		case ssh_FXP_INIT: | 
					
						
							|  |  |  | 			pkt = &sshFxInitPacket{} | 
					
						
							|  |  |  | 		case ssh_FXP_LSTAT: | 
					
						
							|  |  |  | 			pkt = &sshFxpLstatPacket{} | 
					
						
							|  |  |  | 		case ssh_FXP_OPEN: | 
					
						
							|  |  |  | 			pkt = &sshFxpOpenPacket{} | 
					
						
							|  |  |  | 			// readonly handled specially below
 | 
					
						
							|  |  |  | 		case ssh_FXP_CLOSE: | 
					
						
							|  |  |  | 			pkt = &sshFxpClosePacket{} | 
					
						
							|  |  |  | 		case ssh_FXP_READ: | 
					
						
							|  |  |  | 			pkt = &sshFxpReadPacket{} | 
					
						
							|  |  |  | 		case ssh_FXP_WRITE: | 
					
						
							|  |  |  | 			pkt = &sshFxpWritePacket{} | 
					
						
							|  |  |  | 			readonly = false | 
					
						
							|  |  |  | 		case ssh_FXP_FSTAT: | 
					
						
							|  |  |  | 			pkt = &sshFxpFstatPacket{} | 
					
						
							|  |  |  | 		case ssh_FXP_SETSTAT: | 
					
						
							|  |  |  | 			pkt = &sshFxpSetstatPacket{} | 
					
						
							|  |  |  | 			readonly = false | 
					
						
							|  |  |  | 		case ssh_FXP_FSETSTAT: | 
					
						
							|  |  |  | 			pkt = &sshFxpFsetstatPacket{} | 
					
						
							|  |  |  | 			readonly = false | 
					
						
							|  |  |  | 		case ssh_FXP_OPENDIR: | 
					
						
							|  |  |  | 			pkt = &sshFxpOpendirPacket{} | 
					
						
							|  |  |  | 		case ssh_FXP_READDIR: | 
					
						
							|  |  |  | 			pkt = &sshFxpReaddirPacket{} | 
					
						
							|  |  |  | 		case ssh_FXP_REMOVE: | 
					
						
							|  |  |  | 			pkt = &sshFxpRemovePacket{} | 
					
						
							|  |  |  | 			readonly = false | 
					
						
							|  |  |  | 		case ssh_FXP_MKDIR: | 
					
						
							|  |  |  | 			pkt = &sshFxpMkdirPacket{} | 
					
						
							|  |  |  | 			readonly = false | 
					
						
							|  |  |  | 		case ssh_FXP_RMDIR: | 
					
						
							|  |  |  | 			pkt = &sshFxpRmdirPacket{} | 
					
						
							|  |  |  | 			readonly = false | 
					
						
							|  |  |  | 		case ssh_FXP_REALPATH: | 
					
						
							|  |  |  | 			pkt = &sshFxpRealpathPacket{} | 
					
						
							|  |  |  | 		case ssh_FXP_STAT: | 
					
						
							|  |  |  | 			pkt = &sshFxpStatPacket{} | 
					
						
							|  |  |  | 		case ssh_FXP_RENAME: | 
					
						
							|  |  |  | 			pkt = &sshFxpRenamePacket{} | 
					
						
							|  |  |  | 			readonly = false | 
					
						
							|  |  |  | 		case ssh_FXP_READLINK: | 
					
						
							|  |  |  | 			pkt = &sshFxpReadlinkPacket{} | 
					
						
							|  |  |  | 		case ssh_FXP_SYMLINK: | 
					
						
							|  |  |  | 			pkt = &sshFxpSymlinkPacket{} | 
					
						
							|  |  |  | 			readonly = false | 
					
						
							|  |  |  | 		default: | 
					
						
							| 
									
										
										
										
											2016-05-19 13:16:48 +08:00
										 |  |  | 			doneChan <- errors.Errorf("unhandled packet type: %s", p.pktType) | 
					
						
							| 
									
										
										
										
											2015-09-07 10:36:47 +08:00
										 |  |  | 			return | 
					
						
							| 
									
										
										
										
											2015-07-25 16:19:29 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-05-19 12:49:23 +08:00
										 |  |  | 		if err := pkt.UnmarshalBinary(p.pktBytes); err != nil { | 
					
						
							| 
									
										
										
										
											2016-05-23 18:54:08 +08:00
										 |  |  | 			doneChan <- err | 
					
						
							| 
									
										
										
										
											2016-05-19 12:49:23 +08:00
										 |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// handle SFP_OPENDIR specially
 | 
					
						
							|  |  |  | 		switch pkt := pkt.(type) { | 
					
						
							|  |  |  | 		case *sshFxpOpenPacket: | 
					
						
							|  |  |  | 			readonly = pkt.readonly() | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-12-31 01:56:52 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-08 06:27:37 +08:00
										 |  |  | 		// If server is operating read-only and a write operation is requested,
 | 
					
						
							|  |  |  | 		// return permission denied
 | 
					
						
							| 
									
										
										
										
											2016-05-19 12:49:23 +08:00
										 |  |  | 		if !readonly && svr.readOnly { | 
					
						
							| 
									
										
										
										
											2016-05-19 13:04:32 +08:00
										 |  |  | 			if err := svr.sendPacket(statusFromError(pkt.id(), syscall.EPERM)); err != nil { | 
					
						
							| 
									
										
										
										
											2016-05-19 13:16:48 +08:00
										 |  |  | 				doneChan <- errors.Wrap(err, "failed to send read only packet response") | 
					
						
							| 
									
										
										
										
											2016-05-19 13:04:32 +08:00
										 |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2016-01-08 06:27:37 +08:00
										 |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-19 13:04:32 +08:00
										 |  |  | 		if err := pkt.respond(svr); err != nil { | 
					
						
							| 
									
										
										
										
											2016-05-19 13:16:48 +08:00
										 |  |  | 			doneChan <- errors.Wrap(err, "pkt.respond failed") | 
					
						
							| 
									
										
										
										
											2016-05-19 13:04:32 +08:00
										 |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-05-19 12:49:23 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-25 16:19:29 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-09-07 10:36:47 +08:00
										 |  |  | 	doneChan <- nil | 
					
						
							| 
									
										
										
										
											2015-07-25 16:19:29 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-08 04:11:16 +08:00
										 |  |  | // Serve serves SFTP connections until the streams stop or the SFTP subsystem
 | 
					
						
							|  |  |  | // is stopped.
 | 
					
						
							| 
									
										
										
										
											2015-09-07 14:55:15 +08:00
										 |  |  | func (svr *Server) Serve() error { | 
					
						
							| 
									
										
										
										
											2015-08-06 14:24:33 +08:00
										 |  |  | 	go svr.rxPackets() | 
					
						
							| 
									
										
										
										
											2015-09-07 10:36:47 +08:00
										 |  |  | 	doneChan := make(chan error) | 
					
						
							| 
									
										
										
										
											2016-05-29 14:32:05 +08:00
										 |  |  | 	for i := 0; i < sftpServerWorkerCount; i++ { | 
					
						
							| 
									
										
										
										
											2015-09-07 10:36:47 +08:00
										 |  |  | 		go svr.sftpServerWorker(doneChan) | 
					
						
							| 
									
										
										
										
											2015-08-06 14:24:33 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-05-29 14:32:05 +08:00
										 |  |  | 	for i := 0; i < sftpServerWorkerCount; i++ { | 
					
						
							| 
									
										
										
										
											2015-09-07 10:36:47 +08:00
										 |  |  | 		if err := <-doneChan; err != nil { | 
					
						
							|  |  |  | 			// abort early and shut down the session on un-decodable packets
 | 
					
						
							|  |  |  | 			break | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-09-09 08:03:18 +08:00
										 |  |  | 	// close any still-open files
 | 
					
						
							|  |  |  | 	for handle, file := range svr.openFiles { | 
					
						
							|  |  |  | 		fmt.Fprintf(svr.debugStream, "sftp server file with handle '%v' left open: %v\n", handle, file.Name()) | 
					
						
							|  |  |  | 		file.Close() | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-09-07 10:36:47 +08:00
										 |  |  | 	return svr.out.Close() | 
					
						
							| 
									
										
										
										
											2015-08-06 14:24:33 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-25 16:19:29 +08:00
										 |  |  | func (p sshFxInitPacket) respond(svr *Server) error { | 
					
						
							|  |  |  | 	return svr.sendPacket(sshFxVersionPacket{sftpProtocolVersion, nil}) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-08 06:27:37 +08:00
										 |  |  | // The init packet has no ID, so we just return a zero-value ID
 | 
					
						
							| 
									
										
										
										
											2016-05-19 12:49:23 +08:00
										 |  |  | func (p sshFxInitPacket) id() uint32 { return 0 } | 
					
						
							| 
									
										
										
										
											2016-01-08 06:27:37 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-01 06:46:13 +08:00
										 |  |  | type sshFxpStatResponse struct { | 
					
						
							| 
									
										
										
										
											2016-01-05 05:15:21 +08:00
										 |  |  | 	ID   uint32 | 
					
						
							| 
									
										
										
										
											2015-07-25 16:19:29 +08:00
										 |  |  | 	info os.FileInfo | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-01 06:46:13 +08:00
										 |  |  | func (p sshFxpStatResponse) MarshalBinary() ([]byte, error) { | 
					
						
							| 
									
										
										
										
											2015-07-25 16:19:29 +08:00
										 |  |  | 	b := []byte{ssh_FXP_ATTRS} | 
					
						
							| 
									
										
										
										
											2016-01-05 05:15:21 +08:00
										 |  |  | 	b = marshalUint32(b, p.ID) | 
					
						
							| 
									
										
										
										
											2015-07-25 16:19:29 +08:00
										 |  |  | 	b = marshalFileInfo(b, p.info) | 
					
						
							|  |  |  | 	return b, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (p sshFxpLstatPacket) respond(svr *Server) error { | 
					
						
							|  |  |  | 	// stat the requested file
 | 
					
						
							| 
									
										
										
										
											2015-12-31 01:56:52 +08:00
										 |  |  | 	info, err := os.Lstat(p.Path) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2016-01-05 05:15:21 +08:00
										 |  |  | 		return svr.sendPacket(statusFromError(p.ID, err)) | 
					
						
							| 
									
										
										
										
											2015-07-31 00:21:59 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-12-31 01:56:52 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return svr.sendPacket(sshFxpStatResponse{ | 
					
						
							| 
									
										
										
										
											2016-01-05 05:15:21 +08:00
										 |  |  | 		ID:   p.ID, | 
					
						
							| 
									
										
										
										
											2015-12-31 01:56:52 +08:00
										 |  |  | 		info: info, | 
					
						
							|  |  |  | 	}) | 
					
						
							| 
									
										
										
										
											2015-07-31 00:21:59 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-06 03:57:28 +08:00
										 |  |  | func (p sshFxpStatPacket) respond(svr *Server) error { | 
					
						
							|  |  |  | 	// stat the requested file
 | 
					
						
							| 
									
										
										
										
											2015-12-31 01:56:52 +08:00
										 |  |  | 	info, err := os.Stat(p.Path) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2016-01-05 05:15:21 +08:00
										 |  |  | 		return svr.sendPacket(statusFromError(p.ID, err)) | 
					
						
							| 
									
										
										
										
											2015-08-06 03:57:28 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-12-31 01:56:52 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return svr.sendPacket(sshFxpStatResponse{ | 
					
						
							| 
									
										
										
										
											2016-01-05 05:15:21 +08:00
										 |  |  | 		ID:   p.ID, | 
					
						
							| 
									
										
										
										
											2015-12-31 01:56:52 +08:00
										 |  |  | 		info: info, | 
					
						
							|  |  |  | 	}) | 
					
						
							| 
									
										
										
										
											2015-08-06 03:57:28 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-31 00:21:59 +08:00
										 |  |  | func (p sshFxpFstatPacket) respond(svr *Server) error { | 
					
						
							| 
									
										
										
										
											2015-12-31 01:56:52 +08:00
										 |  |  | 	f, ok := svr.getHandle(p.Handle) | 
					
						
							|  |  |  | 	if !ok { | 
					
						
							| 
									
										
										
										
											2016-01-05 05:15:21 +08:00
										 |  |  | 		return svr.sendPacket(statusFromError(p.ID, syscall.EBADF)) | 
					
						
							| 
									
										
										
										
											2015-12-31 01:56:52 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	info, err := f.Stat() | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2016-01-05 05:15:21 +08:00
										 |  |  | 		return svr.sendPacket(statusFromError(p.ID, err)) | 
					
						
							| 
									
										
										
										
											2015-07-25 16:19:29 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-12-31 01:56:52 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return svr.sendPacket(sshFxpStatResponse{ | 
					
						
							| 
									
										
										
										
											2016-01-05 05:15:21 +08:00
										 |  |  | 		ID:   p.ID, | 
					
						
							| 
									
										
										
										
											2015-12-31 01:56:52 +08:00
										 |  |  | 		info: info, | 
					
						
							|  |  |  | 	}) | 
					
						
							| 
									
										
										
										
											2015-07-25 16:19:29 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-26 10:07:33 +08:00
										 |  |  | func (p sshFxpMkdirPacket) respond(svr *Server) error { | 
					
						
							| 
									
										
										
										
											2015-08-01 06:46:13 +08:00
										 |  |  | 	// TODO FIXME: ignore flags field
 | 
					
						
							| 
									
										
										
										
											2015-09-07 10:36:47 +08:00
										 |  |  | 	err := os.Mkdir(p.Path, 0755) | 
					
						
							| 
									
										
										
										
											2016-01-05 05:15:21 +08:00
										 |  |  | 	return svr.sendPacket(statusFromError(p.ID, err)) | 
					
						
							| 
									
										
										
										
											2015-08-01 06:46:13 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-07 16:05:16 +08:00
										 |  |  | func (p sshFxpRmdirPacket) respond(svr *Server) error { | 
					
						
							|  |  |  | 	err := os.Remove(p.Path) | 
					
						
							| 
									
										
										
										
											2016-01-05 05:15:21 +08:00
										 |  |  | 	return svr.sendPacket(statusFromError(p.ID, err)) | 
					
						
							| 
									
										
										
										
											2015-09-07 16:05:16 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-01 06:46:13 +08:00
										 |  |  | func (p sshFxpRemovePacket) respond(svr *Server) error { | 
					
						
							| 
									
										
										
										
											2015-09-07 10:36:47 +08:00
										 |  |  | 	err := os.Remove(p.Filename) | 
					
						
							| 
									
										
										
										
											2016-01-05 05:15:21 +08:00
										 |  |  | 	return svr.sendPacket(statusFromError(p.ID, err)) | 
					
						
							| 
									
										
										
										
											2015-07-26 10:07:33 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-01 06:46:13 +08:00
										 |  |  | func (p sshFxpRenamePacket) respond(svr *Server) error { | 
					
						
							| 
									
										
										
										
											2015-09-07 10:36:47 +08:00
										 |  |  | 	err := os.Rename(p.Oldpath, p.Newpath) | 
					
						
							| 
									
										
										
										
											2016-01-05 05:15:21 +08:00
										 |  |  | 	return svr.sendPacket(statusFromError(p.ID, err)) | 
					
						
							| 
									
										
										
										
											2015-08-01 06:46:13 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-07 16:05:16 +08:00
										 |  |  | func (p sshFxpSymlinkPacket) respond(svr *Server) error { | 
					
						
							|  |  |  | 	err := os.Symlink(p.Targetpath, p.Linkpath) | 
					
						
							| 
									
										
										
										
											2016-01-05 05:15:21 +08:00
										 |  |  | 	return svr.sendPacket(statusFromError(p.ID, err)) | 
					
						
							| 
									
										
										
										
											2015-09-07 16:05:16 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-06 03:57:28 +08:00
										 |  |  | var emptyFileStat = []interface{}{uint32(0)} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-01 06:46:13 +08:00
										 |  |  | func (p sshFxpReadlinkPacket) respond(svr *Server) error { | 
					
						
							| 
									
										
										
										
											2015-12-31 01:56:52 +08:00
										 |  |  | 	f, err := os.Readlink(p.Path) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2016-01-05 05:15:21 +08:00
										 |  |  | 		return svr.sendPacket(statusFromError(p.ID, err)) | 
					
						
							| 
									
										
										
										
											2015-08-06 03:57:28 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-12-31 01:56:52 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return svr.sendPacket(sshFxpNamePacket{ | 
					
						
							| 
									
										
										
										
											2016-01-05 05:15:21 +08:00
										 |  |  | 		ID: p.ID, | 
					
						
							| 
									
										
										
										
											2015-12-31 01:56:52 +08:00
										 |  |  | 		NameAttrs: []sshFxpNameAttr{{ | 
					
						
							|  |  |  | 			Name:     f, | 
					
						
							|  |  |  | 			LongName: f, | 
					
						
							|  |  |  | 			Attrs:    emptyFileStat, | 
					
						
							|  |  |  | 		}}, | 
					
						
							|  |  |  | 	}) | 
					
						
							| 
									
										
										
										
											2015-08-06 03:57:28 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (p sshFxpRealpathPacket) respond(svr *Server) error { | 
					
						
							| 
									
										
										
										
											2015-12-31 01:56:52 +08:00
										 |  |  | 	f, err := filepath.Abs(p.Path) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2016-01-05 05:15:21 +08:00
										 |  |  | 		return svr.sendPacket(statusFromError(p.ID, err)) | 
					
						
							| 
									
										
										
										
											2015-08-01 06:46:13 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-12-31 01:56:52 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	f = filepath.Clean(f) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return svr.sendPacket(sshFxpNamePacket{ | 
					
						
							| 
									
										
										
										
											2016-01-05 05:15:21 +08:00
										 |  |  | 		ID: p.ID, | 
					
						
							| 
									
										
										
										
											2015-12-31 01:56:52 +08:00
										 |  |  | 		NameAttrs: []sshFxpNameAttr{{ | 
					
						
							|  |  |  | 			Name:     f, | 
					
						
							|  |  |  | 			LongName: f, | 
					
						
							|  |  |  | 			Attrs:    emptyFileStat, | 
					
						
							|  |  |  | 		}}, | 
					
						
							|  |  |  | 	}) | 
					
						
							| 
									
										
										
										
											2015-08-01 06:46:13 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (p sshFxpOpendirPacket) respond(svr *Server) error { | 
					
						
							| 
									
										
										
										
											2015-12-31 01:56:52 +08:00
										 |  |  | 	return sshFxpOpenPacket{ | 
					
						
							| 
									
										
										
										
											2016-01-05 05:15:21 +08:00
										 |  |  | 		ID:     p.ID, | 
					
						
							| 
									
										
										
										
											2015-12-31 01:56:52 +08:00
										 |  |  | 		Path:   p.Path, | 
					
						
							|  |  |  | 		Pflags: ssh_FXF_READ, | 
					
						
							|  |  |  | 	}.respond(svr) | 
					
						
							| 
									
										
										
										
											2015-08-01 06:46:13 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-08 06:27:37 +08:00
										 |  |  | func (p sshFxpOpenPacket) readonly() bool { | 
					
						
							|  |  |  | 	return !p.hasPflags(ssh_FXF_WRITE) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (p sshFxpOpenPacket) hasPflags(flags ...uint32) bool { | 
					
						
							|  |  |  | 	for _, f := range flags { | 
					
						
							|  |  |  | 		if p.Pflags&f == 0 { | 
					
						
							|  |  |  | 			return false | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return true | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-26 16:32:19 +08:00
										 |  |  | func (p sshFxpOpenPacket) respond(svr *Server) error { | 
					
						
							| 
									
										
										
										
											2015-12-31 01:56:52 +08:00
										 |  |  | 	var osFlags int | 
					
						
							| 
									
										
										
										
											2016-01-08 06:27:37 +08:00
										 |  |  | 	if p.hasPflags(ssh_FXF_READ, ssh_FXF_WRITE) { | 
					
						
							| 
									
										
										
										
											2015-07-26 16:32:19 +08:00
										 |  |  | 		osFlags |= os.O_RDWR | 
					
						
							| 
									
										
										
										
											2016-01-08 06:27:37 +08:00
										 |  |  | 	} else if p.hasPflags(ssh_FXF_WRITE) { | 
					
						
							| 
									
										
										
										
											2015-07-26 16:32:19 +08:00
										 |  |  | 		osFlags |= os.O_WRONLY | 
					
						
							| 
									
										
										
										
											2016-01-08 06:27:37 +08:00
										 |  |  | 	} else if p.hasPflags(ssh_FXF_READ) { | 
					
						
							| 
									
										
										
										
											2015-07-31 14:43:00 +08:00
										 |  |  | 		osFlags |= os.O_RDONLY | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		// how are they opening?
 | 
					
						
							| 
									
										
										
										
											2016-01-05 05:15:21 +08:00
										 |  |  | 		return svr.sendPacket(statusFromError(p.ID, syscall.EINVAL)) | 
					
						
							| 
									
										
										
										
											2015-07-26 16:32:19 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-07-31 14:43:00 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-08 06:27:37 +08:00
										 |  |  | 	if p.hasPflags(ssh_FXF_APPEND) { | 
					
						
							| 
									
										
										
										
											2015-07-26 16:32:19 +08:00
										 |  |  | 		osFlags |= os.O_APPEND | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-01-08 06:27:37 +08:00
										 |  |  | 	if p.hasPflags(ssh_FXF_CREAT) { | 
					
						
							| 
									
										
										
										
											2015-07-26 16:32:19 +08:00
										 |  |  | 		osFlags |= os.O_CREATE | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-01-08 06:27:37 +08:00
										 |  |  | 	if p.hasPflags(ssh_FXF_TRUNC) { | 
					
						
							| 
									
										
										
										
											2015-07-26 16:32:19 +08:00
										 |  |  | 		osFlags |= os.O_TRUNC | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-01-08 06:27:37 +08:00
										 |  |  | 	if p.hasPflags(ssh_FXF_EXCL) { | 
					
						
							| 
									
										
										
										
											2015-07-26 16:32:19 +08:00
										 |  |  | 		osFlags |= os.O_EXCL | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 01:56:52 +08:00
										 |  |  | 	f, err := os.OpenFile(p.Path, osFlags, 0644) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2016-01-05 05:15:21 +08:00
										 |  |  | 		return svr.sendPacket(statusFromError(p.ID, err)) | 
					
						
							| 
									
										
										
										
											2015-07-26 16:32:19 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-12-31 01:56:52 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	handle := svr.nextHandle(f) | 
					
						
							| 
									
										
										
										
											2016-01-05 05:15:21 +08:00
										 |  |  | 	return svr.sendPacket(sshFxpHandlePacket{p.ID, handle}) | 
					
						
							| 
									
										
										
										
											2015-07-25 16:19:29 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-26 16:32:19 +08:00
										 |  |  | func (p sshFxpClosePacket) respond(svr *Server) error { | 
					
						
							| 
									
										
										
										
											2016-01-05 05:15:21 +08:00
										 |  |  | 	return svr.sendPacket(statusFromError(p.ID, svr.closeHandle(p.Handle))) | 
					
						
							| 
									
										
										
										
											2015-07-25 16:19:29 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-30 08:24:24 +08:00
										 |  |  | func (p sshFxpReadPacket) respond(svr *Server) error { | 
					
						
							| 
									
										
										
										
											2015-12-31 01:56:52 +08:00
										 |  |  | 	f, ok := svr.getHandle(p.Handle) | 
					
						
							|  |  |  | 	if !ok { | 
					
						
							| 
									
										
										
										
											2016-01-05 05:15:21 +08:00
										 |  |  | 		return svr.sendPacket(statusFromError(p.ID, syscall.EBADF)) | 
					
						
							| 
									
										
										
										
											2015-07-30 08:37:58 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-12-31 01:56:52 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if p.Len > svr.maxTxPacket { | 
					
						
							|  |  |  | 		p.Len = svr.maxTxPacket | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	ret := sshFxpDataPacket{ | 
					
						
							| 
									
										
										
										
											2016-01-05 05:15:21 +08:00
										 |  |  | 		ID:     p.ID, | 
					
						
							| 
									
										
										
										
											2015-12-31 01:56:52 +08:00
										 |  |  | 		Length: p.Len, | 
					
						
							|  |  |  | 		Data:   make([]byte, p.Len), | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	n, err := f.ReadAt(ret.Data, int64(p.Offset)) | 
					
						
							|  |  |  | 	if err != nil && (err != io.EOF || n == 0) { | 
					
						
							| 
									
										
										
										
											2016-01-05 05:15:21 +08:00
										 |  |  | 		return svr.sendPacket(statusFromError(p.ID, err)) | 
					
						
							| 
									
										
										
										
											2015-12-31 01:56:52 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ret.Length = uint32(n) | 
					
						
							|  |  |  | 	return svr.sendPacket(ret) | 
					
						
							| 
									
										
										
										
											2015-07-30 08:37:58 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-08 06:27:37 +08:00
										 |  |  | func (p sshFxpWritePacket) respond(svr *Server) error { | 
					
						
							| 
									
										
										
										
											2015-12-31 01:56:52 +08:00
										 |  |  | 	f, ok := svr.getHandle(p.Handle) | 
					
						
							|  |  |  | 	if !ok { | 
					
						
							| 
									
										
										
										
											2016-01-05 05:15:21 +08:00
										 |  |  | 		return svr.sendPacket(statusFromError(p.ID, syscall.EBADF)) | 
					
						
							| 
									
										
										
										
											2015-07-30 08:24:24 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-12-31 01:56:52 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	_, err := f.WriteAt(p.Data, int64(p.Offset)) | 
					
						
							| 
									
										
										
										
											2016-01-05 05:15:21 +08:00
										 |  |  | 	return svr.sendPacket(statusFromError(p.ID, err)) | 
					
						
							| 
									
										
										
										
											2015-07-30 08:24:24 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-01 06:46:13 +08:00
										 |  |  | func (p sshFxpReaddirPacket) respond(svr *Server) error { | 
					
						
							| 
									
										
										
										
											2015-12-31 01:56:52 +08:00
										 |  |  | 	f, ok := svr.getHandle(p.Handle) | 
					
						
							|  |  |  | 	if !ok { | 
					
						
							| 
									
										
										
										
											2016-01-05 05:15:21 +08:00
										 |  |  | 		return svr.sendPacket(statusFromError(p.ID, syscall.EBADF)) | 
					
						
							| 
									
										
										
										
											2015-12-31 01:56:52 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-08-01 06:46:13 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 01:56:52 +08:00
										 |  |  | 	dirname := f.Name() | 
					
						
							|  |  |  | 	dirents, err := f.Readdir(128) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2016-01-05 05:15:21 +08:00
										 |  |  | 		return svr.sendPacket(statusFromError(p.ID, err)) | 
					
						
							| 
									
										
										
										
											2015-12-31 01:56:52 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-08-01 06:46:13 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-05 05:15:21 +08:00
										 |  |  | 	ret := sshFxpNamePacket{ID: p.ID} | 
					
						
							| 
									
										
										
										
											2015-12-31 01:56:52 +08:00
										 |  |  | 	for _, dirent := range dirents { | 
					
						
							|  |  |  | 		ret.NameAttrs = append(ret.NameAttrs, sshFxpNameAttr{ | 
					
						
							|  |  |  | 			Name:     dirent.Name(), | 
					
						
							|  |  |  | 			LongName: runLs(dirname, dirent), | 
					
						
							|  |  |  | 			Attrs:    []interface{}{dirent}, | 
					
						
							|  |  |  | 		}) | 
					
						
							| 
									
										
										
										
											2015-08-01 06:46:13 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-12-31 01:56:52 +08:00
										 |  |  | 	return svr.sendPacket(ret) | 
					
						
							| 
									
										
										
										
											2015-08-01 06:46:13 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-08 06:27:37 +08:00
										 |  |  | func (p sshFxpSetstatPacket) respond(svr *Server) error { | 
					
						
							| 
									
										
										
										
											2015-12-31 01:56:52 +08:00
										 |  |  | 	// additional unmarshalling is required for each possibility here
 | 
					
						
							|  |  |  | 	b := p.Attrs.([]byte) | 
					
						
							|  |  |  | 	var err error | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	debug("setstat name \"%s\"", p.Path) | 
					
						
							|  |  |  | 	if (p.Flags & ssh_FILEXFER_ATTR_SIZE) != 0 { | 
					
						
							|  |  |  | 		var size uint64 | 
					
						
							|  |  |  | 		if size, b, err = unmarshalUint64Safe(b); err == nil { | 
					
						
							|  |  |  | 			err = os.Truncate(p.Path, int64(size)) | 
					
						
							| 
									
										
										
										
											2015-09-07 17:13:07 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-12-31 01:56:52 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	if (p.Flags & ssh_FILEXFER_ATTR_PERMISSIONS) != 0 { | 
					
						
							|  |  |  | 		var mode uint32 | 
					
						
							|  |  |  | 		if mode, b, err = unmarshalUint32Safe(b); err == nil { | 
					
						
							|  |  |  | 			err = os.Chmod(p.Path, os.FileMode(mode)) | 
					
						
							| 
									
										
										
										
											2015-09-07 17:13:07 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-12-31 01:56:52 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	if (p.Flags & ssh_FILEXFER_ATTR_ACMODTIME) != 0 { | 
					
						
							|  |  |  | 		var atime uint32 | 
					
						
							|  |  |  | 		var mtime uint32 | 
					
						
							|  |  |  | 		if atime, b, err = unmarshalUint32Safe(b); err != nil { | 
					
						
							|  |  |  | 		} else if mtime, b, err = unmarshalUint32Safe(b); err != nil { | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			atimeT := time.Unix(int64(atime), 0) | 
					
						
							|  |  |  | 			mtimeT := time.Unix(int64(mtime), 0) | 
					
						
							|  |  |  | 			err = os.Chtimes(p.Path, atimeT, mtimeT) | 
					
						
							| 
									
										
										
										
											2015-09-07 17:13:07 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-12-31 01:56:52 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	if (p.Flags & ssh_FILEXFER_ATTR_UIDGID) != 0 { | 
					
						
							|  |  |  | 		var uid uint32 | 
					
						
							|  |  |  | 		var gid uint32 | 
					
						
							|  |  |  | 		if uid, b, err = unmarshalUint32Safe(b); err != nil { | 
					
						
							|  |  |  | 		} else if gid, b, err = unmarshalUint32Safe(b); err != nil { | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			err = os.Chown(p.Path, int(uid), int(gid)) | 
					
						
							| 
									
										
										
										
											2015-09-07 17:13:07 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-12-31 01:56:52 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-05 05:15:21 +08:00
										 |  |  | 	return svr.sendPacket(statusFromError(p.ID, err)) | 
					
						
							| 
									
										
										
										
											2015-09-07 17:13:07 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-08 06:27:37 +08:00
										 |  |  | func (p sshFxpFsetstatPacket) respond(svr *Server) error { | 
					
						
							| 
									
										
										
										
											2015-12-31 01:56:52 +08:00
										 |  |  | 	f, ok := svr.getHandle(p.Handle) | 
					
						
							|  |  |  | 	if !ok { | 
					
						
							| 
									
										
										
										
											2016-01-05 05:15:21 +08:00
										 |  |  | 		return svr.sendPacket(statusFromError(p.ID, syscall.EBADF)) | 
					
						
							| 
									
										
										
										
											2015-12-31 01:56:52 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// additional unmarshalling is required for each possibility here
 | 
					
						
							|  |  |  | 	b := p.Attrs.([]byte) | 
					
						
							|  |  |  | 	var err error | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	debug("fsetstat name \"%s\"", f.Name()) | 
					
						
							|  |  |  | 	if (p.Flags & ssh_FILEXFER_ATTR_SIZE) != 0 { | 
					
						
							|  |  |  | 		var size uint64 | 
					
						
							|  |  |  | 		if size, b, err = unmarshalUint64Safe(b); err == nil { | 
					
						
							|  |  |  | 			err = f.Truncate(int64(size)) | 
					
						
							| 
									
										
										
										
											2015-09-07 17:13:07 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-12-31 01:56:52 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	if (p.Flags & ssh_FILEXFER_ATTR_PERMISSIONS) != 0 { | 
					
						
							|  |  |  | 		var mode uint32 | 
					
						
							|  |  |  | 		if mode, b, err = unmarshalUint32Safe(b); err == nil { | 
					
						
							|  |  |  | 			err = f.Chmod(os.FileMode(mode)) | 
					
						
							| 
									
										
										
										
											2015-09-07 17:13:07 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-12-31 01:56:52 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	if (p.Flags & ssh_FILEXFER_ATTR_ACMODTIME) != 0 { | 
					
						
							|  |  |  | 		var atime uint32 | 
					
						
							|  |  |  | 		var mtime uint32 | 
					
						
							|  |  |  | 		if atime, b, err = unmarshalUint32Safe(b); err != nil { | 
					
						
							|  |  |  | 		} else if mtime, b, err = unmarshalUint32Safe(b); err != nil { | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			atimeT := time.Unix(int64(atime), 0) | 
					
						
							|  |  |  | 			mtimeT := time.Unix(int64(mtime), 0) | 
					
						
							|  |  |  | 			err = os.Chtimes(f.Name(), atimeT, mtimeT) | 
					
						
							| 
									
										
										
										
											2015-09-07 17:13:07 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-12-31 01:56:52 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	if (p.Flags & ssh_FILEXFER_ATTR_UIDGID) != 0 { | 
					
						
							|  |  |  | 		var uid uint32 | 
					
						
							|  |  |  | 		var gid uint32 | 
					
						
							|  |  |  | 		if uid, b, err = unmarshalUint32Safe(b); err != nil { | 
					
						
							|  |  |  | 		} else if gid, b, err = unmarshalUint32Safe(b); err != nil { | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			err = f.Chown(int(uid), int(gid)) | 
					
						
							| 
									
										
										
										
											2015-09-07 17:13:07 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-12-31 01:56:52 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-05 05:15:21 +08:00
										 |  |  | 	return svr.sendPacket(statusFromError(p.ID, err)) | 
					
						
							| 
									
										
										
										
											2015-09-07 17:13:07 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-05 05:15:21 +08:00
										 |  |  | // translateErrno translates a syscall error number to a SFTP error code.
 | 
					
						
							|  |  |  | func translateErrno(errno syscall.Errno) uint32 { | 
					
						
							| 
									
										
										
										
											2015-12-31 01:56:52 +08:00
										 |  |  | 	switch errno { | 
					
						
							|  |  |  | 	case 0: | 
					
						
							| 
									
										
										
										
											2015-07-31 14:43:00 +08:00
										 |  |  | 		return ssh_FX_OK | 
					
						
							| 
									
										
										
										
											2015-12-31 01:56:52 +08:00
										 |  |  | 	case syscall.ENOENT: | 
					
						
							| 
									
										
										
										
											2015-07-31 14:43:00 +08:00
										 |  |  | 		return ssh_FX_NO_SUCH_FILE | 
					
						
							| 
									
										
										
										
											2015-12-31 01:56:52 +08:00
										 |  |  | 	case syscall.EPERM: | 
					
						
							| 
									
										
										
										
											2015-07-31 14:43:00 +08:00
										 |  |  | 		return ssh_FX_PERMISSION_DENIED | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 01:56:52 +08:00
										 |  |  | 	return ssh_FX_FAILURE | 
					
						
							| 
									
										
										
										
											2015-07-31 14:43:00 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-25 16:19:29 +08:00
										 |  |  | func statusFromError(id uint32, err error) sshFxpStatusPacket { | 
					
						
							|  |  |  | 	ret := sshFxpStatusPacket{ | 
					
						
							| 
									
										
										
										
											2016-01-05 05:15:21 +08:00
										 |  |  | 		ID: id, | 
					
						
							| 
									
										
										
										
											2015-07-25 16:19:29 +08:00
										 |  |  | 		StatusError: StatusError{ | 
					
						
							|  |  |  | 			// ssh_FX_OK                = 0
 | 
					
						
							|  |  |  | 			// ssh_FX_EOF               = 1
 | 
					
						
							|  |  |  | 			// ssh_FX_NO_SUCH_FILE      = 2 ENOENT
 | 
					
						
							|  |  |  | 			// ssh_FX_PERMISSION_DENIED = 3
 | 
					
						
							|  |  |  | 			// ssh_FX_FAILURE           = 4
 | 
					
						
							|  |  |  | 			// ssh_FX_BAD_MESSAGE       = 5
 | 
					
						
							|  |  |  | 			// ssh_FX_NO_CONNECTION     = 6
 | 
					
						
							|  |  |  | 			// ssh_FX_CONNECTION_LOST   = 7
 | 
					
						
							|  |  |  | 			// ssh_FX_OP_UNSUPPORTED    = 8
 | 
					
						
							| 
									
										
										
										
											2015-07-26 10:07:33 +08:00
										 |  |  | 			Code: ssh_FX_OK, | 
					
						
							| 
									
										
										
										
											2015-07-25 16:19:29 +08:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-07-26 10:07:33 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		debug("statusFromError: error is %T %#v", err, err) | 
					
						
							|  |  |  | 		ret.StatusError.Code = ssh_FX_FAILURE | 
					
						
							|  |  |  | 		ret.StatusError.msg = err.Error() | 
					
						
							|  |  |  | 		if err == io.EOF { | 
					
						
							|  |  |  | 			ret.StatusError.Code = ssh_FX_EOF | 
					
						
							| 
									
										
										
										
											2015-07-31 14:43:00 +08:00
										 |  |  | 		} else if errno, ok := err.(syscall.Errno); ok { | 
					
						
							| 
									
										
										
										
											2016-01-05 05:15:21 +08:00
										 |  |  | 			ret.StatusError.Code = translateErrno(errno) | 
					
						
							| 
									
										
										
										
											2015-07-31 14:43:00 +08:00
										 |  |  | 		} else if pathError, ok := err.(*os.PathError); ok { | 
					
						
							| 
									
										
										
										
											2015-07-26 10:07:33 +08:00
										 |  |  | 			debug("statusFromError: error is %T %#v", pathError.Err, pathError.Err) | 
					
						
							|  |  |  | 			if errno, ok := pathError.Err.(syscall.Errno); ok { | 
					
						
							| 
									
										
										
										
											2016-01-05 05:15:21 +08:00
										 |  |  | 				ret.StatusError.Code = translateErrno(errno) | 
					
						
							| 
									
										
										
										
											2015-07-25 16:19:29 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return ret | 
					
						
							|  |  |  | } |