X-Git-Url: https://git.distorted.org.uk/~mdw/dvdrip/blobdiff_plain/62fc1b88ef0dc318c1f545ef37a37b71f3f7e43f..604a495002ac9390d760fffefcbe27372337cc38:/dvd-sector-copy.c diff --git a/dvd-sector-copy.c b/dvd-sector-copy.c index 1e4dc07..03c2a0c 100644 --- a/dvd-sector-copy.c +++ b/dvd-sector-copy.c @@ -104,6 +104,32 @@ static void carefully_write(int fd, const void *buf, size_t sz) } } +static void open_file_on_demand(const char *file, FILE **fp_inout, + const char *what) +{ + FILE *fp; + + if (!*fp_inout) { + fp = fopen(file, "w"); + if (!fp) + bail_syserr(errno, "failed to open %s file `%s'", what, file); + fprintf(fp, "## %s\n\n", what); + *fp_inout = fp; + } +} + +static void check_write(FILE *fp, const char *what) +{ + fflush(fp); + if (ferror(fp)) bail_syserr(errno, "error writing %s file", what); +} + +static void carefully_fclose(FILE *fp, const char *what) +{ + if (fp && (ferror(fp) || fclose(fp))) + bail_syserr(errno, "error writing %s file", what); +} + #define DEFVEC(vtype, etype) \ typedef struct { etype *v; size_t n, sz; } vtype #define VEC_INIT { 0, 0, 0 } @@ -297,6 +323,10 @@ static void clear_progress_internal(void) } static void clear_progress(void) { clear_progress_internal(); fflush(stdout); } +#ifdef DEBUG +static void debug_clear_progress(void) + { if (progresslen) { putchar('\n'); progresslen = 0; } } +#endif static void vappend_progress(const char *fmt, va_list ap) { progresslen += vprintf(fmt, ap); } __attribute__((format(printf, 1, 2))) @@ -368,7 +398,7 @@ static void report_progress(secaddr pos) ("copied %.1f%% (%"PRIuSEC" of %"PRIuSEC"; %.1f %sB/s, ETA %s)", percent, pos, limit, rate, unit, etastr); if (file && id_kind(file->id) == VOB) { - append_progress(" -- %s %d %3.1f%%", + append_progress(" -- %s %d %.1f%%", id_part(file->id) ? "title" : "menu", id_title(file->id), (pos - file->start)*100.0/ @@ -383,6 +413,7 @@ 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); @@ -449,7 +480,13 @@ static ssize_t read_sectors(secaddr pos, void *buf, secaddr want) } if (n > 0) { done += n; pos += n; p += n*SECTORSZ; want -= n; } - else if (!n || errno != EINTR) break; + else if (!n) break; + else if (errno == EIO && errfile) { + open_file_on_demand(errfile, &errfp, "bad-sector error log"); + fprintf(errfp, "%"PRIuSEC" %"PRIuSEC"\n", pos, pos + 1); + check_write(errfp, "bad-sector error log"); + break; + } else if (errno != EINTR) break; } if (fakeerr && !errno) errno = fakeerr; return (!done && errno ? -1 : done); @@ -473,21 +510,20 @@ static void recovered(secaddr bad_lo, secaddr bad_hi) moan("skipping %"PRIuSEC" bad sectors (%"PRIuSEC" .. %"PRIuSEC")", bad_hi - bad_lo, bad_lo, bad_hi); if (mapfile) { - if (!mapfp) { - mapfp = fopen(mapfile, "w"); - if (!mapfp) - bail_syserr(errno, "failed to open bad-sector map file `%s'", - optarg); - fprintf(mapfp, "## bad sector map\n\n"); - } - fprintf(mapfp, "%"PRIuSEC" %"PRIuSEC"\n", bad_lo, bad_hi); - fflush(mapfp); - if (ferror(mapfp)) - bail_syserr(errno, "error writing bad-sector map file"); + open_file_on_demand(mapfile, &mapfp, "bad-sector region map"); + fprintf(mapfp, "%"PRIuSEC" %"PRIuSEC"", bad_lo, bad_hi); + if (file) + fprintf(mapfp, " # %s #%d %"PRIuSEC"..%"PRIuSEC" of %"PRIuSEC" (%.1f%%)", + id_part(file->id) ? "title" : "menu", + id_title(file->id), + bad_lo - file->start, bad_hi - file->start, + file->end - file->start, + (bad_lo - file->start)*100.0/(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"); - status = 1; } struct recoverybuf { @@ -511,7 +547,7 @@ static void show_recovery_buffer_map(const struct recoverybuf *r, va_list ap; va_start(ap, what); - clear_progress(); + debug_clear_progress(); printf(";; recovery buffer ("); vprintf(what, ap); printf("): " @@ -544,7 +580,7 @@ static ssize_t recovery_read(struct recoverybuf *r, ssize_t n; #ifdef DEBUG - clear_progress(); + debug_clear_progress(); show_recovery_buffer_map(r, "begin(%"PRIuSEC", %"PRIuSEC")", pos, want); #endif @@ -612,7 +648,7 @@ static ssize_t recovery_read(struct recoverybuf *r, r->pos + pp, pp, nn); fflush(stdout); #endif - n = recovery_read_sectors(r, pos + pp, pp, nn); + n = recovery_read_sectors(r, r->pos + pp, pp, nn); #ifdef DEBUG printf(" -> %zd\n", n); #endif @@ -626,6 +662,7 @@ static ssize_t recovery_read(struct recoverybuf *r, n = r->pos + r->end - pos; if (!n && want) n = -1; + else if (n > want) n = want; end: #ifdef DEBUG @@ -661,7 +698,7 @@ static ssize_t find_good_sector(secaddr *pos_inout, secaddr end, for (i = 0; i < 4; i++) { n = recovery_read(&r, pos, want); #ifdef DEBUG - clear_progress(); + debug_clear_progress(); printf(";; [retry] try reading %"PRIuSEC" .. %"PRIuSEC" -> %zd\n", pos, pos + want, n); #endif @@ -675,6 +712,12 @@ static ssize_t find_good_sector(secaddr *pos_inout, secaddr end, bad_lo = pos; bad_hi = pos + 1; for (;;) { report_bad_blocks_progress(bad_lo, bad_hi, errno); +#ifdef DEBUG + debug_clear_progress(); + printf(";; bounding bad-block region: " + "%"PRIuSEC" ..%"PRIuSEC".. %"PRIuSEC"\n", + bad_lo, bad_hi - bad_lo, bad_hi); +#endif if (bad_hi >= end) { clear_progress(); moan("giving up on this extent"); @@ -685,7 +728,6 @@ static ssize_t find_good_sector(secaddr *pos_inout, secaddr end, want = run_length_wanted(pos, step, sz, end); n = recovery_read(&r, pos, want); #ifdef DEBUG - clear_progress(); printf(";; [bound] try reading %"PRIuSEC" .. %"PRIuSEC" -> %zd\n", pos, pos + want, n); #endif @@ -697,12 +739,17 @@ static ssize_t find_good_sector(secaddr *pos_inout, secaddr end, good = pos; while (good > bad_hi) { report_bad_blocks_progress(bad_lo, bad_hi, errno); +#ifdef DEBUG + debug_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 pos = bad_hi + (good - bad_hi)/2; step = pos - bad_lo; want = run_length_wanted(pos, step, sz, end); n = recovery_read(&r, pos, want); #ifdef DEBUG - clear_progress(); printf(";; [limit] try reading %"PRIuSEC" .. %"PRIuSEC" -> %zd\n", pos, pos + want, n); #endif @@ -886,7 +933,7 @@ static int parse_range(const char *p, unsigned f, { rc = -1; goto end; } if (!(f&PRF_HYPHEN)) while (ISSPACE(*p)) p++; - if (*p) { rc = -1; goto end; } + if (*p && ((f&PRF_HYPHEN) || *p != '#')) { rc = -1; goto end; } rc = 0; end: @@ -923,9 +970,10 @@ int main(int argc, char *argv[]) p = strrchr(argv[0], '/'); prog = p ? p + 1 : argv[0]; for (;;) { - opt = getopt(argc, argv, "hFR:X:b:cr:"); if (opt < 0) break; + opt = getopt(argc, argv, "hE:FR:X:b:cr:"); if (opt < 0) break; switch (opt) { case 'h': usage(stderr); exit(0); + case 'E': errfile = optarg; break; case 'F': f |= f_fixup; break; case 'R': fp = fopen(optarg, "r"); @@ -1121,7 +1169,7 @@ int main(int argc, char *argv[]) if (f&f_write) emit(pos, ev->pos); pos = ev->pos; #ifdef DEBUG - clear_progress(); + debug_clear_progress(); printf(";;\n"); #endif } @@ -1130,7 +1178,7 @@ int main(int argc, char *argv[]) set_live(ev->file); #ifdef DEBUG store_filename(fn, filetab.v[ev->file].id); - clear_progress(); + debug_clear_progress(); printf(";; %8"PRIuSEC": begin `%s'\n", pos, fn); #endif break; @@ -1142,7 +1190,7 @@ int main(int argc, char *argv[]) "(sector %"PRIuSEC") in output file `%s'", ev->pos, outfile); #ifdef DEBUG - clear_progress(); + debug_clear_progress(); printf(";; %8"PRIuSEC": begin write\n", pos); #endif f |= f_write; @@ -1150,7 +1198,7 @@ int main(int argc, char *argv[]) case EV_STOP: f &= ~f_write; #ifdef DEBUG - clear_progress(); + debug_clear_progress(); printf(";; %8"PRIuSEC": end write\n", pos); #endif break; @@ -1158,7 +1206,7 @@ int main(int argc, char *argv[]) clear_live(ev->file); #ifdef DEBUG store_filename(fn, filetab.v[ev->file].id); - clear_progress(); + debug_clear_progress(); printf(";; %8"PRIuSEC": end `%s'\n", pos, fn); #endif break; @@ -1174,10 +1222,8 @@ int main(int argc, char *argv[]) if (dvd) DVDClose(dvd); if (dvdfd >= 0) close(dvdfd); if (outfd >= 0) close(outfd); - if (mapfp) { - if (ferror(mapfp) || fclose(mapfp)) - bail_syserr(errno, "error writing bad-sector map file"); - } + carefully_fclose(mapfp, "bad-sector region map"); + carefully_fclose(errfp, "bad-sector error log"); #undef f_bogus #undef f_continue