pg_backup_tar.c 26.9 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
B
Bruce Momjian 已提交
19
 *		$Header: /cvsroot/pgsql/src/bin/pg_dump/pg_backup_tar.c,v 1.12 2001/03/22 04:00:13 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 56 57 58
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);
static void _StartBlob(ArchiveHandle *AH, TocEntry *te, int oid);
static void _EndBlob(ArchiveHandle *AH, TocEntry *te, int oid);
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 69
typedef FILE ThingFile;

P
Philip Warner 已提交
70 71
#endif

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

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

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

B
Bruce Momjian 已提交
104 105 106
static char *progname = "Archiver(tar)";

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

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

#ifdef __NOT_USED__
B
Bruce Momjian 已提交
112 113
static char *tarGets(char *buf, int len, TAR_MEMBER *th);

P
Philip Warner 已提交
114
#endif
B
Bruce Momjian 已提交
115
static int	tarPrintf(ArchiveHandle *AH, TAR_MEMBER *th, const char *fmt,...);
P
Philip Warner 已提交
116

B
Bruce Momjian 已提交
117 118 119 120 121 122 123 124
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 已提交
125

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

/*
B
Bruce Momjian 已提交
129
 *	Initializer
P
Philip Warner 已提交
130
 */
B
Bruce Momjian 已提交
131 132
void
InitArchiveFmt_Tar(ArchiveHandle *AH)
P
Philip Warner 已提交
133
{
B
Bruce Momjian 已提交
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 168 169
	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 已提交
170
			ctx->tarFH = fopen(AH->fSpec, PG_BINARY_W);
B
Bruce Momjian 已提交
171
		else
P
Philip Warner 已提交
172
			ctx->tarFH = stdout;
173

B
Bruce Momjian 已提交
174
		if (ctx->tarFH == NULL)
175 176
			die_horribly(NULL, "%s: Could not open TOC file for output.\n", progname);

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

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

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

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

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

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

211 212 213
		if (ctx->tarFH == NULL)
			die_horribly(NULL, "%s: Could not open TOC file for input\n", progname);

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

		ctx->tarFHpos = 0;

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

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

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

}

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

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

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

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

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

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

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

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

B
Bruce Momjian 已提交
305
	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 324
	char		fmode[10];

P
Philip Warner 已提交
325 326 327 328 329
#endif

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

#ifdef HAVE_LIBZ

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

#else

		tm->nFH = ctx->tarFH;

#endif

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

		tm->tmpFH = tmpfile();

B
Bruce Momjian 已提交
361
		if (tm->tmpFH == NULL)
362 363
			die_horribly(AH, "%s: could not generate temp file name.\n", progname);

P
Philip Warner 已提交
364 365 366 367 368 369
#ifdef HAVE_LIBZ

		if (AH->compression != 0)
		{
			sprintf(fmode, "wb%d", AH->compression);
			tm->zFH = gzdopen(dup(fileno(tm->tmpFH)), fmode);
370 371 372
			if (tm->zFH == NULL)
				die_horribly(AH, "%s: could not gzdopen temp file.\n", progname);

B
Bruce Momjian 已提交
373 374
		}
		else
P
Philip Warner 已提交
375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393
			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 已提交
394 395
static void
tarClose(ArchiveHandle *AH, TAR_MEMBER *th)
P
Philip Warner 已提交
396
{
B
Bruce Momjian 已提交
397

P
Philip Warner 已提交
398 399 400 401
	/*
	 * Close the GZ file since we dup'd. This will flush the buffers.
	 */
	if (AH->compression != 0)
402 403
		if (GZCLOSE(th->zFH) != 0)
			die_horribly(AH, "%s: could not close tar member\n", progname);
P
Philip Warner 已提交
404 405

	if (th->mode == 'w')
B
Bruce Momjian 已提交
406 407 408 409 410
		_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 已提交
411 412
	 */

B
Bruce Momjian 已提交
413
	if (th->targetFile)
P
Philip Warner 已提交
414 415 416 417 418 419 420
		free(th->targetFile);

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

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

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

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

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

	return s;
}
B
Bruce Momjian 已提交
459

P
Philip Warner 已提交
460 461
#endif

B
Bruce Momjian 已提交
462
/*
P
Philip Warner 已提交
463 464 465
 * 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 已提交
466 467
static int
_tarReadRaw(ArchiveHandle *AH, void *buf, int len, TAR_MEMBER *th, FILE *fh)
P
Philip Warner 已提交
468
{
B
Bruce Momjian 已提交
469 470 471 472
	lclContext *ctx = (lclContext *) AH->formatData;
	int			avail;
	int			used = 0;
	int			res = 0;
P
Philip Warner 已提交
473 474 475 476 477

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

B
Bruce Momjian 已提交
507 508 509
	/*
	 * fprintf(stderr, "%s: requested %d bytes, got %d from lookahead and
	 * %d from file\n", progname, reqLen, used, res);
P
Philip Warner 已提交
510 511 512 513 514 515
	 */

	ctx->tarFHpos += res + used;

	return (res + used);
}
B
Bruce Momjian 已提交
516 517 518

static int
tarRead(void *buf, int len, TAR_MEMBER *th)
P
Philip Warner 已提交
519
{
B
Bruce Momjian 已提交
520
	int			res;
P
Philip Warner 已提交
521 522 523 524 525 526 527 528 529 530 531 532 533 534

	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 已提交
535 536
static int
tarWrite(const void *buf, int len, TAR_MEMBER *th)
P
Philip Warner 已提交
537
{
B
Bruce Momjian 已提交
538
	int			res;
P
Philip Warner 已提交
539 540

	if (th->zFH != 0)
B
Bruce Momjian 已提交
541
		res = GZWRITE((void *) buf, 1, len, th->zFH);
P
Philip Warner 已提交
542 543 544
	else
		res = fwrite(buf, 1, len, th->nFH);

545 546 547
	if (res != len)
		die_horribly(th->AH, "%s: could not write to tar member (%d != %d)\n", progname, res, len);

P
Philip Warner 已提交
548 549 550 551
	th->pos += res;
	return res;
}

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

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

B
Bruce Momjian 已提交
559
	return dLen;
P
Philip Warner 已提交
560 561
}

B
Bruce Momjian 已提交
562 563
static void
_EndData(ArchiveHandle *AH, TocEntry *te)
P
Philip Warner 已提交
564
{
B
Bruce Momjian 已提交
565
	lclTocEntry *tctx = (lclTocEntry *) te->formatData;
P
Philip Warner 已提交
566

B
Bruce Momjian 已提交
567 568 569
	/* Close the file */
	tarClose(AH, tctx->TH);
	tctx->TH = NULL;
P
Philip Warner 已提交
570 571
}

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

B
Bruce Momjian 已提交
583
	if (!filename)
P
Philip Warner 已提交
584 585 586 587 588
		return;

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

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

B
Bruce Momjian 已提交
595
	tarClose(AH, th);
P
Philip Warner 已提交
596 597 598 599 600 601
}


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

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

		/*
B
Bruce Momjian 已提交
629 630
		 * 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 已提交
631 632 633 634 635 636 637
		 */
		if (strncmp(tmpCopy, "copy ", 5) != 0)
			die_horribly(AH, "%s: COPY statment badly formatted - could not find 'copy' in '%s'\n", progname, tmpCopy);

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

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

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

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

		if (pos2 >= strlen(tmpCopy))
			die_horribly(AH, "%s: COPY statment badly formatted - could not find 'from stdin' in '%s' starting at %d\n",
B
Bruce Momjian 已提交
651
						 progname, tmpCopy, pos1);
P
Philip Warner 已提交
652

B
Bruce Momjian 已提交
653 654
		ahwrite(tmpCopy, 1, pos2, AH);	/* 'copy "table" [with oids]' */
		ahprintf(AH, " from '$$PATH$$/%s' %s", tctx->filename, &tmpCopy[pos2 + 10]);
P
Philip Warner 已提交
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 691 692

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

702 703
	StartRestoreBlobs(AH);

B
Bruce Momjian 已提交
704
	th = tarOpen(AH, NULL, 'r');/* Open next file */
P
Philip Warner 已提交
705 706 707 708 709 710
	while (th != NULL)
	{
		ctx->FH = th;

		oid = atoi(&th->targetFile[5]);

B
Bruce Momjian 已提交
711
		if (strncmp(th->targetFile, "blob_", 5) == 0 && oid != 0)
P
Philip Warner 已提交
712 713 714 715 716
		{
			ahlog(AH, 1, " - Restoring BLOB oid %d\n", oid);

			StartRestoreBlob(AH, oid);

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

		tarClose(AH, th);

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

730 731
	EndRestoreBlobs(AH);

P
Philip Warner 已提交
732 733 734
}


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

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

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

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

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

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

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

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

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

B
Bruce Momjian 已提交
792 793
	if (AH->mode == archModeWrite)
	{
P
Philip Warner 已提交
794 795 796 797 798 799 800 801

		/*
		 * Write the Header & TOC to the archive FIRST
		 */
		th = tarOpen(AH, "toc.dat", 'w');
		ctx->FH = th;
		WriteHead(AH);
		WriteToc(AH);
B
Bruce Momjian 已提交
802
		tarClose(AH, th);		/* Not needed any more */
P
Philip Warner 已提交
803 804 805 806 807 808

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

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

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

P
Philip Warner 已提交
829 830 831 832 833 834
		ctx->isSpecialScript = 1;
		ctx->scriptTH = th;

		ropt = NewRestoreOptions();
		ropt->dropSchema = 1;
		ropt->compression = 0;
835
		ropt->superuser = PQuser(AH->connection);
P
Philip Warner 已提交
836 837 838 839

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

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

		AH->public.verbose = savVerbose;

		tarClose(AH, th);
845 846

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

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

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

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

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

/*
 * BLOB support
 */

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

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

B
Bruce Momjian 已提交
906
	if (oid == 0)
P
Philip Warner 已提交
907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927
		die_horribly(AH, "%s: illegal OID for BLOB (%d)\n", progname, oid);

	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 已提交
928 929
static void
_EndBlob(ArchiveHandle *AH, TocEntry *te, int oid)
P
Philip Warner 已提交
930
{
B
Bruce Momjian 已提交
931
	lclTocEntry *tctx = (lclTocEntry *) te->formatData;
P
Philip Warner 已提交
932 933 934 935 936

	tarClose(AH, tctx->TH);
}

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

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

	tarClose(AH, ctx->blobToc);

}



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

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

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

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

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

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

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

	/*
	 * 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 已提交
1041
	while ((cnt = fread(&buf[0], 1, 32767, tmp)) > 0)
P
Philip Warner 已提交
1042
	{
1043
		res = fwrite(&buf[0], 1, cnt, th->tarFH);
B
Bruce Momjian 已提交
1044
		if (res != cnt)
1045 1046
			die_horribly(AH, "%s: write error appending to TAR archive (%d != %d).\n", progname, res, cnt);
		len += res;
P
Philip Warner 已提交
1047 1048
	}

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

	if (len != th->fileLen)
1053
		die_horribly(AH, "%s: Actual file length does not match expected (%d vs. %d).\n",
B
Bruce Momjian 已提交
1054
					 progname, len, th->pos);
P
Philip Warner 已提交
1055 1056

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

	ctx->tarFHpos += len + pad;
}

/* Locate the file in the archive, read header and position to data */
B
Bruce Momjian 已提交
1067 1068
static TAR_MEMBER *
_tarPositionTo(ArchiveHandle *AH, const char *filename)
P
Philip Warner 已提交
1069
{
B
Bruce Momjian 已提交
1070 1071 1072 1073 1074 1075 1076 1077
	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 已提交
1078 1079 1080 1081 1082 1083

	th->AH = AH;

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

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

	ahlog(AH, 4, "Now at file position %d (%x)\n", ctx->tarFHpos, ctx->tarFHpos);

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

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

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

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

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

B
Bruce Momjian 已提交
1123
		for (i = 0; i < blks; i++)
P
Philip Warner 已提交
1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137
			_tarReadRaw(AH, &header[0], 512, NULL, ctx->tarFH);

		if (!_tarGetHeader(AH, th))
			die_horribly(AH, "%s: unable to find header for %s\n", progname, filename);

	}

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

	return th;
}

/* Read & verify a header */
B
Bruce Momjian 已提交
1138 1139
static int
_tarGetHeader(ArchiveHandle *AH, TAR_MEMBER *th)
P
Philip Warner 已提交
1140
{
B
Bruce Momjian 已提交
1141 1142 1143 1144 1145 1146 1147 1148 1149
	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 已提交
1150

1151 1152
	while (!gotBlock)
	{
B
Bruce Momjian 已提交
1153

1154
		/*
B
Bruce Momjian 已提交
1155 1156 1157
		 * if ( ftell(ctx->tarFH) != ctx->tarFHpos) die_horribly(AH, "%s:
		 * mismatch in actual vs. predicted file pos - %d vs. %d\n",
		 * progname, ftell(ctx->tarFH), ctx->tarFHpos);
1158
		 */
P
Philip Warner 已提交
1159

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

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

		if (len != 512)
			die_horribly(AH, "%s: incomplete tar header found (%d bytes)\n", progname, len);

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

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

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

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

	ahlog(AH, 3, "TOC Entry %s at %d (len=%d, chk=%d)\n", &name[0], hPos, len, sum);

	if (chk != sum)
		die_horribly(AH, "%s: corrupt tar header found in %s "
B
Bruce Momjian 已提交
1202 1203
		  "(expected %d (%o), computed %d (%o)) file position %d (%x)\n",
					 progname, &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 1279
		die_horribly(th->AH, "%s: unable to write tar header\n", progname);

P
Philip Warner 已提交
1280
}