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

Generated by: LCOV version 1.14