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]

