File indexing completed on 2024-05-12 04:51:04
0001 /* 0002 SPDX-FileCopyrightText: 1998-2009 Sebastian Trueg <trueg@k3b.org> 0003 SPDX-License-Identifier: GPL-2.0-or-later 0004 */ 0005 0006 #include "k3bdatajob.h" 0007 #include "k3bdatadoc.h" 0008 #include "k3bisoimager.h" 0009 #include "k3bdatamultisessionparameterjob.h" 0010 #include "k3bchecksumpipe.h" 0011 #include "k3bcore.h" 0012 #include "k3bglobals.h" 0013 #include "k3bversion.h" 0014 #include "k3bdevice.h" 0015 #include "k3bdevicehandler.h" 0016 #include "k3btoc.h" 0017 #include "k3btrack.h" 0018 #include "k3bexternalbinmanager.h" 0019 #include "k3bcdrecordwriter.h" 0020 #include "k3bcdrdaowriter.h" 0021 #include "k3bglobalsettings.h" 0022 #include "k3bactivepipe.h" 0023 #include "k3bfilesplitter.h" 0024 #include "k3bverificationjob.h" 0025 #include "k3biso9660.h" 0026 #include "k3bisooptions.h" 0027 #include "k3bdeviceglobals.h" 0028 #include "k3bgrowisofswriter.h" 0029 #include "k3b_i18n.h" 0030 0031 #include <KIO/Global> 0032 #include <KIO/Job> 0033 0034 #include <QDataStream> 0035 #include <QDateTime> 0036 #include <QDebug> 0037 #include <QFile> 0038 #include <QString> 0039 #include <QStringList> 0040 #include <QTemporaryFile> 0041 0042 0043 0044 class K3b::DataJob::Private 0045 { 0046 public: 0047 Private() 0048 : usedWritingApp(K3b::WritingAppAuto), 0049 verificationJob( 0 ), 0050 pipe( 0 ) { 0051 } 0052 0053 K3b::DataDoc* doc; 0054 0055 bool initializingImager; 0056 bool imageFinished; 0057 bool canceled; 0058 0059 QTemporaryFile* tocFile; 0060 0061 int usedDataMode; 0062 K3b::WritingApp usedWritingApp; 0063 K3b::WritingMode usedWritingMode; 0064 0065 int copies; 0066 int copiesDone; 0067 0068 K3b::VerificationJob* verificationJob; 0069 0070 K3b::FileSplitter imageFile; 0071 K3b::ActivePipe* pipe; 0072 0073 K3b::DataMultiSessionParameterJob* multiSessionParameterJob; 0074 0075 QByteArray checksumCache; 0076 }; 0077 0078 0079 K3b::DataJob::DataJob( K3b::DataDoc* doc, K3b::JobHandler* hdl, QObject* parent ) 0080 : K3b::BurnJob( hdl, parent ) 0081 { 0082 d = new Private; 0083 d->multiSessionParameterJob = new K3b::DataMultiSessionParameterJob( doc, this, this ); 0084 connectSubJob( d->multiSessionParameterJob, 0085 SLOT(slotMultiSessionParamterSetupDone(bool)), 0086 SIGNAL(newTask(QString)), 0087 SIGNAL(newSubTask(QString)) ); 0088 0089 d->doc = doc; 0090 m_writerJob = 0; 0091 d->tocFile = 0; 0092 m_isoImager = 0; 0093 } 0094 0095 0096 K3b::DataJob::~DataJob() 0097 { 0098 qDebug(); 0099 delete d->pipe; 0100 delete d->tocFile; 0101 delete d; 0102 } 0103 0104 0105 K3b::Doc* K3b::DataJob::doc() const 0106 { 0107 return d->doc; 0108 } 0109 0110 0111 K3b::Device::Device* K3b::DataJob::writer() const 0112 { 0113 if( doc()->onlyCreateImages() ) 0114 return 0; // no writer needed -> no blocking on K3b::BurnJob 0115 else 0116 return doc()->burner(); 0117 } 0118 0119 0120 void K3b::DataJob::start() 0121 { 0122 qDebug(); 0123 jobStarted(); 0124 0125 d->canceled = false; 0126 d->imageFinished = false; 0127 d->copies = d->doc->copies(); 0128 d->copiesDone = 0; 0129 0130 prepareImager(); 0131 0132 if( d->doc->dummy() ) { 0133 d->doc->setVerifyData( false ); 0134 d->copies = 1; 0135 } 0136 0137 emit newTask( i18n("Preparing data") ); 0138 0139 // there is no harm in setting these even if we write on-the-fly 0140 d->imageFile.setName( d->doc->tempDir() ); 0141 0142 d->multiSessionParameterJob->start(); 0143 } 0144 0145 0146 void K3b::DataJob::slotMultiSessionParamterSetupDone( bool success ) 0147 { 0148 qDebug() << success; 0149 if ( success ) { 0150 prepareWriting(); 0151 } 0152 else { 0153 if ( d->multiSessionParameterJob->hasBeenCanceled() ) { 0154 emit canceled(); 0155 } 0156 cleanup(); 0157 jobFinished( false ); 0158 } 0159 } 0160 0161 0162 void K3b::DataJob::prepareWriting() 0163 { 0164 qDebug(); 0165 if( !d->doc->onlyCreateImages() && 0166 ( d->multiSessionParameterJob->usedMultiSessionMode() == K3b::DataDoc::CONTINUE || 0167 d->multiSessionParameterJob->usedMultiSessionMode() == K3b::DataDoc::FINISH ) ) { 0168 unsigned int nextSessionStart = d->multiSessionParameterJob->nextSessionStart(); 0169 // for some reason cdrdao needs 150 additional sectors in the ms info 0170 if( writingApp() == K3b::WritingAppCdrdao ) { 0171 nextSessionStart += 150; 0172 } 0173 m_isoImager->setMultiSessionInfo( QString::asprintf( "%u,%u", 0174 d->multiSessionParameterJob->previousSessionStart(), 0175 nextSessionStart ), 0176 d->multiSessionParameterJob->importPreviousSession() ? d->doc->burner() : 0 ); 0177 } 0178 else { 0179 m_isoImager->setMultiSessionInfo( QString(), 0 ); 0180 } 0181 0182 d->initializingImager = true; 0183 m_isoImager->init(); 0184 } 0185 0186 0187 void K3b::DataJob::writeImage() 0188 { 0189 qDebug(); 0190 d->initializingImager = false; 0191 0192 emit burning(false); 0193 0194 // get image file path 0195 if( d->doc->tempDir().isEmpty() ) 0196 d->doc->setTempDir( K3b::findUniqueFilePrefix( d->doc->isoOptions().volumeID() ) + ".iso" ); 0197 0198 // TODO: check if the image file is part of the project and if so warn the user 0199 // and append some number to make the path unique. 0200 0201 // 0202 // Check the image file 0203 if( !d->doc->onTheFly() || d->doc->onlyCreateImages() ) { 0204 d->imageFile.setName( d->doc->tempDir() ); 0205 if( !d->imageFile.open( QIODevice::WriteOnly ) ) { 0206 emit infoMessage( i18n("Could not open %1 for writing", d->doc->tempDir() ), MessageError ); 0207 cleanup(); 0208 jobFinished(false); 0209 return; 0210 } 0211 } 0212 0213 emit newTask( i18n("Creating image file") ); 0214 emit newSubTask( i18n("Track 1 of 1") ); 0215 emit infoMessage( i18n("Creating image file in %1",d->doc->tempDir()), MessageInfo ); 0216 0217 m_isoImager->start(); 0218 startPipe(); 0219 } 0220 0221 0222 void K3b::DataJob::startPipe() 0223 { 0224 qDebug(); 0225 // 0226 // Open the active pipe which does the streaming 0227 // 0228 delete d->pipe; 0229 if ( d->imageFinished || !d->doc->verifyData() ) 0230 d->pipe = new K3b::ActivePipe(); 0231 else 0232 d->pipe = new K3b::ChecksumPipe(); 0233 0234 #ifdef __GNUC__ 0235 #warning Growisofs needs stdin to be closed in order to exit gracefully. Cdrecord does not. However, if closed with cdrecord we loose parts of stderr. Why? 0236 #endif 0237 if( d->imageFinished || ( d->doc->onTheFly() && !d->doc->onlyCreateImages() ) ) 0238 d->pipe->writeTo( m_writerJob->ioDevice(), d->usedWritingApp != K3b::WritingAppCdrecord ); 0239 else 0240 d->pipe->writeTo( &d->imageFile, true ); 0241 0242 if ( d->imageFinished ) 0243 d->pipe->readFrom( &d->imageFile, true ); 0244 else 0245 d->pipe->readFrom( m_isoImager->ioDevice(), true ); 0246 0247 d->pipe->open( true ); 0248 } 0249 0250 0251 bool K3b::DataJob::startOnTheFlyWriting() 0252 { 0253 qDebug(); 0254 if( prepareWriterJob() ) { 0255 if( startWriterJob() ) { 0256 d->initializingImager = false; 0257 m_isoImager->start(); 0258 startPipe(); 0259 return true; 0260 } 0261 } 0262 return false; 0263 } 0264 0265 0266 void K3b::DataJob::cancel() 0267 { 0268 qDebug(); 0269 0270 emit canceled(); 0271 0272 d->canceled = true; 0273 0274 // 0275 // Just cancel all and return, let slotMultiSessionParamterSetupDone, 0276 // slotIsoImagerFinished, and slotWriterJobFinished take care of the rest 0277 // 0278 if ( active() && !cancelAll() ) { 0279 qDebug() << "cancellation already done"; 0280 cleanup(); 0281 jobFinished( false ); 0282 } 0283 } 0284 0285 0286 bool K3b::DataJob::cancelAll() 0287 { 0288 qDebug(); 0289 bool somethingCanceled = false; 0290 if ( m_isoImager->active() ) { 0291 qDebug() << "cancelling iso imager"; 0292 m_isoImager->cancel(); 0293 somethingCanceled = true; 0294 } 0295 if( m_writerJob && m_writerJob->active() ) { 0296 qDebug() << "cancelling writing job"; 0297 m_writerJob->cancel(); 0298 somethingCanceled = true; 0299 } 0300 if( d->verificationJob && d->verificationJob->active() ) { 0301 qDebug() << "cancelling verification job"; 0302 d->verificationJob->cancel(); 0303 somethingCanceled = true; 0304 } 0305 if ( d->multiSessionParameterJob && d->multiSessionParameterJob->active() ) { 0306 qDebug() << "cancelling multiSessionParameterJob"; 0307 d->multiSessionParameterJob->cancel(); 0308 somethingCanceled = true; 0309 } 0310 0311 qDebug() << somethingCanceled; 0312 return somethingCanceled; 0313 } 0314 0315 0316 void K3b::DataJob::slotIsoImagerPercent( int p ) 0317 { 0318 if( d->doc->onlyCreateImages() ) { 0319 emit subPercent( p ); 0320 emit percent( p ); 0321 } 0322 else if( !d->doc->onTheFly() ) { 0323 double totalTasks = d->copies; 0324 double tasksDone = d->copiesDone; // =0 when creating an image 0325 if( d->doc->verifyData() ) { 0326 totalTasks*=2; 0327 tasksDone*=2; 0328 } 0329 if( !d->doc->onTheFly() ) { 0330 totalTasks+=1.0; 0331 } 0332 0333 emit subPercent( p ); 0334 emit percent( (int)((100.0*tasksDone + (double)p) / totalTasks) ); 0335 } 0336 } 0337 0338 0339 void K3b::DataJob::slotIsoImagerFinished( bool success ) 0340 { 0341 qDebug(); 0342 if( d->initializingImager ) { 0343 if( success ) { 0344 if( d->doc->onTheFly() && !d->doc->onlyCreateImages() ) { 0345 if( !startOnTheFlyWriting() ) { 0346 cleanup(); 0347 jobFinished( false ); 0348 } 0349 } 0350 else { 0351 writeImage(); 0352 } 0353 } 0354 else { 0355 if( m_isoImager->hasBeenCanceled() ) { 0356 cancel(); 0357 } 0358 else if ( !cancelAll() ) { 0359 cleanup(); 0360 jobFinished( false ); 0361 } 0362 } 0363 } 0364 else { 0365 // cache the calculated checksum since the ChecksumPipe may be deleted below 0366 if ( ChecksumPipe* cp = qobject_cast<ChecksumPipe*>( d->pipe ) ) 0367 d->checksumCache = cp->checksum(); 0368 0369 if( !d->doc->onTheFly() || 0370 d->doc->onlyCreateImages() ) { 0371 0372 if( success ) { 0373 emit infoMessage( i18n("Image successfully created in %1", d->doc->tempDir()), K3b::Job::MessageSuccess ); 0374 d->imageFinished = true; 0375 0376 if( d->doc->onlyCreateImages() ) { 0377 jobFinished( true ); 0378 } 0379 else if( !d->imageFile.open( QIODevice::ReadOnly ) ) { 0380 emit infoMessage( i18n("Could not open file %1", d->doc->tempDir() ), MessageError ); 0381 cleanup(); 0382 jobFinished(false); 0383 } 0384 else if( prepareWriterJob() ) { 0385 startWriterJob(); 0386 startPipe(); 0387 } 0388 } 0389 else { 0390 if( m_isoImager->hasBeenCanceled() ) 0391 emit canceled(); 0392 else 0393 emit infoMessage( i18n("Error while creating ISO image"), MessageError ); 0394 0395 cancelAll(); 0396 cleanup(); 0397 jobFinished( false ); 0398 } 0399 } 0400 else { // on-the-fly 0401 if( success ) { 0402 if ( !m_writerJob->active() ) 0403 finishCopy(); 0404 } 0405 else { 0406 // 0407 // In case the imager failed let's make sure the writer does not emit an unusable 0408 // error message. 0409 // 0410 if( m_writerJob && m_writerJob->active() ) 0411 m_writerJob->setSourceUnreadable( true ); 0412 0413 // there is one special case which we need to handle here: the iso imager might be canceled 0414 // FIXME: the iso imager should not be able to cancel itself 0415 if( m_isoImager->hasBeenCanceled() && !this->hasBeenCanceled() ) 0416 cancel(); 0417 } 0418 } 0419 } 0420 } 0421 0422 0423 bool K3b::DataJob::startWriterJob() 0424 { 0425 qDebug(); 0426 if( d->doc->dummy() ) 0427 emit newTask( i18n("Simulating") ); 0428 else if( d->copies > 1 ) 0429 emit newTask( i18n("Writing Copy %1",d->copiesDone+1) ); 0430 else 0431 emit newTask( i18n("Writing") ); 0432 0433 emit burning(true); 0434 m_writerJob->start(); 0435 return true; 0436 } 0437 0438 0439 void K3b::DataJob::slotWriterJobPercent( int p ) 0440 { 0441 double totalTasks = d->copies; 0442 double tasksDone = d->copiesDone; 0443 if( d->doc->verifyData() ) { 0444 totalTasks*=2; 0445 tasksDone*=2; 0446 } 0447 if( !d->doc->onTheFly() ) { 0448 totalTasks+=1.0; 0449 tasksDone+=1.0; 0450 } 0451 0452 emit percent( (int)((100.0*tasksDone + (double)p) / totalTasks) ); 0453 } 0454 0455 0456 void K3b::DataJob::slotWriterNextTrack( int t, int tt ) 0457 { 0458 emit newSubTask( i18n("Writing Track %1 of %2",t,tt) ); 0459 } 0460 0461 0462 void K3b::DataJob::slotWriterJobFinished( bool success ) 0463 { 0464 qDebug(); 0465 0466 if( success ) { 0467 if ( !d->doc->onTheFly() || 0468 !m_isoImager->active() ) { 0469 finishCopy(); 0470 } 0471 } 0472 else { 0473 if ( !cancelAll() ) { 0474 cleanup(); 0475 jobFinished( false ); 0476 } 0477 } 0478 } 0479 0480 0481 void K3b::DataJob::finishCopy() 0482 { 0483 // the writerJob should have emitted the "simulation/writing successful" signal 0484 0485 if( d->doc->verifyData() ) { 0486 if( !d->verificationJob ) { 0487 d->verificationJob = new K3b::VerificationJob( this, this ); 0488 connect( d->verificationJob, SIGNAL(infoMessage(QString,int)), 0489 this, SIGNAL(infoMessage(QString,int)) ); 0490 connect( d->verificationJob, SIGNAL(newTask(QString)), 0491 this, SIGNAL(newSubTask(QString)) ); 0492 connect( d->verificationJob, SIGNAL(newSubTask(QString)), 0493 this, SIGNAL(newSubTask(QString)) ); 0494 connect( d->verificationJob, SIGNAL(percent(int)), 0495 this, SLOT(slotVerificationProgress(int)) ); 0496 connect( d->verificationJob, SIGNAL(percent(int)), 0497 this, SIGNAL(subPercent(int)) ); 0498 connect( d->verificationJob, SIGNAL(finished(bool)), 0499 this, SLOT(slotVerificationFinished(bool)) ); 0500 connect( d->verificationJob, SIGNAL(debuggingOutput(QString,QString)), 0501 this, SIGNAL(debuggingOutput(QString,QString)) ); 0502 0503 } 0504 d->verificationJob->clear(); 0505 d->verificationJob->setDevice( d->doc->burner() ); 0506 d->verificationJob->setGrownSessionSize( m_isoImager->size() ); 0507 d->verificationJob->addTrack( 0, d->checksumCache, m_isoImager->size() ); 0508 0509 emit burning(false); 0510 0511 emit newTask( i18n("Verifying written data") ); 0512 0513 d->verificationJob->start(); 0514 } 0515 else { 0516 d->copiesDone++; 0517 0518 if( d->copiesDone < d->copies ) { 0519 if( !K3b::eject( d->doc->burner() ) ) { 0520 blockingInformation( i18n("K3b was unable to eject the written disk. Please do so manually.") ); 0521 } 0522 0523 bool failed = false; 0524 if( d->doc->onTheFly() ) 0525 failed = !startOnTheFlyWriting(); 0526 else 0527 failed = !prepareWriterJob() || !startWriterJob(); 0528 0529 if( failed ) { 0530 cancel(); 0531 } 0532 else if( !d->doc->onTheFly() ) { 0533 #ifdef __GNUC__ 0534 #warning Growisofs needs stdin to be closed in order to exit gracefully. Cdrecord does not. However, if closed with cdrecord we loose parts of stderr. Why? 0535 #endif 0536 d->pipe->writeTo( m_writerJob->ioDevice(), d->usedWritingApp != K3b::WritingAppCdrecord ); 0537 d->pipe->open(true); 0538 } 0539 } 0540 else { 0541 cleanup(); 0542 if ( k3bcore->globalSettings()->ejectMedia() ) { 0543 K3b::Device::eject( d->doc->burner() ); 0544 } 0545 jobFinished(true); 0546 } 0547 } 0548 } 0549 0550 0551 void K3b::DataJob::slotVerificationProgress( int p ) 0552 { 0553 double totalTasks = d->copies*2; 0554 double tasksDone = d->copiesDone*2 + 1; // the writing of the current copy has already been finished 0555 0556 if( !d->doc->onTheFly() ) { 0557 totalTasks+=1.0; 0558 tasksDone+=1.0; 0559 } 0560 0561 emit percent( (int)((100.0*tasksDone + (double)p) / totalTasks) ); 0562 } 0563 0564 0565 void K3b::DataJob::slotVerificationFinished( bool success ) 0566 { 0567 qDebug(); 0568 d->copiesDone++; 0569 0570 // reconnect our imager which we disconnected for the verification 0571 connectImager(); 0572 0573 if( k3bcore->globalSettings()->ejectMedia() || d->copiesDone < d->copies ) 0574 K3b::Device::eject( d->doc->burner() ); 0575 0576 if( !d->canceled && d->copiesDone < d->copies ) { 0577 bool failed = false; 0578 if( d->doc->onTheFly() ) 0579 failed = !startOnTheFlyWriting(); 0580 else 0581 failed = !prepareWriterJob() || !startWriterJob(); 0582 0583 if( failed ) 0584 cancel(); 0585 else if( !d->doc->onTheFly() ) { 0586 #ifdef __GNUC__ 0587 #warning Growisofs needs stdin to be closed in order to exit gracefully. Cdrecord does not. However, if closed with cdrecord we loose parts of stderr. Why? 0588 #endif 0589 d->pipe->writeTo( m_writerJob->ioDevice(), d->usedWritingApp != K3b::WritingAppCdrecord ); 0590 d->pipe->open(true); 0591 } 0592 } 0593 else { 0594 cleanup(); 0595 jobFinished( success ); 0596 } 0597 } 0598 0599 0600 void K3b::DataJob::setWriterJob( K3b::AbstractWriter* writer ) 0601 { 0602 qDebug(); 0603 // FIXME: progressedsize for multiple copies 0604 m_writerJob = writer; 0605 connect( m_writerJob, SIGNAL(infoMessage(QString,int)), this, SIGNAL(infoMessage(QString,int)) ); 0606 connect( m_writerJob, SIGNAL(percent(int)), this, SLOT(slotWriterJobPercent(int)) ); 0607 connect( m_writerJob, SIGNAL(processedSize(int,int)), this, SIGNAL(processedSize(int,int)) ); 0608 connect( m_writerJob, SIGNAL(subPercent(int)), this, SIGNAL(subPercent(int)) ); 0609 connect( m_writerJob, SIGNAL(processedSubSize(int,int)), this, SIGNAL(processedSubSize(int,int)) ); 0610 connect( m_writerJob, SIGNAL(nextTrack(int,int)), this, SLOT(slotWriterNextTrack(int,int)) ); 0611 connect( m_writerJob, SIGNAL(buffer(int)), this, SIGNAL(bufferStatus(int)) ); 0612 connect( m_writerJob, SIGNAL(deviceBuffer(int)), this, SIGNAL(deviceBuffer(int)) ); 0613 connect( m_writerJob, SIGNAL(writeSpeed(int,K3b::Device::SpeedMultiplicator)), this, SIGNAL(writeSpeed(int,K3b::Device::SpeedMultiplicator)) ); 0614 connect( m_writerJob, SIGNAL(finished(bool)), this, SLOT(slotWriterJobFinished(bool)) ); 0615 connect( m_writerJob, SIGNAL(newSubTask(QString)), this, SIGNAL(newSubTask(QString)) ); 0616 connect( m_writerJob, SIGNAL(debuggingOutput(QString,QString)), 0617 this, SIGNAL(debuggingOutput(QString,QString)) ); 0618 } 0619 0620 0621 void K3b::DataJob::setImager( K3b::IsoImager* imager ) 0622 { 0623 qDebug(); 0624 if( m_isoImager != imager ) { 0625 delete m_isoImager; 0626 0627 m_isoImager = imager; 0628 0629 connectImager(); 0630 } 0631 } 0632 0633 0634 void K3b::DataJob::connectImager() 0635 { 0636 qDebug(); 0637 m_isoImager->disconnect( this ); 0638 connect( m_isoImager, SIGNAL(infoMessage(QString,int)), this, SIGNAL(infoMessage(QString,int)) ); 0639 connect( m_isoImager, SIGNAL(percent(int)), this, SLOT(slotIsoImagerPercent(int)) ); 0640 connect( m_isoImager, SIGNAL(finished(bool)), this, SLOT(slotIsoImagerFinished(bool)) ); 0641 connect( m_isoImager, SIGNAL(debuggingOutput(QString,QString)), 0642 this, SIGNAL(debuggingOutput(QString,QString)) ); 0643 } 0644 0645 0646 void K3b::DataJob::prepareImager() 0647 { 0648 qDebug(); 0649 if( !m_isoImager ) 0650 setImager( new K3b::IsoImager( d->doc, this, this ) ); 0651 } 0652 0653 0654 bool K3b::DataJob::prepareWriterJob() 0655 { 0656 qDebug(); 0657 if( m_writerJob ) { 0658 delete m_writerJob; 0659 m_writerJob = 0; 0660 } 0661 0662 // if we append a new session we asked for an appendable cd already 0663 if( !waitForBurnMedium() ) { 0664 return false; 0665 } 0666 0667 // It seems as if cdrecord is not able to append sessions in dao mode whereas cdrdao is 0668 if( d->usedWritingApp == K3b::WritingAppCdrecord ) { 0669 if( !setupCdrecordJob() ) { 0670 return false; 0671 } 0672 } 0673 else if ( d->usedWritingApp == K3b::WritingAppCdrdao ) { 0674 if ( !setupCdrdaoJob() ) { 0675 return false; 0676 } 0677 } 0678 else { 0679 if ( !setupGrowisofsJob() ) { 0680 return false; 0681 } 0682 } 0683 0684 return true; 0685 } 0686 0687 0688 bool K3b::DataJob::waitForBurnMedium() 0689 { 0690 // start with all media types supported by the writer 0691 Device::MediaTypes m = d->doc->supportedMediaTypes() & d->doc->burner()->writeCapabilities(); 0692 // if everything goes wrong we are left with no possible media to request 0693 if ( !m ) { 0694 emit infoMessage( i18n( "Internal Error: No medium type fits. This project cannot be burned." ), MessageError ); 0695 return false; 0696 } 0697 const K3b::ExternalBin* cdrecordBin = k3bcore->externalBinManager()->binObject("cdrecord"); 0698 emit newSubTask( i18n("Waiting for a medium") ); 0699 Device::MediaType foundMedium = waitForMedium( d->doc->burner(), 0700 usedMultiSessionMode() == K3b::DataDoc::CONTINUE || 0701 usedMultiSessionMode() == K3b::DataDoc::FINISH ? 0702 K3b::Device::STATE_INCOMPLETE : 0703 K3b::Device::STATE_EMPTY, 0704 m, 0705 d->doc->burningLength() ); 0706 0707 if( foundMedium == Device::MEDIA_UNKNOWN || hasBeenCanceled() ) { 0708 return false; 0709 } 0710 0711 // ------------------------------- 0712 // CD-R(W) 0713 // ------------------------------- 0714 else if ( foundMedium & K3b::Device::MEDIA_CD_ALL ) { 0715 emit infoMessage( i18n( "Writing %1" , K3b::Device::mediaTypeString( foundMedium ) ), MessageInfo ); 0716 0717 // first of all we determine the data mode 0718 if( d->doc->dataMode() == K3b::DataModeAuto ) { 0719 if( !d->doc->onlyCreateImages() && 0720 ( usedMultiSessionMode() == K3b::DataDoc::CONTINUE || 0721 usedMultiSessionMode() == K3b::DataDoc::FINISH ) ) { 0722 0723 // try to get the last track's datamode 0724 // we already asked for an appendable cdr when fetching 0725 // the ms info 0726 qDebug() << "(K3b::DataJob) determining last track's datamode..."; 0727 0728 // FIXME: use the DeviceHandler 0729 K3b::Device::Toc toc = d->doc->burner()->readToc(); 0730 if( toc.isEmpty() ) { 0731 qDebug() << "(K3b::DataJob) could not retrieve toc."; 0732 emit infoMessage( i18n("Unable to determine the last track's datamode. Using default."), MessageError ); 0733 d->usedDataMode = K3b::DataMode2; 0734 } 0735 else { 0736 if( toc.back().mode() == K3b::Device::Track::MODE1 ) 0737 d->usedDataMode = K3b::DataMode1; 0738 else 0739 d->usedDataMode = K3b::DataMode2; 0740 0741 qDebug() << "(K3b::DataJob) using datamode: " 0742 << (d->usedDataMode == K3b::DataMode1 ? "mode1" : "mode2") 0743 << Qt::endl; 0744 } 0745 } 0746 else if( usedMultiSessionMode() == K3b::DataDoc::NONE ) 0747 d->usedDataMode = K3b::DataMode1; 0748 else 0749 d->usedDataMode = K3b::DataMode2; 0750 } 0751 else 0752 d->usedDataMode = d->doc->dataMode(); 0753 0754 // determine the writing mode 0755 if( d->doc->writingMode() == K3b::WritingModeAuto ) { 0756 // TODO: put this into the cdreocrdwriter and decide based on the size of the 0757 // track 0758 if( writer()->dao() && d->usedDataMode == K3b::DataMode1 && 0759 usedMultiSessionMode() == K3b::DataDoc::NONE ) 0760 d->usedWritingMode = K3b::WritingModeSao; 0761 else 0762 d->usedWritingMode = K3b::WritingModeTao; 0763 } 0764 else 0765 d->usedWritingMode = d->doc->writingMode(); 0766 0767 0768 if ( writingApp() == K3b::WritingAppGrowisofs ) { 0769 emit infoMessage( i18n( "Cannot write %1 media using %2. Falling back to default application." , QString("CD") , QString("growisofs") ), MessageWarning ); 0770 setWritingApp( K3b::WritingAppAuto ); 0771 } 0772 // cdrecord seems to have problems writing xa 1 disks in dao mode? At least on my system! 0773 if( writingApp() == K3b::WritingAppAuto ) { 0774 if( d->usedWritingMode == K3b::WritingModeSao ) { 0775 if( usedMultiSessionMode() != K3b::DataDoc::NONE ) 0776 d->usedWritingApp = K3b::WritingAppCdrdao; 0777 else if( d->usedDataMode == K3b::DataMode2 ) 0778 d->usedWritingApp = K3b::WritingAppCdrdao; 0779 else 0780 d->usedWritingApp = K3b::WritingAppCdrecord; 0781 } 0782 else 0783 d->usedWritingApp = K3b::WritingAppCdrecord; 0784 } 0785 else { 0786 d->usedWritingApp = writingApp(); 0787 } 0788 } 0789 0790 else if ( foundMedium & K3b::Device::MEDIA_DVD_ALL ) { 0791 if ( writingApp() == K3b::WritingAppCdrdao ) { 0792 emit infoMessage( i18n( "Cannot write %1 media using %2. Falling back to default application.", 0793 K3b::Device::mediaTypeString( foundMedium, true ), "cdrdao" ), MessageWarning ); 0794 setWritingApp( K3b::WritingAppAuto ); 0795 } 0796 0797 // make sure that we use the proper parameters for cdrecord 0798 d->usedDataMode = K3b::DataMode1; 0799 0800 d->usedWritingApp = writingApp(); 0801 // let's default to cdrecord for the time being (except for special cases below) 0802 // but prefer growisofs for DVDs 0803 if ( d->usedWritingApp == K3b::WritingAppAuto ) { 0804 if (cdrecordBin && cdrecordBin->hasFeature( "wodim" )) 0805 d->usedWritingApp = K3b::WritingAppGrowisofs; 0806 else 0807 d->usedWritingApp = K3b::WritingAppCdrecord; 0808 } 0809 0810 // ------------------------------- 0811 // DVD Plus 0812 // ------------------------------- 0813 if( foundMedium & K3b::Device::MEDIA_DVD_PLUS_ALL ) { 0814 if( d->doc->dummy() ) { 0815 if( !questionYesNo( i18n("%1 media do not support write simulation. " 0816 "Do you really want to continue? The disc will actually be " 0817 "written to.", Device::mediaTypeString(foundMedium, true)), 0818 i18n("No Simulation with %1", Device::mediaTypeString(foundMedium, true)) ) ) { 0819 return false; 0820 } 0821 0822 d->doc->setDummy( false ); 0823 } 0824 0825 if( d->doc->writingMode() != K3b::WritingModeAuto && d->doc->writingMode() != K3b::WritingModeRestrictedOverwrite ) 0826 emit infoMessage( i18n("Writing mode ignored when writing %1 media.", Device::mediaTypeString(foundMedium, true)), MessageInfo ); 0827 d->usedWritingMode = K3b::WritingModeSao; // since cdrecord uses -sao for DVD+R(W) 0828 0829 // Cdrecord doesn't support multisession DVD+R(W) disks 0830 if( usedMultiSessionMode() != DataDoc::NONE && 0831 d->usedWritingApp == K3b::WritingAppCdrecord ) { 0832 d->usedWritingApp = WritingAppGrowisofs; 0833 } 0834 0835 if( foundMedium & K3b::Device::MEDIA_DVD_PLUS_RW && 0836 ( usedMultiSessionMode() == K3b::DataDoc::CONTINUE || 0837 usedMultiSessionMode() == K3b::DataDoc::FINISH ) ) 0838 emit infoMessage( i18n("Growing ISO 9660 filesystem on %1.", Device::mediaTypeString(foundMedium, true)), MessageInfo ); 0839 else 0840 emit infoMessage( i18n("Writing %1.", Device::mediaTypeString(foundMedium, true)), MessageInfo ); 0841 } 0842 0843 // ------------------------------- 0844 // DVD Minus 0845 // ------------------------------- 0846 else if ( foundMedium & K3b::Device::MEDIA_DVD_MINUS_ALL ) { 0847 if( d->doc->dummy() && !d->doc->burner()->dvdMinusTestwrite() ) { 0848 if( !questionYesNo( i18n("Your writer (%1 %2) does not support simulation with DVD-R(W) media. " 0849 "Do you really want to continue? The media will actually be " 0850 "written to.", 0851 d->doc->burner()->vendor(), 0852 d->doc->burner()->description()), 0853 i18n("No Simulation with DVD-R(W)") ) ) { 0854 return false; 0855 } 0856 0857 d->doc->setDummy( false ); 0858 } 0859 0860 // RESTRICTED OVERWRITE 0861 // -------------------- 0862 if( foundMedium & K3b::Device::MEDIA_DVD_RW_OVWR ) { 0863 d->usedWritingMode = K3b::WritingModeRestrictedOverwrite; 0864 if( usedMultiSessionMode() == K3b::DataDoc::NONE || 0865 usedMultiSessionMode() == K3b::DataDoc::START ) { 0866 // FIXME: can cdrecord handle this? 0867 emit infoMessage( i18n("Writing DVD-RW in restricted overwrite mode."), MessageInfo ); 0868 } 0869 else { 0870 emit infoMessage( i18n("Growing ISO 9660 filesystem on DVD-RW in restricted overwrite mode."), MessageInfo ); 0871 // we can only do this with growisofs 0872 d->usedWritingApp = K3b::WritingAppGrowisofs; 0873 } 0874 } 0875 0876 // NORMAL 0877 // ------ 0878 else { 0879 0880 // FIXME: DVD-R DL jump and stuff 0881 0882 if( d->doc->writingMode() == K3b::WritingModeSao ) { 0883 d->usedWritingMode = K3b::WritingModeSao; 0884 emit infoMessage( i18n("Writing %1 in DAO mode.", K3b::Device::mediaTypeString(foundMedium, true) ), MessageInfo ); 0885 } 0886 0887 else { 0888 // check if the writer supports writing sequential and thus multisession (on -1 the burner cannot handle 0889 // features and we simply ignore it and hope for the best) 0890 if( d->doc->burner()->featureCurrent( K3b::Device::FEATURE_INCREMENTAL_STREAMING_WRITABLE ) == 0 ) { 0891 if( !questionYesNo( i18n("Your writer (%1 %2) does not support Incremental Streaming with %3 " 0892 "media. Multisession will not be possible. Continue anyway?", 0893 d->doc->burner()->vendor(), 0894 d->doc->burner()->description(), 0895 K3b::Device::mediaTypeString(foundMedium, true) ), 0896 i18n("No Incremental Streaming") ) ) { 0897 return false; 0898 } 0899 else { 0900 d->usedWritingMode = K3b::WritingModeSao; 0901 emit infoMessage( i18n("Writing %1 in DAO mode.", K3b::Device::mediaTypeString(foundMedium, true) ), MessageInfo ); 0902 } 0903 } 0904 else { 0905 d->usedWritingMode = K3b::WritingModeIncrementalSequential; 0906 if( !(foundMedium & (K3b::Device::MEDIA_DVD_RW|K3b::Device::MEDIA_DVD_RW_OVWR|K3b::Device::MEDIA_DVD_RW_SEQ)) && 0907 d->doc->writingMode() == K3b::WritingModeRestrictedOverwrite ) 0908 emit infoMessage( i18n("Restricted Overwrite is not possible with DVD-R media."), MessageInfo ); 0909 0910 emit infoMessage( i18n("Writing %1 in incremental mode.", K3b::Device::mediaTypeString(foundMedium, true) ), MessageInfo ); 0911 } 0912 } 0913 } 0914 } 0915 } 0916 0917 // -------------------- 0918 // Blu-ray 0919 // -------------------- 0920 else if ( foundMedium & K3b::Device::MEDIA_BD_ALL ) { 0921 d->usedWritingApp = writingApp(); 0922 if( d->usedWritingApp == K3b::WritingAppAuto ) { 0923 if ( cdrecordBin && cdrecordBin->hasFeature( "wodim" )) 0924 d->usedWritingApp = K3b::WritingAppGrowisofs; 0925 else 0926 d->usedWritingApp = K3b::WritingAppCdrecord; 0927 } 0928 0929 if (d->usedWritingApp == K3b::WritingAppCdrecord && 0930 cdrecordBin && !cdrecordBin->hasFeature("blu-ray")) { 0931 d->usedWritingApp = K3b::WritingAppGrowisofs; 0932 } 0933 0934 if( d->doc->dummy() ) { 0935 if( !questionYesNo( i18n("%1 media do not support write simulation. " 0936 "Do you really want to continue? The disc will actually be " 0937 "written to.", Device::mediaTypeString(foundMedium, true)), 0938 i18n("No Simulation with %1", Device::mediaTypeString(foundMedium, true)) ) ) { 0939 return false; 0940 } 0941 0942 d->doc->setDummy( false ); 0943 } 0944 0945 if( d->doc->writingMode() != K3b::WritingModeAuto ) 0946 emit infoMessage( i18n("Writing mode ignored when writing %1 media.", Device::mediaTypeString(foundMedium, true)), MessageInfo ); 0947 d->usedWritingMode = K3b::WritingModeSao; // cdrecord uses -sao for DVD+R(W), let's assume it's used also for BD-R(E) 0948 0949 // Cdrecord probably doesn't support multisession BD-R disks 0950 // FIXME: check if above is actually true 0951 if( usedMultiSessionMode() != DataDoc::NONE && 0952 d->usedWritingApp == K3b::WritingAppCdrecord ) { 0953 d->usedWritingApp = WritingAppGrowisofs; 0954 } 0955 0956 if( foundMedium & K3b::Device::MEDIA_BD_RE && 0957 ( usedMultiSessionMode() == K3b::DataDoc::CONTINUE || 0958 usedMultiSessionMode() == K3b::DataDoc::FINISH ) ) 0959 emit infoMessage( i18n("Growing ISO 9660 filesystem on %1.", Device::mediaTypeString(foundMedium, true)), MessageInfo ); 0960 else 0961 emit infoMessage( i18n("Writing %1.", Device::mediaTypeString(foundMedium, true)), MessageInfo ); 0962 } 0963 0964 return true; 0965 } 0966 0967 0968 QString K3b::DataJob::jobDescription() const 0969 { 0970 if( d->doc->onlyCreateImages() ) { 0971 return i18n("Creating Data Image File"); 0972 } 0973 else if( d->doc->multiSessionMode() == K3b::DataDoc::NONE || 0974 d->doc->multiSessionMode() == K3b::DataDoc::AUTO ) { 0975 return i18n("Writing Data Project") 0976 + ( d->doc->isoOptions().volumeID().isEmpty() 0977 ? QString() 0978 : QString( " (%1)" ).arg(d->doc->isoOptions().volumeID()) ); 0979 } 0980 else { 0981 return i18n("Writing Multisession Project") 0982 + ( d->doc->isoOptions().volumeID().isEmpty() 0983 ? QString() 0984 : QString( " (%1)" ).arg(d->doc->isoOptions().volumeID()) ); 0985 } 0986 } 0987 0988 0989 QString K3b::DataJob::jobDetails() const 0990 { 0991 if( d->doc->copies() > 1 && 0992 !d->doc->dummy() && 0993 !(d->doc->multiSessionMode() == K3b::DataDoc::CONTINUE || 0994 d->doc->multiSessionMode() == K3b::DataDoc::FINISH) ) 0995 return i18np("ISO 9660 Filesystem (Size: %2) – One copy", 0996 "ISO 9660 Filesystem (Size: %2) – %1 copies", 0997 d->doc->copies(), 0998 KIO::convertSize( d->doc->size() ) ); 0999 else 1000 return i18n( "ISO 9660 Filesystem (Size: %1)", 1001 KIO::convertSize( d->doc->size() ) ); 1002 } 1003 1004 1005 K3b::DataDoc::MultiSessionMode K3b::DataJob::usedMultiSessionMode() const 1006 { 1007 return d->multiSessionParameterJob->usedMultiSessionMode(); 1008 } 1009 1010 1011 void K3b::DataJob::cleanup() 1012 { 1013 qDebug(); 1014 if( !d->doc->onTheFly() && ( d->doc->removeImages() || d->canceled ) ) { 1015 if( QFile::exists( d->doc->tempDir() ) ) { 1016 d->imageFile.remove(); 1017 emit infoMessage( i18n("Removed image file %1",d->doc->tempDir()), K3b::Job::MessageSuccess ); 1018 } 1019 } 1020 1021 if( d->tocFile ) { 1022 delete d->tocFile; 1023 d->tocFile = 0; 1024 } 1025 } 1026 1027 1028 bool K3b::DataJob::hasBeenCanceled() const 1029 { 1030 return d->canceled; 1031 } 1032 1033 1034 bool K3b::DataJob::setupCdrecordJob() 1035 { 1036 qDebug(); 1037 K3b::CdrecordWriter* writer = new K3b::CdrecordWriter( d->doc->burner(), this, this ); 1038 1039 // cdrecord manpage says that "not all" writers are able to write 1040 // multisession disks in dao mode. That means there are writers that can. 1041 1042 // Does it really make sence to write Data ms cds in DAO mode since writing the 1043 // first session of a cd-extra in DAO mode is no problem with my writer while 1044 // writing the second data session is only possible in TAO mode. 1045 if( d->usedWritingMode == K3b::WritingModeSao && 1046 usedMultiSessionMode() != K3b::DataDoc::NONE ) 1047 emit infoMessage( i18n("Most writers do not support writing " 1048 "multisession CDs in DAO mode."), MessageInfo ); 1049 1050 writer->setWritingMode( d->usedWritingMode ); 1051 writer->setSimulate( d->doc->dummy() ); 1052 writer->setBurnSpeed( d->doc->speed() ); 1053 1054 // multisession 1055 writer->setMulti( usedMultiSessionMode() == K3b::DataDoc::START || 1056 usedMultiSessionMode() == K3b::DataDoc::CONTINUE ); 1057 1058 if( d->doc->onTheFly() && 1059 ( usedMultiSessionMode() == K3b::DataDoc::CONTINUE || 1060 usedMultiSessionMode() == K3b::DataDoc::FINISH ) ) 1061 writer->addArgument("-waiti"); 1062 1063 if( d->usedDataMode == K3b::DataMode1 ) 1064 writer->addArgument( "-data" ); 1065 else { 1066 const K3b::ExternalBin* cdrecordBin = k3bcore->externalBinManager()->binObject("cdrecord"); 1067 if( cdrecordBin && cdrecordBin->hasFeature( "xamix" ) ) 1068 writer->addArgument( "-xa" ); 1069 else 1070 writer->addArgument( "-xa1" ); 1071 } 1072 1073 writer->addArgument( QString("-tsize=%1s").arg(m_isoImager->size()) )->addArgument("-"); 1074 1075 setWriterJob( writer ); 1076 1077 return true; 1078 } 1079 1080 1081 bool K3b::DataJob::setupCdrdaoJob() 1082 { 1083 // create cdrdao job 1084 K3b::CdrdaoWriter* writer = new K3b::CdrdaoWriter( d->doc->burner(), this, this ); 1085 writer->setCommand( K3b::CdrdaoWriter::WRITE ); 1086 writer->setSimulate( d->doc->dummy() ); 1087 writer->setBurnSpeed( d->doc->speed() ); 1088 // multisession 1089 writer->setMulti( usedMultiSessionMode() == K3b::DataDoc::START || 1090 usedMultiSessionMode() == K3b::DataDoc::CONTINUE ); 1091 1092 // now write the tocfile 1093 if( d->tocFile ) delete d->tocFile; 1094 d->tocFile = new QTemporaryFile( "XXXXXX.toc" ); 1095 d->tocFile->open(); 1096 1097 QTextStream s( d->tocFile ); 1098 if( d->usedDataMode == K3b::DataMode1 ) { 1099 s << "CD_ROM" << "\n"; 1100 s << "\n"; 1101 s << "TRACK MODE1" << "\n"; 1102 } 1103 else { 1104 s << "CD_ROM_XA" << "\n"; 1105 s << "\n"; 1106 s << "TRACK MODE2_FORM1" << "\n"; 1107 } 1108 1109 s << "DATAFILE \"-\" " << m_isoImager->size()*2048 << "\n"; 1110 1111 d->tocFile->close(); 1112 1113 writer->setTocFile( d->tocFile->fileName() ); 1114 1115 setWriterJob( writer ); 1116 1117 return true; 1118 } 1119 1120 1121 bool K3b::DataJob::setupGrowisofsJob() 1122 { 1123 K3b::GrowisofsWriter* writer = new K3b::GrowisofsWriter( d->doc->burner(), this, this ); 1124 1125 // these do only make sense with DVD-R(W) 1126 writer->setSimulate( d->doc->dummy() ); 1127 writer->setBurnSpeed( d->doc->speed() ); 1128 1129 // Andy said incremental sequential is the default mode and it seems uses have more problems with DAO anyway 1130 // BUT: I also had a report that incremental sequential produced unreadable media! 1131 if( d->doc->writingMode() == K3b::WritingModeSao ) 1132 // || ( d->doc->writingMode() == K3b::WritingModeAuto && 1133 // usedMultiSessionMode() == K3b::DataDoc::NONE ) ) 1134 writer->setWritingMode( K3b::WritingModeSao ); 1135 1136 writer->setMultiSession( usedMultiSessionMode() == K3b::DataDoc::CONTINUE || 1137 usedMultiSessionMode() == K3b::DataDoc::FINISH ); 1138 1139 writer->setCloseDvd( usedMultiSessionMode() == K3b::DataDoc::NONE || 1140 usedMultiSessionMode() == K3b::DataDoc::FINISH ); 1141 1142 writer->setImageToWrite( QString() ); // read from stdin 1143 writer->setTrackSize( m_isoImager->size() ); 1144 1145 if( usedMultiSessionMode() != K3b::DataDoc::NONE ) { 1146 // 1147 // growisofs wants a valid -C parameter for multisession, so we get it from the 1148 // K3b::MsInfoFetcher (see K3b::DataJob::prepareWriting) 1149 // 1150 writer->setMultiSessionInfo( m_isoImager->multiSessionInfo() ); 1151 } 1152 1153 setWriterJob( writer ); 1154 1155 return true; 1156 } 1157 1158 #include "moc_k3bdatajob.cpp"