PostgreSQL Source Code  git master
write_manifest.c File Reference
#include "postgres_fe.h"
#include <fcntl.h>
#include <time.h>
#include <unistd.h>
#include "common/checksum_helper.h"
#include "common/file_perm.h"
#include "common/logging.h"
#include "lib/stringinfo.h"
#include "load_manifest.h"
#include "mb/pg_wchar.h"
#include "write_manifest.h"
Include dependency graph for write_manifest.c:

Go to the source code of this file.

Data Structures

struct  manifest_writer
 

Functions

static void escape_json (StringInfo buf, const char *str)
 
static void flush_manifest (manifest_writer *mwriter)
 
static size_t hex_encode (const uint8 *src, size_t len, char *dst)
 
manifest_writercreate_manifest_writer (char *directory, uint64 system_identifier)
 
void add_file_to_manifest (manifest_writer *mwriter, const char *manifest_path, size_t size, time_t mtime, pg_checksum_type checksum_type, int checksum_length, uint8 *checksum_payload)
 
void finalize_manifest (manifest_writer *mwriter, manifest_wal_range *first_wal_range)
 

Function Documentation

◆ add_file_to_manifest()

void add_file_to_manifest ( manifest_writer mwriter,
const char *  manifest_path,
size_t  size,
time_t  mtime,
pg_checksum_type  checksum_type,
int  checksum_length,
uint8 checksum_payload 
)

Definition at line 76 of file write_manifest.c.

81 {
82  int pathlen = strlen(manifest_path);
83 
84  if (mwriter->first_file)
85  {
86  appendStringInfoChar(&mwriter->buf, '\n');
87  mwriter->first_file = false;
88  }
89  else
90  appendStringInfoString(&mwriter->buf, ",\n");
91 
92  if (pg_encoding_verifymbstr(PG_UTF8, manifest_path, pathlen) == pathlen)
93  {
94  appendStringInfoString(&mwriter->buf, "{ \"Path\": ");
95  escape_json(&mwriter->buf, manifest_path);
96  appendStringInfoString(&mwriter->buf, ", ");
97  }
98  else
99  {
100  appendStringInfoString(&mwriter->buf, "{ \"Encoded-Path\": \"");
101  enlargeStringInfo(&mwriter->buf, 2 * pathlen);
102  mwriter->buf.len += hex_encode((const uint8 *) manifest_path, pathlen,
103  &mwriter->buf.data[mwriter->buf.len]);
104  appendStringInfoString(&mwriter->buf, "\", ");
105  }
106 
107  appendStringInfo(&mwriter->buf, "\"Size\": %zu, ", size);
108 
109  appendStringInfoString(&mwriter->buf, "\"Last-Modified\": \"");
110  enlargeStringInfo(&mwriter->buf, 128);
111  mwriter->buf.len += strftime(&mwriter->buf.data[mwriter->buf.len], 128,
112  "%Y-%m-%d %H:%M:%S %Z",
113  gmtime(&mtime));
114  appendStringInfoChar(&mwriter->buf, '"');
115 
116  if (mwriter->buf.len > 128 * 1024)
117  flush_manifest(mwriter);
118 
119  if (checksum_length > 0)
120  {
121  appendStringInfo(&mwriter->buf,
122  ", \"Checksum-Algorithm\": \"%s\", \"Checksum\": \"",
123  pg_checksum_type_name(checksum_type));
124 
125  enlargeStringInfo(&mwriter->buf, 2 * checksum_length);
126  mwriter->buf.len += hex_encode(checksum_payload, checksum_length,
127  &mwriter->buf.data[mwriter->buf.len]);
128 
129  appendStringInfoChar(&mwriter->buf, '"');
130  }
131 
132  appendStringInfoString(&mwriter->buf, " }");
133 
134  if (mwriter->buf.len > 128 * 1024)
135  flush_manifest(mwriter);
136 }
unsigned char uint8
Definition: c.h:504
char * pg_checksum_type_name(pg_checksum_type type)
@ PG_UTF8
Definition: pg_wchar.h:232
static pg_noinline void Size size
Definition: slab.c:607
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:97
void enlargeStringInfo(StringInfo str, int needed)
Definition: stringinfo.c:289
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:182
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:194
StringInfoData buf
int pg_encoding_verifymbstr(int encoding, const char *mbstr, int len)
Definition: wchar.c:2116
static void flush_manifest(manifest_writer *mwriter)
static size_t hex_encode(const uint8 *src, size_t len, char *dst)
static void escape_json(StringInfo buf, const char *str)

References appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), manifest_writer::buf, StringInfoData::data, enlargeStringInfo(), escape_json(), manifest_writer::first_file, flush_manifest(), hex_encode(), StringInfoData::len, pg_checksum_type_name(), pg_encoding_verifymbstr(), PG_UTF8, and size.

Referenced by process_directory_recursively(), and write_backup_label().

◆ create_manifest_writer()

manifest_writer* create_manifest_writer ( char *  directory,
uint64  system_identifier 
)

Definition at line 48 of file write_manifest.c.

49 {
50  manifest_writer *mwriter = pg_malloc(sizeof(manifest_writer));
51 
52  snprintf(mwriter->pathname, MAXPGPATH, "%s/backup_manifest", directory);
53  mwriter->fd = -1;
54  initStringInfo(&mwriter->buf);
55  mwriter->first_file = true;
56  mwriter->still_checksumming = true;
58 
59  appendStringInfo(&mwriter->buf,
60  "{ \"PostgreSQL-Backup-Manifest-Version\": 2,\n"
61  "\"System-Identifier\": " UINT64_FORMAT ",\n"
62  "\"Files\": [",
63  system_identifier);
64 
65  return mwriter;
66 }
#define UINT64_FORMAT
Definition: c.h:549
int pg_checksum_init(pg_checksum_context *context, pg_checksum_type type)
@ CHECKSUM_TYPE_SHA256
void * pg_malloc(size_t size)
Definition: fe_memutils.c:47
#define MAXPGPATH
#define snprintf
Definition: port.h:238
void initStringInfo(StringInfo str)
Definition: stringinfo.c:59
char pathname[MAXPGPATH]
pg_checksum_context manifest_ctx
static const char * directory
Definition: zic.c:634

References appendStringInfo(), manifest_writer::buf, CHECKSUM_TYPE_SHA256, directory, manifest_writer::fd, manifest_writer::first_file, initStringInfo(), manifest_writer::manifest_ctx, MAXPGPATH, manifest_writer::pathname, pg_checksum_init(), pg_malloc(), snprintf, manifest_writer::still_checksumming, and UINT64_FORMAT.

Referenced by main().

◆ escape_json()

static void escape_json ( StringInfo  buf,
const char *  str 
)
static

Definition at line 195 of file write_manifest.c.

196 {
197  const char *p;
198 
200  for (p = str; *p; p++)
201  {
202  switch (*p)
203  {
204  case '\b':
205  appendStringInfoString(buf, "\\b");
206  break;
207  case '\f':
208  appendStringInfoString(buf, "\\f");
209  break;
210  case '\n':
211  appendStringInfoString(buf, "\\n");
212  break;
213  case '\r':
214  appendStringInfoString(buf, "\\r");
215  break;
216  case '\t':
217  appendStringInfoString(buf, "\\t");
218  break;
219  case '"':
220  appendStringInfoString(buf, "\\\"");
221  break;
222  case '\\':
223  appendStringInfoString(buf, "\\\\");
224  break;
225  default:
226  if ((unsigned char) *p < ' ')
227  appendStringInfo(buf, "\\u%04x", (int) *p);
228  else
230  break;
231  }
232  }
234 }
const char * str
static char * buf
Definition: pg_test_fsync.c:73
#define appendStringInfoCharMacro(str, ch)
Definition: stringinfo.h:204

References appendStringInfo(), appendStringInfoCharMacro, appendStringInfoString(), buf, and str.

Referenced by add_file_to_manifest().

◆ finalize_manifest()

void finalize_manifest ( manifest_writer mwriter,
manifest_wal_range first_wal_range 
)

Definition at line 142 of file write_manifest.c.

144 {
145  uint8 checksumbuf[PG_SHA256_DIGEST_LENGTH];
146  int len;
147  manifest_wal_range *wal_range;
148 
149  /* Terminate the list of files. */
150  appendStringInfoString(&mwriter->buf, "\n],\n");
151 
152  /* Start a list of LSN ranges. */
153  appendStringInfoString(&mwriter->buf, "\"WAL-Ranges\": [\n");
154 
155  for (wal_range = first_wal_range; wal_range != NULL;
156  wal_range = wal_range->next)
157  appendStringInfo(&mwriter->buf,
158  "%s{ \"Timeline\": %u, \"Start-LSN\": \"%X/%X\", \"End-LSN\": \"%X/%X\" }",
159  wal_range == first_wal_range ? "" : ",\n",
160  wal_range->tli,
161  LSN_FORMAT_ARGS(wal_range->start_lsn),
162  LSN_FORMAT_ARGS(wal_range->end_lsn));
163 
164  /* Terminate the list of WAL ranges. */
165  appendStringInfoString(&mwriter->buf, "\n],\n");
166 
167  /* Flush accumulated data and update checksum calculation. */
168  flush_manifest(mwriter);
169 
170  /* Checksum only includes data up to this point. */
171  mwriter->still_checksumming = false;
172 
173  /* Compute and insert manifest checksum. */
174  appendStringInfoString(&mwriter->buf, "\"Manifest-Checksum\": \"");
176  len = pg_checksum_final(&mwriter->manifest_ctx, checksumbuf);
178  mwriter->buf.len +=
179  hex_encode(checksumbuf, len, &mwriter->buf.data[mwriter->buf.len]);
180  appendStringInfoString(&mwriter->buf, "\"}\n");
181 
182  /* Flush the last manifest checksum itself. */
183  flush_manifest(mwriter);
184 
185  /* Close the file. */
186  if (close(mwriter->fd) != 0)
187  pg_fatal("could not close \"%s\": %m", mwriter->pathname);
188  mwriter->fd = -1;
189 }
#define Assert(condition)
Definition: c.h:858
int pg_checksum_final(pg_checksum_context *context, uint8 *output)
#define close(a)
Definition: win32.h:12
#define pg_fatal(...)
const void size_t len
#define PG_SHA256_DIGEST_LENGTH
Definition: sha2.h:23
#define PG_SHA256_DIGEST_STRING_LENGTH
Definition: sha2.h:24
XLogRecPtr end_lsn
Definition: load_manifest.h:48
struct manifest_wal_range * next
Definition: load_manifest.h:49
XLogRecPtr start_lsn
Definition: load_manifest.h:47
#define LSN_FORMAT_ARGS(lsn)
Definition: xlogdefs.h:43

References appendStringInfo(), appendStringInfoString(), Assert, manifest_writer::buf, close, StringInfoData::data, manifest_wal_range::end_lsn, enlargeStringInfo(), manifest_writer::fd, flush_manifest(), hex_encode(), StringInfoData::len, len, LSN_FORMAT_ARGS, manifest_writer::manifest_ctx, manifest_wal_range::next, manifest_writer::pathname, pg_checksum_final(), pg_fatal, PG_SHA256_DIGEST_LENGTH, PG_SHA256_DIGEST_STRING_LENGTH, manifest_wal_range::start_lsn, manifest_writer::still_checksumming, and manifest_wal_range::tli.

Referenced by main().

◆ flush_manifest()

static void flush_manifest ( manifest_writer mwriter)
static

Definition at line 244 of file write_manifest.c.

245 {
246  if (mwriter->fd == -1 &&
247  (mwriter->fd = open(mwriter->pathname,
248  O_WRONLY | O_CREAT | O_EXCL | PG_BINARY,
249  pg_file_create_mode)) < 0)
250  pg_fatal("could not open file \"%s\": %m", mwriter->pathname);
251 
252  if (mwriter->buf.len > 0)
253  {
254  ssize_t wb;
255 
256  wb = write(mwriter->fd, mwriter->buf.data, mwriter->buf.len);
257  if (wb != mwriter->buf.len)
258  {
259  if (wb < 0)
260  pg_fatal("could not write \"%s\": %m", mwriter->pathname);
261  else
262  pg_fatal("could not write file \"%s\": wrote only %d of %d bytes",
263  mwriter->pathname, (int) wb, mwriter->buf.len);
264  }
265 
266  if (mwriter->still_checksumming &&
268  (uint8 *) mwriter->buf.data,
269  mwriter->buf.len) < 0)
270  pg_fatal("could not update checksum of file \"%s\"",
271  mwriter->pathname);
272  resetStringInfo(&mwriter->buf);
273  }
274 }
#define PG_BINARY
Definition: c.h:1273
int pg_checksum_update(pg_checksum_context *context, const uint8 *input, size_t len)
int pg_file_create_mode
Definition: file_perm.c:19
#define write(a, b, c)
Definition: win32.h:14
void resetStringInfo(StringInfo str)
Definition: stringinfo.c:78

References manifest_writer::buf, StringInfoData::data, manifest_writer::fd, StringInfoData::len, manifest_writer::manifest_ctx, manifest_writer::pathname, PG_BINARY, pg_checksum_update(), pg_fatal, pg_file_create_mode, resetStringInfo(), manifest_writer::still_checksumming, and write.

Referenced by add_file_to_manifest(), and finalize_manifest().

◆ hex_encode()

static size_t hex_encode ( const uint8 src,
size_t  len,
char *  dst 
)
static

Definition at line 280 of file write_manifest.c.

281 {
282  const uint8 *end = src + len;
283 
284  while (src < end)
285  {
286  unsigned n1 = (*src >> 4) & 0xF;
287  unsigned n2 = *src & 0xF;
288 
289  *dst++ = n1 < 10 ? '0' + n1 : 'a' + n1 - 10;
290  *dst++ = n2 < 10 ? '0' + n2 : 'a' + n2 - 10;
291  ++src;
292  }
293 
294  return len * 2;
295 }

References len.

Referenced by add_file_to_manifest(), and finalize_manifest().