diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 12:15:05 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 12:15:05 +0000 |
commit | 46651ce6fe013220ed397add242004d764fc0153 (patch) | |
tree | 6e5299f990f88e60174a1d3ae6e48eedd2688b2b /src/common/checksum_helper.c | |
parent | Initial commit. (diff) | |
download | postgresql-14-46651ce6fe013220ed397add242004d764fc0153.tar.xz postgresql-14-46651ce6fe013220ed397add242004d764fc0153.zip |
Adding upstream version 14.5.upstream/14.5upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/common/checksum_helper.c')
-rw-r--r-- | src/common/checksum_helper.c | 232 |
1 files changed, 232 insertions, 0 deletions
diff --git a/src/common/checksum_helper.c b/src/common/checksum_helper.c new file mode 100644 index 0000000..431e247 --- /dev/null +++ b/src/common/checksum_helper.c @@ -0,0 +1,232 @@ +/*------------------------------------------------------------------------- + * + * checksum_helper.c + * Compute a checksum of any of various types using common routines + * + * Portions Copyright (c) 2016-2021, PostgreSQL Global Development Group + * + * IDENTIFICATION + * src/common/checksum_helper.c + * + *------------------------------------------------------------------------- + */ + +#ifndef FRONTEND +#include "postgres.h" +#else +#include "postgres_fe.h" +#endif + +#include "common/checksum_helper.h" + +/* + * If 'name' is a recognized checksum type, set *type to the corresponding + * constant and return true. Otherwise, set *type to CHECKSUM_TYPE_NONE and + * return false. + */ +bool +pg_checksum_parse_type(char *name, pg_checksum_type *type) +{ + pg_checksum_type result_type = CHECKSUM_TYPE_NONE; + bool result = true; + + if (pg_strcasecmp(name, "none") == 0) + result_type = CHECKSUM_TYPE_NONE; + else if (pg_strcasecmp(name, "crc32c") == 0) + result_type = CHECKSUM_TYPE_CRC32C; + else if (pg_strcasecmp(name, "sha224") == 0) + result_type = CHECKSUM_TYPE_SHA224; + else if (pg_strcasecmp(name, "sha256") == 0) + result_type = CHECKSUM_TYPE_SHA256; + else if (pg_strcasecmp(name, "sha384") == 0) + result_type = CHECKSUM_TYPE_SHA384; + else if (pg_strcasecmp(name, "sha512") == 0) + result_type = CHECKSUM_TYPE_SHA512; + else + result = false; + + *type = result_type; + return result; +} + +/* + * Get the canonical human-readable name corresponding to a checksum type. + */ +char * +pg_checksum_type_name(pg_checksum_type type) +{ + switch (type) + { + case CHECKSUM_TYPE_NONE: + return "NONE"; + case CHECKSUM_TYPE_CRC32C: + return "CRC32C"; + case CHECKSUM_TYPE_SHA224: + return "SHA224"; + case CHECKSUM_TYPE_SHA256: + return "SHA256"; + case CHECKSUM_TYPE_SHA384: + return "SHA384"; + case CHECKSUM_TYPE_SHA512: + return "SHA512"; + } + + Assert(false); + return "???"; +} + +/* + * Initialize a checksum context for checksums of the given type. + * Returns 0 for a success, -1 for a failure. + */ +int +pg_checksum_init(pg_checksum_context *context, pg_checksum_type type) +{ + context->type = type; + + switch (type) + { + case CHECKSUM_TYPE_NONE: + /* do nothing */ + break; + case CHECKSUM_TYPE_CRC32C: + INIT_CRC32C(context->raw_context.c_crc32c); + break; + case CHECKSUM_TYPE_SHA224: + context->raw_context.c_sha2 = pg_cryptohash_create(PG_SHA224); + if (context->raw_context.c_sha2 == NULL) + return -1; + if (pg_cryptohash_init(context->raw_context.c_sha2) < 0) + { + pg_cryptohash_free(context->raw_context.c_sha2); + return -1; + } + break; + case CHECKSUM_TYPE_SHA256: + context->raw_context.c_sha2 = pg_cryptohash_create(PG_SHA256); + if (context->raw_context.c_sha2 == NULL) + return -1; + if (pg_cryptohash_init(context->raw_context.c_sha2) < 0) + { + pg_cryptohash_free(context->raw_context.c_sha2); + return -1; + } + break; + case CHECKSUM_TYPE_SHA384: + context->raw_context.c_sha2 = pg_cryptohash_create(PG_SHA384); + if (context->raw_context.c_sha2 == NULL) + return -1; + if (pg_cryptohash_init(context->raw_context.c_sha2) < 0) + { + pg_cryptohash_free(context->raw_context.c_sha2); + return -1; + } + break; + case CHECKSUM_TYPE_SHA512: + context->raw_context.c_sha2 = pg_cryptohash_create(PG_SHA512); + if (context->raw_context.c_sha2 == NULL) + return -1; + if (pg_cryptohash_init(context->raw_context.c_sha2) < 0) + { + pg_cryptohash_free(context->raw_context.c_sha2); + return -1; + } + break; + } + + return 0; +} + +/* + * Update a checksum context with new data. + * Returns 0 for a success, -1 for a failure. + */ +int +pg_checksum_update(pg_checksum_context *context, const uint8 *input, + size_t len) +{ + switch (context->type) + { + case CHECKSUM_TYPE_NONE: + /* do nothing */ + break; + case CHECKSUM_TYPE_CRC32C: + COMP_CRC32C(context->raw_context.c_crc32c, input, len); + break; + case CHECKSUM_TYPE_SHA224: + case CHECKSUM_TYPE_SHA256: + case CHECKSUM_TYPE_SHA384: + case CHECKSUM_TYPE_SHA512: + if (pg_cryptohash_update(context->raw_context.c_sha2, input, len) < 0) + return -1; + break; + } + + return 0; +} + +/* + * Finalize a checksum computation and write the result to an output buffer. + * + * The caller must ensure that the buffer is at least PG_CHECKSUM_MAX_LENGTH + * bytes in length. The return value is the number of bytes actually written, + * or -1 for a failure. + */ +int +pg_checksum_final(pg_checksum_context *context, uint8 *output) +{ + int retval = 0; + + StaticAssertStmt(sizeof(pg_crc32c) <= PG_CHECKSUM_MAX_LENGTH, + "CRC-32C digest too big for PG_CHECKSUM_MAX_LENGTH"); + StaticAssertStmt(PG_SHA224_DIGEST_LENGTH <= PG_CHECKSUM_MAX_LENGTH, + "SHA224 digest too big for PG_CHECKSUM_MAX_LENGTH"); + StaticAssertStmt(PG_SHA256_DIGEST_LENGTH <= PG_CHECKSUM_MAX_LENGTH, + "SHA256 digest too big for PG_CHECKSUM_MAX_LENGTH"); + StaticAssertStmt(PG_SHA384_DIGEST_LENGTH <= PG_CHECKSUM_MAX_LENGTH, + "SHA384 digest too big for PG_CHECKSUM_MAX_LENGTH"); + StaticAssertStmt(PG_SHA512_DIGEST_LENGTH <= PG_CHECKSUM_MAX_LENGTH, + "SHA512 digest too big for PG_CHECKSUM_MAX_LENGTH"); + + switch (context->type) + { + case CHECKSUM_TYPE_NONE: + break; + case CHECKSUM_TYPE_CRC32C: + FIN_CRC32C(context->raw_context.c_crc32c); + retval = sizeof(pg_crc32c); + memcpy(output, &context->raw_context.c_crc32c, retval); + break; + case CHECKSUM_TYPE_SHA224: + retval = PG_SHA224_DIGEST_LENGTH; + if (pg_cryptohash_final(context->raw_context.c_sha2, + output, retval) < 0) + return -1; + pg_cryptohash_free(context->raw_context.c_sha2); + break; + case CHECKSUM_TYPE_SHA256: + retval = PG_SHA256_DIGEST_LENGTH; + if (pg_cryptohash_final(context->raw_context.c_sha2, + output, retval) < 0) + return -1; + pg_cryptohash_free(context->raw_context.c_sha2); + break; + case CHECKSUM_TYPE_SHA384: + retval = PG_SHA384_DIGEST_LENGTH; + if (pg_cryptohash_final(context->raw_context.c_sha2, + output, retval) < 0) + return -1; + pg_cryptohash_free(context->raw_context.c_sha2); + break; + case CHECKSUM_TYPE_SHA512: + retval = PG_SHA512_DIGEST_LENGTH; + if (pg_cryptohash_final(context->raw_context.c_sha2, + output, retval) < 0) + return -1; + pg_cryptohash_free(context->raw_context.c_sha2); + break; + } + + Assert(retval <= PG_CHECKSUM_MAX_LENGTH); + return retval; +} |