pg_backup_tar.c 27.0 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.15 2001/04/25 07:03:19 pjw 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 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
	ctx = (lclTocEntry *) malloc(sizeof(lclTocEntry));
249
	if (te->dataDumper != NULL)
B
Bruce Momjian 已提交
250
	{
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

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

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

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

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

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

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

	if (mode == 'r')
	{
		tm = _tarPositionTo(AH, filename);
B
Bruce Momjian 已提交
331
		if (!tm)				/* Not found */
P
Philip Warner 已提交
332
		{
B
Bruce Momjian 已提交
333 334
			if (filename)		/* Couldn't find the requested file.
								 * Future: DO SEEK(0) and retry. */
P
Philip Warner 已提交
335
				die_horribly(AH, "%s: unable to find file '%s' in archive\n", progname, filename);
B
Bruce Momjian 已提交
336 337
			else
/* Any file OK, non left, so return NULL */
P
Philip Warner 已提交
338 339 340 341 342 343 344 345 346
				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 已提交
347
		/* tm->zFH = gzdopen(dup(fileno(ctx->tarFH)), "rb"); */
P
Philip Warner 已提交
348 349 350 351 352 353 354

#else

		tm->nFH = ctx->tarFH;

#endif

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

		tm->tmpFH = tmpfile();

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

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

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

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

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

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

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

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

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

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

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

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

	return s;
}
B
Bruce Momjian 已提交
460

P
Philip Warner 已提交
461 462
#endif

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

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

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

	ctx->tarFHpos += res + used;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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

		/*
B
Bruce Momjian 已提交
630 631
		 * 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 已提交
632 633 634 635 636 637 638
		 */
		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 已提交
639
				break;
P
Philip Warner 已提交
640 641 642

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

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

B
Bruce Momjian 已提交
646
		for (pos2 = pos1; pos2 < strlen(tmpCopy); pos2++)
P
Philip Warner 已提交
647 648 649 650 651
			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 已提交
652
						 progname, tmpCopy, pos1);
P
Philip Warner 已提交
653

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

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

703 704
	StartRestoreBlobs(AH);

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

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

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

			StartRestoreBlob(AH, oid);

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

		tarClose(AH, th);

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

731 732
	EndRestoreBlobs(AH);

P
Philip Warner 已提交
733 734 735
}


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

		AH->public.verbose = savVerbose;

		tarClose(AH, th);
847 848

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

B
Bruce Momjian 已提交
855
	}
P
Philip Warner 已提交
856

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

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

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

/*
 * BLOB support
 */

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

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

B
Bruce Momjian 已提交
908
	if (oid == 0)
P
Philip Warner 已提交
909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929
		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 已提交
930
static void
931
_EndBlob(ArchiveHandle *AH, TocEntry *te, Oid oid)
P
Philip Warner 已提交
932
{
B
Bruce Momjian 已提交
933
	lclTocEntry *tctx = (lclTocEntry *) te->formatData;
P
Philip Warner 已提交
934 935 936 937 938

	tarClose(AH, tctx->TH);
}

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

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

	tarClose(AH, ctx->blobToc);

}



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

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

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

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

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

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

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

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

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

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

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

	ctx->tarFHpos += len + pad;
}

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

	th->AH = AH;

	/* Go to end of current file, if any */
	if (ctx->tarFHpos != 0)
	{
B
Bruce Momjian 已提交
1086 1087 1088
		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 已提交
1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102

		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 已提交
1103 1104
		else
/* We're just scanning the archibe for the next file, so return null */
P
Philip Warner 已提交
1105 1106 1107 1108 1109 1110
		{
			free(th);
			return NULL;
		}
	}

B
Bruce Momjian 已提交
1111
	while (filename != NULL && strcmp(th->targetFile, filename) != 0)
P
Philip Warner 已提交
1112 1113 1114 1115 1116 1117
	{
		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 已提交
1118 1119
			"%s is required, but comes before %s in the archive file.\n",
						 progname, th->targetFile, filename);
P
Philip Warner 已提交
1120 1121

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

B
Bruce Momjian 已提交
1125
		for (i = 0; i < blks; i++)
P
Philip Warner 已提交
1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139
			_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 已提交
1140 1141
static int
_tarGetHeader(ArchiveHandle *AH, TAR_MEMBER *th)
P
Philip Warner 已提交
1142
{
B
Bruce Momjian 已提交
1143 1144 1145 1146 1147 1148 1149 1150 1151
	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 已提交
1152

1153 1154
	while (!gotBlock)
	{
B
Bruce Momjian 已提交
1155

1156
		/*
B
Bruce Momjian 已提交
1157 1158 1159
		 * 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);
1160
		 */
P
Philip Warner 已提交
1161

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

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

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

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

	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 已提交
1204 1205
		  "(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 已提交
1206 1207 1208 1209 1210 1211 1212

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

	return 1;
}

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

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

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

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

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

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

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

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

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

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

	/* Link name 100 (NULL) */

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

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

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

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

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

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


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

B
Bruce Momjian 已提交
1279
	if (fwrite(h, 1, 512, th->tarFH) != 512)
1280 1281
		die_horribly(th->AH, "%s: unable to write tar header\n", progname);

P
Philip Warner 已提交
1282
}