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
23 * Modifications - 28-Jun-2000 - pjw@rhyme.com.au
27 *-------------------------------------------------------------------------
31 #include "pg_backup.h"
32 #include "pg_backup_archiver.h"
36 * Routines in the format interface
40 static void _ArchiveEntry(ArchiveHandle* AH, TocEntry* te);
41 static void _StartData(ArchiveHandle* AH, TocEntry* te);
42 static int _WriteData(ArchiveHandle* AH, const void* data, int dLen);
43 static void _EndData(ArchiveHandle* AH, TocEntry* te);
44 static int _WriteByte(ArchiveHandle* AH, const int i);
45 static int _ReadByte(ArchiveHandle* );
46 static int _WriteBuf(ArchiveHandle* AH, const void* buf, int len);
47 static int _ReadBuf(ArchiveHandle* AH, void* buf, int len);
48 static void _CloseArchive(ArchiveHandle* AH);
49 static void _PrintTocData(ArchiveHandle* AH, TocEntry* te, RestoreOptions *ropt);
50 static void _WriteExtraToc(ArchiveHandle* AH, TocEntry* te);
51 static void _ReadExtraToc(ArchiveHandle* AH, TocEntry* te);
52 static void _PrintExtraToc(ArchiveHandle* AH, TocEntry* te);
54 static void _PrintData(ArchiveHandle* AH);
55 static void _skipData(ArchiveHandle* AH);
56 static void _skipBlobs(ArchiveHandle* AH);
58 static void _StartBlobs(ArchiveHandle* AH, TocEntry* te);
59 static void _StartBlob(ArchiveHandle* AH, TocEntry* te, int oid);
60 static void _EndBlob(ArchiveHandle* AH, TocEntry* te, int oid);
61 static void _EndBlobs(ArchiveHandle* AH, TocEntry* te);
62 static void _LoadBlobs(ArchiveHandle* AH);
65 * Buffers used in zlib compression and extra data stored in archive and
69 #define zlibOutSize 4096
70 #define zlibInSize 4096
92 static void _readBlockHeader(ArchiveHandle *AH, int *type, int *id);
93 static void _StartDataCompressor(ArchiveHandle* AH, TocEntry* te);
94 static void _EndDataCompressor(ArchiveHandle* AH, TocEntry* te);
95 static int _getFilePos(ArchiveHandle* AH, lclContext* ctx);
96 static int _DoDeflate(ArchiveHandle* AH, lclContext* ctx, int flush);
98 static char* progname = "Archiver(custom)";
103 * Init routine required by ALL formats. This is a global routine
104 * and should be declared in pg_backup_archiver.h
106 * It's task is to create any extra archive context (using AH->formatData),
107 * and to initialize the supported function pointers.
109 * It should also prepare whatever it's input source is for reading/writing,
110 * and in the case of a read mode connection, it should load the Header & TOC.
112 void InitArchiveFmt_Custom(ArchiveHandle* AH)
116 /* Assuming static functions, this can be copied for each format. */
117 AH->ArchiveEntryPtr = _ArchiveEntry;
118 AH->StartDataPtr = _StartData;
119 AH->WriteDataPtr = _WriteData;
120 AH->EndDataPtr = _EndData;
121 AH->WriteBytePtr = _WriteByte;
122 AH->ReadBytePtr = _ReadByte;
123 AH->WriteBufPtr = _WriteBuf;
124 AH->ReadBufPtr = _ReadBuf;
125 AH->ClosePtr = _CloseArchive;
126 AH->PrintTocDataPtr = _PrintTocData;
127 AH->ReadExtraTocPtr = _ReadExtraToc;
128 AH->WriteExtraTocPtr = _WriteExtraToc;
129 AH->PrintExtraTocPtr = _PrintExtraToc;
131 AH->StartBlobsPtr = _StartBlobs;
132 AH->StartBlobPtr = _StartBlob;
133 AH->EndBlobPtr = _EndBlob;
134 AH->EndBlobsPtr = _EndBlobs;
137 * Set up some special context used in compressing data.
139 ctx = (lclContext*)malloc(sizeof(lclContext));
141 die_horribly(AH, "%s: Unable to allocate archive context",progname);
142 AH->formatData = (void*)ctx;
144 ctx->zp = (z_streamp)malloc(sizeof(z_stream));
146 die_horribly(AH, "%s: unable to allocate zlib stream archive context",progname);
148 ctx->zlibOut = (char*)malloc(zlibOutSize);
149 ctx->zlibIn = (char*)malloc(zlibInSize);
150 ctx->inSize = zlibInSize;
153 if (ctx->zlibOut == NULL || ctx->zlibIn == NULL)
154 die_horribly(AH, "%s: unable to allocate buffers in archive context",progname);
159 if (AH->mode == archModeWrite) {
161 if (AH->fSpec && strcmp(AH->fSpec,"") != 0) {
162 AH->FH = fopen(AH->fSpec, PG_BINARY_W);
168 die_horribly(AH, "%s: unable to open archive file %s",progname, AH->fSpec);
170 ctx->hasSeek = (fseek(AH->FH, 0, SEEK_CUR) == 0);
174 if (AH->fSpec && strcmp(AH->fSpec,"") != 0) {
175 AH->FH = fopen(AH->fSpec, PG_BINARY_R);
180 die_horribly(AH, "%s: unable to open archive file %s",progname, AH->fSpec);
182 ctx->hasSeek = (fseek(AH->FH, 0, SEEK_CUR) == 0);
186 ctx->dataStart = _getFilePos(AH, ctx);
192 * Called by the Archiver when the dumper creates a new TOC entry.
196 * Set up extrac format-related TOC data.
198 static void _ArchiveEntry(ArchiveHandle* AH, TocEntry* te)
202 ctx = (lclTocEntry*)calloc(1, sizeof(lclTocEntry));
203 if (te->dataDumper) {
209 te->formatData = (void*)ctx;
214 * Called by the Archiver to save any extra format-related TOC entry
219 * Use the Archiver routines to write data - they are non-endian, and
220 * maintain other important file information.
222 static void _WriteExtraToc(ArchiveHandle* AH, TocEntry* te)
224 lclTocEntry* ctx = (lclTocEntry*)te->formatData;
226 WriteInt(AH, ctx->dataPos);
227 WriteInt(AH, ctx->dataLen);
231 * Called by the Archiver to read any extra format-related TOC data.
235 * Needs to match the order defined in _WriteExtraToc, and sould also
236 * use the Archiver input routines.
238 static void _ReadExtraToc(ArchiveHandle* AH, TocEntry* te)
240 lclTocEntry* ctx = (lclTocEntry*)te->formatData;
243 ctx = (lclTocEntry*)malloc(sizeof(lclTocEntry));
244 te->formatData = (void*)ctx;
247 ctx->dataPos = ReadInt( AH );
248 ctx->dataLen = ReadInt( AH );
252 * Called by the Archiver when restoring an archive to output a comment
253 * that includes useful information about the TOC entry.
258 static void _PrintExtraToc(ArchiveHandle* AH, TocEntry* te)
260 lclTocEntry* ctx = (lclTocEntry*)te->formatData;
262 ahprintf(AH, "-- Data Pos: %d (Length %d)\n", ctx->dataPos, ctx->dataLen);
266 * Called by the archiver when saving TABLE DATA (not schema). This routine
267 * should save whatever format-specific information is needed to read
270 * It is called just prior to the dumper's 'DataDumper' routine being called.
272 * Optional, but strongly recommended.
275 static void _StartData(ArchiveHandle* AH, TocEntry* te)
277 lclContext* ctx = (lclContext*)AH->formatData;
278 lclTocEntry* tctx = (lclTocEntry*)te->formatData;
280 tctx->dataPos = _getFilePos(AH, ctx);
282 _WriteByte(AH, BLK_DATA); /* Block type */
283 WriteInt(AH, te->id); /* For sanity check */
285 _StartDataCompressor(AH, te);
290 * Called by archiver when dumper calls WriteData. This routine is
291 * called for both BLOB and TABLE data; it is the responsibility of
292 * the format to manage each kind of data using StartBlob/StartData.
294 * It should only be called from withing a DataDumper routine.
299 static int _WriteData(ArchiveHandle* AH, const void* data, int dLen)
301 lclContext* ctx = (lclContext*)AH->formatData;
302 z_streamp zp = ctx->zp;
304 zp->next_in = (void*)data;
307 while (zp->avail_in != 0) {
308 /* printf("Deflating %d bytes\n", dLen); */
309 _DoDeflate(AH, ctx, 0);
315 * Called by the archiver when a dumper's 'DataDumper' routine has
321 static void _EndData(ArchiveHandle* AH, TocEntry* te)
323 lclContext* ctx = (lclContext*)AH->formatData;
324 lclTocEntry* tctx = (lclTocEntry*) te->formatData;
326 _EndDataCompressor(AH, te);
328 tctx->dataLen = _getFilePos(AH, ctx) - tctx->dataPos;
332 * Called by the archiver when starting to save all BLOB DATA (not schema).
333 * This routine should save whatever format-specific information is needed
334 * to read the BLOBs back into memory.
336 * It is called just prior to the dumper's DataDumper routine.
338 * Optional, but strongly recommended.
341 static void _StartBlobs(ArchiveHandle* AH, TocEntry* te)
343 lclContext* ctx = (lclContext*)AH->formatData;
344 lclTocEntry* tctx = (lclTocEntry*)te->formatData;
346 tctx->dataPos = _getFilePos(AH, ctx);
348 _WriteByte(AH, BLK_BLOBS); /* Block type */
349 WriteInt(AH, te->id); /* For sanity check */
354 * Called by the archiver when the dumper calls StartBlob.
358 * Must save the passed OID for retrieval at restore-time.
360 static void _StartBlob(ArchiveHandle* AH, TocEntry* te, int oid)
363 die_horribly(AH, "%s: illegal OID for BLOB (%d)\n", progname, oid);
366 _StartDataCompressor(AH, te);
370 * Called by the archiver when the dumper calls EndBlob.
375 static void _EndBlob(ArchiveHandle* AH, TocEntry* te, int oid)
377 _EndDataCompressor(AH, te);
381 * Called by the archiver when finishing saving all BLOB DATA.
386 static void _EndBlobs(ArchiveHandle* AH, TocEntry* te)
388 /* Write out a fake zero OID to mark end-of-blobs. */
393 * Print data for a gievn TOC entry
395 static void _PrintTocData(ArchiveHandle* AH, TocEntry* te, RestoreOptions *ropt)
397 lclContext* ctx = (lclContext*)AH->formatData;
399 lclTocEntry* tctx = (lclTocEntry*) te->formatData;
403 if (tctx->dataPos == 0)
406 if (!ctx->hasSeek || tctx->dataPos < 0) {
408 /* Skip over unnecessary blocks until we get the one we want. */
412 _readBlockHeader(AH, &blkType, &id);
414 while (id != te->id) {
416 if ( (TocIDRequired(AH, id, ropt) & 2) != 0)
417 die_horribly(AH, "%s: Dumping a specific TOC data block out of order is not supported"
418 " without on this input stream (fseek required)\n", progname);
432 default: /* Always have a default */
434 die_horribly(AH, "%s: unrecognized data block type while searching archive %d\n",
439 _readBlockHeader(AH, &blkType, &id);
447 if (fseek(AH->FH, tctx->dataPos, SEEK_SET) != 0)
448 die_horribly(AH, "%s: error %d in file seek\n",progname, errno);
450 _readBlockHeader(AH, &blkType, &id);
456 die_horribly(AH, "%s: Found unexpected block ID (%d) when reading data - expected %d\n",
457 progname, id, te->id);
469 die_horribly(AH, "%s: BLOBs can not be loaded without a database connection\n", progname);
474 default: /* Always have a default */
476 die_horribly(AH, "%s: unrecognized data block type %d while restoring archive\n",
481 ahprintf(AH, "\n\n");
485 * Print data from current file position.
487 static void _PrintData(ArchiveHandle* AH)
489 lclContext* ctx = (lclContext*)AH->formatData;
490 z_streamp zp = ctx->zp;
492 char* in = ctx->zlibIn;
496 char* out = ctx->zlibOut;
503 if (AH->compression != 0) {
508 if (inflateInit(zp) != Z_OK)
509 die_horribly(AH, "%s: could not initialize compression library - %s\n", progname, zp->msg);
514 blkLen = ReadInt(AH);
515 while (blkLen != 0) {
516 if (blkLen > (ctx->inSize - 1)) {
519 ctx->zlibIn = (char*)malloc(blkLen);
521 die_horribly(AH, "%s: failed to allocate decompression buffer\n", progname);
523 ctx->inSize = blkLen;
527 cnt = fread(in, 1, blkLen, AH->FH);
529 die_horribly(AH, "%s: could not read data block - expected %d, got %d\n", progname, blkLen, cnt);
531 ctx->filePos += blkLen;
534 zp->avail_in = blkLen;
538 if (AH->compression != 0) {
540 while (zp->avail_in != 0) {
542 zp->avail_out = zlibOutSize;
543 res = inflate(zp, 0);
544 if (res != Z_OK && res != Z_STREAM_END)
545 die_horribly(AH, "%s: unable to uncompress data - %s\n", progname, zp->msg);
547 out[zlibOutSize - zp->avail_out] = '\0';
548 ahwrite(out, 1, zlibOutSize - zp->avail_out, AH);
552 in[zp->avail_in] = '\0';
553 ahwrite(in, 1, zp->avail_in, AH);
560 blkLen = ReadInt(AH);
565 if (AH->compression != 0)
569 while (res != Z_STREAM_END) {
571 zp->avail_out = zlibOutSize;
572 res = inflate(zp, 0);
573 if (res != Z_OK && res != Z_STREAM_END)
574 die_horribly(AH, "%s: unable to uncompress data - %s\n", progname, zp->msg);
576 out[zlibOutSize - zp->avail_out] = '\0';
577 ahwrite(out, 1, zlibOutSize - zp->avail_out, AH);
584 static void _LoadBlobs(ArchiveHandle* AH)
591 StartRestoreBlob(AH, oid);
593 EndRestoreBlob(AH, oid);
599 * Skip the BLOBs from the current file position.
600 * BLOBS are written sequentially as data blocks (see below).
601 * Each BLOB is preceded by it's original OID.
602 * A zero OID indicated the end of the BLOBS
604 static void _skipBlobs(ArchiveHandle* AH)
617 * Skip data from current file position.
618 * Data blocks are formatted as an integer length, followed by data.
619 * A zero length denoted the end of the block.
621 static void _skipData(ArchiveHandle* AH)
623 lclContext* ctx = (lclContext*)AH->formatData;
625 char* in = ctx->zlibIn;
628 blkLen = ReadInt(AH);
629 while (blkLen != 0) {
630 if (blkLen > ctx->inSize) {
632 ctx->zlibIn = (char*)malloc(blkLen);
633 ctx->inSize = blkLen;
636 cnt = fread(in, 1, blkLen, AH->FH);
638 die_horribly(AH, "%s: could not read data block - expected %d, got %d\n", progname, blkLen, cnt);
640 ctx->filePos += blkLen;
642 blkLen = ReadInt(AH);
648 * Write a byte of data to the archive.
652 * Called by the archiver to do integer & byte output to the archive.
653 * These routines are only used to read & write headers & TOC.
656 static int _WriteByte(ArchiveHandle* AH, const int i)
658 lclContext* ctx = (lclContext*)AH->formatData;
661 res = fputc(i, AH->FH);
669 * Read a byte of data from the archive.
673 * Called by the archiver to read bytes & integers from the archive.
674 * These routines are only used to read & write headers & TOC.
677 static int _ReadByte(ArchiveHandle* AH)
679 lclContext* ctx = (lclContext*)AH->formatData;
690 * Write a buffer of data to the archive.
694 * Called by the archiver to write a block of bytes to the archive.
695 * These routines are only used to read & write headers & TOC.
698 static int _WriteBuf(ArchiveHandle* AH, const void* buf, int len)
700 lclContext* ctx = (lclContext*)AH->formatData;
702 res = fwrite(buf, 1, len, AH->FH);
708 * Read a block of bytes from the archive.
712 * Called by the archiver to read a block of bytes from the archive
713 * These routines are only used to read & write headers & TOC.
716 static int _ReadBuf(ArchiveHandle* AH, void* buf, int len)
718 lclContext* ctx = (lclContext*)AH->formatData;
720 res = fread(buf, 1, len, AH->FH);
730 * When writing the archive, this is the routine that actually starts
731 * the process of saving it to files. No data should be written prior
732 * to this point, since the user could sort the TOC after creating it.
734 * If an archive is to be written, this toutine must call:
735 * WriteHead to save the archive header
736 * WriteToc to save the TOC entries
737 * WriteDataChunks to save all DATA & BLOBs.
740 static void _CloseArchive(ArchiveHandle* AH)
742 lclContext* ctx = (lclContext*)AH->formatData;
745 if (AH->mode == archModeWrite) {
747 tpos = ftell(AH->FH);
749 ctx->dataStart = _getFilePos(AH, ctx);
751 /* This is not an essential operation - it is really only
752 * needed if we expect to be doing seeks to read the data back
753 * - it may be ok to just use the existing self-consistent block
757 fseek(AH->FH, tpos, SEEK_SET);
766 /*--------------------------------------------------
767 * END OF FORMAT CALLBACKS
768 *--------------------------------------------------
772 * Get the current position in the archive file.
774 static int _getFilePos(ArchiveHandle* AH, lclContext* ctx)
779 if (pos != ctx->filePos) {
780 fprintf(stderr, "Warning: ftell mismatch with filePos\n");
789 * Read a data block header. The format changed in V1.3, so we
790 * put the code here for simplicity.
792 static void _readBlockHeader(ArchiveHandle *AH, int *type, int *id)
794 if (AH->version < K_VERS_1_3)
797 *type = _ReadByte(AH);;
803 * If zlib is available, then startit up. This is called from
804 * StartData & StartBlob. The buffers are setup in the Init routine.
807 static void _StartDataCompressor(ArchiveHandle* AH, TocEntry* te)
809 lclContext* ctx = (lclContext*)AH->formatData;
810 z_streamp zp = ctx->zp;
814 if (AH->compression < 0 || AH->compression > 9) {
815 AH->compression = Z_DEFAULT_COMPRESSION;
818 if (AH->compression != 0) {
823 if (deflateInit(zp, AH->compression) != Z_OK)
824 die_horribly(AH, "%s: could not initialize compression library - %s\n",progname, zp->msg);
833 /* Just be paranoid - maye End is called after Start, with no Write */
834 zp->next_out = ctx->zlibOut;
835 zp->avail_out = zlibOutSize;
839 * Send compressed data to the output stream (via ahwrite).
840 * Each data chunk is preceded by it's length.
841 * In the case of Z0, or no zlib, just write the raw data.
844 static int _DoDeflate(ArchiveHandle* AH, lclContext* ctx, int flush)
846 z_streamp zp = ctx->zp;
849 char* out = ctx->zlibOut;
852 if (AH->compression != 0)
854 res = deflate(zp, flush);
855 if (res == Z_STREAM_ERROR)
856 die_horribly(AH, "%s: could not compress data - %s\n",progname, zp->msg);
858 if ( ( (flush == Z_FINISH) && (zp->avail_out < zlibOutSize) )
859 || (zp->avail_out == 0)
860 || (zp->avail_in != 0)
864 * Extra paranoia: avoid zero-length chunks since a zero
865 * length chunk is the EOF marker. This should never happen
868 if (zp->avail_out < zlibOutSize) {
869 /* printf("Wrote %d byte deflated chunk\n", zlibOutSize - zp->avail_out); */
870 WriteInt(AH, zlibOutSize - zp->avail_out);
871 fwrite(out, 1, zlibOutSize - zp->avail_out, AH->FH);
872 ctx->filePos += zlibOutSize - zp->avail_out;
875 zp->avail_out = zlibOutSize;
879 if (zp->avail_in > 0)
881 WriteInt(AH, zp->avail_in);
882 fwrite(zp->next_in, 1, zp->avail_in, AH->FH);
883 ctx->filePos += zp->avail_in;
887 if (flush == Z_FINISH)
904 * Terminate zlib context and flush it's buffers. If no zlib
908 static void _EndDataCompressor(ArchiveHandle* AH, TocEntry* te)
912 lclContext* ctx = (lclContext*)AH->formatData;
913 z_streamp zp = ctx->zp;
916 if (AH->compression != 0)
922 /* printf("Ending data output\n"); */
923 res = _DoDeflate(AH, ctx, Z_FINISH);
924 } while (res != Z_STREAM_END);
926 if (deflateEnd(zp) != Z_OK)
927 die_horribly(AH, "%s: error closing compression stream - %s\n", progname, zp->msg);
931 /* Send the end marker */