LCOV - code coverage report
Current view: top level - src/common - checksum_helper.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 83.5 % 121 101
Test Date: 2026-02-17 17:20:33 Functions: 100.0 % 5 5
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /*-------------------------------------------------------------------------
       2              :  *
       3              :  * checksum_helper.c
       4              :  *    Compute a checksum of any of various types using common routines
       5              :  *
       6              :  * Portions Copyright (c) 2016-2026, PostgreSQL Global Development Group
       7              :  *
       8              :  * IDENTIFICATION
       9              :  *        src/common/checksum_helper.c
      10              :  *
      11              :  *-------------------------------------------------------------------------
      12              :  */
      13              : 
      14              : #ifndef FRONTEND
      15              : #include "postgres.h"
      16              : #else
      17              : #include "postgres_fe.h"
      18              : #endif
      19              : 
      20              : #include "common/checksum_helper.h"
      21              : 
      22              : /*
      23              :  * If 'name' is a recognized checksum type, set *type to the corresponding
      24              :  * constant and return true. Otherwise, set *type to CHECKSUM_TYPE_NONE and
      25              :  * return false.
      26              :  */
      27              : bool
      28       118250 : pg_checksum_parse_type(char *name, pg_checksum_type *type)
      29              : {
      30       118250 :     pg_checksum_type result_type = CHECKSUM_TYPE_NONE;
      31       118250 :     bool        result = true;
      32              : 
      33       118250 :     if (pg_strcasecmp(name, "none") == 0)
      34            3 :         result_type = CHECKSUM_TYPE_NONE;
      35       118247 :     else if (pg_strcasecmp(name, "crc32c") == 0)
      36       109519 :         result_type = CHECKSUM_TYPE_CRC32C;
      37         8728 :     else if (pg_strcasecmp(name, "sha224") == 0)
      38         2908 :         result_type = CHECKSUM_TYPE_SHA224;
      39         5820 :     else if (pg_strcasecmp(name, "sha256") == 0)
      40         1939 :         result_type = CHECKSUM_TYPE_SHA256;
      41         3881 :     else if (pg_strcasecmp(name, "sha384") == 0)
      42         1939 :         result_type = CHECKSUM_TYPE_SHA384;
      43         1942 :     else if (pg_strcasecmp(name, "sha512") == 0)
      44         1939 :         result_type = CHECKSUM_TYPE_SHA512;
      45              :     else
      46            3 :         result = false;
      47              : 
      48       118250 :     *type = result_type;
      49       118250 :     return result;
      50              : }
      51              : 
      52              : /*
      53              :  * Get the canonical human-readable name corresponding to a checksum type.
      54              :  */
      55              : char *
      56       175672 : pg_checksum_type_name(pg_checksum_type type)
      57              : {
      58       175672 :     switch (type)
      59              :     {
      60            0 :         case CHECKSUM_TYPE_NONE:
      61            0 :             return "NONE";
      62       166956 :         case CHECKSUM_TYPE_CRC32C:
      63       166956 :             return "CRC32C";
      64         2905 :         case CHECKSUM_TYPE_SHA224:
      65         2905 :             return "SHA224";
      66         1937 :         case CHECKSUM_TYPE_SHA256:
      67         1937 :             return "SHA256";
      68         1937 :         case CHECKSUM_TYPE_SHA384:
      69         1937 :             return "SHA384";
      70         1937 :         case CHECKSUM_TYPE_SHA512:
      71         1937 :             return "SHA512";
      72              :     }
      73              : 
      74              :     Assert(false);
      75            0 :     return "???";
      76              : }
      77              : 
      78              : /*
      79              :  * Initialize a checksum context for checksums of the given type.
      80              :  * Returns 0 for a success, -1 for a failure.
      81              :  */
      82              : int
      83       246457 : pg_checksum_init(pg_checksum_context *context, pg_checksum_type type)
      84              : {
      85       246457 :     context->type = type;
      86              : 
      87       246457 :     switch (type)
      88              :     {
      89        15823 :         case CHECKSUM_TYPE_NONE:
      90              :             /* do nothing */
      91        15823 :             break;
      92       213198 :         case CHECKSUM_TYPE_CRC32C:
      93       213198 :             INIT_CRC32C(context->raw_context.c_crc32c);
      94       213198 :             break;
      95         5807 :         case CHECKSUM_TYPE_SHA224:
      96         5807 :             context->raw_context.c_sha2 = pg_cryptohash_create(PG_SHA224);
      97         5807 :             if (context->raw_context.c_sha2 == NULL)
      98            0 :                 return -1;
      99         5807 :             if (pg_cryptohash_init(context->raw_context.c_sha2) < 0)
     100              :             {
     101            0 :                 pg_cryptohash_free(context->raw_context.c_sha2);
     102            0 :                 return -1;
     103              :             }
     104         5807 :             break;
     105         3885 :         case CHECKSUM_TYPE_SHA256:
     106         3885 :             context->raw_context.c_sha2 = pg_cryptohash_create(PG_SHA256);
     107         3885 :             if (context->raw_context.c_sha2 == NULL)
     108            0 :                 return -1;
     109         3885 :             if (pg_cryptohash_init(context->raw_context.c_sha2) < 0)
     110              :             {
     111            0 :                 pg_cryptohash_free(context->raw_context.c_sha2);
     112            0 :                 return -1;
     113              :             }
     114         3885 :             break;
     115         3872 :         case CHECKSUM_TYPE_SHA384:
     116         3872 :             context->raw_context.c_sha2 = pg_cryptohash_create(PG_SHA384);
     117         3872 :             if (context->raw_context.c_sha2 == NULL)
     118            0 :                 return -1;
     119         3872 :             if (pg_cryptohash_init(context->raw_context.c_sha2) < 0)
     120              :             {
     121            0 :                 pg_cryptohash_free(context->raw_context.c_sha2);
     122            0 :                 return -1;
     123              :             }
     124         3872 :             break;
     125         3872 :         case CHECKSUM_TYPE_SHA512:
     126         3872 :             context->raw_context.c_sha2 = pg_cryptohash_create(PG_SHA512);
     127         3872 :             if (context->raw_context.c_sha2 == NULL)
     128            0 :                 return -1;
     129         3872 :             if (pg_cryptohash_init(context->raw_context.c_sha2) < 0)
     130              :             {
     131            0 :                 pg_cryptohash_free(context->raw_context.c_sha2);
     132            0 :                 return -1;
     133              :             }
     134         3872 :             break;
     135              :     }
     136              : 
     137       246457 :     return 0;
     138              : }
     139              : 
     140              : /*
     141              :  * Update a checksum context with new data.
     142              :  * Returns 0 for a success, -1 for a failure.
     143              :  */
     144              : int
     145       411642 : pg_checksum_update(pg_checksum_context *context, const uint8 *input,
     146              :                    size_t len)
     147              : {
     148       411642 :     switch (context->type)
     149              :     {
     150        14069 :         case CHECKSUM_TYPE_NONE:
     151              :             /* do nothing */
     152        14069 :             break;
     153       379109 :         case CHECKSUM_TYPE_CRC32C:
     154       379109 :             COMP_CRC32C(context->raw_context.c_crc32c, input, len);
     155       379109 :             break;
     156        18464 :         case CHECKSUM_TYPE_SHA224:
     157              :         case CHECKSUM_TYPE_SHA256:
     158              :         case CHECKSUM_TYPE_SHA384:
     159              :         case CHECKSUM_TYPE_SHA512:
     160        18464 :             if (pg_cryptohash_update(context->raw_context.c_sha2, input, len) < 0)
     161            0 :                 return -1;
     162        18464 :             break;
     163              :     }
     164              : 
     165       411642 :     return 0;
     166              : }
     167              : 
     168              : /*
     169              :  * Finalize a checksum computation and write the result to an output buffer.
     170              :  *
     171              :  * The caller must ensure that the buffer is at least PG_CHECKSUM_MAX_LENGTH
     172              :  * bytes in length. The return value is the number of bytes actually written,
     173              :  * or -1 for a failure.
     174              :  */
     175              : int
     176       230633 : pg_checksum_final(pg_checksum_context *context, uint8 *output)
     177              : {
     178       230633 :     int         retval = 0;
     179              : 
     180              :     StaticAssertDecl(sizeof(pg_crc32c) <= PG_CHECKSUM_MAX_LENGTH,
     181              :                      "CRC-32C digest too big for PG_CHECKSUM_MAX_LENGTH");
     182              :     StaticAssertDecl(PG_SHA224_DIGEST_LENGTH <= PG_CHECKSUM_MAX_LENGTH,
     183              :                      "SHA224 digest too big for PG_CHECKSUM_MAX_LENGTH");
     184              :     StaticAssertDecl(PG_SHA256_DIGEST_LENGTH <= PG_CHECKSUM_MAX_LENGTH,
     185              :                      "SHA256 digest too big for PG_CHECKSUM_MAX_LENGTH");
     186              :     StaticAssertDecl(PG_SHA384_DIGEST_LENGTH <= PG_CHECKSUM_MAX_LENGTH,
     187              :                      "SHA384 digest too big for PG_CHECKSUM_MAX_LENGTH");
     188              :     StaticAssertDecl(PG_SHA512_DIGEST_LENGTH <= PG_CHECKSUM_MAX_LENGTH,
     189              :                      "SHA512 digest too big for PG_CHECKSUM_MAX_LENGTH");
     190              : 
     191       230633 :     switch (context->type)
     192              :     {
     193            2 :         case CHECKSUM_TYPE_NONE:
     194            2 :             break;
     195       213196 :         case CHECKSUM_TYPE_CRC32C:
     196       213196 :             FIN_CRC32C(context->raw_context.c_crc32c);
     197       213196 :             retval = sizeof(pg_crc32c);
     198       213196 :             memcpy(output, &context->raw_context.c_crc32c, retval);
     199       213196 :             break;
     200         5807 :         case CHECKSUM_TYPE_SHA224:
     201         5807 :             retval = PG_SHA224_DIGEST_LENGTH;
     202         5807 :             if (pg_cryptohash_final(context->raw_context.c_sha2,
     203              :                                     output, retval) < 0)
     204            0 :                 return -1;
     205         5807 :             pg_cryptohash_free(context->raw_context.c_sha2);
     206         5807 :             break;
     207         3884 :         case CHECKSUM_TYPE_SHA256:
     208         3884 :             retval = PG_SHA256_DIGEST_LENGTH;
     209         3884 :             if (pg_cryptohash_final(context->raw_context.c_sha2,
     210              :                                     output, retval) < 0)
     211            0 :                 return -1;
     212         3884 :             pg_cryptohash_free(context->raw_context.c_sha2);
     213         3884 :             break;
     214         3872 :         case CHECKSUM_TYPE_SHA384:
     215         3872 :             retval = PG_SHA384_DIGEST_LENGTH;
     216         3872 :             if (pg_cryptohash_final(context->raw_context.c_sha2,
     217              :                                     output, retval) < 0)
     218            0 :                 return -1;
     219         3872 :             pg_cryptohash_free(context->raw_context.c_sha2);
     220         3872 :             break;
     221         3872 :         case CHECKSUM_TYPE_SHA512:
     222         3872 :             retval = PG_SHA512_DIGEST_LENGTH;
     223         3872 :             if (pg_cryptohash_final(context->raw_context.c_sha2,
     224              :                                     output, retval) < 0)
     225            0 :                 return -1;
     226         3872 :             pg_cryptohash_free(context->raw_context.c_sha2);
     227         3872 :             break;
     228              :     }
     229              : 
     230              :     Assert(retval <= PG_CHECKSUM_MAX_LENGTH);
     231       230633 :     return retval;
     232              : }
        

Generated by: LCOV version 2.0-1