]> 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.21 2002/09/04 20:31:34 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         off_t           dataPos;
83         size_t          dataLen;
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
175                 if (AH->fSpec && strcmp(AH->fSpec, "") != 0)
176                         AH->FH = fopen(AH->fSpec, PG_BINARY_W);
177                 else
178                         AH->FH = stdout;
179
180                 if (!AH->FH)
181                         die_horribly(AH, modulename, "could not open archive file %s: %s\n", AH->fSpec, strerror(errno));
182
183                 ctx->hasSeek = (fseeko(AH->FH, 0, SEEK_CUR) == 0);
184
185         }
186         else
187         {
188
189                 if (AH->fSpec && strcmp(AH->fSpec, "") != 0)
190                         AH->FH = fopen(AH->fSpec, PG_BINARY_R);
191                 else
192                         AH->FH = stdin;
193                 if (!AH->FH)
194                         die_horribly(AH, modulename, "could not open archive file %s: %s\n", AH->fSpec, strerror(errno));
195
196                 ctx->hasSeek = (fseeko(AH->FH, 0, SEEK_CUR) == 0);
197
198                 ReadHead(AH);
199                 ReadToc(AH);
200                 ctx->dataStart = _getFilePos(AH, ctx);
201         }
202
203 }
204
205 /*
206  * Called by the Archiver when the dumper creates a new TOC entry.
207  *
208  * Optional.
209  *
210  * Set up extrac format-related TOC data.
211 */
212 static void
213 _ArchiveEntry(ArchiveHandle *AH, TocEntry *te)
214 {
215         lclTocEntry *ctx;
216
217         ctx = (lclTocEntry *) calloc(1, sizeof(lclTocEntry));
218         if (te->dataDumper)
219                 ctx->dataPos = -1;
220         else
221                 ctx->dataPos = 0;
222         ctx->dataLen = 0;
223         te->formatData = (void *) ctx;
224
225 }
226
227 /*
228  * Called by the Archiver to save any extra format-related TOC entry
229  * data.
230  *
231  * Optional.
232  *
233  * Use the Archiver routines to write data - they are non-endian, and
234  * maintain other important file information.
235  */
236 static void
237 _WriteExtraToc(ArchiveHandle *AH, TocEntry *te)
238 {
239         lclTocEntry *ctx = (lclTocEntry *) te->formatData;
240
241         WriteInt(AH, ctx->dataPos);
242         WriteInt(AH, ctx->dataLen);
243 }
244
245 /*
246  * Called by the Archiver to read any extra format-related TOC data.
247  *
248  * Optional.
249  *
250  * Needs to match the order defined in _WriteExtraToc, and sould also
251  * use the Archiver input routines.
252  */
253 static void
254 _ReadExtraToc(ArchiveHandle *AH, TocEntry *te)
255 {
256         lclTocEntry *ctx = (lclTocEntry *) te->formatData;
257
258         if (ctx == NULL)
259         {
260                 ctx = (lclTocEntry *) malloc(sizeof(lclTocEntry));
261                 te->formatData = (void *) ctx;
262         }
263
264         ctx->dataPos = ReadInt(AH);
265         ctx->dataLen = ReadInt(AH);
266 }
267
268 /*
269  * Called by the Archiver when restoring an archive to output a comment
270  * that includes useful information about the TOC entry.
271  *
272  * Optional.
273  *
274  */
275 static void
276 _PrintExtraToc(ArchiveHandle *AH, TocEntry *te)
277 {
278         lclTocEntry *ctx = (lclTocEntry *) te->formatData;
279
280         ahprintf(AH, "-- Data Pos: " INT64_FORMAT " (Length %lu)\n",
281                          (int64) ctx->dataPos, (unsigned long) ctx->dataLen);
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
302         _WriteByte(AH, BLK_DATA);       /* Block type */
303         WriteInt(AH, te->id);           /* For sanity check */
304
305         _StartDataCompressor(AH, te);
306
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 withing a DataDumper routine.
315  *
316  * Mandatory.
317  *
318  */
319 static size_t
320 _WriteData(ArchiveHandle *AH, const void *data, size_t dLen)
321 {
322         lclContext *ctx = (lclContext *) AH->formatData;
323         z_streamp       zp = ctx->zp;
324
325         zp->next_in = (void *) data;
326         zp->avail_in = dLen;
327
328         while (zp->avail_in != 0)
329         {
330                 /* printf("Deflating %lu bytes\n", (unsigned long) dLen); */
331                 _DoDeflate(AH, ctx, 0);
332         }
333         return dLen;
334 }
335
336 /*
337  * Called by the archiver when a dumper's 'DataDumper' routine has
338  * finished.
339  *
340  * Optional.
341  *
342  */
343 static void
344 _EndData(ArchiveHandle *AH, TocEntry *te)
345 {
346         lclContext *ctx = (lclContext *) AH->formatData;
347         lclTocEntry *tctx = (lclTocEntry *) te->formatData;
348
349         _EndDataCompressor(AH, te);
350
351         tctx->dataLen = _getFilePos(AH, ctx) - tctx->dataPos;
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
372         _WriteByte(AH, BLK_BLOBS);      /* Block type */
373         WriteInt(AH, te->id);           /* For sanity check */
374
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->dataPos == 0)
432                 return;
433
434         if (!ctx->hasSeek || tctx->dataPos < 0)
435         {
436
437                 /* Skip over unnecessary blocks until we get the one we want. */
438
439                 found = 0;
440
441                 _readBlockHeader(AH, &blkType, &id);
442
443                 while (id != te->id)
444                 {
445
446                         if ((TocIDRequired(AH, id, ropt) & 2) != 0)
447                                 die_horribly(AH, modulename,
448                                                          "Dumping a specific TOC data block out of order is not supported"
449                                   " without id on this input stream (fseek required)\n");
450
451                         switch (blkType)
452                         {
453
454                                 case BLK_DATA:
455
456                                         _skipData(AH);
457                                         break;
458
459                                 case BLK_BLOBS:
460
461                                         _skipBlobs(AH);
462                                         break;
463
464                                 default:                /* Always have a default */
465
466                                         die_horribly(AH, modulename,
467                                                                  "unrecognized data block type (%d) while searching archive\n",
468                                                                  blkType);
469                                         break;
470                         }
471
472                         _readBlockHeader(AH, &blkType, &id);
473
474                 }
475
476         }
477         else
478         {
479
480                 /* Grab it */
481
482                 if (fseeko(AH->FH, tctx->dataPos, SEEK_SET) != 0)
483                         die_horribly(AH, modulename, "error during file seek: %s\n", strerror(errno));
484
485                 _readBlockHeader(AH, &blkType, &id);
486
487         }
488
489         /* Are we sane? */
490         if (id != te->id)
491                 die_horribly(AH, modulename, "found unexpected block ID (%d) when reading data - expected %d\n",
492                                          id, te->id);
493
494         switch (blkType)
495         {
496
497                 case BLK_DATA:
498
499                         _PrintData(AH);
500                         break;
501
502                 case BLK_BLOBS:
503
504                         if (!AH->connection)
505                                 die_horribly(AH, modulename, "large objects cannot be loaded without a database connection\n");
506
507                         _LoadBlobs(AH);
508                         break;
509
510                 default:                                /* Always have a default */
511
512                         die_horribly(AH, modulename, "unrecognized data block type %d while restoring archive\n",
513                                                  blkType);
514                         break;
515         }
516
517         ahprintf(AH, "\n\n");
518 }
519
520 /*
521  * Print data from current file position.
522 */
523 static void
524 _PrintData(ArchiveHandle *AH)
525 {
526         lclContext *ctx = (lclContext *) AH->formatData;
527         z_streamp       zp = ctx->zp;
528         size_t          blkLen;
529         char       *in = ctx->zlibIn;
530         size_t          cnt;
531
532 #ifdef HAVE_LIBZ
533         int                     res;
534         char       *out = ctx->zlibOut;
535 #endif
536
537 #ifdef HAVE_LIBZ
538
539         res = Z_OK;
540
541         if (AH->compression != 0)
542         {
543                 zp->zalloc = Z_NULL;
544                 zp->zfree = Z_NULL;
545                 zp->opaque = Z_NULL;
546
547                 if (inflateInit(zp) != Z_OK)
548                         die_horribly(AH, modulename, "could not initialize compression library: %s\n", zp->msg);
549         }
550 #endif
551
552         blkLen = ReadInt(AH);
553         while (blkLen != 0)
554         {
555                 if (blkLen + 1 > ctx->inSize)
556                 {
557                         free(ctx->zlibIn);
558                         ctx->zlibIn = NULL;
559                         ctx->zlibIn = (char *) malloc(blkLen + 1);
560                         if (!ctx->zlibIn)
561                                 die_horribly(AH, modulename, "out of memory\n");
562
563                         ctx->inSize = blkLen + 1;
564                         in = ctx->zlibIn;
565                 }
566
567                 cnt = fread(in, 1, blkLen, AH->FH);
568                 if (cnt != blkLen)
569                         die_horribly(AH, modulename,
570                                    "could not read data block - expected %lu, got %lu\n",
571                                                  (unsigned long) blkLen, (unsigned long) cnt);
572
573                 ctx->filePos += blkLen;
574
575                 zp->next_in = in;
576                 zp->avail_in = blkLen;
577
578 #ifdef HAVE_LIBZ
579
580                 if (AH->compression != 0)
581                 {
582
583                         while (zp->avail_in != 0)
584                         {
585                                 zp->next_out = out;
586                                 zp->avail_out = zlibOutSize;
587                                 res = inflate(zp, 0);
588                                 if (res != Z_OK && res != Z_STREAM_END)
589                                         die_horribly(AH, modulename, "unable to uncompress data: %s\n", zp->msg);
590
591                                 out[zlibOutSize - zp->avail_out] = '\0';
592                                 ahwrite(out, 1, zlibOutSize - zp->avail_out, AH);
593                         }
594                 }
595                 else
596                 {
597 #endif
598                         in[zp->avail_in] = '\0';
599                         ahwrite(in, 1, zp->avail_in, AH);
600                         zp->avail_in = 0;
601
602 #ifdef HAVE_LIBZ
603                 }
604 #endif
605
606                 blkLen = ReadInt(AH);
607
608         }
609
610 #ifdef HAVE_LIBZ
611         if (AH->compression != 0)
612         {
613                 zp->next_in = NULL;
614                 zp->avail_in = 0;
615                 while (res != Z_STREAM_END)
616                 {
617                         zp->next_out = out;
618                         zp->avail_out = zlibOutSize;
619                         res = inflate(zp, 0);
620                         if (res != Z_OK && res != Z_STREAM_END)
621                                 die_horribly(AH, modulename, "unable to uncompress data: %s\n", zp->msg);
622
623                         out[zlibOutSize - zp->avail_out] = '\0';
624                         ahwrite(out, 1, zlibOutSize - zp->avail_out, AH);
625                 }
626                 if (inflateEnd(zp) != Z_OK)
627                         die_horribly(AH, modulename, "could not close compression library: %s\n", zp->msg);
628         }
629 #endif
630
631 }
632
633 static void
634 _LoadBlobs(ArchiveHandle *AH)
635 {
636         Oid                     oid;
637
638         StartRestoreBlobs(AH);
639
640         oid = ReadInt(AH);
641         while (oid != 0)
642         {
643                 StartRestoreBlob(AH, oid);
644                 _PrintData(AH);
645                 EndRestoreBlob(AH, oid);
646                 oid = ReadInt(AH);
647         }
648
649         EndRestoreBlobs(AH);
650
651 }
652
653 /*
654  * Skip the BLOBs from the current file position.
655  * BLOBS are written sequentially as data blocks (see below).
656  * Each BLOB is preceded by it's original OID.
657  * A zero OID indicated the end of the BLOBS
658  */
659 static void
660 _skipBlobs(ArchiveHandle *AH)
661 {
662         Oid                     oid;
663
664         oid = ReadInt(AH);
665         while (oid != 0)
666         {
667                 _skipData(AH);
668                 oid = ReadInt(AH);
669         }
670 }
671
672 /*
673  * Skip data from current file position.
674  * Data blocks are formatted as an integer length, followed by data.
675  * A zero length denoted the end of the block.
676 */
677 static void
678 _skipData(ArchiveHandle *AH)
679 {
680         lclContext *ctx = (lclContext *) AH->formatData;
681         size_t          blkLen;
682         char       *in = ctx->zlibIn;
683         size_t          cnt;
684
685         blkLen = ReadInt(AH);
686         while (blkLen != 0)
687         {
688                 if (blkLen > ctx->inSize)
689                 {
690                         free(ctx->zlibIn);
691                         ctx->zlibIn = (char *) malloc(blkLen);
692                         ctx->inSize = blkLen;
693                         in = ctx->zlibIn;
694                 }
695                 cnt = fread(in, 1, blkLen, AH->FH);
696                 if (cnt != blkLen)
697                         die_horribly(AH, modulename,
698                                    "could not read data block - expected %lu, got %lu\n",
699                                                  (unsigned long) blkLen, (unsigned long) cnt);
700
701                 ctx->filePos += blkLen;
702
703                 blkLen = ReadInt(AH);
704         }
705
706 }
707
708 /*
709  * Write a byte of data to the archive.
710  *
711  * Mandatory.
712  *
713  * Called by the archiver to do integer & byte output to the archive.
714  * These routines are only used to read & write headers & TOC.
715  *
716  */
717 static int
718 _WriteByte(ArchiveHandle *AH, const int i)
719 {
720         lclContext *ctx = (lclContext *) AH->formatData;
721         int                     res;
722
723         res = fputc(i, AH->FH);
724         if (res != EOF)
725                 ctx->filePos += 1;
726         else
727                 die_horribly(AH, modulename, "could not write byte: %s\n", strerror(errno));
728         return res;
729 }
730
731 /*
732  * Read a byte of data from the archive.
733  *
734  * Mandatory
735  *
736  * Called by the archiver to read bytes & integers from the archive.
737  * These routines are only used to read & write headers & TOC.
738  *
739  */
740 static int
741 _ReadByte(ArchiveHandle *AH)
742 {
743         lclContext *ctx = (lclContext *) AH->formatData;
744         int                     res;
745
746         res = fgetc(AH->FH);
747         if (res != EOF)
748                 ctx->filePos += 1;
749         return res;
750 }
751
752 /*
753  * Write a buffer of data to the archive.
754  *
755  * Mandatory.
756  *
757  * Called by the archiver to write a block of bytes to the archive.
758  * These routines are only used to read & write headers & TOC.
759  *
760  */
761 static size_t
762 _WriteBuf(ArchiveHandle *AH, const void *buf, size_t len)
763 {
764         lclContext *ctx = (lclContext *) AH->formatData;
765         size_t          res;
766
767         res = fwrite(buf, 1, len, AH->FH);
768
769         if (res != len)
770                 die_horribly(AH, modulename,
771                                          "write error in _WriteBuf (%lu != %lu)\n",
772                                          (unsigned long) res, (unsigned long) len);
773
774         ctx->filePos += res;
775         return res;
776 }
777
778 /*
779  * Read a block of bytes from the archive.
780  *
781  * Mandatory.
782  *
783  * Called by the archiver to read a block of bytes from the archive
784  * These routines are only used to read & write headers & TOC.
785  *
786  */
787 static size_t
788 _ReadBuf(ArchiveHandle *AH, void *buf, size_t len)
789 {
790         lclContext *ctx = (lclContext *) AH->formatData;
791         size_t          res;
792
793         res = fread(buf, 1, len, AH->FH);
794         ctx->filePos += res;
795
796         return res;
797 }
798
799 /*
800  * Close the archive.
801  *
802  * Mandatory.
803  *
804  * When writing the archive, this is the routine that actually starts
805  * the process of saving it to files. No data should be written prior
806  * to this point, since the user could sort the TOC after creating it.
807  *
808  * If an archive is to be written, this toutine must call:
809  *              WriteHead                       to save the archive header
810  *              WriteToc                        to save the TOC entries
811  *              WriteDataChunks         to save all DATA & BLOBs.
812  *
813  */
814 static void
815 _CloseArchive(ArchiveHandle *AH)
816 {
817         lclContext *ctx = (lclContext *) AH->formatData;
818         off_t           tpos;
819
820         if (AH->mode == archModeWrite)
821         {
822                 WriteHead(AH);
823                 tpos = ftello(AH->FH);
824                 WriteToc(AH);
825                 ctx->dataStart = _getFilePos(AH, ctx);
826                 WriteDataChunks(AH);
827
828                 /*
829                  * This is not an essential operation - it is really only needed
830                  * if we expect to be doing seeks to read the data back - it may
831                  * be ok to just use the existing self-consistent block
832                  * formatting.
833                  */
834                 if (ctx->hasSeek)
835                 {
836                         fseeko(AH->FH, tpos, SEEK_SET);
837                         WriteToc(AH);
838                 }
839         }
840
841         if (fclose(AH->FH) != 0)
842                 die_horribly(AH, modulename, "could not close archive file: %s\n", strerror(errno));
843
844         AH->FH = NULL;
845 }
846
847 /*--------------------------------------------------
848  * END OF FORMAT CALLBACKS
849  *--------------------------------------------------
850  */
851
852 /*
853  * Get the current position in the archive file.
854  */
855 static off_t
856 _getFilePos(ArchiveHandle *AH, lclContext *ctx)
857 {
858         off_t           pos;
859
860         if (ctx->hasSeek)
861         {
862                 pos = ftello(AH->FH);
863                 if (pos != ctx->filePos)
864                 {
865                         write_msg(modulename, "WARNING: ftell mismatch with expected position -- ftell ignored\n");
866                         pos = ctx->filePos;
867                 }
868         }
869         else
870                 pos = ctx->filePos;
871         return pos;
872 }
873
874 /*
875  * Read a data block header. The format changed in V1.3, so we
876  * put the code here for simplicity.
877  */
878 static void
879 _readBlockHeader(ArchiveHandle *AH, int *type, int *id)
880 {
881         if (AH->version < K_VERS_1_3)
882                 *type = BLK_DATA;
883         else
884                 *type = _ReadByte(AH);;
885
886         *id = ReadInt(AH);
887 }
888
889 /*
890  * If zlib is available, then startit up. This is called from
891  * StartData & StartBlob. The buffers are setup in the Init routine.
892  *
893  */
894 static void
895 _StartDataCompressor(ArchiveHandle *AH, TocEntry *te)
896 {
897         lclContext *ctx = (lclContext *) AH->formatData;
898         z_streamp       zp = ctx->zp;
899
900 #ifdef HAVE_LIBZ
901
902         if (AH->compression < 0 || AH->compression > 9)
903                 AH->compression = Z_DEFAULT_COMPRESSION;
904
905         if (AH->compression != 0)
906         {
907                 zp->zalloc = Z_NULL;
908                 zp->zfree = Z_NULL;
909                 zp->opaque = Z_NULL;
910
911                 if (deflateInit(zp, AH->compression) != Z_OK)
912                         die_horribly(AH, modulename, "could not initialize compression library: %s\n", zp->msg);
913         }
914
915 #else
916
917         AH->compression = 0;
918 #endif
919
920         /* Just be paranoid - maybe End is called after Start, with no Write */
921         zp->next_out = ctx->zlibOut;
922         zp->avail_out = zlibOutSize;
923 }
924
925 /*
926  * Send compressed data to the output stream (via ahwrite).
927  * Each data chunk is preceded by it's length.
928  * In the case of Z0, or no zlib, just write the raw data.
929  *
930  */
931 static int
932 _DoDeflate(ArchiveHandle *AH, lclContext *ctx, int flush)
933 {
934         z_streamp       zp = ctx->zp;
935
936 #ifdef HAVE_LIBZ
937         char       *out = ctx->zlibOut;
938         int                     res = Z_OK;
939
940         if (AH->compression != 0)
941         {
942                 res = deflate(zp, flush);
943                 if (res == Z_STREAM_ERROR)
944                         die_horribly(AH, modulename, "could not compress data: %s\n", zp->msg);
945
946                 if (((flush == Z_FINISH) && (zp->avail_out < zlibOutSize))
947                         || (zp->avail_out == 0)
948                         || (zp->avail_in != 0)
949                         )
950                 {
951                         /*
952                          * Extra paranoia: avoid zero-length chunks since a zero
953                          * length chunk is the EOF marker. This should never happen
954                          * but...
955                          */
956                         if (zp->avail_out < zlibOutSize)
957                         {
958                                 /*
959                                  * printf("Wrote %lu byte deflated chunk\n", (unsigned
960                                  * long) (zlibOutSize - zp->avail_out));
961                                  */
962                                 WriteInt(AH, zlibOutSize - zp->avail_out);
963                                 if (fwrite(out, 1, zlibOutSize - zp->avail_out, AH->FH) != (zlibOutSize - zp->avail_out))
964                                         die_horribly(AH, modulename, "could not write compressed chunk\n");
965                                 ctx->filePos += zlibOutSize - zp->avail_out;
966                         }
967                         zp->next_out = out;
968                         zp->avail_out = zlibOutSize;
969                 }
970         }
971         else
972 #endif
973         {
974                 if (zp->avail_in > 0)
975                 {
976                         WriteInt(AH, zp->avail_in);
977                         if (fwrite(zp->next_in, 1, zp->avail_in, AH->FH) != zp->avail_in)
978                                 die_horribly(AH, modulename, "could not write uncompressed chunk\n");
979                         ctx->filePos += zp->avail_in;
980                         zp->avail_in = 0;
981                 }
982                 else
983                 {
984 #ifdef HAVE_LIBZ
985                         if (flush == Z_FINISH)
986                                 res = Z_STREAM_END;
987 #endif
988                 }
989
990
991         }
992
993 #ifdef HAVE_LIBZ
994         return res;
995 #else
996         return 1;
997 #endif
998
999 }
1000
1001 /*
1002  * Terminate zlib context and flush it's buffers. If no zlib
1003  * then just return.
1004  *
1005  */
1006 static void
1007 _EndDataCompressor(ArchiveHandle *AH, TocEntry *te)
1008 {
1009
1010 #ifdef HAVE_LIBZ
1011         lclContext *ctx = (lclContext *) AH->formatData;
1012         z_streamp       zp = ctx->zp;
1013         int                     res;
1014
1015         if (AH->compression != 0)
1016         {
1017                 zp->next_in = NULL;
1018                 zp->avail_in = 0;
1019
1020                 do
1021                 {
1022                         /* printf("Ending data output\n"); */
1023                         res = _DoDeflate(AH, ctx, Z_FINISH);
1024                 } while (res != Z_STREAM_END);
1025
1026                 if (deflateEnd(zp) != Z_OK)
1027                         die_horribly(AH, modulename, "could not close compression stream: %s\n", zp->msg);
1028         }
1029 #endif
1030
1031         /* Send the end marker */
1032         WriteInt(AH, 0);
1033 }