storage.go 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. // Copyright 2020 The Gogs Authors. All rights reserved.
  2. // Use of this source code is governed by a MIT-style
  3. // license that can be found in the LICENSE file.
  4. package lfsutil
  5. import (
  6. "io"
  7. "os"
  8. "path/filepath"
  9. "github.com/pkg/errors"
  10. "gogs.io/gogs/internal/osutil"
  11. )
  12. var ErrObjectNotExist = errors.New("Object does not exist")
  13. // Storager is an storage backend for uploading and downloading LFS objects.
  14. type Storager interface {
  15. // Storage returns the name of the storage backend.
  16. Storage() Storage
  17. // Upload reads content from the io.ReadCloser and uploads as given oid.
  18. // The reader is closed once upload is finished. ErrInvalidOID is returned
  19. // if the given oid is not valid.
  20. Upload(oid OID, rc io.ReadCloser) (int64, error)
  21. // Download streams content of given oid to the io.Writer. It is caller's
  22. // responsibility the close the writer when needed. ErrObjectNotExist is
  23. // returned if the given oid does not exist.
  24. Download(oid OID, w io.Writer) error
  25. }
  26. // Storage is the storage type of an LFS object.
  27. type Storage string
  28. const (
  29. StorageLocal Storage = "local"
  30. )
  31. var _ Storager = (*LocalStorage)(nil)
  32. // LocalStorage is a LFS storage backend on local file system.
  33. type LocalStorage struct {
  34. // The root path for storing LFS objects.
  35. Root string
  36. }
  37. func (s *LocalStorage) Storage() Storage {
  38. return StorageLocal
  39. }
  40. func (s *LocalStorage) storagePath(oid OID) string {
  41. if len(oid) < 2 {
  42. return ""
  43. }
  44. return filepath.Join(s.Root, string(oid[0]), string(oid[1]), string(oid))
  45. }
  46. func (s *LocalStorage) Upload(oid OID, rc io.ReadCloser) (int64, error) {
  47. if !ValidOID(oid) {
  48. return 0, ErrInvalidOID
  49. }
  50. var err error
  51. fpath := s.storagePath(oid)
  52. defer func() {
  53. rc.Close()
  54. if err != nil {
  55. _ = os.Remove(fpath)
  56. }
  57. }()
  58. err = os.MkdirAll(filepath.Dir(fpath), os.ModePerm)
  59. if err != nil {
  60. return 0, errors.Wrap(err, "create directories")
  61. }
  62. w, err := os.Create(fpath)
  63. if err != nil {
  64. return 0, errors.Wrap(err, "create file")
  65. }
  66. defer w.Close()
  67. written, err := io.Copy(w, rc)
  68. if err != nil {
  69. return 0, errors.Wrap(err, "copy file")
  70. }
  71. return written, nil
  72. }
  73. func (s *LocalStorage) Download(oid OID, w io.Writer) error {
  74. fpath := s.storagePath(oid)
  75. if !osutil.IsFile(fpath) {
  76. return ErrObjectNotExist
  77. }
  78. r, err := os.Open(fpath)
  79. if err != nil {
  80. return errors.Wrap(err, "open file")
  81. }
  82. defer r.Close()
  83. _, err = io.Copy(w, r)
  84. if err != nil {
  85. return errors.Wrap(err, "copy file")
  86. }
  87. return nil
  88. }