1/*-------------------------------------------------------------------------
3 * Read and manipulate backup label files
5 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
6 * Portions Copyright (c) 1994, Regents of the University of California
8 * src/bin/pg_combinebackup/backup_label.c
10 *-------------------------------------------------------------------------
28 * Parse a backup label file, starting at buf->cursor.
30 * We expect to find a START WAL LOCATION line, followed by a LSN, followed
31 * by a space; the resulting LSN is stored into *start_lsn.
33 * We expect to find a START TIMELINE line, followed by a TLI, followed by
34 * a newline; the resulting TLI is stored into *start_tli.
36 * We expect to find either both INCREMENTAL FROM LSN and INCREMENTAL FROM TLI
37 * or neither. If these are found, they should be followed by an LSN or TLI
38 * respectively and then by a newline, and the values will be stored into
39 * *previous_lsn and *previous_tli, respectively.
41 * Other lines in the provided backup_label data are ignored. filename is used
42 * for error reporting; errors are fatal.
56 while (
buf->cursor <
buf->len)
58 char *s = &
buf->data[
buf->cursor];
60 char *
e = &
buf->data[eo];
68 if (
c >=
e || *
c !=
' ')
69 pg_fatal(
"%s: improper terminator for %s",
76 pg_fatal(
"%s: could not parse TLI for %s",
87 if (
c >=
e || *
c !=
'\n')
88 pg_fatal(
"%s: improper terminator for %s",
97 if (*previous_tli == 0)
105 if ((found & 1) == 0)
107 if ((found & 2) == 0)
109 if ((found & 4) != 0 && (found & 8) == 0)
111 "INCREMENTAL FROM LSN",
"INCREMENTAL FROM TLI");
112 if ((found & 8) != 0 && (found & 4) == 0)
114 "INCREMENTAL FROM TLI",
"INCREMENTAL FROM LSN");
118 * Write a backup label file to the output directory.
120 * This will be identical to the provided backup_label file, except that the
121 * INCREMENTAL FROM LSN and INCREMENTAL FROM TLI lines will be omitted.
123 * The new file will be checksummed using the specified algorithm. If
124 * mwriter != NULL, it will be added to the manifest.
145 while (
buf->cursor <
buf->len)
147 char *s = &
buf->data[
buf->cursor];
149 char *
e = &
buf->data[eo];
156 wb =
write(output_fd, s,
e - s);
162 pg_fatal(
"could not write file \"%s\": wrote %d of %d",
166 pg_fatal(
"could not update checksum of file \"%s\"",
173 if (
close(output_fd) != 0)
183 * We could track the length ourselves, but must stat() to get the
190 checksum_length, checksum_payload);
195 * Return the offset at which the next line in the buffer starts, or there
196 * is none, the offset at which the buffer ends.
198 * The search begins at buf->cursor.
203 int eo =
buf->cursor;
205 while (eo < buf->
len)
207 if (
buf->data[eo] ==
'\n')
216 * Test whether the line that runs from s to e (inclusive of *s, but not
217 * inclusive of *e) starts with the match string provided, and return true
218 * or false according to whether or not this is the case.
220 * If the function returns true and if *sout != NULL, stores a pointer to the
221 * byte following the match into *sout.
226 while (s <
e && *match !=
'0円' && *s == *match)
229 if (*match ==
'0円' && sout != NULL)
232 return (*match ==
'0円');
236 * Parse an LSN starting at s and not stopping at or before e. The return value
237 * is true on success and otherwise false. On success, stores the result into
238 * *lsn and sets *c to the first character that is not part of the LSN.
250 success = (sscanf(s,
"%X/%08X%n", &hi, &lo, &nchars) == 2);
263 * Parse a TLI starting at s and stopping at or before e. The return value is
264 * true on success and otherwise false. On success, stores the result into
265 * *tli. If the first character that is not part of the TLI is anything other
266 * than a newline, that is deemed a failure.
276 success = (sscanf(s,
"%u%n", tli, &nchars) == 1);
279 if (
success && s[nchars] !=
'\n')
static int get_eol_offset(StringInfo buf)
void parse_backup_label(char *filename, StringInfo buf, TimeLineID *start_tli, XLogRecPtr *start_lsn, TimeLineID *previous_tli, XLogRecPtr *previous_lsn)
static bool parse_lsn(char *s, char *e, XLogRecPtr *lsn, char **c)
static bool line_starts_with(char *s, char *e, char *match, char **sout)
void write_backup_label(char *output_directory, StringInfo buf, pg_checksum_type checksum_type, manifest_writer *mwriter)
static bool parse_tli(char *s, char *e, TimeLineID *tli)
int pg_checksum_final(pg_checksum_context *context, uint8 *output)
int pg_checksum_update(pg_checksum_context *context, const uint8 *input, size_t len)
int pg_checksum_init(pg_checksum_context *context, pg_checksum_type type)
#define PG_CHECKSUM_MAX_LENGTH
void add_file_to_manifest(manifest_writer *mwriter, const char *manifest_path, uint64 size, time_t mtime, pg_checksum_type checksum_type, int checksum_length, uint8 *checksum_payload)
#define InvalidXLogRecPtr