115 const char *buffer,
size_t size,
138 parse->context = context;
140 parse->saw_version_field =
false;
156 if (manifest_ctx == NULL)
157 context->
error_cb(context,
"out of memory");
159 context->
error_cb(context,
"could not initialize checksum of manifest");
186 const char *
chunk,
size_t size,
bool is_last)
209 context->
error_cb(context,
"could not update checksum of manifest");
236 parse.context = context;
238 parse.saw_version_field =
false;
280 switch (
parse->state)
287 parse->pathname = NULL;
288 parse->encoded_pathname = NULL;
290 parse->algorithm = NULL;
291 parse->checksum = NULL;
295 parse->timeline = NULL;
296 parse->start_lsn = NULL;
297 parse->end_lsn = NULL;
301 "unexpected object start");
321 switch (
parse->state)
336 "unexpected object end");
355 switch (
parse->state)
365 "unexpected array start");
382 switch (
parse->state)
390 "unexpected array end");
405 switch (
parse->state)
413 if (!
parse->saw_version_field)
415 if (strcmp(fname,
"PostgreSQL-Backup-Manifest-Version") != 0)
417 "expected version indicator");
419 parse->saw_version_field =
true;
424 if (strcmp(fname,
"System-Identifier") == 0)
431 if (strcmp(fname,
"Files") == 0)
438 if (strcmp(fname,
"WAL-Ranges") == 0)
445 if (strcmp(fname,
"Manifest-Checksum") == 0)
453 "unrecognized top-level field");
458 if (strcmp(fname,
"Path") == 0)
460 else if (strcmp(fname,
"Encoded-Path") == 0)
462 else if (strcmp(fname,
"Size") == 0)
464 else if (strcmp(fname,
"Last-Modified") == 0)
466 else if (strcmp(fname,
"Checksum-Algorithm") == 0)
468 else if (strcmp(fname,
"Checksum") == 0)
472 "unexpected file field");
478 if (strcmp(fname,
"Timeline") == 0)
480 else if (strcmp(fname,
"Start-LSN") == 0)
482 else if (strcmp(fname,
"End-LSN") == 0)
486 "unexpected WAL range field");
492 "unexpected object field");
521 switch (
parse->state)
536 switch (
parse->file_field)
561 switch (
parse->wal_range_field)
605 version = strtoi64(
parse->manifest_version, &ep, 10);
608 "manifest version not an integer");
610 if (version != 1 && version != 2)
612 "unexpected manifest version");
633 system_identifier = strtou64(
parse->manifest_system_identifier, &ep, 10);
636 "system identifier in manifest not an integer");
654 int checksum_string_length;
657 uint8 *checksum_payload;
660 if (
parse->pathname == NULL &&
parse->encoded_pathname == NULL)
662 if (
parse->pathname != NULL &&
parse->encoded_pathname != NULL)
664 "both path name and encoded path name");
665 if (
parse->size == NULL)
667 if (
parse->algorithm == NULL &&
parse->checksum != NULL)
669 "checksum without algorithm");
672 if (
parse->encoded_pathname != NULL)
674 int encoded_length = strlen(
parse->encoded_pathname);
675 int raw_length = encoded_length / 2;
678 if (encoded_length % 2 != 0 ||
680 parse->encoded_pathname,
683 "could not decode file name");
684 parse->pathname[raw_length] =
'\0';
686 parse->encoded_pathname = NULL;
693 "file size is not an integer");
696 if (
parse->algorithm == NULL)
699 context->
error_cb(context,
"unrecognized checksum algorithm: \"%s\"",
703 checksum_string_length =
parse->checksum == NULL ? 0
704 : strlen(
parse->checksum);
705 if (checksum_string_length == 0)
708 checksum_payload = NULL;
712 checksum_length = checksum_string_length / 2;
713 checksum_payload =
palloc(checksum_length);
714 if (checksum_string_length % 2 != 0 ||
718 "invalid checksum for file \"%s\": \"%s\"",
724 checksum_type, checksum_length, checksum_payload);
727 if (
parse->size != NULL)
732 if (
parse->algorithm != NULL)
735 parse->algorithm = NULL;
737 if (
parse->checksum != NULL)
740 parse->checksum = NULL;
760 if (
parse->timeline == NULL)
762 if (
parse->start_lsn == NULL)
764 if (
parse->end_lsn == NULL)
768 tli = strtoul(
parse->timeline, &ep, 10);
771 "timeline is not an integer");
774 "could not parse start LSN");
777 "could not parse end LSN");
783 if (
parse->timeline != NULL)
786 parse->timeline = NULL;
788 if (
parse->start_lsn != NULL)
791 parse->start_lsn = NULL;
793 if (
parse->end_lsn != NULL)
796 parse->end_lsn = NULL;
817 size_t number_of_newlines = 0;
818 size_t ultimate_newline = 0;
819 size_t penultimate_newline = 0;
827 if (buffer[
i] ==
'\n')
829 ++number_of_newlines;
830 penultimate_newline = ultimate_newline;
831 ultimate_newline =
i;
840 if (number_of_newlines < 2)
842 "expected at least 2 lines");
843 if (ultimate_newline !=
size - 1)
845 "last line not newline-terminated");
848 if (incr_ctx == NULL)
851 if (manifest_ctx == NULL)
852 context->
error_cb(context,
"out of memory");
854 context->
error_cb(context,
"could not initialize checksum of manifest");
858 manifest_ctx = incr_ctx;
861 context->
error_cb(context,
"could not update checksum of manifest");
863 sizeof(manifest_checksum_actual)) < 0)
864 context->
error_cb(context,
"could not finalize checksum of manifest");
867 if (
parse->manifest_checksum == NULL)
868 context->
error_cb(
parse->context,
"manifest has no checksum");
872 context->
error_cb(context,
"invalid manifest checksum: \"%s\"",
873 parse->manifest_checksum);
874 if (memcmp(manifest_checksum_actual, manifest_checksum_expected,
876 context->
error_cb(context,
"manifest checksum mismatch");
891 context->
error_cb(context,
"could not parse backup manifest: %s", msg);
902 if (
c >=
'0' &&
c <=
'9')
904 if (
c >=
'a' &&
c <=
'f')
906 if (
c >=
'A' &&
c <=
'F')
922 for (
i = 0;
i < nbytes; ++
i)
927 if (n1 < 0 || n2 < 0)
929 result[
i] = n1 * 16 + n2;
944 if (sscanf(
input,
"%X/%X", &hi, &lo) != 2)
946 *result = ((
uint64) hi) << 32 | lo;
#define Assert(condition)
bool pg_checksum_parse_type(char *name, pg_checksum_type *type)
int pg_cryptohash_update(pg_cryptohash_ctx *ctx, const uint8 *data, size_t len)
pg_cryptohash_ctx * pg_cryptohash_create(pg_cryptohash_type type)
int pg_cryptohash_init(pg_cryptohash_ctx *ctx)
void pg_cryptohash_free(pg_cryptohash_ctx *ctx)
int pg_cryptohash_final(pg_cryptohash_ctx *ctx, uint8 *dest, size_t len)
static void PGresult * res
JsonParseErrorType pg_parse_json_incremental(JsonLexContext *lex, const JsonSemAction *sem, const char *json, size_t len, bool is_last)
JsonLexContext * makeJsonLexContextIncremental(JsonLexContext *lex, int encoding, bool need_escapes)
JsonParseErrorType pg_parse_json(JsonLexContext *lex, const JsonSemAction *sem)
JsonLexContext * makeJsonLexContextCstringLen(JsonLexContext *lex, const char *json, size_t len, int encoding, bool need_escapes)
char * json_errdetail(JsonParseErrorType error, JsonLexContext *lex)
void freeJsonLexContext(JsonLexContext *lex)
void pfree(void *pointer)
JsonManifestSemanticState
@ JM_EXPECT_SYSTEM_IDENTIFIER_VALUE
@ JM_EXPECT_TOPLEVEL_START
@ JM_EXPECT_WAL_RANGES_START
@ JM_EXPECT_THIS_FILE_FIELD
@ JM_EXPECT_THIS_FILE_VALUE
@ JM_EXPECT_THIS_WAL_RANGE_VALUE
@ JM_EXPECT_VERSION_VALUE
@ JM_EXPECT_MANIFEST_CHECKSUM_VALUE
@ JM_EXPECT_THIS_WAL_RANGE_FIELD
@ JM_EXPECT_TOPLEVEL_FIELD
@ JM_EXPECT_WAL_RANGES_NEXT
static JsonParseErrorType json_manifest_array_start(void *state)
void json_parse_manifest(JsonManifestParseContext *context, const char *buffer, size_t size)
JsonManifestWALRangeField
JsonManifestParseIncrementalState * json_parse_manifest_incremental_init(JsonManifestParseContext *context)
static bool parse_xlogrecptr(XLogRecPtr *result, char *input)
static void json_manifest_finalize_wal_range(JsonManifestParseState *parse)
static JsonParseErrorType json_manifest_object_field_start(void *state, char *fname, bool isnull)
static void json_manifest_finalize_file(JsonManifestParseState *parse)
static JsonParseErrorType json_manifest_object_end(void *state)
static JsonParseErrorType json_manifest_object_start(void *state)
static void json_manifest_finalize_version(JsonManifestParseState *parse)
static JsonParseErrorType json_manifest_scalar(void *state, char *token, JsonTokenType tokentype)
static void json_manifest_parse_failure(JsonManifestParseContext *context, char *msg)
static JsonParseErrorType json_manifest_array_end(void *state)
@ JMFF_CHECKSUM_ALGORITHM
void json_parse_manifest_incremental_shutdown(JsonManifestParseIncrementalState *incstate)
void json_parse_manifest_incremental_chunk(JsonManifestParseIncrementalState *incstate, const char *chunk, size_t size, bool is_last)
static void json_manifest_finalize_system_identifier(JsonManifestParseState *parse)
static void verify_manifest_checksum(JsonManifestParseState *parse, const char *buffer, size_t size, pg_cryptohash_ctx *incr_ctx)
static int hexdecode_char(char c)
static bool hexdecode_string(uint8 *result, char *input, int nbytes)
static struct subre * parse(struct vars *v, int stopper, int type, struct state *init, struct state *final)
#define PG_SHA256_DIGEST_LENGTH
static pg_noinline void Size size
json_manifest_per_wal_range_callback per_wal_range_cb
json_manifest_system_identifier_callback system_identifier_cb
json_manifest_error_callback error_cb
json_manifest_per_file_callback per_file_cb
json_manifest_version_callback version_cb
pg_cryptohash_ctx * manifest_ctx
char * manifest_system_identifier
JsonManifestWALRangeField wal_range_field
JsonManifestParseContext * context
JsonManifestFileField file_field
pg_checksum_type checksum_algorithm
JsonManifestSemanticState state
json_struct_action array_end
json_struct_action object_start
json_ofield_action object_field_start
json_aelem_action array_element_start
json_scalar_action scalar
json_aelem_action array_element_end
json_struct_action array_start
json_struct_action object_end
json_ofield_action object_field_end