Age Owner TLA Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * pg_backup_tar.c
4 : *
5 : * This file is copied from the 'files' format file, but dumps data into
6 : * one temp file then sends it to the output TAR archive.
7 : *
8 : * The tar format also includes a 'restore.sql' script which is there for
9 : * the benefit of humans. This script is never used by pg_restore.
10 : *
11 : * NOTE: If you untar the created 'tar' file, the resulting files are
12 : * compatible with the 'directory' format. Please keep the two formats in
13 : * sync.
14 : *
15 : * See the headers to pg_backup_directory & pg_restore for more details.
16 : *
17 : * Copyright (c) 2000, Philip Warner
18 : * Rights are granted to use this software in any way so long
19 : * as this notice is not removed.
20 : *
21 : * The author is not responsible for loss or damages that may
22 : * result from its use.
23 : *
24 : *
25 : * IDENTIFICATION
26 : * src/bin/pg_dump/pg_backup_tar.c
27 : *
28 : *-------------------------------------------------------------------------
29 : */
30 : #include "postgres_fe.h"
31 :
32 : #include <sys/stat.h>
33 : #include <ctype.h>
34 : #include <limits.h>
35 : #include <unistd.h>
36 :
37 : #include "common/file_utils.h"
38 : #include "fe_utils/string_utils.h"
39 : #include "pg_backup_archiver.h"
40 : #include "pg_backup_tar.h"
41 : #include "pg_backup_utils.h"
42 : #include "pgtar.h"
43 :
44 : static void _ArchiveEntry(ArchiveHandle *AH, TocEntry *te);
45 : static void _StartData(ArchiveHandle *AH, TocEntry *te);
46 : static void _WriteData(ArchiveHandle *AH, const void *data, size_t dLen);
47 : static void _EndData(ArchiveHandle *AH, TocEntry *te);
48 : static int _WriteByte(ArchiveHandle *AH, const int i);
49 : static int _ReadByte(ArchiveHandle *AH);
50 : static void _WriteBuf(ArchiveHandle *AH, const void *buf, size_t len);
51 : static void _ReadBuf(ArchiveHandle *AH, void *buf, size_t len);
52 : static void _CloseArchive(ArchiveHandle *AH);
53 : static void _PrintTocData(ArchiveHandle *AH, TocEntry *te);
54 : static void _WriteExtraToc(ArchiveHandle *AH, TocEntry *te);
55 : static void _ReadExtraToc(ArchiveHandle *AH, TocEntry *te);
56 : static void _PrintExtraToc(ArchiveHandle *AH, TocEntry *te);
57 :
58 : static void _StartLOs(ArchiveHandle *AH, TocEntry *te);
59 : static void _StartLO(ArchiveHandle *AH, TocEntry *te, Oid oid);
60 : static void _EndLO(ArchiveHandle *AH, TocEntry *te, Oid oid);
61 : static void _EndLOs(ArchiveHandle *AH, TocEntry *te);
62 :
63 : #define K_STD_BUF_SIZE 1024
64 :
65 :
66 : typedef struct
67 : {
68 : FILE *nFH;
69 : FILE *tarFH;
70 : FILE *tmpFH;
71 : char *targetFile;
72 : char mode;
73 : pgoff_t pos;
74 : pgoff_t fileLen;
75 : ArchiveHandle *AH;
76 : } TAR_MEMBER;
77 :
78 : typedef struct
79 : {
80 : int hasSeek;
81 : pgoff_t filePos;
82 : TAR_MEMBER *loToc;
83 : FILE *tarFH;
84 : pgoff_t tarFHpos;
85 : pgoff_t tarNextMember;
86 : TAR_MEMBER *FH;
87 : int isSpecialScript;
88 : TAR_MEMBER *scriptTH;
89 : } lclContext;
90 :
91 : typedef struct
92 : {
93 : TAR_MEMBER *TH;
94 : char *filename;
95 : } lclTocEntry;
96 :
97 : static void _LoadLOs(ArchiveHandle *AH);
98 :
99 : static TAR_MEMBER *tarOpen(ArchiveHandle *AH, const char *filename, char mode);
100 : static void tarClose(ArchiveHandle *AH, TAR_MEMBER *th);
101 :
102 : #ifdef __NOT_USED__
103 : static char *tarGets(char *buf, size_t len, TAR_MEMBER *th);
104 : #endif
105 : static int tarPrintf(TAR_MEMBER *th, const char *fmt,...) pg_attribute_printf(2, 3);
106 :
107 : static void _tarAddFile(ArchiveHandle *AH, TAR_MEMBER *th);
108 : static TAR_MEMBER *_tarPositionTo(ArchiveHandle *AH, const char *filename);
109 : static size_t tarRead(void *buf, size_t len, TAR_MEMBER *th);
110 : static size_t tarWrite(const void *buf, size_t len, TAR_MEMBER *th);
111 : static void _tarWriteHeader(TAR_MEMBER *th);
112 : static int _tarGetHeader(ArchiveHandle *AH, TAR_MEMBER *th);
113 : static size_t _tarReadRaw(ArchiveHandle *AH, void *buf, size_t len, TAR_MEMBER *th, FILE *fh);
114 :
115 : static size_t _scriptOut(ArchiveHandle *AH, const void *buf, size_t len);
116 :
117 : /*
118 : * Initializer
119 : */
120 : void
8053 bruce 121 CBC 5 : InitArchiveFmt_Tar(ArchiveHandle *AH)
122 : {
123 : lclContext *ctx;
124 :
125 : /* Assuming static functions, this can be copied for each format. */
126 5 : AH->ArchiveEntryPtr = _ArchiveEntry;
127 5 : AH->StartDataPtr = _StartData;
128 5 : AH->WriteDataPtr = _WriteData;
129 5 : AH->EndDataPtr = _EndData;
130 5 : AH->WriteBytePtr = _WriteByte;
131 5 : AH->ReadBytePtr = _ReadByte;
132 5 : AH->WriteBufPtr = _WriteBuf;
133 5 : AH->ReadBufPtr = _ReadBuf;
134 5 : AH->ClosePtr = _CloseArchive;
5179 andrew 135 5 : AH->ReopenPtr = NULL;
8053 bruce 136 5 : AH->PrintTocDataPtr = _PrintTocData;
137 5 : AH->ReadExtraTocPtr = _ReadExtraToc;
138 5 : AH->WriteExtraTocPtr = _WriteExtraToc;
139 5 : AH->PrintExtraTocPtr = _PrintExtraToc;
140 :
125 peter 141 GNC 5 : AH->StartLOsPtr = _StartLOs;
142 5 : AH->StartLOPtr = _StartLO;
143 5 : AH->EndLOPtr = _EndLO;
144 5 : AH->EndLOsPtr = _EndLOs;
5179 andrew 145 CBC 5 : AH->ClonePtr = NULL;
146 5 : AH->DeClonePtr = NULL;
147 :
3668 148 5 : AH->WorkerJobDumpPtr = NULL;
149 5 : AH->WorkerJobRestorePtr = NULL;
150 :
151 : /*
152 : * Set up some special context used in compressing data.
153 : */
209 peter 154 GNC 5 : ctx = pg_malloc0_object(lclContext);
8053 bruce 155 CBC 5 : AH->formatData = (void *) ctx;
156 5 : ctx->filePos = 0;
7123 157 5 : ctx->isSpecialScript = 0;
158 :
159 : /* Initialize LO buffering */
7655 160 5 : AH->lo_buf_size = LOBBUFSIZE;
4153 161 5 : AH->lo_buf = (void *) pg_malloc(LOBBUFSIZE);
162 :
163 : /*
164 : * Now open the tar file, and load the TOC if we're in read mode.
165 : */
8053 166 5 : if (AH->mode == archModeWrite)
167 : {
168 3 : if (AH->fSpec && strcmp(AH->fSpec, "") != 0)
169 : {
8297 pjw 170 2 : ctx->tarFH = fopen(AH->fSpec, PG_BINARY_W);
5642 tgl 171 2 : if (ctx->tarFH == NULL)
366 tgl 172 UBC 0 : pg_fatal("could not open TOC file \"%s\" for output: %m",
173 : AH->fSpec);
174 : }
175 : else
176 : {
8297 pjw 177 CBC 1 : ctx->tarFH = stdout;
5642 tgl 178 1 : if (ctx->tarFH == NULL)
366 tgl 179 UBC 0 : pg_fatal("could not open TOC file for output: %m");
180 : }
181 :
8297 pjw 182 CBC 3 : ctx->tarFHpos = 0;
183 :
184 : /*
185 : * Make unbuffered since we will dup() it, and the buffers screw each
186 : * other
187 : */
188 : /* setvbuf(ctx->tarFH, NULL, _IONBF, 0); */
189 :
7471 bruce 190 3 : ctx->hasSeek = checkSeek(ctx->tarFH);
191 :
192 : /*
193 : * We don't support compression because reading the files back is not
194 : * possible since gzdopen uses buffered IO which totally screws file
195 : * positioning.
196 : */
128 michael 197 GNC 3 : if (AH->compression_spec.algorithm != PG_COMPRESSION_NONE)
366 tgl 198 CBC 1 : pg_fatal("compression is not supported by tar archive format");
199 : }
200 : else
201 : { /* Read Mode */
8053 bruce 202 2 : if (AH->fSpec && strcmp(AH->fSpec, "") != 0)
203 : {
8297 pjw 204 2 : ctx->tarFH = fopen(AH->fSpec, PG_BINARY_R);
5642 tgl 205 2 : if (ctx->tarFH == NULL)
366 tgl 206 UBC 0 : pg_fatal("could not open TOC file \"%s\" for input: %m",
207 : AH->fSpec);
208 : }
209 : else
210 : {
8297 pjw 211 0 : ctx->tarFH = stdin;
5642 tgl 212 0 : if (ctx->tarFH == NULL)
366 213 0 : pg_fatal("could not open TOC file for input: %m");
214 : }
215 :
216 : /*
217 : * Make unbuffered since we will dup() it, and the buffers screw each
218 : * other
219 : */
220 : /* setvbuf(ctx->tarFH, NULL, _IONBF, 0); */
221 :
8297 pjw 222 CBC 2 : ctx->tarFHpos = 0;
223 :
7471 bruce 224 2 : ctx->hasSeek = checkSeek(ctx->tarFH);
225 :
8053 226 2 : ctx->FH = (void *) tarOpen(AH, "toc.dat", 'r');
8297 pjw 227 2 : ReadHead(AH);
228 2 : ReadToc(AH);
8053 bruce 229 2 : tarClose(AH, ctx->FH); /* Nothing else in the file... */
230 : }
8297 pjw 231 4 : }
232 :
233 : /*
234 : * - Start a new TOC entry
235 : * Setup the output file name.
236 : */
237 : static void
8053 bruce 238 282 : _ArchiveEntry(ArchiveHandle *AH, TocEntry *te)
239 : {
240 : lclTocEntry *ctx;
241 : char fn[K_STD_BUF_SIZE];
242 :
209 peter 243 GNC 282 : ctx = pg_malloc0_object(lclTocEntry);
8030 pjw 244 CBC 282 : if (te->dataDumper != NULL)
245 : {
374 michael 246 28 : snprintf(fn, sizeof(fn), "%d.dat", te->dumpId);
4153 bruce 247 28 : ctx->filename = pg_strdup(fn);
248 : }
249 : else
250 : {
8297 pjw 251 254 : ctx->filename = NULL;
252 254 : ctx->TH = NULL;
253 : }
8053 bruce 254 282 : te->formatData = (void *) ctx;
8297 pjw 255 282 : }
256 :
257 : static void
8053 bruce 258 282 : _WriteExtraToc(ArchiveHandle *AH, TocEntry *te)
259 : {
260 282 : lclTocEntry *ctx = (lclTocEntry *) te->formatData;
261 :
262 282 : if (ctx->filename)
8297 pjw 263 28 : WriteStr(AH, ctx->filename);
264 : else
265 254 : WriteStr(AH, "");
266 282 : }
267 :
268 : static void
8053 bruce 269 282 : _ReadExtraToc(ArchiveHandle *AH, TocEntry *te)
270 : {
271 282 : lclTocEntry *ctx = (lclTocEntry *) te->formatData;
272 :
273 282 : if (ctx == NULL)
274 : {
209 peter 275 GNC 282 : ctx = pg_malloc0_object(lclTocEntry);
8053 bruce 276 CBC 282 : te->formatData = (void *) ctx;
277 : }
278 :
279 282 : ctx->filename = ReadStr(AH);
280 282 : if (strlen(ctx->filename) == 0)
281 : {
8297 pjw 282 254 : free(ctx->filename);
283 254 : ctx->filename = NULL;
284 : }
8053 bruce 285 282 : ctx->TH = NULL;
8297 pjw 286 282 : }
287 :
288 : static void
8053 bruce 289 548 : _PrintExtraToc(ArchiveHandle *AH, TocEntry *te)
290 : {
291 548 : lclTocEntry *ctx = (lclTocEntry *) te->formatData;
292 :
6976 tgl 293 548 : if (AH->public.verbose && ctx->filename != NULL)
8030 pjw 294 UBC 0 : ahprintf(AH, "-- File: %s\n", ctx->filename);
8297 pjw 295 CBC 548 : }
296 :
297 : static void
8053 bruce 298 27 : _StartData(ArchiveHandle *AH, TocEntry *te)
299 : {
300 27 : lclTocEntry *tctx = (lclTocEntry *) te->formatData;
301 :
8297 pjw 302 27 : tctx->TH = tarOpen(AH, tctx->filename, 'w');
303 27 : }
304 :
305 : static TAR_MEMBER *
8053 bruce 306 66 : tarOpen(ArchiveHandle *AH, const char *filename, char mode)
307 : {
308 66 : lclContext *ctx = (lclContext *) AH->formatData;
309 : TAR_MEMBER *tm;
310 :
8297 pjw 311 66 : if (mode == 'r')
312 : {
313 32 : tm = _tarPositionTo(AH, filename);
8053 bruce 314 32 : if (!tm) /* Not found */
315 : {
4793 tgl 316 UBC 0 : if (filename)
317 : {
318 : /*
319 : * Couldn't find the requested file. Future: do SEEK(0) and
320 : * retry.
321 : */
366 322 0 : pg_fatal("could not find file \"%s\" in archive", filename);
323 : }
324 : else
325 : {
326 : /* Any file OK, none left, so return NULL */
8297 pjw 327 0 : return NULL;
328 : }
329 : }
330 :
128 michael 331 GNC 32 : if (AH->compression_spec.algorithm == PG_COMPRESSION_NONE)
8297 pjw 332 CBC 32 : tm->nFH = ctx->tarFH;
333 : else
366 tgl 334 UBC 0 : pg_fatal("compression is not supported by tar archive format");
335 : }
336 : else
337 : {
338 : int old_umask;
339 :
209 peter 340 GNC 34 : tm = pg_malloc0_object(TAR_MEMBER);
341 :
342 : /*
343 : * POSIX does not require, but permits, tmpfile() to restrict file
344 : * permissions. Given an OS crash after we write data, the filesystem
345 : * might retain the data but forget tmpfile()'s unlink(). If so, the
346 : * file mode protects confidentiality of the data written.
347 : */
2758 noah 348 CBC 34 : old_umask = umask(S_IRWXG | S_IRWXO);
349 :
350 : #ifndef WIN32
8297 pjw 351 34 : tm->tmpFH = tmpfile();
352 : #else
353 :
354 : /*
355 : * On WIN32, tmpfile() generates a filename in the root directory,
356 : * which requires administrative permissions on certain systems. Loop
357 : * until we find a unique file name we can create.
358 : */
359 : while (1)
360 : {
361 : char *name;
362 : int fd;
363 :
364 : name = _tempnam(NULL, "pg_temp_");
365 : if (name == NULL)
366 : break;
367 : fd = open(name, O_RDWR | O_CREAT | O_EXCL | O_BINARY |
368 : O_TEMPORARY, S_IRUSR | S_IWUSR);
369 : free(name);
370 :
371 : if (fd != -1) /* created a file */
372 : {
373 : tm->tmpFH = fdopen(fd, "w+b");
374 : break;
375 : }
376 : else if (errno != EEXIST) /* failure other than file exists */
377 : break;
378 : }
379 : #endif
380 :
8053 bruce 381 34 : if (tm->tmpFH == NULL)
366 tgl 382 UBC 0 : pg_fatal("could not generate temporary file name: %m");
383 :
2758 noah 384 CBC 34 : umask(old_umask);
385 :
128 michael 386 GNC 34 : if (AH->compression_spec.algorithm == PG_COMPRESSION_NONE)
8297 pjw 387 CBC 34 : tm->nFH = tm->tmpFH;
388 : else
366 tgl 389 UBC 0 : pg_fatal("compression is not supported by tar archive format");
390 :
8297 pjw 391 CBC 34 : tm->AH = AH;
4153 bruce 392 34 : tm->targetFile = pg_strdup(filename);
393 : }
394 :
8297 pjw 395 66 : tm->mode = mode;
396 66 : tm->tarFH = ctx->tarFH;
397 :
398 66 : return tm;
399 : }
400 :
401 : static void
8053 bruce 402 66 : tarClose(ArchiveHandle *AH, TAR_MEMBER *th)
403 : {
128 michael 404 GNC 66 : if (AH->compression_spec.algorithm != PG_COMPRESSION_NONE)
366 tgl 405 UBC 0 : pg_fatal("compression is not supported by tar archive format");
406 :
8297 pjw 407 CBC 66 : if (th->mode == 'w')
8053 bruce 408 34 : _tarAddFile(AH, th); /* This will close the temp file */
409 :
410 : /*
411 : * else Nothing to do for normal read since we don't dup() normal file
412 : * handle, and we don't use temp files.
413 : */
414 :
297 peter 415 GNC 66 : free(th->targetFile);
8297 pjw 416 ECB :
8297 pjw 417 CBC 66 : th->nFH = NULL;
8297 pjw 418 GIC 66 : }
419 :
420 : #ifdef __NOT_USED__
421 : static char *
422 : tarGets(char *buf, size_t len, TAR_MEMBER *th)
423 : {
424 : char *s;
425 : size_t cnt = 0;
426 : char c = ' ';
427 : int eof = 0;
428 :
429 : /* Can't read past logical EOF */
430 : if (len > (th->fileLen - th->pos))
431 : len = th->fileLen - th->pos;
432 :
433 : while (cnt < len && c != '\n')
434 : {
435 : if (_tarReadRaw(th->AH, &c, 1, th, NULL) <= 0)
436 : {
437 : eof = 1;
438 : break;
439 : }
440 : buf[cnt++] = c;
441 : }
442 :
443 : if (eof && cnt == 0)
444 : s = NULL;
445 : else
446 : {
447 : buf[cnt++] = '\0';
448 : s = buf;
449 : }
450 :
451 : if (s)
452 : {
453 : len = strlen(s);
454 : th->pos += len;
455 : }
456 :
457 : return s;
458 : }
459 : #endif
460 :
461 : /*
462 : * Just read bytes from the archive. This is the low level read routine
463 : * that is used for ALL reads on a tar file.
464 : */
7537 peter_e 465 ECB : static size_t
7537 peter_e 466 GIC 42871 : _tarReadRaw(ArchiveHandle *AH, void *buf, size_t len, TAR_MEMBER *th, FILE *fh)
8297 pjw 467 ECB : {
8053 bruce 468 GIC 42871 : lclContext *ctx = (lclContext *) AH->formatData;
7537 peter_e 469 ECB : size_t avail;
7537 peter_e 470 CBC 42871 : size_t used = 0;
7537 peter_e 471 GIC 42871 : size_t res = 0;
8297 pjw 472 ECB :
1077 peter 473 GIC 42871 : Assert(th || fh);
1077 peter 474 ECB :
8297 pjw 475 CBC 42871 : avail = AH->lookaheadLen - AH->lookaheadPos;
8297 pjw 476 GIC 42871 : if (avail > 0)
477 : {
8297 pjw 478 EUB : /* We have some lookahead bytes to use */
8053 bruce 479 UBC 0 : if (avail >= len) /* Just use the lookahead buffer */
8297 pjw 480 UIC 0 : used = len;
8297 pjw 481 EUB : else
8297 pjw 482 UIC 0 : used = avail;
483 :
8297 pjw 484 EUB : /* Copy, and adjust buffer pos */
5725 tgl 485 UBC 0 : memcpy(buf, AH->lookahead + AH->lookaheadPos, used);
8297 pjw 486 UIC 0 : AH->lookaheadPos += used;
487 :
8297 pjw 488 EUB : /* Adjust required length */
8297 pjw 489 UIC 0 : len -= used;
490 : }
491 :
8297 pjw 492 ECB : /* Read the file if len > 0 */
8297 pjw 493 GIC 42871 : if (len > 0)
8297 pjw 494 ECB : {
8297 pjw 495 GIC 42871 : if (fh)
3261 bruce 496 ECB : {
8053 bruce 497 CBC 13763 : res = fread(&((char *) buf)[used], 1, len, fh);
3261 bruce 498 GBC 13763 : if (res != len && !feof(fh))
3261 bruce 499 UIC 0 : READ_ERROR_EXIT(fh);
3261 bruce 500 ECB : }
8297 pjw 501 GIC 29108 : else if (th)
8297 pjw 502 ECB : {
374 michael 503 CBC 29108 : res = fread(&((char *) buf)[used], 1, len, th->nFH);
374 michael 504 GBC 29108 : if (res != len && !feof(th->nFH))
374 michael 505 UIC 0 : READ_ERROR_EXIT(th->nFH);
506 : }
507 : }
8297 pjw 508 ECB :
8297 pjw 509 GIC 42871 : ctx->tarFHpos += res + used;
8297 pjw 510 ECB :
8297 pjw 511 GIC 42871 : return (res + used);
512 : }
513 :
7537 peter_e 514 ECB : static size_t
7537 peter_e 515 GIC 29451 : tarRead(void *buf, size_t len, TAR_MEMBER *th)
516 : {
517 : size_t res;
8297 pjw 518 ECB :
8297 pjw 519 CBC 29451 : if (th->pos + len > th->fileLen)
8297 pjw 520 GIC 57 : len = th->fileLen - th->pos;
8297 pjw 521 ECB :
8297 pjw 522 CBC 29451 : if (len <= 0)
8297 pjw 523 GIC 343 : return 0;
8297 pjw 524 ECB :
8297 pjw 525 GIC 29108 : res = _tarReadRaw(th->AH, buf, len, th, NULL);
8297 pjw 526 ECB :
8297 pjw 527 GIC 29108 : th->pos += res;
8297 pjw 528 ECB :
8297 pjw 529 GIC 29108 : return res;
530 : }
531 :
7537 peter_e 532 ECB : static size_t
7537 peter_e 533 GIC 31071 : tarWrite(const void *buf, size_t len, TAR_MEMBER *th)
534 : {
535 : size_t res;
8297 pjw 536 ECB :
374 michael 537 GIC 31071 : res = fwrite(buf, 1, len, th->nFH);
8297 pjw 538 ECB :
8297 pjw 539 CBC 31071 : th->pos += res;
8297 pjw 540 GIC 31071 : return res;
541 : }
542 :
3261 bruce 543 ECB : static void
7537 peter_e 544 GIC 59 : _WriteData(ArchiveHandle *AH, const void *data, size_t dLen)
8297 pjw 545 ECB : {
8053 bruce 546 GIC 59 : lclTocEntry *tctx = (lclTocEntry *) AH->currToc->formatData;
8297 pjw 547 ECB :
3261 bruce 548 GBC 59 : if (tarWrite(data, dLen, tctx->TH) != dLen)
3261 bruce 549 LBC 0 : WRITE_ERROR_EXIT;
8297 pjw 550 GIC 59 : }
551 :
8053 bruce 552 ECB : static void
8053 bruce 553 GIC 27 : _EndData(ArchiveHandle *AH, TocEntry *te)
8297 pjw 554 ECB : {
8053 bruce 555 GIC 27 : lclTocEntry *tctx = (lclTocEntry *) te->formatData;
556 :
8053 bruce 557 ECB : /* Close the file */
8053 bruce 558 CBC 27 : tarClose(AH, tctx->TH);
559 27 : tctx->TH = NULL;
8297 pjw 560 GIC 27 : }
561 :
562 : /*
563 : * Print data for a given file
564 : */
8053 bruce 565 ECB : static void
2643 tgl 566 GIC 27 : _PrintFileData(ArchiveHandle *AH, char *filename)
8297 pjw 567 ECB : {
8053 bruce 568 GIC 27 : lclContext *ctx = (lclContext *) AH->formatData;
569 : char buf[4096];
570 : size_t cnt;
571 : TAR_MEMBER *th;
8297 pjw 572 ECB :
8053 bruce 573 GBC 27 : if (!filename)
8297 pjw 574 UIC 0 : return;
8297 pjw 575 ECB :
8297 pjw 576 CBC 27 : th = tarOpen(AH, filename, 'r');
8297 pjw 577 GIC 27 : ctx->FH = th;
8297 pjw 578 ECB :
8053 bruce 579 GIC 54 : while ((cnt = tarRead(buf, 4095, th)) > 0)
8053 bruce 580 ECB : {
8297 pjw 581 CBC 27 : buf[cnt] = '\0';
8297 pjw 582 GIC 27 : ahwrite(buf, 1, cnt, AH);
583 : }
8297 pjw 584 ECB :
8053 bruce 585 GIC 27 : tarClose(AH, th);
586 : }
587 :
588 :
589 : /*
590 : * Print data for a given TOC entry
591 : */
8053 bruce 592 ECB : static void
2643 tgl 593 GIC 56 : _PrintTocData(ArchiveHandle *AH, TocEntry *te)
8297 pjw 594 ECB : {
8053 bruce 595 CBC 56 : lclContext *ctx = (lclContext *) AH->formatData;
8053 bruce 596 GIC 56 : lclTocEntry *tctx = (lclTocEntry *) te->formatData;
597 : int pos1;
8053 bruce 598 ECB :
8053 bruce 599 GBC 56 : if (!tctx->filename)
8297 pjw 600 UIC 0 : return;
601 :
602 : /*
603 : * If we're writing the special restore.sql script, emit a suitable
604 : * command to include each table's data from the corresponding file.
605 : *
606 : * In the COPY case this is a bit klugy because the regular COPY command
607 : * was already printed before we get control.
3844 tgl 608 ECB : */
8297 pjw 609 GIC 56 : if (ctx->isSpecialScript)
8297 pjw 610 ECB : {
3844 tgl 611 GIC 28 : if (te->copyStmt)
612 : {
3844 tgl 613 ECB : /* Abort the COPY FROM stdin */
3844 tgl 614 GIC 27 : ahprintf(AH, "\\.\n");
615 :
616 : /*
617 : * The COPY statement should look like "COPY ... FROM stdin;\n",
618 : * see dumpTableData().
3844 tgl 619 ECB : */
3844 tgl 620 CBC 27 : pos1 = (int) strlen(te->copyStmt) - 13;
621 27 : if (pos1 < 6 || strncmp(te->copyStmt, "COPY ", 5) != 0 ||
3844 tgl 622 GBC 27 : strcmp(te->copyStmt + pos1, " FROM stdin;\n") != 0)
366 tgl 623 UIC 0 : pg_fatal("unexpected COPY statement syntax: \"%s\"",
624 : te->copyStmt);
625 :
3844 tgl 626 ECB : /* Emit all but the FROM part ... */
3844 tgl 627 GIC 27 : ahwrite(te->copyStmt, 1, pos1, AH);
3844 tgl 628 ECB : /* ... and insert modified FROM */
3844 tgl 629 GIC 27 : ahprintf(AH, " FROM '$$PATH$$/%s';\n\n", tctx->filename);
630 : }
631 : else
632 : {
3844 tgl 633 ECB : /* --inserts mode, no worries, just include the data file */
3844 tgl 634 GIC 1 : ahprintf(AH, "\\i $$PATH$$/%s\n\n", tctx->filename);
635 : }
8297 pjw 636 ECB :
8297 pjw 637 GIC 28 : return;
638 : }
8297 pjw 639 ECB :
8297 pjw 640 CBC 28 : if (strcmp(te->desc, "BLOBS") == 0)
125 peter 641 GNC 1 : _LoadLOs(AH);
8297 pjw 642 ECB : else
2643 tgl 643 GIC 27 : _PrintFileData(AH, tctx->filename);
644 : }
645 :
8053 bruce 646 ECB : static void
125 peter 647 GNC 1 : _LoadLOs(ArchiveHandle *AH)
648 : {
7950 peter_e 649 ECB : Oid oid;
8053 bruce 650 GIC 1 : lclContext *ctx = (lclContext *) AH->formatData;
651 : TAR_MEMBER *th;
7537 peter_e 652 ECB : size_t cnt;
125 peter 653 GNC 1 : bool foundLO = false;
654 : char buf[4096];
8297 pjw 655 ECB :
125 peter 656 GNC 1 : StartRestoreLOs(AH);
8195 pjw 657 ECB :
7833 bruce 658 CBC 1 : th = tarOpen(AH, NULL, 'r'); /* Open next file */
8297 pjw 659 GIC 3 : while (th != NULL)
8297 pjw 660 ECB : {
8297 pjw 661 GIC 3 : ctx->FH = th;
8297 pjw 662 ECB :
7620 tgl 663 GIC 3 : if (strncmp(th->targetFile, "blob_", 5) == 0)
8297 pjw 664 ECB : {
7620 tgl 665 CBC 2 : oid = atooid(&th->targetFile[5]);
7620 tgl 666 GIC 2 : if (oid != 0)
7620 tgl 667 ECB : {
1469 peter 668 GIC 2 : pg_log_info("restoring large object with OID %u", oid);
8297 pjw 669 ECB :
125 peter 670 GNC 2 : StartRestoreLO(AH, oid, AH->public.ropt->dropSchema);
8297 pjw 671 ECB :
7620 tgl 672 GIC 3 : while ((cnt = tarRead(buf, 4095, th)) > 0)
7620 tgl 673 ECB : {
7620 tgl 674 CBC 1 : buf[cnt] = '\0';
7620 tgl 675 GIC 1 : ahwrite(buf, 1, cnt, AH);
7620 tgl 676 ECB : }
125 peter 677 GNC 2 : EndRestoreLO(AH, oid);
678 2 : foundLO = true;
8297 pjw 679 ECB : }
6003 tgl 680 GIC 2 : tarClose(AH, th);
681 : }
682 : else
6003 tgl 683 ECB : {
6003 tgl 684 GIC 1 : tarClose(AH, th);
685 :
686 : /*
687 : * Once we have found the first LO, stop at the first non-LO
688 : * entry (which will be 'blobs.toc'). This coding would eat all
689 : * the rest of the archive if there are no LOs ... but this
690 : * function shouldn't be called at all in that case.
6003 tgl 691 ECB : */
125 peter 692 GNC 1 : if (foundLO)
6003 tgl 693 GIC 1 : break;
694 : }
8297 pjw 695 ECB :
8297 pjw 696 GIC 2 : th = tarOpen(AH, NULL, 'r');
8297 pjw 697 ECB : }
125 peter 698 GNC 1 : EndRestoreLOs(AH);
8297 pjw 699 GIC 1 : }
700 :
701 :
8053 bruce 702 ECB : static int
8053 bruce 703 GIC 26259 : _WriteByte(ArchiveHandle *AH, const int i)
8297 pjw 704 ECB : {
8053 bruce 705 CBC 26259 : lclContext *ctx = (lclContext *) AH->formatData;
8053 bruce 706 GIC 26259 : char b = i; /* Avoid endian problems */
8297 pjw 707 ECB :
3261 bruce 708 GBC 26259 : if (tarWrite(&b, 1, ctx->FH) != 1)
3261 bruce 709 UIC 0 : WRITE_ERROR_EXIT;
3261 bruce 710 ECB :
3261 bruce 711 CBC 26259 : ctx->filePos += 1;
3261 bruce 712 GIC 26259 : return 1;
713 : }
714 :
8053 bruce 715 ECB : static int
8053 bruce 716 GIC 26259 : _ReadByte(ArchiveHandle *AH)
8297 pjw 717 ECB : {
8053 bruce 718 GIC 26259 : lclContext *ctx = (lclContext *) AH->formatData;
719 : size_t res;
720 : unsigned char c;
8297 pjw 721 ECB :
8053 bruce 722 CBC 26259 : res = tarRead(&c, 1, ctx->FH);
5725 tgl 723 GIC 26259 : if (res != 1)
3261 bruce 724 EUB : /* We already would have exited for errors on reads, must be EOF */
366 tgl 725 LBC 0 : pg_fatal("could not read from input file: end of file");
5725 tgl 726 CBC 26259 : ctx->filePos += 1;
8053 bruce 727 GIC 26259 : return c;
728 : }
729 :
3261 bruce 730 ECB : static void
7537 peter_e 731 GIC 3135 : _WriteBuf(ArchiveHandle *AH, const void *buf, size_t len)
8297 pjw 732 ECB : {
8053 bruce 733 GIC 3135 : lclContext *ctx = (lclContext *) AH->formatData;
8297 pjw 734 ECB :
3261 bruce 735 GBC 3135 : if (tarWrite(buf, len, ctx->FH) != len)
3261 bruce 736 UIC 0 : WRITE_ERROR_EXIT;
3261 bruce 737 ECB :
3261 bruce 738 CBC 3135 : ctx->filePos += len;
8297 pjw 739 GIC 3135 : }
740 :
3261 bruce 741 ECB : static void
7537 peter_e 742 GIC 3135 : _ReadBuf(ArchiveHandle *AH, void *buf, size_t len)
8297 pjw 743 ECB : {
8053 bruce 744 GIC 3135 : lclContext *ctx = (lclContext *) AH->formatData;
8297 pjw 745 ECB :
3261 bruce 746 GIC 3135 : if (tarRead(buf, len, ctx->FH) != len)
3261 bruce 747 EUB : /* We already would have exited for errors on reads, must be EOF */
366 tgl 748 UIC 0 : pg_fatal("could not read from input file: end of file");
3260 bruce 749 ECB :
3261 bruce 750 CBC 3135 : ctx->filePos += len;
8297 pjw 751 GIC 3135 : }
752 :
8053 bruce 753 ECB : static void
2643 tgl 754 GIC 4 : _CloseArchive(ArchiveHandle *AH)
8297 pjw 755 ECB : {
8053 bruce 756 GIC 4 : lclContext *ctx = (lclContext *) AH->formatData;
757 : TAR_MEMBER *th;
758 : RestoreOptions *ropt;
759 : RestoreOptions *savRopt;
760 : DumpOptions *savDopt;
761 : int savVerbose,
762 : i;
8297 pjw 763 ECB :
8053 bruce 764 GIC 4 : if (AH->mode == archModeWrite)
765 : {
766 : /*
767 : * Write the Header & TOC to the archive FIRST
8297 pjw 768 ECB : */
8297 pjw 769 CBC 2 : th = tarOpen(AH, "toc.dat", 'w');
770 2 : ctx->FH = th;
771 2 : WriteHead(AH);
772 2 : WriteToc(AH);
8053 bruce 773 GIC 2 : tarClose(AH, th); /* Not needed any more */
774 :
775 : /*
776 : * Now send the data (tables & LOs)
8297 pjw 777 ECB : */
2643 tgl 778 GIC 2 : WriteDataChunks(AH, NULL);
779 :
780 : /*
781 : * Now this format wants to append a script which does a full restore
782 : * if the files have been extracted.
8297 pjw 783 ECB : */
8297 pjw 784 GIC 2 : th = tarOpen(AH, "restore.sql", 'w');
3844 tgl 785 ECB :
957 peter 786 GIC 2 : tarPrintf(th, "--\n"
787 : "-- NOTE:\n"
788 : "--\n"
789 : "-- File paths need to be edited. Search for $$PATH$$ and\n"
790 : "-- replace it with the path to the directory containing\n"
791 : "-- the extracted data files.\n"
792 : "--\n");
8297 pjw 793 ECB :
8297 pjw 794 GIC 2 : AH->CustomOutPtr = _scriptOut;
8053 bruce 795 ECB :
8297 pjw 796 CBC 2 : ctx->isSpecialScript = 1;
8297 pjw 797 GIC 2 : ctx->scriptTH = th;
8297 pjw 798 ECB :
8297 pjw 799 CBC 2 : ropt = NewRestoreOptions();
2643 tgl 800 2 : memcpy(ropt, AH->public.ropt, sizeof(RestoreOptions));
3954 801 2 : ropt->filename = NULL;
8297 pjw 802 2 : ropt->dropSchema = 1;
7639 tgl 803 GIC 2 : ropt->superuser = NULL;
8019 pjw 804 CBC 2 : ropt->suppressDumpWarnings = true;
8297 pjw 805 ECB :
2643 tgl 806 GIC 2 : savDopt = AH->public.dopt;
2643 tgl 807 CBC 2 : savRopt = AH->public.ropt;
808 :
809 2 : SetArchiveOptions((Archive *) AH, NULL, ropt);
3967 tgl 810 ECB :
8297 pjw 811 GIC 2 : savVerbose = AH->public.verbose;
8297 pjw 812 CBC 2 : AH->public.verbose = 0;
813 :
3967 tgl 814 2 : RestoreArchive((Archive *) AH);
815 :
2643 816 2 : SetArchiveOptions((Archive *) AH, savDopt, savRopt);
817 :
8297 pjw 818 2 : AH->public.verbose = savVerbose;
819 :
820 2 : tarClose(AH, th);
821 :
3844 tgl 822 GIC 2 : ctx->isSpecialScript = 0;
823 :
824 : /*
3845 tgl 825 ECB : * EOF marker for tar files is two blocks of NULLs.
826 : */
1080 rhaas 827 CBC 2050 : for (i = 0; i < TAR_BLOCK_SIZE * 2; i++)
8201 pjw 828 EUB : {
8122 pjw 829 GIC 2048 : if (fputc(0, ctx->tarFH) == EOF)
3261 bruce 830 UIC 0 : WRITE_ERROR_EXIT;
831 : }
2209 andrew 832 ECB :
833 : /* Sync the output file if one is defined */
2209 andrew 834 GIC 2 : if (AH->dosync && AH->fSpec)
1469 peter 835 1 : (void) fsync_fname(AH->fSpec, false);
8053 bruce 836 ECB : }
8297 pjw 837 :
8053 bruce 838 GIC 4 : AH->FH = NULL;
8297 pjw 839 4 : }
8297 pjw 840 ECB :
841 : static size_t
7537 peter_e 842 CBC 1614 : _scriptOut(ArchiveHandle *AH, const void *buf, size_t len)
843 : {
8053 bruce 844 1614 : lclContext *ctx = (lclContext *) AH->formatData;
845 :
8297 pjw 846 GIC 1614 : return tarWrite(buf, len, ctx->scriptTH);
847 : }
848 :
849 : /*
850 : * Large Object support
851 : */
852 :
853 : /*
854 : * Called by the archiver when starting to save all BLOB DATA (not schema).
855 : * This routine should save whatever format-specific information is needed
856 : * to read the LOs back into memory.
857 : *
858 : * It is called just prior to the dumper's DataDumper routine.
859 : *
860 : * Optional, but strongly recommended.
861 : *
8297 pjw 862 ECB : */
863 : static void
125 peter 864 GNC 1 : _StartLOs(ArchiveHandle *AH, TocEntry *te)
865 : {
8053 bruce 866 GIC 1 : lclContext *ctx = (lclContext *) AH->formatData;
8053 bruce 867 ECB : char fname[K_STD_BUF_SIZE];
8297 pjw 868 :
8297 pjw 869 CBC 1 : sprintf(fname, "blobs.toc");
125 peter 870 GNC 1 : ctx->loToc = tarOpen(AH, fname, 'w');
8297 pjw 871 GIC 1 : }
872 :
873 : /*
874 : * Called by the archiver when the dumper calls StartLO.
875 : *
876 : * Mandatory.
877 : *
878 : * Must save the passed OID for retrieval at restore-time.
8297 pjw 879 ECB : */
880 : static void
125 peter 881 GNC 2 : _StartLO(ArchiveHandle *AH, TocEntry *te, Oid oid)
8297 pjw 882 ECB : {
8053 bruce 883 GIC 2 : lclContext *ctx = (lclContext *) AH->formatData;
884 2 : lclTocEntry *tctx = (lclTocEntry *) te->formatData;
8053 bruce 885 ECB : char fname[255];
8297 pjw 886 EUB :
8053 bruce 887 GIC 2 : if (oid == 0)
366 tgl 888 LBC 0 : pg_fatal("invalid OID for large object (%u)", oid);
8297 pjw 889 EUB :
128 michael 890 GNC 2 : if (AH->compression_spec.algorithm != PG_COMPRESSION_NONE)
366 tgl 891 LBC 0 : pg_fatal("compression is not supported by tar archive format");
892 :
374 michael 893 CBC 2 : sprintf(fname, "blob_%u.dat", oid);
894 :
125 peter 895 GNC 2 : tarPrintf(ctx->loToc, "%u %s\n", oid, fname);
8297 pjw 896 ECB :
8297 pjw 897 GIC 2 : tctx->TH = tarOpen(AH, fname, 'w');
898 2 : }
899 :
900 : /*
901 : * Called by the archiver when the dumper calls EndLO.
902 : *
903 : * Optional.
904 : *
8297 pjw 905 ECB : */
906 : static void
125 peter 907 GNC 2 : _EndLO(ArchiveHandle *AH, TocEntry *te, Oid oid)
908 : {
8053 bruce 909 CBC 2 : lclTocEntry *tctx = (lclTocEntry *) te->formatData;
8297 pjw 910 ECB :
8297 pjw 911 GIC 2 : tarClose(AH, tctx->TH);
912 2 : }
913 :
914 : /*
915 : * Called by the archiver when finishing saving all BLOB DATA.
916 : *
917 : * Optional.
918 : *
8297 pjw 919 ECB : */
920 : static void
125 peter 921 GNC 1 : _EndLOs(ArchiveHandle *AH, TocEntry *te)
922 : {
8053 bruce 923 GIC 1 : lclContext *ctx = (lclContext *) AH->formatData;
924 :
925 : /* Write out a fake zero OID to mark end-of-LOs. */
8053 bruce 926 ECB : /* WriteInt(AH, 0); */
8297 pjw 927 :
125 peter 928 GNC 1 : tarClose(AH, ctx->loToc);
8297 pjw 929 GIC 1 : }
930 :
931 :
932 :
933 : /*------------
934 : * TAR Support
935 : *------------
936 : */
8297 pjw 937 ECB :
938 : static int
957 peter 939 CBC 4 : tarPrintf(TAR_MEMBER *th, const char *fmt,...)
940 : {
1656 tgl 941 4 : int save_errno = errno;
942 : char *p;
3454 tgl 943 GIC 4 : size_t len = 128; /* initial assumption about buffer size */
944 : size_t cnt;
8053 bruce 945 ECB :
946 : for (;;)
8080 tgl 947 GIC 2 : {
948 : va_list args;
3454 tgl 949 ECB :
950 : /* Allocate work buffer. */
3454 tgl 951 GIC 6 : p = (char *) pg_malloc(len);
3454 tgl 952 ECB :
953 : /* Try to format the data. */
1656 tgl 954 CBC 6 : errno = save_errno;
3454 955 6 : va_start(args, fmt);
3454 tgl 956 GIC 6 : cnt = pvsnprintf(p, len, fmt, args);
3454 tgl 957 CBC 6 : va_end(args);
3454 tgl 958 ECB :
3454 tgl 959 GIC 6 : if (cnt < len)
960 4 : break; /* success */
3454 tgl 961 ECB :
962 : /* Release buffer and loop around to try again with larger len. */
3454 tgl 963 GIC 2 : free(p);
964 2 : len = cnt;
8297 pjw 965 ECB : }
3454 tgl 966 :
8297 pjw 967 CBC 4 : cnt = tarWrite(p, cnt, th);
8297 pjw 968 GIC 4 : free(p);
3454 tgl 969 4 : return (int) cnt;
970 : }
8297 pjw 971 ECB :
972 : bool
8053 bruce 973 GIC 1 : isValidTarHeader(char *header)
8297 pjw 974 ECB : {
975 : int sum;
3750 magnus 976 CBC 1 : int chk = tarChecksum(header);
977 :
2696 tgl 978 1 : sum = read_tar_number(&header[148], 8);
8297 pjw 979 EUB :
7372 tgl 980 GIC 1 : if (sum != chk)
7372 tgl 981 UIC 0 : return false;
7372 tgl 982 ECB :
3845 983 : /* POSIX tar format */
3845 tgl 984 CBC 1 : if (memcmp(&header[257], "ustar\0", 6) == 0 &&
3845 tgl 985 GIC 1 : memcmp(&header[263], "00", 2) == 0)
7372 tgl 986 GBC 1 : return true;
3845 tgl 987 EUB : /* GNU tar format */
3845 tgl 988 UIC 0 : if (memcmp(&header[257], "ustar \0", 8) == 0)
3845 tgl 989 UBC 0 : return true;
3845 tgl 990 EUB : /* not-quite-POSIX format written by pre-9.3 pg_dump */
3845 tgl 991 UIC 0 : if (memcmp(&header[257], "ustar00\0", 8) == 0)
7372 tgl 992 UBC 0 : return true;
993 :
7372 tgl 994 UIC 0 : return false;
995 : }
996 :
8297 pjw 997 ECB : /* Given the member, write the TAR header & copy the file */
998 : static void
8053 bruce 999 CBC 34 : _tarAddFile(ArchiveHandle *AH, TAR_MEMBER *th)
8297 pjw 1000 ECB : {
8053 bruce 1001 GIC 34 : lclContext *ctx = (lclContext *) AH->formatData;
7833 1002 34 : FILE *tmp = th->tmpFH; /* Grab it for convenience */
8297 pjw 1003 ECB : char buf[32768];
1004 : size_t cnt;
5893 magnus 1005 GIC 34 : pgoff_t len = 0;
1006 : size_t res;
1007 : size_t i,
1008 : pad;
1009 :
1010 : /*
8297 pjw 1011 ECB : * Find file len & go back to start.
8297 pjw 1012 EUB : */
973 tgl 1013 CBC 34 : if (fseeko(tmp, 0, SEEK_END) != 0)
366 tgl 1014 LBC 0 : pg_fatal("error during file seek: %m");
7537 peter_e 1015 GBC 34 : th->fileLen = ftello(tmp);
3346 sfrost 1016 CBC 34 : if (th->fileLen < 0)
366 tgl 1017 UBC 0 : pg_fatal("could not determine seek position in archive file: %m");
973 tgl 1018 GIC 34 : if (fseeko(tmp, 0, SEEK_SET) != 0)
366 tgl 1019 LBC 0 : pg_fatal("error during file seek: %m");
1020 :
8297 pjw 1021 CBC 34 : _tarWriteHeader(th);
1022 :
5702 tgl 1023 70 : while ((cnt = fread(buf, 1, sizeof(buf), tmp)) > 0)
8297 pjw 1024 EUB : {
3261 bruce 1025 CBC 36 : if ((res = fwrite(buf, 1, cnt, th->tarFH)) != cnt)
3261 bruce 1026 UIC 0 : WRITE_ERROR_EXIT;
8122 pjw 1027 CBC 36 : len += res;
8297 pjw 1028 EUB : }
3261 bruce 1029 GIC 34 : if (!feof(tmp))
3261 bruce 1030 LBC 0 : READ_ERROR_EXIT(tmp);
8297 pjw 1031 EUB :
8053 bruce 1032 GIC 34 : if (fclose(tmp) != 0) /* This *should* delete it... */
366 tgl 1033 LBC 0 : pg_fatal("could not close temporary file: %m");
8297 pjw 1034 EUB :
8297 pjw 1035 GIC 34 : if (len != th->fileLen)
366 tgl 1036 UIC 0 : pg_fatal("actual file length (%lld) does not match expected (%lld)",
366 tgl 1037 ECB : (long long) len, (long long) th->fileLen);
8297 pjw 1038 :
1080 rhaas 1039 GIC 34 : pad = tarPaddingBytesRequired(len);
8053 bruce 1040 CBC 14794 : for (i = 0; i < pad; i++)
8122 pjw 1041 EUB : {
8053 bruce 1042 GIC 14760 : if (fputc('\0', th->tarFH) == EOF)
3261 bruce 1043 UIC 0 : WRITE_ERROR_EXIT;
8053 bruce 1044 ECB : }
8297 pjw 1045 :
8297 pjw 1046 GIC 34 : ctx->tarFHpos += len + pad;
1047 34 : }
1048 :
8297 pjw 1049 ECB : /* Locate the file in the archive, read header and position to data */
1050 : static TAR_MEMBER *
8053 bruce 1051 CBC 32 : _tarPositionTo(ArchiveHandle *AH, const char *filename)
8297 pjw 1052 ECB : {
8053 bruce 1053 GIC 32 : lclContext *ctx = (lclContext *) AH->formatData;
209 peter 1054 GNC 32 : TAR_MEMBER *th = pg_malloc0_object(TAR_MEMBER);
1055 : char c;
1056 : char header[TAR_BLOCK_SIZE];
1057 : size_t i,
1058 : len,
1059 : blks;
7537 peter_e 1060 ECB : int id;
1061 :
8297 pjw 1062 GIC 32 : th->AH = AH;
8297 pjw 1063 ECB :
1064 : /* Go to end of current file, if any */
8297 pjw 1065 CBC 32 : if (ctx->tarFHpos != 0)
1066 : {
387 tgl 1067 GIC 30 : pg_log_debug("moving from position %lld to next member at file position %lld",
387 tgl 1068 ECB : (long long) ctx->tarFHpos, (long long) ctx->tarNextMember);
8297 pjw 1069 :
8297 pjw 1070 GIC 13761 : while (ctx->tarFHpos < ctx->tarNextMember)
1071 13731 : _tarReadRaw(AH, &c, 1, NULL, ctx->tarFH);
8297 pjw 1072 ECB : }
1073 :
387 tgl 1074 GIC 32 : pg_log_debug("now at file position %lld", (long long) ctx->tarFHpos);
1075 :
1076 : /* We are at the start of the file, or at the next member */
8297 pjw 1077 ECB :
1078 : /* Get the header */
8297 pjw 1079 GBC 32 : if (!_tarGetHeader(AH, th))
8297 pjw 1080 EUB : {
8297 pjw 1081 UIC 0 : if (filename)
366 tgl 1082 0 : pg_fatal("could not find header for file \"%s\" in tar archive", filename);
1083 : else
1084 : {
1085 : /*
1086 : * We're just scanning the archive for the next file, so return
6385 bruce 1087 EUB : * null
1088 : */
8297 pjw 1089 UIC 0 : free(th);
1090 0 : return NULL;
1091 : }
8297 pjw 1092 ECB : }
1093 :
8053 bruce 1094 GBC 32 : while (filename != NULL && strcmp(th->targetFile, filename) != 0)
1095 : {
1469 peter 1096 UBC 0 : pg_log_debug("skipping tar member %s", th->targetFile);
8297 pjw 1097 EUB :
8297 pjw 1098 UBC 0 : id = atoi(th->targetFile);
3967 tgl 1099 UIC 0 : if ((TocIDRequired(AH, id) & REQ_DATA) != 0)
366 1100 0 : pg_fatal("restoring data out of order is not supported in this archive format: "
1101 : "\"%s\" is required, but comes before \"%s\" in the archive file.",
1102 : th->targetFile, filename);
8297 pjw 1103 EUB :
1104 : /* Header doesn't match, so read to next header */
1080 rhaas 1105 UBC 0 : len = th->fileLen;
1080 rhaas 1106 UIC 0 : len += tarPaddingBytesRequired(th->fileLen);
697 tgl 1107 UBC 0 : blks = len / TAR_BLOCK_SIZE; /* # of tar blocks */
8297 pjw 1108 EUB :
8053 bruce 1109 UIC 0 : for (i = 0; i < blks; i++)
1080 rhaas 1110 UBC 0 : _tarReadRaw(AH, &header[0], TAR_BLOCK_SIZE, NULL, ctx->tarFH);
8297 pjw 1111 EUB :
8297 pjw 1112 UIC 0 : if (!_tarGetHeader(AH, th))
366 tgl 1113 0 : pg_fatal("could not find header for file \"%s\" in tar archive", filename);
8297 pjw 1114 ECB : }
1115 :
1080 rhaas 1116 CBC 64 : ctx->tarNextMember = ctx->tarFHpos + th->fileLen
1080 rhaas 1117 GIC 32 : + tarPaddingBytesRequired(th->fileLen);
8297 pjw 1118 CBC 32 : th->pos = 0;
1119 :
8297 pjw 1120 GIC 32 : return th;
1121 : }
1122 :
8297 pjw 1123 ECB : /* Read & verify a header */
1124 : static int
8053 bruce 1125 CBC 32 : _tarGetHeader(ArchiveHandle *AH, TAR_MEMBER *th)
1126 : {
8053 bruce 1127 GIC 32 : lclContext *ctx = (lclContext *) AH->formatData;
1128 : char h[TAR_BLOCK_SIZE];
1129 : char tag[100 + 1];
1130 : int sum,
1131 : chk;
2696 tgl 1132 ECB : pgoff_t len;
1133 : pgoff_t hPos;
8053 bruce 1134 CBC 32 : bool gotBlock = false;
1135 :
8090 pjw 1136 GIC 64 : while (!gotBlock)
8090 pjw 1137 ECB : {
1138 : /* Save the pos for reporting purposes */
8090 pjw 1139 GIC 32 : hPos = ctx->tarFHpos;
8297 pjw 1140 ECB :
1080 rhaas 1141 : /* Read the next tar block, return EOF, exit if short */
1080 rhaas 1142 GBC 32 : len = _tarReadRaw(AH, h, TAR_BLOCK_SIZE, NULL, ctx->tarFH);
8053 bruce 1143 GIC 32 : if (len == 0) /* EOF */
8090 pjw 1144 LBC 0 : return 0;
8090 pjw 1145 EUB :
1080 rhaas 1146 GIC 32 : if (len != TAR_BLOCK_SIZE)
366 tgl 1147 UIC 0 : pg_fatal(ngettext("incomplete tar header found (%lu byte)",
1148 : "incomplete tar header found (%lu bytes)",
1149 : len),
1150 : (unsigned long) len);
8090 pjw 1151 ECB :
1152 : /* Calc checksum */
3750 magnus 1153 GIC 32 : chk = tarChecksum(h);
2696 tgl 1154 32 : sum = read_tar_number(&h[148], 8);
1155 :
1156 : /*
1157 : * If the checksum failed, see if it is a null block. If so, silently
6385 bruce 1158 ECB : * continue to the next block.
8090 pjw 1159 : */
8053 bruce 1160 GIC 32 : if (chk == sum)
8090 pjw 1161 32 : gotBlock = true;
1162 : else
1163 : {
6500 neilc 1164 EUB : int i;
1165 :
1080 rhaas 1166 UBC 0 : for (i = 0; i < TAR_BLOCK_SIZE; i++)
1167 : {
6500 neilc 1168 0 : if (h[i] != 0)
8090 pjw 1169 EUB : {
8053 bruce 1170 UIC 0 : gotBlock = true;
8090 pjw 1171 0 : break;
1172 : }
1173 : }
1174 : }
1175 : }
8297 pjw 1176 ECB :
1177 : /* Name field is 100 bytes, might not be null-terminated */
2696 tgl 1178 CBC 32 : strlcpy(tag, &h[0], 100 + 1);
1179 :
1180 32 : len = read_tar_number(&h[124], 12);
1181 :
387 tgl 1182 GIC 32 : pg_log_debug("TOC Entry %s at %llu (length %llu, checksum %d)",
387 tgl 1183 ECB : tag, (unsigned long long) hPos, (unsigned long long) len, sum);
8297 pjw 1184 EUB :
8297 pjw 1185 GIC 32 : if (chk != sum)
366 tgl 1186 UIC 0 : pg_fatal("corrupt tar header found in %s (expected %d, computed %d) file position %llu",
366 tgl 1187 ECB : tag, sum, chk, (unsigned long long) ftello(ctx->tarFH));
8297 pjw 1188 :
4153 bruce 1189 GIC 32 : th->targetFile = pg_strdup(tag);
8297 pjw 1190 CBC 32 : th->fileLen = len;
1191 :
8297 pjw 1192 GIC 32 : return 1;
1193 : }
1194 :
7520 peter_e 1195 ECB :
1196 : static void
8053 bruce 1197 GIC 34 : _tarWriteHeader(TAR_MEMBER *th)
1198 : {
1080 rhaas 1199 ECB : char h[TAR_BLOCK_SIZE];
1200 :
2696 tgl 1201 GIC 34 : tarCreateHeader(h, th->targetFile, NULL, th->fileLen,
1202 : 0600, 04000, 02000, time(NULL));
8297 pjw 1203 ECB :
3845 tgl 1204 EUB : /* Now write the completed header. */
1080 rhaas 1205 CBC 34 : if (fwrite(h, 1, TAR_BLOCK_SIZE, th->tarFH) != TAR_BLOCK_SIZE)
3261 bruce 1206 UIC 0 : WRITE_ERROR_EXIT;
8297 pjw 1207 GIC 34 : }
|