Fix xslt_process() to ensure that it inserts a NULL terminator after the
[PostgreSQL.git] / src / bin / pg_dump / pg_backup_files.c
blob8faa5e8db9affe7dd361fee24ca3991b85e0514d
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->ReopenPtr = NULL;
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;
100 AH->ClonePtr = NULL;
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;
108 ctx->filePos = 0;
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);
129 if (AH->FH == NULL)
130 die_horribly(NULL, modulename, "could not open output file \"%s\": %s\n",
131 AH->fSpec, strerror(errno));
133 else
135 AH->FH = stdout;
136 if (AH->FH == NULL)
137 die_horribly(NULL, modulename, "could not open output file: %s\n",
138 strerror(errno));
141 ctx->hasSeek = checkSeek(AH->FH);
143 if (AH->compression < 0 || AH->compression > 9)
144 AH->compression = Z_DEFAULT_COMPRESSION;
148 else
149 { /* Read Mode */
151 if (AH->fSpec && strcmp(AH->fSpec, "") != 0)
153 AH->FH = fopen(AH->fSpec, PG_BINARY_R);
154 if (AH->FH == NULL)
155 die_horribly(NULL, modulename, "could not open input file \"%s\": %s\n",
156 AH->fSpec, strerror(errno));
158 else
160 AH->FH = stdin;
161 if (AH->FH == NULL)
162 die_horribly(NULL, modulename, "could not open input file: %s\n",
163 strerror(errno));
166 ctx->hasSeek = checkSeek(AH->FH);
168 ReadHead(AH);
169 ReadToc(AH);
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.
180 static void
181 _ArchiveEntry(ArchiveHandle *AH, TocEntry *te)
183 lclTocEntry *ctx;
184 char fn[K_STD_BUF_SIZE];
186 ctx = (lclTocEntry *) calloc(1, sizeof(lclTocEntry));
187 if (te->dataDumper)
189 #ifdef HAVE_LIBZ
190 if (AH->compression == 0)
191 sprintf(fn, "%d.dat", te->dumpId);
192 else
193 sprintf(fn, "%d.dat.gz", te->dumpId);
194 #else
195 sprintf(fn, "%d.dat", te->dumpId);
196 #endif
197 ctx->filename = strdup(fn);
199 else
201 ctx->filename = NULL;
202 ctx->FH = NULL;
204 te->formatData = (void *) ctx;
207 static void
208 _WriteExtraToc(ArchiveHandle *AH, TocEntry *te)
210 lclTocEntry *ctx = (lclTocEntry *) te->formatData;
212 if (ctx->filename)
213 WriteStr(AH, ctx->filename);
214 else
215 WriteStr(AH, "");
218 static void
219 _ReadExtraToc(ArchiveHandle *AH, TocEntry *te)
221 lclTocEntry *ctx = (lclTocEntry *) te->formatData;
223 if (ctx == NULL)
225 ctx = (lclTocEntry *) calloc(1, sizeof(lclTocEntry));
226 te->formatData = (void *) ctx;
229 ctx->filename = ReadStr(AH);
230 if (strlen(ctx->filename) == 0)
232 free(ctx->filename);
233 ctx->filename = NULL;
235 ctx->FH = NULL;
238 static void
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);
247 static void
248 _StartData(ArchiveHandle *AH, TocEntry *te)
250 lclTocEntry *tctx = (lclTocEntry *) te->formatData;
251 char fmode[10];
253 sprintf(fmode, "wb%d", AH->compression);
255 #ifdef HAVE_LIBZ
256 tctx->FH = gzopen(tctx->filename, fmode);
257 #else
258 tctx->FH = fopen(tctx->filename, PG_BINARY_W);
259 #endif
261 if (tctx->FH == NULL)
262 die_horribly(AH, modulename, "could not open output file \"%s\": %s\n",
263 tctx->filename, strerror(errno));
266 static size_t
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);
273 return dLen;
276 static void
277 _EndData(ArchiveHandle *AH, TocEntry *te)
279 lclTocEntry *tctx = (lclTocEntry *) te->formatData;
281 /* Close the file */
282 if (GZCLOSE(tctx->FH) != 0)
283 die_horribly(AH, modulename, "could not close data file\n");
285 tctx->FH = NULL;
289 * Print data for a given file
291 static void
292 _PrintFileData(ArchiveHandle *AH, char *filename, RestoreOptions *ropt)
294 char buf[4096];
295 size_t cnt;
297 if (!filename)
298 return;
300 #ifdef HAVE_LIBZ
301 AH->FH = gzopen(filename, "rb");
302 #else
303 AH->FH = fopen(filename, PG_BINARY_R);
304 #endif
306 if (AH->FH == NULL)
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)
312 buf[cnt] = '\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
324 static void
325 _PrintTocData(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt)
327 lclTocEntry *tctx = (lclTocEntry *) te->formatData;
329 if (!tctx->filename)
330 return;
332 if (strcmp(te->desc, "BLOBS") == 0)
333 _LoadBlobs(AH, ropt);
334 else
335 _PrintFileData(AH, tctx->filename, ropt);
338 static void
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)
346 size_t fpos;
347 size_t eos;
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')
358 fname[eos] = '\0';
360 else
362 *oid = 0;
363 fname[0] = '\0';
367 static void
368 _LoadBlobs(ArchiveHandle *AH, RestoreOptions *ropt)
370 Oid oid;
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);
383 while (oid != 0)
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));
394 EndRestoreBlobs(AH);
398 static int
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");
406 ctx->filePos += 1;
408 return 1;
411 static int
412 _ReadByte(ArchiveHandle *AH)
414 lclContext *ctx = (lclContext *) AH->formatData;
415 int res;
417 res = getc(AH->FH);
418 if (res == EOF)
419 die_horribly(AH, modulename, "unexpected end of file\n");
420 ctx->filePos += 1;
421 return res;
424 static size_t
425 _WriteBuf(ArchiveHandle *AH, const void *buf, size_t len)
427 lclContext *ctx = (lclContext *) AH->formatData;
428 size_t res;
430 res = fwrite(buf, 1, len, AH->FH);
431 if (res != len)
432 die_horribly(AH, modulename, "could not write to output file: %s\n", strerror(errno));
434 ctx->filePos += res;
435 return res;
438 static size_t
439 _ReadBuf(ArchiveHandle *AH, void *buf, size_t len)
441 lclContext *ctx = (lclContext *) AH->formatData;
442 size_t res;
444 res = fread(buf, 1, len, AH->FH);
445 ctx->filePos += res;
446 return res;
449 static void
450 _CloseArchive(ArchiveHandle *AH)
452 if (AH->mode == archModeWrite)
454 WriteHead(AH);
455 WriteToc(AH);
456 if (fclose(AH->FH) != 0)
457 die_horribly(AH, modulename, "could not close TOC file: %s\n", strerror(errno));
458 WriteDataChunks(AH);
461 AH->FH = NULL;
467 * BLOB support
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.
479 static void
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.
496 * Mandatory.
498 * Must save the passed OID for retrieval at restore-time.
500 static void
501 _StartBlob(ArchiveHandle *AH, TocEntry *te, Oid oid)
503 lclContext *ctx = (lclContext *) AH->formatData;
504 lclTocEntry *tctx = (lclTocEntry *) te->formatData;
505 char fmode[10];
506 char fname[255];
507 char *sfx;
509 if (oid == 0)
510 die_horribly(AH, modulename, "invalid OID for large object (%u)\n", oid);
512 if (AH->compression != 0)
513 sfx = ".gz";
514 else
515 sfx = "";
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);
522 #ifdef HAVE_LIBZ
523 tctx->FH = gzopen(fname, fmode);
524 #else
525 tctx->FH = fopen(fname, PG_BINARY_W);
526 #endif
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.
536 * Optional.
538 static void
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.
550 * Optional.
552 static void
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));