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  }