github.com/2lambda123/git-lfs@v2.5.2+incompatible/lfs/gitscanner_catfilebatch.go (about) 1 package lfs 2 3 import ( 4 "bytes" 5 "crypto/sha256" 6 "fmt" 7 "io" 8 9 "github.com/git-lfs/git-lfs/git" 10 ) 11 12 // runCatFileBatch uses 'git cat-file --batch' to get the object contents of a 13 // git object, given its sha1. The contents will be decoded into a Git LFS 14 // pointer. Git Blob SHA1s are read from the sha1Ch channel and fed to STDIN. 15 // Results are parsed from STDOUT, and any eligible LFS pointers are sent to 16 // pointerCh. If a Git Blob is not an LFS pointer, check the lockableSet to see 17 // if that blob is for a locked file. Any errors are sent to errCh. An error is 18 // returned if the 'git cat-file' command fails to start. 19 func runCatFileBatch(pointerCh chan *WrappedPointer, lockableCh chan string, lockableSet *lockableNameSet, revs *StringChannelWrapper, errCh chan error) error { 20 scanner, err := NewPointerScanner() 21 if err != nil { 22 return err 23 } 24 25 go func() { 26 for r := range revs.Results { 27 canScan := scanner.Scan(r) 28 29 if err := scanner.Err(); err != nil { 30 errCh <- err 31 } else if p := scanner.Pointer(); p != nil { 32 pointerCh <- p 33 } else if b := scanner.BlobSHA(); len(b) == 40 { 34 if name, ok := lockableSet.Check(b); ok { 35 lockableCh <- name 36 } 37 } 38 39 if !canScan { 40 break 41 } 42 } 43 44 if err := revs.Wait(); err != nil { 45 errCh <- err 46 } 47 48 if err := scanner.Close(); err != nil { 49 errCh <- err 50 } 51 52 close(pointerCh) 53 close(errCh) 54 close(lockableCh) 55 }() 56 57 return nil 58 } 59 60 type PointerScanner struct { 61 scanner *git.ObjectScanner 62 63 blobSha string 64 contentsSha string 65 pointer *WrappedPointer 66 err error 67 } 68 69 func NewPointerScanner() (*PointerScanner, error) { 70 scanner, err := git.NewObjectScanner() 71 if err != nil { 72 return nil, err 73 } 74 75 return &PointerScanner{scanner: scanner}, nil 76 } 77 78 func (s *PointerScanner) BlobSHA() string { 79 return s.blobSha 80 } 81 82 func (s *PointerScanner) ContentsSha() string { 83 return s.contentsSha 84 } 85 86 func (s *PointerScanner) Pointer() *WrappedPointer { 87 return s.pointer 88 } 89 90 func (s *PointerScanner) Err() error { 91 return s.err 92 } 93 94 func (s *PointerScanner) Scan(sha string) bool { 95 s.pointer, s.err = nil, nil 96 s.blobSha, s.contentsSha = "", "" 97 98 b, c, p, err := s.next(sha) 99 s.blobSha = b 100 s.contentsSha = c 101 s.pointer = p 102 103 if err != nil { 104 if err != io.EOF { 105 s.err = err 106 } 107 return false 108 } 109 110 return true 111 } 112 113 func (s *PointerScanner) Close() error { 114 return s.scanner.Close() 115 } 116 117 func (s *PointerScanner) next(blob string) (string, string, *WrappedPointer, error) { 118 if !s.scanner.Scan(blob) { 119 if err := s.scanner.Err(); err != nil { 120 return "", "", nil, err 121 } 122 return "", "", nil, io.EOF 123 } 124 125 blobSha := s.scanner.Sha1() 126 size := s.scanner.Size() 127 128 sha := sha256.New() 129 130 var buf *bytes.Buffer 131 var to io.Writer = sha 132 if size <= blobSizeCutoff { 133 buf = bytes.NewBuffer(make([]byte, 0, size)) 134 to = io.MultiWriter(to, buf) 135 } 136 137 read, err := io.CopyN(to, s.scanner.Contents(), int64(size)) 138 if err != nil { 139 return blobSha, "", nil, err 140 } 141 142 if int64(size) != read { 143 return blobSha, "", nil, fmt.Errorf("expected %d bytes, read %d bytes", size, read) 144 } 145 146 var pointer *WrappedPointer 147 var contentsSha string 148 149 if size <= blobSizeCutoff { 150 if p, err := DecodePointer(bytes.NewReader(buf.Bytes())); err != nil { 151 contentsSha = fmt.Sprintf("%x", sha.Sum(nil)) 152 } else { 153 pointer = &WrappedPointer{ 154 Sha1: blobSha, 155 Pointer: p, 156 } 157 contentsSha = p.Oid 158 } 159 } else { 160 contentsSha = fmt.Sprintf("%x", sha.Sum(nil)) 161 } 162 163 return blobSha, contentsSha, pointer, err 164 }