1/*
2 * Copyright 2022, Raghav Sharma, raghavself28@gmail.com
3 * Distributed under the terms of the MIT License.
4 */
5#ifndef _XFS_CKSUM_H
6#define _XFS_CKSUM_H
7
8
9#include "CRCTable.h"
10#include "xfs_types.h"
11#include "system_dependencies.h"
12
13
14#define XFS_CRC_SEED	(~(uint32)0)
15
16
17/*
18   Calculate the intermediate checksum for a buffer that has the CRC field
19   inside it.  The offset of the 32bit crc fields is passed as the
20   cksum_offset parameter. We do not modify the buffer during verification,
21   hence we have to split the CRC calculation across the cksum_offset.
22*/
23static inline uint32
24xfs_start_cksum_safe(const char *buffer, size_t length, uint32 cksum_offset)
25{
26	uint32 zero = 0;
27	uint32 crc;
28
29	// Calculate CRC up to the checksum.
30	crc = calculate_crc32c(XFS_CRC_SEED, (uint8*)buffer, cksum_offset);
31
32	// Skip checksum field
33	crc = calculate_crc32c(crc, (uint8*)&zero, sizeof(uint32));
34
35	// Calculate the rest of the CRC.
36	return calculate_crc32c(crc, (uint8*)buffer + cksum_offset + sizeof(uint32),
37		      length - (cksum_offset + sizeof(uint32)));
38}
39
40
41/*
42   Fast CRC method where the buffer is modified. Callers must have exclusive
43   access to the buffer while the calculation takes place.
44*/
45static inline uint32
46xfs_start_cksum_update(const char *buffer, size_t length, uint32 cksum_offset)
47{
48	// zero the CRC field
49	*(uint32 *)(buffer + cksum_offset) = 0;
50
51	// single pass CRC calculation for the entire buffer
52	return calculate_crc32c(XFS_CRC_SEED, (uint8*)buffer, length);
53}
54
55
56/*
57   Helper to generate the checksum for a buffer.
58
59   This modifies the buffer temporarily - callers must have exclusive
60   access to the buffer while the calculation takes place.
61*/
62static inline void
63xfs_update_cksum(const char *buffer, size_t length, uint32 cksum_offset)
64{
65	uint32 crc = xfs_start_cksum_update(buffer, length, cksum_offset);
66
67	*(uint32 *)(buffer + cksum_offset) = ~crc;
68}
69
70
71/*
72   Helper to verify the checksum for a buffer.
73*/
74static inline int
75xfs_verify_cksum(const char *buffer, size_t length, uint32 cksum_offset)
76{
77	uint32 crc = xfs_start_cksum_safe(buffer, length, cksum_offset);
78
79	TRACE("calculated crc: (%" B_PRIu32 ")\n", ~crc);
80
81	TRACE("buffer = %s, cksum_offset: (%" B_PRIu32 ")\n", buffer, cksum_offset);
82
83	return *(uint32 *)(buffer + cksum_offset) == (~crc);
84}
85
86#endif