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