You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdeadmin/kdat/Archive.cpp

390 lines
9.6 KiB

// KDat - a tar-based DAT archiver
// Copyright (C) 1998-2000 Sean Vyain, svyain@mail.tds.net
// Copyright (C) 2001-2002 Lawrence Widman, kdat@cardiothink.com
//
// 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 2 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, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#include <assert.h>
#include <tqstringlist.h>
#include <kdebug.h>
#include "Archive.h"
#include "Options.h"
#include "TapeManager.h"
Archive::Archive( Tape* tape, int ctime, const TQString & name )
: _stubbed( FALSE ),
_fptr( 0 ),
_offset( 0 ),
_name( name ),
_tape( tape )
{
assert( _tape );
_ctime = ctime;
}
Archive::Archive( Tape* tape, FILE* fptr, int offset )
: _stubbed( TRUE ),
_tape( tape )
{
assert( _tape );
_fptr = fptr;
_offset = offset;
}
Archive::~Archive()
{
}
void Archive::read( int version )
{
if ( !_stubbed ) {
return;
}
_stubbed = FALSE;
fseek( _fptr, _offset, SEEK_SET );
// Archive name (4 bytes + n chars).
int ival;
fread( &ival, sizeof( ival ), 1, _fptr );
char *buf = new char[ival + 1];
buf[ival] = '\0';
fread( buf, sizeof( char ), ival, _fptr );
_name = buf;
delete [] buf;
// Archive creation time (4 bytes).
fread( &ival, sizeof( ival ), 1, _fptr );
_ctime = ival;
// Archive ending block (4 bytes).
fread( &ival, sizeof( ival ), 1, _fptr );
_endBlock = ival;
if ( version > 3 ) {
fread( &ival, sizeof( ival ), 1, _fptr );
int rc = ival;
int start = 0;
int end = 0;
for ( int ii = 0; ii < rc; ii++ ) {
fread( &ival, sizeof( ival ), 1, _fptr );
start = ival;
fread( &ival, sizeof( ival ), 1, _fptr );
end = ival;
_ranges.addRange( start, end );
}
}
// Number of immediate children (4 bytes).
fread( &ival, sizeof( ival ), 1, _fptr );
//===== Read files =====
for ( int count = ival; count > 0; count-- ) {
fread( &ival, sizeof( ival ), 1, _fptr );
addChild( new File( 0, _fptr, ival ) );
}
}
void Archive::readAll( int version )
{
read( version );
TQPtrListIterator<File> i( getChildren() );
for ( ; i.current(); ++i ) {
i.current()->readAll( version );
}
}
void Archive::write( FILE* fptr )
{
_fptr = fptr;
_offset = ftell( _fptr );
int zero = 0;
// Archive name (4 bytes + n chars).
int ival = 4096;
fwrite( &ival, sizeof( ival ), 1, _fptr );
char buf[4096];
memset( buf, 0, 4096 );
memcpy( buf, _name.ascii(), _name.length() > 4095 ? 4095 : _name.length() );
fwrite( buf, sizeof( char ), 4096, _fptr );
// Archive creation time (4 bytes).
ival = getCTime();
fwrite( &ival, sizeof( ival ), 1, _fptr );
// Archive ending block (4 bytes).
ival = getEndBlock();
fwrite( &ival, sizeof( ival ), 1, _fptr );
// Child range list.
ival = _ranges.getRanges().count();
fwrite( &ival, sizeof( ival ), 1, _fptr );
TQPtrListIterator<Range> it( _ranges.getRanges() );
for ( ; it.current(); ++it ) {
ival = it.current()->getStart();
fwrite( &ival, sizeof( ival ), 1, _fptr );
ival = it.current()->getEnd();
fwrite( &ival, sizeof( ival ), 1, _fptr );
}
// Number of immediate children (4 bytes).
ival = getChildren().count();
fwrite( &ival, sizeof( ival ), 1, _fptr );
// Fill in file offsets later...
int fileTable = ftell( _fptr );
for ( ; ival > 0; ival-- ) {
fwrite( &zero, sizeof( zero ), 1, _fptr );
}
//===== Write files =====
TQPtrListIterator<File> i( getChildren() );
int count = 0;
for ( ; i.current(); ++i, count++ ) {
// Fill in the file offset.
int here = ftell( _fptr );
fseek( _fptr, fileTable + 4*count, SEEK_SET );
fwrite( &here, sizeof( here ), 1, _fptr );
fseek( _fptr, here, SEEK_SET );
i.current()->write( _fptr );
}
}
int Archive::getCTime()
{
read();
return _ctime;
}
int Archive::getEndBlock()
{
read();
return _endBlock;
}
TQString Archive::getName()
{
read();
return _name;
}
Tape* Archive::getTape()
{
return _tape;
}
const TQPtrList<File>& Archive::getChildren()
{
read();
return _children;
}
const TQPtrList<Range>& Archive::getRanges()
{
read();
return _ranges.getRanges();
}
void Archive::setEndBlock( int endBlock )
{
read();
_endBlock = endBlock;
if ( _fptr ) {
fseek( _fptr, _offset + 4 + 4096 + 4, SEEK_SET );
fwrite( &_endBlock, sizeof( _endBlock ), 1, _fptr );
}
TapeManager::instance()->tapeModified( _tape );
}
void Archive::setName( const TQString & name )
{
read();
_name = name;
if ( _fptr ) {
char buf[4096];
fseek( _fptr, _offset + 4, SEEK_SET );
memset( buf, 0, 4096 );
memcpy( buf, _name.ascii(), _name.length() > 4095 ? 4095 : _name.length() );
fwrite( buf, sizeof( char ), 4096, _fptr );
fflush( _fptr );
}
/* 2002-01-31 LEW */
#ifdef DEBUG
else {
printf("Archive::setName::_fptr is NULL. %s %d\n", __FILE__, __LINE__);
}
#endif /* DEBUG */
/* 2002-01-31 LEW */
TapeManager::instance()->tapeModified( _tape );
}
void Archive::addChild( File* file )
{
read();
_children.append( file );
}
File* Archive::addFile( int size, int mtime, int startRecord, int endRecord, const TQString & filename )
{
read();
TQStringList path;
TQString fn( filename );
int idx = 0;
while ( ( idx = fn.find( '/' ) ) > -1 ) {
path.append( fn.left( idx + 1 ) );
fn.remove( 0, idx + 1 );
}
if ( fn.length() == 0 ) {
fn = path.last();
path.remove(path.last());
}
File* file = 0;
if ( path.count() == 0 ) {
// Top level file/directory.
file = new File( 0, size, mtime, startRecord, endRecord, fn );
addChild( file );
return file;
}
TQString dir = path.first();
//path.remove(path.first());
path.remove(path.begin());
TQPtrListIterator<File> i( getChildren() );
File* parent = 0;
for ( ; i.current() ; ++i ) {
if ( i.current()->getName() == dir ) {
parent = i.current();
break;
}
}
if ( parent == 0 ) {
parent = new File( 0, 0, 0, startRecord, endRecord, dir );
addChild( parent );
}
for ( TQStringList::Iterator j = path.begin();
j != path.end();
++j ) {
TQString dir = *j;
File* pparent = parent;
TQPtrListIterator<File> i( pparent->getChildren() );
for ( parent = 0; i.current() ; ++i ) {
if ( i.current()->getName() == dir ) {
parent = i.current();
break;
}
}
if ( parent == 0 ) {
parent = new File( pparent, 0, 0, 0, 0, dir );
pparent->addChild( parent );
}
}
file = new File( parent, size, mtime, startRecord, endRecord, fn );
parent->addChild( file );
return file;
}
void Archive::calcRanges()
{
assert( !_stubbed );
_ranges.clear();
TQPtrListIterator<File> it( getChildren() );
for ( ; it.current(); ++it ) {
it.current()->calcRanges();
TQPtrListIterator<Range> it2( it.current()->getRanges() );
for ( ; it2.current(); ++it2 ) {
_ranges.addRange( it2.current()->getStart(), it2.current()->getEnd() );
}
}
//%%% This is a kludge to cope with a bug that I haven't found yet.
//%%% If there is more than one range, then all of the ranges are merged
//%%% into one big contiguous range.
if ( _ranges.getRanges().count() > 1 ) {
kdDebug() << "Archive::calcRanges() -- extra ranges detected, fixing..." << endl;
TQPtrListIterator<Range> iter( _ranges.getRanges() );
for ( ; iter.current(); ++iter ) {
kdDebug() << "Archive::calcRanges() -- range = " << iter.current() << " to " << iter.current()->getEnd() << endl;
}
int start = _ranges.getRanges().getFirst()->getStart();
int end = _ranges.getRanges().getLast()->getEnd();
_ranges.clear();
_ranges.addRange( start, end );
}
/* 2002-01-26 LEW */
// printf("Ranges of tar files on tape (1):\n");
/* 2002-01-26 LEW */
assert( _ranges.getRanges().count() <= 1 );
/* 2002-01-26 LEW */
{
#ifdef DEBUG
#if 0 /* commented out because of compile warnings. Fix 'em if this is needed. */
Range *ptr;
// printf("Ranges of tar files on tape (2):\n");
for ( ptr = _ranges.getRanges().first();
ptr;
ptr = _ranges.getRanges().next() ){
// printf("Range: start %d, end %d\n", ptr->getStart(), ptr->getEnd());
}
#endif
#endif /* DEBUG */
if( _ranges.getRanges().getFirst() == NULL ){
printf("There aren't any tar files on this tape as far as kdat can tell!\n");
_endBlock = 0;
return;
}
/* 2002-01-26 LEW */
_endBlock = _ranges.getRanges().getFirst()->getEnd()
/ ( Options::instance()->getTapeBlockSize() / 512 );
}
}