| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258 |
- // Package sftp implements the SSH File Transfer Protocol as described in
- // https://filezilla-project.org/specs/draft-ietf-secsh-filexfer-02.txt
- package sftp
- import (
- "fmt"
- )
- const (
- 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 (
- 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
- sshFxInvalidHandle = 9
- sshFxNoSuchPath = 10
- sshFxFileAlreadyExists = 11
- sshFxWriteProtect = 12
- sshFxNoMedia = 13
- sshFxNoSpaceOnFilesystem = 14
- sshFxQuotaExceeded = 15
- sshFxUnknownPrincipal = 16
- sshFxLockConflict = 17
- sshFxDirNotEmpty = 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 (
- 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"},
- {"statvfs@openssh.com", "2"},
- }
- sftpExtensions = supportedSFTPExtensions
- )
- type fxp uint8
- func (f fxp) String() string {
- switch f {
- case sshFxpInit:
- return "SSH_FXP_INIT"
- case sshFxpVersion:
- return "SSH_FXP_VERSION"
- case sshFxpOpen:
- return "SSH_FXP_OPEN"
- case sshFxpClose:
- return "SSH_FXP_CLOSE"
- case sshFxpRead:
- return "SSH_FXP_READ"
- case sshFxpWrite:
- return "SSH_FXP_WRITE"
- case sshFxpLstat:
- return "SSH_FXP_LSTAT"
- case sshFxpFstat:
- return "SSH_FXP_FSTAT"
- case sshFxpSetstat:
- return "SSH_FXP_SETSTAT"
- case sshFxpFsetstat:
- return "SSH_FXP_FSETSTAT"
- case sshFxpOpendir:
- return "SSH_FXP_OPENDIR"
- case sshFxpReaddir:
- return "SSH_FXP_READDIR"
- case sshFxpRemove:
- return "SSH_FXP_REMOVE"
- case sshFxpMkdir:
- return "SSH_FXP_MKDIR"
- case sshFxpRmdir:
- return "SSH_FXP_RMDIR"
- case sshFxpRealpath:
- return "SSH_FXP_REALPATH"
- case sshFxpStat:
- return "SSH_FXP_STAT"
- case sshFxpRename:
- return "SSH_FXP_RENAME"
- case sshFxpReadlink:
- return "SSH_FXP_READLINK"
- case sshFxpSymlink:
- return "SSH_FXP_SYMLINK"
- case sshFxpStatus:
- return "SSH_FXP_STATUS"
- case sshFxpHandle:
- return "SSH_FXP_HANDLE"
- case sshFxpData:
- return "SSH_FXP_DATA"
- case sshFxpName:
- return "SSH_FXP_NAME"
- case sshFxpAttrs:
- return "SSH_FXP_ATTRS"
- case sshFxpExtended:
- return "SSH_FXP_EXTENDED"
- case sshFxpExtendedReply:
- return "SSH_FXP_EXTENDED_REPLY"
- default:
- return "unknown"
- }
- }
- type fx uint8
- func (f fx) String() string {
- switch f {
- case sshFxOk:
- return "SSH_FX_OK"
- case sshFxEOF:
- return "SSH_FX_EOF"
- case sshFxNoSuchFile:
- return "SSH_FX_NO_SUCH_FILE"
- case sshFxPermissionDenied:
- return "SSH_FX_PERMISSION_DENIED"
- case sshFxFailure:
- return "SSH_FX_FAILURE"
- case sshFxBadMessage:
- return "SSH_FX_BAD_MESSAGE"
- case sshFxNoConnection:
- return "SSH_FX_NO_CONNECTION"
- case sshFxConnectionLost:
- return "SSH_FX_CONNECTION_LOST"
- case sshFxOPUnsupported:
- 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 fmt.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 %d, got %d", u.want, u.got)
- }
- func unimplementedSeekWhence(whence int) error {
- return fmt.Errorf("sftp: unimplemented seek whence %d", whence)
- }
- func unexpectedCount(want, got uint32) error {
- return fmt.Errorf("sftp: unexpected count: want %d, got %d", 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
- }
- 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: %s", 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
- }
|