Hi Mark,

First of all, sorry for the nonsensical original report.

Mark Brown wrote:
> Oh, I doubt anything in gzio.c will ever be touched again if it can
> possibly be avoided on the basis that it's been working for people for
> years and every attempt to change things causes some kind of
> interoperability issue.

That makes sense.  Here’s what I found from skimming over the new
implementation.  Some of these things may be worth fixing, some not:

gz_open (can segfault if it runs out of memory for path)
gz_comp (reports partial writes with "slow" devices as errors.
        This is wrong in two ways: it discards data, and errno
        contains random nonsense.)
gz_load (blocks in non-blocking situations with "slow" devices)
gzprintf (uses gz_zero and gz_comp, inherently nonresumable)
gzclose_r (does not report I/O errors!)
gzclose_w (uses gz_zero, gz_comp; inherently nonresumable)
gzclose (uses gzclose_r, gzclose_w)

gz{_zero,setparams,write,put[sc],flush} (uses gz_comp)
NEXT gz{_{avail,head,next4,decomp,make,skip},read,gets,{un,}getc} (uses gz_load)

Of these issues, the most important to me is the gz_comp one.  I
would like not to discard data.  For my uses, it would be fine to
restart write() to finish up any partial write.

Doing that would break applications that expect compression not to
block for so long, either because they used gzdopen on a file
descriptor with O_NONBLOCK or because the write to a "slow" device was
interrupted by a signal.  Luckily, it is possible to make both these
people and me happy without introducing new API or ABI.

The most flexible thing is to report enough information to allow
resuming after a partial write.  This means:

 - A field is added to gz_state to represent whether a flush is pending.
   gz_comp deals with any pending flush before starting other I/O.
 - gzwrite returns the number of input bytes consumed.  If not all bytes
   reached the file yet, that’s fine, so there is no need to distinguish
   successful writes from partial writes that consumed all input.
 - This would make gzputc and gzputs automatically behave
   appropriately.
 - A short write in gzflush needs to not go undetected.  gzflush should set
   errno = EINTR in this case and return E_ERRNO so the application
   knows it can be resumed.

A fix for the gz_open bug mentioned above follows (warning: untested).

-- %< --
Subject: Check for malloc() failure in gz_open()

---
 gzlib.c |   12 ++++++++----
 1 files changed, 8 insertions(+), 4 deletions(-)

diff --git a/gzlib.c b/gzlib.c
index bcef6c2..b74cb6b 100644
--- a/gzlib.c
+++ b/gzlib.c
@@ -153,6 +153,14 @@ local gzFile gz_open(path, fd, mode, use64)
         return NULL;
     }
 
+    /* save the path name for error messages */
+    state->path = malloc(strlen(path) + 1);
+    if (state->path == NULL) {
+        free(state);
+        return NULL;
+    }
+    strcpy(state->path, path);
+
     /* open the file with the appropriate mode (or just use fd) */
     state->fd = fd != -1 ? fd :
         open(path,
@@ -176,10 +184,6 @@ local gzFile gz_open(path, fd, mode, use64)
     if (state->mode == GZ_APPEND)
         state->mode = GZ_WRITE;         /* simplify later checks */
 
-    /* save the path name for error messages */
-    state->path = malloc(strlen(path) + 1);
-    strcpy(state->path, path);
-
     /* save the current position for rewinding (only if reading) */
     if (state->mode == GZ_READ) {
         state->start = LSEEK(state->fd, 0, SEEK_CUR);



-- 
To UNSUBSCRIBE, email to debian-bugs-dist-requ...@lists.debian.org
with a subject of "unsubscribe". Trouble? Contact listmas...@lists.debian.org

Reply via email to