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.8 2001/03/19 02:35:28 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, int oid);
66 static void _EndBlob(ArchiveHandle* AH, TocEntry* te, int 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
98 static void _readBlockHeader(ArchiveHandle *AH, int *type, int *id);
99 static void _StartDataCompressor(ArchiveHandle* AH, TocEntry* te);
100 static void _EndDataCompressor(ArchiveHandle* AH, TocEntry* te);
101 static int _getFilePos(ArchiveHandle* AH, lclContext* ctx);
102 static int _DoDeflate(ArchiveHandle* AH, lclContext* ctx, int flush);
104 static char* progname = "Archiver(custom)";
109 * Init routine required by ALL formats. This is a global routine
110 * and should be declared in pg_backup_archiver.h
112 * It's task is to create any extra archive context (using AH->formatData),
113 * and to initialize the supported function pointers.
115 * It should also prepare whatever it's input source is for reading/writing,
116 * and in the case of a read mode connection, it should load the Header & TOC.
118 void InitArchiveFmt_Custom(ArchiveHandle* AH)
122 /* Assuming static functions, this can be copied for each format. */
123 AH->ArchiveEntryPtr = _ArchiveEntry;
124 AH->StartDataPtr = _StartData;
125 AH->WriteDataPtr = _WriteData;
126 AH->EndDataPtr = _EndData;
127 AH->WriteBytePtr = _WriteByte;
128 AH->ReadBytePtr = _ReadByte;
129 AH->WriteBufPtr = _WriteBuf;
130 AH->ReadBufPtr = _ReadBuf;
131 AH->ClosePtr = _CloseArchive;
132 AH->PrintTocDataPtr = _PrintTocData;
133 AH->ReadExtraTocPtr = _ReadExtraToc;
134 AH->WriteExtraTocPtr = _WriteExtraToc;
135 AH->PrintExtraTocPtr = _PrintExtraToc;
137 AH->StartBlobsPtr = _StartBlobs;
138 AH->StartBlobPtr = _StartBlob;
139 AH->EndBlobPtr = _EndBlob;
140 AH->EndBlobsPtr = _EndBlobs;
143 * Set up some special context used in compressing data.
145 ctx = (lclContext*)malloc(sizeof(lclContext));
147 die_horribly(AH, "%s: Unable to allocate archive context",progname);
148 AH->formatData = (void*)ctx;
150 ctx->zp = (z_streamp)malloc(sizeof(z_stream));
152 die_horribly(AH, "%s: unable to allocate zlib stream archive context",progname);
155 * zlibOutSize is the buffer size we tell zlib it can output to. We
156 * actually allocate one extra byte because some routines want to append
157 * a trailing zero byte to the zlib output. The input buffer is expansible
158 * and is always of size ctx->inSize; zlibInSize is just the initial
159 * default size for it.
161 ctx->zlibOut = (char*)malloc(zlibOutSize+1);
162 ctx->zlibIn = (char*)malloc(zlibInSize);
163 ctx->inSize = zlibInSize;
166 if (ctx->zlibOut == NULL || ctx->zlibIn == NULL)
167 die_horribly(AH, "%s: unable to allocate buffers in archive context",progname);
172 if (AH->mode == archModeWrite) {
174 if (AH->fSpec && strcmp(AH->fSpec,"") != 0) {
175 AH->FH = fopen(AH->fSpec, PG_BINARY_W);
181 die_horribly(AH, "%s: unable to open archive file %s",progname, AH->fSpec);
183 ctx->hasSeek = (fseek(AH->FH, 0, SEEK_CUR) == 0);
187 if (AH->fSpec && strcmp(AH->fSpec,"") != 0) {
188 AH->FH = fopen(AH->fSpec, PG_BINARY_R);
193 die_horribly(AH, "%s: unable to open archive file %s",progname, AH->fSpec);
195 ctx->hasSeek = (fseek(AH->FH, 0, SEEK_CUR) == 0);
199 ctx->dataStart = _getFilePos(AH, ctx);
205 * Called by the Archiver when the dumper creates a new TOC entry.
209 * Set up extrac format-related TOC data.
211 static void _ArchiveEntry(ArchiveHandle* AH, TocEntry* te)
215 ctx = (lclTocEntry*)calloc(1, sizeof(lclTocEntry));
216 if (te->dataDumper) {
222 te->formatData = (void*)ctx;
227 * Called by the Archiver to save any extra format-related TOC entry
232 * Use the Archiver routines to write data - they are non-endian, and
233 * maintain other important file information.
235 static void _WriteExtraToc(ArchiveHandle* AH, TocEntry* te)
237 lclTocEntry* ctx = (lclTocEntry*)te->formatData;
239 WriteInt(AH, ctx->dataPos);
240 WriteInt(AH, ctx->dataLen);
244 * Called by the Archiver to read any extra format-related TOC data.
248 * Needs to match the order defined in _WriteExtraToc, and sould also
249 * use the Archiver input routines.
251 static void _ReadExtraToc(ArchiveHandle* AH, TocEntry* te)
253 lclTocEntry* ctx = (lclTocEntry*)te->formatData;
256 ctx = (lclTocEntry*)malloc(sizeof(lclTocEntry));
257 te->formatData = (void*)ctx;
260 ctx->dataPos = ReadInt( AH );
261 ctx->dataLen = ReadInt( AH );
265 * Called by the Archiver when restoring an archive to output a comment
266 * that includes useful information about the TOC entry.
271 static void _PrintExtraToc(ArchiveHandle* AH, TocEntry* te)
273 lclTocEntry* ctx = (lclTocEntry*)te->formatData;
275 ahprintf(AH, "-- Data Pos: %d (Length %d)\n", ctx->dataPos, ctx->dataLen);
279 * Called by the archiver when saving TABLE DATA (not schema). This routine
280 * should save whatever format-specific information is needed to read
283 * It is called just prior to the dumper's 'DataDumper' routine being called.
285 * Optional, but strongly recommended.
288 static void _StartData(ArchiveHandle* AH, TocEntry* te)
290 lclContext* ctx = (lclContext*)AH->formatData;
291 lclTocEntry* tctx = (lclTocEntry*)te->formatData;
293 tctx->dataPos = _getFilePos(AH, ctx);
295 _WriteByte(AH, BLK_DATA); /* Block type */
296 WriteInt(AH, te->id); /* For sanity check */
298 _StartDataCompressor(AH, te);
303 * Called by archiver when dumper calls WriteData. This routine is
304 * called for both BLOB and TABLE data; it is the responsibility of
305 * the format to manage each kind of data using StartBlob/StartData.
307 * It should only be called from withing a DataDumper routine.
312 static int _WriteData(ArchiveHandle* AH, const void* data, int dLen)
314 lclContext* ctx = (lclContext*)AH->formatData;
315 z_streamp zp = ctx->zp;
317 zp->next_in = (void*)data;
320 while (zp->avail_in != 0) {
321 /* printf("Deflating %d bytes\n", dLen); */
322 _DoDeflate(AH, ctx, 0);
328 * Called by the archiver when a dumper's 'DataDumper' routine has
334 static void _EndData(ArchiveHandle* AH, TocEntry* te)
336 lclContext* ctx = (lclContext*)AH->formatData;
337 lclTocEntry* tctx = (lclTocEntry*) te->formatData;
339 _EndDataCompressor(AH, te);
341 tctx->dataLen = _getFilePos(AH, ctx) - tctx->dataPos;
345 * Called by the archiver when starting to save all BLOB DATA (not schema).
346 * This routine should save whatever format-specific information is needed
347 * to read the BLOBs back into memory.
349 * It is called just prior to the dumper's DataDumper routine.
351 * Optional, but strongly recommended.
354 static void _StartBlobs(ArchiveHandle* AH, TocEntry* te)
356 lclContext* ctx = (lclContext*)AH->formatData;
357 lclTocEntry* tctx = (lclTocEntry*)te->formatData;
359 tctx->dataPos = _getFilePos(AH, ctx);
361 _WriteByte(AH, BLK_BLOBS); /* Block type */
362 WriteInt(AH, te->id); /* For sanity check */
367 * Called by the archiver when the dumper calls StartBlob.
371 * Must save the passed OID for retrieval at restore-time.
373 static void _StartBlob(ArchiveHandle* AH, TocEntry* te, int oid)
376 die_horribly(AH, "%s: illegal OID for BLOB (%d)\n", progname, oid);
379 _StartDataCompressor(AH, te);
383 * Called by the archiver when the dumper calls EndBlob.
388 static void _EndBlob(ArchiveHandle* AH, TocEntry* te, int oid)
390 _EndDataCompressor(AH, te);
394 * Called by the archiver when finishing saving all BLOB DATA.
399 static void _EndBlobs(ArchiveHandle* AH, TocEntry* te)
401 /* Write out a fake zero OID to mark end-of-blobs. */
406 * Print data for a gievn TOC entry
408 static void _PrintTocData(ArchiveHandle* AH, TocEntry* te, RestoreOptions *ropt)
410 lclContext* ctx = (lclContext*)AH->formatData;
412 lclTocEntry* tctx = (lclTocEntry*) te->formatData;
416 if (tctx->dataPos == 0)
419 if (!ctx->hasSeek || tctx->dataPos < 0) {
421 /* Skip over unnecessary blocks until we get the one we want. */
425 _readBlockHeader(AH, &blkType, &id);
427 while (id != te->id) {
429 if ( (TocIDRequired(AH, id, ropt) & 2) != 0)
430 die_horribly(AH, "%s: Dumping a specific TOC data block out of order is not supported"
431 " without on this input stream (fseek required)\n", progname);
445 default: /* Always have a default */
447 die_horribly(AH, "%s: unrecognized data block type while searching archive %d\n",
452 _readBlockHeader(AH, &blkType, &id);
460 if (fseek(AH->FH, tctx->dataPos, SEEK_SET) != 0)
461 die_horribly(AH, "%s: error %d in file seek\n",progname, errno);
463 _readBlockHeader(AH, &blkType, &id);
469 die_horribly(AH, "%s: Found unexpected block ID (%d) when reading data - expected %d\n",
470 progname, id, te->id);
482 die_horribly(AH, "%s: BLOBs can not be loaded without a database connection\n", progname);
487 default: /* Always have a default */
489 die_horribly(AH, "%s: unrecognized data block type %d while restoring archive\n",
494 ahprintf(AH, "\n\n");
498 * Print data from current file position.
500 static void _PrintData(ArchiveHandle* AH)
502 lclContext* ctx = (lclContext*)AH->formatData;
503 z_streamp zp = ctx->zp;
505 char* in = ctx->zlibIn;
509 char* out = ctx->zlibOut;
516 if (AH->compression != 0) {
521 if (inflateInit(zp) != Z_OK)
522 die_horribly(AH, "%s: could not initialize compression library - %s\n", progname, zp->msg);
527 blkLen = ReadInt(AH);
528 while (blkLen != 0) {
529 if (blkLen+1 > ctx->inSize) {
532 ctx->zlibIn = (char*)malloc(blkLen+1);
534 die_horribly(AH, "%s: failed to allocate decompression buffer\n", progname);
536 ctx->inSize = blkLen+1;
540 cnt = fread(in, 1, blkLen, AH->FH);
542 die_horribly(AH, "%s: could not read data block - expected %d, got %d\n", progname, blkLen, cnt);
544 ctx->filePos += blkLen;
547 zp->avail_in = blkLen;
551 if (AH->compression != 0) {
553 while (zp->avail_in != 0) {
555 zp->avail_out = zlibOutSize;
556 res = inflate(zp, 0);
557 if (res != Z_OK && res != Z_STREAM_END)
558 die_horribly(AH, "%s: unable to uncompress data - %s\n", progname, zp->msg);
560 out[zlibOutSize - zp->avail_out] = '\0';
561 ahwrite(out, 1, zlibOutSize - zp->avail_out, AH);
565 in[zp->avail_in] = '\0';
566 ahwrite(in, 1, zp->avail_in, AH);
573 blkLen = ReadInt(AH);
578 if (AH->compression != 0)
582 while (res != Z_STREAM_END) {
584 zp->avail_out = zlibOutSize;
585 res = inflate(zp, 0);
586 if (res != Z_OK && res != Z_STREAM_END)
587 die_horribly(AH, "%s: unable to uncompress data - %s\n", progname, zp->msg);
589 out[zlibOutSize - zp->avail_out] = '\0';
590 ahwrite(out, 1, zlibOutSize - zp->avail_out, AH);
597 static void _LoadBlobs(ArchiveHandle* AH)
601 StartRestoreBlobs(AH);
606 StartRestoreBlob(AH, oid);
608 EndRestoreBlob(AH, oid);
617 * Skip the BLOBs from the current file position.
618 * BLOBS are written sequentially as data blocks (see below).
619 * Each BLOB is preceded by it's original OID.
620 * A zero OID indicated the end of the BLOBS
622 static void _skipBlobs(ArchiveHandle* AH)
635 * Skip data from current file position.
636 * Data blocks are formatted as an integer length, followed by data.
637 * A zero length denoted the end of the block.
639 static void _skipData(ArchiveHandle* AH)
641 lclContext* ctx = (lclContext*)AH->formatData;
643 char* in = ctx->zlibIn;
646 blkLen = ReadInt(AH);
647 while (blkLen != 0) {
648 if (blkLen > ctx->inSize) {
650 ctx->zlibIn = (char*)malloc(blkLen);
651 ctx->inSize = blkLen;
654 cnt = fread(in, 1, blkLen, AH->FH);
656 die_horribly(AH, "%s: could not read data block - expected %d, got %d\n", progname, blkLen, cnt);
658 ctx->filePos += blkLen;
660 blkLen = ReadInt(AH);
666 * Write a byte of data to the archive.
670 * Called by the archiver to do integer & byte output to the archive.
671 * These routines are only used to read & write headers & TOC.
674 static int _WriteByte(ArchiveHandle* AH, const int i)
676 lclContext* ctx = (lclContext*)AH->formatData;
679 res = fputc(i, AH->FH);
683 die_horribly(AH, "%s: could not write byte./n",progname);
689 * Read a byte of data from the archive.
693 * Called by the archiver to read bytes & integers from the archive.
694 * These routines are only used to read & write headers & TOC.
697 static int _ReadByte(ArchiveHandle* AH)
699 lclContext* ctx = (lclContext*)AH->formatData;
710 * Write a buffer of data to the archive.
714 * Called by the archiver to write a block of bytes to the archive.
715 * These routines are only used to read & write headers & TOC.
718 static int _WriteBuf(ArchiveHandle* AH, const void* buf, int len)
720 lclContext* ctx = (lclContext*)AH->formatData;
722 res = fwrite(buf, 1, len, AH->FH);
725 die_horribly(AH, "%s: write error in _WriteBuf (%d != %d)\n", progname, res, len);
732 * Read a block of bytes from the archive.
736 * Called by the archiver to read a block of bytes from the archive
737 * These routines are only used to read & write headers & TOC.
740 static int _ReadBuf(ArchiveHandle* AH, void* buf, int len)
742 lclContext* ctx = (lclContext*)AH->formatData;
744 res = fread(buf, 1, len, AH->FH);
754 * When writing the archive, this is the routine that actually starts
755 * the process of saving it to files. No data should be written prior
756 * to this point, since the user could sort the TOC after creating it.
758 * If an archive is to be written, this toutine must call:
759 * WriteHead to save the archive header
760 * WriteToc to save the TOC entries
761 * WriteDataChunks to save all DATA & BLOBs.
764 static void _CloseArchive(ArchiveHandle* AH)
766 lclContext* ctx = (lclContext*)AH->formatData;
769 if (AH->mode == archModeWrite) {
771 tpos = ftell(AH->FH);
773 ctx->dataStart = _getFilePos(AH, ctx);
775 /* This is not an essential operation - it is really only
776 * needed if we expect to be doing seeks to read the data back
777 * - it may be ok to just use the existing self-consistent block
781 fseek(AH->FH, tpos, SEEK_SET);
786 if (fclose(AH->FH) != 0)
787 die_horribly(AH, "%s: could not close archive file\n",progname);
792 /*--------------------------------------------------
793 * END OF FORMAT CALLBACKS
794 *--------------------------------------------------
798 * Get the current position in the archive file.
800 static int _getFilePos(ArchiveHandle* AH, lclContext* ctx)
805 if (pos != ctx->filePos) {
806 fprintf(stderr, "Warning: ftell mismatch with filePos\n");
815 * Read a data block header. The format changed in V1.3, so we
816 * put the code here for simplicity.
818 static void _readBlockHeader(ArchiveHandle *AH, int *type, int *id)
820 if (AH->version < K_VERS_1_3)
823 *type = _ReadByte(AH);;
829 * If zlib is available, then startit up. This is called from
830 * StartData & StartBlob. The buffers are setup in the Init routine.
833 static void _StartDataCompressor(ArchiveHandle* AH, TocEntry* te)
835 lclContext* ctx = (lclContext*)AH->formatData;
836 z_streamp zp = ctx->zp;
840 if (AH->compression < 0 || AH->compression > 9) {
841 AH->compression = Z_DEFAULT_COMPRESSION;
844 if (AH->compression != 0) {
849 if (deflateInit(zp, AH->compression) != Z_OK)
850 die_horribly(AH, "%s: could not initialize compression library - %s\n",progname, zp->msg);
859 /* Just be paranoid - maybe End is called after Start, with no Write */
860 zp->next_out = ctx->zlibOut;
861 zp->avail_out = zlibOutSize;
865 * Send compressed data to the output stream (via ahwrite).
866 * Each data chunk is preceded by it's length.
867 * In the case of Z0, or no zlib, just write the raw data.
870 static int _DoDeflate(ArchiveHandle* AH, lclContext* ctx, int flush)
872 z_streamp zp = ctx->zp;
875 char* out = ctx->zlibOut;
878 if (AH->compression != 0)
880 res = deflate(zp, flush);
881 if (res == Z_STREAM_ERROR)
882 die_horribly(AH, "%s: could not compress data - %s\n",progname, zp->msg);
884 if ( ( (flush == Z_FINISH) && (zp->avail_out < zlibOutSize) )
885 || (zp->avail_out == 0)
886 || (zp->avail_in != 0)
890 * Extra paranoia: avoid zero-length chunks since a zero
891 * length chunk is the EOF marker. This should never happen
894 if (zp->avail_out < zlibOutSize) {
895 /* printf("Wrote %d byte deflated chunk\n", zlibOutSize - zp->avail_out); */
896 WriteInt(AH, zlibOutSize - zp->avail_out);
897 if (fwrite(out, 1, zlibOutSize - zp->avail_out, AH->FH) != (zlibOutSize - zp->avail_out))
898 die_horribly(AH, "%s: could not write compressed chunk\n",progname);
899 ctx->filePos += zlibOutSize - zp->avail_out;
902 zp->avail_out = zlibOutSize;
906 if (zp->avail_in > 0)
908 WriteInt(AH, zp->avail_in);
909 if (fwrite(zp->next_in, 1, zp->avail_in, AH->FH) != zp->avail_in)
910 die_horribly(AH, "%s: could not write uncompressed chunk\n", progname);
911 ctx->filePos += zp->avail_in;
915 if (flush == Z_FINISH)
932 * Terminate zlib context and flush it's buffers. If no zlib
936 static void _EndDataCompressor(ArchiveHandle* AH, TocEntry* te)
940 lclContext* ctx = (lclContext*)AH->formatData;
941 z_streamp zp = ctx->zp;
944 if (AH->compression != 0)
950 /* printf("Ending data output\n"); */
951 res = _DoDeflate(AH, ctx, Z_FINISH);
952 } while (res != Z_STREAM_END);
954 if (deflateEnd(zp) != Z_OK)
955 die_horribly(AH, "%s: error closing compression stream - %s\n", progname, zp->msg);
959 /* Send the end marker */