From 513eba4411f9c6f8b09375734fdaafc49a962eae Mon Sep 17 00:00:00 2001 From: Mark Wooding Date: Wed, 16 Feb 2022 23:37:50 +0000 Subject: [PATCH] dvd-sector-copy.c: Add machinery for installing pretend bad sectors. For testing the recovery algorithm(s). --- dvd-sector-copy.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/dvd-sector-copy.c b/dvd-sector-copy.c index c6bad44..28a4943 100644 --- a/dvd-sector-copy.c +++ b/dvd-sector-copy.c @@ -32,6 +32,12 @@ #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); -- 2.11.0