vendor: update to latest versions of everything

This commit is contained in:
Nick Craig-Wood 2018-09-21 11:01:55 +01:00
parent 4415aa5c2e
commit 467fe30a5e
276 changed files with 38996 additions and 14449 deletions

View file

@ -4,8 +4,8 @@ go_import_path: github.com/pkg/sftp
# current and previous stable releases, plus tip
# remember to exclude previous and tip for macs below
go:
- 1.9.x
- 1.10.x
- 1.11.x
- tip
os:
@ -15,7 +15,7 @@ os:
matrix:
exclude:
- os: osx
go: 1.9.x
go: 1.10.x
- os: osx
go: tip

View file

@ -1,4 +1,4 @@
// +build darwin dragonfly freebsd !android,linux netbsd openbsd solaris
// +build darwin dragonfly freebsd !android,linux netbsd openbsd solaris aix
// +build cgo
package sftp

View file

@ -7,30 +7,30 @@ import (
)
// The goal of the packetManager is to keep the outgoing packets in the same
// order as the incoming. This is due to some sftp clients requiring this
// behavior (eg. winscp).
// order as the incoming as is requires by section 7 of the RFC.
type packetManager struct {
requests chan orderedPacket
responses chan orderedPacket
fini chan struct{}
incoming orderedPackets
outgoing orderedPackets
sender packetSender // connection object
working *sync.WaitGroup
packetCount uint32
}
type packetSender interface {
sendPacket(encoding.BinaryMarshaler) error
}
type packetManager struct {
requests chan requestPacket
responses chan responsePacket
fini chan struct{}
incoming requestPacketIDs
outgoing responsePackets
sender packetSender // connection object
working *sync.WaitGroup
}
func newPktMgr(sender packetSender) *packetManager {
s := &packetManager{
requests: make(chan requestPacket, SftpServerWorkerCount),
responses: make(chan responsePacket, SftpServerWorkerCount),
requests: make(chan orderedPacket, SftpServerWorkerCount),
responses: make(chan orderedPacket, SftpServerWorkerCount),
fini: make(chan struct{}),
incoming: make([]uint32, 0, SftpServerWorkerCount),
outgoing: make([]responsePacket, 0, SftpServerWorkerCount),
incoming: make([]orderedPacket, 0, SftpServerWorkerCount),
outgoing: make([]orderedPacket, 0, SftpServerWorkerCount),
sender: sender,
working: &sync.WaitGroup{},
}
@ -38,31 +38,56 @@ func newPktMgr(sender packetSender) *packetManager {
return s
}
type responsePackets []responsePacket
//// packet ordering
func (s *packetManager) newOrderId() uint32 {
s.packetCount++
return s.packetCount
}
func (r responsePackets) Sort() {
sort.Slice(r, func(i, j int) bool {
return r[i].id() < r[j].id()
})
}
type requestPacketIDs []uint32
func (r requestPacketIDs) Sort() {
sort.Slice(r, func(i, j int) bool {
return r[i] < r[j]
type orderedRequest struct {
requestPacket
orderid uint32
}
func (s *packetManager) newOrderedRequest(p requestPacket) orderedRequest {
return orderedRequest{requestPacket: p, orderid: s.newOrderId()}
}
func (p orderedRequest) orderId() uint32 { return p.orderid }
func (p orderedRequest) setOrderId(oid uint32) { p.orderid = oid }
type orderedResponse struct {
responsePacket
orderid uint32
}
func (s *packetManager) newOrderedResponse(p responsePacket, id uint32,
) orderedResponse {
return orderedResponse{responsePacket: p, orderid: id}
}
func (p orderedResponse) orderId() uint32 { return p.orderid }
func (p orderedResponse) setOrderId(oid uint32) { p.orderid = oid }
type orderedPacket interface {
id() uint32
orderId() uint32
}
type orderedPackets []orderedPacket
func (o orderedPackets) Sort() {
sort.Slice(o, func(i, j int) bool {
return o[i].orderId() < o[j].orderId()
})
}
//// packet registry
// register incoming packets to be handled
// send id of 0 for packets without id
func (s *packetManager) incomingPacket(pkt requestPacket) {
func (s *packetManager) incomingPacket(pkt orderedRequest) {
s.working.Add(1)
s.requests <- pkt // buffer == SftpServerWorkerCount
s.requests <- pkt
}
// register outgoing packets as being ready
func (s *packetManager) readyPacket(pkt responsePacket) {
func (s *packetManager) readyPacket(pkt orderedResponse) {
s.responses <- pkt
s.working.Done()
}
@ -75,38 +100,37 @@ func (s *packetManager) close() {
}
// Passed a worker function, returns a channel for incoming packets.
// The goal is to process packets in the order they are received as is
// requires by section 7 of the RFC, while maximizing throughput of file
// transfers.
func (s *packetManager) workerChan(runWorker func(requestChan)) requestChan {
// Keep process packet responses in the order they are received while
// maximizing throughput of file transfers.
func (s *packetManager) workerChan(runWorker func(chan orderedRequest),
) chan orderedRequest {
rwChan := make(chan requestPacket, SftpServerWorkerCount)
// multiple workers for faster read/writes
rwChan := make(chan orderedRequest, SftpServerWorkerCount)
for i := 0; i < SftpServerWorkerCount; i++ {
runWorker(rwChan)
}
cmdChan := make(chan requestPacket)
// single worker to enforce sequential processing of everything else
cmdChan := make(chan orderedRequest)
runWorker(cmdChan)
pktChan := make(chan requestPacket, SftpServerWorkerCount)
pktChan := make(chan orderedRequest, SftpServerWorkerCount)
go func() {
// start with cmdChan
curChan := cmdChan
for pkt := range pktChan {
// on file open packet, switch to rwChan
switch pkt.(type) {
case *sshFxpOpenPacket:
curChan = rwChan
// on file close packet, switch back to cmdChan
// after waiting for any reads/writes to finish
switch pkt.requestPacket.(type) {
case *sshFxpReadPacket, *sshFxpWritePacket:
s.incomingPacket(pkt)
rwChan <- pkt
continue
case *sshFxpClosePacket:
// wait for rwChan to finish
// wait for reads/writes to finish when file is closed
// incomingPacket() call must occur after this
s.working.Wait()
// stop using rwChan
curChan = cmdChan
}
s.incomingPacket(pkt)
curChan <- pkt
// all non-RW use sequential cmdChan
cmdChan <- pkt
}
close(rwChan)
close(cmdChan)
@ -121,17 +145,13 @@ func (s *packetManager) controller() {
for {
select {
case pkt := <-s.requests:
debug("incoming id: %v", pkt.id())
s.incoming = append(s.incoming, pkt.id())
if len(s.incoming) > 1 {
s.incoming.Sort()
}
debug("incoming id (oid): %v (%v)", pkt.id(), pkt.orderId())
s.incoming = append(s.incoming, pkt)
s.incoming.Sort()
case pkt := <-s.responses:
debug("outgoing pkt: %v", pkt.id())
debug("outgoing id (oid): %v (%v)", pkt.id(), pkt.orderId())
s.outgoing = append(s.outgoing, pkt)
if len(s.outgoing) > 1 {
s.outgoing.Sort()
}
s.outgoing.Sort()
case <-s.fini:
return
}
@ -149,10 +169,11 @@ func (s *packetManager) maybeSendPackets() {
}
out := s.outgoing[0]
in := s.incoming[0]
// debug("incoming: %v", s.incoming)
// debug("outgoing: %v", outfilter(s.outgoing))
if in == out.id() {
s.sender.sendPacket(out)
// debug("incoming: %v", ids(s.incoming))
// debug("outgoing: %v", ids(s.outgoing))
if in.orderId() == out.orderId() {
debug("Sending packet: %v", out.id())
s.sender.sendPacket(out.(encoding.BinaryMarshaler))
// pop off heads
copy(s.incoming, s.incoming[1:]) // shift left
s.incoming = s.incoming[:len(s.incoming)-1] // remove last
@ -164,10 +185,17 @@ func (s *packetManager) maybeSendPackets() {
}
}
//func outfilter(o []responsePacket) []uint32 {
// res := make([]uint32, 0, len(o))
// for _, v := range o {
// res = append(res, v.id())
// }
// return res
//}
// func oids(o []orderedPacket) []uint32 {
// res := make([]uint32, 0, len(o))
// for _, v := range o {
// res = append(res, v.orderId())
// }
// return res
// }
// func ids(o []orderedPacket) []uint32 {
// res := make([]uint32, 0, len(o))
// for _, v := range o {
// res = append(res, v.id())
// }
// return res
// }

View file

@ -12,8 +12,6 @@ type requestPacket interface {
id() uint32
}
type requestChan chan requestPacket
type responsePacket interface {
encoding.BinaryMarshaler
id() uint32
@ -77,6 +75,7 @@ func (p sshFxpStatusPacket) id() uint32 { return p.ID }
func (p sshFxpStatResponse) id() uint32 { return p.ID }
func (p sshFxpNamePacket) id() uint32 { return p.ID }
func (p sshFxpHandlePacket) id() uint32 { return p.ID }
func (p StatVFS) id() uint32 { return p.ID }
func (p sshFxVersionPacket) id() uint32 { return 0 }
// take raw incoming packet data and build packet objects

23
vendor/github.com/pkg/sftp/packet.go generated vendored
View file

@ -125,15 +125,14 @@ func sendPacket(w io.Writer, m encoding.BinaryMarshaler) error {
} else if debugDumpTxPacket {
debug("send packet: %s %d bytes", fxp(bb[0]), len(bb))
}
l := uint32(len(bb))
hdr := []byte{byte(l >> 24), byte(l >> 16), byte(l >> 8), byte(l)}
_, err = w.Write(hdr)
// Slide packet down 4 bytes to make room for length header.
packet := append(bb, make([]byte, 4)...) // optimistically assume bb has capacity
copy(packet[4:], bb)
binary.BigEndian.PutUint32(packet[:4], uint32(len(bb)))
_, err = w.Write(packet)
if err != nil {
return errors.Errorf("failed to send packet header: %v", err)
}
_, err = w.Write(bb)
if err != nil {
return errors.Errorf("failed to send packet body: %v", err)
return errors.Errorf("failed to send packet: %v", err)
}
return nil
}
@ -882,9 +881,9 @@ func (p sshFxpExtendedPacket) readonly() bool {
return p.SpecificPacket.readonly()
}
func (p sshFxpExtendedPacket) respond(svr *Server) error {
func (p sshFxpExtendedPacket) respond(svr *Server) responsePacket {
if p.SpecificPacket == nil {
return nil
return statusFromError(p, nil)
}
return p.SpecificPacket.respond(svr)
}
@ -954,7 +953,7 @@ func (p *sshFxpExtendedPacketPosixRename) UnmarshalBinary(b []byte) error {
return nil
}
func (p sshFxpExtendedPacketPosixRename) respond(s *Server) error {
func (p sshFxpExtendedPacketPosixRename) respond(s *Server) responsePacket {
err := os.Rename(p.Oldpath, p.Newpath)
return s.sendError(p, err)
return statusFromError(p, err)
}

View file

@ -83,6 +83,7 @@ func (fs *root) Filecmd(r *Request) error {
return &os.LinkError{Op: "rename", Old: r.Filepath, New: r.Target,
Err: fmt.Errorf("dest file exists")}
}
file.name = r.Target
fs.files[r.Target] = file
delete(fs.files, r.Filepath)
case "Rmdir", "Remove":

View file

@ -2,7 +2,6 @@ package sftp
import (
"context"
"encoding"
"io"
"os"
"path"
@ -106,7 +105,7 @@ func (rs *RequestServer) Serve() error {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
var wg sync.WaitGroup
runWorker := func(ch requestChan) {
runWorker := func(ch chan orderedRequest) {
wg.Add(1)
go func() {
defer wg.Done()
@ -143,7 +142,7 @@ func (rs *RequestServer) Serve() error {
}
}
pktChan <- pkt
pktChan <- rs.pktMgr.newOrderedRequest(pkt)
}
close(pktChan) // shuts down sftpServerWorkers
@ -160,13 +159,13 @@ func (rs *RequestServer) Serve() error {
}
func (rs *RequestServer) packetWorker(
ctx context.Context, pktChan chan requestPacket,
ctx context.Context, pktChan chan orderedRequest,
) error {
for pkt := range pktChan {
var rpkt responsePacket
switch pkt := pkt.(type) {
switch pkt := pkt.requestPacket.(type) {
case *sshFxInitPacket:
rpkt = sshFxVersionPacket{sftpProtocolVersion, nil}
rpkt = sshFxVersionPacket{Version: sftpProtocolVersion}
case *sshFxpClosePacket:
handle := pkt.getHandle()
rpkt = statusFromError(pkt, rs.closeRequest(handle))
@ -178,7 +177,7 @@ func (rs *RequestServer) packetWorker(
if stat, ok := rpkt.(*sshFxpStatResponse); ok {
if stat.info.IsDir() {
handle := rs.nextRequest(request)
rpkt = sshFxpHandlePacket{pkt.id(), handle}
rpkt = sshFxpHandlePacket{ID: pkt.id(), Handle: handle}
} else {
rpkt = statusFromError(pkt, &os.PathError{
Path: request.Filepath, Err: syscall.ENOTDIR})
@ -187,7 +186,7 @@ func (rs *RequestServer) packetWorker(
case *sshFxpOpenPacket:
request := requestFromPacket(ctx, pkt)
handle := rs.nextRequest(request)
rpkt = sshFxpHandlePacket{pkt.id(), handle}
rpkt = sshFxpHandlePacket{ID: pkt.id(), Handle: handle}
if pkt.hasPflags(ssh_FXF_CREAT) {
if p := request.call(rs.Handlers, pkt); !statusOk(p) {
rpkt = p // if error in write, return it
@ -209,10 +208,8 @@ func (rs *RequestServer) packetWorker(
return errors.Errorf("unexpected packet type %T", pkt)
}
err := rs.sendPacket(rpkt)
if err != nil {
return err
}
rs.pktMgr.readyPacket(
rs.pktMgr.newOrderedResponse(rpkt, pkt.orderId()))
}
return nil
}
@ -244,13 +241,3 @@ func cleanPath(p string) string {
}
return path.Clean(p)
}
// Wrap underlying connection methods to use packetManager
func (rs *RequestServer) sendPacket(m encoding.BinaryMarshaler) error {
if pkt, ok := m.(responsePacket); ok {
rs.pktMgr.readyPacket(pkt)
} else {
return errors.Errorf("unexpected packet type %T", m)
}
return nil
}

View file

@ -116,34 +116,12 @@ func (r *Request) lsInc(offset int64) {
}
// manage file read/write state
func (r *Request) setWriterState(wa io.WriterAt) {
r.state.Lock()
defer r.state.Unlock()
r.state.writerAt = wa
}
func (r *Request) setReaderState(ra io.ReaderAt) {
r.state.Lock()
defer r.state.Unlock()
r.state.readerAt = ra
}
func (r *Request) setListerState(la ListerAt) {
r.state.Lock()
defer r.state.Unlock()
r.state.listerAt = la
}
func (r *Request) getWriter() io.WriterAt {
r.state.RLock()
defer r.state.RUnlock()
return r.state.writerAt
}
func (r *Request) getReader() io.ReaderAt {
r.state.RLock()
defer r.state.RUnlock()
return r.state.readerAt
}
func (r *Request) getLister() ListerAt {
r.state.RLock()
defer r.state.RUnlock()
@ -157,11 +135,15 @@ func (r *Request) close() error {
r.cancelCtx()
}
}()
rd := r.getReader()
r.state.RLock()
rd := r.state.readerAt
r.state.RUnlock()
if c, ok := rd.(io.Closer); ok {
return c.Close()
}
wt := r.getWriter()
r.state.RLock()
wt := r.state.writerAt
r.state.RUnlock()
if c, ok := wt.(io.Closer); ok {
return c.Close()
}
@ -204,13 +186,20 @@ func packetData(p requestPacket) (data []byte, offset int64, length uint32) {
// wrap FileReader handler
func fileget(h FileReader, r *Request, pkt requestPacket) responsePacket {
var err error
reader := r.getReader()
r.state.RLock()
reader := r.state.readerAt
r.state.RUnlock()
if reader == nil {
reader, err = h.Fileread(r)
if err != nil {
return statusFromError(pkt, err)
r.state.Lock()
if r.state.readerAt == nil {
r.state.readerAt, err = h.Fileread(r)
if err != nil {
r.state.Unlock()
return statusFromError(pkt, err)
}
}
r.setReaderState(reader)
reader = r.state.readerAt
r.state.Unlock()
}
_, offset, length := packetData(pkt)
@ -230,13 +219,20 @@ func fileget(h FileReader, r *Request, pkt requestPacket) responsePacket {
// wrap FileWriter handler
func fileput(h FileWriter, r *Request, pkt requestPacket) responsePacket {
var err error
writer := r.getWriter()
r.state.RLock()
writer := r.state.writerAt
r.state.RUnlock()
if writer == nil {
writer, err = h.Filewrite(r)
if err != nil {
return statusFromError(pkt, err)
r.state.Lock()
if r.state.writerAt == nil {
r.state.writerAt, err = h.Filewrite(r)
if err != nil {
r.state.Unlock()
return statusFromError(pkt, err)
}
}
r.setWriterState(writer)
writer = r.state.writerAt
r.state.Unlock()
}
data, offset, _ := packetData(pkt)

195
vendor/github.com/pkg/sftp/server.go generated vendored
View file

@ -66,7 +66,7 @@ func (svr *Server) getHandle(handle string) (*os.File, bool) {
type serverRespondablePacket interface {
encoding.BinaryUnmarshaler
id() uint32
respond(svr *Server) error
respond(svr *Server) responsePacket
}
// NewServer creates a new Server instance around the provided streams, serving
@ -123,12 +123,11 @@ type rxPacket struct {
}
// Up to N parallel servers
func (svr *Server) sftpServerWorker(pktChan chan requestPacket) error {
func (svr *Server) sftpServerWorker(pktChan chan orderedRequest) error {
for pkt := range pktChan {
// readonly checks
readonly := true
switch pkt := pkt.(type) {
switch pkt := pkt.requestPacket.(type) {
case notReadOnly:
readonly = false
case *sshFxpOpenPacket:
@ -140,9 +139,9 @@ func (svr *Server) sftpServerWorker(pktChan chan requestPacket) error {
// If server is operating read-only and a write operation is requested,
// return permission denied
if !readonly && svr.readOnly {
if err := svr.sendError(pkt, syscall.EPERM); err != nil {
return errors.Wrap(err, "failed to send read only packet response")
}
svr.sendPacket(orderedResponse{
responsePacket: statusFromError(pkt, syscall.EPERM),
orderid: pkt.orderId()})
continue
}
@ -153,141 +152,145 @@ func (svr *Server) sftpServerWorker(pktChan chan requestPacket) error {
return nil
}
func handlePacket(s *Server, p interface{}) error {
switch p := p.(type) {
func handlePacket(s *Server, p orderedRequest) error {
var rpkt responsePacket
switch p := p.requestPacket.(type) {
case *sshFxInitPacket:
return s.sendPacket(sshFxVersionPacket{sftpProtocolVersion, nil})
rpkt = sshFxVersionPacket{Version: sftpProtocolVersion}
case *sshFxpStatPacket:
// stat the requested file
info, err := os.Stat(p.Path)
if err != nil {
return s.sendError(p, err)
}
return s.sendPacket(sshFxpStatResponse{
rpkt = sshFxpStatResponse{
ID: p.ID,
info: info,
})
}
if err != nil {
rpkt = statusFromError(p, err)
}
case *sshFxpLstatPacket:
// stat the requested file
info, err := os.Lstat(p.Path)
if err != nil {
return s.sendError(p, err)
}
return s.sendPacket(sshFxpStatResponse{
rpkt = sshFxpStatResponse{
ID: p.ID,
info: info,
})
}
if err != nil {
rpkt = statusFromError(p, err)
}
case *sshFxpFstatPacket:
f, ok := s.getHandle(p.Handle)
if !ok {
return s.sendError(p, syscall.EBADF)
var err error = syscall.EBADF
var info os.FileInfo
if ok {
info, err = f.Stat()
rpkt = sshFxpStatResponse{
ID: p.ID,
info: info,
}
}
info, err := f.Stat()
if err != nil {
return s.sendError(p, err)
rpkt = statusFromError(p, err)
}
return s.sendPacket(sshFxpStatResponse{
ID: p.ID,
info: info,
})
case *sshFxpMkdirPacket:
// TODO FIXME: ignore flags field
err := os.Mkdir(p.Path, 0755)
return s.sendError(p, err)
rpkt = statusFromError(p, err)
case *sshFxpRmdirPacket:
err := os.Remove(p.Path)
return s.sendError(p, err)
rpkt = statusFromError(p, err)
case *sshFxpRemovePacket:
err := os.Remove(p.Filename)
return s.sendError(p, err)
rpkt = statusFromError(p, err)
case *sshFxpRenamePacket:
err := os.Rename(p.Oldpath, p.Newpath)
return s.sendError(p, err)
rpkt = statusFromError(p, err)
case *sshFxpSymlinkPacket:
err := os.Symlink(p.Targetpath, p.Linkpath)
return s.sendError(p, err)
rpkt = statusFromError(p, err)
case *sshFxpClosePacket:
return s.sendError(p, s.closeHandle(p.Handle))
rpkt = statusFromError(p, s.closeHandle(p.Handle))
case *sshFxpReadlinkPacket:
f, err := os.Readlink(p.Path)
if err != nil {
return s.sendError(p, err)
}
return s.sendPacket(sshFxpNamePacket{
rpkt = sshFxpNamePacket{
ID: p.ID,
NameAttrs: []sshFxpNameAttr{{
Name: f,
LongName: f,
Attrs: emptyFileStat,
}},
})
}
if err != nil {
rpkt = statusFromError(p, err)
}
case *sshFxpRealpathPacket:
f, err := filepath.Abs(p.Path)
if err != nil {
return s.sendError(p, err)
}
f = cleanPath(f)
return s.sendPacket(sshFxpNamePacket{
rpkt = sshFxpNamePacket{
ID: p.ID,
NameAttrs: []sshFxpNameAttr{{
Name: f,
LongName: f,
Attrs: emptyFileStat,
}},
})
}
if err != nil {
rpkt = statusFromError(p, err)
}
case *sshFxpOpendirPacket:
if stat, err := os.Stat(p.Path); err != nil {
return s.sendError(p, err)
rpkt = statusFromError(p, err)
} else if !stat.IsDir() {
return s.sendError(p, &os.PathError{
rpkt = statusFromError(p, &os.PathError{
Path: p.Path, Err: syscall.ENOTDIR})
} else {
rpkt = sshFxpOpenPacket{
ID: p.ID,
Path: p.Path,
Pflags: ssh_FXF_READ,
}.respond(s)
}
return sshFxpOpenPacket{
ID: p.ID,
Path: p.Path,
Pflags: ssh_FXF_READ,
}.respond(s)
case *sshFxpReadPacket:
var err error = syscall.EBADF
f, ok := s.getHandle(p.Handle)
if !ok {
return s.sendError(p, syscall.EBADF)
if ok {
err = nil
data := make([]byte, clamp(p.Len, s.maxTxPacket))
n, _err := f.ReadAt(data, int64(p.Offset))
if _err != nil && (_err != io.EOF || n == 0) {
err = _err
}
rpkt = sshFxpDataPacket{
ID: p.ID,
Length: uint32(n),
Data: data[:n],
}
}
if err != nil {
rpkt = statusFromError(p, err)
}
data := make([]byte, clamp(p.Len, s.maxTxPacket))
n, err := f.ReadAt(data, int64(p.Offset))
if err != nil && (err != io.EOF || n == 0) {
return s.sendError(p, err)
}
return s.sendPacket(sshFxpDataPacket{
ID: p.ID,
Length: uint32(n),
Data: data[:n],
})
case *sshFxpWritePacket:
f, ok := s.getHandle(p.Handle)
if !ok {
return s.sendError(p, syscall.EBADF)
var err error = syscall.EBADF
if ok {
_, err = f.WriteAt(p.Data, int64(p.Offset))
}
_, err := f.WriteAt(p.Data, int64(p.Offset))
return s.sendError(p, err)
rpkt = statusFromError(p, err)
case serverRespondablePacket:
err := p.respond(s)
return errors.Wrap(err, "pkt.respond failed")
rpkt = p.respond(s)
default:
return errors.Errorf("unexpected packet type %T", p)
}
s.pktMgr.readyPacket(s.pktMgr.newOrderedResponse(rpkt, p.orderId()))
return nil
}
// Serve serves SFTP connections until the streams stop or the SFTP subsystem
// is stopped.
func (svr *Server) Serve() error {
var wg sync.WaitGroup
runWorker := func(ch requestChan) {
runWorker := func(ch chan orderedRequest) {
wg.Add(1)
go func() {
defer wg.Done()
@ -324,7 +327,7 @@ func (svr *Server) Serve() error {
}
}
pktChan <- pkt
pktChan <- svr.pktMgr.newOrderedRequest(pkt)
}
close(pktChan) // shuts down sftpServerWorkers
@ -338,20 +341,6 @@ func (svr *Server) Serve() error {
return err // error from recvPacket
}
// Wrap underlying connection methods to use packetManager
func (svr *Server) sendPacket(m encoding.BinaryMarshaler) error {
if pkt, ok := m.(responsePacket); ok {
svr.pktMgr.readyPacket(pkt)
} else {
return errors.Errorf("unexpected packet type %T", m)
}
return nil
}
func (svr *Server) sendError(p ider, err error) error {
return svr.sendPacket(statusFromError(p, err))
}
type ider interface {
id() uint32
}
@ -386,7 +375,7 @@ func (p sshFxpOpenPacket) hasPflags(flags ...uint32) bool {
return true
}
func (p sshFxpOpenPacket) respond(svr *Server) error {
func (p sshFxpOpenPacket) respond(svr *Server) responsePacket {
var osFlags int
if p.hasPflags(ssh_FXF_READ, ssh_FXF_WRITE) {
osFlags |= os.O_RDWR
@ -396,7 +385,7 @@ func (p sshFxpOpenPacket) respond(svr *Server) error {
osFlags |= os.O_RDONLY
} else {
// how are they opening?
return svr.sendError(p, syscall.EINVAL)
return statusFromError(p, syscall.EINVAL)
}
if p.hasPflags(ssh_FXF_APPEND) {
@ -414,23 +403,23 @@ func (p sshFxpOpenPacket) respond(svr *Server) error {
f, err := os.OpenFile(p.Path, osFlags, 0644)
if err != nil {
return svr.sendError(p, err)
return statusFromError(p, err)
}
handle := svr.nextHandle(f)
return svr.sendPacket(sshFxpHandlePacket{p.ID, handle})
return sshFxpHandlePacket{ID: p.id(), Handle: handle}
}
func (p sshFxpReaddirPacket) respond(svr *Server) error {
func (p sshFxpReaddirPacket) respond(svr *Server) responsePacket {
f, ok := svr.getHandle(p.Handle)
if !ok {
return svr.sendError(p, syscall.EBADF)
return statusFromError(p, syscall.EBADF)
}
dirname := f.Name()
dirents, err := f.Readdir(128)
if err != nil {
return svr.sendError(p, err)
return statusFromError(p, err)
}
ret := sshFxpNamePacket{ID: p.ID}
@ -441,10 +430,10 @@ func (p sshFxpReaddirPacket) respond(svr *Server) error {
Attrs: []interface{}{dirent},
})
}
return svr.sendPacket(ret)
return ret
}
func (p sshFxpSetstatPacket) respond(svr *Server) error {
func (p sshFxpSetstatPacket) respond(svr *Server) responsePacket {
// additional unmarshalling is required for each possibility here
b := p.Attrs.([]byte)
var err error
@ -483,13 +472,13 @@ func (p sshFxpSetstatPacket) respond(svr *Server) error {
}
}
return svr.sendError(p, err)
return statusFromError(p, err)
}
func (p sshFxpFsetstatPacket) respond(svr *Server) error {
func (p sshFxpFsetstatPacket) respond(svr *Server) responsePacket {
f, ok := svr.getHandle(p.Handle)
if !ok {
return svr.sendError(p, syscall.EBADF)
return statusFromError(p, syscall.EBADF)
}
// additional unmarshalling is required for each possibility here
@ -530,7 +519,7 @@ func (p sshFxpFsetstatPacket) respond(svr *Server) error {
}
}
return svr.sendError(p, err)
return statusFromError(p, err)
}
// translateErrno translates a syscall error number to a SFTP error code.

View file

@ -9,17 +9,17 @@ import (
"syscall"
)
func (p sshFxpExtendedPacketStatVFS) respond(svr *Server) error {
func (p sshFxpExtendedPacketStatVFS) respond(svr *Server) responsePacket {
stat := &syscall.Statfs_t{}
if err := syscall.Statfs(p.Path, stat); err != nil {
return svr.sendPacket(statusFromError(p, err))
return statusFromError(p, err)
}
retPkt, err := statvfsFromStatfst(stat)
if err != nil {
return svr.sendPacket(statusFromError(p, err))
return statusFromError(p, err)
}
retPkt.ID = p.ID
return svr.sendPacket(retPkt)
return retPkt
}

View file

@ -6,6 +6,6 @@ import (
"syscall"
)
func (p sshFxpExtendedPacketStatVFS) respond(svr *Server) error {
return syscall.ENOTSUP
func (p sshFxpExtendedPacketStatVFS) respond(svr *Server) responsePacket {
return statusFromError(p, syscall.ENOTSUP)
}

View file

@ -1,4 +1,4 @@
// +build darwin dragonfly freebsd !android,linux netbsd openbsd solaris
// +build darwin dragonfly freebsd !android,linux netbsd openbsd solaris aix
// +build cgo
package sftp