From bc4152b8da68fe719ab04ffbe98c36282e9feb83 Mon Sep 17 00:00:00 2001 From: Daniel Gustafsson Date: Wed, 25 Jun 2025 15:53:00 +0200 Subject: [PATCH v6 6/6] pg_dump compression API: read_func / gets_func read_func is defined to return the number of bytes read, zero for EOF and throw an error on all error conditions * 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. * none: Don't call ferror on every fread unless it returne zero and we can expect there to be an error or EOF. gets_func is defined go return *s on success and NULL on error or if EOF is found before any char has been read. * lz4, zstd: Convert _read_internal functions to not automatically call pg_fatal on errors to be able to handle gets returning NULL on error. --- src/bin/pg_dump/compress_gzip.c | 15 +++++++++++++-- src/bin/pg_dump/compress_io.h | 2 +- src/bin/pg_dump/compress_lz4.c | 19 +++++++++++++++---- src/bin/pg_dump/compress_none.c | 2 +- src/bin/pg_dump/compress_zstd.c | 28 +++++++++++++++++++++++----- 5 files changed, 53 insertions(+), 13 deletions(-) diff --git a/src/bin/pg_dump/compress_gzip.c b/src/bin/pg_dump/compress_gzip.c index b5fac207866..9772c936e38 100644 --- a/src/bin/pg_dump/compress_gzip.c +++ b/src/bin/pg_dump/compress_gzip.c @@ -258,10 +258,21 @@ Gzip_read(void *ptr, size_t size, CompressFileHandle *CFH) int gzret; gzret = gzread(gzfp, ptr, size); - if (gzret < 0) + + /* + * 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); diff --git a/src/bin/pg_dump/compress_io.h b/src/bin/pg_dump/compress_io.h index 9c40cf0e7bd..99d21065488 100644 --- a/src/bin/pg_dump/compress_io.h +++ b/src/bin/pg_dump/compress_io.h @@ -127,7 +127,7 @@ struct CompressFileHandle * 'ptr'. * * Returns number of bytes read (this might be less than 'size' if EOF was - * reached). Throws error for error conditions other than EOF. + * reached). Exits via pg_fatal all for error conditions. */ size_t (*read_func) (void *ptr, size_t size, CompressFileHandle *CFH); diff --git a/src/bin/pg_dump/compress_lz4.c b/src/bin/pg_dump/compress_lz4.c index 32ced77d562..8660977e41c 100644 --- a/src/bin/pg_dump/compress_lz4.c +++ b/src/bin/pg_dump/compress_lz4.c @@ -459,7 +459,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) @@ -486,7 +490,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; @@ -503,6 +510,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; } @@ -641,11 +650,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; /* diff --git a/src/bin/pg_dump/compress_none.c b/src/bin/pg_dump/compress_none.c index 3a1a5e6f7e7..27ecd36cb61 100644 --- a/src/bin/pg_dump/compress_none.c +++ b/src/bin/pg_dump/compress_none.c @@ -90,7 +90,7 @@ read_none(void *ptr, size_t size, CompressFileHandle *CFH) size_t ret; ret = fread(ptr, 1, size, fp); - if (ferror(fp)) + if (ret == 0 && ferror(fp)) pg_fatal("could not read from input file: %m"); return ret; diff --git a/src/bin/pg_dump/compress_zstd.c b/src/bin/pg_dump/compress_zstd.c index 29f88f17a78..ba09c38748d 100644 --- a/src/bin/pg_dump/compress_zstd.c +++ b/src/bin/pg_dump/compress_zstd.c @@ -260,7 +260,7 @@ InitCompressorZstd(CompressorState *cs, */ static size_t -Zstd_read(void *ptr, size_t size, CompressFileHandle *CFH) +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; @@ -278,7 +278,11 @@ Zstd_read(void *ptr, size_t size, CompressFileHandle *CFH) zstdcs->input.src = pg_malloc0(input_allocated_size); zstdcs->dstream = ZSTD_createDStream(); if (zstdcs->dstream == NULL) - pg_fatal("could not initialize compression library"); + { + if (exit_on_error) + pg_fatal("could not initialize compression library"); + return -1; + } } output->size = size; @@ -306,7 +310,11 @@ Zstd_read(void *ptr, size_t size, CompressFileHandle *CFH) { cnt = fread(unconstify(void *, input->src), 1, input_allocated_size, zstdcs->fp); if (ferror(zstdcs->fp)) - pg_fatal("could not read from input file: %m"); + { + if (exit_on_error) + pg_fatal("could not read from input file: %m"); + return -1; + } input->size = cnt; @@ -323,7 +331,11 @@ Zstd_read(void *ptr, size_t size, CompressFileHandle *CFH) res = ZSTD_decompressStream(zstdcs->dstream, output, input); if (ZSTD_isError(res)) - pg_fatal("could not decompress data: %s", ZSTD_getErrorName(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 */ @@ -404,7 +416,7 @@ Zstd_gets(char *buf, int len, CompressFileHandle *CFH) */ for (i = 0; i < len - 1; ++i) { - if (CFH->read_func(&buf[i], 1, CFH) != 1) + if (Zstd_read_internal(&buf[i], 1, CFH, false) != 1) break; if (buf[i] == '\n') { @@ -416,6 +428,12 @@ 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) { -- 2.39.3 (Apple Git-146)