// $Id$ // // 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include "LoggerWidget.h" #include "Options.h" #include "VerifyDlg.h" #include "TapeDrive.h" #include "Util.h" #include "VerifyDlg.moc" VerifyDlg::VerifyDlg( const TQString & workingDir, int fileno, const RangeList& ranges, bool restore, TQWidget* parent, const char* name ) : TQDialog( parent, name, TRUE ), _restore( restore ), _proc( NULL ), _workingDir( workingDir ), _fileno( fileno ), _ranges( ranges ), _totalKBytes( 0.0 ), _fileCount( 0 ), _wroteStdin( TRUE ), _aborted( FALSE ), _done( FALSE ) { // Calculate size of verify. TQPtrListIterator i( _ranges.getRanges() ); _archiveSize = 0; for ( ; i.current(); ++i ) { _archiveSize += i.current()->getEnd() - i.current()->getStart(); } _archiveSize = ( _archiveSize + 1 ) / 2; if ( _restore ) { setCaption( i18n( "KDat: Restore" ) ); setIconText( i18n( "KDat: Restore" ) ); } else { setCaption( i18n( "KDat: Verify" ) ); setIconText( i18n( "KDat: Verify" ) ); } resize( 500, 300 ); /* 2002-01-26 LEW: "Time remaining" was cut off in mid-"g" in BackupDlg.cpp, so we'll provide that plus some space beyond it. */ // const int labelWidth = 96; const int labelWidth = 110; TQFrame* f1 = new TQFrame( this ); f1->setFrameStyle( TQFrame::Panel | TQFrame::Sunken ); TQFrame* f2 = new TQFrame( this ); f2->setFrameStyle( TQFrame::Panel | TQFrame::Sunken ); TQLabel* lbl1 = new TQLabel( i18n( "Elapsed time:" ), f1 ); lbl1->setFixedSize( labelWidth, lbl1->sizeHint().height() ); _elapsedTime = new TQLabel( i18n( "00:00:00" ), f1 ); _elapsedTime->setFixedHeight( _elapsedTime->sizeHint().height() ); TQLabel* lbl2 = new TQLabel( i18n( "Time remaining:" ), f2 ); lbl2->setFixedSize( labelWidth, lbl2->sizeHint().height() ); _timeRemaining = new TQLabel( i18n( "00:00:00" ), f2 ); _timeRemaining->setFixedHeight( _timeRemaining->sizeHint().height() ); TQLabel* lbl3 = new TQLabel( i18n( "Total KB:" ), f1 ); lbl3->setFixedSize( labelWidth, lbl3->sizeHint().height() ); TQLabel* totalKbytes = new TQLabel( Util::kbytesToString( _archiveSize ), f1 ); totalKbytes->setFixedHeight( totalKbytes->sizeHint().height() ); TQLabel* lbl4 = new TQLabel( i18n( "KB read:" ), f2 ); lbl4->setFixedSize( labelWidth, lbl4->sizeHint().height() ); _kbytesRead = new TQLabel( i18n( "0KB" ), f2 ); _kbytesRead->setFixedHeight( _kbytesRead->sizeHint().height() ); TQLabel* lbl5 = new TQLabel( i18n( "Transfer rate:" ), f1 ); lbl5->setFixedSize( labelWidth, lbl5->sizeHint().height() ); _transferRate = new TQLabel( i18n( "0KB/min" ), f1 ); _transferRate->setFixedHeight( _transferRate->sizeHint().height() ); TQLabel* lbl6; if ( _restore ) { lbl6 = new TQLabel( i18n( "Files:" ), f2 ); lbl6->setFixedSize( labelWidth, lbl6->sizeHint().height() ); } else { lbl6 = new TQLabel( i18n( "Differences:" ), f2 ); lbl6->setFixedSize( labelWidth, lbl6->sizeHint().height() ); } _files = new TQLabel( "0", f2 ); _files->setFixedHeight( _files->sizeHint().height() ); if ( _restore ) { _log = new LoggerWidget( i18n( "Restore log:" ), this ); } else { _log = new LoggerWidget( i18n( "Verify log:" ), this ); } _ok = new KPushButton( KStdGuiItem::ok(), this ); _ok->setFixedSize( 80, _ok->sizeHint().height() ); connect( _ok, TQT_SIGNAL( clicked() ), this, TQT_SLOT( slotOK() ) ); _ok->setEnabled( FALSE ); _save = new TQPushButton( i18n( "&Save Log..." ), this ); _save->setFixedSize( 80, _save->sizeHint().height() ); connect( _save, TQT_SIGNAL( clicked() ), _log, TQT_SLOT( save() ) ); _save->setEnabled( FALSE ); _abort = new TQPushButton( i18n( "&Abort" ), this ); _abort->setFixedSize( 80, _abort->sizeHint().height() ); connect( _abort, TQT_SIGNAL( clicked() ), this, TQT_SLOT( slotAbort() ) ); TQVBoxLayout* l1 = new TQVBoxLayout( this, 8, 4 ); TQHBoxLayout* l1_1 = new TQHBoxLayout(); l1->addLayout( l1_1 ); l1_1->addStrut( 3 * lbl1->height() + 16 ); l1_1->addWidget( f1 ); l1_1->addWidget( f2 ); TQVBoxLayout* l1_1_1 = new TQVBoxLayout( f1, 4, 4 ); TQHBoxLayout* l1_1_1_1 = new TQHBoxLayout(); l1_1_1->addLayout( l1_1_1_1 ); l1_1_1_1->addWidget( lbl1 ); l1_1_1_1->addWidget( _elapsedTime, 1 ); TQHBoxLayout* l1_1_1_2 = new TQHBoxLayout(); l1_1_1->addLayout( l1_1_1_2 ); l1_1_1_2->addWidget( lbl3 ); l1_1_1_2->addWidget( totalKbytes, 1 ); TQHBoxLayout* l1_1_1_3 = new TQHBoxLayout(); l1_1_1->addLayout( l1_1_1_3 ); l1_1_1_3->addWidget( lbl5 ); l1_1_1_3->addWidget( _transferRate, 1 ); TQVBoxLayout* l1_1_2 = new TQVBoxLayout( f2, 4, 4 ); TQHBoxLayout* l1_1_2_1 = new TQHBoxLayout(); l1_1_2->addLayout( l1_1_2_1 ); l1_1_2_1->addWidget( lbl2 ); l1_1_2_1->addWidget( _timeRemaining, 1 ); TQHBoxLayout* l1_1_2_2 = new TQHBoxLayout(); l1_1_2->addLayout( l1_1_2_2 ); l1_1_2_2->addWidget( lbl4 ); l1_1_2_2->addWidget( _kbytesRead, 1 ); TQHBoxLayout* l1_1_2_3 = new TQHBoxLayout(); l1_1_2->addLayout( l1_1_2_3 ); l1_1_2_3->addWidget( lbl6 ); l1_1_2_3->addWidget( _files, 1 ); l1->addWidget( _log, 1 ); TQHBoxLayout* l1_2 = new TQHBoxLayout(); l1->addLayout( l1_2 ); l1_2->addStretch( 1 ); l1_2->addWidget( _ok ); l1_2->addWidget( _save ); l1_2->addWidget( _abort ); } VerifyDlg::~VerifyDlg() { } void VerifyDlg::show() { chdir( TQFile::encodeName(_workingDir) ); _proc = new TDEProcess(); //_proc->setExecutable( Options::instance()->getTarCommand() ); *_proc << Options::instance()->getTarCommand(); if ( _restore ) { *_proc << "-xvf" << "-"; } else { *_proc << "-dvf" << "-"; } connect( _proc, TQT_SIGNAL( processExited( TDEProcess* ) ), this, TQT_SLOT( slotProcessExited( TDEProcess* ) ) ); connect( _proc, TQT_SIGNAL( receivedStdout( TDEProcess*, char*, int ) ), this, TQT_SLOT( slotStdout( TDEProcess*, char*, int ) ) ); connect( _proc, TQT_SIGNAL( wroteStdin( TDEProcess* ) ), this, TQT_SLOT( slotWroteStdin( TDEProcess* ) ) ); _startTime = time( NULL ); startTimer( 100 ); _proc->start( TDEProcess::NotifyOnExit, TDEProcess::All ); TQDialog::show(); } void VerifyDlg::slotProcessExited( TDEProcess* ) { TQT_TQOBJECT(this)->killTimers(); delete _proc; // Set this, or we get caught in a loop. _done = TRUE; _ok->setEnabled( TRUE ); _ok->setDefault( TRUE ); _save->setEnabled( TRUE ); _abort->setEnabled( FALSE ); } void VerifyDlg::slotStdout( TDEProcess*, char* buf, int len ) { TQString data; data.replace( 0, len, buf ); /* 2002-02-23 RG */ // data[len] = '\0'; data.truncate( len ); /* 2002-02-23 RG */ _leftover += data; int newlineIndex; while ( ( newlineIndex = _leftover.find( '\n' ) ) > -1 ) { _log->append( _leftover.left( newlineIndex ) ); // Count differences. if ( _restore ) { _fileCount++; } else { int len = _lastFileName.length(); if ( len > 0 ) { if ( _lastFileName == _leftover.left( len ) ) { if ( ( _leftover[len] == ':' ) && ( _leftover[len+1] == ' ' ) ) { _fileCount++; } else { _lastFileName = _leftover.left( newlineIndex ); } } else { _lastFileName = _leftover.left( newlineIndex ); } } else { _lastFileName = _leftover.left( newlineIndex ); } } _leftover.remove( 0, newlineIndex + 1 ); TQString tmp; tmp.setNum( _fileCount ); _files->setText( tmp ); } } void VerifyDlg::slotWroteStdin( TDEProcess* ) { _wroteStdin = TRUE; } void VerifyDlg::slotOK() { if ( _aborted ) { reject(); } else { accept(); } } void VerifyDlg::slotAbort() { _aborted = TRUE; } void VerifyDlg::timerEvent( TQTimerEvent* ) { TQT_TQOBJECT(this)->killTimers(); int oldElapsed = 0; int bytesToRead; int count; char *buf = new char[Options::instance()->getTapeBlockSize()]; TQPtrListIterator i( _ranges.getRanges() ); for ( ; ( !_done ) && ( !_aborted ) && ( i.current() ); ++i ) { // Move to the beginning of the next range. TapeDrive::instance()->seek( _fileno, i.current()->getStart() ); /* 2002-01-30 LEW */ #ifdef DEBUG printf("Seeking to next range: %d-%d\n", i.current()->getStart(), i.current()->getEnd()); #endif /* DEBUG */ /* 2002-01-30 LEW */ // Read in the records and forward them to tar. bytesToRead = ( i.current()->getEnd() - i.current()->getStart() ) * 512; while ( bytesToRead > 0 ) { count = TapeDrive::instance()->read( buf, bytesToRead > Options::instance()->getTapeBlockSize() ? Options::instance()->getTapeBlockSize() : bytesToRead ); if ( count == 0 ) { // I hope this means end-of-file. Break out of the while loop, and process the next range. /* 2002-01-30 LEW */ #ifdef DEBUG printf("VerifyDlg::timerEvent count==0, so I'm skipping to the next range\n"); #endif /* DEBUG */ /* 2002-01-30 LEW */ break; } if ( count < 0 ) { kdError() << i18n( "failed while reading tape data.\n" ); _proc->closeStdin(); delete [] buf; return; } while ( ( !_done ) && ( !_aborted ) && ( !_wroteStdin ) ) TDEApplication::kApplication()->processEvents(); if ( _done || _aborted ) { /* 2002-01-30 LEW */ #ifdef DEBUG printf("VerifyDlg::timerEvent done/aborted, so I'm skipping to the next range\n"); #endif /* DEBUG */ /* 2002-01-30 LEW */ break; } _wroteStdin = FALSE; _proc->writeStdin( buf, count ); bytesToRead -= count; _totalKBytes += (float)count / 1024.0; // Update stats. int elapsed = time( NULL ) - _startTime; if ( elapsed > oldElapsed ) { updateStats(); TDEApplication::kApplication()->processEvents(); if ( _done || _aborted ) { break; } oldElapsed = elapsed; } } } // Update stats. updateStats(); // Send an EOF block to tar. memset( buf, 0, Options::instance()->getTapeBlockSize() ); _proc->writeStdin( buf, Options::instance()->getTapeBlockSize() ); _proc->closeStdin(); delete [] buf; } void VerifyDlg::updateStats() { TQString str; int elapsed = time( NULL ) - _startTime; str= TQString::fromUtf8( TQCString().sprintf( i18n( "%02d:%02d:%02d" ).utf8(), elapsed / 3600, elapsed / 60 % 60, elapsed % 60 ) ); _elapsedTime->setText( str ); int remain = 0; if ( (int)_totalKBytes > 0 ) { remain = (int)(( (float)_archiveSize - _totalKBytes ) * (float)elapsed / _totalKBytes); } if ( remain < 0 ) { remain = 0; } str = TQString::fromUtf8( TQCString().sprintf( i18n( "%02d:%02d:%02d" ).utf8(), remain / 3600, remain / 60 % 60, remain % 60 ) ); _timeRemaining->setText( str ); str = Util::kbytesToString( (int)_totalKBytes ); _kbytesRead->setText( str ); if ( elapsed > 0 ) { str = i18n( "%1/min" ).arg(Util::kbytesToString( (int)_totalKBytes * 60 / elapsed ) ); _transferRate->setText( str ); } }