/* * * $Id: k3breadcdreader.cpp 619556 2007-01-03 17:38:12Z trueg $ * Copyright (C) 2003 Sebastian Trueg * * This file is part of the K3b project. * Copyright (C) 1998-2007 Sebastian Trueg * * 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 #include #include #include #include #include #include #include #include #include #include #include #include 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, TQObject* 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 TQPtrList& readcdBins = readcdProgram->bins(); for( TQPtrListIterator 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, TQT_SIGNAL(stderrLine(const TQString&)), this, TQT_SLOT(slotStdLine(const TQString&)) ); connect( d->process, TQT_SIGNAL(processExited(KProcess*)), this, TQT_SLOT(slotProcessExited(KProcess*)) ); *d->process << d->readcdBinObject; // display progress *d->process << "-v"; // Again we assume the device to be set! *d->process << TQString("dev=%1").arg(K3b::externalBinDeviceParameter(m_readDevice, d->readcdBinObject)); if( m_speed > 0 ) *d->process << TQString("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 << TQString("retries=%1").arg(m_retries); // readcd does not read the last sector specified if( d->firstSector < d->lastSector ) *d->process << TQString("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 TQStringList& params = d->readcdBinObject->userParameters(); for( TQStringList::const_iterator it = params.begin(); it != params.end(); ++it ) *d->process << *it; kdDebug() << "***** readcd parameters:\n"; const TQValueList& args = d->process->args(); TQString s; for( TQValueList::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 TQString& 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( TQRegExp("\\D"), pos )-pos ).toInt(&ok); if( !ok ) { kdError() << "(K3bReadcdReader) problemSector parsing error in line: " << line.mid( pos, line.find( TQRegExp("\\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( TQRegExp("\\D"), pos )-pos ).toInt(&ok); if( !ok ) { kdError() << "(K3bReadcdReader) problemSector parsing error in line: " << line.mid( pos, line.find( TQRegExp("\\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"