dvd-sector-copy.c: Make `read_sectors' more persistent after short reads.
authorMark Wooding <mdw@distorted.org.uk>
Fri, 18 Feb 2022 18:50:27 +0000 (18:50 +0000)
committerMark Wooding <mdw@distorted.org.uk>
Fri, 18 Feb 2022 18:56:25 +0000 (18:56 +0000)
It now continues trying to read until it gets an error, end-of-file, or
it completes the task requested of it.  For consistency, we must also
report an error after a short read forced by a synthetic bad sector,
which requires a little additional machinery.

dvd-sector-copy.c

index 6735292..bbe0c10 100644 (file)
@@ -415,9 +415,11 @@ static int compare_badblock(const void *a, const void *b)
 
 static ssize_t read_sectors(secaddr pos, void *buf, secaddr want)
 {
-  ssize_t n;
+  ssize_t n, done;
   size_t lo, mid, hi;
+  int fakeerr = 0;
   struct badblock *bad, *best;
+  unsigned char *p = buf;
 
   best = 0; lo = 0; hi = badblocks.n;
 #ifdef DEBUG
@@ -440,23 +442,28 @@ static ssize_t read_sectors(secaddr pos, void *buf, secaddr want)
     printf(";;   next is %"PRIuSEC" .. %"PRIuSEC"\n",
           best->start, best->end);
 #endif
-  if (best && pos + want > best->start) want = best->start - pos;
-
-again:
-  if (vob)
-    n = DVDReadBlocks(vob, pos - file->start, want, buf);
-  else if (file) {
-    if (lseek(dvdfd, (off_t)pos*SECTORSZ, SEEK_SET) < 0)
-      bail_syserr(errno, "failed to seek to sector %"PRIuSEC"", pos);
-    n = read(dvdfd, buf, want*SECTORSZ);
-    if (n >= 0) n /= SECTORSZ;
-  } else {
-    memset(buf, 0, want*SECTORSZ);
-    n = want;
-  }
+  if (best && pos + want > best->start)
+    { want = best->start - pos; fakeerr = EIO; }
+
+  done = 0;
+  while (want) {
+    if (vob)
+      { errno = 0; n = DVDReadBlocks(vob, pos - file->start, want, p); }
+    else if (file) {
+      if (lseek(dvdfd, (off_t)pos*SECTORSZ, SEEK_SET) < 0)
+       bail_syserr(errno, "failed to seek to sector %"PRIuSEC"", pos);
+      errno = 0; n = read(dvdfd, p, want*SECTORSZ);
+      if (n >= 0) n /= SECTORSZ;
+    } else {
+      memset(p, 0, want*SECTORSZ);
+      n = want;
+    }
 
-  if (n < 0 && errno == EINTR) goto again;
-  return (n);
+    if (n > 0) { done += n; pos += n; p += n*SECTORSZ; want -= n; }
+    else if (!n || errno != EINTR) break;
+  }
+  if (fakeerr && !errno) errno = fakeerr;
+  return (!done && errno ? -1 : done);
 }
 
 static ssize_t find_good_sector(secaddr *pos_inout, secaddr end,