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