mirror of
https://github.com/versity/versitygw.git
synced 2026-01-07 04:06:23 +00:00
The CRC32, CRC32c, and CRC64NVME data integrity checksums support calculating the composite full object values for multi-part uploads using the checksum and length of the individual parts. Previously, we were reading all of the part data to recalculate the full object checksum values during the complete multipart upload call. This disabled the optimized copy_file_range() for certain filesystems such as XFS because the part data was being read. If the data is not read, and the file handle is passed directly to io.Copy(), then the filesystem is allowed to optimize the copying of the data from the source to destination files. This now allows both the optimized copy_file_range() optimizations as well as the data integrity features enabled for support composite checksum types.
181 lines
4.7 KiB
Go
181 lines
4.7 KiB
Go
// Copyright (C) 1995-2017 Jean-loup Gailly and Mark Adler
|
|
//
|
|
// This software is provided 'as-is', without any express or implied
|
|
// warranty. In no event will the authors be held liable for any damages
|
|
// arising from the use of this software.
|
|
//
|
|
// Permission is granted to anyone to use this software for any purpose,
|
|
// including commercial applications, and to alter it and redistribute it
|
|
// freely, subject to the following restrictions:
|
|
//
|
|
// 1. The origin of this software must not be misrepresented; you must not
|
|
// claim that you wrote the original software. If you use this software
|
|
// in a product, an acknowledgment in the product documentation would be
|
|
// appreciated but is not required.
|
|
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
// misrepresented as being the original software.
|
|
// 3. This notice may not be removed or altered from any source distribution.
|
|
//
|
|
// Jean-loup Gailly Mark Adler
|
|
// jloup@gzip.org madler@alumni.caltech.edu
|
|
|
|
// Original implementation is from
|
|
// https://github.com/vimeo/go-util/blob/8cd4c737f091d9317f72b25df78ce6cf869f7d30/crc32combine/crc32combine.go
|
|
// extended for crc64 support.
|
|
|
|
// Following is ported from C to Go in 2016 by Justin Ruggles, with minimal alteration.
|
|
// Used uint for unsigned long. Used uint32 for input arguments in order to match
|
|
// the Go hash/crc32 package. zlib CRC32 combine (https://github.com/madler/zlib)
|
|
|
|
package utils
|
|
|
|
import (
|
|
"hash/crc64"
|
|
)
|
|
|
|
const crc64NVME = 0x9a6c_9329_ac4b_c9b5
|
|
|
|
var crc64NVMETable = crc64.MakeTable(crc64NVME)
|
|
|
|
func gf2MatrixTimes(mat []uint64, vec uint64) uint64 {
|
|
var sum uint64
|
|
|
|
for vec != 0 {
|
|
if vec&1 != 0 {
|
|
sum ^= mat[0]
|
|
}
|
|
vec >>= 1
|
|
mat = mat[1:]
|
|
}
|
|
return sum
|
|
}
|
|
|
|
func gf2MatrixSquare(square, mat []uint64) {
|
|
if len(square) != len(mat) {
|
|
panic("square matrix size mismatch")
|
|
}
|
|
for n := range mat {
|
|
square[n] = gf2MatrixTimes(mat, mat[n])
|
|
}
|
|
}
|
|
|
|
// crc32Combine returns the combined CRC-32 hash value of the two passed CRC-32
|
|
// hash values crc1 and crc2. poly represents the generator polynomial
|
|
// and len2 specifies the byte length that the crc2 hash covers.
|
|
func crc32Combine(poly uint32, crc1, crc2 uint32, len2 int64) uint32 {
|
|
// degenerate case (also disallow negative lengths)
|
|
if len2 <= 0 {
|
|
return crc1
|
|
}
|
|
|
|
even := make([]uint64, 32) // even-power-of-two zeros operator
|
|
odd := make([]uint64, 32) // odd-power-of-two zeros operator
|
|
|
|
// put operator for one zero bit in odd
|
|
odd[0] = uint64(poly) // CRC-32 polynomial
|
|
row := uint64(1)
|
|
for n := 1; n < 32; n++ {
|
|
odd[n] = row
|
|
row <<= 1
|
|
}
|
|
|
|
// put operator for two zero bits in even
|
|
gf2MatrixSquare(even, odd)
|
|
|
|
// put operator for four zero bits in odd
|
|
gf2MatrixSquare(odd, even)
|
|
|
|
// apply len2 zeros to crc1 (first square will put the operator for one
|
|
// zero byte, eight zero bits, in even)
|
|
crc1n := uint64(crc1)
|
|
for {
|
|
// apply zeros operator for this bit of len2
|
|
gf2MatrixSquare(even, odd)
|
|
if len2&1 != 0 {
|
|
crc1n = gf2MatrixTimes(even, crc1n)
|
|
}
|
|
len2 >>= 1
|
|
|
|
// if no more bits set, then done
|
|
if len2 == 0 {
|
|
break
|
|
}
|
|
|
|
// another iteration of the loop with odd and even swapped
|
|
gf2MatrixSquare(odd, even)
|
|
if len2&1 != 0 {
|
|
crc1n = gf2MatrixTimes(odd, crc1n)
|
|
}
|
|
len2 >>= 1
|
|
|
|
// if no more bits set, then done
|
|
if len2 == 0 {
|
|
break
|
|
}
|
|
}
|
|
|
|
// return combined crc
|
|
crc1n ^= uint64(crc2)
|
|
return uint32(crc1n)
|
|
}
|
|
|
|
// crc64Combine returns the combined CRC-64 hash value of the two passed CRC-64
|
|
// hash values crc1 and crc2. poly represents the generator polynomial
|
|
// and len2 specifies the byte length that the crc2 hash covers.
|
|
func crc64Combine(poly uint64, crc1, crc2 uint64, len2 int64) uint64 {
|
|
// degenerate case (also disallow negative lengths)
|
|
if len2 <= 0 {
|
|
return crc1
|
|
}
|
|
|
|
even := make([]uint64, 64) // even-power-of-two zeros operator
|
|
odd := make([]uint64, 64) // odd-power-of-two zeros operator
|
|
|
|
// put operator for one zero bit in odd
|
|
odd[0] = poly // CRC-64 polynomial
|
|
row := uint64(1)
|
|
for n := 1; n < 64; n++ {
|
|
odd[n] = row
|
|
row <<= 1
|
|
}
|
|
|
|
// put operator for two zero bits in even
|
|
gf2MatrixSquare(even, odd)
|
|
|
|
// put operator for four zero bits in odd
|
|
gf2MatrixSquare(odd, even)
|
|
|
|
// apply len2 zeros to crc1 (first square will put the operator for one
|
|
// zero byte, eight zero bits, in even)
|
|
crc1n := crc1
|
|
for {
|
|
// apply zeros operator for this bit of len2
|
|
gf2MatrixSquare(even, odd)
|
|
if len2&1 != 0 {
|
|
crc1n = gf2MatrixTimes(even, crc1n)
|
|
}
|
|
len2 >>= 1
|
|
|
|
// if no more bits set, then done
|
|
if len2 == 0 {
|
|
break
|
|
}
|
|
|
|
// another iteration of the loop with odd and even swapped
|
|
gf2MatrixSquare(odd, even)
|
|
if len2&1 != 0 {
|
|
crc1n = gf2MatrixTimes(odd, crc1n)
|
|
}
|
|
len2 >>= 1
|
|
|
|
// if no more bits set, then done
|
|
if len2 == 0 {
|
|
break
|
|
}
|
|
}
|
|
|
|
// return combined crc
|
|
crc1n ^= crc2
|
|
return crc1n
|
|
}
|