MCPcopy Create free account
hub / github.com/gogs/gogs / Upload

Method Upload

internal/lfsutil/storage.go:63–122  ·  view source on GitHub ↗
(oid OID, rc io.ReadCloser)

Source from the content-addressed store, hash-verified

61}
62
63func (s *LocalStorage) Upload(oid OID, rc io.ReadCloser) (int64, error) {
64 if !ValidOID(oid) {
65 return 0, ErrInvalidOID
66 }
67
68 fpath := s.storagePath(oid)
69 dir := filepath.Dir(fpath)
70
71 defer rc.Close()
72
73 if err := os.MkdirAll(dir, os.ModePerm); err != nil {
74 return 0, errors.Wrap(err, "create directories")
75 }
76
77 // If the object file already exists, the client must still prove it has
78 // the original bytes by hashing the request body. Otherwise any caller
79 // with write access to one repository could bind an OID owned by another
80 // repository to their own and download the original content.
81 if fi, err := os.Stat(fpath); err == nil {
82 hash := sha256.New()
83 if _, err := io.Copy(hash, rc); err != nil {
84 return 0, errors.Wrap(err, "read request body")
85 }
86 if computed := hex.EncodeToString(hash.Sum(nil)); computed != string(oid) {
87 return 0, ErrOIDMismatch
88 }
89 return fi.Size(), nil
90 }
91
92 // Write to a temp file and verify the content hash before publishing.
93 // This ensures the final path always contains a complete, hash-verified
94 // file, even when concurrent uploads of the same OID race.
95 if err := os.MkdirAll(s.TempDir, os.ModePerm); err != nil {
96 return 0, errors.Wrap(err, "create temp directory")
97 }
98 tmp, err := os.CreateTemp(s.TempDir, "upload-*")
99 if err != nil {
100 return 0, errors.Wrap(err, "create temp file")
101 }
102 tmpPath := tmp.Name()
103 defer os.Remove(tmpPath)
104
105 hash := sha256.New()
106 written, err := io.Copy(tmp, io.TeeReader(rc, hash))
107 if closeErr := tmp.Close(); err == nil && closeErr != nil {
108 err = closeErr
109 }
110 if err != nil {
111 return 0, errors.Wrap(err, "write object file")
112 }
113
114 if computed := hex.EncodeToString(hash.Sum(nil)); computed != string(oid) {
115 return 0, ErrOIDMismatch
116 }
117
118 if err := os.Rename(tmpPath, fpath); err != nil && !os.IsExist(err) {
119 return 0, errors.Wrap(err, "publish object file")
120 }

Callers 1

TestLocalStorage_UploadFunction · 0.95

Calls 5

storagePathMethod · 0.95
ValidOIDFunction · 0.85
stringFunction · 0.85
RemoveMethod · 0.80
NameMethod · 0.45

Tested by 1

TestLocalStorage_UploadFunction · 0.76