pg_backup_tar.c 27.2 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
19
 *		$Header: /cvsroot/pgsql/src/bin/pg_dump/pg_backup_tar.c,v 1.20 2001/10/28 06:25:58 momjian Exp $
P
Philip Warner 已提交
20 21 22
 *
 * Modifications - 28-Jun-2000 - pjw@rhyme.com.au
 *
B
Bruce Momjian 已提交
23
 *	Initial version.
P
Philip Warner 已提交
24
 *
25 26
 * Modifications - 04-Jan-2001 - pjw@rhyme.com.au
 *
B
Bruce Momjian 已提交
27
 *	  - Check results of IO routines more carefully.
28
 *
P
Philip Warner 已提交
29 30 31
 *-------------------------------------------------------------------------
 */

32 33 34 35
#include "pg_backup.h"
#include "pg_backup_archiver.h"
#include "pg_backup_tar.h"

P
Philip Warner 已提交
36 37 38 39 40
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>

B
Bruce Momjian 已提交
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
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);
56 57
static void _StartBlob(ArchiveHandle *AH, TocEntry *te, Oid oid);
static void _EndBlob(ArchiveHandle *AH, TocEntry *te, Oid oid);
B
Bruce Momjian 已提交
58
static void _EndBlobs(ArchiveHandle *AH, TocEntry *te);
P
Philip Warner 已提交
59 60 61 62 63

#define K_STD_BUF_SIZE 1024


#ifdef HAVE_LIBZ
B
Bruce Momjian 已提交
64 65 66
 /* typedef gzFile	 ThingFile; */
typedef FILE ThingFile;

P
Philip Warner 已提交
67
#else
B
Bruce Momjian 已提交
68
typedef FILE ThingFile;
P
Philip Warner 已提交
69 70
#endif

B
Bruce Momjian 已提交
71 72 73 74 75 76 77 78 79 80 81
typedef struct
{
	ThingFile  *zFH;
	FILE	   *nFH;
	FILE	   *tarFH;
	FILE	   *tmpFH;
	char	   *targetFile;
	char		mode;
	int			pos;
	int			fileLen;
	ArchiveHandle *AH;
P
Philip Warner 已提交
82 83
} TAR_MEMBER;

B
Bruce Momjian 已提交
84 85
typedef struct
{
P
Philip Warner 已提交
86
	int			hasSeek;
B
Bruce Momjian 已提交
87 88 89
	int			filePos;
	TAR_MEMBER *blobToc;
	FILE	   *tarFH;
P
Philip Warner 已提交
90 91
	int			tarFHpos;
	int			tarNextMember;
B
Bruce Momjian 已提交
92
	TAR_MEMBER *FH;
P
Philip Warner 已提交
93
	int			isSpecialScript;
B
Bruce Momjian 已提交
94
	TAR_MEMBER *scriptTH;
P
Philip Warner 已提交
95 96
} lclContext;

B
Bruce Momjian 已提交
97 98 99 100
typedef struct
{
	TAR_MEMBER *TH;
	char	   *filename;
P
Philip Warner 已提交
101 102
} lclTocEntry;

103
static char *modulename = gettext_noop("tar archiver");
B
Bruce Momjian 已提交
104 105

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

B
Bruce Momjian 已提交
107 108
static TAR_MEMBER *tarOpen(ArchiveHandle *AH, const char *filename, char mode);
static void tarClose(ArchiveHandle *AH, TAR_MEMBER *TH);
P
Philip Warner 已提交
109 110

#ifdef __NOT_USED__
B
Bruce Momjian 已提交
111
static char *tarGets(char *buf, int len, TAR_MEMBER *th);
P
Philip Warner 已提交
112
#endif
B
Bruce Momjian 已提交
113
static int	tarPrintf(ArchiveHandle *AH, TAR_MEMBER *th, const char *fmt,...);
P
Philip Warner 已提交
114

B
Bruce Momjian 已提交
115 116 117 118 119 120 121 122
static void _tarAddFile(ArchiveHandle *AH, TAR_MEMBER *th);
static int	_tarChecksum(char *th);
static TAR_MEMBER *_tarPositionTo(ArchiveHandle *AH, const char *filename);
static int	tarRead(void *buf, int len, TAR_MEMBER *th);
static int	tarWrite(const void *buf, int len, TAR_MEMBER *th);
static void _tarWriteHeader(TAR_MEMBER *th);
static int	_tarGetHeader(ArchiveHandle *AH, TAR_MEMBER *th);
static int	_tarReadRaw(ArchiveHandle *AH, void *buf, int len, TAR_MEMBER *th, FILE *fh);
P
Philip Warner 已提交
123

B
Bruce Momjian 已提交
124
static int	_scriptOut(ArchiveHandle *AH, const void *buf, int len);
P
Philip Warner 已提交
125 126

/*
B
Bruce Momjian 已提交
127
 *	Initializer
P
Philip Warner 已提交
128
 */
B
Bruce Momjian 已提交
129 130
void
InitArchiveFmt_Tar(ArchiveHandle *AH)
P
Philip Warner 已提交
131
{
B
Bruce Momjian 已提交
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
	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;

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

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

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

P
Philip Warner 已提交
176 177
		ctx->tarFHpos = 0;

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

		ctx->hasSeek = (fseek(ctx->tarFH, 0, SEEK_CUR) == 0);

B
Bruce Momjian 已提交
186
		if (AH->compression < 0 || AH->compression > 9)
P
Philip Warner 已提交
187 188 189 190 191 192
			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 已提交
193 194 195 196
		/*
		 * 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 已提交
197 198
		 */
		if (AH->compression != 0)
199
			die_horribly(NULL, modulename, "compression not supported by tar output format\n");
P
Philip Warner 已提交
200

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

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

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

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

		ctx->tarFHpos = 0;

		ctx->hasSeek = (fseek(ctx->tarFH, 0, SEEK_CUR) == 0);

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

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

}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

#ifdef HAVE_LIBZ

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

#else

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

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

		tm->tmpFH = tmpfile();

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

P
Philip Warner 已提交
362 363 364 365 366 367
#ifdef HAVE_LIBZ

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

B
Bruce Momjian 已提交
371 372
		}
		else
P
Philip Warner 已提交
373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390
			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 已提交
391 392
static void
tarClose(ArchiveHandle *AH, TAR_MEMBER *th)
P
Philip Warner 已提交
393 394 395 396 397
{
	/*
	 * Close the GZ file since we dup'd. This will flush the buffers.
	 */
	if (AH->compression != 0)
398
		if (GZCLOSE(th->zFH) != 0)
399
			die_horribly(AH, modulename, "could not close tar member\n");
P
Philip Warner 已提交
400 401

	if (th->mode == 'w')
B
Bruce Momjian 已提交
402 403 404 405 406
		_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 已提交
407 408
	 */

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

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

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

	/* 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 已提交
431 432
		if (_tarReadRaw(th->AH, &c, 1, th, NULL) <= 0)
		{
P
Philip Warner 已提交
433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448
			eof = 1;
			break;
		}
		buf[cnt++] = c;
	}

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

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

	return s;
}
#endif

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

	avail = AH->lookaheadLen - AH->lookaheadPos;
	if (avail > 0)
	{
		/* We have some lookahead bytes to use */
B
Bruce Momjian 已提交
473
		if (avail >= len)		/* Just use the lookahead buffer */
P
Philip Warner 已提交
474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489
			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 已提交
490
			res = fread(&((char *) buf)[used], 1, len, fh);
P
Philip Warner 已提交
491 492 493
		else if (th)
		{
			if (th->zFH)
B
Bruce Momjian 已提交
494
				res = GZREAD(&((char *) buf)[used], 1, len, th->zFH);
P
Philip Warner 已提交
495
			else
B
Bruce Momjian 已提交
496 497
				res = fread(&((char *) buf)[used], 1, len, th->nFH);
		}
P
Philip Warner 已提交
498
		else
499
			die_horribly(AH, modulename, "neither th nor fh specified in tarReadRaw() (internal error)\n");
P
Philip Warner 已提交
500 501
	}

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

	ctx->tarFHpos += res + used;

	return (res + used);
}
B
Bruce Momjian 已提交
511 512 513

static int
tarRead(void *buf, int len, TAR_MEMBER *th)
P
Philip Warner 已提交
514
{
B
Bruce Momjian 已提交
515
	int			res;
P
Philip Warner 已提交
516 517 518 519 520 521 522 523 524 525 526 527 528 529

	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;
}

B
Bruce Momjian 已提交
530 531
static int
tarWrite(const void *buf, int len, TAR_MEMBER *th)
P
Philip Warner 已提交
532
{
B
Bruce Momjian 已提交
533
	int			res;
P
Philip Warner 已提交
534 535

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

540
	if (res != len)
541 542
		die_horribly(th->AH, modulename,
					 "could not write to tar member (wrote %d, attempted %d)\n", res, len);
543

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

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

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

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

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

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

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

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

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

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

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


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

	if (!tctx->filename)
P
Philip Warner 已提交
609 610 611 612 613 614 615 616 617 618 619 620
		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 已提交
621
		for (i = 0; i < strlen(tmpCopy); i++)
622
			tmpCopy[i] = tolower((unsigned char) tmpCopy[i]);
P
Philip Warner 已提交
623 624

		/*
B
Bruce Momjian 已提交
625 626
		 * 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 已提交
627 628
		 */
		if (strncmp(tmpCopy, "copy ", 5) != 0)
629 630
			die_horribly(AH, modulename,
						 "bad COPY statement - could not find \"copy\" in string \"%s\"\n", tmpCopy);
P
Philip Warner 已提交
631 632 633 634

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

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

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

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

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

B
Bruce Momjian 已提交
651 652
		ahwrite(tmpCopy, 1, pos2, AH);	/* 'copy "table" [with oids]' */
		ahprintf(AH, " from '$$PATH$$/%s' %s", tctx->filename, &tmpCopy[pos2 + 10]);
P
Philip Warner 已提交
653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690

		return;
	}

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

/* static void _getBlobTocEntry(ArchiveHandle* AH, int *oid, char fname[K_STD_BUF_SIZE])
 * {
 *	lclContext*		ctx = (lclContext*)AH->formatData;
 *	char			blobTe[K_STD_BUF_SIZE];
 *	int				fpos;
 *	int				eos;
 *
 *	if (tarGets(&blobTe[0], K_STD_BUF_SIZE - 1, ctx->blobToc) != NULL)
 *	{
 *		*oid = atoi(blobTe);
 *
 *		fpos = strcspn(blobTe, " ");
 *
 *		strncpy(fname, &blobTe[fpos+1], K_STD_BUF_SIZE - 1);
 *
 *		eos = strlen(fname)-1;
 *
 *		if (fname[eos] == '\n')
 *			fname[eos] = '\0';
 *
 *	} else {
 *
 *		*oid = 0;
 *		fname[0] = '\0';
 *	}
 *}
 */

B
Bruce Momjian 已提交
691 692
static void
_LoadBlobs(ArchiveHandle *AH, RestoreOptions *ropt)
P
Philip Warner 已提交
693
{
694
	Oid			oid;
B
Bruce Momjian 已提交
695 696 697 698
	lclContext *ctx = (lclContext *) AH->formatData;
	TAR_MEMBER *th;
	int			cnt;
	char		buf[4096];
P
Philip Warner 已提交
699

700 701
	StartRestoreBlobs(AH);

702
	th = tarOpen(AH, NULL, 'r');	/* Open next file */
P
Philip Warner 已提交
703 704 705 706
	while (th != NULL)
	{
		ctx->FH = th;

707
		oid = (Oid) strtoul(&th->targetFile[5], NULL, 10);
P
Philip Warner 已提交
708

B
Bruce Momjian 已提交
709
		if (strncmp(th->targetFile, "blob_", 5) == 0 && oid != 0)
P
Philip Warner 已提交
710
		{
711
			ahlog(AH, 1, "restoring large object OID %u\n", oid);
P
Philip Warner 已提交
712 713 714

			StartRestoreBlob(AH, oid);

B
Bruce Momjian 已提交
715 716
			while ((cnt = tarRead(buf, 4095, th)) > 0)
			{
P
Philip Warner 已提交
717 718 719 720 721 722 723 724 725 726 727
				buf[cnt] = '\0';
				ahwrite(buf, 1, cnt, AH);
			}
			EndRestoreBlob(AH, oid);
		}

		tarClose(AH, th);

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

728 729
	EndRestoreBlobs(AH);

P
Philip Warner 已提交
730 731 732
}


B
Bruce Momjian 已提交
733 734
static int
_WriteByte(ArchiveHandle *AH, const int i)
P
Philip Warner 已提交
735
{
B
Bruce Momjian 已提交
736 737 738
	lclContext *ctx = (lclContext *) AH->formatData;
	int			res;
	char		b = i;			/* Avoid endian problems */
P
Philip Warner 已提交
739

B
Bruce Momjian 已提交
740 741
	res = tarWrite(&b, 1, ctx->FH);
	if (res != EOF)
P
Philip Warner 已提交
742
		ctx->filePos += res;
B
Bruce Momjian 已提交
743
	return res;
P
Philip Warner 已提交
744 745
}

B
Bruce Momjian 已提交
746 747
static int
_ReadByte(ArchiveHandle *AH)
P
Philip Warner 已提交
748
{
B
Bruce Momjian 已提交
749 750 751
	lclContext *ctx = (lclContext *) AH->formatData;
	int			res;
	char		c = '\0';
P
Philip Warner 已提交
752

B
Bruce Momjian 已提交
753 754
	res = tarRead(&c, 1, ctx->FH);
	if (res != EOF)
P
Philip Warner 已提交
755
		ctx->filePos += res;
B
Bruce Momjian 已提交
756
	return c;
P
Philip Warner 已提交
757 758
}

B
Bruce Momjian 已提交
759 760
static int
_WriteBuf(ArchiveHandle *AH, const void *buf, int len)
P
Philip Warner 已提交
761
{
B
Bruce Momjian 已提交
762 763
	lclContext *ctx = (lclContext *) AH->formatData;
	int			res;
P
Philip Warner 已提交
764

B
Bruce Momjian 已提交
765 766 767
	res = tarWrite((void *) buf, len, ctx->FH);
	ctx->filePos += res;
	return res;
P
Philip Warner 已提交
768 769
}

B
Bruce Momjian 已提交
770 771
static int
_ReadBuf(ArchiveHandle *AH, void *buf, int len)
P
Philip Warner 已提交
772
{
B
Bruce Momjian 已提交
773 774
	lclContext *ctx = (lclContext *) AH->formatData;
	int			res;
P
Philip Warner 已提交
775

B
Bruce Momjian 已提交
776 777 778
	res = tarRead(buf, len, ctx->FH);
	ctx->filePos += res;
	return res;
P
Philip Warner 已提交
779 780
}

B
Bruce Momjian 已提交
781 782
static void
_CloseArchive(ArchiveHandle *AH)
P
Philip Warner 已提交
783
{
B
Bruce Momjian 已提交
784 785 786 787 788
	lclContext *ctx = (lclContext *) AH->formatData;
	TAR_MEMBER *th;
	RestoreOptions *ropt;
	int			savVerbose,
				i;
P
Philip Warner 已提交
789

B
Bruce Momjian 已提交
790 791
	if (AH->mode == archModeWrite)
	{
P
Philip Warner 已提交
792 793 794 795 796 797 798
		/*
		 * Write the Header & TOC to the archive FIRST
		 */
		th = tarOpen(AH, "toc.dat", 'w');
		ctx->FH = th;
		WriteHead(AH);
		WriteToc(AH);
B
Bruce Momjian 已提交
799
		tarClose(AH, th);		/* Not needed any more */
P
Philip Warner 已提交
800 801 802 803 804 805

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

B
Bruce Momjian 已提交
806 807 808
		/*
		 * Now this format wants to append a script which does a full
		 * restore if the files have been extracted.
P
Philip Warner 已提交
809 810 811
		 */
		th = tarOpen(AH, "restore.sql", 'w');
		tarPrintf(AH, th, "create temporary table pgdump_restore_path(p text);\n");
B
Bruce Momjian 已提交
812 813 814 815 816 817 818 819 820 821
		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 已提交
822 823 824
		tarPrintf(AH, th, "insert into pgdump_restore_path values('/tmp');\n\n");

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

P
Philip Warner 已提交
826 827 828 829 830 831
		ctx->isSpecialScript = 1;
		ctx->scriptTH = th;

		ropt = NewRestoreOptions();
		ropt->dropSchema = 1;
		ropt->compression = 0;
832
		ropt->superuser = PQuser(AH->connection);
833
		ropt->suppressDumpWarnings = true;
P
Philip Warner 已提交
834 835 836 837

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

B
Bruce Momjian 已提交
838
		RestoreArchive((Archive *) AH, ropt);
P
Philip Warner 已提交
839 840 841 842

		AH->public.verbose = savVerbose;

		tarClose(AH, th);
843 844

		/* Add a block of NULLs since it's de-rigeur. */
B
Bruce Momjian 已提交
845
		for (i = 0; i < 512; i++)
846
		{
847
			if (fputc(0, ctx->tarFH) == EOF)
848
				die_horribly(AH, modulename,
849
				   "could not write null block at end of tar archive\n");
850 851
		}

B
Bruce Momjian 已提交
852
	}
P
Philip Warner 已提交
853

B
Bruce Momjian 已提交
854
	AH->FH = NULL;
P
Philip Warner 已提交
855 856
}

B
Bruce Momjian 已提交
857 858
static int
_scriptOut(ArchiveHandle *AH, const void *buf, int len)
P
Philip Warner 已提交
859
{
B
Bruce Momjian 已提交
860 861
	lclContext *ctx = (lclContext *) AH->formatData;

P
Philip Warner 已提交
862 863 864 865 866 867 868 869
	return tarWrite(buf, len, ctx->scriptTH);
}

/*
 * BLOB support
 */

/*
B
Bruce Momjian 已提交
870
 * Called by the archiver when starting to save all BLOB DATA (not schema).
P
Philip Warner 已提交
871
 * This routine should save whatever format-specific information is needed
B
Bruce Momjian 已提交
872
 * to read the BLOBs back into memory.
P
Philip Warner 已提交
873 874 875 876 877 878
 *
 * It is called just prior to the dumper's DataDumper routine.
 *
 * Optional, but strongly recommended.
 *
 */
B
Bruce Momjian 已提交
879 880
static void
_StartBlobs(ArchiveHandle *AH, TocEntry *te)
P
Philip Warner 已提交
881
{
B
Bruce Momjian 已提交
882 883
	lclContext *ctx = (lclContext *) AH->formatData;
	char		fname[K_STD_BUF_SIZE];
P
Philip Warner 已提交
884 885 886 887 888 889 890 891 892 893 894 895 896

	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 已提交
897
static void
898
_StartBlob(ArchiveHandle *AH, TocEntry *te, Oid oid)
P
Philip Warner 已提交
899
{
B
Bruce Momjian 已提交
900 901 902 903
	lclContext *ctx = (lclContext *) AH->formatData;
	lclTocEntry *tctx = (lclTocEntry *) te->formatData;
	char		fname[255];
	char	   *sfx;
P
Philip Warner 已提交
904

B
Bruce Momjian 已提交
905
	if (oid == 0)
906
		die_horribly(AH, modulename, "invalid OID for large object (%u)\n", oid);
P
Philip Warner 已提交
907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926

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

	sprintf(fname, "blob_%d.dat%s", oid, sfx);

	tarPrintf(AH, ctx->blobToc, "%d %s\n", oid, fname);

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

}

/*
 * Called by the archiver when the dumper calls EndBlob.
 *
 * Optional.
 *
 */
B
Bruce Momjian 已提交
927
static void
928
_EndBlob(ArchiveHandle *AH, TocEntry *te, Oid oid)
P
Philip Warner 已提交
929
{
B
Bruce Momjian 已提交
930
	lclTocEntry *tctx = (lclTocEntry *) te->formatData;
P
Philip Warner 已提交
931 932 933 934 935

	tarClose(AH, tctx->TH);
}

/*
B
Bruce Momjian 已提交
936
 * Called by the archiver when finishing saving all BLOB DATA.
P
Philip Warner 已提交
937 938 939 940
 *
 * Optional.
 *
 */
B
Bruce Momjian 已提交
941 942
static void
_EndBlobs(ArchiveHandle *AH, TocEntry *te)
P
Philip Warner 已提交
943
{
B
Bruce Momjian 已提交
944 945
	lclContext *ctx = (lclContext *) AH->formatData;

P
Philip Warner 已提交
946
	/* Write out a fake zero OID to mark end-of-blobs. */
B
Bruce Momjian 已提交
947
	/* WriteInt(AH, 0); */
P
Philip Warner 已提交
948 949 950 951 952 953 954 955 956 957 958 959

	tarClose(AH, ctx->blobToc);

}



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

B
Bruce Momjian 已提交
960 961
static int
tarPrintf(ArchiveHandle *AH, TAR_MEMBER *th, const char *fmt,...)
P
Philip Warner 已提交
962
{
B
Bruce Momjian 已提交
963
	char	   *p = NULL;
P
Philip Warner 已提交
964
	va_list		ap;
B
Bruce Momjian 已提交
965
	int			bSize = strlen(fmt) + 256;		/* Should be enough */
P
Philip Warner 已提交
966 967
	int			cnt = -1;

B
Bruce Momjian 已提交
968 969 970 971 972 973 974 975 976 977
	/*
	 * 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))
978
	{
B
Bruce Momjian 已提交
979 980
		if (p != NULL)
			free(p);
P
Philip Warner 已提交
981
		bSize *= 2;
B
Bruce Momjian 已提交
982
		p = (char *) malloc(bSize);
P
Philip Warner 已提交
983
		if (p == NULL)
984
			die_horribly(AH, modulename, "out of memory\n");
985
		va_start(ap, fmt);
P
Philip Warner 已提交
986
		cnt = vsnprintf(p, bSize, fmt, ap);
987
		va_end(ap);
P
Philip Warner 已提交
988 989 990 991 992 993
	}
	cnt = tarWrite(p, cnt, th);
	free(p);
	return cnt;
}

B
Bruce Momjian 已提交
994 995
static int
_tarChecksum(char *header)
P
Philip Warner 已提交
996
{
B
Bruce Momjian 已提交
997 998 999
	int			i,
				sum;

P
Philip Warner 已提交
1000
	sum = 0;
B
Bruce Momjian 已提交
1001
	for (i = 0; i < 512; i++)
P
Philip Warner 已提交
1002 1003
		if (i < 148 || i >= 156)
			sum += 0xFF & header[i];
B
Bruce Momjian 已提交
1004
	return sum + 256;			/* Assume 8 blanks in checksum field */
P
Philip Warner 已提交
1005 1006
}

B
Bruce Momjian 已提交
1007 1008
int
isValidTarHeader(char *header)
P
Philip Warner 已提交
1009
{
B
Bruce Momjian 已提交
1010 1011
	int			sum;
	int			chk = _tarChecksum(header);
P
Philip Warner 已提交
1012 1013 1014 1015 1016 1017 1018

	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 已提交
1019 1020
static void
_tarAddFile(ArchiveHandle *AH, TAR_MEMBER *th)
P
Philip Warner 已提交
1021
{
B
Bruce Momjian 已提交
1022
	lclContext *ctx = (lclContext *) AH->formatData;
1023
	FILE	   *tmp = th->tmpFH;	/* Grab it for convenience */
P
Philip Warner 已提交
1024 1025 1026
	char		buf[32768];
	int			cnt;
	int			len = 0;
1027
	int			res;
B
Bruce Momjian 已提交
1028 1029
	int			i,
				pad;
P
Philip Warner 已提交
1030 1031 1032 1033 1034 1035 1036 1037 1038 1039

	/*
	 * Find file len & go back to start.
	 */
	fseek(tmp, 0, SEEK_END);
	th->fileLen = ftell(tmp);
	fseek(tmp, 0, SEEK_SET);

	_tarWriteHeader(th);

B
Bruce Momjian 已提交
1040
	while ((cnt = fread(&buf[0], 1, 32767, tmp)) > 0)
P
Philip Warner 已提交
1041
	{
1042
		res = fwrite(&buf[0], 1, cnt, th->tarFH);
B
Bruce Momjian 已提交
1043
		if (res != cnt)
1044
			die_horribly(AH, modulename, "write error appending to tar archive (wrote %d, attempted %d)\n", res, cnt);
1045
		len += res;
P
Philip Warner 已提交
1046 1047
	}

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

	if (len != th->fileLen)
1052 1053
		die_horribly(AH, modulename, "actual file length (%d) does not match expected (%d)\n",
					 len, th->pos);
P
Philip Warner 已提交
1054 1055

	pad = ((len + 511) & ~511) - len;
B
Bruce Momjian 已提交
1056
	for (i = 0; i < pad; i++)
1057
	{
B
Bruce Momjian 已提交
1058
		if (fputc('\0', th->tarFH) == EOF)
1059
			die_horribly(AH, modulename, "could not output padding at end of tar member\n");
B
Bruce Momjian 已提交
1060
	}
P
Philip Warner 已提交
1061 1062 1063 1064 1065

	ctx->tarFHpos += len + pad;
}

/* Locate the file in the archive, read header and position to data */
B
Bruce Momjian 已提交
1066 1067
static TAR_MEMBER *
_tarPositionTo(ArchiveHandle *AH, const char *filename)
P
Philip Warner 已提交
1068
{
B
Bruce Momjian 已提交
1069 1070 1071 1072 1073 1074 1075 1076
	lclContext *ctx = (lclContext *) AH->formatData;
	TAR_MEMBER *th = calloc(1, sizeof(TAR_MEMBER));
	char		c;
	char		header[512];
	int			i,
				len,
				blks,
				id;
P
Philip Warner 已提交
1077 1078 1079 1080 1081 1082

	th->AH = AH;

	/* Go to end of current file, if any */
	if (ctx->tarFHpos != 0)
	{
1083
		ahlog(AH, 4, "moving from position %d (%x) to next member at file position %d (%x)\n",
B
Bruce Momjian 已提交
1084 1085
			  ctx->tarFHpos, ctx->tarFHpos,
			  ctx->tarNextMember, ctx->tarNextMember);
P
Philip Warner 已提交
1086 1087 1088 1089 1090

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

1091
	ahlog(AH, 4, "now at file position %d (%x)\n", ctx->tarFHpos, ctx->tarFHpos);
P
Philip Warner 已提交
1092 1093 1094 1095 1096 1097 1098

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

	/* Get the header */
	if (!_tarGetHeader(AH, th))
	{
		if (filename)
1099
			die_horribly(AH, modulename, "could not find header for file %s in tar archive\n", filename);
B
Bruce Momjian 已提交
1100 1101
		else
/* We're just scanning the archibe for the next file, so return null */
P
Philip Warner 已提交
1102 1103 1104 1105 1106 1107
		{
			free(th);
			return NULL;
		}
	}

B
Bruce Momjian 已提交
1108
	while (filename != NULL && strcmp(th->targetFile, filename) != 0)
P
Philip Warner 已提交
1109
	{
1110
		ahlog(AH, 4, "skipping tar member %s\n", th->targetFile);
P
Philip Warner 已提交
1111 1112 1113

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

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

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

		if (!_tarGetHeader(AH, th))
1126
			die_horribly(AH, modulename, "could not find header for file %s in tar archive\n", filename);
P
Philip Warner 已提交
1127 1128 1129 1130 1131 1132 1133 1134 1135 1136

	}

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

	return th;
}

/* Read & verify a header */
B
Bruce Momjian 已提交
1137 1138
static int
_tarGetHeader(ArchiveHandle *AH, TAR_MEMBER *th)
P
Philip Warner 已提交
1139
{
B
Bruce Momjian 已提交
1140 1141 1142 1143 1144 1145 1146 1147 1148
	lclContext *ctx = (lclContext *) AH->formatData;
	char		h[512];
	char		name[100];
	int			sum,
				chk;
	int			len;
	int			hPos;
	int			i;
	bool		gotBlock = false;
P
Philip Warner 已提交
1149

1150 1151
	while (!gotBlock)
	{
1152 1153 1154 1155 1156 1157
#if 0
		if (ftell(ctx->tarFH) != ctx->tarFHpos)
			die_horribly(AH, modulename,
						 "mismatch in actual vs. predicted file position (%d vs. %d)\n",
						 ftell(ctx->tarFH), ctx->tarFHpos);
#endif
P
Philip Warner 已提交
1158

1159 1160
		/* Save the pos for reporting purposes */
		hPos = ctx->tarFHpos;
P
Philip Warner 已提交
1161

1162 1163
		/* Read a 512 byte block, return EOF, exit if short */
		len = _tarReadRaw(AH, &h[0], 512, NULL, ctx->tarFH);
B
Bruce Momjian 已提交
1164
		if (len == 0)			/* EOF */
1165 1166 1167
			return 0;

		if (len != 512)
1168
			die_horribly(AH, modulename, "incomplete tar header found (%d bytes)\n", len);
1169 1170 1171

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

1173
		/*
B
Bruce Momjian 已提交
1174 1175
		 * If the checksum failed, see if it is a null block. If so, then
		 * just try with next block...
1176 1177
		 */

B
Bruce Momjian 已提交
1178
		if (chk == sum)
1179
			gotBlock = true;
B
Bruce Momjian 已提交
1180 1181 1182
		else
		{
			for (i = 0; i < 512; i++)
1183
			{
B
Bruce Momjian 已提交
1184
				if (h[0] != 0)
1185
				{
B
Bruce Momjian 已提交
1186
					gotBlock = true;
1187 1188 1189 1190 1191
					break;
				}
			}
		}
	}
P
Philip Warner 已提交
1192 1193 1194 1195 1196

	sscanf(&h[0], "%99s", &name[0]);
	sscanf(&h[124], "%12o", &len);
	sscanf(&h[148], "%8o", &sum);

1197
	ahlog(AH, 3, "TOC Entry %s at %d (length %d, checksum %d)\n", &name[0], hPos, len, sum);
P
Philip Warner 已提交
1198 1199

	if (chk != sum)
1200 1201
		die_horribly(AH, modulename,
					 "corrupt tar header found in %s "
1202
		"(expected %d (%o), computed %d (%o)) file position %ld (%lx)\n",
1203
					 &name[0], sum, sum, chk, chk, ftell(ctx->tarFH), ftell(ctx->tarFH));
P
Philip Warner 已提交
1204 1205 1206 1207 1208 1209 1210

	th->targetFile = strdup(name);
	th->fileLen = len;

	return 1;
}

B
Bruce Momjian 已提交
1211 1212
static void
_tarWriteHeader(TAR_MEMBER *th)
P
Philip Warner 已提交
1213 1214 1215 1216 1217 1218
{
	char		h[512];
	int			i;
	int			lastSum = 0;
	int			sum;

B
Bruce Momjian 已提交
1219
	for (i = 0; i < 512; i++)
P
Philip Warner 已提交
1220 1221 1222 1223 1224 1225 1226 1227 1228
		h[i] = '\0';

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

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

	/* User ID 8 */
P
Philip Warner 已提交
1229
	sprintf(&h[108], " 04000 ");
P
Philip Warner 已提交
1230 1231

	/* Group 8 */
P
Philip Warner 已提交
1232
	sprintf(&h[116], " 02000 ");
P
Philip Warner 已提交
1233 1234

	/* File size 12 */
P
Philip Warner 已提交
1235
	sprintf(&h[124], "%10o ", th->fileLen);
P
Philip Warner 已提交
1236 1237

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

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

P
Philip Warner 已提交
1243 1244 1245
	/* Type 1 */
	/* sprintf(&h[156], "%c", LF_NORMAL); */
	sprintf(&h[156], "0");
P
Philip Warner 已提交
1246 1247 1248 1249 1250 1251

	/* Link name 100 (NULL) */

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

B
Bruce Momjian 已提交
1252 1253 1254
	/*
	 * GNU Version... sprintf(&h[257], "ustar"); sprintf(&h[263], "00");
	 */
P
Philip Warner 已提交
1255

P
Philip Warner 已提交
1256
	/* User 32 */
B
Bruce Momjian 已提交
1257 1258
	sprintf(&h[265], "%.31s", "");		/* How do I get username reliably?
										 * Do I need to? */
P
Philip Warner 已提交
1259 1260

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

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

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


B
Bruce Momjian 已提交
1271
	while ((sum = _tarChecksum(h)) != lastSum)
P
Philip Warner 已提交
1272
	{
P
Philip Warner 已提交
1273
		sprintf(&h[148], "%6o ", sum);
P
Philip Warner 已提交
1274 1275 1276
		lastSum = sum;
	}

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

P
Philip Warner 已提交
1280
}