X-Git-Url: https://git.distorted.org.uk/~mdw/dvdrip/blobdiff_plain/50c72655176127c8347fa668091b02d4649320f6..a238b544458f64e91bfbadc492f248325d2677be:/dvd-sector-copy.c diff --git a/dvd-sector-copy.c b/dvd-sector-copy.c index f0800c8..b1ca133 100644 --- a/dvd-sector-copy.c +++ b/dvd-sector-copy.c @@ -8,29 +8,48 @@ static void usage(FILE *fp) prog); } -static double tvdiff(const struct timeval *tv_lo, - const struct timeval *tv_hi) +#define PRF_HYPHEN 1u +static int parse_range(const char *p, unsigned f, + secaddr *start_out, secaddr *end_out) { - return ((tv_hi->tv_sec - tv_lo->tv_sec) + - (tv_hi->tv_usec - tv_lo->tv_usec)/1.0e6); -} + char *q; + int err, rc; + unsigned long start, end; -#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) + err = errno; + + if (ISDIGIT(*p)) { + start = strtoul(p, &q, 0); + if (errno || start >= SECLIMIT) { rc = -1; goto end; } + *start_out = start; p = q; + } else if (!(f&PRF_HYPHEN)) + { rc = -1; goto end; } + else + start = 0; + + if (f&PRF_HYPHEN) { + if (*p != '-') { rc = -1; goto end; } + p++; + } else { + if (!ISSPACE(*p)) { rc = -1; goto end; } + do p++; while (ISSPACE(*p)); + } + + if (ISDIGIT(*p)) { + end = strtoul(p, &q, 0); + if (errno || end > SECLIMIT || end < start) { rc = -1; goto end; } + *end_out = end; p = q; + } else if (!(f&PRF_HYPHEN)) + { rc = -1; goto end; } + + if (!(f&PRF_HYPHEN)) while (ISSPACE(*p)) p++; + if (*p && ((f&PRF_HYPHEN) || *p != '#')) { rc = -1; goto end; } + + rc = 0; +end: + errno = err; + return (rc); +} #define MAXFILES (1 + 2*99 + 1) struct file { @@ -64,6 +83,39 @@ static int compare_event(const void *a, const void *b) return (0); } +#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 + typedef uint_least32_t bits; static bits live[(MAXFILES + 31)/32]; @@ -119,8 +171,8 @@ static void put_menu(dvd_reader_t *dvd, unsigned title) 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)); } @@ -160,17 +212,30 @@ static void put_title(dvd_reader_t *dvd, unsigned title) start[0], start[npart - 1] + SECTORS(len[npart - 1])); } -static secaddr last_pos, limit, nsectors, ndone; -static struct timeval last_time; -static double wsum, wcount; +static dvd_reader_t *dvd; +static int dvdfd = -1, outfd = -1; static struct file *file; +static dvd_file_t *vob; +static const char *mapfile; static FILE *mapfp; +static const char *errfile; static FILE *errfp; +static secaddr limit; static secaddr bad_start; static unsigned retry, max_retries = 4; + +static secaddr nsectors, ndone; +static secaddr last_pos; +static struct timeval last_time; +static double alpha = 0.1; +static double wsum, wcount; static int bad_err; static const char throbber[] = "|<-<|>->"; static unsigned throbix = 0; +static struct progress_item + copy_progress, disc_progress, + file_progress, badblock_progress; + static double scale_bytes(double n, const char **unit_out) { const char *unit = ""; @@ -179,14 +244,9 @@ static double scale_bytes(double n, const char **unit_out) if (n > 1600) { n /= 1024; unit = "M"; } if (n > 1600) { n /= 1024; unit = "G"; } if (n > 1600) { n /= 1024; unit = "T"; } - *unit_out = unit; return (n); } -static struct progress_item - copy_progress, disc_progress, - file_progress, badblock_progress; - #define TIMESTRMAX 16 static char *fmttime(unsigned long t, char *buf) { @@ -270,15 +330,12 @@ static void render_badblock_progress(struct progress_item *item, progress_shownotice(render, bg, 7); } -static double alpha = 0.1; - static void update_progress(secaddr pos) { struct timeval now; double t, f, g; - gettimeofday(&now, 0); - t = tvdiff(&last_time, &now); + gettimeofday(&now, 0); t = tvdiff(&last_time, &now); #define BETA (1 - alpha) @@ -298,12 +355,6 @@ static void update_progress(secaddr pos) static void report_progress(secaddr pos) { update_progress(pos); progress_update(&progress); } -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); static badblock_v badblocks = VEC_INIT; @@ -347,7 +398,10 @@ static ssize_t read_sectors(secaddr pos, void *buf, secaddr want) #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) @@ -357,7 +411,8 @@ static ssize_t read_sectors(secaddr pos, void *buf, secaddr want) 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); } @@ -385,54 +440,6 @@ static ssize_t read_sectors(secaddr pos, void *buf, secaddr want) 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]; - - progress_clear(&progress); - - if (!file || id_kind(file->id) == RAW) - moan("skipping %"PRIuSEC" bad sectors (%"PRIuSEC" .. %"PRIuSEC")", - bad_hi - bad_lo, bad_lo, bad_hi); - else { - store_filename(fn, file->id); - moan("skipping %"PRIuSEC" bad sectors (%"PRIuSEC" .. %"PRIuSEC"; " - "`%s' %"PRIuSEC" .. %"PRIuSEC" of %"PRIuSEC")", - bad_hi - bad_lo, bad_lo, bad_hi, - fn, bad_lo - file->start, bad_hi - file->start, - file->end - file->start); - } - - record_bad_sectors(bad_lo, bad_hi); - - if (lseek(outfd, (off_t)(bad_hi - bad_lo)*SECTORSZ, SEEK_CUR) < 0) - bail_syserr(errno, "failed to seek past bad sectors"); - - progress_removeitem(&progress, &badblock_progress); - progress_update(&progress); -} - struct recoverybuf { unsigned char *buf; secaddr sz, pos, start, end; @@ -442,8 +449,7 @@ struct recoverybuf { static void rearrange_sectors(struct recoverybuf *r, secaddr dest, secaddr src, secaddr len) { - assert(dest + len <= r->sz); - assert(src + len <= r->sz); + assert(dest + len <= r->sz); assert(src + len <= r->sz); memmove(r->buf + dest*SECTORSZ, r->buf + src*SECTORSZ, len*SECTORSZ); } @@ -477,6 +483,7 @@ static ssize_t recovery_read_sectors(struct recoverybuf *r, 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); } @@ -508,9 +515,9 @@ static ssize_t recovery_read_buffer(struct recoverybuf *r, #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); @@ -632,11 +639,50 @@ static secaddr clear_min = 1, clear_max = SECLIMIT; static double step_factor = 2.0; static secaddr step_min = 1, step_max = 0; +static void recovered(secaddr bad_lo, secaddr bad_hi) +{ + char fn[MAXFNSZ]; + + progress_clear(&progress); + + if (!file || id_kind(file->id) == RAW) + moan("skipping %"PRIuSEC" bad sectors (%"PRIuSEC" .. %"PRIuSEC")", + bad_hi - bad_lo, bad_lo, bad_hi); + else { + store_filename(fn, file->id); + moan("skipping %"PRIuSEC" bad sectors (%"PRIuSEC" .. %"PRIuSEC"; " + "`%s' %"PRIuSEC" .. %"PRIuSEC" of %"PRIuSEC")", + bad_hi - bad_lo, bad_lo, bad_hi, + fn, bad_lo - file->start, bad_hi - file->start, + file->end - file->start); + } + + 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"); + + progress_removeitem(&progress, &badblock_progress); + progress_update(&progress); +} + static secaddr run_length_wanted(secaddr pos, secaddr badlen, secaddr end) { 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; @@ -657,13 +703,10 @@ static ssize_t find_good_sector(secaddr *pos_inout, secaddr end, 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", @@ -678,9 +721,11 @@ static ssize_t find_good_sector(secaddr *pos_inout, secaddr end, } } + 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); #ifdef DEBUG progress_clear(&progress); printf(";; bounding bad-block region: " @@ -693,11 +738,12 @@ static ssize_t find_good_sector(secaddr *pos_inout, secaddr end, recovered(bad_lo, end); *pos_inout = end; return (0); } + report_bad_blocks_progress(bad_hi, errno); step = (step_factor - 1)*(bad_hi - bad_lo); if (step < step_min) step = step_min; if (step_max && step > step_max) step = step_max; - if (step > end - bad_hi) step = end - bad_hi; - pos = bad_hi + step - 1; + step += bad_hi - bad_lo; + if (step > end - bad_lo) step = end - bad_lo; want = run_length_wanted(pos, step, end); n = recovery_read(&r, pos, want); #ifdef DEBUG @@ -711,13 +757,13 @@ static ssize_t find_good_sector(secaddr *pos_inout, secaddr end, good = pos; while (good > bad_hi) { - report_bad_blocks_progress(bad_hi, errno); #ifdef DEBUG progress_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 + report_bad_blocks_progress(bad_hi, errno); pos = bad_hi + (good - bad_hi)/2; step = pos - bad_lo; want = run_length_wanted(pos, step, end); @@ -730,7 +776,7 @@ static ssize_t find_good_sector(secaddr *pos_inout, secaddr end, if (n == want) good = pos; else bad_hi = pos + n + 1; } - recovered(bad_lo, bad_hi); *pos_inout = good; + recovered(bad_lo, good); *pos_inout = good; if (good < r.pos + r.start || r.pos + r.end <= good) n = 0; else { @@ -795,7 +841,6 @@ static void emit(secaddr start, secaddr end) bail("failed to open %s %u", id_part(file->id) ? "title" : "menu", id_title(file->id)); - progress_update(&progress); break; default: abort(); @@ -807,6 +852,7 @@ static void emit(secaddr start, secaddr end) progress_additem(&progress, &file_progress); } + progress_update(&progress); pos = start; while (pos < end) { want = end - pos; if (want > BUFSECTORS) want = BUFSECTORS; @@ -826,149 +872,6 @@ static void emit(secaddr start, secaddr end) #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) -{ - char *q; - int err, rc; - unsigned long start, end; - - err = errno; - - if (ISDIGIT(*p)) { - start = strtoul(p, &q, 0); - if (errno || start >= SECLIMIT) { rc = -1; goto end; } - *start_out = start; p = q; - } else if (!(f&PRF_HYPHEN)) - { rc = -1; goto end; } - else - start = 0; - - if (f&PRF_HYPHEN) { - if (*p != '-') { rc = -1; goto end; } - p++; - } else { - if (!ISSPACE(*p)) { rc = -1; goto end; } - do p++; while (ISSPACE(*p)); - } - - if (ISDIGIT(*p)) { - end = strtoul(p, &q, 0); - if (errno || end > SECLIMIT || end < start) { rc = -1; goto end; } - *end_out = end; p = q; - } else if (!(f&PRF_HYPHEN)) - { rc = -1; goto end; } - - if (!(f&PRF_HYPHEN)) while (ISSPACE(*p)) p++; - if (*p && ((f&PRF_HYPHEN) || *p != '#')) { rc = -1; goto end; } - - rc = 0; -end: - errno = err; - 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; @@ -999,6 +902,7 @@ int main(int argc, char *argv[]) #define f_fixup 4u #define f_stats 8u #define f_checkid 16u +#define f_retry 32u #define f_write 256u set_prog(argv[0]); @@ -1012,29 +916,37 @@ int main(int argc, char *argv[]) (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; - else if (*p != ',') bail("unexpected junk in parameters"); + if (*p != ',') bail("unexpected junk in parameters"); p++; } #undef SKIP_PREFIX @@ -1047,8 +959,8 @@ int main(int argc, char *argv[]) bail_syserr(errno, "failed to open ranges file `%s'", optarg); i = 0; last = -1; for (;;) { - BUF_REWIND(&buf); if (read_line(fp, &buf)) break; - p = buf.p; i++; + buf_rewind(&buf); if (read_line(fp, &buf)) break; + i++; p = buf.p; while (ISSPACE(*p)) p++; if (!*p || *p == '#') continue; if (parse_range(p, 0, &start, &end) || @@ -1066,6 +978,7 @@ int main(int argc, char *argv[]) } if (ferror(fp)) bail_syserr(errno, "failed to read ranges file `%s'", optarg); + f |= f_retry; break; case 'X': fp = fopen(optarg, "r"); @@ -1073,15 +986,17 @@ int main(int argc, char *argv[]) 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; 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 (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); @@ -1093,7 +1008,7 @@ int main(int argc, char *argv[]) case 'c': f |= f_continue; break; case 'i': f |= f_checkid; break; case 'r': - start = 0; end = -1; + start = 0; end = -1; f |= f_retry; if (parse_range(optarg, PRF_HYPHEN, &start, &end)) bail("bad range `%s'", optarg); if (start < end) { @@ -1108,8 +1023,6 @@ int main(int argc, char *argv[]) if (argc - optind != 2) f |= f_bogus; if (f&f_bogus) { usage(stderr); exit(2); } - setlocale(LC_ALL, ""); - progress_init(&progress); device = argv[optind]; outfile = argv[optind + 1]; if (badblocks.n) { @@ -1123,7 +1036,9 @@ int main(int argc, char *argv[]) #endif } - open_dvd(device, &dvdfd, &dvd); + setlocale(LC_ALL, ""); + progress_init(&progress); + if (open_dvd(device, O_RDONLY, &dvdfd, &dvd)) exit(2); blksz = SECTORSZ; volsz = device_size(dvdfd, device, &blksz); if (blksz != SECTORSZ) @@ -1133,7 +1048,7 @@ int main(int argc, char *argv[]) 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); @@ -1151,8 +1066,9 @@ int main(int argc, char *argv[]) if (off < 0) bail_syserr(errno, "failed to seek to end of output file `%s'", outfile); - put_event(EV_WRITE, 0, off/SECTORSZ); - } else if (!eventq.n && !(f&f_fixup)) + put_event(EV_WRITE, 0, off/SECTORSZ); f |= f_retry; + } + if (!(f&(f_retry | f_fixup))) put_event(EV_WRITE, 0, 0); /* It's fast enough just to check everything. */ @@ -1167,8 +1083,6 @@ int main(int argc, char *argv[]) for (i = 0, limit = 0; i < filetab.n; i++) if (filetab.v[i].end > limit) limit = filetab.v[i].end; - if (end > limit) end = limit; - #ifdef DEBUG printf("\n;; files:\n"); for (i = 0; i < filetab.n; i++) { @@ -1181,8 +1095,7 @@ int main(int argc, char *argv[]) qsort(eventq.v, eventq.n, sizeof(struct event), compare_event); - f &= ~f_write; start = 0; - for (i = 0; i < eventq.n; i++) { + for (i = 0, f &= ~f_write, start = 0; i < eventq.n; i++) { ev = &eventq.v[i]; switch (ev->ev) { case EV_WRITE: @@ -1201,20 +1114,19 @@ int main(int argc, char *argv[]) #ifdef DEBUG dump_eventq("initial"); #endif - f &= ~f_write; start = 0; - for (i = 0; i < eventq.n; i++) { + for (i = 0, f &= ~f_write, start = last = 0; i < eventq.n; i++) { ev = &eventq.v[i]; 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; + if (f&f_fixup) last = ev->pos; } eventq.n = i; #ifdef DEBUG dump_eventq("trimmed"); #endif if (f&f_fixup) { - put_event(EV_WRITE, 0, start); + put_event(EV_WRITE, 0, last); f |= f_write; } if (f&f_write) { @@ -1239,8 +1151,7 @@ int main(int argc, char *argv[]) #ifdef DEBUG printf("\n;; event sweep:\n"); #endif - f &= ~f_write; - for (pos = 0, i = 0; i < eventq.n; i++) { + for (pos = 0, i = 0, f &= ~f_write; i < eventq.n; i++) { ev = &eventq.v[i]; if (ev->pos > pos) { if (f&f_write) emit(pos, ev->pos); @@ -1266,11 +1177,11 @@ int main(int argc, char *argv[]) "failed to seek to resume position " "(sector %"PRIuSEC") in output file `%s'", ev->pos, outfile); + f |= f_write; #ifdef DEBUG progress_clear(&progress); printf(";; %8"PRIuSEC": begin write\n", pos); #endif - f |= f_write; break; case EV_STOP: f &= ~f_write; @@ -1312,11 +1223,11 @@ int main(int argc, char *argv[]) carefully_fclose(errfp, "bad-sector error log"); progress_free(&progress); + return (0); + #undef f_bogus #undef f_continue #undef f_fixup #undef f_stats #undef f_write - - return (0); }