Fix pg_dump's errno checking for zlib I/O
authorAlvaro Herrera <alvherre@alvh.no-ip.org>
Wed, 2 Aug 2017 22:26:26 +0000 (18:26 -0400)
committerAlvaro Herrera <alvherre@alvh.no-ip.org>
Wed, 2 Aug 2017 22:26:59 +0000 (18:26 -0400)
Some error reports were reporting strerror(errno), which for some error
conditions coming from zlib are wrong, resulting in confusing reports
such as
  pg_restore: [compress_io] could not read from input file: Success
which makes no sense.  To correctly extract the error message we need to
use gzerror(), so let's do that.

This isn't as comprehensive or as neat as I would like, but at least it
should improve things in many common cases.  The zlib abstraction in
compress_io does not seem to be applied consistently enough; we could
perhaps improve that, but it seems master-only material, not a bug fix
for back-patching.

This problem goes back all the way, but I decided to apply back to 9.4
only, because older branches don't contain commit 14ea89366 which this
change depends on.

Authors: Vladimir Kunschikov, Álvaro Herrera
Discussion: https://postgr.es/m/1498120508308.9826@infotecs.ru

src/bin/pg_dump/compress_io.c
src/bin/pg_dump/compress_io.h
src/bin/pg_dump/pg_backup_directory.c
src/bin/pg_dump/pg_backup_tar.c

index 991fe11e8a6e798ec75a1e7fc1e98c961f4fff2e..e94f7d3274372ffdef2a559a6413548fa4721819 100644 (file)
@@ -592,8 +592,14 @@ cfread(void *ptr, int size, cfp *fp)
    {
        ret = gzread(fp->compressedfp, ptr, size);
        if (ret != size && !gzeof(fp->compressedfp))
+       {
+           int     errnum;
+           const char *errmsg = gzerror(fp->compressedfp, &errnum);
+
            exit_horribly(modulename,
-                         "could not read from input file: %s\n", strerror(errno));
+                         "could not read from input file: %s\n",
+                         errnum == Z_ERRNO ? strerror(errno) : errmsg);
+       }
    }
    else
 #endif
@@ -695,6 +701,22 @@ cfeof(cfp *fp)
        return feof(fp->uncompressedfp);
 }
 
+const char *
+get_cfp_error(cfp *fp)
+{
+#ifdef HAVE_LIBZ
+   if (fp->compressedfp)
+   {
+       int         errnum;
+       const char *errmsg = gzerror(fp->compressedfp, &errnum);
+
+       if (errnum != Z_ERRNO)
+           return errmsg;
+   }
+#endif
+   return strerror(errno);
+}
+
 #ifdef HAVE_LIBZ
 static int
 hasSuffix(const char *filename, const char *suffix)
index 8f2e752cba78b42e3b768581b342cc0cd3c2cb82..f42eb84007c02776a84be3c956ec5243af03834e 100644 (file)
@@ -65,5 +65,6 @@ extern int    cfgetc(cfp *fp);
 extern char *cfgets(cfp *fp, char *buf, int len);
 extern int cfclose(cfp *fp);
 extern int cfeof(cfp *fp);
+extern const char *get_cfp_error(cfp *fp);
 
 #endif
index 79922da8ba36b2feee69f12ac27a757aff83d6e1..112fbb0f0c8c54ebaab879e04e4f17496abe4479 100644 (file)
@@ -352,7 +352,9 @@ _WriteData(ArchiveHandle *AH, const void *data, size_t dLen)
    lclContext *ctx = (lclContext *) AH->formatData;
 
    if (dLen > 0 && cfwrite(data, dLen, ctx->dataFH) != dLen)
-       WRITE_ERROR_EXIT;
+       exit_horribly(modulename, "could not write to output file: %s\n",
+                     get_cfp_error(ctx->dataFH));
+
 
    return;
 }
@@ -490,7 +492,8 @@ _WriteByte(ArchiveHandle *AH, const int i)
    lclContext *ctx = (lclContext *) AH->formatData;
 
    if (cfwrite(&c, 1, ctx->dataFH) != 1)
-       WRITE_ERROR_EXIT;
+       exit_horribly(modulename, "could not write to output file: %s\n",
+                     get_cfp_error(ctx->dataFH));
 
    return 1;
 }
@@ -519,7 +522,8 @@ _WriteBuf(ArchiveHandle *AH, const void *buf, size_t len)
    lclContext *ctx = (lclContext *) AH->formatData;
 
    if (cfwrite(buf, len, ctx->dataFH) != len)
-       WRITE_ERROR_EXIT;
+       exit_horribly(modulename, "could not write to output file: %s\n",
+                     get_cfp_error(ctx->dataFH));
 
    return;
 }
index f839712945fc64b69077a81ca04fcbccd2c2b2b3..3c41d40a9380bcc78bb74a81c9b6ba7bc9d3d827 100644 (file)
@@ -555,8 +555,14 @@ _tarReadRaw(ArchiveHandle *AH, void *buf, size_t len, TAR_MEMBER *th, FILE *fh)
            {
                res = GZREAD(&((char *) buf)[used], 1, len, th->zFH);
                if (res != len && !GZEOF(th->zFH))
+               {
+                   int     errnum;
+                   const char *errmsg = gzerror(th->zFH, &errnum);
+
                    exit_horribly(modulename,
-                                 "could not read from input file: %s\n", strerror(errno));
+                                 "could not read from input file: %s\n",
+                                 errnum == Z_ERRNO ? strerror(errno) : errmsg);
+               }
            }
            else
            {