summaryrefslogtreecommitdiff
path: root/src/bin/pg_dump/pg_backup_tar.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/bin/pg_dump/pg_backup_tar.c')
-rw-r--r--src/bin/pg_dump/pg_backup_tar.c1260
1 files changed, 0 insertions, 1260 deletions
diff --git a/src/bin/pg_dump/pg_backup_tar.c b/src/bin/pg_dump/pg_backup_tar.c
deleted file mode 100644
index 5b48ca8b99e..00000000000
--- a/src/bin/pg_dump/pg_backup_tar.c
+++ /dev/null
@@ -1,1260 +0,0 @@
-/*-------------------------------------------------------------------------
- *
- * pg_backup_tar.c
- *
- * This file is copied from the 'files' format file, but dumps data into
- * one temp file then sends it to the output TAR archive.
- *
- * See the headers to pg_backup_files & pg_restore for more details.
- *
- * Copyright (c) 2000, Philip Warner
- * Rights are granted to use this software in any way so long
- * as this notice is not removed.
- *
- * The author is not responsible for loss or damages that may
- * result from it's use.
- *
- *
- * IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_backup_tar.c,v 1.23 2002/05/29 01:38:56 tgl Exp $
- *
- * Modifications - 28-Jun-2000 - pjw@rhyme.com.au
- *
- * Initial version.
- *
- * Modifications - 04-Jan-2001 - pjw@rhyme.com.au
- *
- * - Check results of IO routines more carefully.
- *
- *-------------------------------------------------------------------------
- */
-
-#include "pg_backup.h"
-#include "pg_backup_archiver.h"
-#include "pg_backup_tar.h"
-
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-#include <unistd.h>
-
-static void _ArchiveEntry(ArchiveHandle *AH, TocEntry *te);
-static void _StartData(ArchiveHandle *AH, TocEntry *te);
-static int _WriteData(ArchiveHandle *AH, const void *data, int dLen);
-static void _EndData(ArchiveHandle *AH, TocEntry *te);
-static int _WriteByte(ArchiveHandle *AH, const int i);
-static int _ReadByte(ArchiveHandle *);
-static int _WriteBuf(ArchiveHandle *AH, const void *buf, int len);
-static int _ReadBuf(ArchiveHandle *AH, void *buf, int len);
-static void _CloseArchive(ArchiveHandle *AH);
-static void _PrintTocData(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt);
-static void _WriteExtraToc(ArchiveHandle *AH, TocEntry *te);
-static void _ReadExtraToc(ArchiveHandle *AH, TocEntry *te);
-static void _PrintExtraToc(ArchiveHandle *AH, TocEntry *te);
-
-static void _StartBlobs(ArchiveHandle *AH, TocEntry *te);
-static void _StartBlob(ArchiveHandle *AH, TocEntry *te, Oid oid);
-static void _EndBlob(ArchiveHandle *AH, TocEntry *te, Oid oid);
-static void _EndBlobs(ArchiveHandle *AH, TocEntry *te);
-
-#define K_STD_BUF_SIZE 1024
-
-
-#ifdef HAVE_LIBZ
- /* typedef gzFile ThingFile; */
-typedef FILE ThingFile;
-
-#else
-typedef FILE ThingFile;
-#endif
-
-typedef struct
-{
- ThingFile *zFH;
- FILE *nFH;
- FILE *tarFH;
- FILE *tmpFH;
- char *targetFile;
- char mode;
- int pos;
- int fileLen;
- ArchiveHandle *AH;
-} TAR_MEMBER;
-
-typedef struct
-{
- int hasSeek;
- int filePos;
- TAR_MEMBER *blobToc;
- FILE *tarFH;
- int tarFHpos;
- int tarNextMember;
- TAR_MEMBER *FH;
- int isSpecialScript;
- TAR_MEMBER *scriptTH;
-} lclContext;
-
-typedef struct
-{
- TAR_MEMBER *TH;
- char *filename;
-} lclTocEntry;
-
-static char *modulename = gettext_noop("tar archiver");
-
-static void _LoadBlobs(ArchiveHandle *AH, RestoreOptions *ropt);
-
-static TAR_MEMBER *tarOpen(ArchiveHandle *AH, const char *filename, char mode);
-static void tarClose(ArchiveHandle *AH, TAR_MEMBER *TH);
-
-#ifdef __NOT_USED__
-static char *tarGets(char *buf, int len, TAR_MEMBER *th);
-#endif
-static int tarPrintf(ArchiveHandle *AH, TAR_MEMBER *th, const char *fmt,...);
-
-static void _tarAddFile(ArchiveHandle *AH, TAR_MEMBER *th);
-static int _tarChecksum(char *th);
-static TAR_MEMBER *_tarPositionTo(ArchiveHandle *AH, const char *filename);
-static int tarRead(void *buf, int len, TAR_MEMBER *th);
-static int tarWrite(const void *buf, int len, TAR_MEMBER *th);
-static void _tarWriteHeader(TAR_MEMBER *th);
-static int _tarGetHeader(ArchiveHandle *AH, TAR_MEMBER *th);
-static int _tarReadRaw(ArchiveHandle *AH, void *buf, int len, TAR_MEMBER *th, FILE *fh);
-
-static int _scriptOut(ArchiveHandle *AH, const void *buf, int len);
-
-/*
- * Initializer
- */
-void
-InitArchiveFmt_Tar(ArchiveHandle *AH)
-{
- lclContext *ctx;
-
- /* Assuming static functions, this can be copied for each format. */
- AH->ArchiveEntryPtr = _ArchiveEntry;
- AH->StartDataPtr = _StartData;
- AH->WriteDataPtr = _WriteData;
- AH->EndDataPtr = _EndData;
- AH->WriteBytePtr = _WriteByte;
- AH->ReadBytePtr = _ReadByte;
- AH->WriteBufPtr = _WriteBuf;
- AH->ReadBufPtr = _ReadBuf;
- AH->ClosePtr = _CloseArchive;
- AH->PrintTocDataPtr = _PrintTocData;
- AH->ReadExtraTocPtr = _ReadExtraToc;
- AH->WriteExtraTocPtr = _WriteExtraToc;
- AH->PrintExtraTocPtr = _PrintExtraToc;
-
- AH->StartBlobsPtr = _StartBlobs;
- AH->StartBlobPtr = _StartBlob;
- AH->EndBlobPtr = _EndBlob;
- AH->EndBlobsPtr = _EndBlobs;
-
- /*
- * Set up some special context used in compressing data.
- */
- ctx = (lclContext *) malloc(sizeof(lclContext));
- AH->formatData = (void *) ctx;
- ctx->filePos = 0;
-
- /* Initialize LO buffering */
- AH->lo_buf_size = LOBBUFSIZE;
- AH->lo_buf = (void *)malloc(LOBBUFSIZE);
- if(AH->lo_buf == NULL)
- die_horribly(AH, modulename, "out of memory\n");
-
- /*
- * Now open the TOC file
- */
- if (AH->mode == archModeWrite)
- {
-
- if (AH->fSpec && strcmp(AH->fSpec, "") != 0)
- ctx->tarFH = fopen(AH->fSpec, PG_BINARY_W);
- else
- ctx->tarFH = stdout;
-
- if (ctx->tarFH == NULL)
- die_horribly(NULL, modulename,
- "could not open TOC file for output: %s\n", strerror(errno));
-
- ctx->tarFHpos = 0;
-
- /*
- * Make unbuffered since we will dup() it, and the buffers screw
- * each other
- */
- /* setvbuf(ctx->tarFH, NULL, _IONBF, 0); */
-
- ctx->hasSeek = (fseek(ctx->tarFH, 0, SEEK_CUR) == 0);
-
- if (AH->compression < 0 || AH->compression > 9)
- AH->compression = Z_DEFAULT_COMPRESSION;
-
- /* Don't compress into tar files unless asked to do so */
- if (AH->compression == Z_DEFAULT_COMPRESSION)
- AH->compression = 0;
-
- /*
- * We don't support compression because reading the files back is
- * not possible since gzdopen uses buffered IO which totally
- * screws file positioning.
- */
- if (AH->compression != 0)
- die_horribly(NULL, modulename, "compression not supported by tar output format\n");
-
- }
- else
- { /* Read Mode */
-
- if (AH->fSpec && strcmp(AH->fSpec, "") != 0)
- ctx->tarFH = fopen(AH->fSpec, PG_BINARY_R);
- else
- ctx->tarFH = stdin;
-
- if (ctx->tarFH == NULL)
- die_horribly(NULL, modulename, "could not open TOC file for input: %s\n", strerror(errno));
-
- /*
- * Make unbuffered since we will dup() it, and the buffers screw
- * each other
- */
- /* setvbuf(ctx->tarFH, NULL, _IONBF, 0); */
-
- ctx->tarFHpos = 0;
-
- ctx->hasSeek = (fseek(ctx->tarFH, 0, SEEK_CUR) == 0);
-
- /*
- * Forcibly unmark the header as read since we use the lookahead
- * buffer
- */
- AH->readHeader = 0;
-
- ctx->FH = (void *) tarOpen(AH, "toc.dat", 'r');
- ReadHead(AH);
- ReadToc(AH);
- tarClose(AH, ctx->FH); /* Nothing else in the file... */
- }
-
-}
-
-/*
- * - Start a new TOC entry
- * Setup the output file name.
- */
-static void
-_ArchiveEntry(ArchiveHandle *AH, TocEntry *te)
-{
- lclTocEntry *ctx;
- char fn[K_STD_BUF_SIZE];
-
- ctx = (lclTocEntry *) malloc(sizeof(lclTocEntry));
- if (te->dataDumper != NULL)
- {
-#ifdef HAVE_LIBZ
- if (AH->compression == 0)
- sprintf(fn, "%d.dat", te->id);
- else
- sprintf(fn, "%d.dat.gz", te->id);
-#else
- sprintf(fn, "%d.dat", te->id);
-#endif
- ctx->filename = strdup(fn);
- }
- else
- {
- ctx->filename = NULL;
- ctx->TH = NULL;
- }
- te->formatData = (void *) ctx;
-}
-
-static void
-_WriteExtraToc(ArchiveHandle *AH, TocEntry *te)
-{
- lclTocEntry *ctx = (lclTocEntry *) te->formatData;
-
- if (ctx->filename)
- WriteStr(AH, ctx->filename);
- else
- WriteStr(AH, "");
-}
-
-static void
-_ReadExtraToc(ArchiveHandle *AH, TocEntry *te)
-{
- lclTocEntry *ctx = (lclTocEntry *) te->formatData;
-
- if (ctx == NULL)
- {
- ctx = (lclTocEntry *) malloc(sizeof(lclTocEntry));
- te->formatData = (void *) ctx;
- }
-
- ctx->filename = ReadStr(AH);
- if (strlen(ctx->filename) == 0)
- {
- free(ctx->filename);
- ctx->filename = NULL;
- }
- ctx->TH = NULL;
-}
-
-static void
-_PrintExtraToc(ArchiveHandle *AH, TocEntry *te)
-{
- lclTocEntry *ctx = (lclTocEntry *) te->formatData;
-
- if (ctx->filename != NULL)
- ahprintf(AH, "-- File: %s\n", ctx->filename);
-}
-
-static void
-_StartData(ArchiveHandle *AH, TocEntry *te)
-{
- lclTocEntry *tctx = (lclTocEntry *) te->formatData;
-
- tctx->TH = tarOpen(AH, tctx->filename, 'w');
-}
-
-static TAR_MEMBER *
-tarOpen(ArchiveHandle *AH, const char *filename, char mode)
-{
- lclContext *ctx = (lclContext *) AH->formatData;
- TAR_MEMBER *tm;
-
-#ifdef HAVE_LIBZ
- char fmode[10];
-#endif
-
- if (mode == 'r')
- {
- tm = _tarPositionTo(AH, filename);
- if (!tm) /* Not found */
- {
- if (filename) /* Couldn't find the requested file.
- * Future: DO SEEK(0) and retry. */
- die_horribly(AH, modulename, "could not find file %s in archive\n", filename);
- else
-/* Any file OK, non left, so return NULL */
- return NULL;
- }
-
-#ifdef HAVE_LIBZ
-
- if (AH->compression == 0)
- tm->nFH = ctx->tarFH;
- else
- die_horribly(AH, modulename, "compression support is disabled in this format\n");
- /* tm->zFH = gzdopen(dup(fileno(ctx->tarFH)), "rb"); */
-
-#else
-
- tm->nFH = ctx->tarFH;
-#endif
-
- }
- else
- {
- tm = calloc(1, sizeof(TAR_MEMBER));
-
- tm->tmpFH = tmpfile();
-
- if (tm->tmpFH == NULL)
- die_horribly(AH, modulename, "could not generate temporary file name: %s\n", strerror(errno));
-
-#ifdef HAVE_LIBZ
-
- if (AH->compression != 0)
- {
- sprintf(fmode, "wb%d", AH->compression);
- tm->zFH = gzdopen(dup(fileno(tm->tmpFH)), fmode);
- if (tm->zFH == NULL)
- die_horribly(AH, modulename, "could not gzdopen temporary file\n");
-
- }
- else
- tm->nFH = tm->tmpFH;
-
-#else
-
- tm->nFH = tm->tmpFH;
-#endif
-
- tm->AH = AH;
- tm->targetFile = strdup(filename);
- }
-
- tm->mode = mode;
- tm->tarFH = ctx->tarFH;
-
- return tm;
-
-}
-
-static void
-tarClose(ArchiveHandle *AH, TAR_MEMBER *th)
-{
- /*
- * Close the GZ file since we dup'd. This will flush the buffers.
- */
- if (AH->compression != 0)
- if (GZCLOSE(th->zFH) != 0)
- die_horribly(AH, modulename, "could not close tar member\n");
-
- if (th->mode == 'w')
- _tarAddFile(AH, th); /* This will close the temp file */
-
- /*
- * else Nothing to do for normal read since we don't dup() normal file
- * handle, and we don't use temp files.
- */
-
- if (th->targetFile)
- free(th->targetFile);
-
- th->nFH = NULL;
- th->zFH = NULL;
-}
-
-#ifdef __NOT_USED__
-static char *
-tarGets(char *buf, int len, TAR_MEMBER *th)
-{
- char *s;
- int cnt = 0;
- char c = ' ';
- int eof = 0;
-
- /* Can't read past logical EOF */
- if (len > (th->fileLen - th->pos))
- len = th->fileLen - th->pos;
-
- while (cnt < len && c != '\n')
- {
- if (_tarReadRaw(th->AH, &c, 1, th, NULL) <= 0)
- {
- eof = 1;
- break;
- }
- buf[cnt++] = c;
- }
-
- if (eof && cnt == 0)
- s = NULL;
- else
- {
- buf[cnt++] = '\0';
- s = buf;
- }
-
- if (s)
- {
- len = strlen(s);
- th->pos += len;
- }
-
- return s;
-}
-#endif
-
-/*
- * Just read bytes from the archive. This is the low level read routine
- * that is used for ALL reads on a tar file.
- */
-static int
-_tarReadRaw(ArchiveHandle *AH, void *buf, int len, TAR_MEMBER *th, FILE *fh)
-{
- lclContext *ctx = (lclContext *) AH->formatData;
- int avail;
- int used = 0;
- int res = 0;
-
- avail = AH->lookaheadLen - AH->lookaheadPos;
- if (avail > 0)
- {
- /* We have some lookahead bytes to use */
- if (avail >= len) /* Just use the lookahead buffer */
- used = len;
- else
- used = avail;
-
- /* Copy, and adjust buffer pos */
- memcpy(buf, AH->lookahead, used);
- AH->lookaheadPos += used;
-
- /* Adjust required length */
- len -= used;
- }
-
- /* Read the file if len > 0 */
- if (len > 0)
- {
- if (fh)
- res = fread(&((char *) buf)[used], 1, len, fh);
- else if (th)
- {
- if (th->zFH)
- res = GZREAD(&((char *) buf)[used], 1, len, th->zFH);
- else
- res = fread(&((char *) buf)[used], 1, len, th->nFH);
- }
- else
- die_horribly(AH, modulename, "neither th nor fh specified in tarReadRaw() (internal error)\n");
- }
-
-#if 0
- write_msg(modulename, "requested %d bytes, got %d from lookahead and %d from file\n",
- reqLen, used, res);
-#endif
-
- ctx->tarFHpos += res + used;
-
- return (res + used);
-}
-
-static int
-tarRead(void *buf, int len, TAR_MEMBER *th)
-{
- int res;
-
- if (th->pos + len > th->fileLen)
- len = th->fileLen - th->pos;
-
- if (len <= 0)
- return 0;
-
- res = _tarReadRaw(th->AH, buf, len, th, NULL);
-
- th->pos += res;
-
- return res;
-}
-
-static int
-tarWrite(const void *buf, int len, TAR_MEMBER *th)
-{
- int res;
-
- if (th->zFH != 0)
- res = GZWRITE((void *) buf, 1, len, th->zFH);
- else
- res = fwrite(buf, 1, len, th->nFH);
-
- if (res != len)
- die_horribly(th->AH, modulename,
- "could not write to tar member (wrote %d, attempted %d)\n", res, len);
-
- th->pos += res;
- return res;
-}
-
-static int
-_WriteData(ArchiveHandle *AH, const void *data, int dLen)
-{
- lclTocEntry *tctx = (lclTocEntry *) AH->currToc->formatData;
-
- dLen = tarWrite((void *) data, dLen, tctx->TH);
-
- return dLen;
-}
-
-static void
-_EndData(ArchiveHandle *AH, TocEntry *te)
-{
- lclTocEntry *tctx = (lclTocEntry *) te->formatData;
-
- /* Close the file */
- tarClose(AH, tctx->TH);
- tctx->TH = NULL;
-}
-
-/*
- * Print data for a given file
- */
-static void
-_PrintFileData(ArchiveHandle *AH, char *filename, RestoreOptions *ropt)
-{
- lclContext *ctx = (lclContext *) AH->formatData;
- char buf[4096];
- int cnt;
- TAR_MEMBER *th;
-
- if (!filename)
- return;
-
- th = tarOpen(AH, filename, 'r');
- ctx->FH = th;
-
- while ((cnt = tarRead(buf, 4095, th)) > 0)
- {
- buf[cnt] = '\0';
- ahwrite(buf, 1, cnt, AH);
- }
-
- tarClose(AH, th);
-}
-
-
-/*
- * Print data for a given TOC entry
-*/
-static void
-_PrintTocData(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt)
-{
- lclContext *ctx = (lclContext *) AH->formatData;
- lclTocEntry *tctx = (lclTocEntry *) te->formatData;
- char *tmpCopy;
- int i,
- pos1,
- pos2;
-
- if (!tctx->filename)
- return;
-
- if (ctx->isSpecialScript)
- {
- if (!te->copyStmt)
- return;
-
- /* Abort the default COPY */
- ahprintf(AH, "\\.\n");
-
- /* Get a copy of the COPY statement and clean it up */
- tmpCopy = strdup(te->copyStmt);
- for (i = 0; i < strlen(tmpCopy); i++)
- tmpCopy[i] = tolower((unsigned char) tmpCopy[i]);
-
- /*
- * This is very nasty; we don't know if the archive used WITH
- * OIDS, so we search the string for it in a paranoid sort of way.
- */
- if (strncmp(tmpCopy, "copy ", 5) != 0)
- die_horribly(AH, modulename,
- "bad COPY statement - could not find \"copy\" in string \"%s\"\n", tmpCopy);
-
- pos1 = 5;
- for (pos1 = 5; pos1 < strlen(tmpCopy); pos1++)
- if (tmpCopy[pos1] != ' ')
- break;
-
- if (tmpCopy[pos1] == '"')
- pos1 += 2;
-
- pos1 += strlen(te->name);
-
- for (pos2 = pos1; pos2 < strlen(tmpCopy); pos2++)
- if (strncmp(&tmpCopy[pos2], "from stdin", 10) == 0)
- break;
-
- if (pos2 >= strlen(tmpCopy))
- die_horribly(AH, modulename,
- "bad COPY statement - could not find \"from stdin\" in string \"%s\" starting at position %d\n",
- tmpCopy, pos1);
-
- ahwrite(tmpCopy, 1, pos2, AH); /* 'copy "table" [with oids]' */
- ahprintf(AH, " from '$$PATH$$/%s' %s", tctx->filename, &tmpCopy[pos2 + 10]);
-
- return;
- }
-
- if (strcmp(te->desc, "BLOBS") == 0)
- _LoadBlobs(AH, ropt);
- else
- _PrintFileData(AH, tctx->filename, ropt);
-}
-
-static void
-_LoadBlobs(ArchiveHandle *AH, RestoreOptions *ropt)
-{
- Oid oid;
- lclContext *ctx = (lclContext *) AH->formatData;
- TAR_MEMBER *th;
- int cnt;
- char buf[4096];
-
- StartRestoreBlobs(AH);
-
- th = tarOpen(AH, NULL, 'r'); /* Open next file */
- while (th != NULL)
- {
- ctx->FH = th;
-
- if (strncmp(th->targetFile, "blob_", 5) == 0)
- {
- oid = atooid(&th->targetFile[5]);
- if (oid != 0)
- {
- ahlog(AH, 1, "restoring large object OID %u\n", oid);
-
- StartRestoreBlob(AH, oid);
-
- while ((cnt = tarRead(buf, 4095, th)) > 0)
- {
- buf[cnt] = '\0';
- ahwrite(buf, 1, cnt, AH);
- }
- EndRestoreBlob(AH, oid);
- }
- }
-
- tarClose(AH, th);
-
- th = tarOpen(AH, NULL, 'r');
- }
-
- EndRestoreBlobs(AH);
-
-}
-
-
-static int
-_WriteByte(ArchiveHandle *AH, const int i)
-{
- lclContext *ctx = (lclContext *) AH->formatData;
- int res;
- char b = i; /* Avoid endian problems */
-
- res = tarWrite(&b, 1, ctx->FH);
- if (res != EOF)
- ctx->filePos += res;
- return res;
-}
-
-static int
-_ReadByte(ArchiveHandle *AH)
-{
- lclContext *ctx = (lclContext *) AH->formatData;
- int res;
- char c = '\0';
-
- res = tarRead(&c, 1, ctx->FH);
- if (res != EOF)
- ctx->filePos += res;
- return c;
-}
-
-static int
-_WriteBuf(ArchiveHandle *AH, const void *buf, int len)
-{
- lclContext *ctx = (lclContext *) AH->formatData;
- int res;
-
- res = tarWrite((void *) buf, len, ctx->FH);
- ctx->filePos += res;
- return res;
-}
-
-static int
-_ReadBuf(ArchiveHandle *AH, void *buf, int len)
-{
- lclContext *ctx = (lclContext *) AH->formatData;
- int res;
-
- res = tarRead(buf, len, ctx->FH);
- ctx->filePos += res;
- return res;
-}
-
-static void
-_CloseArchive(ArchiveHandle *AH)
-{
- lclContext *ctx = (lclContext *) AH->formatData;
- TAR_MEMBER *th;
- RestoreOptions *ropt;
- int savVerbose,
- i;
-
- if (AH->mode == archModeWrite)
- {
- /*
- * Write the Header & TOC to the archive FIRST
- */
- th = tarOpen(AH, "toc.dat", 'w');
- ctx->FH = th;
- WriteHead(AH);
- WriteToc(AH);
- tarClose(AH, th); /* Not needed any more */
-
- /*
- * Now send the data (tables & blobs)
- */
- WriteDataChunks(AH);
-
- /*
- * Now this format wants to append a script which does a full
- * restore if the files have been extracted.
- */
- th = tarOpen(AH, "restore.sql", 'w');
- tarPrintf(AH, th, "create temporary table pgdump_restore_path(p text);\n");
- tarPrintf(AH, th, "--\n"
- "-- NOTE:\n"
- "--\n"
- "-- File paths need to be edited. Search for $$PATH$$ and\n"
- "-- replace it with the path to the directory containing\n"
- "-- the extracted data files.\n"
- "--\n"
- "-- Edit the following to match the path where the\n"
- "-- tar archive has been extracted.\n"
- "--\n");
- tarPrintf(AH, th, "insert into pgdump_restore_path values('/tmp');\n\n");
-
- AH->CustomOutPtr = _scriptOut;
-
- ctx->isSpecialScript = 1;
- ctx->scriptTH = th;
-
- ropt = NewRestoreOptions();
- ropt->dropSchema = 1;
- ropt->compression = 0;
- ropt->superuser = NULL;
- ropt->suppressDumpWarnings = true;
-
- savVerbose = AH->public.verbose;
- AH->public.verbose = 0;
-
- RestoreArchive((Archive *) AH, ropt);
-
- AH->public.verbose = savVerbose;
-
- tarClose(AH, th);
-
- /* Add a block of NULLs since it's de-rigeur. */
- for (i = 0; i < 512; i++)
- {
- if (fputc(0, ctx->tarFH) == EOF)
- die_horribly(AH, modulename,
- "could not write null block at end of tar archive\n");
- }
-
- }
-
- AH->FH = NULL;
-}
-
-static int
-_scriptOut(ArchiveHandle *AH, const void *buf, int len)
-{
- lclContext *ctx = (lclContext *) AH->formatData;
-
- return tarWrite(buf, len, ctx->scriptTH);
-}
-
-/*
- * BLOB support
- */
-
-/*
- * Called by the archiver when starting to save all BLOB DATA (not schema).
- * This routine should save whatever format-specific information is needed
- * to read the BLOBs back into memory.
- *
- * It is called just prior to the dumper's DataDumper routine.
- *
- * Optional, but strongly recommended.
- *
- */
-static void
-_StartBlobs(ArchiveHandle *AH, TocEntry *te)
-{
- lclContext *ctx = (lclContext *) AH->formatData;
- char fname[K_STD_BUF_SIZE];
-
- sprintf(fname, "blobs.toc");
- ctx->blobToc = tarOpen(AH, fname, 'w');
-
-}
-
-/*
- * Called by the archiver when the dumper calls StartBlob.
- *
- * Mandatory.
- *
- * Must save the passed OID for retrieval at restore-time.
- */
-static void
-_StartBlob(ArchiveHandle *AH, TocEntry *te, Oid oid)
-{
- lclContext *ctx = (lclContext *) AH->formatData;
- lclTocEntry *tctx = (lclTocEntry *) te->formatData;
- char fname[255];
- char *sfx;
-
- if (oid == 0)
- die_horribly(AH, modulename, "invalid OID for large object (%u)\n", oid);
-
- if (AH->compression != 0)
- sfx = ".gz";
- else
- sfx = "";
-
- sprintf(fname, "blob_%u.dat%s", oid, sfx);
-
- tarPrintf(AH, ctx->blobToc, "%u %s\n", oid, fname);
-
- tctx->TH = tarOpen(AH, fname, 'w');
-
-}
-
-/*
- * Called by the archiver when the dumper calls EndBlob.
- *
- * Optional.
- *
- */
-static void
-_EndBlob(ArchiveHandle *AH, TocEntry *te, Oid oid)
-{
- lclTocEntry *tctx = (lclTocEntry *) te->formatData;
-
- tarClose(AH, tctx->TH);
-}
-
-/*
- * Called by the archiver when finishing saving all BLOB DATA.
- *
- * Optional.
- *
- */
-static void
-_EndBlobs(ArchiveHandle *AH, TocEntry *te)
-{
- lclContext *ctx = (lclContext *) AH->formatData;
-
- /* Write out a fake zero OID to mark end-of-blobs. */
- /* WriteInt(AH, 0); */
-
- tarClose(AH, ctx->blobToc);
-
-}
-
-
-
-/*------------
- * TAR Support
- *------------
- */
-
-static int
-tarPrintf(ArchiveHandle *AH, TAR_MEMBER *th, const char *fmt,...)
-{
- char *p = NULL;
- va_list ap;
- int bSize = strlen(fmt) + 256; /* Should be enough */
- int cnt = -1;
-
- /*
- * This is paranoid: deal with the possibility that vsnprintf is
- * willing to ignore trailing null
- */
-
- /*
- * or returns > 0 even if string does not fit. It may be the case that
- * it returns cnt = bufsize
- */
- while (cnt < 0 || cnt >= (bSize - 1))
- {
- if (p != NULL)
- free(p);
- bSize *= 2;
- p = (char *) malloc(bSize);
- if (p == NULL)
- die_horribly(AH, modulename, "out of memory\n");
- va_start(ap, fmt);
- cnt = vsnprintf(p, bSize, fmt, ap);
- va_end(ap);
- }
- cnt = tarWrite(p, cnt, th);
- free(p);
- return cnt;
-}
-
-static int
-_tarChecksum(char *header)
-{
- int i,
- sum;
-
- sum = 0;
- for (i = 0; i < 512; i++)
- if (i < 148 || i >= 156)
- sum += 0xFF & header[i];
- return sum + 256; /* Assume 8 blanks in checksum field */
-}
-
-int
-isValidTarHeader(char *header)
-{
- int sum;
- int chk = _tarChecksum(header);
-
- sscanf(&header[148], "%8o", &sum);
-
- return (sum == chk && strncmp(&header[257], "ustar ", 7) == 0);
-}
-
-/* Given the member, write the TAR header & copy the file */
-static void
-_tarAddFile(ArchiveHandle *AH, TAR_MEMBER *th)
-{
- lclContext *ctx = (lclContext *) AH->formatData;
- FILE *tmp = th->tmpFH; /* Grab it for convenience */
- char buf[32768];
- int cnt;
- int len = 0;
- int res;
- int i,
- pad;
-
- /*
- * Find file len & go back to start.
- */
- fseek(tmp, 0, SEEK_END);
- th->fileLen = ftell(tmp);
- fseek(tmp, 0, SEEK_SET);
-
- _tarWriteHeader(th);
-
- while ((cnt = fread(&buf[0], 1, 32767, tmp)) > 0)
- {
- res = fwrite(&buf[0], 1, cnt, th->tarFH);
- if (res != cnt)
- die_horribly(AH, modulename, "write error appending to tar archive (wrote %d, attempted %d)\n", res, cnt);
- len += res;
- }
-
- if (fclose(tmp) != 0) /* This *should* delete it... */
- die_horribly(AH, modulename, "could not close tar member: %s\n", strerror(errno));
-
- if (len != th->fileLen)
- die_horribly(AH, modulename, "actual file length (%d) does not match expected (%d)\n",
- len, th->pos);
-
- pad = ((len + 511) & ~511) - len;
- for (i = 0; i < pad; i++)
- {
- if (fputc('\0', th->tarFH) == EOF)
- die_horribly(AH, modulename, "could not output padding at end of tar member\n");
- }
-
- ctx->tarFHpos += len + pad;
-}
-
-/* Locate the file in the archive, read header and position to data */
-static TAR_MEMBER *
-_tarPositionTo(ArchiveHandle *AH, const char *filename)
-{
- lclContext *ctx = (lclContext *) AH->formatData;
- TAR_MEMBER *th = calloc(1, sizeof(TAR_MEMBER));
- char c;
- char header[512];
- int i,
- len,
- blks,
- id;
-
- th->AH = AH;
-
- /* Go to end of current file, if any */
- if (ctx->tarFHpos != 0)
- {
- ahlog(AH, 4, "moving from position %d (%x) to next member at file position %d (%x)\n",
- ctx->tarFHpos, ctx->tarFHpos,
- ctx->tarNextMember, ctx->tarNextMember);
-
- while (ctx->tarFHpos < ctx->tarNextMember)
- _tarReadRaw(AH, &c, 1, NULL, ctx->tarFH);
- }
-
- ahlog(AH, 4, "now at file position %d (%x)\n", ctx->tarFHpos, ctx->tarFHpos);
-
- /* We are at the start of the file. or at the next member */
-
- /* Get the header */
- if (!_tarGetHeader(AH, th))
- {
- if (filename)
- die_horribly(AH, modulename, "could not find header for file %s in tar archive\n", filename);
- else
-/* We're just scanning the archibe for the next file, so return null */
- {
- free(th);
- return NULL;
- }
- }
-
- while (filename != NULL && strcmp(th->targetFile, filename) != 0)
- {
- ahlog(AH, 4, "skipping tar member %s\n", th->targetFile);
-
- id = atoi(th->targetFile);
- if ((TocIDRequired(AH, id, AH->ropt) & 2) != 0)
- die_horribly(AH, modulename, "dumping data out of order is not supported in this archive format: "
- "%s is required, but comes before %s in the archive file.\n",
- th->targetFile, filename);
-
- /* Header doesn't match, so read to next header */
- len = ((th->fileLen + 511) & ~511); /* Padded length */
- blks = len >> 9; /* # of 512 byte blocks */
-
- for (i = 0; i < blks; i++)
- _tarReadRaw(AH, &header[0], 512, NULL, ctx->tarFH);
-
- if (!_tarGetHeader(AH, th))
- die_horribly(AH, modulename, "could not find header for file %s in tar archive\n", filename);
-
- }
-
- ctx->tarNextMember = ctx->tarFHpos + ((th->fileLen + 511) & ~511);
- th->pos = 0;
-
- return th;
-}
-
-/* Read & verify a header */
-static int
-_tarGetHeader(ArchiveHandle *AH, TAR_MEMBER *th)
-{
- lclContext *ctx = (lclContext *) AH->formatData;
- char h[512];
- char name[100];
- int sum,
- chk;
- int len;
- int hPos;
- int i;
- bool gotBlock = false;
-
- while (!gotBlock)
- {
-#if 0
- if (ftell(ctx->tarFH) != ctx->tarFHpos)
- die_horribly(AH, modulename,
- "mismatch in actual vs. predicted file position (%d vs. %d)\n",
- ftell(ctx->tarFH), ctx->tarFHpos);
-#endif
-
- /* Save the pos for reporting purposes */
- hPos = ctx->tarFHpos;
-
- /* Read a 512 byte block, return EOF, exit if short */
- len = _tarReadRaw(AH, &h[0], 512, NULL, ctx->tarFH);
- if (len == 0) /* EOF */
- return 0;
-
- if (len != 512)
- die_horribly(AH, modulename, "incomplete tar header found (%d bytes)\n", len);
-
- /* Calc checksum */
- chk = _tarChecksum(&h[0]);
-
- /*
- * If the checksum failed, see if it is a null block. If so, then
- * just try with next block...
- */
-
- if (chk == sum)
- gotBlock = true;
- else
- {
- for (i = 0; i < 512; i++)
- {
- if (h[0] != 0)
- {
- gotBlock = true;
- break;
- }
- }
- }
- }
-
- sscanf(&h[0], "%99s", &name[0]);
- sscanf(&h[124], "%12o", &len);
- sscanf(&h[148], "%8o", &sum);
-
- ahlog(AH, 3, "TOC Entry %s at %d (length %d, checksum %d)\n", &name[0], hPos, len, sum);
-
- if (chk != sum)
- die_horribly(AH, modulename,
- "corrupt tar header found in %s "
- "(expected %d (%o), computed %d (%o)) file position %ld (%lx)\n",
- &name[0], sum, sum, chk, chk, ftell(ctx->tarFH), ftell(ctx->tarFH));
-
- th->targetFile = strdup(name);
- th->fileLen = len;
-
- return 1;
-}
-
-static void
-_tarWriteHeader(TAR_MEMBER *th)
-{
- char h[512];
- int i;
- int lastSum = 0;
- int sum;
-
- for (i = 0; i < 512; i++)
- h[i] = '\0';
-
- /* Name 100 */
- sprintf(&h[0], "%.99s", th->targetFile);
-
- /* Mode 8 */
- sprintf(&h[100], "100600 ");
-
- /* User ID 8 */
- sprintf(&h[108], " 04000 ");
-
- /* Group 8 */
- sprintf(&h[116], " 02000 ");
-
- /* File size 12 */
- sprintf(&h[124], "%10o ", th->fileLen);
-
- /* Mod Time 12 */
- sprintf(&h[136], "%10o ", (int) time(NULL));
-
- /* Checksum 8 */
- sprintf(&h[148], "%6o ", lastSum);
-
- /* Type 1 */
- /* sprintf(&h[156], "%c", LF_NORMAL); */
- sprintf(&h[156], "0");
-
- /* Link name 100 (NULL) */
-
- /* Magic 8 */
- sprintf(&h[257], "ustar ");
-
- /*
- * GNU Version... sprintf(&h[257], "ustar"); sprintf(&h[263], "00");
- */
-
- /* User 32 */
- sprintf(&h[265], "%.31s", ""); /* How do I get username reliably?
- * Do I need to? */
-
- /* Group 32 */
- sprintf(&h[297], "%.31s", ""); /* How do I get group reliably? Do
- * I need to? */
-
- /* Maj Dev 8 */
- /* sprintf(&h[329], "%6o ", 0); */
-
- /* Min Dev */
- /* sprintf(&h[337], "%6o ", 0); */
-
-
- while ((sum = _tarChecksum(h)) != lastSum)
- {
- sprintf(&h[148], "%6o ", sum);
- lastSum = sum;
- }
-
- if (fwrite(h, 1, 512, th->tarFH) != 512)
- die_horribly(th->AH, modulename, "unable to write tar header\n");
-
-}