gitea源码

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. // Copyright 2016 The Gogs Authors. All rights reserved.
  2. // Copyright 2019 The Gitea Authors. All rights reserved.
  3. // SPDX-License-Identifier: MIT
  4. package repo
  5. import (
  6. "context"
  7. "fmt"
  8. "io"
  9. "mime/multipart"
  10. "os"
  11. "path/filepath"
  12. "code.gitea.io/gitea/models/db"
  13. "code.gitea.io/gitea/modules/log"
  14. "code.gitea.io/gitea/modules/setting"
  15. "code.gitea.io/gitea/modules/util"
  16. gouuid "github.com/google/uuid"
  17. )
  18. // ErrUploadNotExist represents a "UploadNotExist" kind of error.
  19. type ErrUploadNotExist struct {
  20. ID int64
  21. UUID string
  22. }
  23. // IsErrUploadNotExist checks if an error is a ErrUploadNotExist.
  24. func IsErrUploadNotExist(err error) bool {
  25. _, ok := err.(ErrUploadNotExist)
  26. return ok
  27. }
  28. func (err ErrUploadNotExist) Error() string {
  29. return fmt.Sprintf("attachment does not exist [id: %d, uuid: %s]", err.ID, err.UUID)
  30. }
  31. func (err ErrUploadNotExist) Unwrap() error {
  32. return util.ErrNotExist
  33. }
  34. // Upload represent a uploaded file to a repo to be deleted when moved
  35. type Upload struct {
  36. ID int64 `xorm:"pk autoincr"`
  37. UUID string `xorm:"uuid UNIQUE"`
  38. Name string
  39. }
  40. func init() {
  41. db.RegisterModel(new(Upload))
  42. }
  43. // LocalPath returns where uploads are temporarily stored in local file system based on given UUID.
  44. func (upload *Upload) LocalPath() string {
  45. uuid := upload.UUID
  46. return setting.AppDataTempDir("repo-uploads").JoinPath(uuid[0:1], uuid[1:2], uuid)
  47. }
  48. // NewUpload creates a new upload object.
  49. func NewUpload(ctx context.Context, name string, buf []byte, file multipart.File) (_ *Upload, err error) {
  50. upload := &Upload{
  51. UUID: gouuid.New().String(),
  52. Name: name,
  53. }
  54. localPath := upload.LocalPath()
  55. if err = os.MkdirAll(filepath.Dir(localPath), os.ModePerm); err != nil {
  56. return nil, fmt.Errorf("MkdirAll: %w", err)
  57. }
  58. fw, err := os.Create(localPath)
  59. if err != nil {
  60. return nil, fmt.Errorf("Create: %w", err)
  61. }
  62. defer fw.Close()
  63. if _, err = fw.Write(buf); err != nil {
  64. return nil, fmt.Errorf("Write: %w", err)
  65. } else if _, err = io.Copy(fw, file); err != nil {
  66. return nil, fmt.Errorf("Copy: %w", err)
  67. }
  68. if _, err := db.GetEngine(ctx).Insert(upload); err != nil {
  69. return nil, err
  70. }
  71. return upload, nil
  72. }
  73. // GetUploadByUUID returns the Upload by UUID
  74. func GetUploadByUUID(ctx context.Context, uuid string) (*Upload, error) {
  75. upload := &Upload{}
  76. has, err := db.GetEngine(ctx).Where("uuid=?", uuid).Get(upload)
  77. if err != nil {
  78. return nil, err
  79. } else if !has {
  80. return nil, ErrUploadNotExist{0, uuid}
  81. }
  82. return upload, nil
  83. }
  84. // GetUploadsByUUIDs returns multiple uploads by UUIDS
  85. func GetUploadsByUUIDs(ctx context.Context, uuids []string) ([]*Upload, error) {
  86. if len(uuids) == 0 {
  87. return []*Upload{}, nil
  88. }
  89. // Silently drop invalid uuids.
  90. uploads := make([]*Upload, 0, len(uuids))
  91. return uploads, db.GetEngine(ctx).In("uuid", uuids).Find(&uploads)
  92. }
  93. // DeleteUploads deletes multiple uploads
  94. func DeleteUploads(ctx context.Context, uploads ...*Upload) (err error) {
  95. if len(uploads) == 0 {
  96. return nil
  97. }
  98. ids := make([]int64, len(uploads))
  99. for i := range uploads {
  100. ids[i] = uploads[i].ID
  101. }
  102. if err = db.DeleteByIDs[Upload](ctx, ids...); err != nil {
  103. return fmt.Errorf("delete uploads: %w", err)
  104. }
  105. for _, upload := range uploads {
  106. localPath := upload.LocalPath()
  107. isFile, err := util.IsFile(localPath)
  108. if err != nil {
  109. log.Error("Unable to check if %s is a file. Error: %v", localPath, err)
  110. }
  111. if !isFile {
  112. continue
  113. }
  114. if err := util.Remove(localPath); err != nil {
  115. return fmt.Errorf("remove upload: %w", err)
  116. }
  117. }
  118. return nil
  119. }
  120. // DeleteUploadByUUID deletes a upload by UUID
  121. func DeleteUploadByUUID(ctx context.Context, uuid string) error {
  122. upload, err := GetUploadByUUID(ctx, uuid)
  123. if err != nil {
  124. if IsErrUploadNotExist(err) {
  125. return nil
  126. }
  127. return fmt.Errorf("GetUploadByUUID: %w", err)
  128. }
  129. if err := DeleteUploads(ctx, upload); err != nil {
  130. return fmt.Errorf("DeleteUpload: %w", err)
  131. }
  132. return nil
  133. }