/* GNU ddrescue - Data recovery tool
Copyright (C) 2004, 2005, 2006, 2007 Antonio Diaz Diaz.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
class Block
{
long long _pos, _size; // size == -1 means undefined size
static bool verify( const long long p, const long long s ) throw()
{ return ( p >= 0 && s >= -1 && ( s < 0 || p + s >= 0 ) ); }
public:
Block() throw() : _pos( 0 ), _size( 0 ) {}
Block( const long long p, const long long s ) throw();
long long pos() const throw() { return _pos; }
long long size() const throw() { return _size; }
long long end() const throw() { return (_size < 0) ? -1 : _pos + _size; }
long long hard_blocks( const int hardbs ) const throw();
void pos( const long long p ) throw();
void size( const long long s ) throw();
void dec_pos( const long long delta ) throw();
void inc_size( const long long delta ) throw();
bool operator<( const Block & b ) const throw() { return _pos < b._pos; }
bool can_be_split( const int hardbs ) const throw();
bool follows( const Block & b ) const throw()
{ return ( b._size >= 0 && b._pos + b._size == _pos ); }
bool includes( const long long pos ) const throw()
{ return ( _pos <= pos && ( _size < 0 || _pos + _size > pos ) ); }
bool overlaps( const Block & b ) const throw()
{ return ( ( _size < 0 || _pos + _size > b._pos ) &&
( b._size < 0 || b._pos + b._size > _pos ) ); }
bool join( const Block & b ) throw();
Block overlap( const Block & b ) const throw();
Block split( long long pos, const int hardbs = 1 ) throw();
Block backsplit( long long pos, const int hardbs = 1 ) throw();
};
class Sblock : public Block
{
public:
enum Status
{ non_tried = '?', non_trimmed = '*', non_split = '/', bad_block = '-',
finished = '+' };
private:
Status _status;
public:
Sblock( const Block & b, const Status st ) throw();
Sblock( const long long p, const long long s, const Status st ) throw();
Status status() const throw() { return _status; }
void status( const Status st ) throw();
bool join( const Sblock & sb ) throw()
{ if( _status == sb._status ) return Block::join( sb ); else return false; }
Sblock split( const long long pos, const int hardbs = 1 ) throw()
{ return Sblock( Block::split( pos, hardbs ), _status ); }
static bool isstatus( const int st ) throw()
{ return ( st == non_tried || st == non_trimmed || st == non_split ||
st == bad_block || st == finished ); }
};
class Logbook
{
public:
enum Status
{ copying = '?', trimming = '*', splitting = '/', retrying = '-',
finished = '+' };
private:
long long _current_pos;
Status _current_status;
Block _domain; // rescue domain
char *iobuf_base, *_iobuf; // iobuf is aligned to page and hardbs
const char * const _filename;
const int _hardbs, _softbs, _verbosity;
const char * _final_msg;
int _final_errno;
std::vector< Sblock > sblock_vector; // note: blocks are consecutive
bool read_logfile() throw();
bool check_domain_size( const long long isize ) throw();
public:
Logbook( const long long pos, const long long max_size,
const long long isize, const char * name,
const int cluster, const int hardbs,
const int verbosity, const bool complete_only ) throw();
~Logbook() throw() { delete[] iobuf_base; }
bool blank() const throw();
void compact_sblock_vector() throw();
void split_domain_border_sblocks() throw();
bool update_logfile( const int odes, const bool force = false ) throw();
long long current_pos() const throw() { return _current_pos; }
Status current_status() const throw() { return _current_status; }
const Block & domain() const throw() { return _domain; }
const char *filename() const throw() { return _filename; }
char * iobuf() const throw() { return _iobuf; }
int hardbs() const throw() { return _hardbs; }
int softbs() const throw() { return _softbs; }
int verbosity() const throw() { return _verbosity; }
const char * final_msg() const throw() { return _final_msg; }
int final_errno() const throw() { return _final_errno; }
void current_pos( const long long pos ) throw() { _current_pos = pos; }
void current_status( Status st ) throw() { _current_status = st; }
void final_msg( const char * const msg ) throw() { _final_msg = msg; }
void final_errno( const int e ) throw() { _final_errno = e; }
const Sblock & sblock( const int i ) const throw() { return sblock_vector[i]; }
Sblock & sblock( const int i ) throw() { return sblock_vector[i]; }
int sblocks() const throw() { return sblock_vector.size(); }
void erase_sblock( const int i ) throw()
{ sblock_vector.erase( sblock_vector.begin() + i ); }
void insert_sblock( const int i, const Sblock & sb ) throw()
{ sblock_vector.insert( sblock_vector.begin() + i, sb ); }
void truncate_vector( const int i ) throw()
{ sblock_vector.erase( sblock_vector.begin() + i, sblock_vector.end() ); }
static bool isstatus( const int st ) throw()
{ return ( st == copying || st == trimming || st == splitting ||
st == retrying || st == finished ); }
};
class Fillbook : public Logbook
{
long long filled_size; // size already filled
long long remaining_size; // size to be filled
int filled_areas; // areas already filled
int remaining_areas; // areas to be filled
int _odes; // output file descriptor
int fill_areas( const std::string & filltypes ) throw();
int fill_block( const Block & b ) throw();
void show_status( const long long opos, bool force = false ) throw();
public:
Fillbook( const long long pos, const long long max_size,
const char * name, const int cluster, const int hardbs,
const int verbosity ) throw()
: Logbook( pos, max_size, 0, name, cluster, hardbs, verbosity, true ) {}
int do_fill( const int odes, const std::string & filltypes ) throw();
bool read_buffer( const long long ipos, const int ides ) throw();
};
class Rescuebook : public Logbook
{
long long offset; // rescue offset (opos - ipos);
long long sparse_size; // end position of pending writes
long long recsize, errsize; // total recovered and error sizes
int errors; // errors found so far
int _ides, _odes; // input and output file descriptors
const int _max_errors, _max_retries;
const bool _nosplit;
const bool _sparse;
bool sync_sparse_file() throw();
int write_block_or_move( const int fd, const char * buf,
const int size, const long long pos ) throw();
int copy_block( const Block & b, int & copied_size, int & error_size ) throw();
void count_errors() throw();
bool too_many_errors() const throw()
{ return ( _max_errors >= 0 && errors > _max_errors ); }
bool find_valid_index( int & index, const Sblock::Status st ) const throw();
int copy_and_update( int & index, const Sblock::Status st,
const int size, bool & block_done,
int & copied_size, int & error_size,
const char * msg, bool & first_post ) throw();
int copy_non_tried() throw();
int trim_errors() throw();
int split_errors() throw();
int copy_errors() throw();
void show_status( const long long ipos, const char * msg = 0,
bool force = false ) throw();
public:
Rescuebook( const long long ipos, const long long opos,
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, const bool sparse ) throw()
: Logbook( ipos, max_size, isize, name, cluster, hardbs,
verbosity, complete_only ),
sparse_size( 0 ), _max_errors( max_errors ),
_max_retries( max_retries ), _nosplit( nosplit ), _sparse( sparse )
{ if( opos < 0 ) offset = 0; else offset = opos - domain().pos(); }
long long rescue_opos() const throw() { return domain().pos() + offset; }
int do_rescue( const int ides, const int odes ) throw();
};
// Defined in ddrescue.cc
//
const char * format_num( long long num, long long max = 999999,
const int set_prefix = 0 ) throw();
void set_handler() throw();
// Defined in main.cc
//
void input_pos_error( const long long pos, const long long isize ) throw();
void internal_error( const char * msg ) throw() __attribute__ ((noreturn));
void show_error( const char * msg,
const int errcode = 0, const bool help = false ) throw();
void write_logfile_header( FILE * f ) throw();
syntax highlighted by Code2HTML, v. 0.9.1