chiark / gitweb /
dvd-sector-copy.c: Add machinery for installing pretend bad sectors.
authorMark Wooding <mdw@distorted.org.uk>
Wed, 16 Feb 2022 23:37:50 +0000 (23:37 +0000)
committerMark Wooding <mdw@distorted.org.uk>
Wed, 16 Feb 2022 23:37:50 +0000 (23:37 +0000)
For testing the recovery algorithm(s).

dvd-sector-copy.c

index c6bad44ca543d67fa3a81e2115f45e8623b37470..28a4943263391a01e45906dde7b30157b68e4782 100644 (file)
 #define ISDIGIT(ch) CTYPE_HACK(isdigit, ch)
 #define ISSPACE(ch) CTYPE_HACK(isspace, ch)
 
+#ifdef DEBUG
+#  define D(x) x
+#else
+#  define D(x)
+#endif
+
 #define N(v) (sizeof(v)/sizeof((v)[0]))
 
 #define SECTORSZ 2048
@@ -390,9 +396,51 @@ static int dvdfd = -1, outfd = -1;
 static dvd_file_t *vob;
 static const char *mapfile; static FILE *mapfp;
 
+struct badblock { secaddr start, end; };
+DEFVEC(badblock_v, struct badblock);
+static badblock_v badblocks = VEC_INIT;
+
+static int compare_badblock(const void *a, const void *b)
+{
+  const struct badblock *ba = a, *bb = b;
+
+  if (ba->start < bb->start) return (-1);
+  else if (ba->start > bb->start) return (+1);
+
+  if (ba->end < bb->end) return (-1);
+  else if (ba->end > bb->end) return (+1);
+
+  return (0);
+}
+
 static ssize_t read_sectors(secaddr pos, void *buf, secaddr want)
 {
   ssize_t n;
+  size_t lo, mid, hi;
+  struct badblock *bad, *best;
+
+  best = 0; lo = 0; hi = badblocks.n;
+#ifdef 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];
+#ifdef DEBUG
+    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); }
+  }
+#ifdef DEBUG
+  if (best)
+    printf(";;   next is %"PRIuSEC" .. %"PRIuSEC"\n",
+          best->start, best->end);
+#endif
+  if (best && pos + want > best->start) want = best->start - pos;
 
 again:
   if (vob)
@@ -651,6 +699,7 @@ int main(int argc, char *argv[])
   secaddr start, end, last;
   const struct event *ev;
   const char *device, *outfile;
+  struct badblock *bad;
   int opt, blksz;
   unsigned n;
   size_t i;
@@ -699,6 +748,25 @@ int main(int argc, char *argv[])
        if (ferror(fp))
          bail_syserr(errno, "failed to read ranges file `%s'", optarg);
        break;
+      case 'X':
+       fp = fopen(optarg, "r");
+       if (!fp)
+         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;
+         p = buf.p; i++;
+         while (ISSPACE(*p)) p++;
+         if (!*p || *p == '#') continue;
+         if (parse_range(p, 0, &start, &end) ||
+             (last <= SECLIMIT && start < last))
+           bail("bad range `%s' at `%s' line %zu", buf.p, optarg, i);
+         if (start < end)
+           { VEC_PUSH(bad, &badblocks); bad->start = start; bad->end = end; }
+       }
+       if (ferror(fp))
+         bail_syserr(errno, "failed to read bad-blocks file `%s'", optarg);
+       break;
       case 'b':
        if (mapfile) bail("can't have multiple map files");
        mapfile = optarg;
@@ -721,6 +789,17 @@ int main(int argc, char *argv[])
 
   device = argv[optind]; outfile = argv[optind + 1];
 
+  if (badblocks.n) {
+    qsort(badblocks.v, badblocks.n, sizeof(struct badblock),
+         compare_badblock);
+#ifdef DEBUG
+    printf(";; fake bad blocks:\n");
+    for (i = 0; i < badblocks.n; i++)
+      printf(";;\t%8"PRIuSEC" .. %"PRIuSEC"\n",
+            badblocks.v[i].start, badblocks.v[i].end);
+#endif
+  }
+
   dvdfd = open(device, O_RDONLY);
   if (dvdfd < 0)
     bail_syserr(errno, "failed to open device `%s'", device);