Skip to content

Commit cf762f6

Browse files
modules/lfstransfer: modify transfer.Backend interface
Make a few changes to make the transfer backend suit Gitea better. Merge Upload into one method: Makes things simpler since out content store verifies size & hashes itself Change Download return into io.ReadCloser: Removes dependency on filesystem Add size: int64 arguments wherever appropriate In arguments for Upload and Verify, and in return for Download
1 parent 5416fa9 commit cf762f6

File tree

3 files changed

+51
-33
lines changed

3 files changed

+51
-33
lines changed

Diff for: modules/lfstransfer/transfer/backend.go

+3-5
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package transfer
22

33
import (
44
"io"
5-
"io/fs"
65
)
76

87
const (
@@ -15,10 +14,9 @@ const (
1514
// Backend is a Git LFS backend.
1615
type Backend interface {
1716
Batch(op string, pointers []BatchItem, args Args) ([]BatchItem, error)
18-
StartUpload(oid string, r io.Reader, args Args) (io.Closer, error)
19-
FinishUpload(state io.Closer, args Args) error
20-
Verify(oid string, args Args) (Status, error)
21-
Download(oid string, args Args) (fs.File, error)
17+
Upload(oid string, size int64, r io.Reader, args Args) error
18+
Verify(oid string, size int64, args Args) (Status, error)
19+
Download(oid string, args Args) (io.ReadCloser, int64, error)
2220
LockBackend(args Args) LockBackend
2321
}
2422

Diff for: modules/lfstransfer/transfer/hash.go

+37
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package transfer
22

33
import (
44
"encoding/hex"
5+
"fmt"
56
"hash"
67
"io"
78
)
@@ -40,3 +41,39 @@ func (h *HashingReader) Read(p []byte) (int, error) {
4041
h.hash.Write(p[:n])
4142
return n, err
4243
}
44+
45+
var _ io.Reader = (*VerifyingReader)(nil)
46+
47+
// VerifyingReader is a reader that hashes the data it reads.
48+
// At EOF, it compares the OID and size with expected values and replaces EOF
49+
// with an error in the case of mismatch.
50+
type VerifyingReader struct {
51+
r *HashingReader
52+
expectedOid string
53+
expectedSize int64
54+
}
55+
56+
// NewVerifyingReader creates a new VerifyingReader.
57+
func NewVerifyingReader(r *HashingReader, oid string, size int64) *VerifyingReader {
58+
return &VerifyingReader{
59+
r: r,
60+
expectedOid: oid,
61+
expectedSize: size,
62+
}
63+
}
64+
65+
// Read reads data from the underlying HashingReader.
66+
// At EOF, it compares results and returns error if OID or size mismatch
67+
func (v *VerifyingReader) Read(p []byte) (int, error) {
68+
n, err := v.r.Read(p)
69+
if err == io.EOF {
70+
// stream consumed, now check for mismatch
71+
if v.r.Size() != v.expectedSize {
72+
err = fmt.Errorf("%w: invalid object size, expected %v, got %v", ErrCorruptData, v.expectedSize, v.r.Size())
73+
}
74+
if v.r.Oid() != v.expectedOid {
75+
err = fmt.Errorf("%w: invalid object ID, expected %v, got %v", ErrCorruptData, v.expectedOid, v.r.Oid())
76+
}
77+
}
78+
return n, err
79+
}

Diff for: modules/lfstransfer/transfer/processor.go

+11-28
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package transfer
22

33
import (
4-
"crypto/sha256"
54
"errors"
65
"fmt"
76
"io"
@@ -161,29 +160,13 @@ func (p *Processor) PutObject(oid string) (Status, error) {
161160
if err != nil {
162161
return nil, err
163162
}
164-
r := p.handler.Reader()
165-
rdr := NewHashingReader(r, sha256.New())
166-
state, err := p.backend.StartUpload(oid, rdr, args)
163+
rdr := io.Reader(p.handler.Reader())
164+
// we don't need to verify data here because the backend already does
165+
//rdr = NewVerifyingReader(NewHashingReader(rdr, sha256.New()), oid, expectedSize)
166+
err = p.backend.Upload(oid, expectedSize, rdr, args)
167167
if err != nil {
168168
return nil, err
169169
}
170-
defer state.Close() // nolint: errcheck
171-
actualSize := rdr.Size()
172-
if actualSize != expectedSize {
173-
err := fmt.Errorf("invalid size, expected %d, got %d", expectedSize, actualSize)
174-
if actualSize > expectedSize {
175-
err = fmt.Errorf("%w: %s", ErrExtraData, err)
176-
} else {
177-
err = fmt.Errorf("%w: %s", ErrMissingData, err)
178-
}
179-
return nil, err
180-
}
181-
if actualOid := rdr.Oid(); actualOid != oid {
182-
return nil, fmt.Errorf("%w: %s", ErrCorruptData, fmt.Sprintf("invalid object ID, expected %s, got %s", oid, actualOid))
183-
}
184-
if err := p.backend.FinishUpload(state, args); err != nil {
185-
return nil, err
186-
}
187170
return SuccessStatus(), nil
188171
}
189172

@@ -197,7 +180,11 @@ func (p *Processor) VerifyObject(oid string) (Status, error) {
197180
if err != nil {
198181
return nil, fmt.Errorf("%w: %s", ErrParseError, err)
199182
}
200-
return p.backend.Verify(oid, args)
183+
size, err := SizeFromArgs(args)
184+
if err != nil {
185+
return nil, fmt.Errorf("%w: %s", ErrParseError, err)
186+
}
187+
return p.backend.Verify(oid, size, args)
201188
}
202189

203190
// GetObject writes an object ID to the transfer protocol.
@@ -210,18 +197,14 @@ func (p *Processor) GetObject(oid string) (Status, error) {
210197
if err != nil {
211198
return nil, fmt.Errorf("%w: %s", ErrParseError, err)
212199
}
213-
r, err := p.backend.Download(oid, args)
200+
r, size, err := p.backend.Download(oid, args)
214201
if errors.Is(err, fs.ErrNotExist) {
215202
return NewStatus(StatusNotFound, fmt.Sprintf("object %s not found", oid)), nil
216203
}
217204
if err != nil {
218205
return nil, err
219206
}
220-
info, err := r.Stat()
221-
if err != nil {
222-
return nil, err
223-
}
224-
return NewSuccessStatusWithReader(r, fmt.Sprintf("size=%d", info.Size())), nil
207+
return NewSuccessStatusWithReader(r, fmt.Sprintf("size=%d", size)), nil
225208
}
226209

227210
// Lock writes a lock to the transfer protocol.

0 commit comments

Comments
 (0)