File indexing completed on 2025-03-16 04:29:29
0001 /* 0002 SPDX-FileCopyrightText: 2003-2009 Sebastian Trueg <trueg@k3b.org> 0003 SPDX-FileCopyrightText: 2011 Michal Malek <michalm@jabster.pl> 0004 SPDX-FileCopyrightText: 1998-2009 Sebastian Trueg <trueg@k3b.org> 0005 0006 SPDX-License-Identifier: GPL-2.0-or-later 0007 */ 0008 0009 #include "k3bclonejob.h" 0010 0011 #include "k3breadcdreader.h" 0012 #include "k3bcdrecordwriter.h" 0013 #include "k3bexternalbinmanager.h" 0014 #include "k3bdevice.h" 0015 #include "k3bdevicehandler.h" 0016 #include "k3bglobals.h" 0017 #include "k3bcore.h" 0018 #include "k3bclonetocreader.h" 0019 #include "k3bglobalsettings.h" 0020 #include "k3b_i18n.h" 0021 0022 #include <QDebug> 0023 #include <QFile> 0024 #include <QFileInfo> 0025 0026 0027 0028 class K3b::CloneJob::Private 0029 { 0030 public: 0031 Private() 0032 : doneCopies(0) { 0033 } 0034 0035 int doneCopies; 0036 }; 0037 0038 0039 K3b::CloneJob::CloneJob( K3b::JobHandler* hdl, QObject* parent ) 0040 : K3b::BurnJob( hdl, parent ), 0041 m_writerDevice(0), 0042 m_readerDevice(0), 0043 m_writerJob(0), 0044 m_readcdReader(0), 0045 m_removeImageFiles(false), 0046 m_canceled(false), 0047 m_running(false), 0048 m_simulate(false), 0049 m_speed(1), 0050 m_copies(1), 0051 m_onlyCreateImage(false), 0052 m_onlyBurnExistingImage(false), 0053 m_readRetries(128) 0054 { 0055 d = new Private; 0056 } 0057 0058 0059 K3b::CloneJob::~CloneJob() 0060 { 0061 delete d; 0062 } 0063 0064 0065 void K3b::CloneJob::start() 0066 { 0067 jobStarted(); 0068 0069 m_canceled = false; 0070 m_running = true; 0071 0072 0073 // TODO: check the cd size and warn the user if not enough space 0074 0075 // 0076 // We first check if cdrecord has clone support 0077 // The readcdReader will check the same for readcd 0078 // 0079 const K3b::ExternalBin* cdrecordBin = k3bcore->externalBinManager()->binObject( "cdrecord" ); 0080 if( !cdrecordBin ) { 0081 emit infoMessage( i18n("Could not find %1 executable.",QString("cdrecord")), MessageError ); 0082 jobFinished(false); 0083 m_running = false; 0084 return; 0085 } 0086 else if( cdrecordBin && !cdrecordBin->hasFeature( "clone" ) ) { 0087 emit infoMessage( i18n("Cdrecord version %1 does not have cloning support.",cdrecordBin->version()), MessageError ); 0088 jobFinished(false); 0089 m_running = false; 0090 return; 0091 } 0092 0093 if( (!m_onlyCreateImage && !writer()) || 0094 (!m_onlyBurnExistingImage && !readingDevice()) ) { 0095 emit infoMessage( i18n("No device set."), MessageError ); 0096 jobFinished(false); 0097 m_running = false; 0098 return; 0099 } 0100 0101 if( !m_onlyCreateImage ) { 0102 if( !writer()->supportsWritingMode( K3b::Device::WRITINGMODE_RAW_R96R ) && 0103 !writer()->supportsWritingMode( K3b::Device::WRITINGMODE_RAW_R16 ) ) { 0104 emit infoMessage( i18n("CD writer %1 (%2) does not support cloning.", 0105 writer()->vendor(), 0106 writer()->description()), MessageError ); 0107 m_running = false; 0108 jobFinished(false); 0109 return; 0110 } 0111 } 0112 0113 if( m_imagePath.isEmpty() ) { 0114 m_imagePath = K3b::findTempFile( "img" ); 0115 } 0116 else if( QFileInfo(m_imagePath).isDir() ) { 0117 m_imagePath = K3b::findTempFile( "img", m_imagePath ); 0118 } 0119 0120 if( m_onlyBurnExistingImage ) { 0121 startWriting(); 0122 } 0123 else { 0124 emit burning( false ); 0125 0126 prepareReader(); 0127 0128 if( waitForMedium( readingDevice(), 0129 K3b::Device::STATE_COMPLETE, 0130 K3b::Device::MEDIA_WRITABLE_CD|K3b::Device::MEDIA_CD_ROM ) == Device::MEDIA_UNKNOWN ) { 0131 m_running = false; 0132 emit canceled(); 0133 jobFinished(false); 0134 return; 0135 } 0136 0137 emit newTask( i18n("Reading clone image") ); 0138 0139 m_readcdReader->start(); 0140 } 0141 } 0142 0143 0144 void K3b::CloneJob::prepareReader() 0145 { 0146 if( !m_readcdReader ) { 0147 m_readcdReader = new K3b::ReadcdReader( this, this ); 0148 connect( m_readcdReader, SIGNAL(percent(int)), this, SLOT(slotReadingPercent(int)) ); 0149 connect( m_readcdReader, SIGNAL(percent(int)), this, SIGNAL(subPercent(int)) ); 0150 connect( m_readcdReader, SIGNAL(processedSize(int,int)), this, SIGNAL(processedSubSize(int,int)) ); 0151 connect( m_readcdReader, SIGNAL(finished(bool)), this, SLOT(slotReadingFinished(bool)) ); 0152 connect( m_readcdReader, SIGNAL(infoMessage(QString,int)), this, SIGNAL(infoMessage(QString,int)) ); 0153 connect( m_readcdReader, SIGNAL(newTask(QString)), this, SIGNAL(newSubTask(QString)) ); 0154 connect( m_readcdReader, SIGNAL(debuggingOutput(QString,QString)), 0155 this, SIGNAL(debuggingOutput(QString,QString)) ); 0156 } 0157 0158 m_readcdReader->setReadDevice( readingDevice() ); 0159 m_readcdReader->setReadSpeed( 0 ); // MAX 0160 m_readcdReader->setDisableCorrection( m_noCorrection ); 0161 m_readcdReader->setImagePath( m_imagePath ); 0162 m_readcdReader->setClone( true ); 0163 m_readcdReader->setRetries( m_readRetries ); 0164 } 0165 0166 0167 void K3b::CloneJob::prepareWriter() 0168 { 0169 if( !m_writerJob ) { 0170 m_writerJob = new K3b::CdrecordWriter( writer(), this, this ); 0171 connect( m_writerJob, SIGNAL(infoMessage(QString,int)), this, SIGNAL(infoMessage(QString,int)) ); 0172 connect( m_writerJob, SIGNAL(percent(int)), this, SLOT(slotWriterPercent(int)) ); 0173 connect( m_writerJob, SIGNAL(percent(int)), this, SIGNAL(subPercent(int)) ); 0174 connect( m_writerJob, SIGNAL(nextTrack(int,int)), this, SLOT(slotWriterNextTrack(int,int)) ); 0175 connect( m_writerJob, SIGNAL(processedSize(int,int)), this, SIGNAL(processedSubSize(int,int)) ); 0176 connect( m_writerJob, SIGNAL(buffer(int)), this, SIGNAL(bufferStatus(int)) ); 0177 connect( m_writerJob, SIGNAL(deviceBuffer(int)), this, SIGNAL(deviceBuffer(int)) ); 0178 connect( m_writerJob, SIGNAL(writeSpeed(int,K3b::Device::SpeedMultiplicator)), this, SIGNAL(writeSpeed(int,K3b::Device::SpeedMultiplicator)) ); 0179 connect( m_writerJob, SIGNAL(finished(bool)), this, SLOT(slotWriterFinished(bool)) ); 0180 // connect( m_writerJob, SIGNAL(newTask(QString)), this, SIGNAL(newTask(QString)) ); 0181 connect( m_writerJob, SIGNAL(newSubTask(QString)), this, SIGNAL(newSubTask(QString)) ); 0182 connect( m_writerJob, SIGNAL(debuggingOutput(QString,QString)), 0183 this, SIGNAL(debuggingOutput(QString,QString)) ); 0184 } 0185 0186 m_writerJob->clearArguments(); 0187 m_writerJob->setWritingMode( K3b::WritingModeRaw ); 0188 m_writerJob->setClone( true ); 0189 m_writerJob->setSimulate( m_simulate ); 0190 m_writerJob->setBurnSpeed( m_speed ); 0191 m_writerJob->addArgument( m_imagePath ); 0192 } 0193 0194 0195 void K3b::CloneJob::cancel() 0196 { 0197 if( m_running ) { 0198 m_canceled = true; 0199 if( m_readcdReader ) 0200 m_readcdReader->cancel(); 0201 if( m_writerJob ) 0202 m_writerJob->cancel(); 0203 } 0204 } 0205 0206 0207 void K3b::CloneJob::slotWriterPercent( int p ) 0208 { 0209 if( m_onlyBurnExistingImage ) 0210 emit percent( (int)((double)(d->doneCopies)*100.0/(double)(m_copies) + (double)p/(double)(m_copies)) ); 0211 else 0212 emit percent( (int)((double)(1+d->doneCopies)*100.0/(double)(1+m_copies) + (double)p/(double)(1+m_copies)) ); 0213 } 0214 0215 0216 void K3b::CloneJob::slotWriterNextTrack( int t, int tt ) 0217 { 0218 emit newSubTask( i18n("Writing Track %1 of %2",t,tt) ); 0219 } 0220 0221 0222 void K3b::CloneJob::slotWriterFinished( bool success ) 0223 { 0224 if( m_canceled ) { 0225 removeImageFiles(); 0226 m_running = false; 0227 emit canceled(); 0228 jobFinished(false); 0229 return; 0230 } 0231 0232 if( success ) { 0233 d->doneCopies++; 0234 0235 emit infoMessage( i18n("Successfully written clone copy %1.",d->doneCopies), MessageInfo ); 0236 0237 if( d->doneCopies < m_copies ) { 0238 K3b::Device::eject( writer() ); 0239 startWriting(); 0240 } 0241 else { 0242 if ( k3bcore->globalSettings()->ejectMedia() ) { 0243 K3b::Device::eject( writer() ); 0244 } 0245 0246 if( m_removeImageFiles ) 0247 removeImageFiles(); 0248 m_running = false; 0249 jobFinished(true); 0250 } 0251 } 0252 else { 0253 removeImageFiles(); 0254 m_running = false; 0255 jobFinished(false); 0256 } 0257 } 0258 0259 0260 void K3b::CloneJob::slotReadingPercent( int p ) 0261 { 0262 emit percent( m_onlyCreateImage ? p : (int)((double)p/(double)(1+m_copies)) ); 0263 } 0264 0265 0266 void K3b::CloneJob::slotReadingFinished( bool success ) 0267 { 0268 if( m_canceled ) { 0269 removeImageFiles(); 0270 m_running = false; 0271 emit canceled(); 0272 jobFinished(false); 0273 return; 0274 } 0275 0276 if( success ) { 0277 // 0278 // Make a quick test if the image is really valid. 0279 // Readcd does not seem to have proper exit codes 0280 // 0281 K3b::CloneTocReader ctr( m_imagePath ); 0282 if( ctr.isValid() ) { 0283 emit infoMessage( i18n("Successfully read disk."), MessageInfo ); 0284 if( m_onlyCreateImage ) { 0285 m_running = false; 0286 jobFinished(true); 0287 } 0288 else { 0289 if( writer() == readingDevice() && k3bcore->globalSettings()->ejectMedia() ) 0290 K3b::Device::eject( writer() ); 0291 startWriting(); 0292 } 0293 } 0294 else { 0295 emit infoMessage( i18n("Failed to read disk completely in clone mode."), MessageError ); 0296 removeImageFiles(); 0297 m_running = false; 0298 jobFinished(false); 0299 } 0300 } 0301 else { 0302 emit infoMessage( i18n("Error while reading disk."), MessageError ); 0303 removeImageFiles(); 0304 m_running = false; 0305 jobFinished(false); 0306 } 0307 } 0308 0309 0310 void K3b::CloneJob::startWriting() 0311 { 0312 emit burning( true ); 0313 0314 // start writing 0315 prepareWriter(); 0316 0317 if( waitForMedium( writer(), 0318 K3b::Device::STATE_EMPTY, 0319 K3b::Device::MEDIA_WRITABLE_CD ) == Device::MEDIA_UNKNOWN ) { 0320 removeImageFiles(); 0321 m_running = false; 0322 emit canceled(); 0323 jobFinished(false); 0324 return; 0325 } 0326 0327 if( m_simulate ) 0328 emit newTask( i18n("Simulating clone copy") ); 0329 else 0330 emit newTask( i18n("Writing clone copy %1",d->doneCopies+1) ); 0331 0332 m_writerJob->start(); 0333 } 0334 0335 0336 void K3b::CloneJob::removeImageFiles() 0337 { 0338 if( !m_onlyBurnExistingImage ) { 0339 emit infoMessage( i18n("Removing image files."), MessageInfo ); 0340 if( QFile::exists( m_imagePath ) ) 0341 QFile::remove( m_imagePath ); 0342 if( QFile::exists( m_imagePath + ".toc" ) ) 0343 QFile::remove( m_imagePath + ".toc" ); 0344 } 0345 } 0346 0347 0348 QString K3b::CloneJob::jobDescription() const 0349 { 0350 if( m_onlyCreateImage ) 0351 return i18n("Creating Clone Image"); 0352 else if( m_onlyBurnExistingImage ) { 0353 if( m_simulate ) 0354 return i18n("Simulating Clone Image"); 0355 else 0356 return i18n("Burning Clone Image"); 0357 } 0358 else if( m_simulate ) 0359 return i18n("Simulating CD Cloning"); 0360 else 0361 return i18n("Cloning CD"); 0362 } 0363 0364 0365 QString K3b::CloneJob::jobDetails() const 0366 { 0367 return i18np("Creating 1 clone copy", 0368 "Creating %1 clone copies", 0369 (m_simulate||m_onlyCreateImage) ? 1 : m_copies ); 0370 } 0371 0372 0373 QString K3b::CloneJob::jobSource() const 0374 { 0375 if( m_readerDevice ) 0376 return m_readerDevice->vendor() + ' ' + m_readerDevice->description(); 0377 else 0378 return QString(); 0379 } 0380 0381 0382 QString K3b::CloneJob::jobTarget() const 0383 { 0384 if( m_writerDevice ) 0385 return m_writerDevice->vendor() + ' ' + m_writerDevice->description(); 0386 else 0387 return m_imagePath; 0388 } 0389 0390 #include "moc_k3bclonejob.cpp"