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
;
91 AH
->PrintTocDataPtr
= _PrintTocData
;
92 AH
->ReadExtraTocPtr
= _ReadExtraToc
;
93 AH
->WriteExtraTocPtr
= _WriteExtraToc
;
94 AH
->PrintExtraTocPtr
= _PrintExtraToc
;
96 AH
->StartBlobsPtr
= _StartBlobs
;
97 AH
->StartBlobPtr
= _StartBlob
;
98 AH
->EndBlobPtr
= _EndBlob
;
99 AH
->EndBlobsPtr
= _EndBlobs
;
101 AH
->DeClonePtr
= NULL
;
104 * Set up some special context used in compressing data.
106 ctx
= (lclContext
*) calloc(1, sizeof(lclContext
));
107 AH
->formatData
= (void *) ctx
;
110 /* Initialize LO buffering */
111 AH
->lo_buf_size
= LOBBUFSIZE
;
112 AH
->lo_buf
= (void *) malloc(LOBBUFSIZE
);
113 if (AH
->lo_buf
== NULL
)
114 die_horribly(AH
, modulename
, "out of memory\n");
117 * Now open the TOC file
119 if (AH
->mode
== archModeWrite
)
122 write_msg(modulename
, "WARNING:\n"
123 " This format is for demonstration purposes; it is not intended for\n"
124 " normal use. Files will be written in the current working directory.\n");
126 if (AH
->fSpec
&& strcmp(AH
->fSpec
, "") != 0)
128 AH
->FH
= fopen(AH
->fSpec
, PG_BINARY_W
);
130 die_horribly(NULL
, modulename
, "could not open output file \"%s\": %s\n",
131 AH
->fSpec
, strerror(errno
));
137 die_horribly(NULL
, modulename
, "could not open output file: %s\n",
141 ctx
->hasSeek
= checkSeek(AH
->FH
);
143 if (AH
->compression
< 0 || AH
->compression
> 9)
144 AH
->compression
= Z_DEFAULT_COMPRESSION
;
151 if (AH
->fSpec
&& strcmp(AH
->fSpec
, "") != 0)
153 AH
->FH
= fopen(AH
->fSpec
, PG_BINARY_R
);
155 die_horribly(NULL
, modulename
, "could not open input file \"%s\": %s\n",
156 AH
->fSpec
, strerror(errno
));
162 die_horribly(NULL
, modulename
, "could not open input file: %s\n",
166 ctx
->hasSeek
= checkSeek(AH
->FH
);
170 /* Nothing else in the file... */
171 if (fclose(AH
->FH
) != 0)
172 die_horribly(AH
, modulename
, "could not close TOC file: %s\n", strerror(errno
));
177 * - Start a new TOC entry
178 * Setup the output file name.
181 _ArchiveEntry(ArchiveHandle
*AH
, TocEntry
*te
)
184 char fn
[K_STD_BUF_SIZE
];
186 ctx
= (lclTocEntry
*) calloc(1, sizeof(lclTocEntry
));
190 if (AH
->compression
== 0)
191 sprintf(fn
, "%d.dat", te
->dumpId
);
193 sprintf(fn
, "%d.dat.gz", te
->dumpId
);
195 sprintf(fn
, "%d.dat", te
->dumpId
);
197 ctx
->filename
= strdup(fn
);
201 ctx
->filename
= NULL
;
204 te
->formatData
= (void *) ctx
;
208 _WriteExtraToc(ArchiveHandle
*AH
, TocEntry
*te
)
210 lclTocEntry
*ctx
= (lclTocEntry
*) te
->formatData
;
213 WriteStr(AH
, ctx
->filename
);
219 _ReadExtraToc(ArchiveHandle
*AH
, TocEntry
*te
)
221 lclTocEntry
*ctx
= (lclTocEntry
*) te
->formatData
;
225 ctx
= (lclTocEntry
*) calloc(1, sizeof(lclTocEntry
));
226 te
->formatData
= (void *) ctx
;
229 ctx
->filename
= ReadStr(AH
);
230 if (strlen(ctx
->filename
) == 0)
233 ctx
->filename
= NULL
;
239 _PrintExtraToc(ArchiveHandle
*AH
, TocEntry
*te
)
241 lclTocEntry
*ctx
= (lclTocEntry
*) te
->formatData
;
243 if (AH
->public.verbose
)
244 ahprintf(AH
, "-- File: %s\n", ctx
->filename
);
248 _StartData(ArchiveHandle
*AH
, TocEntry
*te
)
250 lclTocEntry
*tctx
= (lclTocEntry
*) te
->formatData
;
253 sprintf(fmode
, "wb%d", AH
->compression
);
256 tctx
->FH
= gzopen(tctx
->filename
, fmode
);
258 tctx
->FH
= fopen(tctx
->filename
, PG_BINARY_W
);
261 if (tctx
->FH
== NULL
)
262 die_horribly(AH
, modulename
, "could not open output file \"%s\": %s\n",
263 tctx
->filename
, strerror(errno
));
267 _WriteData(ArchiveHandle
*AH
, const void *data
, size_t dLen
)
269 lclTocEntry
*tctx
= (lclTocEntry
*) AH
->currToc
->formatData
;
271 GZWRITE((void *) data
, 1, dLen
, tctx
->FH
);
277 _EndData(ArchiveHandle
*AH
, TocEntry
*te
)
279 lclTocEntry
*tctx
= (lclTocEntry
*) te
->formatData
;
282 if (GZCLOSE(tctx
->FH
) != 0)
283 die_horribly(AH
, modulename
, "could not close data file\n");
289 * Print data for a given file
292 _PrintFileData(ArchiveHandle
*AH
, char *filename
, RestoreOptions
*ropt
)
301 AH
->FH
= gzopen(filename
, "rb");
303 AH
->FH
= fopen(filename
, PG_BINARY_R
);
307 die_horribly(AH
, modulename
, "could not open input file \"%s\": %s\n",
308 filename
, strerror(errno
));
310 while ((cnt
= GZREAD(buf
, 1, 4095, AH
->FH
)) > 0)
313 ahwrite(buf
, 1, cnt
, AH
);
316 if (GZCLOSE(AH
->FH
) != 0)
317 die_horribly(AH
, modulename
, "could not close data file after reading\n");
322 * Print data for a given TOC entry
325 _PrintTocData(ArchiveHandle
*AH
, TocEntry
*te
, RestoreOptions
*ropt
)
327 lclTocEntry
*tctx
= (lclTocEntry
*) te
->formatData
;
332 if (strcmp(te
->desc
, "BLOBS") == 0)
333 _LoadBlobs(AH
, ropt
);
335 _PrintFileData(AH
, tctx
->filename
, ropt
);
339 _getBlobTocEntry(ArchiveHandle
*AH
, Oid
*oid
, char fname
[K_STD_BUF_SIZE
])
341 lclContext
*ctx
= (lclContext
*) AH
->formatData
;
342 char blobTe
[K_STD_BUF_SIZE
];
344 if (fgets(blobTe
, sizeof(blobTe
), ctx
->blobToc
) != NULL
)
349 *oid
= atooid(blobTe
);
351 fpos
= strcspn(blobTe
, " ");
353 strlcpy(fname
, &blobTe
[fpos
+ 1], K_STD_BUF_SIZE
);
355 eos
= strlen(fname
) - 1;
357 if (fname
[eos
] == '\n')
368 _LoadBlobs(ArchiveHandle
*AH
, RestoreOptions
*ropt
)
371 lclContext
*ctx
= (lclContext
*) AH
->formatData
;
372 char fname
[K_STD_BUF_SIZE
];
374 StartRestoreBlobs(AH
);
376 ctx
->blobToc
= fopen("blobs.toc", PG_BINARY_R
);
378 if (ctx
->blobToc
== NULL
)
379 die_horribly(AH
, modulename
, "could not open large object TOC for input: %s\n", strerror(errno
));
381 _getBlobTocEntry(AH
, &oid
, fname
);
385 StartRestoreBlob(AH
, oid
);
386 _PrintFileData(AH
, fname
, ropt
);
387 EndRestoreBlob(AH
, oid
);
388 _getBlobTocEntry(AH
, &oid
, fname
);
391 if (fclose(ctx
->blobToc
) != 0)
392 die_horribly(AH
, modulename
, "could not close large object TOC file: %s\n", strerror(errno
));
399 _WriteByte(ArchiveHandle
*AH
, const int i
)
401 lclContext
*ctx
= (lclContext
*) AH
->formatData
;
403 if (fputc(i
, AH
->FH
) == EOF
)
404 die_horribly(AH
, modulename
, "could not write byte\n");
412 _ReadByte(ArchiveHandle
*AH
)
414 lclContext
*ctx
= (lclContext
*) AH
->formatData
;
419 die_horribly(AH
, modulename
, "unexpected end of file\n");
425 _WriteBuf(ArchiveHandle
*AH
, const void *buf
, size_t len
)
427 lclContext
*ctx
= (lclContext
*) AH
->formatData
;
430 res
= fwrite(buf
, 1, len
, AH
->FH
);
432 die_horribly(AH
, modulename
, "could not write to output file: %s\n", strerror(errno
));
439 _ReadBuf(ArchiveHandle
*AH
, void *buf
, size_t len
)
441 lclContext
*ctx
= (lclContext
*) AH
->formatData
;
444 res
= fread(buf
, 1, len
, AH
->FH
);
450 _CloseArchive(ArchiveHandle
*AH
)
452 if (AH
->mode
== archModeWrite
)
456 if (fclose(AH
->FH
) != 0)
457 die_horribly(AH
, modulename
, "could not close TOC file: %s\n", strerror(errno
));
471 * Called by the archiver when starting to save all BLOB DATA (not schema).
472 * This routine should save whatever format-specific information is needed
473 * to read the BLOBs back into memory.
475 * It is called just prior to the dumper's DataDumper routine.
477 * Optional, but strongly recommended.
480 _StartBlobs(ArchiveHandle
*AH
, TocEntry
*te
)
482 lclContext
*ctx
= (lclContext
*) AH
->formatData
;
483 char fname
[K_STD_BUF_SIZE
];
485 sprintf(fname
, "blobs.toc");
486 ctx
->blobToc
= fopen(fname
, PG_BINARY_W
);
488 if (ctx
->blobToc
== NULL
)
489 die_horribly(AH
, modulename
,
490 "could not open large object TOC for output: %s\n", strerror(errno
));
494 * Called by the archiver when the dumper calls StartBlob.
498 * Must save the passed OID for retrieval at restore-time.
501 _StartBlob(ArchiveHandle
*AH
, TocEntry
*te
, Oid oid
)
503 lclContext
*ctx
= (lclContext
*) AH
->formatData
;
504 lclTocEntry
*tctx
= (lclTocEntry
*) te
->formatData
;
510 die_horribly(AH
, modulename
, "invalid OID for large object (%u)\n", oid
);
512 if (AH
->compression
!= 0)
517 sprintf(fmode
, "wb%d", AH
->compression
);
518 sprintf(fname
, "blob_%u.dat%s", oid
, sfx
);
520 fprintf(ctx
->blobToc
, "%u %s\n", oid
, fname
);
523 tctx
->FH
= gzopen(fname
, fmode
);
525 tctx
->FH
= fopen(fname
, PG_BINARY_W
);
528 if (tctx
->FH
== NULL
)
529 die_horribly(AH
, modulename
, "could not open large object file \"%s\" for input: %s\n",
530 fname
, strerror(errno
));
534 * Called by the archiver when the dumper calls EndBlob.
539 _EndBlob(ArchiveHandle
*AH
, TocEntry
*te
, Oid oid
)
541 lclTocEntry
*tctx
= (lclTocEntry
*) te
->formatData
;
543 if (GZCLOSE(tctx
->FH
) != 0)
544 die_horribly(AH
, modulename
, "could not close large object file\n");
548 * Called by the archiver when finishing saving all BLOB DATA.
553 _EndBlobs(ArchiveHandle
*AH
, TocEntry
*te
)
555 lclContext
*ctx
= (lclContext
*) AH
->formatData
;
557 /* Write out a fake zero OID to mark end-of-blobs. */
558 /* WriteInt(AH, 0); */
560 if (fclose(ctx
->blobToc
) != 0)
561 die_horribly(AH
, modulename
, "could not close large object TOC file: %s\n", strerror(errno
));