va_end(ap);
}
-struct source {
- dvd_reader_t *dvd;
- int dvdfd;
- struct file *file;
- dvd_file_t *vob;
-
- unsigned f;
-#define SRCF_ALLPROGRESS 1u
- secaddr last_pos, limit, nsectors, ndone;
- struct timeval last_time;
- double wsum, wcount;
- const char *mapfile; FILE *mapfp;
-};
-#define SOURCE_INIT { 0, -1, 0, 0, 0, 0, 0, 0, 0, { 0, 0 }, 0.0, 0.0, 0, 0 }
-
-static void report_progress(struct source *src, secaddr pos)
+static dvd_reader_t *dvd;
+static int dvdfd = -1;
+static struct file *file;
+static dvd_file_t *vob;
+
+unsigned flags;
+# define F_ALLPROGRESS 1u
+static secaddr last_pos, limit, nsectors, ndone;
+static struct timeval last_time;
+static double wsum, wcount;
+static const char *mapfile; static FILE *mapfp;
+
+static void report_progress(secaddr pos)
{
char etastr[32];
struct timeval now;
#define BETA (1 - ALPHA)
gettimeofday(&now, 0);
- t = (now.tv_sec - src->last_time.tv_sec) +
- (now.tv_usec - src->last_time.tv_usec)/1000000.0;
+ t = (now.tv_sec - last_time.tv_sec) +
+ (now.tv_usec - last_time.tv_usec)/1000000.0;
if (t) {
- g = src->wcount ? pow(BETA, t) : 0.0; f = (1 - g)/(1 - BETA);
- src->wsum = f*(pos - src->last_pos)/t + g*src->wsum;
- src->wcount = f + g*src->wcount;
- src->ndone += pos - src->last_pos;
- src->last_time = now; src->last_pos = pos;
+ g = wcount ? pow(BETA, t) : 0.0; f = (1 - g)/(1 - BETA);
+ wsum = f*(pos - last_pos)/t + g*wsum;
+ wcount = f + g*wcount;
+ ndone += pos - last_pos;
+ last_time = now; last_pos = pos;
}
- if (!src->wsum || !src->wcount)
+ if (!wsum || !wcount)
{ rate = 0; strcpy(etastr, "???"); }
else {
- rate = src->wsum/src->wcount;
- eta = (int)((src->nsectors - src->ndone)/rate);
+ rate = wsum/wcount;
+ eta = (int)((nsectors - ndone)/rate);
sprintf(etastr, "%d:%02d:%02d", eta/3600, (eta/60)%60, eta%60);
}
if (rate > 128) { rate /= 1024; unit = "M"; }
if (rate > 128) { rate /= 1024; unit = "G"; }
- if (src->f&SRCF_ALLPROGRESS) percent = pos*100.0/src->limit;
- else percent = src->ndone*100.0/src->nsectors;
+ if (flags&F_ALLPROGRESS) percent = pos*100.0/limit;
+ else percent = ndone*100.0/nsectors;
print_progress
("copied %.1f%% (%"PRIuSEC" of %"PRIuSEC"; %.1f %sB/s, ETA %s)",
- percent, pos, src->limit, rate, unit, etastr);
- if (src->file && id_kind(src->file->id) == VOB) {
+ percent, pos, limit, rate, unit, etastr);
+ if (file && id_kind(file->id) == VOB) {
append_progress(" -- %s %d %3.1f%%",
- id_part(src->file->id) ? "title" : "menu",
- id_title(src->file->id),
- (pos - src->file->start)*100.0/
- (src->file->end - src->file->start));
+ id_part(file->id) ? "title" : "menu",
+ id_title(file->id),
+ (pos - file->start)*100.0/
+ (file->end - file->start));
}
#undef ALPHA
#undef BETA
}
-static void report_bad_blocks_progress(struct source *src,
- secaddr lo, secaddr hi, int err)
+static void report_bad_blocks_progress(secaddr lo, secaddr hi, int err)
{
- report_progress(src, hi);
+ report_progress(hi);
if (lo == hi) append_progress(": retrying bad sector");
else
fflush(stdout);
}
-static ssize_t read_sectors(struct source *src, secaddr pos,
- void *buf, secaddr want)
+static ssize_t read_sectors(secaddr pos, void *buf, secaddr want)
{
ssize_t n;
again:
- if (src->vob)
- n = DVDReadBlocks(src->vob, pos - src->file->start, want, buf);
- else if (src->file) {
- if (lseek(src->dvdfd, (off_t)pos*SECTORSZ, SEEK_SET) < 0)
+ if (vob)
+ n = DVDReadBlocks(vob, pos - file->start, want, buf);
+ else if (file) {
+ if (lseek(dvdfd, (off_t)pos*SECTORSZ, SEEK_SET) < 0)
bail_syserr(errno, "failed to seek to sector %"PRIuSEC"", pos);
- n = read(src->dvdfd, buf, want*SECTORSZ);
+ n = read(dvdfd, buf, want*SECTORSZ);
if (n >= 0) n /= SECTORSZ;
} else {
memset(buf, 0, want*SECTORSZ);
}
}
-static void emit(struct source *src, int outfd, secaddr start, secaddr end)
+static void emit(int outfd, secaddr start, secaddr end)
{
#define BUFSECTORS 512
#endif
if (least == -1)
- { src->file = 0; src->vob = 0; }
+ { file = 0; vob = 0; }
else {
- src->file = &filetab.v[least];
- switch (id_kind(src->file->id)) {
+ file = &filetab.v[least];
+ switch (id_kind(file->id)) {
case RAW:
- src->vob = 0;
+ vob = 0;
break;
case VOB:
if (first_time) { clear_progress(); first_time = 0; }
- src->vob = DVDOpenFile(src->dvd, id_title(src->file->id),
- id_part(src->file->id)
- ? DVD_READ_TITLE_VOBS
- : DVD_READ_MENU_VOBS);
- if (!src->vob)
+ vob = DVDOpenFile(dvd, id_title(file->id),
+ id_part(file->id)
+ ? DVD_READ_TITLE_VOBS
+ : DVD_READ_MENU_VOBS);
+ if (!vob)
bail("failed to open %s %u",
- id_part(src->file->id) ? "title" : "menu",
- id_title(src->file->id));
+ id_part(file->id) ? "title" : "menu",
+ id_title(file->id));
break;
default:
abort();
pos = start;
while (pos < end) {
want = end - pos; if (want > BUFSECTORS) want = BUFSECTORS;
- n = read_sectors(src, pos, buf, want);
+ n = read_sectors(pos, buf, want);
if (n <= 0) {
- report_bad_blocks_progress(src, pos, pos, errno);
+ report_bad_blocks_progress(pos, pos, errno);
for (i = 0; i < 4; i++) {
- n = read_sectors(src, pos, buf, 1);
+ n = read_sectors(pos, buf, 1);
if (n > 0) {
clear_progress();
moan("sector %"PRIuSEC" read ok after retry", pos);
bad_lo = pos; step = 1; bad_hi = pos + 1;
for (;;) {
- report_bad_blocks_progress(src, bad_lo, bad_hi, errno);
+ report_bad_blocks_progress(bad_lo, bad_hi, errno);
if (bad_hi >= end) {
clear_progress();
moan("giving up on this extent");
step *= 2;
if (step > end - bad_lo) step = end - bad_lo;
pos = bad_lo + step - 1;
- n = read_sectors(src, pos, buf, 1);
+ n = read_sectors(pos, buf, 1);
if (n > 0) break;
bad_hi = pos + 1;
}
good = pos;
while (good > bad_hi) {
- report_bad_blocks_progress(src, bad_lo, bad_hi, errno);
+ report_bad_blocks_progress(bad_lo, bad_hi, errno);
pos = bad_hi + (good - bad_hi)/2;
- n = read_sectors(src, pos, buf, 1);
+ n = read_sectors(pos, buf, 1);
if (n > 0) good = pos;
else bad_hi = pos + 1;
}
clear_progress();
moan("skipping %"PRIuSEC" bad sectors (%"PRIuSEC" .. %"PRIuSEC")",
bad_hi - bad_lo, bad_lo, bad_hi);
- if (src->mapfile) {
- if (!src->mapfp) {
- src->mapfp = fopen(src->mapfile, "w");
- if (!src->mapfp)
+ if (mapfile) {
+ if (!mapfp) {
+ mapfp = fopen(mapfile, "w");
+ if (!mapfp)
bail_syserr(errno, "failed to open bad-sector map file `%s'",
optarg);
- fprintf(src->mapfp, "## bad sector map\n\n");
+ fprintf(mapfp, "## bad sector map\n\n");
}
- fprintf(src->mapfp, "%"PRIuSEC" %"PRIuSEC"\n", bad_lo, bad_hi);
- fflush(src->mapfp);
- if (ferror(src->mapfp))
+ fprintf(mapfp, "%"PRIuSEC" %"PRIuSEC"\n", bad_lo, bad_hi);
+ fflush(mapfp);
+ if (ferror(mapfp))
bail_syserr(errno, "error writing bad-sector map file");
}
if (outfd >= 0 &&
}
if (n > 0) { carefully_write(outfd, buf, n*SECTORSZ); pos += n; }
- report_progress(src, pos); fflush(stdout);
+ report_progress(pos); fflush(stdout);
}
- if (src->vob) { DVDCloseFile(src->vob); src->vob = 0; }
+ if (vob) { DVDCloseFile(vob); vob = 0; }
#undef BUFSECTORS
}
uint64_t volsz;
secaddr pos;
off_t off;
- struct source src = SOURCE_INIT;
unsigned long start, end;
const struct event *ev;
const char *device = "/dev/dvd", *outfile = 0;
bad_range_file:
bail("bad range `%s' at `%s' line %zu", buf.p, optarg, i);
case 'b':
- if (src.mapfile) bail("can't have multiple map files");
- src.mapfile = optarg;
+ if (mapfile) bail("can't have multiple map files");
+ mapfile = optarg;
break;
case 'c': f |= f_continue; break;
case 'o': outfile = optarg; break;
if (optind < argc) f |= f_bogus;
if (f&f_bogus) { usage(stderr); exit(2); }
- src.dvdfd = open(device, O_RDONLY);
- if (src.dvdfd < 0)
+ dvdfd = open(device, O_RDONLY);
+ if (dvdfd < 0)
bail_syserr(errno, "failed to open device `%s'", device);
- if (fstat(src.dvdfd, &st))
+ if (fstat(dvdfd, &st))
bail_syserr(errno, "failed to stat device `%s'", device);
if (S_ISREG(st.st_mode)) {
blksz = SECTORSZ;
volsz = st.st_size;
} else if (S_ISBLK(st.st_mode)) {
- if (ioctl(src.dvdfd, BLKSSZGET, &blksz))
+ if (ioctl(dvdfd, BLKSSZGET, &blksz))
bail_syserr(errno, "failed to get block size for `%s'", device);
- if (ioctl(src.dvdfd, BLKGETSIZE64, &volsz))
+ if (ioctl(dvdfd, BLKGETSIZE64, &volsz))
bail_syserr(errno, "failed to get volume size for `%s'", device);
} else
bail("can't use `%s' as source: expected file or block device", device);
put_event(EV_WRITE, 0, 0);
#ifdef notdef
- src.dvd = DVDOpen2(0, &logger, device);
+ dvd = DVDOpen2(0, &logger, device);
#else
- src.dvd = DVDOpen(device);
+ dvd = DVDOpen(device);
#endif
- if (!src.dvd) bail("failed to open DVD on `%s'", device);
+ if (!dvd) bail("failed to open DVD on `%s'", device);
/* It's fast enough just to check everything. */
- put_menu(src.dvd, 0);
+ put_menu(dvd, 0);
for (i = 1; i < 100; i++) {
- put_menu(src.dvd, i);
- put_title(src.dvd, i);
+ put_menu(dvd, i);
+ put_title(dvd, i);
}
put_file(mkident(RAW, 0, 0), 0, volsz/SECTORSZ);
assert(filetab.n <= MAXFILES);
- for (i = 0, src.limit = 0; i < filetab.n; i++)
- if (filetab.v[i].end > src.limit) src.limit = filetab.v[i].end;
+ for (i = 0, limit = 0; i < filetab.n; i++)
+ if (filetab.v[i].end > limit) limit = filetab.v[i].end;
- if (end > src.limit) end = src.limit;
+ if (end > limit) end = limit;
#ifdef DEBUG
printf("\n;; files:\n");
ev = &eventq.v[i];
switch (ev->ev) {
case EV_WRITE: start = ev->pos; f |= f_write; break;
- case EV_STOP: src.nsectors += ev->pos - start; f &= ~f_write; break;
+ case EV_STOP: nsectors += ev->pos - start; f &= ~f_write; break;
}
- if (ev->pos >= src.limit) break;
+ if (ev->pos >= limit) break;
if (f&f_fixup) start = ev->pos;
}
eventq.n = i;
n++; f |= f_write;
}
if (f&f_write) {
- src.nsectors += src.limit - start;
- put_event(EV_STOP, 0, src.limit);
+ nsectors += limit - start;
+ put_event(EV_STOP, 0, limit);
}
- if (n == 1 && (f&f_write))
- src.f |= SRCF_ALLPROGRESS;
+ if (n == 1 && (f&f_write)) flags |= F_ALLPROGRESS;
f &= ~f_write;
#ifdef DEBUG
for (pos = 0, i = 0; i < eventq.n; i++) {
ev = &eventq.v[i];
if (ev->pos > pos) {
- if (f&f_write) emit(&src, outfd, pos, ev->pos);
+ if (f&f_write) emit(outfd, pos, ev->pos);
pos = ev->pos;
#ifdef DEBUG
clear_progress();
#endif
break;
case EV_WRITE:
- gettimeofday(&src.last_time, 0); src.last_pos = pos;
+ gettimeofday(&last_time, 0); last_pos = pos;
if (outfd >= 0 &&
lseek(outfd, (off_t)ev->pos*SECTORSZ, SEEK_SET) < 0)
bail_syserr(errno,
if (progresslen) putchar('\n');
- if (outfd >= 0 && ftruncate(outfd, (off_t)src.limit*SECTORSZ) < 0)
+ if (outfd >= 0 && ftruncate(outfd, (off_t)limit*SECTORSZ) < 0)
bail_syserr(errno, "failed to set output file `%s' length", outfile);
- if (src.dvd) DVDClose(src.dvd);
- if (src.dvdfd >= 0) close(src.dvdfd);
+ if (dvd) DVDClose(dvd);
+ if (dvdfd >= 0) close(dvdfd);
if (outfd >= 0) close(outfd);
- if (src.mapfp) {
- if (ferror(src.mapfp) || fclose(src.mapfp))
+ if (mapfp) {
+ if (ferror(mapfp) || fclose(mapfp))
bail_syserr(errno, "error writing bad-sector map file");
}