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-03-17 13:15:07 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       125570 : pg_checksum_parse_type(char *name, pg_checksum_type *type)
      29              : {
      30       125570 :     pg_checksum_type result_type = CHECKSUM_TYPE_NONE;
      31       125570 :     bool        result = true;
      32              : 
      33       125570 :     if (pg_strcasecmp(name, "none") == 0)
      34            3 :         result_type = CHECKSUM_TYPE_NONE;
      35       125567 :     else if (pg_strcasecmp(name, "crc32c") == 0)
      36       116299 :         result_type = CHECKSUM_TYPE_CRC32C;
      37         9268 :     else if (pg_strcasecmp(name, "sha224") == 0)
      38         3088 :         result_type = CHECKSUM_TYPE_SHA224;
      39         6180 :     else if (pg_strcasecmp(name, "sha256") == 0)
      40         2059 :         result_type = CHECKSUM_TYPE_SHA256;
      41         4121 :     else if (pg_strcasecmp(name, "sha384") == 0)
      42         2059 :         result_type = CHECKSUM_TYPE_SHA384;
      43         2062 :     else if (pg_strcasecmp(name, "sha512") == 0)
      44         2059 :         result_type = CHECKSUM_TYPE_SHA512;
      45              :     else
      46            3 :         result = false;
      47              : 
      48       125570 :     *type = result_type;
      49       125570 :     return result;
      50              : }
      51              : 
      52              : /*
      53              :  * Get the canonical human-readable name corresponding to a checksum type.
      54              :  */
      55              : char *
      56       186568 : pg_checksum_type_name(pg_checksum_type type)
      57              : {
      58       186568 :     switch (type)
      59              :     {
      60            0 :         case CHECKSUM_TYPE_NONE:
      61            0 :             return "NONE";
      62       177312 :         case CHECKSUM_TYPE_CRC32C:
      63       177312 :             return "CRC32C";
      64         3085 :         case CHECKSUM_TYPE_SHA224:
      65         3085 :             return "SHA224";
      66         2057 :         case CHECKSUM_TYPE_SHA256:
      67         2057 :             return "SHA256";
      68         2057 :         case CHECKSUM_TYPE_SHA384:
      69         2057 :             return "SHA384";
      70         2057 :         case CHECKSUM_TYPE_SHA512:
      71         2057 :             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       261732 : pg_checksum_init(pg_checksum_context *context, pg_checksum_type type)
      84              : {
      85       261732 :     context->type = type;
      86              : 
      87       261732 :     switch (type)
      88              :     {
      89        16802 :         case CHECKSUM_TYPE_NONE:
      90              :             /* do nothing */
      91        16802 :             break;
      92       226414 :         case CHECKSUM_TYPE_CRC32C:
      93       226414 :             INIT_CRC32C(context->raw_context.c_crc32c);
      94       226414 :             break;
      95         6167 :         case CHECKSUM_TYPE_SHA224:
      96         6167 :             context->raw_context.c_sha2 = pg_cryptohash_create(PG_SHA224);
      97         6167 :             if (context->raw_context.c_sha2 == NULL)
      98            0 :                 return -1;
      99         6167 :             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         6167 :             break;
     105         4125 :         case CHECKSUM_TYPE_SHA256:
     106         4125 :             context->raw_context.c_sha2 = pg_cryptohash_create(PG_SHA256);
     107         4125 :             if (context->raw_context.c_sha2 == NULL)
     108            0 :                 return -1;
     109         4125 :             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         4125 :             break;
     115         4112 :         case CHECKSUM_TYPE_SHA384:
     116         4112 :             context->raw_context.c_sha2 = pg_cryptohash_create(PG_SHA384);
     117         4112 :             if (context->raw_context.c_sha2 == NULL)
     118            0 :                 return -1;
     119         4112 :             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         4112 :             break;
     125         4112 :         case CHECKSUM_TYPE_SHA512:
     126         4112 :             context->raw_context.c_sha2 = pg_cryptohash_create(PG_SHA512);
     127         4112 :             if (context->raw_context.c_sha2 == NULL)
     128            0 :                 return -1;
     129         4112 :             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         4112 :             break;
     135              :     }
     136              : 
     137       261732 :     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       425797 : pg_checksum_update(pg_checksum_context *context, const uint8 *input,
     146              :                    size_t len)
     147              : {
     148       425797 :     switch (context->type)
     149              :     {
     150        14694 :         case CHECKSUM_TYPE_NONE:
     151              :             /* do nothing */
     152        14694 :             break;
     153       391858 :         case CHECKSUM_TYPE_CRC32C:
     154       391858 :             COMP_CRC32C(context->raw_context.c_crc32c, input, len);
     155       391858 :             break;
     156        19245 :         case CHECKSUM_TYPE_SHA224:
     157              :         case CHECKSUM_TYPE_SHA256:
     158              :         case CHECKSUM_TYPE_SHA384:
     159              :         case CHECKSUM_TYPE_SHA512:
     160        19245 :             if (pg_cryptohash_update(context->raw_context.c_sha2, input, len) < 0)
     161            0 :                 return -1;
     162        19245 :             break;
     163              :     }
     164              : 
     165       425797 :     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       244929 : pg_checksum_final(pg_checksum_context *context, uint8 *output)
     177              : {
     178       244929 :     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       244929 :     switch (context->type)
     192              :     {
     193            2 :         case CHECKSUM_TYPE_NONE:
     194            2 :             break;
     195       226412 :         case CHECKSUM_TYPE_CRC32C:
     196       226412 :             FIN_CRC32C(context->raw_context.c_crc32c);
     197       226412 :             retval = sizeof(pg_crc32c);
     198       226412 :             memcpy(output, &context->raw_context.c_crc32c, retval);
     199       226412 :             break;
     200         6167 :         case CHECKSUM_TYPE_SHA224:
     201         6167 :             retval = PG_SHA224_DIGEST_LENGTH;
     202         6167 :             if (pg_cryptohash_final(context->raw_context.c_sha2,
     203              :                                     output, retval) < 0)
     204            0 :                 return -1;
     205         6167 :             pg_cryptohash_free(context->raw_context.c_sha2);
     206         6167 :             break;
     207         4124 :         case CHECKSUM_TYPE_SHA256:
     208         4124 :             retval = PG_SHA256_DIGEST_LENGTH;
     209         4124 :             if (pg_cryptohash_final(context->raw_context.c_sha2,
     210              :                                     output, retval) < 0)
     211            0 :                 return -1;
     212         4124 :             pg_cryptohash_free(context->raw_context.c_sha2);
     213         4124 :             break;
     214         4112 :         case CHECKSUM_TYPE_SHA384:
     215         4112 :             retval = PG_SHA384_DIGEST_LENGTH;
     216         4112 :             if (pg_cryptohash_final(context->raw_context.c_sha2,
     217              :                                     output, retval) < 0)
     218            0 :                 return -1;
     219         4112 :             pg_cryptohash_free(context->raw_context.c_sha2);
     220         4112 :             break;
     221         4112 :         case CHECKSUM_TYPE_SHA512:
     222         4112 :             retval = PG_SHA512_DIGEST_LENGTH;
     223         4112 :             if (pg_cryptohash_final(context->raw_context.c_sha2,
     224              :                                     output, retval) < 0)
     225            0 :                 return -1;
     226         4112 :             pg_cryptohash_free(context->raw_context.c_sha2);
     227         4112 :             break;
     228              :     }
     229              : 
     230              :     Assert(retval <= PG_CHECKSUM_MAX_LENGTH);
     231       244929 :     return retval;
     232              : }
        

Generated by: LCOV version 2.0-1