Force a checkpoint in CREATE DATABASE before starting to copy the files,
[PostgreSQL.git] / src / bin / pg_dump / pg_backup_files.c
blob34b07e7dbab588d71adf128840b9309539075715
1 /*-------------------------------------------------------------------------
3 * pg_backup_files.c
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.
22 * IDENTIFICATION
23 * $PostgreSQL$
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
51 typedef struct
53 int hasSeek;
54 pgoff_t filePos;
55 FILE *blobToc;
56 } lclContext;
58 typedef struct
60 #ifdef HAVE_LIBZ
61 gzFile *FH;
62 #else
63 FILE *FH;
64 #endif
65 char *filename;
66 } lclTocEntry;
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);
73 * Initializer
75 void
76 InitArchiveFmt_Files(ArchiveHandle *AH)
78 lclContext *ctx;
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;
105 ctx->filePos = 0;
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);
126 if (AH->FH == NULL)
127 die_horribly(NULL, modulename, "could not open output file \"%s\": %s\n",
128 AH->fSpec, strerror(errno));
130 else
132 AH->FH = stdout;
133 if (AH->FH == NULL)
134 die_horribly(NULL, modulename, "could not open output file: %s\n",
135 strerror(errno));
138 ctx->hasSeek = checkSeek(AH->FH);
140 if (AH->compression < 0 || AH->compression > 9)
141 AH->compression = Z_DEFAULT_COMPRESSION;
145 else
146 { /* Read Mode */
148 if (AH->fSpec && strcmp(AH->fSpec, "") != 0)
150 AH->FH = fopen(AH->fSpec, PG_BINARY_R);
151 if (AH->FH == NULL)
152 die_horribly(NULL, modulename, "could not open input file \"%s\": %s\n",
153 AH->fSpec, strerror(errno));
155 else
157 AH->FH = stdin;
158 if (AH->FH == NULL)
159 die_horribly(NULL, modulename, "could not open input file: %s\n",
160 strerror(errno));
163 ctx->hasSeek = checkSeek(AH->FH);
165 ReadHead(AH);
166 ReadToc(AH);
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.
177 static void
178 _ArchiveEntry(ArchiveHandle *AH, TocEntry *te)
180 lclTocEntry *ctx;
181 char fn[K_STD_BUF_SIZE];
183 ctx = (lclTocEntry *) calloc(1, sizeof(lclTocEntry));
184 if (te->dataDumper)
186 #ifdef HAVE_LIBZ
187 if (AH->compression == 0)
188 sprintf(fn, "%d.dat", te->dumpId);
189 else
190 sprintf(fn, "%d.dat.gz", te->dumpId);
191 #else
192 sprintf(fn, "%d.dat", te->dumpId);
193 #endif
194 ctx->filename = strdup(fn);
196 else
198 ctx->filename = NULL;
199 ctx->FH = NULL;
201 te->formatData = (void *) ctx;
204 static void
205 _WriteExtraToc(ArchiveHandle *AH, TocEntry *te)
207 lclTocEntry *ctx = (lclTocEntry *) te->formatData;
209 if (ctx->filename)
210 WriteStr(AH, ctx->filename);
211 else
212 WriteStr(AH, "");
215 static void
216 _ReadExtraToc(ArchiveHandle *AH, TocEntry *te)
218 lclTocEntry *ctx = (lclTocEntry *) te->formatData;
220 if (ctx == NULL)
222 ctx = (lclTocEntry *) calloc(1, sizeof(lclTocEntry));
223 te->formatData = (void *) ctx;
226 ctx->filename = ReadStr(AH);
227 if (strlen(ctx->filename) == 0)
229 free(ctx->filename);
230 ctx->filename = NULL;
232 ctx->FH = NULL;
235 static void
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);
244 static void
245 _StartData(ArchiveHandle *AH, TocEntry *te)
247 lclTocEntry *tctx = (lclTocEntry *) te->formatData;
248 char fmode[10];
250 sprintf(fmode, "wb%d", AH->compression);
252 #ifdef HAVE_LIBZ
253 tctx->FH = gzopen(tctx->filename, fmode);
254 #else
255 tctx->FH = fopen(tctx->filename, PG_BINARY_W);
256 #endif
258 if (tctx->FH == NULL)
259 die_horribly(AH, modulename, "could not open output file \"%s\": %s\n",
260 tctx->filename, strerror(errno));
263 static size_t
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);
270 return dLen;
273 static void
274 _EndData(ArchiveHandle *AH, TocEntry *te)
276 lclTocEntry *tctx = (lclTocEntry *) te->formatData;
278 /* Close the file */
279 if (GZCLOSE(tctx->FH) != 0)
280 die_horribly(AH, modulename, "could not close data file\n");
282 tctx->FH = NULL;
286 * Print data for a given file
288 static void
289 _PrintFileData(ArchiveHandle *AH, char *filename, RestoreOptions *ropt)
291 char buf[4096];
292 size_t cnt;
294 if (!filename)
295 return;
297 #ifdef HAVE_LIBZ
298 AH->FH = gzopen(filename, "rb");
299 #else
300 AH->FH = fopen(filename, PG_BINARY_R);
301 #endif
303 if (AH->FH == NULL)
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)
309 buf[cnt] = '\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
321 static void
322 _PrintTocData(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt)
324 lclTocEntry *tctx = (lclTocEntry *) te->formatData;
326 if (!tctx->filename)
327 return;
329 if (strcmp(te->desc, "BLOBS") == 0)
330 _LoadBlobs(AH, ropt);
331 else
332 _PrintFileData(AH, tctx->filename, ropt);
335 static void
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)
343 size_t fpos;
344 size_t eos;
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')
355 fname[eos] = '\0';
357 else
359 *oid = 0;
360 fname[0] = '\0';
364 static void
365 _LoadBlobs(ArchiveHandle *AH, RestoreOptions *ropt)
367 Oid oid;
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);
380 while (oid != 0)
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));
391 EndRestoreBlobs(AH);
395 static int
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");
403 ctx->filePos += 1;
405 return 1;
408 static int
409 _ReadByte(ArchiveHandle *AH)
411 lclContext *ctx = (lclContext *) AH->formatData;
412 int res;
414 res = getc(AH->FH);
415 if (res == EOF)
416 die_horribly(AH, modulename, "unexpected end of file\n");
417 ctx->filePos += 1;
418 return res;
421 static size_t
422 _WriteBuf(ArchiveHandle *AH, const void *buf, size_t len)
424 lclContext *ctx = (lclContext *) AH->formatData;
425 size_t res;
427 res = fwrite(buf, 1, len, AH->FH);
428 if (res != len)
429 die_horribly(AH, modulename, "could not write to output file: %s\n", strerror(errno));
431 ctx->filePos += res;
432 return res;
435 static size_t
436 _ReadBuf(ArchiveHandle *AH, void *buf, size_t len)
438 lclContext *ctx = (lclContext *) AH->formatData;
439 size_t res;
441 res = fread(buf, 1, len, AH->FH);
442 ctx->filePos += res;
443 return res;
446 static void
447 _CloseArchive(ArchiveHandle *AH)
449 if (AH->mode == archModeWrite)
451 WriteHead(AH);
452 WriteToc(AH);
453 if (fclose(AH->FH) != 0)
454 die_horribly(AH, modulename, "could not close TOC file: %s\n", strerror(errno));
455 WriteDataChunks(AH);
458 AH->FH = NULL;
464 * BLOB support
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.
476 static void
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.
493 * Mandatory.
495 * Must save the passed OID for retrieval at restore-time.
497 static void
498 _StartBlob(ArchiveHandle *AH, TocEntry *te, Oid oid)
500 lclContext *ctx = (lclContext *) AH->formatData;
501 lclTocEntry *tctx = (lclTocEntry *) te->formatData;
502 char fmode[10];
503 char fname[255];
504 char *sfx;
506 if (oid == 0)
507 die_horribly(AH, modulename, "invalid OID for large object (%u)\n", oid);
509 if (AH->compression != 0)
510 sfx = ".gz";
511 else
512 sfx = "";
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);
519 #ifdef HAVE_LIBZ
520 tctx->FH = gzopen(fname, fmode);
521 #else
522 tctx->FH = fopen(fname, PG_BINARY_W);
523 #endif
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.
533 * Optional.
535 static void
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.
547 * Optional.
549 static void
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));