1 /*-------------------------------------------------------------------------
5 * This file is copied from the 'custom' format file, but dumps data into
6 * separate files, and the TOC into the 'main' file.
8 * IT IS FOR DEMONSTRATION PURPOSES ONLY.
10 * (and could probably be used as a basis for writing a tar file)
12 * See the headers to pg_restore for more details.
14 * Copyright (c) 2000, Philip Warner
15 * Rights are granted to use this software in any way so long
16 * as this notice is not removed.
18 * The author is not responsible for loss or damages that may
19 * result from it's use.
25 *-------------------------------------------------------------------------
28 #include "pg_backup_archiver.h"
30 static void _ArchiveEntry(ArchiveHandle
*AH
, TocEntry
*te
);
31 static void _StartData(ArchiveHandle
*AH
, TocEntry
*te
);
32 static size_t _WriteData(ArchiveHandle
*AH
, const void *data
, size_t dLen
);
33 static void _EndData(ArchiveHandle
*AH
, TocEntry
*te
);
34 static int _WriteByte(ArchiveHandle
*AH
, const int i
);
35 static int _ReadByte(ArchiveHandle
*);
36 static size_t _WriteBuf(ArchiveHandle
*AH
, const void *buf
, size_t len
);
37 static size_t _ReadBuf(ArchiveHandle
*AH
, void *buf
, size_t len
);
38 static void _CloseArchive(ArchiveHandle
*AH
);
39 static void _PrintTocData(ArchiveHandle
*AH
, TocEntry
*te
, RestoreOptions
*ropt
);
40 static void _WriteExtraToc(ArchiveHandle
*AH
, TocEntry
*te
);
41 static void _ReadExtraToc(ArchiveHandle
*AH
, TocEntry
*te
);
42 static void _PrintExtraToc(ArchiveHandle
*AH
, TocEntry
*te
);
44 static void _StartBlobs(ArchiveHandle
*AH
, TocEntry
*te
);
45 static void _StartBlob(ArchiveHandle
*AH
, TocEntry
*te
, Oid oid
);
46 static void _EndBlob(ArchiveHandle
*AH
, TocEntry
*te
, Oid oid
);
47 static void _EndBlobs(ArchiveHandle
*AH
, TocEntry
*te
);
49 #define K_STD_BUF_SIZE 1024
68 static const char *modulename
= gettext_noop("file archiver");
69 static void _LoadBlobs(ArchiveHandle
*AH
, RestoreOptions
*ropt
);
70 static void _getBlobTocEntry(ArchiveHandle
*AH
, Oid
*oid
, char *fname
);
76 InitArchiveFmt_Files(ArchiveHandle
*AH
)
80 /* Assuming static functions, this can be copied for each format. */
81 AH
->ArchiveEntryPtr
= _ArchiveEntry
;
82 AH
->StartDataPtr
= _StartData
;
83 AH
->WriteDataPtr
= _WriteData
;
84 AH
->EndDataPtr
= _EndData
;
85 AH
->WriteBytePtr
= _WriteByte
;
86 AH
->ReadBytePtr
= _ReadByte
;
87 AH
->WriteBufPtr
= _WriteBuf
;
88 AH
->ReadBufPtr
= _ReadBuf
;
89 AH
->ClosePtr
= _CloseArchive
;
90 AH
->PrintTocDataPtr
= _PrintTocData
;
91 AH
->ReadExtraTocPtr
= _ReadExtraToc
;
92 AH
->WriteExtraTocPtr
= _WriteExtraToc
;
93 AH
->PrintExtraTocPtr
= _PrintExtraToc
;
95 AH
->StartBlobsPtr
= _StartBlobs
;
96 AH
->StartBlobPtr
= _StartBlob
;
97 AH
->EndBlobPtr
= _EndBlob
;
98 AH
->EndBlobsPtr
= _EndBlobs
;
101 * Set up some special context used in compressing data.
103 ctx
= (lclContext
*) calloc(1, sizeof(lclContext
));
104 AH
->formatData
= (void *) ctx
;
107 /* Initialize LO buffering */
108 AH
->lo_buf_size
= LOBBUFSIZE
;
109 AH
->lo_buf
= (void *) malloc(LOBBUFSIZE
);
110 if (AH
->lo_buf
== NULL
)
111 die_horribly(AH
, modulename
, "out of memory\n");
114 * Now open the TOC file
116 if (AH
->mode
== archModeWrite
)
119 write_msg(modulename
, "WARNING:\n"
120 " This format is for demonstration purposes; it is not intended for\n"
121 " normal use. Files will be written in the current working directory.\n");
123 if (AH
->fSpec
&& strcmp(AH
->fSpec
, "") != 0)
125 AH
->FH
= fopen(AH
->fSpec
, PG_BINARY_W
);
127 die_horribly(NULL
, modulename
, "could not open output file \"%s\": %s\n",
128 AH
->fSpec
, strerror(errno
));
134 die_horribly(NULL
, modulename
, "could not open output file: %s\n",
138 ctx
->hasSeek
= checkSeek(AH
->FH
);
140 if (AH
->compression
< 0 || AH
->compression
> 9)
141 AH
->compression
= Z_DEFAULT_COMPRESSION
;
148 if (AH
->fSpec
&& strcmp(AH
->fSpec
, "") != 0)
150 AH
->FH
= fopen(AH
->fSpec
, PG_BINARY_R
);
152 die_horribly(NULL
, modulename
, "could not open input file \"%s\": %s\n",
153 AH
->fSpec
, strerror(errno
));
159 die_horribly(NULL
, modulename
, "could not open input file: %s\n",
163 ctx
->hasSeek
= checkSeek(AH
->FH
);
167 /* Nothing else in the file... */
168 if (fclose(AH
->FH
) != 0)
169 die_horribly(AH
, modulename
, "could not close TOC file: %s\n", strerror(errno
));
174 * - Start a new TOC entry
175 * Setup the output file name.
178 _ArchiveEntry(ArchiveHandle
*AH
, TocEntry
*te
)
181 char fn
[K_STD_BUF_SIZE
];
183 ctx
= (lclTocEntry
*) calloc(1, sizeof(lclTocEntry
));
187 if (AH
->compression
== 0)
188 sprintf(fn
, "%d.dat", te
->dumpId
);
190 sprintf(fn
, "%d.dat.gz", te
->dumpId
);
192 sprintf(fn
, "%d.dat", te
->dumpId
);
194 ctx
->filename
= strdup(fn
);
198 ctx
->filename
= NULL
;
201 te
->formatData
= (void *) ctx
;
205 _WriteExtraToc(ArchiveHandle
*AH
, TocEntry
*te
)
207 lclTocEntry
*ctx
= (lclTocEntry
*) te
->formatData
;
210 WriteStr(AH
, ctx
->filename
);
216 _ReadExtraToc(ArchiveHandle
*AH
, TocEntry
*te
)
218 lclTocEntry
*ctx
= (lclTocEntry
*) te
->formatData
;
222 ctx
= (lclTocEntry
*) calloc(1, sizeof(lclTocEntry
));
223 te
->formatData
= (void *) ctx
;
226 ctx
->filename
= ReadStr(AH
);
227 if (strlen(ctx
->filename
) == 0)
230 ctx
->filename
= NULL
;
236 _PrintExtraToc(ArchiveHandle
*AH
, TocEntry
*te
)
238 lclTocEntry
*ctx
= (lclTocEntry
*) te
->formatData
;
240 if (AH
->public.verbose
)
241 ahprintf(AH
, "-- File: %s\n", ctx
->filename
);
245 _StartData(ArchiveHandle
*AH
, TocEntry
*te
)
247 lclTocEntry
*tctx
= (lclTocEntry
*) te
->formatData
;
250 sprintf(fmode
, "wb%d", AH
->compression
);
253 tctx
->FH
= gzopen(tctx
->filename
, fmode
);
255 tctx
->FH
= fopen(tctx
->filename
, PG_BINARY_W
);
258 if (tctx
->FH
== NULL
)
259 die_horribly(AH
, modulename
, "could not open output file \"%s\": %s\n",
260 tctx
->filename
, strerror(errno
));
264 _WriteData(ArchiveHandle
*AH
, const void *data
, size_t dLen
)
266 lclTocEntry
*tctx
= (lclTocEntry
*) AH
->currToc
->formatData
;
268 GZWRITE((void *) data
, 1, dLen
, tctx
->FH
);
274 _EndData(ArchiveHandle
*AH
, TocEntry
*te
)
276 lclTocEntry
*tctx
= (lclTocEntry
*) te
->formatData
;
279 if (GZCLOSE(tctx
->FH
) != 0)
280 die_horribly(AH
, modulename
, "could not close data file\n");
286 * Print data for a given file
289 _PrintFileData(ArchiveHandle
*AH
, char *filename
, RestoreOptions
*ropt
)
298 AH
->FH
= gzopen(filename
, "rb");
300 AH
->FH
= fopen(filename
, PG_BINARY_R
);
304 die_horribly(AH
, modulename
, "could not open input file \"%s\": %s\n",
305 filename
, strerror(errno
));
307 while ((cnt
= GZREAD(buf
, 1, 4095, AH
->FH
)) > 0)
310 ahwrite(buf
, 1, cnt
, AH
);
313 if (GZCLOSE(AH
->FH
) != 0)
314 die_horribly(AH
, modulename
, "could not close data file after reading\n");
319 * Print data for a given TOC entry
322 _PrintTocData(ArchiveHandle
*AH
, TocEntry
*te
, RestoreOptions
*ropt
)
324 lclTocEntry
*tctx
= (lclTocEntry
*) te
->formatData
;
329 if (strcmp(te
->desc
, "BLOBS") == 0)
330 _LoadBlobs(AH
, ropt
);
332 _PrintFileData(AH
, tctx
->filename
, ropt
);
336 _getBlobTocEntry(ArchiveHandle
*AH
, Oid
*oid
, char fname
[K_STD_BUF_SIZE
])
338 lclContext
*ctx
= (lclContext
*) AH
->formatData
;
339 char blobTe
[K_STD_BUF_SIZE
];
341 if (fgets(blobTe
, sizeof(blobTe
), ctx
->blobToc
) != NULL
)
346 *oid
= atooid(blobTe
);
348 fpos
= strcspn(blobTe
, " ");
350 strlcpy(fname
, &blobTe
[fpos
+ 1], K_STD_BUF_SIZE
);
352 eos
= strlen(fname
) - 1;
354 if (fname
[eos
] == '\n')
365 _LoadBlobs(ArchiveHandle
*AH
, RestoreOptions
*ropt
)
368 lclContext
*ctx
= (lclContext
*) AH
->formatData
;
369 char fname
[K_STD_BUF_SIZE
];
371 StartRestoreBlobs(AH
);
373 ctx
->blobToc
= fopen("blobs.toc", PG_BINARY_R
);
375 if (ctx
->blobToc
== NULL
)
376 die_horribly(AH
, modulename
, "could not open large object TOC for input: %s\n", strerror(errno
));
378 _getBlobTocEntry(AH
, &oid
, fname
);
382 StartRestoreBlob(AH
, oid
);
383 _PrintFileData(AH
, fname
, ropt
);
384 EndRestoreBlob(AH
, oid
);
385 _getBlobTocEntry(AH
, &oid
, fname
);
388 if (fclose(ctx
->blobToc
) != 0)
389 die_horribly(AH
, modulename
, "could not close large object TOC file: %s\n", strerror(errno
));
396 _WriteByte(ArchiveHandle
*AH
, const int i
)
398 lclContext
*ctx
= (lclContext
*) AH
->formatData
;
400 if (fputc(i
, AH
->FH
) == EOF
)
401 die_horribly(AH
, modulename
, "could not write byte\n");
409 _ReadByte(ArchiveHandle
*AH
)
411 lclContext
*ctx
= (lclContext
*) AH
->formatData
;
416 die_horribly(AH
, modulename
, "unexpected end of file\n");
422 _WriteBuf(ArchiveHandle
*AH
, const void *buf
, size_t len
)
424 lclContext
*ctx
= (lclContext
*) AH
->formatData
;
427 res
= fwrite(buf
, 1, len
, AH
->FH
);
429 die_horribly(AH
, modulename
, "could not write to output file: %s\n", strerror(errno
));
436 _ReadBuf(ArchiveHandle
*AH
, void *buf
, size_t len
)
438 lclContext
*ctx
= (lclContext
*) AH
->formatData
;
441 res
= fread(buf
, 1, len
, AH
->FH
);
447 _CloseArchive(ArchiveHandle
*AH
)
449 if (AH
->mode
== archModeWrite
)
453 if (fclose(AH
->FH
) != 0)
454 die_horribly(AH
, modulename
, "could not close TOC file: %s\n", strerror(errno
));
468 * Called by the archiver when starting to save all BLOB DATA (not schema).
469 * This routine should save whatever format-specific information is needed
470 * to read the BLOBs back into memory.
472 * It is called just prior to the dumper's DataDumper routine.
474 * Optional, but strongly recommended.
477 _StartBlobs(ArchiveHandle
*AH
, TocEntry
*te
)
479 lclContext
*ctx
= (lclContext
*) AH
->formatData
;
480 char fname
[K_STD_BUF_SIZE
];
482 sprintf(fname
, "blobs.toc");
483 ctx
->blobToc
= fopen(fname
, PG_BINARY_W
);
485 if (ctx
->blobToc
== NULL
)
486 die_horribly(AH
, modulename
,
487 "could not open large object TOC for output: %s\n", strerror(errno
));
491 * Called by the archiver when the dumper calls StartBlob.
495 * Must save the passed OID for retrieval at restore-time.
498 _StartBlob(ArchiveHandle
*AH
, TocEntry
*te
, Oid oid
)
500 lclContext
*ctx
= (lclContext
*) AH
->formatData
;
501 lclTocEntry
*tctx
= (lclTocEntry
*) te
->formatData
;
507 die_horribly(AH
, modulename
, "invalid OID for large object (%u)\n", oid
);
509 if (AH
->compression
!= 0)
514 sprintf(fmode
, "wb%d", AH
->compression
);
515 sprintf(fname
, "blob_%u.dat%s", oid
, sfx
);
517 fprintf(ctx
->blobToc
, "%u %s\n", oid
, fname
);
520 tctx
->FH
= gzopen(fname
, fmode
);
522 tctx
->FH
= fopen(fname
, PG_BINARY_W
);
525 if (tctx
->FH
== NULL
)
526 die_horribly(AH
, modulename
, "could not open large object file \"%s\" for input: %s\n",
527 fname
, strerror(errno
));
531 * Called by the archiver when the dumper calls EndBlob.
536 _EndBlob(ArchiveHandle
*AH
, TocEntry
*te
, Oid oid
)
538 lclTocEntry
*tctx
= (lclTocEntry
*) te
->formatData
;
540 if (GZCLOSE(tctx
->FH
) != 0)
541 die_horribly(AH
, modulename
, "could not close large object file\n");
545 * Called by the archiver when finishing saving all BLOB DATA.
550 _EndBlobs(ArchiveHandle
*AH
, TocEntry
*te
)
552 lclContext
*ctx
= (lclContext
*) AH
->formatData
;
554 /* Write out a fake zero OID to mark end-of-blobs. */
555 /* WriteInt(AH, 0); */
557 if (fclose(ctx
->blobToc
) != 0)
558 die_horribly(AH
, modulename
, "could not close large object TOC file: %s\n", strerror(errno
));