bug-ddrescue
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Bug-ddrescue] patch to fill error areas with specific data (--fill, --


From: Christian Franke
Subject: [Bug-ddrescue] patch to fill error areas with specific data (--fill, --fill-from)
Date: Sat, 02 Jun 2007 22:50:16 +0200
User-agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.2pre) Gecko/20070111 SeaMonkey/1.1

Hi,

the attached patch adds a feature I recently missed when I recovered a damaged DVD with ddrescue:

-f, --fill="STRING" -- Fills error areas with "STRING" instead of nulls.

-F, --fill-from=FILE -- Same, but data is read from FILE.

The fill data is repeated up to the size of the error area.
Data sizes greater than the block size (-b) are silently ignored.

On a failed read retry, the (possibly changed) fill data is rewritten.


Example:

$ ddrescue -f "BAD BLOCK " ...

fills the error areas with "BAD BLOCK BAD BLOCK BAD BLOCK ..."

This allows to find the bad blocks e.g. when the image is examined in a hex editor.


Thanks for any comment

Christian

diff -rup 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-02 21:52:35.046875000 +0200
@@ -76,6 +76,20 @@ 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()
+  {
+  int rest = size;
+  while( rest > 0 )
+   {
+     int n = ( rest <= fill_size ? rest : fill_size );
+     memcpy( buf + size - rest, fill_data, n );
+     rest -= n;
+   }
+  return writeblock( fd, buf, size, pos );
+  }
+
 } // end namespace
 
 
@@ -119,6 +133,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() + rd, 
_fill_data, _fill_size ) != size - rd )
+          { show_error( "write error", errno ); return 1; }
+        }
       }
     }
   return 0;
@@ -153,7 +172,14 @@ int Logbook::copy_bad_block( const Block
     {
     if( !errno1 ) { errsize -= size - rd; return -2; } // EOF
     else                                               // read_error
+      {
       result.push_back( Sblock( block.pos()+rd, size-rd, Sblock::bad_block ) );
+      if (_fill_data)
+        {
+        if( writebadblock( _odes, iobuf, size - rd, block.pos() + rd, 
_fill_data, _fill_size ) != size - rd )
+          { show_error( "write error", errno ); return 1; }
+        }
+      }
     }
   return 0;
   }
diff -rup 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-02 21:11:35.531250000 +0200
@@ -78,6 +78,8 @@ 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;
   std::vector< Sblock > sblock_vector; // note: blocks are consecutive
 
   void set_rescue_domain( const long long ipos, const long long opos,
@@ -95,8 +97,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, int fill_size ) 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 -rup 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-02 21:29:00.515625000 +0200
@@ -471,10 +471,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, int fill_size ) 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)
   {
   int alignment = sysconf( _SC_PAGESIZE );
   if( alignment < _hardbs || alignment % _hardbs ) alignment = _hardbs;
diff -rup 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-02 21:30:49.500000000 +0200
@@ -62,6 +62,8 @@ 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" );
@@ -183,6 +185,7 @@ int main( const int argc, const char * a
   int max_errors = -1, max_retries = 0;
   int o_direct = 0, o_trunc = 0, verbosity = 0;
   bool complete_only = false, nosplit = false;
+  const char * fill_string = 0, * fill_file = 0;
   invocation_name = argv[0];
 
   const Arg_parser::Option options[] =
@@ -193,6 +196,8 @@ 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  },
@@ -229,6 +234,8 @@ 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;
@@ -262,13 +269,33 @@ 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 );
+    close (fd);
+    if (fill_size < 0) 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 );
   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]