github.com/keysonzzz/kmg@v0.0.0-20151121023212-05317bfd7d39/third/kmgQiniu/Hash.go (about)

     1  package kmgQiniu
     2  
     3  import (
     4  	"bytes"
     5  	"crypto/sha1"
     6  	"encoding/base64"
     7  	"io"
     8  	"os"
     9  )
    10  
    11  const (
    12  	hash_BLOCK_BITS = 22 // Indicate that the blocksize is 4M
    13  	hash_BLOCK_SIZE = 1 << hash_BLOCK_BITS
    14  )
    15  
    16  func hashBlockCount(fsize int64) int {
    17  
    18  	return int((fsize + (hash_BLOCK_SIZE - 1)) >> hash_BLOCK_BITS)
    19  }
    20  
    21  func calSha1(b []byte, r io.Reader) ([]byte, error) {
    22  
    23  	h := sha1.New()
    24  	_, err := io.Copy(h, r)
    25  	if err != nil {
    26  		return nil, err
    27  	}
    28  	return h.Sum(b), nil
    29  }
    30  
    31  //计算从文件计算七牛hash值
    32  func ComputeHashFromFile(filename string) (etag string, err error) {
    33  	f, err := os.Open(filename)
    34  	if err != nil {
    35  		return
    36  	}
    37  	defer f.Close()
    38  
    39  	fi, err := f.Stat()
    40  	if err != nil {
    41  		return
    42  	}
    43  
    44  	fsize := fi.Size()
    45  	blockCnt := hashBlockCount(fsize)
    46  	sha1Buf := make([]byte, 0, 21)
    47  
    48  	if blockCnt <= 1 { // file size <= 4M
    49  		sha1Buf = append(sha1Buf, 0x16)
    50  		sha1Buf, err = calSha1(sha1Buf, f)
    51  		if err != nil {
    52  			return
    53  		}
    54  	} else { // file size > 4M
    55  		sha1Buf = append(sha1Buf, 0x96)
    56  		sha1BlockBuf := make([]byte, 0, blockCnt*20)
    57  		for i := 0; i < blockCnt; i++ {
    58  			body := io.LimitReader(f, hash_BLOCK_SIZE)
    59  			sha1BlockBuf, err = calSha1(sha1BlockBuf, body)
    60  			if err != nil {
    61  				return
    62  			}
    63  		}
    64  		sha1Buf, _ = calSha1(sha1Buf, bytes.NewReader(sha1BlockBuf))
    65  	}
    66  	etag = base64.URLEncoding.EncodeToString(sha1Buf)
    67  	return
    68  }
    69  
    70  func ComputeHashFromBytes(b []byte) (etag string) {
    71  	f := bytes.NewReader(b)
    72  	blockCnt := hashBlockCount(int64(len(b)))
    73  	sha1Buf := make([]byte, 0, 21)
    74  
    75  	var err error
    76  	if blockCnt <= 1 { // file size <= 4M
    77  		sha1Buf = append(sha1Buf, 0x16)
    78  		sha1Buf, err = calSha1(sha1Buf, f)
    79  		if err != nil {
    80  			panic(err)
    81  		}
    82  	} else { // file size > 4M
    83  		sha1Buf = append(sha1Buf, 0x96)
    84  		sha1BlockBuf := make([]byte, 0, blockCnt*20)
    85  		for i := 0; i < blockCnt; i++ {
    86  			body := io.LimitReader(f, hash_BLOCK_SIZE)
    87  			sha1BlockBuf, err = calSha1(sha1BlockBuf, body)
    88  			if err != nil {
    89  				panic(err)
    90  			}
    91  		}
    92  		sha1Buf, _ = calSha1(sha1Buf, bytes.NewReader(sha1BlockBuf))
    93  	}
    94  	etag = base64.URLEncoding.EncodeToString(sha1Buf)
    95  	return
    96  }