vendor: update all dependencies

This commit is contained in:
Nick Craig-Wood 2020-02-25 14:20:57 +00:00
parent 17b4058ee9
commit abb9f89f65
443 changed files with 32118 additions and 18237 deletions

View file

@ -4,25 +4,25 @@ 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.11.x
- 1.12.x
- 1.13.x
- tip
os:
- linux
- osx
env:
global:
- GO111MODULE=on
matrix:
exclude:
- os: osx
go: 1.10.x
go: 1.12.x
- os: osx
go: tip
env:
global:
- GO111MODULE=on
addons:
ssh_known_hosts:
- bitbucket.org

11
vendor/github.com/pkg/sftp/Makefile generated vendored Normal file
View file

@ -0,0 +1,11 @@
integration:
go test -integration -v
go test -testserver -v
go test -integration -testserver -v
integration_w_race:
go test -race -integration -v
go test -race -testserver -v
go test -race -integration -testserver -v

59
vendor/github.com/pkg/sftp/attrs.go generated vendored
View file

@ -10,11 +10,14 @@ import (
)
const (
ssh_FILEXFER_ATTR_SIZE = 0x00000001
ssh_FILEXFER_ATTR_UIDGID = 0x00000002
ssh_FILEXFER_ATTR_PERMISSIONS = 0x00000004
ssh_FILEXFER_ATTR_ACMODTIME = 0x00000008
ssh_FILEXFER_ATTR_EXTENDED = 0x80000000
sshFileXferAttrSize = 0x00000001
sshFileXferAttrUIDGID = 0x00000002
sshFileXferAttrPermissions = 0x00000004
sshFileXferAttrACmodTime = 0x00000008
sshFileXferAttrExtented = 0x80000000
sshFileXferAttrAll = sshFileXferAttrSize | sshFileXferAttrUIDGID | sshFileXferAttrPermissions |
sshFileXferAttrACmodTime | sshFileXferAttrExtented
)
// fileInfo is an artificial type designed to satisfy os.FileInfo.
@ -77,9 +80,9 @@ func fileInfoFromStat(st *FileStat, name string) os.FileInfo {
func fileStatFromInfo(fi os.FileInfo) (uint32, FileStat) {
mtime := fi.ModTime().Unix()
atime := mtime
var flags uint32 = ssh_FILEXFER_ATTR_SIZE |
ssh_FILEXFER_ATTR_PERMISSIONS |
ssh_FILEXFER_ATTR_ACMODTIME
var flags uint32 = sshFileXferAttrSize |
sshFileXferAttrPermissions |
sshFileXferAttrACmodTime
fileStat := FileStat{
Size: uint64(fi.Size()),
@ -101,31 +104,31 @@ func unmarshalAttrs(b []byte) (*FileStat, []byte) {
func getFileStat(flags uint32, b []byte) (*FileStat, []byte) {
var fs FileStat
if flags&ssh_FILEXFER_ATTR_SIZE == ssh_FILEXFER_ATTR_SIZE {
fs.Size, b = unmarshalUint64(b)
if flags&sshFileXferAttrSize == sshFileXferAttrSize {
fs.Size, b, _ = unmarshalUint64Safe(b)
}
if flags&ssh_FILEXFER_ATTR_UIDGID == ssh_FILEXFER_ATTR_UIDGID {
fs.UID, b = unmarshalUint32(b)
if flags&sshFileXferAttrUIDGID == sshFileXferAttrUIDGID {
fs.UID, b, _ = unmarshalUint32Safe(b)
}
if flags&ssh_FILEXFER_ATTR_UIDGID == ssh_FILEXFER_ATTR_UIDGID {
fs.GID, b = unmarshalUint32(b)
if flags&sshFileXferAttrUIDGID == sshFileXferAttrUIDGID {
fs.GID, b, _ = unmarshalUint32Safe(b)
}
if flags&ssh_FILEXFER_ATTR_PERMISSIONS == ssh_FILEXFER_ATTR_PERMISSIONS {
fs.Mode, b = unmarshalUint32(b)
if flags&sshFileXferAttrPermissions == sshFileXferAttrPermissions {
fs.Mode, b, _ = unmarshalUint32Safe(b)
}
if flags&ssh_FILEXFER_ATTR_ACMODTIME == ssh_FILEXFER_ATTR_ACMODTIME {
fs.Atime, b = unmarshalUint32(b)
fs.Mtime, b = unmarshalUint32(b)
if flags&sshFileXferAttrACmodTime == sshFileXferAttrACmodTime {
fs.Atime, b, _ = unmarshalUint32Safe(b)
fs.Mtime, b, _ = unmarshalUint32Safe(b)
}
if flags&ssh_FILEXFER_ATTR_EXTENDED == ssh_FILEXFER_ATTR_EXTENDED {
if flags&sshFileXferAttrExtented == sshFileXferAttrExtented {
var count uint32
count, b = unmarshalUint32(b)
count, b, _ = unmarshalUint32Safe(b)
ext := make([]StatExtended, count)
for i := uint32(0); i < count; i++ {
var typ string
var data string
typ, b = unmarshalString(b)
data, b = unmarshalString(b)
typ, b, _ = unmarshalStringSafe(b)
data, b, _ = unmarshalStringSafe(b)
ext[i] = StatExtended{typ, data}
}
fs.Extended = ext
@ -152,17 +155,17 @@ func marshalFileInfo(b []byte, fi os.FileInfo) []byte {
flags, fileStat := fileStatFromInfo(fi)
b = marshalUint32(b, flags)
if flags&ssh_FILEXFER_ATTR_SIZE != 0 {
if flags&sshFileXferAttrSize != 0 {
b = marshalUint64(b, fileStat.Size)
}
if flags&ssh_FILEXFER_ATTR_UIDGID != 0 {
if flags&sshFileXferAttrUIDGID != 0 {
b = marshalUint32(b, fileStat.UID)
b = marshalUint32(b, fileStat.GID)
}
if flags&ssh_FILEXFER_ATTR_PERMISSIONS != 0 {
if flags&sshFileXferAttrPermissions != 0 {
b = marshalUint32(b, fileStat.Mode)
}
if flags&ssh_FILEXFER_ATTR_ACMODTIME != 0 {
if flags&sshFileXferAttrACmodTime != 0 {
b = marshalUint32(b, fileStat.Atime)
b = marshalUint32(b, fileStat.Mtime)
}
@ -173,7 +176,7 @@ func marshalFileInfo(b []byte, fi os.FileInfo) []byte {
// toFileMode converts sftp filemode bits to the os.FileMode specification
func toFileMode(mode uint32) os.FileMode {
var fm = os.FileMode(mode & 0777)
switch mode & syscall.S_IFMT {
switch mode & S_IFMT {
case syscall.S_IFBLK:
fm |= os.ModeDevice
case syscall.S_IFCHR:

View file

@ -10,7 +10,7 @@ import (
func fileStatFromInfoOs(fi os.FileInfo, flags *uint32, fileStat *FileStat) {
if statt, ok := fi.Sys().(*syscall.Stat_t); ok {
*flags |= ssh_FILEXFER_ATTR_UIDGID
*flags |= sshFileXferAttrUIDGID
fileStat.UID = statt.Uid
fileStat.GID = statt.Gid
}

187
vendor/github.com/pkg/sftp/client.go generated vendored
View file

@ -15,12 +15,18 @@ import (
"golang.org/x/crypto/ssh"
)
// InternalInconsistency indicates the packets sent and the data queued to be
// written to the file don't match up. It is an unusual error and usually is
// caused by bad behavior server side or connection issues. The error is
// limited in scope to the call where it happened, the client object is still
// OK to use as long as the connection is still open.
var InternalInconsistency = errors.New("internal inconsistency")
var (
// ErrInternalInconsistency indicates the packets sent and the data queued to be
// written to the file don't match up. It is an unusual error and usually is
// caused by bad behavior server side or connection issues. The error is
// limited in scope to the call where it happened, the client object is still
// OK to use as long as the connection is still open.
ErrInternalInconsistency = errors.New("internal inconsistency")
// InternalInconsistency alias for ErrInternalInconsistency.
//
// Deprecated: please use ErrInternalInconsistency
InternalInconsistency = ErrInternalInconsistency
)
// A ClientOption is a function which applies configuration to a Client.
type ClientOption func(*Client) error
@ -45,6 +51,30 @@ func MaxPacketChecked(size int) ClientOption {
}
}
// UseFstat sets whether to use Fstat or Stat when File.WriteTo is called
// (usually when copying files).
// Some servers limit the amount of open files and calling Stat after opening
// the file will throw an error From the server. Setting this flag will call
// Fstat instead of Stat which is suppose to be called on an open file handle.
//
// It has been found that that with IBM Sterling SFTP servers which have
// "extractability" level set to 1 which means only 1 file can be opened at
// any given time.
//
// If the server you are working with still has an issue with both Stat and
// Fstat calls you can always open a file and read it until the end.
//
// Another reason to read the file until its end and Fstat doesn't work is
// that in some servers, reading a full file will automatically delete the
// file as some of these mainframes map the file to a message in a queue.
// Once the file has been read it will get deleted.
func UseFstat(value bool) ClientOption {
return func(c *Client) error {
c.useFstat = value
return nil
}
}
// MaxPacketUnchecked sets the maximum size of the payload, measured in bytes.
// It accepts sizes larger than the 32768 bytes all servers should support.
// Only use a setting higher than 32768 if your application always connects to
@ -155,12 +185,17 @@ type Client struct {
maxPacket int // max packet size read or written.
nextid uint32
maxConcurrentRequests int
useFstat bool
}
// Create creates the named file mode 0666 (before umask), truncating it if it
// already exists. If successful, methods on the returned File can be used for
// I/O; the associated file descriptor has mode O_RDWR. If you need more
// control over the flags/mode used to open the file see client.OpenFile.
//
// Note that some SFTP servers (eg. AWS Transfer) do not support opening files
// read/write at the same time. For those services you will need to use
// `client.OpenFile(os.O_WRONLY|os.O_CREATE|os.O_TRUNC)`.
func (c *Client) Create(path string) (*File, error) {
return c.open(path, flags(os.O_RDWR|os.O_CREATE|os.O_TRUNC))
}
@ -183,8 +218,8 @@ func (c *Client) recvVersion() error {
if err != nil {
return err
}
if typ != ssh_FXP_VERSION {
return &unexpectedPacketErr{ssh_FXP_VERSION, typ}
if typ != sshFxpVersion {
return &unexpectedPacketErr{sshFxpVersion, typ}
}
version, _ := unmarshalUint32(data)
@ -222,7 +257,7 @@ func (c *Client) ReadDir(p string) ([]os.FileInfo, error) {
break
}
switch typ {
case ssh_FXP_NAME:
case sshFxpName:
sid, data := unmarshalUint32(data)
if sid != id {
return nil, &unexpectedIDErr{id, sid}
@ -239,7 +274,7 @@ func (c *Client) ReadDir(p string) ([]os.FileInfo, error) {
}
attrs = append(attrs, fileInfoFromStat(attr, path.Base(filename)))
}
case ssh_FXP_STATUS:
case sshFxpStatus:
// TODO(dfc) scope warning!
err = normaliseError(unmarshalStatus(id, data))
done = true
@ -263,14 +298,14 @@ func (c *Client) opendir(path string) (string, error) {
return "", err
}
switch typ {
case ssh_FXP_HANDLE:
case sshFxpHandle:
sid, data := unmarshalUint32(data)
if sid != id {
return "", &unexpectedIDErr{id, sid}
}
handle, _ := unmarshalString(data)
return handle, nil
case ssh_FXP_STATUS:
case sshFxpStatus:
return "", normaliseError(unmarshalStatus(id, data))
default:
return "", unimplementedPacketErr(typ)
@ -289,14 +324,14 @@ func (c *Client) Stat(p string) (os.FileInfo, error) {
return nil, err
}
switch typ {
case ssh_FXP_ATTRS:
case sshFxpAttrs:
sid, data := unmarshalUint32(data)
if sid != id {
return nil, &unexpectedIDErr{id, sid}
}
attr, _ := unmarshalAttrs(data)
return fileInfoFromStat(attr, path.Base(p)), nil
case ssh_FXP_STATUS:
case sshFxpStatus:
return nil, normaliseError(unmarshalStatus(id, data))
default:
return nil, unimplementedPacketErr(typ)
@ -315,14 +350,14 @@ func (c *Client) Lstat(p string) (os.FileInfo, error) {
return nil, err
}
switch typ {
case ssh_FXP_ATTRS:
case sshFxpAttrs:
sid, data := unmarshalUint32(data)
if sid != id {
return nil, &unexpectedIDErr{id, sid}
}
attr, _ := unmarshalAttrs(data)
return fileInfoFromStat(attr, path.Base(p)), nil
case ssh_FXP_STATUS:
case sshFxpStatus:
return nil, normaliseError(unmarshalStatus(id, data))
default:
return nil, unimplementedPacketErr(typ)
@ -340,7 +375,7 @@ func (c *Client) ReadLink(p string) (string, error) {
return "", err
}
switch typ {
case ssh_FXP_NAME:
case sshFxpName:
sid, data := unmarshalUint32(data)
if sid != id {
return "", &unexpectedIDErr{id, sid}
@ -351,13 +386,32 @@ func (c *Client) ReadLink(p string) (string, error) {
}
filename, _ := unmarshalString(data) // ignore dummy attributes
return filename, nil
case ssh_FXP_STATUS:
case sshFxpStatus:
return "", normaliseError(unmarshalStatus(id, data))
default:
return "", unimplementedPacketErr(typ)
}
}
// Link creates a hard link at 'newname', pointing at the same inode as 'oldname'
func (c *Client) Link(oldname, newname string) error {
id := c.nextID()
typ, data, err := c.sendPacket(sshFxpHardlinkPacket{
ID: id,
Oldpath: oldname,
Newpath: newname,
})
if err != nil {
return err
}
switch typ {
case sshFxpStatus:
return normaliseError(unmarshalStatus(id, data))
default:
return unimplementedPacketErr(typ)
}
}
// Symlink creates a symbolic link at 'newname', pointing at target 'oldname'
func (c *Client) Symlink(oldname, newname string) error {
id := c.nextID()
@ -370,7 +424,7 @@ func (c *Client) Symlink(oldname, newname string) error {
return err
}
switch typ {
case ssh_FXP_STATUS:
case sshFxpStatus:
return normaliseError(unmarshalStatus(id, data))
default:
return unimplementedPacketErr(typ)
@ -390,7 +444,7 @@ func (c *Client) setstat(path string, flags uint32, attrs interface{}) error {
return err
}
switch typ {
case ssh_FXP_STATUS:
case sshFxpStatus:
return normaliseError(unmarshalStatus(id, data))
default:
return unimplementedPacketErr(typ)
@ -404,7 +458,7 @@ func (c *Client) Chtimes(path string, atime time.Time, mtime time.Time) error {
Mtime uint32
}
attrs := times{uint32(atime.Unix()), uint32(mtime.Unix())}
return c.setstat(path, ssh_FILEXFER_ATTR_ACMODTIME, attrs)
return c.setstat(path, sshFileXferAttrACmodTime, attrs)
}
// Chown changes the user and group owners of the named file.
@ -414,12 +468,12 @@ func (c *Client) Chown(path string, uid, gid int) error {
GID uint32
}
attrs := owner{uint32(uid), uint32(gid)}
return c.setstat(path, ssh_FILEXFER_ATTR_UIDGID, attrs)
return c.setstat(path, sshFileXferAttrUIDGID, attrs)
}
// Chmod changes the permissions of the named file.
func (c *Client) Chmod(path string, mode os.FileMode) error {
return c.setstat(path, ssh_FILEXFER_ATTR_PERMISSIONS, uint32(mode))
return c.setstat(path, sshFileXferAttrPermissions, uint32(mode))
}
// Truncate sets the size of the named file. Although it may be safely assumed
@ -427,7 +481,7 @@ func (c *Client) Chmod(path string, mode os.FileMode) error {
// the SFTP protocol does not specify what behavior the server should do when setting
// size greater than the current size.
func (c *Client) Truncate(path string, size int64) error {
return c.setstat(path, ssh_FILEXFER_ATTR_SIZE, uint64(size))
return c.setstat(path, sshFileXferAttrSize, uint64(size))
}
// Open opens the named file for reading. If successful, methods on the
@ -455,14 +509,14 @@ func (c *Client) open(path string, pflags uint32) (*File, error) {
return nil, err
}
switch typ {
case ssh_FXP_HANDLE:
case sshFxpHandle:
sid, data := unmarshalUint32(data)
if sid != id {
return nil, &unexpectedIDErr{id, sid}
}
handle, _ := unmarshalString(data)
return &File{c: c, path: path, handle: handle}, nil
case ssh_FXP_STATUS:
case sshFxpStatus:
return nil, normaliseError(unmarshalStatus(id, data))
default:
return nil, unimplementedPacketErr(typ)
@ -482,7 +536,7 @@ func (c *Client) close(handle string) error {
return err
}
switch typ {
case ssh_FXP_STATUS:
case sshFxpStatus:
return normaliseError(unmarshalStatus(id, data))
default:
return unimplementedPacketErr(typ)
@ -499,14 +553,14 @@ func (c *Client) fstat(handle string) (*FileStat, error) {
return nil, err
}
switch typ {
case ssh_FXP_ATTRS:
case sshFxpAttrs:
sid, data := unmarshalUint32(data)
if sid != id {
return nil, &unexpectedIDErr{id, sid}
}
attr, _ := unmarshalAttrs(data)
return attr, nil
case ssh_FXP_STATUS:
case sshFxpStatus:
return nil, normaliseError(unmarshalStatus(id, data))
default:
return nil, unimplementedPacketErr(typ)
@ -530,7 +584,7 @@ func (c *Client) StatVFS(path string) (*StatVFS, error) {
switch typ {
// server responded with valid data
case ssh_FXP_EXTENDED_REPLY:
case sshFxpExtendedReply:
var response StatVFS
err = binary.Read(bytes.NewReader(data), binary.BigEndian, &response)
if err != nil {
@ -540,8 +594,8 @@ func (c *Client) StatVFS(path string) (*StatVFS, error) {
return &response, nil
// the resquest failed
case ssh_FXP_STATUS:
return nil, errors.New(fxp(ssh_FXP_STATUS).String())
case sshFxpStatus:
return nil, errors.New(fxp(sshFxpStatus).String())
default:
return nil, unimplementedPacketErr(typ)
@ -562,7 +616,7 @@ func (c *Client) Remove(path string) error {
switch err.Code {
// some servers, *cough* osx *cough*, return EPERM, not ENODIR.
// serv-u returns ssh_FX_FILE_IS_A_DIRECTORY
case ssh_FX_PERMISSION_DENIED, ssh_FX_FAILURE, ssh_FX_FILE_IS_A_DIRECTORY:
case sshFxPermissionDenied, sshFxFailure, sshFxFileIsADirectory:
return c.RemoveDirectory(path)
}
}
@ -579,7 +633,7 @@ func (c *Client) removeFile(path string) error {
return err
}
switch typ {
case ssh_FXP_STATUS:
case sshFxpStatus:
return normaliseError(unmarshalStatus(id, data))
default:
return unimplementedPacketErr(typ)
@ -597,7 +651,7 @@ func (c *Client) RemoveDirectory(path string) error {
return err
}
switch typ {
case ssh_FXP_STATUS:
case sshFxpStatus:
return normaliseError(unmarshalStatus(id, data))
default:
return unimplementedPacketErr(typ)
@ -616,7 +670,7 @@ func (c *Client) Rename(oldname, newname string) error {
return err
}
switch typ {
case ssh_FXP_STATUS:
case sshFxpStatus:
return normaliseError(unmarshalStatus(id, data))
default:
return unimplementedPacketErr(typ)
@ -636,7 +690,7 @@ func (c *Client) PosixRename(oldname, newname string) error {
return err
}
switch typ {
case ssh_FXP_STATUS:
case sshFxpStatus:
return normaliseError(unmarshalStatus(id, data))
default:
return unimplementedPacketErr(typ)
@ -653,7 +707,7 @@ func (c *Client) realpath(path string) (string, error) {
return "", err
}
switch typ {
case ssh_FXP_NAME:
case sshFxpName:
sid, data := unmarshalUint32(data)
if sid != id {
return "", &unexpectedIDErr{id, sid}
@ -664,7 +718,7 @@ func (c *Client) realpath(path string) (string, error) {
}
filename, _ := unmarshalString(data) // ignore attributes
return filename, nil
case ssh_FXP_STATUS:
case sshFxpStatus:
return "", normaliseError(unmarshalStatus(id, data))
default:
return "", unimplementedPacketErr(typ)
@ -690,7 +744,7 @@ func (c *Client) Mkdir(path string) error {
return err
}
switch typ {
case ssh_FXP_STATUS:
case sshFxpStatus:
return normaliseError(unmarshalStatus(id, data))
default:
return unimplementedPacketErr(typ)
@ -845,14 +899,14 @@ func (f *File) Read(b []byte) (int, error) {
}
delete(reqs, reqID)
switch res.typ {
case ssh_FXP_STATUS:
case sshFxpStatus:
if firstErr.err == nil || req.offset < firstErr.offset {
firstErr = offsetErr{
offset: req.offset,
err: normaliseError(unmarshalStatus(reqID, res.data)),
}
}
case ssh_FXP_DATA:
case sshFxpData:
l, data := unmarshalUint32(data)
n := copy(req.b, data[:l])
read += n
@ -884,15 +938,26 @@ func (f *File) Read(b []byte) (int, error) {
// maximise throughput for transferring the entire file (especially
// over high latency links).
func (f *File) WriteTo(w io.Writer) (int64, error) {
fi, err := f.c.Stat(f.path)
if err != nil {
return 0, err
var fileSize uint64
if f.c.useFstat {
fileStat, err := f.c.fstat(f.handle)
if err != nil {
return 0, err
}
fileSize = fileStat.Size
} else {
fi, err := f.c.Stat(f.path)
if err != nil {
return 0, err
}
fileSize = uint64(fi.Size())
}
inFlight := 0
desiredInFlight := 1
offset := f.offset
writeOffset := offset
fileSize := uint64(fi.Size())
// see comment on same line in Read() above
ch := make(chan result, f.c.maxConcurrentRequests+1)
type inflightRead struct {
@ -934,7 +999,7 @@ func (f *File) WriteTo(w io.Writer) (int64, error) {
if inFlight == 0 {
if firstErr.err == nil && len(pendingWrites) > 0 {
return copied, InternalInconsistency
return copied, ErrInternalInconsistency
}
break
}
@ -952,11 +1017,11 @@ func (f *File) WriteTo(w io.Writer) (int64, error) {
}
delete(reqs, reqID)
switch res.typ {
case ssh_FXP_STATUS:
case sshFxpStatus:
if firstErr.err == nil || req.offset < firstErr.offset {
firstErr = offsetErr{offset: req.offset, err: normaliseError(unmarshalStatus(reqID, res.data))}
}
case ssh_FXP_DATA:
case sshFxpData:
l, data := unmarshalUint32(data)
if req.offset == writeOffset {
nbytes, err := w.Write(data)
@ -1071,7 +1136,7 @@ func (f *File) Write(b []byte) (int, error) {
continue
}
switch res.typ {
case ssh_FXP_STATUS:
case sshFxpStatus:
id, _ := unmarshalUint32(res.data)
err := normaliseError(unmarshalStatus(id, res.data))
if err != nil && firstErr == nil {
@ -1139,7 +1204,7 @@ func (f *File) ReadFrom(r io.Reader) (int64, error) {
continue
}
switch res.typ {
case ssh_FXP_STATUS:
case sshFxpStatus:
id, _ := unmarshalUint32(res.data)
err := normaliseError(unmarshalStatus(id, res.data))
if err != nil && firstErr == nil {
@ -1218,11 +1283,11 @@ func normaliseError(err error) error {
switch err := err.(type) {
case *StatusError:
switch err.Code {
case ssh_FX_EOF:
case sshFxEOF:
return io.EOF
case ssh_FX_NO_SUCH_FILE:
case sshFxNoSuchFile:
return os.ErrNotExist
case ssh_FX_OK:
case sshFxOk:
return nil
default:
return err
@ -1260,24 +1325,24 @@ func flags(f int) uint32 {
var out uint32
switch f & os.O_WRONLY {
case os.O_WRONLY:
out |= ssh_FXF_WRITE
out |= sshFxfWrite
case os.O_RDONLY:
out |= ssh_FXF_READ
out |= sshFxfRead
}
if f&os.O_RDWR == os.O_RDWR {
out |= ssh_FXF_READ | ssh_FXF_WRITE
out |= sshFxfRead | sshFxfWrite
}
if f&os.O_APPEND == os.O_APPEND {
out |= ssh_FXF_APPEND
out |= sshFxfAppend
}
if f&os.O_CREATE == os.O_CREATE {
out |= ssh_FXF_CREAT
out |= sshFxfCreat
}
if f&os.O_TRUNC == os.O_TRUNC {
out |= ssh_FXF_TRUNC
out |= sshFxfTrunc
}
if f&os.O_EXCL == os.O_EXCL {
out |= ssh_FXF_EXCL
out |= sshFxfExcl
}
return out
}

View file

@ -39,7 +39,7 @@ func newPktMgr(sender packetSender) *packetManager {
}
//// packet ordering
func (s *packetManager) newOrderId() uint32 {
func (s *packetManager) newOrderID() uint32 {
s.packetCount++
return s.packetCount
}
@ -50,10 +50,10 @@ type orderedRequest struct {
}
func (s *packetManager) newOrderedRequest(p requestPacket) orderedRequest {
return orderedRequest{requestPacket: p, orderid: s.newOrderId()}
return orderedRequest{requestPacket: p, orderid: s.newOrderID()}
}
func (p orderedRequest) orderId() uint32 { return p.orderid }
func (p orderedRequest) setOrderId(oid uint32) { p.orderid = oid }
func (p orderedRequest) orderID() uint32 { return p.orderid }
func (p orderedRequest) setOrderID(oid uint32) { p.orderid = oid }
type orderedResponse struct {
responsePacket
@ -64,18 +64,18 @@ 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 }
func (p orderedResponse) orderID() uint32 { return p.orderid }
func (p orderedResponse) setOrderID(oid uint32) { p.orderid = oid }
type orderedPacket interface {
id() uint32
orderId() 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()
return o[i].orderID() < o[j].orderID()
})
}
@ -145,11 +145,11 @@ func (s *packetManager) controller() {
for {
select {
case pkt := <-s.requests:
debug("incoming id (oid): %v (%v)", pkt.id(), pkt.orderId())
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 id (oid): %v (%v)", pkt.id(), pkt.orderId())
debug("outgoing id (oid): %v (%v)", pkt.id(), pkt.orderID())
s.outgoing = append(s.outgoing, pkt)
s.outgoing.Sort()
case <-s.fini:
@ -171,7 +171,7 @@ func (s *packetManager) maybeSendPackets() {
in := s.incoming[0]
// debug("incoming: %v", ids(s.incoming))
// debug("outgoing: %v", ids(s.outgoing))
if in.orderId() == out.orderId() {
if in.orderID() == out.orderID() {
debug("Sending packet: %v", out.id())
s.sender.sendPacket(out.(encoding.BinaryMarshaler))
// pop off heads

View file

@ -49,8 +49,9 @@ func (p sshFxpOpendirPacket) getPath() string { return p.Path }
func (p sshFxpOpenPacket) getPath() string { return p.Path }
func (p sshFxpExtendedPacketPosixRename) getPath() string { return p.Oldpath }
func (p sshFxpExtendedPacketHardlink) getPath() string { return p.Oldpath }
// hasHandle
// getHandle
func (p sshFxpFstatPacket) getHandle() string { return p.Handle }
func (p sshFxpFsetstatPacket) getHandle() string { return p.Handle }
func (p sshFxpReadPacket) getHandle() string { return p.Handle }
@ -68,6 +69,7 @@ func (p sshFxpRmdirPacket) notReadOnly() {}
func (p sshFxpRenamePacket) notReadOnly() {}
func (p sshFxpSymlinkPacket) notReadOnly() {}
func (p sshFxpExtendedPacketPosixRename) notReadOnly() {}
func (p sshFxpExtendedPacketHardlink) notReadOnly() {}
// some packets with ID are missing id()
func (p sshFxpDataPacket) id() uint32 { return p.ID }
@ -82,45 +84,45 @@ func (p sshFxVersionPacket) id() uint32 { return 0 }
func makePacket(p rxPacket) (requestPacket, error) {
var pkt requestPacket
switch p.pktType {
case ssh_FXP_INIT:
case sshFxpInit:
pkt = &sshFxInitPacket{}
case ssh_FXP_LSTAT:
case sshFxpLstat:
pkt = &sshFxpLstatPacket{}
case ssh_FXP_OPEN:
case sshFxpOpen:
pkt = &sshFxpOpenPacket{}
case ssh_FXP_CLOSE:
case sshFxpClose:
pkt = &sshFxpClosePacket{}
case ssh_FXP_READ:
case sshFxpRead:
pkt = &sshFxpReadPacket{}
case ssh_FXP_WRITE:
case sshFxpWrite:
pkt = &sshFxpWritePacket{}
case ssh_FXP_FSTAT:
case sshFxpFstat:
pkt = &sshFxpFstatPacket{}
case ssh_FXP_SETSTAT:
case sshFxpSetstat:
pkt = &sshFxpSetstatPacket{}
case ssh_FXP_FSETSTAT:
case sshFxpFsetstat:
pkt = &sshFxpFsetstatPacket{}
case ssh_FXP_OPENDIR:
case sshFxpOpendir:
pkt = &sshFxpOpendirPacket{}
case ssh_FXP_READDIR:
case sshFxpReaddir:
pkt = &sshFxpReaddirPacket{}
case ssh_FXP_REMOVE:
case sshFxpRemove:
pkt = &sshFxpRemovePacket{}
case ssh_FXP_MKDIR:
case sshFxpMkdir:
pkt = &sshFxpMkdirPacket{}
case ssh_FXP_RMDIR:
case sshFxpRmdir:
pkt = &sshFxpRmdirPacket{}
case ssh_FXP_REALPATH:
case sshFxpRealpath:
pkt = &sshFxpRealpathPacket{}
case ssh_FXP_STAT:
case sshFxpStat:
pkt = &sshFxpStatPacket{}
case ssh_FXP_RENAME:
case sshFxpRename:
pkt = &sshFxpRenamePacket{}
case ssh_FXP_READLINK:
case sshFxpReadlink:
pkt = &sshFxpReadlinkPacket{}
case ssh_FXP_SYMLINK:
case sshFxpSymlink:
pkt = &sshFxpSymlinkPacket{}
case ssh_FXP_EXTENDED:
case sshFxpExtended:
pkt = &sshFxpExtendedPacket{}
default:
return nil, errors.Errorf("unhandled packet type: %s", p.pktType)

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

@ -13,11 +13,13 @@ import (
)
var (
errLongPacket = errors.New("packet too long")
errShortPacket = errors.New("packet too short")
errUnknownExtendedPacket = errors.New("unknown extended packet")
)
const (
maxMsgLength = 256 * 1024
debugDumpTxPacket = false
debugDumpRxPacket = false
debugDumpTxPacketBytes = false
@ -143,6 +145,10 @@ func recvPacket(r io.Reader) (uint8, []byte, error) {
return 0, nil, err
}
l, _ := unmarshalUint32(b)
if l > maxMsgLength {
debug("recv packet %d bytes too long", l)
return 0, nil, errLongPacket
}
b = make([]byte, l)
if _, err := io.ReadFull(r, b); err != nil {
debug("recv packet %d bytes: err %v", l, err)
@ -189,7 +195,7 @@ func (p sshFxInitPacket) MarshalBinary() ([]byte, error) {
}
b := make([]byte, 0, l)
b = append(b, ssh_FXP_INIT)
b = append(b, sshFxpInit)
b = marshalUint32(b, p.Version)
for _, e := range p.Extensions {
b = marshalString(b, e.Name)
@ -216,9 +222,11 @@ func (p *sshFxInitPacket) UnmarshalBinary(b []byte) error {
type sshFxVersionPacket struct {
Version uint32
Extensions []struct {
Name, Data string
}
Extensions []sshExtensionPair
}
type sshExtensionPair struct {
Name, Data string
}
func (p sshFxVersionPacket) MarshalBinary() ([]byte, error) {
@ -228,7 +236,7 @@ func (p sshFxVersionPacket) MarshalBinary() ([]byte, error) {
}
b := make([]byte, 0, l)
b = append(b, ssh_FXP_VERSION)
b = append(b, sshFxpVersion)
b = marshalUint32(b, p.Version)
for _, e := range p.Extensions {
b = marshalString(b, e.Name)
@ -266,7 +274,7 @@ type sshFxpReaddirPacket struct {
func (p sshFxpReaddirPacket) id() uint32 { return p.ID }
func (p sshFxpReaddirPacket) MarshalBinary() ([]byte, error) {
return marshalIDString(ssh_FXP_READDIR, p.ID, p.Handle)
return marshalIDString(sshFxpReaddir, p.ID, p.Handle)
}
func (p *sshFxpReaddirPacket) UnmarshalBinary(b []byte) error {
@ -281,7 +289,7 @@ type sshFxpOpendirPacket struct {
func (p sshFxpOpendirPacket) id() uint32 { return p.ID }
func (p sshFxpOpendirPacket) MarshalBinary() ([]byte, error) {
return marshalIDString(ssh_FXP_OPENDIR, p.ID, p.Path)
return marshalIDString(sshFxpOpendir, p.ID, p.Path)
}
func (p *sshFxpOpendirPacket) UnmarshalBinary(b []byte) error {
@ -296,7 +304,7 @@ type sshFxpLstatPacket struct {
func (p sshFxpLstatPacket) id() uint32 { return p.ID }
func (p sshFxpLstatPacket) MarshalBinary() ([]byte, error) {
return marshalIDString(ssh_FXP_LSTAT, p.ID, p.Path)
return marshalIDString(sshFxpLstat, p.ID, p.Path)
}
func (p *sshFxpLstatPacket) UnmarshalBinary(b []byte) error {
@ -311,7 +319,7 @@ type sshFxpStatPacket struct {
func (p sshFxpStatPacket) id() uint32 { return p.ID }
func (p sshFxpStatPacket) MarshalBinary() ([]byte, error) {
return marshalIDString(ssh_FXP_STAT, p.ID, p.Path)
return marshalIDString(sshFxpStat, p.ID, p.Path)
}
func (p *sshFxpStatPacket) UnmarshalBinary(b []byte) error {
@ -326,7 +334,7 @@ type sshFxpFstatPacket struct {
func (p sshFxpFstatPacket) id() uint32 { return p.ID }
func (p sshFxpFstatPacket) MarshalBinary() ([]byte, error) {
return marshalIDString(ssh_FXP_FSTAT, p.ID, p.Handle)
return marshalIDString(sshFxpFstat, p.ID, p.Handle)
}
func (p *sshFxpFstatPacket) UnmarshalBinary(b []byte) error {
@ -341,7 +349,7 @@ type sshFxpClosePacket struct {
func (p sshFxpClosePacket) id() uint32 { return p.ID }
func (p sshFxpClosePacket) MarshalBinary() ([]byte, error) {
return marshalIDString(ssh_FXP_CLOSE, p.ID, p.Handle)
return marshalIDString(sshFxpClose, p.ID, p.Handle)
}
func (p *sshFxpClosePacket) UnmarshalBinary(b []byte) error {
@ -356,7 +364,7 @@ type sshFxpRemovePacket struct {
func (p sshFxpRemovePacket) id() uint32 { return p.ID }
func (p sshFxpRemovePacket) MarshalBinary() ([]byte, error) {
return marshalIDString(ssh_FXP_REMOVE, p.ID, p.Filename)
return marshalIDString(sshFxpRemove, p.ID, p.Filename)
}
func (p *sshFxpRemovePacket) UnmarshalBinary(b []byte) error {
@ -371,7 +379,7 @@ type sshFxpRmdirPacket struct {
func (p sshFxpRmdirPacket) id() uint32 { return p.ID }
func (p sshFxpRmdirPacket) MarshalBinary() ([]byte, error) {
return marshalIDString(ssh_FXP_RMDIR, p.ID, p.Path)
return marshalIDString(sshFxpRmdir, p.ID, p.Path)
}
func (p *sshFxpRmdirPacket) UnmarshalBinary(b []byte) error {
@ -392,7 +400,7 @@ func (p sshFxpSymlinkPacket) MarshalBinary() ([]byte, error) {
4 + len(p.Linkpath)
b := make([]byte, 0, l)
b = append(b, ssh_FXP_SYMLINK)
b = append(b, sshFxpSymlink)
b = marshalUint32(b, p.ID)
b = marshalString(b, p.Targetpath)
b = marshalString(b, p.Linkpath)
@ -411,6 +419,30 @@ func (p *sshFxpSymlinkPacket) UnmarshalBinary(b []byte) error {
return nil
}
type sshFxpHardlinkPacket struct {
ID uint32
Oldpath string
Newpath string
}
func (p sshFxpHardlinkPacket) id() uint32 { return p.ID }
func (p sshFxpHardlinkPacket) MarshalBinary() ([]byte, error) {
const ext = "hardlink@openssh.com"
l := 1 + 4 + // type(byte) + uint32
4 + len(ext) +
4 + len(p.Oldpath) +
4 + len(p.Newpath)
b := make([]byte, 0, l)
b = append(b, sshFxpExtended)
b = marshalUint32(b, p.ID)
b = marshalString(b, ext)
b = marshalString(b, p.Oldpath)
b = marshalString(b, p.Newpath)
return b, nil
}
type sshFxpReadlinkPacket struct {
ID uint32
Path string
@ -419,7 +451,7 @@ type sshFxpReadlinkPacket struct {
func (p sshFxpReadlinkPacket) id() uint32 { return p.ID }
func (p sshFxpReadlinkPacket) MarshalBinary() ([]byte, error) {
return marshalIDString(ssh_FXP_READLINK, p.ID, p.Path)
return marshalIDString(sshFxpReadlink, p.ID, p.Path)
}
func (p *sshFxpReadlinkPacket) UnmarshalBinary(b []byte) error {
@ -434,7 +466,7 @@ type sshFxpRealpathPacket struct {
func (p sshFxpRealpathPacket) id() uint32 { return p.ID }
func (p sshFxpRealpathPacket) MarshalBinary() ([]byte, error) {
return marshalIDString(ssh_FXP_REALPATH, p.ID, p.Path)
return marshalIDString(sshFxpRealpath, p.ID, p.Path)
}
func (p *sshFxpRealpathPacket) UnmarshalBinary(b []byte) error {
@ -464,7 +496,7 @@ type sshFxpNamePacket struct {
func (p sshFxpNamePacket) MarshalBinary() ([]byte, error) {
b := []byte{}
b = append(b, ssh_FXP_NAME)
b = append(b, sshFxpName)
b = marshalUint32(b, p.ID)
b = marshalUint32(b, uint32(len(p.NameAttrs)))
for _, na := range p.NameAttrs {
@ -493,7 +525,7 @@ func (p sshFxpOpenPacket) MarshalBinary() ([]byte, error) {
4 + 4
b := make([]byte, 0, l)
b = append(b, ssh_FXP_OPEN)
b = append(b, sshFxpOpen)
b = marshalUint32(b, p.ID)
b = marshalString(b, p.Path)
b = marshalUint32(b, p.Pflags)
@ -530,7 +562,7 @@ func (p sshFxpReadPacket) MarshalBinary() ([]byte, error) {
8 + 4 // uint64 + uint32
b := make([]byte, 0, l)
b = append(b, ssh_FXP_READ)
b = append(b, sshFxpRead)
b = marshalUint32(b, p.ID)
b = marshalString(b, p.Handle)
b = marshalUint64(b, p.Offset)
@ -566,7 +598,7 @@ func (p sshFxpRenamePacket) MarshalBinary() ([]byte, error) {
4 + len(p.Newpath)
b := make([]byte, 0, l)
b = append(b, ssh_FXP_RENAME)
b = append(b, sshFxpRename)
b = marshalUint32(b, p.ID)
b = marshalString(b, p.Oldpath)
b = marshalString(b, p.Newpath)
@ -601,7 +633,7 @@ func (p sshFxpPosixRenamePacket) MarshalBinary() ([]byte, error) {
4 + len(p.Newpath)
b := make([]byte, 0, l)
b = append(b, ssh_FXP_EXTENDED)
b = append(b, sshFxpExtended)
b = marshalUint32(b, p.ID)
b = marshalString(b, ext)
b = marshalString(b, p.Oldpath)
@ -626,7 +658,7 @@ func (p sshFxpWritePacket) MarshalBinary() ([]byte, error) {
len(p.Data)
b := make([]byte, 0, l)
b = append(b, ssh_FXP_WRITE)
b = append(b, sshFxpWrite)
b = marshalUint32(b, p.ID)
b = marshalString(b, p.Handle)
b = marshalUint64(b, p.Offset)
@ -667,7 +699,7 @@ func (p sshFxpMkdirPacket) MarshalBinary() ([]byte, error) {
4 // uint32
b := make([]byte, 0, l)
b = append(b, ssh_FXP_MKDIR)
b = append(b, sshFxpMkdir)
b = marshalUint32(b, p.ID)
b = marshalString(b, p.Path)
b = marshalUint32(b, p.Flags)
@ -709,7 +741,7 @@ func (p sshFxpSetstatPacket) MarshalBinary() ([]byte, error) {
4 // uint32 + uint64
b := make([]byte, 0, l)
b = append(b, ssh_FXP_SETSTAT)
b = append(b, sshFxpSetstat)
b = marshalUint32(b, p.ID)
b = marshalString(b, p.Path)
b = marshalUint32(b, p.Flags)
@ -723,7 +755,7 @@ func (p sshFxpFsetstatPacket) MarshalBinary() ([]byte, error) {
4 // uint32 + uint64
b := make([]byte, 0, l)
b = append(b, ssh_FXP_FSETSTAT)
b = append(b, sshFxpFsetstat)
b = marshalUint32(b, p.ID)
b = marshalString(b, p.Handle)
b = marshalUint32(b, p.Flags)
@ -763,7 +795,7 @@ type sshFxpHandlePacket struct {
}
func (p sshFxpHandlePacket) MarshalBinary() ([]byte, error) {
b := []byte{ssh_FXP_HANDLE}
b := []byte{sshFxpHandle}
b = marshalUint32(b, p.ID)
b = marshalString(b, p.Handle)
return b, nil
@ -775,7 +807,7 @@ type sshFxpStatusPacket struct {
}
func (p sshFxpStatusPacket) MarshalBinary() ([]byte, error) {
b := []byte{ssh_FXP_STATUS}
b := []byte{sshFxpStatus}
b = marshalUint32(b, p.ID)
b = marshalStatus(b, p.StatusError)
return b, nil
@ -788,7 +820,7 @@ type sshFxpDataPacket struct {
}
func (p sshFxpDataPacket) MarshalBinary() ([]byte, error) {
b := []byte{ssh_FXP_DATA}
b := []byte{sshFxpData}
b = marshalUint32(b, p.ID)
b = marshalUint32(b, p.Length)
b = append(b, p.Data[:p.Length]...)
@ -823,7 +855,7 @@ func (p sshFxpStatvfsPacket) MarshalBinary() ([]byte, error) {
len("statvfs@openssh.com")
b := make([]byte, 0, l)
b = append(b, ssh_FXP_EXTENDED)
b = append(b, sshFxpExtended)
b = marshalUint32(b, p.ID)
b = marshalString(b, "statvfs@openssh.com")
b = marshalString(b, p.Path)
@ -856,10 +888,10 @@ func (p *StatVFS) FreeSpace() uint64 {
return p.Frsize * p.Bfree
}
// Convert to ssh_FXP_EXTENDED_REPLY packet binary format
// MarshalBinary converts to ssh_FXP_EXTENDED_REPLY packet binary format
func (p *StatVFS) MarshalBinary() ([]byte, error) {
var buf bytes.Buffer
buf.Write([]byte{ssh_FXP_EXTENDED_REPLY})
buf.Write([]byte{sshFxpExtendedReply})
err := binary.Write(&buf, binary.BigEndian, p)
return buf.Bytes(), err
}
@ -903,6 +935,8 @@ func (p *sshFxpExtendedPacket) UnmarshalBinary(b []byte) error {
p.SpecificPacket = &sshFxpExtendedPacketStatVFS{}
case "posix-rename@openssh.com":
p.SpecificPacket = &sshFxpExtendedPacketPosixRename{}
case "hardlink@openssh.com":
p.SpecificPacket = &sshFxpExtendedPacketHardlink{}
default:
return errors.Wrapf(errUnknownExtendedPacket, "packet type %v", p.SpecificPacket)
}
@ -957,3 +991,32 @@ func (p sshFxpExtendedPacketPosixRename) respond(s *Server) responsePacket {
err := os.Rename(p.Oldpath, p.Newpath)
return statusFromError(p, err)
}
type sshFxpExtendedPacketHardlink struct {
ID uint32
ExtendedRequest string
Oldpath string
Newpath string
}
// https://github.com/openssh/openssh-portable/blob/master/PROTOCOL
func (p sshFxpExtendedPacketHardlink) id() uint32 { return p.ID }
func (p sshFxpExtendedPacketHardlink) readonly() bool { return true }
func (p *sshFxpExtendedPacketHardlink) UnmarshalBinary(b []byte) error {
var err error
if p.ID, b, err = unmarshalUint32Safe(b); err != nil {
return err
} else if p.ExtendedRequest, b, err = unmarshalStringSafe(b); err != nil {
return err
} else if p.Oldpath, b, err = unmarshalStringSafe(b); err != nil {
return err
} else if p.Newpath, _, err = unmarshalStringSafe(b); err != nil {
return err
}
return nil
}
func (p sshFxpExtendedPacketHardlink) respond(s *Server) responsePacket {
err := os.Link(p.Oldpath, p.Newpath)
return statusFromError(p, err)
}

View file

@ -5,7 +5,7 @@ package sftp
// request and AttrFlags() and Attributes() when working with SetStat requests.
import "os"
// File Open and Write Flags. Correlate directly with with os.OpenFile flags
// FileOpenFlags defines Open and Write Flags. Correlate directly with with os.OpenFile flags
// (https://golang.org/pkg/os/#pkg-constants).
type FileOpenFlags struct {
Read, Write, Append, Creat, Trunc, Excl bool
@ -13,12 +13,12 @@ type FileOpenFlags struct {
func newFileOpenFlags(flags uint32) FileOpenFlags {
return FileOpenFlags{
Read: flags&ssh_FXF_READ != 0,
Write: flags&ssh_FXF_WRITE != 0,
Append: flags&ssh_FXF_APPEND != 0,
Creat: flags&ssh_FXF_CREAT != 0,
Trunc: flags&ssh_FXF_TRUNC != 0,
Excl: flags&ssh_FXF_EXCL != 0,
Read: flags&sshFxfRead != 0,
Write: flags&sshFxfWrite != 0,
Append: flags&sshFxfAppend != 0,
Creat: flags&sshFxfCreat != 0,
Trunc: flags&sshFxfTrunc != 0,
Excl: flags&sshFxfExcl != 0,
}
}
@ -28,7 +28,7 @@ func (r *Request) Pflags() FileOpenFlags {
return newFileOpenFlags(r.Flags)
}
// Flags that indicate whether SFTP file attributes were passed. When a flag is
// FileAttrFlags that indicate whether SFTP file attributes were passed. When a flag is
// true the corresponding attribute should be available from the FileStat
// object returned by Attributes method. Used with SetStat.
type FileAttrFlags struct {
@ -37,14 +37,14 @@ type FileAttrFlags struct {
func newFileAttrFlags(flags uint32) FileAttrFlags {
return FileAttrFlags{
Size: (flags & ssh_FILEXFER_ATTR_SIZE) != 0,
UidGid: (flags & ssh_FILEXFER_ATTR_UIDGID) != 0,
Permissions: (flags & ssh_FILEXFER_ATTR_PERMISSIONS) != 0,
Acmodtime: (flags & ssh_FILEXFER_ATTR_ACMODTIME) != 0,
Size: (flags & sshFileXferAttrSize) != 0,
UidGid: (flags & sshFileXferAttrUIDGID) != 0,
Permissions: (flags & sshFileXferAttrPermissions) != 0,
Acmodtime: (flags & sshFileXferAttrACmodTime) != 0,
}
}
// FileAttrFlags returns a FileAttrFlags boolean struct based on the
// AttrFlags returns a FileAttrFlags boolean struct based on the
// bitmap/uint32 file attribute flags from the SFTP packaet.
func (r *Request) AttrFlags() FileAttrFlags {
return newFileAttrFlags(r.Flags)
@ -55,7 +55,7 @@ func (a FileStat) FileMode() os.FileMode {
return os.FileMode(a.Mode)
}
// Attributres parses file attributes byte blob and return them in a
// Attributes parses file attributes byte blob and return them in a
// FileStat object.
func (r *Request) Attributes() *FileStat {
fs, _ := getFileStat(r.Flags, r.Attrs)

View file

@ -1,40 +1,52 @@
package sftp
type fxerr uint32
// Error types that match the SFTP's SSH_FXP_STATUS codes. Gives you more
// direct control of the errors being sent vs. letting the library work them
// out from the standard os/io errors.
type fxerr uint32
const (
ErrSshFxOk = fxerr(ssh_FX_OK)
ErrSshFxEof = fxerr(ssh_FX_EOF)
ErrSshFxNoSuchFile = fxerr(ssh_FX_NO_SUCH_FILE)
ErrSshFxPermissionDenied = fxerr(ssh_FX_PERMISSION_DENIED)
ErrSshFxFailure = fxerr(ssh_FX_FAILURE)
ErrSshFxBadMessage = fxerr(ssh_FX_BAD_MESSAGE)
ErrSshFxNoConnection = fxerr(ssh_FX_NO_CONNECTION)
ErrSshFxConnectionLost = fxerr(ssh_FX_CONNECTION_LOST)
ErrSshFxOpUnsupported = fxerr(ssh_FX_OP_UNSUPPORTED)
ErrSSHFxOk = fxerr(sshFxOk)
ErrSSHFxEOF = fxerr(sshFxEOF)
ErrSSHFxNoSuchFile = fxerr(sshFxNoSuchFile)
ErrSSHFxPermissionDenied = fxerr(sshFxPermissionDenied)
ErrSSHFxFailure = fxerr(sshFxFailure)
ErrSSHFxBadMessage = fxerr(sshFxBadMessage)
ErrSSHFxNoConnection = fxerr(sshFxNoConnection)
ErrSSHFxConnectionLost = fxerr(sshFxConnectionLost)
ErrSSHFxOpUnsupported = fxerr(sshFxOPUnsupported)
)
// Deprecated error types, these are aliases for the new ones, please use the new ones directly
const (
ErrSshFxOk = ErrSSHFxOk
ErrSshFxEof = ErrSSHFxEOF
ErrSshFxNoSuchFile = ErrSSHFxNoSuchFile
ErrSshFxPermissionDenied = ErrSSHFxPermissionDenied
ErrSshFxFailure = ErrSSHFxFailure
ErrSshFxBadMessage = ErrSSHFxBadMessage
ErrSshFxNoConnection = ErrSSHFxNoConnection
ErrSshFxConnectionLost = ErrSSHFxConnectionLost
ErrSshFxOpUnsupported = ErrSSHFxOpUnsupported
)
func (e fxerr) Error() string {
switch e {
case ErrSshFxOk:
case ErrSSHFxOk:
return "OK"
case ErrSshFxEof:
case ErrSSHFxEOF:
return "EOF"
case ErrSshFxNoSuchFile:
case ErrSSHFxNoSuchFile:
return "No Such File"
case ErrSshFxPermissionDenied:
case ErrSSHFxPermissionDenied:
return "Permission Denied"
case ErrSshFxBadMessage:
case ErrSSHFxBadMessage:
return "Bad Message"
case ErrSshFxNoConnection:
case ErrSSHFxNoConnection:
return "No Connection"
case ErrSshFxConnectionLost:
case ErrSSHFxConnectionLost:
return "Connection Lost"
case ErrSshFxOpUnsupported:
case ErrSSHFxOpUnsupported:
return "Operation Unsupported"
default:
return "Failure"

View file

@ -11,6 +11,7 @@ import (
"os"
"path/filepath"
"sort"
"strings"
"sync"
"syscall"
"time"
@ -90,18 +91,51 @@ func (fs *root) Filecmd(r *Request) error {
file.name = r.Target
fs.files[r.Target] = file
delete(fs.files, r.Filepath)
if file.IsDir() {
for path, file := range fs.files {
if strings.HasPrefix(path, r.Filepath+"/") {
file.name = r.Target + path[len(r.Filepath):]
fs.files[r.Target+path[len(r.Filepath):]] = file
delete(fs.files, path)
}
}
}
case "Rmdir", "Remove":
_, err := fs.fetch(filepath.Dir(r.Filepath))
file, err := fs.fetch(filepath.Dir(r.Filepath))
if err != nil {
return err
}
if file.IsDir() {
for path := range fs.files {
if strings.HasPrefix(path, r.Filepath+"/") {
return &os.PathError{
Op: "remove",
Path: r.Filepath + "/",
Err: fmt.Errorf("directory is not empty"),
}
}
}
}
delete(fs.files, r.Filepath)
case "Mkdir":
_, err := fs.fetch(filepath.Dir(r.Filepath))
if err != nil {
return err
}
fs.files[r.Filepath] = newMemFile(r.Filepath, true)
case "Link":
file, err := fs.fetch(r.Filepath)
if err != nil {
return err
}
if file.IsDir() {
return fmt.Errorf("hard link not allowed for directory")
}
fs.files[r.Target] = file
case "Symlink":
_, err := fs.fetch(r.Filepath)
if err != nil {
@ -147,15 +181,15 @@ func (fs *root) Filelist(r *Request) (ListerAt, error) {
if !file.IsDir() {
return nil, syscall.ENOTDIR
}
ordered_names := []string{}
for fn, _ := range fs.files {
orderedNames := []string{}
for fn := range fs.files {
if filepath.Dir(fn) == r.Filepath {
ordered_names = append(ordered_names, fn)
orderedNames = append(orderedNames, fn)
}
}
sort.Strings(ordered_names)
list := make([]os.FileInfo, len(ordered_names))
for i, fn := range ordered_names {
sort.Strings(orderedNames)
list := make([]os.FileInfo, len(orderedNames))
for i, fn := range orderedNames {
list[i] = fs.files[fn]
}
return listerat(list), nil
@ -199,13 +233,15 @@ func (fs *root) fetch(path string) (*memFile, error) {
// Implements os.FileInfo, Reader and Writer interfaces.
// These are the 3 interfaces necessary for the Handlers.
// Implements the optional interface TransferError.
type memFile struct {
name string
modtime time.Time
symlink string
isdir bool
content []byte
contentLock sync.RWMutex
name string
modtime time.Time
symlink string
isdir bool
content []byte
transferError error
contentLock sync.RWMutex
}
// factory to make sure modtime is set
@ -265,3 +301,7 @@ func (f *memFile) WriteAt(p []byte, off int64) (int, error) {
copy(f.content[off:], p)
return len(p), nil
}
func (f *memFile) TransferError(err error) {
f.transferError = err
}

View file

@ -25,6 +25,8 @@ type FileReader interface {
// The request server code will call Close() on the returned io.WriterAt
// ojbect if an io.Closer type assertion succeeds.
// Note in cases of an error, the error text will be sent to the client.
// Note when receiving an Append flag it is important to not open files using
// O_APPEND if you plan to use WriteAt, as they conflict.
// Called for Methods: Put, Open
type FileWriter interface {
Filewrite(*Request) (io.WriterAt, error)
@ -32,7 +34,7 @@ type FileWriter interface {
// FileCmder should return an error
// Note in cases of an error, the error text will be sent to the client.
// Called for Methods: Setstat, Rename, Rmdir, Mkdir, Symlink, Remove
// Called for Methods: Setstat, Rename, Rmdir, Mkdir, Link, Symlink, Remove
type FileCmder interface {
Filecmd(*Request) error
}
@ -53,3 +55,10 @@ type FileLister interface {
type ListerAt interface {
ListAt([]os.FileInfo, int64) (int, error)
}
// TransferError is an optional interface that readerAt and writerAt
// can implement to be notified about the error causing Serve() to exit
// with the request still open
type TransferError interface {
TransferError(err error)
}

View file

@ -116,11 +116,7 @@ func (rs *RequestServer) Serve() error {
if err != nil {
switch errors.Cause(err) {
case errUnknownExtendedPacket:
if err := rs.serverConn.sendError(pkt, ErrSshFxOpUnsupported); err != nil {
debug("failed to send err packet: %v", err)
rs.conn.Close() // shuts down recvPacket
break
}
// do nothing
default:
debug("makePacket err: %v", err)
rs.conn.Close() // shuts down recvPacket
@ -137,6 +133,20 @@ func (rs *RequestServer) Serve() error {
// make sure all open requests are properly closed
// (eg. possible on dropped connections, client crashes, etc.)
for handle, req := range rs.openRequests {
if err != nil {
req.state.RLock()
writer := req.state.writerAt
reader := req.state.readerAt
req.state.RUnlock()
if t, ok := writer.(TransferError); ok {
debug("notify error: %v to writer: %v\n", err, writer)
t.TransferError(err)
}
if t, ok := reader.(TransferError); ok {
debug("notify error: %v to reader: %v\n", err, reader)
t.TransferError(err)
}
}
delete(rs.openRequests, handle)
req.close()
}
@ -148,10 +158,16 @@ func (rs *RequestServer) packetWorker(
ctx context.Context, pktChan chan orderedRequest,
) error {
for pkt := range pktChan {
if epkt, ok := pkt.requestPacket.(*sshFxpExtendedPacket); ok {
if epkt.SpecificPacket != nil {
pkt.requestPacket = epkt.SpecificPacket
}
}
var rpkt responsePacket
switch pkt := pkt.requestPacket.(type) {
case *sshFxInitPacket:
rpkt = sshFxVersionPacket{Version: sftpProtocolVersion}
rpkt = sshFxVersionPacket{Version: sftpProtocolVersion, Extensions: sftpExtensions}
case *sshFxpClosePacket:
handle := pkt.getHandle()
rpkt = statusFromError(pkt, rs.closeRequest(handle))
@ -174,6 +190,10 @@ func (rs *RequestServer) packetWorker(
request = NewRequest("Stat", request.Filepath)
rpkt = request.call(rs.Handlers, pkt)
}
case *sshFxpExtendedPacketPosixRename:
request := NewRequest("Rename", pkt.Oldpath)
request.Target = pkt.Newpath
rpkt = request.call(rs.Handlers, pkt)
case hasHandle:
handle := pkt.getHandle()
request, ok := rs.getRequest(handle)
@ -187,11 +207,11 @@ func (rs *RequestServer) packetWorker(
rpkt = request.call(rs.Handlers, pkt)
request.close()
default:
return errors.Errorf("unexpected packet type %T", pkt)
rpkt = statusFromError(pkt, ErrSSHFxOpUnsupported)
}
rs.pktMgr.readyPacket(
rs.pktMgr.newOrderedResponse(rpkt, pkt.orderId()))
rs.pktMgr.newOrderedResponse(rpkt, pkt.orderID()))
}
return nil
}

View file

@ -14,10 +14,10 @@ func fakeFileInfoSys() interface{} {
func testOsSys(sys interface{}) error {
fstat := sys.(*FileStat)
if fstat.UID != uint32(65534) {
return errors.New("Uid failed to match.")
return errors.New("Uid failed to match")
}
if fstat.GID != uint32(65534) {
return errors.New("Gid failed to match:")
return errors.New("Gid failed to match")
}
return nil
}

View file

@ -18,7 +18,7 @@ var MaxFilelist int64 = 100
// Request contains the data and state for the incoming service request.
type Request struct {
// Get, Put, Setstat, Stat, Rename, Remove
// Rmdir, Mkdir, List, Readlink, Symlink
// Rmdir, Mkdir, List, Readlink, Link, Symlink
Method string
Filepath string
Flags uint32
@ -56,6 +56,8 @@ func requestFromPacket(ctx context.Context, pkt hasPath) *Request {
request.Target = cleanPath(p.Newpath)
case *sshFxpSymlinkPacket:
request.Target = cleanPath(p.Linkpath)
case *sshFxpExtendedPacketHardlink:
request.Target = cleanPath(p.Newpath)
}
return request
}
@ -158,7 +160,7 @@ func (r *Request) call(handlers Handlers, pkt requestPacket) responsePacket {
return fileget(handlers.FileGet, r, pkt)
case "Put":
return fileput(handlers.FilePut, r, pkt)
case "Setstat", "Rename", "Rmdir", "Mkdir", "Symlink", "Remove":
case "Setstat", "Rename", "Rmdir", "Mkdir", "Link", "Symlink", "Remove":
return filecmd(handlers.FileCmd, r, pkt)
case "List":
return filelist(handlers.FileList, r, pkt)
@ -378,6 +380,8 @@ func requestMethod(p requestPacket) (method string) {
method = "Readlink"
case *sshFxpMkdirPacket:
method = "Mkdir"
case *sshFxpExtendedPacketHardlink:
method = "Link"
}
return method
}

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

@ -18,6 +18,7 @@ import (
)
const (
// SftpServerWorkerCount defines the number of workers for the SFTP server
SftpServerWorkerCount = 8
)
@ -141,7 +142,7 @@ func (svr *Server) sftpServerWorker(pktChan chan orderedRequest) error {
if !readonly && svr.readOnly {
svr.sendPacket(orderedResponse{
responsePacket: statusFromError(pkt, syscall.EPERM),
orderid: pkt.orderId()})
orderid: pkt.orderID()})
continue
}
@ -156,7 +157,10 @@ func handlePacket(s *Server, p orderedRequest) error {
var rpkt responsePacket
switch p := p.requestPacket.(type) {
case *sshFxInitPacket:
rpkt = sshFxVersionPacket{Version: sftpProtocolVersion}
rpkt = sshFxVersionPacket{
Version: sftpProtocolVersion,
Extensions: sftpExtensions,
}
case *sshFxpStatPacket:
// stat the requested file
info, err := os.Stat(p.Path)
@ -246,7 +250,7 @@ func handlePacket(s *Server, p orderedRequest) error {
rpkt = sshFxpOpenPacket{
ID: p.ID,
Path: p.Path,
Pflags: ssh_FXF_READ,
Pflags: sshFxfRead,
}.respond(s)
}
case *sshFxpReadPacket:
@ -276,13 +280,19 @@ func handlePacket(s *Server, p orderedRequest) error {
_, err = f.WriteAt(p.Data, int64(p.Offset))
}
rpkt = statusFromError(p, err)
case *sshFxpExtendedPacket:
if p.SpecificPacket == nil {
rpkt = statusFromError(p, ErrSSHFxOpUnsupported)
} else {
rpkt = p.respond(s)
}
case serverRespondablePacket:
rpkt = p.respond(s)
default:
return errors.Errorf("unexpected packet type %T", p)
}
s.pktMgr.readyPacket(s.pktMgr.newOrderedResponse(rpkt, p.orderId()))
s.pktMgr.readyPacket(s.pktMgr.newOrderedResponse(rpkt, p.orderID()))
return nil
}
@ -315,11 +325,11 @@ func (svr *Server) Serve() error {
if err != nil {
switch errors.Cause(err) {
case errUnknownExtendedPacket:
if err := svr.serverConn.sendError(pkt, ErrSshFxOpUnsupported); err != nil {
debug("failed to send err packet: %v", err)
svr.conn.Close() // shuts down recvPacket
break
}
//if err := svr.serverConn.sendError(pkt, ErrSshFxOpUnsupported); err != nil {
// debug("failed to send err packet: %v", err)
// svr.conn.Close() // shuts down recvPacket
// break
//}
default:
debug("makePacket err: %v", err)
svr.conn.Close() // shuts down recvPacket
@ -354,7 +364,7 @@ type sshFxpStatResponse struct {
}
func (p sshFxpStatResponse) MarshalBinary() ([]byte, error) {
b := []byte{ssh_FXP_ATTRS}
b := []byte{sshFxpAttrs}
b = marshalUint32(b, p.ID)
b = marshalFileInfo(b, p.info)
return b, nil
@ -363,7 +373,7 @@ func (p sshFxpStatResponse) MarshalBinary() ([]byte, error) {
var emptyFileStat = []interface{}{uint32(0)}
func (p sshFxpOpenPacket) readonly() bool {
return !p.hasPflags(ssh_FXF_WRITE)
return !p.hasPflags(sshFxfWrite)
}
func (p sshFxpOpenPacket) hasPflags(flags ...uint32) bool {
@ -377,27 +387,27 @@ func (p sshFxpOpenPacket) hasPflags(flags ...uint32) bool {
func (p sshFxpOpenPacket) respond(svr *Server) responsePacket {
var osFlags int
if p.hasPflags(ssh_FXF_READ, ssh_FXF_WRITE) {
if p.hasPflags(sshFxfRead, sshFxfWrite) {
osFlags |= os.O_RDWR
} else if p.hasPflags(ssh_FXF_WRITE) {
} else if p.hasPflags(sshFxfWrite) {
osFlags |= os.O_WRONLY
} else if p.hasPflags(ssh_FXF_READ) {
} else if p.hasPflags(sshFxfRead) {
osFlags |= os.O_RDONLY
} else {
// how are they opening?
return statusFromError(p, syscall.EINVAL)
}
if p.hasPflags(ssh_FXF_APPEND) {
osFlags |= os.O_APPEND
}
if p.hasPflags(ssh_FXF_CREAT) {
// Don't use O_APPEND flag as it conflicts with WriteAt.
// The sshFxfAppend flag is a no-op here as the client sends the offsets.
if p.hasPflags(sshFxfCreat) {
osFlags |= os.O_CREATE
}
if p.hasPflags(ssh_FXF_TRUNC) {
if p.hasPflags(sshFxfTrunc) {
osFlags |= os.O_TRUNC
}
if p.hasPflags(ssh_FXF_EXCL) {
if p.hasPflags(sshFxfExcl) {
osFlags |= os.O_EXCL
}
@ -439,19 +449,19 @@ func (p sshFxpSetstatPacket) respond(svr *Server) responsePacket {
var err error
debug("setstat name \"%s\"", p.Path)
if (p.Flags & ssh_FILEXFER_ATTR_SIZE) != 0 {
if (p.Flags & sshFileXferAttrSize) != 0 {
var size uint64
if size, b, err = unmarshalUint64Safe(b); err == nil {
err = os.Truncate(p.Path, int64(size))
}
}
if (p.Flags & ssh_FILEXFER_ATTR_PERMISSIONS) != 0 {
if (p.Flags & sshFileXferAttrPermissions) != 0 {
var mode uint32
if mode, b, err = unmarshalUint32Safe(b); err == nil {
err = os.Chmod(p.Path, os.FileMode(mode))
}
}
if (p.Flags & ssh_FILEXFER_ATTR_ACMODTIME) != 0 {
if (p.Flags & sshFileXferAttrACmodTime) != 0 {
var atime uint32
var mtime uint32
if atime, b, err = unmarshalUint32Safe(b); err != nil {
@ -462,7 +472,7 @@ func (p sshFxpSetstatPacket) respond(svr *Server) responsePacket {
err = os.Chtimes(p.Path, atimeT, mtimeT)
}
}
if (p.Flags & ssh_FILEXFER_ATTR_UIDGID) != 0 {
if (p.Flags & sshFileXferAttrUIDGID) != 0 {
var uid uint32
var gid uint32
if uid, b, err = unmarshalUint32Safe(b); err != nil {
@ -486,19 +496,19 @@ func (p sshFxpFsetstatPacket) respond(svr *Server) responsePacket {
var err error
debug("fsetstat name \"%s\"", f.Name())
if (p.Flags & ssh_FILEXFER_ATTR_SIZE) != 0 {
if (p.Flags & sshFileXferAttrSize) != 0 {
var size uint64
if size, b, err = unmarshalUint64Safe(b); err == nil {
err = f.Truncate(int64(size))
}
}
if (p.Flags & ssh_FILEXFER_ATTR_PERMISSIONS) != 0 {
if (p.Flags & sshFileXferAttrPermissions) != 0 {
var mode uint32
if mode, b, err = unmarshalUint32Safe(b); err == nil {
err = f.Chmod(os.FileMode(mode))
}
}
if (p.Flags & ssh_FILEXFER_ATTR_ACMODTIME) != 0 {
if (p.Flags & sshFileXferAttrACmodTime) != 0 {
var atime uint32
var mtime uint32
if atime, b, err = unmarshalUint32Safe(b); err != nil {
@ -509,7 +519,7 @@ func (p sshFxpFsetstatPacket) respond(svr *Server) responsePacket {
err = os.Chtimes(f.Name(), atimeT, mtimeT)
}
}
if (p.Flags & ssh_FILEXFER_ATTR_UIDGID) != 0 {
if (p.Flags & sshFileXferAttrUIDGID) != 0 {
var uid uint32
var gid uint32
if uid, b, err = unmarshalUint32Safe(b); err != nil {
@ -526,30 +536,30 @@ func (p sshFxpFsetstatPacket) respond(svr *Server) responsePacket {
func translateErrno(errno syscall.Errno) uint32 {
switch errno {
case 0:
return ssh_FX_OK
return sshFxOk
case syscall.ENOENT:
return ssh_FX_NO_SUCH_FILE
return sshFxNoSuchFile
case syscall.EPERM:
return ssh_FX_PERMISSION_DENIED
return sshFxPermissionDenied
}
return ssh_FX_FAILURE
return sshFxFailure
}
func statusFromError(p ider, err error) sshFxpStatusPacket {
ret := sshFxpStatusPacket{
ID: p.id(),
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
Code: ssh_FX_OK,
// sshFXOk = 0
// sshFXEOF = 1
// sshFXNoSuchFile = 2 ENOENT
// sshFXPermissionDenied = 3
// sshFXFailure = 4
// sshFXBadMessage = 5
// sshFXNoConnection = 6
// sshFXConnectionLost = 7
// sshFXOPUnsupported = 8
Code: sshFxOk,
},
}
if err == nil {
@ -557,7 +567,7 @@ func statusFromError(p ider, err error) sshFxpStatusPacket {
}
debug("statusFromError: error is %T %#v", err, err)
ret.StatusError.Code = ssh_FX_FAILURE
ret.StatusError.Code = sshFxFailure
ret.StatusError.msg = err.Error()
switch e := err.(type) {
@ -573,9 +583,9 @@ func statusFromError(p ider, err error) sshFxpStatusPacket {
default:
switch e {
case io.EOF:
ret.StatusError.Code = ssh_FX_EOF
ret.StatusError.Code = sshFxEOF
case os.ErrNotExist:
ret.StatusError.Code = ssh_FX_NO_SUCH_FILE
ret.StatusError.Code = sshFxNoSuchFile
}
}

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

@ -9,139 +9,148 @@ import (
)
const (
ssh_FXP_INIT = 1
ssh_FXP_VERSION = 2
ssh_FXP_OPEN = 3
ssh_FXP_CLOSE = 4
ssh_FXP_READ = 5
ssh_FXP_WRITE = 6
ssh_FXP_LSTAT = 7
ssh_FXP_FSTAT = 8
ssh_FXP_SETSTAT = 9
ssh_FXP_FSETSTAT = 10
ssh_FXP_OPENDIR = 11
ssh_FXP_READDIR = 12
ssh_FXP_REMOVE = 13
ssh_FXP_MKDIR = 14
ssh_FXP_RMDIR = 15
ssh_FXP_REALPATH = 16
ssh_FXP_STAT = 17
ssh_FXP_RENAME = 18
ssh_FXP_READLINK = 19
ssh_FXP_SYMLINK = 20
ssh_FXP_STATUS = 101
ssh_FXP_HANDLE = 102
ssh_FXP_DATA = 103
ssh_FXP_NAME = 104
ssh_FXP_ATTRS = 105
ssh_FXP_EXTENDED = 200
ssh_FXP_EXTENDED_REPLY = 201
sshFxpInit = 1
sshFxpVersion = 2
sshFxpOpen = 3
sshFxpClose = 4
sshFxpRead = 5
sshFxpWrite = 6
sshFxpLstat = 7
sshFxpFstat = 8
sshFxpSetstat = 9
sshFxpFsetstat = 10
sshFxpOpendir = 11
sshFxpReaddir = 12
sshFxpRemove = 13
sshFxpMkdir = 14
sshFxpRmdir = 15
sshFxpRealpath = 16
sshFxpStat = 17
sshFxpRename = 18
sshFxpReadlink = 19
sshFxpSymlink = 20
sshFxpStatus = 101
sshFxpHandle = 102
sshFxpData = 103
sshFxpName = 104
sshFxpAttrs = 105
sshFxpExtended = 200
sshFxpExtendedReply = 201
)
const (
ssh_FX_OK = 0
ssh_FX_EOF = 1
ssh_FX_NO_SUCH_FILE = 2
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
sshFxOk = 0
sshFxEOF = 1
sshFxNoSuchFile = 2
sshFxPermissionDenied = 3
sshFxFailure = 4
sshFxBadMessage = 5
sshFxNoConnection = 6
sshFxConnectionLost = 7
sshFxOPUnsupported = 8
// see draft-ietf-secsh-filexfer-13
// https://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-9.1
ssh_FX_INVALID_HANDLE = 9
ssh_FX_NO_SUCH_PATH = 10
ssh_FX_FILE_ALREADY_EXISTS = 11
ssh_FX_WRITE_PROTECT = 12
ssh_FX_NO_MEDIA = 13
ssh_FX_NO_SPACE_ON_FILESYSTEM = 14
ssh_FX_QUOTA_EXCEEDED = 15
ssh_FX_UNKNOWN_PRINCIPAL = 16
ssh_FX_LOCK_CONFLICT = 17
ssh_FX_DIR_NOT_EMPTY = 18
ssh_FX_NOT_A_DIRECTORY = 19
ssh_FX_INVALID_FILENAME = 20
ssh_FX_LINK_LOOP = 21
ssh_FX_CANNOT_DELETE = 22
ssh_FX_INVALID_PARAMETER = 23
ssh_FX_FILE_IS_A_DIRECTORY = 24
ssh_FX_BYTE_RANGE_LOCK_CONFLICT = 25
ssh_FX_BYTE_RANGE_LOCK_REFUSED = 26
ssh_FX_DELETE_PENDING = 27
ssh_FX_FILE_CORRUPT = 28
ssh_FX_OWNER_INVALID = 29
ssh_FX_GROUP_INVALID = 30
ssh_FX_NO_MATCHING_BYTE_RANGE_LOCK = 31
sshFxInvalidHandle = 9
sshFxNoSuchPath = 10
sshFxFileAlreadyExists = 11
sshFxWriteProtect = 12
sshFxNoMedia = 13
sshFxNoSpaceOnFilesystem = 14
sshFxQuotaExceeded = 15
sshFxUnlnownPrincipal = 16
sshFxLockConflict = 17
sshFxDitNotEmpty = 18
sshFxNotADirectory = 19
sshFxInvalidFilename = 20
sshFxLinkLoop = 21
sshFxCannotDelete = 22
sshFxInvalidParameter = 23
sshFxFileIsADirectory = 24
sshFxByteRangeLockConflict = 25
sshFxByteRangeLockRefused = 26
sshFxDeletePending = 27
sshFxFileCorrupt = 28
sshFxOwnerInvalid = 29
sshFxGroupInvalid = 30
sshFxNoMatchingByteRangeLock = 31
)
const (
ssh_FXF_READ = 0x00000001
ssh_FXF_WRITE = 0x00000002
ssh_FXF_APPEND = 0x00000004
ssh_FXF_CREAT = 0x00000008
ssh_FXF_TRUNC = 0x00000010
ssh_FXF_EXCL = 0x00000020
sshFxfRead = 0x00000001
sshFxfWrite = 0x00000002
sshFxfAppend = 0x00000004
sshFxfCreat = 0x00000008
sshFxfTrunc = 0x00000010
sshFxfExcl = 0x00000020
)
var (
// supportedSFTPExtensions defines the supported extensions
supportedSFTPExtensions = []sshExtensionPair{
{"hardlink@openssh.com", "1"},
{"posix-rename@openssh.com", "1"},
}
sftpExtensions = supportedSFTPExtensions
)
type fxp uint8
func (f fxp) String() string {
switch f {
case ssh_FXP_INIT:
case sshFxpInit:
return "SSH_FXP_INIT"
case ssh_FXP_VERSION:
case sshFxpVersion:
return "SSH_FXP_VERSION"
case ssh_FXP_OPEN:
case sshFxpOpen:
return "SSH_FXP_OPEN"
case ssh_FXP_CLOSE:
case sshFxpClose:
return "SSH_FXP_CLOSE"
case ssh_FXP_READ:
case sshFxpRead:
return "SSH_FXP_READ"
case ssh_FXP_WRITE:
case sshFxpWrite:
return "SSH_FXP_WRITE"
case ssh_FXP_LSTAT:
case sshFxpLstat:
return "SSH_FXP_LSTAT"
case ssh_FXP_FSTAT:
case sshFxpFstat:
return "SSH_FXP_FSTAT"
case ssh_FXP_SETSTAT:
case sshFxpSetstat:
return "SSH_FXP_SETSTAT"
case ssh_FXP_FSETSTAT:
case sshFxpFsetstat:
return "SSH_FXP_FSETSTAT"
case ssh_FXP_OPENDIR:
case sshFxpOpendir:
return "SSH_FXP_OPENDIR"
case ssh_FXP_READDIR:
case sshFxpReaddir:
return "SSH_FXP_READDIR"
case ssh_FXP_REMOVE:
case sshFxpRemove:
return "SSH_FXP_REMOVE"
case ssh_FXP_MKDIR:
case sshFxpMkdir:
return "SSH_FXP_MKDIR"
case ssh_FXP_RMDIR:
case sshFxpRmdir:
return "SSH_FXP_RMDIR"
case ssh_FXP_REALPATH:
case sshFxpRealpath:
return "SSH_FXP_REALPATH"
case ssh_FXP_STAT:
case sshFxpStat:
return "SSH_FXP_STAT"
case ssh_FXP_RENAME:
case sshFxpRename:
return "SSH_FXP_RENAME"
case ssh_FXP_READLINK:
case sshFxpReadlink:
return "SSH_FXP_READLINK"
case ssh_FXP_SYMLINK:
case sshFxpSymlink:
return "SSH_FXP_SYMLINK"
case ssh_FXP_STATUS:
case sshFxpStatus:
return "SSH_FXP_STATUS"
case ssh_FXP_HANDLE:
case sshFxpHandle:
return "SSH_FXP_HANDLE"
case ssh_FXP_DATA:
case sshFxpData:
return "SSH_FXP_DATA"
case ssh_FXP_NAME:
case sshFxpName:
return "SSH_FXP_NAME"
case ssh_FXP_ATTRS:
case sshFxpAttrs:
return "SSH_FXP_ATTRS"
case ssh_FXP_EXTENDED:
case sshFxpExtended:
return "SSH_FXP_EXTENDED"
case ssh_FXP_EXTENDED_REPLY:
case sshFxpExtendedReply:
return "SSH_FXP_EXTENDED_REPLY"
default:
return "unknown"
@ -152,23 +161,23 @@ type fx uint8
func (f fx) String() string {
switch f {
case ssh_FX_OK:
case sshFxOk:
return "SSH_FX_OK"
case ssh_FX_EOF:
case sshFxEOF:
return "SSH_FX_EOF"
case ssh_FX_NO_SUCH_FILE:
case sshFxNoSuchFile:
return "SSH_FX_NO_SUCH_FILE"
case ssh_FX_PERMISSION_DENIED:
case sshFxPermissionDenied:
return "SSH_FX_PERMISSION_DENIED"
case ssh_FX_FAILURE:
case sshFxFailure:
return "SSH_FX_FAILURE"
case ssh_FX_BAD_MESSAGE:
case sshFxBadMessage:
return "SSH_FX_BAD_MESSAGE"
case ssh_FX_NO_CONNECTION:
case sshFxNoConnection:
return "SSH_FX_NO_CONNECTION"
case ssh_FX_CONNECTION_LOST:
case sshFxConnectionLost:
return "SSH_FX_CONNECTION_LOST"
case ssh_FX_OP_UNSUPPORTED:
case sshFxOPUnsupported:
return "SSH_FX_OP_UNSUPPORTED"
default:
return "unknown"
@ -214,4 +223,37 @@ type StatusError struct {
msg, lang string
}
func (s *StatusError) Error() string { return fmt.Sprintf("sftp: %q (%v)", s.msg, fx(s.Code)) }
func (s *StatusError) Error() string {
return fmt.Sprintf("sftp: %q (%v)", s.msg, fx(s.Code))
}
// FxCode returns the error code typed to match against the exported codes
func (s *StatusError) FxCode() fxerr {
return fxerr(s.Code)
}
func getSupportedExtensionByName(extensionName string) (sshExtensionPair, error) {
for _, supportedExtension := range supportedSFTPExtensions {
if supportedExtension.Name == extensionName {
return supportedExtension, nil
}
}
return sshExtensionPair{}, fmt.Errorf("Unsupported extension: %v", extensionName)
}
// SetSFTPExtensions allows to customize the supported server extensions.
// See the variable supportedSFTPExtensions for supported extensions.
// This method accepts a slice of sshExtensionPair names for example 'hardlink@openssh.com'.
// If an invalid extension is given an error will be returned and nothing will be changed
func SetSFTPExtensions(extensions ...string) error {
tempExtensions := []sshExtensionPair{}
for _, extension := range extensions {
sftpExtension, err := getSupportedExtensionByName(extension)
if err != nil {
return err
}
tempExtensions = append(tempExtensions, sftpExtension)
}
sftpExtensions = tempExtensions
return nil
}

9
vendor/github.com/pkg/sftp/syscall_fixed.go generated vendored Normal file
View file

@ -0,0 +1,9 @@
// +build plan9 windows js,wasm
// Go defines S_IFMT on windows, plan9 and js/wasm as 0x1f000 instead of
// 0xf000. None of the the other S_IFxyz values include the "1" (in 0x1f000)
// which prevents them from matching the bitmask.
package sftp
const S_IFMT = 0xf000

8
vendor/github.com/pkg/sftp/syscall_good.go generated vendored Normal file
View file

@ -0,0 +1,8 @@
// +build !plan9,!windows
// +build !js !wasm
package sftp
import "syscall"
const S_IFMT = syscall.S_IFMT