root/src/add-ons/kernel/file_systems/xfs/Checksum.h
/*
 * Copyright 2022, Raghav Sharma, raghavself28@gmail.com
 * Distributed under the terms of the MIT License.
 */
#ifndef _XFS_CKSUM_H
#define _XFS_CKSUM_H


#include "CRCTable.h"
#include "xfs_types.h"
#include "system_dependencies.h"


#define XFS_CRC_SEED    (~(uint32)0)


/*
   Calculate the intermediate checksum for a buffer that has the CRC field
   inside it.  The offset of the 32bit crc fields is passed as the
   cksum_offset parameter. We do not modify the buffer during verification,
   hence we have to split the CRC calculation across the cksum_offset.
*/
static inline uint32
xfs_start_cksum_safe(const char *buffer, size_t length, uint32 cksum_offset)
{
        uint32 zero = 0;
        uint32 crc;

        // Calculate CRC up to the checksum.
        crc = calculate_crc32c(XFS_CRC_SEED, (uint8*)buffer, cksum_offset);

        // Skip checksum field
        crc = calculate_crc32c(crc, (uint8*)&zero, sizeof(uint32));

        // Calculate the rest of the CRC.
        return calculate_crc32c(crc, (uint8*)buffer + cksum_offset + sizeof(uint32),
                      length - (cksum_offset + sizeof(uint32)));
}


/*
   Fast CRC method where the buffer is modified. Callers must have exclusive
   access to the buffer while the calculation takes place.
*/
static inline uint32
xfs_start_cksum_update(const char *buffer, size_t length, uint32 cksum_offset)
{
        // zero the CRC field
        *(uint32 *)(buffer + cksum_offset) = 0;

        // single pass CRC calculation for the entire buffer
        return calculate_crc32c(XFS_CRC_SEED, (uint8*)buffer, length);
}


/*
   Helper to generate the checksum for a buffer.

   This modifies the buffer temporarily - callers must have exclusive
   access to the buffer while the calculation takes place.
*/
static inline void
xfs_update_cksum(const char *buffer, size_t length, uint32 cksum_offset)
{
        uint32 crc = xfs_start_cksum_update(buffer, length, cksum_offset);

        *(uint32 *)(buffer + cksum_offset) = ~crc;
}


/*
   Helper to verify the checksum for a buffer.
*/
static inline int
xfs_verify_cksum(const char *buffer, size_t length, uint32 cksum_offset)
{
        uint32 crc = xfs_start_cksum_safe(buffer, length, cksum_offset);

        TRACE("calculated crc: (%" B_PRIu32 ")\n", ~crc);

        TRACE("buffer = %s, cksum_offset: (%" B_PRIu32 ")\n", buffer, cksum_offset);

        return *(uint32 *)(buffer + cksum_offset) == (~crc);
}