Bug 539

Summary: dd gets stuck on bad sectors
Product: Busybox Reporter: James Laird <j_laird>
Component: OtherAssignee: unassigned
Status: RESOLVED FIXED    
Severity: major CC: busybox-cvs
Priority: P5    
Version: unspecified   
Target Milestone: ---   
Hardware: All   
OS: All   
Host: Target:
Build:

Description James Laird 2009-08-05 04:41:07 UTC
busybox dd does not force seek past bad blocks when using conv=sync,noerror (as for example GNU dd does); this appears to cause it to try and read bad sectors in an infinite loop when imaging faulty hard drives, while continuing to write out zero blocks to the output file (breaking sync and never terminating).
Comment 1 Denys Vlasenko 2009-08-05 21:04:52 UTC
What GNU dd does with conv=noerror (without sync, that is)?

sync seems to be a dangerous option for image creation, it will result in extra NUL bytes if there are any short reads.

Typically there are no short reads, but I imagine if you use bs=1M and you hit a bad sector, there will be a short read and then a failed read. You do not want to pad short read result, you want it to be copied as-is, and then next read fails and dd seeks over 1M, writing 1M NULs to output. This at least preserves file size.

With conv=sync,noerror, there will be extra bytes: 1st 1M block is <data up to bad sector><NUL padding to 1M>, 2nd 1M block is 1M of NULs.

I plan to fix the bug in dd.c as follows:

                n = safe_read(ifd, ibuf, ibs);
                if (n == 0)
                        break;
                if (n < 0) {
                        if (!(flags & FLAG_NOERROR))
                                goto die_infile;
                        n = ibs;
                        bb_simple_perror_msg(infile);
==>                     /* GNU dd with conv=noerror skips over "bad blocks" */
==>                     xlseek(ifd, ibs, SEEK_CUR);
                }

Please try it.
Comment 2 James Laird 2009-08-06 05:51:35 UTC
I disagree.
With noerror:
If you get a short read you should seek to the end of the current block and then continue. The short-read block is padded with nulls (standard noerror operation).
Where sync comes in is that blocks for which no data is read at all are correctly inserted as nul blocks in the output (otherwise you break data structures).

From GNU dd - when a partial read occurs, a partial seek is performed:
"advance_input_after_read_error (input_blocksize - partread)"
Your suggestion may advance to a non-block start byte after a partial read.
Comment 3 Denys Vlasenko 2009-08-22 18:07:01 UTC
I do not understand your last comment
Comment 4 Denys Vlasenko 2009-09-20 02:30:17 UTC
Fixed in git, including correct behavior with and without conv=sync