Move routines to manipulate WAL into PostgreSQL::Test::Cluster
[pgsql.git] / src / bin / pg_dump / pg_backup_tar.c
blobb5ba3b46dd999f5578caed6d2237388d2078c72c
1 /*-------------------------------------------------------------------------
3 * pg_backup_tar.c
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.
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.
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.
15 * See the headers to pg_backup_directory & pg_restore for more details.
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.
21 * The author is not responsible for loss or damages that may
22 * result from its use.
25 * IDENTIFICATION
26 * src/bin/pg_dump/pg_backup_tar.c
28 *-------------------------------------------------------------------------
30 #include "postgres_fe.h"
32 #include <sys/stat.h>
33 #include <ctype.h>
34 #include <limits.h>
35 #include <unistd.h>
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"
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);
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);
63 #define K_STD_BUF_SIZE 1024
66 typedef struct
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;
78 typedef struct
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;
91 typedef struct
93 TAR_MEMBER *TH;
94 char *filename;
95 } lclTocEntry;
97 static void _LoadLOs(ArchiveHandle *AH, TocEntry *te);
99 static TAR_MEMBER *tarOpen(ArchiveHandle *AH, const char *filename, char mode);
100 static void tarClose(ArchiveHandle *AH, TAR_MEMBER *th);
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);
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);
115 static size_t _scriptOut(ArchiveHandle *AH, const void *buf, size_t len);
118 * Initializer
120 void
121 InitArchiveFmt_Tar(ArchiveHandle *AH)
123 lclContext *ctx;
125 /* Assuming static functions, this can be copied for each format. */
126 AH->ArchiveEntryPtr = _ArchiveEntry;
127 AH->StartDataPtr = _StartData;
128 AH->WriteDataPtr = _WriteData;
129 AH->EndDataPtr = _EndData;
130 AH->WriteBytePtr = _WriteByte;
131 AH->ReadBytePtr = _ReadByte;
132 AH->WriteBufPtr = _WriteBuf;
133 AH->ReadBufPtr = _ReadBuf;
134 AH->ClosePtr = _CloseArchive;
135 AH->ReopenPtr = NULL;
136 AH->PrintTocDataPtr = _PrintTocData;
137 AH->ReadExtraTocPtr = _ReadExtraToc;
138 AH->WriteExtraTocPtr = _WriteExtraToc;
139 AH->PrintExtraTocPtr = _PrintExtraToc;
141 AH->StartLOsPtr = _StartLOs;
142 AH->StartLOPtr = _StartLO;
143 AH->EndLOPtr = _EndLO;
144 AH->EndLOsPtr = _EndLOs;
145 AH->ClonePtr = NULL;
146 AH->DeClonePtr = NULL;
148 AH->WorkerJobDumpPtr = NULL;
149 AH->WorkerJobRestorePtr = NULL;
152 * Set up some special context used in compressing data.
154 ctx = pg_malloc0_object(lclContext);
155 AH->formatData = ctx;
156 ctx->filePos = 0;
157 ctx->isSpecialScript = 0;
160 * Now open the tar file, and load the TOC if we're in read mode.
162 if (AH->mode == archModeWrite)
164 if (AH->fSpec && strcmp(AH->fSpec, "") != 0)
166 ctx->tarFH = fopen(AH->fSpec, PG_BINARY_W);
167 if (ctx->tarFH == NULL)
168 pg_fatal("could not open TOC file \"%s\" for output: %m",
169 AH->fSpec);
171 else
173 ctx->tarFH = stdout;
174 if (ctx->tarFH == NULL)
175 pg_fatal("could not open TOC file for output: %m");
178 ctx->tarFHpos = 0;
181 * Make unbuffered since we will dup() it, and the buffers screw each
182 * other
184 /* setvbuf(ctx->tarFH, NULL, _IONBF, 0); */
186 ctx->hasSeek = checkSeek(ctx->tarFH);
189 * We don't support compression because reading the files back is not
190 * possible since gzdopen uses buffered IO which totally screws file
191 * positioning.
193 if (AH->compression_spec.algorithm != PG_COMPRESSION_NONE)
194 pg_fatal("compression is not supported by tar archive format");
196 else
197 { /* Read Mode */
198 if (AH->fSpec && strcmp(AH->fSpec, "") != 0)
200 ctx->tarFH = fopen(AH->fSpec, PG_BINARY_R);
201 if (ctx->tarFH == NULL)
202 pg_fatal("could not open TOC file \"%s\" for input: %m",
203 AH->fSpec);
205 else
207 ctx->tarFH = stdin;
208 if (ctx->tarFH == NULL)
209 pg_fatal("could not open TOC file for input: %m");
213 * Make unbuffered since we will dup() it, and the buffers screw each
214 * other
216 /* setvbuf(ctx->tarFH, NULL, _IONBF, 0); */
218 ctx->tarFHpos = 0;
220 ctx->hasSeek = checkSeek(ctx->tarFH);
222 ctx->FH = tarOpen(AH, "toc.dat", 'r');
223 ReadHead(AH);
224 ReadToc(AH);
225 tarClose(AH, ctx->FH); /* Nothing else in the file... */
230 * - Start a new TOC entry
231 * Setup the output file name.
233 static void
234 _ArchiveEntry(ArchiveHandle *AH, TocEntry *te)
236 lclTocEntry *ctx;
237 char fn[K_STD_BUF_SIZE];
239 ctx = pg_malloc0_object(lclTocEntry);
240 if (te->dataDumper != NULL)
242 snprintf(fn, sizeof(fn), "%d.dat", te->dumpId);
243 ctx->filename = pg_strdup(fn);
245 else
247 ctx->filename = NULL;
248 ctx->TH = NULL;
250 te->formatData = ctx;
253 static void
254 _WriteExtraToc(ArchiveHandle *AH, TocEntry *te)
256 lclTocEntry *ctx = (lclTocEntry *) te->formatData;
258 if (ctx->filename)
259 WriteStr(AH, ctx->filename);
260 else
261 WriteStr(AH, "");
264 static void
265 _ReadExtraToc(ArchiveHandle *AH, TocEntry *te)
267 lclTocEntry *ctx = (lclTocEntry *) te->formatData;
269 if (ctx == NULL)
271 ctx = pg_malloc0_object(lclTocEntry);
272 te->formatData = ctx;
275 ctx->filename = ReadStr(AH);
276 if (strlen(ctx->filename) == 0)
278 free(ctx->filename);
279 ctx->filename = NULL;
281 ctx->TH = NULL;
284 static void
285 _PrintExtraToc(ArchiveHandle *AH, TocEntry *te)
287 lclTocEntry *ctx = (lclTocEntry *) te->formatData;
289 if (AH->public.verbose && ctx->filename != NULL)
290 ahprintf(AH, "-- File: %s\n", ctx->filename);
293 static void
294 _StartData(ArchiveHandle *AH, TocEntry *te)
296 lclTocEntry *tctx = (lclTocEntry *) te->formatData;
298 tctx->TH = tarOpen(AH, tctx->filename, 'w');
301 static TAR_MEMBER *
302 tarOpen(ArchiveHandle *AH, const char *filename, char mode)
304 lclContext *ctx = (lclContext *) AH->formatData;
305 TAR_MEMBER *tm;
307 if (mode == 'r')
309 tm = _tarPositionTo(AH, filename);
310 if (!tm) /* Not found */
312 if (filename)
315 * Couldn't find the requested file. Future: do SEEK(0) and
316 * retry.
318 pg_fatal("could not find file \"%s\" in archive", filename);
320 else
322 /* Any file OK, none left, so return NULL */
323 return NULL;
327 if (AH->compression_spec.algorithm == PG_COMPRESSION_NONE)
328 tm->nFH = ctx->tarFH;
329 else
330 pg_fatal("compression is not supported by tar archive format");
332 else
334 int old_umask;
336 tm = pg_malloc0_object(TAR_MEMBER);
339 * POSIX does not require, but permits, tmpfile() to restrict file
340 * permissions. Given an OS crash after we write data, the filesystem
341 * might retain the data but forget tmpfile()'s unlink(). If so, the
342 * file mode protects confidentiality of the data written.
344 old_umask = umask(S_IRWXG | S_IRWXO);
346 #ifndef WIN32
347 tm->tmpFH = tmpfile();
348 #else
351 * On WIN32, tmpfile() generates a filename in the root directory,
352 * which requires administrative permissions on certain systems. Loop
353 * until we find a unique file name we can create.
355 while (1)
357 char *name;
358 int fd;
360 name = _tempnam(NULL, "pg_temp_");
361 if (name == NULL)
362 break;
363 fd = open(name, O_RDWR | O_CREAT | O_EXCL | O_BINARY |
364 O_TEMPORARY, S_IRUSR | S_IWUSR);
365 free(name);
367 if (fd != -1) /* created a file */
369 tm->tmpFH = fdopen(fd, "w+b");
370 break;
372 else if (errno != EEXIST) /* failure other than file exists */
373 break;
375 #endif
377 if (tm->tmpFH == NULL)
378 pg_fatal("could not generate temporary file name: %m");
380 umask(old_umask);
382 if (AH->compression_spec.algorithm == PG_COMPRESSION_NONE)
383 tm->nFH = tm->tmpFH;
384 else
385 pg_fatal("compression is not supported by tar archive format");
387 tm->AH = AH;
388 tm->targetFile = pg_strdup(filename);
391 tm->mode = mode;
392 tm->tarFH = ctx->tarFH;
394 return tm;
397 static void
398 tarClose(ArchiveHandle *AH, TAR_MEMBER *th)
400 if (AH->compression_spec.algorithm != PG_COMPRESSION_NONE)
401 pg_fatal("compression is not supported by tar archive format");
403 if (th->mode == 'w')
404 _tarAddFile(AH, th); /* This will close the temp file */
407 * else Nothing to do for normal read since we don't dup() normal file
408 * handle, and we don't use temp files.
411 free(th->targetFile);
413 th->nFH = NULL;
416 #ifdef __NOT_USED__
417 static char *
418 tarGets(char *buf, size_t len, TAR_MEMBER *th)
420 char *s;
421 size_t cnt = 0;
422 char c = ' ';
423 int eof = 0;
425 /* Can't read past logical EOF */
426 if (len > (th->fileLen - th->pos))
427 len = th->fileLen - th->pos;
429 while (cnt < len && c != '\n')
431 if (_tarReadRaw(th->AH, &c, 1, th, NULL) <= 0)
433 eof = 1;
434 break;
436 buf[cnt++] = c;
439 if (eof && cnt == 0)
440 s = NULL;
441 else
443 buf[cnt++] = '\0';
444 s = buf;
447 if (s)
449 len = strlen(s);
450 th->pos += len;
453 return s;
455 #endif
458 * Just read bytes from the archive. This is the low level read routine
459 * that is used for ALL reads on a tar file.
461 static size_t
462 _tarReadRaw(ArchiveHandle *AH, void *buf, size_t len, TAR_MEMBER *th, FILE *fh)
464 lclContext *ctx = (lclContext *) AH->formatData;
465 size_t avail;
466 size_t used = 0;
467 size_t res = 0;
469 Assert(th || fh);
471 avail = AH->lookaheadLen - AH->lookaheadPos;
472 if (avail > 0)
474 /* We have some lookahead bytes to use */
475 if (avail >= len) /* Just use the lookahead buffer */
476 used = len;
477 else
478 used = avail;
480 /* Copy, and adjust buffer pos */
481 memcpy(buf, AH->lookahead + AH->lookaheadPos, used);
482 AH->lookaheadPos += used;
484 /* Adjust required length */
485 len -= used;
488 /* Read the file if len > 0 */
489 if (len > 0)
491 if (fh)
493 res = fread(&((char *) buf)[used], 1, len, fh);
494 if (res != len && !feof(fh))
495 READ_ERROR_EXIT(fh);
497 else if (th)
499 res = fread(&((char *) buf)[used], 1, len, th->nFH);
500 if (res != len && !feof(th->nFH))
501 READ_ERROR_EXIT(th->nFH);
505 ctx->tarFHpos += res + used;
507 return (res + used);
510 static size_t
511 tarRead(void *buf, size_t len, TAR_MEMBER *th)
513 size_t res;
515 if (th->pos + len > th->fileLen)
516 len = th->fileLen - th->pos;
518 if (len <= 0)
519 return 0;
521 res = _tarReadRaw(th->AH, buf, len, th, NULL);
523 th->pos += res;
525 return res;
528 static size_t
529 tarWrite(const void *buf, size_t len, TAR_MEMBER *th)
531 size_t res;
533 res = fwrite(buf, 1, len, th->nFH);
535 th->pos += res;
536 return res;
539 static void
540 _WriteData(ArchiveHandle *AH, const void *data, size_t dLen)
542 lclTocEntry *tctx = (lclTocEntry *) AH->currToc->formatData;
544 if (tarWrite(data, dLen, tctx->TH) != dLen)
545 WRITE_ERROR_EXIT;
548 static void
549 _EndData(ArchiveHandle *AH, TocEntry *te)
551 lclTocEntry *tctx = (lclTocEntry *) te->formatData;
553 /* Close the file */
554 tarClose(AH, tctx->TH);
555 tctx->TH = NULL;
559 * Print data for a given file
561 static void
562 _PrintFileData(ArchiveHandle *AH, char *filename)
564 lclContext *ctx = (lclContext *) AH->formatData;
565 char buf[4096];
566 size_t cnt;
567 TAR_MEMBER *th;
569 if (!filename)
570 return;
572 th = tarOpen(AH, filename, 'r');
573 ctx->FH = th;
575 while ((cnt = tarRead(buf, 4095, th)) > 0)
577 buf[cnt] = '\0';
578 ahwrite(buf, 1, cnt, AH);
581 tarClose(AH, th);
586 * Print data for a given TOC entry
588 static void
589 _PrintTocData(ArchiveHandle *AH, TocEntry *te)
591 lclContext *ctx = (lclContext *) AH->formatData;
592 lclTocEntry *tctx = (lclTocEntry *) te->formatData;
593 int pos1;
595 if (!tctx->filename)
596 return;
599 * If we're writing the special restore.sql script, emit a suitable
600 * command to include each table's data from the corresponding file.
602 * In the COPY case this is a bit klugy because the regular COPY command
603 * was already printed before we get control.
605 if (ctx->isSpecialScript)
607 if (te->copyStmt)
609 /* Abort the COPY FROM stdin */
610 ahprintf(AH, "\\.\n");
613 * The COPY statement should look like "COPY ... FROM stdin;\n",
614 * see dumpTableData().
616 pos1 = (int) strlen(te->copyStmt) - 13;
617 if (pos1 < 6 || strncmp(te->copyStmt, "COPY ", 5) != 0 ||
618 strcmp(te->copyStmt + pos1, " FROM stdin;\n") != 0)
619 pg_fatal("unexpected COPY statement syntax: \"%s\"",
620 te->copyStmt);
622 /* Emit all but the FROM part ... */
623 ahwrite(te->copyStmt, 1, pos1, AH);
624 /* ... and insert modified FROM */
625 ahprintf(AH, " FROM '$$PATH$$/%s';\n\n", tctx->filename);
627 else
629 /* --inserts mode, no worries, just include the data file */
630 ahprintf(AH, "\\i $$PATH$$/%s\n\n", tctx->filename);
633 return;
636 if (strcmp(te->desc, "BLOBS") == 0)
637 _LoadLOs(AH, te);
638 else
639 _PrintFileData(AH, tctx->filename);
642 static void
643 _LoadLOs(ArchiveHandle *AH, TocEntry *te)
645 Oid oid;
646 lclContext *ctx = (lclContext *) AH->formatData;
647 TAR_MEMBER *th;
648 size_t cnt;
649 bool foundLO = false;
650 char buf[4096];
652 StartRestoreLOs(AH);
655 * The blobs_NNN.toc or blobs.toc file is fairly useless to us because it
656 * will appear only after the associated blob_NNN.dat files. For archive
657 * versions >= 16 we can look at the BLOBS entry's te->tag to discover the
658 * OID of the first blob we want to restore, and then search forward to
659 * find the appropriate blob_<oid>.dat file. For older versions we rely
660 * on the knowledge that there was only one BLOBS entry and just search
661 * for the first blob_<oid>.dat file. Once we find the first blob file to
662 * restore, restore all blobs until we reach the blobs[_NNN].toc file.
664 if (AH->version >= K_VERS_1_16)
666 /* We rely on atooid to not complain about nnnn..nnnn tags */
667 oid = atooid(te->tag);
668 snprintf(buf, sizeof(buf), "blob_%u.dat", oid);
669 th = tarOpen(AH, buf, 'r'); /* Advance to first desired file */
671 else
672 th = tarOpen(AH, NULL, 'r'); /* Open next file */
674 while (th != NULL)
676 ctx->FH = th;
678 if (strncmp(th->targetFile, "blob_", 5) == 0)
680 oid = atooid(&th->targetFile[5]);
681 if (oid != 0)
683 pg_log_info("restoring large object with OID %u", oid);
685 StartRestoreLO(AH, oid, AH->public.ropt->dropSchema);
687 while ((cnt = tarRead(buf, 4095, th)) > 0)
689 buf[cnt] = '\0';
690 ahwrite(buf, 1, cnt, AH);
692 EndRestoreLO(AH, oid);
693 foundLO = true;
695 tarClose(AH, th);
697 else
699 tarClose(AH, th);
702 * Once we have found the first LO, stop at the first non-LO entry
703 * (which will be 'blobs[_NNN].toc'). This coding would eat all
704 * the rest of the archive if there are no LOs ... but this
705 * function shouldn't be called at all in that case.
707 if (foundLO)
708 break;
711 th = tarOpen(AH, NULL, 'r');
713 EndRestoreLOs(AH);
717 static int
718 _WriteByte(ArchiveHandle *AH, const int i)
720 lclContext *ctx = (lclContext *) AH->formatData;
721 char b = i; /* Avoid endian problems */
723 if (tarWrite(&b, 1, ctx->FH) != 1)
724 WRITE_ERROR_EXIT;
726 ctx->filePos += 1;
727 return 1;
730 static int
731 _ReadByte(ArchiveHandle *AH)
733 lclContext *ctx = (lclContext *) AH->formatData;
734 size_t res;
735 unsigned char c;
737 res = tarRead(&c, 1, ctx->FH);
738 if (res != 1)
739 /* We already would have exited for errors on reads, must be EOF */
740 pg_fatal("could not read from input file: end of file");
741 ctx->filePos += 1;
742 return c;
745 static void
746 _WriteBuf(ArchiveHandle *AH, const void *buf, size_t len)
748 lclContext *ctx = (lclContext *) AH->formatData;
750 if (tarWrite(buf, len, ctx->FH) != len)
751 WRITE_ERROR_EXIT;
753 ctx->filePos += len;
756 static void
757 _ReadBuf(ArchiveHandle *AH, void *buf, size_t len)
759 lclContext *ctx = (lclContext *) AH->formatData;
761 if (tarRead(buf, len, ctx->FH) != len)
762 /* We already would have exited for errors on reads, must be EOF */
763 pg_fatal("could not read from input file: end of file");
765 ctx->filePos += len;
768 static void
769 _CloseArchive(ArchiveHandle *AH)
771 lclContext *ctx = (lclContext *) AH->formatData;
772 TAR_MEMBER *th;
773 RestoreOptions *ropt;
774 RestoreOptions *savRopt;
775 DumpOptions *savDopt;
776 int savVerbose,
779 if (AH->mode == archModeWrite)
782 * Write the Header & TOC to the archive FIRST
784 th = tarOpen(AH, "toc.dat", 'w');
785 ctx->FH = th;
786 WriteHead(AH);
787 WriteToc(AH);
788 tarClose(AH, th); /* Not needed any more */
791 * Now send the data (tables & LOs)
793 WriteDataChunks(AH, NULL);
796 * Now this format wants to append a script which does a full restore
797 * if the files have been extracted.
799 th = tarOpen(AH, "restore.sql", 'w');
801 tarPrintf(th, "--\n"
802 "-- NOTE:\n"
803 "--\n"
804 "-- File paths need to be edited. Search for $$PATH$$ and\n"
805 "-- replace it with the path to the directory containing\n"
806 "-- the extracted data files.\n"
807 "--\n");
809 AH->CustomOutPtr = _scriptOut;
811 ctx->isSpecialScript = 1;
812 ctx->scriptTH = th;
814 ropt = NewRestoreOptions();
815 memcpy(ropt, AH->public.ropt, sizeof(RestoreOptions));
816 ropt->filename = NULL;
817 ropt->dropSchema = 1;
818 ropt->superuser = NULL;
819 ropt->suppressDumpWarnings = true;
821 savDopt = AH->public.dopt;
822 savRopt = AH->public.ropt;
824 SetArchiveOptions((Archive *) AH, NULL, ropt);
826 savVerbose = AH->public.verbose;
827 AH->public.verbose = 0;
829 RestoreArchive((Archive *) AH);
831 SetArchiveOptions((Archive *) AH, savDopt, savRopt);
833 AH->public.verbose = savVerbose;
835 tarClose(AH, th);
837 ctx->isSpecialScript = 0;
840 * EOF marker for tar files is two blocks of NULLs.
842 for (i = 0; i < TAR_BLOCK_SIZE * 2; i++)
844 if (fputc(0, ctx->tarFH) == EOF)
845 WRITE_ERROR_EXIT;
848 /* Sync the output file if one is defined */
849 if (AH->dosync && AH->fSpec)
850 (void) fsync_fname(AH->fSpec, false);
853 AH->FH = NULL;
856 static size_t
857 _scriptOut(ArchiveHandle *AH, const void *buf, size_t len)
859 lclContext *ctx = (lclContext *) AH->formatData;
861 return tarWrite(buf, len, ctx->scriptTH);
865 * Large Object support
869 * Called by the archiver when starting to save BLOB DATA (not schema).
870 * This routine should save whatever format-specific information is needed
871 * to read the LOs back into memory.
873 * It is called just prior to the dumper's DataDumper routine.
875 * Optional, but strongly recommended.
878 static void
879 _StartLOs(ArchiveHandle *AH, TocEntry *te)
881 lclContext *ctx = (lclContext *) AH->formatData;
882 char fname[K_STD_BUF_SIZE];
884 sprintf(fname, "blobs_%d.toc", te->dumpId);
885 ctx->loToc = tarOpen(AH, fname, 'w');
889 * Called by the archiver when the dumper calls StartLO.
891 * Mandatory.
893 * Must save the passed OID for retrieval at restore-time.
895 static void
896 _StartLO(ArchiveHandle *AH, TocEntry *te, Oid oid)
898 lclContext *ctx = (lclContext *) AH->formatData;
899 lclTocEntry *tctx = (lclTocEntry *) te->formatData;
900 char fname[255];
902 if (oid == 0)
903 pg_fatal("invalid OID for large object (%u)", oid);
905 if (AH->compression_spec.algorithm != PG_COMPRESSION_NONE)
906 pg_fatal("compression is not supported by tar archive format");
908 sprintf(fname, "blob_%u.dat", oid);
910 tarPrintf(ctx->loToc, "%u %s\n", oid, fname);
912 tctx->TH = tarOpen(AH, fname, 'w');
916 * Called by the archiver when the dumper calls EndLO.
918 * Optional.
921 static void
922 _EndLO(ArchiveHandle *AH, TocEntry *te, Oid oid)
924 lclTocEntry *tctx = (lclTocEntry *) te->formatData;
926 tarClose(AH, tctx->TH);
930 * Called by the archiver when finishing saving BLOB DATA.
932 * Optional.
935 static void
936 _EndLOs(ArchiveHandle *AH, TocEntry *te)
938 lclContext *ctx = (lclContext *) AH->formatData;
940 /* Write out a fake zero OID to mark end-of-LOs. */
941 /* WriteInt(AH, 0); */
943 tarClose(AH, ctx->loToc);
948 /*------------
949 * TAR Support
950 *------------
953 static int
954 tarPrintf(TAR_MEMBER *th, const char *fmt,...)
956 int save_errno = errno;
957 char *p;
958 size_t len = 128; /* initial assumption about buffer size */
959 size_t cnt;
961 for (;;)
963 va_list args;
965 /* Allocate work buffer. */
966 p = (char *) pg_malloc(len);
968 /* Try to format the data. */
969 errno = save_errno;
970 va_start(args, fmt);
971 cnt = pvsnprintf(p, len, fmt, args);
972 va_end(args);
974 if (cnt < len)
975 break; /* success */
977 /* Release buffer and loop around to try again with larger len. */
978 free(p);
979 len = cnt;
982 cnt = tarWrite(p, cnt, th);
983 free(p);
984 return (int) cnt;
987 bool
988 isValidTarHeader(char *header)
990 int sum;
991 int chk = tarChecksum(header);
993 sum = read_tar_number(&header[TAR_OFFSET_CHECKSUM], 8);
995 if (sum != chk)
996 return false;
998 /* POSIX tar format */
999 if (memcmp(&header[TAR_OFFSET_MAGIC], "ustar\0", 6) == 0 &&
1000 memcmp(&header[TAR_OFFSET_VERSION], "00", 2) == 0)
1001 return true;
1002 /* GNU tar format */
1003 if (memcmp(&header[TAR_OFFSET_MAGIC], "ustar \0", 8) == 0)
1004 return true;
1005 /* not-quite-POSIX format written by pre-9.3 pg_dump */
1006 if (memcmp(&header[TAR_OFFSET_MAGIC], "ustar00\0", 8) == 0)
1007 return true;
1009 return false;
1012 /* Given the member, write the TAR header & copy the file */
1013 static void
1014 _tarAddFile(ArchiveHandle *AH, TAR_MEMBER *th)
1016 lclContext *ctx = (lclContext *) AH->formatData;
1017 FILE *tmp = th->tmpFH; /* Grab it for convenience */
1018 char buf[32768];
1019 size_t cnt;
1020 pgoff_t len = 0;
1021 size_t res;
1022 size_t i,
1023 pad;
1026 * Find file len & go back to start.
1028 if (fseeko(tmp, 0, SEEK_END) != 0)
1029 pg_fatal("error during file seek: %m");
1030 th->fileLen = ftello(tmp);
1031 if (th->fileLen < 0)
1032 pg_fatal("could not determine seek position in archive file: %m");
1033 if (fseeko(tmp, 0, SEEK_SET) != 0)
1034 pg_fatal("error during file seek: %m");
1036 _tarWriteHeader(th);
1038 while ((cnt = fread(buf, 1, sizeof(buf), tmp)) > 0)
1040 if ((res = fwrite(buf, 1, cnt, th->tarFH)) != cnt)
1041 WRITE_ERROR_EXIT;
1042 len += res;
1044 if (!feof(tmp))
1045 READ_ERROR_EXIT(tmp);
1047 if (fclose(tmp) != 0) /* This *should* delete it... */
1048 pg_fatal("could not close temporary file: %m");
1050 if (len != th->fileLen)
1051 pg_fatal("actual file length (%lld) does not match expected (%lld)",
1052 (long long) len, (long long) th->fileLen);
1054 pad = tarPaddingBytesRequired(len);
1055 for (i = 0; i < pad; i++)
1057 if (fputc('\0', th->tarFH) == EOF)
1058 WRITE_ERROR_EXIT;
1061 ctx->tarFHpos += len + pad;
1064 /* Locate the file in the archive, read header and position to data */
1065 static TAR_MEMBER *
1066 _tarPositionTo(ArchiveHandle *AH, const char *filename)
1068 lclContext *ctx = (lclContext *) AH->formatData;
1069 TAR_MEMBER *th = pg_malloc0_object(TAR_MEMBER);
1070 char c;
1071 char header[TAR_BLOCK_SIZE];
1072 size_t i,
1073 len,
1074 blks;
1075 int id;
1077 th->AH = AH;
1079 /* Go to end of current file, if any */
1080 if (ctx->tarFHpos != 0)
1082 pg_log_debug("moving from position %lld to next member at file position %lld",
1083 (long long) ctx->tarFHpos, (long long) ctx->tarNextMember);
1085 while (ctx->tarFHpos < ctx->tarNextMember)
1086 _tarReadRaw(AH, &c, 1, NULL, ctx->tarFH);
1089 pg_log_debug("now at file position %lld", (long long) ctx->tarFHpos);
1091 /* We are at the start of the file, or at the next member */
1093 /* Get the header */
1094 if (!_tarGetHeader(AH, th))
1096 if (filename)
1097 pg_fatal("could not find header for file \"%s\" in tar archive", filename);
1098 else
1101 * We're just scanning the archive for the next file, so return
1102 * null
1104 free(th);
1105 return NULL;
1109 while (filename != NULL && strcmp(th->targetFile, filename) != 0)
1111 pg_log_debug("skipping tar member %s", th->targetFile);
1113 id = atoi(th->targetFile);
1114 if ((TocIDRequired(AH, id) & REQ_DATA) != 0)
1115 pg_fatal("restoring data out of order is not supported in this archive format: "
1116 "\"%s\" is required, but comes before \"%s\" in the archive file.",
1117 th->targetFile, filename);
1119 /* Header doesn't match, so read to next header */
1120 len = th->fileLen;
1121 len += tarPaddingBytesRequired(th->fileLen);
1122 blks = len / TAR_BLOCK_SIZE; /* # of tar blocks */
1124 for (i = 0; i < blks; i++)
1125 _tarReadRaw(AH, &header[0], TAR_BLOCK_SIZE, NULL, ctx->tarFH);
1127 if (!_tarGetHeader(AH, th))
1128 pg_fatal("could not find header for file \"%s\" in tar archive", filename);
1131 ctx->tarNextMember = ctx->tarFHpos + th->fileLen
1132 + tarPaddingBytesRequired(th->fileLen);
1133 th->pos = 0;
1135 return th;
1138 /* Read & verify a header */
1139 static int
1140 _tarGetHeader(ArchiveHandle *AH, TAR_MEMBER *th)
1142 lclContext *ctx = (lclContext *) AH->formatData;
1143 char h[TAR_BLOCK_SIZE];
1144 char tag[100 + 1];
1145 int sum,
1146 chk;
1147 pgoff_t len;
1148 pgoff_t hPos;
1149 bool gotBlock = false;
1151 while (!gotBlock)
1153 /* Save the pos for reporting purposes */
1154 hPos = ctx->tarFHpos;
1156 /* Read the next tar block, return EOF, exit if short */
1157 len = _tarReadRaw(AH, h, TAR_BLOCK_SIZE, NULL, ctx->tarFH);
1158 if (len == 0) /* EOF */
1159 return 0;
1161 if (len != TAR_BLOCK_SIZE)
1162 pg_fatal(ngettext("incomplete tar header found (%lu byte)",
1163 "incomplete tar header found (%lu bytes)",
1164 len),
1165 (unsigned long) len);
1167 /* Calc checksum */
1168 chk = tarChecksum(h);
1169 sum = read_tar_number(&h[TAR_OFFSET_CHECKSUM], 8);
1172 * If the checksum failed, see if it is a null block. If so, silently
1173 * continue to the next block.
1175 if (chk == sum)
1176 gotBlock = true;
1177 else
1179 int i;
1181 for (i = 0; i < TAR_BLOCK_SIZE; i++)
1183 if (h[i] != 0)
1185 gotBlock = true;
1186 break;
1192 /* Name field is 100 bytes, might not be null-terminated */
1193 strlcpy(tag, &h[TAR_OFFSET_NAME], 100 + 1);
1195 len = read_tar_number(&h[TAR_OFFSET_SIZE], 12);
1197 pg_log_debug("TOC Entry %s at %llu (length %llu, checksum %d)",
1198 tag, (unsigned long long) hPos, (unsigned long long) len, sum);
1200 if (chk != sum)
1201 pg_fatal("corrupt tar header found in %s (expected %d, computed %d) file position %llu",
1202 tag, sum, chk, (unsigned long long) ftello(ctx->tarFH));
1204 th->targetFile = pg_strdup(tag);
1205 th->fileLen = len;
1207 return 1;
1211 static void
1212 _tarWriteHeader(TAR_MEMBER *th)
1214 char h[TAR_BLOCK_SIZE];
1216 tarCreateHeader(h, th->targetFile, NULL, th->fileLen,
1217 0600, 04000, 02000, time(NULL));
1219 /* Now write the completed header. */
1220 if (fwrite(h, 1, TAR_BLOCK_SIZE, th->tarFH) != TAR_BLOCK_SIZE)
1221 WRITE_ERROR_EXIT;