github.com/git-lfs/git-lfs@v2.5.2+incompatible/lfs/gitfilter_clean.go (about) 1 package lfs 2 3 import ( 4 "bytes" 5 "crypto/sha256" 6 "encoding/hex" 7 "io" 8 "io/ioutil" 9 "os" 10 11 "github.com/git-lfs/git-lfs/errors" 12 "github.com/git-lfs/git-lfs/tools" 13 ) 14 15 type cleanedAsset struct { 16 Filename string 17 *Pointer 18 } 19 20 func (f *GitFilter) Clean(reader io.Reader, fileName string, fileSize int64, cb tools.CopyCallback) (*cleanedAsset, error) { 21 extensions, err := f.cfg.SortedExtensions() 22 if err != nil { 23 return nil, err 24 } 25 26 var oid string 27 var size int64 28 var tmp *os.File 29 var exts []*PointerExtension 30 if len(extensions) > 0 { 31 request := &pipeRequest{"clean", reader, fileName, extensions} 32 33 var response pipeResponse 34 if response, err = pipeExtensions(f.cfg, request); err != nil { 35 return nil, err 36 } 37 38 oid = response.results[len(response.results)-1].oidOut 39 tmp = response.file 40 var stat os.FileInfo 41 if stat, err = os.Stat(tmp.Name()); err != nil { 42 return nil, err 43 } 44 size = stat.Size() 45 46 for _, result := range response.results { 47 if result.oidIn != result.oidOut { 48 ext := NewPointerExtension(result.name, len(exts), result.oidIn) 49 exts = append(exts, ext) 50 } 51 } 52 } else { 53 oid, size, tmp, err = f.copyToTemp(reader, fileSize, cb) 54 if err != nil { 55 return nil, err 56 } 57 } 58 59 pointer := NewPointer(oid, size, exts) 60 return &cleanedAsset{tmp.Name(), pointer}, err 61 } 62 63 func (f *GitFilter) copyToTemp(reader io.Reader, fileSize int64, cb tools.CopyCallback) (oid string, size int64, tmp *os.File, err error) { 64 tmp, err = ioutil.TempFile(f.cfg.TempDir(), "") 65 if err != nil { 66 return 67 } 68 69 defer tmp.Close() 70 71 oidHash := sha256.New() 72 writer := io.MultiWriter(oidHash, tmp) 73 74 if fileSize == 0 { 75 cb = nil 76 } 77 78 ptr, buf, err := DecodeFrom(reader) 79 80 by := make([]byte, blobSizeCutoff) 81 n, rerr := buf.Read(by) 82 by = by[:n] 83 84 if rerr != nil || (err == nil && len(by) < 512) { 85 err = errors.NewCleanPointerError(ptr, by) 86 return 87 } 88 89 var from io.Reader = bytes.NewReader(by) 90 if fileSize < 0 || int64(len(by)) < fileSize { 91 // If there is still more data to be read from the file, tack on 92 // the original reader and continue the read from there. 93 from = io.MultiReader(from, reader) 94 } 95 96 size, err = tools.CopyWithCallback(writer, from, fileSize, cb) 97 98 if err != nil { 99 return 100 } 101 102 oid = hex.EncodeToString(oidHash.Sum(nil)) 103 return 104 } 105 106 func (a *cleanedAsset) Teardown() error { 107 return os.Remove(a.Filename) 108 }