bug-ddrescue
[Top][All Lists]
Advanced

[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() )

reply via email to

[Prev in Thread] Current Thread [Next in Thread]