PostgreSQL Source Code git master
Loading...
Searching...
No Matches
astreamer_tar.c File Reference
#include "postgres_fe.h"
#include <time.h>
#include "common/logging.h"
#include "fe_utils/astreamer.h"
#include "pgtar.h"
Include dependency graph for astreamer_tar.c:

Go to the source code of this file.

Data Structures

struct  astreamer_tar_parser
 
struct  astreamer_tar_archiver
 

Typedefs

typedef struct astreamer_tar_parser astreamer_tar_parser
 
typedef struct astreamer_tar_archiver astreamer_tar_archiver
 

Functions

static void astreamer_tar_parser_content (astreamer *streamer, astreamer_member *member, const char *data, int len, astreamer_archive_context context)
 
static void astreamer_tar_parser_finalize (astreamer *streamer)
 
static void astreamer_tar_parser_free (astreamer *streamer)
 
static bool astreamer_tar_header (astreamer_tar_parser *mystreamer)
 
static void astreamer_tar_archiver_content (astreamer *streamer, astreamer_member *member, const char *data, int len, astreamer_archive_context context)
 
static void astreamer_tar_archiver_finalize (astreamer *streamer)
 
static void astreamer_tar_archiver_free (astreamer *streamer)
 
static void astreamer_tar_terminator_content (astreamer *streamer, astreamer_member *member, const char *data, int len, astreamer_archive_context context)
 
static void astreamer_tar_terminator_finalize (astreamer *streamer)
 
static void astreamer_tar_terminator_free (astreamer *streamer)
 
astreamerastreamer_tar_parser_new (astreamer *next)
 
astreamerastreamer_tar_archiver_new (astreamer *next)
 
astreamerastreamer_tar_terminator_new (astreamer *next)
 

Variables

static const astreamer_ops astreamer_tar_parser_ops
 
static const astreamer_ops astreamer_tar_archiver_ops
 
static const astreamer_ops astreamer_tar_terminator_ops
 

Typedef Documentation

◆ astreamer_tar_archiver

◆ astreamer_tar_parser

Function Documentation

◆ astreamer_tar_archiver_content()

static void astreamer_tar_archiver_content ( astreamer streamer,
astreamer_member member,
const char data,
int  len,
astreamer_archive_context  context 
)
static

Definition at line 422 of file astreamer_tar.c.

426{
428 char buffer[2 * TAR_BLOCK_SIZE];
429
430 Assert(context != ASTREAMER_UNKNOWN);
431
432 if (context == ASTREAMER_MEMBER_HEADER && len != TAR_BLOCK_SIZE)
433 {
434 Assert(len == 0);
435
436 /* Replace zero-length tar header with a newly constructed one. */
437 tarCreateHeader(buffer, member->pathname, NULL,
438 member->size, member->mode, member->uid, member->gid,
439 time(NULL));
440 data = buffer;
442
443 /* Also make a note to replace padding, in case size changed. */
444 mystreamer->rearchive_member = true;
445 }
446 else if (context == ASTREAMER_MEMBER_TRAILER &&
447 mystreamer->rearchive_member)
448 {
450
451 /* Also replace padding, if we regenerated the header. */
452 memset(buffer, 0, pad_bytes);
453 data = buffer;
454 len = pad_bytes;
455
456 /* Don't do this again unless we replace another header. */
457 mystreamer->rearchive_member = false;
458 }
459 else if (context == ASTREAMER_ARCHIVE_TRAILER)
460 {
461 /* Trailer should always be two blocks of zero bytes. */
462 memset(buffer, 0, 2 * TAR_BLOCK_SIZE);
463 data = buffer;
464 len = 2 * TAR_BLOCK_SIZE;
465 }
466
467 astreamer_content(streamer->bbs_next, member, data, len, context);
468}
static void astreamer_content(astreamer *streamer, astreamer_member *member, const char *data, int len, astreamer_archive_context context)
Definition astreamer.h:137
@ ASTREAMER_MEMBER_HEADER
Definition astreamer.h:65
@ ASTREAMER_MEMBER_TRAILER
Definition astreamer.h:67
@ ASTREAMER_ARCHIVE_TRAILER
Definition astreamer.h:68
@ ASTREAMER_UNKNOWN
Definition astreamer.h:64
#define Assert(condition)
Definition c.h:943
const void size_t len
const void * data
static size_t tarPaddingBytesRequired(size_t len)
Definition pgtar.h:84
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:143
#define TAR_BLOCK_SIZE
Definition pgtar.h:17
static int fb(int x)
char pathname[MAXPGPATH]
Definition astreamer.h:81
astreamer * bbs_next
Definition astreamer.h:112

References Assert, ASTREAMER_ARCHIVE_TRAILER, astreamer_content(), ASTREAMER_MEMBER_HEADER, ASTREAMER_MEMBER_TRAILER, ASTREAMER_UNKNOWN, astreamer::bbs_next, data, fb(), astreamer_member::gid, len, astreamer_member::mode, astreamer_member::pathname, astreamer_member::size, TAR_BLOCK_SIZE, tarCreateHeader(), tarPaddingBytesRequired(), and astreamer_member::uid.

◆ astreamer_tar_archiver_finalize()

static void astreamer_tar_archiver_finalize ( astreamer streamer)
static

Definition at line 474 of file astreamer_tar.c.

475{
476 astreamer_finalize(streamer->bbs_next);
477}
static void astreamer_finalize(astreamer *streamer)
Definition astreamer.h:147

References astreamer_finalize(), and astreamer::bbs_next.

◆ astreamer_tar_archiver_free()

static void astreamer_tar_archiver_free ( astreamer streamer)
static

Definition at line 483 of file astreamer_tar.c.

484{
485 astreamer_free(streamer->bbs_next);
486 pfree(streamer);
487}
static void astreamer_free(astreamer *streamer)
Definition astreamer.h:155
void pfree(void *pointer)
Definition mcxt.c:1616

References astreamer_free(), astreamer::bbs_next, and pfree().

◆ astreamer_tar_archiver_new()

astreamer * astreamer_tar_archiver_new ( astreamer next)

Definition at line 388 of file astreamer_tar.c.

389{
390 astreamer_tar_archiver *streamer;
391
393 *((const astreamer_ops **) &streamer->base.bbs_ops) =
395 streamer->base.bbs_next = next;
396
397 return &streamer->base;
398}
static const astreamer_ops astreamer_tar_archiver_ops
static int32 next
Definition blutils.c:225
#define palloc0_object(type)
Definition fe_memutils.h:75
const astreamer_ops * bbs_ops
Definition astreamer.h:111

References astreamer_tar_archiver_ops, astreamer_tar_archiver::base, astreamer::bbs_next, astreamer::bbs_ops, next, and palloc0_object.

Referenced by CreateBackupStreamer().

◆ astreamer_tar_header()

static bool astreamer_tar_header ( astreamer_tar_parser mystreamer)
static

Definition at line 267 of file astreamer_tar.c.

268{
269 bool has_nonzero_byte = false;
270 int i;
271 astreamer_member *member = &mystreamer->member;
272 char *buffer = mystreamer->base.bbs_buffer.data;
273
274 Assert(mystreamer->base.bbs_buffer.len == TAR_BLOCK_SIZE);
275
276 /* Zero out fields of *member, just for consistency. */
277 memset(member, 0, sizeof(astreamer_member));
278
279 /* Check whether we've got a block of all zero bytes. */
280 for (i = 0; i < TAR_BLOCK_SIZE; ++i)
281 {
282 if (buffer[i] != '\0')
283 {
284 has_nonzero_byte = true;
285 break;
286 }
287 }
288
289 /*
290 * If the entire block was zeros, this is the end of the archive, not the
291 * start of the next file.
292 */
293 if (!has_nonzero_byte)
294 return false;
295
296 /*
297 * Verify that we have a reasonable-looking header.
298 */
299 if (!isValidTarHeader(buffer))
300 pg_fatal("input file does not appear to be a valid tar archive");
301
302 /*
303 * Parse key fields out of the header.
304 */
305 strlcpy(member->pathname, &buffer[TAR_OFFSET_NAME], MAXPGPATH);
306 if (member->pathname[0] == '\0')
307 pg_fatal("tar member has empty name");
308 member->size = read_tar_number(&buffer[TAR_OFFSET_SIZE], 12);
309 member->mode = read_tar_number(&buffer[TAR_OFFSET_MODE], 8);
310 member->uid = read_tar_number(&buffer[TAR_OFFSET_UID], 8);
311 member->gid = read_tar_number(&buffer[TAR_OFFSET_GID], 8);
312
313 switch (buffer[TAR_OFFSET_TYPEFLAG])
314 {
317 member->is_regular = true;
318 break;
320 member->is_directory = true;
321 break;
323 member->is_symlink = true;
324 strlcpy(member->linktarget, &buffer[TAR_OFFSET_LINKNAME], 100);
325 break;
328 pg_fatal("pax extensions to tar format are not supported");
329 break;
330 default:
331 /* For special filetypes, set none of the three is_xxx flags */
332 break;
333 }
334
335 /* Compute number of padding bytes. */
336 mystreamer->pad_bytes_expected = tarPaddingBytesRequired(member->size);
337
338 /* Forward the entire header to the next astreamer. */
339 astreamer_content(mystreamer->base.bbs_next, member,
340 buffer, TAR_BLOCK_SIZE,
342
343 return true;
344}
int i
Definition isn.c:77
#define pg_fatal(...)
#define MAXPGPATH
uint64 read_tar_number(const char *s, int len)
Definition tar.c:58
@ TAR_FILETYPE_PAX_EXTENDED_GLOBAL
Definition pgtar.h:66
@ TAR_FILETYPE_SYMLINK
Definition pgtar.h:63
@ TAR_FILETYPE_PLAIN_OLD
Definition pgtar.h:62
@ TAR_FILETYPE_DIRECTORY
Definition pgtar.h:64
@ TAR_FILETYPE_PLAIN
Definition pgtar.h:61
@ TAR_FILETYPE_PAX_EXTENDED
Definition pgtar.h:65
@ 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
bool isValidTarHeader(const char *header)
Definition tar.c:112
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition strlcpy.c:45
char linktarget[MAXPGPATH]
Definition astreamer.h:90

References Assert, astreamer_content(), ASTREAMER_MEMBER_HEADER, fb(), astreamer_member::gid, i, astreamer_member::is_directory, astreamer_member::is_regular, astreamer_member::is_symlink, isValidTarHeader(), astreamer_member::linktarget, MAXPGPATH, astreamer_member::mode, astreamer_member::pathname, pg_fatal, read_tar_number(), astreamer_member::size, strlcpy(), TAR_BLOCK_SIZE, TAR_FILETYPE_DIRECTORY, TAR_FILETYPE_PAX_EXTENDED, TAR_FILETYPE_PAX_EXTENDED_GLOBAL, TAR_FILETYPE_PLAIN, TAR_FILETYPE_PLAIN_OLD, 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 astreamer_member::uid.

Referenced by astreamer_tar_parser_content().

◆ astreamer_tar_parser_content()

static void astreamer_tar_parser_content ( astreamer streamer,
astreamer_member member,
const char data,
int  len,
astreamer_archive_context  context 
)
static

Definition at line 111 of file astreamer_tar.c.

114{
116 size_t nbytes;
117
118 /* Expect unparsed input. */
119 Assert(member == NULL);
120 Assert(context == ASTREAMER_UNKNOWN);
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 (!astreamer_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 */
143 {
144 if (mystreamer->member.size == 0)
145 {
146 /* No content; trailer is zero-length. */
147 astreamer_content(mystreamer->base.bbs_next,
148 &mystreamer->member,
149 NULL, 0,
151
152 /* Expect next header. */
153 mystreamer->next_context = ASTREAMER_MEMBER_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 astreamer_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 astreamer_content(mystreamer->base.bbs_next,
197 &mystreamer->member,
198 NULL, 0,
200
201 /* Expect next header. */
202 mystreamer->next_context = ASTREAMER_MEMBER_HEADER;
203 }
204 else
205 {
206 /* Trailer is not zero-length. */
207 mystreamer->next_context = ASTREAMER_MEMBER_TRAILER;
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 (!astreamer_buffer_until(streamer, &data, &len,
221 mystreamer->pad_bytes_expected))
222 return;
223
224 /* OK, now we can send it. */
225 astreamer_content(mystreamer->base.bbs_next,
226 &mystreamer->member,
227 mystreamer->base.bbs_buffer.data,
228 mystreamer->pad_bytes_expected,
230
231 /* Expect next file header. */
232 mystreamer->next_context = ASTREAMER_MEMBER_HEADER;
233 mystreamer->base.bbs_buffer.len = 0;
234 break;
235
237
238 /*
239 * We've seen an end-of-archive indicator, so anything more is
240 * buffered and sent as part of the archive trailer.
241 *
242 * Per POSIX, the last physical block of a tar archive is
243 * always full-sized, so there may be undefined data after the
244 * two zero blocks that mark end-of-archive. GNU tar, for
245 * example, zero-pads to a 10kB boundary by default. We just
246 * buffer whatever we receive and pass it along at finalize
247 * time.
248 */
249 astreamer_buffer_bytes(streamer, &data, &len, len);
250 return;
251
252 default:
253 /* Shouldn't happen. */
254 pg_fatal("unexpected state while parsing tar archive");
255 }
256 }
257}
static bool astreamer_buffer_until(astreamer *streamer, const char **data, int *len, int target_bytes)
Definition astreamer.h:186
@ ASTREAMER_MEMBER_CONTENTS
Definition astreamer.h:66
static void astreamer_buffer_bytes(astreamer *streamer, const char **data, int *len, int nbytes)
Definition astreamer.h:168
static bool astreamer_tar_header(astreamer_tar_parser *mystreamer)
#define Min(x, y)
Definition c.h:1091

References Assert, ASTREAMER_ARCHIVE_TRAILER, astreamer_buffer_bytes(), astreamer_buffer_until(), astreamer_content(), ASTREAMER_MEMBER_CONTENTS, ASTREAMER_MEMBER_HEADER, ASTREAMER_MEMBER_TRAILER, astreamer_tar_header(), ASTREAMER_UNKNOWN, data, fb(), len, Min, pg_fatal, and TAR_BLOCK_SIZE.

◆ astreamer_tar_parser_finalize()

static void astreamer_tar_parser_finalize ( astreamer streamer)
static

Definition at line 350 of file astreamer_tar.c.

351{
353
354 if (mystreamer->next_context != ASTREAMER_ARCHIVE_TRAILER &&
355 (mystreamer->next_context != ASTREAMER_MEMBER_HEADER ||
356 mystreamer->base.bbs_buffer.len > 0))
357 pg_fatal("COPY stream ended before last file was finished");
358
359 /* Send the archive trailer, even if empty. */
361 streamer->bbs_buffer.data, streamer->bbs_buffer.len,
363
364 /* Now finalize successor. */
365 astreamer_finalize(streamer->bbs_next);
366}
StringInfoData bbs_buffer
Definition astreamer.h:113

References ASTREAMER_ARCHIVE_TRAILER, astreamer_content(), astreamer_finalize(), ASTREAMER_MEMBER_HEADER, astreamer::bbs_buffer, astreamer::bbs_next, StringInfoData::data, fb(), StringInfoData::len, and pg_fatal.

◆ astreamer_tar_parser_free()

static void astreamer_tar_parser_free ( astreamer streamer)
static

Definition at line 372 of file astreamer_tar.c.

373{
374 pfree(streamer->bbs_buffer.data);
375 astreamer_free(streamer->bbs_next);
376 pfree(streamer);
377}

References astreamer_free(), astreamer::bbs_buffer, astreamer::bbs_next, StringInfoData::data, and pfree().

◆ astreamer_tar_parser_new()

astreamer * astreamer_tar_parser_new ( astreamer next)

Definition at line 93 of file astreamer_tar.c.

94{
95 astreamer_tar_parser *streamer;
96
98 *((const astreamer_ops **) &streamer->base.bbs_ops) =
100 streamer->base.bbs_next = next;
101 initStringInfo(&streamer->base.bbs_buffer);
103
104 return &streamer->base;
105}
static const astreamer_ops astreamer_tar_parser_ops
void initStringInfo(StringInfo str)
Definition stringinfo.c:97
astreamer_archive_context next_context

References ASTREAMER_MEMBER_HEADER, astreamer_tar_parser_ops, astreamer_tar_parser::base, astreamer::bbs_buffer, astreamer::bbs_next, astreamer::bbs_ops, initStringInfo(), next, astreamer_tar_parser::next_context, and palloc0_object.

Referenced by create_archive_verifier(), CreateBackupStreamer(), and init_archive_reader().

◆ astreamer_tar_terminator_content()

static void astreamer_tar_terminator_content ( astreamer streamer,
astreamer_member member,
const char data,
int  len,
astreamer_archive_context  context 
)
static

Definition at line 510 of file astreamer_tar.c.

514{
515 /* Expect unparsed input. */
516 Assert(member == NULL);
517 Assert(context == ASTREAMER_UNKNOWN);
518
519 /* Just forward it. */
520 astreamer_content(streamer->bbs_next, member, data, len, context);
521}

References Assert, astreamer_content(), ASTREAMER_UNKNOWN, astreamer::bbs_next, data, fb(), and len.

◆ astreamer_tar_terminator_finalize()

static void astreamer_tar_terminator_finalize ( astreamer streamer)
static

Definition at line 528 of file astreamer_tar.c.

529{
530 char buffer[2 * TAR_BLOCK_SIZE];
531
532 memset(buffer, 0, 2 * TAR_BLOCK_SIZE);
533 astreamer_content(streamer->bbs_next, NULL, buffer,
535 astreamer_finalize(streamer->bbs_next);
536}

References astreamer_content(), astreamer_finalize(), ASTREAMER_UNKNOWN, astreamer::bbs_next, fb(), and TAR_BLOCK_SIZE.

◆ astreamer_tar_terminator_free()

static void astreamer_tar_terminator_free ( astreamer streamer)
static

Definition at line 542 of file astreamer_tar.c.

543{
544 astreamer_free(streamer->bbs_next);
545 pfree(streamer);
546}

References astreamer_free(), astreamer::bbs_next, and pfree().

◆ astreamer_tar_terminator_new()

astreamer * astreamer_tar_terminator_new ( astreamer next)

Definition at line 494 of file astreamer_tar.c.

495{
496 astreamer *streamer;
497
498 streamer = palloc0_object(astreamer);
499 *((const astreamer_ops **) &streamer->bbs_ops) =
501 streamer->bbs_next = next;
502
503 return streamer;
504}
static const astreamer_ops astreamer_tar_terminator_ops

References astreamer_tar_terminator_ops, astreamer::bbs_next, astreamer::bbs_ops, next, and palloc0_object.

Referenced by CreateBackupStreamer().

Variable Documentation

◆ astreamer_tar_archiver_ops

const astreamer_ops astreamer_tar_archiver_ops
static
Initial value:
= {
}
static void astreamer_tar_archiver_free(astreamer *streamer)
static void astreamer_tar_archiver_finalize(astreamer *streamer)
static void astreamer_tar_archiver_content(astreamer *streamer, astreamer_member *member, const char *data, int len, astreamer_archive_context context)

Definition at line 66 of file astreamer_tar.c.

Referenced by astreamer_tar_archiver_new().

◆ astreamer_tar_parser_ops

const astreamer_ops astreamer_tar_parser_ops
static
Initial value:
= {
}
static void astreamer_tar_parser_content(astreamer *streamer, astreamer_member *member, const char *data, int len, astreamer_archive_context context)
static void astreamer_tar_parser_finalize(astreamer *streamer)
static void astreamer_tar_parser_free(astreamer *streamer)

Definition at line 53 of file astreamer_tar.c.

53 {
57};

Referenced by astreamer_tar_parser_new().

◆ astreamer_tar_terminator_ops

const astreamer_ops astreamer_tar_terminator_ops
static
Initial value:
= {
}
static void astreamer_tar_terminator_content(astreamer *streamer, astreamer_member *member, const char *data, int len, astreamer_archive_context context)
static void astreamer_tar_terminator_free(astreamer *streamer)
static void astreamer_tar_terminator_finalize(astreamer *streamer)

Definition at line 79 of file astreamer_tar.c.

Referenced by astreamer_tar_terminator_new().