I'm currently trying hard to rescue a very big file off a HDD which is about to die (clicking sounds). The read failure is caused by just a small couple defective sectors.
As the backup I could retrieve is way too old, my first plan was to get the file off there even with the corrupt data.
PhotoRec turned out to be the ideal choice for this job since it indeed managed to recover the whole file. (
testdisk was an epic fail, as it would've simply cut off the file where the error was detected)
Having retrieved the (partly corrupt) file onto the intact target HDD, the next steps to take were:
hdparm --read-sector <device>and create binary data files from its output
- use the valid data from these to repair the (few) corrupt sectors using a hex editor like
And indeed, raw-read routines of
hdparm (I used v9.43) (
--read-sector) could be convinced to read the data off the (few) bad sectors on that one erroneous cylinder, but only gave me back a true ascii file. There is no way I know of directly getting the output to a binary file to perform the second step described above. Moreover, all words in the output files turned out to be byte-swapped (x86-32 here on Linux; fixed in v9.45, cf. this older entry in bug tracker).
Fortunately though, there is a way to make it work even with v9.43 and earlier, by using
--verbose option, which (at the
incoming_data line) will allow the hex values to get output exactly as read, in correct byte order!
So this is what I came up with so far, to read 50 sectors starting from 5000:
i=0 while [[ $((i++)) -lt 50 ]]; do sudo hdparm --verbose --read-sector $((5000+i)) /dev/sdb 2>&1 | grep 'incoming_data' | cut -f2- -d: | sed 's/^ //' | tee -a ascdata1_nl done tr '\n' ' ' < ascdata1_nl > ascdata1
Caveat: First file,
ascdata1_nl, still contains newline characters. When the loop is finished, after transforming the newlines into spaces,
ascdata1 will now contain the values as needed. Now byte by byte gets written into a .bin file:
while read -d ' ' hexbyte; do printf "\x$hexbyte" | tee -a bindata.bin; done < ascdata1
The result will be a true binary file which can (e. g. with 'Okteta') be used to replace the (erroneous) zeroed areas in the file.
Short answer: it works that way.
Still, this procedure appears a bit over-complicated to me (?).
Any simpler way to obtain a binary file from a
--read-sector "hex" dump?
perl, I am sure the
hdparmcan be omitted since
unpack()will do a fine job. (Just I haven't managed to do this with byte pairs)
dd conv=swab: I also gave this
ddoption a try, which will unfortunately swap nibbles only, turning
a6b8 d6b7into (useless)