diff --git a/src/bin/pg_dump/pg_backup_archiver.c b/src/bin/pg_dump/pg_backup_archiver.c index a7ad61ffa9..d9a028aa52 100644 --- a/src/bin/pg_dump/pg_backup_archiver.c +++ b/src/bin/pg_dump/pg_backup_archiver.c @@ -2104,6 +2104,7 @@ _discoverArchiveFormat(ArchiveHandle *AH) if (AH->lookahead) free(AH->lookahead); + AH->readHeader = 0; AH->lookaheadSize = 512; AH->lookahead = pg_malloc0(512); AH->lookaheadLen = 0; @@ -2177,62 +2178,9 @@ _discoverArchiveFormat(ArchiveHandle *AH) if (strncmp(sig, "PGDMP", 5) == 0) { - int byteread; - char vmaj, - vmin, - vrev; - - /* - * Finish reading (most of) a custom-format header. - * - * NB: this code must agree with ReadHead(). - */ - if ((byteread = fgetc(fh)) == EOF) - READ_ERROR_EXIT(fh); - - vmaj = byteread; - - if ((byteread = fgetc(fh)) == EOF) - READ_ERROR_EXIT(fh); - - vmin = byteread; - - /* Save these too... */ - AH->lookahead[AH->lookaheadLen++] = vmaj; - AH->lookahead[AH->lookaheadLen++] = vmin; - - /* Check header version; varies from V1.0 */ - if (vmaj > 1 || (vmaj == 1 && vmin > 0)) /* Version > 1.0 */ - { - if ((byteread = fgetc(fh)) == EOF) - READ_ERROR_EXIT(fh); - - vrev = byteread; - AH->lookahead[AH->lookaheadLen++] = vrev; - } - else - vrev = 0; - - AH->version = MAKE_ARCHIVE_VERSION(vmaj, vmin, vrev); - - if ((AH->intSize = fgetc(fh)) == EOF) - READ_ERROR_EXIT(fh); - AH->lookahead[AH->lookaheadLen++] = AH->intSize; - - if (AH->version >= K_VERS_1_7) - { - if ((AH->offSize = fgetc(fh)) == EOF) - READ_ERROR_EXIT(fh); - AH->lookahead[AH->lookaheadLen++] = AH->offSize; - } - else - AH->offSize = AH->intSize; - - if ((byteread = fgetc(fh)) == EOF) - READ_ERROR_EXIT(fh); - - AH->format = byteread; - AH->lookahead[AH->lookaheadLen++] = AH->format; + /* It's custom format, stop here */ + AH->format = archCustom; + AH->readHeader = 1; } else { @@ -2269,23 +2217,16 @@ _discoverArchiveFormat(ArchiveHandle *AH) 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 */ - - /* Close the file */ + /* Close the file if we opened it */ if (wantClose) + { if (fclose(fh) != 0) exit_horribly(modulename, "could not close input file: %s\n", strerror(errno)); + /* Forget lookahead, since we'll re-read header after re-opening */ + AH->readHeader = 0; + AH->lookaheadLen = 0; + } return AH->format; } @@ -3778,7 +3719,9 @@ WriteHead(ArchiveHandle *AH) void ReadHead(ArchiveHandle *AH) { - char tmpMag[7]; + char vmaj, + vmin, + vrev; int fmt; struct tm crtm; @@ -3790,49 +3733,47 @@ ReadHead(ArchiveHandle *AH) */ if (!AH->readHeader) { - char vmaj, - vmin, - vrev; + char tmpMag[7]; AH->ReadBufPtr(AH, tmpMag, 5); if (strncmp(tmpMag, "PGDMP", 5) != 0) exit_horribly(modulename, "did not find magic string in file header\n"); - - vmaj = AH->ReadBytePtr(AH); - vmin = AH->ReadBytePtr(AH); - - if (vmaj > 1 || (vmaj == 1 && vmin > 0)) /* Version > 1.0 */ - vrev = AH->ReadBytePtr(AH); - else - vrev = 0; - - AH->version = MAKE_ARCHIVE_VERSION(vmaj, vmin, vrev); - - if (AH->version < K_VERS_1_0 || AH->version > K_VERS_MAX) - exit_horribly(modulename, "unsupported version (%d.%d) in file header\n", - vmaj, vmin); - - AH->intSize = AH->ReadBytePtr(AH); - if (AH->intSize > 32) - exit_horribly(modulename, "sanity check on integer size (%lu) failed\n", - (unsigned long) AH->intSize); - - if (AH->intSize > sizeof(int)) - write_msg(modulename, "WARNING: archive was made on a machine with larger integers, some operations might fail\n"); - - if (AH->version >= K_VERS_1_7) - AH->offSize = AH->ReadBytePtr(AH); - else - AH->offSize = AH->intSize; - - fmt = AH->ReadBytePtr(AH); - - if (AH->format != fmt) - exit_horribly(modulename, "expected format (%d) differs from format found in file (%d)\n", - AH->format, fmt); } + vmaj = AH->ReadBytePtr(AH); + vmin = AH->ReadBytePtr(AH); + + if (vmaj > 1 || (vmaj == 1 && vmin > 0)) /* Version > 1.0 */ + vrev = AH->ReadBytePtr(AH); + else + vrev = 0; + + AH->version = MAKE_ARCHIVE_VERSION(vmaj, vmin, vrev); + + if (AH->version < K_VERS_1_0 || AH->version > K_VERS_MAX) + exit_horribly(modulename, "unsupported version (%d.%d) in file header\n", + vmaj, vmin); + + AH->intSize = AH->ReadBytePtr(AH); + if (AH->intSize > 32) + exit_horribly(modulename, "sanity check on integer size (%lu) failed\n", + (unsigned long) AH->intSize); + + if (AH->intSize > sizeof(int)) + write_msg(modulename, "WARNING: archive was made on a machine with larger integers, some operations might fail\n"); + + if (AH->version >= K_VERS_1_7) + AH->offSize = AH->ReadBytePtr(AH); + else + AH->offSize = AH->intSize; + + fmt = AH->ReadBytePtr(AH); + + if (AH->format != fmt) + exit_horribly(modulename, "expected format (%d) differs from format found in file (%d)\n", + AH->format, fmt); + if (AH->version >= K_VERS_1_2) { if (AH->version < K_VERS_1_4) diff --git a/src/bin/pg_dump/pg_backup_archiver.h b/src/bin/pg_dump/pg_backup_archiver.h index 6a6d740d7f..ac7eea4ef6 100644 --- a/src/bin/pg_dump/pg_backup_archiver.h +++ b/src/bin/pg_dump/pg_backup_archiver.h @@ -262,15 +262,21 @@ struct _archiveHandle time_t createDate; /* Date archive created */ /* - * Fields used when discovering header. A format can always get the - * previous read bytes from here... + * Fields used when discovering archive format. For tar format, we load + * the first block into the lookahead buffer, and verify that it looks + * like a tar header. The tar module must then consume bytes from the + * lookahead buffer before reading any more from the file. For custom + * format, we load only the "PGDMP" marker into the buffer, and then set + * readHeader after confirming it matches. The buffer is vestigial in + * this case, as the subsequent code just checks readHeader and doesn't + * examine the buffer. */ - int readHeader; /* Used if file header has been read already */ + int readHeader; /* Set if we already read "PGDMP" marker */ char *lookahead; /* Buffer used when reading header to discover * format */ - size_t lookaheadSize; /* Size of allocated buffer */ - size_t lookaheadLen; /* Length of data in lookahead */ - pgoff_t lookaheadPos; /* Current read position in lookahead buffer */ + size_t lookaheadSize; /* Allocated size of buffer */ + size_t lookaheadLen; /* Length of valid data in lookahead */ + size_t lookaheadPos; /* Current read position in lookahead buffer */ ArchiveEntryPtrType ArchiveEntryPtr; /* Called for each metadata object */ StartDataPtrType StartDataPtr; /* Called when table data is about to be diff --git a/src/bin/pg_dump/pg_backup_tar.c b/src/bin/pg_dump/pg_backup_tar.c index a0f761d650..c297f30834 100644 --- a/src/bin/pg_dump/pg_backup_tar.c +++ b/src/bin/pg_dump/pg_backup_tar.c @@ -236,12 +236,6 @@ InitArchiveFmt_Tar(ArchiveHandle *AH) 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);