+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;
+ secaddr good_lo, good_hi;
+};
+
+static void rearrange_sectors(struct recoverybuf *r,
+ secaddr dest, secaddr src, secaddr len)
+{
+ assert(dest + len <= r->sz);
+ assert(src + len <= r->sz);
+ memmove(r->buf + dest*SECTORSZ, r->buf + src*SECTORSZ, len*SECTORSZ);
+}
+
+#ifdef DEBUG
+static PRINTF_LIKE(2, 3)
+ void show_recovery_buffer_map(const struct recoverybuf *r,
+ const char *what, ...)
+{
+ va_list ap;
+
+ va_start(ap, what);
+ progress_clear(&progress);
+ printf(";; recovery buffer (");
+ vprintf(what, ap);
+ printf("): "
+ "(%"PRIuSEC") ..%"PRIuSEC".. "
+ "[%"PRIuSEC" ..%"PRIuSEC".. %"PRIuSEC"] "
+ "..%"PRIuSEC".. (%"PRIuSEC")\n",
+ r->pos, r->start,
+ r->pos + r->start, r->end - r->start, r->pos + r->end,
+ r->sz - r->end, r->pos + r->sz);
+ va_end(ap);
+ assert(r->start <= r->end);
+ assert(r->end <= r->sz);
+}
+#endif
+
+static ssize_t recovery_read_sectors(struct recoverybuf *r,
+ secaddr pos, secaddr off, secaddr want)