/* 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 .
*/
#define _FILE_OFFSET_BITS 64
#include
#include
#include
#include
#include "ddrescue.h"
Block::Block( const long long p, const long long s ) throw()
{
if( !verify( p, s ) )
{
std::fprintf( stderr, "p = %lld, s = %lld, p + s = %lld\n", p, s, p + s );
internal_error( "bad parameter building a Block" );
}
_pos = p; _size = s;
}
long long Block::hard_blocks( const int hardbs ) const throw()
{
if( _size <= 0 ) return _size;
long long s = _size + ( _pos % hardbs );
int tail = ( _pos + _size ) % hardbs;
if( tail != 0 ) s += ( hardbs - tail );
return s / hardbs;
}
void Block::pos( const long long p ) throw()
{
if( !verify( p, _size ) ) internal_error( "bad pos relocating a Block" );
_pos = p;
}
void Block::size( const long long s ) throw()
{
if( !verify( _pos, s ) ) internal_error( "bad size resizing a Block" );
_size = s;
}
void Block::dec_pos( const long long delta ) throw()
{
if( ( _size >= 0 && _size + delta < 0 ) ||
!verify( _pos - delta, (_size >= 0) ? _size + delta : _size ) )
internal_error( "bad delta left extending a Block" );
_pos -= delta; if( _size >= 0 ) _size += delta;
}
void Block::inc_size( const long long delta ) throw()
{
if( _size >= 0 )
{
if( _size + delta < 0 || !verify( _pos, _size + delta ) )
internal_error( "bad delta right extending a Block" );
_size += delta;
}
}
// Returns true if 'block' spans more than one hardware block.
//
bool Block::can_be_split( const int hardbs ) const throw()
{
if( _size <= 0 ) return ( _size < 0 );
return ( _size > hardbs - ( _pos % hardbs ) );
}
bool Block::join( const Block & b ) throw()
{
bool done = false;
if( _size >= 0 && _pos + _size == b._pos )
{ if( b._size >= 0 ) _size += b._size; else _size = -1; done = true; }
else if( b._size >= 0 && b._pos + b._size == _pos )
{ _pos = b._pos; if( _size >= 0 ) _size += b._size; done = true; }
if( done && !verify( _pos, _size ) )
internal_error( "size overflow joining two Blocks" );
return done;
}
Block Block::overlap( const Block & b ) const throw()
{
const long long p = std::max( _pos, b._pos );
long long s;
if( _size < 0 )
{ if( b._size < 0 ) s = -1; else s = std::max( 0LL, b.end() - p ); }
else
{
if( b._size < 0 ) s = std::max( 0LL, end() - p );
else s = std::max( 0LL, std::min( end(), b.end() ) - p );
}
return Block( p, s );
}
Block Block::split( long long pos, const int hardbs ) throw()
{
if( hardbs > 1 ) pos -= pos % hardbs;
if( _pos < pos && ( _size < 0 || _pos + _size > pos ) )
{
const Block b( _pos, pos - _pos );
_pos = pos; if( _size > 0 ) _size -= b._size;
return b;
}
return Block();
}
Block Block::backsplit( long long pos, const int hardbs ) throw()
{
if( hardbs > 1 ) pos -= pos % hardbs;
if( _pos < pos && _size > 0 && _pos + _size > pos )
{
const Block b( pos, _pos + _size - pos );
_size -= b._size;
return b;
}
return Block();
}
Sblock::Sblock( const Block & b, const Status st ) throw()
: Block( b )
{
if( isstatus( st ) ) _status = st;
else internal_error( "bad status building a Sblock" );
}
Sblock::Sblock( const long long p, const long long s, const Status st ) throw()
: Block( p, s )
{
if( isstatus( st ) ) _status = st;
else internal_error( "bad status building a Sblock" );
}
void Sblock::status( const Status st ) throw()
{
if( isstatus( st ) ) _status = st;
else internal_error( "bad status change in a Sblock" );
}