sftp.go 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. package ssh
  2. import (
  3. "fmt"
  4. "os"
  5. "time"
  6. "github.com/pkg/sftp"
  7. )
  8. func (me *Client) List(dir string, proc func(path string, err error) error) error {
  9. // open an SFTP session over an existing ssh connection.
  10. client, err := sftp.NewClient(me.Client)
  11. if err != nil {
  12. return err
  13. }
  14. defer client.Close()
  15. // walk a directory
  16. w := client.Walk(dir)
  17. for w.Step() {
  18. err = proc(w.Path(), w.Err())
  19. if err != nil {
  20. return err
  21. }
  22. }
  23. return nil
  24. }
  25. func (me *Client) Stat(fpath string) (os.FileInfo, error) {
  26. // open an SFTP session over an existing ssh connection.
  27. client, err := sftp.NewClient(me.Client)
  28. if err != nil {
  29. return nil, err
  30. }
  31. defer client.Close()
  32. return client.Lstat(fpath)
  33. }
  34. func (me *Client) ReadFile(fpath string) (data []byte, err error) {
  35. // open an SFTP session over an existing ssh connection.
  36. client, err := sftp.NewClient(me.Client)
  37. if err != nil {
  38. return nil, err
  39. }
  40. defer client.Close()
  41. f, err := client.Open(fpath)
  42. if err != nil {
  43. return nil, err
  44. }
  45. defer f.Close()
  46. var size int
  47. if info, err := f.Stat(); err == nil {
  48. size64 := info.Size()
  49. if int64(int(size64)) == size64 {
  50. size = int(size64)
  51. }
  52. }
  53. size++ // one byte for final read at EOF
  54. // If a file claims a small size, read at least 512 bytes.
  55. // In particular, files in Linux's /proc claim size 0 but
  56. // then do not work right if read in small pieces,
  57. // so an initial read of 1 byte would not work correctly.
  58. offset := len(data)
  59. if size > cap(data) {
  60. ndata := make([]byte, len(data), size)
  61. copy(ndata, data)
  62. data = ndata
  63. }
  64. for {
  65. n, err := f.ReadAt(data[offset:cap(data)], int64(offset))
  66. offset += n
  67. if err != nil {
  68. return data[:offset], err
  69. }
  70. if offset >= cap(data) {
  71. d := append(data[:cap(data)], 0)
  72. data = d[:offset]
  73. }
  74. }
  75. }
  76. func (me *Client) WriteFile(fpath string, bs []byte, mode os.FileMode, mtime time.Time) error {
  77. // open an SFTP session over an existing ssh connection.
  78. client, err := sftp.NewClient(me.Client)
  79. if err != nil {
  80. return err
  81. }
  82. defer client.Close()
  83. // leave your mark
  84. f, err := client.Create(fpath)
  85. if err != nil {
  86. return err
  87. }
  88. defer f.Close()
  89. w := 0
  90. for w < len(bs) {
  91. n, err := f.Write(bs[w:])
  92. w += n
  93. if err != nil {
  94. return err
  95. }
  96. }
  97. err = client.Chmod(fpath, mode)
  98. if err != nil {
  99. return err
  100. }
  101. err = client.Chtimes(fpath, mtime, mtime)
  102. if err != nil {
  103. return err
  104. }
  105. // check it's there
  106. fi, err := client.Lstat(fpath)
  107. if err != nil {
  108. return err
  109. }
  110. if fi.Size() != int64(len(bs)) {
  111. return fmt.Errorf("write file size incorrect")
  112. }
  113. if !fi.ModTime().Equal(mtime) {
  114. return fmt.Errorf("write file time incorrect")
  115. }
  116. return nil
  117. }