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
19
 *		$Header: /cvsroot/pgsql/src/bin/pg_dump/pg_backup_tar.c,v 1.14 2001/04/14 13:11:03 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);
P
Philip Warner 已提交
837 838 839 840

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

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

		AH->public.verbose = savVerbose;

		tarClose(AH, th);
846 847

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

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

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

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

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

/*
 * BLOB support
 */

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

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

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

	tarClose(AH, tctx->TH);
}

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

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

	tarClose(AH, ctx->blobToc);

}



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

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

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

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

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

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

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

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

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

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

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

	ctx->tarFHpos += len + pad;
}

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

	th->AH = AH;

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

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

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

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

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

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

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

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

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

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

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

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

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

	return 1;
}

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

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

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

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

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

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

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

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

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

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

	/* Link name 100 (NULL) */

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

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

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

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

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

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


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

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

P
Philip Warner 已提交
1281
}