📄 pg_backup_archiver.c
字号:
va_start(ap, fmt); _die_horribly(AH, modulename, fmt, ap);}static void_moveAfter(ArchiveHandle *AH, TocEntry *pos, TocEntry *te){ te->prev->next = te->next; te->next->prev = te->prev; te->prev = pos; te->next = pos->next; pos->next->prev = te; pos->next = te; te->_moved = 1;}static void_moveBefore(ArchiveHandle *AH, TocEntry *pos, TocEntry *te){ te->prev->next = te->next; te->next->prev = te->prev; te->prev = pos->prev; te->next = pos; pos->prev->next = te; pos->prev = te; te->_moved = 1;}static TocEntry *_getTocEntry(ArchiveHandle *AH, int id){ TocEntry *te; te = AH->toc->next; while (te != AH->toc) { if (te->id == id) return te; te = te->next; } return NULL;}intTocIDRequired(ArchiveHandle *AH, int id, RestoreOptions *ropt){ TocEntry *te = _getTocEntry(AH, id); if (!te) return 0; return _tocEntryRequired(te, ropt);}size_tWriteOffset(ArchiveHandle *AH, off_t o, int wasSet){ int off; /* Save the flag */ (*AH->WriteBytePtr) (AH, wasSet); /* Write out off_t smallest byte first, prevents endian mismatch */ for (off = 0; off < sizeof(off_t); off++) { (*AH->WriteBytePtr) (AH, o & 0xFF); o >>= 8; } return sizeof(off_t) + 1;}intReadOffset(ArchiveHandle *AH, off_t *o){ int i; int off; int offsetFlg; /* Initialize to zero */ *o = 0; /* Check for old version */ if (AH->version < K_VERS_1_7) { /* Prior versions wrote offsets using WriteInt */ i = ReadInt(AH); /* -1 means not set */ if (i < 0) return K_OFFSET_POS_NOT_SET; else if (i == 0) return K_OFFSET_NO_DATA; /* Cast to off_t because it was written as an int. */ *o = (off_t) i; return K_OFFSET_POS_SET; } /* * Read the flag indicating the state of the data pointer. Check if * valid and die if not. * * This used to be handled by a negative or zero pointer, now we use an * extra byte specifically for the state. */ offsetFlg = (*AH->ReadBytePtr) (AH) & 0xFF; switch (offsetFlg) { case K_OFFSET_POS_NOT_SET: case K_OFFSET_NO_DATA: case K_OFFSET_POS_SET: break; default: die_horribly(AH, modulename, "Unexpected data offset flag %d\n", offsetFlg); } /* * Read the bytes */ for (off = 0; off < AH->offSize; off++) { if (off < sizeof(off_t)) *o |= ((off_t) ((*AH->ReadBytePtr) (AH))) << (off * 8); else { if ((*AH->ReadBytePtr) (AH) != 0) die_horribly(AH, modulename, "file offset in dump file is too large\n"); } } return offsetFlg;}size_tWriteInt(ArchiveHandle *AH, int i){ int b; /* * This is a bit yucky, but I don't want to make the binary format * very dependent on representation, and not knowing much about it, I * write out a sign byte. If you change this, don't forget to change * the file version #, and modify readInt to read the new format AS * WELL AS the old formats. */ /* SIGN byte */ if (i < 0) { (*AH->WriteBytePtr) (AH, 1); i = -i; } else (*AH->WriteBytePtr) (AH, 0); for (b = 0; b < AH->intSize; b++) { (*AH->WriteBytePtr) (AH, i & 0xFF); i >>= 8; } return AH->intSize + 1;}intReadInt(ArchiveHandle *AH){ int res = 0; int bv, b; int sign = 0; /* Default positive */ int bitShift = 0; if (AH->version > K_VERS_1_0) /* Read a sign byte */ sign = (*AH->ReadBytePtr) (AH); for (b = 0; b < AH->intSize; b++) { bv = (*AH->ReadBytePtr) (AH) & 0xFF; if (bv != 0) res = res + (bv << bitShift); bitShift += 8; } if (sign) res = -res; return res;}size_tWriteStr(ArchiveHandle *AH, const char *c){ size_t res; if (c) { res = WriteInt(AH, strlen(c)); res += (*AH->WriteBufPtr) (AH, c, strlen(c)); } else res = WriteInt(AH, -1); return res;}char *ReadStr(ArchiveHandle *AH){ char *buf; int l; l = ReadInt(AH); if (l == -1) buf = NULL; else { buf = (char *) malloc(l + 1); if (!buf) die_horribly(AH, modulename, "out of memory\n"); (*AH->ReadBufPtr) (AH, (void *) buf, l); buf[l] = '\0'; } return buf;}static int_discoverArchiveFormat(ArchiveHandle *AH){ FILE *fh; char sig[6]; /* More than enough */ size_t cnt; int wantClose = 0;#if 0 write_msg(modulename, "attempting to ascertain archive format\n");#endif if (AH->lookahead) free(AH->lookahead); AH->lookaheadSize = 512; AH->lookahead = calloc(1, 512); AH->lookaheadLen = 0; AH->lookaheadPos = 0; if (AH->fSpec) { wantClose = 1; fh = fopen(AH->fSpec, PG_BINARY_R); } else fh = stdin; if (!fh) die_horribly(AH, modulename, "could not open input file: %s\n", strerror(errno)); cnt = fread(sig, 1, 5, fh); if (cnt != 5) { if (ferror(fh)) die_horribly(AH, modulename, "could not read input file: %s\n", strerror(errno)); else die_horribly(AH, modulename, "input file is too short (read %lu, expected 5)\n", (unsigned long) cnt); } /* Save it, just in case we need it later */ strncpy(&AH->lookahead[0], sig, 5); AH->lookaheadLen = 5; if (strncmp(sig, "PGDMP", 5) == 0) { AH->vmaj = fgetc(fh); AH->vmin = fgetc(fh); /* Save these too... */ AH->lookahead[AH->lookaheadLen++] = AH->vmaj; AH->lookahead[AH->lookaheadLen++] = AH->vmin; /* Check header version; varies from V1.0 */ if (AH->vmaj > 1 || ((AH->vmaj == 1) && (AH->vmin > 0))) /* Version > 1.0 */ { AH->vrev = fgetc(fh); AH->lookahead[AH->lookaheadLen++] = AH->vrev; } else AH->vrev = 0; /* Make a convenient integer <maj><min><rev>00 */ AH->version = ((AH->vmaj * 256 + AH->vmin) * 256 + AH->vrev) * 256 + 0; AH->intSize = fgetc(fh); AH->lookahead[AH->lookaheadLen++] = AH->intSize; if (AH->version >= K_VERS_1_7) { AH->offSize = fgetc(fh); AH->lookahead[AH->lookaheadLen++] = AH->offSize; } else AH->offSize = AH->intSize; AH->format = fgetc(fh); AH->lookahead[AH->lookaheadLen++] = AH->format; } else { /* * *Maybe* we have a tar archive format file... So, read first 512 * byte header... */ cnt = fread(&AH->lookahead[AH->lookaheadLen], 1, 512 - AH->lookaheadLen, fh); AH->lookaheadLen += cnt; if (AH->lookaheadLen != 512) die_horribly(AH, modulename, "input file does not appear to be a valid archive (too short?)\n"); if (!isValidTarHeader(AH->lookahead)) die_horribly(AH, modulename, "input file does not appear to be a valid archive\n"); AH->format = archTar; } /* If we can't seek, then mark the header as read */ if (fseeko(fh, 0, SEEK_SET) != 0) { /* * NOTE: Formats that use the lookahead buffer can unset this in * their Init routine. */ AH->readHeader = 1; } else AH->lookaheadLen = 0; /* Don't bother since we've reset the file */#if 0 write_msg(modulename, "read %lu bytes into lookahead buffer\n", (unsigned long) AH->lookaheadLen);#endif /* Close the file */ if (wantClose) if (fclose(fh) != 0) die_horribly(AH, modulename, "could not close the input file after reading header: %s\n", strerror(errno)); return AH->format;}/* * Allocate an archive handle */static ArchiveHandle *_allocAH(const char *FileSpec, const ArchiveFormat fmt, const int compression, ArchiveMode mode){ ArchiveHandle *AH;#if 0 write_msg(modulename, "allocating AH for %s, format %d\n", FileSpec, fmt);#endif AH = (ArchiveHandle *) calloc(1, sizeof(ArchiveHandle)); if (!AH) die_horribly(AH, modulename, "out of memory\n"); /* AH->debugLevel = 100; */ AH->vmaj = K_VERS_MAJOR; AH->vmin = K_VERS_MINOR; AH->vrev = K_VERS_REV; AH->createDate = time(NULL); AH->intSize = sizeof(int); AH->offSize = sizeof(off_t); AH->lastID = 0; if (FileSpec) { AH->fSpec = strdup(FileSpec); /* * Not used; maybe later.... * * AH->workDir = strdup(FileSpec); for(i=strlen(FileSpec) ; i > 0 ; * i--) if (AH->workDir[i-1] == '/') */ } else AH->fSpec = NULL; AH->currUser = strdup(""); /* So it's valid, but we can free() it * later if necessary */ AH->currSchema = strdup(""); /* ditto */ AH->toc = (TocEntry *) calloc(1, sizeof(TocEntry)); if (!AH->toc) die_horribly(AH, modulename, "out of memory\n"); AH->toc->next = AH->toc; AH->toc->prev = AH->toc; AH->mode = mode; AH->compression = compression; AH->pgCopyBuf = createPQExpBuffer(); AH->sqlBuf = createPQExpBuffer(); /* Open stdout with no compression for AH output handle */ AH->gzOut = 0; AH->OF = stdout;#if 0 write_msg(modulename, "archive format is %d\n", fmt);#endif if (fmt == archUnknown) AH->format = _discoverArchiveFormat(AH); else AH->format = fmt; switch (AH->format) { case archCustom: InitArchiveFmt_Custom(AH); break; case archFiles: InitArchiveFmt_Files(AH); break; case archNull: InitArchiveFmt_Null(AH); break; case archTar: InitArchiveFmt_Tar(AH); break; default: die_horribly(AH, modulename, "unrecognized file format \"%d\"\n", fmt); } return AH;}voidWriteDataChunks(ArchiveHandle *AH){ TocEntry *te = AH->toc->next; StartDataPtr startPtr; EndDataPtr endPtr; while (te != AH->toc) { if (te->dataDumper != NULL) { AH->currToc = te; /* printf("Writing data for %d (%x)\n", te->id, te); */ if (strcmp(te->desc, "BLOBS") == 0) { startPtr = AH->StartBlobsPtr; endPtr = AH->EndBlobsPtr; } else { startPtr = AH->StartDataPtr; endPtr = AH->EndDataPtr; } if (startPtr != NULL) (*startPtr) (AH, te); /* * printf("Dumper arg for %d is %x\n", te->id, * te->dataDumperArg); */ /* * The user-provided DataDumper routine needs to call * AH->WriteData */ (*te->dataDumper) ((Archive *) AH, te->oid, te->dataDumperArg); if (endPtr != NULL) (*endPtr) (AH, te); AH->currToc = NULL; } te = te->next; }}voidWriteToc(ArchiveHandle *AH){ TocEntry *te = AH->toc->next; const char *dep; int i; /* printf("%d TOC Entries to save\n", AH->tocCount); */ WriteInt(AH, AH->tocCount); while (te != AH->toc) { WriteInt(AH, te->id); WriteInt(AH, te->dataDumper ? 1 : 0); WriteStr(AH, te->oid); WriteStr(AH, te->tag); WriteStr(AH, te->desc); WriteStr(AH, te->defn); WriteStr(AH, te->dropStmt); WriteStr(AH, te->copyStmt); WriteStr(AH, te->namespace); WriteStr(AH, te->owner); /* Dump list of dependencies */ if (te->depOid != NULL) { i = 0; while ((dep = (*te->depOid)[i++]) != NULL) WriteStr(AH, dep); } WriteStr(AH, NULL); /* Terminate List */ if (AH->WriteExtraTocPtr) (*AH->WriteExtraTocPtr) (AH, te); te = te->next; }}voidReadToc(ArchiveHandle *AH){ int i; char *((*deps)[]); int depIdx; int depSize; TocEntry *te = AH->toc->next; AH->tocCount = ReadInt(AH); for (i = 0; i < AH->tocCount; i++) { te = (TocEntry *) calloc(1, sizeof(TocEntry)); te->id = ReadInt(AH); /* Sanity check */ if (te->id <= 0 || te->id > AH->tocCount) die_horribly(AH, modulename, "entry ID %d out of range -- perhaps a corrupt TOC\n", te->id); te->hadDumper = ReadInt(AH); te->oid = ReadStr(AH); te->oidVal = atooid(te->oid); te->tag = ReadStr(AH); te->desc = ReadStr(AH); te->defn = ReadStr(AH); te->dropStmt = ReadStr(AH); if (AH->version >= K_VERS_1_3) te->copyStmt = ReadStr(AH); if (AH->version >= K_VERS_1_6) te->namespace = ReadStr(AH); te->owner = ReadStr(AH); /* Read TOC entry dependencies */ if (AH->version >= K_VERS_1_5) { depSize = 100; deps = malloc(sizeof(char *) * depSize); depIdx = 0; do { if (depIdx >= depSize) { depSize *= 2; deps = realloc(deps, sizeof(char *) * depSize); } (*deps)[depIdx] = ReadStr(AH);#if 0 if ((*deps)[depIdx]) write_msg(modulename, "read dependency for %s -> %s\n", te->tag, (*deps)[depIdx]);#endif } while ((*deps)[depIdx++] != NULL); if (depIdx > 1) /* We have a non-null entry */ te->depOid = realloc(deps, sizeof(char *) * depIdx); /* trim it */ else { free(deps); te->depOid = NULL; /* no deps */ } } else te->depOid = NULL; /* Set maxOidVal etc for use in sorting */ _fixupOidInfo(te); if (AH->ReadExtraTocPtr) (*AH->ReadExtraTocPtr) (AH, te); ahlog(AH, 3, "read TOC entry %d (ID %d) for %s %s\n", i, te->id, te->desc, te->tag); te->prev = AH->toc->prev; AH->toc->prev->next = te; AH->toc->prev = te; te->next = AH->toc; }}static teReqs_tocEntryRequired(TocEntry *te, RestoreOptions *ropt){ teReqs res = 3; /* Schema = 1, Data = 2, Both = 3 */ /* ENCODING objects are dumped specially, so always reject here */ if (strcmp(te->desc, "ENCODING") == 0) return 0; /* If it's an ACL, maybe ignore it */ if (ropt->aclsSkip && strcmp(te->desc, "ACL") == 0) return 0; if (!ropt->create && strcmp(te->desc, "DATABASE") == 0) return 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -