pg_backup_files.c 12.1 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
 *		$Header: /cvsroot/pgsql/src/bin/pg_dump/pg_backup_files.c,v 1.16 2002/05/29 01:38:56 tgl Exp $
24 25 26
 *
 * Modifications - 28-Jun-2000 - pjw@rhyme.com.au
 *
B
Bruce Momjian 已提交
27
 *	Initial version.
28
 *
29 30
 * Modifications - 04-Jan-2001 - pjw@rhyme.com.au
 *
B
Bruce Momjian 已提交
31
 *	  - Check results of IO routines more carefully.
32
 *
33 34 35 36 37 38
 *-------------------------------------------------------------------------
 */

#include "pg_backup.h"
#include "pg_backup_archiver.h"

B
Bruce Momjian 已提交
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
static void _ArchiveEntry(ArchiveHandle *AH, TocEntry *te);
static void _StartData(ArchiveHandle *AH, TocEntry *te);
static int	_WriteData(ArchiveHandle *AH, const void *data, int dLen);
static void _EndData(ArchiveHandle *AH, TocEntry *te);
static int	_WriteByte(ArchiveHandle *AH, const int i);
static int	_ReadByte(ArchiveHandle *);
static int	_WriteBuf(ArchiveHandle *AH, const void *buf, int len);
static int	_ReadBuf(ArchiveHandle *AH, void *buf, int len);
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);
54 55
static void _StartBlob(ArchiveHandle *AH, TocEntry *te, Oid oid);
static void _EndBlob(ArchiveHandle *AH, TocEntry *te, Oid oid);
B
Bruce Momjian 已提交
56
static void _EndBlobs(ArchiveHandle *AH, TocEntry *te);
57 58 59

#define K_STD_BUF_SIZE 1024

B
Bruce Momjian 已提交
60 61 62 63 64
typedef struct
{
	int			hasSeek;
	int			filePos;
	FILE	   *blobToc;
65 66
} lclContext;

B
Bruce Momjian 已提交
67 68
typedef struct
{
69
#ifdef HAVE_LIBZ
B
Bruce Momjian 已提交
70
	gzFile	   *FH;
71
#else
B
Bruce Momjian 已提交
72
	FILE	   *FH;
73
#endif
B
Bruce Momjian 已提交
74
	char	   *filename;
75 76
} lclTocEntry;

77
static char *modulename = gettext_noop("file archiver");
B
Bruce Momjian 已提交
78
static void _LoadBlobs(ArchiveHandle *AH, RestoreOptions *ropt);
79
static void _getBlobTocEntry(ArchiveHandle *AH, Oid *oid, char *fname);
80 81

/*
B
Bruce Momjian 已提交
82
 *	Initializer
83
 */
B
Bruce Momjian 已提交
84 85
void
InitArchiveFmt_Files(ArchiveHandle *AH)
86
{
B
Bruce Momjian 已提交
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115
	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.
	 */
	ctx = (lclContext *) malloc(sizeof(lclContext));
	AH->formatData = (void *) ctx;
	ctx->filePos = 0;

116 117 118 119 120 121
	/* Initialize LO buffering */
	AH->lo_buf_size = LOBBUFSIZE;
	AH->lo_buf = (void *)malloc(LOBBUFSIZE);
	if(AH->lo_buf == NULL)
                die_horribly(AH, modulename, "out of memory\n");

B
Bruce Momjian 已提交
122 123 124 125 126
	/*
	 * Now open the TOC file
	 */
	if (AH->mode == archModeWrite)
	{
127

128
		write_msg(modulename, "WARNING:\n"
129
				  "  This format is for demonstration purposes; it is not intended for\n"
130
				  "  normal use. Files will be written in the current working directory.\n");
131

B
Bruce Momjian 已提交
132
		if (AH->fSpec && strcmp(AH->fSpec, "") != 0)
133
			AH->FH = fopen(AH->fSpec, PG_BINARY_W);
B
Bruce Momjian 已提交
134
		else
135
			AH->FH = stdout;
136 137

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

140 141
		ctx->hasSeek = (fseek(AH->FH, 0, SEEK_CUR) == 0);

B
Bruce Momjian 已提交
142
		if (AH->compression < 0 || AH->compression > 9)
143 144 145
			AH->compression = Z_DEFAULT_COMPRESSION;


B
Bruce Momjian 已提交
146 147 148
	}
	else
	{							/* Read Mode */
149

B
Bruce Momjian 已提交
150
		if (AH->fSpec && strcmp(AH->fSpec, "") != 0)
151
			AH->FH = fopen(AH->fSpec, PG_BINARY_R);
B
Bruce Momjian 已提交
152
		else
153
			AH->FH = stdin;
154 155

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

158 159 160 161
		ctx->hasSeek = (fseek(AH->FH, 0, SEEK_CUR) == 0);

		ReadHead(AH);
		ReadToc(AH);
162 163
		/* Nothing else in the file... */
		if (fclose(AH->FH) != 0)
164
			die_horribly(AH, modulename, "could not close TOC file: %s\n", strerror(errno));
B
Bruce Momjian 已提交
165
	}
166 167 168 169 170

}

/*
 * - Start a new TOC entry
B
Bruce Momjian 已提交
171
 *	 Setup the output file name.
172
 */
B
Bruce Momjian 已提交
173 174
static void
_ArchiveEntry(ArchiveHandle *AH, TocEntry *te)
175
{
B
Bruce Momjian 已提交
176 177
	lclTocEntry *ctx;
	char		fn[K_STD_BUF_SIZE];
178

B
Bruce Momjian 已提交
179 180 181
	ctx = (lclTocEntry *) malloc(sizeof(lclTocEntry));
	if (te->dataDumper)
	{
182
#ifdef HAVE_LIBZ
B
Bruce Momjian 已提交
183
		if (AH->compression == 0)
184
			sprintf(fn, "%d.dat", te->id);
B
Bruce Momjian 已提交
185
		else
186 187 188 189 190
			sprintf(fn, "%d.dat.gz", te->id);
#else
		sprintf(fn, "%d.dat", te->id);
#endif
		ctx->filename = strdup(fn);
B
Bruce Momjian 已提交
191 192 193
	}
	else
	{
194 195
		ctx->filename = NULL;
		ctx->FH = NULL;
B
Bruce Momjian 已提交
196 197
	}
	te->formatData = (void *) ctx;
198 199
}

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

B
Bruce Momjian 已提交
205
	if (ctx->filename)
206
		WriteStr(AH, ctx->filename);
B
Bruce Momjian 已提交
207
	else
208 209 210
		WriteStr(AH, "");
}

B
Bruce Momjian 已提交
211 212
static void
_ReadExtraToc(ArchiveHandle *AH, TocEntry *te)
213
{
B
Bruce Momjian 已提交
214
	lclTocEntry *ctx = (lclTocEntry *) te->formatData;
215

B
Bruce Momjian 已提交
216 217 218 219 220
	if (ctx == NULL)
	{
		ctx = (lclTocEntry *) malloc(sizeof(lclTocEntry));
		te->formatData = (void *) ctx;
	}
221

B
Bruce Momjian 已提交
222 223 224
	ctx->filename = ReadStr(AH);
	if (strlen(ctx->filename) == 0)
	{
225 226
		free(ctx->filename);
		ctx->filename = NULL;
B
Bruce Momjian 已提交
227 228
	}
	ctx->FH = NULL;
229 230
}

B
Bruce Momjian 已提交
231 232
static void
_PrintExtraToc(ArchiveHandle *AH, TocEntry *te)
233
{
B
Bruce Momjian 已提交
234
	lclTocEntry *ctx = (lclTocEntry *) te->formatData;
235

B
Bruce Momjian 已提交
236
	ahprintf(AH, "-- File: %s\n", ctx->filename);
237 238
}

B
Bruce Momjian 已提交
239 240
static void
_StartData(ArchiveHandle *AH, TocEntry *te)
241
{
B
Bruce Momjian 已提交
242 243
	lclTocEntry *tctx = (lclTocEntry *) te->formatData;
	char		fmode[10];
244

B
Bruce Momjian 已提交
245
	sprintf(fmode, "wb%d", AH->compression);
246 247

#ifdef HAVE_LIBZ
B
Bruce Momjian 已提交
248
	tctx->FH = gzopen(tctx->filename, fmode);
249
#else
B
Bruce Momjian 已提交
250
	tctx->FH = fopen(tctx->filename, PG_BINARY_W);
251
#endif
252 253

	if (tctx->FH == NULL)
254
		die_horribly(AH, modulename, "could not open data file for output\n");
255

256 257
}

B
Bruce Momjian 已提交
258 259
static int
_WriteData(ArchiveHandle *AH, const void *data, int dLen)
260
{
B
Bruce Momjian 已提交
261
	lclTocEntry *tctx = (lclTocEntry *) AH->currToc->formatData;
262

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

B
Bruce Momjian 已提交
265
	return dLen;
266 267
}

B
Bruce Momjian 已提交
268 269
static void
_EndData(ArchiveHandle *AH, TocEntry *te)
270
{
B
Bruce Momjian 已提交
271
	lclTocEntry *tctx = (lclTocEntry *) te->formatData;
272

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

B
Bruce Momjian 已提交
277
	tctx->FH = NULL;
278 279
}

B
Bruce Momjian 已提交
280 281
/*
 * Print data for a given file
282
 */
B
Bruce Momjian 已提交
283 284
static void
_PrintFileData(ArchiveHandle *AH, char *filename, RestoreOptions *ropt)
285
{
B
Bruce Momjian 已提交
286 287
	char		buf[4096];
	int			cnt;
288

B
Bruce Momjian 已提交
289
	if (!filename)
290 291 292
		return;

#ifdef HAVE_LIBZ
B
Bruce Momjian 已提交
293
	AH->FH = gzopen(filename, "rb");
294
#else
B
Bruce Momjian 已提交
295
	AH->FH = fopen(filename, PG_BINARY_R);
296 297
#endif

298
	if (AH->FH == NULL)
299
		die_horribly(AH, modulename, "could not open data file for input\n");
300

B
Bruce Momjian 已提交
301 302
	while ((cnt = GZREAD(buf, 1, 4095, AH->FH)) > 0)
	{
303 304
		buf[cnt] = '\0';
		ahwrite(buf, 1, cnt, AH);
B
Bruce Momjian 已提交
305
	}
306

307
	if (GZCLOSE(AH->FH) != 0)
308
		die_horribly(AH, modulename, "could not close data file after reading\n");
309

310 311 312 313 314 315
}


/*
 * Print data for a given TOC entry
*/
B
Bruce Momjian 已提交
316 317
static void
_PrintTocData(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt)
318
{
B
Bruce Momjian 已提交
319
	lclTocEntry *tctx = (lclTocEntry *) te->formatData;
320

B
Bruce Momjian 已提交
321
	if (!tctx->filename)
322 323 324 325 326 327 328 329
		return;

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

B
Bruce Momjian 已提交
330
static void
331
_getBlobTocEntry(ArchiveHandle *AH, Oid *oid, char fname[K_STD_BUF_SIZE])
332
{
B
Bruce Momjian 已提交
333 334 335 336
	lclContext *ctx = (lclContext *) AH->formatData;
	char		blobTe[K_STD_BUF_SIZE];
	int			fpos;
	int			eos;
337 338 339

	if (fgets(&blobTe[0], K_STD_BUF_SIZE - 1, ctx->blobToc) != NULL)
	{
340
		*oid = atooid(blobTe);
341 342 343

		fpos = strcspn(blobTe, " ");

B
Bruce Momjian 已提交
344
		strncpy(fname, &blobTe[fpos + 1], K_STD_BUF_SIZE - 1);
345

B
Bruce Momjian 已提交
346
		eos = strlen(fname) - 1;
347 348 349 350

		if (fname[eos] == '\n')
			fname[eos] = '\0';

B
Bruce Momjian 已提交
351 352 353
	}
	else
	{
354 355 356 357 358 359

		*oid = 0;
		fname[0] = '\0';
	}
}

B
Bruce Momjian 已提交
360 361
static void
_LoadBlobs(ArchiveHandle *AH, RestoreOptions *ropt)
362
{
363
	Oid			oid;
B
Bruce Momjian 已提交
364 365
	lclContext *ctx = (lclContext *) AH->formatData;
	char		fname[K_STD_BUF_SIZE];
366

367 368
	StartRestoreBlobs(AH);

369 370
	ctx->blobToc = fopen("blobs.toc", PG_BINARY_R);

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

374 375
	_getBlobTocEntry(AH, &oid, fname);

B
Bruce Momjian 已提交
376 377
	while (oid != 0)
	{
378 379 380 381
		StartRestoreBlob(AH, oid);
		_PrintFileData(AH, fname, ropt);
		EndRestoreBlob(AH, oid);
		_getBlobTocEntry(AH, &oid, fname);
B
Bruce Momjian 已提交
382
	}
383

384
	if (fclose(ctx->blobToc) != 0)
385
		die_horribly(AH, modulename, "could not close large object TOC file: %s\n", strerror(errno));
386 387

	EndRestoreBlobs(AH);
388 389 390
}


B
Bruce Momjian 已提交
391 392
static int
_WriteByte(ArchiveHandle *AH, const int i)
393
{
B
Bruce Momjian 已提交
394
	lclContext *ctx = (lclContext *) AH->formatData;
395

B
Bruce Momjian 已提交
396
	if (fputc(i, AH->FH) == EOF)
397
		die_horribly(AH, modulename, "could not write byte\n");
398 399 400

	ctx->filePos += 1;

B
Bruce Momjian 已提交
401
	return 1;
402 403
}

B
Bruce Momjian 已提交
404 405
static int
_ReadByte(ArchiveHandle *AH)
406
{
B
Bruce Momjian 已提交
407 408
	lclContext *ctx = (lclContext *) AH->formatData;
	int			res;
409

B
Bruce Momjian 已提交
410 411
	res = fgetc(AH->FH);
	if (res != EOF)
412
		ctx->filePos += 1;
B
Bruce Momjian 已提交
413
	return res;
414 415
}

B
Bruce Momjian 已提交
416 417
static int
_WriteBuf(ArchiveHandle *AH, const void *buf, int len)
418
{
B
Bruce Momjian 已提交
419 420 421 422
	lclContext *ctx = (lclContext *) AH->formatData;
	int			res;

	res = fwrite(buf, 1, len, AH->FH);
423
	if (res != len)
424
		die_horribly(AH, modulename, "write error in _WriteBuf (%d != %d)\n", res, len);
425

B
Bruce Momjian 已提交
426 427
	ctx->filePos += res;
	return res;
428 429
}

B
Bruce Momjian 已提交
430 431
static int
_ReadBuf(ArchiveHandle *AH, void *buf, int len)
432
{
B
Bruce Momjian 已提交
433 434
	lclContext *ctx = (lclContext *) AH->formatData;
	int			res;
435

B
Bruce Momjian 已提交
436 437 438
	res = fread(buf, 1, len, AH->FH);
	ctx->filePos += res;
	return res;
439 440
}

B
Bruce Momjian 已提交
441 442
static void
_CloseArchive(ArchiveHandle *AH)
443
{
B
Bruce Momjian 已提交
444 445
	if (AH->mode == archModeWrite)
	{
446 447
		WriteHead(AH);
		WriteToc(AH);
448
		if (fclose(AH->FH) != 0)
449
			die_horribly(AH, modulename, "could not close TOC file: %s\n", strerror(errno));
450
		WriteDataChunks(AH);
B
Bruce Momjian 已提交
451
	}
452

B
Bruce Momjian 已提交
453
	AH->FH = NULL;
454 455 456 457 458 459 460 461 462
}



/*
 * BLOB support
 */

/*
B
Bruce Momjian 已提交
463
 * Called by the archiver when starting to save all BLOB DATA (not schema).
464
 * This routine should save whatever format-specific information is needed
B
Bruce Momjian 已提交
465
 * to read the BLOBs back into memory.
466 467 468 469 470 471
 *
 * It is called just prior to the dumper's DataDumper routine.
 *
 * Optional, but strongly recommended.
 *
 */
B
Bruce Momjian 已提交
472 473
static void
_StartBlobs(ArchiveHandle *AH, TocEntry *te)
474
{
B
Bruce Momjian 已提交
475 476
	lclContext *ctx = (lclContext *) AH->formatData;
	char		fname[K_STD_BUF_SIZE];
477 478 479

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

	if (ctx->blobToc == NULL)
482
		die_horribly(AH, modulename,
483
					 "could not open large object TOC for output: %s\n", strerror(errno));
484

485 486 487 488 489 490 491 492 493
}

/*
 * Called by the archiver when the dumper calls StartBlob.
 *
 * Mandatory.
 *
 * Must save the passed OID for retrieval at restore-time.
 */
B
Bruce Momjian 已提交
494
static void
495
_StartBlob(ArchiveHandle *AH, TocEntry *te, Oid oid)
496
{
B
Bruce Momjian 已提交
497 498 499 500 501
	lclContext *ctx = (lclContext *) AH->formatData;
	lclTocEntry *tctx = (lclTocEntry *) te->formatData;
	char		fmode[10];
	char		fname[255];
	char	   *sfx;
502

B
Bruce Momjian 已提交
503
	if (oid == 0)
504
		die_horribly(AH, modulename, "invalid OID for large object (%u)\n", oid);
505 506 507 508 509 510

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

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

514
	fprintf(ctx->blobToc, "%u %s\n", oid, fname);
515 516

#ifdef HAVE_LIBZ
B
Bruce Momjian 已提交
517
	tctx->FH = gzopen(fname, fmode);
518
#else
B
Bruce Momjian 已提交
519
	tctx->FH = fopen(fname, PG_BINARY_W);
520 521
#endif

522
	if (tctx->FH == NULL)
523
		die_horribly(AH, modulename, "could not open large object file\n");
524 525 526 527 528 529 530 531
}

/*
 * Called by the archiver when the dumper calls EndBlob.
 *
 * Optional.
 *
 */
B
Bruce Momjian 已提交
532
static void
533
_EndBlob(ArchiveHandle *AH, TocEntry *te, Oid oid)
534
{
B
Bruce Momjian 已提交
535
	lclTocEntry *tctx = (lclTocEntry *) te->formatData;
536

537
	if (GZCLOSE(tctx->FH) != 0)
538
		die_horribly(AH, modulename, "could not close large object file\n");
539 540 541
}

/*
B
Bruce Momjian 已提交
542
 * Called by the archiver when finishing saving all BLOB DATA.
543 544 545 546
 *
 * Optional.
 *
 */
B
Bruce Momjian 已提交
547 548
static void
_EndBlobs(ArchiveHandle *AH, TocEntry *te)
549
{
B
Bruce Momjian 已提交
550 551
	lclContext *ctx = (lclContext *) AH->formatData;

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

555
	if (fclose(ctx->blobToc) != 0)
556
		die_horribly(AH, modulename, "could not close large object TOC file: %s\n", strerror(errno));
557 558

}