diff options
Diffstat (limited to 'libk3b/jobs/k3breadcdreader.cpp')
-rw-r--r-- | libk3b/jobs/k3breadcdreader.cpp | 335 |
1 files changed, 335 insertions, 0 deletions
diff --git a/libk3b/jobs/k3breadcdreader.cpp b/libk3b/jobs/k3breadcdreader.cpp new file mode 100644 index 0000000..d75eb63 --- /dev/null +++ b/libk3b/jobs/k3breadcdreader.cpp @@ -0,0 +1,335 @@ +/* + * + * $Id: k3breadcdreader.cpp 619556 2007-01-03 17:38:12Z trueg $ + * Copyright (C) 2003 Sebastian Trueg <trueg@k3b.org> + * + * This file is part of the K3b project. + * Copyright (C) 1998-2007 Sebastian Trueg <trueg@k3b.org> + * + * 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. + * See the file "COPYING" for the exact licensing terms. + */ + + +#include "k3breadcdreader.h" + +#include <k3bcore.h> +#include <k3bexternalbinmanager.h> +#include <k3bdevice.h> +#include <k3bdevicemanager.h> +#include <k3bprocess.h> +#include <k3bmsf.h> +#include <k3bglobals.h> + +#include <kdebug.h> +#include <klocale.h> +#include <kconfig.h> + +#include <qregexp.h> +#include <qvaluelist.h> +#include <qstringlist.h> + + + +class K3bReadcdReader::Private +{ +public: + Private() + : process(0), + fdToWriteTo(-1), + canceled(false) { + } + + K3b::Msf firstSector, lastSector; + + K3bProcess* process; + const K3bExternalBin* readcdBinObject; + + int fdToWriteTo; + bool canceled; + + long blocksToRead; + int unreadableBlocks; + + int lastProgress; + int lastProcessedSize; +}; + + + +K3bReadcdReader::K3bReadcdReader( K3bJobHandler* jh, QObject* parent, const char* name ) + : K3bJob( jh, parent, name ), + m_noCorr(false), + m_clone(false), + m_noError(false), + m_c2Scan(false), + m_speed(0), + m_retries(128) +{ + d = new Private(); +} + + +K3bReadcdReader::~K3bReadcdReader() +{ + delete d->process; + delete d; +} + + +bool K3bReadcdReader::active() const +{ + return (d->process ? d->process->isRunning() : false); +} + + +void K3bReadcdReader::writeToFd( int fd ) +{ + d->fdToWriteTo = fd; +} + + +void K3bReadcdReader::start() +{ + jobStarted(); + + d->blocksToRead = 1; + d->unreadableBlocks = 0; + d->lastProgress = 0; + d->lastProcessedSize = 0; + + // the first thing to do is to check for readcd + d->readcdBinObject = k3bcore->externalBinManager()->binObject( "readcd" ); + if( !d->readcdBinObject ) { + emit infoMessage( i18n("Could not find %1 executable.").arg("readcd"), ERROR ); + jobFinished(false); + return; + } + + // check if we have clone support if we need it + if( m_clone ) { + bool foundCloneSupport = false; + + if( !d->readcdBinObject->hasFeature( "clone" ) ) { + // search all readcd installations + K3bExternalProgram* readcdProgram = k3bcore->externalBinManager()->program( "readcd" ); + const QPtrList<K3bExternalBin>& readcdBins = readcdProgram->bins(); + for( QPtrListIterator<K3bExternalBin> it( readcdBins ); it.current(); ++it ) { + if( it.current()->hasFeature( "clone" ) ) { + d->readcdBinObject = it.current(); + emit infoMessage( i18n("Using readcd %1 instead of default version for clone support.").arg(d->readcdBinObject->version), INFO ); + foundCloneSupport = true; + break; + } + } + + if( !foundCloneSupport ) { + emit infoMessage( i18n("Could not find readcd executable with cloning support."), ERROR ); + jobFinished(false); + return; + } + } + } + + + // create the commandline + delete d->process; + d->process = new K3bProcess(); + connect( d->process, SIGNAL(stderrLine(const QString&)), this, SLOT(slotStdLine(const QString&)) ); + connect( d->process, SIGNAL(processExited(KProcess*)), this, SLOT(slotProcessExited(KProcess*)) ); + + + *d->process << d->readcdBinObject; + + // display progress + *d->process << "-v"; + + // Again we assume the device to be set! + *d->process << QString("dev=%1").arg(K3b::externalBinDeviceParameter(m_readDevice, + d->readcdBinObject)); + if( m_speed > 0 ) + *d->process << QString("speed=%1").arg(m_speed); + + + // output + if( d->fdToWriteTo != -1 ) { + *d->process << "f=-"; + d->process->dupStdout( d->fdToWriteTo ); + } + else { + emit newTask( i18n("Writing image to %1.").arg(m_imagePath) ); + emit infoMessage( i18n("Writing image to %1.").arg(m_imagePath), INFO ); + *d->process << "f=" + m_imagePath; + } + + + if( m_noError ) + *d->process << "-noerror"; + if( m_clone ) { + *d->process << "-clone"; + // noCorr can only be used with cloning + if( m_noCorr ) + *d->process << "-nocorr"; + } + if( m_c2Scan ) + *d->process << "-c2scan"; + + *d->process << QString("retries=%1").arg(m_retries); + + // readcd does not read the last sector specified + if( d->firstSector < d->lastSector ) + *d->process << QString("sectors=%1-%2").arg(d->firstSector.lba()).arg(d->lastSector.lba()+1); + + // Joerg sais it is a Linux kernel bug, anyway, with the default value it does not work + *d->process << "ts=128k"; + + // additional user parameters from config + const QStringList& params = d->readcdBinObject->userParameters(); + for( QStringList::const_iterator it = params.begin(); it != params.end(); ++it ) + *d->process << *it; + + + kdDebug() << "***** readcd parameters:\n"; + const QValueList<QCString>& args = d->process->args(); + QString s; + for( QValueList<QCString>::const_iterator it = args.begin(); it != args.end(); ++it ) { + s += *it + " "; + } + kdDebug() << s << endl << flush; + + emit debuggingOutput("readcd command:", s); + + d->canceled = false; + + if( !d->process->start( KProcess::NotifyOnExit, KProcess::AllOutput) ) { + // something went wrong when starting the program + // it "should" be the executable + kdError() << "(K3bReadcdReader) could not start readcd" << endl; + emit infoMessage( i18n("Could not start readcd."), K3bJob::ERROR ); + jobFinished( false ); + } +} + + +void K3bReadcdReader::cancel() +{ + if( d->process ) { + if( d->process->isRunning() ) { + d->canceled = true; + d->process->kill(); + } + } +} + + +void K3bReadcdReader::slotStdLine( const QString& line ) +{ + emit debuggingOutput( "readcd", line ); + + int pos = -1; + + if( line.startsWith( "end:" ) ) { + bool ok; + d->blocksToRead = line.mid(4).toInt(&ok); + if( d->firstSector < d->lastSector ) + d->blocksToRead -= d->firstSector.lba(); + if( !ok ) + kdError() << "(K3bReadcdReader) blocksToRead parsing error in line: " + << line.mid(4) << endl; + } + + else if( line.startsWith( "addr:" ) ) { + bool ok; + long currentReadBlock = line.mid( 6, line.find("cnt")-7 ).toInt(&ok); + if( d->firstSector < d->lastSector ) + currentReadBlock -= d->firstSector.lba(); + if( ok ) { + int p = (int)(100.0 * (double)currentReadBlock / (double)d->blocksToRead); + if( p > d->lastProgress ) { + emit percent( p ); + d->lastProgress = p; + } + int ps = currentReadBlock*2/1024; + if( ps > d->lastProcessedSize ) { + emit processedSize( ps, d->blocksToRead*2/1024 ); + d->lastProcessedSize = ps; + } + } + else + kdError() << "(K3bReadcdReader) currentReadBlock parsing error in line: " + << line.mid( 6, line.find("cnt")-7 ) << endl; + } + + else if( line.contains("Cannot read source disk") ) { + emit infoMessage( i18n("Cannot read source disk."), ERROR ); + } + + else if( (pos = line.find("Retrying from sector")) >= 0 ) { + // parse the sector + pos += 21; + bool ok; + int problemSector = line.mid( pos, line.find( QRegExp("\\D"), pos )-pos ).toInt(&ok); + if( !ok ) { + kdError() << "(K3bReadcdReader) problemSector parsing error in line: " + << line.mid( pos, line.find( QRegExp("\\D"), pos )-pos ) << endl; + } + emit infoMessage( i18n("Retrying from sector %1.").arg(problemSector), INFO ); + } + + else if( (pos = line.find("Error on sector")) >= 0 ) { + d->unreadableBlocks++; + + pos += 16; + bool ok; + int problemSector = line.mid( pos, line.find( QRegExp("\\D"), pos )-pos ).toInt(&ok); + if( !ok ) { + kdError() << "(K3bReadcdReader) problemSector parsing error in line: " + << line.mid( pos, line.find( QRegExp("\\D"), pos )-pos ) << endl; + } + + if( line.contains( "not corrected") ) { + emit infoMessage( i18n("Uncorrected error in sector %1").arg(problemSector), ERROR ); + } + else { + emit infoMessage( i18n("Corrected error in sector %1").arg(problemSector), ERROR ); + } + } + + else { + kdDebug() << "(readcd) " << line << endl; + } +} + +void K3bReadcdReader::slotProcessExited( KProcess* p ) +{ + if( d->canceled ) { + emit canceled(); + jobFinished(false); + } + else if( p->normalExit() ) { + if( p->exitStatus() == 0 ) { + jobFinished( true ); + } + else { + emit infoMessage( i18n("%1 returned error: %2").arg("Readcd").arg(p->exitStatus()), ERROR ); + jobFinished( false ); + } + } + else { + emit infoMessage( i18n("Readcd exited abnormally."), ERROR ); + jobFinished( false ); + } +} + + +void K3bReadcdReader::setSectorRange( const K3b::Msf& first, const K3b::Msf& last ) +{ + d->firstSector = first; + d->lastSector = last; +} + +#include "k3breadcdreader.moc" + |