~vcs-imports/mammoth-replicator/trunk

« back to all changes in this revision

Viewing changes to src/bin/pg_dump/pg_backup_custom.c

  • Committer: alvherre
  • Date: 2005-12-16 21:24:52 UTC
  • Revision ID: svn-v4:db760fc0-0f08-0410-9d63-cc6633f64896:trunk:1
Initial import of the REL8_0_3 sources from the Pgsql CVS repository.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*-------------------------------------------------------------------------
 
2
 *
 
3
 * pg_backup_custom.c
 
4
 *
 
5
 *      Implements the custom output format.
 
6
 *
 
7
 *      The comments with the routined in this code are a good place to
 
8
 *      understand how to write a new format.
 
9
 *
 
10
 *      See the headers to pg_restore for more details.
 
11
 *
 
12
 * Copyright (c) 2000, Philip Warner
 
13
 *              Rights are granted to use this software in any way so long
 
14
 *              as this notice is not removed.
 
15
 *
 
16
 *      The author is not responsible for loss or damages that may
 
17
 *      and any liability will be limited to the time taken to fix any
 
18
 *      related bug.
 
19
 *
 
20
 *
 
21
 * IDENTIFICATION
 
22
 *              $PostgreSQL: pgsql/src/bin/pg_dump/pg_backup_custom.c,v 1.29.4.1 2005-01-25 22:44:47 tgl 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 *) calloc(1, 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 *) calloc(1, 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
        if (AH->public.verbose)
 
283
                ahprintf(AH, "-- Data Pos: " INT64_FORMAT "\n",
 
284
                                 (int64) ctx->dataPos);
 
285
}
 
286
 
 
287
/*
 
288
 * Called by the archiver when saving TABLE DATA (not schema). This routine
 
289
 * should save whatever format-specific information is needed to read
 
290
 * the archive back.
 
291
 *
 
292
 * It is called just prior to the dumper's 'DataDumper' routine being called.
 
293
 *
 
294
 * Optional, but strongly recommended.
 
295
 *
 
296
 */
 
297
static void
 
298
_StartData(ArchiveHandle *AH, TocEntry *te)
 
299
{
 
300
        lclContext *ctx = (lclContext *) AH->formatData;
 
301
        lclTocEntry *tctx = (lclTocEntry *) te->formatData;
 
302
 
 
303
        tctx->dataPos = _getFilePos(AH, ctx);
 
304
        tctx->dataState = K_OFFSET_POS_SET;
 
305
 
 
306
        _WriteByte(AH, BLK_DATA);       /* Block type */
 
307
        WriteInt(AH, te->dumpId);       /* For sanity check */
 
308
 
 
309
        _StartDataCompressor(AH, te);
 
310
}
 
311
 
 
312
/*
 
313
 * Called by archiver when dumper calls WriteData. This routine is
 
314
 * called for both BLOB and TABLE data; it is the responsibility of
 
315
 * the format to manage each kind of data using StartBlob/StartData.
 
316
 *
 
317
 * It should only be called from withing a DataDumper routine.
 
318
 *
 
319
 * Mandatory.
 
320
 *
 
321
 */
 
322
static size_t
 
323
_WriteData(ArchiveHandle *AH, const void *data, size_t dLen)
 
324
{
 
325
        lclContext *ctx = (lclContext *) AH->formatData;
 
326
        z_streamp       zp = ctx->zp;
 
327
 
 
328
        zp->next_in = (void *) data;
 
329
        zp->avail_in = dLen;
 
330
 
 
331
        while (zp->avail_in != 0)
 
332
        {
 
333
                /* printf("Deflating %lu bytes\n", (unsigned long) dLen); */
 
334
                _DoDeflate(AH, ctx, 0);
 
335
        }
 
336
        return dLen;
 
337
}
 
338
 
 
339
/*
 
340
 * Called by the archiver when a dumper's 'DataDumper' routine has
 
341
 * finished.
 
342
 *
 
343
 * Optional.
 
344
 *
 
345
 */
 
346
static void
 
347
_EndData(ArchiveHandle *AH, TocEntry *te)
 
348
{
 
349
/*      lclContext *ctx = (lclContext *) AH->formatData; */
 
350
/*      lclTocEntry *tctx = (lclTocEntry *) te->formatData; */
 
351
 
 
352
        _EndDataCompressor(AH, te);
 
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
        tctx->dataState = K_OFFSET_POS_SET;
 
373
 
 
374
        _WriteByte(AH, BLK_BLOBS);      /* Block type */
 
375
        WriteInt(AH, te->dumpId);       /* For sanity check */
 
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 given 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->dataState == K_OFFSET_NO_DATA)
 
433
                return;
 
434
 
 
435
        if (!ctx->hasSeek || tctx->dataState == K_OFFSET_POS_NOT_SET)
 
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->dumpId)
 
444
                {
 
445
                        if ((TocIDRequired(AH, id, ropt) & REQ_DATA) != 0)
 
446
                                die_horribly(AH, modulename,
 
447
                                                         "Dumping a specific TOC data block out of order is not supported"
 
448
                                  " without ID on this input stream (fseek required)\n");
 
449
 
 
450
                        switch (blkType)
 
451
                        {
 
452
                                case BLK_DATA:
 
453
                                        _skipData(AH);
 
454
                                        break;
 
455
 
 
456
                                case BLK_BLOBS:
 
457
                                        _skipBlobs(AH);
 
458
                                        break;
 
459
 
 
460
                                default:                /* Always have a default */
 
461
                                        die_horribly(AH, modulename,
 
462
                                                                 "unrecognized data block type (%d) while searching archive\n",
 
463
                                                                 blkType);
 
464
                                        break;
 
465
                        }
 
466
                        _readBlockHeader(AH, &blkType, &id);
 
467
                }
 
468
        }
 
469
        else
 
470
        {
 
471
                /* Grab it */
 
472
                if (fseeko(AH->FH, tctx->dataPos, SEEK_SET) != 0)
 
473
                        die_horribly(AH, modulename, "error during file seek: %s\n", strerror(errno));
 
474
 
 
475
                _readBlockHeader(AH, &blkType, &id);
 
476
        }
 
477
 
 
478
        /* Are we sane? */
 
479
        if (id != te->dumpId)
 
480
                die_horribly(AH, modulename, "found unexpected block ID (%d) when reading data -- expected %d\n",
 
481
                                         id, te->dumpId);
 
482
 
 
483
        switch (blkType)
 
484
        {
 
485
                case BLK_DATA:
 
486
                        _PrintData(AH);
 
487
                        break;
 
488
 
 
489
                case BLK_BLOBS:
 
490
                        if (!AH->connection)
 
491
                                die_horribly(AH, modulename, "large objects cannot be loaded without a database connection\n");
 
492
 
 
493
                        _LoadBlobs(AH);
 
494
                        break;
 
495
 
 
496
                default:                                /* Always have a default */
 
497
                        die_horribly(AH, modulename, "unrecognized data block type %d while restoring archive\n",
 
498
                                                 blkType);
 
499
                        break;
 
500
        }
 
501
}
 
502
 
 
503
/*
 
504
 * Print data from current file position.
 
505
*/
 
506
static void
 
507
_PrintData(ArchiveHandle *AH)
 
508
{
 
509
        lclContext *ctx = (lclContext *) AH->formatData;
 
510
        z_streamp       zp = ctx->zp;
 
511
        size_t          blkLen;
 
512
        char       *in = ctx->zlibIn;
 
513
        size_t          cnt;
 
514
 
 
515
#ifdef HAVE_LIBZ
 
516
        int                     res;
 
517
        char       *out = ctx->zlibOut;
 
518
#endif
 
519
 
 
520
#ifdef HAVE_LIBZ
 
521
 
 
522
        res = Z_OK;
 
523
 
 
524
        if (AH->compression != 0)
 
525
        {
 
526
                zp->zalloc = Z_NULL;
 
527
                zp->zfree = Z_NULL;
 
528
                zp->opaque = Z_NULL;
 
529
 
 
530
                if (inflateInit(zp) != Z_OK)
 
531
                        die_horribly(AH, modulename, "could not initialize compression library: %s\n", zp->msg);
 
532
        }
 
533
#endif
 
534
 
 
535
        blkLen = ReadInt(AH);
 
536
        while (blkLen != 0)
 
537
        {
 
538
                if (blkLen + 1 > ctx->inSize)
 
539
                {
 
540
                        free(ctx->zlibIn);
 
541
                        ctx->zlibIn = NULL;
 
542
                        ctx->zlibIn = (char *) malloc(blkLen + 1);
 
543
                        if (!ctx->zlibIn)
 
544
                                die_horribly(AH, modulename, "out of memory\n");
 
545
 
 
546
                        ctx->inSize = blkLen + 1;
 
547
                        in = ctx->zlibIn;
 
548
                }
 
549
 
 
550
                cnt = fread(in, 1, blkLen, AH->FH);
 
551
                if (cnt != blkLen)
 
552
                        die_horribly(AH, modulename,
 
553
                                  "could not read data block -- expected %lu, got %lu\n",
 
554
                                                 (unsigned long) blkLen, (unsigned long) cnt);
 
555
 
 
556
                ctx->filePos += blkLen;
 
557
 
 
558
                zp->next_in = in;
 
559
                zp->avail_in = blkLen;
 
560
 
 
561
#ifdef HAVE_LIBZ
 
562
 
 
563
                if (AH->compression != 0)
 
564
                {
 
565
                        while (zp->avail_in != 0)
 
566
                        {
 
567
                                zp->next_out = out;
 
568
                                zp->avail_out = zlibOutSize;
 
569
                                res = inflate(zp, 0);
 
570
                                if (res != Z_OK && res != Z_STREAM_END)
 
571
                                        die_horribly(AH, modulename, "could not uncompress data: %s\n", zp->msg);
 
572
 
 
573
                                out[zlibOutSize - zp->avail_out] = '\0';
 
574
                                ahwrite(out, 1, zlibOutSize - zp->avail_out, AH);
 
575
                        }
 
576
                }
 
577
                else
 
578
                {
 
579
#endif
 
580
                        in[zp->avail_in] = '\0';
 
581
                        ahwrite(in, 1, zp->avail_in, AH);
 
582
                        zp->avail_in = 0;
 
583
 
 
584
#ifdef HAVE_LIBZ
 
585
                }
 
586
#endif
 
587
                blkLen = ReadInt(AH);
 
588
        }
 
589
 
 
590
#ifdef HAVE_LIBZ
 
591
        if (AH->compression != 0)
 
592
        {
 
593
                zp->next_in = NULL;
 
594
                zp->avail_in = 0;
 
595
                while (res != Z_STREAM_END)
 
596
                {
 
597
                        zp->next_out = out;
 
598
                        zp->avail_out = zlibOutSize;
 
599
                        res = inflate(zp, 0);
 
600
                        if (res != Z_OK && res != Z_STREAM_END)
 
601
                                die_horribly(AH, modulename, "could not uncompress data: %s\n", zp->msg);
 
602
 
 
603
                        out[zlibOutSize - zp->avail_out] = '\0';
 
604
                        ahwrite(out, 1, zlibOutSize - zp->avail_out, AH);
 
605
                }
 
606
                if (inflateEnd(zp) != Z_OK)
 
607
                        die_horribly(AH, modulename, "could not close compression library: %s\n", zp->msg);
 
608
        }
 
609
#endif
 
610
}
 
611
 
 
612
static void
 
613
_LoadBlobs(ArchiveHandle *AH)
 
614
{
 
615
        Oid                     oid;
 
616
 
 
617
        StartRestoreBlobs(AH);
 
618
 
 
619
        oid = ReadInt(AH);
 
620
        while (oid != 0)
 
621
        {
 
622
                StartRestoreBlob(AH, oid);
 
623
                _PrintData(AH);
 
624
                EndRestoreBlob(AH, oid);
 
625
                oid = ReadInt(AH);
 
626
        }
 
627
 
 
628
        EndRestoreBlobs(AH);
 
629
}
 
630
 
 
631
/*
 
632
 * Skip the BLOBs from the current file position.
 
633
 * BLOBS are written sequentially as data blocks (see below).
 
634
 * Each BLOB is preceded by it's original OID.
 
635
 * A zero OID indicated the end of the BLOBS
 
636
 */
 
637
static void
 
638
_skipBlobs(ArchiveHandle *AH)
 
639
{
 
640
        Oid                     oid;
 
641
 
 
642
        oid = ReadInt(AH);
 
643
        while (oid != 0)
 
644
        {
 
645
                _skipData(AH);
 
646
                oid = ReadInt(AH);
 
647
        }
 
648
}
 
649
 
 
650
/*
 
651
 * Skip data from current file position.
 
652
 * Data blocks are formatted as an integer length, followed by data.
 
653
 * A zero length denoted the end of the block.
 
654
*/
 
655
static void
 
656
_skipData(ArchiveHandle *AH)
 
657
{
 
658
        lclContext *ctx = (lclContext *) AH->formatData;
 
659
        size_t          blkLen;
 
660
        char       *in = ctx->zlibIn;
 
661
        size_t          cnt;
 
662
 
 
663
        blkLen = ReadInt(AH);
 
664
        while (blkLen != 0)
 
665
        {
 
666
                if (blkLen > ctx->inSize)
 
667
                {
 
668
                        free(ctx->zlibIn);
 
669
                        ctx->zlibIn = (char *) malloc(blkLen);
 
670
                        ctx->inSize = blkLen;
 
671
                        in = ctx->zlibIn;
 
672
                }
 
673
                cnt = fread(in, 1, blkLen, AH->FH);
 
674
                if (cnt != blkLen)
 
675
                        die_horribly(AH, modulename,
 
676
                                  "could not read data block -- expected %lu, got %lu\n",
 
677
                                                 (unsigned long) blkLen, (unsigned long) cnt);
 
678
 
 
679
                ctx->filePos += blkLen;
 
680
 
 
681
                blkLen = ReadInt(AH);
 
682
        }
 
683
}
 
684
 
 
685
/*
 
686
 * Write a byte of data to the archive.
 
687
 *
 
688
 * Mandatory.
 
689
 *
 
690
 * Called by the archiver to do integer & byte output to the archive.
 
691
 * These routines are only used to read & write headers & TOC.
 
692
 *
 
693
 */
 
694
static int
 
695
_WriteByte(ArchiveHandle *AH, const int i)
 
696
{
 
697
        lclContext *ctx = (lclContext *) AH->formatData;
 
698
        int                     res;
 
699
 
 
700
        res = fputc(i, AH->FH);
 
701
        if (res != EOF)
 
702
                ctx->filePos += 1;
 
703
        else
 
704
                die_horribly(AH, modulename, "could not write byte: %s\n", strerror(errno));
 
705
        return res;
 
706
}
 
707
 
 
708
/*
 
709
 * Read a byte of data from the archive.
 
710
 *
 
711
 * Mandatory
 
712
 *
 
713
 * Called by the archiver to read bytes & integers from the archive.
 
714
 * These routines are only used to read & write headers & TOC.
 
715
 *
 
716
 */
 
717
static int
 
718
_ReadByte(ArchiveHandle *AH)
 
719
{
 
720
        lclContext *ctx = (lclContext *) AH->formatData;
 
721
        int                     res;
 
722
 
 
723
        res = fgetc(AH->FH);
 
724
        if (res != EOF)
 
725
                ctx->filePos += 1;
 
726
        return res;
 
727
}
 
728
 
 
729
/*
 
730
 * Write a buffer of data to the archive.
 
731
 *
 
732
 * Mandatory.
 
733
 *
 
734
 * Called by the archiver to write a block of bytes to the archive.
 
735
 * These routines are only used to read & write headers & TOC.
 
736
 *
 
737
 */
 
738
static size_t
 
739
_WriteBuf(ArchiveHandle *AH, const void *buf, size_t len)
 
740
{
 
741
        lclContext *ctx = (lclContext *) AH->formatData;
 
742
        size_t          res;
 
743
 
 
744
        res = fwrite(buf, 1, len, AH->FH);
 
745
 
 
746
        if (res != len)
 
747
                die_horribly(AH, modulename,
 
748
                                         "write error in _WriteBuf (%lu != %lu)\n",
 
749
                                         (unsigned long) res, (unsigned long) len);
 
750
 
 
751
        ctx->filePos += res;
 
752
        return res;
 
753
}
 
754
 
 
755
/*
 
756
 * Read a block of bytes from the archive.
 
757
 *
 
758
 * Mandatory.
 
759
 *
 
760
 * Called by the archiver to read a block of bytes from the archive
 
761
 * These routines are only used to read & write headers & TOC.
 
762
 *
 
763
 */
 
764
static size_t
 
765
_ReadBuf(ArchiveHandle *AH, void *buf, size_t len)
 
766
{
 
767
        lclContext *ctx = (lclContext *) AH->formatData;
 
768
        size_t          res;
 
769
 
 
770
        res = fread(buf, 1, len, AH->FH);
 
771
        ctx->filePos += res;
 
772
 
 
773
        return res;
 
774
}
 
775
 
 
776
/*
 
777
 * Close the archive.
 
778
 *
 
779
 * Mandatory.
 
780
 *
 
781
 * When writing the archive, this is the routine that actually starts
 
782
 * the process of saving it to files. No data should be written prior
 
783
 * to this point, since the user could sort the TOC after creating it.
 
784
 *
 
785
 * If an archive is to be written, this toutine must call:
 
786
 *              WriteHead                       to save the archive header
 
787
 *              WriteToc                        to save the TOC entries
 
788
 *              WriteDataChunks         to save all DATA & BLOBs.
 
789
 *
 
790
 */
 
791
static void
 
792
_CloseArchive(ArchiveHandle *AH)
 
793
{
 
794
        lclContext *ctx = (lclContext *) AH->formatData;
 
795
        off_t           tpos;
 
796
 
 
797
        if (AH->mode == archModeWrite)
 
798
        {
 
799
                WriteHead(AH);
 
800
                tpos = ftello(AH->FH);
 
801
                WriteToc(AH);
 
802
                ctx->dataStart = _getFilePos(AH, ctx);
 
803
                WriteDataChunks(AH);
 
804
 
 
805
                /*
 
806
                 * This is not an essential operation - it is really only needed
 
807
                 * if we expect to be doing seeks to read the data back - it may
 
808
                 * be ok to just use the existing self-consistent block
 
809
                 * formatting.
 
810
                 */
 
811
                if (ctx->hasSeek)
 
812
                {
 
813
                        fseeko(AH->FH, tpos, SEEK_SET);
 
814
                        WriteToc(AH);
 
815
                }
 
816
        }
 
817
 
 
818
        if (fclose(AH->FH) != 0)
 
819
                die_horribly(AH, modulename, "could not close archive file: %s\n", strerror(errno));
 
820
 
 
821
        AH->FH = NULL;
 
822
}
 
823
 
 
824
/*--------------------------------------------------
 
825
 * END OF FORMAT CALLBACKS
 
826
 *--------------------------------------------------
 
827
 */
 
828
 
 
829
/*
 
830
 * Get the current position in the archive file.
 
831
 */
 
832
static off_t
 
833
_getFilePos(ArchiveHandle *AH, lclContext *ctx)
 
834
{
 
835
        off_t           pos;
 
836
 
 
837
        if (ctx->hasSeek)
 
838
        {
 
839
                pos = ftello(AH->FH);
 
840
                if (pos != ctx->filePos)
 
841
                {
 
842
                        write_msg(modulename, "WARNING: ftell mismatch with expected position -- ftell used\n");
 
843
 
 
844
                        /*
 
845
                         * Prior to 1.7 (pg7.3) we relied on the internally maintained
 
846
                         * pointer. Now we rely on off_t always. pos = ctx->filePos;
 
847
                         */
 
848
                }
 
849
        }
 
850
        else
 
851
                pos = ctx->filePos;
 
852
        return pos;
 
853
}
 
854
 
 
855
/*
 
856
 * Read a data block header. The format changed in V1.3, so we
 
857
 * put the code here for simplicity.
 
858
 */
 
859
static void
 
860
_readBlockHeader(ArchiveHandle *AH, int *type, int *id)
 
861
{
 
862
        if (AH->version < K_VERS_1_3)
 
863
                *type = BLK_DATA;
 
864
        else
 
865
                *type = _ReadByte(AH);
 
866
 
 
867
        *id = ReadInt(AH);
 
868
}
 
869
 
 
870
/*
 
871
 * If zlib is available, then startit up. This is called from
 
872
 * StartData & StartBlob. The buffers are setup in the Init routine.
 
873
 *
 
874
 */
 
875
static void
 
876
_StartDataCompressor(ArchiveHandle *AH, TocEntry *te)
 
877
{
 
878
        lclContext *ctx = (lclContext *) AH->formatData;
 
879
        z_streamp       zp = ctx->zp;
 
880
 
 
881
#ifdef HAVE_LIBZ
 
882
 
 
883
        if (AH->compression < 0 || AH->compression > 9)
 
884
                AH->compression = Z_DEFAULT_COMPRESSION;
 
885
 
 
886
        if (AH->compression != 0)
 
887
        {
 
888
                zp->zalloc = Z_NULL;
 
889
                zp->zfree = Z_NULL;
 
890
                zp->opaque = Z_NULL;
 
891
 
 
892
                if (deflateInit(zp, AH->compression) != Z_OK)
 
893
                        die_horribly(AH, modulename, "could not initialize compression library: %s\n", zp->msg);
 
894
        }
 
895
 
 
896
#else
 
897
 
 
898
        AH->compression = 0;
 
899
#endif
 
900
 
 
901
        /* Just be paranoid - maybe End is called after Start, with no Write */
 
902
        zp->next_out = ctx->zlibOut;
 
903
        zp->avail_out = zlibOutSize;
 
904
}
 
905
 
 
906
/*
 
907
 * Send compressed data to the output stream (via ahwrite).
 
908
 * Each data chunk is preceded by it's length.
 
909
 * In the case of Z0, or no zlib, just write the raw data.
 
910
 *
 
911
 */
 
912
static int
 
913
_DoDeflate(ArchiveHandle *AH, lclContext *ctx, int flush)
 
914
{
 
915
        z_streamp       zp = ctx->zp;
 
916
 
 
917
#ifdef HAVE_LIBZ
 
918
        char       *out = ctx->zlibOut;
 
919
        int                     res = Z_OK;
 
920
 
 
921
        if (AH->compression != 0)
 
922
        {
 
923
                res = deflate(zp, flush);
 
924
                if (res == Z_STREAM_ERROR)
 
925
                        die_horribly(AH, modulename, "could not compress data: %s\n", zp->msg);
 
926
 
 
927
                if (((flush == Z_FINISH) && (zp->avail_out < zlibOutSize))
 
928
                        || (zp->avail_out == 0)
 
929
                        || (zp->avail_in != 0)
 
930
                        )
 
931
                {
 
932
                        /*
 
933
                         * Extra paranoia: avoid zero-length chunks since a zero
 
934
                         * length chunk is the EOF marker. This should never happen
 
935
                         * but...
 
936
                         */
 
937
                        if (zp->avail_out < zlibOutSize)
 
938
                        {
 
939
                                /*
 
940
                                 * printf("Wrote %lu byte deflated chunk\n", (unsigned
 
941
                                 * long) (zlibOutSize - zp->avail_out));
 
942
                                 */
 
943
                                WriteInt(AH, zlibOutSize - zp->avail_out);
 
944
                                if (fwrite(out, 1, zlibOutSize - zp->avail_out, AH->FH) != (zlibOutSize - zp->avail_out))
 
945
                                        die_horribly(AH, modulename, "could not write compressed chunk\n");
 
946
                                ctx->filePos += zlibOutSize - zp->avail_out;
 
947
                        }
 
948
                        zp->next_out = out;
 
949
                        zp->avail_out = zlibOutSize;
 
950
                }
 
951
        }
 
952
        else
 
953
#endif
 
954
        {
 
955
                if (zp->avail_in > 0)
 
956
                {
 
957
                        WriteInt(AH, zp->avail_in);
 
958
                        if (fwrite(zp->next_in, 1, zp->avail_in, AH->FH) != zp->avail_in)
 
959
                                die_horribly(AH, modulename, "could not write uncompressed chunk\n");
 
960
                        ctx->filePos += zp->avail_in;
 
961
                        zp->avail_in = 0;
 
962
                }
 
963
                else
 
964
                {
 
965
#ifdef HAVE_LIBZ
 
966
                        if (flush == Z_FINISH)
 
967
                                res = Z_STREAM_END;
 
968
#endif
 
969
                }
 
970
        }
 
971
 
 
972
#ifdef HAVE_LIBZ
 
973
        return res;
 
974
#else
 
975
        return 1;
 
976
#endif
 
977
}
 
978
 
 
979
/*
 
980
 * Terminate zlib context and flush it's buffers. If no zlib
 
981
 * then just return.
 
982
 *
 
983
 */
 
984
static void
 
985
_EndDataCompressor(ArchiveHandle *AH, TocEntry *te)
 
986
{
 
987
 
 
988
#ifdef HAVE_LIBZ
 
989
        lclContext *ctx = (lclContext *) AH->formatData;
 
990
        z_streamp       zp = ctx->zp;
 
991
        int                     res;
 
992
 
 
993
        if (AH->compression != 0)
 
994
        {
 
995
                zp->next_in = NULL;
 
996
                zp->avail_in = 0;
 
997
 
 
998
                do
 
999
                {
 
1000
                        /* printf("Ending data output\n"); */
 
1001
                        res = _DoDeflate(AH, ctx, Z_FINISH);
 
1002
                } while (res != Z_STREAM_END);
 
1003
 
 
1004
                if (deflateEnd(zp) != Z_OK)
 
1005
                        die_horribly(AH, modulename, "could not close compression stream: %s\n", zp->msg);
 
1006
        }
 
1007
#endif
 
1008
 
 
1009
        /* Send the end marker */
 
1010
        WriteInt(AH, 0);
 
1011
}