pg_backup_files.c 12.0 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14
/*-------------------------------------------------------------------------
 *
 * pg_backup_files.c
 *
 *	This file is copied from the 'custom' format file, but dumps data into
 *	separate files, and the TOC into the 'main' file.
 *
 *	IT IS FOR DEMONSTRATION PURPOSES ONLY.
 *
 *	(and could probably be used as a basis for writing a tar file)
 *
 *	See the headers to pg_restore for more details.
 *
 * Copyright (c) 2000, Philip Warner
B
Bruce Momjian 已提交
15 16
 *		Rights are granted to use this software in any way so long
 *		as this notice is not removed.
17 18 19 20 21 22
 *
 *	The author is not responsible for loss or damages that may
 *	result from it's use.
 *
 *
 * IDENTIFICATION
23
 *		$PostgreSQL: pgsql/src/bin/pg_dump/pg_backup_files.c,v 1.32 2007/03/18 16:50:44 neilc Exp $
24
 *
25 26 27 28 29
 *-------------------------------------------------------------------------
 */

#include "pg_backup_archiver.h"

B
Bruce Momjian 已提交
30 31
static void _ArchiveEntry(ArchiveHandle *AH, TocEntry *te);
static void _StartData(ArchiveHandle *AH, TocEntry *te);
B
Bruce Momjian 已提交
32
static size_t _WriteData(ArchiveHandle *AH, const void *data, size_t dLen);
B
Bruce Momjian 已提交
33 34 35
static void _EndData(ArchiveHandle *AH, TocEntry *te);
static int	_WriteByte(ArchiveHandle *AH, const int i);
static int	_ReadByte(ArchiveHandle *);
B
Bruce Momjian 已提交
36 37
static size_t _WriteBuf(ArchiveHandle *AH, const void *buf, size_t len);
static size_t _ReadBuf(ArchiveHandle *AH, void *buf, size_t len);
B
Bruce Momjian 已提交
38 39 40 41 42 43 44
static void _CloseArchive(ArchiveHandle *AH);
static void _PrintTocData(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt);
static void _WriteExtraToc(ArchiveHandle *AH, TocEntry *te);
static void _ReadExtraToc(ArchiveHandle *AH, TocEntry *te);
static void _PrintExtraToc(ArchiveHandle *AH, TocEntry *te);

static void _StartBlobs(ArchiveHandle *AH, TocEntry *te);
45 46
static void _StartBlob(ArchiveHandle *AH, TocEntry *te, Oid oid);
static void _EndBlob(ArchiveHandle *AH, TocEntry *te, Oid oid);
B
Bruce Momjian 已提交
47
static void _EndBlobs(ArchiveHandle *AH, TocEntry *te);
48 49 50

#define K_STD_BUF_SIZE 1024

B
Bruce Momjian 已提交
51 52 53
typedef struct
{
	int			hasSeek;
54
	pgoff_t		filePos;
B
Bruce Momjian 已提交
55
	FILE	   *blobToc;
56 57
} lclContext;

B
Bruce Momjian 已提交
58 59
typedef struct
{
60
#ifdef HAVE_LIBZ
B
Bruce Momjian 已提交
61
	gzFile	   *FH;
62
#else
B
Bruce Momjian 已提交
63
	FILE	   *FH;
64
#endif
B
Bruce Momjian 已提交
65
	char	   *filename;
66 67
} lclTocEntry;

68
static const char *modulename = gettext_noop("file archiver");
B
Bruce Momjian 已提交
69
static void _LoadBlobs(ArchiveHandle *AH, RestoreOptions *ropt);
70
static void _getBlobTocEntry(ArchiveHandle *AH, Oid *oid, char *fname);
71 72

/*
B
Bruce Momjian 已提交
73
 *	Initializer
74
 */
B
Bruce Momjian 已提交
75 76
void
InitArchiveFmt_Files(ArchiveHandle *AH)
77
{
B
Bruce Momjian 已提交
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
	lclContext *ctx;

	/* Assuming static functions, this can be copied for each format. */
	AH->ArchiveEntryPtr = _ArchiveEntry;
	AH->StartDataPtr = _StartData;
	AH->WriteDataPtr = _WriteData;
	AH->EndDataPtr = _EndData;
	AH->WriteBytePtr = _WriteByte;
	AH->ReadBytePtr = _ReadByte;
	AH->WriteBufPtr = _WriteBuf;
	AH->ReadBufPtr = _ReadBuf;
	AH->ClosePtr = _CloseArchive;
	AH->PrintTocDataPtr = _PrintTocData;
	AH->ReadExtraTocPtr = _ReadExtraToc;
	AH->WriteExtraTocPtr = _WriteExtraToc;
	AH->PrintExtraTocPtr = _PrintExtraToc;

	AH->StartBlobsPtr = _StartBlobs;
	AH->StartBlobPtr = _StartBlob;
	AH->EndBlobPtr = _EndBlob;
	AH->EndBlobsPtr = _EndBlobs;

	/*
	 * Set up some special context used in compressing data.
	 */
103
	ctx = (lclContext *) calloc(1, sizeof(lclContext));
B
Bruce Momjian 已提交
104 105 106
	AH->formatData = (void *) ctx;
	ctx->filePos = 0;

107 108
	/* Initialize LO buffering */
	AH->lo_buf_size = LOBBUFSIZE;
B
Bruce Momjian 已提交
109
	AH->lo_buf = (void *) malloc(LOBBUFSIZE);
P
Peter Eisentraut 已提交
110 111
	if (AH->lo_buf == NULL)
		die_horribly(AH, modulename, "out of memory\n");
112

B
Bruce Momjian 已提交
113 114 115 116 117
	/*
	 * Now open the TOC file
	 */
	if (AH->mode == archModeWrite)
	{
118

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");
122

B
Bruce Momjian 已提交
123
		if (AH->fSpec && strcmp(AH->fSpec, "") != 0)
124
			AH->FH = fopen(AH->fSpec, PG_BINARY_W);
B
Bruce Momjian 已提交
125
		else
126
			AH->FH = stdout;
127 128

		if (AH->FH == NULL)
129
			die_horribly(NULL, modulename, "could not open output file: %s\n", strerror(errno));
130

131
		ctx->hasSeek = checkSeek(AH->FH);
132

B
Bruce Momjian 已提交
133
		if (AH->compression < 0 || AH->compression > 9)
134 135 136
			AH->compression = Z_DEFAULT_COMPRESSION;


B
Bruce Momjian 已提交
137 138 139
	}
	else
	{							/* Read Mode */
140

B
Bruce Momjian 已提交
141
		if (AH->fSpec && strcmp(AH->fSpec, "") != 0)
142
			AH->FH = fopen(AH->fSpec, PG_BINARY_R);
B
Bruce Momjian 已提交
143
		else
144
			AH->FH = stdin;
145 146

		if (AH->FH == NULL)
147
			die_horribly(NULL, modulename, "could not open input file: %s\n", strerror(errno));
148

149
		ctx->hasSeek = checkSeek(AH->FH);
150 151 152

		ReadHead(AH);
		ReadToc(AH);
153 154
		/* Nothing else in the file... */
		if (fclose(AH->FH) != 0)
155
			die_horribly(AH, modulename, "could not close TOC file: %s\n", strerror(errno));
B
Bruce Momjian 已提交
156
	}
157 158 159 160
}

/*
 * - Start a new TOC entry
B
Bruce Momjian 已提交
161
 *	 Setup the output file name.
162
 */
B
Bruce Momjian 已提交
163 164
static void
_ArchiveEntry(ArchiveHandle *AH, TocEntry *te)
165
{
B
Bruce Momjian 已提交
166 167
	lclTocEntry *ctx;
	char		fn[K_STD_BUF_SIZE];
168

169
	ctx = (lclTocEntry *) calloc(1, sizeof(lclTocEntry));
B
Bruce Momjian 已提交
170 171
	if (te->dataDumper)
	{
172
#ifdef HAVE_LIBZ
B
Bruce Momjian 已提交
173
		if (AH->compression == 0)
174
			sprintf(fn, "%d.dat", te->dumpId);
B
Bruce Momjian 已提交
175
		else
176
			sprintf(fn, "%d.dat.gz", te->dumpId);
177
#else
178
		sprintf(fn, "%d.dat", te->dumpId);
179 180
#endif
		ctx->filename = strdup(fn);
B
Bruce Momjian 已提交
181 182 183
	}
	else
	{
184 185
		ctx->filename = NULL;
		ctx->FH = NULL;
B
Bruce Momjian 已提交
186 187
	}
	te->formatData = (void *) ctx;
188 189
}

B
Bruce Momjian 已提交
190 191
static void
_WriteExtraToc(ArchiveHandle *AH, TocEntry *te)
192
{
B
Bruce Momjian 已提交
193
	lclTocEntry *ctx = (lclTocEntry *) te->formatData;
194

B
Bruce Momjian 已提交
195
	if (ctx->filename)
196
		WriteStr(AH, ctx->filename);
B
Bruce Momjian 已提交
197
	else
198 199 200
		WriteStr(AH, "");
}

B
Bruce Momjian 已提交
201 202
static void
_ReadExtraToc(ArchiveHandle *AH, TocEntry *te)
203
{
B
Bruce Momjian 已提交
204
	lclTocEntry *ctx = (lclTocEntry *) te->formatData;
205

B
Bruce Momjian 已提交
206 207
	if (ctx == NULL)
	{
208
		ctx = (lclTocEntry *) calloc(1, sizeof(lclTocEntry));
B
Bruce Momjian 已提交
209 210
		te->formatData = (void *) ctx;
	}
211

B
Bruce Momjian 已提交
212 213 214
	ctx->filename = ReadStr(AH);
	if (strlen(ctx->filename) == 0)
	{
215 216
		free(ctx->filename);
		ctx->filename = NULL;
B
Bruce Momjian 已提交
217 218
	}
	ctx->FH = NULL;
219 220
}

B
Bruce Momjian 已提交
221 222
static void
_PrintExtraToc(ArchiveHandle *AH, TocEntry *te)
223
{
B
Bruce Momjian 已提交
224
	lclTocEntry *ctx = (lclTocEntry *) te->formatData;
225

226 227
	if (AH->public.verbose)
		ahprintf(AH, "-- File: %s\n", ctx->filename);
228 229
}

B
Bruce Momjian 已提交
230 231
static void
_StartData(ArchiveHandle *AH, TocEntry *te)
232
{
B
Bruce Momjian 已提交
233 234
	lclTocEntry *tctx = (lclTocEntry *) te->formatData;
	char		fmode[10];
235

B
Bruce Momjian 已提交
236
	sprintf(fmode, "wb%d", AH->compression);
237 238

#ifdef HAVE_LIBZ
B
Bruce Momjian 已提交
239
	tctx->FH = gzopen(tctx->filename, fmode);
240
#else
B
Bruce Momjian 已提交
241
	tctx->FH = fopen(tctx->filename, PG_BINARY_W);
242
#endif
243 244

	if (tctx->FH == NULL)
245
		die_horribly(AH, modulename, "could not open output file: %s\n", strerror(errno));
246 247
}

P
Peter Eisentraut 已提交
248 249
static size_t
_WriteData(ArchiveHandle *AH, const void *data, size_t dLen)
250
{
B
Bruce Momjian 已提交
251
	lclTocEntry *tctx = (lclTocEntry *) AH->currToc->formatData;
252

B
Bruce Momjian 已提交
253
	GZWRITE((void *) data, 1, dLen, tctx->FH);
254

B
Bruce Momjian 已提交
255
	return dLen;
256 257
}

B
Bruce Momjian 已提交
258 259
static void
_EndData(ArchiveHandle *AH, TocEntry *te)
260
{
B
Bruce Momjian 已提交
261
	lclTocEntry *tctx = (lclTocEntry *) te->formatData;
262

B
Bruce Momjian 已提交
263
	/* Close the file */
264
	if (GZCLOSE(tctx->FH) != 0)
265
		die_horribly(AH, modulename, "could not close data file\n");
266

B
Bruce Momjian 已提交
267
	tctx->FH = NULL;
268 269
}

B
Bruce Momjian 已提交
270 271
/*
 * Print data for a given file
272
 */
B
Bruce Momjian 已提交
273 274
static void
_PrintFileData(ArchiveHandle *AH, char *filename, RestoreOptions *ropt)
275
{
B
Bruce Momjian 已提交
276
	char		buf[4096];
P
Peter Eisentraut 已提交
277
	size_t		cnt;
278

B
Bruce Momjian 已提交
279
	if (!filename)
280 281 282
		return;

#ifdef HAVE_LIBZ
B
Bruce Momjian 已提交
283
	AH->FH = gzopen(filename, "rb");
284
#else
B
Bruce Momjian 已提交
285
	AH->FH = fopen(filename, PG_BINARY_R);
286 287
#endif

288
	if (AH->FH == NULL)
289
		die_horribly(AH, modulename, "could not open input file: %s\n", strerror(errno));
290

B
Bruce Momjian 已提交
291 292
	while ((cnt = GZREAD(buf, 1, 4095, AH->FH)) > 0)
	{
293 294
		buf[cnt] = '\0';
		ahwrite(buf, 1, cnt, AH);
B
Bruce Momjian 已提交
295
	}
296

297
	if (GZCLOSE(AH->FH) != 0)
298
		die_horribly(AH, modulename, "could not close data file after reading\n");
299 300 301 302 303 304
}


/*
 * Print data for a given TOC entry
*/
B
Bruce Momjian 已提交
305 306
static void
_PrintTocData(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt)
307
{
B
Bruce Momjian 已提交
308
	lclTocEntry *tctx = (lclTocEntry *) te->formatData;
309

B
Bruce Momjian 已提交
310
	if (!tctx->filename)
311 312 313 314 315 316 317 318
		return;

	if (strcmp(te->desc, "BLOBS") == 0)
		_LoadBlobs(AH, ropt);
	else
		_PrintFileData(AH, tctx->filename, ropt);
}

B
Bruce Momjian 已提交
319
static void
320
_getBlobTocEntry(ArchiveHandle *AH, Oid *oid, char fname[K_STD_BUF_SIZE])
321
{
B
Bruce Momjian 已提交
322 323
	lclContext *ctx = (lclContext *) AH->formatData;
	char		blobTe[K_STD_BUF_SIZE];
324

325
	if (fgets(blobTe, sizeof(blobTe), ctx->blobToc) != NULL)
326
	{
327 328 329
		size_t		fpos;
		size_t		eos;

330
		*oid = atooid(blobTe);
331 332 333

		fpos = strcspn(blobTe, " ");

334
		strlcpy(fname, &blobTe[fpos + 1], K_STD_BUF_SIZE);
335

B
Bruce Momjian 已提交
336
		eos = strlen(fname) - 1;
337 338 339

		if (fname[eos] == '\n')
			fname[eos] = '\0';
B
Bruce Momjian 已提交
340 341 342
	}
	else
	{
343 344 345 346 347
		*oid = 0;
		fname[0] = '\0';
	}
}

B
Bruce Momjian 已提交
348 349
static void
_LoadBlobs(ArchiveHandle *AH, RestoreOptions *ropt)
350
{
351
	Oid			oid;
B
Bruce Momjian 已提交
352 353
	lclContext *ctx = (lclContext *) AH->formatData;
	char		fname[K_STD_BUF_SIZE];
354

355 356
	StartRestoreBlobs(AH);

357 358
	ctx->blobToc = fopen("blobs.toc", PG_BINARY_R);

B
Bruce Momjian 已提交
359
	if (ctx->blobToc == NULL)
360
		die_horribly(AH, modulename, "could not open large object TOC for input: %s\n", strerror(errno));
361

362 363
	_getBlobTocEntry(AH, &oid, fname);

B
Bruce Momjian 已提交
364 365
	while (oid != 0)
	{
366 367 368 369
		StartRestoreBlob(AH, oid);
		_PrintFileData(AH, fname, ropt);
		EndRestoreBlob(AH, oid);
		_getBlobTocEntry(AH, &oid, fname);
B
Bruce Momjian 已提交
370
	}
371

372
	if (fclose(ctx->blobToc) != 0)
373
		die_horribly(AH, modulename, "could not close large object TOC file: %s\n", strerror(errno));
374 375

	EndRestoreBlobs(AH);
376 377 378
}


B
Bruce Momjian 已提交
379 380
static int
_WriteByte(ArchiveHandle *AH, const int i)
381
{
B
Bruce Momjian 已提交
382
	lclContext *ctx = (lclContext *) AH->formatData;
383

B
Bruce Momjian 已提交
384
	if (fputc(i, AH->FH) == EOF)
385
		die_horribly(AH, modulename, "could not write byte\n");
386 387 388

	ctx->filePos += 1;

B
Bruce Momjian 已提交
389
	return 1;
390 391
}

B
Bruce Momjian 已提交
392 393
static int
_ReadByte(ArchiveHandle *AH)
394
{
B
Bruce Momjian 已提交
395 396
	lclContext *ctx = (lclContext *) AH->formatData;
	int			res;
397

B
Bruce Momjian 已提交
398 399
	res = fgetc(AH->FH);
	if (res != EOF)
400
		ctx->filePos += 1;
B
Bruce Momjian 已提交
401
	return res;
402 403
}

P
Peter Eisentraut 已提交
404 405
static size_t
_WriteBuf(ArchiveHandle *AH, const void *buf, size_t len)
406
{
B
Bruce Momjian 已提交
407
	lclContext *ctx = (lclContext *) AH->formatData;
P
Peter Eisentraut 已提交
408
	size_t		res;
B
Bruce Momjian 已提交
409 410

	res = fwrite(buf, 1, len, AH->FH);
411
	if (res != len)
412
		die_horribly(AH, modulename, "could not write to output file: %s\n", strerror(errno));
413

B
Bruce Momjian 已提交
414 415
	ctx->filePos += res;
	return res;
416 417
}

P
Peter Eisentraut 已提交
418 419
static size_t
_ReadBuf(ArchiveHandle *AH, void *buf, size_t len)
420
{
B
Bruce Momjian 已提交
421
	lclContext *ctx = (lclContext *) AH->formatData;
P
Peter Eisentraut 已提交
422
	size_t		res;
423

B
Bruce Momjian 已提交
424 425 426
	res = fread(buf, 1, len, AH->FH);
	ctx->filePos += res;
	return res;
427 428
}

B
Bruce Momjian 已提交
429 430
static void
_CloseArchive(ArchiveHandle *AH)
431
{
B
Bruce Momjian 已提交
432 433
	if (AH->mode == archModeWrite)
	{
434 435
		WriteHead(AH);
		WriteToc(AH);
436
		if (fclose(AH->FH) != 0)
437
			die_horribly(AH, modulename, "could not close TOC file: %s\n", strerror(errno));
438
		WriteDataChunks(AH);
B
Bruce Momjian 已提交
439
	}
440

B
Bruce Momjian 已提交
441
	AH->FH = NULL;
442 443 444 445 446 447 448 449 450
}



/*
 * BLOB support
 */

/*
B
Bruce Momjian 已提交
451
 * Called by the archiver when starting to save all BLOB DATA (not schema).
452
 * This routine should save whatever format-specific information is needed
B
Bruce Momjian 已提交
453
 * to read the BLOBs back into memory.
454 455 456 457 458
 *
 * It is called just prior to the dumper's DataDumper routine.
 *
 * Optional, but strongly recommended.
 */
B
Bruce Momjian 已提交
459 460
static void
_StartBlobs(ArchiveHandle *AH, TocEntry *te)
461
{
B
Bruce Momjian 已提交
462 463
	lclContext *ctx = (lclContext *) AH->formatData;
	char		fname[K_STD_BUF_SIZE];
464 465 466

	sprintf(fname, "blobs.toc");
	ctx->blobToc = fopen(fname, PG_BINARY_W);
467 468

	if (ctx->blobToc == NULL)
469
		die_horribly(AH, modulename,
B
Bruce Momjian 已提交
470
		"could not open large object TOC for output: %s\n", strerror(errno));
471 472 473 474 475 476 477 478 479
}

/*
 * Called by the archiver when the dumper calls StartBlob.
 *
 * Mandatory.
 *
 * Must save the passed OID for retrieval at restore-time.
 */
B
Bruce Momjian 已提交
480
static void
481
_StartBlob(ArchiveHandle *AH, TocEntry *te, Oid oid)
482
{
B
Bruce Momjian 已提交
483 484 485 486 487
	lclContext *ctx = (lclContext *) AH->formatData;
	lclTocEntry *tctx = (lclTocEntry *) te->formatData;
	char		fmode[10];
	char		fname[255];
	char	   *sfx;
488

B
Bruce Momjian 已提交
489
	if (oid == 0)
490
		die_horribly(AH, modulename, "invalid OID for large object (%u)\n", oid);
491 492 493 494 495 496

	if (AH->compression != 0)
		sfx = ".gz";
	else
		sfx = "";

B
Bruce Momjian 已提交
497
	sprintf(fmode, "wb%d", AH->compression);
498
	sprintf(fname, "blob_%u.dat%s", oid, sfx);
499

500
	fprintf(ctx->blobToc, "%u %s\n", oid, fname);
501 502

#ifdef HAVE_LIBZ
B
Bruce Momjian 已提交
503
	tctx->FH = gzopen(fname, fmode);
504
#else
B
Bruce Momjian 已提交
505
	tctx->FH = fopen(fname, PG_BINARY_W);
506 507
#endif

508
	if (tctx->FH == NULL)
509
		die_horribly(AH, modulename, "could not open large object file for input: %s\n", strerror(errno));
510 511 512 513 514 515 516
}

/*
 * Called by the archiver when the dumper calls EndBlob.
 *
 * Optional.
 */
B
Bruce Momjian 已提交
517
static void
518
_EndBlob(ArchiveHandle *AH, TocEntry *te, Oid oid)
519
{
B
Bruce Momjian 已提交
520
	lclTocEntry *tctx = (lclTocEntry *) te->formatData;
521

522
	if (GZCLOSE(tctx->FH) != 0)
523
		die_horribly(AH, modulename, "could not close large object file\n");
524 525 526
}

/*
B
Bruce Momjian 已提交
527
 * Called by the archiver when finishing saving all BLOB DATA.
528 529 530
 *
 * Optional.
 */
B
Bruce Momjian 已提交
531 532
static void
_EndBlobs(ArchiveHandle *AH, TocEntry *te)
533
{
B
Bruce Momjian 已提交
534 535
	lclContext *ctx = (lclContext *) AH->formatData;

536
	/* Write out a fake zero OID to mark end-of-blobs. */
B
Bruce Momjian 已提交
537
	/* WriteInt(AH, 0); */
538

539
	if (fclose(ctx->blobToc) != 0)
540
		die_horribly(AH, modulename, "could not close large object TOC file: %s\n", strerror(errno));
541
}