On Sat, Mar 1, 2014 at 12:27:19PM -0800, Sean Chittenden wrote: > The attached patch fixes the case when `pg_dump -Fd …` is called > on a partition where write(2) fails for some reason or another. In > this case, backup jobs were returning with a successful exit code even > though most of the files in the dump directory were all zero length. > > I haven’t tested this patch’s failure conditions but the fix seems > simple enough: cfwrite() needs to have its return status checked > everywhere and exit_horribly() upon any failure. In this case, > callers of _WriteData() were not checking the return status and were > discarding the negative return status (e.g. ENOSPC). > > I made a cursory pass over the code and found one other instance where > write status wasn’t being checked and also included that.
As is often the case with pg_dump, the problems you saw are a small part of a larger set of problems in that code --- there is general ignoring of read and write errors. I have developed a comprehensive patch that addresses all the issues I could find. The use of function pointers and the calling of functions directly and through function pointers makes the fix quite complex. I ended up placing checks at the lowest level and removing checks at higher layers where they were sporadically placed. Patch attached. I have tested dump/restore of all four dump output formats with the 9.3 regression database and all tests passed. I believe this patch is too complex to backpatch, and I don't know how it could be fixed more simply. -- Bruce Momjian <br...@momjian.us> http://momjian.us EnterpriseDB http://enterprisedb.com + Everyone has their own god. +
diff --git a/src/bin/pg_dump/compress_io.c b/src/bin/pg_dump/compress_io.c new file mode 100644 index 10bc3f0..bad21b5 *** a/src/bin/pg_dump/compress_io.c --- b/src/bin/pg_dump/compress_io.c *************** static void InitCompressorZlib(Compresso *** 86,99 **** static void DeflateCompressorZlib(ArchiveHandle *AH, CompressorState *cs, bool flush); static void ReadDataFromArchiveZlib(ArchiveHandle *AH, ReadFunc readF); ! static size_t WriteDataToArchiveZlib(ArchiveHandle *AH, CompressorState *cs, const char *data, size_t dLen); static void EndCompressorZlib(ArchiveHandle *AH, CompressorState *cs); #endif /* Routines that support uncompressed data I/O */ static void ReadDataFromArchiveNone(ArchiveHandle *AH, ReadFunc readF); ! static size_t WriteDataToArchiveNone(ArchiveHandle *AH, CompressorState *cs, const char *data, size_t dLen); /* --- 86,99 ---- static void DeflateCompressorZlib(ArchiveHandle *AH, CompressorState *cs, bool flush); static void ReadDataFromArchiveZlib(ArchiveHandle *AH, ReadFunc readF); ! static void WriteDataToArchiveZlib(ArchiveHandle *AH, CompressorState *cs, const char *data, size_t dLen); static void EndCompressorZlib(ArchiveHandle *AH, CompressorState *cs); #endif /* Routines that support uncompressed data I/O */ static void ReadDataFromArchiveNone(ArchiveHandle *AH, ReadFunc readF); ! static void WriteDataToArchiveNone(ArchiveHandle *AH, CompressorState *cs, const char *data, size_t dLen); /* *************** ReadDataFromArchive(ArchiveHandle *AH, i *** 179,185 **** /* * Compress and write data to the output stream (via writeF). */ ! size_t WriteDataToArchive(ArchiveHandle *AH, CompressorState *cs, const void *data, size_t dLen) { --- 179,185 ---- /* * Compress and write data to the output stream (via writeF). */ ! void WriteDataToArchive(ArchiveHandle *AH, CompressorState *cs, const void *data, size_t dLen) { *************** WriteDataToArchive(ArchiveHandle *AH, Co *** 190,203 **** { case COMPR_ALG_LIBZ: #ifdef HAVE_LIBZ ! return WriteDataToArchiveZlib(AH, cs, data, dLen); #else exit_horribly(modulename, "not built with zlib support\n"); #endif case COMPR_ALG_NONE: ! return WriteDataToArchiveNone(AH, cs, data, dLen); } ! return 0; /* keep compiler quiet */ } /* --- 190,205 ---- { case COMPR_ALG_LIBZ: #ifdef HAVE_LIBZ ! WriteDataToArchiveZlib(AH, cs, data, dLen); #else exit_horribly(modulename, "not built with zlib support\n"); #endif + break; case COMPR_ALG_NONE: ! WriteDataToArchiveNone(AH, cs, data, dLen); ! break; } ! return; } /* *************** DeflateCompressorZlib(ArchiveHandle *AH, *** 298,307 **** */ size_t len = cs->zlibOutSize - zp->avail_out; ! if (cs->writeF(AH, out, len) != len) ! exit_horribly(modulename, ! "could not write to output file: %s\n", ! strerror(errno)); } zp->next_out = (void *) out; zp->avail_out = cs->zlibOutSize; --- 300,306 ---- */ size_t len = cs->zlibOutSize - zp->avail_out; ! cs->writeF(AH, out, len); } zp->next_out = (void *) out; zp->avail_out = cs->zlibOutSize; *************** DeflateCompressorZlib(ArchiveHandle *AH, *** 312,318 **** } } ! static size_t WriteDataToArchiveZlib(ArchiveHandle *AH, CompressorState *cs, const char *data, size_t dLen) { --- 311,317 ---- } } ! static void WriteDataToArchiveZlib(ArchiveHandle *AH, CompressorState *cs, const char *data, size_t dLen) { *************** WriteDataToArchiveZlib(ArchiveHandle *AH *** 320,330 **** cs->zp->avail_in = dLen; DeflateCompressorZlib(AH, cs, false); ! /* ! * we have either succeeded in writing dLen bytes or we have called ! * exit_horribly() ! */ ! return dLen; } static void --- 319,325 ---- cs->zp->avail_in = dLen; DeflateCompressorZlib(AH, cs, false); ! return; } static void *************** ReadDataFromArchiveNone(ArchiveHandle *A *** 427,445 **** free(buf); } ! static size_t WriteDataToArchiveNone(ArchiveHandle *AH, CompressorState *cs, const char *data, size_t dLen) { ! /* ! * Any write function should do its own error checking but to make sure we ! * do a check here as well... ! */ ! if (cs->writeF(AH, data, dLen) != dLen) ! exit_horribly(modulename, ! "could not write to output file: %s\n", ! strerror(errno)); ! return dLen; } --- 422,433 ---- free(buf); } ! static void WriteDataToArchiveNone(ArchiveHandle *AH, CompressorState *cs, const char *data, size_t dLen) { ! cs->writeF(AH, data, dLen); ! return; } *************** cfopen(const char *path, const char *mod *** 573,584 **** int cfread(void *ptr, int size, cfp *fp) { #ifdef HAVE_LIBZ if (fp->compressedfp) ! return gzread(fp->compressedfp, ptr, size); else #endif ! return fread(ptr, 1, size, fp->uncompressedfp); } int --- 561,587 ---- int cfread(void *ptr, int size, cfp *fp) { + int ret; + + if (size == 0) + return 0; + #ifdef HAVE_LIBZ if (fp->compressedfp) ! { ! ret = gzread(fp->compressedfp, ptr, size); ! if (ret != size && !gzeof(fp->compressedfp)) ! exit_horribly(modulename, ! "could not read from input file: %s\n", strerror(errno)); ! } else #endif ! { ! ret = fread(ptr, 1, size, fp->uncompressedfp); ! if (ret != size && !feof(fp->uncompressedfp)) ! READ_ERROR_EXIT(fp->uncompressedfp); ! } ! return ret; } int diff --git a/src/bin/pg_dump/compress_io.h b/src/bin/pg_dump/compress_io.h new file mode 100644 index aecfba5..713c78b *** a/src/bin/pg_dump/compress_io.h --- b/src/bin/pg_dump/compress_io.h *************** typedef enum *** 29,35 **** } CompressionAlgorithm; /* Prototype for callback function to WriteDataToArchive() */ ! typedef size_t (*WriteFunc) (ArchiveHandle *AH, const char *buf, size_t len); /* * Prototype for callback function to ReadDataFromArchive() --- 29,35 ---- } CompressionAlgorithm; /* Prototype for callback function to WriteDataToArchive() */ ! typedef void (*WriteFunc) (ArchiveHandle *AH, const char *buf, size_t len); /* * Prototype for callback function to ReadDataFromArchive() *************** typedef struct CompressorState Compresso *** 50,56 **** extern CompressorState *AllocateCompressor(int compression, WriteFunc writeF); extern void ReadDataFromArchive(ArchiveHandle *AH, int compression, ReadFunc readF); ! extern size_t WriteDataToArchive(ArchiveHandle *AH, CompressorState *cs, const void *data, size_t dLen); extern void EndCompressor(ArchiveHandle *AH, CompressorState *cs); --- 50,56 ---- extern CompressorState *AllocateCompressor(int compression, WriteFunc writeF); extern void ReadDataFromArchive(ArchiveHandle *AH, int compression, ReadFunc readF); ! extern void WriteDataToArchive(ArchiveHandle *AH, CompressorState *cs, const void *data, size_t dLen); extern void EndCompressor(ArchiveHandle *AH, CompressorState *cs); diff --git a/src/bin/pg_dump/pg_backup.h b/src/bin/pg_dump/pg_backup.h new file mode 100644 index 83f7216..08ace67 *** a/src/bin/pg_dump/pg_backup.h --- b/src/bin/pg_dump/pg_backup.h *************** extern void ArchiveEntry(Archive *AHX, *** 180,186 **** DataDumperPtr dumpFn, void *dumpArg); /* Called to write *data* to the archive */ ! extern size_t WriteData(Archive *AH, const void *data, size_t dLen); extern int StartBlob(Archive *AH, Oid oid); extern int EndBlob(Archive *AH, Oid oid); --- 180,186 ---- DataDumperPtr dumpFn, void *dumpArg); /* Called to write *data* to the archive */ ! extern void WriteData(Archive *AH, const void *data, size_t dLen); extern int StartBlob(Archive *AH, Oid oid); extern int EndBlob(Archive *AH, Oid oid); *************** extern RestoreOptions *NewRestoreOptions *** 208,214 **** extern void SortTocFromFile(Archive *AHX, RestoreOptions *ropt); /* Convenience functions used only when writing DATA */ ! extern int archputs(const char *s, Archive *AH); extern int archprintf(Archive *AH, const char *fmt,...) /* This extension allows gcc to check the format string */ --- 208,214 ---- extern void SortTocFromFile(Archive *AHX, RestoreOptions *ropt); /* Convenience functions used only when writing DATA */ ! extern void archputs(const char *s, Archive *AH); extern int archprintf(Archive *AH, const char *fmt,...) /* This extension allows gcc to check the format string */ diff --git a/src/bin/pg_dump/pg_backup_archiver.c b/src/bin/pg_dump/pg_backup_archiver.c new file mode 100644 index 9464540..566f29b *** a/src/bin/pg_dump/pg_backup_archiver.c --- b/src/bin/pg_dump/pg_backup_archiver.c *************** _enableTriggersIfNecessary(ArchiveHandle *** 855,861 **** */ /* Public */ ! size_t WriteData(Archive *AHX, const void *data, size_t dLen) { ArchiveHandle *AH = (ArchiveHandle *) AHX; --- 855,861 ---- */ /* Public */ ! void WriteData(Archive *AHX, const void *data, size_t dLen) { ArchiveHandle *AH = (ArchiveHandle *) AHX; *************** WriteData(Archive *AHX, const void *data *** 863,869 **** if (!AH->currToc) exit_horribly(modulename, "internal error -- WriteData cannot be called outside the context of a DataDumper routine\n"); ! return (*AH->WriteDataPtr) (AH, data, dLen); } /* --- 863,871 ---- if (!AH->currToc) exit_horribly(modulename, "internal error -- WriteData cannot be called outside the context of a DataDumper routine\n"); ! (*AH->WriteDataPtr) (AH, data, dLen); ! ! return; } /* *************** SortTocFromFile(Archive *AHX, RestoreOpt *** 1246,1255 **** **********************/ /* Public */ ! int archputs(const char *s, Archive *AH) { ! return WriteData(AH, s, strlen(s)); } /* Public */ --- 1248,1258 ---- **********************/ /* Public */ ! void archputs(const char *s, Archive *AH) { ! WriteData(AH, s, strlen(s)); ! return; } /* Public */ *************** dump_lo_buf(ArchiveHandle *AH) *** 1486,1496 **** * format to create a custom output routine to 'fake' a restore if it * wants to generate a script (see TAR output). */ ! int ahwrite(const void *ptr, size_t size, size_t nmemb, ArchiveHandle *AH) { ! size_t res; ! if (AH->writingBlob) { size_t remaining = size * nmemb; --- 1489,1499 ---- * format to create a custom output routine to 'fake' a restore if it * wants to generate a script (see TAR output). */ ! void ahwrite(const void *ptr, size_t size, size_t nmemb, ArchiveHandle *AH) { ! int bytes_written = 0; ! if (AH->writingBlob) { size_t remaining = size * nmemb; *************** ahwrite(const void *ptr, size_t size, si *** 1509,1531 **** 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(ptr, size, nmemb, AH->OF); ! if (res != (nmemb * size)) ! exit_horribly(modulename, "could not write to output file: %s\n", strerror(errno)); ! return res; ! } else if (AH->CustomOutPtr) ! { ! res = AH->CustomOutPtr (AH, ptr, size * nmemb); ! ! if (res != (nmemb * size)) ! exit_horribly(modulename, "could not write to custom output routine\n"); ! return res; ! } else { /* --- 1512,1523 ---- memcpy((char *) AH->lo_buf + AH->lo_buf_used, ptr, remaining); AH->lo_buf_used += remaining; ! bytes_written = size * nmemb; } else if (AH->gzOut) ! bytes_written = GZWRITE(ptr, size, nmemb, AH->OF); else if (AH->CustomOutPtr) ! bytes_written = AH->CustomOutPtr (AH, ptr, size * nmemb); else { /* *************** ahwrite(const void *ptr, size_t size, si *** 1533,1548 **** * connected then send it to the DB. */ if (RestoringToDB(AH)) ! return ExecuteSqlCommandBuf(AH, (const char *) ptr, size * nmemb); else ! { ! res = fwrite(ptr, size, nmemb, AH->OF); ! if (res != nmemb) ! exit_horribly(modulename, "could not write to output file: %s\n", ! strerror(errno)); ! return res; ! } } } /* on some error, we may decide to go on... */ --- 1525,1539 ---- * connected then send it to the DB. */ if (RestoringToDB(AH)) ! bytes_written = ExecuteSqlCommandBuf(AH, (const char *) ptr, size * nmemb); else ! bytes_written = fwrite(ptr, size, nmemb, AH->OF) * size; } + + if (bytes_written != size * nmemb) + WRITE_ERROR_EXIT; + + return; } /* on some error, we may decide to go on... */ *************** WriteStr(ArchiveHandle *AH, const char * *** 1847,1854 **** if (c) { ! res = WriteInt(AH, strlen(c)); ! res += (*AH->WriteBufPtr) (AH, c, strlen(c)); } else res = WriteInt(AH, -1); --- 1838,1848 ---- if (c) { ! int len = strlen(c); ! ! res = WriteInt(AH, len); ! (*AH->WriteBufPtr) (AH, c, len); ! res += len; } else res = WriteInt(AH, -1); *************** ReadStr(ArchiveHandle *AH) *** 1868,1875 **** else { buf = (char *) pg_malloc(l + 1); ! if ((*AH->ReadBufPtr) (AH, (void *) buf, l) != l) ! exit_horribly(modulename, "unexpected end of file\n"); buf[l] = '\0'; } --- 1862,1868 ---- else { buf = (char *) pg_malloc(l + 1); ! (*AH->ReadBufPtr) (AH, (void *) buf, l); buf[l] = '\0'; } *************** _discoverArchiveFormat(ArchiveHandle *AH *** 2029,2034 **** --- 2022,2029 ---- * read first 512 byte header... */ cnt = fread(&AH->lookahead[AH->lookaheadLen], 1, 512 - AH->lookaheadLen, fh); + if (cnt != 512 - AH->lookaheadLen) + READ_ERROR_EXIT(fh); AH->lookaheadLen += cnt; if (AH->lookaheadLen >= strlen(TEXT_DUMPALL_HEADER) && *************** ReadHead(ArchiveHandle *AH) *** 3318,3325 **** */ if (!AH->readHeader) { ! if ((*AH->ReadBufPtr) (AH, tmpMag, 5) != 5) ! exit_horribly(modulename, "unexpected end of file\n"); if (strncmp(tmpMag, "PGDMP", 5) != 0) exit_horribly(modulename, "did not find magic string in file header\n"); --- 3313,3319 ---- */ if (!AH->readHeader) { ! (*AH->ReadBufPtr) (AH, tmpMag, 5); if (strncmp(tmpMag, "PGDMP", 5) != 0) exit_horribly(modulename, "did not find magic string in file header\n"); diff --git a/src/bin/pg_dump/pg_backup_archiver.h b/src/bin/pg_dump/pg_backup_archiver.h new file mode 100644 index 25aa158..92ec1d8 *** a/src/bin/pg_dump/pg_backup_archiver.h --- b/src/bin/pg_dump/pg_backup_archiver.h *************** *** 45,54 **** --- 45,56 ---- #define GZCLOSE(fh) gzclose(fh) #define GZWRITE(p, s, n, fh) gzwrite(fh, p, (n) * (s)) #define GZREAD(p, s, n, fh) gzread(fh, p, (n) * (s)) + #define GZEOF(fh) gzeof(fh) #else #define GZCLOSE(fh) fclose(fh) #define GZWRITE(p, s, n, fh) (fwrite(p, s, n, fh) * (s)) #define GZREAD(p, s, n, fh) fread(p, s, n, fh) + #define GZEOF(fh) feof(fh) /* this is just the redefinition of a libz constant */ #define Z_DEFAULT_COMPRESSION (-1) *************** struct _restoreList; *** 115,120 **** --- 117,138 ---- struct ParallelArgs; struct ParallelState; + #define READ_ERROR_EXIT(fd) \ + do { \ + if (feof(fd)) \ + exit_horribly(modulename, \ + "could not read from input file: end of file\n"); \ + else \ + exit_horribly(modulename, \ + "could not read from input file: %s\n", strerror(errno)); \ + } while (0) + + #define WRITE_ERROR_EXIT \ + do { \ + exit_horribly(modulename, "could not write to output file: %s\n", \ + strerror(errno)); \ + } while (0) + typedef enum T_Action { ACT_DUMP, *************** typedef void (*ReopenPtr) (struct _archi *** 126,132 **** typedef void (*ArchiveEntryPtr) (struct _archiveHandle * AH, struct _tocEntry * te); typedef void (*StartDataPtr) (struct _archiveHandle * AH, struct _tocEntry * te); ! typedef size_t (*WriteDataPtr) (struct _archiveHandle * AH, const void *data, size_t dLen); typedef void (*EndDataPtr) (struct _archiveHandle * AH, struct _tocEntry * te); typedef void (*StartBlobsPtr) (struct _archiveHandle * AH, struct _tocEntry * te); --- 144,150 ---- typedef void (*ArchiveEntryPtr) (struct _archiveHandle * AH, struct _tocEntry * te); typedef void (*StartDataPtr) (struct _archiveHandle * AH, struct _tocEntry * te); ! typedef void (*WriteDataPtr) (struct _archiveHandle * AH, const void *data, size_t dLen); typedef void (*EndDataPtr) (struct _archiveHandle * AH, struct _tocEntry * te); typedef void (*StartBlobsPtr) (struct _archiveHandle * AH, struct _tocEntry * te); *************** typedef void (*EndBlobsPtr) (struct _arc *** 136,143 **** typedef int (*WriteBytePtr) (struct _archiveHandle * AH, const int i); typedef int (*ReadBytePtr) (struct _archiveHandle * AH); ! typedef size_t (*WriteBufPtr) (struct _archiveHandle * AH, const void *c, size_t len); ! typedef size_t (*ReadBufPtr) (struct _archiveHandle * AH, void *buf, size_t len); typedef void (*SaveArchivePtr) (struct _archiveHandle * AH); typedef void (*WriteExtraTocPtr) (struct _archiveHandle * AH, struct _tocEntry * te); typedef void (*ReadExtraTocPtr) (struct _archiveHandle * AH, struct _tocEntry * te); --- 154,161 ---- typedef int (*WriteBytePtr) (struct _archiveHandle * AH, const int i); typedef int (*ReadBytePtr) (struct _archiveHandle * AH); ! typedef void (*WriteBufPtr) (struct _archiveHandle * AH, const void *c, size_t len); ! typedef void (*ReadBufPtr) (struct _archiveHandle * AH, void *buf, size_t len); typedef void (*SaveArchivePtr) (struct _archiveHandle * AH); typedef void (*WriteExtraTocPtr) (struct _archiveHandle * AH, struct _tocEntry * te); typedef void (*ReadExtraTocPtr) (struct _archiveHandle * AH, struct _tocEntry * te); *************** extern bool isValidTarHeader(char *heade *** 413,419 **** extern int ReconnectToServer(ArchiveHandle *AH, const char *dbname, const char *newUser); extern void DropBlobIfExists(ArchiveHandle *AH, Oid oid); ! int ahwrite(const void *ptr, size_t size, size_t nmemb, ArchiveHandle *AH); int ahprintf(ArchiveHandle *AH, const char *fmt,...) __attribute__((format(PG_PRINTF_ATTRIBUTE, 2, 3))); void ahlog(ArchiveHandle *AH, int level, const char *fmt,...) __attribute__((format(PG_PRINTF_ATTRIBUTE, 3, 4))); --- 431,437 ---- extern int ReconnectToServer(ArchiveHandle *AH, const char *dbname, const char *newUser); extern void DropBlobIfExists(ArchiveHandle *AH, Oid oid); ! void ahwrite(const void *ptr, size_t size, size_t nmemb, ArchiveHandle *AH); int ahprintf(ArchiveHandle *AH, const char *fmt,...) __attribute__((format(PG_PRINTF_ATTRIBUTE, 2, 3))); void ahlog(ArchiveHandle *AH, int level, const char *fmt,...) __attribute__((format(PG_PRINTF_ATTRIBUTE, 3, 4))); diff --git a/src/bin/pg_dump/pg_backup_custom.c b/src/bin/pg_dump/pg_backup_custom.c new file mode 100644 index 72bdc39..9a8bc42 *** a/src/bin/pg_dump/pg_backup_custom.c --- b/src/bin/pg_dump/pg_backup_custom.c *************** *** 35,46 **** 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 _ReopenArchive(ArchiveHandle *AH); static void _PrintTocData(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt); --- 35,46 ---- static void _ArchiveEntry(ArchiveHandle *AH, TocEntry *te); static void _StartData(ArchiveHandle *AH, TocEntry *te); ! static void _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 void _WriteBuf(ArchiveHandle *AH, const void *buf, size_t len); ! static void _ReadBuf(ArchiveHandle *AH, void *buf, size_t len); static void _CloseArchive(ArchiveHandle *AH); static void _ReopenArchive(ArchiveHandle *AH); static void _PrintTocData(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt); *************** typedef struct *** 86,92 **** static void _readBlockHeader(ArchiveHandle *AH, int *type, int *id); static pgoff_t _getFilePos(ArchiveHandle *AH, lclContext *ctx); ! static size_t _CustomWriteFunc(ArchiveHandle *AH, const char *buf, size_t len); static size_t _CustomReadFunc(ArchiveHandle *AH, char **buf, size_t *buflen); /* translator: this is a module name */ --- 86,92 ---- static void _readBlockHeader(ArchiveHandle *AH, int *type, int *id); static pgoff_t _getFilePos(ArchiveHandle *AH, lclContext *ctx); ! static void _CustomWriteFunc(ArchiveHandle *AH, const char *buf, size_t len); static size_t _CustomReadFunc(ArchiveHandle *AH, char **buf, size_t *buflen); /* translator: this is a module name */ *************** _StartData(ArchiveHandle *AH, TocEntry * *** 315,330 **** * * Mandatory. */ ! static size_t _WriteData(ArchiveHandle *AH, const void *data, size_t dLen) { lclContext *ctx = (lclContext *) AH->formatData; CompressorState *cs = ctx->cs; ! if (dLen == 0) ! return 0; ! return WriteDataToArchive(AH, cs, data, dLen); } /* --- 315,331 ---- * * Mandatory. */ ! static void _WriteData(ArchiveHandle *AH, const void *data, size_t dLen) { lclContext *ctx = (lclContext *) AH->formatData; CompressorState *cs = ctx->cs; ! if (dLen > 0) ! /* WriteDataToArchive() internally throws write errors */ ! WriteDataToArchive(AH, cs, data, dLen); ! return; } /* *************** static int *** 610,623 **** _WriteByte(ArchiveHandle *AH, const int i) { lclContext *ctx = (lclContext *) AH->formatData; ! int res; ! res = fputc(i, AH->FH); ! if (res != EOF) ! ctx->filePos += 1; ! else ! exit_horribly(modulename, "could not write byte: %s\n", strerror(errno)); ! return res; } /* --- 611,623 ---- _WriteByte(ArchiveHandle *AH, const int i) { lclContext *ctx = (lclContext *) AH->formatData; ! int res; ! if ((res = fputc(i, AH->FH)) == EOF) ! WRITE_ERROR_EXIT; ! ctx->filePos += 1; ! ! return 1; } /* *************** _ReadByte(ArchiveHandle *AH) *** 636,642 **** res = getc(AH->FH); if (res == EOF) ! exit_horribly(modulename, "unexpected end of file\n"); ctx->filePos += 1; return res; } --- 636,642 ---- res = getc(AH->FH); if (res == EOF) ! READ_ERROR_EXIT(AH->FH); ctx->filePos += 1; return res; } *************** _ReadByte(ArchiveHandle *AH) *** 648,667 **** * * Called by the archiver to write a block of bytes to the archive. */ ! 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) ! exit_horribly(modulename, ! "could not write to output file: %s\n", strerror(errno)); ! ctx->filePos += res; ! return res; } /* --- 648,663 ---- * * Called by the archiver to write a block of bytes to the archive. */ ! static void _WriteBuf(ArchiveHandle *AH, const void *buf, size_t len) { lclContext *ctx = (lclContext *) AH->formatData; ! if (fwrite(buf, 1, len, AH->FH) != len) ! WRITE_ERROR_EXIT; ! ctx->filePos += len; ! return; } /* *************** _WriteBuf(ArchiveHandle *AH, const void *** 671,686 **** * * Called by the archiver to read a block of bytes from the archive */ ! 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; } /* --- 667,682 ---- * * Called by the archiver to read a block of bytes from the archive */ ! static void _ReadBuf(ArchiveHandle *AH, void *buf, size_t len) { lclContext *ctx = (lclContext *) AH->formatData; ! if (fread(buf, 1, len, AH->FH) != len) ! READ_ERROR_EXIT(AH->FH); ! ctx->filePos += len; ! return; } /* *************** _readBlockHeader(ArchiveHandle *AH, int *** 955,969 **** * Callback function for WriteDataToArchive. Writes one block of (compressed) * data to the archive. */ ! static size_t _CustomWriteFunc(ArchiveHandle *AH, const char *buf, size_t len) { /* never write 0-byte blocks (this should not happen) */ ! if (len == 0) ! return 0; ! ! WriteInt(AH, len); ! return _WriteBuf(AH, buf, len); } /* --- 951,966 ---- * Callback function for WriteDataToArchive. Writes one block of (compressed) * data to the archive. */ ! static void _CustomWriteFunc(ArchiveHandle *AH, const char *buf, size_t len) { /* never write 0-byte blocks (this should not happen) */ ! if (len > 0) ! { ! WriteInt(AH, len); ! _WriteBuf(AH, buf, len); ! } ! return; } /* *************** static size_t *** 974,980 **** _CustomReadFunc(ArchiveHandle *AH, char **buf, size_t *buflen) { size_t blkLen; - size_t cnt; /* Read length */ blkLen = ReadInt(AH); --- 971,976 ---- *************** _CustomReadFunc(ArchiveHandle *AH, char *** 989,1003 **** *buflen = blkLen; } ! cnt = _ReadBuf(AH, *buf, blkLen); ! if (cnt != blkLen) ! { ! if (feof(AH->FH)) ! exit_horribly(modulename, ! "could not read from input file: end of file\n"); ! else ! exit_horribly(modulename, ! "could not read from input file: %s\n", strerror(errno)); ! } ! return cnt; } --- 985,992 ---- *buflen = blkLen; } ! /* exits app on read errors */ ! _ReadBuf(AH, *buf, blkLen); ! ! return blkLen; } diff --git a/src/bin/pg_dump/pg_backup_db.c b/src/bin/pg_dump/pg_backup_db.c new file mode 100644 index cd2dded..980d68f *** a/src/bin/pg_dump/pg_backup_db.c --- b/src/bin/pg_dump/pg_backup_db.c *************** ExecuteSqlCommandBuf(ArchiveHandle *AH, *** 540,546 **** } } ! return 1; } /* --- 540,546 ---- } } ! return bufLen; } /* diff --git a/src/bin/pg_dump/pg_backup_directory.c b/src/bin/pg_dump/pg_backup_directory.c new file mode 100644 index 0fae53b..29f33de *** a/src/bin/pg_dump/pg_backup_directory.c --- b/src/bin/pg_dump/pg_backup_directory.c *************** static const char *modulename = gettext_ *** 66,76 **** static void _ArchiveEntry(ArchiveHandle *AH, TocEntry *te); static void _StartData(ArchiveHandle *AH, TocEntry *te); static void _EndData(ArchiveHandle *AH, TocEntry *te); ! static size_t _WriteData(ArchiveHandle *AH, const void *data, size_t dLen); 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 _ReopenArchive(ArchiveHandle *AH); static void _PrintTocData(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt); --- 66,76 ---- static void _ArchiveEntry(ArchiveHandle *AH, TocEntry *te); static void _StartData(ArchiveHandle *AH, TocEntry *te); static void _EndData(ArchiveHandle *AH, TocEntry *te); ! static void _WriteData(ArchiveHandle *AH, const void *data, size_t dLen); static int _WriteByte(ArchiveHandle *AH, const int i); static int _ReadByte(ArchiveHandle *); ! static void _WriteBuf(ArchiveHandle *AH, const void *buf, size_t len); ! static void _ReadBuf(ArchiveHandle *AH, void *buf, size_t len); static void _CloseArchive(ArchiveHandle *AH); static void _ReopenArchive(ArchiveHandle *AH); static void _PrintTocData(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt); *************** _StartData(ArchiveHandle *AH, TocEntry * *** 350,367 **** * * We write the data to the open data file. */ ! static size_t _WriteData(ArchiveHandle *AH, const void *data, size_t dLen) { lclContext *ctx = (lclContext *) AH->formatData; - if (dLen == 0) - return 0; - /* Are we aborting? */ checkAborting(AH); ! return cfwrite(data, dLen, ctx->dataFH); } /* --- 350,367 ---- * * We write the data to the open data file. */ ! static void _WriteData(ArchiveHandle *AH, const void *data, size_t dLen) { lclContext *ctx = (lclContext *) AH->formatData; /* Are we aborting? */ checkAborting(AH); + + if (dLen > 0 && cfwrite(data, dLen, ctx->dataFH) != dLen) + WRITE_ERROR_EXIT; ! return; } /* *************** _PrintFileData(ArchiveHandle *AH, char * *** 408,414 **** ahwrite(buf, 1, cnt, AH); free(buf); ! if (cfclose(cfp) !=0) exit_horribly(modulename, "could not close data file: %s\n", strerror(errno)); } --- 408,414 ---- ahwrite(buf, 1, cnt, AH); free(buf); ! if (cfclose(cfp) != 0) exit_horribly(modulename, "could not close data file: %s\n", strerror(errno)); } *************** _WriteByte(ArchiveHandle *AH, const int *** 495,501 **** lclContext *ctx = (lclContext *) AH->formatData; if (cfwrite(&c, 1, ctx->dataFH) != 1) ! exit_horribly(modulename, "could not write byte\n"); return 1; } --- 495,501 ---- lclContext *ctx = (lclContext *) AH->formatData; if (cfwrite(&c, 1, ctx->dataFH) != 1) ! WRITE_ERROR_EXIT; return 1; } *************** _ReadByte(ArchiveHandle *AH) *** 514,520 **** res = cfgetc(ctx->dataFH); if (res == EOF) ! exit_horribly(modulename, "unexpected end of file\n"); return res; } --- 514,521 ---- res = cfgetc(ctx->dataFH); if (res == EOF) ! exit_horribly(modulename, ! "could not read from input file: end of file\n"); return res; } *************** _ReadByte(ArchiveHandle *AH) *** 523,543 **** * Write a buffer of data to the archive. * Called by the archiver to write a block of bytes to the TOC or a data file. */ ! static size_t _WriteBuf(ArchiveHandle *AH, const void *buf, size_t len) { lclContext *ctx = (lclContext *) AH->formatData; - size_t res; /* Are we aborting? */ checkAborting(AH); ! res = cfwrite(buf, len, ctx->dataFH); ! if (res != len) ! exit_horribly(modulename, "could not write to output file: %s\n", ! strerror(errno)); ! return res; } /* --- 524,541 ---- * Write a buffer of data to the archive. * Called by the archiver to write a block of bytes to the TOC or a data file. */ ! static void _WriteBuf(ArchiveHandle *AH, const void *buf, size_t len) { lclContext *ctx = (lclContext *) AH->formatData; /* Are we aborting? */ checkAborting(AH); ! if (cfwrite(buf, len, ctx->dataFH) != len) ! WRITE_ERROR_EXIT; ! return; } /* *************** _WriteBuf(ArchiveHandle *AH, const void *** 545,559 **** * * Called by the archiver to read a block of bytes from the archive */ ! static size_t _ReadBuf(ArchiveHandle *AH, void *buf, size_t len) { lclContext *ctx = (lclContext *) AH->formatData; - size_t res; ! res = cfread(buf, len, ctx->dataFH); ! return res; } /* --- 543,562 ---- * * Called by the archiver to read a block of bytes from the archive */ ! static void _ReadBuf(ArchiveHandle *AH, void *buf, size_t len) { lclContext *ctx = (lclContext *) AH->formatData; ! /* ! * If there was an I/O error, we already exited in cfread(), ! * so here we exit on short reads. ! */ ! if (cfread(buf, len, ctx->dataFH) != len) ! exit_horribly(modulename, ! "could not read from input file: end of file\n"); ! return; } /* diff --git a/src/bin/pg_dump/pg_backup_null.c b/src/bin/pg_dump/pg_backup_null.c new file mode 100644 index c321068..3bce588 *** a/src/bin/pg_dump/pg_backup_null.c --- b/src/bin/pg_dump/pg_backup_null.c *************** *** 30,41 **** #include "libpq/libpq-fs.h" ! ! static size_t _WriteData(ArchiveHandle *AH, const void *data, size_t dLen); ! static size_t _WriteBlobData(ArchiveHandle *AH, const void *data, size_t dLen); static void _EndData(ArchiveHandle *AH, TocEntry *te); static int _WriteByte(ArchiveHandle *AH, const int i); ! static size_t _WriteBuf(ArchiveHandle *AH, const void *buf, size_t len); static void _CloseArchive(ArchiveHandle *AH); static void _PrintTocData(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt); static void _StartBlobs(ArchiveHandle *AH, TocEntry *te); --- 30,40 ---- #include "libpq/libpq-fs.h" ! static void _WriteData(ArchiveHandle *AH, const void *data, size_t dLen); ! static void _WriteBlobData(ArchiveHandle *AH, const void *data, size_t dLen); static void _EndData(ArchiveHandle *AH, TocEntry *te); static int _WriteByte(ArchiveHandle *AH, const int i); ! static void _WriteBuf(ArchiveHandle *AH, const void *buf, size_t len); static void _CloseArchive(ArchiveHandle *AH); static void _PrintTocData(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt); static void _StartBlobs(ArchiveHandle *AH, TocEntry *te); *************** InitArchiveFmt_Null(ArchiveHandle *AH) *** 84,102 **** /* * Called by dumper via archiver from within a data dump routine */ ! static size_t _WriteData(ArchiveHandle *AH, const void *data, size_t dLen) { ! /* Just send it to output */ ahwrite(data, 1, dLen, AH); ! return dLen; } /* * Called by dumper via archiver from within a data dump routine * We substitute this for _WriteData while emitting a BLOB */ ! static size_t _WriteBlobData(ArchiveHandle *AH, const void *data, size_t dLen) { if (dLen > 0) --- 83,101 ---- /* * Called by dumper via archiver from within a data dump routine */ ! static void _WriteData(ArchiveHandle *AH, const void *data, size_t dLen) { ! /* Just send it to output, ahwrite() already errors on failure */ ahwrite(data, 1, dLen, AH); ! return; } /* * Called by dumper via archiver from within a data dump routine * We substitute this for _WriteData while emitting a BLOB */ ! static void _WriteBlobData(ArchiveHandle *AH, const void *data, size_t dLen) { if (dLen > 0) *************** _WriteBlobData(ArchiveHandle *AH, const *** 112,118 **** destroyPQExpBuffer(buf); } ! return dLen; } static void --- 111,117 ---- destroyPQExpBuffer(buf); } ! return; } static void *************** _WriteByte(ArchiveHandle *AH, const int *** 220,230 **** return 0; } ! static size_t _WriteBuf(ArchiveHandle *AH, const void *buf, size_t len) { /* Don't do anything */ ! return len; } static void --- 219,229 ---- return 0; } ! static void _WriteBuf(ArchiveHandle *AH, const void *buf, size_t len) { /* Don't do anything */ ! return; } static void diff --git a/src/bin/pg_dump/pg_backup_tar.c b/src/bin/pg_dump/pg_backup_tar.c new file mode 100644 index 3bdbf86..b08d04f *** a/src/bin/pg_dump/pg_backup_tar.c --- b/src/bin/pg_dump/pg_backup_tar.c *************** *** 42,53 **** 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); --- 42,53 ---- static void _ArchiveEntry(ArchiveHandle *AH, TocEntry *te); static void _StartData(ArchiveHandle *AH, TocEntry *te); ! static void _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 void _WriteBuf(ArchiveHandle *AH, const void *buf, size_t len); ! static void _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); *************** _tarReadRaw(ArchiveHandle *AH, void *buf *** 548,560 **** --- 548,573 ---- if (len > 0) { if (fh) + { res = fread(&((char *) buf)[used], 1, len, fh); + if (res != len && !feof(fh)) + READ_ERROR_EXIT(fh); + } else if (th) { if (th->zFH) + { res = GZREAD(&((char *) buf)[used], 1, len, th->zFH); + if (res != len && !GZEOF(fh)) + exit_horribly(modulename, + "could not read from input file: %s\n", strerror(errno)); + } else + { res = fread(&((char *) buf)[used], 1, len, th->nFH); + if (res != len && !feof(fh)) + READ_ERROR_EXIT(fh); + } } else exit_horribly(modulename, "internal error -- neither th nor fh specified in tarReadRaw()\n"); *************** tarWrite(const void *buf, size_t len, TA *** 593,614 **** else res = fwrite(buf, 1, len, th->nFH); - if (res != len) - exit_horribly(modulename, - "could not write to output file: %s\n", strerror(errno)); - 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(data, dLen, tctx->TH); ! return dLen; } static void --- 606,624 ---- else res = fwrite(buf, 1, len, th->nFH); th->pos += res; return res; } ! static void _WriteData(ArchiveHandle *AH, const void *data, size_t dLen) { lclTocEntry *tctx = (lclTocEntry *) AH->currToc->formatData; ! if (tarWrite(data, dLen, tctx->TH) != dLen) ! WRITE_ERROR_EXIT; ! return; } static void *************** static int *** 766,778 **** _WriteByte(ArchiveHandle *AH, const int i) { lclContext *ctx = (lclContext *) AH->formatData; - int res; char b = i; /* Avoid endian problems */ ! res = tarWrite(&b, 1, ctx->FH); ! if (res != EOF) ! ctx->filePos += res; ! return res; } static int --- 776,788 ---- _WriteByte(ArchiveHandle *AH, const int i) { lclContext *ctx = (lclContext *) AH->formatData; char b = i; /* Avoid endian problems */ ! if (tarWrite(&b, 1, ctx->FH) != 1) ! WRITE_ERROR_EXIT; ! ! ctx->filePos += 1; ! return 1; } static int *************** _ReadByte(ArchiveHandle *AH) *** 784,814 **** res = tarRead(&c, 1, ctx->FH); if (res != 1) ! exit_horribly(modulename, "unexpected end of file\n"); ctx->filePos += 1; return c; } ! static size_t _WriteBuf(ArchiveHandle *AH, const void *buf, size_t len) { lclContext *ctx = (lclContext *) AH->formatData; - size_t res; ! res = tarWrite(buf, len, ctx->FH); ! 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 = tarRead(buf, len, ctx->FH); ! ctx->filePos += res; ! return res; } static void --- 794,829 ---- res = tarRead(&c, 1, ctx->FH); if (res != 1) ! /* We already would have exited for errors on reads, must be EOF */ ! exit_horribly(modulename, ! "could not read from input file: end of file\n"); ctx->filePos += 1; return c; } ! static void _WriteBuf(ArchiveHandle *AH, const void *buf, size_t len) { lclContext *ctx = (lclContext *) AH->formatData; ! if (tarWrite(buf, len, ctx->FH) != len) ! WRITE_ERROR_EXIT; ! ! ctx->filePos += len; } ! static void _ReadBuf(ArchiveHandle *AH, void *buf, size_t len) { lclContext *ctx = (lclContext *) AH->formatData; ! if (tarRead(buf, len, ctx->FH) != len) ! /* We already would have exited for errors on reads, must be EOF */ ! exit_horribly(modulename, ! "could not read from input file: end of file\n"); ! ! ctx->filePos += len; ! return; } static void *************** _tarAddFile(ArchiveHandle *AH, TAR_MEMBE *** 1084,1094 **** while ((cnt = fread(buf, 1, sizeof(buf), tmp)) > 0) { ! res = fwrite(buf, 1, cnt, th->tarFH); ! if (res != cnt) ! exit_horribly(modulename, ! "could not write to output file: %s\n", ! strerror(errno)); len += res; } --- 1099,1106 ---- while ((cnt = fread(buf, 1, sizeof(buf), tmp)) > 0) { ! if ((res = fwrite(buf, 1, cnt, th->tarFH)) != cnt) ! WRITE_ERROR_EXIT; len += res; } *************** _tarWriteHeader(TAR_MEMBER *th) *** 1294,1298 **** /* Now write the completed header. */ if (fwrite(h, 1, 512, th->tarFH) != 512) ! exit_horribly(modulename, "could not write to output file: %s\n", strerror(errno)); } --- 1306,1310 ---- /* Now write the completed header. */ if (fwrite(h, 1, 512, th->tarFH) != 512) ! WRITE_ERROR_EXIT; }
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers