pg_backup_tar.c 27.1 KB
Newer Older
P
Philip Warner 已提交
1 2 3 4 5 6 7 8 9 10
/*-------------------------------------------------------------------------
 *
 * pg_backup_tar.c
 *
 *	This file is copied from the 'files' format file, but dumps data into
 *	one temp file then sends it to the output TAR archive.
 *
 *	See the headers to pg_backup_files & pg_restore for more details.
 *
 * Copyright (c) 2000, Philip Warner
B
Bruce Momjian 已提交
11 12
 *		Rights are granted to use this software in any way so long
 *		as this notice is not removed.
P
Philip Warner 已提交
13 14 15 16 17 18
 *
 *	The author is not responsible for loss or damages that may
 *	result from it's use.
 *
 *
 * IDENTIFICATION
P
Peter Eisentraut 已提交
19
 *		$Header: /cvsroot/pgsql/src/bin/pg_dump/pg_backup_tar.c,v 1.25 2002/08/20 17:54:44 petere Exp $
20
 *
P
Philip Warner 已提交
21 22 23
 *-------------------------------------------------------------------------
 */

24 25 26 27
#include "pg_backup.h"
#include "pg_backup_archiver.h"
#include "pg_backup_tar.h"

P
Philip Warner 已提交
28 29 30 31 32
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>

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

#define K_STD_BUF_SIZE 1024


#ifdef HAVE_LIBZ
B
Bruce Momjian 已提交
56 57 58
 /* typedef gzFile	 ThingFile; */
typedef FILE ThingFile;

P
Philip Warner 已提交
59
#else
B
Bruce Momjian 已提交
60
typedef FILE ThingFile;
P
Philip Warner 已提交
61 62
#endif

B
Bruce Momjian 已提交
63 64 65 66 67 68 69 70
typedef struct
{
	ThingFile  *zFH;
	FILE	   *nFH;
	FILE	   *tarFH;
	FILE	   *tmpFH;
	char	   *targetFile;
	char		mode;
P
Peter Eisentraut 已提交
71 72
	off_t		pos;
	off_t		fileLen;
B
Bruce Momjian 已提交
73
	ArchiveHandle *AH;
P
Philip Warner 已提交
74 75
} TAR_MEMBER;

B
Bruce Momjian 已提交
76 77
typedef struct
{
P
Philip Warner 已提交
78
	int			hasSeek;
P
Peter Eisentraut 已提交
79
	off_t		filePos;
B
Bruce Momjian 已提交
80 81
	TAR_MEMBER *blobToc;
	FILE	   *tarFH;
P
Peter Eisentraut 已提交
82 83
	off_t		tarFHpos;
	off_t		tarNextMember;
B
Bruce Momjian 已提交
84
	TAR_MEMBER *FH;
P
Philip Warner 已提交
85
	int			isSpecialScript;
B
Bruce Momjian 已提交
86
	TAR_MEMBER *scriptTH;
P
Philip Warner 已提交
87 88
} lclContext;

B
Bruce Momjian 已提交
89 90 91 92
typedef struct
{
	TAR_MEMBER *TH;
	char	   *filename;
P
Philip Warner 已提交
93 94
} lclTocEntry;

95
static char *modulename = gettext_noop("tar archiver");
B
Bruce Momjian 已提交
96 97

static void _LoadBlobs(ArchiveHandle *AH, RestoreOptions *ropt);
P
Philip Warner 已提交
98

B
Bruce Momjian 已提交
99 100
static TAR_MEMBER *tarOpen(ArchiveHandle *AH, const char *filename, char mode);
static void tarClose(ArchiveHandle *AH, TAR_MEMBER *TH);
P
Philip Warner 已提交
101 102

#ifdef __NOT_USED__
P
Peter Eisentraut 已提交
103
static char *tarGets(char *buf, size_t len, TAR_MEMBER *th);
P
Philip Warner 已提交
104
#endif
B
Bruce Momjian 已提交
105
static int	tarPrintf(ArchiveHandle *AH, TAR_MEMBER *th, const char *fmt,...);
P
Philip Warner 已提交
106

B
Bruce Momjian 已提交
107 108 109
static void _tarAddFile(ArchiveHandle *AH, TAR_MEMBER *th);
static int	_tarChecksum(char *th);
static TAR_MEMBER *_tarPositionTo(ArchiveHandle *AH, const char *filename);
P
Peter Eisentraut 已提交
110 111
static size_t	tarRead(void *buf, size_t len, TAR_MEMBER *th);
static size_t	tarWrite(const void *buf, size_t len, TAR_MEMBER *th);
B
Bruce Momjian 已提交
112 113
static void _tarWriteHeader(TAR_MEMBER *th);
static int	_tarGetHeader(ArchiveHandle *AH, TAR_MEMBER *th);
P
Peter Eisentraut 已提交
114
static size_t	_tarReadRaw(ArchiveHandle *AH, void *buf, size_t len, TAR_MEMBER *th, FILE *fh);
P
Philip Warner 已提交
115

P
Peter Eisentraut 已提交
116
static size_t	_scriptOut(ArchiveHandle *AH, const void *buf, size_t len);
P
Philip Warner 已提交
117 118

/*
B
Bruce Momjian 已提交
119
 *	Initializer
P
Philip Warner 已提交
120
 */
B
Bruce Momjian 已提交
121 122
void
InitArchiveFmt_Tar(ArchiveHandle *AH)
P
Philip Warner 已提交
123
{
B
Bruce Momjian 已提交
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
	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;
152

153 154 155
	/* Initialize LO buffering */
	AH->lo_buf_size = LOBBUFSIZE;
	AH->lo_buf = (void *)malloc(LOBBUFSIZE);
P
Peter Eisentraut 已提交
156 157
	if (AH->lo_buf == NULL)
		die_horribly(AH, modulename, "out of memory\n");
B
Bruce Momjian 已提交
158 159 160 161 162 163 164 165

	/*
	 * Now open the TOC file
	 */
	if (AH->mode == archModeWrite)
	{

		if (AH->fSpec && strcmp(AH->fSpec, "") != 0)
P
Philip Warner 已提交
166
			ctx->tarFH = fopen(AH->fSpec, PG_BINARY_W);
B
Bruce Momjian 已提交
167
		else
P
Philip Warner 已提交
168
			ctx->tarFH = stdout;
169

B
Bruce Momjian 已提交
170
		if (ctx->tarFH == NULL)
171
			die_horribly(NULL, modulename,
172
			"could not open TOC file for output: %s\n", strerror(errno));
173

P
Philip Warner 已提交
174 175
		ctx->tarFHpos = 0;

B
Bruce Momjian 已提交
176 177 178 179
		/*
		 * Make unbuffered since we will dup() it, and the buffers screw
		 * each other
		 */
180
		/* setvbuf(ctx->tarFH, NULL, _IONBF, 0); */
P
Philip Warner 已提交
181

P
Peter Eisentraut 已提交
182
		ctx->hasSeek = (fseeko(ctx->tarFH, 0, SEEK_CUR) == 0);
P
Philip Warner 已提交
183

B
Bruce Momjian 已提交
184
		if (AH->compression < 0 || AH->compression > 9)
P
Philip Warner 已提交
185 186 187 188 189 190
			AH->compression = Z_DEFAULT_COMPRESSION;

		/* Don't compress into tar files unless asked to do so */
		if (AH->compression == Z_DEFAULT_COMPRESSION)
			AH->compression = 0;

B
Bruce Momjian 已提交
191 192 193 194
		/*
		 * We don't support compression because reading the files back is
		 * not possible since gzdopen uses buffered IO which totally
		 * screws file positioning.
P
Philip Warner 已提交
195 196
		 */
		if (AH->compression != 0)
197
			die_horribly(NULL, modulename, "compression not supported by tar output format\n");
P
Philip Warner 已提交
198

B
Bruce Momjian 已提交
199 200 201
	}
	else
	{							/* Read Mode */
P
Philip Warner 已提交
202

B
Bruce Momjian 已提交
203
		if (AH->fSpec && strcmp(AH->fSpec, "") != 0)
P
Philip Warner 已提交
204
			ctx->tarFH = fopen(AH->fSpec, PG_BINARY_R);
B
Bruce Momjian 已提交
205
		else
P
Philip Warner 已提交
206 207
			ctx->tarFH = stdin;

208
		if (ctx->tarFH == NULL)
209
			die_horribly(NULL, modulename, "could not open TOC file for input: %s\n", strerror(errno));
210

B
Bruce Momjian 已提交
211 212 213 214
		/*
		 * Make unbuffered since we will dup() it, and the buffers screw
		 * each other
		 */
215
		/* setvbuf(ctx->tarFH, NULL, _IONBF, 0); */
P
Philip Warner 已提交
216 217 218

		ctx->tarFHpos = 0;

P
Peter Eisentraut 已提交
219
		ctx->hasSeek = (fseeko(ctx->tarFH, 0, SEEK_CUR) == 0);
P
Philip Warner 已提交
220

B
Bruce Momjian 已提交
221 222 223 224
		/*
		 * Forcibly unmark the header as read since we use the lookahead
		 * buffer
		 */
P
Philip Warner 已提交
225 226
		AH->readHeader = 0;

B
Bruce Momjian 已提交
227
		ctx->FH = (void *) tarOpen(AH, "toc.dat", 'r');
P
Philip Warner 已提交
228 229
		ReadHead(AH);
		ReadToc(AH);
B
Bruce Momjian 已提交
230 231
		tarClose(AH, ctx->FH);	/* Nothing else in the file... */
	}
P
Philip Warner 已提交
232 233 234 235 236

}

/*
 * - Start a new TOC entry
B
Bruce Momjian 已提交
237
 *	 Setup the output file name.
P
Philip Warner 已提交
238
 */
B
Bruce Momjian 已提交
239 240
static void
_ArchiveEntry(ArchiveHandle *AH, TocEntry *te)
P
Philip Warner 已提交
241
{
B
Bruce Momjian 已提交
242 243
	lclTocEntry *ctx;
	char		fn[K_STD_BUF_SIZE];
P
Philip Warner 已提交
244

B
Bruce Momjian 已提交
245
	ctx = (lclTocEntry *) malloc(sizeof(lclTocEntry));
246
	if (te->dataDumper != NULL)
B
Bruce Momjian 已提交
247
	{
P
Philip Warner 已提交
248
#ifdef HAVE_LIBZ
B
Bruce Momjian 已提交
249
		if (AH->compression == 0)
P
Philip Warner 已提交
250
			sprintf(fn, "%d.dat", te->id);
B
Bruce Momjian 已提交
251
		else
P
Philip Warner 已提交
252 253 254 255 256
			sprintf(fn, "%d.dat.gz", te->id);
#else
		sprintf(fn, "%d.dat", te->id);
#endif
		ctx->filename = strdup(fn);
B
Bruce Momjian 已提交
257 258 259
	}
	else
	{
P
Philip Warner 已提交
260 261
		ctx->filename = NULL;
		ctx->TH = NULL;
B
Bruce Momjian 已提交
262 263
	}
	te->formatData = (void *) ctx;
P
Philip Warner 已提交
264 265
}

B
Bruce Momjian 已提交
266 267
static void
_WriteExtraToc(ArchiveHandle *AH, TocEntry *te)
P
Philip Warner 已提交
268
{
B
Bruce Momjian 已提交
269
	lclTocEntry *ctx = (lclTocEntry *) te->formatData;
P
Philip Warner 已提交
270

B
Bruce Momjian 已提交
271
	if (ctx->filename)
P
Philip Warner 已提交
272
		WriteStr(AH, ctx->filename);
B
Bruce Momjian 已提交
273
	else
P
Philip Warner 已提交
274 275 276
		WriteStr(AH, "");
}

B
Bruce Momjian 已提交
277 278
static void
_ReadExtraToc(ArchiveHandle *AH, TocEntry *te)
P
Philip Warner 已提交
279
{
B
Bruce Momjian 已提交
280
	lclTocEntry *ctx = (lclTocEntry *) te->formatData;
P
Philip Warner 已提交
281

B
Bruce Momjian 已提交
282 283 284 285 286
	if (ctx == NULL)
	{
		ctx = (lclTocEntry *) malloc(sizeof(lclTocEntry));
		te->formatData = (void *) ctx;
	}
P
Philip Warner 已提交
287

B
Bruce Momjian 已提交
288 289 290
	ctx->filename = ReadStr(AH);
	if (strlen(ctx->filename) == 0)
	{
P
Philip Warner 已提交
291 292
		free(ctx->filename);
		ctx->filename = NULL;
B
Bruce Momjian 已提交
293 294
	}
	ctx->TH = NULL;
P
Philip Warner 已提交
295 296
}

B
Bruce Momjian 已提交
297 298
static void
_PrintExtraToc(ArchiveHandle *AH, TocEntry *te)
P
Philip Warner 已提交
299
{
B
Bruce Momjian 已提交
300
	lclTocEntry *ctx = (lclTocEntry *) te->formatData;
P
Philip Warner 已提交
301

302 303
	if (ctx->filename != NULL)
		ahprintf(AH, "-- File: %s\n", ctx->filename);
P
Philip Warner 已提交
304 305
}

B
Bruce Momjian 已提交
306 307
static void
_StartData(ArchiveHandle *AH, TocEntry *te)
P
Philip Warner 已提交
308
{
B
Bruce Momjian 已提交
309
	lclTocEntry *tctx = (lclTocEntry *) te->formatData;
P
Philip Warner 已提交
310 311 312 313

	tctx->TH = tarOpen(AH, tctx->filename, 'w');
}

B
Bruce Momjian 已提交
314 315
static TAR_MEMBER *
tarOpen(ArchiveHandle *AH, const char *filename, char mode)
P
Philip Warner 已提交
316
{
B
Bruce Momjian 已提交
317 318 319
	lclContext *ctx = (lclContext *) AH->formatData;
	TAR_MEMBER *tm;

P
Philip Warner 已提交
320
#ifdef HAVE_LIBZ
B
Bruce Momjian 已提交
321
	char		fmode[10];
P
Philip Warner 已提交
322 323 324 325 326
#endif

	if (mode == 'r')
	{
		tm = _tarPositionTo(AH, filename);
B
Bruce Momjian 已提交
327
		if (!tm)				/* Not found */
P
Philip Warner 已提交
328
		{
B
Bruce Momjian 已提交
329 330
			if (filename)		/* Couldn't find the requested file.
								 * Future: DO SEEK(0) and retry. */
331
				die_horribly(AH, modulename, "could not find file %s in archive\n", filename);
B
Bruce Momjian 已提交
332 333
			else
/* Any file OK, non left, so return NULL */
P
Philip Warner 已提交
334 335 336 337 338 339 340 341
				return NULL;
		}

#ifdef HAVE_LIBZ

		if (AH->compression == 0)
			tm->nFH = ctx->tarFH;
		else
342
			die_horribly(AH, modulename, "compression support is disabled in this format\n");
B
Bruce Momjian 已提交
343
		/* tm->zFH = gzdopen(dup(fileno(ctx->tarFH)), "rb"); */
P
Philip Warner 已提交
344 345 346 347 348 349

#else

		tm->nFH = ctx->tarFH;
#endif

B
Bruce Momjian 已提交
350 351 352
	}
	else
	{
P
Philip Warner 已提交
353 354 355 356
		tm = calloc(1, sizeof(TAR_MEMBER));

		tm->tmpFH = tmpfile();

B
Bruce Momjian 已提交
357
		if (tm->tmpFH == NULL)
358
			die_horribly(AH, modulename, "could not generate temporary file name: %s\n", strerror(errno));
359

P
Philip Warner 已提交
360 361 362 363 364 365
#ifdef HAVE_LIBZ

		if (AH->compression != 0)
		{
			sprintf(fmode, "wb%d", AH->compression);
			tm->zFH = gzdopen(dup(fileno(tm->tmpFH)), fmode);
366
			if (tm->zFH == NULL)
367
				die_horribly(AH, modulename, "could not gzdopen temporary file\n");
368

B
Bruce Momjian 已提交
369 370
		}
		else
P
Philip Warner 已提交
371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388
			tm->nFH = tm->tmpFH;

#else

		tm->nFH = tm->tmpFH;
#endif

		tm->AH = AH;
		tm->targetFile = strdup(filename);
	}

	tm->mode = mode;
	tm->tarFH = ctx->tarFH;

	return tm;

}

B
Bruce Momjian 已提交
389 390
static void
tarClose(ArchiveHandle *AH, TAR_MEMBER *th)
P
Philip Warner 已提交
391 392 393 394 395
{
	/*
	 * Close the GZ file since we dup'd. This will flush the buffers.
	 */
	if (AH->compression != 0)
396
		if (GZCLOSE(th->zFH) != 0)
397
			die_horribly(AH, modulename, "could not close tar member\n");
P
Philip Warner 已提交
398 399

	if (th->mode == 'w')
B
Bruce Momjian 已提交
400 401 402 403 404
		_tarAddFile(AH, th);	/* This will close the temp file */

	/*
	 * else Nothing to do for normal read since we don't dup() normal file
	 * handle, and we don't use temp files.
P
Philip Warner 已提交
405 406
	 */

B
Bruce Momjian 已提交
407
	if (th->targetFile)
P
Philip Warner 已提交
408 409 410 411 412 413 414
		free(th->targetFile);

	th->nFH = NULL;
	th->zFH = NULL;
}

#ifdef __NOT_USED__
B
Bruce Momjian 已提交
415
static char *
P
Peter Eisentraut 已提交
416
tarGets(char *buf, size_t len, TAR_MEMBER *th)
P
Philip Warner 已提交
417
{
B
Bruce Momjian 已提交
418
	char	   *s;
P
Peter Eisentraut 已提交
419
	size_t		cnt = 0;
B
Bruce Momjian 已提交
420 421
	char		c = ' ';
	int			eof = 0;
P
Philip Warner 已提交
422 423 424 425 426 427 428

	/* Can't read past logical EOF */
	if (len > (th->fileLen - th->pos))
		len = th->fileLen - th->pos;

	while (cnt < len && c != '\n')
	{
B
Bruce Momjian 已提交
429 430
		if (_tarReadRaw(th->AH, &c, 1, th, NULL) <= 0)
		{
P
Philip Warner 已提交
431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446
			eof = 1;
			break;
		}
		buf[cnt++] = c;
	}

	if (eof && cnt == 0)
		s = NULL;
	else
	{
		buf[cnt++] = '\0';
		s = buf;
	}

	if (s)
	{
B
Bruce Momjian 已提交
447
		len = strlen(s);
P
Philip Warner 已提交
448 449 450 451 452 453 454
		th->pos += len;
	}

	return s;
}
#endif

B
Bruce Momjian 已提交
455
/*
P
Philip Warner 已提交
456 457 458
 * Just read bytes from the archive. This is the low level read routine
 * that is used for ALL reads on a tar file.
 */
P
Peter Eisentraut 已提交
459 460
static size_t
_tarReadRaw(ArchiveHandle *AH, void *buf, size_t len, TAR_MEMBER *th, FILE *fh)
P
Philip Warner 已提交
461
{
B
Bruce Momjian 已提交
462
	lclContext *ctx = (lclContext *) AH->formatData;
P
Peter Eisentraut 已提交
463 464 465
	size_t		avail;
	size_t		used = 0;
	size_t		res = 0;
P
Philip Warner 已提交
466 467 468 469 470

	avail = AH->lookaheadLen - AH->lookaheadPos;
	if (avail > 0)
	{
		/* We have some lookahead bytes to use */
B
Bruce Momjian 已提交
471
		if (avail >= len)		/* Just use the lookahead buffer */
P
Philip Warner 已提交
472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487
			used = len;
		else
			used = avail;

		/* Copy, and adjust buffer pos */
		memcpy(buf, AH->lookahead, used);
		AH->lookaheadPos += used;

		/* Adjust required length */
		len -= used;
	}

	/* Read the file if len > 0 */
	if (len > 0)
	{
		if (fh)
B
Bruce Momjian 已提交
488
			res = fread(&((char *) buf)[used], 1, len, fh);
P
Philip Warner 已提交
489 490 491
		else if (th)
		{
			if (th->zFH)
B
Bruce Momjian 已提交
492
				res = GZREAD(&((char *) buf)[used], 1, len, th->zFH);
P
Philip Warner 已提交
493
			else
B
Bruce Momjian 已提交
494 495
				res = fread(&((char *) buf)[used], 1, len, th->nFH);
		}
P
Philip Warner 已提交
496
		else
497
			die_horribly(AH, modulename, "neither th nor fh specified in tarReadRaw() (internal error)\n");
P
Philip Warner 已提交
498 499
	}

500 501 502 503
#if 0
	write_msg(modulename, "requested %d bytes, got %d from lookahead and %d from file\n",
			  reqLen, used, res);
#endif
P
Philip Warner 已提交
504 505 506 507 508

	ctx->tarFHpos += res + used;

	return (res + used);
}
B
Bruce Momjian 已提交
509

P
Peter Eisentraut 已提交
510 511
static size_t
tarRead(void *buf, size_t len, TAR_MEMBER *th)
P
Philip Warner 已提交
512
{
P
Peter Eisentraut 已提交
513
	size_t		res;
P
Philip Warner 已提交
514 515 516 517 518 519 520 521 522 523 524 525 526 527

	if (th->pos + len > th->fileLen)
		len = th->fileLen - th->pos;

	if (len <= 0)
		return 0;

	res = _tarReadRaw(th->AH, buf, len, th, NULL);

	th->pos += res;

	return res;
}

P
Peter Eisentraut 已提交
528 529
static size_t
tarWrite(const void *buf, size_t len, TAR_MEMBER *th)
P
Philip Warner 已提交
530
{
P
Peter Eisentraut 已提交
531
	size_t		res;
P
Philip Warner 已提交
532 533

	if (th->zFH != 0)
B
Bruce Momjian 已提交
534
		res = GZWRITE((void *) buf, 1, len, th->zFH);
P
Philip Warner 已提交
535 536 537
	else
		res = fwrite(buf, 1, len, th->nFH);

538
	if (res != len)
539
		die_horribly(th->AH, modulename,
P
Peter Eisentraut 已提交
540 541
					 "could not write to tar member (wrote %lu, attempted %lu)\n",
					 (unsigned long) res, (unsigned long) len);
542

P
Philip Warner 已提交
543 544 545 546
	th->pos += res;
	return res;
}

P
Peter Eisentraut 已提交
547 548
static size_t
_WriteData(ArchiveHandle *AH, const void *data, size_t dLen)
P
Philip Warner 已提交
549
{
B
Bruce Momjian 已提交
550
	lclTocEntry *tctx = (lclTocEntry *) AH->currToc->formatData;
P
Philip Warner 已提交
551

B
Bruce Momjian 已提交
552
	dLen = tarWrite((void *) data, dLen, tctx->TH);
P
Philip Warner 已提交
553

B
Bruce Momjian 已提交
554
	return dLen;
P
Philip Warner 已提交
555 556
}

B
Bruce Momjian 已提交
557 558
static void
_EndData(ArchiveHandle *AH, TocEntry *te)
P
Philip Warner 已提交
559
{
B
Bruce Momjian 已提交
560
	lclTocEntry *tctx = (lclTocEntry *) te->formatData;
P
Philip Warner 已提交
561

B
Bruce Momjian 已提交
562 563 564
	/* Close the file */
	tarClose(AH, tctx->TH);
	tctx->TH = NULL;
P
Philip Warner 已提交
565 566
}

B
Bruce Momjian 已提交
567 568
/*
 * Print data for a given file
P
Philip Warner 已提交
569
 */
B
Bruce Momjian 已提交
570 571
static void
_PrintFileData(ArchiveHandle *AH, char *filename, RestoreOptions *ropt)
P
Philip Warner 已提交
572
{
B
Bruce Momjian 已提交
573 574
	lclContext *ctx = (lclContext *) AH->formatData;
	char		buf[4096];
P
Peter Eisentraut 已提交
575
	size_t		cnt;
B
Bruce Momjian 已提交
576
	TAR_MEMBER *th;
P
Philip Warner 已提交
577

B
Bruce Momjian 已提交
578
	if (!filename)
P
Philip Warner 已提交
579 580 581 582 583
		return;

	th = tarOpen(AH, filename, 'r');
	ctx->FH = th;

B
Bruce Momjian 已提交
584 585
	while ((cnt = tarRead(buf, 4095, th)) > 0)
	{
P
Philip Warner 已提交
586 587
		buf[cnt] = '\0';
		ahwrite(buf, 1, cnt, AH);
B
Bruce Momjian 已提交
588
	}
P
Philip Warner 已提交
589

B
Bruce Momjian 已提交
590
	tarClose(AH, th);
P
Philip Warner 已提交
591 592 593 594 595 596
}


/*
 * Print data for a given TOC entry
*/
B
Bruce Momjian 已提交
597 598
static void
_PrintTocData(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt)
P
Philip Warner 已提交
599
{
B
Bruce Momjian 已提交
600 601 602
	lclContext *ctx = (lclContext *) AH->formatData;
	lclTocEntry *tctx = (lclTocEntry *) te->formatData;
	char	   *tmpCopy;
P
Peter Eisentraut 已提交
603
	size_t		i,
B
Bruce Momjian 已提交
604 605 606 607
				pos1,
				pos2;

	if (!tctx->filename)
P
Philip Warner 已提交
608 609 610 611 612 613 614 615 616 617 618 619
		return;

	if (ctx->isSpecialScript)
	{
		if (!te->copyStmt)
			return;

		/* Abort the default COPY */
		ahprintf(AH, "\\.\n");

		/* Get a copy of the COPY statement and clean it up */
		tmpCopy = strdup(te->copyStmt);
B
Bruce Momjian 已提交
620
		for (i = 0; i < strlen(tmpCopy); i++)
621
			tmpCopy[i] = tolower((unsigned char) tmpCopy[i]);
P
Philip Warner 已提交
622 623

		/*
B
Bruce Momjian 已提交
624 625
		 * This is very nasty; we don't know if the archive used WITH
		 * OIDS, so we search the string for it in a paranoid sort of way.
P
Philip Warner 已提交
626 627
		 */
		if (strncmp(tmpCopy, "copy ", 5) != 0)
628 629
			die_horribly(AH, modulename,
						 "bad COPY statement - could not find \"copy\" in string \"%s\"\n", tmpCopy);
P
Philip Warner 已提交
630 631 632 633

		pos1 = 5;
		for (pos1 = 5; pos1 < strlen(tmpCopy); pos1++)
			if (tmpCopy[pos1] != ' ')
B
Bruce Momjian 已提交
634
				break;
P
Philip Warner 已提交
635 636 637

		if (tmpCopy[pos1] == '"')
			pos1 += 2;
B
Bruce Momjian 已提交
638

639
		pos1 += strlen(te->tag);
P
Philip Warner 已提交
640

B
Bruce Momjian 已提交
641
		for (pos2 = pos1; pos2 < strlen(tmpCopy); pos2++)
P
Philip Warner 已提交
642 643 644 645
			if (strncmp(&tmpCopy[pos2], "from stdin", 10) == 0)
				break;

		if (pos2 >= strlen(tmpCopy))
646
			die_horribly(AH, modulename,
P
Peter Eisentraut 已提交
647 648
						 "bad COPY statement - could not find \"from stdin\" in string \"%s\" starting at position %lu\n",
						 tmpCopy, (unsigned long) pos1);
P
Philip Warner 已提交
649

B
Bruce Momjian 已提交
650 651
		ahwrite(tmpCopy, 1, pos2, AH);	/* 'copy "table" [with oids]' */
		ahprintf(AH, " from '$$PATH$$/%s' %s", tctx->filename, &tmpCopy[pos2 + 10]);
P
Philip Warner 已提交
652 653 654 655 656 657 658 659 660 661

		return;
	}

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

B
Bruce Momjian 已提交
662 663
static void
_LoadBlobs(ArchiveHandle *AH, RestoreOptions *ropt)
P
Philip Warner 已提交
664
{
665
	Oid			oid;
B
Bruce Momjian 已提交
666 667
	lclContext *ctx = (lclContext *) AH->formatData;
	TAR_MEMBER *th;
P
Peter Eisentraut 已提交
668
	size_t		cnt;
B
Bruce Momjian 已提交
669
	char		buf[4096];
P
Philip Warner 已提交
670

671 672
	StartRestoreBlobs(AH);

673
	th = tarOpen(AH, NULL, 'r');	/* Open next file */
P
Philip Warner 已提交
674 675 676 677
	while (th != NULL)
	{
		ctx->FH = th;

678
		if (strncmp(th->targetFile, "blob_", 5) == 0)
P
Philip Warner 已提交
679
		{
680 681 682 683
			oid = atooid(&th->targetFile[5]);
			if (oid != 0)
			{
				ahlog(AH, 1, "restoring large object OID %u\n", oid);
P
Philip Warner 已提交
684

685
				StartRestoreBlob(AH, oid);
P
Philip Warner 已提交
686

687 688 689 690 691 692
				while ((cnt = tarRead(buf, 4095, th)) > 0)
				{
					buf[cnt] = '\0';
					ahwrite(buf, 1, cnt, AH);
				}
				EndRestoreBlob(AH, oid);
P
Philip Warner 已提交
693 694 695 696 697 698 699 700
			}
		}

		tarClose(AH, th);

		th = tarOpen(AH, NULL, 'r');
	}

701 702
	EndRestoreBlobs(AH);

P
Philip Warner 已提交
703 704 705
}


B
Bruce Momjian 已提交
706 707
static int
_WriteByte(ArchiveHandle *AH, const int i)
P
Philip Warner 已提交
708
{
B
Bruce Momjian 已提交
709 710 711
	lclContext *ctx = (lclContext *) AH->formatData;
	int			res;
	char		b = i;			/* Avoid endian problems */
P
Philip Warner 已提交
712

B
Bruce Momjian 已提交
713 714
	res = tarWrite(&b, 1, ctx->FH);
	if (res != EOF)
P
Philip Warner 已提交
715
		ctx->filePos += res;
B
Bruce Momjian 已提交
716
	return res;
P
Philip Warner 已提交
717 718
}

B
Bruce Momjian 已提交
719 720
static int
_ReadByte(ArchiveHandle *AH)
P
Philip Warner 已提交
721
{
B
Bruce Momjian 已提交
722 723 724
	lclContext *ctx = (lclContext *) AH->formatData;
	int			res;
	char		c = '\0';
P
Philip Warner 已提交
725

B
Bruce Momjian 已提交
726 727
	res = tarRead(&c, 1, ctx->FH);
	if (res != EOF)
P
Philip Warner 已提交
728
		ctx->filePos += res;
B
Bruce Momjian 已提交
729
	return c;
P
Philip Warner 已提交
730 731
}

P
Peter Eisentraut 已提交
732 733
static size_t
_WriteBuf(ArchiveHandle *AH, const void *buf, size_t len)
P
Philip Warner 已提交
734
{
B
Bruce Momjian 已提交
735
	lclContext *ctx = (lclContext *) AH->formatData;
P
Peter Eisentraut 已提交
736
	size_t		res;
P
Philip Warner 已提交
737

B
Bruce Momjian 已提交
738 739 740
	res = tarWrite((void *) buf, len, ctx->FH);
	ctx->filePos += res;
	return res;
P
Philip Warner 已提交
741 742
}

P
Peter Eisentraut 已提交
743 744
static size_t
_ReadBuf(ArchiveHandle *AH, void *buf, size_t len)
P
Philip Warner 已提交
745
{
B
Bruce Momjian 已提交
746
	lclContext *ctx = (lclContext *) AH->formatData;
P
Peter Eisentraut 已提交
747
	size_t		res;
P
Philip Warner 已提交
748

B
Bruce Momjian 已提交
749 750 751
	res = tarRead(buf, len, ctx->FH);
	ctx->filePos += res;
	return res;
P
Philip Warner 已提交
752 753
}

B
Bruce Momjian 已提交
754 755
static void
_CloseArchive(ArchiveHandle *AH)
P
Philip Warner 已提交
756
{
B
Bruce Momjian 已提交
757 758 759 760 761
	lclContext *ctx = (lclContext *) AH->formatData;
	TAR_MEMBER *th;
	RestoreOptions *ropt;
	int			savVerbose,
				i;
P
Philip Warner 已提交
762

B
Bruce Momjian 已提交
763 764
	if (AH->mode == archModeWrite)
	{
P
Philip Warner 已提交
765 766 767 768 769 770 771
		/*
		 * Write the Header & TOC to the archive FIRST
		 */
		th = tarOpen(AH, "toc.dat", 'w');
		ctx->FH = th;
		WriteHead(AH);
		WriteToc(AH);
B
Bruce Momjian 已提交
772
		tarClose(AH, th);		/* Not needed any more */
P
Philip Warner 已提交
773 774 775 776 777 778

		/*
		 * Now send the data (tables & blobs)
		 */
		WriteDataChunks(AH);

B
Bruce Momjian 已提交
779 780 781
		/*
		 * Now this format wants to append a script which does a full
		 * restore if the files have been extracted.
P
Philip Warner 已提交
782 783 784
		 */
		th = tarOpen(AH, "restore.sql", 'w');
		tarPrintf(AH, th, "create temporary table pgdump_restore_path(p text);\n");
B
Bruce Momjian 已提交
785 786 787 788 789 790 791 792 793 794
		tarPrintf(AH, th, "--\n"
				  "-- NOTE:\n"
				  "--\n"
			 "-- File paths need to be edited. Search for $$PATH$$ and\n"
			  "-- replace it with the path to the directory containing\n"
				  "-- the extracted data files.\n"
				  "--\n"
				  "-- Edit the following to match the path where the\n"
				  "-- tar archive has been extracted.\n"
				  "--\n");
P
Philip Warner 已提交
795 796 797
		tarPrintf(AH, th, "insert into pgdump_restore_path values('/tmp');\n\n");

		AH->CustomOutPtr = _scriptOut;
B
Bruce Momjian 已提交
798

P
Philip Warner 已提交
799 800 801 802 803 804
		ctx->isSpecialScript = 1;
		ctx->scriptTH = th;

		ropt = NewRestoreOptions();
		ropt->dropSchema = 1;
		ropt->compression = 0;
805
		ropt->superuser = NULL;
806
		ropt->suppressDumpWarnings = true;
P
Philip Warner 已提交
807 808 809 810

		savVerbose = AH->public.verbose;
		AH->public.verbose = 0;

B
Bruce Momjian 已提交
811
		RestoreArchive((Archive *) AH, ropt);
P
Philip Warner 已提交
812 813 814 815

		AH->public.verbose = savVerbose;

		tarClose(AH, th);
816 817

		/* Add a block of NULLs since it's de-rigeur. */
B
Bruce Momjian 已提交
818
		for (i = 0; i < 512; i++)
819
		{
820
			if (fputc(0, ctx->tarFH) == EOF)
821
				die_horribly(AH, modulename,
822
				   "could not write null block at end of tar archive\n");
823 824
		}

B
Bruce Momjian 已提交
825
	}
P
Philip Warner 已提交
826

B
Bruce Momjian 已提交
827
	AH->FH = NULL;
P
Philip Warner 已提交
828 829
}

P
Peter Eisentraut 已提交
830 831
static size_t
_scriptOut(ArchiveHandle *AH, const void *buf, size_t len)
P
Philip Warner 已提交
832
{
B
Bruce Momjian 已提交
833 834
	lclContext *ctx = (lclContext *) AH->formatData;

P
Philip Warner 已提交
835 836 837 838 839 840 841 842
	return tarWrite(buf, len, ctx->scriptTH);
}

/*
 * BLOB support
 */

/*
B
Bruce Momjian 已提交
843
 * Called by the archiver when starting to save all BLOB DATA (not schema).
P
Philip Warner 已提交
844
 * This routine should save whatever format-specific information is needed
B
Bruce Momjian 已提交
845
 * to read the BLOBs back into memory.
P
Philip Warner 已提交
846 847 848 849 850 851
 *
 * It is called just prior to the dumper's DataDumper routine.
 *
 * Optional, but strongly recommended.
 *
 */
B
Bruce Momjian 已提交
852 853
static void
_StartBlobs(ArchiveHandle *AH, TocEntry *te)
P
Philip Warner 已提交
854
{
B
Bruce Momjian 已提交
855 856
	lclContext *ctx = (lclContext *) AH->formatData;
	char		fname[K_STD_BUF_SIZE];
P
Philip Warner 已提交
857 858 859 860 861 862 863 864 865 866 867 868 869

	sprintf(fname, "blobs.toc");
	ctx->blobToc = tarOpen(AH, fname, 'w');

}

/*
 * Called by the archiver when the dumper calls StartBlob.
 *
 * Mandatory.
 *
 * Must save the passed OID for retrieval at restore-time.
 */
B
Bruce Momjian 已提交
870
static void
871
_StartBlob(ArchiveHandle *AH, TocEntry *te, Oid oid)
P
Philip Warner 已提交
872
{
B
Bruce Momjian 已提交
873 874 875 876
	lclContext *ctx = (lclContext *) AH->formatData;
	lclTocEntry *tctx = (lclTocEntry *) te->formatData;
	char		fname[255];
	char	   *sfx;
P
Philip Warner 已提交
877

B
Bruce Momjian 已提交
878
	if (oid == 0)
879
		die_horribly(AH, modulename, "invalid OID for large object (%u)\n", oid);
P
Philip Warner 已提交
880 881 882 883 884 885

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

886
	sprintf(fname, "blob_%u.dat%s", oid, sfx);
P
Philip Warner 已提交
887

888
	tarPrintf(AH, ctx->blobToc, "%u %s\n", oid, fname);
P
Philip Warner 已提交
889 890 891 892 893 894 895 896 897 898 899

	tctx->TH = tarOpen(AH, fname, 'w');

}

/*
 * Called by the archiver when the dumper calls EndBlob.
 *
 * Optional.
 *
 */
B
Bruce Momjian 已提交
900
static void
901
_EndBlob(ArchiveHandle *AH, TocEntry *te, Oid oid)
P
Philip Warner 已提交
902
{
B
Bruce Momjian 已提交
903
	lclTocEntry *tctx = (lclTocEntry *) te->formatData;
P
Philip Warner 已提交
904 905 906 907 908

	tarClose(AH, tctx->TH);
}

/*
B
Bruce Momjian 已提交
909
 * Called by the archiver when finishing saving all BLOB DATA.
P
Philip Warner 已提交
910 911 912 913
 *
 * Optional.
 *
 */
B
Bruce Momjian 已提交
914 915
static void
_EndBlobs(ArchiveHandle *AH, TocEntry *te)
P
Philip Warner 已提交
916
{
B
Bruce Momjian 已提交
917 918
	lclContext *ctx = (lclContext *) AH->formatData;

P
Philip Warner 已提交
919
	/* Write out a fake zero OID to mark end-of-blobs. */
B
Bruce Momjian 已提交
920
	/* WriteInt(AH, 0); */
P
Philip Warner 已提交
921 922 923 924 925 926 927 928 929 930 931 932

	tarClose(AH, ctx->blobToc);

}



/*------------
 * TAR Support
 *------------
 */

B
Bruce Momjian 已提交
933 934
static int
tarPrintf(ArchiveHandle *AH, TAR_MEMBER *th, const char *fmt,...)
P
Philip Warner 已提交
935
{
B
Bruce Momjian 已提交
936
	char	   *p = NULL;
P
Philip Warner 已提交
937
	va_list		ap;
P
Peter Eisentraut 已提交
938
	size_t		bSize = strlen(fmt) + 256;		/* Should be enough */
P
Philip Warner 已提交
939 940
	int			cnt = -1;

B
Bruce Momjian 已提交
941 942 943 944 945 946 947 948 949 950
	/*
	 * This is paranoid: deal with the possibility that vsnprintf is
	 * willing to ignore trailing null
	 */

	/*
	 * or returns > 0 even if string does not fit. It may be the case that
	 * it returns cnt = bufsize
	 */
	while (cnt < 0 || cnt >= (bSize - 1))
951
	{
B
Bruce Momjian 已提交
952 953
		if (p != NULL)
			free(p);
P
Philip Warner 已提交
954
		bSize *= 2;
B
Bruce Momjian 已提交
955
		p = (char *) malloc(bSize);
P
Philip Warner 已提交
956
		if (p == NULL)
957
			die_horribly(AH, modulename, "out of memory\n");
958
		va_start(ap, fmt);
P
Philip Warner 已提交
959
		cnt = vsnprintf(p, bSize, fmt, ap);
960
		va_end(ap);
P
Philip Warner 已提交
961 962 963 964 965 966
	}
	cnt = tarWrite(p, cnt, th);
	free(p);
	return cnt;
}

B
Bruce Momjian 已提交
967 968
static int
_tarChecksum(char *header)
P
Philip Warner 已提交
969
{
B
Bruce Momjian 已提交
970 971 972
	int			i,
				sum;

P
Philip Warner 已提交
973
	sum = 0;
B
Bruce Momjian 已提交
974
	for (i = 0; i < 512; i++)
P
Philip Warner 已提交
975 976
		if (i < 148 || i >= 156)
			sum += 0xFF & header[i];
B
Bruce Momjian 已提交
977
	return sum + 256;			/* Assume 8 blanks in checksum field */
P
Philip Warner 已提交
978 979
}

B
Bruce Momjian 已提交
980 981
int
isValidTarHeader(char *header)
P
Philip Warner 已提交
982
{
B
Bruce Momjian 已提交
983 984
	int			sum;
	int			chk = _tarChecksum(header);
P
Philip Warner 已提交
985 986 987 988 989 990 991

	sscanf(&header[148], "%8o", &sum);

	return (sum == chk && strncmp(&header[257], "ustar  ", 7) == 0);
}

/* Given the member, write the TAR header & copy the file */
B
Bruce Momjian 已提交
992 993
static void
_tarAddFile(ArchiveHandle *AH, TAR_MEMBER *th)
P
Philip Warner 已提交
994
{
B
Bruce Momjian 已提交
995
	lclContext *ctx = (lclContext *) AH->formatData;
996
	FILE	   *tmp = th->tmpFH;	/* Grab it for convenience */
P
Philip Warner 已提交
997
	char		buf[32768];
P
Peter Eisentraut 已提交
998 999 1000 1001
	size_t		cnt;
	off_t		len = 0;
	size_t		res;
	size_t		i,
B
Bruce Momjian 已提交
1002
				pad;
P
Philip Warner 已提交
1003 1004 1005 1006

	/*
	 * Find file len & go back to start.
	 */
P
Peter Eisentraut 已提交
1007 1008 1009
	fseeko(tmp, 0, SEEK_END);
	th->fileLen = ftello(tmp);
	fseeko(tmp, 0, SEEK_SET);
P
Philip Warner 已提交
1010 1011 1012

	_tarWriteHeader(th);

B
Bruce Momjian 已提交
1013
	while ((cnt = fread(&buf[0], 1, 32767, tmp)) > 0)
P
Philip Warner 已提交
1014
	{
1015
		res = fwrite(&buf[0], 1, cnt, th->tarFH);
B
Bruce Momjian 已提交
1016
		if (res != cnt)
P
Peter Eisentraut 已提交
1017 1018 1019
			die_horribly(AH, modulename,
						 "write error appending to tar archive (wrote %lu, attempted %lu)\n",
						 (unsigned long) res, (unsigned long) cnt);
1020
		len += res;
P
Philip Warner 已提交
1021 1022
	}

B
Bruce Momjian 已提交
1023
	if (fclose(tmp) != 0)		/* This *should* delete it... */
1024
		die_horribly(AH, modulename, "could not close tar member: %s\n", strerror(errno));
P
Philip Warner 已提交
1025 1026

	if (len != th->fileLen)
P
Peter Eisentraut 已提交
1027 1028
		die_horribly(AH, modulename, "actual file length (" INT64_FORMAT ") does not match expected (" INT64_FORMAT ")\n",
					 (int64) len, (int64) th->pos);
P
Philip Warner 已提交
1029 1030

	pad = ((len + 511) & ~511) - len;
B
Bruce Momjian 已提交
1031
	for (i = 0; i < pad; i++)
1032
	{
B
Bruce Momjian 已提交
1033
		if (fputc('\0', th->tarFH) == EOF)
1034
			die_horribly(AH, modulename, "could not output padding at end of tar member\n");
B
Bruce Momjian 已提交
1035
	}
P
Philip Warner 已提交
1036 1037 1038 1039 1040

	ctx->tarFHpos += len + pad;
}

/* Locate the file in the archive, read header and position to data */
B
Bruce Momjian 已提交
1041 1042
static TAR_MEMBER *
_tarPositionTo(ArchiveHandle *AH, const char *filename)
P
Philip Warner 已提交
1043
{
B
Bruce Momjian 已提交
1044 1045 1046 1047
	lclContext *ctx = (lclContext *) AH->formatData;
	TAR_MEMBER *th = calloc(1, sizeof(TAR_MEMBER));
	char		c;
	char		header[512];
P
Peter Eisentraut 已提交
1048
	size_t		i,
B
Bruce Momjian 已提交
1049
				len,
P
Peter Eisentraut 已提交
1050 1051
				blks;
	int			id;
P
Philip Warner 已提交
1052 1053 1054 1055 1056 1057

	th->AH = AH;

	/* Go to end of current file, if any */
	if (ctx->tarFHpos != 0)
	{
P
Peter Eisentraut 已提交
1058 1059
		ahlog(AH, 4, "moving from position " INT64_FORMAT " to next member at file position " INT64_FORMAT "\n",
			  (int64) ctx->tarFHpos, (int64) ctx->tarNextMember);
P
Philip Warner 已提交
1060 1061 1062 1063 1064

		while (ctx->tarFHpos < ctx->tarNextMember)
			_tarReadRaw(AH, &c, 1, NULL, ctx->tarFH);
	}

P
Peter Eisentraut 已提交
1065
	ahlog(AH, 4, "now at file position " INT64_FORMAT "\n", (int64) ctx->tarFHpos);
P
Philip Warner 已提交
1066 1067 1068 1069 1070 1071 1072

	/* We are at the start of the file. or at the next member */

	/* Get the header */
	if (!_tarGetHeader(AH, th))
	{
		if (filename)
1073
			die_horribly(AH, modulename, "could not find header for file %s in tar archive\n", filename);
B
Bruce Momjian 已提交
1074 1075
		else
/* We're just scanning the archibe for the next file, so return null */
P
Philip Warner 已提交
1076 1077 1078 1079 1080 1081
		{
			free(th);
			return NULL;
		}
	}

B
Bruce Momjian 已提交
1082
	while (filename != NULL && strcmp(th->targetFile, filename) != 0)
P
Philip Warner 已提交
1083
	{
1084
		ahlog(AH, 4, "skipping tar member %s\n", th->targetFile);
P
Philip Warner 已提交
1085 1086 1087

		id = atoi(th->targetFile);
		if ((TocIDRequired(AH, id, AH->ropt) & 2) != 0)
1088
			die_horribly(AH, modulename, "dumping data out of order is not supported in this archive format: "
1089
			"%s is required, but comes before %s in the archive file.\n",
1090
						 th->targetFile, filename);
P
Philip Warner 已提交
1091 1092

		/* Header doesn't match, so read to next header */
B
Bruce Momjian 已提交
1093 1094
		len = ((th->fileLen + 511) & ~511);		/* Padded length */
		blks = len >> 9;		/* # of 512 byte blocks */
P
Philip Warner 已提交
1095

B
Bruce Momjian 已提交
1096
		for (i = 0; i < blks; i++)
P
Philip Warner 已提交
1097 1098 1099
			_tarReadRaw(AH, &header[0], 512, NULL, ctx->tarFH);

		if (!_tarGetHeader(AH, th))
1100
			die_horribly(AH, modulename, "could not find header for file %s in tar archive\n", filename);
P
Philip Warner 已提交
1101 1102 1103 1104 1105 1106 1107 1108 1109 1110

	}

	ctx->tarNextMember = ctx->tarFHpos + ((th->fileLen + 511) & ~511);
	th->pos = 0;

	return th;
}

/* Read & verify a header */
B
Bruce Momjian 已提交
1111 1112
static int
_tarGetHeader(ArchiveHandle *AH, TAR_MEMBER *th)
P
Philip Warner 已提交
1113
{
B
Bruce Momjian 已提交
1114 1115
	lclContext *ctx = (lclContext *) AH->formatData;
	char		h[512];
1116
	char		tag[100];
B
Bruce Momjian 已提交
1117 1118
	int			sum,
				chk;
P
Peter Eisentraut 已提交
1119 1120
	size_t		len;
	off_t		hPos;
B
Bruce Momjian 已提交
1121 1122
	int			i;
	bool		gotBlock = false;
P
Philip Warner 已提交
1123

1124 1125
	while (!gotBlock)
	{
1126
#if 0
P
Peter Eisentraut 已提交
1127
		if (ftello(ctx->tarFH) != ctx->tarFHpos)
1128
			die_horribly(AH, modulename,
P
Peter Eisentraut 已提交
1129 1130
						 "mismatch in actual vs. predicted file position (" INT64_FORMAT " vs. " INT64_FORMAT ")\n",
						 (int64) ftello(ctx->tarFH), (int64) ctx->tarFHpos);
1131
#endif
P
Philip Warner 已提交
1132

1133 1134
		/* Save the pos for reporting purposes */
		hPos = ctx->tarFHpos;
P
Philip Warner 已提交
1135

1136 1137
		/* Read a 512 byte block, return EOF, exit if short */
		len = _tarReadRaw(AH, &h[0], 512, NULL, ctx->tarFH);
B
Bruce Momjian 已提交
1138
		if (len == 0)			/* EOF */
1139 1140 1141
			return 0;

		if (len != 512)
P
Peter Eisentraut 已提交
1142 1143 1144
			die_horribly(AH, modulename,
						 "incomplete tar header found (%lu bytes)\n",
						 (unsigned long) len);
1145 1146 1147

		/* Calc checksum */
		chk = _tarChecksum(&h[0]);
P
Philip Warner 已提交
1148

1149
		/*
B
Bruce Momjian 已提交
1150 1151
		 * If the checksum failed, see if it is a null block. If so, then
		 * just try with next block...
1152 1153
		 */

B
Bruce Momjian 已提交
1154
		if (chk == sum)
1155
			gotBlock = true;
B
Bruce Momjian 已提交
1156 1157 1158
		else
		{
			for (i = 0; i < 512; i++)
1159
			{
B
Bruce Momjian 已提交
1160
				if (h[0] != 0)
1161
				{
B
Bruce Momjian 已提交
1162
					gotBlock = true;
1163 1164 1165 1166 1167
					break;
				}
			}
		}
	}
P
Philip Warner 已提交
1168

1169
	sscanf(&h[0], "%99s", &tag[0]);
P
Philip Warner 已提交
1170 1171 1172
	sscanf(&h[124], "%12o", &len);
	sscanf(&h[148], "%8o", &sum);

P
Peter Eisentraut 已提交
1173 1174
	ahlog(AH, 3, "TOC Entry %s at " INT64_FORMAT " (length %lu, checksum %d)\n",
		  &tag[0], (int64) hPos, (unsigned long) len, sum);
P
Philip Warner 已提交
1175 1176

	if (chk != sum)
1177 1178
		die_horribly(AH, modulename,
					 "corrupt tar header found in %s "
P
Peter Eisentraut 已提交
1179 1180
					 "(expected %d, computed %d) file position " INT64_FORMAT "\n",
					 &tag[0], sum, chk, (int64) ftello(ctx->tarFH));
P
Philip Warner 已提交
1181

1182
	th->targetFile = strdup(tag);
P
Philip Warner 已提交
1183 1184 1185 1186 1187
	th->fileLen = len;

	return 1;
}

B
Bruce Momjian 已提交
1188 1189
static void
_tarWriteHeader(TAR_MEMBER *th)
P
Philip Warner 已提交
1190 1191 1192 1193 1194 1195
{
	char		h[512];
	int			i;
	int			lastSum = 0;
	int			sum;

B
Bruce Momjian 已提交
1196
	for (i = 0; i < 512; i++)
P
Philip Warner 已提交
1197 1198 1199 1200 1201 1202 1203 1204 1205
		h[i] = '\0';

	/* Name 100 */
	sprintf(&h[0], "%.99s", th->targetFile);

	/* Mode 8 */
	sprintf(&h[100], "100600 ");

	/* User ID 8 */
P
Philip Warner 已提交
1206
	sprintf(&h[108], " 04000 ");
P
Philip Warner 已提交
1207 1208

	/* Group 8 */
P
Philip Warner 已提交
1209
	sprintf(&h[116], " 02000 ");
P
Philip Warner 已提交
1210 1211

	/* File size 12 */
P
Peter Eisentraut 已提交
1212 1213
	/* FIXME: This goes only up to 2^30. -- What about larger files? */
	sprintf(&h[124], "%10o ", (unsigned int) th->fileLen);
P
Philip Warner 已提交
1214 1215

	/* Mod Time 12 */
B
Bruce Momjian 已提交
1216
	sprintf(&h[136], "%10o ", (int) time(NULL));
P
Philip Warner 已提交
1217 1218

	/* Checksum 8 */
P
Philip Warner 已提交
1219
	sprintf(&h[148], "%6o ", lastSum);
P
Philip Warner 已提交
1220

P
Philip Warner 已提交
1221 1222 1223
	/* Type 1 */
	/* sprintf(&h[156], "%c", LF_NORMAL); */
	sprintf(&h[156], "0");
P
Philip Warner 已提交
1224

1225
	/* Link tag 100 (NULL) */
P
Philip Warner 已提交
1226 1227 1228 1229

	/* Magic 8 */
	sprintf(&h[257], "ustar  ");

B
Bruce Momjian 已提交
1230 1231 1232
	/*
	 * GNU Version... sprintf(&h[257], "ustar"); sprintf(&h[263], "00");
	 */
P
Philip Warner 已提交
1233

P
Philip Warner 已提交
1234
	/* User 32 */
B
Bruce Momjian 已提交
1235 1236
	sprintf(&h[265], "%.31s", "");		/* How do I get username reliably?
										 * Do I need to? */
P
Philip Warner 已提交
1237 1238

	/* Group 32 */
B
Bruce Momjian 已提交
1239 1240
	sprintf(&h[297], "%.31s", "");		/* How do I get group reliably? Do
										 * I need to? */
P
Philip Warner 已提交
1241 1242

	/* Maj Dev 8 */
P
Philip Warner 已提交
1243
	/* sprintf(&h[329], "%6o ", 0); */
P
Philip Warner 已提交
1244 1245

	/* Min Dev */
P
Philip Warner 已提交
1246
	/* sprintf(&h[337], "%6o ", 0); */
P
Philip Warner 已提交
1247 1248


B
Bruce Momjian 已提交
1249
	while ((sum = _tarChecksum(h)) != lastSum)
P
Philip Warner 已提交
1250
	{
P
Philip Warner 已提交
1251
		sprintf(&h[148], "%6o ", sum);
P
Philip Warner 已提交
1252 1253 1254
		lastSum = sum;
	}

B
Bruce Momjian 已提交
1255
	if (fwrite(h, 1, 512, th->tarFH) != 512)
1256
		die_horribly(th->AH, modulename, "unable to write tar header\n");
1257

P
Philip Warner 已提交
1258
}