PostgreSQL Source Code  git master
parse_manifest.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * parse_manifest.c
4  * Parse a backup manifest in JSON format.
5  *
6  * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  * src/common/parse_manifest.c
10  *
11  *-------------------------------------------------------------------------
12  */
13 
14 #include "postgres_fe.h"
15 
16 #include "common/jsonapi.h"
17 #include "common/parse_manifest.h"
18 
19 /*
20  * Semantic states for JSON manifest parsing.
21  */
22 typedef enum
23 {
40 
41 /*
42  * Possible fields for one file as described by the manifest.
43  */
44 typedef enum
45 {
53 
54 /*
55  * Possible fields for one file as described by the manifest.
56  */
57 typedef enum
58 {
63 
64 /*
65  * Internal state used while decoding the JSON-format backup manifest.
66  */
67 typedef struct
68 {
71 
72  /* These fields are used for parsing objects in the list of files. */
74  char *pathname;
76  char *size;
77  char *algorithm;
79  char *checksum;
80 
81  /* These fields are used for parsing objects in the list of WAL ranges. */
83  char *timeline;
84  char *start_lsn;
85  char *end_lsn;
86 
87  /* Miscellaneous other stuff. */
93 
94 /* typedef appears in parse_manifest.h */
96 {
100 };
101 
107  bool isnull);
109  JsonTokenType tokentype);
115  char *buffer, size_t size,
116  pg_cryptohash_ctx *incr_ctx);
118  char *msg);
119 
120 static int hexdecode_char(char c);
121 static bool hexdecode_string(uint8 *result, char *input, int nbytes);
122 static bool parse_xlogrecptr(XLogRecPtr *result, char *input);
123 
124 /*
125  * Set up for incremental parsing of the manifest.
126  */
127 
130 {
133  pg_cryptohash_ctx *manifest_ctx;
134 
135  incstate = palloc(sizeof(JsonManifestParseIncrementalState));
137 
138  parse->context = context;
140  parse->saw_version_field = false;
141 
142  makeJsonLexContextIncremental(&(incstate->lex), PG_UTF8, true);
143 
144  incstate->sem.semstate = parse;
150  incstate->sem.object_field_end = NULL;
151  incstate->sem.array_element_start = NULL;
152  incstate->sem.array_element_end = NULL;
153  incstate->sem.scalar = json_manifest_scalar;
154 
155  manifest_ctx = pg_cryptohash_create(PG_SHA256);
156  if (manifest_ctx == NULL)
157  context->error_cb(context, "out of memory");
158  if (pg_cryptohash_init(manifest_ctx) < 0)
159  context->error_cb(context, "could not initialize checksum of manifest");
160  incstate->manifest_ctx = manifest_ctx;
161 
162  return incstate;
163 }
164 
165 /*
166  * Free an incremental state object and its contents.
167  */
168 void
170 {
171  pfree(incstate->sem.semstate);
172  freeJsonLexContext(&(incstate->lex));
173  /* incstate->manifest_ctx has already been freed */
174  pfree(incstate);
175 }
176 
177 /*
178  * parse the manifest in pieces.
179  *
180  * The caller must ensure that the final piece contains the final lines
181  * with the complete checksum.
182  */
183 
184 void
186  JsonManifestParseIncrementalState *incstate, char *chunk, int size,
187  bool is_last)
188 {
190  expected;
193 
194  res = pg_parse_json_incremental(&(incstate->lex), &(incstate->sem),
195  chunk, size, is_last);
196 
197  expected = is_last ? JSON_SUCCESS : JSON_INCOMPLETE;
198 
199  if (res != expected)
201  json_errdetail(res, &(incstate->lex)));
202 
203  if (is_last && parse->state != JM_EXPECT_EOF)
204  json_manifest_parse_failure(context, "manifest ended unexpectedly");
205 
206  if (!is_last)
207  {
208  if (pg_cryptohash_update(incstate->manifest_ctx,
209  (uint8 *) chunk, size) < 0)
210  context->error_cb(context, "could not update checksum of manifest");
211  }
212  else
213  {
215  }
216 }
217 
218 
219 /*
220  * Main entrypoint to parse a JSON-format backup manifest.
221  *
222  * Caller should set up the parsing context and then invoke this function.
223  * For each file whose information is extracted from the manifest,
224  * context->per_file_cb is invoked. In case of trouble, context->error_cb is
225  * invoked and is expected not to return.
226  */
227 void
229  size_t size)
230 {
231  JsonLexContext *lex;
232  JsonParseErrorType json_error;
235 
236  /* Set up our private parsing context. */
237  parse.context = context;
239  parse.saw_version_field = false;
240 
241  /* Create a JSON lexing context. */
242  lex = makeJsonLexContextCstringLen(NULL, buffer, size, PG_UTF8, true);
243 
244  /* Set up semantic actions. */
245  sem.semstate = &parse;
251  sem.object_field_end = NULL;
252  sem.array_element_start = NULL;
253  sem.array_element_end = NULL;
255 
256  /* Run the actual JSON parser. */
257  json_error = pg_parse_json(lex, &sem);
258  if (json_error != JSON_SUCCESS)
260  if (parse.state != JM_EXPECT_EOF)
261  json_manifest_parse_failure(context, "manifest ended unexpectedly");
262 
263  /* Verify the manifest checksum. */
264  verify_manifest_checksum(&parse, buffer, size, NULL);
265 
266  freeJsonLexContext(lex);
267 }
268 
269 /*
270  * Invoked at the start of each object in the JSON document.
271  *
272  * The document as a whole is expected to be an object; each file and each
273  * WAL range is also expected to be an object. If we're anywhere else in the
274  * document, it's an error.
275  */
276 static JsonParseErrorType
278 {
280 
281  switch (parse->state)
282  {
285  break;
288  parse->pathname = NULL;
289  parse->encoded_pathname = NULL;
290  parse->size = NULL;
291  parse->algorithm = NULL;
292  parse->checksum = NULL;
293  break;
296  parse->timeline = NULL;
297  parse->start_lsn = NULL;
298  parse->end_lsn = NULL;
299  break;
300  default:
302  "unexpected object start");
303  break;
304  }
305 
306  return JSON_SUCCESS;
307 }
308 
309 /*
310  * Invoked at the end of each object in the JSON document.
311  *
312  * The possible cases here are the same as for json_manifest_object_start.
313  * There's nothing special to do at the end of the document, but when we
314  * reach the end of an object representing a particular file or WAL range,
315  * we must call json_manifest_finalize_file() to save the associated details.
316  */
317 static JsonParseErrorType
319 {
321 
322  switch (parse->state)
323  {
325  parse->state = JM_EXPECT_EOF;
326  break;
329  parse->state = JM_EXPECT_FILES_NEXT;
330  break;
334  break;
335  default:
337  "unexpected object end");
338  break;
339  }
340 
341  return JSON_SUCCESS;
342 }
343 
344 /*
345  * Invoked at the start of each array in the JSON document.
346  *
347  * Within the toplevel object, the value associated with the "Files" key
348  * should be an array. Similarly for the "WAL-Ranges" key. No other arrays
349  * are expected.
350  */
351 static JsonParseErrorType
353 {
355 
356  switch (parse->state)
357  {
359  parse->state = JM_EXPECT_FILES_NEXT;
360  break;
363  break;
364  default:
366  "unexpected array start");
367  break;
368  }
369 
370  return JSON_SUCCESS;
371 }
372 
373 /*
374  * Invoked at the end of each array in the JSON document.
375  *
376  * The cases here are analogous to those in json_manifest_array_start.
377  */
378 static JsonParseErrorType
380 {
382 
383  switch (parse->state)
384  {
388  break;
389  default:
391  "unexpected array end");
392  break;
393  }
394 
395  return JSON_SUCCESS;
396 }
397 
398 /*
399  * Invoked at the start of each object field in the JSON document.
400  */
401 static JsonParseErrorType
402 json_manifest_object_field_start(void *state, char *fname, bool isnull)
403 {
405 
406  switch (parse->state)
407  {
409 
410  /*
411  * Inside toplevel object. The version indicator should always be
412  * the first field.
413  */
414  if (!parse->saw_version_field)
415  {
416  if (strcmp(fname, "PostgreSQL-Backup-Manifest-Version") != 0)
418  "expected version indicator");
420  parse->saw_version_field = true;
421  break;
422  }
423 
424  /* Is this the system identifier? */
425  if (strcmp(fname, "System-Identifier") == 0)
426  {
428  break;
429  }
430 
431  /* Is this the list of files? */
432  if (strcmp(fname, "Files") == 0)
433  {
434  parse->state = JM_EXPECT_FILES_START;
435  break;
436  }
437 
438  /* Is this the list of WAL ranges? */
439  if (strcmp(fname, "WAL-Ranges") == 0)
440  {
442  break;
443  }
444 
445  /* Is this the manifest checksum? */
446  if (strcmp(fname, "Manifest-Checksum") == 0)
447  {
449  break;
450  }
451 
452  /* It's not a field we recognize. */
454  "unrecognized top-level field");
455  break;
456 
458  /* Inside object for one file; which key have we got? */
459  if (strcmp(fname, "Path") == 0)
460  parse->file_field = JMFF_PATH;
461  else if (strcmp(fname, "Encoded-Path") == 0)
462  parse->file_field = JMFF_ENCODED_PATH;
463  else if (strcmp(fname, "Size") == 0)
464  parse->file_field = JMFF_SIZE;
465  else if (strcmp(fname, "Last-Modified") == 0)
466  parse->file_field = JMFF_LAST_MODIFIED;
467  else if (strcmp(fname, "Checksum-Algorithm") == 0)
468  parse->file_field = JMFF_CHECKSUM_ALGORITHM;
469  else if (strcmp(fname, "Checksum") == 0)
470  parse->file_field = JMFF_CHECKSUM;
471  else
473  "unexpected file field");
475  break;
476 
478  /* Inside object for one file; which key have we got? */
479  if (strcmp(fname, "Timeline") == 0)
480  parse->wal_range_field = JMWRF_TIMELINE;
481  else if (strcmp(fname, "Start-LSN") == 0)
482  parse->wal_range_field = JMWRF_START_LSN;
483  else if (strcmp(fname, "End-LSN") == 0)
484  parse->wal_range_field = JMWRF_END_LSN;
485  else
487  "unexpected WAL range field");
489  break;
490 
491  default:
493  "unexpected object field");
494  break;
495  }
496 
497  pfree(fname);
498 
499  return JSON_SUCCESS;
500 }
501 
502 /*
503  * Invoked at the start of each scalar in the JSON document.
504  *
505  * Object field names don't reach this code; those are handled by
506  * json_manifest_object_field_start. When we're inside of the object for
507  * a particular file or WAL range, that function will have noticed the name
508  * of the field, and we'll get the corresponding value here. When we're in
509  * the toplevel object, the parse state itself tells us which field this is.
510  *
511  * In all cases except for PostgreSQL-Backup-Manifest-Version, which we
512  * can just check on the spot, the goal here is just to save the value in
513  * the parse state for later use. We don't actually do anything until we
514  * reach either the end of the object representing this file, or the end
515  * of the manifest, as the case may be.
516  */
517 static JsonParseErrorType
519 {
521 
522  switch (parse->state)
523  {
525  parse->manifest_version = token;
528  break;
529 
531  parse->manifest_system_identifier = token;
534  break;
535 
537  switch (parse->file_field)
538  {
539  case JMFF_PATH:
540  parse->pathname = token;
541  break;
542  case JMFF_ENCODED_PATH:
543  parse->encoded_pathname = token;
544  break;
545  case JMFF_SIZE:
546  parse->size = token;
547  break;
548  case JMFF_LAST_MODIFIED:
549  pfree(token); /* unused */
550  break;
552  parse->algorithm = token;
553  break;
554  case JMFF_CHECKSUM:
555  parse->checksum = token;
556  break;
557  }
559  break;
560 
562  switch (parse->wal_range_field)
563  {
564  case JMWRF_TIMELINE:
565  parse->timeline = token;
566  break;
567  case JMWRF_START_LSN:
568  parse->start_lsn = token;
569  break;
570  case JMWRF_END_LSN:
571  parse->end_lsn = token;
572  break;
573  }
575  break;
576 
578  parse->state = JM_EXPECT_TOPLEVEL_END;
579  parse->manifest_checksum = token;
580  break;
581 
582  default:
583  json_manifest_parse_failure(parse->context, "unexpected scalar");
584  break;
585  }
586 
587  return JSON_SUCCESS;
588 }
589 
590 /*
591  * Do additional parsing and sanity-checking of the manifest version, and invoke
592  * the callback so that the caller can gets that detail and take actions
593  * accordingly. This happens for each manifest when the corresponding JSON
594  * object is completely parsed.
595  */
596 static void
598 {
600  int version;
601  char *ep;
602 
603  Assert(parse->saw_version_field);
604 
605  /* Parse version. */
606  version = strtoi64(parse->manifest_version, &ep, 10);
607  if (*ep)
609  "manifest version not an integer");
610 
611  if (version != 1 && version != 2)
613  "unexpected manifest version");
614 
615  /* Invoke the callback for version */
616  context->version_cb(context, version);
617 }
618 
619 /*
620  * Do additional parsing and sanity-checking of the system identifier, and
621  * invoke the callback so that the caller can gets that detail and take actions
622  * accordingly.
623  */
624 static void
626 {
628  uint64 system_identifier;
629  char *ep;
630 
631  Assert(parse->manifest_system_identifier != NULL);
632 
633  /* Parse system identifier. */
634  system_identifier = strtou64(parse->manifest_system_identifier, &ep, 10);
635  if (*ep)
637  "manifest system identifier not an integer");
638 
639  /* Invoke the callback for system identifier */
640  context->system_identifier_cb(context, system_identifier);
641 }
642 
643 /*
644  * Do additional parsing and sanity-checking of the details gathered for one
645  * file, and invoke the per-file callback so that the caller gets those
646  * details. This happens for each file when the corresponding JSON object is
647  * completely parsed.
648  */
649 static void
651 {
653  size_t size;
654  char *ep;
655  int checksum_string_length;
656  pg_checksum_type checksum_type;
657  int checksum_length;
658  uint8 *checksum_payload;
659 
660  /* Pathname and size are required. */
661  if (parse->pathname == NULL && parse->encoded_pathname == NULL)
662  json_manifest_parse_failure(parse->context, "missing path name");
663  if (parse->pathname != NULL && parse->encoded_pathname != NULL)
665  "both path name and encoded path name");
666  if (parse->size == NULL)
667  json_manifest_parse_failure(parse->context, "missing size");
668  if (parse->algorithm == NULL && parse->checksum != NULL)
670  "checksum without algorithm");
671 
672  /* Decode encoded pathname, if that's what we have. */
673  if (parse->encoded_pathname != NULL)
674  {
675  int encoded_length = strlen(parse->encoded_pathname);
676  int raw_length = encoded_length / 2;
677 
678  parse->pathname = palloc(raw_length + 1);
679  if (encoded_length % 2 != 0 ||
680  !hexdecode_string((uint8 *) parse->pathname,
681  parse->encoded_pathname,
682  raw_length))
684  "could not decode file name");
685  parse->pathname[raw_length] = '\0';
686  pfree(parse->encoded_pathname);
687  parse->encoded_pathname = NULL;
688  }
689 
690  /* Parse size. */
691  size = strtoul(parse->size, &ep, 10);
692  if (*ep)
694  "file size is not an integer");
695 
696  /* Parse the checksum algorithm, if it's present. */
697  if (parse->algorithm == NULL)
698  checksum_type = CHECKSUM_TYPE_NONE;
699  else if (!pg_checksum_parse_type(parse->algorithm, &checksum_type))
700  context->error_cb(context, "unrecognized checksum algorithm: \"%s\"",
701  parse->algorithm);
702 
703  /* Parse the checksum payload, if it's present. */
704  checksum_string_length = parse->checksum == NULL ? 0
705  : strlen(parse->checksum);
706  if (checksum_string_length == 0)
707  {
708  checksum_length = 0;
709  checksum_payload = NULL;
710  }
711  else
712  {
713  checksum_length = checksum_string_length / 2;
714  checksum_payload = palloc(checksum_length);
715  if (checksum_string_length % 2 != 0 ||
716  !hexdecode_string(checksum_payload, parse->checksum,
717  checksum_length))
718  context->error_cb(context,
719  "invalid checksum for file \"%s\": \"%s\"",
720  parse->pathname, parse->checksum);
721  }
722 
723  /* Invoke the callback with the details we've gathered. */
724  context->per_file_cb(context, parse->pathname, size,
725  checksum_type, checksum_length, checksum_payload);
726 
727  /* Free memory we no longer need. */
728  if (parse->size != NULL)
729  {
730  pfree(parse->size);
731  parse->size = NULL;
732  }
733  if (parse->algorithm != NULL)
734  {
735  pfree(parse->algorithm);
736  parse->algorithm = NULL;
737  }
738  if (parse->checksum != NULL)
739  {
740  pfree(parse->checksum);
741  parse->checksum = NULL;
742  }
743 }
744 
745 /*
746  * Do additional parsing and sanity-checking of the details gathered for one
747  * WAL range, and invoke the per-WAL-range callback so that the caller gets
748  * those details. This happens for each WAL range when the corresponding JSON
749  * object is completely parsed.
750  */
751 static void
753 {
755  TimeLineID tli;
756  XLogRecPtr start_lsn,
757  end_lsn;
758  char *ep;
759 
760  /* Make sure all fields are present. */
761  if (parse->timeline == NULL)
762  json_manifest_parse_failure(parse->context, "missing timeline");
763  if (parse->start_lsn == NULL)
764  json_manifest_parse_failure(parse->context, "missing start LSN");
765  if (parse->end_lsn == NULL)
766  json_manifest_parse_failure(parse->context, "missing end LSN");
767 
768  /* Parse timeline. */
769  tli = strtoul(parse->timeline, &ep, 10);
770  if (*ep)
772  "timeline is not an integer");
773  if (!parse_xlogrecptr(&start_lsn, parse->start_lsn))
775  "could not parse start LSN");
776  if (!parse_xlogrecptr(&end_lsn, parse->end_lsn))
778  "could not parse end LSN");
779 
780  /* Invoke the callback with the details we've gathered. */
781  context->per_wal_range_cb(context, tli, start_lsn, end_lsn);
782 
783  /* Free memory we no longer need. */
784  if (parse->timeline != NULL)
785  {
786  pfree(parse->timeline);
787  parse->timeline = NULL;
788  }
789  if (parse->start_lsn != NULL)
790  {
791  pfree(parse->start_lsn);
792  parse->start_lsn = NULL;
793  }
794  if (parse->end_lsn != NULL)
795  {
796  pfree(parse->end_lsn);
797  parse->end_lsn = NULL;
798  }
799 }
800 
801 /*
802  * Verify that the manifest checksum is correct.
803  *
804  * The last line of the manifest file is excluded from the manifest checksum,
805  * because the last line is expected to contain the checksum that covers
806  * the rest of the file.
807  *
808  * For an incremental parse, this will just be called on the last chunk of the
809  * manifest, and the cryptohash context passed in. For a non-incremental
810  * parse incr_ctx will be NULL.
811  */
812 static void
814  size_t size, pg_cryptohash_ctx *incr_ctx)
815 {
817  size_t i;
818  size_t number_of_newlines = 0;
819  size_t ultimate_newline = 0;
820  size_t penultimate_newline = 0;
821  pg_cryptohash_ctx *manifest_ctx;
822  uint8 manifest_checksum_actual[PG_SHA256_DIGEST_LENGTH];
823  uint8 manifest_checksum_expected[PG_SHA256_DIGEST_LENGTH];
824 
825  /* Find the last two newlines in the file. */
826  for (i = 0; i < size; ++i)
827  {
828  if (buffer[i] == '\n')
829  {
830  ++number_of_newlines;
831  penultimate_newline = ultimate_newline;
832  ultimate_newline = i;
833  }
834  }
835 
836  /*
837  * Make sure that the last newline is right at the end, and that there are
838  * at least two lines total. We need this to be true in order for the
839  * following code, which computes the manifest checksum, to work properly.
840  */
841  if (number_of_newlines < 2)
843  "expected at least 2 lines");
844  if (ultimate_newline != size - 1)
846  "last line not newline-terminated");
847 
848  /* Checksum the rest. */
849  if (incr_ctx == NULL)
850  {
851  manifest_ctx = pg_cryptohash_create(PG_SHA256);
852  if (manifest_ctx == NULL)
853  context->error_cb(context, "out of memory");
854  if (pg_cryptohash_init(manifest_ctx) < 0)
855  context->error_cb(context, "could not initialize checksum of manifest");
856  }
857  else
858  {
859  manifest_ctx = incr_ctx;
860  }
861  if (pg_cryptohash_update(manifest_ctx, (uint8 *) buffer, penultimate_newline + 1) < 0)
862  context->error_cb(context, "could not update checksum of manifest");
863  if (pg_cryptohash_final(manifest_ctx, manifest_checksum_actual,
864  sizeof(manifest_checksum_actual)) < 0)
865  context->error_cb(context, "could not finalize checksum of manifest");
866 
867  /* Now verify it. */
868  if (parse->manifest_checksum == NULL)
869  context->error_cb(parse->context, "manifest has no checksum");
870  if (strlen(parse->manifest_checksum) != PG_SHA256_DIGEST_LENGTH * 2 ||
871  !hexdecode_string(manifest_checksum_expected, parse->manifest_checksum,
873  context->error_cb(context, "invalid manifest checksum: \"%s\"",
874  parse->manifest_checksum);
875  if (memcmp(manifest_checksum_actual, manifest_checksum_expected,
877  context->error_cb(context, "manifest checksum mismatch");
878  pg_cryptohash_free(manifest_ctx);
879 }
880 
881 /*
882  * Report a parse error.
883  *
884  * This is intended to be used for fairly low-level failures that probably
885  * shouldn't occur unless somebody has deliberately constructed a bad manifest,
886  * or unless the server is generating bad manifests due to some bug. msg should
887  * be a short string giving some hint as to what the problem is.
888  */
889 static void
891 {
892  context->error_cb(context, "could not parse backup manifest: %s", msg);
893 }
894 
895 /*
896  * Convert a character which represents a hexadecimal digit to an integer.
897  *
898  * Returns -1 if the character is not a hexadecimal digit.
899  */
900 static int
902 {
903  if (c >= '0' && c <= '9')
904  return c - '0';
905  if (c >= 'a' && c <= 'f')
906  return c - 'a' + 10;
907  if (c >= 'A' && c <= 'F')
908  return c - 'A' + 10;
909 
910  return -1;
911 }
912 
913 /*
914  * Decode a hex string into a byte string, 2 hex chars per byte.
915  *
916  * Returns false if invalid characters are encountered; otherwise true.
917  */
918 static bool
919 hexdecode_string(uint8 *result, char *input, int nbytes)
920 {
921  int i;
922 
923  for (i = 0; i < nbytes; ++i)
924  {
925  int n1 = hexdecode_char(input[i * 2]);
926  int n2 = hexdecode_char(input[i * 2 + 1]);
927 
928  if (n1 < 0 || n2 < 0)
929  return false;
930  result[i] = n1 * 16 + n2;
931  }
932 
933  return true;
934 }
935 
936 /*
937  * Parse an XLogRecPtr expressed using the usual string format.
938  */
939 static bool
941 {
942  uint32 hi;
943  uint32 lo;
944 
945  if (sscanf(input, "%X/%X", &hi, &lo) != 2)
946  return false;
947  *result = ((uint64) hi) << 32 | lo;
948  return true;
949 }
unsigned int uint32
Definition: c.h:506
#define strtoi64(str, endptr, base)
Definition: c.h:1297
#define Assert(condition)
Definition: c.h:858
#define strtou64(str, endptr, base)
Definition: c.h:1298
unsigned char uint8
Definition: c.h:504
bool pg_checksum_parse_type(char *name, pg_checksum_type *type)
pg_checksum_type
@ CHECKSUM_TYPE_NONE
int pg_cryptohash_update(pg_cryptohash_ctx *ctx, const uint8 *data, size_t len)
Definition: cryptohash.c:136
int pg_cryptohash_init(pg_cryptohash_ctx *ctx)
Definition: cryptohash.c:100
void pg_cryptohash_free(pg_cryptohash_ctx *ctx)
Definition: cryptohash.c:238
pg_cryptohash_ctx * pg_cryptohash_create(pg_cryptohash_type type)
Definition: cryptohash.c:74
int pg_cryptohash_final(pg_cryptohash_ctx *ctx, uint8 *dest, size_t len)
Definition: cryptohash.c:172
@ PG_SHA256
Definition: cryptohash.h:24
uint64 chunk
#define token
Definition: indent_globs.h:126
FILE * input
int i
Definition: isn.c:73
JsonParseErrorType pg_parse_json_incremental(JsonLexContext *lex, JsonSemAction *sem, char *json, int len, bool is_last)
Definition: jsonapi.c:649
char * json_errdetail(JsonParseErrorType error, JsonLexContext *lex)
Definition: jsonapi.c:2096
JsonParseErrorType pg_parse_json(JsonLexContext *lex, JsonSemAction *sem)
Definition: jsonapi.c:521
JsonLexContext * makeJsonLexContextCstringLen(JsonLexContext *lex, char *json, int len, int encoding, bool need_escapes)
Definition: jsonapi.c:326
void freeJsonLexContext(JsonLexContext *lex)
Definition: jsonapi.c:482
JsonLexContext * makeJsonLexContextIncremental(JsonLexContext *lex, int encoding, bool need_escapes)
Definition: jsonapi.c:366
JsonParseErrorType
Definition: jsonapi.h:37
@ JSON_SUCCESS
Definition: jsonapi.h:38
@ JSON_INCOMPLETE
Definition: jsonapi.h:39
JsonTokenType
Definition: jsonapi.h:20
void pfree(void *pointer)
Definition: mcxt.c:1520
void * palloc(Size size)
Definition: mcxt.c:1316
JsonManifestSemanticState
@ JM_EXPECT_TOPLEVEL_END
@ JM_EXPECT_FILES_START
@ JM_EXPECT_SYSTEM_IDENTIFIER_VALUE
@ JM_EXPECT_TOPLEVEL_START
@ JM_EXPECT_EOF
@ JM_EXPECT_WAL_RANGES_START
@ JM_EXPECT_FILES_NEXT
@ 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)
JsonManifestWALRangeField
@ JMWRF_START_LSN
@ JMWRF_TIMELINE
@ JMWRF_END_LSN
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)
void json_parse_manifest_incremental_chunk(JsonManifestParseIncrementalState *incstate, char *chunk, int size, bool is_last)
JsonManifestParseIncrementalState * json_parse_manifest_incremental_init(JsonManifestParseContext *context)
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)
JsonManifestFileField
@ JMFF_ENCODED_PATH
@ JMFF_PATH
@ JMFF_LAST_MODIFIED
@ JMFF_CHECKSUM_ALGORITHM
@ JMFF_CHECKSUM
@ JMFF_SIZE
void json_parse_manifest(JsonManifestParseContext *context, char *buffer, size_t size)
static void verify_manifest_checksum(JsonManifestParseState *parse, char *buffer, size_t size, pg_cryptohash_ctx *incr_ctx)
void json_parse_manifest_incremental_shutdown(JsonManifestParseIncrementalState *incstate)
static void json_manifest_finalize_system_identifier(JsonManifestParseState *parse)
static int hexdecode_char(char c)
static bool hexdecode_string(uint8 *result, char *input, int nbytes)
@ PG_UTF8
Definition: pg_wchar.h:232
char * c
tree context
Definition: radixtree.h:1829
static struct subre * parse(struct vars *v, int stopper, int type, struct state *init, struct state *final)
Definition: regcomp.c:715
#define PG_SHA256_DIGEST_LENGTH
Definition: sha2.h:23
static pg_noinline void Size size
Definition: slab.c:607
pg_cryptohash_ctx * manifest_ctx
JsonManifestWALRangeField wal_range_field
JsonManifestParseContext * context
JsonManifestFileField file_field
pg_checksum_type checksum_algorithm
JsonManifestSemanticState state
json_struct_action array_end
Definition: jsonapi.h:138
json_struct_action object_start
Definition: jsonapi.h:135
json_ofield_action object_field_start
Definition: jsonapi.h:139
json_aelem_action array_element_start
Definition: jsonapi.h:141
json_scalar_action scalar
Definition: jsonapi.h:143
void * semstate
Definition: jsonapi.h:134
json_aelem_action array_element_end
Definition: jsonapi.h:142
json_struct_action array_start
Definition: jsonapi.h:137
json_struct_action object_end
Definition: jsonapi.h:136
json_ofield_action object_field_end
Definition: jsonapi.h:140
Definition: regguts.h:323
JsonSemAction sem
uint64 XLogRecPtr
Definition: xlogdefs.h:21
uint32 TimeLineID
Definition: xlogdefs.h:59