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;
+
+ 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; }
-#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)
+ rc = 0;
+end:
+ errno = err;
+ return (rc);
+}
#define MAXFILES (1 + 2*99 + 1)
struct file {
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];
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));
}
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 = "";
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)
{
progress_shownotice(render, bg, 7);
}
-static double alpha = 0.1;
-
static void update_progress(secaddr pos)
{
struct timeval now;
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;
#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];
-
- 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;
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);
}
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);
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;
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);
#ifdef DEBUG
progress_clear(&progress);
printf(";; bounding bad-block region: "
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
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);
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 {
bail("failed to open %s %u",
id_part(file->id) ? "title" : "menu",
id_title(file->id));
- progress_update(&progress);
break;
default:
abort();
progress_additem(&progress, &file_progress);
}
+ progress_update(&progress);
pos = start;
while (pos < end) {
want = end - pos; if (want > BUFSECTORS) want = BUFSECTORS;
#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);
-}
-
int main(int argc, char *argv[])
{
unsigned f = 0;
const char *device, *outfile;
struct badblock *bad;
int opt, blksz;
- unsigned n;
size_t i;
FILE *fp;
struct buf buf = BUF_INIT;
#define f_fixup 4u
#define f_stats 8u
#define f_checkid 16u
+#define f_retry 32u
#define f_write 256u
set_prog(argv[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;
- else if (*p != ',') bail("unexpected junk in parameters");
+ if (*p != ',') bail("unexpected junk in parameters");
p++;
}
#undef SKIP_PREFIX
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) ||
}
if (ferror(fp))
bail_syserr(errno, "failed to read ranges file `%s'", optarg);
+ f |= f_retry;
break;
case 'X':
fp = fopen(optarg, "r");
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);
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) {
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) {
#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)
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);
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. */
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++) {
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
qsort(eventq.v, eventq.n, sizeof(struct event), compare_event);
- f &= ~f_write; start = 0; n = 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:
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);
- n++; f |= f_write; start = ev->pos;
+ f |= f_write; start = ev->pos;
break;
case EV_STOP:
f &= ~f_write;
}
}
- f &= ~f_write; start = 0;
- for (i = 0; i < eventq.n; i++) {
+#ifdef DEBUG
+ dump_eventq("initial");
+#endif
+ for (i = 0, f &= ~f_write, start = last = 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 (f&f_fixup) start = ev->pos;
+ if (ev->ev == EV_STOP) { nsectors += ev->pos - start; f &= ~f_write; }
+ 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);
- n++; f |= f_write;
+ put_event(EV_WRITE, 0, last);
+ f |= f_write;
}
if (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);
#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);
"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;
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",