📄 pg_backup_files.c
字号:
/*------------------------------------------------------------------------- * * pg_backup_files.c * * This file is copied from the 'custom' format file, but dumps data into * separate files, and the TOC into the 'main' file. * * IT IS FOR DEMONSTRATION PURPOSES ONLY. * * (and could probably be used as a basis for writing a tar file) * * See the headers to 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_files.c,v 1.27 2005/10/15 02:49:38 momjian Exp $ * *------------------------------------------------------------------------- */#include "pg_backup.h"#include "pg_backup_archiver.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 1024typedef struct{ int hasSeek; off_t filePos; FILE *blobToc;} lclContext;typedef struct{#ifdef HAVE_LIBZ gzFile *FH;#else FILE *FH;#endif char *filename;} lclTocEntry;static char *modulename = gettext_noop("file archiver");static void _LoadBlobs(ArchiveHandle *AH, RestoreOptions *ropt);static void _getBlobTocEntry(ArchiveHandle *AH, Oid *oid, char *fname);/* * Initializer */voidInitArchiveFmt_Files(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; /* 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) { write_msg(modulename, "WARNING:\n" " This format is for demonstration purposes; it is not intended for\n" " normal use. Files will be written in the current working directory.\n"); if (AH->fSpec && strcmp(AH->fSpec, "") != 0) AH->FH = fopen(AH->fSpec, PG_BINARY_W); else AH->FH = stdout; if (AH->FH == NULL) die_horribly(NULL, modulename, "could not open output file: %s\n", strerror(errno)); ctx->hasSeek = checkSeek(AH->FH); if (AH->compression < 0 || AH->compression > 9) AH->compression = Z_DEFAULT_COMPRESSION; } else { /* Read Mode */ if (AH->fSpec && strcmp(AH->fSpec, "") != 0) AH->FH = fopen(AH->fSpec, PG_BINARY_R); else AH->FH = stdin; if (AH->FH == NULL) die_horribly(NULL, modulename, "could not open input file: %s\n", strerror(errno)); ctx->hasSeek = checkSeek(AH->FH); ReadHead(AH); ReadToc(AH); /* Nothing else in the file... */ if (fclose(AH->FH) != 0) die_horribly(AH, modulename, "could not close TOC file: %s\n", strerror(errno)); }}/* * - 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) {#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->FH = 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->FH = NULL;}static void_PrintExtraToc(ArchiveHandle *AH, TocEntry *te){ lclTocEntry *ctx = (lclTocEntry *) te->formatData; if (AH->public.verbose) ahprintf(AH, "-- File: %s\n", ctx->filename);}static void_StartData(ArchiveHandle *AH, TocEntry *te){ lclTocEntry *tctx = (lclTocEntry *) te->formatData; char fmode[10]; sprintf(fmode, "wb%d", AH->compression);#ifdef HAVE_LIBZ tctx->FH = gzopen(tctx->filename, fmode);#else tctx->FH = fopen(tctx->filename, PG_BINARY_W);#endif if (tctx->FH == NULL) die_horribly(AH, modulename, "could not open data file for output\n");}static size_t_WriteData(ArchiveHandle *AH, const void *data, size_t dLen){ lclTocEntry *tctx = (lclTocEntry *) AH->currToc->formatData; GZWRITE((void *) data, 1, dLen, tctx->FH); return dLen;}static void_EndData(ArchiveHandle *AH, TocEntry *te){ lclTocEntry *tctx = (lclTocEntry *) te->formatData; /* Close the file */ if (GZCLOSE(tctx->FH) != 0) die_horribly(AH, modulename, "could not close data file\n"); tctx->FH = NULL;}/* * Print data for a given file */static void_PrintFileData(ArchiveHandle *AH, char *filename, RestoreOptions *ropt){ char buf[4096]; size_t cnt; if (!filename) return;#ifdef HAVE_LIBZ AH->FH = gzopen(filename, "rb");#else AH->FH = fopen(filename, PG_BINARY_R);#endif if (AH->FH == NULL) die_horribly(AH, modulename, "could not open data file for input\n"); while ((cnt = GZREAD(buf, 1, 4095, AH->FH)) > 0) { buf[cnt] = '\0'; ahwrite(buf, 1, cnt, AH); } if (GZCLOSE(AH->FH) != 0) die_horribly(AH, modulename, "could not close data file after reading\n");}/* * Print data for a given TOC entry*/static void_PrintTocData(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt){ lclTocEntry *tctx = (lclTocEntry *) te->formatData; if (!tctx->filename) return; if (strcmp(te->desc, "BLOBS") == 0) _LoadBlobs(AH, ropt); else _PrintFileData(AH, tctx->filename, ropt);}static void_getBlobTocEntry(ArchiveHandle *AH, Oid *oid, char fname[K_STD_BUF_SIZE]){ lclContext *ctx = (lclContext *) AH->formatData; char blobTe[K_STD_BUF_SIZE]; size_t fpos; size_t eos; if (fgets(&blobTe[0], K_STD_BUF_SIZE - 1, ctx->blobToc) != NULL) { *oid = atooid(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'; }}static void_LoadBlobs(ArchiveHandle *AH, RestoreOptions *ropt){ Oid oid; lclContext *ctx = (lclContext *) AH->formatData; char fname[K_STD_BUF_SIZE]; StartRestoreBlobs(AH); ctx->blobToc = fopen("blobs.toc", PG_BINARY_R); if (ctx->blobToc == NULL) die_horribly(AH, modulename, "could not open large object TOC for input: %s\n", strerror(errno)); _getBlobTocEntry(AH, &oid, fname); while (oid != 0) { StartRestoreBlob(AH, oid); _PrintFileData(AH, fname, ropt); EndRestoreBlob(AH, oid); _getBlobTocEntry(AH, &oid, fname); } if (fclose(ctx->blobToc) != 0) die_horribly(AH, modulename, "could not close large object TOC file: %s\n", strerror(errno)); EndRestoreBlobs(AH);}static int_WriteByte(ArchiveHandle *AH, const int i){ lclContext *ctx = (lclContext *) AH->formatData; if (fputc(i, AH->FH) == EOF) die_horribly(AH, modulename, "could not write byte\n"); ctx->filePos += 1; return 1;}static int_ReadByte(ArchiveHandle *AH){ lclContext *ctx = (lclContext *) AH->formatData; int res; res = fgetc(AH->FH); if (res != EOF) ctx->filePos += 1; return res;}static size_t_WriteBuf(ArchiveHandle *AH, const void *buf, size_t len){ lclContext *ctx = (lclContext *) AH->formatData; size_t res; res = fwrite(buf, 1, len, AH->FH); if (res != len) die_horribly(AH, modulename, "write error in _WriteBuf (%lu != %lu)\n", (unsigned long) res, (unsigned long) len); ctx->filePos += res; return res;}static size_t_ReadBuf(ArchiveHandle *AH, void *buf, size_t len){ lclContext *ctx = (lclContext *) AH->formatData; size_t res; res = fread(buf, 1, len, AH->FH); ctx->filePos += res; return res;}static void_CloseArchive(ArchiveHandle *AH){ if (AH->mode == archModeWrite) { WriteHead(AH); WriteToc(AH); if (fclose(AH->FH) != 0) die_horribly(AH, modulename, "could not close TOC file: %s\n", strerror(errno)); WriteDataChunks(AH); } AH->FH = NULL;}/* * BLOB support *//* * Called by the archiver when starting to save all BLOB DATA (not schema). * This routine should save whatever format-specific information is needed * to read the BLOBs back into memory. * * It is called just prior to the dumper's DataDumper routine. * * Optional, but strongly recommended. */static void_StartBlobs(ArchiveHandle *AH, TocEntry *te){ lclContext *ctx = (lclContext *) AH->formatData; char fname[K_STD_BUF_SIZE]; sprintf(fname, "blobs.toc"); ctx->blobToc = fopen(fname, PG_BINARY_W); if (ctx->blobToc == NULL) die_horribly(AH, modulename, "could not open large object TOC for output: %s\n", strerror(errno));}/* * Called by the archiver when the dumper calls StartBlob. * * Mandatory. * * Must save the passed OID for retrieval at restore-time. */static void_StartBlob(ArchiveHandle *AH, TocEntry *te, Oid oid){ lclContext *ctx = (lclContext *) AH->formatData; lclTocEntry *tctx = (lclTocEntry *) te->formatData; char fmode[10]; char fname[255]; char *sfx; if (oid == 0) die_horribly(AH, modulename, "invalid OID for large object (%u)\n", oid); if (AH->compression != 0) sfx = ".gz"; else sfx = ""; sprintf(fmode, "wb%d", AH->compression); sprintf(fname, "blob_%u.dat%s", oid, sfx); fprintf(ctx->blobToc, "%u %s\n", oid, fname);#ifdef HAVE_LIBZ tctx->FH = gzopen(fname, fmode);#else tctx->FH = fopen(fname, PG_BINARY_W);#endif if (tctx->FH == NULL) die_horribly(AH, modulename, "could not open large object file\n");}/* * Called by the archiver when the dumper calls EndBlob. * * Optional. */static void_EndBlob(ArchiveHandle *AH, TocEntry *te, Oid oid){ lclTocEntry *tctx = (lclTocEntry *) te->formatData; if (GZCLOSE(tctx->FH) != 0) die_horribly(AH, modulename, "could not close large object file\n");}/* * Called by the archiver when finishing saving all BLOB DATA. * * Optional. */static void_EndBlobs(ArchiveHandle *AH, TocEntry *te){ lclContext *ctx = (lclContext *) AH->formatData; /* Write out a fake zero OID to mark end-of-blobs. */ /* WriteInt(AH, 0); */ if (fclose(ctx->blobToc) != 0) die_horribly(AH, modulename, "could not close large object TOC file: %s\n", strerror(errno));}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -