1 /*-------------------------------------------------------------------------
5 * Implements the custom output format.
7 * The comments with the routined in this code are a good place to
8 * understand how to write a new format.
10 * See the headers to pg_restore for more details.
12 * Copyright (c) 2000, Philip Warner
13 * Rights are granted to use this software in any way so long
14 * as this notice is not removed.
16 * The author is not responsible for loss or damages that may
17 * and any liability will be limited to the time taken to fix any
22 * $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_backup_custom.c,v 1.11 2001/04/25 07:03:19 pjw Exp $
24 * Modifications - 28-Jun-2000 - pjw@rhyme.com.au
28 * Modifications - 04-Jan-2001 - pjw@rhyme.com.au
30 * - Check results of IO routines more carefully.
32 *-------------------------------------------------------------------------
35 #include "pg_backup.h"
36 #include "pg_backup_archiver.h"
42 * Routines in the format interface
46 static void _ArchiveEntry(ArchiveHandle *AH, TocEntry *te);
47 static void _StartData(ArchiveHandle *AH, TocEntry *te);
48 static int _WriteData(ArchiveHandle *AH, const void *data, int dLen);
49 static void _EndData(ArchiveHandle *AH, TocEntry *te);
50 static int _WriteByte(ArchiveHandle *AH, const int i);
51 static int _ReadByte(ArchiveHandle *);
52 static int _WriteBuf(ArchiveHandle *AH, const void *buf, int len);
53 static int _ReadBuf(ArchiveHandle *AH, void *buf, int len);
54 static void _CloseArchive(ArchiveHandle *AH);
55 static void _PrintTocData(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt);
56 static void _WriteExtraToc(ArchiveHandle *AH, TocEntry *te);
57 static void _ReadExtraToc(ArchiveHandle *AH, TocEntry *te);
58 static void _PrintExtraToc(ArchiveHandle *AH, TocEntry *te);
60 static void _PrintData(ArchiveHandle *AH);
61 static void _skipData(ArchiveHandle *AH);
62 static void _skipBlobs(ArchiveHandle *AH);
64 static void _StartBlobs(ArchiveHandle *AH, TocEntry *te);
65 static void _StartBlob(ArchiveHandle *AH, TocEntry *te, Oid oid);
66 static void _EndBlob(ArchiveHandle *AH, TocEntry *te, Oid oid);
67 static void _EndBlobs(ArchiveHandle *AH, TocEntry *te);
68 static void _LoadBlobs(ArchiveHandle *AH);
71 * Buffers used in zlib compression and extra data stored in archive and
75 #define zlibOutSize 4096
76 #define zlibInSize 4096
100 static void _readBlockHeader(ArchiveHandle *AH, int *type, int *id);
101 static void _StartDataCompressor(ArchiveHandle *AH, TocEntry *te);
102 static void _EndDataCompressor(ArchiveHandle *AH, TocEntry *te);
103 static int _getFilePos(ArchiveHandle *AH, lclContext *ctx);
104 static int _DoDeflate(ArchiveHandle *AH, lclContext *ctx, int flush);
106 static char *progname = "Archiver(custom)";
111 * Init routine required by ALL formats. This is a global routine
112 * and should be declared in pg_backup_archiver.h
114 * It's task is to create any extra archive context (using AH->formatData),
115 * and to initialize the supported function pointers.
117 * It should also prepare whatever it's input source is for reading/writing,
118 * and in the case of a read mode connection, it should load the Header & TOC.
121 InitArchiveFmt_Custom(ArchiveHandle *AH)
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->PrintTocDataPtr = _PrintTocData;
136 AH->ReadExtraTocPtr = _ReadExtraToc;
137 AH->WriteExtraTocPtr = _WriteExtraToc;
138 AH->PrintExtraTocPtr = _PrintExtraToc;
140 AH->StartBlobsPtr = _StartBlobs;
141 AH->StartBlobPtr = _StartBlob;
142 AH->EndBlobPtr = _EndBlob;
143 AH->EndBlobsPtr = _EndBlobs;
146 * Set up some special context used in compressing data.
148 ctx = (lclContext *) malloc(sizeof(lclContext));
150 die_horribly(AH, "%s: Unable to allocate archive context", progname);
151 AH->formatData = (void *) ctx;
153 ctx->zp = (z_streamp) malloc(sizeof(z_stream));
155 die_horribly(AH, "%s: unable to allocate zlib stream archive context", progname);
158 * zlibOutSize is the buffer size we tell zlib it can output to. We
159 * actually allocate one extra byte because some routines want to
160 * append a trailing zero byte to the zlib output. The input buffer
161 * is expansible and is always of size ctx->inSize; zlibInSize is just
162 * the initial default size for it.
164 ctx->zlibOut = (char *) malloc(zlibOutSize + 1);
165 ctx->zlibIn = (char *) malloc(zlibInSize);
166 ctx->inSize = zlibInSize;
169 if (ctx->zlibOut == NULL || ctx->zlibIn == NULL)
170 die_horribly(AH, "%s: unable to allocate buffers in archive context", progname);
175 if (AH->mode == archModeWrite)
178 if (AH->fSpec && strcmp(AH->fSpec, "") != 0)
179 AH->FH = fopen(AH->fSpec, PG_BINARY_W);
184 die_horribly(AH, "%s: unable to open archive file %s", progname, AH->fSpec);
186 ctx->hasSeek = (fseek(AH->FH, 0, SEEK_CUR) == 0);
192 if (AH->fSpec && strcmp(AH->fSpec, "") != 0)
193 AH->FH = fopen(AH->fSpec, PG_BINARY_R);
197 die_horribly(AH, "%s: unable to open archive file %s", progname, AH->fSpec);
199 ctx->hasSeek = (fseek(AH->FH, 0, SEEK_CUR) == 0);
203 ctx->dataStart = _getFilePos(AH, ctx);
209 * Called by the Archiver when the dumper creates a new TOC entry.
213 * Set up extrac format-related TOC data.
216 _ArchiveEntry(ArchiveHandle *AH, TocEntry *te)
220 ctx = (lclTocEntry *) calloc(1, sizeof(lclTocEntry));
226 te->formatData = (void *) ctx;
231 * Called by the Archiver to save any extra format-related TOC entry
236 * Use the Archiver routines to write data - they are non-endian, and
237 * maintain other important file information.
240 _WriteExtraToc(ArchiveHandle *AH, TocEntry *te)
242 lclTocEntry *ctx = (lclTocEntry *) te->formatData;
244 WriteInt(AH, ctx->dataPos);
245 WriteInt(AH, ctx->dataLen);
249 * Called by the Archiver to read any extra format-related TOC data.
253 * Needs to match the order defined in _WriteExtraToc, and sould also
254 * use the Archiver input routines.
257 _ReadExtraToc(ArchiveHandle *AH, TocEntry *te)
259 lclTocEntry *ctx = (lclTocEntry *) te->formatData;
263 ctx = (lclTocEntry *) malloc(sizeof(lclTocEntry));
264 te->formatData = (void *) ctx;
267 ctx->dataPos = ReadInt(AH);
268 ctx->dataLen = ReadInt(AH);
272 * Called by the Archiver when restoring an archive to output a comment
273 * that includes useful information about the TOC entry.
279 _PrintExtraToc(ArchiveHandle *AH, TocEntry *te)
281 lclTocEntry *ctx = (lclTocEntry *) te->formatData;
283 ahprintf(AH, "-- Data Pos: %d (Length %d)\n", ctx->dataPos, ctx->dataLen);
287 * Called by the archiver when saving TABLE DATA (not schema). This routine
288 * should save whatever format-specific information is needed to read
291 * It is called just prior to the dumper's 'DataDumper' routine being called.
293 * Optional, but strongly recommended.
297 _StartData(ArchiveHandle *AH, TocEntry *te)
299 lclContext *ctx = (lclContext *) AH->formatData;
300 lclTocEntry *tctx = (lclTocEntry *) te->formatData;
302 tctx->dataPos = _getFilePos(AH, ctx);
304 _WriteByte(AH, BLK_DATA); /* Block type */
305 WriteInt(AH, te->id); /* For sanity check */
307 _StartDataCompressor(AH, te);
312 * Called by archiver when dumper calls WriteData. This routine is
313 * called for both BLOB and TABLE data; it is the responsibility of
314 * the format to manage each kind of data using StartBlob/StartData.
316 * It should only be called from withing a DataDumper routine.
322 _WriteData(ArchiveHandle *AH, const void *data, int dLen)
324 lclContext *ctx = (lclContext *) AH->formatData;
325 z_streamp zp = ctx->zp;
327 zp->next_in = (void *) data;
330 while (zp->avail_in != 0)
332 /* printf("Deflating %d bytes\n", dLen); */
333 _DoDeflate(AH, ctx, 0);
339 * Called by the archiver when a dumper's 'DataDumper' routine has
346 _EndData(ArchiveHandle *AH, TocEntry *te)
348 lclContext *ctx = (lclContext *) AH->formatData;
349 lclTocEntry *tctx = (lclTocEntry *) te->formatData;
351 _EndDataCompressor(AH, te);
353 tctx->dataLen = _getFilePos(AH, ctx) - tctx->dataPos;
357 * Called by the archiver when starting to save all BLOB DATA (not schema).
358 * This routine should save whatever format-specific information is needed
359 * to read the BLOBs back into memory.
361 * It is called just prior to the dumper's DataDumper routine.
363 * Optional, but strongly recommended.
367 _StartBlobs(ArchiveHandle *AH, TocEntry *te)
369 lclContext *ctx = (lclContext *) AH->formatData;
370 lclTocEntry *tctx = (lclTocEntry *) te->formatData;
372 tctx->dataPos = _getFilePos(AH, ctx);
374 _WriteByte(AH, BLK_BLOBS); /* Block type */
375 WriteInt(AH, te->id); /* For sanity check */
380 * Called by the archiver when the dumper calls StartBlob.
384 * Must save the passed OID for retrieval at restore-time.
387 _StartBlob(ArchiveHandle *AH, TocEntry *te, Oid oid)
390 die_horribly(AH, "%s: illegal OID for BLOB (%d)\n", progname, oid);
393 _StartDataCompressor(AH, te);
397 * Called by the archiver when the dumper calls EndBlob.
403 _EndBlob(ArchiveHandle *AH, TocEntry *te, Oid oid)
405 _EndDataCompressor(AH, te);
409 * Called by the archiver when finishing saving all BLOB DATA.
415 _EndBlobs(ArchiveHandle *AH, TocEntry *te)
417 /* Write out a fake zero OID to mark end-of-blobs. */
422 * Print data for a gievn TOC entry
425 _PrintTocData(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt)
427 lclContext *ctx = (lclContext *) AH->formatData;
429 lclTocEntry *tctx = (lclTocEntry *) te->formatData;
433 if (tctx->dataPos == 0)
436 if (!ctx->hasSeek || tctx->dataPos < 0)
439 /* Skip over unnecessary blocks until we get the one we want. */
443 _readBlockHeader(AH, &blkType, &id);
448 if ((TocIDRequired(AH, id, ropt) & 2) != 0)
449 die_horribly(AH, "%s: Dumping a specific TOC data block out of order is not supported"
450 " without on this input stream (fseek required)\n", progname);
465 default: /* Always have a default */
467 die_horribly(AH, "%s: unrecognized data block type while searching archive %d\n",
472 _readBlockHeader(AH, &blkType, &id);
482 if (fseek(AH->FH, tctx->dataPos, SEEK_SET) != 0)
483 die_horribly(AH, "%s: error %d in file seek\n", progname, errno);
485 _readBlockHeader(AH, &blkType, &id);
491 die_horribly(AH, "%s: Found unexpected block ID (%d) when reading data - expected %d\n",
492 progname, id, te->id);
505 die_horribly(AH, "%s: BLOBs can not be loaded without a database connection\n", progname);
510 default: /* Always have a default */
512 die_horribly(AH, "%s: unrecognized data block type %d while restoring archive\n",
517 ahprintf(AH, "\n\n");
521 * Print data from current file position.
524 _PrintData(ArchiveHandle *AH)
526 lclContext *ctx = (lclContext *) AH->formatData;
527 z_streamp zp = ctx->zp;
529 char *in = ctx->zlibIn;
534 char *out = ctx->zlibOut;
542 if (AH->compression != 0)
548 if (inflateInit(zp) != Z_OK)
549 die_horribly(AH, "%s: could not initialize compression library - %s\n", progname, zp->msg);
554 blkLen = ReadInt(AH);
557 if (blkLen + 1 > ctx->inSize)
561 ctx->zlibIn = (char *) malloc(blkLen + 1);
563 die_horribly(AH, "%s: failed to allocate decompression buffer\n", progname);
565 ctx->inSize = blkLen + 1;
569 cnt = fread(in, 1, blkLen, AH->FH);
571 die_horribly(AH, "%s: could not read data block - expected %d, got %d\n", progname, blkLen, cnt);
573 ctx->filePos += blkLen;
576 zp->avail_in = blkLen;
580 if (AH->compression != 0)
583 while (zp->avail_in != 0)
586 zp->avail_out = zlibOutSize;
587 res = inflate(zp, 0);
588 if (res != Z_OK && res != Z_STREAM_END)
589 die_horribly(AH, "%s: unable to uncompress data - %s\n", progname, zp->msg);
591 out[zlibOutSize - zp->avail_out] = '\0';
592 ahwrite(out, 1, zlibOutSize - zp->avail_out, AH);
598 in[zp->avail_in] = '\0';
599 ahwrite(in, 1, zp->avail_in, AH);
606 blkLen = ReadInt(AH);
611 if (AH->compression != 0)
615 while (res != Z_STREAM_END)
618 zp->avail_out = zlibOutSize;
619 res = inflate(zp, 0);
620 if (res != Z_OK && res != Z_STREAM_END)
621 die_horribly(AH, "%s: unable to uncompress data - %s\n", progname, zp->msg);
623 out[zlibOutSize - zp->avail_out] = '\0';
624 ahwrite(out, 1, zlibOutSize - zp->avail_out, AH);
632 _LoadBlobs(ArchiveHandle *AH)
636 StartRestoreBlobs(AH);
641 StartRestoreBlob(AH, oid);
643 EndRestoreBlob(AH, oid);
652 * Skip the BLOBs from the current file position.
653 * BLOBS are written sequentially as data blocks (see below).
654 * Each BLOB is preceded by it's original OID.
655 * A zero OID indicated the end of the BLOBS
658 _skipBlobs(ArchiveHandle *AH)
671 * Skip data from current file position.
672 * Data blocks are formatted as an integer length, followed by data.
673 * A zero length denoted the end of the block.
676 _skipData(ArchiveHandle *AH)
678 lclContext *ctx = (lclContext *) AH->formatData;
680 char *in = ctx->zlibIn;
683 blkLen = ReadInt(AH);
686 if (blkLen > ctx->inSize)
689 ctx->zlibIn = (char *) malloc(blkLen);
690 ctx->inSize = blkLen;
693 cnt = fread(in, 1, blkLen, AH->FH);
695 die_horribly(AH, "%s: could not read data block - expected %d, got %d\n", progname, blkLen, cnt);
697 ctx->filePos += blkLen;
699 blkLen = ReadInt(AH);
705 * Write a byte of data to the archive.
709 * Called by the archiver to do integer & byte output to the archive.
710 * These routines are only used to read & write headers & TOC.
714 _WriteByte(ArchiveHandle *AH, const int i)
716 lclContext *ctx = (lclContext *) AH->formatData;
719 res = fputc(i, AH->FH);
723 die_horribly(AH, "%s: could not write byte./n", progname);
728 * Read a byte of data from the archive.
732 * Called by the archiver to read bytes & integers from the archive.
733 * These routines are only used to read & write headers & TOC.
737 _ReadByte(ArchiveHandle *AH)
739 lclContext *ctx = (lclContext *) AH->formatData;
749 * Write a buffer of data to the archive.
753 * Called by the archiver to write a block of bytes to the archive.
754 * These routines are only used to read & write headers & TOC.
758 _WriteBuf(ArchiveHandle *AH, const void *buf, int len)
760 lclContext *ctx = (lclContext *) AH->formatData;
763 res = fwrite(buf, 1, len, AH->FH);
766 die_horribly(AH, "%s: write error in _WriteBuf (%d != %d)\n", progname, res, len);
773 * Read a block of bytes from the archive.
777 * Called by the archiver to read a block of bytes from the archive
778 * These routines are only used to read & write headers & TOC.
782 _ReadBuf(ArchiveHandle *AH, void *buf, int len)
784 lclContext *ctx = (lclContext *) AH->formatData;
787 res = fread(buf, 1, len, AH->FH);
798 * When writing the archive, this is the routine that actually starts
799 * the process of saving it to files. No data should be written prior
800 * to this point, since the user could sort the TOC after creating it.
802 * If an archive is to be written, this toutine must call:
803 * WriteHead to save the archive header
804 * WriteToc to save the TOC entries
805 * WriteDataChunks to save all DATA & BLOBs.
809 _CloseArchive(ArchiveHandle *AH)
811 lclContext *ctx = (lclContext *) AH->formatData;
814 if (AH->mode == archModeWrite)
817 tpos = ftell(AH->FH);
819 ctx->dataStart = _getFilePos(AH, ctx);
823 * This is not an essential operation - it is really only needed
824 * if we expect to be doing seeks to read the data back - it may
825 * be ok to just use the existing self-consistent block
830 fseek(AH->FH, tpos, SEEK_SET);
835 if (fclose(AH->FH) != 0)
836 die_horribly(AH, "%s: could not close archive file\n", progname);
841 /*--------------------------------------------------
842 * END OF FORMAT CALLBACKS
843 *--------------------------------------------------
847 * Get the current position in the archive file.
850 _getFilePos(ArchiveHandle *AH, lclContext *ctx)
857 if (pos != ctx->filePos)
859 fprintf(stderr, "Warning: ftell mismatch with filePos - filePos used\n");
869 * Read a data block header. The format changed in V1.3, so we
870 * put the code here for simplicity.
873 _readBlockHeader(ArchiveHandle *AH, int *type, int *id)
875 if (AH->version < K_VERS_1_3)
878 *type = _ReadByte(AH);;
884 * If zlib is available, then startit up. This is called from
885 * StartData & StartBlob. The buffers are setup in the Init routine.
889 _StartDataCompressor(ArchiveHandle *AH, TocEntry *te)
891 lclContext *ctx = (lclContext *) AH->formatData;
892 z_streamp zp = ctx->zp;
896 if (AH->compression < 0 || AH->compression > 9)
897 AH->compression = Z_DEFAULT_COMPRESSION;
899 if (AH->compression != 0)
905 if (deflateInit(zp, AH->compression) != Z_OK)
906 die_horribly(AH, "%s: could not initialize compression library - %s\n", progname, zp->msg);
915 /* Just be paranoid - maybe End is called after Start, with no Write */
916 zp->next_out = ctx->zlibOut;
917 zp->avail_out = zlibOutSize;
921 * Send compressed data to the output stream (via ahwrite).
922 * Each data chunk is preceded by it's length.
923 * In the case of Z0, or no zlib, just write the raw data.
927 _DoDeflate(ArchiveHandle *AH, lclContext *ctx, int flush)
929 z_streamp zp = ctx->zp;
932 char *out = ctx->zlibOut;
935 if (AH->compression != 0)
937 res = deflate(zp, flush);
938 if (res == Z_STREAM_ERROR)
939 die_horribly(AH, "%s: could not compress data - %s\n", progname, zp->msg);
941 if (((flush == Z_FINISH) && (zp->avail_out < zlibOutSize))
942 || (zp->avail_out == 0)
943 || (zp->avail_in != 0)
948 * Extra paranoia: avoid zero-length chunks since a zero
949 * length chunk is the EOF marker. This should never happen
952 if (zp->avail_out < zlibOutSize)
956 * printf("Wrote %d byte deflated chunk\n", zlibOutSize -
959 WriteInt(AH, zlibOutSize - zp->avail_out);
960 if (fwrite(out, 1, zlibOutSize - zp->avail_out, AH->FH) != (zlibOutSize - zp->avail_out))
961 die_horribly(AH, "%s: could not write compressed chunk\n", progname);
962 ctx->filePos += zlibOutSize - zp->avail_out;
965 zp->avail_out = zlibOutSize;
971 if (zp->avail_in > 0)
973 WriteInt(AH, zp->avail_in);
974 if (fwrite(zp->next_in, 1, zp->avail_in, AH->FH) != zp->avail_in)
975 die_horribly(AH, "%s: could not write uncompressed chunk\n", progname);
976 ctx->filePos += zp->avail_in;
982 if (flush == Z_FINISH)
999 * Terminate zlib context and flush it's buffers. If no zlib
1004 _EndDataCompressor(ArchiveHandle *AH, TocEntry *te)
1008 lclContext *ctx = (lclContext *) AH->formatData;
1009 z_streamp zp = ctx->zp;
1012 if (AH->compression != 0)
1019 /* printf("Ending data output\n"); */
1020 res = _DoDeflate(AH, ctx, Z_FINISH);
1021 } while (res != Z_STREAM_END);
1023 if (deflateEnd(zp) != Z_OK)
1024 die_horribly(AH, "%s: error closing compression stream - %s\n", progname, zp->msg);
1028 /* Send the end marker */