A gzclose call has the same potential for errors as a write,
since the compressor needs to flush its buffers before closing
its output file.  The same applies to BZ2_bzclose, but
unfortunately libbz2's gzio-style API does not expose the error
code.  Luckily, the only possible errors are I/O errors, which
can be detected through errno.

Similarly, explicitly closing a file descriptor can reveal errors
writing out buffered data.

Closing input handles, on the other hand, would be a waste of
time: all it would accomplish is to free some resources held by a
process that is about to exit anyway.

Signed-off-by: Jonathan Nieder <[email protected]>
---
 lib/dpkg/compression-backend.c |   55 ++++++++++++++++++++++++++++++++++-----
 1 files changed, 48 insertions(+), 7 deletions(-)

diff --git a/lib/dpkg/compression-backend.c b/lib/dpkg/compression-backend.c
index 9bfbcee..101018a 100644
--- a/lib/dpkg/compression-backend.c
+++ b/lib/dpkg/compression-backend.c
@@ -83,16 +83,21 @@ fd_fd_filter(int fd_in, int fd_out, const char *desc,
                        ohshite(_("%s: internal " format " error: %s"), \
                                desc, "write"); \
        } \
+       \
+       if (close(fd_out)) \
+               ohshite(_("%s: internal " format " error: %s"), \
+                       desc, "close"); \
        exit(0); \
 } while(0)
 
-#define COMPRESS(format, zFile, zdopen, zwrite, zclose, zerror, ERR_ERRNO, \
+#define COMPRESS(format, zFile, zdopen, zwrite, zclose, \
+               zcloseerror, zerror, ERR_ERRNO, \
                fd_in, fd_out, compression, desc) do \
 { \
        char combuf[] = {'w', compression, '\0'}; \
-       int actualread, actualwrite; \
        char buffer[4096]; \
        zFile zfile; \
+       int actualread, actualwrite, err = 0; \
        \
        zfile = zdopen(fd_out, combuf); \
        while ((actualread = read(fd_in, buffer, sizeof(buffer)))) { \
@@ -102,7 +107,6 @@ fd_fd_filter(int fd_in, int fd_out, const char *desc,
                \
                actualwrite = zwrite(zfile, buffer, actualread); \
                if (actualwrite != actualread) { \
-                       int err = 0; \
                        const char *errmsg = zerror(zfile, &err); \
                        \
                        if (err == ERR_ERRNO) \
@@ -111,7 +115,15 @@ fd_fd_filter(int fd_in, int fd_out, const char *desc,
                                desc, "write", errmsg); \
                } \
        } \
-       zclose(zfile); \
+       \
+       err = zclose(zfile); \
+       if (err) { \
+               const char *errmsg = err == ERR_ERRNO ? \
+                       strerror(errno) : zcloseerror(err); \
+               \
+               ohshit(_("%s: internal " format " error: %s: %s"), \
+                       desc, "close", errmsg); \
+       } \
        exit(0); \
 } while(0)
 
@@ -133,7 +145,8 @@ decompress_gzip(int fd_in, int fd_out, const char *desc)
 void
 compress_gzip(int fd_in, int fd_out, char compression, const char *desc)
 {
-       COMPRESS("gzip", gzFile, gzdopen, gzwrite, gzclose, gzerror, Z_ERRNO,
+       COMPRESS("gzip", gzFile, gzdopen, gzwrite, gzclose,
+               zError, gzerror, Z_ERRNO,
                fd_in, fd_out, compression, desc);
 }
 #else /* !WITH_ZLIB */
@@ -151,6 +164,34 @@ compress_gzip(int fd_in, int fd_out, char compression, 
const char *desc)
 #endif
 
 #ifdef WITH_BZ2
+/*
+ * BZ2_bzclose does not pass on the error code to the caller.
+ * To work around this, we could
+ *  - set errno to 0 and compare the value afterwards, hoping
+ *    that libbz2 did not recover from any errors itself
+ *  or
+ *  - modify a copy of BZ2_bzclose to expose the error
+ * This function follows the former course, so it can continue
+ * to work even if the layout of BZFILE objects should change.
+ */
+static int
+bzclose(BZFILE *b)
+{
+       errno = 0;
+       BZ2_bzclose(b);
+       if (errno)
+               return BZ_IO_ERROR;
+
+       return 0;
+}
+
+static const char * DPKG_ATTR_CONST
+bzcloseerror(int err)
+{
+       /* bzclose only returns BZ_OK and BZ_IO_ERROR. */
+       return _("Unexpected error (bug)");
+}
+
 void
 decompress_bzip2(int fd_in, int fd_out, const char *desc)
 {
@@ -162,8 +203,8 @@ decompress_bzip2(int fd_in, int fd_out, const char *desc)
 void
 compress_bzip2(int fd_in, int fd_out, char compression, const char *desc)
 {
-       COMPRESS("bzip2", BZFILE *, BZ2_bzdopen, BZ2_bzwrite, BZ2_bzclose,
-               BZ2_bzerror, BZ_IO_ERROR,
+       COMPRESS("bzip2", BZFILE *, BZ2_bzdopen, BZ2_bzwrite, bzclose,
+               bzcloseerror, BZ2_bzerror, BZ_IO_ERROR,
                fd_in, fd_out, compression, desc);
 }
 #else /* !WITH_BZ2 */
-- 
1.6.5.rc1.199.g596ec


-- 
To UNSUBSCRIBE, email to [email protected]
with a subject of "unsubscribe". Trouble? Contact [email protected]

Reply via email to