]> granicus.if.org Git - postgresql/blob - src/bin/pg_dump/pg_backup_custom.c
55ff39a4fe817ebd2d2812a92950e71785c18393
[postgresql] / src / bin / pg_dump / pg_backup_custom.c
1 /*-------------------------------------------------------------------------
2  *
3  * pg_backup_custom.c
4  *
5  *      Implements the custom output format.
6  *
7  *      The comments with the routined in this code are a good place to
8  *      understand how to write a new format.
9  *
10  *      See the headers to pg_restore for more details.
11  *
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.
15  *
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
18  *      related bug.
19  *
20  *
21  * IDENTIFICATION
22  *              src/bin/pg_dump/pg_backup_custom.c
23  *
24  *-------------------------------------------------------------------------
25  */
26
27 #include "compress_io.h"
28
29 /*--------
30  * Routines in the format interface
31  *--------
32  */
33
34 static void _ArchiveEntry(ArchiveHandle *AH, TocEntry *te);
35 static void _StartData(ArchiveHandle *AH, TocEntry *te);
36 static size_t _WriteData(ArchiveHandle *AH, const void *data, size_t dLen);
37 static void _EndData(ArchiveHandle *AH, TocEntry *te);
38 static int      _WriteByte(ArchiveHandle *AH, const int i);
39 static int      _ReadByte(ArchiveHandle *);
40 static size_t _WriteBuf(ArchiveHandle *AH, const void *buf, size_t len);
41 static size_t _ReadBuf(ArchiveHandle *AH, void *buf, size_t len);
42 static void _CloseArchive(ArchiveHandle *AH);
43 static void _ReopenArchive(ArchiveHandle *AH);
44 static void _PrintTocData(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt);
45 static void _WriteExtraToc(ArchiveHandle *AH, TocEntry *te);
46 static void _ReadExtraToc(ArchiveHandle *AH, TocEntry *te);
47 static void _PrintExtraToc(ArchiveHandle *AH, TocEntry *te);
48
49 static void _PrintData(ArchiveHandle *AH);
50 static void _skipData(ArchiveHandle *AH);
51 static void _skipBlobs(ArchiveHandle *AH);
52
53 static void _StartBlobs(ArchiveHandle *AH, TocEntry *te);
54 static void _StartBlob(ArchiveHandle *AH, TocEntry *te, Oid oid);
55 static void _EndBlob(ArchiveHandle *AH, TocEntry *te, Oid oid);
56 static void _EndBlobs(ArchiveHandle *AH, TocEntry *te);
57 static void _LoadBlobs(ArchiveHandle *AH, bool drop);
58 static void _Clone(ArchiveHandle *AH);
59 static void _DeClone(ArchiveHandle *AH);
60
61 typedef struct
62 {
63         CompressorState *cs;
64         int                     hasSeek;
65         pgoff_t         filePos;
66         pgoff_t         dataStart;
67 } lclContext;
68
69 typedef struct
70 {
71         int                     dataState;
72         pgoff_t         dataPos;
73 } lclTocEntry;
74
75
76 /*------
77  * Static declarations
78  *------
79  */
80 static void _readBlockHeader(ArchiveHandle *AH, int *type, int *id);
81 static pgoff_t _getFilePos(ArchiveHandle *AH, lclContext *ctx);
82
83 static size_t _CustomWriteFunc(ArchiveHandle *AH, const char *buf, size_t len);
84 static size_t _CustomReadFunc(ArchiveHandle *AH, char **buf, size_t *buflen);
85
86 static const char *modulename = gettext_noop("custom archiver");
87
88
89
90 /*
91  *      Init routine required by ALL formats. This is a global routine
92  *      and should be declared in pg_backup_archiver.h
93  *
94  *      It's task is to create any extra archive context (using AH->formatData),
95  *      and to initialize the supported function pointers.
96  *
97  *      It should also prepare whatever it's input source is for reading/writing,
98  *      and in the case of a read mode connection, it should load the Header & TOC.
99  */
100 void
101 InitArchiveFmt_Custom(ArchiveHandle *AH)
102 {
103         lclContext *ctx;
104
105         /* Assuming static functions, this can be copied for each format. */
106         AH->ArchiveEntryPtr = _ArchiveEntry;
107         AH->StartDataPtr = _StartData;
108         AH->WriteDataPtr = _WriteData;
109         AH->EndDataPtr = _EndData;
110         AH->WriteBytePtr = _WriteByte;
111         AH->ReadBytePtr = _ReadByte;
112         AH->WriteBufPtr = _WriteBuf;
113         AH->ReadBufPtr = _ReadBuf;
114         AH->ClosePtr = _CloseArchive;
115         AH->ReopenPtr = _ReopenArchive;
116         AH->PrintTocDataPtr = _PrintTocData;
117         AH->ReadExtraTocPtr = _ReadExtraToc;
118         AH->WriteExtraTocPtr = _WriteExtraToc;
119         AH->PrintExtraTocPtr = _PrintExtraToc;
120
121         AH->StartBlobsPtr = _StartBlobs;
122         AH->StartBlobPtr = _StartBlob;
123         AH->EndBlobPtr = _EndBlob;
124         AH->EndBlobsPtr = _EndBlobs;
125         AH->ClonePtr = _Clone;
126         AH->DeClonePtr = _DeClone;
127
128         /* Set up a private area. */
129         ctx = (lclContext *) calloc(1, sizeof(lclContext));
130         if (ctx == NULL)
131                 die_horribly(AH, modulename, "out of memory\n");
132         AH->formatData = (void *) ctx;
133
134         /* Initialize LO buffering */
135         AH->lo_buf_size = LOBBUFSIZE;
136         AH->lo_buf = (void *) malloc(LOBBUFSIZE);
137         if (AH->lo_buf == NULL)
138                 die_horribly(AH, modulename, "out of memory\n");
139
140         ctx->filePos = 0;
141
142         /*
143          * Now open the file
144          */
145         if (AH->mode == archModeWrite)
146         {
147                 if (AH->fSpec && strcmp(AH->fSpec, "") != 0)
148                 {
149                         AH->FH = fopen(AH->fSpec, PG_BINARY_W);
150                         if (!AH->FH)
151                                 die_horribly(AH, modulename, "could not open output file \"%s\": %s\n",
152                                                          AH->fSpec, strerror(errno));
153                 }
154                 else
155                 {
156                         AH->FH = stdout;
157                         if (!AH->FH)
158                                 die_horribly(AH, modulename, "could not open output file: %s\n",
159                                                          strerror(errno));
160                 }
161
162                 ctx->hasSeek = checkSeek(AH->FH);
163         }
164         else
165         {
166                 if (AH->fSpec && strcmp(AH->fSpec, "") != 0)
167                 {
168                         AH->FH = fopen(AH->fSpec, PG_BINARY_R);
169                         if (!AH->FH)
170                                 die_horribly(AH, modulename, "could not open input file \"%s\": %s\n",
171                                                          AH->fSpec, strerror(errno));
172                 }
173                 else
174                 {
175                         AH->FH = stdin;
176                         if (!AH->FH)
177                                 die_horribly(AH, modulename, "could not open input file: %s\n",
178                                                          strerror(errno));
179                 }
180
181                 ctx->hasSeek = checkSeek(AH->FH);
182
183                 ReadHead(AH);
184                 ReadToc(AH);
185                 ctx->dataStart = _getFilePos(AH, ctx);
186         }
187
188 }
189
190 /*
191  * Called by the Archiver when the dumper creates a new TOC entry.
192  *
193  * Optional.
194  *
195  * Set up extrac format-related TOC data.
196 */
197 static void
198 _ArchiveEntry(ArchiveHandle *AH, TocEntry *te)
199 {
200         lclTocEntry *ctx;
201
202         ctx = (lclTocEntry *) calloc(1, sizeof(lclTocEntry));
203         if (te->dataDumper)
204                 ctx->dataState = K_OFFSET_POS_NOT_SET;
205         else
206                 ctx->dataState = K_OFFSET_NO_DATA;
207
208         te->formatData = (void *) ctx;
209 }
210
211 /*
212  * Called by the Archiver to save any extra format-related TOC entry
213  * data.
214  *
215  * Optional.
216  *
217  * Use the Archiver routines to write data - they are non-endian, and
218  * maintain other important file information.
219  */
220 static void
221 _WriteExtraToc(ArchiveHandle *AH, TocEntry *te)
222 {
223         lclTocEntry *ctx = (lclTocEntry *) te->formatData;
224
225         WriteOffset(AH, ctx->dataPos, ctx->dataState);
226 }
227
228 /*
229  * Called by the Archiver to read any extra format-related TOC data.
230  *
231  * Optional.
232  *
233  * Needs to match the order defined in _WriteExtraToc, and sould also
234  * use the Archiver input routines.
235  */
236 static void
237 _ReadExtraToc(ArchiveHandle *AH, TocEntry *te)
238 {
239         lclTocEntry *ctx = (lclTocEntry *) te->formatData;
240
241         if (ctx == NULL)
242         {
243                 ctx = (lclTocEntry *) calloc(1, sizeof(lclTocEntry));
244                 te->formatData = (void *) ctx;
245         }
246
247         ctx->dataState = ReadOffset(AH, &(ctx->dataPos));
248
249         /*
250          * Prior to V1.7 (pg7.3), we dumped the data size as an int now we don't
251          * dump it at all.
252          */
253         if (AH->version < K_VERS_1_7)
254                 ReadInt(AH);
255 }
256
257 /*
258  * Called by the Archiver when restoring an archive to output a comment
259  * that includes useful information about the TOC entry.
260  *
261  * Optional.
262  *
263  */
264 static void
265 _PrintExtraToc(ArchiveHandle *AH, TocEntry *te)
266 {
267         lclTocEntry *ctx = (lclTocEntry *) te->formatData;
268
269         if (AH->public.verbose)
270                 ahprintf(AH, "-- Data Pos: " INT64_FORMAT "\n",
271                                  (int64) ctx->dataPos);
272 }
273
274 /*
275  * Called by the archiver when saving TABLE DATA (not schema). This routine
276  * should save whatever format-specific information is needed to read
277  * the archive back.
278  *
279  * It is called just prior to the dumper's 'DataDumper' routine being called.
280  *
281  * Optional, but strongly recommended.
282  *
283  */
284 static void
285 _StartData(ArchiveHandle *AH, TocEntry *te)
286 {
287         lclContext *ctx = (lclContext *) AH->formatData;
288         lclTocEntry *tctx = (lclTocEntry *) te->formatData;
289
290         tctx->dataPos = _getFilePos(AH, ctx);
291         tctx->dataState = K_OFFSET_POS_SET;
292
293         _WriteByte(AH, BLK_DATA);       /* Block type */
294         WriteInt(AH, te->dumpId);       /* For sanity check */
295
296         ctx->cs = AllocateCompressor(AH->compression, _CustomWriteFunc);
297 }
298
299 /*
300  * Called by archiver when dumper calls WriteData. This routine is
301  * called for both BLOB and TABLE data; it is the responsibility of
302  * the format to manage each kind of data using StartBlob/StartData.
303  *
304  * It should only be called from within a DataDumper routine.
305  *
306  * Mandatory.
307  */
308 static size_t
309 _WriteData(ArchiveHandle *AH, const void *data, size_t dLen)
310 {
311         lclContext *ctx = (lclContext *) AH->formatData;
312         CompressorState *cs = ctx->cs;
313
314         if (dLen == 0)
315                 return 0;
316
317         return WriteDataToArchive(AH, cs, data, dLen);
318 }
319
320 /*
321  * Called by the archiver when a dumper's 'DataDumper' routine has
322  * finished.
323  *
324  * Optional.
325  *
326  */
327 static void
328 _EndData(ArchiveHandle *AH, TocEntry *te)
329 {
330         lclContext *ctx = (lclContext *) AH->formatData;
331
332         EndCompressor(AH, ctx->cs);
333         /* Send the end marker */
334         WriteInt(AH, 0);
335 }
336
337 /*
338  * Called by the archiver when starting to save all BLOB DATA (not schema).
339  * This routine should save whatever format-specific information is needed
340  * to read the BLOBs back into memory.
341  *
342  * It is called just prior to the dumper's DataDumper routine.
343  *
344  * Optional, but strongly recommended.
345  */
346 static void
347 _StartBlobs(ArchiveHandle *AH, TocEntry *te)
348 {
349         lclContext *ctx = (lclContext *) AH->formatData;
350         lclTocEntry *tctx = (lclTocEntry *) te->formatData;
351
352         tctx->dataPos = _getFilePos(AH, ctx);
353         tctx->dataState = K_OFFSET_POS_SET;
354
355         _WriteByte(AH, BLK_BLOBS);      /* Block type */
356         WriteInt(AH, te->dumpId);       /* For sanity check */
357 }
358
359 /*
360  * Called by the archiver when the dumper calls StartBlob.
361  *
362  * Mandatory.
363  *
364  * Must save the passed OID for retrieval at restore-time.
365  */
366 static void
367 _StartBlob(ArchiveHandle *AH, TocEntry *te, Oid oid)
368 {
369         lclContext *ctx = (lclContext *) AH->formatData;
370
371         if (oid == 0)
372                 die_horribly(AH, modulename, "invalid OID for large object\n");
373
374         WriteInt(AH, oid);
375
376         ctx->cs = AllocateCompressor(AH->compression, _CustomWriteFunc);
377 }
378
379 /*
380  * Called by the archiver when the dumper calls EndBlob.
381  *
382  * Optional.
383  */
384 static void
385 _EndBlob(ArchiveHandle *AH, TocEntry *te, Oid oid)
386 {
387         lclContext *ctx = (lclContext *) AH->formatData;
388
389         EndCompressor(AH, ctx->cs);
390         /* Send the end marker */
391         WriteInt(AH, 0);
392 }
393
394 /*
395  * Called by the archiver when finishing saving all BLOB DATA.
396  *
397  * Optional.
398  */
399 static void
400 _EndBlobs(ArchiveHandle *AH, TocEntry *te)
401 {
402         /* Write out a fake zero OID to mark end-of-blobs. */
403         WriteInt(AH, 0);
404 }
405
406 /*
407  * Print data for a given TOC entry
408  */
409 static void
410 _PrintTocData(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt)
411 {
412         lclContext *ctx = (lclContext *) AH->formatData;
413         lclTocEntry *tctx = (lclTocEntry *) te->formatData;
414         int                     blkType;
415         int                     id;
416
417         if (tctx->dataState == K_OFFSET_NO_DATA)
418                 return;
419
420         if (!ctx->hasSeek || tctx->dataState == K_OFFSET_POS_NOT_SET)
421         {
422                 /*
423                  * We cannot seek directly to the desired block.  Instead, skip over
424                  * block headers until we find the one we want.  This could fail if we
425                  * are asked to restore items out-of-order.
426                  */
427                 _readBlockHeader(AH, &blkType, &id);
428
429                 while (blkType != EOF && id != te->dumpId)
430                 {
431                         switch (blkType)
432                         {
433                                 case BLK_DATA:
434                                         _skipData(AH);
435                                         break;
436
437                                 case BLK_BLOBS:
438                                         _skipBlobs(AH);
439                                         break;
440
441                                 default:                /* Always have a default */
442                                         die_horribly(AH, modulename,
443                                                                  "unrecognized data block type (%d) while searching archive\n",
444                                                                  blkType);
445                                         break;
446                         }
447                         _readBlockHeader(AH, &blkType, &id);
448                 }
449         }
450         else
451         {
452                 /* We can just seek to the place we need to be. */
453                 if (fseeko(AH->FH, tctx->dataPos, SEEK_SET) != 0)
454                         die_horribly(AH, modulename, "error during file seek: %s\n",
455                                                  strerror(errno));
456
457                 _readBlockHeader(AH, &blkType, &id);
458         }
459
460         /* Produce suitable failure message if we fell off end of file */
461         if (blkType == EOF)
462         {
463                 if (tctx->dataState == K_OFFSET_POS_NOT_SET)
464                         die_horribly(AH, modulename, "could not find block ID %d in archive -- "
465                                                  "possibly due to out-of-order restore request, "
466                                                  "which cannot be handled due to lack of data offsets in archive\n",
467                                                  te->dumpId);
468                 else if (!ctx->hasSeek)
469                         die_horribly(AH, modulename, "could not find block ID %d in archive -- "
470                                                  "possibly due to out-of-order restore request, "
471                                   "which cannot be handled due to non-seekable input file\n",
472                                                  te->dumpId);
473                 else    /* huh, the dataPos led us to EOF? */
474                         die_horribly(AH, modulename, "could not find block ID %d in archive -- "
475                                                  "possibly corrupt archive\n",
476                                                  te->dumpId);
477         }
478
479         /* Are we sane? */
480         if (id != te->dumpId)
481                 die_horribly(AH, modulename, "found unexpected block ID (%d) when reading data -- expected %d\n",
482                                          id, te->dumpId);
483
484         switch (blkType)
485         {
486                 case BLK_DATA:
487                         _PrintData(AH);
488                         break;
489
490                 case BLK_BLOBS:
491                         _LoadBlobs(AH, ropt->dropSchema);
492                         break;
493
494                 default:                                /* Always have a default */
495                         die_horribly(AH, modulename, "unrecognized data block type %d while restoring archive\n",
496                                                  blkType);
497                         break;
498         }
499 }
500
501 /*
502  * Print data from current file position.
503 */
504 static void
505 _PrintData(ArchiveHandle *AH)
506 {
507         ReadDataFromArchive(AH, AH->compression, _CustomReadFunc);
508 }
509
510 static void
511 _LoadBlobs(ArchiveHandle *AH, bool drop)
512 {
513         Oid                     oid;
514
515         StartRestoreBlobs(AH);
516
517         oid = ReadInt(AH);
518         while (oid != 0)
519         {
520                 StartRestoreBlob(AH, oid, drop);
521                 _PrintData(AH);
522                 EndRestoreBlob(AH, oid);
523                 oid = ReadInt(AH);
524         }
525
526         EndRestoreBlobs(AH);
527 }
528
529 /*
530  * Skip the BLOBs from the current file position.
531  * BLOBS are written sequentially as data blocks (see below).
532  * Each BLOB is preceded by it's original OID.
533  * A zero OID indicated the end of the BLOBS
534  */
535 static void
536 _skipBlobs(ArchiveHandle *AH)
537 {
538         Oid                     oid;
539
540         oid = ReadInt(AH);
541         while (oid != 0)
542         {
543                 _skipData(AH);
544                 oid = ReadInt(AH);
545         }
546 }
547
548 /*
549  * Skip data from current file position.
550  * Data blocks are formatted as an integer length, followed by data.
551  * A zero length denoted the end of the block.
552 */
553 static void
554 _skipData(ArchiveHandle *AH)
555 {
556         lclContext *ctx = (lclContext *) AH->formatData;
557         size_t          blkLen;
558         char       *buf = NULL;
559         int                     buflen = 0;
560         size_t          cnt;
561
562         blkLen = ReadInt(AH);
563         while (blkLen != 0)
564         {
565                 if (blkLen > buflen)
566                 {
567                         if (buf)
568                                 free(buf);
569                         buf = (char *) malloc(blkLen);
570                         buflen = blkLen;
571                 }
572                 cnt = fread(buf, 1, blkLen, AH->FH);
573                 if (cnt != blkLen)
574                 {
575                         if (feof(AH->FH))
576                                 die_horribly(AH, modulename,
577                                                          "could not read from input file: end of file\n");
578                         else
579                                 die_horribly(AH, modulename,
580                                         "could not read from input file: %s\n", strerror(errno));
581                 }
582
583                 ctx->filePos += blkLen;
584
585                 blkLen = ReadInt(AH);
586         }
587
588         if (buf)
589                 free(buf);
590 }
591
592 /*
593  * Write a byte of data to the archive.
594  *
595  * Mandatory.
596  *
597  * Called by the archiver to do integer & byte output to the archive.
598  */
599 static int
600 _WriteByte(ArchiveHandle *AH, const int i)
601 {
602         lclContext *ctx = (lclContext *) AH->formatData;
603         int                     res;
604
605         res = fputc(i, AH->FH);
606         if (res != EOF)
607                 ctx->filePos += 1;
608         else
609                 die_horribly(AH, modulename, "could not write byte: %s\n", strerror(errno));
610         return res;
611 }
612
613 /*
614  * Read a byte of data from the archive.
615  *
616  * Mandatory
617  *
618  * Called by the archiver to read bytes & integers from the archive.
619  * EOF should be treated as a fatal error.
620  */
621 static int
622 _ReadByte(ArchiveHandle *AH)
623 {
624         lclContext *ctx = (lclContext *) AH->formatData;
625         int                     res;
626
627         res = getc(AH->FH);
628         if (res == EOF)
629                 die_horribly(AH, modulename, "unexpected end of file\n");
630         ctx->filePos += 1;
631         return res;
632 }
633
634 /*
635  * Write a buffer of data to the archive.
636  *
637  * Mandatory.
638  *
639  * Called by the archiver to write a block of bytes to the archive.
640  */
641 static size_t
642 _WriteBuf(ArchiveHandle *AH, const void *buf, size_t len)
643 {
644         lclContext *ctx = (lclContext *) AH->formatData;
645         size_t          res;
646
647         res = fwrite(buf, 1, len, AH->FH);
648
649         if (res != len)
650                 die_horribly(AH, modulename,
651                                          "could not write to output file: %s\n", strerror(errno));
652
653         ctx->filePos += res;
654         return res;
655 }
656
657 /*
658  * Read a block of bytes from the archive.
659  *
660  * Mandatory.
661  *
662  * Called by the archiver to read a block of bytes from the archive
663  */
664 static size_t
665 _ReadBuf(ArchiveHandle *AH, void *buf, size_t len)
666 {
667         lclContext *ctx = (lclContext *) AH->formatData;
668         size_t          res;
669
670         res = fread(buf, 1, len, AH->FH);
671         ctx->filePos += res;
672
673         return res;
674 }
675
676 /*
677  * Close the archive.
678  *
679  * Mandatory.
680  *
681  * When writing the archive, this is the routine that actually starts
682  * the process of saving it to files. No data should be written prior
683  * to this point, since the user could sort the TOC after creating it.
684  *
685  * If an archive is to be written, this toutine must call:
686  *              WriteHead                       to save the archive header
687  *              WriteToc                        to save the TOC entries
688  *              WriteDataChunks         to save all DATA & BLOBs.
689  *
690  */
691 static void
692 _CloseArchive(ArchiveHandle *AH)
693 {
694         lclContext *ctx = (lclContext *) AH->formatData;
695         pgoff_t         tpos;
696
697         if (AH->mode == archModeWrite)
698         {
699                 WriteHead(AH);
700                 tpos = ftello(AH->FH);
701                 WriteToc(AH);
702                 ctx->dataStart = _getFilePos(AH, ctx);
703                 WriteDataChunks(AH);
704
705                 /*
706                  * If possible, re-write the TOC in order to update the data offset
707                  * information.  This is not essential, as pg_restore can cope in most
708                  * cases without it; but it can make pg_restore significantly faster
709                  * in some situations (especially parallel restore).
710                  */
711                 if (ctx->hasSeek &&
712                         fseeko(AH->FH, tpos, SEEK_SET) == 0)
713                         WriteToc(AH);
714         }
715
716         if (fclose(AH->FH) != 0)
717                 die_horribly(AH, modulename, "could not close archive file: %s\n", strerror(errno));
718
719         AH->FH = NULL;
720 }
721
722 /*
723  * Reopen the archive's file handle.
724  *
725  * We close the original file handle, except on Windows.  (The difference
726  * is because on Windows, this is used within a multithreading context,
727  * and we don't want a thread closing the parent file handle.)
728  */
729 static void
730 _ReopenArchive(ArchiveHandle *AH)
731 {
732         lclContext *ctx = (lclContext *) AH->formatData;
733         pgoff_t         tpos;
734
735         if (AH->mode == archModeWrite)
736                 die_horribly(AH, modulename, "can only reopen input archives\n");
737
738         /*
739          * These two cases are user-facing errors since they represent unsupported
740          * (but not invalid) use-cases.  Word the error messages appropriately.
741          */
742         if (AH->fSpec == NULL || strcmp(AH->fSpec, "") == 0)
743                 die_horribly(AH, modulename, "parallel restore from stdin is not supported\n");
744         if (!ctx->hasSeek)
745                 die_horribly(AH, modulename, "parallel restore from non-seekable file is not supported\n");
746
747         errno = 0;
748         tpos = ftello(AH->FH);
749         if (errno)
750                 die_horribly(AH, modulename, "could not determine seek position in archive file: %s\n",
751                                          strerror(errno));
752
753 #ifndef WIN32
754         if (fclose(AH->FH) != 0)
755                 die_horribly(AH, modulename, "could not close archive file: %s\n",
756                                          strerror(errno));
757 #endif
758
759         AH->FH = fopen(AH->fSpec, PG_BINARY_R);
760         if (!AH->FH)
761                 die_horribly(AH, modulename, "could not open input file \"%s\": %s\n",
762                                          AH->fSpec, strerror(errno));
763
764         if (fseeko(AH->FH, tpos, SEEK_SET) != 0)
765                 die_horribly(AH, modulename, "could not set seek position in archive file: %s\n",
766                                          strerror(errno));
767 }
768
769 /*
770  * Clone format-specific fields during parallel restoration.
771  */
772 static void
773 _Clone(ArchiveHandle *AH)
774 {
775         lclContext *ctx = (lclContext *) AH->formatData;
776
777         AH->formatData = (lclContext *) malloc(sizeof(lclContext));
778         if (AH->formatData == NULL)
779                 die_horribly(AH, modulename, "out of memory\n");
780         memcpy(AH->formatData, ctx, sizeof(lclContext));
781         ctx = (lclContext *) AH->formatData;
782
783         /* sanity check, shouldn't happen */
784         if (ctx->cs != NULL)
785                 die_horribly(AH, modulename, "compressor active\n");
786
787         /*
788          * Note: we do not make a local lo_buf because we expect at most one BLOBS
789          * entry per archive, so no parallelism is possible.  Likewise,
790          * TOC-entry-local state isn't an issue because any one TOC entry is
791          * touched by just one worker child.
792          */
793 }
794
795 static void
796 _DeClone(ArchiveHandle *AH)
797 {
798         lclContext *ctx = (lclContext *) AH->formatData;
799
800         free(ctx);
801 }
802
803 /*--------------------------------------------------
804  * END OF FORMAT CALLBACKS
805  *--------------------------------------------------
806  */
807
808 /*
809  * Get the current position in the archive file.
810  */
811 static pgoff_t
812 _getFilePos(ArchiveHandle *AH, lclContext *ctx)
813 {
814         pgoff_t         pos;
815
816         if (ctx->hasSeek)
817         {
818                 pos = ftello(AH->FH);
819                 if (pos != ctx->filePos)
820                 {
821                         write_msg(modulename, "WARNING: ftell mismatch with expected position -- ftell used\n");
822
823                         /*
824                          * Prior to 1.7 (pg7.3) we relied on the internally maintained
825                          * pointer. Now we rely on ftello() always, unless the file has
826                          * been found to not support it.
827                          */
828                 }
829         }
830         else
831                 pos = ctx->filePos;
832         return pos;
833 }
834
835 /*
836  * Read a data block header. The format changed in V1.3, so we
837  * centralize the code here for simplicity.  Returns *type = EOF
838  * if at EOF.
839  */
840 static void
841 _readBlockHeader(ArchiveHandle *AH, int *type, int *id)
842 {
843         lclContext *ctx = (lclContext *) AH->formatData;
844         int                     byt;
845
846         /*
847          * Note: if we are at EOF with a pre-1.3 input file, we'll die_horribly
848          * inside ReadInt rather than returning EOF.  It doesn't seem worth
849          * jumping through hoops to deal with that case better, because no such
850          * files are likely to exist in the wild: only some 7.1 development
851          * versions of pg_dump ever generated such files.
852          */
853         if (AH->version < K_VERS_1_3)
854                 *type = BLK_DATA;
855         else
856         {
857                 byt = getc(AH->FH);
858                 *type = byt;
859                 if (byt == EOF)
860                 {
861                         *id = 0;                        /* don't return an uninitialized value */
862                         return;
863                 }
864                 ctx->filePos += 1;
865         }
866
867         *id = ReadInt(AH);
868 }
869
870 /*
871  * Callback function for WriteDataToArchive. Writes one block of (compressed)
872  * data to the archive.
873  */
874 static size_t
875 _CustomWriteFunc(ArchiveHandle *AH, const char *buf, size_t len)
876 {
877         /* never write 0-byte blocks (this should not happen) */
878         if (len == 0)
879                 return 0;
880
881         WriteInt(AH, len);
882         return _WriteBuf(AH, buf, len);
883 }
884
885 /*
886  * Callback function for ReadDataFromArchive. To keep things simple, we
887  * always read one compressed block at a time.
888  */
889 static size_t
890 _CustomReadFunc(ArchiveHandle *AH, char **buf, size_t *buflen)
891 {
892         size_t          blkLen;
893         size_t          cnt;
894
895         /* Read length */
896         blkLen = ReadInt(AH);
897         if (blkLen == 0)
898                 return 0;
899
900         /* If the caller's buffer is not large enough, allocate a bigger one */
901         if (blkLen > *buflen)
902         {
903                 free(*buf);
904                 *buf = (char *) malloc(blkLen);
905                 if (!(*buf))
906                         die_horribly(AH, modulename, "out of memory\n");
907                 *buflen = blkLen;
908         }
909
910         cnt = _ReadBuf(AH, *buf, blkLen);
911         if (cnt != blkLen)
912         {
913                 if (feof(AH->FH))
914                         die_horribly(AH, modulename,
915                                                  "could not read from input file: end of file\n");
916                 else
917                         die_horribly(AH, modulename,
918                                         "could not read from input file: %s\n", strerror(errno));
919         }
920         return cnt;
921 }