/* * * $Id: k3bclonejob.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 "k3bclonejob.h" #include #include #include #include #include #include #include #include #include #include #include #include class K3bCloneJob::Private { public: Private() : doneCopies(0) { } int doneCopies; }; K3bCloneJob::K3bCloneJob( K3bJobHandler* hdl, TQObject* parent, const char* name ) : K3bBurnJob( hdl, parent, name ), m_writerDevice(0), m_readerDevice(0), m_writerJob(0), m_readcdReader(0), m_removeImageFiles(false), m_canceled(false), m_running(false), m_simulate(false), m_speed(1), m_copies(1), m_onlyCreateImage(false), m_onlyBurnExistingImage(false), m_readRetries(128) { d = new Private; } K3bCloneJob::~K3bCloneJob() { delete d; } void K3bCloneJob::start() { jobStarted(); m_canceled = false; m_running = true; // TODO: check the cd size and warn the user if not enough space // // We first check if cdrecord has clone support // The readcdReader will check the same for readcd // const K3bExternalBin* cdrecordBin = k3bcore->externalBinManager()->binObject( "cdrecord" ); if( !cdrecordBin ) { emit infoMessage( i18n("Could not find %1 executable.").tqarg("cdrecord"), ERROR ); jobFinished(false); m_running = false; return; } else if( !cdrecordBin->hasFeature( "clone" ) ) { emit infoMessage( i18n("Cdrecord version %1 does not have cloning support.").tqarg(cdrecordBin->version), ERROR ); jobFinished(false); m_running = false; return; } if( (!m_onlyCreateImage && !writer()) || (!m_onlyBurnExistingImage && !readingDevice()) ) { emit infoMessage( i18n("No device set."), ERROR ); jobFinished(false); m_running = false; return; } if( !m_onlyCreateImage ) { if( !writer()->supportsWritingMode( K3bDevice::RAW_R96R ) && !writer()->supportsWritingMode( K3bDevice::RAW_R16 ) ) { emit infoMessage( i18n("CD writer %1 does not support cloning.") .tqarg(writer()->vendor()) .tqarg(writer()->description()), ERROR ); m_running = false; jobFinished(false); return; } } if( m_imagePath.isEmpty() ) { m_imagePath = K3b::findTempFile( "img" ); } else if( TQFileInfo(m_imagePath).isDir() ) { m_imagePath = K3b::findTempFile( "img", m_imagePath ); } if( m_onlyBurnExistingImage ) { startWriting(); } else { emit burning( false ); prepareReader(); if( waitForMedia( readingDevice(), K3bDevice::STATE_COMPLETE, K3bDevice::MEDIA_WRITABLE_CD|K3bDevice::MEDIA_CD_ROM ) < 0 ) { m_running = false; emit canceled(); jobFinished(false); return; } emit newTask( i18n("Reading clone image") ); m_readcdReader->start(); } } void K3bCloneJob::prepareReader() { if( !m_readcdReader ) { m_readcdReader = new K3bReadcdReader( this, this ); connect( m_readcdReader, TQT_SIGNAL(percent(int)), this, TQT_SLOT(slotReadingPercent(int)) ); connect( m_readcdReader, TQT_SIGNAL(percent(int)), this, TQT_SIGNAL(subPercent(int)) ); connect( m_readcdReader, TQT_SIGNAL(processedSize(int, int)), this, TQT_SIGNAL(processedSubSize(int, int)) ); connect( m_readcdReader, TQT_SIGNAL(finished(bool)), this, TQT_SLOT(slotReadingFinished(bool)) ); connect( m_readcdReader, TQT_SIGNAL(infoMessage(const TQString&, int)), this, TQT_SIGNAL(infoMessage(const TQString&, int)) ); connect( m_readcdReader, TQT_SIGNAL(newTask(const TQString&)), this, TQT_SIGNAL(newSubTask(const TQString&)) ); connect( m_readcdReader, TQT_SIGNAL(debuggingOutput(const TQString&, const TQString&)), this, TQT_SIGNAL(debuggingOutput(const TQString&, const TQString&)) ); } m_readcdReader->setReadDevice( readingDevice() ); m_readcdReader->setReadSpeed( 0 ); // MAX m_readcdReader->setDisableCorrection( m_noCorrection ); m_readcdReader->setImagePath( m_imagePath ); m_readcdReader->setClone( true ); m_readcdReader->setRetries( m_readRetries ); } void K3bCloneJob::prepareWriter() { if( !m_writerJob ) { m_writerJob = new K3bCdrecordWriter( writer(), this, this ); connect( m_writerJob, TQT_SIGNAL(infoMessage(const TQString&, int)), this, TQT_SIGNAL(infoMessage(const TQString&, int)) ); connect( m_writerJob, TQT_SIGNAL(percent(int)), this, TQT_SLOT(slotWriterPercent(int)) ); connect( m_writerJob, TQT_SIGNAL(percent(int)), this, TQT_SIGNAL(subPercent(int)) ); connect( m_writerJob, TQT_SIGNAL(nextTrack(int, int)), this, TQT_SLOT(slotWriterNextTrack(int, int)) ); connect( m_writerJob, TQT_SIGNAL(processedSize(int, int)), this, TQT_SIGNAL(processedSubSize(int, int)) ); connect( m_writerJob, TQT_SIGNAL(buffer(int)), this, TQT_SIGNAL(bufferStatus(int)) ); connect( m_writerJob, TQT_SIGNAL(deviceBuffer(int)), this, TQT_SIGNAL(deviceBuffer(int)) ); connect( m_writerJob, TQT_SIGNAL(writeSpeed(int, int)), this, TQT_SIGNAL(writeSpeed(int, int)) ); connect( m_writerJob, TQT_SIGNAL(finished(bool)), this, TQT_SLOT(slotWriterFinished(bool)) ); // connect( m_writerJob, TQT_SIGNAL(newTask(const TQString&)), this, TQT_SIGNAL(newTask(const TQString&)) ); connect( m_writerJob, TQT_SIGNAL(newSubTask(const TQString&)), this, TQT_SIGNAL(newSubTask(const TQString&)) ); connect( m_writerJob, TQT_SIGNAL(debuggingOutput(const TQString&, const TQString&)), this, TQT_SIGNAL(debuggingOutput(const TQString&, const TQString&)) ); } m_writerJob->clearArguments(); m_writerJob->setWritingMode( K3b::RAW ); m_writerJob->setClone( true ); m_writerJob->setSimulate( m_simulate ); m_writerJob->setBurnSpeed( m_speed ); m_writerJob->addArgument( m_imagePath ); } void K3bCloneJob::cancel() { if( m_running ) { m_canceled = true; if( m_readcdReader ) m_readcdReader->cancel(); if( m_writerJob ) m_writerJob->cancel(); } } void K3bCloneJob::slotWriterPercent( int p ) { if( m_onlyBurnExistingImage ) emit percent( (int)((double)(d->doneCopies)*100.0/(double)(m_copies) + (double)p/(double)(m_copies)) ); else emit percent( (int)((double)(1+d->doneCopies)*100.0/(double)(1+m_copies) + (double)p/(double)(1+m_copies)) ); } void K3bCloneJob::slotWriterNextTrack( int t, int tt ) { emit newSubTask( i18n("Writing Track %1 of %2").tqarg(t).tqarg(tt) ); } void K3bCloneJob::slotWriterFinished( bool success ) { if( m_canceled ) { removeImageFiles(); m_running = false; emit canceled(); jobFinished(false); return; } if( success ) { d->doneCopies++; emit infoMessage( i18n("Successfully written clone copy %1.").tqarg(d->doneCopies), INFO ); if( d->doneCopies < m_copies ) { K3bDevice::eject( writer() ); startWriting(); } else { if( m_removeImageFiles ) removeImageFiles(); m_running = false; jobFinished(true); } } else { removeImageFiles(); m_running = false; jobFinished(false); } } void K3bCloneJob::slotReadingPercent( int p ) { emit percent( m_onlyCreateImage ? p : (int)((double)p/(double)(1+m_copies)) ); } void K3bCloneJob::slotReadingFinished( bool success ) { if( m_canceled ) { removeImageFiles(); m_running = false; emit canceled(); jobFinished(false); return; } if( success ) { // // Make a quick test if the image is really valid. // Readcd does not seem to have proper exit codes // K3bCloneTocReader ctr( m_imagePath ); if( ctr.isValid() ) { emit infoMessage( i18n("Successfully read disk."), INFO ); if( m_onlyCreateImage ) { m_running = false; jobFinished(true); } else { if( writer() == readingDevice() ) K3bDevice::eject( writer() ); startWriting(); } } else { emit infoMessage( i18n("Failed to read disk completely in clone mode."), ERROR ); removeImageFiles(); m_running = false; jobFinished(false); } } else { emit infoMessage( i18n("Error while reading disk."), ERROR ); removeImageFiles(); m_running = false; jobFinished(false); } } void K3bCloneJob::startWriting() { emit burning( true ); // start writing prepareWriter(); if( waitForMedia( writer(), K3bDevice::STATE_EMPTY, K3bDevice::MEDIA_WRITABLE_CD ) < 0 ) { removeImageFiles(); m_running = false; emit canceled(); jobFinished(false); return; } if( m_simulate ) emit newTask( i18n("Simulating clone copy") ); else emit newTask( i18n("Writing clone copy %1").tqarg(d->doneCopies+1) ); m_writerJob->start(); } void K3bCloneJob::removeImageFiles() { if( !m_onlyBurnExistingImage ) { emit infoMessage( i18n("Removing image files."), INFO ); if( TQFile::exists( m_imagePath ) ) TQFile::remove( m_imagePath ); if( TQFile::exists( m_imagePath + ".toc" ) ) TQFile::remove( m_imagePath + ".toc" ); } } TQString K3bCloneJob::jobDescription() const { if( m_onlyCreateImage ) return i18n("Creating Clone Image"); else if( m_onlyBurnExistingImage ) { if( m_simulate ) return i18n("Simulating Clone Image"); else return i18n("Burning Clone Image"); } else if( m_simulate ) return i18n("Simulating CD Cloning"); else return i18n("Cloning CD"); } TQString K3bCloneJob::jobDetails() const { return i18n("Creating 1 clone copy", "Creating %n clone copies", (m_simulate||m_onlyCreateImage) ? 1 : m_copies ); } #include "k3bclonejob.moc"