3 * Make an unscrambled copy of a DVD.
5 * (c) 2022 Mark Wooding
8 /*----- Licensing notice --------------------------------------------------*
10 * This file is part of the DVD ripping toolset.
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.
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
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/>.
26 /*----- Header files ------------------------------------------------------*/
31 # include <linux/cdrom.h>
34 /*----- Program usage summary ---------------------------------------------*/
36 static void usage(FILE *fp
)
39 "usage: %s [-ci] [-B PARAM=VALUE,...] [-R MAP]\n"
40 "\t[-b OUTMAP] [-r [START]-[END]] DEVICE OUTFILE\n",
44 /*----- Random utilities --------------------------------------------------*/
47 static int parse_range(const char *p
, unsigned f
,
48 secaddr
*start_out
, secaddr
*end_out
)
49 /* Parse a range of sectors from the string P. If successful, store
50 * the specified start sector address in *START_OUT and the end
51 * address in *END_OUT, and return zero. On failure, return -1;
52 * *START_OUT and/or *END_OUT are clobbered.
54 * The acceptable syntax depends on the flags.
56 * * The `PRF_HYPHEN' syntax is intended for use on the
57 * command-line. It accepts `[START]-[END]'; if the start and/or
58 * end addresses are omitted then *START_OUT and/or *END_OUT are
61 * * The default syntax matches what's written to the bad-sector
62 * output files. It accepts `START END [# COMMENT]'.
67 unsigned long start
, end
;
69 /* Save any existing error code. */
72 /* Parse the start address. */
74 /* We found a digit: this is a good start. Convert the integer, check
75 * that it's in range, save it.
78 start
= strtoul(p
, &q
, 0);
79 if (errno
|| start
>= SECLIMIT
) { rc
= -1; goto end
; }
80 *start_out
= start
; p
= q
;
81 } else if (!(f
&PRF_HYPHEN
)) {
82 /* No digit. We're parsing the map-file syntax, so this is an error. */
86 /* We're parsing the command-line syntax, so this is OK. Set our
87 * internal idea of the position for the range check later, but don't
88 * alter the caller's variables.
94 /* Parse the delimiter. */
96 if (*p
!= '-') { rc
= -1; goto end
; }
99 if (!ISSPACE(*p
)) { rc
= -1; goto end
; }
100 do p
++; while (ISSPACE(*p
));
103 /* Parse the end address. */
105 /* We found a digit. Parse the integer and check that it's strictly
106 * larger than the start address.
109 end
= strtoul(p
, &q
, 0);
110 if (errno
|| end
> SECLIMIT
|| end
< start
) { rc
= -1; goto end
; }
111 *end_out
= end
; p
= q
;
112 } else if (!(f
&PRF_HYPHEN
)) {
113 /* No digit. We're parsing the file syntax, so this is an error. */
118 /* In the file syntax, we're now allowed whitespace, so skip past that. */
119 if (!(f
&PRF_HYPHEN
)) while (ISSPACE(*p
)) p
++;
121 /* Check that there's nothing else. The file syntax allows a trailing
122 * comment here, but the command-line syntax doesn't.
124 if (*p
&& ((f
&PRF_HYPHEN
) || *p
!= '#')) { rc
= -1; goto end
; }
133 /*----- A few words about the overall approach ----------------------------*
135 * The objective is to produce a working copy of the input (commercial,
136 * pressed) DVD disc, only with all of the scrambled video data unscrambled
137 * so that it can be read without the need for cracking CSS keys, which, in
138 * the absence of a cooperative drive with access to the key tables in the
139 * disc lead-in data -- which we /don't/ copy -- is often slow and prone to
140 * failure. Producing a sector-by-sector image preserves all of the menus
141 * and special features, and also any other bonus data stored in the
142 * filesystem for use by computers, such as PDF scripts. DVD images are
143 * large because DVD video is inefficiently compressed by modern standards,
144 * but disk space is cheap and the tradeoff seems worthwhile to me.
146 * The approach is, in essence, simple: start at the beginning of the disc,
147 * reading sectors into a buffer and writing them to the output file, and
148 * continue until we reach the end. But we must cope with scrambled video
149 * files. Fortunately, `libdvdread' knows how to deal with these, and will
150 * tell us where they are on the disc.
152 * Given this information, we build a table of `events', with the sector
153 * numbers at which they occur. An `event' might be something like `such-
154 * and-such a video file began' or `such-and-such a file ended'. Chunks of
155 * disc between events can be read using the same strategy -- either reading
156 * unscrambled sectors directly from the block device, or decrypting
157 * scrambled sectors through `libdvdread' -- while at sector boundaries we
158 * might need to change strategy.
160 * Note that files can /overlap/. The DVD spec says that this can't happen,
161 * and that the data for video titles is laid out with higher-numbered
162 * titlesets occupying higher-numbered sectors, but it does anyway. I think
163 * this is intended to frustrate copiers like `dvdbackup' which try to copy
164 * the DVD files into a directory on the filesystem. The result is that they
165 * copy the same sectors into multiple, very large files, and turn an 8 GB
166 * DVD image into a 60 GB directory. (The reused regions often also contain
167 * intentionally bad sectors, so you have to wait for the drive to fail the
168 * same sectors over and over again. This is no fun.) As far as I know,
169 * files are either disjoint or coincident, but more complex arrangements are
170 * possible in principle. Also, I guess it's possible that the same sector
171 * should be decrypted with different keys depending on which titleset we're
172 * considering it being part of, but (a) DVD CSS keys aren't long enough to
173 * do this very well, and (b) I'm not aware of this actually being a thing.
174 * (Indeed, `libdvdcss' indexes keys by start sector, so such a disc probably
175 * wouldn't play back properly through VLC or `mpv'.)
177 * There's an additional consideration. We want to be able to fill in an
178 * ouptut image file incrementally, in several runs. A run can be
179 * interrupted for lots of reasons (e.g., a faster drive might have become
180 * available; it might be beneficial to switch to a more forgiving drive; it
181 * might be necessary to stop and clean the disc; the output filesystem might
182 * have become full; ...). And discs don't always read perfectly: some discs
183 * are damaged and have areas which can't be read; some discs (I'm looking at
184 * you, Sony, Disney, Lionsgate, and E-One) have intentional bad sectors,
185 * presumably specifically to make my life annoying. So we have other events
186 * which say things like `start writing stuff to the output' or `stop writing
187 * things to the output'. And we have a rather elaborate algorithm for
188 * trying to skip past a region of bad blocks, because drives get /really/
189 * slow when reading bad sectors.
192 /*----- The file and event tables -----------------------------------------*/
194 #define MAXFILES (1 + 2*99 + 1)
195 /* How many (interesting) files there can be. This counts the
196 * magical `raw' file which refers to direct disc access, the master
197 * menu file, and 99 possible menu and titleset pairs. (A titleset
198 * can be split into 9 parts in order to keep each file below a
199 * gigabyte in size, but the rules require that the parts together
200 * form a single contiguous chunk on the disc, in the right order, so
201 * we treat them as a single file. We check this in `put_title'
202 * below, just in case some disc somewhere tries to be awkward, but I
203 * don't have a disc like that in my collection, and I doubt it would
208 /* An interesting DVD file. It has a name, encoded as an `ident'
209 * (see `lib.h'), and start and end sectors. (The `end' here, as
210 * everywhere in this code, is /exclusive/, so that the file's length
211 * is simply end - start.)
214 ident id
; /* file name */
215 secaddr start
, end
; /* start (inclusive) and end
216 * (exclusive) sector numbers */
218 DEFVEC(file_v
, struct file
); /* a vector of files */
219 static file_v filetab
= VEC_INIT
; /* the file table */
222 /* Event codes. The ordering of these is important, because we use
223 * them to tie-break comparisons of events happening at the same
224 * sector when we sort the event queue.
227 EV_STOP
, /* stop copying stuff to output */
228 EV_BEGIN
, /* a (maybe scrambled) file begins */
229 EV_END
, /* a file ends */
230 EV_WRITE
/* start copying stuff to output */
236 unsigned char ev
; /* event code (`EV_...') */
237 unsigned char file
; /* the file (`EV_BEGIN', `EV_END');
238 * index into `filetab' */
239 secaddr pos
; /* the sector at which it happens */
241 DEFVEC(event_v
, struct event
); /* a vector of events */
242 static event_v eventq
= VEC_INIT
; /* the event queue */
244 static int compare_event(const void *a
, const void *b
)
245 /* A `qsort' comparison function for events. Event A sorts earlier
246 * than event B iff A's sector number is smaller than B's, or A's
247 * event code is less than B's.
250 const struct event
*eva
= a
, *evb
= b
;
252 /* Primary ordering by position. */
253 if (eva
->pos
< evb
->pos
) return (-1);
254 else if (eva
->pos
> evb
->pos
) return (+1);
256 /* Secondary ordering by event code. */
257 if (eva
->ev
< evb
->ev
) return (-1);
258 else if (eva
->ev
> evb
->ev
) return (+1);
260 /* We currently have a final tie-break on file numbers so that the ordering
261 * is deterministic, but this is an arbitrary choice that shouldn't be
264 if (eva
->file
< evb
->file
) return (-1);
265 else if (eva
->file
> evb
->file
) return (+1);
267 /* These events are equal. */
272 static void dump_eventq(const char *what
)
273 /* Dump the event queue, labelling the output with WHAT. */
276 const struct event
*ev
;
279 printf("\n;; event dump (%s):\n", what
);
280 for (i
= 0; i
< eventq
.n
; i
++) {
284 store_filename(fn
, filetab
.v
[ev
->file
].id
);
285 printf(";; %8"PRIuSEC
": begin %s\n", ev
->pos
, fn
);
288 store_filename(fn
, filetab
.v
[ev
->file
].id
);
289 printf(";; %8"PRIuSEC
": end %s\n", ev
->pos
, fn
);
292 printf(";; %8"PRIuSEC
": write\n", ev
->pos
);
295 printf(";; %8"PRIuSEC
": stop\n", ev
->pos
);
298 printf(";; %8"PRIuSEC
": ?%u\n", ev
->pos
, ev
->ev
);
305 typedef uint_least32_t bits
;
306 static bits live
[(MAXFILES
+ 31)/32];
307 /* A bitmap which keeps track of which files are currently `active',
308 * i.e., that contain the sector we're currently thinking about. We
309 * set and clear these bits as we encounter `EV_BEGIN' and `EV_END'
313 static inline int livep(unsigned i
)
314 /* Return whether file I is active. */
315 { return (live
[i
/32]&((bits
)1 << (i
%32))); }
317 static inline void set_live(unsigned i
)
318 /* Note that we've seen the start of file I. */
319 { live
[i
/32] |= (bits
)1 << (i
%32); }
321 static inline void clear_live(unsigned i
)
322 /* Note that we've seen the end of file I. */
323 { live
[i
/32] &= ~((bits
)1 << (i
%32)); }
325 static inline int least_live(void)
326 /* Return the smallest index for any active file. This is going to
327 * be the file that we ask `libdvdread' to unscramble for us. This
328 * is important: the imaginary `raw' file that represents the entire
329 * block device has the highest index, and we want any actual video
330 * file to be used in preference so that we unscramble the data.
333 unsigned i
, n
= (filetab
.n
+ 32)/32;
336 /* First part: find the first nonzero word in the `live' table. */
337 for (i
= 0; i
< n
; i
++) { b
= live
[i
]; if (b
) goto found
; }
341 /* Second part: identify which bit in this word is nonzero. First, see if
342 * the bottom 16 bits are clear: if so, shift down and add 16 to the
343 * total. Now we know that the first set bit is indeed in the low 16
344 * bits, so see whether the low 8 bits are clear, and so on.
347 if (!(b
&0x0000ffff)) { b
>>= 16; i
+= 16; }
348 if (!(b
&0x000000ff)) { b
>>= 8; i
+= 8; }
349 if (!(b
&0x0000000f)) { b
>>= 4; i
+= 4; }
350 if (!(b
&0x00000003)) { b
>>= 2; i
+= 2; }
351 if (!(b
&0x00000001)) { b
>>= 1; i
+= 1; }
358 static void put_event(unsigned evtype
, unsigned file
, secaddr pos
)
359 /* Add an event to the queue, with type EVTYPE, for the given FILE,
360 * and at sector POS. You can add events in any order because we'll
361 * sort them later. For `EV_WRITE' and `EV_STOP' events, the FILE
362 * doesn't matter: use zero for concreteness.
367 VEC_PUSH(ev
, &eventq
);
368 ev
->ev
= evtype
; ev
->file
= file
; ev
->pos
= pos
;
371 static void put_file(ident id
, secaddr start
, secaddr end
)
372 /* Add a (VOB) file to the file table and event queue, with ident ID,
373 * starting at sector START and ending just before sector END.
379 VEC_PUSH(f
, &filetab
); i
= f
- filetab
.v
;
380 f
->id
= id
; f
->start
= start
; f
->end
= end
;
381 put_event(EV_BEGIN
, i
, start
);
382 put_event(EV_END
, i
, end
);
385 static void put_menu(dvd_reader_t
*dvd
, unsigned title
)
386 /* Add the menu file for the given TITLE number to the file table and
387 * event queue; use the reader DVD to find out which sectors it
388 * occupies, if it even exists.
391 ident id
= mkident(VOB
, title
, 0);
395 /* Find out where the file is. */
396 store_filename(fn
, id
);
397 start
= UDFFindFile(dvd
, fn
, &len
); if (!start
) return;
400 /* Print out what we've discovered. */
401 printf(";; %8"PRIuSEC
" .. %-8"PRIuSEC
": %s\n",
402 start
, start
+ SECTORS(len
), fn
);
405 /* Register the file and boundary events. */
406 put_file(id
, start
, start
+ SECTORS(len
));
409 static void put_title(dvd_reader_t
*dvd
, unsigned title
)
410 /* Add the titleset file for the given TITLE number to the file table
411 * and event queue; use the reader DVD to find out which sectors it
412 * occupies, if it even exists.
416 secaddr start
[9], len
[9];
419 /* First step: find out where all of the parts of the titleset are. I'm
420 * assuming that there aren't gaps in the numbering.
422 for (i
= 0; i
< 9; i
++) {
423 store_filename(fn
, mkident(VOB
, title
, i
+ 1));
424 start
[i
] = UDFFindFile(dvd
, fn
, &len
[i
]); if (!start
[i
]) break;
426 npart
= i
; if (!npart
) return;
429 /* Print out what we've discovered. */
430 for (i
= 0; i
< npart
; i
++) {
431 store_filename(fn
, mkident(VOB
, title
, i
+ 1));
432 printf(";; %8"PRIuSEC
" .. %-8"PRIuSEC
": %s\n",
433 start
[i
], start
[i
] + SECTORS(len
[i
]), fn
);
437 /* Second step: check that the parts all butt up against each other in the
438 * correct order. For this to work, the lengths, which are expressed in
439 * /bytes/ by `UDFFindFile', of all but the last part must be a whole
443 for (i
= 0; i
< npart
- 1; i
++) {
445 bail("title %u part %u length = %"PRIuSEC
" not a multiple of %d",
446 title
, i
, len
[i
], SECTORSZ
);
447 if (start
[i
] + len
[i
]/SECTORSZ
!= start
[i
+ 1])
449 ("title %u part %u end = %"PRIuSEC
" /= part %u start = %"PRIuSEC
"",
450 title
, i
, start
[i
] + len
[i
]/SECTORSZ
, i
+ 1, start
[i
+ 1]);
453 /* All good: register a single file and its boundary events. */
454 put_file(mkident(VOB
, title
, 1),
455 start
[0], start
[npart
- 1] + SECTORS(len
[npart
- 1]));
458 /*----- Moving average machinery ------------------------------------------*
460 * We're using an exponential moving average with a weighting factor of α
461 * (`alpha', above); larger values are more sensitive to recent changes. If
462 * the old average was v_1, and the measurement in the current interval is x,
463 * then the new average after this interval is
465 * v = α x + (1 − α) v_1 .
467 * Write β = 1 − α; so
469 * v = α x + β v_1 .
471 * Let x_0 = x, let x_1 be the measurement from the previous interval, and,
472 * in general, let x_i be the measurement from i intervals ago. Then another
473 * way to write the above would be
475 * v = α (x_0 + β x_1 + ⋯ + β^i x_i + ⋯) .
477 * Alas, our time intervals are not regular. Suppose that we get our next
478 * measurement after a gap of t intervals, for some integer t. We can
479 * compensate approximately by pretending that all of the missed intervals --
480 * and our new one -- had the same mean rate. Then we'd have calculated
482 * v = α (x + β x + ⋯ + β^{t−1} x) + β^t v_1
485 * = α x ------- + β^t v_1
488 * = x (1 − β^t) + β^t v_1 (since α = 1 − β)
490 * = x + β^t (v_1 − x) .
492 * Does this work in general? It's clearly correct in the case t = 1.
494 * Suppose the old average was v_2, and that over a period of t intervals
495 * (where t is not necessarily an integer) we measured a mean rate of x, and
496 * then after u intervals we measured a mean rate of x /again/. Then we'd
499 * v_1 = x + β^t (v_2 − x)
503 * v = x + β^u (v_1 − x)
505 * = x + β^u (x + β^t (v_2 − x) − x)
507 * = x + β^{t+u} (v_2 − x) ,
509 * which is exactly what we'd have done if we'd calculated the same mean rate
510 * over the combined span of t + u intervals.
512 * One final wrinkle, in case that wasn't enough. There's a problem with the
513 * initial setup of an exponential moving average. Apparently
514 * (https://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average)
515 * explains that we can do this better by calculating the average after k
518 * x_0 + β x_1 + β^2 x_2 + ⋯ + β^{k−1} x_{k−1}
519 * v′ = ------------------------------------------- .
520 * 1 + β + β^2 + ⋯ + β^{k−1}
522 * The numerator is our existing v/α; the denominator is (1 − β^k)/α; the
523 * factors of α cancel, and we find that v′ = v/(1 − β^k). This still holds
524 * in our situation, where k may not be an integer.
526 * To apply all of this:
528 * * we maintain the moving average v in `avg';
530 * * we maintain the total β^k in `corr'; and
532 * * we compute v′ = v/(1 − β^k) on demand up in `render_perfstats'.
538 #define AVG_INIT { 0.0, 1.0 }
540 static double alpha
= 0.1; /* weighting factor for average */
542 static void update_avg(struct avg
*a
, double t
, double n
)
544 double rate
= n
/t
, beta_t
= pow(1 - alpha
, t
);
546 a
->avg
= rate
+ beta_t
*(a
->avg
- rate
);
550 static inline double current_avg(const struct avg
*a
)
551 { return (a
->avg
/(1 - a
->corr
)); }
553 /*----- The nonlinear progress model --------------------------------------*/
555 /* The recorded portion of a single-layer DVD (i.e., DVD-5) can hold 2298496
556 * sectors of user data. This is preceded by 0x30000 = 196608 sectors of
557 * lead-in information, for a totoal of 2495104 sectors.
559 * The readable portion of a disc is an annulus with respective internal and
560 * external diameters of 44 mm and 117 mm. This annulus has an area of
561 * 9230.8 mm^2, so DVD has a storage density of about 270.3 sectors/mm^2. If
562 * the interior of the annulus were used for data storage rather than leaving
563 * a hole for a spindle and a clamping area, then it would be 10751 mm^2 and
564 * could store 2906107 sectors. (That means that the portion of the disc
565 * that's actually used to make it spin could have stored an additional
568 * Sectors aren't stored on the surface willy-nilly, but arranged into a
569 * single archimedean spiral; bits are stored along this spiral at a
570 * more-or-less constant pitch. We are therefore led into an investigation
571 * of the arc-length of archimedean spirals.
573 * It's best to start with the polar equation of the spiral, which is simply
577 * for a given constant k. The arc length of a curve expressed using polar
578 * coordinates is given by
580 * s = ∫ √(r^2 + (dr/dθ)^2) dθ
582 * = ∫ √(k^2 θ^2 + k^2) dθ
584 * = k ∫ √(1 + θ^2) dθ
587 * = - [ θ √(1 + θ^2) + log(θ + √(1 + θ^2)) ] - s_0.
590 * We're assuming that the sectors are spaced out at a constant linear
591 * density along the spiral. We don't know the units for s, but there's some
592 * constant L such that A = s/L; so
595 * A = --- [ θ √(1 + θ^2) + log(θ + √(1 + θ^2)) ] - A_0
598 * for some suitable constant A_0.
600 * Finally, we're assuming that the disc is spinning with some approximately
601 * constant angular velocity ω, so θ = ω t, giving
604 * A = --- [ ω t √(1 + ω^2 t^2) + log(ω + √(1 + ω^2 t^2)) ] + A_0 .
607 * We can calculate approximate values for k/(2 L) and A_0. As stated above,
608 * the track pitch is about 0.75 µm; our inside and outside diameters of
609 * 44 mm and 117 mm correspond to angles of 184306 and 490088 radians
610 * respectively. Feeding those into the above equation for s gives arc
611 * lengths of 16984492558 and 120093346360 respectively, in unknown units.
612 * The difference is 103108853802, which should correspond to 2495104
613 * sectors, giving us 41324 arc-length units per sector. As a cross-check,
614 * the arc length corresponding to the inside diameter yields 411003 sectors,
615 * which is the same as we calculated above. This will be our A_0
619 static double archimedes_arclen(double t
)
620 /* Given an angle T, return the arc length of the canonical
621 * archimedean spiral r = θ, from θ = 0 up to θ = T.
627 return (t
*u
+ log(t
+ u
))/2;
631 static double inv_archimedes_arclen(double s
)
632 /* Given an arc length S, return the angle T such that the arc length
633 * of the canonical archimedean spiral r = θ, from θ = 0 up to θ = T,
637 /* There is no closed-form solution, so we're going to invert the arc-
638 * length formula above numerically, using the Newton--Raphson method.
640 * Given an incorrect guess x_0 of a zero of some function f, we refine the
641 * guess by approximating f by its tangent at the point (x_0, f(x_0)).
642 * This will be a line with an equation like
644 * y = f'(x_0) x + c .
646 * We know that y = f(x_0) when x = x_0, so we can calculate
648 * c = f(x_0) - f'(x_0) x_0 .
650 * This will be zero when
652 * y = f'(x_0) x + f(x_0) - f'(x_0) x_0 = 0
656 * f'(x_0) x_0) - f(x_0) f(x_0)
657 * x = --------------------- = x_0 - ------- .
663 /* We need to choose an initial estimate. This seems to work well in
669 /* Compute s' = f(t). We open-code this calculation because the
670 * intermediate value √(1 + t^2) is also the gradient.
673 ss
= (t
*u
+ log(t
+ u
))/2;
675 /* Determine the error in f(t). We don't actually need much precision
676 * here, but 2 ulp seems achievable in practice with minimal cost: the
677 * usually sequence converges after only five iterations.
680 if (e
<= 2*DBL_EPSILON
) return (t
);
682 /* Not good enough. Refine the guess and go around again. */
687 static double sectors_to_angle(secaddr base
, secaddr low
, secaddr high
)
688 /* Return the angle, in radians, subtended by the range LOW up to
689 * HIGH of user sector addresses, given the physical sector address
690 * BASE of the first user-data sectors.
693 #define A0 411003.262489
694 #define K 41324.4713654
696 return (inv_archimedes_arclen(K
*(A0
+ base
+ high
)) -
697 inv_archimedes_arclen(K
*(A0
+ base
+ low
)));
704 FLAT
, /* not actually a real DVD */
705 SINGLE
, /* disc with only one layer */
706 PTP
, /* two layers, parallel track path */
707 OTP
/* two layers, opposite track path */
711 unsigned shape
; /* one of the four codes above */
712 secaddr start0
, start1
; /* initial physical sector */
713 secaddr midpoint
; /* sector address of layer switch */
717 static void setup_geometry(struct geometry
*g
, int fd
, unsigned f
,
719 /* Initialize G with information about the disc structure. FD is a
720 * file descriptor for the device; SZ is the size of the disc in
721 * sectors. If `GF_BLKDEV' is clear in F then assume that FD refers
722 * to a regular file; G is populated with a `FLAT' performance model.
723 * If `GF_BLKDEV' is set, then FD refers to a block device, so try to
724 * retreive detailed structure information from the drive.
729 const struct dvd_layer
*ly
;
733 #define LAYER_LIMIT 2298496 /* maximum (user) sectors on layer */
734 #define DVDROM_OFFSET 0x30000 /* usual initial physical sector */
736 if (!(f
&GF_BLKDEV
)) {
737 /* We're reading from a regular file. Assume that progress will be
742 g
->midpoint
= SECLIMIT
;
747 /* We have Linux and its DVD ioctl(2) calls. Interrogate the disc to
748 * discover its structure.
751 ds
.type
= DVD_STRUCT_PHYSICAL
;
752 ds
.physical
.layer_num
= 0;
753 if (ioctl(fd
, DVD_READ_STRUCT
, &ds
)) {
754 moan_syserr(errno
, "failed to read physical disc structure");
755 goto guess_structure
;
757 ly
= &ds
.physical
.layer
[0];
758 switch (ly
->nlayers
) {
761 g
->start0
= g
->start1
= 0;
762 g
->midpoint
= SECLIMIT
;
765 g
->start0
= ly
->start_sector
;
766 if (ly
->track_path
) {
769 g
->midpoint
= ly
->end_sector_l0
- ly
->start_sector
+ 1;
772 g
->midpoint
= ly
->end_sector
- ly
->start_sector
+ 1;
773 ds
.physical
.layer_num
= 1;
774 if (ioctl(fd
, DVD_READ_STRUCT
, &ds
)) {
775 moan_syserr(errno
, "failed to read layer 1 physical structure");
776 goto guess_structure
;
778 g
->start1
= ly
->start_sector
;
782 moan("unexpected layer count %d", ly
->nlayers
+ 1);
783 goto guess_structure
;
789 /* Either we don't have Linux, or we found something confusing. Let's try
790 * to guess at what's going on.
792 * If the volume size is small enough to fit on a single layer then assume
793 * that's what's happened; otherwise assume opposite track path with a cut
794 * at the midpoint, rounded up to an ECC block (16 sectors).
796 g
->start0
= DVDROM_OFFSET
; g
->start1
= 0;
797 if (sz
<= LAYER_LIMIT
) {
799 g
->midpoint
= SECLIMIT
;
802 t
= (sz
+ DVDROM_OFFSET
)/2;
812 static double linear_progress(const struct geometry
*g
,
813 secaddr a0
, secaddr a1
)
814 /* Convert the sector range from A0 to A1 into a progress measurement
815 * which is, by intention, approximately linearly related to time,
816 * given a geometry description G.
826 theta
= sectors_to_angle(g
->start0
, a0
, a1
);
829 if (a0
< g
->midpoint
)
830 theta
+= sectors_to_angle(g
->start0
,
831 a0
, a1
< g
->midpoint ? a1
: g
->midpoint
);
832 if (a1
> g
->midpoint
)
833 theta
+= sectors_to_angle(g
->start1
,
834 a0
> g
->midpoint ? a0
: g
->midpoint
, a1
);
837 if (a0
< g
->midpoint
)
838 theta
+= sectors_to_angle(g
->start0
,
839 a0
, a1
< g
->midpoint ? a1
: g
->midpoint
);
840 if (a1
> g
->midpoint
)
841 theta
+= sectors_to_angle(g
->start0
,
844 2*g
->midpoint
- a0
: g
->midpoint
);
852 /*----- Common variables used by the copying machinery --------------------*/
854 /* General reading state. */
855 static dvd_reader_t
*dvd
; /* `libdvdread' state for device */
856 static int dvdfd
= -1, outfd
= -1; /* input device and output image */
857 static struct file
*file
; /* currently active file */
858 static dvd_file_t
*vob
; /* current `.VOB' file, or null */
859 static const char *mapfile
; static FILE *mapfp
; /* skipped regions map */
860 static const char *errfile
; static FILE *errfp
; /* bad-sector log */
861 static secaddr limit
; /* upper bound on sectors */
863 static secaddr bad_start
; /* start of current bad region */
864 static unsigned retry
, max_retries
= 4; /* retry state */
866 /*----- Progress reporting ------------------------------------------------*/
868 static secaddr nsectors
, ndone
; /* number of sectors done/to do */
869 static double total_linear
, done_linear
; /* linear progress tracking */
870 static secaddr last_pos
; /* position last time we updated */
871 static struct timeval last_time
; /* time last time we updated */
872 static struct geometry geom
; /* disc geometry for progress */
873 static struct avg avg_rate
= AVG_INIT
, avg_linear
= AVG_INIT
;
874 static int bad_err
; /* most recent error code */
875 static FILE *progressfp
; /* file on which to trace progress data */
877 static const char throbber
[] = "|<-<|>->"; /* throbber pattern */
878 static unsigned throbix
= 0; /* current throbber index */
880 static struct progress_item
/* stock progress items */
881 copy_progress
, disc_progress
,
882 file_progress
, badblock_progress
;
884 static double scale_bytes(double n
, const char **unit_out
)
885 /* Determine a human-readable representation for N bytes. Divide N
886 * by some power of 1024, and store in *UNIT_OUT a string
887 * representing the conventional unit-prefix for that power of 1024.
890 const char *unit
= "";
892 if (n
> 1600) { n
/= 1024; unit
= "k"; }
893 if (n
> 1600) { n
/= 1024; unit
= "M"; }
894 if (n
> 1600) { n
/= 1024; unit
= "G"; }
895 if (n
> 1600) { n
/= 1024; unit
= "T"; }
896 *unit_out
= unit
; return (n
);
899 #define TIMESTRMAX 16 /* maximum length of a duration string */
900 static char *fmttime(unsigned long t
, char *buf
)
901 /* Format a count T of seconds. Write a suitable string to BUF,
902 * which will be no longer than `TIMESTRMAX' bytes including the
903 * terminating zero. Return BUF.
906 if (t
< 60) sprintf(buf
, "%ld s", t
);
907 else if (t
< 3600) sprintf(buf
, "%ld:%02ld", t
/60, t
%60);
908 else sprintf(buf
, "%ld:%02ld:%02ld", t
/3600, (t
/60)%60, t
%60);
912 static void render_perfstats(struct progress_render_state
*render
)
913 /* Add performance statistics to RENDER.
915 * Specifically: the average transfer rate, and the estimated time to
916 * completion. (See `update_progress' for how the average
917 * computation works.)
921 char timebuf
[TIMESTRMAX
];
922 double rate
, linrate
;
925 /* If there's no average computed yet, then use some placeholder values. */
926 rate
= current_avg(&avg_rate
);
927 linrate
= current_avg(&avg_linear
);
928 eta
= (int)((total_linear
- done_linear
)/linrate
+ 0.5);
930 /* Write out the statistics. */
931 rate
= scale_bytes(rate
*SECTORSZ
, &unit
);
932 progress_putright(render
, "ETA %s ",
933 avg_linear
.avg ?
fmttime(eta
, timebuf
) : "???");
934 progress_putright(render
, "%.1f %sB/s, ", rate
, unit
);
937 static void render_copy_progress(struct progress_item
*item
,
938 struct progress_render_state
*render
)
939 /* Render the progress for the copy, i.e., the number of sectors
940 * copied against the total number to be copied.
943 double frac
= (double)ndone
/nsectors
;
945 progress_putleft(render
, " %c copied %.1f%%",
946 throbber
[throbix
], 100.0*frac
);
947 render_perfstats(render
);
948 progress_putleft(render
, " (%"PRIuSEC
" of %"PRIuSEC
")", ndone
, nsectors
);
950 progress_showbar(render
, frac
);
953 static void render_disc_progress(struct progress_item
*item
,
954 struct progress_render_state
*render
)
955 /* Render the progress for the disc, i.e., the current position
956 * against the total number of sectors on the disc.
959 double frac
= (double)last_pos
/limit
;
961 progress_putleft(render
, " disc %.1f%% (%"PRIuSEC
" of %"PRIuSEC
")",
962 100.0*frac
, last_pos
, limit
);
963 progress_showbar(render
, frac
);
966 static void render_file_progress(struct progress_item
*item
,
967 struct progress_render_state
*render
)
968 /* Render the progress for the current file, i.e., the current
969 * position within the file against the file size.
972 secaddr off
= last_pos
- file
->start
, len
= file
->end
- file
->start
;
976 store_filename(fn
, file
->id
);
977 frac
= (double)off
/len
;
978 progress_putleft(render
, " `%s' %.1f%% (%"PRIuSEC
" of %"PRIuSEC
")",
979 fn
, 100.0*frac
, off
, len
);
980 progress_showbar(render
, frac
);
983 static void render_badblock_progress(struct progress_item
*item
,
984 struct progress_render_state
*render
)
985 /* Render a notice about the progress through the current bad block
989 secaddr n
= last_pos
- bad_start
;
993 progress_putleft(render
, " Retrying bad sector %"PRIuSEC
"", bad_start
);
994 progress_putright(render
, "attempt %u/%u ", retry
+ 1, max_retries
);
997 progress_putleft(render
, " Found %"PRIuSEC
" bad %s",
998 n
, n
== 1 ?
"sector" : "sectors");
999 progress_putright(render
, "%"PRIuSEC
" .. %"PRIuSEC
" ",
1000 bad_start
, last_pos
);
1003 if (bad_err
&& bad_err
!= EIO
)
1004 progress_putleft(render
, " (%s)", strerror(bad_err
));
1005 progress_shownotice(render
, bg
, 7);
1008 static void update_progress(secaddr pos
)
1009 /* Recompute the data displayed by the progress renderer functions
1010 * above, based on the new current sector POS.
1016 /* Find the current time and the delta since the last time we updated.
1017 * This will be the length of the current interval.
1019 gettimeofday(&now
, 0); t
= tvdiff(&last_time
, &now
);
1021 /* If no time at all has passed (unlikely!) then skip the rate
1022 * calculation. (The moving average wouldn't be affected anyway.)
1025 /* Update the moving average and the correction term, and start the next
1029 delta_r
= linear_progress(&geom
, last_pos
, pos
);
1030 update_avg(&avg_rate
, t
, pos
- last_pos
);
1031 update_avg(&avg_linear
, t
, delta_r
);
1032 ndone
+= pos
- last_pos
; done_linear
+= delta_r
;
1033 last_time
= now
; last_pos
= pos
;
1036 /* Trace progress state if requested. */
1038 fprintf(progressfp
, "%10ju.%06ld %"PRIuSEC
" %f %f\n",
1039 (uintmax_t)now
.tv_sec
, now
.tv_usec
,
1041 (total_linear
- done_linear
)/current_avg(&avg_linear
));
1042 check_write(progressfp
, "progress trace file");
1045 /* Advance the throbber character. */
1046 throbix
++; if (!throbber
[throbix
]) throbix
= 0;
1049 static void report_progress(secaddr pos
)
1050 /* Update the progress variables (as `update_progress') and redraw
1051 * the progress display.
1053 { update_progress(pos
); progress_update(&progress
); }
1055 /*----- Basic disc I/O ----------------------------------------------------*/
1057 struct badblock
{ secaddr start
, end
; };
1058 DEFVEC(badblock_v
, struct badblock
);
1059 static badblock_v badblocks
= VEC_INIT
;
1060 /* This is a list of /fake/ bad-block ranges, used to test the
1061 * recovery algorithm. It's a rule that the ranges in this table
1062 * mustn't overlap -- though it's OK if they abut.
1065 static int compare_badblock(const void *a
, const void *b
)
1066 /* A `qsort' comparison function for the fake bad-blocks list.
1067 * Ranges which start earlier are sorted before rangers which start
1071 const struct badblock
*ba
= a
, *bb
= b
;
1073 /* Order by start sector. */
1074 if (ba
->start
< bb
->start
) return (-1);
1075 else if (ba
->start
> bb
->start
) return (+1);
1077 /* Order by end sector as a tiebreak. This shouldn't be possible. */
1078 if (ba
->end
< bb
->end
) return (-1);
1079 else if (ba
->end
> bb
->end
) return (+1);
1081 /* They're equal. This shouldn't be possible either. */
1085 static double bad_block_delay
= 0.0, good_block_delay
= 0.0;
1086 /* delay parameters for performance testing */
1088 static ssize_t
read_sectors(secaddr pos
, void *buf
, secaddr want
)
1089 /* Try to read WANT sectors from the input, starting with sector POS,
1090 * and write the contents to BUF. Return the number of /whole
1091 * sectors/ read; this will be 0 at end-of-file (though that
1092 * shouldn't happen). The returned length will be smaller than WANT
1093 * only if end-of-file or a system error prevents reading further.
1094 * Returns -1 on a system error if that prevented us from reading
1097 * This function is where the fake bad-blocks list is handled.
1103 struct badblock
*bad
, *best
;
1104 unsigned char *p
= buf
;
1106 /* See whether the requested range intersects a bad-blocks range. */
1108 /* Since the list is sorted, we use a binary search. We're looking for
1109 * the earliest-starting range which /ends after/ POS. If this starts
1110 * /at or before/ POS, then POS itself is a bad sector, and we should
1111 * pretend an I/O error; otherwise, if the bad range /starts/ somewhere
1112 * in the range we're trying to read then we must pretend a short read;
1113 * and otherwise there's nothing to do.
1116 /* Throughout, `best' points to the earliest-starting range we've found
1117 * which (starts and) finishes after POS. Ranges with indices below LO
1118 * end too early to be interesting; similarly, ranges with indices HI or
1119 * above start later than POS. If we find a range which actually covers
1120 * POS exactly then we'll stop early.
1122 best
= 0; lo
= 0; hi
= badblocks
.n
;
1124 progress_clear(&progress
);
1125 printf(";; searching badblocks for %"PRIuSEC
" .. %"PRIuSEC
"\n",
1129 /* Standard binary-search loop: we continue until the pointers
1133 /* Try the midpoint between the two bounds. */
1134 mid
= lo
+ (hi
- lo
)/2; bad
= &badblocks
.v
[mid
];
1136 printf(";; try %zu (%"PRIuSEC
" .. %"PRIuSEC
")... ",
1137 mid
, bad
->start
, bad
->end
);
1140 /* Follow our invariant. If the range starts strictly after POS, then
1141 * it's too late to overlap, so bring down HI to cover it; but it must
1142 * be closer than any previous block we've found, so remember it in
1143 * `best'. Similarly, if the range ends /at or before/ POS then it
1144 * stops too early, so bring up LO to cover it (but otherwise forget
1145 * about it because it can't affect what we're doing).
1147 * If we get a match then we stop immediately and fake a bad block.
1149 if (pos
< bad
->start
) { D( printf("high\n"); ) best
= bad
; hi
= mid
; }
1150 else if (pos
>= bad
->end
) { D( printf("low\n"); ) lo
= mid
+ 1; }
1152 D( printf("match!\n"); )
1153 errno
= EIO
; sit(bad_block_delay
); return (-1);
1157 /* We're done. Check to see whether the bad range starts early enough.
1158 * If so, remember that we're simulating an error, apply the delay, and
1159 * bamboozle the rest of the code into performing a short read.
1163 printf(";; next is %"PRIuSEC
" .. %"PRIuSEC
"\n",
1164 best
->start
, best
->end
);
1166 if (best
&& pos
+ want
> best
->start
)
1167 { want
= best
->start
- pos
; fakeerr
= EIO
; sit(bad_block_delay
); }
1170 /* Try to read stuff into the buffer until we find a reason why we can't
1171 * continue. Obviously we need to keep track of how much stuff we've read
1172 * on previous iterations.
1174 done
= 0; errno
= 0;
1177 /* Read from the current file's input source. If that's a scrambled
1178 * video file, then use `libdvdread'; if it's the `raw' file, then go to
1179 * the block device; if it's nothing at all, then fill with zeros.
1180 * Always force a seek to the right place, in case things got messed up
1181 * by some previous error.
1184 { errno
= 0; n
= DVDReadBlocks(vob
, pos
- file
->start
, want
, p
); }
1186 if (lseek(dvdfd
, (off_t
)pos
*SECTORSZ
, SEEK_SET
) < 0)
1187 bail_syserr(errno
, "failed to seek to sector %"PRIuSEC
"", pos
);
1188 errno
= 0; n
= read(dvdfd
, p
, want
*SECTORSZ
);
1189 if (n
>= 0) n
/= SECTORSZ
;
1191 memset(p
, 0, want
*SECTORSZ
);
1195 /* If we read some stuff then update the buffer pointer and lengths. If
1196 * we hit end-of-file then stop. If we hit a bad sector then maybe make
1197 * a note of it in the bad-sector log. On any other kind of error, just
1200 if (n
> 0) { done
+= n
; pos
+= n
; p
+= n
*SECTORSZ
; want
-= n
; }
1202 else if (errno
== EIO
&& errfile
) {
1203 open_file_on_demand(errfile
, &errfp
, "bad-sector error log");
1204 fprintf(errfp
, "%"PRIuSEC
" %"PRIuSEC
"\n", pos
, pos
+ 1);
1205 check_write(errfp
, "bad-sector error log");
1207 } else if (errno
!= EINTR
) break;
1210 /* We made it. If we saved up a fake error, and there wasn't a real error
1211 * (which should obviously take priority) then present the fake error to
1212 * the caller. If there wasn't an error, then everything must have been
1213 * good so impose the good-block delay -- note that a bad-block delay will
1214 * already have been imposed above. Finally, return the accumulated count
1215 * of sectors successfully read, or report the end-of-file or error
1216 * condition as applicable.
1218 if (fakeerr
&& !errno
) errno
= fakeerr
;
1219 else if (done
> 0 && good_block_delay
) sit(done
*good_block_delay
);
1220 return (!done
&& errno ?
-1 : done
);
1223 /*----- Tracking machinery for the bad-sector algorithm -------------------*
1225 * While we're probing around trying to find the end of the bad region, we'll
1226 * have read some good data. We want to try to keep as much good data as we
1227 * can, and avoid re-reading it because (a) it's pointless I/O work, but more
1228 * importantly (b) it might not work the second time. The machinery here
1229 * is for making this work properly.
1231 * There are two parts to this which don't really intersect, but for
1232 * convenience the tracking information for them is kept in the same
1233 * `recoverybuf' structure.
1235 * * The `short-range' machinery keeps track of a contiguous region of good
1236 * data stored in the caller's buffer.
1238 * * The `long-range' machinery keeps track of a contiguous region of good
1239 * data that's beyond the range of the buffer.
1242 struct recoverybuf
{
1243 /* Information used to keep track of where good and bad sectors are
1244 * while we're trying to find the end of a region of bad sectors.
1247 /* Short-range buffer tracking. */
1248 unsigned char *buf
; /* pointer to the actual buffer */
1249 secaddr sz
; /* size of the buffer in sectors */
1250 secaddr pos
; /* sector address corresponding to
1251 * the start of the buffer */
1252 secaddr start
, end
; /* bounds of the live region within
1253 * the buffer, as offsets in
1254 * sectors from the buffer start */
1256 /* Long-range tracking. */
1257 secaddr good_lo
, good_hi
; /* known-good region, as absolute
1258 * sector addresses */
1261 static void rearrange_sectors(struct recoverybuf
*r
,
1262 secaddr dest
, secaddr src
, secaddr len
)
1263 /* Shuffle data about in R's buffer. Specifically, move LEN sectors
1264 * starting SRC sectors from the start of the buffer to a new
1265 * position DEST sectors from the start.
1267 * Unsurprisingly, this is a trivial wrapper around `memmove', with
1268 * some range checking thrown in; it's only used by `recovery_read_-
1269 * buffer' and `find_good_sector' below.
1272 assert(dest
+ len
<= r
->sz
); assert(src
+ len
<= r
->sz
);
1273 memmove(r
->buf
+ dest
*SECTORSZ
, r
->buf
+ src
*SECTORSZ
, len
*SECTORSZ
);
1277 static PRINTF_LIKE(2, 3)
1278 void show_recovery_buffer_map(const struct recoverybuf
*r
,
1279 const char *what
, ...)
1280 /* Dump a simple visualization of the short-range tracking state. */
1285 progress_clear(&progress
);
1286 printf(";; recovery buffer (");
1289 "(%"PRIuSEC
") ..%"PRIuSEC
".. "
1290 "[%"PRIuSEC
" ..%"PRIuSEC
".. %"PRIuSEC
"] "
1291 "..%"PRIuSEC
".. (%"PRIuSEC
")\n",
1293 r
->pos
+ r
->start
, r
->end
- r
->start
, r
->pos
+ r
->end
,
1294 r
->sz
- r
->end
, r
->pos
+ r
->sz
);
1296 assert(r
->start
<= r
->end
);
1297 assert(r
->end
<= r
->sz
);
1301 static ssize_t
recovery_read_sectors(struct recoverybuf
*r
,
1302 secaddr pos
, secaddr off
, secaddr want
)
1303 /* Try to read WANT sectors starting at sector address POS from the
1304 * current file into R's buffer, at offset OFF sectors from the start
1305 * of the buffer. Return the number of sectors read, zero if at end
1306 * of file, or -1 in the event of a system error.
1308 * This is a trivial wrapper around `read_sectors' with some
1309 * additional range checking, used only by `recovery_read_buffer'
1315 assert(off
<= r
->sz
); assert(want
<= r
->sz
- off
);
1316 assert(pos
== r
->pos
+ off
);
1317 n
= read_sectors(pos
, r
->buf
+ off
*SECTORSZ
, want
);
1321 static ssize_t
recovery_read_buffer(struct recoverybuf
*r
,
1322 secaddr pos
, secaddr want
)
1323 /* Try to read WANT sectors, starting at sector address POS, from the
1324 * current file into the buffer R, returning a count of the number of
1325 * sectors read, or 0 if at end of file, or -1 in the case of a
1326 * system error, as for `read_sectors'. The data will end up
1327 * /somewhere/ in the buffer, but not necessarily at the start.
1330 secaddr diff
, pp
, nn
;
1333 /* This is the main piece of the short-range tracking machinery. It's
1334 * rather complicated, so hold on tight. (It's much simpler -- and less
1335 * broken -- than earlier versions were, though.)
1339 progress_clear(&progress
);
1340 show_recovery_buffer_map(r
, "begin(%"PRIuSEC
", %"PRIuSEC
")", pos
, want
);
1343 /* The first order of business is to make space in the buffer for this new
1344 * data. We therefore start with a case analysis.
1347 /* The new position is before the current start of the buffer, so we have
1348 * no choice but to decrease the buffer position, which will involve
1349 * shifting the existing material upwards.
1352 /* Determine how far up we'll need to shift. */
1353 diff
= r
->pos
- pos
;
1355 if (r
->start
+ diff
>= r
->sz
) {
1356 /* The material that's currently in the buffer would be completely
1357 * shifted off the end, so we have no choice but to discard it
1361 r
->pos
= pos
; r
->start
= r
->end
= 0;
1363 show_recovery_buffer_map(r
, "cleared; shift up by %"PRIuSEC
"", diff
);
1366 /* Some of the material in the buffer will still be there. We might
1367 * lose some stuff off the end: start by throwing that away, and then
1368 * whatever's left can be moved easily.
1371 if (r
->end
+ diff
> r
->sz
) r
->end
= r
->sz
- diff
;
1372 rearrange_sectors(r
, r
->start
+ diff
, r
->start
, r
->end
- r
->start
);
1373 r
->pos
-= diff
; r
->start
+= diff
; r
->end
+= diff
;
1375 show_recovery_buffer_map(r
, "shifted up by %"PRIuSEC
"", diff
);
1378 } else if (pos
> r
->pos
+ r
->end
) {
1379 /* The new position is strictly beyond the old region. We /could/ maybe
1380 * keep this material, but it turns out to be better not to. To keep it,
1381 * we'd have to also read the stuff that's in between the end of the old
1382 * region and the start of the new one, and that might contain bad
1383 * sectors which the caller is specifically trying to skip. We just
1384 * discard the entire region here so as not to subvert the caller's
1388 r
->pos
= pos
; r
->start
= r
->end
= 0;
1390 show_recovery_buffer_map(r
, "cleared; beyond previous region");
1392 } else if (pos
+ want
> r
->pos
+ r
->sz
) {
1393 /* The requested range of sectors extends beyond the region currently
1394 * covered by the buffer. We must therefore increase the buffer position
1395 * which will involve shifting the existing material downwards.
1398 /* Determine how far down we'll need to shift. */
1399 diff
= (pos
+ want
) - (r
->pos
+ r
->sz
);
1401 if (r
->end
<= diff
) {
1402 /* The material that's currently in the buffer would be completely
1403 * shifted off the beginning, so we have no choice but to discard it
1407 r
->pos
= pos
; r
->start
= r
->end
= 0;
1409 show_recovery_buffer_map(r
, "cleared; shift down by %"PRIuSEC
"", diff
);
1412 /* Some of the material in the buffer will still be there. We might
1413 * lose some stuff off the beginning: start by throwing that away, and
1414 * then whatever's left can be moved easily.
1417 if (r
->start
< diff
) r
->start
= diff
;
1418 rearrange_sectors(r
, r
->start
- diff
, r
->start
, r
->end
- r
->start
);
1419 r
->pos
+= diff
; r
->start
-= diff
; r
->end
-= diff
;
1421 show_recovery_buffer_map(r
, "shifted down by %"PRIuSEC
"", diff
);
1426 /* We now have space in the buffer in which to put the new material.
1427 * However, the buffer already contains some stuff. We may need to read
1428 * some data from the input file into an area before the existing
1429 * material, or into an area following the existing stuff, or both, or
1430 * (possibly) neither.
1433 if (pos
< r
->pos
+ r
->start
) {
1434 /* The requested position is before the current good material, so we'll
1435 * need to read some stuff there.
1438 /* Determine the place in the buffer where this data will be placed, and
1439 * how long it will need to be. Try to extend it all the way to the
1440 * existing region even if this is more than the caller wants, because it
1441 * will mean that we can join it onto the existing region rather than
1442 * having to decide which of two disconnected parts to throw away.
1444 pp
= pos
- r
->pos
; nn
= r
->start
- pp
;
1446 /* Read the data. */
1448 printf(";; read low (%"PRIuSEC
"@%"PRIuSEC
", %"PRIuSEC
")", pos
, pp
, nn
);
1451 n
= recovery_read_sectors(r
, pos
, pp
, nn
);
1453 printf(" -> %zd\n", n
);
1456 /* See whether it worked. */
1458 /* We didn't get everything we wanted. */
1460 /* If we got more than the caller asked for then technically this is
1461 * good; but there must be some problem lurking up ahead, and the
1462 * caller will want to skip past that. So we don't update the tracking
1463 * information to reflect our new data; even though this /looks/ like a
1464 * success, it isn't really.
1466 if (n
>= 0 && n
> want
) n
= want
;
1472 /* Extend the region to include the new piece. */
1475 show_recovery_buffer_map(r
, "joined new region");
1479 if (pos
+ want
> r
->pos
+ r
->end
) {
1480 /* The requested region extends beyond the current region, so we'll need
1481 * to read some stuff there.
1484 /* Determine the place in the buffer where this data will be placed, and
1485 * how long it will need to be. Note that pos <= r->pos + r->end, so
1486 * there won't be a gap between the old good region and the material
1487 * we're trying to read.
1489 pp
= r
->end
; nn
= (pos
+ want
) - (r
->pos
+ r
->end
);
1491 /* Read the data. */
1493 printf(";; read high (%"PRIuSEC
"@%"PRIuSEC
", %"PRIuSEC
")",
1494 r
->pos
+ pp
, pp
, nn
);
1497 n
= recovery_read_sectors(r
, r
->pos
+ pp
, pp
, nn
);
1499 printf(" -> %zd\n", n
);
1502 /* See whether it worked. */
1504 /* We read something, so add it onto the existing region. */
1508 show_recovery_buffer_map(r
, "joined new region");
1513 /* Work out the return value to pass back to the caller. The newly read
1514 * material has been merged with the existing region (the case where we
1515 * didn't manage to join the two together has been handled already), so we
1516 * can easily work out how much stuff is available by looking at the
1517 * tracking information. It only remains to bound the region size by the
1520 n
= r
->pos
+ r
->end
- pos
;
1521 if (!n
&& want
) n
= -1;
1522 else if (n
> want
) n
= want
;
1527 show_recovery_buffer_map(r
, "done; return %zd", n
);
1532 static ssize_t
recovery_read_multiple(struct recoverybuf
*r
,
1533 secaddr pos
, secaddr want
)
1534 /* Try to read WANT sectors, starting at sector address POS, from the
1535 * current file, returning a count of the number of sectors read, or
1536 * 0 if at end of file, or -1 in the case of a system error, as for
1537 * `read_sectors'. Some data might end up in R's buffer, but if WANT
1538 * is larger than R->sz then a lot will be just thrown away.
1540 * This is only used by `recovery_read' below.
1544 secaddr skip
, want0
= want
;
1546 /* If the request is larger than the buffer, then we start at the /end/ and
1547 * work backwards. If we encounter a bad sector while we're doing this,
1548 * then we report a short read as far as the bad sector: the idea is to
1549 * find the /latest/ bad sector we can. The caller will want to skip past
1550 * the bad sector, so the fact that we implicitly lied about the earlier
1551 * data as being `good' won't matter.
1554 while (want
> r
->sz
) {
1555 /* There's (strictly!) more than a buffer's worth. Fill the buffer with
1556 * stuff and reduce the requested size.
1559 skip
= want
- r
->sz
;
1560 n
= recovery_read_buffer(r
, pos
+ skip
, r
->sz
);
1562 /* If it failed, then we always return a positive result, because we're
1563 * pretending we managed to read all of the (nonempty) preceding
1566 if (n
< r
->sz
) return (skip
+ (n
>= 0 ? n
: 0));
1568 /* Cross off a buffer's worth and go around again. */
1572 /* Read the last piece. If it fails or comes up short, then we don't need
1573 * to mess with the return code this time.
1575 n
= recovery_read_buffer(r
, pos
, want
);
1576 if (n
< 0 || n
< want
) return (n
);
1578 /* It all worked. Return the full original amount requested. */
1582 static ssize_t
recovery_read(struct recoverybuf
*r
,
1583 secaddr pos
, secaddr want
)
1584 /* Try to read WANT sectors, starting at sector address POS, from the
1585 * current file, returning a count of the number of
1586 * sectors read, or 0 if at end of file, or -1 in the case of a
1587 * system error, as for `read_sectors'. Some data might end up in
1588 * R's buffer, but if WANT is larger than R->sz then a lot will be
1592 secaddr lo
= pos
, hi
= pos
+ want
, span
; /* calculate the request bounds */
1595 /* This is the main piece of the long-range tracking machinery.
1596 * Fortunately, it's much simpler than the short-range stuff that we've
1600 if (hi
< r
->good_lo
|| lo
> r
->good_hi
) {
1601 /* The requested region doesn't abut or overlap with the existing good
1602 * region, so it's no good to us. Just read the requested region; if it
1603 * worked at all, then replace the current known-good region with the
1604 * region that was successfully read.
1607 n
= recovery_read_multiple(r
, lo
, hi
- lo
);
1608 if (n
> 0) { r
->good_lo
= lo
; r
->good_hi
= lo
+ n
; }
1612 if (hi
> r
->good_hi
) {
1613 /* The requested region ends later than the current known-good region.
1614 * Read the missing piece. We're doing this first so that we find later
1618 span
= hi
- r
->good_hi
;
1619 n
= recovery_read_multiple(r
, r
->good_hi
, span
);
1621 /* If we read anything at all, then extend the known-good region. */
1622 if (n
> 0) r
->good_hi
+= n
;
1624 /* If we didn't read everything we wanted, then report this as a short
1625 * read (so including some nonempty portion of the known-good region).
1627 if (n
< 0 || n
< span
) return (r
->good_hi
- lo
);
1630 if (lo
< r
->good_lo
) {
1631 /* The requested region begins earlier than the known-good region. */
1633 span
= r
->good_lo
- lo
;
1634 n
= recovery_read_multiple(r
, lo
, span
);
1636 /* If we read everything we wanted, then extend the known-good region.
1637 * Otherwise, we're better off keeping the stuff after the bad block.
1639 if (n
== span
) r
->good_lo
= lo
;
1643 /* Everything read OK, and we've extended the known-good region to cover
1644 * the requested region. So return an appropriate code by consulting the
1645 * new known-good region.
1647 n
= r
->good_hi
- pos
; if (n
> want
) n
= want
;
1648 if (!n
) { errno
= EIO
; n
= -1; }
1652 /*----- Skipping past regions of bad sectors ------------------------------*/
1654 static double clear_factor
= 0.5; /* proportion of clear sectors needed */
1655 static secaddr clear_min
= 1, clear_max
= SECLIMIT
; /* absolute bounds */
1656 static double step_factor
= 2.0; /* factor for how far to look ahead */
1657 static secaddr step_min
= 1, step_max
= 0; /* and absolute bounds */
1659 static void recovered(secaddr bad_lo
, secaddr bad_hi
)
1660 /* Do all of the things that are necessary when a region of bad
1661 * sectors has been found between BAD_LO (inclusive) and BAD_HI
1667 /* Remove the progress display temporarily. */
1668 progress_clear(&progress
);
1670 /* Print a message into the permanent output log. */
1671 if (!file
|| id_kind(file
->id
) == RAW
)
1672 moan("skipping %"PRIuSEC
" bad sectors (%"PRIuSEC
" .. %"PRIuSEC
")",
1673 bad_hi
- bad_lo
, bad_lo
, bad_hi
);
1675 store_filename(fn
, file
->id
);
1676 moan("skipping %"PRIuSEC
" bad sectors (%"PRIuSEC
" .. %"PRIuSEC
"; "
1677 "`%s' %"PRIuSEC
" .. %"PRIuSEC
" of %"PRIuSEC
")",
1678 bad_hi
- bad_lo
, bad_lo
, bad_hi
,
1679 fn
, bad_lo
- file
->start
, bad_hi
- file
->start
,
1680 file
->end
- file
->start
);
1684 /* The user requested a map of the skipped regions, so write an entry. */
1686 /* Open the file, if it's not open already. */
1687 open_file_on_demand(mapfile
, &mapfp
, "bad-sector region map");
1689 /* Write the sector range. */
1690 fprintf(mapfp
, "%"PRIuSEC
" %"PRIuSEC
" # %"PRIuSEC
" sectors",
1691 bad_lo
, bad_hi
, bad_hi
- bad_lo
);
1693 /* If we're currently reading from a file then note down the position in
1694 * the file in the comment. (Intentional bad sectors are frequently at
1695 * the start and end of titles, so this helps a reader to decide how
1698 if (file
&& id_kind(file
->id
) != RAW
)
1699 fprintf(mapfp
, "; `%s' %"PRIuSEC
" .. %"PRIuSEC
" of %"PRIuSEC
"",
1700 fn
, bad_lo
- file
->start
, bad_hi
- file
->start
,
1701 file
->end
- file
->start
);
1703 /* Done. Flush the output to the file so that we don't lose it if we
1707 check_write(mapfp
, "bad-sector region map");
1710 /* Adjust the position in our output file to skip past the bad region.
1711 * (This avoids overwriting anything that was there already, which is
1712 * almost certainly less wrong than anything we could come up with here.)
1714 if (lseek(outfd
, (off_t
)(bad_hi
- bad_lo
)*SECTORSZ
, SEEK_CUR
) < 0)
1715 bail_syserr(errno
, "failed to seek past bad sectors");
1717 /* Remove our notice now that we're no longer messing about with bad
1718 * sectors, and reinstate the progress display.
1720 progress_removeitem(&progress
, &badblock_progress
);
1721 progress_update(&progress
);
1724 static secaddr
run_length_wanted(secaddr pos
, secaddr badlen
, secaddr end
)
1725 /* Return the number of good sectors that we want to see before
1726 * we're happy, given that we're about to try to read sector POS,
1727 * which is BADLEN sectors beyond where we found the first bad
1728 * sector, and the current region ends at sector END (i.e., this is
1729 * where the next event occurs).
1734 /* Apply the factor to BADLEN to get an initial length. */
1735 want
= ceil(clear_factor
*badlen
);
1737 /* Apply the user-configurable lower bound. */
1738 if (want
< clear_min
) want
= clear_min
;
1740 /* Cap this with the end of the region. */
1741 if (want
> end
- pos
) want
= end
- pos
;
1743 /* And apply the user-configurable upper bound. */
1744 if (clear_max
&& want
> clear_max
) want
= clear_max
;
1750 static void report_bad_blocks_progress(secaddr bad_hi
, int err
)
1751 /* Report progress while we're trying to work past a region of bad
1752 * sectors. We're about to investigate BAD_HI, and the most recent
1755 { bad_err
= err
; report_progress(bad_hi
); }
1757 static ssize_t
find_good_sector(secaddr
*pos_inout
, secaddr end
,
1758 unsigned char *buf
, secaddr sz
)
1759 /* Work out a place to resume after finding a bad sector. The
1760 * current position, where we found a problem, is in *POS_INOUT. The
1761 * current input region goes up up sector END (i.e., this is where
1762 * the next event occurs). The caller's buffer is at BUF, and can
1763 * hold SZ sectors. On exit, update *POS_INOUT to be the start of a
1764 * region of /good/ sector that we decided was worth exploring, and
1765 * return the number of sectors we've already read at that position
1766 * and left at the start of the buffer. (This number may be zero,
1767 * depending on how things work out. That doesn't mean that we hit
1770 * Altough the return value is `ssize_t', this is only to fit in with
1771 * other read functions; a negative return is not actually possible.
1774 secaddr pos
= *pos_inout
, bad_lo
, bad_hi
, good
, step
, want
;
1775 struct recoverybuf r
;
1778 /* Initial setup. Save the initial state and establish the bad-blocks
1781 bad_start
= pos
; bad_err
= errno
;
1782 badblock_progress
.render
= render_badblock_progress
;
1783 progress_additem(&progress
, &badblock_progress
);
1785 /* First, retry the `bad' sector a few times. Sometimes, with damaged
1786 * discs, this actually works. We'll try to read a full buffer, but we're
1787 * not expecting much.
1789 want
= sz
; if (want
> end
- pos
) want
= end
- pos
;
1790 for (retry
= 0; retry
< max_retries
; retry
++) {
1792 /* Show the progress report. */
1793 report_bad_blocks_progress(pos
, errno
);
1795 /* Try reading stuff. */
1796 n
= read_sectors(pos
, buf
, want
);
1798 progress_clear(&progress
);
1799 printf(";; [retry] try reading %"PRIuSEC
" .. %"PRIuSEC
" -> %zd\n",
1800 pos
, pos
+ want
, n
);
1804 /* We won! Remove the progress display, and leave a permanent message
1805 * to inform the user what happened.
1807 progress_clear(&progress
);
1808 moan("sector %"PRIuSEC
" read ok after retry", pos
);
1809 progress_removeitem(&progress
, &badblock_progress
);
1810 progress_update(&progress
);
1815 /* We're going to have to be more creative. Set up the tracking state. */
1816 r
.buf
= buf
; r
.sz
= sz
; r
.pos
= r
.start
= r
.end
= 0;
1817 r
.good_lo
= r
.good_hi
= 0;
1819 /* Set up the region bound. We know the bad area starts at POS, and that
1820 * it covers at least one sector.
1822 bad_lo
= pos
; bad_hi
= pos
+ 1;
1824 /* Second major step: try to find somewhere on the other side of the bad
1829 progress_clear(&progress
);
1830 printf(";; bounding bad-block region: "
1831 "%"PRIuSEC
" ..%"PRIuSEC
".. %"PRIuSEC
"\n",
1832 bad_lo
, bad_hi
- bad_lo
, bad_hi
);
1835 /* If our upper bound has reached all the way to the end of the input
1836 * region then there's nowhere to recover to. Set the next position to
1837 * the end of the region and return.
1839 if (bad_hi
>= end
) {
1840 progress_clear(&progress
);
1841 moan("giving up on this extent");
1842 recovered(bad_lo
, end
); *pos_inout
= end
;
1846 /* Give a progress update. */
1847 report_bad_blocks_progress(bad_hi
, errno
);
1849 /* Choose a new place to look. Apply the step factor to the size of the
1850 * current gap between the start and end of the bad region, and then
1851 * bound by the user bounds and the input-region end.
1853 * We make progress because `step' is at least 1: `step_min' is at least
1854 * 1, and bad_hi < end or we'd have already bailed.
1856 step
= (step_factor
- 1)*(bad_hi
- bad_lo
);
1857 if (step
< step_min
) step
= step_min
;
1858 if (step_max
&& step
> step_max
) step
= step_max
;
1859 step
+= bad_hi
- bad_lo
;
1860 if (step
> end
- bad_lo
) step
= end
- bad_lo
;
1862 /* Now we look at the last sector of the new interval we've just marked
1865 pos
= bad_lo
+ step
- 1;
1866 want
= run_length_wanted(pos
, step
, end
);
1867 n
= recovery_read(&r
, pos
, want
);
1869 printf(";; [bound] try reading %"PRIuSEC
" .. %"PRIuSEC
" -> %zd\n",
1870 pos
, pos
+ want
, n
);
1873 /* If everything went OK then we're done with this phase. */
1874 if (n
== want
) break;
1876 /* If it failed then extend the bad region to cover (the end of) the bad
1877 * sector which terminated the run, and go around again.
1880 bad_hi
= pos
+ n
+ 1;
1883 /* Third major step: identify exactly where the bad region ends. This is
1887 while (good
> bad_hi
) {
1889 progress_clear(&progress
);
1890 printf(";; limiting bad-block region: "
1891 "%"PRIuSEC
" ..%"PRIuSEC
".. %"PRIuSEC
" ..%"PRIuSEC
".. %"PRIuSEC
"\n",
1892 bad_lo
, bad_hi
- bad_lo
, bad_hi
, good
- bad_hi
, good
);
1895 /* Update the progress report. */
1896 report_bad_blocks_progress(bad_hi
, errno
);
1898 /* Pick a new place to try. */
1899 pos
= bad_hi
+ (good
- bad_hi
)/2; step
= pos
- bad_lo
;
1900 want
= run_length_wanted(pos
, step
, end
);
1903 n
= recovery_read(&r
, pos
, want
);
1905 printf(";; [limit] try reading %"PRIuSEC
" .. %"PRIuSEC
" -> %zd\n",
1906 pos
, pos
+ want
, n
);
1909 /* If that worked -- i.e., we got all the data we wanted -- then bring
1910 * down the `good' bound. If it failed, then bring up `bad_hi' to cover
1911 * the bad sector which terminated our read attempt.
1914 if (n
== want
) good
= pos
;
1915 else bad_hi
= pos
+ n
+ 1;
1918 /* We're done. It's time to tidy up.
1920 * One subtle point: it's possible that, as a result of retrying previous
1921 * bad blocks, that we ended up with bad_hi > good, so it's important that
1922 * we make a consistent choice between the two. I've gone with `good'
1923 * because (a) this gives us more of the original data from the disc and
1924 * (b) hopefully any marginal sectors are now in our buffer
1926 recovered(bad_lo
, good
); *pos_inout
= good
;
1928 /* Figure out how much data we can return to the caller from our buffer. */
1929 if (good
< r
.pos
+ r
.start
|| r
.pos
+ r
.end
<= good
) {
1930 /* Our new position is outside of the region covered by the short-range
1931 * tracking, so there's nothing to return.
1936 /* The new position is covered, so shuffle the data to the start of the
1937 * buffer and return as much as we can.
1940 n
= r
.pos
+ r
.end
- good
;
1941 rearrange_sectors(&r
, 0, good
- r
.pos
, n
);
1946 show_recovery_buffer_map(&r
, "returning %zd good sectors at %"PRIuSEC
"",
1952 /*----- Copying data from a single input file -----------------------------*/
1954 static void emit(secaddr start
, secaddr end
)
1955 /* Copy sectors with absolute addresses from START (inclusive) to END
1956 * (exclusive) to the output. The entire input region comes from the
1957 * same source, already established as `file'.
1960 #define BUFSECTORS 512 /* this is a megabyte */
1963 unsigned char buf
[BUFSECTORS
*SECTORSZ
];
1967 static int first_time
= 1;
1975 /* Choose an active file through which to read the source contents. We're
1976 * guaranteed that this file will do for the entire input region. We
1977 * choose the active file with the smallest index. The virtual `raw' file
1978 * which represents the underlying block device has the largest index, so
1979 * we'll always use a `.VOB' file if one is available. Looking at the
1980 * protocol suggests that the host and drive identify the per-title CSS key
1981 * by the start sector address of the `.VOB' file, so coincident files must
1982 * all use the same key. I've not encountered properly overlapping files
1985 least
= least_live();
1987 printf(";; %8"PRIuSEC
" .. %"PRIuSEC
"\n", start
, end
);
1988 for (i
= 0; i
< filetab
.n
; i
++) {
1989 if (!livep(i
)) continue;
1990 if (act
== -1) act
= i
;
1991 f
= &filetab
.v
[i
]; store_filename(fn
, f
->id
);
1992 printf(";;\t\t%8"PRIuSEC
" .. %-8"PRIuSEC
" %s\n",
1993 start
- f
->start
, end
- f
->start
, fn
);
1995 if (act
== -1) printf(";;\t\t#<no live source>\n");
1996 assert(act
== least
);
1999 /* Set the global variables up for reading from the file we decided on.
2000 * These will be primarily used by `read_sectors' and `update_progress'.
2003 /* There's nothing at all. This can happen because the kernel reported
2004 * the wrong block-device size for some reason but the filesystem has
2005 * identified files which start beyond the reported size, leaving a gap.
2010 /* There's a (possibly) virtual file. */
2012 file
= &filetab
.v
[least
];
2013 switch (id_kind(file
->id
)) {
2016 /* It's the raw device. Clear `vob' to prompt `read_sectors' to read
2017 * directly from `dvdfd'.
2024 /* It's a `.VOB' file. We read these through `libdvdread', which
2025 * handles CSS unscrambling for us.
2028 /* The first time we open a `.VOB' file, `libdvdread' wants to spray
2029 * a bunch of information about how it's getting on cracking the
2030 * title keys. This will interfere with the progress display, so
2031 * preemptively hide the display.
2033 if (first_time
) { progress_clear(&progress
); first_time
= 0; }
2035 /* Open the `.VOB' file. */
2036 vob
= DVDOpenFile(dvd
, id_title(file
->id
),
2038 ? DVD_READ_TITLE_VOBS
2039 : DVD_READ_MENU_VOBS
);
2041 bail("failed to open %s %u",
2042 id_part(file
->id
) ?
"title" : "menu",
2043 id_title(file
->id
));
2047 /* Some other kind of thing; but there shouldn't be anything else in
2048 * the file table, so there's a bug.
2055 /* If we're not reading from the raw device then add an additional progress
2056 * bar for the current file. This isn't completely pointless: having a
2057 * ready visualization for whereabouts we are in a file is valuable when we
2058 * encounter bad blocks, because regions of intentional bad blocks near the
2059 * starts and and ends of VOBs are common on discs from annoying studios.
2061 if (file
&& id_kind(file
->id
) != RAW
) {
2062 file_progress
.render
= render_file_progress
;
2063 progress_additem(&progress
, &file_progress
);
2066 /* Put the progress display back, if we took it away, and show the file
2067 * progress bar if we added one.
2069 update_progress(start
);
2071 /* Read the input region and copy it to the disc. */
2075 /* Decide how much we want. Fill the buffer, unless there's not enough
2078 want
= end
- pos
; if (want
> BUFSECTORS
) want
= BUFSECTORS
;
2080 /* Try to read the input. */
2081 n
= read_sectors(pos
, buf
, want
);
2084 /* It didn't work. Time to deploy the skipping-past-bad-blocks
2085 * machinery we worked so hard on. This will fill the buffer with
2086 * stuff and return a new count of how much it read.
2089 n
= find_good_sector(&pos
, end
, buf
, BUFSECTORS
);
2092 /* We made some progress. Write the stuff that we read to the output
2093 * file and update the position.
2096 carefully_write(outfd
, buf
, n
*SECTORSZ
); pos
+= n
;
2099 /* Report our new progress. */
2100 report_progress(pos
);
2103 /* Close the `libdvdread' file, if we opened one. */
2104 if (vob
) { DVDCloseFile(vob
); vob
= 0; }
2106 /* If we added a per-file progress bar, then take it away again. */
2107 if (file
&& id_kind(file
->id
) != RAW
)
2108 progress_removeitem(&progress
, &file_progress
);
2110 /* Update the progress display to report our glorious success. */
2111 progress_update(&progress
);
2116 /*----- Main program ------------------------------------------------------*/
2118 int main(int argc
, char *argv
[])
2125 secaddr start
, end
, last
;
2126 const struct event
*ev
;
2127 const char *device
, *outfile
;
2128 struct badblock
*bad
;
2132 struct buf buf
= BUF_INIT
;
2133 struct timeval tv0
, tv1
;
2134 double t
, rate
, tot
;
2135 const char *rateunit
, *totunit
;
2136 char timebuf
[TIMESTRMAX
], id_in
[MAXIDSZ
], id_out
[MAXIDSZ
];
2137 dvd_reader_t
*dvd_out
;
2139 const struct file
*file
;
2144 #define f_continue 2u
2147 #define f_checkid 16u
2149 #define f_write 256u
2154 /* First up, handle the command-line options. */
2156 opt
= getopt(argc
, argv
, "hB:E:FP:R:X:b:cir:s"); if (opt
< 0) break;
2160 case 'h': usage(stderr
); exit(0);
2162 /* `-B PARAM=VALUE[,...]': Setting internal parameters. */
2165 /* Set up a cursor into the parameter string. */
2168 #define SKIP_PREFIX(s) \
2169 (STRNCMP(p, ==, s "=", sizeof(s)) && (p += sizeof(s), 1))
2170 /* If the text at P matches `S=' then advance P past that and
2171 * evaluate nonzero; otherwise evaluate zero.
2176 if (SKIP_PREFIX("cf"))
2177 clear_factor
= parse_float(&p
, PNF_JUNK
, 0, DBL_MAX
,
2180 else if (SKIP_PREFIX("cmin"))
2181 clear_min
= parse_int(&p
, PNF_JUNK
, 1, SECLIMIT
,
2184 else if (SKIP_PREFIX("cmax"))
2185 clear_max
= parse_int(&p
, PNF_JUNK
, 1, SECLIMIT
,
2188 else if (SKIP_PREFIX("sf"))
2189 step_factor
= parse_float(&p
, PNF_JUNK
, 0, DBL_MAX
,
2192 else if (SKIP_PREFIX("smin"))
2193 step_min
= parse_int(&p
, PNF_JUNK
, 1, SECLIMIT
- 1,
2196 else if (SKIP_PREFIX("smax"))
2197 step_max
= parse_int(&p
, PNF_JUNK
, 1, SECLIMIT
- 1,
2200 else if (SKIP_PREFIX("retry"))
2201 max_retries
= parse_int(&p
, PNF_JUNK
, 0, INT_MAX
, "retries");
2203 else if (SKIP_PREFIX("alpha"))
2204 alpha
= parse_float(&p
, PNF_JUNK
, 0, 1, "average decay factor");
2206 else if (SKIP_PREFIX("_badwait"))
2207 bad_block_delay
= parse_float(&p
, PNF_JUNK
, 0, DBL_MAX
,
2210 else if (SKIP_PREFIX("_blkwait"))
2211 good_block_delay
= parse_float(&p
, PNF_JUNK
, 0, DBL_MAX
,
2212 "good block delay");
2215 bail("unknown bad blocks parameter `%s'", p
);
2217 /* If we're now at the end of the string then we're done. */
2220 /* We're not done yet, so there should now be a comma and another
2221 * parameter setting.
2223 if (*p
!= ',') bail("unexpected junk in parameters");
2230 /* `-E FILE' (undocumented): Log the bad sectors we encountered to
2233 case 'E': errfile
= optarg
; break;
2235 /* `-F' (undocumented): Hack for fixing up images that were broken by
2236 * an old early-stop bug.
2238 case 'F': f
|= f_fixup
; break;
2240 /* `-P FILE' (undocumented): trace progress state to FILE. */
2242 if (progressfp
) bail("progress trace file already set");
2243 progressfp
= fopen(optarg
, "w");
2245 bail_syserr(errno
, "failed to open progress trace file `%s'",
2249 /* `-R FILE': Read ranges to retry from FILE. Retry ranges are
2250 * converted into `EV_WRITE' and `EV_STOP' events.
2253 fp
= fopen(optarg
, "r");
2255 bail_syserr(errno
, "failed to open ranges file `%s'", optarg
);
2257 /* We're going to try to coalesce adjacent ranges from the file.
2258 * When we found a region to skip, we'd have stopped at the a file
2259 * boundary, and possibly restarted again immediately afterwards,
2260 * resulting in two adjacent regions in the file. To do that, and
2261 * also to police the restriction that ranges occur in ascending
2262 * order, we keep track of the upper bound for the most recent range
2263 * -- but there isn't one yet, so we use a sentinel value.
2268 /* Read a line from the buffer. If there's nothing left then we're
2271 buf_rewind(&buf
); if (read_line(fp
, &buf
)) break;
2273 /* Increment the line counter and establish a cursor. */
2276 /* Skip initial whitespace. */
2277 while (ISSPACE(*p
)) p
++;
2279 /* If this is a comment then ignore it and go round again. */
2280 if (!*p
|| *p
== '#') continue;
2282 /* Parse the range. Check that the ranges are coming out in
2285 if (parse_range(p
, 0, &start
, &end
) ||
2286 (last
<= SECLIMIT
&& start
< last
))
2287 bail("bad range `%s' at `%s' line %zu", buf
.p
, optarg
, i
);
2289 /* Ignore empty ranges: this is important (see below where we sort
2290 * the event queue). If this abuts the previous range then just
2291 * overwrite the previous end position. Otherwise, write a new
2296 eventq
.v
[eventq
.n
- 1].pos
= end
;
2298 put_event(EV_WRITE
, 0, start
);
2299 put_event(EV_STOP
, 0, end
);
2305 /* Check for read errors. */
2307 bail_syserr(errno
, "failed to read ranges file `%s'", optarg
);
2311 /* `-X FILE' (undocumented): Read ranges of bad-blocks from FILE to
2312 * establish fake bad blocks: see `read_sectors' above for the details.
2314 * This is very similar to the `-R' option above, except that it
2315 * doesn't do the range coalescing thing.
2318 fp
= fopen(optarg
, "r");
2320 bail_syserr(errno
, "failed to open bad-blocks file `%s'", optarg
);
2323 buf_rewind(&buf
); if (read_line(fp
, &buf
)) break;
2325 while (ISSPACE(*p
)) p
++;
2326 if (!*p
|| *p
== '#') continue;
2327 if (parse_range(p
, 0, &start
, &end
) ||
2328 (last
<= SECLIMIT
&& start
< last
))
2329 bail("bad range `%s' at `%s' line %zu", buf
.p
, optarg
, i
);
2331 VEC_PUSH(bad
, &badblocks
);
2332 bad
->start
= start
; bad
->end
= end
;
2336 bail_syserr(errno
, "failed to read bad-blocks file `%s'", optarg
);
2339 /* Log regions skipped because of bad blocks to a file. */
2341 if (mapfile
) bail("can't have multiple map files");
2345 /* `-c': Continue copying where we left off last time. */
2346 case 'c': f
|= f_continue
; break;
2348 /* `-i': Check that we're copying from the right disc. */
2349 case 'i': f
|= f_checkid
; break;
2351 /* `-r [START]-[END]': Manually provide a range of sectors to retry. */
2353 start
= 0; end
= -1; f
|= f_retry
;
2354 if (parse_range(optarg
, PRF_HYPHEN
, &start
, &end
))
2355 bail("bad range `%s'", optarg
);
2357 /* Again, ignore empty ranges. */
2358 put_event(EV_WRITE
, 0, start
);
2359 if (end
<= SECLIMIT
) put_event(EV_STOP
, 0, end
);
2363 /* `-s': Print statistics at the end. */
2364 case 's': f
|= f_stats
; break;
2366 /* Anything else is an error. */
2367 default: f
|= f_bogus
; break;
2371 /* We expect two arguments. Check this. Complain about bad usage if we
2372 * have bad arguments or options.
2374 if (argc
- optind
!= 2) f
|= f_bogus
;
2375 if (f
&f_bogus
) { usage(stderr
); exit(2); }
2376 device
= argv
[optind
]; outfile
= argv
[optind
+ 1];
2378 /* If there are fake bad blocks (the `-X' option) then sort the list
2379 * because `read_sectors' wants to use a binary search.
2382 qsort(badblocks
.v
, badblocks
.n
, sizeof(struct badblock
),
2385 printf(";; fake bad blocks:\n");
2386 for (i
= 0; i
< badblocks
.n
; i
++)
2387 printf(";;\t%8"PRIuSEC
" .. %"PRIuSEC
"\n",
2388 badblocks
.v
[i
].start
, badblocks
.v
[i
].end
);
2392 /* Prepare to display progress information. */
2393 setlocale(LC_ALL
, "");
2394 progress_init(&progress
);
2396 /* Open the input device. (This may pop up a notice if there's nothing in
2399 if (open_dvd(device
, O_RDONLY
, &dvdfd
, &dvd
)) exit(2);
2401 /* Determine the size of the input device and check the sector size. */
2402 blksz
= -1; volsz
= device_size(dvdfd
, device
, &blksz
);
2404 { blksz
= SECTORSZ
; f
|= f_file
; }
2405 else if (blksz
!= SECTORSZ
)
2406 bail("device `%s' block size %d /= %d", device
, blksz
, SECTORSZ
);
2408 bail("device `%s' volume size %"PRIu64
" not a multiple of %d",
2409 device
, volsz
, SECTORSZ
);
2411 setup_geometry(&geom
, dvdfd
, f
&f_file ?
0 : GF_BLKDEV
, volsz
/blksz
);
2414 switch (geom
.shape
) {
2416 fprintf(progressfp
, ":model flat-model\n");
2419 fprintf(progressfp
, ":model single-layer-model :start %"PRIuSEC
"\n",
2424 ":model parallel-track-path-model "
2425 ":start0 %"PRIuSEC
" :start1 %"PRIuSEC
" "
2426 ":midpoint %"PRIuSEC
"\n",
2427 geom
.start0
, geom
.start1
, geom
.midpoint
);
2431 ":model opposite-track-path-model "
2432 ":start %"PRIuSEC
" :midpoint %"PRIuSEC
"\n",
2433 geom
.start0
, geom
.midpoint
);
2440 /* Maybe check that we're copying from the right disc. This is intended to
2441 * help avoid image corruption by from the wrong disc, but it obviously
2442 * only works if the output file is mostly there.
2445 if (open_dvd(outfile
, O_RDONLY
, 0, &dvd_out
)) exit(2);
2446 if (dvd_id(id_in
, dvd
, DIF_MUSTIFOHASH
, device
) ||
2447 dvd_id(id_out
, dvd_out
, DIF_MUSTIFOHASH
, device
))
2449 if (STRCMP(id_in
, !=, id_out
))
2450 bail("DVD id mismatch: input `%s' is `%s'; output `%s' is `%s'",
2451 device
, id_in
, outfile
, id_out
);
2454 /* Open the output file. */
2455 outfd
= open(outfile
, O_WRONLY
| O_CREAT
, 0666);
2457 bail_syserr(errno
, "failed to create output file `%s'", outfile
);
2460 /* If we're continuing from where we left off, then find out where that
2461 * was and make a note to copy from there to the end of the disc. Note
2462 * that we're not relying on this position: in particular, it might not
2463 * even be sector-aligned (in which case we'll ignore the final partial
2464 * sector). We'll seek to the right place again when we start writing.
2467 off
= lseek(outfd
, 0, SEEK_END
);
2469 bail_syserr(errno
, "failed to seek to end of output file `%s'",
2471 put_event(EV_WRITE
, 0, off
/SECTORSZ
); f
|= f_retry
;
2474 if (!(f
&(f_retry
| f_fixup
))) {
2475 /* If there are no ranges to retry and we're not fixing an ancient early-
2476 * stop bug, then there's no range to retry and we should just copy
2480 put_event(EV_WRITE
, 0, 0);
2483 /* Now it's time to figure out what the input looks like. Work through the
2484 * titlesets in order, mapping out where the video-object files are. We
2485 * could figure out how many there are properly, but it's fast enough just
2486 * to try everything. That's the menu only for the special titleset 0, and
2487 * menu and titles for the remaining titlesets 1 up to 99.
2490 for (i
= 1; i
< 100; i
++) {
2495 /* Make a final virtual file for the raw device. (See `emit', which
2496 * assumes that this is the last entry in the file table.) Check that we
2497 * don't have more files than we expect, because the bitmap table has fixed
2500 put_file(mkident(RAW
, 0, 0), 0, volsz
/SECTORSZ
);
2501 assert(filetab
.n
<= MAXFILES
);
2503 /* Find an upper limit for what we're supposed to copy. Since the `RAW'
2504 * entry covers the reported size of the input device, this ought to cover
2507 for (i
= 0, limit
= 0; i
< filetab
.n
; i
++)
2508 if (filetab
.v
[i
].end
> limit
) limit
= filetab
.v
[i
].end
;
2510 printf("\n;; files:\n");
2511 for (i
= 0; i
< filetab
.n
; i
++) {
2512 file
= &filetab
.v
[i
];
2513 store_filename(fn
, file
->id
);
2514 printf(";;\t%8"PRIuSEC
" .. %-8"PRIuSEC
" %s\n",
2515 file
->start
, file
->end
, fn
);
2519 /* Sort the event list.
2521 * The event-code ordering is important here.
2523 * * `EV_STOP' sorts /before/ `EV_WRITE'. If we have two abutting ranges
2524 * to retry, then we should stop at the end of the first, and then
2525 * immediately start again. If empty ranges were permitted then we'd
2526 * stop writing and /then/ start, continuing forever, which is clearly
2529 * * `EV_BEGIN' sorts before `EV_END'. If we have empty files then we
2530 * should set the bit that indicates that it's started, and then clear
2531 * it, in that order. If we have abutting files, then we'll just both
2532 * bits for an instant, but that's not a problem.
2534 qsort(eventq
.v
, eventq
.n
, sizeof(struct event
), compare_event
);
2536 /* Check that the event list is well-formed. We start out at the
2537 * beginning, not writing anything.
2539 for (i
= 0, f
&= ~f_write
, start
= 0; i
< eventq
.n
; i
++) {
2544 /* Start writing. We shouldn't be writing yet! */
2547 bail("overlapping ranges: range from %"PRIuSEC
" "
2548 "still open at %"PRIuSEC
"",
2550 f
|= f_write
; start
= ev
->pos
;
2554 /* Stop writing. Make a note that we've done this. */
2561 dump_eventq("initial");
2564 /* Now we make a second pass over the event queue to fix it up. Also
2565 * count up how much work we'll be doing so that we can report progress.
2567 for (i
= 0, f
&= ~f_write
, start
= last
= 0; i
< eventq
.n
; i
++) {
2570 /* If we're supposed to start writing then make a note of the start
2571 * position. We'll want this to count up how much work we're doing. The
2572 * start position of the final range is also used by the logic below that
2573 * determines the progress display.
2575 if (ev
->ev
== EV_WRITE
) { start
= ev
->pos
; f
|= f_write
; }
2577 /* If this event position is past our final limit then stop. Nothing
2578 * beyond here can possibly be interesting. (Since `EV_WRITE' sorts
2579 * before other events, we will notice an `EV_WRITE' exactly at the limit
2580 * sector, but not any other kind of event.)
2582 if (ev
->pos
>= limit
) break;
2584 /* If we're supposed to stop writing here, then add the size of the
2585 * most recent range onto our running total.
2587 if (ev
->ev
== EV_STOP
) {
2588 nsectors
+= ev
->pos
- start
;
2589 total_linear
+= linear_progress(&geom
, start
, ev
->pos
);
2593 /* If we're fixing up images affected by the old early-stop bug, then
2594 * remember this position.
2596 if (f
&f_fixup
) last
= ev
->pos
;
2599 /* Truncate the event queue at the point we reached the sector limit. */
2602 dump_eventq("trimmed");
2605 /* Finally, the early-stop bug fix.
2607 * The bug was caused by a broken version of the event-queue truncation
2608 * logic: it trimmed the event queue, but didn't add a final event at the
2609 * file limit. The effect was that the interval between the last event --
2610 * likely `EV_END' for a VOB file -- and the overall end of the disc didn't
2611 * get copied. We address this by starting to write at the position of
2615 put_event(EV_WRITE
, 0, last
);
2619 /* If we're still writing then avoid the early-end bug by adding an
2620 * `EV_STOP' event at the limit position. Include this range in the sector
2624 nsectors
+= limit
- start
;
2625 total_linear
+= linear_progress(&geom
, start
, limit
);
2626 put_event(EV_STOP
, 0, limit
);
2629 dump_eventq("final");
2632 /* Set up the main progress display.
2634 * If we're copying a single region from somewhere to the end of the disc
2635 * then it seems more sensible to use a single progress bar for both. If
2636 * we're reading multiple ranges, maybe because we're retrying bad blocks,
2637 * then it's better to have separate bars for how much actual copying we've
2638 * done, and which part of the disc we're currently working on.
2640 copy_progress
.render
= render_copy_progress
;
2641 progress_additem(&progress
, ©_progress
);
2642 if (nsectors
== limit
- start
) {
2643 ndone
= start
; nsectors
= limit
;
2644 done_linear
= linear_progress(&geom
, 0, start
);
2645 total_linear
+= done_linear
;
2648 disc_progress
.render
= render_disc_progress
;
2649 progress_additem(&progress
, &disc_progress
);
2652 /* If we're producing overall statistics then make a note of the current
2655 if (f
&f_stats
) gettimeofday(&tv0
, 0);
2657 /* We're now ready to start our sweep through the disc. */
2659 printf("\n;; event sweep:\n");
2662 /* We start at the beginning of the disc, and the start of the event queue,
2663 * not writing. We'll advance through the events one by one.
2665 for (pos
= 0, i
= 0, f
&= ~f_write
; i
< eventq
.n
; i
++) {
2667 /* Get the next event. */
2670 /* If there's a nonempty range between here and the previous event then
2671 * we need to process this.
2673 if (ev
->pos
> pos
) {
2675 /* If we're writing then copy the interval from the previous event to
2676 * here to the output.
2678 if (f
&f_write
) emit(pos
, ev
->pos
);
2680 /* Advance the current position now that the output is up-to-date. */
2684 progress_clear(&progress
);
2689 /* Decide what to action to take in response to the event. */
2693 /* A file has started. Set the appropriate bit in the active-files
2698 store_filename(fn
, filetab
.v
[ev
->file
].id
);
2699 progress_clear(&progress
);
2700 printf(";; %8"PRIuSEC
": begin `%s'\n", pos
, fn
);
2705 /* We're supposed to start writing. */
2707 /* Note the current time and position for the progress display. */
2708 gettimeofday(&last_time
, 0); last_pos
= pos
;
2710 /* Seek to the right place in the output file. */
2711 if (lseek(outfd
, (off_t
)ev
->pos
*SECTORSZ
, SEEK_SET
) < 0)
2713 "failed to seek to resume position "
2714 "(sector %"PRIuSEC
") in output file `%s'",
2717 /* Engage the write head. */
2721 progress_clear(&progress
);
2722 printf(";; %8"PRIuSEC
": begin write\n", pos
);
2727 /* We're supposed to stop writing. Disengage the write head. */
2731 progress_clear(&progress
);
2732 printf(";; %8"PRIuSEC
": end write\n", pos
);
2737 /* We've found the end of a file. Clear its bit in the table. */
2739 clear_live(ev
->file
);
2741 store_filename(fn
, filetab
.v
[ev
->file
].id
);
2742 progress_clear(&progress
);
2743 printf(";; %8"PRIuSEC
": end `%s'\n", pos
, fn
);
2747 /* Something else. Clearly a bug. */
2752 /* Take down the progress display because we're done. */
2753 progress_clear(&progress
);
2755 /* Set the output file length correctly. */
2756 if (ftruncate(outfd
, (off_t
)limit
*SECTORSZ
) < 0)
2757 bail_syserr(errno
, "failed to set output file `%s' length", outfile
);
2759 /* Report overall statistics. */
2761 gettimeofday(&tv1
, 0); t
= tvdiff(&tv0
, &tv1
);
2762 if (nsectors
== limit
) { ndone
-= start
; nsectors
-= start
; }
2763 tot
= scale_bytes((double)nsectors
*SECTORSZ
, &totunit
);
2764 rate
= scale_bytes((double)nsectors
*SECTORSZ
/t
, &rateunit
);
2765 moan("all done: %.1f %sB in %s -- %.1f %sB/s",
2766 tot
, totunit
, fmttime(t
, timebuf
), rate
, rateunit
);
2770 if (dvd
) DVDClose(dvd
);
2771 if (dvdfd
>= 0) close(dvdfd
);
2772 if (outfd
>= 0) close(outfd
);
2773 carefully_fclose(mapfp
, "bad-sector region map");
2774 carefully_fclose(errfp
, "bad-sector error log");
2775 carefully_fclose(progressfp
, "progress trace file");
2776 progress_free(&progress
);
2788 /*----- That's all, folks -------------------------------------------------*/