PostgreSQL Source Code  git master
bbstreamer_tar.c File Reference
#include "postgres_fe.h"
#include <time.h>
#include "bbstreamer.h"
#include "common/logging.h"
#include "pgtar.h"
Include dependency graph for bbstreamer_tar.c:

Go to the source code of this file.

Data Structures

struct  bbstreamer_tar_parser
 
struct  bbstreamer_tar_archiver
 

Typedefs

typedef struct bbstreamer_tar_parser bbstreamer_tar_parser
 
typedef struct bbstreamer_tar_archiver bbstreamer_tar_archiver
 

Functions

static void bbstreamer_tar_parser_content (bbstreamer *streamer, bbstreamer_member *member, const char *data, int len, bbstreamer_archive_context context)
 
static void bbstreamer_tar_parser_finalize (bbstreamer *streamer)
 
static void bbstreamer_tar_parser_free (bbstreamer *streamer)
 
static bool bbstreamer_tar_header (bbstreamer_tar_parser *mystreamer)
 
static void bbstreamer_tar_archiver_content (bbstreamer *streamer, bbstreamer_member *member, const char *data, int len, bbstreamer_archive_context context)
 
static void bbstreamer_tar_archiver_finalize (bbstreamer *streamer)
 
static void bbstreamer_tar_archiver_free (bbstreamer *streamer)
 
static void bbstreamer_tar_terminator_content (bbstreamer *streamer, bbstreamer_member *member, const char *data, int len, bbstreamer_archive_context context)
 
static void bbstreamer_tar_terminator_finalize (bbstreamer *streamer)
 
static void bbstreamer_tar_terminator_free (bbstreamer *streamer)
 
bbstreamerbbstreamer_tar_parser_new (bbstreamer *next)
 
bbstreamerbbstreamer_tar_archiver_new (bbstreamer *next)
 
bbstreamerbbstreamer_tar_terminator_new (bbstreamer *next)
 

Variables

const bbstreamer_ops bbstreamer_tar_parser_ops
 
const bbstreamer_ops bbstreamer_tar_archiver_ops
 
const bbstreamer_ops bbstreamer_tar_terminator_ops
 

Typedef Documentation

◆ bbstreamer_tar_archiver

◆ bbstreamer_tar_parser

Function Documentation

◆ bbstreamer_tar_archiver_content()

static void bbstreamer_tar_archiver_content ( bbstreamer streamer,
bbstreamer_member member,
const char *  data,
int  len,
bbstreamer_archive_context  context 
)
static

Definition at line 390 of file bbstreamer_tar.c.

394 {
395  bbstreamer_tar_archiver *mystreamer = (bbstreamer_tar_archiver *) streamer;
396  char buffer[2 * TAR_BLOCK_SIZE];
397 
399 
401  {
402  Assert(len == 0);
403 
404  /* Replace zero-length tar header with a newly constructed one. */
405  tarCreateHeader(buffer, member->pathname, NULL,
406  member->size, member->mode, member->uid, member->gid,
407  time(NULL));
408  data = buffer;
410 
411  /* Also make a note to replace padding, in case size changed. */
412  mystreamer->rearchive_member = true;
413  }
414  else if (context == BBSTREAMER_MEMBER_TRAILER &&
415  mystreamer->rearchive_member)
416  {
417  int pad_bytes = tarPaddingBytesRequired(member->size);
418 
419  /* Also replace padding, if we regenerated the header. */
420  memset(buffer, 0, pad_bytes);
421  data = buffer;
422  len = pad_bytes;
423 
424  /* Don't do this again unless we replace another header. */
425  mystreamer->rearchive_member = false;
426  }
428  {
429  /* Trailer should always be two blocks of zero bytes. */
430  memset(buffer, 0, 2 * TAR_BLOCK_SIZE);
431  data = buffer;
432  len = 2 * TAR_BLOCK_SIZE;
433  }
434 
435  bbstreamer_content(streamer->bbs_next, member, data, len, context);
436 }
static void bbstreamer_content(bbstreamer *streamer, bbstreamer_member *member, const char *data, int len, bbstreamer_archive_context context)
Definition: bbstreamer.h:126
@ BBSTREAMER_ARCHIVE_TRAILER
Definition: bbstreamer.h:59
@ BBSTREAMER_MEMBER_HEADER
Definition: bbstreamer.h:56
@ BBSTREAMER_MEMBER_TRAILER
Definition: bbstreamer.h:58
@ BBSTREAMER_UNKNOWN
Definition: bbstreamer.h:55
#define Assert(condition)
Definition: c.h:858
const void size_t len
const void * data
static size_t tarPaddingBytesRequired(size_t len)
Definition: pgtar.h:79
enum tarError tarCreateHeader(char *h, const char *filename, const char *linktarget, pgoff_t size, mode_t mode, uid_t uid, gid_t gid, time_t mtime)
Definition: tar.c:114
#define TAR_BLOCK_SIZE
Definition: pgtar.h:17
tree context
Definition: radixtree.h:1833
char pathname[MAXPGPATH]
Definition: bbstreamer.h:72
bbstreamer * bbs_next
Definition: bbstreamer.h:101

References Assert, bbstreamer::bbs_next, BBSTREAMER_ARCHIVE_TRAILER, bbstreamer_content(), BBSTREAMER_MEMBER_HEADER, BBSTREAMER_MEMBER_TRAILER, BBSTREAMER_UNKNOWN, context, data, bbstreamer_member::gid, len, bbstreamer_member::mode, bbstreamer_member::pathname, bbstreamer_tar_archiver::rearchive_member, bbstreamer_member::size, TAR_BLOCK_SIZE, tarCreateHeader(), tarPaddingBytesRequired(), and bbstreamer_member::uid.

◆ bbstreamer_tar_archiver_finalize()

static void bbstreamer_tar_archiver_finalize ( bbstreamer streamer)
static

Definition at line 442 of file bbstreamer_tar.c.

443 {
444  bbstreamer_finalize(streamer->bbs_next);
445 }
static void bbstreamer_finalize(bbstreamer *streamer)
Definition: bbstreamer.h:136

References bbstreamer::bbs_next, and bbstreamer_finalize().

◆ bbstreamer_tar_archiver_free()

static void bbstreamer_tar_archiver_free ( bbstreamer streamer)
static

Definition at line 451 of file bbstreamer_tar.c.

452 {
453  bbstreamer_free(streamer->bbs_next);
454  pfree(streamer);
455 }
static void bbstreamer_free(bbstreamer *streamer)
Definition: bbstreamer.h:144
void pfree(void *pointer)
Definition: mcxt.c:1520

References bbstreamer::bbs_next, bbstreamer_free(), and pfree().

◆ bbstreamer_tar_archiver_new()

bbstreamer* bbstreamer_tar_archiver_new ( bbstreamer next)

Definition at line 356 of file bbstreamer_tar.c.

357 {
358  bbstreamer_tar_archiver *streamer;
359 
360  streamer = palloc0(sizeof(bbstreamer_tar_archiver));
361  *((const bbstreamer_ops **) &streamer->base.bbs_ops) =
363  streamer->base.bbs_next = next;
364 
365  return &streamer->base;
366 }
const bbstreamer_ops bbstreamer_tar_archiver_ops
static int32 next
Definition: blutils.c:221
void * palloc0(Size size)
Definition: mcxt.c:1346
const bbstreamer_ops * bbs_ops
Definition: bbstreamer.h:100

References bbstreamer_tar_archiver::base, bbstreamer::bbs_next, bbstreamer::bbs_ops, bbstreamer_tar_archiver_ops, next, and palloc0().

Referenced by CreateBackupStreamer().

◆ bbstreamer_tar_header()

static bool bbstreamer_tar_header ( bbstreamer_tar_parser mystreamer)
static

Definition at line 261 of file bbstreamer_tar.c.

262 {
263  bool has_nonzero_byte = false;
264  int i;
265  bbstreamer_member *member = &mystreamer->member;
266  char *buffer = mystreamer->base.bbs_buffer.data;
267 
268  Assert(mystreamer->base.bbs_buffer.len == TAR_BLOCK_SIZE);
269 
270  /* Check whether we've got a block of all zero bytes. */
271  for (i = 0; i < TAR_BLOCK_SIZE; ++i)
272  {
273  if (buffer[i] != '\0')
274  {
275  has_nonzero_byte = true;
276  break;
277  }
278  }
279 
280  /*
281  * If the entire block was zeros, this is the end of the archive, not the
282  * start of the next file.
283  */
284  if (!has_nonzero_byte)
285  return false;
286 
287  /*
288  * Parse key fields out of the header.
289  */
290  strlcpy(member->pathname, &buffer[TAR_OFFSET_NAME], MAXPGPATH);
291  if (member->pathname[0] == '\0')
292  pg_fatal("tar member has empty name");
293  member->size = read_tar_number(&buffer[TAR_OFFSET_SIZE], 12);
294  member->mode = read_tar_number(&buffer[TAR_OFFSET_MODE], 8);
295  member->uid = read_tar_number(&buffer[TAR_OFFSET_UID], 8);
296  member->gid = read_tar_number(&buffer[TAR_OFFSET_GID], 8);
297  member->is_directory =
299  member->is_link =
301  if (member->is_link)
302  strlcpy(member->linktarget, &buffer[TAR_OFFSET_LINKNAME], 100);
303 
304  /* Compute number of padding bytes. */
305  mystreamer->pad_bytes_expected = tarPaddingBytesRequired(member->size);
306 
307  /* Forward the entire header to the next bbstreamer. */
308  bbstreamer_content(mystreamer->base.bbs_next, member,
309  buffer, TAR_BLOCK_SIZE,
311 
312  return true;
313 }
int i
Definition: isn.c:73
#define pg_fatal(...)
#define MAXPGPATH
uint64 read_tar_number(const char *s, int len)
Definition: tar.c:58
@ TAR_FILETYPE_SYMLINK
Definition: pgtar.h:61
@ TAR_FILETYPE_DIRECTORY
Definition: pgtar.h:62
@ TAR_OFFSET_MODE
Definition: pgtar.h:40
@ TAR_OFFSET_UID
Definition: pgtar.h:41
@ TAR_OFFSET_TYPEFLAG
Definition: pgtar.h:46
@ TAR_OFFSET_NAME
Definition: pgtar.h:39
@ TAR_OFFSET_SIZE
Definition: pgtar.h:43
@ TAR_OFFSET_GID
Definition: pgtar.h:42
@ TAR_OFFSET_LINKNAME
Definition: pgtar.h:47
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
char linktarget[MAXPGPATH]
Definition: bbstreamer.h:79
bbstreamer_member member
StringInfoData bbs_buffer
Definition: bbstreamer.h:102

References Assert, bbstreamer_tar_parser::base, bbstreamer::bbs_buffer, bbstreamer::bbs_next, bbstreamer_content(), BBSTREAMER_MEMBER_HEADER, StringInfoData::data, bbstreamer_member::gid, i, bbstreamer_member::is_directory, bbstreamer_member::is_link, StringInfoData::len, bbstreamer_member::linktarget, MAXPGPATH, bbstreamer_tar_parser::member, bbstreamer_member::mode, bbstreamer_tar_parser::pad_bytes_expected, bbstreamer_member::pathname, pg_fatal, read_tar_number(), bbstreamer_member::size, strlcpy(), TAR_BLOCK_SIZE, TAR_FILETYPE_DIRECTORY, TAR_FILETYPE_SYMLINK, TAR_OFFSET_GID, TAR_OFFSET_LINKNAME, TAR_OFFSET_MODE, TAR_OFFSET_NAME, TAR_OFFSET_SIZE, TAR_OFFSET_TYPEFLAG, TAR_OFFSET_UID, tarPaddingBytesRequired(), and bbstreamer_member::uid.

Referenced by bbstreamer_tar_parser_content().

◆ bbstreamer_tar_parser_content()

static void bbstreamer_tar_parser_content ( bbstreamer streamer,
bbstreamer_member member,
const char *  data,
int  len,
bbstreamer_archive_context  context 
)
static

Definition at line 111 of file bbstreamer_tar.c.

114 {
115  bbstreamer_tar_parser *mystreamer = (bbstreamer_tar_parser *) streamer;
116  size_t nbytes;
117 
118  /* Expect unparsed input. */
119  Assert(member == NULL);
121 
122  while (len > 0)
123  {
124  switch (mystreamer->next_context)
125  {
127 
128  /*
129  * If we're expecting an archive member header, accumulate a
130  * full block of data before doing anything further.
131  */
132  if (!bbstreamer_buffer_until(streamer, &data, &len,
134  return;
135 
136  /*
137  * Now we can process the header and get ready to process the
138  * file contents; however, we might find out that what we
139  * thought was the next file header is actually the start of
140  * the archive trailer. Switch modes accordingly.
141  */
142  if (bbstreamer_tar_header(mystreamer))
143  {
144  if (mystreamer->member.size == 0)
145  {
146  /* No content; trailer is zero-length. */
147  bbstreamer_content(mystreamer->base.bbs_next,
148  &mystreamer->member,
149  NULL, 0,
151 
152  /* Expect next header. */
154  }
155  else
156  {
157  /* Expect contents. */
159  }
160  mystreamer->base.bbs_buffer.len = 0;
161  mystreamer->file_bytes_sent = 0;
162  }
163  else
165  break;
166 
168 
169  /*
170  * Send as much content as we have, but not more than the
171  * remaining file length.
172  */
173  Assert(mystreamer->file_bytes_sent < mystreamer->member.size);
174  nbytes = mystreamer->member.size - mystreamer->file_bytes_sent;
175  nbytes = Min(nbytes, len);
176  Assert(nbytes > 0);
177  bbstreamer_content(mystreamer->base.bbs_next,
178  &mystreamer->member,
179  data, nbytes,
181  mystreamer->file_bytes_sent += nbytes;
182  data += nbytes;
183  len -= nbytes;
184 
185  /*
186  * If we've not yet sent the whole file, then there's more
187  * content to come; otherwise, it's time to expect the file
188  * trailer.
189  */
190  Assert(mystreamer->file_bytes_sent <= mystreamer->member.size);
191  if (mystreamer->file_bytes_sent == mystreamer->member.size)
192  {
193  if (mystreamer->pad_bytes_expected == 0)
194  {
195  /* Trailer is zero-length. */
196  bbstreamer_content(mystreamer->base.bbs_next,
197  &mystreamer->member,
198  NULL, 0,
200 
201  /* Expect next header. */
203  }
204  else
205  {
206  /* Trailer is not zero-length. */
208  }
209  mystreamer->base.bbs_buffer.len = 0;
210  }
211  break;
212 
214 
215  /*
216  * If we're expecting an archive member trailer, accumulate
217  * the expected number of padding bytes before sending
218  * anything onward.
219  */
220  if (!bbstreamer_buffer_until(streamer, &data, &len,
221  mystreamer->pad_bytes_expected))
222  return;
223 
224  /* OK, now we can send it. */
225  bbstreamer_content(mystreamer->base.bbs_next,
226  &mystreamer->member,
227  data, mystreamer->pad_bytes_expected,
229 
230  /* Expect next file header. */
232  mystreamer->base.bbs_buffer.len = 0;
233  break;
234 
236 
237  /*
238  * We've seen an end-of-archive indicator, so anything more is
239  * buffered and sent as part of the archive trailer. But we
240  * don't expect more than 2 blocks.
241  */
242  bbstreamer_buffer_bytes(streamer, &data, &len, len);
243  if (len > 2 * TAR_BLOCK_SIZE)
244  pg_fatal("tar file trailer exceeds 2 blocks");
245  return;
246 
247  default:
248  /* Shouldn't happen. */
249  pg_fatal("unexpected state while parsing tar archive");
250  }
251  }
252 }
static void bbstreamer_buffer_bytes(bbstreamer *streamer, const char **data, int *len, int nbytes)
Definition: bbstreamer.h:157
static bool bbstreamer_buffer_until(bbstreamer *streamer, const char **data, int *len, int target_bytes)
Definition: bbstreamer.h:175
@ BBSTREAMER_MEMBER_CONTENTS
Definition: bbstreamer.h:57
static bool bbstreamer_tar_header(bbstreamer_tar_parser *mystreamer)
#define Min(x, y)
Definition: c.h:1004
bbstreamer_archive_context next_context

References Assert, bbstreamer_tar_parser::base, bbstreamer::bbs_buffer, bbstreamer::bbs_next, BBSTREAMER_ARCHIVE_TRAILER, bbstreamer_buffer_bytes(), bbstreamer_buffer_until(), bbstreamer_content(), BBSTREAMER_MEMBER_CONTENTS, BBSTREAMER_MEMBER_HEADER, BBSTREAMER_MEMBER_TRAILER, bbstreamer_tar_header(), BBSTREAMER_UNKNOWN, context, data, bbstreamer_tar_parser::file_bytes_sent, StringInfoData::len, len, bbstreamer_tar_parser::member, Min, bbstreamer_tar_parser::next_context, bbstreamer_tar_parser::pad_bytes_expected, pg_fatal, bbstreamer_member::size, and TAR_BLOCK_SIZE.

◆ bbstreamer_tar_parser_finalize()

static void bbstreamer_tar_parser_finalize ( bbstreamer streamer)
static

Definition at line 319 of file bbstreamer_tar.c.

320 {
321  bbstreamer_tar_parser *mystreamer = (bbstreamer_tar_parser *) streamer;
322 
323  if (mystreamer->next_context != BBSTREAMER_ARCHIVE_TRAILER &&
324  (mystreamer->next_context != BBSTREAMER_MEMBER_HEADER ||
325  mystreamer->base.bbs_buffer.len > 0))
326  pg_fatal("COPY stream ended before last file was finished");
327 
328  /* Send the archive trailer, even if empty. */
329  bbstreamer_content(streamer->bbs_next, NULL,
330  streamer->bbs_buffer.data, streamer->bbs_buffer.len,
332 
333  /* Now finalize successor. */
334  bbstreamer_finalize(streamer->bbs_next);
335 }

References bbstreamer_tar_parser::base, bbstreamer::bbs_buffer, bbstreamer::bbs_next, BBSTREAMER_ARCHIVE_TRAILER, bbstreamer_content(), bbstreamer_finalize(), BBSTREAMER_MEMBER_HEADER, StringInfoData::data, StringInfoData::len, bbstreamer_tar_parser::next_context, and pg_fatal.

◆ bbstreamer_tar_parser_free()

static void bbstreamer_tar_parser_free ( bbstreamer streamer)
static

Definition at line 341 of file bbstreamer_tar.c.

342 {
343  pfree(streamer->bbs_buffer.data);
344  bbstreamer_free(streamer->bbs_next);
345 }

References bbstreamer::bbs_buffer, bbstreamer::bbs_next, bbstreamer_free(), StringInfoData::data, and pfree().

◆ bbstreamer_tar_parser_new()

bbstreamer* bbstreamer_tar_parser_new ( bbstreamer next)

Definition at line 93 of file bbstreamer_tar.c.

94 {
95  bbstreamer_tar_parser *streamer;
96 
97  streamer = palloc0(sizeof(bbstreamer_tar_parser));
98  *((const bbstreamer_ops **) &streamer->base.bbs_ops) =
100  streamer->base.bbs_next = next;
101  initStringInfo(&streamer->base.bbs_buffer);
103 
104  return &streamer->base;
105 }
const bbstreamer_ops bbstreamer_tar_parser_ops
void initStringInfo(StringInfo str)
Definition: stringinfo.c:59

References bbstreamer_tar_parser::base, bbstreamer::bbs_buffer, bbstreamer::bbs_next, bbstreamer::bbs_ops, BBSTREAMER_MEMBER_HEADER, bbstreamer_tar_parser_ops, initStringInfo(), next, bbstreamer_tar_parser::next_context, and palloc0().

Referenced by CreateBackupStreamer().

◆ bbstreamer_tar_terminator_content()

static void bbstreamer_tar_terminator_content ( bbstreamer streamer,
bbstreamer_member member,
const char *  data,
int  len,
bbstreamer_archive_context  context 
)
static

Definition at line 478 of file bbstreamer_tar.c.

482 {
483  /* Expect unparsed input. */
484  Assert(member == NULL);
486 
487  /* Just forward it. */
488  bbstreamer_content(streamer->bbs_next, member, data, len, context);
489 }

References Assert, bbstreamer::bbs_next, bbstreamer_content(), BBSTREAMER_UNKNOWN, context, data, and len.

◆ bbstreamer_tar_terminator_finalize()

static void bbstreamer_tar_terminator_finalize ( bbstreamer streamer)
static

Definition at line 496 of file bbstreamer_tar.c.

497 {
498  char buffer[2 * TAR_BLOCK_SIZE];
499 
500  memset(buffer, 0, 2 * TAR_BLOCK_SIZE);
501  bbstreamer_content(streamer->bbs_next, NULL, buffer,
503  bbstreamer_finalize(streamer->bbs_next);
504 }

References bbstreamer::bbs_next, bbstreamer_content(), bbstreamer_finalize(), BBSTREAMER_UNKNOWN, and TAR_BLOCK_SIZE.

◆ bbstreamer_tar_terminator_free()

static void bbstreamer_tar_terminator_free ( bbstreamer streamer)
static

Definition at line 510 of file bbstreamer_tar.c.

511 {
512  bbstreamer_free(streamer->bbs_next);
513  pfree(streamer);
514 }

References bbstreamer::bbs_next, bbstreamer_free(), and pfree().

◆ bbstreamer_tar_terminator_new()

bbstreamer* bbstreamer_tar_terminator_new ( bbstreamer next)

Definition at line 462 of file bbstreamer_tar.c.

463 {
464  bbstreamer *streamer;
465 
466  streamer = palloc0(sizeof(bbstreamer));
467  *((const bbstreamer_ops **) &streamer->bbs_ops) =
469  streamer->bbs_next = next;
470 
471  return streamer;
472 }
const bbstreamer_ops bbstreamer_tar_terminator_ops

References bbstreamer::bbs_next, bbstreamer::bbs_ops, bbstreamer_tar_terminator_ops, next, and palloc0().

Referenced by CreateBackupStreamer().

Variable Documentation

◆ bbstreamer_tar_archiver_ops

const bbstreamer_ops bbstreamer_tar_archiver_ops
Initial value:
= {
}
static void bbstreamer_tar_archiver_finalize(bbstreamer *streamer)
static void bbstreamer_tar_archiver_free(bbstreamer *streamer)
static void bbstreamer_tar_archiver_content(bbstreamer *streamer, bbstreamer_member *member, const char *data, int len, bbstreamer_archive_context context)

Definition at line 66 of file bbstreamer_tar.c.

Referenced by bbstreamer_tar_archiver_new().

◆ bbstreamer_tar_parser_ops

const bbstreamer_ops bbstreamer_tar_parser_ops
Initial value:
= {
}
static void bbstreamer_tar_parser_content(bbstreamer *streamer, bbstreamer_member *member, const char *data, int len, bbstreamer_archive_context context)
static void bbstreamer_tar_parser_finalize(bbstreamer *streamer)
static void bbstreamer_tar_parser_free(bbstreamer *streamer)

Definition at line 53 of file bbstreamer_tar.c.

Referenced by bbstreamer_tar_parser_new().

◆ bbstreamer_tar_terminator_ops

const bbstreamer_ops bbstreamer_tar_terminator_ops
Initial value:
= {
}
static void bbstreamer_tar_terminator_free(bbstreamer *streamer)
static void bbstreamer_tar_terminator_content(bbstreamer *streamer, bbstreamer_member *member, const char *data, int len, bbstreamer_archive_context context)
static void bbstreamer_tar_terminator_finalize(bbstreamer *streamer)

Definition at line 79 of file bbstreamer_tar.c.

Referenced by bbstreamer_tar_terminator_new().