📄 pg_backup_archiver.c
字号:
newToc->nDeps = 0; } newToc->dataDumper = dumpFn; newToc->dataDumperArg = dumpArg; newToc->hadDumper = dumpFn ? true : false; newToc->formatData = NULL; if (AH->ArchiveEntryPtr !=NULL) (*AH->ArchiveEntryPtr) (AH, newToc);}/* Public */voidPrintTOCSummary(Archive *AHX, RestoreOptions *ropt){ ArchiveHandle *AH = (ArchiveHandle *) AHX; TocEntry *te = AH->toc->next; OutputContext sav; char *fmtName; if (ropt->filename) sav = SetOutput(AH, ropt->filename, 0 /* no compression */ ); ahprintf(AH, ";\n; Archive created at %s", ctime(&AH->createDate)); ahprintf(AH, "; dbname: %s\n; TOC Entries: %d\n; Compression: %d\n", AH->archdbname, AH->tocCount, AH->compression); switch (AH->format) { case archFiles: fmtName = "FILES"; break; case archCustom: fmtName = "CUSTOM"; break; case archTar: fmtName = "TAR"; break; default: fmtName = "UNKNOWN"; } ahprintf(AH, "; Dump Version: %d.%d-%d\n", AH->vmaj, AH->vmin, AH->vrev); ahprintf(AH, "; Format: %s\n", fmtName); ahprintf(AH, "; Integer: %d bytes\n", (int) AH->intSize); ahprintf(AH, "; Offset: %d bytes\n", (int) AH->offSize); if (AH->archiveRemoteVersion) ahprintf(AH, "; Dumped from database version: %s\n", AH->archiveRemoteVersion); if (AH->archiveDumpVersion) ahprintf(AH, "; Dumped by pg_dump version: %s\n", AH->archiveDumpVersion); ahprintf(AH, ";\n;\n; Selected TOC Entries:\n;\n"); while (te != AH->toc) { if (_tocEntryRequired(te, ropt, true) != 0) ahprintf(AH, "%d; %u %u %s %s %s %s\n", te->dumpId, te->catalogId.tableoid, te->catalogId.oid, te->desc, te->namespace ? te->namespace : "-", te->tag, te->owner); te = te->next; } if (ropt->filename) ResetOutput(AH, sav);}/*********** * BLOB Archival ***********//* Called by a dumper to signal start of a BLOB */intStartBlob(Archive *AHX, Oid oid){ ArchiveHandle *AH = (ArchiveHandle *) AHX; if (!AH->StartBlobPtr) die_horribly(AH, modulename, "large-object output not supported in chosen format\n"); (*AH->StartBlobPtr) (AH, AH->currToc, oid); return 1;}/* Called by a dumper to signal end of a BLOB */intEndBlob(Archive *AHX, Oid oid){ ArchiveHandle *AH = (ArchiveHandle *) AHX; if (AH->EndBlobPtr) (*AH->EndBlobPtr) (AH, AH->currToc, oid); return 1;}/********** * BLOB Restoration **********//* * Called by a format handler before any blobs are restored */voidStartRestoreBlobs(ArchiveHandle *AH){ if (AH->connection) StartTransaction(AH); else ahprintf(AH, "BEGIN;\n\n"); AH->blobCount = 0;}/* * Called by a format handler after all blobs are restored */voidEndRestoreBlobs(ArchiveHandle *AH){ if (AH->connection) CommitTransaction(AH); else ahprintf(AH, "COMMIT;\n\n"); ahlog(AH, 1, "restored %d large objects\n", AH->blobCount);}/* * Called by a format handler to initiate restoration of a blob */voidStartRestoreBlob(ArchiveHandle *AH, Oid oid){ Oid loOid; AH->blobCount++; /* Initialize the LO Buffer */ AH->lo_buf_used = 0; ahlog(AH, 2, "restoring large object with OID %u\n", oid); if (AH->connection) { loOid = lo_create(AH->connection, oid); if (loOid == 0 || loOid != oid) die_horribly(AH, modulename, "could not create large object %u\n", oid); AH->loFd = lo_open(AH->connection, oid, INV_WRITE); if (AH->loFd == -1) die_horribly(AH, modulename, "could not open large object\n"); } else { ahprintf(AH, "SELECT lo_open(lo_create(%u), %d);\n", oid, INV_WRITE); } AH->writingBlob = 1;}voidEndRestoreBlob(ArchiveHandle *AH, Oid oid){ if (AH->lo_buf_used > 0) { /* Write remaining bytes from the LO buffer */ dump_lo_buf(AH); } AH->writingBlob = 0; if (AH->connection) { lo_close(AH->connection, AH->loFd); AH->loFd = -1; } else { ahprintf(AH, "SELECT lo_close(0);\n\n"); }}/*********** * Sorting and Reordering ***********/voidSortTocFromFile(Archive *AHX, RestoreOptions *ropt){ ArchiveHandle *AH = (ArchiveHandle *) AHX; FILE *fh; char buf[1024]; char *cmnt; char *endptr; DumpId id; TocEntry *te; TocEntry *tePrev; /* Allocate space for the 'wanted' array, and init it */ ropt->idWanted = (bool *) malloc(sizeof(bool) * AH->maxDumpId); memset(ropt->idWanted, 0, sizeof(bool) * AH->maxDumpId); ropt->limitToList = true; /* Set prev entry as head of list */ tePrev = AH->toc; /* Setup the file */ fh = fopen(ropt->tocFile, PG_BINARY_R); if (!fh) die_horribly(AH, modulename, "could not open TOC file\n"); while (fgets(buf, sizeof(buf), fh) != NULL) { /* Truncate line at comment, if any */ cmnt = strchr(buf, ';'); if (cmnt != NULL) cmnt[0] = '\0'; /* Ignore if all blank */ if (strspn(buf, " \t\r") == strlen(buf)) continue; /* Get an ID, check it's valid and not already seen */ id = strtol(buf, &endptr, 10); if (endptr == buf || id <= 0 || id > AH->maxDumpId || ropt->idWanted[id - 1]) { write_msg(modulename, "WARNING: line ignored: %s\n", buf); continue; } /* Find TOC entry */ te = getTocEntryByDumpId(AH, id); if (!te) die_horribly(AH, modulename, "could not find entry for ID %d\n", id); ropt->idWanted[id - 1] = true; _moveAfter(AH, tePrev, te); tePrev = te; } if (fclose(fh) != 0) die_horribly(AH, modulename, "could not close TOC file: %s\n", strerror(errno));}/********************** * 'Convenience functions that look like standard IO functions * for writing data when in dump mode. **********************//* Public */intarchputs(const char *s, Archive *AH){ return WriteData(AH, s, strlen(s));}/* Public */intarchprintf(Archive *AH, const char *fmt,...){ char *p = NULL; va_list ap; int bSize = strlen(fmt) + 256; int cnt = -1; /* * 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)) { if (p != NULL) free(p); bSize *= 2; p = (char *) malloc(bSize); if (p == NULL) exit_horribly(AH, modulename, "out of memory\n"); va_start(ap, fmt); cnt = vsnprintf(p, bSize, fmt, ap); va_end(ap); } WriteData(AH, p, cnt); free(p); return cnt;}/******************************* * Stuff below here should be 'private' to the archiver routines *******************************/OutputContextSetOutput(ArchiveHandle *AH, char *filename, int compression){ OutputContext sav; int fn; /* Replace the AH output file handle */ sav.OF = AH->OF; sav.gzOut = AH->gzOut; if (filename) fn = -1; else if (AH->FH) fn = fileno(AH->FH); else if (AH->fSpec) { fn = -1; filename = AH->fSpec; } else fn = fileno(stdout); /* If compression explicitly requested, use gzopen */#ifdef HAVE_LIBZ if (compression != 0) { char fmode[10]; /* Don't use PG_BINARY_x since this is zlib */ sprintf(fmode, "wb%d", compression); if (fn >= 0) AH->OF = gzdopen(dup(fn), fmode); else AH->OF = gzopen(filename, fmode); AH->gzOut = 1; } else#endif { /* Use fopen */ if (fn >= 0) AH->OF = fdopen(dup(fn), PG_BINARY_W); else AH->OF = fopen(filename, PG_BINARY_W); AH->gzOut = 0; } if (!AH->OF) die_horribly(AH, modulename, "could not open output file: %s\n", strerror(errno)); return sav;}voidResetOutput(ArchiveHandle *AH, OutputContext sav){ int res; if (AH->gzOut) res = GZCLOSE(AH->OF); else res = fclose(AH->OF); if (res != 0) die_horribly(AH, modulename, "could not close output file: %s\n", strerror(errno)); AH->gzOut = sav.gzOut; AH->OF = sav.OF;}/* * Print formatted text to the output file (usually stdout). */intahprintf(ArchiveHandle *AH, const char *fmt,...){ char *p = NULL; va_list ap; int bSize = strlen(fmt) + 256; /* Should be enough */ int cnt = -1; /* * 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)) { if (p != NULL) free(p); bSize *= 2; p = (char *) malloc(bSize); if (p == NULL) die_horribly(AH, modulename, "out of memory\n"); va_start(ap, fmt); cnt = vsnprintf(p, bSize, fmt, ap); va_end(ap); } ahwrite(p, 1, cnt, AH); free(p); return cnt;}voidahlog(ArchiveHandle *AH, int level, const char *fmt,...){ va_list ap; if (AH->debugLevel < level && (!AH->public.verbose || level > 1)) return; va_start(ap, fmt); _write_msg(NULL, fmt, ap); va_end(ap);}/* * Single place for logic which says 'We are restoring to a direct DB connection'. */intRestoringToDB(ArchiveHandle *AH){ return (AH->ropt && AH->ropt->useDB && AH->connection);}/* * Dump the current contents of the LO data buffer while writing a BLOB */static voiddump_lo_buf(ArchiveHandle *AH){ if (AH->connection) { size_t res; res = lo_write(AH->connection, AH->loFd, AH->lo_buf, AH->lo_buf_used); ahlog(AH, 5, "wrote %lu bytes of large object data (result = %lu)\n", (unsigned long) AH->lo_buf_used, (unsigned long) res); if (res != AH->lo_buf_used) die_horribly(AH, modulename, "could not write to large object (result: %lu, expected: %lu)\n", (unsigned long) res, (unsigned long) AH->lo_buf_used); } else { unsigned char *str; size_t len; str = PQescapeBytea((const unsigned char *) AH->lo_buf, AH->lo_buf_used, &len); if (!str) die_horribly(AH, modulename, "out of memory\n"); /* Hack: turn off writingBlob so ahwrite doesn't recurse to here */ AH->writingBlob = 0; ahprintf(AH, "SELECT lowrite(0, '%s');\n", str); AH->writingBlob = 1; free(str); } AH->lo_buf_used = 0;}/* * Write buffer to the output file (usually stdout). This is user for * outputting 'restore' scripts etc. It is even possible for an archive * format to create a custom output routine to 'fake' a restore if it * wants to generate a script (see TAR output). */intahwrite(const void *ptr, size_t size, size_t nmemb, ArchiveHandle *AH){ size_t res; if (AH->writingBlob) { size_t remaining = size * nmemb; while (AH->lo_buf_used + remaining > AH->lo_buf_size) { size_t avail = AH->lo_buf_size - AH->lo_buf_used; memcpy((char *) AH->lo_buf + AH->lo_buf_used, ptr, avail); ptr = (const void *) ((const char *) ptr + avail); remaining -= avail; AH->lo_buf_used += avail; dump_lo_buf(AH); } memcpy((char *) AH->lo_buf + AH->lo_buf_used, ptr, remaining); AH->lo_buf_used += remaining; return size * nmemb; } else if (AH->gzOut) { res = GZWRITE((void *) ptr, size, nmemb, AH->OF); if (res != (nmemb * size)) die_horribly(AH, modulename, "could not write to compressed archive\n"); return res; } else if (AH->CustomOutPtr) { res = AH->CustomOutPtr (AH, ptr, size * nmemb); if (res != (nmemb * size)) die_horribly(AH, modulename, "could not write to custom output routine\n"); return res; } else { /* * If we're doing a restore, and it's direct to DB, and we're * connected then send it to the DB. */ if (RestoringToDB(AH)) return ExecuteSqlCommandBuf(AH, (void *) ptr, size * nmemb); /* Always 1, currently */ else { res = fwrite((void *) ptr, size, nmemb, AH->OF); if (res != nmemb) die_horribly(AH, modulename, "could not write to output file (%lu != %lu)\n", (unsigned long) res, (unsigned long) nmemb);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -