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.
static ssize_t read_sectors(secaddr pos, void *buf, secaddr want)
{
static ssize_t read_sectors(secaddr pos, void *buf, secaddr want)
{
struct badblock *bad, *best;
struct badblock *bad, *best;
+ unsigned char *p = buf;
best = 0; lo = 0; hi = badblocks.n;
#ifdef DEBUG
best = 0; lo = 0; hi = badblocks.n;
#ifdef DEBUG
printf(";; next is %"PRIuSEC" .. %"PRIuSEC"\n",
best->start, best->end);
#endif
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,
}
static ssize_t find_good_sector(secaddr *pos_inout, secaddr end,