pg_dump: Fix compression API errorhandling

Compression in pg_dump is abstracted using an API with multiple
implementations which can be selected at runtime by the user.
The API and its implementations have evolved over time, notable
commits include bf9aa490db, e9960732a9, 84adc8e20, and 0da243fed.
The errorhandling defined by the API was however problematic and
the implementations had a few bugs and/or were not following the
API specification.  This commit modifies the API to ensure that
callers can perform errorhandling efficiently and fixes all the
implementations such that they all implement the API in the same
way.  A full list of the changes can be seen below.

 * write_func:
   - Make write_func throw an error on all error conditions.  All
     callers of write_func were already checking for success and
     calling pg_fatal on all errors, so we might as well make the
     API support that case directly with simpler errorhandling as
     a result.

 * open_func:
   - zstd: move stream initialization from the open function to
     the read and write functions as they can have fatal errors.
     Also ensure to dup the file descriptor like none and gzip.
   - lz4: Ensure to dup the file descriptor like none and gzip.

 * close_func:
   - zstd: Ensure to close the file descriptor even if closing
     down the compressor fails, and clean up state allocation on
     fclose failures.  Make sure to capture errors set by fclose.
   - lz4: Ensure to close the file descriptor even if closing
     down the compressor fails, and instead of calling pg_fatal
     log the failures using pg_log_error. Make sure to capture
     errors set by fclose.
   - none: Make sure to catch errors set by fclose.

 * read_func / gets_func:
   - Make read_func unconditionally return the number of read
     bytes instead of making it optional per implementation.
   - lz4: Make sure to call throw an error and not return -1
   - gzip: gzread returning zero cannot be assumed to indicate
     EOF as it is documented to return zero for some types of
     errors.
   - lz4, zstd: Convert the _read_internal helper functions to
     not call pg_fatal on errors to be able to handle gets_func
     returning NULL on error.

 * getc_func:
   - zstd: Use an unsigned char rather than an int to read char
     into.

 * LZ4Stream_init:
   - Make sure to not switch to inited state until we know that
     initialization succeeded and reset errno just in case.

On top of these changes there are minor comment cleanups and
improvements as well as an attempt to consistently reset errno
in codepaths where it is inspected.

This work was initiated by a report of API misuse, which turned
into a larger body of work.  As this is an internal API these
changes can be backpatched into all affected branches.

Author: Tom Lane <tgl@sss.pgh.pa.us>
Author: Daniel Gustafsson <daniel@yesql.se>
Reported-by: Evgeniy Gorbanev <gorbanyoves@basealt.ru>
Discussion: https://postgr.es/m/517794.1750082166@sss.pgh.pa.us
Backpatch-through: 16
REL_16_STABLE
Daniel Gustafsson 2 weeks ago
parent f0fe1da509
commit ec017a305b
  1. 35
      src/bin/pg_dump/compress_gzip.c
  2. 2
      src/bin/pg_dump/compress_io.c
  3. 15
      src/bin/pg_dump/compress_io.h
  4. 85
      src/bin/pg_dump/compress_lz4.c
  5. 29
      src/bin/pg_dump/compress_none.c
  6. 140
      src/bin/pg_dump/compress_zstd.c
  7. 2
      src/bin/pg_dump/pg_backup_archiver.c
  8. 52
      src/bin/pg_dump/pg_backup_directory.c

@ -251,34 +251,49 @@ InitCompressorGzip(CompressorState *cs,
*----------------------
*/
static bool
Gzip_read(void *ptr, size_t size, size_t *rsize, CompressFileHandle *CFH)
static size_t
Gzip_read(void *ptr, size_t size, CompressFileHandle *CFH)
{
gzFile gzfp = (gzFile) CFH->private_data;
int gzret;
gzret = gzread(gzfp, ptr, size);
if (gzret <= 0 && !gzeof(gzfp))
/*
* gzread returns zero on EOF as well as some error conditions, and less
* than zero on other error conditions, so we need to inspect for EOF on
* zero.
*/
if (gzret <= 0)
{
int errnum;
const char *errmsg = gzerror(gzfp, &errnum);
const char *errmsg;
if (gzret == 0 && gzeof(gzfp))
return 0;
errmsg = gzerror(gzfp, &errnum);
pg_fatal("could not read from input file: %s",
errnum == Z_ERRNO ? strerror(errno) : errmsg);
}
if (rsize)
*rsize = (size_t) gzret;
return true;
return (size_t) gzret;
}
static bool
static void
Gzip_write(const void *ptr, size_t size, CompressFileHandle *CFH)
{
gzFile gzfp = (gzFile) CFH->private_data;
int errnum;
const char *errmsg;
return gzwrite(gzfp, ptr, size) > 0;
if (gzwrite(gzfp, ptr, size) != size)
{
errmsg = gzerror(gzfp, &errnum);
pg_fatal("could not write to file: %s",
errnum == Z_ERRNO ? strerror(errno) : errmsg);
}
}
static int

@ -270,6 +270,7 @@ InitDiscoverCompressFileHandle(const char *path, const char *mode)
}
CFH = InitCompressFileHandle(compression_spec);
errno = 0;
if (!CFH->open_func(fname, -1, mode, CFH))
{
free_keep_errno(CFH);
@ -290,6 +291,7 @@ EndCompressFileHandle(CompressFileHandle *CFH)
{
bool ret = false;
errno = 0;
if (CFH->private_data)
ret = CFH->close_func(CFH);

@ -123,21 +123,22 @@ struct CompressFileHandle
CompressFileHandle *CFH);
/*
* Read 'size' bytes of data from the file and store them into 'ptr'.
* Optionally it will store the number of bytes read in 'rsize'.
* Read up to 'size' bytes of data from the file and store them into
* 'ptr'.
*
* Returns true on success and throws an internal error otherwise.
* Returns number of bytes read (this might be less than 'size' if EOF was
* reached). Exits via pg_fatal for all error conditions.
*/
bool (*read_func) (void *ptr, size_t size, size_t *rsize,
size_t (*read_func) (void *ptr, size_t size,
CompressFileHandle *CFH);
/*
* Write 'size' bytes of data into the file from 'ptr'.
*
* Returns true on success and false on error.
* Returns nothing, exits via pg_fatal for all error conditions.
*/
bool (*write_func) (const void *ptr, size_t size,
struct CompressFileHandle *CFH);
void (*write_func) (const void *ptr, size_t size,
CompressFileHandle *CFH);
/*
* Read at most size - 1 characters from the compress file handle into

@ -12,6 +12,8 @@
*-------------------------------------------------------------------------
*/
#include "postgres_fe.h"
#include <unistd.h>
#include "pg_backup_utils.h"
#include "compress_lz4.h"
@ -358,7 +360,6 @@ LZ4Stream_init(LZ4State *state, int size, bool compressing)
return true;
state->compressing = compressing;
state->inited = true;
/* When compressing, write LZ4 header to the output stream. */
if (state->compressing)
@ -367,6 +368,7 @@ LZ4Stream_init(LZ4State *state, int size, bool compressing)
if (!LZ4State_compression_init(state))
return false;
errno = 0;
if (fwrite(state->buffer, 1, state->compressedlen, state->fp) != state->compressedlen)
{
errno = (errno) ? errno : ENOSPC;
@ -390,6 +392,7 @@ LZ4Stream_init(LZ4State *state, int size, bool compressing)
state->overflowlen = 0;
}
state->inited = true;
return true;
}
@ -457,7 +460,11 @@ LZ4Stream_read_internal(LZ4State *state, void *ptr, int ptrsize, bool eol_flag)
/* Lazy init */
if (!LZ4Stream_init(state, size, false /* decompressing */ ))
{
pg_log_error("unable to initialize LZ4 library: %s",
LZ4F_getErrorName(state->errcode));
return -1;
}
/* No work needs to be done for a zero-sized output buffer */
if (size <= 0)
@ -484,7 +491,10 @@ LZ4Stream_read_internal(LZ4State *state, void *ptr, int ptrsize, bool eol_flag)
rsize = fread(readbuf, 1, size, state->fp);
if (rsize < size && !feof(state->fp))
{
pg_log_error("could not read from input file: %m");
return -1;
}
rp = (char *) readbuf;
rend = (char *) readbuf + rsize;
@ -501,6 +511,8 @@ LZ4Stream_read_internal(LZ4State *state, void *ptr, int ptrsize, bool eol_flag)
if (LZ4F_isError(status))
{
state->errcode = status;
pg_log_error("could not read from input file: %s",
LZ4F_getErrorName(state->errcode));
return -1;
}
@ -558,7 +570,7 @@ LZ4Stream_read_internal(LZ4State *state, void *ptr, int ptrsize, bool eol_flag)
/*
* Compress size bytes from ptr and write them to the stream.
*/
static bool
static void
LZ4Stream_write(const void *ptr, size_t size, CompressFileHandle *CFH)
{
LZ4State *state = (LZ4State *) CFH->private_data;
@ -567,7 +579,8 @@ LZ4Stream_write(const void *ptr, size_t size, CompressFileHandle *CFH)
/* Lazy init */
if (!LZ4Stream_init(state, size, true))
return false;
pg_fatal("unable to initialize LZ4 library: %s",
LZ4F_getErrorName(state->errcode));
while (remaining > 0)
{
@ -578,28 +591,24 @@ LZ4Stream_write(const void *ptr, size_t size, CompressFileHandle *CFH)
status = LZ4F_compressUpdate(state->ctx, state->buffer, state->buflen,
ptr, chunk, NULL);
if (LZ4F_isError(status))
{
state->errcode = status;
return false;
}
pg_fatal("error during writing: %s", LZ4F_getErrorName(status));
errno = 0;
if (fwrite(state->buffer, 1, status, state->fp) != status)
{
errno = (errno) ? errno : ENOSPC;
return false;
pg_fatal("error during writing: %m");
}
ptr = ((const char *) ptr) + chunk;
}
return true;
}
/*
* fread() equivalent implementation for LZ4 compressed files.
*/
static bool
LZ4Stream_read(void *ptr, size_t size, size_t *rsize, CompressFileHandle *CFH)
static size_t
LZ4Stream_read(void *ptr, size_t size, CompressFileHandle *CFH)
{
LZ4State *state = (LZ4State *) CFH->private_data;
int ret;
@ -607,10 +616,7 @@ LZ4Stream_read(void *ptr, size_t size, size_t *rsize, CompressFileHandle *CFH)
if ((ret = LZ4Stream_read_internal(state, ptr, size, false)) < 0)
pg_fatal("could not read from input file: %s", LZ4Stream_get_error(CFH));
if (rsize)
*rsize = (size_t) ret;
return true;
return (size_t) ret;
}
/*
@ -643,11 +649,13 @@ LZ4Stream_gets(char *ptr, int size, CompressFileHandle *CFH)
int ret;
ret = LZ4Stream_read_internal(state, ptr, size - 1, true);
if (ret < 0 || (ret == 0 && !LZ4Stream_eof(CFH)))
pg_fatal("could not read from input file: %s", LZ4Stream_get_error(CFH));
/* Done reading */
if (ret == 0)
/*
* LZ4Stream_read_internal returning 0 or -1 means that it was either an
* EOF or an error, but gets_func is defined to return NULL in either case
* so we can treat both the same here.
*/
if (ret <= 0)
return NULL;
/*
@ -669,6 +677,7 @@ LZ4Stream_close(CompressFileHandle *CFH)
FILE *fp;
LZ4State *state = (LZ4State *) CFH->private_data;
size_t status;
int ret;
fp = state->fp;
if (state->inited)
@ -677,24 +686,30 @@ LZ4Stream_close(CompressFileHandle *CFH)
{
status = LZ4F_compressEnd(state->ctx, state->buffer, state->buflen, NULL);
if (LZ4F_isError(status))
pg_fatal("could not end compression: %s",
{
pg_log_error("could not end compression: %s",
LZ4F_getErrorName(status));
else if (fwrite(state->buffer, 1, status, state->fp) != status)
}
else
{
errno = 0;
if (fwrite(state->buffer, 1, status, state->fp) != status)
{
errno = (errno) ? errno : ENOSPC;
WRITE_ERROR_EXIT;
pg_log_error("could not write to output file: %m");
}
}
status = LZ4F_freeCompressionContext(state->ctx);
if (LZ4F_isError(status))
pg_fatal("could not end compression: %s",
pg_log_error("could not end compression: %s",
LZ4F_getErrorName(status));
}
else
{
status = LZ4F_freeDecompressionContext(state->dtx);
if (LZ4F_isError(status))
pg_fatal("could not end decompression: %s",
pg_log_error("could not end decompression: %s",
LZ4F_getErrorName(status));
pg_free(state->overflowbuf);
}
@ -703,29 +718,35 @@ LZ4Stream_close(CompressFileHandle *CFH)
}
pg_free(state);
CFH->private_data = NULL;
errno = 0;
ret = fclose(fp);
if (ret != 0)
{
pg_log_error("could not close file: %m");
return false;
}
return fclose(fp) == 0;
return true;
}
static bool
LZ4Stream_open(const char *path, int fd, const char *mode,
CompressFileHandle *CFH)
{
FILE *fp;
LZ4State *state = (LZ4State *) CFH->private_data;
if (fd >= 0)
fp = fdopen(fd, mode);
state->fp = fdopen(dup(fd), mode);
else
fp = fopen(path, mode);
if (fp == NULL)
state->fp = fopen(path, mode);
if (state->fp == NULL)
{
state->errcode = errno;
return false;
}
state->fp = fp;
return true;
}

@ -83,36 +83,32 @@ InitCompressorNone(CompressorState *cs,
* Private routines
*/
static bool
read_none(void *ptr, size_t size, size_t *rsize, CompressFileHandle *CFH)
static size_t
read_none(void *ptr, size_t size, CompressFileHandle *CFH)
{
FILE *fp = (FILE *) CFH->private_data;
size_t ret;
if (size == 0)
return true;
ret = fread(ptr, 1, size, fp);
if (ret != size && !feof(fp))
if (ferror(fp))
pg_fatal("could not read from input file: %s",
strerror(errno));
if (rsize)
*rsize = ret;
return true;
return ret;
}
static bool
static void
write_none(const void *ptr, size_t size, CompressFileHandle *CFH)
{
size_t ret;
errno = 0;
ret = fwrite(ptr, 1, size, (FILE *) CFH->private_data);
if (ret != size)
return false;
return true;
{
errno = (errno) ? errno : ENOSPC;
pg_fatal("could not write to file: %m");
}
}
static const char *
@ -154,7 +150,12 @@ close_none(CompressFileHandle *CFH)
CFH->private_data = NULL;
if (fp)
{
errno = 0;
ret = fclose(fp);
if (ret != 0)
pg_log_error("could not close file: %m");
}
return ret == 0;
}

@ -13,6 +13,7 @@
*/
#include "postgres_fe.h"
#include <unistd.h>
#include "pg_backup_utils.h"
#include "compress_zstd.h"
@ -257,8 +258,8 @@ InitCompressorZstd(CompressorState *cs,
* Compressed stream API
*/
static bool
Zstd_read(void *ptr, size_t size, size_t *rdsize, CompressFileHandle *CFH)
static size_t
Zstd_read_internal(void *ptr, size_t size, CompressFileHandle *CFH, bool exit_on_error)
{
ZstdCompressorState *zstdcs = (ZstdCompressorState *) CFH->private_data;
ZSTD_inBuffer *input = &zstdcs->input;
@ -267,6 +268,22 @@ Zstd_read(void *ptr, size_t size, size_t *rdsize, CompressFileHandle *CFH)
size_t res,
cnt;
/*
* If this is the first call to the reading function, initialize the
* required datastructures.
*/
if (zstdcs->dstream == NULL)
{
zstdcs->input.src = pg_malloc0(input_allocated_size);
zstdcs->dstream = ZSTD_createDStream();
if (zstdcs->dstream == NULL)
{
if (exit_on_error)
pg_fatal("could not initialize compression library");
return -1;
}
}
output->size = size;
output->dst = ptr;
output->pos = 0;
@ -291,6 +308,13 @@ Zstd_read(void *ptr, size_t size, size_t *rdsize, CompressFileHandle *CFH)
if (input->pos == input->size)
{
cnt = fread(unconstify(void *, input->src), 1, input_allocated_size, zstdcs->fp);
if (ferror(zstdcs->fp))
{
if (exit_on_error)
pg_fatal("could not read from input file: %m");
return -1;
}
input->size = cnt;
Assert(cnt <= input_allocated_size);
@ -306,7 +330,11 @@ Zstd_read(void *ptr, size_t size, size_t *rdsize, CompressFileHandle *CFH)
res = ZSTD_decompressStream(zstdcs->dstream, output, input);
if (ZSTD_isError(res))
{
if (exit_on_error)
pg_fatal("could not decompress data: %s", ZSTD_getErrorName(res));
return -1;
}
if (output->pos == output->size)
break; /* No more room for output */
@ -319,13 +347,10 @@ Zstd_read(void *ptr, size_t size, size_t *rdsize, CompressFileHandle *CFH)
break; /* We read all the data that fits */
}
if (rdsize != NULL)
*rdsize = output->pos;
return true;
return output->pos;
}
static bool
static void
Zstd_write(const void *ptr, size_t size, CompressFileHandle *CFH)
{
ZstdCompressorState *zstdcs = (ZstdCompressorState *) CFH->private_data;
@ -338,41 +363,40 @@ Zstd_write(const void *ptr, size_t size, CompressFileHandle *CFH)
input->size = size;
input->pos = 0;
if (zstdcs->cstream == NULL)
{
zstdcs->output.size = ZSTD_CStreamOutSize();
zstdcs->output.dst = pg_malloc0(zstdcs->output.size);
zstdcs->cstream = _ZstdCStreamParams(CFH->compression_spec);
if (zstdcs->cstream == NULL)
pg_fatal("could not initialize compression library");
}
/* Consume all input, to be flushed later */
while (input->pos != input->size)
{
output->pos = 0;
res = ZSTD_compressStream2(zstdcs->cstream, output, input, ZSTD_e_continue);
if (ZSTD_isError(res))
{
zstdcs->zstderror = ZSTD_getErrorName(res);
return false;
}
pg_fatal("could not write to file: %s", ZSTD_getErrorName(res));
errno = 0;
cnt = fwrite(output->dst, 1, output->pos, zstdcs->fp);
if (cnt != output->pos)
{
zstdcs->zstderror = strerror(errno);
return false;
errno = (errno) ? errno : ENOSPC;
pg_fatal("could not write to file: %m");
}
}
return size;
}
static int
Zstd_getc(CompressFileHandle *CFH)
{
ZstdCompressorState *zstdcs = (ZstdCompressorState *) CFH->private_data;
int ret;
unsigned char ret;
if (CFH->read_func(&ret, 1, NULL, CFH) != 1)
{
if (feof(zstdcs->fp))
if (CFH->read_func(&ret, 1, CFH) != 1)
pg_fatal("could not read from input file: end of file");
else
pg_fatal("could not read from input file: %m");
}
return ret;
}
@ -389,11 +413,7 @@ Zstd_gets(char *buf, int len, CompressFileHandle *CFH)
*/
for (i = 0; i < len - 1; ++i)
{
size_t readsz;
if (!CFH->read_func(&buf[i], 1, &readsz, CFH))
break;
if (readsz != 1)
if (Zstd_read_internal(&buf[i], 1, CFH, false) != 1)
break;
if (buf[i] == '\n')
{
@ -405,10 +425,17 @@ Zstd_gets(char *buf, int len, CompressFileHandle *CFH)
return i > 0 ? buf : NULL;
}
static size_t
Zstd_read(void *ptr, size_t size, CompressFileHandle *CFH)
{
return Zstd_read_internal(ptr, size, CFH, true);
}
static bool
Zstd_close(CompressFileHandle *CFH)
{
ZstdCompressorState *zstdcs = (ZstdCompressorState *) CFH->private_data;
bool success = true;
if (zstdcs->cstream)
{
@ -425,14 +452,18 @@ Zstd_close(CompressFileHandle *CFH)
if (ZSTD_isError(res))
{
zstdcs->zstderror = ZSTD_getErrorName(res);
return false;
success = false;
break;
}
errno = 0;
cnt = fwrite(output->dst, 1, output->pos, zstdcs->fp);
if (cnt != output->pos)
{
errno = (errno) ? errno : ENOSPC;
zstdcs->zstderror = strerror(errno);
return false;
success = false;
break;
}
if (res == 0)
@ -449,11 +480,16 @@ Zstd_close(CompressFileHandle *CFH)
pg_free(unconstify(void *, zstdcs->input.src));
}
errno = 0;
if (fclose(zstdcs->fp) != 0)
return false;
{
zstdcs->zstderror = strerror(errno);
success = false;
}
pg_free(zstdcs);
return true;
CFH->private_data = NULL;
return success;
}
static bool
@ -471,35 +507,33 @@ Zstd_open(const char *path, int fd, const char *mode,
FILE *fp;
ZstdCompressorState *zstdcs;
/*
* Clear state storage to avoid having the fd point to non-NULL memory on
* error return.
*/
CFH->private_data = NULL;
zstdcs = (ZstdCompressorState *) pg_malloc_extended(sizeof(*zstdcs),
MCXT_ALLOC_NO_OOM | MCXT_ALLOC_ZERO);
if (!zstdcs)
{
errno = ENOMEM;
return false;
}
if (fd >= 0)
fp = fdopen(fd, mode);
fp = fdopen(dup(fd), mode);
else
fp = fopen(path, mode);
if (fp == NULL)
{
pg_free(zstdcs);
return false;
}
zstdcs = (ZstdCompressorState *) pg_malloc0(sizeof(*zstdcs));
CFH->private_data = zstdcs;
zstdcs->fp = fp;
if (mode[0] == 'r')
{
zstdcs->input.src = pg_malloc0(ZSTD_DStreamInSize());
zstdcs->dstream = ZSTD_createDStream();
if (zstdcs->dstream == NULL)
pg_fatal("could not initialize compression library");
}
else if (mode[0] == 'w' || mode[0] == 'a')
{
zstdcs->output.size = ZSTD_CStreamOutSize();
zstdcs->output.dst = pg_malloc0(zstdcs->output.size);
zstdcs->cstream = _ZstdCStreamParams(CFH->compression_spec);
if (zstdcs->cstream == NULL)
pg_fatal("could not initialize compression library");
}
else
pg_fatal("unhandled mode \"%s\"", mode);
CFH->private_data = zstdcs;
return true;
}

@ -1761,7 +1761,7 @@ ahwrite(const void *ptr, size_t size, size_t nmemb, ArchiveHandle *AH)
{
CompressFileHandle *CFH = (CompressFileHandle *) AH->OF;
if (CFH->write_func(ptr, size * nmemb, CFH))
CFH->write_func(ptr, size * nmemb, CFH);
bytes_written = size * nmemb;
}

@ -347,15 +347,9 @@ _WriteData(ArchiveHandle *AH, const void *data, size_t dLen)
lclContext *ctx = (lclContext *) AH->formatData;
CompressFileHandle *CFH = ctx->dataFH;
errno = 0;
if (dLen > 0 && !CFH->write_func(data, dLen, CFH))
{
/* if write didn't set errno, assume problem is no disk space */
if (errno == 0)
errno = ENOSPC;
pg_fatal("could not write to output file: %s",
CFH->get_error_func(CFH));
}
if (dLen <= 0)
return;
CFH->write_func(data, dLen, CFH);
}
/*
@ -382,7 +376,7 @@ _EndData(ArchiveHandle *AH, TocEntry *te)
static void
_PrintFileData(ArchiveHandle *AH, char *filename)
{
size_t cnt = 0;
size_t cnt;
char *buf;
size_t buflen;
CompressFileHandle *CFH;
@ -397,7 +391,7 @@ _PrintFileData(ArchiveHandle *AH, char *filename)
buflen = DEFAULT_IO_BUFFER_SIZE;
buf = pg_malloc(buflen);
while (CFH->read_func(buf, buflen, &cnt, CFH) && cnt > 0)
while ((cnt = CFH->read_func(buf, buflen, CFH)) > 0)
{
ahwrite(buf, 1, cnt, AH);
}
@ -490,16 +484,7 @@ _WriteByte(ArchiveHandle *AH, const int i)
lclContext *ctx = (lclContext *) AH->formatData;
CompressFileHandle *CFH = ctx->dataFH;
errno = 0;
if (!CFH->write_func(&c, 1, CFH))
{
/* if write didn't set errno, assume problem is no disk space */
if (errno == 0)
errno = ENOSPC;
pg_fatal("could not write to output file: %s",
CFH->get_error_func(CFH));
}
CFH->write_func(&c, 1, CFH);
return 1;
}
@ -528,15 +513,7 @@ _WriteBuf(ArchiveHandle *AH, const void *buf, size_t len)
lclContext *ctx = (lclContext *) AH->formatData;
CompressFileHandle *CFH = ctx->dataFH;
errno = 0;
if (!CFH->write_func(buf, len, CFH))
{
/* if write didn't set errno, assume problem is no disk space */
if (errno == 0)
errno = ENOSPC;
pg_fatal("could not write to output file: %s",
CFH->get_error_func(CFH));
}
CFH->write_func(buf, len, CFH);
}
/*
@ -551,10 +528,10 @@ _ReadBuf(ArchiveHandle *AH, void *buf, size_t len)
CompressFileHandle *CFH = ctx->dataFH;
/*
* If there was an I/O error, we already exited in readF(), so here we
* exit on short reads.
* We do not expect a short read, so fail if we get one. The read_func
* already dealt with any outright I/O error.
*/
if (!CFH->read_func(buf, len, NULL, CFH))
if (CFH->read_func(buf, len, CFH) != len)
pg_fatal("could not read from input file: end of file");
}
@ -696,14 +673,7 @@ _EndLO(ArchiveHandle *AH, TocEntry *te, Oid oid)
/* register the LO in blobs.toc */
len = snprintf(buf, sizeof(buf), "%u blob_%u.dat\n", oid, oid);
if (!CFH->write_func(buf, len, CFH))
{
/* if write didn't set errno, assume problem is no disk space */
if (errno == 0)
errno = ENOSPC;
pg_fatal("could not write to LOs TOC file: %s",
CFH->get_error_func(CFH));
}
CFH->write_func(buf, len, CFH);
}
/*

Loading…
Cancel
Save