Monorepo for Tangled
tangled.org
1// Copyright 2021 The Gitea Authors. All rights reserved.
2// SPDX-License-Identifier: MIT
3
4package gitea
5
6import (
7 "bufio"
8 "bytes"
9 "context"
10 "io"
11
12 "github.com/go-git/go-git/v5/plumbing"
13)
14
15func GetBlobSize(ctx context.Context, repoPath string, hash plumbing.Hash) (int64, error) {
16 wr, rd, cancel := CatFileBatchCheck(ctx, repoPath)
17 defer cancel()
18 if _, err := wr.Write([]byte(hash.String() + "\n")); err != nil {
19 return 0, err
20 }
21 _, _, size, err := ReadBatchLine(rd)
22 return size, err
23}
24
25// ReadBlob returns blob size and [io.ReadCloser] of that blob.
26func ReadBlob(ctx context.Context, repoPath string, hash plumbing.Hash) (int64, io.ReadCloser, error) {
27 wr, rd, cancel := CatFileBatch(ctx, repoPath)
28
29 _, err := wr.Write([]byte(hash.String() + "\n"))
30 if err != nil {
31 cancel()
32 return 0, nil, err
33 }
34 _, _, size, err := ReadBatchLine(rd)
35 if err != nil {
36 cancel()
37 return 0, nil, err
38 }
39
40 if size < 4096 {
41 bs, err := io.ReadAll(io.LimitReader(rd, size))
42 defer cancel()
43 if err != nil {
44 return 0, nil, err
45 }
46 _, err = rd.Discard(1)
47 return size, io.NopCloser(bytes.NewReader(bs)), err
48 }
49
50 return size, &blobReader{
51 rd: rd,
52 n: size,
53 cancel: cancel,
54 }, nil
55}
56
57type blobReader struct {
58 rd *bufio.Reader
59 n int64
60 cancel func()
61}
62
63func (b *blobReader) Read(p []byte) (n int, err error) {
64 if b.n <= 0 {
65 return 0, io.EOF
66 }
67 if int64(len(p)) > b.n {
68 p = p[0:b.n]
69 }
70 n, err = b.rd.Read(p)
71 b.n -= int64(n)
72 return n, err
73}
74
75// Close implements io.Closer
76func (b *blobReader) Close() error {
77 if b.rd == nil {
78 return nil
79 }
80
81 defer b.cancel()
82
83 if err := DiscardFull(b.rd, b.n+1); err != nil {
84 return err
85 }
86
87 b.rd = nil
88
89 return nil
90}