Source Code (Use browser search to find items of interest.)

Class Index

kdat'Archive (./kdeadmin/kdat/Archive.h:33)

class Archive {
    bool _stubbed;

    int         _endBlock;
    int         _ctime;
    FILE*       _fptr;
    int         _offset;
    QString     _name;
    QList<File> _children;
    RangeList   _ranges;
    Tape*       _tape;
public:
    /**
     * Create a new archive.
     *
     * @param tape       The tape containing this archive.
     * @param ctime      The create time of the archive.
     * @param name       The name given to this archive by the user.
     */
    Archive( Tape* tape, int ctime, const char* name );

    /**
     * Create a new stubbed instance of an archive.  The file pointer and
     * offset specify where the actual instance data can be found.  The real
     * data is read on demand when one of the accessor functions is called.
     *
     * @param tape   The tape containing this archive.
     * @param fptr   The open index file containing this archive entry.  The file
     *               must be left open so that the archive entry information can
     *               be read at a later time.
     * @param offset The offset that will be seeked to when reading the archive
     *               entry information.
     */
    Archive( Tape* tape, FILE* fptr, int offset );

    /**
     * Destroy the archive entry and all of its children.
     */
    ~Archive();

    /**
     * Insure that all of the data fields for this archive entry have been read
     * in.  If the archive entry is a stub then the actual data is read from the
     * index file.  If the archive entry is not a stub then no action is taken.
     *
     * @param version The version of the old tape index.
     */
    void read( int version = KDAT_INDEX_FILE_VERSION );

    /**
     * Recursively read the instance data for this archive entry and all of it's
     * children.  This method is used when converting from an older index format.
     *
     * @param version The version of the old tape index.
     */
    void readAll( int version );

    /**
     * Write out the archive entry to the open file.  Entries for each of its
     * children will also be written.
     */
    void write( FILE* fptr );

    /**
     * Get the creation time for this archive.
     *
     * @return The creation time in seconds since the Epoch.
     */
    int getCTime();

    /**
     * Get the last tape block of this archive.
     *
     * @return The last tape block used by this archive.
     */
    int getEndBlock();

    /**
     * Get the name of this archive.
     *
     * @return The name of this archive.
     */
    QString getName();

    /**
     * Get the tape that contains this archive.
     *
     * @return A pointer to the tape containing this archive.
     */
    Tape* getTape();
    
    /**
     * Get the list of top-level files in this archive.
     *
     * @return A list of the immediate children of this archive.
     */
    const QList<File>& getChildren();

    /**
     * Get the list of ranges of this file and all of its children.
     *
     * @return A list of ranges.
     */
    const QList<Range>& getRanges();

    /**
     * Set the ending tape block for this archive.
     *
     * @param endBlock The last tape block used by this archive.
     */
    void setEndBlock( int endBlock );

    /**
     * Set the name of this archive.
     *
     * @param name The new archive name.
     */
    void setName( const char* name );

    /**
     * Add a new top level file as a child of this archive.
     *
     * @param file The file to add.
     */
    void addChild( File* file );

    /**
     * Create a new file entry, and add it to the archive.  Based on the
     * full path name of the file, an appropriate parent is found.  The parent
     * may be this archive or another file entry.  File entries will be created
     * on demand if some or all of the file's path does not yet exist in this
     * archive.
     *
     * @param size        The size, in bytes, of the file.
     * @param mtime       The last modification time for the file, in seconds since
     *                    the Epoch.
     * @param startRecord The first tar record number of this file.
     * @param endRecord   The last tar record number of this file.
     * @param name        The full path name for the file.
     *
     * @return A pointer to the newly created file entry.
     */
    File* addFile( int size, int mtime, int startRecord, int endRecord, const char* name );

    /**
     * Recursively calculate the list of ranges for all of the archive's children.
     */
    void calcRanges();
};

kdat'Archive::Archive() (./kdeadmin/kdat/Archive.cpp:26)

Archive::Archive( Tape* tape, int ctime, const char* name )
        : _stubbed( FALSE ),
          _fptr( 0 ),
          _offset( 0 ),
          _name( name ),
          _tape( tape )
{
    assert( _tape );

    _ctime = ctime;
}


kdat'Archive::Archive() (./kdeadmin/kdat/Archive.cpp:38)

Archive::Archive( Tape* tape, FILE* fptr, int offset )
        : _stubbed( TRUE ),
          _tape( tape )
{
    assert( _tape );

    _fptr   = fptr;
    _offset = offset;
}


kdat'Archive::~Archive() (./kdeadmin/kdat/Archive.cpp:48)

Archive::~Archive()
{
}


kdat'Archive::read() (./kdeadmin/kdat/Archive.cpp:52)

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 ) );
    }
}


kdat'Archive::readAll() (./kdeadmin/kdat/Archive.cpp:104)

void Archive::readAll( int version )
{
    read( version );

    QListIterator<File> i( getChildren() );
    for ( ; i.current(); ++i ) {
        i.current()->readAll( version );
    }
}


kdat'Archive::write() (./kdeadmin/kdat/Archive.cpp:114)

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.data(), _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 );
    QListIterator<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 =====
    QListIterator<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 );
    }
}


kdat'Archive::getCTime() (./kdeadmin/kdat/Archive.cpp:172)

int Archive::getCTime()
{
    read();
    
    return _ctime;
}


kdat'Archive::getEndBlock() (./kdeadmin/kdat/Archive.cpp:179)

int Archive::getEndBlock()
{
    read();

    return _endBlock;
}


kdat'Archive::getName() (./kdeadmin/kdat/Archive.cpp:186)

QString Archive::getName()
{
    read();
    
    return _name;
}


kdat'Archive::getTape() (./kdeadmin/kdat/Archive.cpp:193)

Tape* Archive::getTape()
{
    return _tape;
}


kdat'Archive::getChildren() (./kdeadmin/kdat/Archive.cpp:198)

const QList<File>& Archive::getChildren()
{
    read();

    return _children;
}


kdat'Archive::getRanges() (./kdeadmin/kdat/Archive.cpp:205)

const QList<Range>& Archive::getRanges()
{
    read();

    return _ranges.getRanges();
}


kdat'Archive::setEndBlock() (./kdeadmin/kdat/Archive.cpp:212)

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 );
}


kdat'Archive::setName() (./kdeadmin/kdat/Archive.cpp:226)

void Archive::setName( const char* name )
{
    read();

    _name = name;

    if ( _fptr ) {
        char buf[4096];
        fseek( _fptr, _offset + 4, SEEK_SET );
        memset( buf, 0, 4096 );
        memcpy( buf, _name.data(), _name.length() > 4095 ? 4095 : _name.length() );
        fwrite( buf, sizeof( char ), 4096, _fptr );
        fflush( _fptr );
    }

    TapeManager::instance()->tapeModified( _tape );
}


kdat'Archive::addChild() (./kdeadmin/kdat/Archive.cpp:244)

void Archive::addChild( File* file )
{
    read();
    
    _children.append( file );
}


kdat'Archive::addFile() (./kdeadmin/kdat/Archive.cpp:251)

File* Archive::addFile( int size, int mtime, int startRecord, int endRecord, const char* name )
{
    read();

    QStrList path;

    QString fn( name );
    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.removeLast();
    }

    File* file = 0;
    if ( path.count() == 0 ) {
        // Top level file/directory.
        file = new File( 0, size, mtime, startRecord, endRecord, fn );
        
        addChild( file );
        return file;
    }

    QString dir = path.first();
    path.removeFirst();
    QListIterator<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 );
    }

    QStrListIterator j( path );
    for ( ; j.current(); ++j ) {
        QString dir = j.current();
        File* pparent = parent;
        QListIterator<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;
}


kdat'Archive::calcRanges() (./kdeadmin/kdat/Archive.cpp:318)

void Archive::calcRanges()
{
    assert( !_stubbed );

    _ranges.clear();

    QListIterator<File> it( getChildren() );
    for ( ; it.current(); ++it ) {
        it.current()->calcRanges();
        QListIterator<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 ) {
        debug( "Archive::calcRanges() -- extra ranges detected, fixing..." );
        QListIterator<Range> iter( _ranges.getRanges() );
        for ( ; iter.current(); ++iter ) {
            debug( "Archive::calcRanges() -- range = %d to %d", iter.current()->getStart(), iter.current()->getEnd() );
        }
        int start = _ranges.getRanges().getFirst()->getStart();
        int end = _ranges.getRanges().getLast()->getEnd();
        _ranges.clear();
        _ranges.addRange( start, end );
    }

    assert( _ranges.getRanges().count() <= 1 );

    _endBlock = _ranges.getRanges().getFirst()->getEnd() / ( Options::instance()->getTapeBlockSize() / 512 );
}