sftp/request.go

164 lines
4.0 KiB
Go
Raw Normal View History

2016-07-09 03:38:35 +08:00
package sftp
2016-07-09 08:22:52 +08:00
import (
"io"
"os"
"path"
"syscall"
)
// Valid Method values:
// Get, Put, SetStat, Rename, Rmdir, Mkdir, Symlink, List, Stat, Readlink
2016-07-09 03:38:35 +08:00
type Request struct {
Method string
Filepath string
Pflags uint32
Attrs []byte // convert to sub-struct
Target string // for renames and sym-links
pktChan chan packet
cur_pkt packet
2016-07-09 08:22:52 +08:00
svr *RequestServer
2016-07-09 03:38:35 +08:00
}
2016-07-09 08:22:52 +08:00
func newRequest(path string, svr *RequestServer) *Request {
request := &Request{Filepath: path, svr: svr}
2016-07-09 03:38:35 +08:00
go request.requestWorker()
return request
}
func (r *Request) sendError(err error) error {
return r.svr.sendError(r.cur_pkt, err)
}
func (r *Request) close() { close(r.pktChan) }
func (r *Request) requestWorker() error {
for p := range r.pktChan {
r.populate(p)
r.cur_pkt = p
2016-07-12 02:06:08 +08:00
handlers := r.svr.Handlers
2016-07-09 08:22:52 +08:00
switch r.Method {
case "Get":
return fileget(handlers.FileGet, r)
case "Put":
return fileput(handlers.FilePut, r)
case "SetStat", "Rename", "Rmdir", "Mkdir", "Symlink":
return filecmd(handlers.FileCmd, r)
case "List", "Stat", "Readlink":
return fileinfo(handlers.FileInfo, r)
}
2016-07-09 03:38:35 +08:00
}
return nil
}
2016-07-09 08:22:52 +08:00
func fileget(h FileReader, r *Request) error {
reader, err := h.Filereader(r)
if err != nil { return r.sendError(syscall.EBADF) }
pkt, ok := r.cur_pkt.(*sshFxpReadPacket)
if !ok { return r.sendError(syscall.EBADF) }
data := make([]byte, clamp(pkt.Len, maxTxPacket))
n, err := reader.Read(data)
if err != nil && (err != io.EOF || n == 0) {
return r.sendError(err)
}
return r.svr.sendPacket(sshFxpDataPacket{
ID: pkt.ID,
Length: uint32(n),
Data: data[:n],
})
}
func fileput(h FileWriter, r *Request) error {
writer, err := h.Filewriter(r)
if err != nil { return r.sendError(syscall.EBADF) }
pkt, ok := r.cur_pkt.(*sshFxpWritePacket)
if !ok { return r.sendError(syscall.EBADF) }
_, err = writer.Write(pkt.Data)
return r.sendError(err)
}
func filecmd(h FileCmder, r *Request) error {
err := h.Filecmd(r)
return r.sendError(err)
}
func fileinfo(h FileInfoer, r *Request) error {
finfo, err := h.Fileinfo(r)
if err != nil { return r.sendError(err) }
p, ok := r.cur_pkt.(packet)
if !ok { return r.sendError(syscall.EBADF) }
switch r.Method {
case "List":
dirname := path.Base(r.Filepath)
ret := sshFxpNamePacket{ID: p.id()}
for _, fi := range finfo {
ret.NameAttrs = append(ret.NameAttrs, sshFxpNameAttr{
Name: fi.Name(),
LongName: runLs(dirname, fi),
Attrs: []interface{}{fi},
})
}
case "Stat":
if len(finfo) == 0 {
err = &os.PathError{"stat", r.Filepath, syscall.ENOENT}
return r.sendError(err)
}
return r.svr.sendPacket(sshFxpStatResponse{
ID: p.id(),
info: finfo[0],
})
case "Readlink":
if len(finfo) == 0 {
err = &os.PathError{"readlink", r.Filepath, syscall.ENOENT}
return r.sendError(err)
}
return r.svr.sendPacket(sshFxpNamePacket{
ID: p.id(),
NameAttrs: []sshFxpNameAttr{{
Name: finfo[0].Name(),
LongName: finfo[0].Name(),
Attrs: emptyFileStat,
}},
})
}
return r.sendError(err)
}
2016-07-09 03:38:35 +08:00
func (r *Request) populate(p interface{}) {
switch p := p.(type) {
case *sshFxpSetstatPacket:
r.Method = "Setstat"
r.Pflags = p.Flags
r.Attrs = p.Attrs.([]byte)
case *sshFxpFsetstatPacket:
r.Method = "Setstat"
r.Pflags = p.Flags
r.Attrs = p.Attrs.([]byte)
case *sshFxpRenamePacket:
r.Method = "Rename"
r.Target = p.Newpath
case *sshFxpSymlinkPacket:
r.Method = "Symlink"
r.Target = p.Linkpath
// below here method and path are all the data
case *sshFxpReaddirPacket:
r.Method = "List"
case *sshFxpStatPacket, *sshFxpLstatPacket, *sshFxpFstatPacket,
*sshFxpRealpathPacket, *sshFxpRemovePacket:
r.Method = "Stat"
case *sshFxpRmdirPacket:
r.Method = "Rmdir"
case *sshFxpReadlinkPacket:
r.Method = "Readlink"
// special cases
case *sshFxpReadPacket:
r.Method = "Get"
// data processed elsewhere
case *sshFxpWritePacket:
r.Method = "Put"
// data processed elsewhere
case *sshFxpMkdirPacket:
r.Method = "Mkdir"
2016-07-09 08:22:52 +08:00
//r.Attrs are ignored in ./packet.go
2016-07-09 03:38:35 +08:00
}
}