github.com/psexton/git-lfs@v2.1.1-0.20170517224304-289a18b2bc53+incompatible/lfs/pointer_clean.go (about)

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