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
 *		$Header: /cvsroot/pgsql/src/bin/pg_dump/pg_backup_files.c,v 1.20 2002/10/22 19:15:23 momjian Exp $
24
 *
25 26 27 28 29 30
 *-------------------------------------------------------------------------
 */

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

B
Bruce Momjian 已提交
31 32
static void _ArchiveEntry(ArchiveHandle *AH, TocEntry *te);
static void _StartData(ArchiveHandle *AH, TocEntry *te);
B
Bruce Momjian 已提交
33
static size_t _WriteData(ArchiveHandle *AH, const void *data, size_t dLen);
B
Bruce Momjian 已提交
34 35 36
static void _EndData(ArchiveHandle *AH, TocEntry *te);
static int	_WriteByte(ArchiveHandle *AH, const int i);
static int	_ReadByte(ArchiveHandle *);
B
Bruce Momjian 已提交
37 38
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 已提交
39 40 41 42 43 44 45
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);
46 47
static void _StartBlob(ArchiveHandle *AH, TocEntry *te, Oid oid);
static void _EndBlob(ArchiveHandle *AH, TocEntry *te, Oid oid);
B
Bruce Momjian 已提交
48
static void _EndBlobs(ArchiveHandle *AH, TocEntry *te);
49 50 51

#define K_STD_BUF_SIZE 1024

B
Bruce Momjian 已提交
52 53 54
typedef struct
{
	int			hasSeek;
P
Peter Eisentraut 已提交
55
	off_t		filePos;
B
Bruce Momjian 已提交
56
	FILE	   *blobToc;
57 58
} lclContext;

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

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

/*
B
Bruce Momjian 已提交
74
 *	Initializer
75
 */
B
Bruce Momjian 已提交
76 77
void
InitArchiveFmt_Files(ArchiveHandle *AH)
78
{
B
Bruce Momjian 已提交
79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
	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;

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

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

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

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

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

P
Peter Eisentraut 已提交
132
		ctx->hasSeek = (fseeko(AH->FH, 0, SEEK_CUR) == 0);
133

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


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

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

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

P
Peter Eisentraut 已提交
150
		ctx->hasSeek = (fseeko(AH->FH, 0, SEEK_CUR) == 0);
151 152 153

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

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

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

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

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

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

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

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

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

B
Bruce Momjian 已提交
227
	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 data file for output\n");
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 data file for input\n");
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];
P
Peter Eisentraut 已提交
324 325
	size_t		fpos;
	size_t		eos;
326 327 328

	if (fgets(&blobTe[0], K_STD_BUF_SIZE - 1, ctx->blobToc) != NULL)
	{
329
		*oid = atooid(blobTe);
330 331 332

		fpos = strcspn(blobTe, " ");

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

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

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

B
Bruce Momjian 已提交
340 341 342
	}
	else
	{
343 344 345 346 347 348

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

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

356 357
	StartRestoreBlobs(AH);

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

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

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

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

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

	EndRestoreBlobs(AH);
377 378 379
}


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

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

	ctx->filePos += 1;

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

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

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

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

	res = fwrite(buf, 1, len, AH->FH);
412
	if (res != len)
413
		die_horribly(AH, modulename, "write error in _WriteBuf (%lu != %lu)\n", (unsigned long) res, (unsigned long) len);
414

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

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

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

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

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



/*
 * BLOB support
 */

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

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

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

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

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

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

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

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

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

510
	if (tctx->FH == NULL)
511
		die_horribly(AH, modulename, "could not open large object file\n");
512 513 514 515 516 517 518 519
}

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

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

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

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

543
	if (fclose(ctx->blobToc) != 0)
544
		die_horribly(AH, modulename, "could not close large object TOC file: %s\n", strerror(errno));
545 546

}