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 */ 23 static inline uint32 24 xfs_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 */ 45 static inline uint32 46 xfs_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 */ 62 static inline void 63 xfs_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 */ 74 static inline int 75 xfs_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