dvd-sector-copy.c (report_progress): Show a throbber to help gauge speed.
[dvdrip] / dvd-sector-copy.c
index 36b5425..90efce2 100644 (file)
@@ -356,6 +356,9 @@ static struct timeval last_time;
 static double wsum, wcount;
 static struct file *file;
 
+static const char throbber[] = "|<-<|>->";
+static unsigned throbix = 0;
+
 static void report_progress(secaddr pos)
 {
   char etastr[32];
@@ -395,8 +398,9 @@ static void report_progress(secaddr pos)
   if (flags&F_ALLPROGRESS) percent = pos*100.0/limit;
   else percent = ndone*100.0/nsectors;
   print_progress
-    ("copied %.1f%% (%"PRIuSEC" of %"PRIuSEC"; %.1f %sB/s, ETA %s)",
-     percent, pos, limit,  rate, unit, etastr);
+    ("%c copied %.1f%% (%"PRIuSEC" of %"PRIuSEC"; %.1f %sB/s, ETA %s)",
+     throbber[throbix], percent, pos, limit,  rate, unit, etastr);
+  throbix++; if (!throbber[throbix]) throbix = 0;
   if (file && id_kind(file->id) == VOB) {
     append_progress(" -- %s %d %.1f%%",
                    id_part(file->id) ? "title" : "menu",
@@ -413,6 +417,7 @@ static dvd_reader_t *dvd;
 static int dvdfd = -1, outfd = -1;
 static dvd_file_t *vob;
 static const char *mapfile; static FILE *mapfp;
+static const char *errfile; static FILE *errfp;
 
 struct badblock { secaddr start, end; };
 DEFVEC(badblock_v, struct badblock);
@@ -479,7 +484,13 @@ static ssize_t read_sectors(secaddr pos, void *buf, secaddr want)
     }
 
     if (n > 0) { done += n; pos += n; p += n*SECTORSZ; want -= n; }
-    else if (!n || errno != EINTR) break;
+    else if (!n) break;
+    else if (errno == EIO && errfile) {
+      open_file_on_demand(errfile, &errfp, "bad-sector error log");
+      fprintf(errfp, "%"PRIuSEC" %"PRIuSEC"\n", pos, pos + 1);
+      check_write(errfp, "bad-sector error log");
+      break;
+    } else if (errno != EINTR) break;
   }
   if (fakeerr && !errno) errno = fakeerr;
   return (!done && errno ? -1 : done);
@@ -505,7 +516,7 @@ static void recovered(secaddr bad_lo, secaddr bad_hi)
   if (mapfile) {
     open_file_on_demand(mapfile, &mapfp, "bad-sector region map");
     fprintf(mapfp, "%"PRIuSEC" %"PRIuSEC"", bad_lo, bad_hi);
-    if (file)
+    if (file && id_kind(file->id) != RAW)
       fprintf(mapfp, " # %s #%d %"PRIuSEC"..%"PRIuSEC" of %"PRIuSEC" (%.1f%%)",
              id_part(file->id) ? "title" : "menu",
              id_title(file->id),
@@ -517,7 +528,6 @@ static void recovered(secaddr bad_lo, secaddr bad_hi)
   }
   if (lseek(outfd, (off_t)(bad_hi - bad_lo)*SECTORSZ, SEEK_CUR) < 0)
     bail_syserr(errno, "failed to seek past bad sectors");
-  status = 1;
 }
 
 struct recoverybuf {
@@ -656,6 +666,7 @@ static ssize_t recovery_read(struct recoverybuf *r,
 
   n = r->pos + r->end - pos;
   if (!n && want) n = -1;
+  else if (n > want) n = want;
 
 end:
 #ifdef DEBUG
@@ -705,6 +716,12 @@ static ssize_t find_good_sector(secaddr *pos_inout, secaddr end,
   bad_lo = pos; bad_hi = pos + 1;
   for (;;) {
     report_bad_blocks_progress(bad_lo, bad_hi, errno);
+#ifdef DEBUG
+    debug_clear_progress();
+    printf(";; bounding bad-block region: "
+          "%"PRIuSEC" ..%"PRIuSEC".. %"PRIuSEC"\n",
+          bad_lo, bad_hi - bad_lo, bad_hi);
+#endif
     if (bad_hi >= end) {
       clear_progress();
       moan("giving up on this extent");
@@ -715,7 +732,6 @@ 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
-    debug_clear_progress();
     printf(";; [bound] try reading %"PRIuSEC" .. %"PRIuSEC" -> %zd\n",
           pos, pos + want, n);
 #endif
@@ -727,12 +743,17 @@ static ssize_t find_good_sector(secaddr *pos_inout, secaddr end,
   good = pos;
   while (good > bad_hi) {
     report_bad_blocks_progress(bad_lo, bad_hi, errno);
+#ifdef DEBUG
+    debug_clear_progress();
+    printf(";; limiting bad-block region: "
+          "%"PRIuSEC" ..%"PRIuSEC".. %"PRIuSEC" ..%"PRIuSEC".. %"PRIuSEC"\n",
+          bad_lo, bad_hi - bad_lo, bad_hi, good - bad_hi, good);
+#endif
     pos = bad_hi + (good - bad_hi)/2;
     step = pos - bad_lo;
     want = run_length_wanted(pos, step, sz, end);
     n = recovery_read(&r, pos, want);
 #ifdef DEBUG
-    debug_clear_progress();
     printf(";; [limit] try reading %"PRIuSEC" .. %"PRIuSEC" -> %zd\n",
           pos, pos + want, n);
 #endif
@@ -916,7 +937,7 @@ static int parse_range(const char *p, unsigned f,
     { rc = -1; goto end; }
 
   if (!(f&PRF_HYPHEN)) while (ISSPACE(*p)) p++;
-  if (*p && ((f&PRF_HYPHEN) || *p != '=')) { rc = -1; goto end; }
+  if (*p && ((f&PRF_HYPHEN) || *p != '#')) { rc = -1; goto end; }
 
   rc = 0;
 end:
@@ -953,9 +974,10 @@ int main(int argc, char *argv[])
 
   p = strrchr(argv[0], '/'); prog = p ? p + 1 : argv[0];
   for (;;) {
-    opt = getopt(argc, argv, "hFR:X:b:cr:"); if (opt < 0) break;
+    opt = getopt(argc, argv, "hE:FR:X:b:cr:"); if (opt < 0) break;
     switch (opt) {
       case 'h': usage(stderr); exit(0);
+      case 'E': errfile = optarg; break;
       case 'F': f |= f_fixup; break;
       case 'R':
        fp = fopen(optarg, "r");
@@ -1205,6 +1227,7 @@ int main(int argc, char *argv[])
   if (dvdfd >= 0) close(dvdfd);
   if (outfd >= 0) close(outfd);
   carefully_fclose(mapfp, "bad-sector region map");
+  carefully_fclose(errfp, "bad-sector error log");
 
 #undef f_bogus
 #undef f_continue