dvdrip: Collect together bad-blocks lists from repeated runs.
[dvdrip] / dvd-sector-copy.c
index 908bbbc..4e5f97b 100644 (file)
@@ -297,6 +297,10 @@ static void clear_progress_internal(void)
 }
 static void clear_progress(void)
   { clear_progress_internal(); fflush(stdout); }
+#ifdef DEBUG
+static void debug_clear_progress(void)
+  { if (progresslen) { putchar('\n'); progresslen = 0; } }
+#endif
 static void vappend_progress(const char *fmt, va_list ap)
   { progresslen += vprintf(fmt, ap); }
 __attribute__((format(printf, 1, 2)))
@@ -409,30 +413,31 @@ static ssize_t read_sectors(secaddr pos, void *buf, secaddr want)
   struct badblock *bad, *best;
   unsigned char *p = buf;
 
-  best = 0; lo = 0; hi = badblocks.n;
+  if (badblocks.n) {
+    best = 0; lo = 0; hi = badblocks.n;
 #ifdef DEBUG
-  clear_progress();
-  printf(";; searching badblocks for %"PRIuSEC" .. %"PRIuSEC"\n",
-        pos, pos + want);
+    debug_clear_progress();
+    printf(";; searching badblocks for %"PRIuSEC" .. %"PRIuSEC"\n",
+          pos, pos + want);
 #endif
-  while (lo < hi) {
-    mid = lo + (hi - lo)/2; bad = &badblocks.v[mid];
+    while (lo < hi) {
+      mid = lo + (hi - lo)/2; bad = &badblocks.v[mid];
 #ifdef DEBUG
-    printf(";;   try %zu (%"PRIuSEC" .. %"PRIuSEC")... ",
-          mid, bad->start, bad->end);
+      printf(";;   try %zu (%"PRIuSEC" .. %"PRIuSEC")... ",
+            mid, bad->start, bad->end);
 #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); }
-  }
+      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); }
+    }
 #ifdef DEBUG
-  if (best)
-    printf(";;   next is %"PRIuSEC" .. %"PRIuSEC"\n",
-          best->start, best->end);
+    if (best)
+      printf(";;   next is %"PRIuSEC" .. %"PRIuSEC"\n",
+            best->start, best->end);
 #endif
-  if (best && pos + want > best->start)
-    { want = best->start - pos; fakeerr = EIO; }
-
+    if (best && pos + want > best->start)
+      { want = best->start - pos; fakeerr = EIO; }
+  }
   done = 0;
   while (want) {
     if (vob)
@@ -510,7 +515,7 @@ static void show_recovery_buffer_map(const struct recoverybuf *r,
   va_list ap;
 
   va_start(ap, what);
-  clear_progress();
+  debug_clear_progress();
   printf(";; recovery buffer (");
   vprintf(what, ap);
   printf("): "
@@ -531,7 +536,7 @@ static ssize_t recovery_read_sectors(struct recoverybuf *r,
 {
   ssize_t n;
 
-  assert(off + want <= r->sz);
+  assert(off <= r->sz); assert(want <= r->sz - off);
   n = read_sectors(pos, r->buf + off*SECTORSZ, want);
   return (n);
 }
@@ -543,7 +548,7 @@ static ssize_t recovery_read(struct recoverybuf *r,
   ssize_t n;
 
 #ifdef DEBUG
-  clear_progress();
+  debug_clear_progress();
   show_recovery_buffer_map(r, "begin(%"PRIuSEC", %"PRIuSEC")", pos, want);
 #endif
 
@@ -557,7 +562,7 @@ static ssize_t recovery_read(struct recoverybuf *r,
     } else {
       if (r->end + diff > r->sz) r->end = r->sz - diff;
       rearrange_sectors(r, r->start + diff, r->start, r->end - r->start);
-      r->start += diff; r->end += diff;
+      r->pos -= diff; r->start += diff; r->end += diff;
 #ifdef DEBUG
       show_recovery_buffer_map(r, "shifted up by %"PRIuSEC"", diff);
 #endif
@@ -577,7 +582,7 @@ static ssize_t recovery_read(struct recoverybuf *r,
     } else {
       if (r->start < diff) r->start = diff;
       rearrange_sectors(r, r->start - diff, r->start, r->end - r->start);
-      r->start -= diff; r->end -= diff;
+      r->pos += diff; r->start -= diff; r->end -= diff;
 #ifdef DEBUG
       show_recovery_buffer_map(r, "shifted down by %"PRIuSEC"", diff);
 #endif
@@ -592,10 +597,10 @@ static ssize_t recovery_read(struct recoverybuf *r,
 #endif
     n = recovery_read_sectors(r, pos, pp, nn);
 #ifdef DEBUG
-    printf(" -> %ld\n", n);
+    printf(" -> %zd\n", n);
 #endif
     if (n != nn) {
-      if (n > want) n = want;
+      if (n >= 0 && n > want) n = want;
       goto end;
     }
     r->start = pp;
@@ -609,11 +614,11 @@ static ssize_t recovery_read(struct recoverybuf *r,
 #ifdef DEBUG
     printf(";; read high (%"PRIuSEC"@%"PRIuSEC", %"PRIuSEC")",
           r->pos + pp, pp, nn);
-fflush(stdout);
+    fflush(stdout);
 #endif
-    n = recovery_read_sectors(r, pos, pp, nn);
+    n = recovery_read_sectors(r, pos + pp, pp, nn);
 #ifdef DEBUG
-    printf(" -> %ld\n", n);
+    printf(" -> %zd\n", n);
 #endif
     if (n > 0) {
       r->end += n;
@@ -628,7 +633,7 @@ fflush(stdout);
 
 end:
 #ifdef DEBUG
-  show_recovery_buffer_map(r, "done; return %ld", n);
+  show_recovery_buffer_map(r, "done; return %zd", n);
 #endif
   return (n);
 }
@@ -660,8 +665,8 @@ static ssize_t find_good_sector(secaddr *pos_inout, secaddr end,
   for (i = 0; i < 4; i++) {
     n = recovery_read(&r, pos, want);
 #ifdef DEBUG
-    clear_progress();
-    printf(";; [retry] try reading %"PRIuSEC" .. %"PRIuSEC" -> %ld\n",
+    debug_clear_progress();
+    printf(";; [retry] try reading %"PRIuSEC" .. %"PRIuSEC" -> %zd\n",
           pos, pos + want, n);
 #endif
     if (n > 0) {
@@ -684,8 +689,8 @@ static ssize_t find_good_sector(secaddr *pos_inout, secaddr end,
     want = run_length_wanted(pos, step, sz, end);
     n = recovery_read(&r, pos, want);
 #ifdef DEBUG
-    clear_progress();
-    printf(";; [bound] try reading %"PRIuSEC" .. %"PRIuSEC" -> %ld\n",
+    debug_clear_progress();
+    printf(";; [bound] try reading %"PRIuSEC" .. %"PRIuSEC" -> %zd\n",
           pos, pos + want, n);
 #endif
     if (n == want) break;
@@ -701,8 +706,8 @@ static ssize_t find_good_sector(secaddr *pos_inout, secaddr end,
     want = run_length_wanted(pos, step, sz, end);
     n = recovery_read(&r, pos, want);
 #ifdef DEBUG
-    clear_progress();
-    printf(";; [limit] try reading %"PRIuSEC" .. %"PRIuSEC" -> %ld\n",
+    debug_clear_progress();
+    printf(";; [limit] try reading %"PRIuSEC" .. %"PRIuSEC" -> %zd\n",
           pos, pos + want, n);
 #endif
     if (n < 0) n = 0;
@@ -710,10 +715,16 @@ static ssize_t find_good_sector(secaddr *pos_inout, secaddr end,
     else bad_hi = pos + n + 1;
   }
   recovered(bad_lo, bad_hi); *pos_inout = good;
-  if (r.pos + r.start <= good && good <= r.pos + r.end) {
-    rearrange_sectors(&r, 0, good - r.pos, r.pos + r.end - good);
-  } else
+  if (good < r.pos + r.start || r.pos + r.end <= good)
     n = 0;
+  else {
+    n = r.pos + r.end - good;
+    rearrange_sectors(&r, 0, good - r.pos, n);
+  }
+#ifdef DEBUG
+  show_recovery_buffer_map(&r, "returning %zd good sectors at %"PRIuSEC"",
+                          n, good);
+#endif
   return (n);
 }
 
@@ -1114,7 +1125,7 @@ int main(int argc, char *argv[])
       if (f&f_write) emit(pos, ev->pos);
       pos = ev->pos;
 #ifdef DEBUG
-      clear_progress();
+      debug_clear_progress();
       printf(";;\n");
 #endif
     }
@@ -1123,7 +1134,7 @@ int main(int argc, char *argv[])
        set_live(ev->file);
 #ifdef DEBUG
        store_filename(fn, filetab.v[ev->file].id);
-       clear_progress();
+       debug_clear_progress();
        printf(";; %8"PRIuSEC": begin `%s'\n", pos, fn);
 #endif
        break;
@@ -1135,7 +1146,7 @@ int main(int argc, char *argv[])
                      "(sector %"PRIuSEC") in output file `%s'",
                      ev->pos, outfile);
 #ifdef DEBUG
-       clear_progress();
+       debug_clear_progress();
        printf(";; %8"PRIuSEC": begin write\n", pos);
 #endif
        f |= f_write;
@@ -1143,7 +1154,7 @@ int main(int argc, char *argv[])
       case EV_STOP:
        f &= ~f_write;
 #ifdef DEBUG
-       clear_progress();
+       debug_clear_progress();
        printf(";; %8"PRIuSEC": end write\n", pos);
 #endif
        break;
@@ -1151,7 +1162,7 @@ int main(int argc, char *argv[])
        clear_live(ev->file);
 #ifdef DEBUG
        store_filename(fn, filetab.v[ev->file].id);
-       clear_progress();
+       debug_clear_progress();
        printf(";; %8"PRIuSEC": end `%s'\n", pos, fn);
 #endif
        break;