1/*-------------------------------------------------------------------------
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
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.
26 * src/bin/pg_dump/pg_backup_tar.c
28 *-------------------------------------------------------------------------
63 #define K_STD_BUF_SIZE 1024
125 /* Assuming static functions, this can be copied for each format. */
135 AH->ReopenPtr = NULL;
146 AH->DeClonePtr = NULL;
148 AH->WorkerJobDumpPtr = NULL;
149 AH->WorkerJobRestorePtr = NULL;
152 * Set up some special context used in compressing data.
155 AH->formatData = ctx;
160 * Now open the tar file, and load the TOC if we're in read mode.
164 if (AH->fSpec && strcmp(AH->fSpec,
"") != 0)
167 if (ctx->
tarFH == NULL)
168 pg_fatal(
"could not open TOC file \"%s\" for output: %m",
174 if (ctx->
tarFH == NULL)
175 pg_fatal(
"could not open TOC file for output: %m");
181 * Make unbuffered since we will dup() it, and the buffers screw each
184 /* setvbuf(ctx->tarFH, NULL, _IONBF, 0); */
189 * We don't support compression because reading the files back is not
190 * possible since gzdopen uses buffered IO which totally screws file
194 pg_fatal(
"compression is not supported by tar archive format");
198 if (AH->fSpec && strcmp(AH->fSpec,
"") != 0)
201 if (ctx->
tarFH == NULL)
202 pg_fatal(
"could not open TOC file \"%s\" for input: %m",
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
216 /* setvbuf(ctx->tarFH, NULL, _IONBF, 0); */
225 tarClose(AH, ctx->
FH);
/* Nothing else in the file... */
230 * - Start a new TOC entry
231 * Setup the output file name.
310 if (!
tm)
/* Not found */
315 * Couldn't find the requested file. Future: do SEEK(0) and
322 /* Any file OK, none left, so return NULL */
330 pg_fatal(
"compression is not supported by tar archive format");
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.
347 tm->tmpFH = tmpfile();
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.
360 name = _tempnam(NULL,
"pg_temp_");
363 fd = open(
name, O_RDWR | O_CREAT | O_EXCL | O_BINARY |
367 if (
fd != -1)
/* created a file */
369 tm->tmpFH = fdopen(
fd,
"w+b");
372 else if (errno != EEXIST)
/* failure other than file exists */
377 if (
tm->tmpFH == NULL)
378 pg_fatal(
"could not generate temporary file name: %m");
385 pg_fatal(
"compression is not supported by tar archive format");
401 pg_fatal(
"compression is not supported by tar archive format");
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.
425 /* Can't read past logical EOF */
429 while (cnt <
len &&
c !=
'\n')
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.
474 /* We have some lookahead bytes to use */
475 if (avail >=
len)
/* Just use the lookahead buffer */
480 /* Copy, and adjust buffer pos */
484 /* Adjust required length */
488 /* Read the file if len > 0 */
493 res = fread(&((
char *)
buf)[used], 1,
len, fh);
494 if (res !=
len && !feof(fh))
499 res = fread(&((
char *)
buf)[used], 1,
len, th->
nFH);
500 if (res !=
len && !feof(th->
nFH))
559 * Print data for a given file
586 * Print data for a given TOC entry
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.
609 /* Abort the COPY FROM stdin */
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\"",
622 /* Emit all but the FROM part ... */
624 /* ... and insert modified FROM */
625 ahprintf(AH,
" FROM '$$PATH$$/%s';\n\n", tctx->filename);
629 /* --inserts mode, no worries, just include the data file */
630 ahprintf(AH,
"\\i $$PATH$$/%s\n\n", tctx->filename);
636 if (strcmp(te->
desc,
"BLOBS") == 0)
649 bool foundLO =
false;
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.
666 /* We rely on atooid to not complain about nnnn..nnnn tags */
669 th =
tarOpen(AH,
buf,
'r');
/* Advance to first desired file */
672 th =
tarOpen(AH, NULL,
'r');
/* Open next file */
683 pg_log_info(
"restoring large object with OID %u", oid);
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.
721 char b =
i;
/* Avoid endian problems */
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");
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");
782 * Write the Header & TOC to the archive FIRST
784 th =
tarOpen(AH,
"toc.dat",
'w');
788 tarClose(AH, th);
/* Not needed any more */
791 * Now send the data (tables & LOs)
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');
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"
816 ropt->filename = NULL;
817 ropt->dropSchema = 1;
818 ropt->superuser = NULL;
819 ropt->suppressDumpWarnings =
true;
826 savVerbose = AH->public.
verbose;
833 AH->public.
verbose = savVerbose;
840 * EOF marker for tar files is two blocks of NULLs.
844 if (fputc(0, ctx->
tarFH) == EOF)
848 /* Sync the output file if one is defined */
849 if (AH->dosync && AH->fSpec)
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.
889 * Called by the archiver when the dumper calls StartLO.
893 * Must save the passed OID for retrieval at restore-time.
903 pg_fatal(
"invalid OID for large object (%u)", oid);
906 pg_fatal(
"compression is not supported by tar archive format");
908 sprintf(fname,
"blob_%u.dat", oid);
912 tctx->TH =
tarOpen(AH, fname,
'w');
916 * Called by the archiver when the dumper calls EndLO.
930 * Called by the archiver when finishing saving BLOB DATA.
940 /* Write out a fake zero OID to mark end-of-LOs. */
941 /* WriteInt(AH, 0); */
956 int save_errno = errno;
958 size_t len = 128;
/* initial assumption about buffer size */
965 /* Allocate work buffer. */
968 /* Try to format the data. */
977 /* Release buffer and loop around to try again with larger len. */
998 /* POSIX tar format */
1002 /* GNU tar format */
1005 /* not-quite-POSIX format written by pre-9.3 pg_dump */
1012/* Given the member, write the TAR header & copy the file */
1017 FILE *tmp = th->
tmpFH;
/* Grab it for convenience */
1026 * Find file len & go back to start.
1029 pg_fatal(
"error during file seek: %m");
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");
1038 while ((cnt = fread(
buf, 1,
sizeof(
buf), tmp)) > 0)
1040 if ((res = fwrite(
buf, 1, cnt, th->
tarFH)) != cnt)
1047 if (fclose(tmp) != 0)
/* This *should* delete it... */
1048 pg_fatal(
"could not close temporary file: %m");
1051 pg_fatal(
"actual file length (%lld) does not match expected (%lld)",
1055 for (
i = 0;
i < pad;
i++)
1057 if (fputc(
'0円', th->
tarFH) == EOF)
1064/* Locate the file in the archive, read header and position to data */
1079 /* Go to end of current file, if any */
1082 pg_log_debug(
"moving from position %lld to next member at file position %lld",
1091 /* We are at the start of the file, or at the next member */
1093 /* Get the header */
1097 pg_fatal(
"could not find header for file \"%s\" in tar archive",
filename);
1101 * We're just scanning the archive for the next file, so return
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.",
1119 /* Header doesn't match, so read to next header */
1124 for (
i = 0;
i < blks;
i++)
1128 pg_fatal(
"could not find header for file \"%s\" in tar archive",
filename);
1138/* Read & verify a header */
1149 bool gotBlock =
false;
1153 /* Save the pos for reporting purposes */
1156 /* Read the next tar block, return EOF, exit if short */
1158 if (
len == 0)
/* EOF */
1163 "incomplete tar header found (%lu bytes)",
1165 (
unsigned long)
len);
1172 * If the checksum failed, see if it is a null block. If so, silently
1173 * continue to the next block.
1192 /* Name field is 100 bytes, might not be null-terminated */
1197 pg_log_debug(
"TOC Entry %s at %llu (length %llu, checksum %d)",
1198 tag, (
unsigned long long) hPos, (
unsigned long long)
len, 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));
1217 0600, 04000, 02000, time(NULL));
1219 /* Now write the completed header. */
#define ngettext(s, p, n)
#define pg_attribute_printf(f, a)
void fsync_fname(const char *fname, bool isdir)
void * pg_malloc(size_t size)
char * pg_strdup(const char *in)
#define pg_malloc0_object(type)
Assert(PointerIsAligned(start, uint64))
if(TABLE==NULL||TABLE_index==NULL)
#define pg_log_debug(...)
RestoreOptions * NewRestoreOptions(void)
void SetArchiveOptions(Archive *AH, DumpOptions *dopt, RestoreOptions *ropt)
void RestoreArchive(Archive *AHX)
int TocIDRequired(ArchiveHandle *AH, DumpId id)
void ahwrite(const void *ptr, size_t size, size_t nmemb, ArchiveHandle *AH)
void WriteHead(ArchiveHandle *AH)
char * ReadStr(ArchiveHandle *AH)
void StartRestoreLOs(ArchiveHandle *AH)
void WriteDataChunks(ArchiveHandle *AH, ParallelState *pstate)
int ahprintf(ArchiveHandle *AH, const char *fmt,...)
void ReadHead(ArchiveHandle *AH)
void ReadToc(ArchiveHandle *AH)
void EndRestoreLO(ArchiveHandle *AH, Oid oid)
void WriteToc(ArchiveHandle *AH)
void EndRestoreLOs(ArchiveHandle *AH)
void StartRestoreLO(ArchiveHandle *AH, Oid oid, bool drop)
size_t WriteStr(ArchiveHandle *AH, const char *c)
#define READ_ERROR_EXIT(fd)
static void _PrintTocData(ArchiveHandle *AH, TocEntry *te)
static void _StartData(ArchiveHandle *AH, TocEntry *te)
static size_t tarRead(void *buf, size_t len, TAR_MEMBER *th)
static void _PrintExtraToc(ArchiveHandle *AH, TocEntry *te)
static void _WriteData(ArchiveHandle *AH, const void *data, size_t dLen)
static void _ArchiveEntry(ArchiveHandle *AH, TocEntry *te)
static void _CloseArchive(ArchiveHandle *AH)
static int tarPrintf(TAR_MEMBER *th, const char *fmt,...) pg_attribute_printf(2
static void _tarWriteHeader(TAR_MEMBER *th)
static void _StartLOs(ArchiveHandle *AH, TocEntry *te)
void InitArchiveFmt_Tar(ArchiveHandle *AH)
static size_t _tarReadRaw(ArchiveHandle *AH, void *buf, size_t len, TAR_MEMBER *th, FILE *fh)
static void _WriteExtraToc(ArchiveHandle *AH, TocEntry *te)
static void _EndLO(ArchiveHandle *AH, TocEntry *te, Oid oid)
static void _EndLOs(ArchiveHandle *AH, TocEntry *te)
static int _WriteByte(ArchiveHandle *AH, const int i)
static void _StartLO(ArchiveHandle *AH, TocEntry *te, Oid oid)
static int _ReadByte(ArchiveHandle *AH)
bool isValidTarHeader(char *header)
static void _ReadExtraToc(ArchiveHandle *AH, TocEntry *te)
static void _ReadBuf(ArchiveHandle *AH, void *buf, size_t len)
static TAR_MEMBER * tarOpen(ArchiveHandle *AH, const char *filename, char mode)
static void _EndData(ArchiveHandle *AH, TocEntry *te)
static size_t tarWrite(const void *buf, size_t len, TAR_MEMBER *th)
static int _tarGetHeader(ArchiveHandle *AH, TAR_MEMBER *th)
static size_t _scriptOut(ArchiveHandle *AH, const void *buf, size_t len)
static TAR_MEMBER * _tarPositionTo(ArchiveHandle *AH, const char *filename)
static void _PrintFileData(ArchiveHandle *AH, char *filename)
static int static void _tarAddFile(ArchiveHandle *AH, TAR_MEMBER *th)
static void _LoadLOs(ArchiveHandle *AH, TocEntry *te)
static void _WriteBuf(ArchiveHandle *AH, const void *buf, size_t len)
static void tarClose(ArchiveHandle *AH, TAR_MEMBER *th)
static PgChecksumMode mode
uint64 read_tar_number(const char *s, int len)
static size_t tarPaddingBytesRequired(size_t len)
int tarChecksum(char *header)
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)
size_t strlcpy(char *dst, const char *src, size_t siz)
static int fd(const char *x, int i)
size_t pvsnprintf(char *buf, size_t len, const char *fmt, va_list args)
CustomOutPtrType CustomOutPtr
pg_compress_specification compression_spec
struct _tocEntry * currToc
pg_compress_algorithm algorithm
static void * fn(void *arg)
#define fseeko(stream, offset, origin)