1// Package sftp implements the SSH File Transfer Protocol as described in 2// https://tools.ietf.org/html/draft-ietf-secsh-filexfer-02 3package sftp 4 5import ( 6 "fmt" 7 8 "github.com/pkg/errors" 9) 10 11const ( 12 ssh_FXP_INIT = 1 13 ssh_FXP_VERSION = 2 14 ssh_FXP_OPEN = 3 15 ssh_FXP_CLOSE = 4 16 ssh_FXP_READ = 5 17 ssh_FXP_WRITE = 6 18 ssh_FXP_LSTAT = 7 19 ssh_FXP_FSTAT = 8 20 ssh_FXP_SETSTAT = 9 21 ssh_FXP_FSETSTAT = 10 22 ssh_FXP_OPENDIR = 11 23 ssh_FXP_READDIR = 12 24 ssh_FXP_REMOVE = 13 25 ssh_FXP_MKDIR = 14 26 ssh_FXP_RMDIR = 15 27 ssh_FXP_REALPATH = 16 28 ssh_FXP_STAT = 17 29 ssh_FXP_RENAME = 18 30 ssh_FXP_READLINK = 19 31 ssh_FXP_SYMLINK = 20 32 ssh_FXP_STATUS = 101 33 ssh_FXP_HANDLE = 102 34 ssh_FXP_DATA = 103 35 ssh_FXP_NAME = 104 36 ssh_FXP_ATTRS = 105 37 ssh_FXP_EXTENDED = 200 38 ssh_FXP_EXTENDED_REPLY = 201 39) 40 41const ( 42 ssh_FX_OK = 0 43 ssh_FX_EOF = 1 44 ssh_FX_NO_SUCH_FILE = 2 45 ssh_FX_PERMISSION_DENIED = 3 46 ssh_FX_FAILURE = 4 47 ssh_FX_BAD_MESSAGE = 5 48 ssh_FX_NO_CONNECTION = 6 49 ssh_FX_CONNECTION_LOST = 7 50 ssh_FX_OP_UNSUPPORTED = 8 51 52 // see draft-ietf-secsh-filexfer-13 53 // https://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-9.1 54 ssh_FX_INVALID_HANDLE = 9 55 ssh_FX_NO_SUCH_PATH = 10 56 ssh_FX_FILE_ALREADY_EXISTS = 11 57 ssh_FX_WRITE_PROTECT = 12 58 ssh_FX_NO_MEDIA = 13 59 ssh_FX_NO_SPACE_ON_FILESYSTEM = 14 60 ssh_FX_QUOTA_EXCEEDED = 15 61 ssh_FX_UNKNOWN_PRINCIPAL = 16 62 ssh_FX_LOCK_CONFLICT = 17 63 ssh_FX_DIR_NOT_EMPTY = 18 64 ssh_FX_NOT_A_DIRECTORY = 19 65 ssh_FX_INVALID_FILENAME = 20 66 ssh_FX_LINK_LOOP = 21 67 ssh_FX_CANNOT_DELETE = 22 68 ssh_FX_INVALID_PARAMETER = 23 69 ssh_FX_FILE_IS_A_DIRECTORY = 24 70 ssh_FX_BYTE_RANGE_LOCK_CONFLICT = 25 71 ssh_FX_BYTE_RANGE_LOCK_REFUSED = 26 72 ssh_FX_DELETE_PENDING = 27 73 ssh_FX_FILE_CORRUPT = 28 74 ssh_FX_OWNER_INVALID = 29 75 ssh_FX_GROUP_INVALID = 30 76 ssh_FX_NO_MATCHING_BYTE_RANGE_LOCK = 31 77) 78 79const ( 80 ssh_FXF_READ = 0x00000001 81 ssh_FXF_WRITE = 0x00000002 82 ssh_FXF_APPEND = 0x00000004 83 ssh_FXF_CREAT = 0x00000008 84 ssh_FXF_TRUNC = 0x00000010 85 ssh_FXF_EXCL = 0x00000020 86) 87 88type fxp uint8 89 90func (f fxp) String() string { 91 switch f { 92 case ssh_FXP_INIT: 93 return "SSH_FXP_INIT" 94 case ssh_FXP_VERSION: 95 return "SSH_FXP_VERSION" 96 case ssh_FXP_OPEN: 97 return "SSH_FXP_OPEN" 98 case ssh_FXP_CLOSE: 99 return "SSH_FXP_CLOSE" 100 case ssh_FXP_READ: 101 return "SSH_FXP_READ" 102 case ssh_FXP_WRITE: 103 return "SSH_FXP_WRITE" 104 case ssh_FXP_LSTAT: 105 return "SSH_FXP_LSTAT" 106 case ssh_FXP_FSTAT: 107 return "SSH_FXP_FSTAT" 108 case ssh_FXP_SETSTAT: 109 return "SSH_FXP_SETSTAT" 110 case ssh_FXP_FSETSTAT: 111 return "SSH_FXP_FSETSTAT" 112 case ssh_FXP_OPENDIR: 113 return "SSH_FXP_OPENDIR" 114 case ssh_FXP_READDIR: 115 return "SSH_FXP_READDIR" 116 case ssh_FXP_REMOVE: 117 return "SSH_FXP_REMOVE" 118 case ssh_FXP_MKDIR: 119 return "SSH_FXP_MKDIR" 120 case ssh_FXP_RMDIR: 121 return "SSH_FXP_RMDIR" 122 case ssh_FXP_REALPATH: 123 return "SSH_FXP_REALPATH" 124 case ssh_FXP_STAT: 125 return "SSH_FXP_STAT" 126 case ssh_FXP_RENAME: 127 return "SSH_FXP_RENAME" 128 case ssh_FXP_READLINK: 129 return "SSH_FXP_READLINK" 130 case ssh_FXP_SYMLINK: 131 return "SSH_FXP_SYMLINK" 132 case ssh_FXP_STATUS: 133 return "SSH_FXP_STATUS" 134 case ssh_FXP_HANDLE: 135 return "SSH_FXP_HANDLE" 136 case ssh_FXP_DATA: 137 return "SSH_FXP_DATA" 138 case ssh_FXP_NAME: 139 return "SSH_FXP_NAME" 140 case ssh_FXP_ATTRS: 141 return "SSH_FXP_ATTRS" 142 case ssh_FXP_EXTENDED: 143 return "SSH_FXP_EXTENDED" 144 case ssh_FXP_EXTENDED_REPLY: 145 return "SSH_FXP_EXTENDED_REPLY" 146 default: 147 return "unknown" 148 } 149} 150 151type fx uint8 152 153func (f fx) String() string { 154 switch f { 155 case ssh_FX_OK: 156 return "SSH_FX_OK" 157 case ssh_FX_EOF: 158 return "SSH_FX_EOF" 159 case ssh_FX_NO_SUCH_FILE: 160 return "SSH_FX_NO_SUCH_FILE" 161 case ssh_FX_PERMISSION_DENIED: 162 return "SSH_FX_PERMISSION_DENIED" 163 case ssh_FX_FAILURE: 164 return "SSH_FX_FAILURE" 165 case ssh_FX_BAD_MESSAGE: 166 return "SSH_FX_BAD_MESSAGE" 167 case ssh_FX_NO_CONNECTION: 168 return "SSH_FX_NO_CONNECTION" 169 case ssh_FX_CONNECTION_LOST: 170 return "SSH_FX_CONNECTION_LOST" 171 case ssh_FX_OP_UNSUPPORTED: 172 return "SSH_FX_OP_UNSUPPORTED" 173 default: 174 return "unknown" 175 } 176} 177 178type unexpectedPacketErr struct { 179 want, got uint8 180} 181 182func (u *unexpectedPacketErr) Error() string { 183 return fmt.Sprintf("sftp: unexpected packet: want %v, got %v", fxp(u.want), fxp(u.got)) 184} 185 186func unimplementedPacketErr(u uint8) error { 187 return errors.Errorf("sftp: unimplemented packet type: got %v", fxp(u)) 188} 189 190type unexpectedIDErr struct{ want, got uint32 } 191 192func (u *unexpectedIDErr) Error() string { 193 return fmt.Sprintf("sftp: unexpected id: want %v, got %v", u.want, u.got) 194} 195 196func unimplementedSeekWhence(whence int) error { 197 return errors.Errorf("sftp: unimplemented seek whence %v", whence) 198} 199 200func unexpectedCount(want, got uint32) error { 201 return errors.Errorf("sftp: unexpected count: want %v, got %v", want, got) 202} 203 204type unexpectedVersionErr struct{ want, got uint32 } 205 206func (u *unexpectedVersionErr) Error() string { 207 return fmt.Sprintf("sftp: unexpected server version: want %v, got %v", u.want, u.got) 208} 209 210// A StatusError is returned when an SFTP operation fails, and provides 211// additional information about the failure. 212type StatusError struct { 213 Code uint32 214 msg, lang string 215} 216 217func (s *StatusError) Error() string { return fmt.Sprintf("sftp: %q (%v)", s.msg, fx(s.Code)) } 218