LCOV - code coverage report
Current view: top level - src/common - checksum_helper.c (source / functions) Hit Total Coverage
Test: PostgreSQL 17devel Lines: 102 122 83.6 %
Date: 2024-04-26 00:11:43 Functions: 5 5 100.0 %
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-2024, 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      172062 : pg_checksum_parse_type(char *name, pg_checksum_type *type)
      29             : {
      30      172062 :     pg_checksum_type result_type = CHECKSUM_TYPE_NONE;
      31      172062 :     bool        result = true;
      32             : 
      33      172062 :     if (pg_strcasecmp(name, "none") == 0)
      34           4 :         result_type = CHECKSUM_TYPE_NONE;
      35      172058 :     else if (pg_strcasecmp(name, "crc32c") == 0)
      36      162384 :         result_type = CHECKSUM_TYPE_CRC32C;
      37        9674 :     else if (pg_strcasecmp(name, "sha224") == 0)
      38        3868 :         result_type = CHECKSUM_TYPE_SHA224;
      39        5806 :     else if (pg_strcasecmp(name, "sha256") == 0)
      40        1934 :         result_type = CHECKSUM_TYPE_SHA256;
      41        3872 :     else if (pg_strcasecmp(name, "sha384") == 0)
      42        1934 :         result_type = CHECKSUM_TYPE_SHA384;
      43        1938 :     else if (pg_strcasecmp(name, "sha512") == 0)
      44        1934 :         result_type = CHECKSUM_TYPE_SHA512;
      45             :     else
      46           4 :         result = false;
      47             : 
      48      172062 :     *type = result_type;
      49      172062 :     return result;
      50             : }
      51             : 
      52             : /*
      53             :  * Get the canonical human-readable name corresponding to a checksum type.
      54             :  */
      55             : char *
      56      284694 : pg_checksum_type_name(pg_checksum_type type)
      57             : {
      58      284694 :     switch (type)
      59             :     {
      60           0 :         case CHECKSUM_TYPE_NONE:
      61           0 :             return "NONE";
      62      275034 :         case CHECKSUM_TYPE_CRC32C:
      63      275034 :             return "CRC32C";
      64        3864 :         case CHECKSUM_TYPE_SHA224:
      65        3864 :             return "SHA224";
      66        1932 :         case CHECKSUM_TYPE_SHA256:
      67        1932 :             return "SHA256";
      68        1932 :         case CHECKSUM_TYPE_SHA384:
      69        1932 :             return "SHA384";
      70        1932 :         case CHECKSUM_TYPE_SHA512:
      71        1932 :             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      391096 : pg_checksum_init(pg_checksum_context *context, pg_checksum_type type)
      84             : {
      85      391096 :     context->type = type;
      86             : 
      87      391096 :     switch (type)
      88             :     {
      89       22496 :         case CHECKSUM_TYPE_NONE:
      90             :             /* do nothing */
      91       22496 :             break;
      92      349272 :         case CHECKSUM_TYPE_CRC32C:
      93      349272 :             INIT_CRC32C(context->raw_context.c_crc32c);
      94      349272 :             break;
      95        7724 :         case CHECKSUM_TYPE_SHA224:
      96        7724 :             context->raw_context.c_sha2 = pg_cryptohash_create(PG_SHA224);
      97        7724 :             if (context->raw_context.c_sha2 == NULL)
      98           0 :                 return -1;
      99        7724 :             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        7724 :             break;
     105        3880 :         case CHECKSUM_TYPE_SHA256:
     106        3880 :             context->raw_context.c_sha2 = pg_cryptohash_create(PG_SHA256);
     107        3880 :             if (context->raw_context.c_sha2 == NULL)
     108           0 :                 return -1;
     109        3880 :             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        3880 :             break;
     115        3862 :         case CHECKSUM_TYPE_SHA384:
     116        3862 :             context->raw_context.c_sha2 = pg_cryptohash_create(PG_SHA384);
     117        3862 :             if (context->raw_context.c_sha2 == NULL)
     118           0 :                 return -1;
     119        3862 :             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        3862 :             break;
     125        3862 :         case CHECKSUM_TYPE_SHA512:
     126        3862 :             context->raw_context.c_sha2 = pg_cryptohash_create(PG_SHA512);
     127        3862 :             if (context->raw_context.c_sha2 == NULL)
     128           0 :                 return -1;
     129        3862 :             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        3862 :             break;
     135             :     }
     136             : 
     137      391096 :     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      426734 : pg_checksum_update(pg_checksum_context *context, const uint8 *input,
     146             :                    size_t len)
     147             : {
     148      426734 :     switch (context->type)
     149             :     {
     150       21004 :         case CHECKSUM_TYPE_NONE:
     151             :             /* do nothing */
     152       21004 :             break;
     153      386302 :         case CHECKSUM_TYPE_CRC32C:
     154      386302 :             COMP_CRC32C(context->raw_context.c_crc32c, input, len);
     155      386302 :             break;
     156       19428 :         case CHECKSUM_TYPE_SHA224:
     157             :         case CHECKSUM_TYPE_SHA256:
     158             :         case CHECKSUM_TYPE_SHA384:
     159             :         case CHECKSUM_TYPE_SHA512:
     160       19428 :             if (pg_cryptohash_update(context->raw_context.c_sha2, input, len) < 0)
     161           0 :                 return -1;
     162       19428 :             break;
     163             :     }
     164             : 
     165      426734 :     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      368602 : pg_checksum_final(pg_checksum_context *context, uint8 *output)
     177             : {
     178      368602 :     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      368602 :     switch (context->type)
     192             :     {
     193           4 :         case CHECKSUM_TYPE_NONE:
     194           4 :             break;
     195      349270 :         case CHECKSUM_TYPE_CRC32C:
     196      349270 :             FIN_CRC32C(context->raw_context.c_crc32c);
     197      349270 :             retval = sizeof(pg_crc32c);
     198      349270 :             memcpy(output, &context->raw_context.c_crc32c, retval);
     199      349270 :             break;
     200        7724 :         case CHECKSUM_TYPE_SHA224:
     201        7724 :             retval = PG_SHA224_DIGEST_LENGTH;
     202        7724 :             if (pg_cryptohash_final(context->raw_context.c_sha2,
     203             :                                     output, retval) < 0)
     204           0 :                 return -1;
     205        7724 :             pg_cryptohash_free(context->raw_context.c_sha2);
     206        7724 :             break;
     207        3880 :         case CHECKSUM_TYPE_SHA256:
     208        3880 :             retval = PG_SHA256_DIGEST_LENGTH;
     209        3880 :             if (pg_cryptohash_final(context->raw_context.c_sha2,
     210             :                                     output, retval) < 0)
     211           0 :                 return -1;
     212        3880 :             pg_cryptohash_free(context->raw_context.c_sha2);
     213        3880 :             break;
     214        3862 :         case CHECKSUM_TYPE_SHA384:
     215        3862 :             retval = PG_SHA384_DIGEST_LENGTH;
     216        3862 :             if (pg_cryptohash_final(context->raw_context.c_sha2,
     217             :                                     output, retval) < 0)
     218           0 :                 return -1;
     219        3862 :             pg_cryptohash_free(context->raw_context.c_sha2);
     220        3862 :             break;
     221        3862 :         case CHECKSUM_TYPE_SHA512:
     222        3862 :             retval = PG_SHA512_DIGEST_LENGTH;
     223        3862 :             if (pg_cryptohash_final(context->raw_context.c_sha2,
     224             :                                     output, retval) < 0)
     225           0 :                 return -1;
     226        3862 :             pg_cryptohash_free(context->raw_context.c_sha2);
     227        3862 :             break;
     228             :     }
     229             : 
     230      368602 :     Assert(retval <= PG_CHECKSUM_MAX_LENGTH);
     231      368602 :     return retval;
     232             : }

Generated by: LCOV version 1.14