If you're rich enough, there are companies that can do a good job recovering data from disks. I've never been able to afford them, so I can't suggest any. (The last time I looked, the "going rate" was ~$1000 just to look at your problem, and it went up from there to actually do anything about recovering the data.)
As a cheaper solution, I usually start
ddrescue with the "fill from file", no retry, options to get an image with the problem areas filled in with zeros. Then I run
foremost on the result to see what, if anything, I get.
Here's another script - again, for a simpler problem. In this case, I had a lot of floppy disks from which I wanted to recover what I could before I retired my last computer with a floppy disk drive installed. But look at the section I highlighted, where
ddrescue first tries to image the disk. If that fails, it re-runs
ddrescue, retrying each bad spot three times in both the forward and reverse directions, and then zero-fills any remaining bad spots. A similar strategy might get you farther along.
Code:
#!/bin/bash
#############################################################################
#
# Copy the contents of a floppy disk to a sub-directory of Documents
# called Floppy/<Label> where <label> is the disk label. If the disk is
# not labeled, the contents will be copied to "disk_n" where n is incremented
# by one from the last floppy so copied.
#
# Empty floppies will be skipped.
#
#############################################################################
#
# Function to print help message
#
help()
{
cat <<EOF >>/dev/stderr
$0: {-h | --help} : Print this message and exit.
{-o | --output_directory } : Parent directory for output. (Default: $(pwd))
{-i | --image=}image_file_name : Use floppy image (Wild cards permitted.)
{-r | --read=}device_name : Read from device (Default: /dev/fd0)
Input options may be repeated as often as wished.
EOF
exit $1
}
########################
#
# Get or create the output directory
getOutputDir()
{
# Argument: $1=device or image name
# Get the label text, if any
label=$(echo "$(dosfslabel ${1})" | sed 's/^[[:space:]]//;s/[[:space:]]*$//')
[ -z "$label" ] && label="Floppy"
[ "$label" = "NO NAME" ] && label="Floppy"
[ "$label" = "(null)" ] && label="Floppy"
# See if the label has alread been used
[ -z "${dir}" ] && dir="$(pwd)"
ret="${dir}/${label}"
# Create the output directory
if [ -d "${ret}" ] || [ "$label" = "Floppy" ];then
[ -d "${ret}" ] && mv "${ret}" "${ret}_0"
n=0
while [ -d "${ret}_${n}" ]
do
n=$(($n + 1))
done
ret="${ret}_${n}"
fi
mkdir -p "${ret}"
# Return the output directory name
echo "${ret}"
}
########################
#
# Return Y or N
#
# Arguments: $1 = Question
# $2 = Default answer (Must be "Y" or "N")
ask_yes_no()
{
[ "${2}" != "Y" ] && [ "${2}" != "N" ] && echo $0: Default must be \"Y\" or \"N\" > /dev/stderr && exit 2
if [ $2 = Y ]; then
question="${1} (Y/n)"
else
question="${1} (y/N)"
fi
read -p "${question}" resp
echo "${resp}" |sed 's/^[[:space:]]*$/'$2'/;s/^[[:space:]]*//;s/^[nN].*$/N/;s/^[yY].*$/'$2'/'
}
########################
#
# Copy from an input device
#
copy_from()
{
device="${1}"
fini="Y"
while [ "${fini}" = "Y" ]
do
out="$(getOutputDir "${device}")"
# Use ddrescue to create an image of the floppy disk
image="${out}/disk.img"
log="${out}/disk.log"
echo
echo "Creating ${image} from ${device}."
echo ddrescue -nb 1024 "${device}" "${image}" "${log}"
ddrescue -nb 1024 "${device}" "${image}" "${log}"
if [ $? -ne 0 ]
then
echo ddrescue -nb 1024 "${device}" "${image}" "${log}" failed.
echo Removing "${image}", "${log}" and "${out}"
[ -e "${image}" ] && rm -f "${image}"
[ -e "${log}" ] && rm -f "${log}"
[ -e "${out}" ] && rm -rf "${out}"
else
if [ -n "$(grep "-" "${log}")" ]
then
echo ddrescue -dr 3 "${device}" "${image}" "${log}"
ddrescue -dr 3 "${device}" "${image}" "${log}"
echo -n 0$'\x00' > zero
[ -n "$(grep "-" "${log}")" ] && echo "ddrescue --fill=- zero "${image}" "${log}"" && ddrescue --fill=- zero "${image}" "${log}"
rm -f zero
fi
echo Copying the contents of \"${image}\" to \"${out}/\"
opt="ro,users"
[ -f "${image}" ] && opt="loop,${opt}"
sudo mount -t vfat "${image}" /mnt/floppy -o $opt
stat /mnt/floppy/* &>/dev/null
if [ "$?" -ne 0 ]
then
echo "Failed to mount ${image} as a FAT file system."
else
cp -rbv /mnt/floppy/* "${out}"
sudo umount /mnt/floppy &>/dev/null
fi
fi
if [ -b "${device}" ]
then
echo "Remove the floppy disk from the drive. Insert the next one, if any."
fini=$(ask_yes_no "Continue?" Y)
[ "${fini}" != "Y" ] && break
else
break
fi
done
}
#############################################################
#
# Main Program
#
#########################
#
# Make sure that the mount point exists
[ -d /mnt/floppy ] || sudo mkdir -p /mnt/floppy
#########################
#
# Parse the arguments
#
dir="$(pwd)"
temp=$(getopt -n $0 -oho:i::r: -lhelp -loutput_directory -limage -lread -- "$@")
[ $? -ne 0 ] && help 1
eval set -- "$temp"
while true
do
case "$1" in
-h|--help)
help 0;;
-o|--output_directory)
dir=$(dirname "$2"/./)
shift 2
if [ -d "$dir" ]
then
echo Output will be created in "$dir"
else
mkdir -p "$dir"
[ $? -ne 0 ] && echo Could not create directory "$dir" > /dev/stderr && exit 3
echo Output will be created in "$dir"
fi;;
-r|--read)
case "$2" in
"") shift;
copy_from /dev/fd0;;
*) device="$2";
shift 2;
copy_from $device;;
esac;;
--) shift;
break;;
*) echo "Internal setopt error! ("$@")" >> /dev/stderr;
exit 1;;
esac
done
if [ $# -ne 0 ]
then
echo $0: $# unrecognized arguments: \""$@"\" >> /dev/stderr
echo >> /dev/stderr
help 2
fi
exit 0
Note: I'm working on a Win 7 system right now, so, if you copy from that code block, you might find that your file is in MSDOS format, not UNIX. (I.e., contains unneeded \r characters.)