[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Bug-ddrescue] patch to fill error areas with specific data (--fill,
From: |
Christian Franke |
Subject: |
Re: [Bug-ddrescue] patch to fill error areas with specific data (--fill, --fill-from) |
Date: |
Tue, 05 Jun 2007 23:02:22 +0200 |
User-agent: |
Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.2pre) Gecko/20070111 SeaMonkey/1.1 |
Antonio Diaz Diaz wrote:
Christian Franke wrote:
Yes, using an extra (e.g. Logbook::fill_errors()) method to do this
in a separate pass within do_rescue() is an alternative.
But then already detected error areas would not be filled if ddrescue
is interrupted with ^C.
I meant a pass separate from the rescue. That is, if you use the
--fill option, ddrescue does not rescue anything. It only fills the
error areas described in the logfile. I think it is the best way to be
sure that every bad sector is filled.
With the on-the-fly method, once you have rescued part of the file
without the fill option there is no way to fill the bad sectors so
rescued, unless you overwrite them every retry, what is not very
efficient.
Another alternative:
Only new bad blocks are filled on the fly.
If --refill is specified, all known error areas are re-filled with new
data (nullbytes if none) after reading logfile.
See attached patch. It also fixes a minor issue in Logbook::count_errors().
Christian
diff -up ddrescue-1.4-rc1.orig/ddrescue.cc ddrescue-1.4-rc1/ddrescue.cc
--- ddrescue-1.4-rc1.orig/ddrescue.cc 2007-06-01 00:31:44.000000000 +0200
+++ ddrescue-1.4-rc1/ddrescue.cc 2007-06-05 22:30:18.305674700 +0200
@@ -76,9 +76,47 @@ int writeblock( const int fd, const char
return ( rest > 0 ) ? size - rest : size;
}
+
+int writebadblock( const int fd, char * buf, const int size, const long long
pos,
+ const char * fill_data, const int fill_size ) throw()
+ {
+ if ( fill_data )
+ {
+ int rest = size;
+ while( rest > 0 )
+ {
+ const int n = ( rest <= fill_size ? rest : fill_size );
+ memcpy( buf + size - rest, fill_data, n );
+ rest -= n;
+ }
+ }
+ else
+ memset( buf, 0, size );
+ return writeblock( fd, buf, size, pos );
+ }
+
} // end namespace
+// Return values: 1 write error, 0 OK, -1 interrupted.
+//
+int Logbook::fill_bad_block( const Block & block ) throw()
+ {
+ if( interrupted ) return -1;
+ long rest = block.size();
+ long pos = block.pos();
+ while( rest > 0 )
+ {
+ int size = ( rest <= _softbs ? rest : _softbs );
+ if( writebadblock( _odes, iobuf, size, pos + _offset, _fill_data,
_fill_size ) != size )
+ { show_error( "write error", errno ); return 1; }
+ rest -= size;
+ pos += size;
+ }
+ return 0;
+ }
+
+
// Return values: 1 write error, 0 OK, -1 interrupted, -2 EOF.
//
int Logbook::copy_non_tried_block( const Block & block,
@@ -119,6 +157,11 @@ int Logbook::copy_non_tried_block( const
result.push_back( Sblock( b, Sblock::bad_cluster ) );
else result.push_back( Sblock( b, Sblock::bad_block ) );
errsize += size - rd;
+ if ( _fill_data )
+ {
+ if( writebadblock( _odes, iobuf, size - rd, block.pos() + _offset +
rd, _fill_data, _fill_size ) != size - rd )
+ { show_error( "write error", errno ); return 1; }
+ }
}
}
return 0;
diff -up ddrescue-1.4-rc1.orig/ddrescue.h ddrescue-1.4-rc1/ddrescue.h
--- ddrescue-1.4-rc1.orig/ddrescue.h 2007-06-01 00:07:06.000000000 +0200
+++ ddrescue-1.4-rc1/ddrescue.h 2007-06-05 21:31:15.227549700 +0200
@@ -78,14 +78,19 @@ class Logbook
int errors; // errors found so far
int _ides, _odes; // input and output file descriptors
const bool _nosplit;
+ const char *_fill_data; // optional error area fill data
+ int _fill_size;
+ bool _refill;
std::vector< Sblock > sblock_vector; // note: blocks are consecutive
void set_rescue_domain( const long long ipos, const long long opos,
const long long max_size, const long long isize )
throw();
bool read_logfile() throw();
+ int fill_bad_block( const Block & block ) throw();
int copy_non_tried_block( const Block & block, std::vector< Sblock > &
result ) throw();
int copy_bad_block( const Block & block, std::vector< Sblock > & result )
throw();
void count_errors() throw();
+ int fill_errors() throw();
int copy_non_tried() throw();
int split_errors() throw();
int copy_errors() throw();
@@ -95,8 +100,9 @@ public:
const long long max_size, const long long isize,
const char * name, const int cluster, const int hardbs,
const int max_errors, const int max_retries, const int verbosity,
- const bool complete_only, const bool nosplit ) throw();
- ~Logbook() throw() { delete[] iobuf_base; }
+ const bool complete_only, const bool nosplit,
+ const char * fill_data, const int fill_size, const bool refill )
throw();
+ ~Logbook() throw() { delete[] iobuf_base; delete[] _fill_data; }
long long rescue_ipos() const throw() { return _domain.pos(); }
long long rescue_opos() const throw() { return _domain.pos() + _offset; }
diff -up ddrescue-1.4-rc1.orig/logbook.cc ddrescue-1.4-rc1/logbook.cc
--- ddrescue-1.4-rc1.orig/logbook.cc 2007-06-01 00:57:20.000000000 +0200
+++ ddrescue-1.4-rc1/logbook.cc 2007-06-05 21:13:33.665049700 +0200
@@ -285,14 +285,38 @@ void Logbook::count_errors() throw()
switch( sb.status() )
{
case Sblock::non_tried: break;
- case Sblock::bad_cluster: ++errors; break;
- case Sblock::bad_block: errors += b.hard_blocks( _hardbs ); break;
+ case Sblock::bad_block: ++errors; break;
+ case Sblock::bad_cluster: errors += b.hard_blocks( _hardbs ); break;
case Sblock::done: break;
}
}
}
+// refill damaged parts of the domain
+
+int Logbook::fill_errors() throw()
+ {
+ bool first_post = true;
+ for( unsigned i = 0; i < sblock_vector.size(); ++i )
+ {
+ const Sblock & sb = sblock_vector[i];
+ const Block b = sb.overlap( _domain );
+ if( b.size() == 0 ) { if( sb < _domain ) continue; else break; }
+ if( sb.status() != Sblock::bad_cluster && sb.status() != Sblock::bad_block
) continue;
+ if( _verbosity >= 0 )
+ {
+ show_status( b.pos(), b.pos() + _offset, recsize, errsize, errors,
+ "Filling error areas...", first_post ); first_post = false;
+ }
+ int retval = fill_bad_block( b );
+ if (retval)
+ return retval;
+ }
+ return 0;
+ }
+
+
// Read the non-damaged part of the domain, skipping over the damaged areas.
//
int Logbook::copy_non_tried() throw()
@@ -471,10 +495,12 @@ Logbook::Logbook( const long long ipos,
const long long max_size, const long long isize,
const char * name, const int cluster, const int hardbs,
const int max_errors, const int max_retries, const int
verbosity,
- const bool complete_only, const bool nosplit ) throw()
+ const bool complete_only, const bool nosplit,
+ const char * fill_data, const int fill_size, const bool
refill ) throw()
: filename( name ), _hardbs( hardbs ), _softbs( cluster * hardbs ),
_max_errors( max_errors ), _max_retries( max_retries ),
- _verbosity( verbosity ), _nosplit( nosplit )
+ _verbosity( verbosity ), _nosplit( nosplit ),
+ _fill_data(fill_data), _fill_size(fill_size), _refill(refill)
{
int alignment = sysconf( _SC_PAGESIZE );
if( alignment < _hardbs || alignment % _hardbs ) alignment = _hardbs;
@@ -545,7 +571,9 @@ int Logbook::do_rescue( const int ides,
}
}
int retval = 0;
- if( _max_errors < 0 || errors <= _max_errors )
+ if( _refill && errors > 0 )
+ retval = fill_errors();
+ if( retval == 0 && ( _max_errors < 0 || errors <= _max_errors ) )
retval = copy_non_tried();
if( retval == 0 && !_nosplit && ( _max_errors < 0 || errors <= _max_errors )
)
retval = split_errors();
diff -up ddrescue-1.4-rc1.orig/main.cc ddrescue-1.4-rc1/main.cc
--- ddrescue-1.4-rc1.orig/main.cc 2007-05-31 17:15:56.000000000 +0200
+++ ddrescue-1.4-rc1/main.cc 2007-06-05 21:36:40.977549700 +0200
@@ -62,11 +62,14 @@ void show_help( const int cluster, const
std::printf( " -C, --complete-only do not read new data beyond
logfile limits\n" );
std::printf( " -d, --direct use direct disc access for
input file\n" );
std::printf( " -e, --max-errors=<n> maximum number of error areas
allowed\n" );
+ std::printf( " -f, --fill=<string> fill error areas with string
['\\0']\n" );
+ std::printf( " -F, --fill-from=<file> fill error areas from a file\n"
);
std::printf( " -i, --input-position=<pos> starting position in input file
[0]\n" );
std::printf( " -n, --no-split do not try to split error
areas\n" );
std::printf( " -o, --output-position=<pos> starting position in output
file [ipos]\n" );
std::printf( " -q, --quiet quiet operation\n" );
std::printf( " -r, --max-retries=<n> exit after given retries
(-1=infinity) [0]\n" );
+ std::printf( " -R, --refill refill old error areas\n" );
std::printf( " -s, --max-size=<bytes> maximum size of data to be
copied\n" );
std::printf( " -t, --truncate truncate output file\n" );
std::printf( " -v, --verbose verbose operation\n" );
@@ -182,7 +185,8 @@ int main( const int argc, const char * a
int cluster = 0, hardbs = 512;
int max_errors = -1, max_retries = 0;
int o_direct = 0, o_trunc = 0, verbosity = 0;
- bool complete_only = false, nosplit = false;
+ bool complete_only = false, nosplit = false, refill = false;
+ const char * fill_string = 0, * fill_file = 0;
invocation_name = argv[0];
const Arg_parser::Option options[] =
@@ -193,12 +197,15 @@ int main( const int argc, const char * a
{ 'C', "complete-only", Arg_parser::no },
{ 'd', "direct", Arg_parser::no },
{ 'e', "max-errors", Arg_parser::yes },
+ { 'f', "fill", Arg_parser::yes },
+ { 'F', "fill-from", Arg_parser::yes },
{ 'h', "help", Arg_parser::no },
{ 'i', "input-position", Arg_parser::yes },
{ 'n', "no-split", Arg_parser::no },
{ 'o', "output-position", Arg_parser::yes },
{ 'q', "quiet", Arg_parser::no },
{ 'r', "max-retries", Arg_parser::yes },
+ { 'R', "refill", Arg_parser::no },
{ 's', "max-size", Arg_parser::yes },
{ 't', "truncate", Arg_parser::no },
{ 'v', "verbose", Arg_parser::no },
@@ -229,12 +236,15 @@ int main( const int argc, const char * a
{ show_error( "direct disc access not available" ); return
1; }
break;
case 'e': max_errors = getnum( arg, 0, -1, INT_MAX ); break;
+ case 'f': fill_string = arg; break;
+ case 'F': fill_file = arg; break;
case 'h': show_help( cluster_bytes / default_hardbs, default_hardbs );
return 0;
case 'i': ipos = getnum( arg, hardbs, 0 ); break;
case 'n': nosplit = true; break;
case 'o': opos = getnum( arg, hardbs, 0 ); break;
case 'q': verbosity = -1; break;
case 'r': max_retries = getnum( arg, 0, -1, INT_MAX ); break;
+ case 'R': refill = true; break;
case 's': max_size = getnum( arg, hardbs, -1 ); break;
case 't': o_trunc = O_TRUNC; break;
case 'v': verbosity = 1; break;
@@ -262,13 +272,34 @@ int main( const int argc, const char * a
if( check_identical ( iname, oname ) )
{ show_error( "infile and outfile are identical" ); return 1; }
+ char * fill_data = 0; int fill_size = 0;
+ if( fill_string && *fill_string )
+ {
+ fill_size = strlen(fill_string);
+ if (fill_size > hardbs) fill_size = hardbs;
+ fill_data = new char[fill_size];
+ memcpy( fill_data, fill_string, fill_size );
+ }
+ else if (fill_file)
+ {
+ int fd = open( fill_file, O_RDONLY );
+ if( fd < 0 ) { show_error( "cannot open fill data file", errno ); return
1; }
+ fill_data = new char[hardbs];
+ fill_size = read( fd, fill_data, hardbs );
+ if (fill_size < 0) show_error( "read error on fill data file", errno );
+ if (fill_size == 0) show_error( "fill data file is empty" );
+ close (fd);
+ if (fill_size <= 0) { delete [] fill_data; return 1; }
+ }
+
const int ides = open( iname, O_RDONLY | o_direct );
if( ides < 0 ) { show_error( "cannot open input file", errno ); return 1; }
const long long isize = lseek( ides, 0, SEEK_END );
if( isize < 0 ) { show_error( "input file is not seekable" ); return 1; }
Logbook logbook( ipos, opos, max_size, isize, logname, cluster, hardbs,
- max_errors, max_retries, verbosity, complete_only, nosplit
);
+ max_errors, max_retries, verbosity, complete_only, nosplit,
+ fill_data, fill_size, refill );
if( logbook.rescue_size() == 0 )
{ if( verbosity >= 0 ) { show_error( "Nothing to do" ); } return 0; }
if( o_trunc && !logbook.blank() )
- [Bug-ddrescue] patch to fill error areas with specific data (--fill, --fill-from), Christian Franke, 2007/06/02
- Re: [Bug-ddrescue] patch to fill error areas with specific data (--fill, --fill-from), Antonio Diaz Diaz, 2007/06/04
- Re: [Bug-ddrescue] patch to fill error areas with specific data (--fill, --fill-from), Christian Franke, 2007/06/04
- Re: [Bug-ddrescue] patch to fill error areas with specific data (--fill, --fill-from), Antonio Diaz Diaz, 2007/06/04
- Re: [Bug-ddrescue] patch to fill error areas with specific data (--fill, --fill-from), Christian Franke, 2007/06/04
- Re: [Bug-ddrescue] patch to fill error areas with specific data (--fill, --fill-from),
Christian Franke <=
- Re: [Bug-ddrescue] patch to fill error areas with specific data (--fill, --fill-from), Antonio Diaz Diaz, 2007/06/08