public unsafe zio_cksum_t Calculate(ArraySegment <byte> input) { if (input.Count % 4 != 0) { throw new ArgumentException("Input must have a length that is a multiple of 4."); } ulong a, b, c, d; a = b = c = d = 0; fixed(byte *ptr = input.Array) { int size = input.Count / 4; uint *intPtr = (uint *)(ptr + input.Offset); for (int i = 0; i < size; i++) { a += intPtr[i]; b += a; c += b; d += c; } } zio_cksum_t ret = new zio_cksum_t() { word1 = a, word2 = b, word3 = c, word4 = d }; return(ret); }
public unsafe static bool IsEmbeddedChecksumValid(ArraySegment <byte> bytes, zio_cksum_t verifier) { int embeddedChecksumSize = sizeof(zio_eck_t); if (bytes.Count <= embeddedChecksumSize) { throw new ArgumentOutOfRangeException(nameof(bytes), "Not enough space for an embedded checksum."); fixed(byte *bytePtr = bytes.Array) { zio_eck_t *pzec = (zio_eck_t *)(bytePtr + bytes.Offset + bytes.Count - embeddedChecksumSize); if (!pzec->IsMagicValid) { return(false); } var expectedChecksum = pzec->zec_cksum; pzec->zec_cksum = verifier; var actualChecksum = sEmbeddedChecksum.Calculate(bytes); pzec->zec_cksum = expectedChecksum; return(actualChecksum.Equals(expectedChecksum)); } } const int SPA_MINBLOCKSHIFT = 9;
private static zio_cksum_t CalculateGangChecksumVerifier(ref blkptr_t blkptr) { var ret = new zio_cksum_t(); ret.word1 = (ulong)blkptr.dva1.VDev; ret.word2 = (ulong)(blkptr.dva1.Offset << SPA_MINBLOCKSHIFT); ret.word3 = (ulong)blkptr.PhysBirth; ret.word4 = 0; return(ret); }
/// <summary> /// Reads and verifies data from a label. /// </summary> /// <param name="offset"></param> /// <param name="count"></param> /// <returns>true if the checksum is valid, false otherwise</returns> public bool ReadLabelBytes(ArraySegment <byte> dest, long offset) { ReadBytes(dest, offset); var verifier = new zio_cksum_t() { word1 = (ulong)offset, word2 = 0, word3 = 0, word4 = 0, }; return(Zio.IsEmbeddedChecksumValid(dest, verifier)); }