acdde7350550955e974bed01d15f3ce8cebd6ba0
[dvdrip] / dvd-sector-copy.c
1 /* -*-c-*-
2 *
3 * Make an unscrambled copy of a DVD.
4 *
5 * (c) 2022 Mark Wooding
6 */
7
8 /*----- Licensing notice --------------------------------------------------*
9 *
10 * This file is part of the DVD ripping toolset.
11 *
12 * DVDrip is free software: you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the
14 * Free Software Foundation; either version 3 of the License, or (at your
15 * option) any later version.
16 *
17 * DVDrip is distributed in the hope that it will be useful, but WITHOUT
18 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 * for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with DVDrip. If not, see <https://www.gnu.org/licenses/>.
24 */
25
26 /*----- Header files ------------------------------------------------------*/
27
28 #include "lib.h"
29
30 /*----- Program usage summary ---------------------------------------------*/
31
32 static void usage(FILE *fp)
33 {
34 fprintf(fp,
35 "usage: %s [-ci] [-B PARAM=VALUE,...] [-R MAP]\n"
36 "\t[-b OUTMAP] [-r [START]-[END]] DEVICE OUTFILE\n",
37 prog);
38 }
39
40 /*----- Random utilities --------------------------------------------------*/
41
42 #define PRF_HYPHEN 1u
43 static int parse_range(const char *p, unsigned f,
44 secaddr *start_out, secaddr *end_out)
45 /* Parse a range of sectors from the string P. If successful, store
46 * the specified start sector address in *START_OUT and the end
47 * address in *END_OUT, and return zero. On failure, return -1;
48 * *START_OUT and/or *END_OUT are clobbered.
49 *
50 * The acceptable syntax depends on the flags.
51 *
52 * * The `PRF_HYPHEN' syntax is intended for use on the
53 * command-line. It accepts `[START]-[END]'; if the start and/or
54 * end addresses are omitted then *START_OUT and/or *END_OUT are
55 * left unchanged.
56 *
57 * * The default syntax matches what's written to the bad-sector
58 * output files. It accepts `START END [# COMMENT]'.
59 */
60 {
61 char *q;
62 int err, rc;
63 unsigned long start, end;
64
65 /* Save any existing error code. */
66 err = errno;
67
68 /* Parse the start address. */
69 if (ISDIGIT(*p)) {
70 /* We found a digit: this is a good start. Convert the integer, check
71 * that it's in range, save it.
72 */
73
74 start = strtoul(p, &q, 0);
75 if (errno || start >= SECLIMIT) { rc = -1; goto end; }
76 *start_out = start; p = q;
77 } else if (!(f&PRF_HYPHEN)) {
78 /* No digit. We're parsing the map-file syntax, so this is an error. */
79
80 rc = -1; goto end;
81 } else {
82 /* We're parsing the command-line syntax, so this is OK. Set our
83 * internal idea of the position for the range check later, but don't
84 * alter the caller's variables.
85 */
86
87 start = 0;
88 }
89
90 /* Parse the delimiter. */
91 if (f&PRF_HYPHEN) {
92 if (*p != '-') { rc = -1; goto end; }
93 p++;
94 } else {
95 if (!ISSPACE(*p)) { rc = -1; goto end; }
96 do p++; while (ISSPACE(*p));
97 }
98
99 /* Parse the end address. */
100 if (ISDIGIT(*p)) {
101 /* We found a digit. Parse the integer and check that it's strictly
102 * larger than the start address.
103 */
104
105 end = strtoul(p, &q, 0);
106 if (errno || end > SECLIMIT || end < start) { rc = -1; goto end; }
107 *end_out = end; p = q;
108 } else if (!(f&PRF_HYPHEN)) {
109 /* No digit. We're parsing the file syntax, so this is an error. */
110
111 rc = -1; goto end;
112 }
113
114 /* In the file syntax, we're now allowed whitespace, so skip past that. */
115 if (!(f&PRF_HYPHEN)) while (ISSPACE(*p)) p++;
116
117 /* Check that there's nothing else. The file syntax allows a trailing
118 * comment here, but the command-line syntax doesn't.
119 */
120 if (*p && ((f&PRF_HYPHEN) || *p != '#')) { rc = -1; goto end; }
121
122 /* All done! */
123 rc = 0;
124 end:
125 errno = err;
126 return (rc);
127 }
128
129 /*----- A few words about the overall approach ----------------------------*
130 *
131 * The objective is to produce a working copy of the input (commercial,
132 * pressed) DVD disc, only with all of the scrambled video data unscrambled
133 * so that it can be read without the need for cracking CSS keys, which, in
134 * the absence of a cooperative drive with access to the key tables in the
135 * disc lead-in data -- which we /don't/ copy -- is often slow and prone to
136 * failure. Producing a sector-by-sector image preserves all of the menus
137 * and special features, and also any other bonus data stored in the
138 * filesystem for use by computers, such as PDF scripts. DVD images are
139 * large because DVD video is inefficiently compressed by modern standards,
140 * but disk space is cheap and the tradeoff seems worthwhile to me.
141 *
142 * The approach is, in essence, simple: start at the beginning of the disc,
143 * reading sectors into a buffer and writing them to the output file, and
144 * continue until we reach the end. But we must cope with scrambled video
145 * files. Fortunately, `libdvdread' knows how to deal with these, and will
146 * tell us where they are on the disc.
147 *
148 * Given this information, we build a table of `events', with the sector
149 * numbers at which they occur. An `event' might be something like `such-
150 * and-such a video file began' or `such-and-such a file ended'. Chunks of
151 * disc between events can be read using the same strategy -- either reading
152 * unscrambled sectors directly from the block device, or decrypting
153 * scrambled sectors through `libdvdread' -- while at sector boundaries we
154 * might need to change strategy.
155 *
156 * Note that files can /overlap/. The DVD spec says that this can't happen,
157 * and that the data for video titles is laid out with higher-numbered
158 * titlesets occupying higher-numbered sectors, but it does anyway. I think
159 * this is intended to frustrate copiers like `dvdbackup' which try to copy
160 * the DVD files into a directory on the filesystem. The result is that they
161 * copy the same sectors into multiple, very large files, and turn an 8 GB
162 * DVD image into a 60 GB directory. (The reused regions often also contain
163 * intentionally bad sectors, so you have to wait for the drive to fail the
164 * same sectors over and over again. This is no fun.) As far as I know,
165 * files are either disjoint or coincident, but more complex arrangements are
166 * possible in principle. Also, I guess it's possible that the same sector
167 * should be decrypted with different keys depending on which titleset we're
168 * considering it being part of, but (a) DVD CSS keys aren't long enough to
169 * do this very well, and (b) I'm not aware of this actually being a thing.
170 * (Indeed, `libdvdcss' indexes keys by start sector, so such a disc probably
171 * wouldn't play back properly through VLC or `mpv'.)
172 *
173 * There's an additional consideration. We want to be able to fill in an
174 * ouptut image file incrementally, in several runs. A run can be
175 * interrupted for lots of reasons (e.g., a faster drive might have become
176 * available; it might be beneficial to switch to a more forgiving drive; it
177 * might be necessary to stop and clean the disc; the output filesystem might
178 * have become full; ...). And discs don't always read perfectly: some discs
179 * are damaged and have areas which can't be read; some discs (I'm looking at
180 * you, Sony, Disney, Lionsgate, and E-One) have intentional bad sectors,
181 * presumably specifically to make my life annoying. So we have other events
182 * which say things like `start writing stuff to the output' or `stop writing
183 * things to the output'. And we have a rather elaborate algorithm for
184 * trying to skip past a region of bad blocks, because drives get /really/
185 * slow when reading bad sectors.
186 */
187
188 /*----- The file and event tables -----------------------------------------*/
189
190 #define MAXFILES (1 + 2*99 + 1)
191 /* How many (interesting) files there can be. This counts the
192 * magical `raw' file which refers to direct disc access, the master
193 * menu file, and 99 possible menu and titleset pairs. (A titleset
194 * can be split into 9 parts in order to keep each file below a
195 * gigabyte in size, but the rules require that the parts together
196 * form a single contiguous chunk on the disc, in the right order, so
197 * we treat them as a single file. We check this in `put_title'
198 * below, just in case some disc somewhere tries to be awkward, but I
199 * don't have a disc like that in my collection, and I doubt it would
200 * work very well.)
201 */
202
203 struct file {
204 /* An interesting DVD file. It has a name, encoded as an `ident'
205 * (see `lib.h'), and start and end sectors. (The `end' here, as
206 * everywhere in this code, is /exclusive/, so that the file's length
207 * is simply end - start.)
208 */
209
210 ident id; /* file name */
211 secaddr start, end; /* start (inclusive) and end
212 * (exclusive) sector numbers */
213 };
214 DEFVEC(file_v, struct file); /* a vector of files */
215 static file_v filetab = VEC_INIT; /* the file table */
216
217 enum {
218 /* Event codes. The ordering of these is important, because we use
219 * them to tie-break comparisons of events happening at the same
220 * sector when we sort the event queue.
221 */
222
223 EV_STOP, /* stop copying stuff to output */
224 EV_BEGIN, /* a (maybe scrambled) file begins */
225 EV_END, /* a file ends */
226 EV_WRITE /* start copying stuff to output */
227 };
228
229 struct event {
230 /* An event. */
231
232 unsigned char ev; /* event code (`EV_...') */
233 unsigned char file; /* the file (`EV_BEGIN', `EV_END');
234 * index into `filetab' */
235 secaddr pos; /* the sector at which it happens */
236 };
237 DEFVEC(event_v, struct event); /* a vector of events */
238 static event_v eventq = VEC_INIT; /* the event queue */
239
240 static int compare_event(const void *a, const void *b)
241 /* A `qsort' comparison function for events. Event A sorts earlier
242 * than event B iff A's sector number is smaller than B's, or A's
243 * event code is less than B's.
244 */
245 {
246 const struct event *eva = a, *evb = b;
247
248 /* Primary ordering by position. */
249 if (eva->pos < evb->pos) return (-1);
250 else if (eva->pos > evb->pos) return (+1);
251
252 /* Secondary ordering by event code. */
253 if (eva->ev < evb->ev) return (-1);
254 else if (eva->ev > evb->ev) return (+1);
255
256 /* We currently have a final tie-break on file numbers so that the ordering
257 * is deterministic, but this is an arbitrary choice that shouldn't be
258 * relied upon.
259 */
260 if (eva->file < evb->file) return (-1);
261 else if (eva->file > evb->file) return (+1);
262
263 /* These events are equal. */
264 return (0);
265 }
266
267 #ifdef DEBUG
268 static void dump_eventq(const char *what)
269 /* Dump the event queue, labelling the output with WHAT. */
270 {
271 unsigned i;
272 const struct event *ev;
273 char fn[MAXFNSZ];
274
275 printf("\n;; event dump (%s):\n", what);
276 for (i = 0; i < eventq.n; i++) {
277 ev = &eventq.v[i];
278 switch (ev->ev) {
279 case EV_BEGIN:
280 store_filename(fn, filetab.v[ev->file].id);
281 printf(";; %8"PRIuSEC": begin %s\n", ev->pos, fn);
282 break;
283 case EV_END:
284 store_filename(fn, filetab.v[ev->file].id);
285 printf(";; %8"PRIuSEC": end %s\n", ev->pos, fn);
286 break;
287 case EV_WRITE:
288 printf(";; %8"PRIuSEC": write\n", ev->pos);
289 break;
290 case EV_STOP:
291 printf(";; %8"PRIuSEC": stop\n", ev->pos);
292 break;
293 default:
294 printf(";; %8"PRIuSEC": ?%u\n", ev->pos, ev->ev);
295 break;
296 }
297 }
298 }
299 #endif
300
301 typedef uint_least32_t bits;
302 static bits live[(MAXFILES + 31)/32];
303 /* A bitmap which keeps track of which files are currently `active',
304 * i.e., that contain the sector we're currently thinking about. We
305 * set and clear these bits as we encounter `EV_BEGIN' and `EV_END'
306 * events.
307 */
308
309 static inline int livep(unsigned i)
310 /* Return whether file I is active. */
311 { return (live[i/32]&((bits)1 << (i%32))); }
312
313 static inline void set_live(unsigned i)
314 /* Note that we've seen the start of file I. */
315 { live[i/32] |= (bits)1 << (i%32); }
316
317 static inline void clear_live(unsigned i)
318 /* Note that we've seen the end of file I. */
319 { live[i/32] &= ~((bits)1 << (i%32)); }
320
321 static inline int least_live(void)
322 /* Return the smallest index for any active file. This is going to
323 * be the file that we ask `libdvdread' to unscramble for us. This
324 * is important: the imaginary `raw' file that represents the entire
325 * block device has the highest index, and we want any actual video
326 * file to be used in preference so that we unscramble the data.
327 */
328 {
329 unsigned i, n = (filetab.n + 32)/32;
330 bits b;
331
332 /* First part: find the first nonzero word in the `live' table. */
333 for (i = 0; i < n; i++) { b = live[i]; if (b) goto found; }
334 return (-1);
335
336 found:
337 /* Second part: identify which bit in this word is nonzero. First, see if
338 * the bottom 16 bits are clear: if so, shift down and add 16 to the
339 * total. Now we know that the first set bit is indeed in the low 16
340 * bits, so see whether the low 8 bits are clear, and so on.
341 */
342 i *= 32;
343 if (!(b&0x0000ffff)) { b >>= 16; i += 16; }
344 if (!(b&0x000000ff)) { b >>= 8; i += 8; }
345 if (!(b&0x0000000f)) { b >>= 4; i += 4; }
346 if (!(b&0x00000003)) { b >>= 2; i += 2; }
347 if (!(b&0x00000001)) { b >>= 1; i += 1; }
348 assert(b&1);
349
350 /* Done. */
351 return (i);
352 }
353
354 static void put_event(unsigned evtype, unsigned file, secaddr pos)
355 /* Add an event to the queue, with type EVTYPE, for the given FILE,
356 * and at sector POS. You can add events in any order because we'll
357 * sort them later. For `EV_WRITE' and `EV_STOP' events, the FILE
358 * doesn't matter: use zero for concreteness.
359 */
360 {
361 struct event *ev;
362
363 VEC_PUSH(ev, &eventq);
364 ev->ev = evtype; ev->file = file; ev->pos = pos;
365 }
366
367 static void put_file(ident id, secaddr start, secaddr end)
368 /* Add a (VOB) file to the file table and event queue, with ident ID,
369 * starting at sector START and ending just before sector END.
370 */
371 {
372 struct file *f;
373 size_t i;
374
375 VEC_PUSH(f, &filetab); i = f - filetab.v;
376 f->id = id; f->start = start; f->end = end;
377 put_event(EV_BEGIN, i, start);
378 put_event(EV_END, i, end);
379 }
380
381 static void put_menu(dvd_reader_t *dvd, unsigned title)
382 /* Add the menu file for the given TITLE number to the file table and
383 * event queue; use the reader DVD to find out which sectors it
384 * occupies, if it even exists.
385 */
386 {
387 ident id = mkident(VOB, title, 0);
388 char fn[MAXFNSZ];
389 secaddr start, len;
390
391 /* Find out where the file is. */
392 store_filename(fn, id);
393 start = UDFFindFile(dvd, fn, &len); if (!start) return;
394
395 #ifdef DEBUG
396 /* Print out what we've discovered. */
397 printf(";; %8"PRIuSEC" .. %-8"PRIuSEC": %s\n",
398 start, start + SECTORS(len), fn);
399 #endif
400
401 /* Register the file and boundary events. */
402 put_file(id, start, start + SECTORS(len));
403 }
404
405 static void put_title(dvd_reader_t *dvd, unsigned title)
406 /* Add the titleset file for the given TITLE number to the file table
407 * and event queue; use the reader DVD to find out which sectors it
408 * occupies, if it even exists.
409 */
410 {
411 char fn[MAXFNSZ];
412 secaddr start[9], len[9];
413 unsigned i, npart;
414
415 /* First step: find out where all of the parts of the titleset are. I'm
416 * assuming that there aren't gaps in the numbering.
417 */
418 for (i = 0; i < 9; i++) {
419 store_filename(fn, mkident(VOB, title, i + 1));
420 start[i] = UDFFindFile(dvd, fn, &len[i]); if (!start[i]) break;
421 }
422 npart = i; if (!npart) return;
423
424 #ifdef DEBUG
425 /* Print out what we've discovered. */
426 for (i = 0; i < npart; i++) {
427 store_filename(fn, mkident(VOB, title, i + 1));
428 printf(";; %8"PRIuSEC" .. %-8"PRIuSEC": %s\n",
429 start[i], start[i] + SECTORS(len[i]), fn);
430 }
431 #endif
432
433 /* Second step: check that the parts all butt up against each other in the
434 * correct order. For this to work, the lengths, which are expressed in
435 * /bytes/ by `UDFFindFile', of all but the last part must be a whole
436 * number of sectors.
437 */
438 if (npart > 1)
439 for (i = 0; i < npart - 1; i++) {
440 if (len[i]%SECTORSZ)
441 bail("title %u part %u length = %"PRIuSEC" not a multiple of %d",
442 title, i, len[i], SECTORSZ);
443 if (start[i] + len[i]/SECTORSZ != start[i + 1])
444 bail
445 ("title %u part %u end = %"PRIuSEC" /= part %u start = %"PRIuSEC"",
446 title, i, start[i] + len[i]/SECTORSZ, i + 1, start[i + 1]);
447 }
448
449 /* All good: register a single file and its boundary events. */
450 put_file(mkident(VOB, title, 1),
451 start[0], start[npart - 1] + SECTORS(len[npart - 1]));
452 }
453
454 /*----- Moving average machinery ------------------------------------------*
455 *
456 * We're using an exponential moving average with a weighting factor of α
457 * (`alpha', above); larger values are more sensitive to recent changes. If
458 * the old average was v_1, and the measurement in the current interval is x,
459 * then the new average after this interval is
460 *
461 * v = α x + (1 − α) v_1 .
462 *
463 * Write β = 1 − α; so
464 *
465 * v = α x + β v_1 .
466 *
467 * Let x_0 = x, let x_1 be the measurement from the previous interval, and,
468 * in general, let x_i be the measurement from i intervals ago. Then another
469 * way to write the above would be
470 *
471 * v = α (x_0 + β x_1 + ⋯ + β^i x_i + ⋯) .
472 *
473 * Alas, our time intervals are not regular. Suppose that we get our next
474 * measurement after a gap of t intervals, for some integer t. We can
475 * compensate approximately by pretending that all of the missed intervals --
476 * and our new one -- had the same mean rate. Then we'd have calculated
477 *
478 * v = α (x + β x + ⋯ + β^{t−1} x) + β^t v_1
479 *
480 * 1 − β^t
481 * = α x ------- + β^t v_1
482 * 1 − β
483 *
484 * = x (1 − β^t) + β^t v_1 (since α = 1 − β)
485 *
486 * = x + β^t (v_1 − x) .
487 *
488 * Does this work in general? It's clearly correct in the case t = 1.
489 *
490 * Suppose the old average was v_2, and that over a period of t intervals
491 * (where t is not necessarily an integer) we measured a mean rate of x, and
492 * then after u intervals we measured a mean rate of x /again/. Then we'd
493 * firstly determine
494 *
495 * v_1 = x + β^t (v_2 − x)
496 *
497 * and then
498 *
499 * v = x + β^u (v_1 − x)
500 *
501 * = x + β^u (x + β^t (v_2 − x) − x)
502 *
503 * = x + β^{t+u} (v_2 − x) ,
504 *
505 * which is exactly what we'd have done if we'd calculated the same mean rate
506 * over the combined span of t + u intervals.
507 *
508 * One final wrinkle, in case that wasn't enough. There's a problem with the
509 * initial setup of an exponential moving average. Apparently
510 * (https://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average)
511 * explains that we can do this better by calculating the average after k
512 * intervals as
513 *
514 * x_0 + β x_1 + β^2 x_2 + ⋯ + β^{k−1} x_{k−1}
515 * v′ = ------------------------------------------- .
516 * 1 + β + β^2 + ⋯ + β^{k−1}
517 *
518 * The numerator is our existing v/α; the denominator is (1 − β^k)/α; the
519 * factors of α cancel, and we find that v′ = v/(1 − β^k). This still holds
520 * in our situation, where k may not be an integer.
521 *
522 * To apply all of this:
523 *
524 * * we maintain the moving average v in `avg';
525 *
526 * * we maintain the total β^k in `corr'; and
527 *
528 * * we compute v′ = v/(1 − β^k) on demand up in `render_perfstats'.
529 */
530
531 struct avg {
532 double avg, corr;
533 };
534 #define AVG_INIT { 0.0, 1.0 }
535
536 static double alpha = 0.1; /* weighting factor for average */
537
538 static void update_avg(struct avg *a, double t, double n)
539 {
540 double rate = n/t, beta_t = pow(1 - alpha, t);
541
542 a->avg = rate + beta_t*(a->avg - rate);
543 a->corr *= beta_t;
544 }
545
546 static inline double current_avg(const struct avg *a)
547 { return (a->avg/(1 - a->corr)); }
548
549 /*----- Common variables used by the copying machinery --------------------*/
550
551 /* General reading state. */
552 static dvd_reader_t *dvd; /* `libdvdread' state for device */
553 static int dvdfd = -1, outfd = -1; /* input device and output image */
554 static struct file *file; /* currently active file */
555 static dvd_file_t *vob; /* current `.VOB' file, or null */
556 static const char *mapfile; static FILE *mapfp; /* skipped regions map */
557 static const char *errfile; static FILE *errfp; /* bad-sector log */
558 static secaddr limit; /* upper bound on sectors */
559
560 static secaddr bad_start; /* start of current bad region */
561 static unsigned retry, max_retries = 4; /* retry state */
562
563 /*----- Progress reporting ------------------------------------------------*/
564
565 static secaddr nsectors, ndone; /* number of sectors done/to do */
566 static secaddr last_pos; /* position last time we updated */
567 static struct timeval last_time; /* time last time we updated */
568 static struct avg avg_rate = AVG_INIT;
569 static int bad_err; /* most recent error code */
570
571 static const char throbber[] = "|<-<|>->"; /* throbber pattern */
572 static unsigned throbix = 0; /* current throbber index */
573
574 static struct progress_item /* stock progress items */
575 copy_progress, disc_progress,
576 file_progress, badblock_progress;
577
578 static double scale_bytes(double n, const char **unit_out)
579 /* Determine a human-readable representation for N bytes. Divide N
580 * by some power of 1024, and store in *UNIT_OUT a string
581 * representing the conventional unit-prefix for that power of 1024.
582 */
583 {
584 const char *unit = "";
585
586 if (n > 1600) { n /= 1024; unit = "k"; }
587 if (n > 1600) { n /= 1024; unit = "M"; }
588 if (n > 1600) { n /= 1024; unit = "G"; }
589 if (n > 1600) { n /= 1024; unit = "T"; }
590 *unit_out = unit; return (n);
591 }
592
593 #define TIMESTRMAX 16 /* maximum length of a duration string */
594 static char *fmttime(unsigned long t, char *buf)
595 /* Format a count T of seconds. Write a suitable string to BUF,
596 * which will be no longer than `TIMESTRMAX' bytes including the
597 * terminating zero. Return BUF.
598 */
599 {
600 if (t < 60) sprintf(buf, "%ld s", t);
601 else if (t < 3600) sprintf(buf, "%ld:%02ld", t/60, t%60);
602 else sprintf(buf, "%ld:%02ld:%02ld", t/3600, (t/60)%60, t%60);
603 return (buf);
604 }
605
606 static void render_perfstats(struct progress_render_state *render)
607 /* Add performance statistics to RENDER.
608 *
609 * Specifically: the average transfer rate, and the estimated time to
610 * completion. (See `update_progress' for how the average
611 * computation works.)
612 */
613 {
614 int eta;
615 char timebuf[TIMESTRMAX];
616 double rate;
617 const char *unit;
618
619 /* If there's no average computed yet, then use some placeholder values. */
620 rate = current_avg(&avg_rate); eta = (int)((nsectors - ndone)/rate + 0.5);
621
622 /* Write out the statistics. */
623 rate = scale_bytes(rate*SECTORSZ, &unit);
624 progress_putright(render, "ETA %s ",
625 avg_rate.avg ? fmttime(eta, timebuf) : "???");
626 progress_putright(render, "%.1f %sB/s, ", rate, unit);
627 }
628
629 static void render_copy_progress(struct progress_item *item,
630 struct progress_render_state *render)
631 /* Render the progress for the copy, i.e., the number of sectors
632 * copied against the total number to be copied.
633 */
634 {
635 double frac = (double)ndone/nsectors;
636
637 progress_putleft(render, " %c copied %.1f%%",
638 throbber[throbix], 100.0*frac);
639 render_perfstats(render);
640 progress_putleft(render, " (%"PRIuSEC" of %"PRIuSEC")", ndone, nsectors);
641
642 progress_showbar(render, frac);
643 }
644
645 static void render_disc_progress(struct progress_item *item,
646 struct progress_render_state *render)
647 /* Render the progress for the disc, i.e., the current position
648 * against the total number of sectors on the disc.
649 */
650 {
651 double frac = (double)last_pos/limit;
652
653 progress_putleft(render, " disc %.1f%% (%"PRIuSEC" of %"PRIuSEC")",
654 100.0*frac, last_pos, limit);
655 progress_showbar(render, frac);
656 }
657
658 static void render_file_progress(struct progress_item *item,
659 struct progress_render_state *render)
660 /* Render the progress for the current file, i.e., the current
661 * position within the file against the file size.
662 */
663 {
664 secaddr off = last_pos - file->start, len = file->end - file->start;
665 char fn[MAXFNSZ];
666 double frac;
667
668 store_filename(fn, file->id);
669 frac = (double)off/len;
670 progress_putleft(render, " `%s' %.1f%% (%"PRIuSEC" of %"PRIuSEC")",
671 fn, 100.0*frac, off, len);
672 progress_showbar(render, frac);
673 }
674
675 static void render_badblock_progress(struct progress_item *item,
676 struct progress_render_state *render)
677 /* Render a notice about the progress through the current bad block
678 * region.
679 */
680 {
681 secaddr n = last_pos - bad_start;
682 int bg;
683
684 if (!n) {
685 progress_putleft(render, " Retrying bad sector %"PRIuSEC"", bad_start);
686 progress_putright(render, "attempt %u/%u ", retry + 1, max_retries);
687 bg = 4;
688 } else {
689 progress_putleft(render, " Found %"PRIuSEC" bad %s",
690 n, n == 1 ? "sector" : "sectors");
691 progress_putright(render, "%"PRIuSEC" .. %"PRIuSEC" ",
692 bad_start, last_pos);
693 bg = 1;
694 }
695 if (bad_err && bad_err != EIO)
696 progress_putleft(render, " (%s)", strerror(bad_err));
697 progress_shownotice(render, bg, 7);
698 }
699
700 static void update_progress(secaddr pos)
701 /* Recompute the data displayed by the progress renderer functions
702 * above, based on the new current sector POS.
703 */
704 {
705 struct timeval now;
706 double t;
707
708 /* Find the current time and the delta since the last time we updated.
709 * This will be the length of the current interval.
710 */
711 gettimeofday(&now, 0); t = tvdiff(&last_time, &now);
712
713 /* If no time at all has passed (unlikely!) then skip the rate
714 * calculation. (The moving average wouldn't be affected anyway.)
715 */
716 if (t) {
717 /* Update the moving average and the correction term, and start the next
718 * interval.
719 */
720
721 update_avg(&avg_rate, t, pos - last_pos);
722 ndone += pos - last_pos; last_time = now; last_pos = pos;
723 }
724
725 /* Advance the throbber character. */
726 throbix++; if (!throbber[throbix]) throbix = 0;
727 }
728
729 static void report_progress(secaddr pos)
730 /* Update the progress variables (as `update_progress') and redraw
731 * the progress display.
732 */
733 { update_progress(pos); progress_update(&progress); }
734
735 /*----- Basic disc I/O ----------------------------------------------------*/
736
737 struct badblock { secaddr start, end; };
738 DEFVEC(badblock_v, struct badblock);
739 static badblock_v badblocks = VEC_INIT;
740 /* This is a list of /fake/ bad-block ranges, used to test the
741 * recovery algorithm. It's a rule that the ranges in this table
742 * mustn't overlap -- though it's OK if they abut.
743 */
744
745 static int compare_badblock(const void *a, const void *b)
746 /* A `qsort' comparison function for the fake bad-blocks list.
747 * Ranges which start earlier are sorted before rangers which start
748 * later.
749 */
750 {
751 const struct badblock *ba = a, *bb = b;
752
753 /* Order by start sector. */
754 if (ba->start < bb->start) return (-1);
755 else if (ba->start > bb->start) return (+1);
756
757 /* Order by end sector as a tiebreak. This shouldn't be possible. */
758 if (ba->end < bb->end) return (-1);
759 else if (ba->end > bb->end) return (+1);
760
761 /* They're equal. This shouldn't be possible either. */
762 return (0);
763 }
764
765 static double bad_block_delay = 0.0, good_block_delay = 0.0;
766 /* delay parameters for performance testing */
767
768 static ssize_t read_sectors(secaddr pos, void *buf, secaddr want)
769 /* Try to read WANT sectors from the input, starting with sector POS,
770 * and write the contents to BUF. Return the number of /whole
771 * sectors/ read; this will be 0 at end-of-file (though that
772 * shouldn't happen). The returned length will be smaller than WANT
773 * only if end-of-file or a system error prevents reading further.
774 * Returns -1 on a system error if that prevented us from reading
775 * anything at all.
776 *
777 * This function is where the fake bad-blocks list is handled.
778 */
779 {
780 ssize_t n, done;
781 size_t lo, mid, hi;
782 int fakeerr = 0;
783 struct badblock *bad, *best;
784 unsigned char *p = buf;
785
786 /* See whether the requested range intersects a bad-blocks range. */
787 if (badblocks.n) {
788 /* Since the list is sorted, we use a binary search. We're looking for
789 * the earliest-starting range which /ends after/ POS. If this starts
790 * /at or before/ POS, then POS itself is a bad sector, and we should
791 * pretend an I/O error; otherwise, if the bad range /starts/ somewhere
792 * in the range we're trying to read then we must pretend a short read;
793 * and otherwise there's nothing to do.
794 */
795
796 /* Throughout, `best' points to the earliest-starting range we've found
797 * which (starts and) finishes after POS. Ranges with indices below LO
798 * end too early to be interesting; similarly, ranges with indices HI or
799 * above start later than POS. If we find a range which actually covers
800 * POS exactly then we'll stop early.
801 */
802 best = 0; lo = 0; hi = badblocks.n;
803 #ifdef DEBUG
804 progress_clear(&progress);
805 printf(";; searching badblocks for %"PRIuSEC" .. %"PRIuSEC"\n",
806 pos, pos + want);
807 #endif
808 while (lo < hi) {
809 /* Standard binary-search loop: we continue until the pointers
810 * converge.
811 */
812
813 /* Try the midpoint between the two bounds. */
814 mid = lo + (hi - lo)/2; bad = &badblocks.v[mid];
815 #ifdef DEBUG
816 printf(";; try %zu (%"PRIuSEC" .. %"PRIuSEC")... ",
817 mid, bad->start, bad->end);
818 #endif
819
820 /* Follow our invariant. If the range starts strictly after POS, then
821 * it's too late to overlap, so bring down HI to cover it; but it must
822 * be closer than any previous block we've found, so remember it in
823 * `best'. Similarly, if the range ends /at or before/ POS then it
824 * stops too early, so bring up LO to cover it (but otherwise forget
825 * about it because it can't affect what we're doing).
826 *
827 * If we get a match then we stop immediately and fake a bad block.
828 */
829 if (pos < bad->start) { D( printf("high\n"); ) best = bad; hi = mid; }
830 else if (pos >= bad->end) { D( printf("low\n"); ) lo = mid + 1; }
831 else {
832 D( printf("match!\n"); )
833 errno = EIO; sit(bad_block_delay); return (-1);
834 }
835 }
836
837 /* We're done. Check to see whether the bad range starts early enough.
838 * If so, remember that we're simulating an error, apply the delay, and
839 * bamboozle the rest of the code into performing a short read.
840 */
841 #ifdef DEBUG
842 if (best)
843 printf(";; next is %"PRIuSEC" .. %"PRIuSEC"\n",
844 best->start, best->end);
845 #endif
846 if (best && pos + want > best->start)
847 { want = best->start - pos; fakeerr = EIO; sit(bad_block_delay); }
848 }
849
850 /* Try to read stuff into the buffer until we find a reason why we can't
851 * continue. Obviously we need to keep track of how much stuff we've read
852 * on previous iterations.
853 */
854 done = 0; errno = 0;
855 while (want) {
856
857 /* Read from the current file's input source. If that's a scrambled
858 * video file, then use `libdvdread'; if it's the `raw' file, then go to
859 * the block device; if it's nothing at all, then fill with zeros.
860 * Always force a seek to the right place, in case things got messed up
861 * by some previous error.
862 */
863 if (vob)
864 { errno = 0; n = DVDReadBlocks(vob, pos - file->start, want, p); }
865 else if (file) {
866 if (lseek(dvdfd, (off_t)pos*SECTORSZ, SEEK_SET) < 0)
867 bail_syserr(errno, "failed to seek to sector %"PRIuSEC"", pos);
868 errno = 0; n = read(dvdfd, p, want*SECTORSZ);
869 if (n >= 0) n /= SECTORSZ;
870 } else {
871 memset(p, 0, want*SECTORSZ);
872 n = want;
873 }
874
875 /* If we read some stuff then update the buffer pointer and lengths. If
876 * we hit end-of-file then stop. If we hit a bad sector then maybe make
877 * a note of it in the bad-sector log. On any other kind of error, just
878 * stop.
879 */
880 if (n > 0) { done += n; pos += n; p += n*SECTORSZ; want -= n; }
881 else if (!n) break;
882 else if (errno == EIO && errfile) {
883 open_file_on_demand(errfile, &errfp, "bad-sector error log");
884 fprintf(errfp, "%"PRIuSEC" %"PRIuSEC"\n", pos, pos + 1);
885 check_write(errfp, "bad-sector error log");
886 break;
887 } else if (errno != EINTR) break;
888 }
889
890 /* We made it. If we saved up a fake error, and there wasn't a real error
891 * (which should obviously take priority) then present the fake error to
892 * the caller. If there wasn't an error, then everything must have been
893 * good so impose the good-block delay -- note that a bad-block delay will
894 * already have been imposed above. Finally, return the accumulated count
895 * of sectors successfully read, or report the end-of-file or error
896 * condition as applicable.
897 */
898 if (fakeerr && !errno) errno = fakeerr;
899 else if (done > 0 && good_block_delay) sit(done*good_block_delay);
900 return (!done && errno ? -1 : done);
901 }
902
903 /*----- Tracking machinery for the bad-sector algorithm -------------------*
904 *
905 * While we're probing around trying to find the end of the bad region, we'll
906 * have read some good data. We want to try to keep as much good data as we
907 * can, and avoid re-reading it because (a) it's pointless I/O work, but more
908 * importantly (b) it might not work the second time. The machinery here
909 * is for making this work properly.
910 *
911 * There are two parts to this which don't really intersect, but for
912 * convenience the tracking information for them is kept in the same
913 * `recoverybuf' structure.
914 *
915 * * The `short-range' machinery keeps track of a contiguous region of good
916 * data stored in the caller's buffer.
917 *
918 * * The `long-range' machinery keeps track of a contiguous region of good
919 * data that's beyond the range of the buffer.
920 */
921
922 struct recoverybuf {
923 /* Information used to keep track of where good and bad sectors are
924 * while we're trying to find the end of a region of bad sectors.
925 */
926
927 /* Short-range buffer tracking. */
928 unsigned char *buf; /* pointer to the actual buffer */
929 secaddr sz; /* size of the buffer in sectors */
930 secaddr pos; /* sector address corresponding to
931 * the start of the buffer */
932 secaddr start, end; /* bounds of the live region within
933 * the buffer, as offsets in
934 * sectors from the buffer start */
935
936 /* Long-range tracking. */
937 secaddr good_lo, good_hi; /* known-good region, as absolute
938 * sector addresses */
939 };
940
941 static void rearrange_sectors(struct recoverybuf *r,
942 secaddr dest, secaddr src, secaddr len)
943 /* Shuffle data about in R's buffer. Specifically, move LEN sectors
944 * starting SRC sectors from the start of the buffer to a new
945 * position DEST sectors from the start.
946 *
947 * Unsurprisingly, this is a trivial wrapper around `memmove', with
948 * some range checking thrown in; it's only used by `recovery_read_-
949 * buffer' and `find_good_sector' below.
950 */
951 {
952 assert(dest + len <= r->sz); assert(src + len <= r->sz);
953 memmove(r->buf + dest*SECTORSZ, r->buf + src*SECTORSZ, len*SECTORSZ);
954 }
955
956 #ifdef DEBUG
957 static PRINTF_LIKE(2, 3)
958 void show_recovery_buffer_map(const struct recoverybuf *r,
959 const char *what, ...)
960 /* Dump a simple visualization of the short-range tracking state. */
961 {
962 va_list ap;
963
964 va_start(ap, what);
965 progress_clear(&progress);
966 printf(";; recovery buffer (");
967 vprintf(what, ap);
968 printf("): "
969 "(%"PRIuSEC") ..%"PRIuSEC".. "
970 "[%"PRIuSEC" ..%"PRIuSEC".. %"PRIuSEC"] "
971 "..%"PRIuSEC".. (%"PRIuSEC")\n",
972 r->pos, r->start,
973 r->pos + r->start, r->end - r->start, r->pos + r->end,
974 r->sz - r->end, r->pos + r->sz);
975 va_end(ap);
976 assert(r->start <= r->end);
977 assert(r->end <= r->sz);
978 }
979 #endif
980
981 static ssize_t recovery_read_sectors(struct recoverybuf *r,
982 secaddr pos, secaddr off, secaddr want)
983 /* Try to read WANT sectors starting at sector address POS from the
984 * current file into R's buffer, at offset OFF sectors from the start
985 * of the buffer. Return the number of sectors read, zero if at end
986 * of file, or -1 in the event of a system error.
987 *
988 * This is a trivial wrapper around `read_sectors' with some
989 * additional range checking, used only by `recovery_read_buffer'
990 * below.
991 */
992 {
993 ssize_t n;
994
995 assert(off <= r->sz); assert(want <= r->sz - off);
996 assert(pos == r->pos + off);
997 n = read_sectors(pos, r->buf + off*SECTORSZ, want);
998 return (n);
999 }
1000
1001 static ssize_t recovery_read_buffer(struct recoverybuf *r,
1002 secaddr pos, secaddr want)
1003 /* Try to read WANT sectors, starting at sector address POS, from the
1004 * current file into the buffer R, returning a count of the number of
1005 * sectors read, or 0 if at end of file, or -1 in the case of a
1006 * system error, as for `read_sectors'. The data will end up
1007 * /somewhere/ in the buffer, but not necessarily at the start.
1008 */
1009 {
1010 secaddr diff, pp, nn;
1011 ssize_t n;
1012
1013 /* This is the main piece of the short-range tracking machinery. It's
1014 * rather complicated, so hold on tight. (It's much simpler -- and less
1015 * broken -- than earlier versions were, though.)
1016 */
1017
1018 #ifdef DEBUG
1019 progress_clear(&progress);
1020 show_recovery_buffer_map(r, "begin(%"PRIuSEC", %"PRIuSEC")", pos, want);
1021 #endif
1022
1023 /* The first order of business is to make space in the buffer for this new
1024 * data. We therefore start with a case analysis.
1025 */
1026 if (pos < r->pos) {
1027 /* The new position is before the current start of the buffer, so we have
1028 * no choice but to decrease the buffer position, which will involve
1029 * shifting the existing material upwards.
1030 */
1031
1032 /* Determine how far up we'll need to shift. */
1033 diff = r->pos - pos;
1034
1035 if (r->start + diff >= r->sz) {
1036 /* The material that's currently in the buffer would be completely
1037 * shifted off the end, so we have no choice but to discard it
1038 * completely.
1039 */
1040
1041 r->pos = pos; r->start = r->end = 0;
1042 #ifdef DEBUG
1043 show_recovery_buffer_map(r, "cleared; shift up by %"PRIuSEC"", diff);
1044 #endif
1045 } else {
1046 /* Some of the material in the buffer will still be there. We might
1047 * lose some stuff off the end: start by throwing that away, and then
1048 * whatever's left can be moved easily.
1049 */
1050
1051 if (r->end + diff > r->sz) r->end = r->sz - diff;
1052 rearrange_sectors(r, r->start + diff, r->start, r->end - r->start);
1053 r->pos -= diff; r->start += diff; r->end += diff;
1054 #ifdef DEBUG
1055 show_recovery_buffer_map(r, "shifted up by %"PRIuSEC"", diff);
1056 #endif
1057 }
1058 } else if (pos > r->pos + r->end) {
1059 /* The new position is strictly beyond the old region. We /could/ maybe
1060 * keep this material, but it turns out to be better not to. To keep it,
1061 * we'd have to also read the stuff that's in between the end of the old
1062 * region and the start of the new one, and that might contain bad
1063 * sectors which the caller is specifically trying to skip. We just
1064 * discard the entire region here so as not to subvert the caller's
1065 * optimizations.
1066 */
1067
1068 r->pos = pos; r->start = r->end = 0;
1069 #ifdef DEBUG
1070 show_recovery_buffer_map(r, "cleared; beyond previous region");
1071 #endif
1072 } else if (pos + want > r->pos + r->sz) {
1073 /* The requested range of sectors extends beyond the region currently
1074 * covered by the buffer. We must therefore increase the buffer position
1075 * which will involve shifting the existing material downwards.
1076 */
1077
1078 /* Determine how far down we'll need to shift. */
1079 diff = (pos + want) - (r->pos + r->sz);
1080
1081 if (r->end <= diff) {
1082 /* The material that's currently in the buffer would be completely
1083 * shifted off the beginning, so we have no choice but to discard it
1084 * completely.
1085 */
1086
1087 r->pos = pos; r->start = r->end = 0;
1088 #ifdef DEBUG
1089 show_recovery_buffer_map(r, "cleared; shift down by %"PRIuSEC"", diff);
1090 #endif
1091 } else {
1092 /* Some of the material in the buffer will still be there. We might
1093 * lose some stuff off the beginning: start by throwing that away, and
1094 * then whatever's left can be moved easily.
1095 */
1096
1097 if (r->start < diff) r->start = diff;
1098 rearrange_sectors(r, r->start - diff, r->start, r->end - r->start);
1099 r->pos += diff; r->start -= diff; r->end -= diff;
1100 #ifdef DEBUG
1101 show_recovery_buffer_map(r, "shifted down by %"PRIuSEC"", diff);
1102 #endif
1103 }
1104 }
1105
1106 /* We now have space in the buffer in which to put the new material.
1107 * However, the buffer already contains some stuff. We may need to read
1108 * some data from the input file into an area before the existing
1109 * material, or into an area following the existing stuff, or both, or
1110 * (possibly) neither.
1111 */
1112
1113 if (pos < r->pos + r->start) {
1114 /* The requested position is before the current good material, so we'll
1115 * need to read some stuff there.
1116 */
1117
1118 /* Determine the place in the buffer where this data will be placed, and
1119 * how long it will need to be. Try to extend it all the way to the
1120 * existing region even if this is more than the caller wants, because it
1121 * will mean that we can join it onto the existing region rather than
1122 * having to decide which of two disconnected parts to throw away.
1123 */
1124 pp = pos - r->pos; nn = r->start - pp;
1125
1126 /* Read the data. */
1127 #ifdef DEBUG
1128 printf(";; read low (%"PRIuSEC"@%"PRIuSEC", %"PRIuSEC")", pos, pp, nn);
1129 fflush(stdout);
1130 #endif
1131 n = recovery_read_sectors(r, pos, pp, nn);
1132 #ifdef DEBUG
1133 printf(" -> %zd\n", n);
1134 #endif
1135
1136 /* See whether it worked. */
1137 if (n != nn) {
1138 /* We didn't get everything we wanted. */
1139
1140 /* If we got more than the caller asked for then technically this is
1141 * good; but there must be some problem lurking up ahead, and the
1142 * caller will want to skip past that. So we don't update the tracking
1143 * information to reflect our new data; even though this /looks/ like a
1144 * success, it isn't really.
1145 */
1146 if (n >= 0 && n > want) n = want;
1147
1148 /* We're done. */
1149 goto end;
1150 }
1151
1152 /* Extend the region to include the new piece. */
1153 r->start = pp;
1154 #ifdef DEBUG
1155 show_recovery_buffer_map(r, "joined new region");
1156 #endif
1157 }
1158
1159 if (pos + want > r->pos + r->end) {
1160 /* The requested region extends beyond the current region, so we'll need
1161 * to read some stuff there.
1162 */
1163
1164 /* Determine the place in the buffer where this data will be placed, and
1165 * how long it will need to be. Note that pos <= r->pos + r->end, so
1166 * there won't be a gap between the old good region and the material
1167 * we're trying to read.
1168 */
1169 pp = r->end; nn = (pos + want) - (r->pos + r->end);
1170
1171 /* Read the data. */
1172 #ifdef DEBUG
1173 printf(";; read high (%"PRIuSEC"@%"PRIuSEC", %"PRIuSEC")",
1174 r->pos + pp, pp, nn);
1175 fflush(stdout);
1176 #endif
1177 n = recovery_read_sectors(r, r->pos + pp, pp, nn);
1178 #ifdef DEBUG
1179 printf(" -> %zd\n", n);
1180 #endif
1181
1182 /* See whether it worked. */
1183 if (n > 0) {
1184 /* We read something, so add it onto the existing region. */
1185
1186 r->end += n;
1187 #ifdef DEBUG
1188 show_recovery_buffer_map(r, "joined new region");
1189 #endif
1190 }
1191 }
1192
1193 /* Work out the return value to pass back to the caller. The newly read
1194 * material has been merged with the existing region (the case where we
1195 * didn't manage to join the two together has been handled already), so we
1196 * can easily work out how much stuff is available by looking at the
1197 * tracking information. It only remains to bound the region size by the
1198 * requested length.
1199 */
1200 n = r->pos + r->end - pos;
1201 if (!n && want) n = -1;
1202 else if (n > want) n = want;
1203
1204 end:
1205 /* Done. */
1206 #ifdef DEBUG
1207 show_recovery_buffer_map(r, "done; return %zd", n);
1208 #endif
1209 return (n);
1210 }
1211
1212 static ssize_t recovery_read_multiple(struct recoverybuf *r,
1213 secaddr pos, secaddr want)
1214 /* Try to read WANT sectors, starting at sector address POS, from the
1215 * current file, returning a count of the number of sectors read, or
1216 * 0 if at end of file, or -1 in the case of a system error, as for
1217 * `read_sectors'. Some data might end up in R's buffer, but if WANT
1218 * is larger than R->sz then a lot will be just thrown away.
1219 *
1220 * This is only used by `recovery_read' below.
1221 */
1222 {
1223 ssize_t n;
1224 secaddr skip, want0 = want;
1225
1226 /* If the request is larger than the buffer, then we start at the /end/ and
1227 * work backwards. If we encounter a bad sector while we're doing this,
1228 * then we report a short read as far as the bad sector: the idea is to
1229 * find the /latest/ bad sector we can. The caller will want to skip past
1230 * the bad sector, so the fact that we implicitly lied about the earlier
1231 * data as being `good' won't matter.
1232 */
1233
1234 while (want > r->sz) {
1235 /* There's (strictly!) more than a buffer's worth. Fill the buffer with
1236 * stuff and reduce the requested size.
1237 */
1238
1239 skip = want - r->sz;
1240 n = recovery_read_buffer(r, pos + skip, r->sz);
1241
1242 /* If it failed, then we always return a positive result, because we're
1243 * pretending we managed to read all of the (nonempty) preceding
1244 * material.
1245 */
1246 if (n < r->sz) return (skip + (n >= 0 ? n : 0));
1247
1248 /* Cross off a buffer's worth and go around again. */
1249 want -= r->sz;
1250 }
1251
1252 /* Read the last piece. If it fails or comes up short, then we don't need
1253 * to mess with the return code this time.
1254 */
1255 n = recovery_read_buffer(r, pos, want);
1256 if (n < 0 || n < want) return (n);
1257
1258 /* It all worked. Return the full original amount requested. */
1259 return (want0);
1260 }
1261
1262 static ssize_t recovery_read(struct recoverybuf *r,
1263 secaddr pos, secaddr want)
1264 /* Try to read WANT sectors, starting at sector address POS, from the
1265 * current file, returning a count of the number of
1266 * sectors read, or 0 if at end of file, or -1 in the case of a
1267 * system error, as for `read_sectors'. Some data might end up in
1268 * R's buffer, but if WANT is larger than R->sz then a lot will be
1269 * just thrown away.
1270 */
1271 {
1272 secaddr lo = pos, hi = pos + want, span; /* calculate the request bounds */
1273 ssize_t n;
1274
1275 /* This is the main piece of the long-range tracking machinery.
1276 * Fortunately, it's much simpler than the short-range stuff that we've
1277 * just dealt with.
1278 */
1279
1280 if (hi < r->good_lo || lo > r->good_hi) {
1281 /* The requested region doesn't abut or overlap with the existing good
1282 * region, so it's no good to us. Just read the requested region; if it
1283 * worked at all, then replace the current known-good region with the
1284 * region that was successfully read.
1285 */
1286
1287 n = recovery_read_multiple(r, lo, hi - lo);
1288 if (n > 0) { r->good_lo = lo; r->good_hi = lo + n; }
1289 return (n);
1290 }
1291
1292 if (hi > r->good_hi) {
1293 /* The requested region ends later than the current known-good region.
1294 * Read the missing piece. We're doing this first so that we find later
1295 * bad sectors.
1296 */
1297
1298 span = hi - r->good_hi;
1299 n = recovery_read_multiple(r, r->good_hi, span);
1300
1301 /* If we read anything at all, then extend the known-good region. */
1302 if (n > 0) r->good_hi += n;
1303
1304 /* If we didn't read everything we wanted, then report this as a short
1305 * read (so including some nonempty portion of the known-good region).
1306 */
1307 if (n < 0 || n < span) return (r->good_hi - lo);
1308 }
1309
1310 if (lo < r->good_lo) {
1311 /* The requested region begins earlier than the known-good region. */
1312
1313 span = r->good_lo - lo;
1314 n = recovery_read_multiple(r, lo, span);
1315
1316 /* If we read everything we wanted, then extend the known-good region.
1317 * Otherwise, we're better off keeping the stuff after the bad block.
1318 */
1319 if (n == span) r->good_lo = lo;
1320 else return (n);
1321 }
1322
1323 /* Everything read OK, and we've extended the known-good region to cover
1324 * the requested region. So return an appropriate code by consulting the
1325 * new known-good region.
1326 */
1327 n = r->good_hi - pos; if (n > want) n = want;
1328 if (!n) { errno = EIO; n = -1; }
1329 return (n);
1330 }
1331
1332 /*----- Skipping past regions of bad sectors ------------------------------*/
1333
1334 static double clear_factor = 0.5; /* proportion of clear sectors needed */
1335 static secaddr clear_min = 1, clear_max = SECLIMIT; /* absolute bounds */
1336 static double step_factor = 2.0; /* factor for how far to look ahead */
1337 static secaddr step_min = 1, step_max = 0; /* and absolute bounds */
1338
1339 static void recovered(secaddr bad_lo, secaddr bad_hi)
1340 /* Do all of the things that are necessary when a region of bad
1341 * sectors has been found between BAD_LO (inclusive) and BAD_HI
1342 * (exclusive).
1343 */
1344 {
1345 char fn[MAXFNSZ];
1346
1347 /* Remove the progress display temporarily. */
1348 progress_clear(&progress);
1349
1350 /* Print a message into the permanent output log. */
1351 if (!file || id_kind(file->id) == RAW)
1352 moan("skipping %"PRIuSEC" bad sectors (%"PRIuSEC" .. %"PRIuSEC")",
1353 bad_hi - bad_lo, bad_lo, bad_hi);
1354 else {
1355 store_filename(fn, file->id);
1356 moan("skipping %"PRIuSEC" bad sectors (%"PRIuSEC" .. %"PRIuSEC"; "
1357 "`%s' %"PRIuSEC" .. %"PRIuSEC" of %"PRIuSEC")",
1358 bad_hi - bad_lo, bad_lo, bad_hi,
1359 fn, bad_lo - file->start, bad_hi - file->start,
1360 file->end - file->start);
1361 }
1362
1363 if (mapfile) {
1364 /* The user requested a map of the skipped regions, so write an entry. */
1365
1366 /* Open the file, if it's not open already. */
1367 open_file_on_demand(mapfile, &mapfp, "bad-sector region map");
1368
1369 /* Write the sector range. */
1370 fprintf(mapfp, "%"PRIuSEC" %"PRIuSEC" # %"PRIuSEC" sectors",
1371 bad_lo, bad_hi, bad_hi - bad_lo);
1372
1373 /* If we're currently reading from a file then note down the position in
1374 * the file in the comment. (Intentional bad sectors are frequently at
1375 * the start and end of titles, so this helps a reader to decide how
1376 * concerned to be.)
1377 */
1378 if (file && id_kind(file->id) != RAW)
1379 fprintf(mapfp, "; `%s' %"PRIuSEC" .. %"PRIuSEC" of %"PRIuSEC"",
1380 fn, bad_lo - file->start, bad_hi - file->start,
1381 file->end - file->start);
1382
1383 /* Done. Flush the output to the file so that we don't lose it if we
1384 * crash!
1385 */
1386 fputc('\n', mapfp);
1387 check_write(mapfp, "bad-sector region map");
1388 }
1389
1390 /* Adjust the position in our output file to skip past the bad region.
1391 * (This avoids overwriting anything that was there already, which is
1392 * almost certainly less wrong than anything we could come up with here.)
1393 */
1394 if (lseek(outfd, (off_t)(bad_hi - bad_lo)*SECTORSZ, SEEK_CUR) < 0)
1395 bail_syserr(errno, "failed to seek past bad sectors");
1396
1397 /* Remove our notice now that we're no longer messing about with bad
1398 * sectors, and reinstate the progress display.
1399 */
1400 progress_removeitem(&progress, &badblock_progress);
1401 progress_update(&progress);
1402 }
1403
1404 static secaddr run_length_wanted(secaddr pos, secaddr badlen, secaddr end)
1405 /* Return the number of good sectors that we want to see before
1406 * we're happy, given that we're about to try to read sector POS,
1407 * which is BADLEN sectors beyond where we found the first bad
1408 * sector, and the current region ends at sector END (i.e., this is
1409 * where the next event occurs).
1410 */
1411 {
1412 secaddr want;
1413
1414 /* Apply the factor to BADLEN to get an initial length. */
1415 want = ceil(clear_factor*badlen);
1416
1417 /* Apply the user-configurable lower bound. */
1418 if (want < clear_min) want = clear_min;
1419
1420 /* Cap this with the end of the region. */
1421 if (want > end - pos) want = end - pos;
1422
1423 /* And apply the user-configurable upper bound. */
1424 if (clear_max && want > clear_max) want = clear_max;
1425
1426 /* We're done. */
1427 return (want);
1428 }
1429
1430 static void report_bad_blocks_progress(secaddr bad_hi, int err)
1431 /* Report progress while we're trying to work past a region of bad
1432 * sectors. We're about to investigate BAD_HI, and the most recent
1433 * error was ERR.
1434 */
1435 { bad_err = err; report_progress(bad_hi); }
1436
1437 static ssize_t find_good_sector(secaddr *pos_inout, secaddr end,
1438 unsigned char *buf, secaddr sz)
1439 /* Work out a place to resume after finding a bad sector. The
1440 * current position, where we found a problem, is in *POS_INOUT. The
1441 * current input region goes up up sector END (i.e., this is where
1442 * the next event occurs). The caller's buffer is at BUF, and can
1443 * hold SZ sectors. On exit, update *POS_INOUT to be the start of a
1444 * region of /good/ sector that we decided was worth exploring, and
1445 * return the number of sectors we've already read at that position
1446 * and left at the start of the buffer. (This number may be zero,
1447 * depending on how things work out. That doesn't mean that we hit
1448 * end-of-file.)
1449 *
1450 * Altough the return value is `ssize_t', this is only to fit in with
1451 * other read functions; a negative return is not actually possible.
1452 */
1453 {
1454 secaddr pos = *pos_inout, bad_lo, bad_hi, good, step, want;
1455 struct recoverybuf r;
1456 ssize_t n;
1457
1458 /* Initial setup. Save the initial state and establish the bad-blocks
1459 * progress notice.
1460 */
1461 bad_start = pos; bad_err = errno;
1462 badblock_progress.render = render_badblock_progress;
1463 progress_additem(&progress, &badblock_progress);
1464
1465 /* First, retry the `bad' sector a few times. Sometimes, with damaged
1466 * discs, this actually works. We'll try to read a full buffer, but we're
1467 * not expecting much.
1468 */
1469 want = sz; if (want > end - pos) want = end - pos;
1470 for (retry = 0; retry < max_retries; retry++) {
1471
1472 /* Show the progress report. */
1473 report_bad_blocks_progress(pos, errno);
1474
1475 /* Try reading stuff. */
1476 n = read_sectors(pos, buf, want);
1477 #ifdef DEBUG
1478 progress_clear(&progress);
1479 printf(";; [retry] try reading %"PRIuSEC" .. %"PRIuSEC" -> %zd\n",
1480 pos, pos + want, n);
1481 #endif
1482
1483 if (n > 0) {
1484 /* We won! Remove the progress display, and leave a permanent message
1485 * to inform the user what happened.
1486 */
1487 progress_clear(&progress);
1488 moan("sector %"PRIuSEC" read ok after retry", pos);
1489 progress_removeitem(&progress, &badblock_progress);
1490 progress_update(&progress);
1491 return (n);
1492 }
1493 }
1494
1495 /* We're going to have to be more creative. Set up the tracking state. */
1496 r.buf = buf; r.sz = sz; r.pos = r.start = r.end = 0;
1497 r.good_lo = r.good_hi = 0;
1498
1499 /* Set up the region bound. We know the bad area starts at POS, and that
1500 * it covers at least one sector.
1501 */
1502 bad_lo = pos; bad_hi = pos + 1;
1503
1504 /* Second major step: try to find somewhere on the other side of the bad
1505 * region.
1506 */
1507 for (;;) {
1508 #ifdef DEBUG
1509 progress_clear(&progress);
1510 printf(";; bounding bad-block region: "
1511 "%"PRIuSEC" ..%"PRIuSEC".. %"PRIuSEC"\n",
1512 bad_lo, bad_hi - bad_lo, bad_hi);
1513 #endif
1514
1515 /* If our upper bound has reached all the way to the end of the input
1516 * region then there's nowhere to recover to. Set the next position to
1517 * the end of the region and return.
1518 */
1519 if (bad_hi >= end) {
1520 progress_clear(&progress);
1521 moan("giving up on this extent");
1522 recovered(bad_lo, end); *pos_inout = end;
1523 return (0);
1524 }
1525
1526 /* Give a progress update. */
1527 report_bad_blocks_progress(bad_hi, errno);
1528
1529 /* Choose a new place to look. Apply the step factor to the size of the
1530 * current gap between the start and end of the bad region, and then
1531 * bound by the user bounds and the input-region end.
1532 *
1533 * We make progress because `step' is at least 1: `step_min' is at least
1534 * 1, and bad_hi < end or we'd have already bailed.
1535 */
1536 step = (step_factor - 1)*(bad_hi - bad_lo);
1537 if (step < step_min) step = step_min;
1538 if (step_max && step > step_max) step = step_max;
1539 step += bad_hi - bad_lo;
1540 if (step > end - bad_lo) step = end - bad_lo;
1541
1542 /* Now we look at the last sector of the new interval we've just marked
1543 * out.
1544 */
1545 pos = bad_lo + step - 1;
1546 want = run_length_wanted(pos, step, end);
1547 n = recovery_read(&r, pos, want);
1548 #ifdef DEBUG
1549 printf(";; [bound] try reading %"PRIuSEC" .. %"PRIuSEC" -> %zd\n",
1550 pos, pos + want, n);
1551 #endif
1552
1553 /* If everything went OK then we're done with this phase. */
1554 if (n == want) break;
1555
1556 /* If it failed then extend the bad region to cover (the end of) the bad
1557 * sector which terminated the run, and go around again.
1558 */
1559 if (n < 0) n = 0;
1560 bad_hi = pos + n + 1;
1561 }
1562
1563 /* Third major step: identify exactly where the bad region ends. This is
1564 * a binary search.
1565 */
1566 good = pos;
1567 while (good > bad_hi) {
1568 #ifdef DEBUG
1569 progress_clear(&progress);
1570 printf(";; limiting bad-block region: "
1571 "%"PRIuSEC" ..%"PRIuSEC".. %"PRIuSEC" ..%"PRIuSEC".. %"PRIuSEC"\n",
1572 bad_lo, bad_hi - bad_lo, bad_hi, good - bad_hi, good);
1573 #endif
1574
1575 /* Update the progress report. */
1576 report_bad_blocks_progress(bad_hi, errno);
1577
1578 /* Pick a new place to try. */
1579 pos = bad_hi + (good - bad_hi)/2; step = pos - bad_lo;
1580 want = run_length_wanted(pos, step, end);
1581
1582 /* Try reading. */
1583 n = recovery_read(&r, pos, want);
1584 #ifdef DEBUG
1585 printf(";; [limit] try reading %"PRIuSEC" .. %"PRIuSEC" -> %zd\n",
1586 pos, pos + want, n);
1587 #endif
1588
1589 /* If that worked -- i.e., we got all the data we wanted -- then bring
1590 * down the `good' bound. If it failed, then bring up `bad_hi' to cover
1591 * the bad sector which terminated our read attempt.
1592 */
1593 if (n < 0) n = 0;
1594 if (n == want) good = pos;
1595 else bad_hi = pos + n + 1;
1596 }
1597
1598 /* We're done. It's time to tidy up.
1599 *
1600 * One subtle point: it's possible that, as a result of retrying previous
1601 * bad blocks, that we ended up with bad_hi > good, so it's important that
1602 * we make a consistent choice between the two. I've gone with `good'
1603 * because (a) this gives us more of the original data from the disc and
1604 * (b) hopefully any marginal sectors are now in our buffer
1605 */
1606 recovered(bad_lo, good); *pos_inout = good;
1607
1608 /* Figure out how much data we can return to the caller from our buffer. */
1609 if (good < r.pos + r.start || r.pos + r.end <= good) {
1610 /* Our new position is outside of the region covered by the short-range
1611 * tracking, so there's nothing to return.
1612 */
1613
1614 n = 0;
1615 } else {
1616 /* The new position is covered, so shuffle the data to the start of the
1617 * buffer and return as much as we can.
1618 */
1619
1620 n = r.pos + r.end - good;
1621 rearrange_sectors(&r, 0, good - r.pos, n);
1622 }
1623
1624 /* We're done. */
1625 #ifdef DEBUG
1626 show_recovery_buffer_map(&r, "returning %zd good sectors at %"PRIuSEC"",
1627 n, good);
1628 #endif
1629 return (n);
1630 }
1631
1632 /*----- Copying data from a single input file -----------------------------*/
1633
1634 static void emit(secaddr start, secaddr end)
1635 /* Copy sectors with absolute addresses from START (inclusive) to END
1636 * (exclusive) to the output. The entire input region comes from the
1637 * same source, already established as `file'.
1638 */
1639 {
1640 #define BUFSECTORS 512 /* this is a megabyte */
1641
1642 int least;
1643 unsigned char buf[BUFSECTORS*SECTORSZ];
1644 secaddr pos;
1645 size_t want;
1646 ssize_t n;
1647 static int first_time = 1;
1648 #ifdef DEBUG
1649 struct file *f;
1650 char fn[MAXFNSZ];
1651 int act = -1;
1652 int i;
1653 #endif
1654
1655 /* Choose an active file through which to read the source contents. We're
1656 * guaranteed that this file will do for the entire input region. We
1657 * choose the active file with the smallest index. The virtual `raw' file
1658 * which represents the underlying block device has the largest index, so
1659 * we'll always use a `.VOB' file if one is available. Looking at the
1660 * protocol suggests that the host and drive identify the per-title CSS key
1661 * by the start sector address of the `.VOB' file, so coincident files must
1662 * all use the same key. I've not encountered properly overlapping files
1663 * in the wild.
1664 */
1665 least = least_live();
1666 #ifdef DEBUG
1667 printf(";; %8"PRIuSEC" .. %"PRIuSEC"\n", start, end);
1668 for (i = 0; i < filetab.n; i++) {
1669 if (!livep(i)) continue;
1670 if (act == -1) act = i;
1671 f = &filetab.v[i]; store_filename(fn, f->id);
1672 printf(";;\t\t%8"PRIuSEC" .. %-8"PRIuSEC" %s\n",
1673 start - f->start, end - f->start, fn);
1674 }
1675 if (act == -1) printf(";;\t\t#<no live source>\n");
1676 assert(act == least);
1677 #endif
1678
1679 /* Set the global variables up for reading from the file we decided on.
1680 * These will be primarily used by `read_sectors' and `update_progress'.
1681 */
1682 if (least == -1) {
1683 /* There's nothing at all. This can happen because the kernel reported
1684 * the wrong block-device size for some reason but the filesystem has
1685 * identified files which start beyond the reported size, leaving a gap.
1686 */
1687
1688 file = 0; vob = 0;
1689 } else {
1690 /* There's a (possibly) virtual file. */
1691
1692 file = &filetab.v[least];
1693 switch (id_kind(file->id)) {
1694
1695 case RAW:
1696 /* It's the raw device. Clear `vob' to prompt `read_sectors' to read
1697 * directly from `dvdfd'.
1698 */
1699
1700 vob = 0;
1701 break;
1702
1703 case VOB:
1704 /* It's a `.VOB' file. We read these through `libdvdread', which
1705 * handles CSS unscrambling for us.
1706 */
1707
1708 /* The first time we open a `.VOB' file, `libdvdread' wants to spray
1709 * a bunch of information about how it's getting on cracking the
1710 * title keys. This will interfere with the progress display, so
1711 * preemptively hide the display.
1712 */
1713 if (first_time) { progress_clear(&progress); first_time = 0; }
1714
1715 /* Open the `.VOB' file. */
1716 vob = DVDOpenFile(dvd, id_title(file->id),
1717 id_part(file->id)
1718 ? DVD_READ_TITLE_VOBS
1719 : DVD_READ_MENU_VOBS);
1720 if (!vob)
1721 bail("failed to open %s %u",
1722 id_part(file->id) ? "title" : "menu",
1723 id_title(file->id));
1724 break;
1725
1726 default:
1727 /* Some other kind of thing; but there shouldn't be anything else in
1728 * the file table, so there's a bug.
1729 */
1730 abort();
1731
1732 }
1733 }
1734
1735 /* If we're not reading from the raw device then add an additional progress
1736 * bar for the current file. This isn't completely pointless: having a
1737 * ready visualization for whereabouts we are in a file is valuable when we
1738 * encounter bad blocks, because regions of intentional bad blocks near the
1739 * starts and and ends of VOBs are common on discs from annoying studios.
1740 */
1741 if (file && id_kind(file->id) != RAW) {
1742 file_progress.render = render_file_progress;
1743 progress_additem(&progress, &file_progress);
1744 }
1745
1746 /* Put the progress display back, if we took it away, and show the file
1747 * progress bar if we added one.
1748 */
1749 progress_update(&progress);
1750
1751 /* Read the input region and copy it to the disc. */
1752 pos = start;
1753 while (pos < end) {
1754
1755 /* Decide how much we want. Fill the buffer, unless there's not enough
1756 * input left.
1757 */
1758 want = end - pos; if (want > BUFSECTORS) want = BUFSECTORS;
1759
1760 /* Try to read the input. */
1761 n = read_sectors(pos, buf, want);
1762
1763 if (n <= 0) {
1764 /* It didn't work. Time to deploy the skipping-past-bad-blocks
1765 * machinery we worked so hard on. This will fill the buffer with
1766 * stuff and return a new count of how much it read.
1767 */
1768
1769 n = find_good_sector(&pos, end, buf, BUFSECTORS);
1770 }
1771 if (n > 0) {
1772 /* We made some progress. Write the stuff that we read to the output
1773 * file and update the position.
1774 */
1775
1776 carefully_write(outfd, buf, n*SECTORSZ); pos += n;
1777 }
1778
1779 /* Report our new progress. */
1780 report_progress(pos);
1781 }
1782
1783 /* Close the `libdvdread' file, if we opened one. */
1784 if (vob) { DVDCloseFile(vob); vob = 0; }
1785
1786 /* If we added a per-file progress bar, then take it away again. */
1787 if (file && id_kind(file->id) != RAW)
1788 progress_removeitem(&progress, &file_progress);
1789
1790 /* Update the progress display to report our glorious success. */
1791 progress_update(&progress);
1792
1793 #undef BUFSECTORS
1794 }
1795
1796 /*----- Main program ------------------------------------------------------*/
1797
1798 int main(int argc, char *argv[])
1799 {
1800 unsigned f = 0;
1801 const char *p;
1802 off_t volsz;
1803 secaddr pos;
1804 off_t off;
1805 secaddr start, end, last;
1806 const struct event *ev;
1807 const char *device, *outfile;
1808 struct badblock *bad;
1809 int opt, blksz;
1810 size_t i;
1811 FILE *fp;
1812 struct buf buf = BUF_INIT;
1813 struct timeval tv0, tv1;
1814 double t, rate, tot;
1815 const char *rateunit, *totunit;
1816 char timebuf[TIMESTRMAX], id_in[MAXIDSZ], id_out[MAXIDSZ];
1817 dvd_reader_t *dvd_out;
1818 #ifdef DEBUG
1819 const struct file *file;
1820 char fn[MAXFNSZ];
1821 #endif
1822
1823 #define f_bogus 1u
1824 #define f_continue 2u
1825 #define f_fixup 4u
1826 #define f_stats 8u
1827 #define f_checkid 16u
1828 #define f_retry 32u
1829 #define f_write 256u
1830
1831 set_prog(argv[0]);
1832
1833 /* First up, handle the command-line options. */
1834 for (;;) {
1835 opt = getopt(argc, argv, "hB:E:FR:X:b:cir:s"); if (opt < 0) break;
1836 switch (opt) {
1837
1838 /* `-h': Help. */
1839 case 'h': usage(stderr); exit(0);
1840
1841 /* `-B PARAM=VALUE[,...]': Setting internal parameters. */
1842 case 'B':
1843
1844 /* Set up a cursor into the parameter string. */
1845 p = optarg;
1846
1847 #define SKIP_PREFIX(s) \
1848 (STRNCMP(p, ==, s "=", sizeof(s)) && (p += sizeof(s), 1))
1849 /* If the text at P matches `S=' then advance P past that and
1850 * evaluate nonzero; otherwise evaluate zero.
1851 */
1852
1853 for (;;) {
1854
1855 if (SKIP_PREFIX("cf"))
1856 clear_factor = parse_float(&p, PNF_JUNK, 0, DBL_MAX,
1857 "clear factor");
1858
1859 else if (SKIP_PREFIX("cmin"))
1860 clear_min = parse_int(&p, PNF_JUNK, 1, SECLIMIT,
1861 "clear minimum");
1862
1863 else if (SKIP_PREFIX("cmax"))
1864 clear_max = parse_int(&p, PNF_JUNK, 1, SECLIMIT,
1865 "clear maximum");
1866
1867 else if (SKIP_PREFIX("sf"))
1868 step_factor = parse_float(&p, PNF_JUNK, 0, DBL_MAX,
1869 "step factor");
1870
1871 else if (SKIP_PREFIX("smin"))
1872 step_min = parse_int(&p, PNF_JUNK, 1, SECLIMIT - 1,
1873 "step minimum");
1874
1875 else if (SKIP_PREFIX("smax"))
1876 step_max = parse_int(&p, PNF_JUNK, 1, SECLIMIT - 1,
1877 "step maximum");
1878
1879 else if (SKIP_PREFIX("retry"))
1880 max_retries = parse_int(&p, PNF_JUNK, 0, INT_MAX, "retries");
1881
1882 else if (SKIP_PREFIX("alpha"))
1883 alpha = parse_float(&p, PNF_JUNK, 0, 1, "average decay factor");
1884
1885 else if (SKIP_PREFIX("_badwait"))
1886 bad_block_delay = parse_float(&p, PNF_JUNK, 0, DBL_MAX,
1887 "bad-block delay");
1888
1889 else if (SKIP_PREFIX("_blkwait"))
1890 good_block_delay = parse_float(&p, PNF_JUNK, 0, DBL_MAX,
1891 "good block delay");
1892
1893 else
1894 bail("unknown bad blocks parameter `%s'", p);
1895
1896 /* If we're now at the end of the string then we're done. */
1897 if (!*p) break;
1898
1899 /* We're not done yet, so there should now be a comma and another
1900 * parameter setting.
1901 */
1902 if (*p != ',') bail("unexpected junk in parameters");
1903 p++;
1904 }
1905
1906 #undef SKIP_PREFIX
1907 break;
1908
1909 /* `-E FILE' (undocumented): Log the bad sectors we encountered to
1910 * FILE.
1911 */
1912 case 'E': errfile = optarg; break;
1913
1914 /* `-F' (undocumented): Hack for fixing up images that were broken by
1915 * an old early-stop bug.
1916 */
1917 case 'F': f |= f_fixup; break;
1918
1919 /* `-R FILE': Read ranges to retry from FILE. Retry ranges are
1920 * converted into `EV_WRITE' and `EV_STOP' events.
1921 */
1922 case 'R':
1923 fp = fopen(optarg, "r");
1924 if (!fp)
1925 bail_syserr(errno, "failed to open ranges file `%s'", optarg);
1926
1927 /* We're going to try to coalesce adjacent ranges from the file.
1928 * When we found a region to skip, we'd have stopped at the a file
1929 * boundary, and possibly restarted again immediately afterwards,
1930 * resulting in two adjacent regions in the file. To do that, and
1931 * also to police the restriction that ranges occur in ascending
1932 * order, we keep track of the upper bound for the most recent range
1933 * -- but there isn't one yet, so we use a sentinel value.
1934 */
1935 i = 0; last = -1;
1936 for (;;) {
1937
1938 /* Read a line from the buffer. If there's nothing left then we're
1939 * done.
1940 */
1941 buf_rewind(&buf); if (read_line(fp, &buf)) break;
1942
1943 /* Increment the line counter and establish a cursor. */
1944 i++; p = buf.p;
1945
1946 /* Skip initial whitespace. */
1947 while (ISSPACE(*p)) p++;
1948
1949 /* If this is a comment then ignore it and go round again. */
1950 if (!*p || *p == '#') continue;
1951
1952 /* Parse the range. Check that the ranges are coming out in
1953 * ascending order.
1954 */
1955 if (parse_range(p, 0, &start, &end) ||
1956 (last <= SECLIMIT && start < last))
1957 bail("bad range `%s' at `%s' line %zu", buf.p, optarg, i);
1958
1959 /* Ignore empty ranges: this is important (see below where we sort
1960 * the event queue). If this abuts the previous range then just
1961 * overwrite the previous end position. Otherwise, write a new
1962 * pair of events.
1963 */
1964 if (start < end) {
1965 if (start == last)
1966 eventq.v[eventq.n - 1].pos = end;
1967 else {
1968 put_event(EV_WRITE, 0, start);
1969 put_event(EV_STOP, 0, end);
1970 }
1971 last = end;
1972 }
1973 }
1974
1975 /* Check for read errors. */
1976 if (ferror(fp))
1977 bail_syserr(errno, "failed to read ranges file `%s'", optarg);
1978 f |= f_retry;
1979 break;
1980
1981 /* `-X FILE' (undocumented): Read ranges of bad-blocks from FILE to
1982 * establish fake bad blocks: see `read_sectors' above for the details.
1983 *
1984 * This is very similar to the `-R' option above, except that it
1985 * doesn't do the range coalescing thing.
1986 */
1987 case 'X':
1988 fp = fopen(optarg, "r");
1989 if (!fp)
1990 bail_syserr(errno, "failed to open bad-blocks file `%s'", optarg);
1991 i = 0; last = -1;
1992 for (;;) {
1993 buf_rewind(&buf); if (read_line(fp, &buf)) break;
1994 p = buf.p; i++;
1995 while (ISSPACE(*p)) p++;
1996 if (!*p || *p == '#') continue;
1997 if (parse_range(p, 0, &start, &end) ||
1998 (last <= SECLIMIT && start < last))
1999 bail("bad range `%s' at `%s' line %zu", buf.p, optarg, i);
2000 if (start < end) {
2001 VEC_PUSH(bad, &badblocks);
2002 bad->start = start; bad->end = end;
2003 }
2004 }
2005 if (ferror(fp))
2006 bail_syserr(errno, "failed to read bad-blocks file `%s'", optarg);
2007 break;
2008
2009 /* Log regions skipped because of bad blocks to a file. */
2010 case 'b':
2011 if (mapfile) bail("can't have multiple map files");
2012 mapfile = optarg;
2013 break;
2014
2015 /* `-c': Continue copying where we left off last time. */
2016 case 'c': f |= f_continue; break;
2017
2018 /* `-i': Check that we're copying from the right disc. */
2019 case 'i': f |= f_checkid; break;
2020
2021 /* `-r [START]-[END]': Manually provide a range of sectors to retry. */
2022 case 'r':
2023 start = 0; end = -1; f |= f_retry;
2024 if (parse_range(optarg, PRF_HYPHEN, &start, &end))
2025 bail("bad range `%s'", optarg);
2026 if (start < end) {
2027 /* Again, ignore empty ranges. */
2028 put_event(EV_WRITE, 0, start);
2029 if (end <= SECLIMIT) put_event(EV_STOP, 0, end);
2030 }
2031 break;
2032
2033 /* `-s': Print statistics at the end. */
2034 case 's': f |= f_stats; break;
2035
2036 /* Anything else is an error. */
2037 default: f |= f_bogus; break;
2038 }
2039 }
2040
2041 /* We expect two arguments. Check this. Complain about bad usage if we
2042 * have bad arguments or options.
2043 */
2044 if (argc - optind != 2) f |= f_bogus;
2045 if (f&f_bogus) { usage(stderr); exit(2); }
2046 device = argv[optind]; outfile = argv[optind + 1];
2047
2048 /* If there are fake bad blocks (the `-X' option) then sort the list
2049 * because `read_sectors' wants to use a binary search.
2050 */
2051 if (badblocks.n) {
2052 qsort(badblocks.v, badblocks.n, sizeof(struct badblock),
2053 compare_badblock);
2054 #ifdef DEBUG
2055 printf(";; fake bad blocks:\n");
2056 for (i = 0; i < badblocks.n; i++)
2057 printf(";;\t%8"PRIuSEC" .. %"PRIuSEC"\n",
2058 badblocks.v[i].start, badblocks.v[i].end);
2059 #endif
2060 }
2061
2062 /* Prepare to display progress information. */
2063 setlocale(LC_ALL, "");
2064 progress_init(&progress);
2065
2066 /* Open the input device. (This may pop up a notice if there's nothing in
2067 * the drive.)
2068 */
2069 if (open_dvd(device, O_RDONLY, &dvdfd, &dvd)) exit(2);
2070
2071 /* Determine the size of the input device and check the sector size. */
2072 blksz = SECTORSZ; volsz = device_size(dvdfd, device, &blksz);
2073 if (blksz != SECTORSZ)
2074 bail("device `%s' block size %d /= %d", device, blksz, SECTORSZ);
2075 if (volsz%SECTORSZ)
2076 bail("device `%s' volume size %"PRIu64" not a multiple of %d",
2077 device, volsz, SECTORSZ);
2078
2079 /* Maybe check that we're copying from the right disc. This is intended to
2080 * help avoid image corruption by from the wrong disc, but it obviously
2081 * only works if the output file is mostly there.
2082 */
2083 if (f&f_checkid) {
2084 if (open_dvd(outfile, O_RDONLY, 0, &dvd_out)) exit(2);
2085 if (dvd_id(id_in, dvd, DIF_MUSTIFOHASH, device) ||
2086 dvd_id(id_out, dvd_out, DIF_MUSTIFOHASH, device))
2087 exit(2);
2088 if (STRCMP(id_in, !=, id_out))
2089 bail("DVD id mismatch: input `%s' is `%s'; output `%s' is `%s'",
2090 device, id_in, outfile, id_out);
2091 }
2092
2093 /* Open the output file. */
2094 outfd = open(outfile, O_WRONLY | O_CREAT, 0666);
2095 if (outfd < 0)
2096 bail_syserr(errno, "failed to create output file `%s'", outfile);
2097
2098 if (f&f_continue) {
2099 /* If we're continuing from where we left off, then find out where that
2100 * was and make a note to copy from there to the end of the disc. Note
2101 * that we're not relying on this position: in particular, it might not
2102 * even be sector-aligned (in which case we'll ignore the final partial
2103 * sector). We'll seek to the right place again when we start writing.
2104 */
2105
2106 off = lseek(outfd, 0, SEEK_END);
2107 if (off < 0)
2108 bail_syserr(errno, "failed to seek to end of output file `%s'",
2109 outfile);
2110 put_event(EV_WRITE, 0, off/SECTORSZ); f |= f_retry;
2111 }
2112
2113 if (!(f&(f_retry | f_fixup))) {
2114 /* If there are no ranges to retry and we're not fixing an ancient early-
2115 * stop bug, then there's no range to retry and we should just copy
2116 * everything.
2117 */
2118
2119 put_event(EV_WRITE, 0, 0);
2120 }
2121
2122 /* Now it's time to figure out what the input looks like. Work through the
2123 * titlesets in order, mapping out where the video-object files are. We
2124 * could figure out how many there are properly, but it's fast enough just
2125 * to try everything. That's the menu only for the special titleset 0, and
2126 * menu and titles for the remaining titlesets 1 up to 99.
2127 */
2128 put_menu(dvd, 0);
2129 for (i = 1; i < 100; i++) {
2130 put_menu(dvd, i);
2131 put_title(dvd, i);
2132 }
2133
2134 /* Make a final virtual file for the raw device. (See `emit', which
2135 * assumes that this is the last entry in the file table.) Check that we
2136 * don't have more files than we expect, because the bitmap table has fixed
2137 * size.
2138 */
2139 put_file(mkident(RAW, 0, 0), 0, volsz/SECTORSZ);
2140 assert(filetab.n <= MAXFILES);
2141
2142 /* Find an upper limit for what we're supposed to copy. Since the `RAW'
2143 * entry covers the reported size of the input device, this ought to cover
2144 * all of our bases.
2145 */
2146 for (i = 0, limit = 0; i < filetab.n; i++)
2147 if (filetab.v[i].end > limit) limit = filetab.v[i].end;
2148 #ifdef DEBUG
2149 printf("\n;; files:\n");
2150 for (i = 0; i < filetab.n; i++) {
2151 file = &filetab.v[i];
2152 store_filename(fn, file->id);
2153 printf(";;\t%8"PRIuSEC" .. %-8"PRIuSEC" %s\n",
2154 file->start, file->end, fn);
2155 }
2156 #endif
2157
2158 /* Sort the event list.
2159 *
2160 * The event-code ordering is important here.
2161 *
2162 * * `EV_STOP' sorts /before/ `EV_WRITE'. If we have two abutting ranges
2163 * to retry, then we should stop at the end of the first, and then
2164 * immediately start again. If empty ranges were permitted then we'd
2165 * stop writing and /then/ start, continuing forever, which is clearly
2166 * wrong.
2167 *
2168 * * `EV_BEGIN' sorts before `EV_END'. If we have empty files then we
2169 * should set the bit that indicates that it's started, and then clear
2170 * it, in that order. If we have abutting files, then we'll just both
2171 * bits for an instant, but that's not a problem.
2172 */
2173 qsort(eventq.v, eventq.n, sizeof(struct event), compare_event);
2174
2175 /* Check that the event list is well-formed. We start out at the
2176 * beginning, not writing anything.
2177 */
2178 for (i = 0, f &= ~f_write, start = 0; i < eventq.n; i++) {
2179 ev = &eventq.v[i];
2180 switch (ev->ev) {
2181
2182 case EV_WRITE:
2183 /* Start writing. We shouldn't be writing yet! */
2184
2185 if (f&f_write)
2186 bail("overlapping ranges: range from %"PRIuSEC" "
2187 "still open at %"PRIuSEC"",
2188 start, ev->pos);
2189 f |= f_write; start = ev->pos;
2190 break;
2191
2192 case EV_STOP:
2193 /* Stop writing. Make a note that we've done this. */
2194
2195 f &= ~f_write;
2196 break;
2197 }
2198 }
2199 #ifdef DEBUG
2200 dump_eventq("initial");
2201 #endif
2202
2203 /* Now we make a second pass over the event queue to fix it up. Also
2204 * count up how much work we'll be doing so that we can report progress.
2205 */
2206 for (i = 0, f &= ~f_write, start = last = 0; i < eventq.n; i++) {
2207 ev = &eventq.v[i];
2208
2209 /* If we're supposed to start writing then make a note of the start
2210 * position. We'll want this to count up how much work we're doing. The
2211 * start position of the final range is also used by the logic below that
2212 * determines the progress display.
2213 */
2214 if (ev->ev == EV_WRITE) { start = ev->pos; f |= f_write; }
2215
2216 /* If this event position is past our final limit then stop. Nothing
2217 * beyond here can possibly be interesting. (Since `EV_WRITE' sorts
2218 * before other events, we will notice an `EV_WRITE' exactly at the limit
2219 * sector, but not any other kind of event.)
2220 */
2221 if (ev->pos >= limit) break;
2222
2223 /* If we're supposed to stop writing here, then add the size of the
2224 * most recent range onto our running total.
2225 */
2226 if (ev->ev == EV_STOP) { nsectors += ev->pos - start; f &= ~f_write; }
2227
2228 /* If we're fixing up images affected by the old early-stop bug, then
2229 * remember this position.
2230 */
2231 if (f&f_fixup) last = ev->pos;
2232 }
2233
2234 /* Truncate the event queue at the point we reached the sector limit. */
2235 eventq.n = i;
2236 #ifdef DEBUG
2237 dump_eventq("trimmed");
2238 #endif
2239
2240 /* Finally, the early-stop bug fix.
2241 *
2242 * The bug was caused by a broken version of the event-queue truncation
2243 * logic: it trimmed the event queue, but didn't add a final event at the
2244 * file limit. The effect was that the interval between the last event --
2245 * likely `EV_END' for a VOB file -- and the overall end of the disc didn't
2246 * get copied. We address this by starting to write at the position of
2247 * this last event.
2248 */
2249 if (f&f_fixup) {
2250 put_event(EV_WRITE, 0, last);
2251 f |= f_write;
2252 }
2253
2254 /* If we're still writing then avoid the early-end bug by adding an
2255 * `EV_STOP' event at the limit position. Include this range in the sector
2256 * count.
2257 */
2258 if (f&f_write) {
2259 nsectors += limit - start;
2260 put_event(EV_STOP, 0, limit);
2261 }
2262 #ifdef DEBUG
2263 dump_eventq("final");
2264 #endif
2265
2266 /* Set up the main progress display.
2267 *
2268 * If we're copying a single region from somewhere to the end of the disc
2269 * then it seems more sensible to use a single progress bar for both. If
2270 * we're reading multiple ranges, maybe because we're retrying bad blocks,
2271 * then it's better to have separate bars for how much actual copying we've
2272 * done, and which part of the disc we're currently working on.
2273 */
2274 copy_progress.render = render_copy_progress;
2275 progress_additem(&progress, &copy_progress);
2276 if (nsectors == limit - start)
2277 { ndone = start; nsectors = limit; }
2278 else {
2279 disc_progress.render = render_disc_progress;
2280 progress_additem(&progress, &disc_progress);
2281 }
2282
2283 /* If we're producing overall statistics then make a note of the current
2284 * time.
2285 */
2286 if (f&f_stats) gettimeofday(&tv0, 0);
2287
2288 /* We're now ready to start our sweep through the disc. */
2289 #ifdef DEBUG
2290 printf("\n;; event sweep:\n");
2291 #endif
2292
2293 /* We start at the beginning of the disc, and the start of the event queue,
2294 * not writing. We'll advance through the events one by one.
2295 */
2296 for (pos = 0, i = 0, f &= ~f_write; i < eventq.n; i++) {
2297
2298 /* Get the next event. */
2299 ev = &eventq.v[i];
2300
2301 /* If there's a nonempty range between here and the previous event then
2302 * we need to process this.
2303 */
2304 if (ev->pos > pos) {
2305
2306 /* If we're writing then copy the interval from the previous event to
2307 * here to the output.
2308 */
2309 if (f&f_write) emit(pos, ev->pos);
2310
2311 /* Advance the current position now that the output is up-to-date. */
2312 pos = ev->pos;
2313
2314 #ifdef DEBUG
2315 progress_clear(&progress);
2316 printf(";;\n");
2317 #endif
2318 }
2319
2320 /* Decide what to action to take in response to the event. */
2321 switch (ev->ev) {
2322
2323 case EV_BEGIN:
2324 /* A file has started. Set the appropriate bit in the active-files
2325 * map.
2326 */
2327 set_live(ev->file);
2328 #ifdef DEBUG
2329 store_filename(fn, filetab.v[ev->file].id);
2330 progress_clear(&progress);
2331 printf(";; %8"PRIuSEC": begin `%s'\n", pos, fn);
2332 #endif
2333 break;
2334
2335 case EV_WRITE:
2336 /* We're supposed to start writing. */
2337
2338 /* Note the current time and position for the progress display. */
2339 gettimeofday(&last_time, 0); last_pos = pos;
2340
2341 /* Seek to the right place in the output file. */
2342 if (lseek(outfd, (off_t)ev->pos*SECTORSZ, SEEK_SET) < 0)
2343 bail_syserr(errno,
2344 "failed to seek to resume position "
2345 "(sector %"PRIuSEC") in output file `%s'",
2346 ev->pos, outfile);
2347
2348 /* Engage the write head. */
2349 f |= f_write;
2350
2351 #ifdef DEBUG
2352 progress_clear(&progress);
2353 printf(";; %8"PRIuSEC": begin write\n", pos);
2354 #endif
2355 break;
2356
2357 case EV_STOP:
2358 /* We're supposed to stop writing. Disengage the write head. */
2359
2360 f &= ~f_write;
2361 #ifdef DEBUG
2362 progress_clear(&progress);
2363 printf(";; %8"PRIuSEC": end write\n", pos);
2364 #endif
2365 break;
2366
2367 case EV_END:
2368 /* We've found the end of a file. Clear its bit in the table. */
2369
2370 clear_live(ev->file);
2371 #ifdef DEBUG
2372 store_filename(fn, filetab.v[ev->file].id);
2373 progress_clear(&progress);
2374 printf(";; %8"PRIuSEC": end `%s'\n", pos, fn);
2375 #endif
2376 break;
2377
2378 /* Something else. Clearly a bug. */
2379 default: abort();
2380 }
2381 }
2382
2383 /* Take down the progress display because we're done. */
2384 progress_clear(&progress);
2385
2386 /* Set the output file length correctly. */
2387 if (ftruncate(outfd, (off_t)limit*SECTORSZ) < 0)
2388 bail_syserr(errno, "failed to set output file `%s' length", outfile);
2389
2390 /* Report overall statistics. */
2391 if (f&f_stats) {
2392 gettimeofday(&tv1, 0); t = tvdiff(&tv0, &tv1);
2393 if (nsectors == limit) { ndone -= start; nsectors -= start; }
2394 tot = scale_bytes((double)nsectors*SECTORSZ, &totunit);
2395 rate = scale_bytes((double)nsectors*SECTORSZ/t, &rateunit);
2396 moan("all done: %.1f %sB in %s -- %.1f %sB/s",
2397 tot, totunit, fmttime(t, timebuf), rate, rateunit);
2398 }
2399
2400 /* Close files. */
2401 if (dvd) DVDClose(dvd);
2402 if (dvdfd >= 0) close(dvdfd);
2403 if (outfd >= 0) close(outfd);
2404 carefully_fclose(mapfp, "bad-sector region map");
2405 carefully_fclose(errfp, "bad-sector error log");
2406 progress_free(&progress);
2407
2408 /* We're done! */
2409 return (0);
2410
2411 #undef f_bogus
2412 #undef f_continue
2413 #undef f_fixup
2414 #undef f_stats
2415 #undef f_write
2416 }
2417
2418 /*----- That's all, folks -------------------------------------------------*/