code.gitea.io/gitea@v1.19.3/modules/git/blob_nogogit.go (about) 1 // Copyright 2020 The Gitea Authors. All rights reserved. 2 // SPDX-License-Identifier: MIT 3 4 //go:build !gogit 5 6 package git 7 8 import ( 9 "bufio" 10 "bytes" 11 "io" 12 "math" 13 14 "code.gitea.io/gitea/modules/log" 15 ) 16 17 // Blob represents a Git object. 18 type Blob struct { 19 ID SHA1 20 21 gotSize bool 22 size int64 23 name string 24 repo *Repository 25 } 26 27 // DataAsync gets a ReadCloser for the contents of a blob without reading it all. 28 // Calling the Close function on the result will discard all unread output. 29 func (b *Blob) DataAsync() (io.ReadCloser, error) { 30 wr, rd, cancel := b.repo.CatFileBatch(b.repo.Ctx) 31 32 _, err := wr.Write([]byte(b.ID.String() + "\n")) 33 if err != nil { 34 cancel() 35 return nil, err 36 } 37 _, _, size, err := ReadBatchLine(rd) 38 if err != nil { 39 cancel() 40 return nil, err 41 } 42 b.gotSize = true 43 b.size = size 44 45 if size < 4096 { 46 bs, err := io.ReadAll(io.LimitReader(rd, size)) 47 defer cancel() 48 if err != nil { 49 return nil, err 50 } 51 _, err = rd.Discard(1) 52 return io.NopCloser(bytes.NewReader(bs)), err 53 } 54 55 return &blobReader{ 56 rd: rd, 57 n: size, 58 cancel: cancel, 59 }, nil 60 } 61 62 // Size returns the uncompressed size of the blob 63 func (b *Blob) Size() int64 { 64 if b.gotSize { 65 return b.size 66 } 67 68 wr, rd, cancel := b.repo.CatFileBatchCheck(b.repo.Ctx) 69 defer cancel() 70 _, err := wr.Write([]byte(b.ID.String() + "\n")) 71 if err != nil { 72 log.Debug("error whilst reading size for %s in %s. Error: %v", b.ID.String(), b.repo.Path, err) 73 return 0 74 } 75 _, _, b.size, err = ReadBatchLine(rd) 76 if err != nil { 77 log.Debug("error whilst reading size for %s in %s. Error: %v", b.ID.String(), b.repo.Path, err) 78 return 0 79 } 80 81 b.gotSize = true 82 83 return b.size 84 } 85 86 type blobReader struct { 87 rd *bufio.Reader 88 n int64 89 cancel func() 90 } 91 92 func (b *blobReader) Read(p []byte) (n int, err error) { 93 if b.n <= 0 { 94 return 0, io.EOF 95 } 96 if int64(len(p)) > b.n { 97 p = p[0:b.n] 98 } 99 n, err = b.rd.Read(p) 100 b.n -= int64(n) 101 return n, err 102 } 103 104 // Close implements io.Closer 105 func (b *blobReader) Close() error { 106 defer b.cancel() 107 if b.n > 0 { 108 for b.n > math.MaxInt32 { 109 n, err := b.rd.Discard(math.MaxInt32) 110 b.n -= int64(n) 111 if err != nil { 112 return err 113 } 114 b.n -= math.MaxInt32 115 } 116 n, err := b.rd.Discard(int(b.n)) 117 b.n -= int64(n) 118 if err != nil { 119 return err 120 } 121 } 122 if b.n == 0 { 123 _, err := b.rd.Discard(1) 124 b.n-- 125 return err 126 } 127 return nil 128 }