X-Git-Url: https://git.distorted.org.uk/~mdw/dvdrip/blobdiff_plain/ea027dd67d0b1a23995c0029248d52a1dc1a625c..69d1ae9dda83cf77000b4939fb0cae0126d5f065:/dvd-sector-copy.c diff --git a/dvd-sector-copy.c b/dvd-sector-copy.c index c336d3d..2c461e1 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/ @@ -409,30 +439,31 @@ static ssize_t read_sectors(secaddr pos, void *buf, secaddr want) struct badblock *bad, *best; unsigned char *p = buf; - best = 0; lo = 0; hi = badblocks.n; + if (badblocks.n) { + best = 0; lo = 0; hi = badblocks.n; #ifdef DEBUG - clear_progress(); - printf(";; searching badblocks for %"PRIuSEC" .. %"PRIuSEC"\n", - pos, pos + want); + debug_clear_progress(); + printf(";; searching badblocks for %"PRIuSEC" .. %"PRIuSEC"\n", + pos, pos + want); #endif - while (lo < hi) { - mid = lo + (hi - lo)/2; bad = &badblocks.v[mid]; + while (lo < hi) { + mid = lo + (hi - lo)/2; bad = &badblocks.v[mid]; #ifdef DEBUG - printf(";; try %zu (%"PRIuSEC" .. %"PRIuSEC")... ", - mid, bad->start, bad->end); + printf(";; try %zu (%"PRIuSEC" .. %"PRIuSEC")... ", + mid, bad->start, bad->end); #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); } - } + 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); } + } #ifdef DEBUG - if (best) - printf(";; next is %"PRIuSEC" .. %"PRIuSEC"\n", - best->start, best->end); + if (best) + printf(";; next is %"PRIuSEC" .. %"PRIuSEC"\n", + best->start, best->end); #endif - if (best && pos + want > best->start) - { want = best->start - pos; fakeerr = EIO; } - + if (best && pos + want > best->start) + { want = best->start - pos; fakeerr = EIO; } + } done = 0; while (want) { if (vob) @@ -472,17 +503,9 @@ 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"); - } + open_file_on_demand(mapfile, &mapfp, "bad-sector region map"); fprintf(mapfp, "%"PRIuSEC" %"PRIuSEC"\n", bad_lo, bad_hi); - fflush(mapfp); - if (ferror(mapfp)) - bail_syserr(errno, "error writing bad-sector map file"); + 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"); @@ -510,7 +533,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("): " @@ -531,7 +554,7 @@ static ssize_t recovery_read_sectors(struct recoverybuf *r, { ssize_t n; - assert(off + want <= r->sz); + assert(off <= r->sz); assert(want <= r->sz - off); n = read_sectors(pos, r->buf + off*SECTORSZ, want); return (n); } @@ -543,7 +566,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 @@ -595,7 +618,7 @@ static ssize_t recovery_read(struct recoverybuf *r, printf(" -> %zd\n", n); #endif if (n != nn) { - if (n > want) n = want; + if (n >= 0 && n > want) n = want; goto end; } r->start = pp; @@ -609,9 +632,9 @@ static ssize_t recovery_read(struct recoverybuf *r, #ifdef DEBUG printf(";; read high (%"PRIuSEC"@%"PRIuSEC", %"PRIuSEC")", r->pos + pp, pp, nn); -fflush(stdout); + fflush(stdout); #endif - n = recovery_read_sectors(r, pos, pp, nn); + n = recovery_read_sectors(r, r->pos + pp, pp, nn); #ifdef DEBUG printf(" -> %zd\n", n); #endif @@ -660,7 +683,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 @@ -684,7 +707,7 @@ 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(); + debug_clear_progress(); printf(";; [bound] try reading %"PRIuSEC" .. %"PRIuSEC" -> %zd\n", pos, pos + want, n); #endif @@ -701,7 +724,7 @@ 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(); + debug_clear_progress(); printf(";; [limit] try reading %"PRIuSEC" .. %"PRIuSEC" -> %zd\n", pos, pos + want, n); #endif @@ -710,10 +733,16 @@ static ssize_t find_good_sector(secaddr *pos_inout, secaddr end, else bad_hi = pos + n + 1; } recovered(bad_lo, bad_hi); *pos_inout = good; - if (r.pos + r.start <= good && good <= r.pos + r.end) { - rearrange_sectors(&r, 0, good - r.pos, r.pos + r.end - good); - } else + if (good < r.pos + r.start || r.pos + r.end <= good) n = 0; + else { + n = r.pos + r.end - good; + rearrange_sectors(&r, 0, good - r.pos, n); + } +#ifdef DEBUG + show_recovery_buffer_map(&r, "returning %zd good sectors at %"PRIuSEC"", + n, good); +#endif return (n); } @@ -1114,7 +1143,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 } @@ -1123,7 +1152,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; @@ -1135,7 +1164,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; @@ -1143,7 +1172,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; @@ -1151,7 +1180,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; @@ -1167,10 +1196,7 @@ 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"); #undef f_bogus #undef f_continue