From 1ffa5846e8ada8b991fad61fb43b7cb2a411bd64 Mon Sep 17 00:00:00 2001 From: kanade Date: Thu, 30 Jun 2022 17:25:24 +0800 Subject: [PATCH] init --- .gitignore | 12 ++++++ LICENSE | 21 +++++++++++ README.md | 1 + etag.go | 102 +++++++++++++++++++++++++++++++++++++++++++++++++++ etag_test.go | 15 ++++++++ 5 files changed, 151 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.md create mode 100644 etag.go create mode 100644 etag_test.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f1c181e --- /dev/null +++ b/.gitignore @@ -0,0 +1,12 @@ +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, build with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..6158730 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 golangkit + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..6a369f3 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# filetag \ No newline at end of file diff --git a/etag.go b/etag.go new file mode 100644 index 0000000..0b3ea5e --- /dev/null +++ b/etag.go @@ -0,0 +1,102 @@ +package filetag + +import ( + "bytes" + "crypto/sha1" + "encoding/base64" + "io" + "mime/multipart" + "os" +) + +const ( + _BlockBits = 22 // Indicate that the blockSize is 4M + _BlockSize = 1 << _BlockBits +) + +func blockCount(fileSize int64) int { + return int((fileSize + (_BlockSize -1)) >> _BlockBits) +} + +// 计算文件SHA1值 +func sha1Value(b []byte, r io.Reader) ([]byte, error) { + + h := sha1.New() + _, err := io.Copy(h, r) + if err != nil { + return nil, err + } + return h.Sum(b), nil +} + +// 依据文件大小将计算出etag值 +func Filename(fn string) (etag string, err error) { + f, err := os.Open(fn) + if err != nil { + return + } + defer f.Close() + + fi, err := f.Stat() + if err != nil { + return + } + + fileSize := fi.Size() + blockCnt := blockCount(fileSize) + sha1Buf := make([]byte, 0, 21) + + if blockCnt <= 1 { // file size <= 4M + sha1Buf = append(sha1Buf, 0x16) + sha1Buf, err = sha1Value(sha1Buf, f) + if err != nil { + return + } + } else { // file size > 4M + sha1Buf = append(sha1Buf, 0x96) + sha1BlockBuf := make([]byte, 0, blockCnt * 20) + for i := 0; i < blockCnt; i ++ { + body := io.LimitReader(f, _BlockSize) + sha1BlockBuf, err = sha1Value(sha1BlockBuf, body) + if err != nil { + return + } + } + sha1Buf, _ = sha1Value(sha1Buf, bytes.NewReader(sha1BlockBuf)) + } + etag = base64.URLEncoding.EncodeToString(sha1Buf) + return +} + +// 依据文件大小将计算出etag值 +func Multipart(f *multipart.FileHeader) (etag string, err error) { + src, err := f.Open() + if err != nil { + return + } + defer src.Close() + + blockCnt := blockCount(f.Size) + sha1Buf := make([]byte, 0, 21) + + if blockCnt <= 1 { // file size <= 4M + sha1Buf = append(sha1Buf, 0x16) + sha1Buf, err = sha1Value(sha1Buf, src) + if err != nil { + return + } + } else { // file size > 4M + sha1Buf = append(sha1Buf, 0x96) + sha1BlockBuf := make([]byte, 0, blockCnt * 20) + for i := 0; i < blockCnt; i ++ { + body := io.LimitReader(src, _BlockSize) + sha1BlockBuf, err = sha1Value(sha1BlockBuf, body) + if err != nil { + return + } + } + sha1Buf, _ = sha1Value(sha1Buf, bytes.NewReader(sha1BlockBuf)) + } + etag = base64.URLEncoding.EncodeToString(sha1Buf) + return +} \ No newline at end of file diff --git a/etag_test.go b/etag_test.go new file mode 100644 index 0000000..d4159f3 --- /dev/null +++ b/etag_test.go @@ -0,0 +1,15 @@ +package filetag + +import ( + "fmt" + "testing" +) + +func Test_etag(t *testing.T) { + etag, err := With("/Users/xorshine/Desktop/c.jpeg") + if err != nil { + t.Fatal(err) + return + } + fmt.Println(etag) +}