#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
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)
secaddr start, end, last;
const struct event *ev;
const char *device, *outfile;
+ struct badblock *bad;
int opt, blksz;
unsigned n;
size_t i;
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;
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);