Skip to content

Commit 57b5a96

Browse files
committed
Minimal fix for unterminated tar archive problem.
Commit 23a1c65 improved pg_basebackup's ability to parse tar archives, but also arranged to parse them only when we need to make some modification to the contents of the archive. That's a problem, because the server doesn't actually terminate tar archives. When the new parsing logic was engaged, pg_basebackup would properly terminate the tar file, but when it was skipped, pg_basebackup would just write whatever it got from the server, meaning that the terminator was missing. Most versions of tar are willing to overlook the missing terminator, but the AIX buildfarm animals were not. Fix by inventing a new kind of bbstreamer that just blindly adds a terminator, and using it whenever we don't parse the tar archive. Discussion: http://postgr.es/m/CA+TgmoZbNzsWwM4BE5Jb_qHncY817DYZwGf+2-7hkMQ27ZwsMQ@mail.gmail.com
1 parent b0cf544 commit 57b5a96

File tree

3 files changed

+78
-1
lines changed

3 files changed

+78
-1
lines changed

src/bin/pg_basebackup/bbstreamer.h

+1
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,7 @@ extern bbstreamer *bbstreamer_extractor_new(const char *basepath,
206206
void (*report_output_file) (const char *));
207207

208208
extern bbstreamer *bbstreamer_tar_parser_new(bbstreamer *next);
209+
extern bbstreamer *bbstreamer_tar_terminator_new(bbstreamer *next);
209210
extern bbstreamer *bbstreamer_tar_archiver_new(bbstreamer *next);
210211

211212
extern bbstreamer *bbstreamer_recovery_injector_new(bbstreamer *next,

src/bin/pg_basebackup/bbstreamer_tar.c

+72
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,19 @@ const bbstreamer_ops bbstreamer_tar_archiver_ops = {
5959
.free = bbstreamer_tar_archiver_free
6060
};
6161

62+
static void bbstreamer_tar_terminator_content(bbstreamer *streamer,
63+
bbstreamer_member *member,
64+
const char *data, int len,
65+
bbstreamer_archive_context context);
66+
static void bbstreamer_tar_terminator_finalize(bbstreamer *streamer);
67+
static void bbstreamer_tar_terminator_free(bbstreamer *streamer);
68+
69+
const bbstreamer_ops bbstreamer_tar_terminator_ops = {
70+
.content = bbstreamer_tar_terminator_content,
71+
.finalize = bbstreamer_tar_terminator_finalize,
72+
.free = bbstreamer_tar_terminator_free
73+
};
74+
6275
/*
6376
* Create a bbstreamer that can parse a stream of content as tar data.
6477
*
@@ -442,3 +455,62 @@ bbstreamer_tar_archiver_free(bbstreamer *streamer)
442455
bbstreamer_free(streamer->bbs_next);
443456
pfree(streamer);
444457
}
458+
459+
/*
460+
* Create a bbstreamer that blindly adds two blocks of NUL bytes to the
461+
* end of an incomplete tarfile that the server might send us.
462+
*/
463+
bbstreamer *
464+
bbstreamer_tar_terminator_new(bbstreamer *next)
465+
{
466+
bbstreamer *streamer;
467+
468+
streamer = palloc0(sizeof(bbstreamer));
469+
*((const bbstreamer_ops **) &streamer->bbs_ops) =
470+
&bbstreamer_tar_terminator_ops;
471+
streamer->bbs_next = next;
472+
473+
return streamer;
474+
}
475+
476+
/*
477+
* Pass all the content through without change.
478+
*/
479+
static void
480+
bbstreamer_tar_terminator_content(bbstreamer *streamer,
481+
bbstreamer_member *member,
482+
const char *data, int len,
483+
bbstreamer_archive_context context)
484+
{
485+
/* Expect unparsed input. */
486+
Assert(member == NULL);
487+
Assert(context == BBSTREAMER_UNKNOWN);
488+
489+
/* Just forward it. */
490+
bbstreamer_content(streamer->bbs_next, member, data, len, context);
491+
}
492+
493+
/*
494+
* At the end, blindly add the two blocks of NUL bytes which the server fails
495+
* to supply.
496+
*/
497+
static void
498+
bbstreamer_tar_terminator_finalize(bbstreamer *streamer)
499+
{
500+
char buffer[2 * TAR_BLOCK_SIZE];
501+
502+
memset(buffer, 0, 2 * TAR_BLOCK_SIZE);
503+
bbstreamer_content(streamer->bbs_next, NULL, buffer,
504+
2 * TAR_BLOCK_SIZE, BBSTREAMER_UNKNOWN);
505+
bbstreamer_finalize(streamer->bbs_next);
506+
}
507+
508+
/*
509+
* Free memory associated with a tar terminator.
510+
*/
511+
static void
512+
bbstreamer_tar_terminator_free(bbstreamer *streamer)
513+
{
514+
bbstreamer_free(streamer->bbs_next);
515+
pfree(streamer);
516+
}

src/bin/pg_basebackup/pg_basebackup.c

+5-1
Original file line numberDiff line numberDiff line change
@@ -1073,10 +1073,14 @@ CreateBackupStreamer(char *archive_name, char *spclocation,
10731073

10741074
/*
10751075
* If we're doing anything that involves understanding the contents of
1076-
* the archive, we'll need to parse it.
1076+
* the archive, we'll need to parse it. If not, we can skip parsing it,
1077+
* but the tar files the server sends are not properly terminated, so
1078+
* we'll need to add the terminator here.
10771079
*/
10781080
if (must_parse_archive)
10791081
streamer = bbstreamer_tar_parser_new(streamer);
1082+
else
1083+
streamer = bbstreamer_tar_terminator_new(streamer);
10801084

10811085
/* Return the results. */
10821086
*manifest_inject_streamer_p = manifest_inject_streamer;

0 commit comments

Comments
 (0)