sftp_file_writer.go 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. // sftp_helpers.go
  2. package sftpd
  3. import (
  4. "io"
  5. "os"
  6. "sync"
  7. "time"
  8. "github.com/pkg/sftp"
  9. )
  10. // FileInfo implements os.FileInfo.
  11. type FileInfo struct {
  12. name string
  13. size int64
  14. mode os.FileMode
  15. modTime time.Time
  16. isDir bool
  17. }
  18. func (fi *FileInfo) Name() string { return fi.name }
  19. func (fi *FileInfo) Size() int64 { return fi.size }
  20. func (fi *FileInfo) Mode() os.FileMode { return fi.mode }
  21. func (fi *FileInfo) ModTime() time.Time { return fi.modTime }
  22. func (fi *FileInfo) IsDir() bool { return fi.isDir }
  23. func (fi *FileInfo) Sys() interface{} { return nil }
  24. // bufferReader wraps a byte slice to io.ReaderAt.
  25. type bufferReader struct {
  26. b []byte
  27. i int64
  28. }
  29. func NewBufferReader(b []byte) *bufferReader { return &bufferReader{b: b} }
  30. func (r *bufferReader) Read(p []byte) (int, error) {
  31. if r.i >= int64(len(r.b)) {
  32. return 0, io.EOF
  33. }
  34. n := copy(p, r.b[r.i:])
  35. r.i += int64(n)
  36. return n, nil
  37. }
  38. func (r *bufferReader) ReadAt(p []byte, off int64) (int, error) {
  39. if off >= int64(len(r.b)) {
  40. return 0, io.EOF
  41. }
  42. n := copy(p, r.b[off:])
  43. if n < len(p) {
  44. return n, io.EOF
  45. }
  46. return n, nil
  47. }
  48. // listerat implements sftp.ListerAt.
  49. type listerat []os.FileInfo
  50. func (l listerat) ListAt(ls []os.FileInfo, offset int64) (int, error) {
  51. if offset >= int64(len(l)) {
  52. return 0, io.EOF
  53. }
  54. n := copy(ls, l[offset:])
  55. if n < len(ls) {
  56. return n, io.EOF
  57. }
  58. return n, nil
  59. }
  60. // SeaweedSftpFileWriter buffers writes and flushes on Close.
  61. type SeaweedSftpFileWriter struct {
  62. fs SftpServer
  63. req *sftp.Request
  64. mu sync.Mutex
  65. tmpFile *os.File
  66. permissions os.FileMode
  67. uid uint32
  68. gid uint32
  69. offset int64
  70. }
  71. func (w *SeaweedSftpFileWriter) Write(p []byte) (int, error) {
  72. w.mu.Lock()
  73. defer w.mu.Unlock()
  74. n, err := w.tmpFile.WriteAt(p, w.offset)
  75. w.offset += int64(n)
  76. return n, err
  77. }
  78. func (w *SeaweedSftpFileWriter) WriteAt(p []byte, off int64) (int, error) {
  79. w.mu.Lock()
  80. defer w.mu.Unlock()
  81. return w.tmpFile.WriteAt(p, off)
  82. }
  83. func (w *SeaweedSftpFileWriter) Close() error {
  84. w.mu.Lock()
  85. defer w.mu.Unlock()
  86. defer os.Remove(w.tmpFile.Name()) // Clean up temp file
  87. defer w.tmpFile.Close()
  88. if _, err := w.tmpFile.Seek(0, io.SeekStart); err != nil {
  89. return err
  90. }
  91. // Stream the file instead of loading it
  92. return w.fs.putFile(w.req.Filepath, w.tmpFile, w.fs.user)
  93. }