]> granicus.if.org Git - postgresql/blob - src/bin/pg_dump/pg_backup_custom.c
Code cleanup: mark some variables with the "const" modifier, when they
[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  *              $PostgreSQL: pgsql/src/bin/pg_dump/pg_backup_custom.c,v 1.38 2007/03/18 16:50:44 neilc Exp $
23  *
24  *-------------------------------------------------------------------------
25  */
26
27 #include "pg_backup_archiver.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 _PrintTocData(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt);
44 static void _WriteExtraToc(ArchiveHandle *AH, TocEntry *te);
45 static void _ReadExtraToc(ArchiveHandle *AH, TocEntry *te);
46 static void _PrintExtraToc(ArchiveHandle *AH, TocEntry *te);
47
48 static void _PrintData(ArchiveHandle *AH);
49 static void _skipData(ArchiveHandle *AH);
50 static void _skipBlobs(ArchiveHandle *AH);
51
52 static void _StartBlobs(ArchiveHandle *AH, TocEntry *te);
53 static void _StartBlob(ArchiveHandle *AH, TocEntry *te, Oid oid);
54 static void _EndBlob(ArchiveHandle *AH, TocEntry *te, Oid oid);
55 static void _EndBlobs(ArchiveHandle *AH, TocEntry *te);
56 static void _LoadBlobs(ArchiveHandle *AH);
57
58 /*------------
59  * Buffers used in zlib compression and extra data stored in archive and
60  * in TOC entries.
61  *------------
62  */
63 #define zlibOutSize 4096
64 #define zlibInSize      4096
65
66 typedef struct
67 {
68         z_streamp       zp;
69         char       *zlibOut;
70         char       *zlibIn;
71         size_t          inSize;
72         int                     hasSeek;
73         pgoff_t         filePos;
74         pgoff_t         dataStart;
75 } lclContext;
76
77 typedef struct
78 {
79         int                     dataState;
80         pgoff_t         dataPos;
81 } lclTocEntry;
82
83
84 /*------
85  * Static declarations
86  *------
87  */
88 static void _readBlockHeader(ArchiveHandle *AH, int *type, int *id);
89 static void _StartDataCompressor(ArchiveHandle *AH, TocEntry *te);
90 static void _EndDataCompressor(ArchiveHandle *AH, TocEntry *te);
91 static pgoff_t _getFilePos(ArchiveHandle *AH, lclContext *ctx);
92 static int      _DoDeflate(ArchiveHandle *AH, lclContext *ctx, int flush);
93
94 static const char *modulename = gettext_noop("custom archiver");
95
96
97
98 /*
99  *      Init routine required by ALL formats. This is a global routine
100  *      and should be declared in pg_backup_archiver.h
101  *
102  *      It's task is to create any extra archive context (using AH->formatData),
103  *      and to initialize the supported function pointers.
104  *
105  *      It should also prepare whatever it's input source is for reading/writing,
106  *      and in the case of a read mode connection, it should load the Header & TOC.
107  */
108 void
109 InitArchiveFmt_Custom(ArchiveHandle *AH)
110 {
111         lclContext *ctx;
112
113         /* Assuming static functions, this can be copied for each format. */
114         AH->ArchiveEntryPtr = _ArchiveEntry;
115         AH->StartDataPtr = _StartData;
116         AH->WriteDataPtr = _WriteData;
117         AH->EndDataPtr = _EndData;
118         AH->WriteBytePtr = _WriteByte;
119         AH->ReadBytePtr = _ReadByte;
120         AH->WriteBufPtr = _WriteBuf;
121         AH->ReadBufPtr = _ReadBuf;
122         AH->ClosePtr = _CloseArchive;
123         AH->PrintTocDataPtr = _PrintTocData;
124         AH->ReadExtraTocPtr = _ReadExtraToc;
125         AH->WriteExtraTocPtr = _WriteExtraToc;
126         AH->PrintExtraTocPtr = _PrintExtraToc;
127
128         AH->StartBlobsPtr = _StartBlobs;
129         AH->StartBlobPtr = _StartBlob;
130         AH->EndBlobPtr = _EndBlob;
131         AH->EndBlobsPtr = _EndBlobs;
132
133         /*
134          * Set up some special context used in compressing data.
135          */
136         ctx = (lclContext *) calloc(1, sizeof(lclContext));
137         if (ctx == NULL)
138                 die_horribly(AH, modulename, "out of memory\n");
139         AH->formatData = (void *) ctx;
140
141         ctx->zp = (z_streamp) malloc(sizeof(z_stream));
142         if (ctx->zp == NULL)
143                 die_horribly(AH, modulename, "out of memory\n");
144
145         /* Initialize LO buffering */
146         AH->lo_buf_size = LOBBUFSIZE;
147         AH->lo_buf = (void *) malloc(LOBBUFSIZE);
148         if (AH->lo_buf == NULL)
149                 die_horribly(AH, modulename, "out of memory\n");
150
151         /*
152          * zlibOutSize is the buffer size we tell zlib it can output to.  We
153          * actually allocate one extra byte because some routines want to append a
154          * trailing zero byte to the zlib output.  The input buffer is expansible
155          * and is always of size ctx->inSize; zlibInSize is just the initial
156          * default size for it.
157          */
158         ctx->zlibOut = (char *) malloc(zlibOutSize + 1);
159         ctx->zlibIn = (char *) malloc(zlibInSize);
160         ctx->inSize = zlibInSize;
161         ctx->filePos = 0;
162
163         if (ctx->zlibOut == NULL || ctx->zlibIn == NULL)
164                 die_horribly(AH, modulename, "out of memory\n");
165
166         /*
167          * Now open the file
168          */
169         if (AH->mode == archModeWrite)
170         {
171                 if (AH->fSpec && strcmp(AH->fSpec, "") != 0)
172                         AH->FH = fopen(AH->fSpec, PG_BINARY_W);
173                 else
174                         AH->FH = stdout;
175
176                 if (!AH->FH)
177                         die_horribly(AH, modulename, "could not open output file \"%s\": %s\n", AH->fSpec, strerror(errno));
178
179                 ctx->hasSeek = checkSeek(AH->FH);
180         }
181         else
182         {
183                 if (AH->fSpec && strcmp(AH->fSpec, "") != 0)
184                         AH->FH = fopen(AH->fSpec, PG_BINARY_R);
185                 else
186                         AH->FH = stdin;
187                 if (!AH->FH)
188                         die_horribly(AH, modulename, "could not open input file \"%s\": %s\n", AH->fSpec, strerror(errno));
189
190                 ctx->hasSeek = checkSeek(AH->FH);
191
192                 ReadHead(AH);
193                 ReadToc(AH);
194                 ctx->dataStart = _getFilePos(AH, ctx);
195         }
196
197 }
198
199 /*
200  * Called by the Archiver when the dumper creates a new TOC entry.
201  *
202  * Optional.
203  *
204  * Set up extrac format-related TOC data.
205 */
206 static void
207 _ArchiveEntry(ArchiveHandle *AH, TocEntry *te)
208 {
209         lclTocEntry *ctx;
210
211         ctx = (lclTocEntry *) calloc(1, sizeof(lclTocEntry));
212         if (te->dataDumper)
213                 ctx->dataState = K_OFFSET_POS_NOT_SET;
214         else
215                 ctx->dataState = K_OFFSET_NO_DATA;
216
217         te->formatData = (void *) ctx;
218 }
219
220 /*
221  * Called by the Archiver to save any extra format-related TOC entry
222  * data.
223  *
224  * Optional.
225  *
226  * Use the Archiver routines to write data - they are non-endian, and
227  * maintain other important file information.
228  */
229 static void
230 _WriteExtraToc(ArchiveHandle *AH, TocEntry *te)
231 {
232         lclTocEntry *ctx = (lclTocEntry *) te->formatData;
233
234         WriteOffset(AH, ctx->dataPos, ctx->dataState);
235 }
236
237 /*
238  * Called by the Archiver to read any extra format-related TOC data.
239  *
240  * Optional.
241  *
242  * Needs to match the order defined in _WriteExtraToc, and sould also
243  * use the Archiver input routines.
244  */
245 static void
246 _ReadExtraToc(ArchiveHandle *AH, TocEntry *te)
247 {
248         int                     junk;
249         lclTocEntry *ctx = (lclTocEntry *) te->formatData;
250
251         if (ctx == NULL)
252         {
253                 ctx = (lclTocEntry *) calloc(1, sizeof(lclTocEntry));
254                 te->formatData = (void *) ctx;
255         }
256
257         ctx->dataState = ReadOffset(AH, &(ctx->dataPos));
258
259         /*
260          * Prior to V1.7 (pg7.3), we dumped the data size as an int now we don't
261          * dump it at all.
262          */
263         if (AH->version < K_VERS_1_7)
264                 junk = ReadInt(AH);
265 }
266
267 /*
268  * Called by the Archiver when restoring an archive to output a comment
269  * that includes useful information about the TOC entry.
270  *
271  * Optional.
272  *
273  */
274 static void
275 _PrintExtraToc(ArchiveHandle *AH, TocEntry *te)
276 {
277         lclTocEntry *ctx = (lclTocEntry *) te->formatData;
278
279         if (AH->public.verbose)
280                 ahprintf(AH, "-- Data Pos: " INT64_FORMAT "\n",
281                                  (int64) ctx->dataPos);
282 }
283
284 /*
285  * Called by the archiver when saving TABLE DATA (not schema). This routine
286  * should save whatever format-specific information is needed to read
287  * the archive back.
288  *
289  * It is called just prior to the dumper's 'DataDumper' routine being called.
290  *
291  * Optional, but strongly recommended.
292  *
293  */
294 static void
295 _StartData(ArchiveHandle *AH, TocEntry *te)
296 {
297         lclContext *ctx = (lclContext *) AH->formatData;
298         lclTocEntry *tctx = (lclTocEntry *) te->formatData;
299
300         tctx->dataPos = _getFilePos(AH, ctx);
301         tctx->dataState = K_OFFSET_POS_SET;
302
303         _WriteByte(AH, BLK_DATA);       /* Block type */
304         WriteInt(AH, te->dumpId);       /* For sanity check */
305
306         _StartDataCompressor(AH, te);
307 }
308
309 /*
310  * Called by archiver when dumper calls WriteData. This routine is
311  * called for both BLOB and TABLE data; it is the responsibility of
312  * the format to manage each kind of data using StartBlob/StartData.
313  *
314  * It should only be called from within a DataDumper routine.
315  *
316  * Mandatory.
317  */
318 static size_t
319 _WriteData(ArchiveHandle *AH, const void *data, size_t dLen)
320 {
321         lclContext *ctx = (lclContext *) AH->formatData;
322         z_streamp       zp = ctx->zp;
323
324         zp->next_in = (void *) data;
325         zp->avail_in = dLen;
326
327         while (zp->avail_in != 0)
328         {
329                 /* printf("Deflating %lu bytes\n", (unsigned long) dLen); */
330                 _DoDeflate(AH, ctx, 0);
331         }
332         return dLen;
333 }
334
335 /*
336  * Called by the archiver when a dumper's 'DataDumper' routine has
337  * finished.
338  *
339  * Optional.
340  *
341  */
342 static void
343 _EndData(ArchiveHandle *AH, TocEntry *te)
344 {
345 /*      lclContext *ctx = (lclContext *) AH->formatData; */
346 /*      lclTocEntry *tctx = (lclTocEntry *) te->formatData; */
347
348         _EndDataCompressor(AH, te);
349 }
350
351 /*
352  * Called by the archiver when starting to save all BLOB DATA (not schema).
353  * This routine should save whatever format-specific information is needed
354  * to read the BLOBs back into memory.
355  *
356  * It is called just prior to the dumper's DataDumper routine.
357  *
358  * Optional, but strongly recommended.
359  */
360 static void
361 _StartBlobs(ArchiveHandle *AH, TocEntry *te)
362 {
363         lclContext *ctx = (lclContext *) AH->formatData;
364         lclTocEntry *tctx = (lclTocEntry *) te->formatData;
365
366         tctx->dataPos = _getFilePos(AH, ctx);
367         tctx->dataState = K_OFFSET_POS_SET;
368
369         _WriteByte(AH, BLK_BLOBS);      /* Block type */
370         WriteInt(AH, te->dumpId);       /* For sanity check */
371 }
372
373 /*
374  * Called by the archiver when the dumper calls StartBlob.
375  *
376  * Mandatory.
377  *
378  * Must save the passed OID for retrieval at restore-time.
379  */
380 static void
381 _StartBlob(ArchiveHandle *AH, TocEntry *te, Oid oid)
382 {
383         if (oid == 0)
384                 die_horribly(AH, modulename, "invalid OID for large object\n");
385
386         WriteInt(AH, oid);
387         _StartDataCompressor(AH, te);
388 }
389
390 /*
391  * Called by the archiver when the dumper calls EndBlob.
392  *
393  * Optional.
394  */
395 static void
396 _EndBlob(ArchiveHandle *AH, TocEntry *te, Oid oid)
397 {
398         _EndDataCompressor(AH, te);
399 }
400
401 /*
402  * Called by the archiver when finishing saving all BLOB DATA.
403  *
404  * Optional.
405  */
406 static void
407 _EndBlobs(ArchiveHandle *AH, TocEntry *te)
408 {
409         /* Write out a fake zero OID to mark end-of-blobs. */
410         WriteInt(AH, 0);
411 }
412
413 /*
414  * Print data for a given TOC entry
415  */
416 static void
417 _PrintTocData(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt)
418 {
419         lclContext *ctx = (lclContext *) AH->formatData;
420         int                     id;
421         lclTocEntry *tctx = (lclTocEntry *) te->formatData;
422         int                     blkType;
423         int                     found = 0;
424
425         if (tctx->dataState == K_OFFSET_NO_DATA)
426                 return;
427
428         if (!ctx->hasSeek || tctx->dataState == K_OFFSET_POS_NOT_SET)
429         {
430                 /* Skip over unnecessary blocks until we get the one we want. */
431
432                 found = 0;
433
434                 _readBlockHeader(AH, &blkType, &id);
435
436                 while (id != te->dumpId)
437                 {
438                         if ((TocIDRequired(AH, id, ropt) & REQ_DATA) != 0)
439                                 die_horribly(AH, modulename,
440                                                          "dumping a specific TOC data block out of order is not supported"
441                                           " without ID on this input stream (fseek required)\n");
442
443                         switch (blkType)
444                         {
445                                 case BLK_DATA:
446                                         _skipData(AH);
447                                         break;
448
449                                 case BLK_BLOBS:
450                                         _skipBlobs(AH);
451                                         break;
452
453                                 default:                /* Always have a default */
454                                         die_horribly(AH, modulename,
455                                                                  "unrecognized data block type (%d) while searching archive\n",
456                                                                  blkType);
457                                         break;
458                         }
459                         _readBlockHeader(AH, &blkType, &id);
460                 }
461         }
462         else
463         {
464                 /* Grab it */
465                 if (fseeko(AH->FH, tctx->dataPos, SEEK_SET) != 0)
466                         die_horribly(AH, modulename, "error during file seek: %s\n", strerror(errno));
467
468                 _readBlockHeader(AH, &blkType, &id);
469         }
470
471         /* Are we sane? */
472         if (id != te->dumpId)
473                 die_horribly(AH, modulename, "found unexpected block ID (%d) when reading data -- expected %d\n",
474                                          id, te->dumpId);
475
476         switch (blkType)
477         {
478                 case BLK_DATA:
479                         _PrintData(AH);
480                         break;
481
482                 case BLK_BLOBS:
483                         _LoadBlobs(AH);
484                         break;
485
486                 default:                                /* Always have a default */
487                         die_horribly(AH, modulename, "unrecognized data block type %d while restoring archive\n",
488                                                  blkType);
489                         break;
490         }
491 }
492
493 /*
494  * Print data from current file position.
495 */
496 static void
497 _PrintData(ArchiveHandle *AH)
498 {
499         lclContext *ctx = (lclContext *) AH->formatData;
500         z_streamp       zp = ctx->zp;
501         size_t          blkLen;
502         char       *in = ctx->zlibIn;
503         size_t          cnt;
504
505 #ifdef HAVE_LIBZ
506         int                     res;
507         char       *out = ctx->zlibOut;
508 #endif
509
510 #ifdef HAVE_LIBZ
511
512         res = Z_OK;
513
514         if (AH->compression != 0)
515         {
516                 zp->zalloc = Z_NULL;
517                 zp->zfree = Z_NULL;
518                 zp->opaque = Z_NULL;
519
520                 if (inflateInit(zp) != Z_OK)
521                         die_horribly(AH, modulename, "could not initialize compression library: %s\n", zp->msg);
522         }
523 #endif
524
525         blkLen = ReadInt(AH);
526         while (blkLen != 0)
527         {
528                 if (blkLen + 1 > ctx->inSize)
529                 {
530                         free(ctx->zlibIn);
531                         ctx->zlibIn = NULL;
532                         ctx->zlibIn = (char *) malloc(blkLen + 1);
533                         if (!ctx->zlibIn)
534                                 die_horribly(AH, modulename, "out of memory\n");
535
536                         ctx->inSize = blkLen + 1;
537                         in = ctx->zlibIn;
538                 }
539
540                 cnt = fread(in, 1, blkLen, AH->FH);
541                 if (cnt != blkLen)
542                 {
543                         if (feof(AH->FH))
544                                 die_horribly(AH, modulename,
545                                                          "could not read from input file: end of file\n");
546                         else
547                                 die_horribly(AH, modulename,
548                                         "could not read from input file: %s\n", strerror(errno));
549                 }
550
551                 ctx->filePos += blkLen;
552
553                 zp->next_in = (void *) in;
554                 zp->avail_in = blkLen;
555
556 #ifdef HAVE_LIBZ
557
558                 if (AH->compression != 0)
559                 {
560                         while (zp->avail_in != 0)
561                         {
562                                 zp->next_out = (void *) out;
563                                 zp->avail_out = zlibOutSize;
564                                 res = inflate(zp, 0);
565                                 if (res != Z_OK && res != Z_STREAM_END)
566                                         die_horribly(AH, modulename, "could not uncompress data: %s\n", zp->msg);
567
568                                 out[zlibOutSize - zp->avail_out] = '\0';
569                                 ahwrite(out, 1, zlibOutSize - zp->avail_out, AH);
570                         }
571                 }
572                 else
573                 {
574 #endif
575                         in[zp->avail_in] = '\0';
576                         ahwrite(in, 1, zp->avail_in, AH);
577                         zp->avail_in = 0;
578
579 #ifdef HAVE_LIBZ
580                 }
581 #endif
582                 blkLen = ReadInt(AH);
583         }
584
585 #ifdef HAVE_LIBZ
586         if (AH->compression != 0)
587         {
588                 zp->next_in = NULL;
589                 zp->avail_in = 0;
590                 while (res != Z_STREAM_END)
591                 {
592                         zp->next_out = (void *) out;
593                         zp->avail_out = zlibOutSize;
594                         res = inflate(zp, 0);
595                         if (res != Z_OK && res != Z_STREAM_END)
596                                 die_horribly(AH, modulename, "could not uncompress data: %s\n", zp->msg);
597
598                         out[zlibOutSize - zp->avail_out] = '\0';
599                         ahwrite(out, 1, zlibOutSize - zp->avail_out, AH);
600                 }
601                 if (inflateEnd(zp) != Z_OK)
602                         die_horribly(AH, modulename, "could not close compression library: %s\n", zp->msg);
603         }
604 #endif
605 }
606
607 static void
608 _LoadBlobs(ArchiveHandle *AH)
609 {
610         Oid                     oid;
611
612         StartRestoreBlobs(AH);
613
614         oid = ReadInt(AH);
615         while (oid != 0)
616         {
617                 StartRestoreBlob(AH, oid);
618                 _PrintData(AH);
619                 EndRestoreBlob(AH, oid);
620                 oid = ReadInt(AH);
621         }
622
623         EndRestoreBlobs(AH);
624 }
625
626 /*
627  * Skip the BLOBs from the current file position.
628  * BLOBS are written sequentially as data blocks (see below).
629  * Each BLOB is preceded by it's original OID.
630  * A zero OID indicated the end of the BLOBS
631  */
632 static void
633 _skipBlobs(ArchiveHandle *AH)
634 {
635         Oid                     oid;
636
637         oid = ReadInt(AH);
638         while (oid != 0)
639         {
640                 _skipData(AH);
641                 oid = ReadInt(AH);
642         }
643 }
644
645 /*
646  * Skip data from current file position.
647  * Data blocks are formatted as an integer length, followed by data.
648  * A zero length denoted the end of the block.
649 */
650 static void
651 _skipData(ArchiveHandle *AH)
652 {
653         lclContext *ctx = (lclContext *) AH->formatData;
654         size_t          blkLen;
655         char       *in = ctx->zlibIn;
656         size_t          cnt;
657
658         blkLen = ReadInt(AH);
659         while (blkLen != 0)
660         {
661                 if (blkLen > ctx->inSize)
662                 {
663                         free(ctx->zlibIn);
664                         ctx->zlibIn = (char *) malloc(blkLen);
665                         ctx->inSize = blkLen;
666                         in = ctx->zlibIn;
667                 }
668                 cnt = fread(in, 1, blkLen, AH->FH);
669                 if (cnt != blkLen)
670                 {
671                         if (feof(AH->FH))
672                                 die_horribly(AH, modulename,
673                                                          "could not read from input file: end of file\n");
674                         else
675                                 die_horribly(AH, modulename,
676                                         "could not read from input file: %s\n", strerror(errno));
677                 }
678
679                 ctx->filePos += blkLen;
680
681                 blkLen = ReadInt(AH);
682         }
683 }
684
685 /*
686  * Write a byte of data to the archive.
687  *
688  * Mandatory.
689  *
690  * Called by the archiver to do integer & byte output to the archive.
691  * These routines are only used to read & write headers & TOC.
692  *
693  */
694 static int
695 _WriteByte(ArchiveHandle *AH, const int i)
696 {
697         lclContext *ctx = (lclContext *) AH->formatData;
698         int                     res;
699
700         res = fputc(i, AH->FH);
701         if (res != EOF)
702                 ctx->filePos += 1;
703         else
704                 die_horribly(AH, modulename, "could not write byte: %s\n", strerror(errno));
705         return res;
706 }
707
708 /*
709  * Read a byte of data from the archive.
710  *
711  * Mandatory
712  *
713  * Called by the archiver to read bytes & integers from the archive.
714  * These routines are only used to read & write headers & TOC.
715  *
716  */
717 static int
718 _ReadByte(ArchiveHandle *AH)
719 {
720         lclContext *ctx = (lclContext *) AH->formatData;
721         int                     res;
722
723         res = fgetc(AH->FH);
724         if (res != EOF)
725                 ctx->filePos += 1;
726         return res;
727 }
728
729 /*
730  * Write a buffer of data to the archive.
731  *
732  * Mandatory.
733  *
734  * Called by the archiver to write a block of bytes to the archive.
735  * These routines are only used to read & write headers & TOC.
736  *
737  */
738 static size_t
739 _WriteBuf(ArchiveHandle *AH, const void *buf, size_t len)
740 {
741         lclContext *ctx = (lclContext *) AH->formatData;
742         size_t          res;
743
744         res = fwrite(buf, 1, len, AH->FH);
745
746         if (res != len)
747                 die_horribly(AH, modulename,
748                                          "could not write to output file: %s\n", strerror(errno));
749
750         ctx->filePos += res;
751         return res;
752 }
753
754 /*
755  * Read a block of bytes from the archive.
756  *
757  * Mandatory.
758  *
759  * Called by the archiver to read a block of bytes from the archive
760  * These routines are only used to read & write headers & TOC.
761  *
762  */
763 static size_t
764 _ReadBuf(ArchiveHandle *AH, void *buf, size_t len)
765 {
766         lclContext *ctx = (lclContext *) AH->formatData;
767         size_t          res;
768
769         res = fread(buf, 1, len, AH->FH);
770         ctx->filePos += res;
771
772         return res;
773 }
774
775 /*
776  * Close the archive.
777  *
778  * Mandatory.
779  *
780  * When writing the archive, this is the routine that actually starts
781  * the process of saving it to files. No data should be written prior
782  * to this point, since the user could sort the TOC after creating it.
783  *
784  * If an archive is to be written, this toutine must call:
785  *              WriteHead                       to save the archive header
786  *              WriteToc                        to save the TOC entries
787  *              WriteDataChunks         to save all DATA & BLOBs.
788  *
789  */
790 static void
791 _CloseArchive(ArchiveHandle *AH)
792 {
793         lclContext *ctx = (lclContext *) AH->formatData;
794         pgoff_t         tpos;
795
796         if (AH->mode == archModeWrite)
797         {
798                 WriteHead(AH);
799                 tpos = ftello(AH->FH);
800                 WriteToc(AH);
801                 ctx->dataStart = _getFilePos(AH, ctx);
802                 WriteDataChunks(AH);
803
804                 /*
805                  * This is not an essential operation - it is really only needed if we
806                  * expect to be doing seeks to read the data back - it may be ok to
807                  * just use the existing self-consistent block formatting.
808                  */
809                 if (ctx->hasSeek)
810                 {
811                         fseeko(AH->FH, tpos, SEEK_SET);
812                         WriteToc(AH);
813                 }
814         }
815
816         if (fclose(AH->FH) != 0)
817                 die_horribly(AH, modulename, "could not close archive file: %s\n", strerror(errno));
818
819         AH->FH = NULL;
820 }
821
822 /*--------------------------------------------------
823  * END OF FORMAT CALLBACKS
824  *--------------------------------------------------
825  */
826
827 /*
828  * Get the current position in the archive file.
829  */
830 static pgoff_t
831 _getFilePos(ArchiveHandle *AH, lclContext *ctx)
832 {
833         pgoff_t         pos;
834
835         if (ctx->hasSeek)
836         {
837                 pos = ftello(AH->FH);
838                 if (pos != ctx->filePos)
839                 {
840                         write_msg(modulename, "WARNING: ftell mismatch with expected position -- ftell used\n");
841
842                         /*
843                          * Prior to 1.7 (pg7.3) we relied on the internally maintained
844                          * pointer. Now we rely on pgoff_t always. pos = ctx->filePos;
845                          */
846                 }
847         }
848         else
849                 pos = ctx->filePos;
850         return pos;
851 }
852
853 /*
854  * Read a data block header. The format changed in V1.3, so we
855  * put the code here for simplicity.
856  */
857 static void
858 _readBlockHeader(ArchiveHandle *AH, int *type, int *id)
859 {
860         if (AH->version < K_VERS_1_3)
861                 *type = BLK_DATA;
862         else
863                 *type = _ReadByte(AH);
864
865         *id = ReadInt(AH);
866 }
867
868 /*
869  * If zlib is available, then startit up. This is called from
870  * StartData & StartBlob. The buffers are setup in the Init routine.
871  */
872 static void
873 _StartDataCompressor(ArchiveHandle *AH, TocEntry *te)
874 {
875         lclContext *ctx = (lclContext *) AH->formatData;
876         z_streamp       zp = ctx->zp;
877
878 #ifdef HAVE_LIBZ
879
880         if (AH->compression < 0 || AH->compression > 9)
881                 AH->compression = Z_DEFAULT_COMPRESSION;
882
883         if (AH->compression != 0)
884         {
885                 zp->zalloc = Z_NULL;
886                 zp->zfree = Z_NULL;
887                 zp->opaque = Z_NULL;
888
889                 if (deflateInit(zp, AH->compression) != Z_OK)
890                         die_horribly(AH, modulename, "could not initialize compression library: %s\n", zp->msg);
891         }
892 #else
893
894         AH->compression = 0;
895 #endif
896
897         /* Just be paranoid - maybe End is called after Start, with no Write */
898         zp->next_out = (void *) ctx->zlibOut;
899         zp->avail_out = zlibOutSize;
900 }
901
902 /*
903  * Send compressed data to the output stream (via ahwrite).
904  * Each data chunk is preceded by it's length.
905  * In the case of Z0, or no zlib, just write the raw data.
906  *
907  */
908 static int
909 _DoDeflate(ArchiveHandle *AH, lclContext *ctx, int flush)
910 {
911         z_streamp       zp = ctx->zp;
912
913 #ifdef HAVE_LIBZ
914         char       *out = ctx->zlibOut;
915         int                     res = Z_OK;
916
917         if (AH->compression != 0)
918         {
919                 res = deflate(zp, flush);
920                 if (res == Z_STREAM_ERROR)
921                         die_horribly(AH, modulename, "could not compress data: %s\n", zp->msg);
922
923                 if (((flush == Z_FINISH) && (zp->avail_out < zlibOutSize))
924                         || (zp->avail_out == 0)
925                         || (zp->avail_in != 0)
926                         )
927                 {
928                         /*
929                          * Extra paranoia: avoid zero-length chunks since a zero length
930                          * chunk is the EOF marker. This should never happen but...
931                          */
932                         if (zp->avail_out < zlibOutSize)
933                         {
934                                 /*
935                                  * printf("Wrote %lu byte deflated chunk\n", (unsigned long)
936                                  * (zlibOutSize - zp->avail_out));
937                                  */
938                                 WriteInt(AH, zlibOutSize - zp->avail_out);
939                                 if (fwrite(out, 1, zlibOutSize - zp->avail_out, AH->FH) != (zlibOutSize - zp->avail_out))
940                                         die_horribly(AH, modulename, "could not write to output file: %s\n", strerror(errno));
941                                 ctx->filePos += zlibOutSize - zp->avail_out;
942                         }
943                         zp->next_out = (void *) out;
944                         zp->avail_out = zlibOutSize;
945                 }
946         }
947         else
948 #endif
949         {
950                 if (zp->avail_in > 0)
951                 {
952                         WriteInt(AH, zp->avail_in);
953                         if (fwrite(zp->next_in, 1, zp->avail_in, AH->FH) != zp->avail_in)
954                                 die_horribly(AH, modulename, "could not write to output file: %s\n", strerror(errno));
955                         ctx->filePos += zp->avail_in;
956                         zp->avail_in = 0;
957                 }
958                 else
959                 {
960 #ifdef HAVE_LIBZ
961                         if (flush == Z_FINISH)
962                                 res = Z_STREAM_END;
963 #endif
964                 }
965         }
966
967 #ifdef HAVE_LIBZ
968         return res;
969 #else
970         return 1;
971 #endif
972 }
973
974 /*
975  * Terminate zlib context and flush it's buffers. If no zlib
976  * then just return.
977  *
978  */
979 static void
980 _EndDataCompressor(ArchiveHandle *AH, TocEntry *te)
981 {
982
983 #ifdef HAVE_LIBZ
984         lclContext *ctx = (lclContext *) AH->formatData;
985         z_streamp       zp = ctx->zp;
986         int                     res;
987
988         if (AH->compression != 0)
989         {
990                 zp->next_in = NULL;
991                 zp->avail_in = 0;
992
993                 do
994                 {
995                         /* printf("Ending data output\n"); */
996                         res = _DoDeflate(AH, ctx, Z_FINISH);
997                 } while (res != Z_STREAM_END);
998
999                 if (deflateEnd(zp) != Z_OK)
1000                         die_horribly(AH, modulename, "could not close compression stream: %s\n", zp->msg);
1001         }
1002 #endif
1003
1004         /* Send the end marker */
1005         WriteInt(AH, 0);
1006 }