prog);
}
-static double tvdiff(const struct timeval *tv_lo,
- const struct timeval *tv_hi)
-{
- return ((tv_hi->tv_sec - tv_lo->tv_sec) +
- (tv_hi->tv_usec - tv_lo->tv_usec)/1.0e6);
-}
-
-#define DEFVEC(vtype, etype) \
- typedef struct { etype *v; size_t n, sz; } vtype
-#define VEC_INIT { 0, 0, 0 }
-#define VEC_FREE(vv) do { \
- free((vv)->v); (vv)->v 0; (vv)->n = (vv)->sz = 0; \
-} while (0)
-#define VEC_PUSH(p, vv) do { \
- size_t _want; \
- if ((vv)->n >= (vv)->sz) { \
- (vv)->sz = (vv)->sz ? 2*(vv)->sz : 32; \
- _want = (vv)->sz*sizeof(*(vv)->v); \
- (vv)->v = realloc((vv)->v, _want); \
- if (!(vv)->v) bail("out of memory allocating %zu bytes", _want); \
- } \
- (p) = &(vv)->v[(vv)->n++]; \
-} while (0)
-
#define MAXFILES (1 + 2*99 + 1)
struct file {
ident id;
store_filename(fn, id);
start = UDFFindFile(dvd, fn, &len); if (!start) return;
#ifdef DEBUG
- printf(";; %8"PRIuSEC" .. %-8"PRIuSEC": %s\n",
- start, start + SECTORS(len), fn);
+ printf(";; %8"PRIuSEC" .. %-8"PRIuSEC": %s\n",
+ start, start + SECTORS(len), fn);
#endif
put_file(id, start, start + SECTORS(len));
}
#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); }
+ else {
+ D( printf("match!\n"); )
+ errno = EIO; sit(bad_block_delay); return (-1);
+ }
}
#ifdef DEBUG
if (best)
if (best && pos + want > best->start)
{ want = best->start - pos; fakeerr = EIO; sit(bad_block_delay); }
}
- done = 0;
+
+ done = 0; errno = 0;
while (want) {
if (vob)
{ errno = 0; n = DVDReadBlocks(vob, pos - file->start, want, p); }
return (!done && errno ? -1 : done);
}
-static void record_bad_sectors(secaddr bad_lo, secaddr bad_hi)
-{
- char fn[MAXFNSZ];
-
- if (!mapfile) return;
-
- open_file_on_demand(mapfile, &mapfp, "bad-sector region map");
- fprintf(mapfp, "%"PRIuSEC" %"PRIuSEC" # %"PRIuSEC" sectors",
- bad_lo, bad_hi, bad_hi - bad_lo);
-
- if (file && id_kind(file->id) != RAW) {
- store_filename(fn, file->id);
- fprintf(mapfp, "; `%s' %"PRIuSEC" .. %"PRIuSEC" of %"PRIuSEC"",
- fn, bad_lo - file->start, bad_hi - file->start,
- file->end - file->start);
- }
-
- fputc('\n', mapfp);
- check_write(mapfp, "bad-sector region map");
-}
-
static void recovered(secaddr bad_lo, secaddr bad_hi)
{
char fn[MAXFNSZ];
file->end - file->start);
}
- record_bad_sectors(bad_lo, bad_hi);
+ if (mapfile) {
+ open_file_on_demand(mapfile, &mapfp, "bad-sector region map");
+ fprintf(mapfp, "%"PRIuSEC" %"PRIuSEC" # %"PRIuSEC" sectors",
+ bad_lo, bad_hi, bad_hi - bad_lo);
+
+ if (file && id_kind(file->id) != RAW)
+ fprintf(mapfp, "; `%s' %"PRIuSEC" .. %"PRIuSEC" of %"PRIuSEC"",
+ fn, bad_lo - file->start, bad_hi - file->start,
+ file->end - file->start);
+
+ fputc('\n', mapfp);
+ check_write(mapfp, "bad-sector region map");
+ }
if (lseek(outfd, (off_t)(bad_hi - bad_lo)*SECTORSZ, SEEK_CUR) < 0)
bail_syserr(errno, "failed to seek past bad sectors");
ssize_t n;
assert(off <= r->sz); assert(want <= r->sz - off);
+ assert(pos == r->pos + off);
n = read_sectors(pos, r->buf + off*SECTORSZ, want);
return (n);
}
#endif
}
} else if (pos > r->pos + r->end) {
- r->pos = pos; r->start = r->end = 0;
+ r->pos = pos; r->start = r->end = 0;
#ifdef DEBUG
- show_recovery_buffer_map(r, "cleared; beyond previous region");
+ show_recovery_buffer_map(r, "cleared; beyond previous region");
#endif
} else if (pos + want > r->pos + r->sz) {
diff = (pos + want) - (r->pos + r->sz);
{
secaddr want;
- want = clear_factor*badlen;
+ want = ceil(clear_factor*badlen);
if (want < clear_min) want = clear_min;
if (want > end - pos) want = end - pos;
if (clear_max && want > clear_max) want = clear_max;
badblock_progress.render = render_badblock_progress;
progress_additem(&progress, &badblock_progress);
- r.buf = buf; r.sz = sz; r.pos = r.start = r.end = 0;
- r.good_lo = r.good_hi = 0;
-
want = sz; if (want > end - pos) want = end - pos;
for (retry = 0; retry < max_retries; retry++) {
report_bad_blocks_progress(pos, errno);
- n = recovery_read(&r, pos, want);
+ n = read_sectors(pos, buf, want);
#ifdef DEBUG
progress_clear(&progress);
printf(";; [retry] try reading %"PRIuSEC" .. %"PRIuSEC" -> %zd\n",
}
}
+ r.buf = buf; r.sz = sz; r.pos = r.start = r.end = 0;
+ r.good_lo = r.good_hi = 0;
+
bad_lo = pos; bad_hi = pos + 1;
for (;;) {
report_bad_blocks_progress(bad_hi, errno);
if (n == want) good = pos;
else bad_hi = pos + n + 1;
}
- recovered(bad_lo, bad_hi); *pos_inout = good;
- if (good < r.pos + r.start || r.pos + r.end <= good)
+ recovered(bad_lo, bad_hi); *pos_inout = bad_hi;
+ if (bad_hi < r.pos + r.start || r.pos + r.end <= bad_hi)
n = 0;
else {
- n = r.pos + r.end - good;
- rearrange_sectors(&r, 0, good - r.pos, n);
+ n = r.pos + r.end - bad_hi;
+ rearrange_sectors(&r, 0, bad_hi - r.pos, n);
}
#ifdef DEBUG
show_recovery_buffer_map(&r, "returning %zd good sectors at %"PRIuSEC"",
- n, good);
+ n, bad_hi);
#endif
return (n);
}
#undef BUFSECTORS
}
-struct buf {
- char *p;
- size_t n, sz;
-};
-#define BUF_INIT { 0, 0, 0 }
-#define BUF_REWIND(b) do { (b)->n = 0; } while (0)
-#define BUF_FREE(b) do { \
- buf *_b = (b); \
- free(_b->p); _b->p = 0; _b->n = _b->sz = 0; \
-} while (0)
-#define BUF_PUTC(b, ch) do { \
- struct buf *_b = (b); \
- if (_b->n >= _b->sz) { \
- _b->sz = _b->sz ? 2*_b->sz : 32; \
- _b->p = realloc(_b->p, _b->sz); \
- if (!_b->p) bail("out of memory allocating %zu bytes", _b->sz); \
- } \
- _b->p[_b->n] = (ch); \
-} while (0)
-
-static int read_line(FILE *fp, struct buf *b)
-{
- int ch;
-
- ch = getc(fp);
- if (ch == EOF)
- return (-1);
- else if (ch != '\n') do {
- BUF_PUTC(b, ch); b->n++;
- ch = getc(fp);
- } while (ch != EOF && ch != '\n');
- BUF_PUTC(b, 0);
- return (0);
-}
-
-static double parse_float(const char **p_inout, double min, double max,
- const char *what)
-{
- const char *p;
- char *q;
- double x;
- int err;
-
- err = errno; errno = 0;
- p = *p_inout;
- x = strtod(p, &q);
- if (errno || x < min || x > max) bail("bad %s `%s'", what, p);
- *p_inout = q; errno = err;
- return (x);
-}
-
-static long parse_int(const char **p_inout, long min, long max,
- const char *what)
-{
- const char *p;
- char *q;
- long x;
- int err;
-
- err = errno; errno = 0;
- p = *p_inout;
- x = strtoul(p, &q, 0);
- if (errno || x < min || x > max) bail("bad %s `%s'", what, p);
- *p_inout = q; errno = err;
- return (x);
-}
-
#define PRF_HYPHEN 1u
static int parse_range(const char *p, unsigned f,
secaddr *start_out, secaddr *end_out)
return (rc);
}
+#ifdef DEBUG
+static void dump_eventq(const char *what)
+{
+ unsigned i;
+ const struct event *ev;
+ char fn[MAXFNSZ];
+
+ printf("\n;; event dump (%s):\n", what);
+ for (i = 0; i < eventq.n; i++) {
+ ev = &eventq.v[i];
+ switch (ev->ev) {
+ case EV_BEGIN:
+ store_filename(fn, filetab.v[ev->file].id);
+ printf(";; %8"PRIuSEC": begin %s\n", ev->pos, fn);
+ break;
+ case EV_END:
+ store_filename(fn, filetab.v[ev->file].id);
+ printf(";; %8"PRIuSEC": end %s\n", ev->pos, fn);
+ break;
+ case EV_WRITE:
+ printf(";; %8"PRIuSEC": write\n", ev->pos);
+ break;
+ case EV_STOP:
+ printf(";; %8"PRIuSEC": stop\n", ev->pos);
+ break;
+ default:
+ printf(";; %8"PRIuSEC": ?%u\n", ev->pos, ev->ev);
+ break;
+ }
+ }
+}
+#endif
+
int main(int argc, char *argv[])
{
unsigned f = 0;
(STRNCMP(p, ==, s "=", sizeof(s)) && (p += sizeof(s), 1))
for (;;) {
if (SKIP_PREFIX("cf"))
- clear_factor = parse_float(&p, 0, DBL_MAX, "clear factor");
+ clear_factor = parse_float(&p, PNF_JUNK, 0, DBL_MAX,
+ "clear factor");
else if (SKIP_PREFIX("cmin"))
- clear_min = parse_int(&p, 1, SECLIMIT, "clear minimum");
+ clear_min = parse_int(&p, PNF_JUNK, 1, SECLIMIT,
+ "clear minimum");
else if (SKIP_PREFIX("cmax"))
- clear_max = parse_int(&p, 1, SECLIMIT, "clear maximum");
+ clear_max = parse_int(&p, PNF_JUNK, 1, SECLIMIT,
+ "clear maximum");
else if (SKIP_PREFIX("sf"))
- step_factor = parse_float(&p, 0, DBL_MAX, "step factor");
+ step_factor = parse_float(&p, PNF_JUNK, 0, DBL_MAX,
+ "step factor");
else if (SKIP_PREFIX("smin"))
- step_min = parse_int(&p, 1, SECLIMIT - 1, "step minimum");
+ step_min = parse_int(&p, PNF_JUNK, 1, SECLIMIT - 1,
+ "step minimum");
else if (SKIP_PREFIX("smax"))
- step_max = parse_int(&p, 1, SECLIMIT - 1, "step maximum");
+ step_max = parse_int(&p, PNF_JUNK, 1, SECLIMIT - 1,
+ "step maximum");
else if (SKIP_PREFIX("retry"))
- max_retries = parse_int(&p, 0, INT_MAX, "retries");
+ max_retries = parse_int(&p, PNF_JUNK, 0, INT_MAX, "retries");
else if (SKIP_PREFIX("alpha"))
- alpha = parse_float(&p, 0, 1, "average decay factor");
+ alpha = parse_float(&p, PNF_JUNK, 0, 1, "average decay factor");
else if (SKIP_PREFIX("_badwait"))
- bad_block_delay = parse_float(&p, 0, DBL_MAX, "bad-block delay");
+ bad_block_delay = parse_float(&p, PNF_JUNK, 0, DBL_MAX,
+ "bad-block delay");
else if (SKIP_PREFIX("_blkwait"))
- good_block_delay = parse_float(&p, 0, DBL_MAX, "good block delay");
+ good_block_delay = parse_float(&p, PNF_JUNK, 0, DBL_MAX,
+ "good block delay");
else
bail("unknown bad blocks parameter `%s'", p);
if (!*p) break;
bail_syserr(errno, "failed to open ranges file `%s'", optarg);
i = 0; last = -1;
for (;;) {
- BUF_REWIND(&buf); if (read_line(fp, &buf)) break;
+ buf_rewind(&buf); if (read_line(fp, &buf)) break;
p = buf.p; i++;
while (ISSPACE(*p)) p++;
if (!*p || *p == '#') continue;
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;
+ buf_rewind(&buf); if (read_line(fp, &buf)) break;
p = buf.p; i++;
while (ISSPACE(*p)) p++;
if (!*p || *p == '#') continue;
#endif
}
- open_dvd(device, &dvdfd, &dvd);
+ if (open_dvd(device, O_RDONLY, &dvdfd, &dvd)) exit(2);
blksz = SECTORSZ; volsz = device_size(dvdfd, device, &blksz);
if (blksz != SECTORSZ)
device, volsz, SECTORSZ);
if (f&f_checkid) {
- open_dvd(outfile, 0, &dvd_out);
+ if (open_dvd(outfile, O_RDONLY, 0, &dvd_out)) exit(2);
if (dvd_id(id_in, dvd, DIF_MUSTIFOHASH, device) ||
dvd_id(id_out, dvd_out, DIF_MUSTIFOHASH, device))
exit(2);
for (i = 0; i < filetab.n; i++) {
file = &filetab.v[i];
store_filename(fn, file->id);
- printf(";;\t%8"PRIuSEC" %s\n", file->start, fn);
+ printf(";;\t%8"PRIuSEC" .. %-8"PRIuSEC" %s\n",
+ file->start, file->end, fn);
}
#endif
switch (ev->ev) {
case EV_WRITE:
if (f&f_write)
- bail("overlapping ranges: range from %"PRIuSEC" still open at %"PRIuSEC"",
+ bail("overlapping ranges: range from %"PRIuSEC" "
+ "still open at %"PRIuSEC"",
start, ev->pos);
f |= f_write; start = ev->pos;
break;
}
}
+#ifdef DEBUG
+ dump_eventq("initial");
+#endif
f &= ~f_write; start = 0;
for (i = 0; i < eventq.n; i++) {
ev = &eventq.v[i];
- switch (ev->ev) {
- case EV_WRITE: start = ev->pos; f |= f_write; break;
- case EV_STOP: nsectors += ev->pos - start; f &= ~f_write; break;
- }
+ if (ev->ev == EV_WRITE) { start = ev->pos; f |= f_write; }
if (ev->pos >= limit) break;
+ if (ev->ev == EV_STOP) { nsectors += ev->pos - start; f &= ~f_write; }
if (f&f_fixup) start = ev->pos;
}
eventq.n = i;
+#ifdef DEBUG
+ dump_eventq("trimmed");
+#endif
if (f&f_fixup) {
put_event(EV_WRITE, 0, start);
f |= f_write;
nsectors += limit - start;
put_event(EV_STOP, 0, limit);
}
+#ifdef DEBUG
+ dump_eventq("final");
+#endif
copy_progress.render = render_copy_progress;
progress_additem(&progress, ©_progress);
if (f&f_stats) {
gettimeofday(&tv1, 0); t = tvdiff(&tv0, &tv1);
- if (nsectors == limit - start) { ndone -= start; nsectors -= start; }
+ if (nsectors == limit) { ndone -= start; nsectors -= start; }
tot = scale_bytes((double)nsectors*SECTORSZ, &totunit);
rate = scale_bytes((double)nsectors*SECTORSZ/t, &rateunit);
moan("all done: %.1f %sB in %s -- %.1f %sB/s",