pg_backup_tar.c 28.3 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.34 2003/02/01 19:29:16 tgl Exp $
20
 *
P
Philip Warner 已提交
21 22 23
 *-------------------------------------------------------------------------
 */

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

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

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

#define K_STD_BUF_SIZE 1024


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

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

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

77 78 79 80 81 82 83 84 85 86 87
/*
 * Maximum file size for a tar member: The limit inherent in the
 * format is 2^33-1 bytes (nearly 8 GB).  But we don't want to exceed
 * what we can represent by an off_t.
 */
#ifdef INT64_IS_BUSTED
#define MAX_TAR_MEMBER_FILELEN INT_MAX
#else
#define MAX_TAR_MEMBER_FILELEN (((int64) 1 << Min(33, sizeof(off_t)*8 - 1)) - 1)
#endif

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

B
Bruce Momjian 已提交
101 102 103 104
typedef struct
{
	TAR_MEMBER *TH;
	char	   *filename;
P
Philip Warner 已提交
105 106
} lclTocEntry;

107
static char *modulename = gettext_noop("tar archiver");
B
Bruce Momjian 已提交
108 109

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

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

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

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

B
Bruce Momjian 已提交
128
static size_t _scriptOut(ArchiveHandle *AH, const void *buf, size_t len);
P
Philip Warner 已提交
129 130

/*
B
Bruce Momjian 已提交
131
 *	Initializer
P
Philip Warner 已提交
132
 */
B
Bruce Momjian 已提交
133 134
void
InitArchiveFmt_Tar(ArchiveHandle *AH)
P
Philip Warner 已提交
135
{
B
Bruce Momjian 已提交
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
	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;
164

165 166
	/* Initialize LO buffering */
	AH->lo_buf_size = LOBBUFSIZE;
B
Bruce Momjian 已提交
167
	AH->lo_buf = (void *) malloc(LOBBUFSIZE);
P
Peter Eisentraut 已提交
168 169
	if (AH->lo_buf == NULL)
		die_horribly(AH, modulename, "out of memory\n");
B
Bruce Momjian 已提交
170 171 172 173 174 175 176 177

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

		if (AH->fSpec && strcmp(AH->fSpec, "") != 0)
P
Philip Warner 已提交
178
			ctx->tarFH = fopen(AH->fSpec, PG_BINARY_W);
B
Bruce Momjian 已提交
179
		else
P
Philip Warner 已提交
180
			ctx->tarFH = stdout;
181

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

P
Philip Warner 已提交
186 187
		ctx->tarFHpos = 0;

B
Bruce Momjian 已提交
188 189 190 191
		/*
		 * Make unbuffered since we will dup() it, and the buffers screw
		 * each other
		 */
192
		/* setvbuf(ctx->tarFH, NULL, _IONBF, 0); */
P
Philip Warner 已提交
193

194
		ctx->hasSeek = checkSeek(ctx->tarFH);
P
Philip Warner 已提交
195

B
Bruce Momjian 已提交
196
		if (AH->compression < 0 || AH->compression > 9)
P
Philip Warner 已提交
197 198 199 200 201 202
			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 已提交
203 204 205 206
		/*
		 * 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 已提交
207 208
		 */
		if (AH->compression != 0)
209
			die_horribly(NULL, modulename, "compression not supported by tar output format\n");
P
Philip Warner 已提交
210

B
Bruce Momjian 已提交
211 212 213
	}
	else
	{							/* Read Mode */
P
Philip Warner 已提交
214

B
Bruce Momjian 已提交
215
		if (AH->fSpec && strcmp(AH->fSpec, "") != 0)
P
Philip Warner 已提交
216
			ctx->tarFH = fopen(AH->fSpec, PG_BINARY_R);
B
Bruce Momjian 已提交
217
		else
P
Philip Warner 已提交
218 219
			ctx->tarFH = stdin;

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

B
Bruce Momjian 已提交
223 224 225 226
		/*
		 * Make unbuffered since we will dup() it, and the buffers screw
		 * each other
		 */
227
		/* setvbuf(ctx->tarFH, NULL, _IONBF, 0); */
P
Philip Warner 已提交
228 229 230

		ctx->tarFHpos = 0;

231
		ctx->hasSeek = checkSeek(ctx->tarFH);
P
Philip Warner 已提交
232

B
Bruce Momjian 已提交
233 234 235 236
		/*
		 * Forcibly unmark the header as read since we use the lookahead
		 * buffer
		 */
P
Philip Warner 已提交
237 238
		AH->readHeader = 0;

B
Bruce Momjian 已提交
239
		ctx->FH = (void *) tarOpen(AH, "toc.dat", 'r');
P
Philip Warner 已提交
240 241
		ReadHead(AH);
		ReadToc(AH);
B
Bruce Momjian 已提交
242 243
		tarClose(AH, ctx->FH);	/* Nothing else in the file... */
	}
P
Philip Warner 已提交
244 245 246 247
}

/*
 * - Start a new TOC entry
B
Bruce Momjian 已提交
248
 *	 Setup the output file name.
P
Philip Warner 已提交
249
 */
B
Bruce Momjian 已提交
250 251
static void
_ArchiveEntry(ArchiveHandle *AH, TocEntry *te)
P
Philip Warner 已提交
252
{
B
Bruce Momjian 已提交
253 254
	lclTocEntry *ctx;
	char		fn[K_STD_BUF_SIZE];
P
Philip Warner 已提交
255

B
Bruce Momjian 已提交
256
	ctx = (lclTocEntry *) malloc(sizeof(lclTocEntry));
257
	if (te->dataDumper != NULL)
B
Bruce Momjian 已提交
258
	{
P
Philip Warner 已提交
259
#ifdef HAVE_LIBZ
B
Bruce Momjian 已提交
260
		if (AH->compression == 0)
P
Philip Warner 已提交
261
			sprintf(fn, "%d.dat", te->id);
B
Bruce Momjian 已提交
262
		else
P
Philip Warner 已提交
263 264 265 266 267
			sprintf(fn, "%d.dat.gz", te->id);
#else
		sprintf(fn, "%d.dat", te->id);
#endif
		ctx->filename = strdup(fn);
B
Bruce Momjian 已提交
268 269 270
	}
	else
	{
P
Philip Warner 已提交
271 272
		ctx->filename = NULL;
		ctx->TH = NULL;
B
Bruce Momjian 已提交
273 274
	}
	te->formatData = (void *) ctx;
P
Philip Warner 已提交
275 276
}

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

B
Bruce Momjian 已提交
282
	if (ctx->filename)
P
Philip Warner 已提交
283
		WriteStr(AH, ctx->filename);
B
Bruce Momjian 已提交
284
	else
P
Philip Warner 已提交
285 286 287
		WriteStr(AH, "");
}

B
Bruce Momjian 已提交
288 289
static void
_ReadExtraToc(ArchiveHandle *AH, TocEntry *te)
P
Philip Warner 已提交
290
{
B
Bruce Momjian 已提交
291
	lclTocEntry *ctx = (lclTocEntry *) te->formatData;
P
Philip Warner 已提交
292

B
Bruce Momjian 已提交
293 294 295 296 297
	if (ctx == NULL)
	{
		ctx = (lclTocEntry *) malloc(sizeof(lclTocEntry));
		te->formatData = (void *) ctx;
	}
P
Philip Warner 已提交
298

B
Bruce Momjian 已提交
299 300 301
	ctx->filename = ReadStr(AH);
	if (strlen(ctx->filename) == 0)
	{
P
Philip Warner 已提交
302 303
		free(ctx->filename);
		ctx->filename = NULL;
B
Bruce Momjian 已提交
304 305
	}
	ctx->TH = NULL;
P
Philip Warner 已提交
306 307
}

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

313 314
	if (ctx->filename != NULL)
		ahprintf(AH, "-- File: %s\n", ctx->filename);
P
Philip Warner 已提交
315 316
}

B
Bruce Momjian 已提交
317 318
static void
_StartData(ArchiveHandle *AH, TocEntry *te)
P
Philip Warner 已提交
319
{
B
Bruce Momjian 已提交
320
	lclTocEntry *tctx = (lclTocEntry *) te->formatData;
P
Philip Warner 已提交
321 322 323 324

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

B
Bruce Momjian 已提交
325 326
static TAR_MEMBER *
tarOpen(ArchiveHandle *AH, const char *filename, char mode)
P
Philip Warner 已提交
327
{
B
Bruce Momjian 已提交
328 329 330
	lclContext *ctx = (lclContext *) AH->formatData;
	TAR_MEMBER *tm;

P
Philip Warner 已提交
331
#ifdef HAVE_LIBZ
B
Bruce Momjian 已提交
332
	char		fmode[10];
P
Philip Warner 已提交
333 334 335 336 337
#endif

	if (mode == 'r')
	{
		tm = _tarPositionTo(AH, filename);
B
Bruce Momjian 已提交
338
		if (!tm)				/* Not found */
P
Philip Warner 已提交
339
		{
B
Bruce Momjian 已提交
340 341
			if (filename)		/* Couldn't find the requested file.
								 * Future: DO SEEK(0) and retry. */
342
				die_horribly(AH, modulename, "could not find file %s in archive\n", filename);
B
Bruce Momjian 已提交
343 344
			else
/* Any file OK, non left, so return NULL */
P
Philip Warner 已提交
345 346 347 348 349 350 351 352
				return NULL;
		}

#ifdef HAVE_LIBZ

		if (AH->compression == 0)
			tm->nFH = ctx->tarFH;
		else
353
			die_horribly(AH, modulename, "compression support is disabled in this format\n");
B
Bruce Momjian 已提交
354
		/* tm->zFH = gzdopen(dup(fileno(ctx->tarFH)), "rb"); */
P
Philip Warner 已提交
355 356 357 358 359

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

B
Bruce Momjian 已提交
360 361 362
	}
	else
	{
P
Philip Warner 已提交
363 364 365 366
		tm = calloc(1, sizeof(TAR_MEMBER));

		tm->tmpFH = tmpfile();

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

P
Philip Warner 已提交
370 371 372 373 374 375
#ifdef HAVE_LIBZ

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

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

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

B
Bruce Momjian 已提交
417
	if (th->targetFile)
P
Philip Warner 已提交
418 419 420 421 422 423 424
		free(th->targetFile);

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

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

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

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

	if (s)
	{
B
Bruce Momjian 已提交
457
		len = strlen(s);
P
Philip Warner 已提交
458 459 460 461 462 463 464
		th->pos += len;
	}

	return s;
}
#endif

B
Bruce Momjian 已提交
465
/*
P
Philip Warner 已提交
466 467 468
 * Just read bytes from the archive. This is the low level read routine
 * that is used for ALL reads on a tar file.
 */
P
Peter Eisentraut 已提交
469 470
static size_t
_tarReadRaw(ArchiveHandle *AH, void *buf, size_t len, TAR_MEMBER *th, FILE *fh)
P
Philip Warner 已提交
471
{
B
Bruce Momjian 已提交
472
	lclContext *ctx = (lclContext *) AH->formatData;
P
Peter Eisentraut 已提交
473 474 475
	size_t		avail;
	size_t		used = 0;
	size_t		res = 0;
P
Philip Warner 已提交
476 477 478 479 480

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

510 511 512 513
#if 0
	write_msg(modulename, "requested %d bytes, got %d from lookahead and %d from file\n",
			  reqLen, used, res);
#endif
P
Philip Warner 已提交
514 515 516 517 518

	ctx->tarFHpos += res + used;

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

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

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

	if (len <= 0)
		return 0;

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

	th->pos += res;

	return res;
}

P
Peter Eisentraut 已提交
538 539
static size_t
tarWrite(const void *buf, size_t len, TAR_MEMBER *th)
P
Philip Warner 已提交
540
{
P
Peter Eisentraut 已提交
541
	size_t		res;
P
Philip Warner 已提交
542 543

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

548
	if (res != len)
549
		die_horribly(th->AH, modulename,
B
Bruce Momjian 已提交
550
			"could not write to tar member (wrote %lu, attempted %lu)\n",
P
Peter Eisentraut 已提交
551
					 (unsigned long) res, (unsigned long) len);
552

P
Philip Warner 已提交
553 554 555 556
	th->pos += res;
	return res;
}

P
Peter Eisentraut 已提交
557 558
static size_t
_WriteData(ArchiveHandle *AH, const void *data, size_t dLen)
P
Philip Warner 已提交
559
{
B
Bruce Momjian 已提交
560
	lclTocEntry *tctx = (lclTocEntry *) AH->currToc->formatData;
P
Philip Warner 已提交
561

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

B
Bruce Momjian 已提交
564
	return dLen;
P
Philip Warner 已提交
565 566
}

B
Bruce Momjian 已提交
567 568
static void
_EndData(ArchiveHandle *AH, TocEntry *te)
P
Philip Warner 已提交
569
{
B
Bruce Momjian 已提交
570
	lclTocEntry *tctx = (lclTocEntry *) te->formatData;
P
Philip Warner 已提交
571

B
Bruce Momjian 已提交
572 573 574
	/* Close the file */
	tarClose(AH, tctx->TH);
	tctx->TH = NULL;
P
Philip Warner 已提交
575 576
}

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

B
Bruce Momjian 已提交
588
	if (!filename)
P
Philip Warner 已提交
589 590 591 592 593
		return;

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

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

B
Bruce Momjian 已提交
600
	tarClose(AH, th);
P
Philip Warner 已提交
601 602 603 604 605 606
}


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

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

		/*
B
Bruce Momjian 已提交
634 635
		 * 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 已提交
636 637
		 */
		if (strncmp(tmpCopy, "copy ", 5) != 0)
638 639
			die_horribly(AH, modulename,
						 "bad COPY statement - could not find \"copy\" in string \"%s\"\n", tmpCopy);
P
Philip Warner 已提交
640 641 642 643

		pos1 = 5;
		for (pos1 = 5; pos1 < strlen(tmpCopy); pos1++)
			if (tmpCopy[pos1] != ' ')
B
Bruce Momjian 已提交
644
				break;
P
Philip Warner 已提交
645 646 647

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

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

B
Bruce Momjian 已提交
651
		for (pos2 = pos1; pos2 < strlen(tmpCopy); pos2++)
P
Philip Warner 已提交
652 653 654 655
			if (strncmp(&tmpCopy[pos2], "from stdin", 10) == 0)
				break;

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

B
Bruce Momjian 已提交
660 661
		ahwrite(tmpCopy, 1, pos2, AH);	/* 'copy "table" [with oids]' */
		ahprintf(AH, " from '$$PATH$$/%s' %s", tctx->filename, &tmpCopy[pos2 + 10]);
P
Philip Warner 已提交
662 663 664 665 666 667 668 669 670 671

		return;
	}

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

B
Bruce Momjian 已提交
672 673
static void
_LoadBlobs(ArchiveHandle *AH, RestoreOptions *ropt)
P
Philip Warner 已提交
674
{
675
	Oid			oid;
B
Bruce Momjian 已提交
676 677
	lclContext *ctx = (lclContext *) AH->formatData;
	TAR_MEMBER *th;
P
Peter Eisentraut 已提交
678
	size_t		cnt;
B
Bruce Momjian 已提交
679
	char		buf[4096];
P
Philip Warner 已提交
680

681 682
	StartRestoreBlobs(AH);

683
	th = tarOpen(AH, NULL, 'r');	/* Open next file */
P
Philip Warner 已提交
684 685 686 687
	while (th != NULL)
	{
		ctx->FH = th;

688
		if (strncmp(th->targetFile, "blob_", 5) == 0)
P
Philip Warner 已提交
689
		{
690 691 692 693
			oid = atooid(&th->targetFile[5]);
			if (oid != 0)
			{
				ahlog(AH, 1, "restoring large object OID %u\n", oid);
P
Philip Warner 已提交
694

695
				StartRestoreBlob(AH, oid);
P
Philip Warner 已提交
696

697 698 699 700 701 702
				while ((cnt = tarRead(buf, 4095, th)) > 0)
				{
					buf[cnt] = '\0';
					ahwrite(buf, 1, cnt, AH);
				}
				EndRestoreBlob(AH, oid);
P
Philip Warner 已提交
703 704 705 706 707 708 709
			}
		}

		tarClose(AH, th);

		th = tarOpen(AH, NULL, 'r');
	}
710
	EndRestoreBlobs(AH);
P
Philip Warner 已提交
711 712 713
}


B
Bruce Momjian 已提交
714 715
static int
_WriteByte(ArchiveHandle *AH, const int i)
P
Philip Warner 已提交
716
{
B
Bruce Momjian 已提交
717 718 719
	lclContext *ctx = (lclContext *) AH->formatData;
	int			res;
	char		b = i;			/* Avoid endian problems */
P
Philip Warner 已提交
720

B
Bruce Momjian 已提交
721 722
	res = tarWrite(&b, 1, ctx->FH);
	if (res != EOF)
P
Philip Warner 已提交
723
		ctx->filePos += res;
B
Bruce Momjian 已提交
724
	return res;
P
Philip Warner 已提交
725 726
}

B
Bruce Momjian 已提交
727 728
static int
_ReadByte(ArchiveHandle *AH)
P
Philip Warner 已提交
729
{
B
Bruce Momjian 已提交
730 731 732
	lclContext *ctx = (lclContext *) AH->formatData;
	int			res;
	char		c = '\0';
P
Philip Warner 已提交
733

B
Bruce Momjian 已提交
734 735
	res = tarRead(&c, 1, ctx->FH);
	if (res != EOF)
P
Philip Warner 已提交
736
		ctx->filePos += res;
B
Bruce Momjian 已提交
737
	return c;
P
Philip Warner 已提交
738 739
}

P
Peter Eisentraut 已提交
740 741
static size_t
_WriteBuf(ArchiveHandle *AH, const void *buf, size_t len)
P
Philip Warner 已提交
742
{
B
Bruce Momjian 已提交
743
	lclContext *ctx = (lclContext *) AH->formatData;
P
Peter Eisentraut 已提交
744
	size_t		res;
P
Philip Warner 已提交
745

B
Bruce Momjian 已提交
746 747 748
	res = tarWrite((void *) buf, len, ctx->FH);
	ctx->filePos += res;
	return res;
P
Philip Warner 已提交
749 750
}

P
Peter Eisentraut 已提交
751 752
static size_t
_ReadBuf(ArchiveHandle *AH, void *buf, size_t len)
P
Philip Warner 已提交
753
{
B
Bruce Momjian 已提交
754
	lclContext *ctx = (lclContext *) AH->formatData;
P
Peter Eisentraut 已提交
755
	size_t		res;
P
Philip Warner 已提交
756

B
Bruce Momjian 已提交
757 758 759
	res = tarRead(buf, len, ctx->FH);
	ctx->filePos += res;
	return res;
P
Philip Warner 已提交
760 761
}

B
Bruce Momjian 已提交
762 763
static void
_CloseArchive(ArchiveHandle *AH)
P
Philip Warner 已提交
764
{
B
Bruce Momjian 已提交
765 766 767 768 769
	lclContext *ctx = (lclContext *) AH->formatData;
	TAR_MEMBER *th;
	RestoreOptions *ropt;
	int			savVerbose,
				i;
P
Philip Warner 已提交
770

B
Bruce Momjian 已提交
771 772
	if (AH->mode == archModeWrite)
	{
P
Philip Warner 已提交
773 774 775 776 777 778 779
		/*
		 * Write the Header & TOC to the archive FIRST
		 */
		th = tarOpen(AH, "toc.dat", 'w');
		ctx->FH = th;
		WriteHead(AH);
		WriteToc(AH);
B
Bruce Momjian 已提交
780
		tarClose(AH, th);		/* Not needed any more */
P
Philip Warner 已提交
781 782 783 784 785 786

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

B
Bruce Momjian 已提交
787 788 789
		/*
		 * Now this format wants to append a script which does a full
		 * restore if the files have been extracted.
P
Philip Warner 已提交
790 791 792
		 */
		th = tarOpen(AH, "restore.sql", 'w');
		tarPrintf(AH, th, "create temporary table pgdump_restore_path(p text);\n");
B
Bruce Momjian 已提交
793 794 795 796 797 798 799 800 801 802
		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 已提交
803 804 805
		tarPrintf(AH, th, "insert into pgdump_restore_path values('/tmp');\n\n");

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

P
Philip Warner 已提交
807 808 809 810 811 812
		ctx->isSpecialScript = 1;
		ctx->scriptTH = th;

		ropt = NewRestoreOptions();
		ropt->dropSchema = 1;
		ropt->compression = 0;
813
		ropt->superuser = NULL;
814
		ropt->suppressDumpWarnings = true;
P
Philip Warner 已提交
815 816 817 818

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

B
Bruce Momjian 已提交
819
		RestoreArchive((Archive *) AH, ropt);
P
Philip Warner 已提交
820 821 822 823

		AH->public.verbose = savVerbose;

		tarClose(AH, th);
824 825

		/* Add a block of NULLs since it's de-rigeur. */
B
Bruce Momjian 已提交
826
		for (i = 0; i < 512; i++)
827
		{
828
			if (fputc(0, ctx->tarFH) == EOF)
829
				die_horribly(AH, modulename,
830
				   "could not write null block at end of tar archive\n");
831
		}
B
Bruce Momjian 已提交
832
	}
P
Philip Warner 已提交
833

B
Bruce Momjian 已提交
834
	AH->FH = NULL;
P
Philip Warner 已提交
835 836
}

P
Peter Eisentraut 已提交
837 838
static size_t
_scriptOut(ArchiveHandle *AH, const void *buf, size_t len)
P
Philip Warner 已提交
839
{
B
Bruce Momjian 已提交
840 841
	lclContext *ctx = (lclContext *) AH->formatData;

P
Philip Warner 已提交
842 843 844 845 846 847 848 849
	return tarWrite(buf, len, ctx->scriptTH);
}

/*
 * BLOB support
 */

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

	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 已提交
876
static void
877
_StartBlob(ArchiveHandle *AH, TocEntry *te, Oid oid)
P
Philip Warner 已提交
878
{
B
Bruce Momjian 已提交
879 880 881 882
	lclContext *ctx = (lclContext *) AH->formatData;
	lclTocEntry *tctx = (lclTocEntry *) te->formatData;
	char		fname[255];
	char	   *sfx;
P
Philip Warner 已提交
883

B
Bruce Momjian 已提交
884
	if (oid == 0)
885
		die_horribly(AH, modulename, "invalid OID for large object (%u)\n", oid);
P
Philip Warner 已提交
886 887 888 889 890 891

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

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

894
	tarPrintf(AH, ctx->blobToc, "%u %s\n", oid, fname);
P
Philip Warner 已提交
895 896 897 898 899 900 901 902 903 904

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

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

	tarClose(AH, tctx->TH);
}

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

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

	tarClose(AH, ctx->blobToc);
}



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

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

B
Bruce Momjian 已提交
945 946 947 948 949 950 951 952 953 954
	/*
	 * 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))
955
	{
B
Bruce Momjian 已提交
956 957
		if (p != NULL)
			free(p);
P
Philip Warner 已提交
958
		bSize *= 2;
B
Bruce Momjian 已提交
959
		p = (char *) malloc(bSize);
P
Philip Warner 已提交
960
		if (p == NULL)
961
			die_horribly(AH, modulename, "out of memory\n");
962
		va_start(ap, fmt);
P
Philip Warner 已提交
963
		cnt = vsnprintf(p, bSize, fmt, ap);
964
		va_end(ap);
P
Philip Warner 已提交
965 966 967 968 969 970
	}
	cnt = tarWrite(p, cnt, th);
	free(p);
	return cnt;
}

B
Bruce Momjian 已提交
971 972
static int
_tarChecksum(char *header)
P
Philip Warner 已提交
973
{
B
Bruce Momjian 已提交
974 975 976
	int			i,
				sum;

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

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

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

992 993 994 995 996 997 998 999 1000 1001 1002
	if (sum != chk)
		return false;

	/* POSIX format */
	if (strncmp(&header[257], "ustar00", 7) == 0)
		return true;
	/* older format */
	if (strncmp(&header[257], "ustar  ", 7) == 0)
		return true;

	return false;
P
Philip Warner 已提交
1003 1004 1005
}

/* Given the member, write the TAR header & copy the file */
B
Bruce Momjian 已提交
1006 1007
static void
_tarAddFile(ArchiveHandle *AH, TAR_MEMBER *th)
P
Philip Warner 已提交
1008
{
B
Bruce Momjian 已提交
1009
	lclContext *ctx = (lclContext *) AH->formatData;
1010
	FILE	   *tmp = th->tmpFH;	/* Grab it for convenience */
P
Philip Warner 已提交
1011
	char		buf[32768];
P
Peter Eisentraut 已提交
1012 1013 1014 1015
	size_t		cnt;
	off_t		len = 0;
	size_t		res;
	size_t		i,
B
Bruce Momjian 已提交
1016
				pad;
P
Philip Warner 已提交
1017 1018 1019 1020

	/*
	 * Find file len & go back to start.
	 */
P
Peter Eisentraut 已提交
1021 1022
	fseeko(tmp, 0, SEEK_END);
	th->fileLen = ftello(tmp);
1023 1024
	if (th->fileLen > MAX_TAR_MEMBER_FILELEN)
		die_horribly(AH, modulename, "archive member too large for tar format\n");
P
Peter Eisentraut 已提交
1025
	fseeko(tmp, 0, SEEK_SET);
P
Philip Warner 已提交
1026 1027 1028

	_tarWriteHeader(th);

B
Bruce Momjian 已提交
1029
	while ((cnt = fread(&buf[0], 1, 32767, tmp)) > 0)
P
Philip Warner 已提交
1030
	{
1031
		res = fwrite(&buf[0], 1, cnt, th->tarFH);
B
Bruce Momjian 已提交
1032
		if (res != cnt)
P
Peter Eisentraut 已提交
1033 1034 1035
			die_horribly(AH, modulename,
						 "write error appending to tar archive (wrote %lu, attempted %lu)\n",
						 (unsigned long) res, (unsigned long) cnt);
1036
		len += res;
P
Philip Warner 已提交
1037 1038
	}

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

	if (len != th->fileLen)
1043
	{
B
Bruce Momjian 已提交
1044 1045 1046
		char		buf1[100],
					buf2[100];

1047 1048 1049 1050 1051
		snprintf(buf1, 100, INT64_FORMAT, (int64) len);
		snprintf(buf2, 100, INT64_FORMAT, (int64) th->pos);
		die_horribly(AH, modulename, "actual file length (%s) does not match expected (%s)\n",
					 buf1, buf2);
	}
P
Philip Warner 已提交
1052 1053

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

	ctx->tarFHpos += len + pad;
}

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

	th->AH = AH;

	/* Go to end of current file, if any */
	if (ctx->tarFHpos != 0)
	{
B
Bruce Momjian 已提交
1081 1082 1083
		char		buf1[100],
					buf2[100];

1084 1085 1086 1087
		snprintf(buf1, 100, INT64_FORMAT, (int64) ctx->tarFHpos);
		snprintf(buf2, 100, INT64_FORMAT, (int64) ctx->tarNextMember);
		ahlog(AH, 4, "moving from position %s to next member at file position %s\n",
			  buf1, buf2);
P
Philip Warner 已提交
1088 1089 1090 1091 1092

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

1093
	{
B
Bruce Momjian 已提交
1094 1095
		char		buf[100];

1096 1097 1098
		snprintf(buf, 100, INT64_FORMAT, (int64) ctx->tarFHpos);
		ahlog(AH, 4, "now at file position %s\n", buf);
	}
P
Philip Warner 已提交
1099 1100 1101 1102 1103 1104 1105

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

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

B
Bruce Momjian 已提交
1115
	while (filename != NULL && strcmp(th->targetFile, filename) != 0)
P
Philip Warner 已提交
1116
	{
1117
		ahlog(AH, 4, "skipping tar member %s\n", th->targetFile);
P
Philip Warner 已提交
1118 1119 1120

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

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

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

		if (!_tarGetHeader(AH, th))
1133
			die_horribly(AH, modulename, "could not find header for file %s in tar archive\n", filename);
P
Philip Warner 已提交
1134 1135 1136 1137 1138 1139 1140 1141 1142 1143

	}

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

	return th;
}

/* Read & verify a header */
B
Bruce Momjian 已提交
1144 1145
static int
_tarGetHeader(ArchiveHandle *AH, TAR_MEMBER *th)
P
Philip Warner 已提交
1146
{
B
Bruce Momjian 已提交
1147 1148
	lclContext *ctx = (lclContext *) AH->formatData;
	char		h[512];
1149
	char		tag[100];
B
Bruce Momjian 已提交
1150 1151
	int			sum,
				chk;
P
Peter Eisentraut 已提交
1152
	size_t		len;
1153
	unsigned long	ullen;
P
Peter Eisentraut 已提交
1154
	off_t		hPos;
B
Bruce Momjian 已提交
1155 1156
	int			i;
	bool		gotBlock = false;
P
Philip Warner 已提交
1157

1158 1159
	while (!gotBlock)
	{
1160
#if 0
P
Peter Eisentraut 已提交
1161
		if (ftello(ctx->tarFH) != ctx->tarFHpos)
1162
		{
B
Bruce Momjian 已提交
1163 1164 1165
			char		buf1[100],
						buf2[100];

1166 1167
			snprintf(buf1, 100, INT64_FORMAT, (int64) ftello(ctx->tarFH));
			snprintf(buf2, 100, INT64_FORMAT, (int64) ftello(ctx->tarFHpos));
1168
			die_horribly(AH, modulename,
1169 1170 1171
						 "mismatch in actual vs. predicted file position (%s vs. %s)\n",
						 buf1, buf2);
		}
1172
#endif
P
Philip Warner 已提交
1173

1174 1175
		/* Save the pos for reporting purposes */
		hPos = ctx->tarFHpos;
P
Philip Warner 已提交
1176

1177 1178
		/* Read a 512 byte block, return EOF, exit if short */
		len = _tarReadRaw(AH, &h[0], 512, NULL, ctx->tarFH);
B
Bruce Momjian 已提交
1179
		if (len == 0)			/* EOF */
1180 1181 1182
			return 0;

		if (len != 512)
P
Peter Eisentraut 已提交
1183 1184 1185
			die_horribly(AH, modulename,
						 "incomplete tar header found (%lu bytes)\n",
						 (unsigned long) len);
1186 1187 1188

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

1190
		/*
B
Bruce Momjian 已提交
1191 1192
		 * If the checksum failed, see if it is a null block. If so, then
		 * just try with next block...
1193 1194
		 */

B
Bruce Momjian 已提交
1195
		if (chk == sum)
1196
			gotBlock = true;
B
Bruce Momjian 已提交
1197 1198 1199
		else
		{
			for (i = 0; i < 512; i++)
1200
			{
B
Bruce Momjian 已提交
1201
				if (h[0] != 0)
1202
				{
B
Bruce Momjian 已提交
1203
					gotBlock = true;
1204 1205 1206 1207 1208
					break;
				}
			}
		}
	}
P
Philip Warner 已提交
1209

1210 1211 1212
	sscanf(&h[0], "%99s", tag);
	sscanf(&h[124], "%12lo", &ullen);
	len = (size_t) ullen;
P
Philip Warner 已提交
1213 1214
	sscanf(&h[148], "%8o", &sum);

1215
	{
B
Bruce Momjian 已提交
1216 1217
		char		buf[100];

1218 1219
		snprintf(buf, 100, INT64_FORMAT, (int64) hPos);
		ahlog(AH, 3, "TOC Entry %s at %s (length %lu, checksum %d)\n",
1220
			  tag, buf, (unsigned long) len, sum);
1221
	}
P
Philip Warner 已提交
1222 1223

	if (chk != sum)
1224
	{
B
Bruce Momjian 已提交
1225 1226
		char		buf[100];

1227
		snprintf(buf, 100, INT64_FORMAT, (int64) ftello(ctx->tarFH));
1228 1229
		die_horribly(AH, modulename,
					 "corrupt tar header found in %s "
1230
					 "(expected %d, computed %d) file position %s\n",
1231
					 tag, sum, chk, buf);
1232
	}
P
Philip Warner 已提交
1233

1234
	th->targetFile = strdup(tag);
P
Philip Warner 已提交
1235 1236 1237 1238 1239
	th->fileLen = len;

	return 1;
}

1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256

/*
 * Utility routine to print possibly larger than 32 bit integers in a
 * portable fashion.  Filled with zeros.
 */
static void print_val(char *s, uint64 val, unsigned int base, size_t len)
{
        int i;
        for (i = len; i > 0; i--)
        {
                int digit = val % base;
                s[i - 1] = '0' + digit;
                val = val / base;
        }
}


B
Bruce Momjian 已提交
1257 1258
static void
_tarWriteHeader(TAR_MEMBER *th)
P
Philip Warner 已提交
1259 1260 1261 1262 1263
{
	char		h[512];
	int			lastSum = 0;
	int			sum;

1264
	memset(h, 0, sizeof(h));
P
Philip Warner 已提交
1265 1266 1267 1268 1269 1270 1271 1272

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

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

	/* User ID 8 */
1273
	sprintf(&h[108], "004000 ");
P
Philip Warner 已提交
1274 1275

	/* Group 8 */
1276
	sprintf(&h[116], "002000 ");
P
Philip Warner 已提交
1277

1278 1279 1280
	/* File size 12 - 11 digits, 1 space, no NUL */
	print_val(&h[124], th->fileLen, 8, 11);
	sprintf(&h[135], " ");
P
Philip Warner 已提交
1281 1282

	/* Mod Time 12 */
1283
	sprintf(&h[136], "%011o ", (int) time(NULL));
P
Philip Warner 已提交
1284 1285

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

1288
	/* Type - regular file */
P
Philip Warner 已提交
1289
	sprintf(&h[156], "0");
P
Philip Warner 已提交
1290

1291
	/* Link tag 100 (NULL) */
P
Philip Warner 已提交
1292

1293 1294
	/* Magic 6 + Version 2 */
	sprintf(&h[257], "ustar00");
P
Philip Warner 已提交
1295

1296
#if 0
P
Philip Warner 已提交
1297
	/* User 32 */
B
Bruce Momjian 已提交
1298 1299
	sprintf(&h[265], "%.31s", "");		/* How do I get username reliably?
										 * Do I need to? */
P
Philip Warner 已提交
1300 1301

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

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

1308 1309 1310
	/* Min Dev 8 */
	sprintf(&h[337], "%6o ", 0);
#endif
P
Philip Warner 已提交
1311

B
Bruce Momjian 已提交
1312
	while ((sum = _tarChecksum(h)) != lastSum)
P
Philip Warner 已提交
1313
	{
1314
		sprintf(&h[148], "%06o ", sum);
P
Philip Warner 已提交
1315 1316 1317
		lastSum = sum;
	}

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

P
Philip Warner 已提交
1321
}