summaryrefslogtreecommitdiffstats
path: root/libk3b/jobs/k3bclonejob.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libk3b/jobs/k3bclonejob.cpp')
-rw-r--r--libk3b/jobs/k3bclonejob.cpp375
1 files changed, 375 insertions, 0 deletions
diff --git a/libk3b/jobs/k3bclonejob.cpp b/libk3b/jobs/k3bclonejob.cpp
new file mode 100644
index 0000000..9fb61ab
--- /dev/null
+++ b/libk3b/jobs/k3bclonejob.cpp
@@ -0,0 +1,375 @@
+/*
+ *
+ * $Id: k3bclonejob.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 "k3bclonejob.h"
+
+#include <k3breadcdreader.h>
+#include <k3bcdrecordwriter.h>
+#include <k3bexternalbinmanager.h>
+#include <k3bdevice.h>
+#include <k3bdevicehandler.h>
+#include <k3bglobals.h>
+#include <k3bcore.h>
+#include <k3bclonetocreader.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+
+#include <qfile.h>
+#include <qfileinfo.h>
+
+
+
+class K3bCloneJob::Private
+{
+public:
+ Private()
+ : doneCopies(0) {
+ }
+
+ int doneCopies;
+};
+
+
+K3bCloneJob::K3bCloneJob( K3bJobHandler* hdl, QObject* 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.").arg("cdrecord"), ERROR );
+ jobFinished(false);
+ m_running = false;
+ return;
+ }
+ else if( !cdrecordBin->hasFeature( "clone" ) ) {
+ emit infoMessage( i18n("Cdrecord version %1 does not have cloning support.").arg(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.")
+ .arg(writer()->vendor())
+ .arg(writer()->description()), ERROR );
+ m_running = false;
+ jobFinished(false);
+ return;
+ }
+ }
+
+ if( m_imagePath.isEmpty() ) {
+ m_imagePath = K3b::findTempFile( "img" );
+ }
+ else if( QFileInfo(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, SIGNAL(percent(int)), this, SLOT(slotReadingPercent(int)) );
+ connect( m_readcdReader, SIGNAL(percent(int)), this, SIGNAL(subPercent(int)) );
+ connect( m_readcdReader, SIGNAL(processedSize(int, int)), this, SIGNAL(processedSubSize(int, int)) );
+ connect( m_readcdReader, SIGNAL(finished(bool)), this, SLOT(slotReadingFinished(bool)) );
+ connect( m_readcdReader, SIGNAL(infoMessage(const QString&, int)), this, SIGNAL(infoMessage(const QString&, int)) );
+ connect( m_readcdReader, SIGNAL(newTask(const QString&)), this, SIGNAL(newSubTask(const QString&)) );
+ connect( m_readcdReader, SIGNAL(debuggingOutput(const QString&, const QString&)),
+ this, SIGNAL(debuggingOutput(const QString&, const QString&)) );
+ }
+
+ 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, SIGNAL(infoMessage(const QString&, int)), this, SIGNAL(infoMessage(const QString&, int)) );
+ connect( m_writerJob, SIGNAL(percent(int)), this, SLOT(slotWriterPercent(int)) );
+ connect( m_writerJob, SIGNAL(percent(int)), this, SIGNAL(subPercent(int)) );
+ connect( m_writerJob, SIGNAL(nextTrack(int, int)), this, SLOT(slotWriterNextTrack(int, int)) );
+ connect( m_writerJob, SIGNAL(processedSize(int, int)), this, SIGNAL(processedSubSize(int, int)) );
+ connect( m_writerJob, SIGNAL(buffer(int)), this, SIGNAL(bufferStatus(int)) );
+ connect( m_writerJob, SIGNAL(deviceBuffer(int)), this, SIGNAL(deviceBuffer(int)) );
+ connect( m_writerJob, SIGNAL(writeSpeed(int, int)), this, SIGNAL(writeSpeed(int, int)) );
+ connect( m_writerJob, SIGNAL(finished(bool)), this, SLOT(slotWriterFinished(bool)) );
+ // connect( m_writerJob, SIGNAL(newTask(const QString&)), this, SIGNAL(newTask(const QString&)) );
+ connect( m_writerJob, SIGNAL(newSubTask(const QString&)), this, SIGNAL(newSubTask(const QString&)) );
+ connect( m_writerJob, SIGNAL(debuggingOutput(const QString&, const QString&)),
+ this, SIGNAL(debuggingOutput(const QString&, const QString&)) );
+ }
+
+ 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").arg(t).arg(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.").arg(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").arg(d->doneCopies+1) );
+
+ m_writerJob->start();
+}
+
+
+void K3bCloneJob::removeImageFiles()
+{
+ if( !m_onlyBurnExistingImage ) {
+ emit infoMessage( i18n("Removing image files."), INFO );
+ if( QFile::exists( m_imagePath ) )
+ QFile::remove( m_imagePath );
+ if( QFile::exists( m_imagePath + ".toc" ) )
+ QFile::remove( m_imagePath + ".toc" );
+ }
+}
+
+
+QString 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");
+}
+
+
+QString K3bCloneJob::jobDetails() const
+{
+ return i18n("Creating 1 clone copy",
+ "Creating %n clone copies",
+ (m_simulate||m_onlyCreateImage) ? 1 : m_copies );
+}
+
+#include "k3bclonejob.moc"