⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pg_backup_tar.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 2 页
字号:
/*------------------------------------------------------------------------- * * 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 *		Rights are granted to use this software in any way so long *		as this notice is not removed. * *	The author is not responsible for loss or damages that may *	result from it's use. * * * IDENTIFICATION *		$PostgreSQL: pgsql/src/bin/pg_dump/pg_backup_tar.c,v 1.49 2005/10/15 02:49:38 momjian Exp $ * *------------------------------------------------------------------------- */#include "pg_backup.h"#include "pg_backup_archiver.h"#include "pg_backup_tar.h"#include <ctype.h>#include <limits.h>#include <unistd.h>static void _ArchiveEntry(ArchiveHandle *AH, TocEntry *te);static void _StartData(ArchiveHandle *AH, TocEntry *te);static size_t _WriteData(ArchiveHandle *AH, const void *data, size_t dLen);static void _EndData(ArchiveHandle *AH, TocEntry *te);static int	_WriteByte(ArchiveHandle *AH, const int i);static int	_ReadByte(ArchiveHandle *);static size_t _WriteBuf(ArchiveHandle *AH, const void *buf, size_t len);static size_t _ReadBuf(ArchiveHandle *AH, void *buf, size_t len);static void _CloseArchive(ArchiveHandle *AH);static void _PrintTocData(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt);static void _WriteExtraToc(ArchiveHandle *AH, TocEntry *te);static void _ReadExtraToc(ArchiveHandle *AH, TocEntry *te);static void _PrintExtraToc(ArchiveHandle *AH, TocEntry *te);static void _StartBlobs(ArchiveHandle *AH, TocEntry *te);static void _StartBlob(ArchiveHandle *AH, TocEntry *te, Oid oid);static void _EndBlob(ArchiveHandle *AH, TocEntry *te, Oid oid);static void _EndBlobs(ArchiveHandle *AH, TocEntry *te);#define K_STD_BUF_SIZE 1024#ifdef HAVE_LIBZ /* typedef gzFile	 ThingFile; */typedef FILE ThingFile;#elsetypedef FILE ThingFile;#endiftypedef struct{	ThingFile  *zFH;	FILE	   *nFH;	FILE	   *tarFH;	FILE	   *tmpFH;	char	   *targetFile;	char		mode;	off_t		pos;	off_t		fileLen;	ArchiveHandle *AH;} TAR_MEMBER;/* * 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)#endiftypedef struct{	int			hasSeek;	off_t		filePos;	TAR_MEMBER *blobToc;	FILE	   *tarFH;	off_t		tarFHpos;	off_t		tarNextMember;	TAR_MEMBER *FH;	int			isSpecialScript;	TAR_MEMBER *scriptTH;} lclContext;typedef struct{	TAR_MEMBER *TH;	char	   *filename;} lclTocEntry;static char *modulename = gettext_noop("tar archiver");static void _LoadBlobs(ArchiveHandle *AH, RestoreOptions *ropt);static TAR_MEMBER *tarOpen(ArchiveHandle *AH, const char *filename, char mode);static void tarClose(ArchiveHandle *AH, TAR_MEMBER *TH);#ifdef __NOT_USED__static char *tarGets(char *buf, size_t len, TAR_MEMBER *th);#endifstatic int	tarPrintf(ArchiveHandle *AH, TAR_MEMBER *th, const char *fmt,...);static void _tarAddFile(ArchiveHandle *AH, TAR_MEMBER *th);static int	_tarChecksum(char *th);static TAR_MEMBER *_tarPositionTo(ArchiveHandle *AH, const char *filename);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);static void _tarWriteHeader(TAR_MEMBER *th);static int	_tarGetHeader(ArchiveHandle *AH, TAR_MEMBER *th);static size_t _tarReadRaw(ArchiveHandle *AH, void *buf, size_t len, TAR_MEMBER *th, FILE *fh);static size_t _scriptOut(ArchiveHandle *AH, const void *buf, size_t len);/* *	Initializer */voidInitArchiveFmt_Tar(ArchiveHandle *AH){	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 *) calloc(1, sizeof(lclContext));	AH->formatData = (void *) ctx;	ctx->filePos = 0;	ctx->isSpecialScript = 0;	/* Initialize LO buffering */	AH->lo_buf_size = LOBBUFSIZE;	AH->lo_buf = (void *) malloc(LOBBUFSIZE);	if (AH->lo_buf == NULL)		die_horribly(AH, modulename, "out of memory\n");	/*	 * Now open the TOC file	 */	if (AH->mode == archModeWrite)	{		if (AH->fSpec && strcmp(AH->fSpec, "") != 0)			ctx->tarFH = fopen(AH->fSpec, PG_BINARY_W);		else			ctx->tarFH = stdout;		if (ctx->tarFH == NULL)			die_horribly(NULL, modulename,				"could not open TOC file for output: %s\n", strerror(errno));		ctx->tarFHpos = 0;		/*		 * Make unbuffered since we will dup() it, and the buffers screw each		 * other		 */		/* setvbuf(ctx->tarFH, NULL, _IONBF, 0); */		ctx->hasSeek = checkSeek(ctx->tarFH);		if (AH->compression < 0 || AH->compression > 9)			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;		/*		 * We don't support compression because reading the files back is not		 * possible since gzdopen uses buffered IO which totally screws file		 * positioning.		 */		if (AH->compression != 0)			die_horribly(NULL, modulename, "compression not supported by tar output format\n");	}	else	{							/* Read Mode */		if (AH->fSpec && strcmp(AH->fSpec, "") != 0)			ctx->tarFH = fopen(AH->fSpec, PG_BINARY_R);		else			ctx->tarFH = stdin;		if (ctx->tarFH == NULL)			die_horribly(NULL, modulename, "could not open TOC file for input: %s\n", strerror(errno));		/*		 * Make unbuffered since we will dup() it, and the buffers screw each		 * other		 */		/* setvbuf(ctx->tarFH, NULL, _IONBF, 0); */		ctx->tarFHpos = 0;		ctx->hasSeek = checkSeek(ctx->tarFH);		/*		 * Forcibly unmark the header as read since we use the lookahead		 * buffer		 */		AH->readHeader = 0;		ctx->FH = (void *) tarOpen(AH, "toc.dat", 'r');		ReadHead(AH);		ReadToc(AH);		tarClose(AH, ctx->FH);	/* Nothing else in the file... */	}}/* * - Start a new TOC entry *	 Setup the output file name. */static void_ArchiveEntry(ArchiveHandle *AH, TocEntry *te){	lclTocEntry *ctx;	char		fn[K_STD_BUF_SIZE];	ctx = (lclTocEntry *) calloc(1, sizeof(lclTocEntry));	if (te->dataDumper != NULL)	{#ifdef HAVE_LIBZ		if (AH->compression == 0)			sprintf(fn, "%d.dat", te->dumpId);		else			sprintf(fn, "%d.dat.gz", te->dumpId);#else		sprintf(fn, "%d.dat", te->dumpId);#endif		ctx->filename = strdup(fn);	}	else	{		ctx->filename = NULL;		ctx->TH = NULL;	}	te->formatData = (void *) ctx;}static void_WriteExtraToc(ArchiveHandle *AH, TocEntry *te){	lclTocEntry *ctx = (lclTocEntry *) te->formatData;	if (ctx->filename)		WriteStr(AH, ctx->filename);	else		WriteStr(AH, "");}static void_ReadExtraToc(ArchiveHandle *AH, TocEntry *te){	lclTocEntry *ctx = (lclTocEntry *) te->formatData;	if (ctx == NULL)	{		ctx = (lclTocEntry *) calloc(1, sizeof(lclTocEntry));		te->formatData = (void *) ctx;	}	ctx->filename = ReadStr(AH);	if (strlen(ctx->filename) == 0)	{		free(ctx->filename);		ctx->filename = NULL;	}	ctx->TH = NULL;}static void_PrintExtraToc(ArchiveHandle *AH, TocEntry *te){	lclTocEntry *ctx = (lclTocEntry *) te->formatData;	if (AH->public.verbose && ctx->filename != NULL)		ahprintf(AH, "-- File: %s\n", ctx->filename);}static void_StartData(ArchiveHandle *AH, TocEntry *te){	lclTocEntry *tctx = (lclTocEntry *) te->formatData;	tctx->TH = tarOpen(AH, tctx->filename, 'w');}static TAR_MEMBER *tarOpen(ArchiveHandle *AH, const char *filename, char mode){	lclContext *ctx = (lclContext *) AH->formatData;	TAR_MEMBER *tm;#ifdef HAVE_LIBZ	char		fmode[10];#endif	if (mode == 'r')	{		tm = _tarPositionTo(AH, filename);		if (!tm)				/* Not found */		{			if (filename)		/* Couldn't find the requested file. Future:								 * DO SEEK(0) and retry. */				die_horribly(AH, modulename, "could not find file %s in archive\n", filename);			else				/* Any file OK, non left, so return NULL */				return NULL;		}#ifdef HAVE_LIBZ		if (AH->compression == 0)			tm->nFH = ctx->tarFH;		else			die_horribly(AH, modulename, "compression support is disabled in this format\n");		/* tm->zFH = gzdopen(dup(fileno(ctx->tarFH)), "rb"); */#else		tm->nFH = ctx->tarFH;#endif	}	else	{		tm = calloc(1, sizeof(TAR_MEMBER));		tm->tmpFH = tmpfile();		if (tm->tmpFH == NULL)			die_horribly(AH, modulename, "could not generate temporary file name: %s\n", strerror(errno));#ifdef HAVE_LIBZ		if (AH->compression != 0)		{			sprintf(fmode, "wb%d", AH->compression);			tm->zFH = gzdopen(dup(fileno(tm->tmpFH)), fmode);			if (tm->zFH == NULL)				die_horribly(AH, modulename, "could not open temporary file\n");		}		else			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;}static voidtarClose(ArchiveHandle *AH, TAR_MEMBER *th){	/*	 * Close the GZ file since we dup'd. This will flush the buffers.	 */	if (AH->compression != 0)		if (GZCLOSE(th->zFH) != 0)			die_horribly(AH, modulename, "could not close tar member\n");	if (th->mode == 'w')		_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.	 */	if (th->targetFile)		free(th->targetFile);	th->nFH = NULL;	th->zFH = NULL;}#ifdef __NOT_USED__static char *tarGets(char *buf, size_t len, TAR_MEMBER *th){	char	   *s;	size_t		cnt = 0;	char		c = ' ';	int			eof = 0;	/* Can't read past logical EOF */	if (len > (th->fileLen - th->pos))		len = th->fileLen - th->pos;	while (cnt < len && c != '\n')	{		if (_tarReadRaw(th->AH, &c, 1, th, NULL) <= 0)		{			eof = 1;			break;		}		buf[cnt++] = c;	}	if (eof && cnt == 0)		s = NULL;	else	{		buf[cnt++] = '\0';		s = buf;	}	if (s)	{		len = strlen(s);		th->pos += len;	}	return s;}#endif/* * Just read bytes from the archive. This is the low level read routine * that is used for ALL reads on a tar file. */static size_t_tarReadRaw(ArchiveHandle *AH, void *buf, size_t len, TAR_MEMBER *th, FILE *fh){	lclContext *ctx = (lclContext *) AH->formatData;	size_t		avail;	size_t		used = 0;	size_t		res = 0;	avail = AH->lookaheadLen - AH->lookaheadPos;	if (avail > 0)	{		/* We have some lookahead bytes to use */		if (avail >= len)		/* Just use the lookahead buffer */			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)			res = fread(&((char *) buf)[used], 1, len, fh);		else if (th)		{			if (th->zFH)				res = GZREAD(&((char *) buf)[used], 1, len, th->zFH);			else				res = fread(&((char *) buf)[used], 1, len, th->nFH);		}		else			die_horribly(AH, modulename, "internal error -- neither th nor fh specified in tarReadRaw()\n");	}#if 0	write_msg(modulename, "requested %d bytes, got %d from lookahead and %d from file\n",			  reqLen, used, res);#endif	ctx->tarFHpos += res + used;	return (res + used);}static size_ttarRead(void *buf, size_t len, TAR_MEMBER *th){	size_t		res;	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;}static size_ttarWrite(const void *buf, size_t len, TAR_MEMBER *th){	size_t		res;	if (th->zFH != 0)		res = GZWRITE((void *) buf, 1, len, th->zFH);	else		res = fwrite(buf, 1, len, th->nFH);	if (res != len)		die_horribly(th->AH, modulename,				"could not write to tar member (wrote %lu, attempted %lu)\n",					 (unsigned long) res, (unsigned long) len);	th->pos += res;	return res;}static size_t_WriteData(ArchiveHandle *AH, const void *data, size_t dLen){	lclTocEntry *tctx = (lclTocEntry *) AH->currToc->formatData;	dLen = tarWrite((void *) data, dLen, tctx->TH);	return dLen;}static void_EndData(ArchiveHandle *AH, TocEntry *te){	lclTocEntry *tctx = (lclTocEntry *) te->formatData;	/* Close the file */	tarClose(AH, tctx->TH);	tctx->TH = NULL;}/* * Print data for a given file */static void_PrintFileData(ArchiveHandle *AH, char *filename, RestoreOptions *ropt){	lclContext *ctx = (lclContext *) AH->formatData;	char		buf[4096];	size_t		cnt;	TAR_MEMBER *th;	if (!filename)		return;	th = tarOpen(AH, filename, 'r');	ctx->FH = th;	while ((cnt = tarRead(buf, 4095, th)) > 0)	{		buf[cnt] = '\0';		ahwrite(buf, 1, cnt, AH);	}	tarClose(AH, th);}/* * Print data for a given TOC entry*/static void_PrintTocData(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt){	lclContext *ctx = (lclContext *) AH->formatData;	lclTocEntry *tctx = (lclTocEntry *) te->formatData;	char	   *tmpCopy;	size_t		i,				pos1,				pos2;	if (!tctx->filename)		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);		for (i = 0; i < strlen(tmpCopy); i++)			tmpCopy[i] = pg_tolower((unsigned char) tmpCopy[i]);		/*		 * 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.		 */		if (strncmp(tmpCopy, "copy ", 5) != 0)			die_horribly(AH, modulename,						 "invalid COPY statement -- could not find \"copy\" in string \"%s\"\n", tmpCopy);		pos1 = 5;		for (pos1 = 5; pos1 < strlen(tmpCopy); pos1++)			if (tmpCopy[pos1] != ' ')				break;		if (tmpCopy[pos1] == '"')			pos1 += 2;		pos1 += strlen(te->tag);		for (pos2 = pos1; pos2 < strlen(tmpCopy); pos2++)			if (strncmp(&tmpCopy[pos2], "from stdin", 10) == 0)				break;		if (pos2 >= strlen(tmpCopy))			die_horribly(AH, modulename,						 "invalid COPY statement -- could not find \"from stdin\" in string \"%s\" starting at position %lu\n",						 tmpCopy, (unsigned long) pos1);		ahwrite(tmpCopy, 1, pos2, AH);	/* 'copy "table" [with oids]' */		ahprintf(AH, " from '$$PATH$$/%s' %s", tctx->filename, &tmpCopy[pos2 + 10]);		return;	}	if (strcmp(te->desc, "BLOBS") == 0)		_LoadBlobs(AH, ropt);	else		_PrintFileData(AH, tctx->filename, ropt);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -