dvd-sector-copy.c (find_good_sector): Use plain `read_sectors' for retries.
[dvdrip] / dvd-sector-copy.c
index fe8da21..8c4ba1f 100644 (file)
@@ -8,30 +8,6 @@ static void usage(FILE *fp)
          prog);
 }
 
-static double tvdiff(const struct timeval *tv_lo,
-                    const struct timeval *tv_hi)
-{
-  return ((tv_hi->tv_sec - tv_lo->tv_sec) +
-         (tv_hi->tv_usec - tv_lo->tv_usec)/1.0e6);
-}
-
-#define DEFVEC(vtype, etype)                                           \
-       typedef struct { etype *v; size_t n, sz; } vtype
-#define VEC_INIT { 0, 0, 0 }
-#define VEC_FREE(vv) do {                                              \
-  free((vv)->v); (vv)->v 0; (vv)->n = (vv)->sz = 0;                    \
-} while (0)
-#define VEC_PUSH(p, vv) do {                                           \
-  size_t _want;                                                                \
-  if ((vv)->n >= (vv)->sz) {                                           \
-    (vv)->sz = (vv)->sz ? 2*(vv)->sz : 32;                             \
-    _want = (vv)->sz*sizeof(*(vv)->v);                                 \
-    (vv)->v = realloc((vv)->v, _want);                                 \
-    if (!(vv)->v) bail("out of memory allocating %zu bytes", _want);   \
-  }                                                                    \
-  (p) = &(vv)->v[(vv)->n++];                                           \
-} while (0)
-
 #define MAXFILES (1 + 2*99 + 1)
 struct file {
   ident id;
@@ -119,8 +95,8 @@ static void put_menu(dvd_reader_t *dvd, unsigned title)
   store_filename(fn, id);
   start = UDFFindFile(dvd, fn, &len); if (!start) return;
 #ifdef DEBUG
-      printf(";; %8"PRIuSEC" .. %-8"PRIuSEC": %s\n",
-            start, start + SECTORS(len), fn);
+  printf(";; %8"PRIuSEC" .. %-8"PRIuSEC": %s\n",
+        start, start + SECTORS(len), fn);
 #endif
   put_file(id, start, start + SECTORS(len));
 }
@@ -347,7 +323,10 @@ static ssize_t read_sectors(secaddr pos, void *buf, secaddr want)
 #endif
       if (pos < bad->start) { D( printf("high\n"); ) best = bad; hi = mid; }
       else if (pos >= bad->end) { D( printf("low\n"); ) lo = mid + 1; }
-      else { D( printf("match!\n"); ) errno = EIO; return (-1); }
+      else {
+       D( printf("match!\n"); )
+       errno = EIO; sit(bad_block_delay); return (-1);
+      }
     }
 #ifdef DEBUG
     if (best)
@@ -357,7 +336,8 @@ static ssize_t read_sectors(secaddr pos, void *buf, secaddr want)
     if (best && pos + want > best->start)
       { want = best->start - pos; fakeerr = EIO; sit(bad_block_delay); }
   }
-  done = 0;
+
+  done = 0; errno = 0;
   while (want) {
     if (vob)
       { errno = 0; n = DVDReadBlocks(vob, pos - file->start, want, p); }
@@ -385,27 +365,6 @@ static ssize_t read_sectors(secaddr pos, void *buf, secaddr want)
   return (!done && errno ? -1 : done);
 }
 
-static void record_bad_sectors(secaddr bad_lo, secaddr bad_hi)
-{
-  char fn[MAXFNSZ];
-
-  if (!mapfile) return;
-
-  open_file_on_demand(mapfile, &mapfp, "bad-sector region map");
-  fprintf(mapfp, "%"PRIuSEC" %"PRIuSEC" # %"PRIuSEC" sectors",
-         bad_lo, bad_hi, bad_hi - bad_lo);
-
-  if (file && id_kind(file->id) != RAW) {
-    store_filename(fn, file->id);
-    fprintf(mapfp, "; `%s' %"PRIuSEC" .. %"PRIuSEC" of %"PRIuSEC"",
-           fn, bad_lo - file->start, bad_hi - file->start,
-           file->end - file->start);
-  }
-
-  fputc('\n', mapfp);
-  check_write(mapfp, "bad-sector region map");
-}
-
 static void recovered(secaddr bad_lo, secaddr bad_hi)
 {
   char fn[MAXFNSZ];
@@ -424,7 +383,19 @@ static void recovered(secaddr bad_lo, secaddr bad_hi)
         file->end - file->start);
   }
 
-  record_bad_sectors(bad_lo, bad_hi);
+  if (mapfile) {
+    open_file_on_demand(mapfile, &mapfp, "bad-sector region map");
+    fprintf(mapfp, "%"PRIuSEC" %"PRIuSEC" # %"PRIuSEC" sectors",
+           bad_lo, bad_hi, bad_hi - bad_lo);
+
+    if (file && id_kind(file->id) != RAW)
+      fprintf(mapfp, "; `%s' %"PRIuSEC" .. %"PRIuSEC" of %"PRIuSEC"",
+             fn, bad_lo - file->start, bad_hi - file->start,
+             file->end - file->start);
+
+    fputc('\n', mapfp);
+    check_write(mapfp, "bad-sector region map");
+  }
 
   if (lseek(outfd, (off_t)(bad_hi - bad_lo)*SECTORSZ, SEEK_CUR) < 0)
     bail_syserr(errno, "failed to seek past bad sectors");
@@ -477,6 +448,7 @@ static ssize_t recovery_read_sectors(struct recoverybuf *r,
   ssize_t n;
 
   assert(off <= r->sz); assert(want <= r->sz - off);
+  assert(pos == r->pos + off);
   n = read_sectors(pos, r->buf + off*SECTORSZ, want);
   return (n);
 }
@@ -508,9 +480,9 @@ static ssize_t recovery_read_buffer(struct recoverybuf *r,
 #endif
     }
   } else if (pos > r->pos + r->end) {
-      r->pos = pos; r->start = r->end = 0;
+    r->pos = pos; r->start = r->end = 0;
 #ifdef DEBUG
-      show_recovery_buffer_map(r, "cleared; beyond previous region");
+    show_recovery_buffer_map(r, "cleared; beyond previous region");
 #endif
   } else if (pos + want > r->pos + r->sz) {
     diff = (pos + want) - (r->pos + r->sz);
@@ -636,7 +608,7 @@ static secaddr run_length_wanted(secaddr pos, secaddr badlen, secaddr end)
 {
   secaddr want;
 
-  want = clear_factor*badlen;
+  want = ceil(clear_factor*badlen);
   if (want < clear_min) want = clear_min;
   if (want > end - pos) want = end - pos;
   if (clear_max && want > clear_max) want = clear_max;
@@ -657,13 +629,10 @@ static ssize_t find_good_sector(secaddr *pos_inout, secaddr end,
   badblock_progress.render = render_badblock_progress;
   progress_additem(&progress, &badblock_progress);
 
-  r.buf = buf; r.sz = sz; r.pos = r.start = r.end = 0;
-  r.good_lo = r.good_hi = 0;
-
   want = sz; if (want > end - pos) want = end - pos;
   for (retry = 0; retry < max_retries; retry++) {
     report_bad_blocks_progress(pos, errno);
-    n = recovery_read(&r, pos, want);
+    n = read_sectors(pos, buf, want);
 #ifdef DEBUG
     progress_clear(&progress);
     printf(";; [retry] try reading %"PRIuSEC" .. %"PRIuSEC" -> %zd\n",
@@ -678,6 +647,9 @@ static ssize_t find_good_sector(secaddr *pos_inout, secaddr end,
     }
   }
 
+  r.buf = buf; r.sz = sz; r.pos = r.start = r.end = 0;
+  r.good_lo = r.good_hi = 0;
+
   bad_lo = pos; bad_hi = pos + 1;
   for (;;) {
     report_bad_blocks_progress(bad_hi, errno);
@@ -730,16 +702,16 @@ static ssize_t find_good_sector(secaddr *pos_inout, secaddr end,
     if (n == want) good = pos;
     else bad_hi = pos + n + 1;
   }
-  recovered(bad_lo, bad_hi); *pos_inout = good;
-  if (good < r.pos + r.start || r.pos + r.end <= good)
+  recovered(bad_lo, bad_hi); *pos_inout = bad_hi;
+  if (bad_hi < r.pos + r.start || r.pos + r.end <= bad_hi)
     n = 0;
   else {
-    n = r.pos + r.end - good;
-    rearrange_sectors(&r, 0, good - r.pos, n);
+    n = r.pos + r.end - bad_hi;
+    rearrange_sectors(&r, 0, bad_hi - r.pos, n);
   }
 #ifdef DEBUG
   show_recovery_buffer_map(&r, "returning %zd good sectors at %"PRIuSEC"",
-                          n, good);
+                          n, bad_hi);
 #endif
   return (n);
 }
@@ -826,73 +798,6 @@ static void emit(secaddr start, secaddr end)
 #undef BUFSECTORS
 }
 
-struct buf {
-  char *p;
-  size_t n, sz;
-};
-#define BUF_INIT { 0, 0, 0 }
-#define BUF_REWIND(b) do { (b)->n = 0; } while (0)
-#define BUF_FREE(b) do {                                               \
-  buf *_b = (b);                                                       \
-  free(_b->p); _b->p = 0; _b->n = _b->sz = 0;                          \
-} while (0)
-#define BUF_PUTC(b, ch) do {                                           \
-  struct buf *_b = (b);                                                        \
-  if (_b->n >= _b->sz) {                                               \
-    _b->sz = _b->sz ? 2*_b->sz : 32;                                   \
-    _b->p = realloc(_b->p, _b->sz);                                    \
-    if (!_b->p) bail("out of memory allocating %zu bytes", _b->sz);    \
-  }                                                                    \
-  _b->p[_b->n] = (ch);                                                 \
-} while (0)
-
-static int read_line(FILE *fp, struct buf *b)
-{
-  int ch;
-
-  ch = getc(fp);
-  if (ch == EOF)
-    return (-1);
-  else if (ch != '\n') do {
-    BUF_PUTC(b, ch); b->n++;
-    ch = getc(fp);
-  } while (ch != EOF && ch != '\n');
-  BUF_PUTC(b, 0);
-  return (0);
-}
-
-static double parse_float(const char **p_inout, double min, double max,
-                         const char *what)
-{
-  const char *p;
-  char *q;
-  double x;
-  int err;
-
-  err = errno; errno = 0;
-  p = *p_inout;
-  x = strtod(p, &q);
-  if (errno || x < min || x > max) bail("bad %s `%s'", what, p);
-  *p_inout = q; errno = err;
-  return (x);
-}
-
-static long parse_int(const char **p_inout, long min, long max,
-                     const char *what)
-{
-  const char *p;
-  char *q;
-  long x;
-  int err;
-
-  err = errno; errno = 0;
-  p = *p_inout;
-  x = strtoul(p, &q, 0);
-  if (errno || x < min || x > max) bail("bad %s `%s'", what, p);
-  *p_inout = q; errno = err;
-  return (x);
-}
-
 #define PRF_HYPHEN 1u
 static int parse_range(const char *p, unsigned f,
                       secaddr *start_out, secaddr *end_out)
@@ -1012,25 +917,33 @@ int main(int argc, char *argv[])
        (STRNCMP(p, ==, s "=", sizeof(s)) && (p += sizeof(s), 1))
        for (;;) {
          if (SKIP_PREFIX("cf"))
-           clear_factor = parse_float(&p, 0, DBL_MAX, "clear factor");
+           clear_factor = parse_float(&p, PNF_JUNK, 0, DBL_MAX,
+                                      "clear factor");
          else if (SKIP_PREFIX("cmin"))
-           clear_min = parse_int(&p, 1, SECLIMIT, "clear minimum");
+           clear_min = parse_int(&p, PNF_JUNK, 1, SECLIMIT,
+                                 "clear minimum");
          else if (SKIP_PREFIX("cmax"))
-           clear_max = parse_int(&p, 1, SECLIMIT, "clear maximum");
+           clear_max = parse_int(&p, PNF_JUNK, 1, SECLIMIT,
+                                 "clear maximum");
          else if (SKIP_PREFIX("sf"))
-           step_factor = parse_float(&p, 0, DBL_MAX, "step factor");
+           step_factor = parse_float(&p, PNF_JUNK, 0, DBL_MAX,
+                                     "step factor");
          else if (SKIP_PREFIX("smin"))
-           step_min = parse_int(&p, 1, SECLIMIT - 1, "step minimum");
+           step_min = parse_int(&p, PNF_JUNK, 1, SECLIMIT - 1,
+                                "step minimum");
          else if (SKIP_PREFIX("smax"))
-           step_max = parse_int(&p, 1, SECLIMIT - 1, "step maximum");
+           step_max = parse_int(&p, PNF_JUNK, 1, SECLIMIT - 1,
+                                "step maximum");
          else if (SKIP_PREFIX("retry"))
-           max_retries = parse_int(&p, 0, INT_MAX, "retries");
+           max_retries = parse_int(&p, PNF_JUNK, 0, INT_MAX, "retries");
          else if (SKIP_PREFIX("alpha"))
-           alpha = parse_float(&p, 0, 1, "average decay factor");
+           alpha = parse_float(&p, PNF_JUNK, 0, 1, "average decay factor");
          else if (SKIP_PREFIX("_badwait"))
-           bad_block_delay = parse_float(&p, 0, DBL_MAX, "bad-block delay");
+           bad_block_delay = parse_float(&p, PNF_JUNK, 0, DBL_MAX,
+                                         "bad-block delay");
          else if (SKIP_PREFIX("_blkwait"))
-           good_block_delay = parse_float(&p, 0, DBL_MAX, "good block delay");
+           good_block_delay = parse_float(&p, PNF_JUNK, 0, DBL_MAX,
+                                          "good block delay");
          else
            bail("unknown bad blocks parameter `%s'", p);
          if (!*p) break;
@@ -1047,7 +960,7 @@ int main(int argc, char *argv[])
          bail_syserr(errno, "failed to open ranges file `%s'", optarg);
        i = 0; last = -1;
        for (;;) {
-         BUF_REWIND(&buf); if (read_line(fp, &buf)) break;
+         buf_rewind(&buf); if (read_line(fp, &buf)) break;
          p = buf.p; i++;
          while (ISSPACE(*p)) p++;
          if (!*p || *p == '#') continue;
@@ -1073,7 +986,7 @@ int main(int argc, char *argv[])
          bail_syserr(errno, "failed to open bad-blocks file `%s'", optarg);
        i = 0; last = -1;
        for (;;) {
-         BUF_REWIND(&buf); if (read_line(fp, &buf)) break;
+         buf_rewind(&buf); if (read_line(fp, &buf)) break;
          p = buf.p; i++;
          while (ISSPACE(*p)) p++;
          if (!*p || *p == '#') continue;
@@ -1123,7 +1036,7 @@ int main(int argc, char *argv[])
 #endif
   }
 
-  open_dvd(device, &dvdfd, &dvd);
+  if (open_dvd(device, O_RDONLY, &dvdfd, &dvd)) exit(2);
 
   blksz = SECTORSZ; volsz = device_size(dvdfd, device, &blksz);
   if (blksz != SECTORSZ)
@@ -1133,7 +1046,7 @@ int main(int argc, char *argv[])
         device, volsz, SECTORSZ);
 
   if (f&f_checkid) {
-    open_dvd(outfile, 0, &dvd_out);
+    if (open_dvd(outfile, O_RDONLY, 0, &dvd_out)) exit(2);
     if (dvd_id(id_in, dvd, DIF_MUSTIFOHASH, device) ||
        dvd_id(id_out, dvd_out, DIF_MUSTIFOHASH, device))
       exit(2);
@@ -1174,7 +1087,8 @@ int main(int argc, char *argv[])
   for (i = 0; i < filetab.n; i++) {
     file = &filetab.v[i];
     store_filename(fn, file->id);
-    printf(";;\t%8"PRIuSEC" %s\n", file->start, fn);
+    printf(";;\t%8"PRIuSEC" .. %-8"PRIuSEC" %s\n",
+          file->start, file->end, fn);
   }
 #endif
 
@@ -1186,7 +1100,8 @@ int main(int argc, char *argv[])
     switch (ev->ev) {
       case EV_WRITE:
        if (f&f_write)
-         bail("overlapping ranges: range from %"PRIuSEC" still open at %"PRIuSEC"",
+         bail("overlapping ranges: range from %"PRIuSEC" "
+              "still open at %"PRIuSEC"",
               start, ev->pos);
        f |= f_write; start = ev->pos;
        break;