rclone/vendor/github.com/pkg/sftp/sftp.go

260 lines
6.5 KiB
Go
Raw Normal View History

2016-11-13 01:04:55 +01:00
// Package sftp implements the SSH File Transfer Protocol as described in
// https://tools.ietf.org/html/draft-ietf-secsh-filexfer-02
2016-11-13 01:04:55 +01:00
package sftp
import (
"fmt"
"github.com/pkg/errors"
)
const (
2020-02-25 15:20:57 +01:00
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
2016-11-13 01:04:55 +01:00
)
const (
2020-02-25 15:20:57 +01:00
sshFxOk = 0
sshFxEOF = 1
sshFxNoSuchFile = 2
sshFxPermissionDenied = 3
sshFxFailure = 4
sshFxBadMessage = 5
sshFxNoConnection = 6
sshFxConnectionLost = 7
sshFxOPUnsupported = 8
2016-11-13 01:04:55 +01:00
// see draft-ietf-secsh-filexfer-13
// https://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-9.1
2020-02-25 15:20:57 +01:00
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
2016-11-13 01:04:55 +01:00
)
const (
2020-02-25 15:20:57 +01:00
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
2016-11-13 01:04:55 +01:00
)
type fxp uint8
func (f fxp) String() string {
switch f {
2020-02-25 15:20:57 +01:00
case sshFxpInit:
2016-11-13 01:04:55 +01:00
return "SSH_FXP_INIT"
2020-02-25 15:20:57 +01:00
case sshFxpVersion:
2016-11-13 01:04:55 +01:00
return "SSH_FXP_VERSION"
2020-02-25 15:20:57 +01:00
case sshFxpOpen:
2016-11-13 01:04:55 +01:00
return "SSH_FXP_OPEN"
2020-02-25 15:20:57 +01:00
case sshFxpClose:
2016-11-13 01:04:55 +01:00
return "SSH_FXP_CLOSE"
2020-02-25 15:20:57 +01:00
case sshFxpRead:
2016-11-13 01:04:55 +01:00
return "SSH_FXP_READ"
2020-02-25 15:20:57 +01:00
case sshFxpWrite:
2016-11-13 01:04:55 +01:00
return "SSH_FXP_WRITE"
2020-02-25 15:20:57 +01:00
case sshFxpLstat:
2016-11-13 01:04:55 +01:00
return "SSH_FXP_LSTAT"
2020-02-25 15:20:57 +01:00
case sshFxpFstat:
2016-11-13 01:04:55 +01:00
return "SSH_FXP_FSTAT"
2020-02-25 15:20:57 +01:00
case sshFxpSetstat:
2016-11-13 01:04:55 +01:00
return "SSH_FXP_SETSTAT"
2020-02-25 15:20:57 +01:00
case sshFxpFsetstat:
2016-11-13 01:04:55 +01:00
return "SSH_FXP_FSETSTAT"
2020-02-25 15:20:57 +01:00
case sshFxpOpendir:
2016-11-13 01:04:55 +01:00
return "SSH_FXP_OPENDIR"
2020-02-25 15:20:57 +01:00
case sshFxpReaddir:
2016-11-13 01:04:55 +01:00
return "SSH_FXP_READDIR"
2020-02-25 15:20:57 +01:00
case sshFxpRemove:
2016-11-13 01:04:55 +01:00
return "SSH_FXP_REMOVE"
2020-02-25 15:20:57 +01:00
case sshFxpMkdir:
2016-11-13 01:04:55 +01:00
return "SSH_FXP_MKDIR"
2020-02-25 15:20:57 +01:00
case sshFxpRmdir:
2016-11-13 01:04:55 +01:00
return "SSH_FXP_RMDIR"
2020-02-25 15:20:57 +01:00
case sshFxpRealpath:
2016-11-13 01:04:55 +01:00
return "SSH_FXP_REALPATH"
2020-02-25 15:20:57 +01:00
case sshFxpStat:
2016-11-13 01:04:55 +01:00
return "SSH_FXP_STAT"
2020-02-25 15:20:57 +01:00
case sshFxpRename:
2016-11-13 01:04:55 +01:00
return "SSH_FXP_RENAME"
2020-02-25 15:20:57 +01:00
case sshFxpReadlink:
2016-11-13 01:04:55 +01:00
return "SSH_FXP_READLINK"
2020-02-25 15:20:57 +01:00
case sshFxpSymlink:
2016-11-13 01:04:55 +01:00
return "SSH_FXP_SYMLINK"
2020-02-25 15:20:57 +01:00
case sshFxpStatus:
2016-11-13 01:04:55 +01:00
return "SSH_FXP_STATUS"
2020-02-25 15:20:57 +01:00
case sshFxpHandle:
2016-11-13 01:04:55 +01:00
return "SSH_FXP_HANDLE"
2020-02-25 15:20:57 +01:00
case sshFxpData:
2016-11-13 01:04:55 +01:00
return "SSH_FXP_DATA"
2020-02-25 15:20:57 +01:00
case sshFxpName:
2016-11-13 01:04:55 +01:00
return "SSH_FXP_NAME"
2020-02-25 15:20:57 +01:00
case sshFxpAttrs:
2016-11-13 01:04:55 +01:00
return "SSH_FXP_ATTRS"
2020-02-25 15:20:57 +01:00
case sshFxpExtended:
2016-11-13 01:04:55 +01:00
return "SSH_FXP_EXTENDED"
2020-02-25 15:20:57 +01:00
case sshFxpExtendedReply:
2016-11-13 01:04:55 +01:00
return "SSH_FXP_EXTENDED_REPLY"
default:
return "unknown"
}
}
type fx uint8
func (f fx) String() string {
switch f {
2020-02-25 15:20:57 +01:00
case sshFxOk:
2016-11-13 01:04:55 +01:00
return "SSH_FX_OK"
2020-02-25 15:20:57 +01:00
case sshFxEOF:
2016-11-13 01:04:55 +01:00
return "SSH_FX_EOF"
2020-02-25 15:20:57 +01:00
case sshFxNoSuchFile:
2016-11-13 01:04:55 +01:00
return "SSH_FX_NO_SUCH_FILE"
2020-02-25 15:20:57 +01:00
case sshFxPermissionDenied:
2016-11-13 01:04:55 +01:00
return "SSH_FX_PERMISSION_DENIED"
2020-02-25 15:20:57 +01:00
case sshFxFailure:
2016-11-13 01:04:55 +01:00
return "SSH_FX_FAILURE"
2020-02-25 15:20:57 +01:00
case sshFxBadMessage:
2016-11-13 01:04:55 +01:00
return "SSH_FX_BAD_MESSAGE"
2020-02-25 15:20:57 +01:00
case sshFxNoConnection:
2016-11-13 01:04:55 +01:00
return "SSH_FX_NO_CONNECTION"
2020-02-25 15:20:57 +01:00
case sshFxConnectionLost:
2016-11-13 01:04:55 +01:00
return "SSH_FX_CONNECTION_LOST"
2020-02-25 15:20:57 +01:00
case sshFxOPUnsupported:
2016-11-13 01:04:55 +01:00
return "SSH_FX_OP_UNSUPPORTED"
default:
return "unknown"
}
}
type unexpectedPacketErr struct {
want, got uint8
}
func (u *unexpectedPacketErr) Error() string {
return fmt.Sprintf("sftp: unexpected packet: want %v, got %v", fxp(u.want), fxp(u.got))
}
func unimplementedPacketErr(u uint8) error {
return errors.Errorf("sftp: unimplemented packet type: got %v", fxp(u))
}
type unexpectedIDErr struct{ want, got uint32 }
func (u *unexpectedIDErr) Error() string {
return fmt.Sprintf("sftp: unexpected id: want %v, got %v", u.want, u.got)
}
func unimplementedSeekWhence(whence int) error {
return errors.Errorf("sftp: unimplemented seek whence %v", whence)
}
func unexpectedCount(want, got uint32) error {
return errors.Errorf("sftp: unexpected count: want %v, got %v", want, got)
}
type unexpectedVersionErr struct{ want, got uint32 }
func (u *unexpectedVersionErr) Error() string {
return fmt.Sprintf("sftp: unexpected server version: want %v, got %v", u.want, u.got)
}
// A StatusError is returned when an SFTP operation fails, and provides
// additional information about the failure.
type StatusError struct {
Code uint32
msg, lang string
}
2020-02-25 15:20:57 +01:00
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
}