sftp.go 5.6 KB

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