[plug] CD/DVD recovery

Brad Campbell brad at wasp.net.au
Tue Aug 17 12:38:58 WST 2004


G'day all

For recovering badly scratched CD's I use cdparanoia. It might take 12 hours to read 1 3 minute song 
but it gets the audio off. I never found anything that would work for CD's & DVD's to retrieve an 
.iso image. A friend lent me some (ahem) cheap dvd's she picked up in a 3rd world country and I 
noticed that most of them were either de-laminating, warped or so badly scratched they would not 
even polish clean with toothpaste. Needless to say they were impossible to copy by regular means, so 
I took this as a challenge. The script below is the result.

It reads a dvd/cd 10000*512 bytes at a time (dd standard blocks) and will retry a block until it's 
blue in the face. If it reads a partial block it will take up reading from the end of the completed 
portion next time and if it reads nothing it will wind back 10 blocks and have another go.
It took about 8 hours but it managed a complete read of the worst disk I have ever seen and the 
image was then loopback mounted, ripped and de-css'd with vobcopy to play perfectly with xine. So I won!

I have 3 dvd readers. My laptop drive, my Internal dvd drive and my USB-2 DVD writer. One disk was 
so bad that the internal and laptop drives would not even ack it existed. The dvd writer would 
though and that is the one that took 8 hours to get a read.
You can resume the read on another drive by hand editing the POS value to the last POS it printed 
before you gave it the ctrl-c.

I used it to move the read around the 3 different drives as some drives had better luck with certain 
parts of the disk.

I post it here certainly not as an example of good bash code (or any code for that matter) but 
simply hoping it might help someone one day.

It's a bit unorthodox in its usage of fdisk to determine the number of blocks on the disk, but it's 
the only way I came up with from the shell. It's also dirty in the way it reads the output from dd 
(I used to check dd's error code but I found it impossible to do if I was redirecting the output as 
I ended up checking the errorcode of the redirection or I ended up grepping the result code. So I 
just check to see if were at the end of the disk by total number of blocks or I check to see if we 
spat out as many as we were asked to spit out.

Watch the wrap.


#!/bin/sh
BYTES=`fdisk -l /dev/scd0 | grep Disk | cut -f2 -d"," | cut -f2 -d" "`
BLOCKS=`dc -e "$BYTES 512 / p"`
echo $BLOCKS
COUNT=10000
POS=0
while [ "$POS" -le "$BLOCKS" ] ; do
         let RETRY=1
         let RCOUNT=0
         while [ ! "$RETRY" -eq "0" ] ; do
         COPIED=`dd if=/dev/scd0 of=/raid0/test.iso seek=$POS skip=$POS count=$COUNT 2>&1 | grep 
"records out" | cut -f1 -d"+"`
         echo -n Copied $COPIED blocks from $POS " "
         let POS+=$COPIED
         if [ "$COPIED" -ne "$COUNT" ] ; then
                 echo
                 echo Copied not equal to count!
                 if [ "$POS" -ne "$BLOCKS" ] ; then
                         echo And were not at end of disc
                         let RETRY=1
                 else echo Yahoo!!! End of disk!
                      exit 1
                 fi;
                 else let RETRY=0
         fi;
         if [ "$COPIED" -eq "0" ] ; then
                 let POS-=10
                 fi;
         echo with Result $RETRY and $RCOUNT retries
         let RCOUNT++
         if [ "$RCOUNT" -ge "50" ] ; then
                 echo Ctrl-S here to clean disk
                 eject /dev/scd0
                 sleep 1
                 eject -t /dev/scd0
                 sleep 1
                 let RCOUNT=0
                 fi;
         done;
done;



More information about the plug mailing list