3
* Copyright (C) 2003-2009 Sebastian Trueg <trueg@k3b.org>
5
* This file is part of the K3b project.
6
* Copyright (C) 1998-2009 Sebastian Trueg <trueg@k3b.org>
8
* This program is free software; you can redistribute it and/or modify
9
* it under the terms of the GNU General Public License as published by
10
* the Free Software Foundation; either version 2 of the License, or
11
* (at your option) any later version.
12
* See the file "COPYING" for the exact licensing terms.
16
#include "k3bdatajob.h"
17
#include "k3bdatadoc.h"
18
#include "k3bisoimager.h"
19
#include "k3bdatamultisessionparameterjob.h"
20
#include "k3bchecksumpipe.h"
22
#include "k3bglobals.h"
23
#include "k3bversion.h"
24
#include "k3bdevice.h"
25
#include "k3bdevicehandler.h"
28
#include "k3bdevicehandler.h"
29
#include "k3bexternalbinmanager.h"
30
#include "k3bcdrecordwriter.h"
31
#include "k3bcdrdaowriter.h"
32
#include "k3bglobalsettings.h"
33
#include "k3bactivepipe.h"
34
#include "k3bfilesplitter.h"
35
#include "k3bverificationjob.h"
36
#include "k3biso9660.h"
37
#include "k3bisooptions.h"
38
#include "k3bdeviceglobals.h"
39
#include "k3bgrowisofswriter.h"
41
#include <kapplication.h>
43
#include <kstandarddirs.h>
44
#include <ktemporaryfile.h>
45
#include <kio/global.h>
49
#include <qstringlist.h>
50
#include <qdatetime.h>
52
#include <qdatastream.h>
57
class K3b::DataJob::Private
61
: usedWritingApp(K3b::WritingAppCdrecord),
68
bool initializingImager;
72
KTemporaryFile* tocFile;
75
K3b::WritingApp usedWritingApp;
76
K3b::WritingMode usedWritingMode;
81
K3b::VerificationJob* verificationJob;
83
K3b::FileSplitter imageFile;
84
K3b::ActivePipe* pipe;
86
K3b::DataMultiSessionParameterJob* multiSessionParameterJob;
88
QByteArray checksumCache;
92
K3b::DataJob::DataJob( K3b::DataDoc* doc, K3b::JobHandler* hdl, QObject* parent )
93
: K3b::BurnJob( hdl, parent )
96
d->multiSessionParameterJob = new K3b::DataMultiSessionParameterJob( doc, this, this );
97
connectSubJob( d->multiSessionParameterJob,
98
SLOT( slotMultiSessionParamterSetupDone( bool ) ),
99
SIGNAL( newTask( const QString& ) ),
100
SIGNAL( newSubTask( const QString& ) ) );
109
K3b::DataJob::~DataJob()
118
K3b::Doc* K3b::DataJob::doc() const
124
K3b::Device::Device* K3b::DataJob::writer() const
126
if( doc()->onlyCreateImages() )
127
return 0; // no writer needed -> no blocking on K3b::BurnJob
129
return doc()->burner();
133
void K3b::DataJob::start()
139
d->imageFinished = false;
140
d->copies = d->doc->copies();
145
if( d->doc->dummy() ) {
146
d->doc->setVerifyData( false );
150
emit newTask( i18n("Preparing data") );
152
// there is no harm in setting these even if we write on-the-fly
153
d->imageFile.setName( d->doc->tempDir() );
155
d->multiSessionParameterJob->start();
159
void K3b::DataJob::slotMultiSessionParamterSetupDone( bool success )
166
if ( d->multiSessionParameterJob->hasBeenCanceled() ) {
170
jobFinished( false );
175
void K3b::DataJob::prepareWriting()
178
if( !d->doc->onlyCreateImages() &&
179
( d->multiSessionParameterJob->usedMultiSessionMode() == K3b::DataDoc::CONTINUE ||
180
d->multiSessionParameterJob->usedMultiSessionMode() == K3b::DataDoc::FINISH ) ) {
181
unsigned int nextSessionStart = d->multiSessionParameterJob->nextSessionStart();
182
// for some reason cdrdao needs 150 additional sectors in the ms info
183
if( writingApp() == K3b::WritingAppCdrdao ) {
184
nextSessionStart += 150;
186
m_isoImager->setMultiSessionInfo( QString().sprintf( "%u,%u",
187
d->multiSessionParameterJob->previousSessionStart(),
189
d->multiSessionParameterJob->importPreviousSession() ? d->doc->burner() : 0 );
192
m_isoImager->setMultiSessionInfo( QString(), 0 );
195
d->initializingImager = true;
200
void K3b::DataJob::writeImage()
203
d->initializingImager = false;
207
// get image file path
208
if( d->doc->tempDir().isEmpty() )
209
d->doc->setTempDir( K3b::findUniqueFilePrefix( d->doc->isoOptions().volumeID() ) + ".iso" );
211
// TODO: check if the image file is part of the project and if so warn the user
212
// and append some number to make the path unique.
215
// Check the image file
216
if( !d->doc->onTheFly() || d->doc->onlyCreateImages() ) {
217
d->imageFile.setName( d->doc->tempDir() );
218
if( !d->imageFile.open( QIODevice::WriteOnly ) ) {
219
emit infoMessage( i18n("Could not open %1 for writing", d->doc->tempDir() ), MessageError );
226
emit newTask( i18n("Creating image file") );
227
emit newSubTask( i18n("Track 1 of 1") );
228
emit infoMessage( i18n("Creating image file in %1",d->doc->tempDir()), MessageInfo );
230
m_isoImager->start();
235
void K3b::DataJob::startPipe()
239
// Open the active pipe which does the streaming
242
if ( d->imageFinished || !d->doc->verifyData() )
243
d->pipe = new K3b::ActivePipe();
245
d->pipe = new K3b::ChecksumPipe();
248
#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?
250
if( d->imageFinished || ( d->doc->onTheFly() && !d->doc->onlyCreateImages() ) )
251
d->pipe->writeTo( m_writerJob->ioDevice(), d->usedWritingApp != K3b::WritingAppCdrecord );
253
d->pipe->writeTo( &d->imageFile, true );
255
if ( d->imageFinished )
256
d->pipe->readFrom( &d->imageFile, true );
258
d->pipe->readFrom( m_isoImager->ioDevice(), true );
260
d->pipe->open( true );
264
bool K3b::DataJob::startOnTheFlyWriting()
267
if( prepareWriterJob() ) {
268
if( startWriterJob() ) {
269
d->initializingImager = false;
270
m_isoImager->start();
279
void K3b::DataJob::cancel()
288
// Just cancel all and return, let slotMultiSessionParamterSetupDone,
289
// slotIsoImagerFinished, and slotWriterJobFinished take care of the rest
291
if ( active() && !cancelAll() ) {
292
kDebug() << "cancellation already done";
294
jobFinished( false );
299
bool K3b::DataJob::cancelAll()
302
bool somethingCanceled = false;
303
if ( m_isoImager->active() ) {
304
kDebug() << "cancelling iso imager";
305
m_isoImager->cancel();
306
somethingCanceled = true;
308
if( m_writerJob && m_writerJob->active() ) {
309
kDebug() << "cancelling writing job";
310
m_writerJob->cancel();
311
somethingCanceled = true;
313
if( d->verificationJob && d->verificationJob->active() ) {
314
kDebug() << "cancelling verification job";
315
d->verificationJob->cancel();
316
somethingCanceled = true;
318
if ( d->multiSessionParameterJob && d->multiSessionParameterJob->active() ) {
319
kDebug() << "cancelling multiSessionParameterJob";
320
d->multiSessionParameterJob->cancel();
321
somethingCanceled = true;
324
kDebug() << somethingCanceled;
325
return somethingCanceled;
329
void K3b::DataJob::slotIsoImagerPercent( int p )
331
if( d->doc->onlyCreateImages() ) {
332
emit subPercent( p );
335
else if( !d->doc->onTheFly() ) {
336
double totalTasks = d->copies;
337
double tasksDone = d->copiesDone; // =0 when creating an image
338
if( d->doc->verifyData() ) {
342
if( !d->doc->onTheFly() ) {
346
emit subPercent( p );
347
emit percent( (int)((100.0*tasksDone + (double)p) / totalTasks) );
352
void K3b::DataJob::slotIsoImagerFinished( bool success )
355
if( d->initializingImager ) {
357
if( d->doc->onTheFly() && !d->doc->onlyCreateImages() ) {
358
if( !startOnTheFlyWriting() ) {
360
jobFinished( false );
368
if( m_isoImager->hasBeenCanceled() ) {
371
else if ( !cancelAll() ) {
373
jobFinished( false );
378
// cache the calculated checksum since the ChecksumPipe may be deleted below
379
if ( ChecksumPipe* cp = qobject_cast<ChecksumPipe*>( d->pipe ) )
380
d->checksumCache = cp->checksum();
382
if( !d->doc->onTheFly() ||
383
d->doc->onlyCreateImages() ) {
386
emit infoMessage( i18n("Image successfully created in %1", d->doc->tempDir()), K3b::Job::MessageSuccess );
387
d->imageFinished = true;
389
if( d->doc->onlyCreateImages() ) {
392
else if( !d->imageFile.open( QIODevice::ReadOnly ) ) {
393
emit infoMessage( i18n("Could not open file %1", d->doc->tempDir() ), MessageError );
397
else if( prepareWriterJob() ) {
403
if( m_isoImager->hasBeenCanceled() )
406
emit infoMessage( i18n("Error while creating ISO image"), MessageError );
410
jobFinished( false );
415
if ( !m_writerJob->active() )
420
// In case the imager failed let's make sure the writer does not emit an unusable
423
if( m_writerJob && m_writerJob->active() )
424
m_writerJob->setSourceUnreadable( true );
426
// there is one special case which we need to handle here: the iso imager might be canceled
427
// FIXME: the iso imager should not be able to cancel itself
428
if( m_isoImager->hasBeenCanceled() && !this->hasBeenCanceled() )
436
bool K3b::DataJob::startWriterJob()
439
if( d->doc->dummy() )
440
emit newTask( i18n("Simulating") );
441
else if( d->copies > 1 )
442
emit newTask( i18n("Writing Copy %1",d->copiesDone+1) );
444
emit newTask( i18n("Writing") );
447
m_writerJob->start();
452
void K3b::DataJob::slotWriterJobPercent( int p )
454
double totalTasks = d->copies;
455
double tasksDone = d->copiesDone;
456
if( d->doc->verifyData() ) {
460
if( !d->doc->onTheFly() ) {
465
emit percent( (int)((100.0*tasksDone + (double)p) / totalTasks) );
469
void K3b::DataJob::slotWriterNextTrack( int t, int tt )
471
emit newSubTask( i18n("Writing Track %1 of %2",t,tt) );
475
void K3b::DataJob::slotWriterJobFinished( bool success )
480
if ( !d->doc->onTheFly() ||
481
!m_isoImager->active() ) {
486
if ( !cancelAll() ) {
488
jobFinished( false );
494
void K3b::DataJob::finishCopy()
496
// the writerJob should have emitted the "simulation/writing successful" signal
498
if( d->doc->verifyData() ) {
499
if( !d->verificationJob ) {
500
d->verificationJob = new K3b::VerificationJob( this, this );
501
connect( d->verificationJob, SIGNAL(infoMessage(const QString&, int)),
502
this, SIGNAL(infoMessage(const QString&, int)) );
503
connect( d->verificationJob, SIGNAL(newTask(const QString&)),
504
this, SIGNAL(newSubTask(const QString&)) );
505
connect( d->verificationJob, SIGNAL(newSubTask(const QString&)),
506
this, SIGNAL(newSubTask(const QString&)) );
507
connect( d->verificationJob, SIGNAL(percent(int)),
508
this, SLOT(slotVerificationProgress(int)) );
509
connect( d->verificationJob, SIGNAL(percent(int)),
510
this, SIGNAL(subPercent(int)) );
511
connect( d->verificationJob, SIGNAL(finished(bool)),
512
this, SLOT(slotVerificationFinished(bool)) );
513
connect( d->verificationJob, SIGNAL(debuggingOutput(const QString&, const QString&)),
514
this, SIGNAL(debuggingOutput(const QString&, const QString&)) );
517
d->verificationJob->clear();
518
d->verificationJob->setDevice( d->doc->burner() );
519
d->verificationJob->setGrownSessionSize( m_isoImager->size() );
520
d->verificationJob->addTrack( 0, d->checksumCache, m_isoImager->size() );
524
emit newTask( i18n("Verifying written data") );
526
d->verificationJob->start();
531
if( d->copiesDone < d->copies ) {
532
if( !K3b::eject( d->doc->burner() ) ) {
533
blockingInformation( i18n("K3b was unable to eject the written disk. Please do so manually.") );
537
if( d->doc->onTheFly() )
538
failed = !startOnTheFlyWriting();
540
failed = !prepareWriterJob() || !startWriterJob();
545
else if( !d->doc->onTheFly() ) {
547
#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?
549
d->pipe->writeTo( m_writerJob->ioDevice(), d->usedWritingApp != K3b::WritingAppCdrecord );
555
if ( k3bcore->globalSettings()->ejectMedia() ) {
556
K3b::Device::eject( d->doc->burner() );
564
void K3b::DataJob::slotVerificationProgress( int p )
566
double totalTasks = d->copies*2;
567
double tasksDone = d->copiesDone*2 + 1; // the writing of the current copy has already been finished
569
if( !d->doc->onTheFly() ) {
574
emit percent( (int)((100.0*tasksDone + (double)p) / totalTasks) );
578
void K3b::DataJob::slotVerificationFinished( bool success )
583
// reconnect our imager which we deconnected for the verification
586
if( k3bcore->globalSettings()->ejectMedia() || d->copiesDone < d->copies )
587
K3b::Device::eject( d->doc->burner() );
589
if( !d->canceled && d->copiesDone < d->copies ) {
591
if( d->doc->onTheFly() )
592
failed = !startOnTheFlyWriting();
594
failed = !prepareWriterJob() || !startWriterJob();
598
else if( !d->doc->onTheFly() ) {
600
#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?
602
d->pipe->writeTo( m_writerJob->ioDevice(), d->usedWritingApp != K3b::WritingAppCdrecord );
608
jobFinished( success );
613
void K3b::DataJob::setWriterJob( K3b::AbstractWriter* writer )
616
// FIXME: progressedsize for multiple copies
617
m_writerJob = writer;
618
connect( m_writerJob, SIGNAL(infoMessage(const QString&, int)), this, SIGNAL(infoMessage(const QString&, int)) );
619
connect( m_writerJob, SIGNAL(percent(int)), this, SLOT(slotWriterJobPercent(int)) );
620
connect( m_writerJob, SIGNAL(processedSize(int, int)), this, SIGNAL(processedSize(int, int)) );
621
connect( m_writerJob, SIGNAL(subPercent(int)), this, SIGNAL(subPercent(int)) );
622
connect( m_writerJob, SIGNAL(processedSubSize(int, int)), this, SIGNAL(processedSubSize(int, int)) );
623
connect( m_writerJob, SIGNAL(nextTrack(int, int)), this, SLOT(slotWriterNextTrack(int, int)) );
624
connect( m_writerJob, SIGNAL(buffer(int)), this, SIGNAL(bufferStatus(int)) );
625
connect( m_writerJob, SIGNAL(deviceBuffer(int)), this, SIGNAL(deviceBuffer(int)) );
626
connect( m_writerJob, SIGNAL(writeSpeed(int, K3b::Device::SpeedMultiplicator)), this, SIGNAL(writeSpeed(int, K3b::Device::SpeedMultiplicator)) );
627
connect( m_writerJob, SIGNAL(finished(bool)), this, SLOT(slotWriterJobFinished(bool)) );
628
connect( m_writerJob, SIGNAL(newSubTask(const QString&)), this, SIGNAL(newSubTask(const QString&)) );
629
connect( m_writerJob, SIGNAL(debuggingOutput(const QString&, const QString&)),
630
this, SIGNAL(debuggingOutput(const QString&, const QString&)) );
634
void K3b::DataJob::setImager( K3b::IsoImager* imager )
637
if( m_isoImager != imager ) {
640
m_isoImager = imager;
647
void K3b::DataJob::connectImager()
650
m_isoImager->disconnect( this );
651
connect( m_isoImager, SIGNAL(infoMessage(const QString&, int)), this, SIGNAL(infoMessage(const QString&, int)) );
652
connect( m_isoImager, SIGNAL(percent(int)), this, SLOT(slotIsoImagerPercent(int)) );
653
connect( m_isoImager, SIGNAL(finished(bool)), this, SLOT(slotIsoImagerFinished(bool)) );
654
connect( m_isoImager, SIGNAL(debuggingOutput(const QString&, const QString&)),
655
this, SIGNAL(debuggingOutput(const QString&, const QString&)) );
659
void K3b::DataJob::prepareImager()
663
setImager( new K3b::IsoImager( d->doc, this, this ) );
667
bool K3b::DataJob::prepareWriterJob()
675
// if we append a new session we asked for an appendable cd already
676
if( !waitForBurnMedium() ) {
680
// It seems as if cdrecord is not able to append sessions in dao mode whereas cdrdao is
681
if( d->usedWritingApp == K3b::WritingAppCdrecord ) {
682
if( !setupCdrecordJob() ) {
686
else if ( d->usedWritingApp == K3b::WritingAppCdrdao ) {
687
if ( !setupCdrdaoJob() ) {
692
if ( !setupGrowisofsJob() ) {
701
bool K3b::DataJob::waitForBurnMedium()
703
// start with all media types supported by the writer
704
Device::MediaTypes m = d->doc->supportedMediaTypes() & d->doc->burner()->writeCapabilities();
706
// if everything goes wrong we are left with no possible media to request
708
emit infoMessage( i18n( "Internal Error: No medium type fits. This project cannot be burned." ), MessageError );
712
emit newSubTask( i18n("Waiting for a medium") );
713
Device::MediaType foundMedium = waitForMedium( d->doc->burner(),
714
usedMultiSessionMode() == K3b::DataDoc::CONTINUE ||
715
usedMultiSessionMode() == K3b::DataDoc::FINISH ?
716
K3b::Device::STATE_INCOMPLETE :
717
K3b::Device::STATE_EMPTY,
719
d->doc->burningLength() );
721
if( foundMedium == Device::MEDIA_UNKNOWN || hasBeenCanceled() ) {
725
// -------------------------------
727
// -------------------------------
728
else if ( foundMedium & K3b::Device::MEDIA_CD_ALL ) {
729
emit infoMessage( i18n( "Writing %1" , K3b::Device::mediaTypeString( foundMedium ) ), MessageInfo );
731
// first of all we determine the data mode
732
if( d->doc->dataMode() == K3b::DataModeAuto ) {
733
if( !d->doc->onlyCreateImages() &&
734
( usedMultiSessionMode() == K3b::DataDoc::CONTINUE ||
735
usedMultiSessionMode() == K3b::DataDoc::FINISH ) ) {
737
// try to get the last track's datamode
738
// we already asked for an appendable cdr when fetching
740
kDebug() << "(K3b::DataJob) determining last track's datamode...";
742
// FIXME: use the DeviceHandler
743
K3b::Device::Toc toc = d->doc->burner()->readToc();
744
if( toc.isEmpty() ) {
745
kDebug() << "(K3b::DataJob) could not retrieve toc.";
746
emit infoMessage( i18n("Unable to determine the last track's datamode. Using default."), MessageError );
747
d->usedDataMode = K3b::DataMode2;
750
if( toc.back().mode() == K3b::Device::Track::MODE1 )
751
d->usedDataMode = K3b::DataMode1;
753
d->usedDataMode = K3b::DataMode2;
755
kDebug() << "(K3b::DataJob) using datamode: "
756
<< (d->usedDataMode == K3b::DataMode1 ? "mode1" : "mode2")
760
else if( usedMultiSessionMode() == K3b::DataDoc::NONE )
761
d->usedDataMode = K3b::DataMode1;
763
d->usedDataMode = K3b::DataMode2;
766
d->usedDataMode = d->doc->dataMode();
768
// determine the writing mode
769
if( d->doc->writingMode() == K3b::WritingModeAuto ) {
770
// TODO: put this into the cdreocrdwriter and decide based on the size of the
772
if( writer()->dao() && d->usedDataMode == K3b::DataMode1 &&
773
usedMultiSessionMode() == K3b::DataDoc::NONE )
774
d->usedWritingMode = K3b::WritingModeSao;
776
d->usedWritingMode = K3b::WritingModeTao;
779
d->usedWritingMode = d->doc->writingMode();
782
if ( writingApp() == K3b::WritingAppGrowisofs ) {
783
emit infoMessage( i18n( "Cannot write %1 media using %2. Falling back to default application." , QString("CD") , QString("growisofs") ), MessageWarning );
784
setWritingApp( K3b::WritingAppAuto );
786
// cdrecord seems to have problems writing xa 1 disks in dao mode? At least on my system!
787
if( writingApp() == K3b::WritingAppAuto ) {
788
if( d->usedWritingMode == K3b::WritingModeSao ) {
789
if( usedMultiSessionMode() != K3b::DataDoc::NONE )
790
d->usedWritingApp = K3b::WritingAppCdrdao;
791
else if( d->usedDataMode == K3b::DataMode2 )
792
d->usedWritingApp = K3b::WritingAppCdrdao;
794
d->usedWritingApp = K3b::WritingAppCdrecord;
797
d->usedWritingApp = K3b::WritingAppCdrecord;
800
d->usedWritingApp = writingApp();
804
else if ( foundMedium & K3b::Device::MEDIA_DVD_ALL ) {
805
if ( writingApp() == K3b::WritingAppCdrdao ) {
806
emit infoMessage( i18n( "Cannot write %1 media using %2. Falling back to default application.",
807
K3b::Device::mediaTypeString( foundMedium, true ), "cdrdao" ), MessageWarning );
808
setWritingApp( K3b::WritingAppAuto );
811
// make sure that we use the proper parameters for cdrecord
812
d->usedDataMode = K3b::DataMode1;
814
d->usedWritingApp = writingApp();
815
// let's default to cdrecord for the time being (except for special cases below)
816
if ( d->usedWritingApp == K3b::WritingAppAuto ) {
817
d->usedWritingApp = K3b::WritingAppCdrecord;
820
// -------------------------------
822
// -------------------------------
823
if( foundMedium & K3b::Device::MEDIA_DVD_PLUS_ALL ) {
824
if( d->doc->dummy() ) {
825
if( !questionYesNo( i18n("%1 media do not support write simulation. "
826
"Do you really want to continue? The disc will actually be "
827
"written to.", Device::mediaTypeString(foundMedium, true)),
828
i18n("No Simulation with %1", Device::mediaTypeString(foundMedium, true)) ) ) {
832
d->doc->setDummy( false );
835
if( d->doc->writingMode() != K3b::WritingModeAuto && d->doc->writingMode() != K3b::WritingModeRestrictedOverwrite )
836
emit infoMessage( i18n("Writing mode ignored when writing %1 media.", Device::mediaTypeString(foundMedium, true)), MessageInfo );
837
d->usedWritingMode = K3b::WritingModeSao; // since cdrecord uses -sao for DVD+R(W)
839
// Cdrecord doesn't support multisession DVD+R(W) disks
840
if( usedMultiSessionMode() != DataDoc::NONE &&
841
d->usedWritingApp == K3b::WritingAppCdrecord ) {
842
d->usedWritingApp = WritingAppGrowisofs;
845
if( foundMedium & K3b::Device::MEDIA_DVD_PLUS_RW &&
846
( usedMultiSessionMode() == K3b::DataDoc::CONTINUE ||
847
usedMultiSessionMode() == K3b::DataDoc::FINISH ) )
848
emit infoMessage( i18n("Growing ISO9660 filesystem on %1.", Device::mediaTypeString(foundMedium, true)), MessageInfo );
850
emit infoMessage( i18n("Writing %1.", Device::mediaTypeString(foundMedium, true)), MessageInfo );
853
// -------------------------------
855
// -------------------------------
856
else if ( foundMedium & K3b::Device::MEDIA_DVD_MINUS_ALL ) {
857
if( d->doc->dummy() && !d->doc->burner()->dvdMinusTestwrite() ) {
858
if( !questionYesNo( i18n("Your writer (%1 %2) does not support simulation with DVD-R(W) media. "
859
"Do you really want to continue? The media will actually be "
861
d->doc->burner()->vendor(),
862
d->doc->burner()->description()),
863
i18n("No Simulation with DVD-R(W)") ) ) {
867
d->doc->setDummy( false );
870
// RESTRICTED OVERWRITE
871
// --------------------
872
if( foundMedium & K3b::Device::MEDIA_DVD_RW_OVWR ) {
873
d->usedWritingMode = K3b::WritingModeRestrictedOverwrite;
874
if( usedMultiSessionMode() == K3b::DataDoc::NONE ||
875
usedMultiSessionMode() == K3b::DataDoc::START ) {
876
// FIXME: can cdrecord handle this?
877
emit infoMessage( i18n("Writing DVD-RW in restricted overwrite mode."), MessageInfo );
880
emit infoMessage( i18n("Growing ISO9660 filesystem on DVD-RW in restricted overwrite mode."), MessageInfo );
881
// we can only do this with growisofs
882
d->usedWritingApp = K3b::WritingAppGrowisofs;
890
// FIXME: DVD-R DL jump and stuff
892
if( d->doc->writingMode() == K3b::WritingModeSao ) {
893
d->usedWritingMode = K3b::WritingModeSao;
894
emit infoMessage( i18n("Writing %1 in DAO mode.", K3b::Device::mediaTypeString(foundMedium, true) ), MessageInfo );
898
// check if the writer supports writing sequential and thus multisession (on -1 the burner cannot handle
899
// features and we simply ignore it and hope for the best)
900
if( d->doc->burner()->featureCurrent( K3b::Device::FEATURE_INCREMENTAL_STREAMING_WRITABLE ) == 0 ) {
901
if( !questionYesNo( i18n("Your writer (%1 %2) does not support Incremental Streaming with %3 "
902
"media. Multisession will not be possible. Continue anyway?",
903
d->doc->burner()->vendor(),
904
d->doc->burner()->description(),
905
K3b::Device::mediaTypeString(foundMedium, true) ),
906
i18n("No Incremental Streaming") ) ) {
910
d->usedWritingMode = K3b::WritingModeSao;
911
emit infoMessage( i18n("Writing %1 in DAO mode.", K3b::Device::mediaTypeString(foundMedium, true) ), MessageInfo );
915
d->usedWritingMode = K3b::WritingModeIncrementalSequential;
916
if( !(foundMedium & (K3b::Device::MEDIA_DVD_RW|K3b::Device::MEDIA_DVD_RW_OVWR|K3b::Device::MEDIA_DVD_RW_SEQ)) &&
917
d->doc->writingMode() == K3b::WritingModeRestrictedOverwrite )
918
emit infoMessage( i18n("Restricted Overwrite is not possible with DVD-R media."), MessageInfo );
920
emit infoMessage( i18n("Writing %1 in incremental mode.", K3b::Device::mediaTypeString(foundMedium, true) ), MessageInfo );
927
// --------------------
929
// --------------------
930
else if ( foundMedium & K3b::Device::MEDIA_BD_ALL ) {
931
d->usedWritingApp = writingApp();
932
if( d->usedWritingApp == K3b::WritingAppAuto ) {
933
d->usedWritingApp = K3b::WritingAppCdrecord;
936
if ( d->usedWritingApp == K3b::WritingAppCdrecord &&
937
!k3bcore->externalBinManager()->binObject("cdrecord")->hasFeature( "blu-ray" ) ) {
938
d->usedWritingApp = K3b::WritingAppGrowisofs;
941
if( d->doc->dummy() ) {
942
if( !questionYesNo( i18n("%1 media do not support write simulation. "
943
"Do you really want to continue? The disc will actually be "
944
"written to.", Device::mediaTypeString(foundMedium, true)),
945
i18n("No Simulation with %1", Device::mediaTypeString(foundMedium, true)) ) ) {
949
d->doc->setDummy( false );
952
if( d->doc->writingMode() != K3b::WritingModeAuto )
953
emit infoMessage( i18n("Writing mode ignored when writing %1 media.", Device::mediaTypeString(foundMedium, true)), MessageInfo );
954
d->usedWritingMode = K3b::WritingModeSao; // cdrecord uses -sao for DVD+R(W), let's assume it's used also for BD-R(E)
956
// Cdrecord probably doesn't support multisession BD-R disks
957
// FIXME: check if above is actually true
958
if( usedMultiSessionMode() != DataDoc::NONE &&
959
d->usedWritingApp == K3b::WritingAppCdrecord ) {
960
d->usedWritingApp = WritingAppGrowisofs;
963
if( foundMedium & K3b::Device::MEDIA_BD_RE &&
964
( usedMultiSessionMode() == K3b::DataDoc::CONTINUE ||
965
usedMultiSessionMode() == K3b::DataDoc::FINISH ) )
966
emit infoMessage( i18n("Growing ISO9660 filesystem on %1.", Device::mediaTypeString(foundMedium, true)), MessageInfo );
968
emit infoMessage( i18n("Writing %1.", Device::mediaTypeString(foundMedium, true)), MessageInfo );
975
QString K3b::DataJob::jobDescription() const
977
if( d->doc->onlyCreateImages() ) {
978
return i18n("Creating Data Image File");
980
else if( d->doc->multiSessionMode() == K3b::DataDoc::NONE ||
981
d->doc->multiSessionMode() == K3b::DataDoc::AUTO ) {
982
return i18n("Writing Data Project")
983
+ ( d->doc->isoOptions().volumeID().isEmpty()
985
: QString( " (%1)" ).arg(d->doc->isoOptions().volumeID()) );
988
return i18n("Writing Multisession Project")
989
+ ( d->doc->isoOptions().volumeID().isEmpty()
991
: QString( " (%1)" ).arg(d->doc->isoOptions().volumeID()) );
996
QString K3b::DataJob::jobDetails() const
998
if( d->doc->copies() > 1 &&
1000
!(d->doc->multiSessionMode() == K3b::DataDoc::CONTINUE ||
1001
d->doc->multiSessionMode() == K3b::DataDoc::FINISH) )
1002
return i18np("ISO9660 Filesystem (Size: %2) - %1 copy",
1003
"ISO9660 Filesystem (Size: %2) - %1 copies",
1005
KIO::convertSize( d->doc->size() ) );
1007
return i18n( "ISO9660 Filesystem (Size: %1)",
1008
KIO::convertSize( d->doc->size() ) );
1012
K3b::DataDoc::MultiSessionMode K3b::DataJob::usedMultiSessionMode() const
1014
return d->multiSessionParameterJob->usedMultiSessionMode();
1018
void K3b::DataJob::cleanup()
1021
if( !d->doc->onTheFly() && ( d->doc->removeImages() || d->canceled ) ) {
1022
if( QFile::exists( d->doc->tempDir() ) ) {
1023
d->imageFile.remove();
1024
emit infoMessage( i18n("Removed image file %1",d->doc->tempDir()), K3b::Job::MessageSuccess );
1035
bool K3b::DataJob::hasBeenCanceled() const
1041
bool K3b::DataJob::setupCdrecordJob()
1044
K3b::CdrecordWriter* writer = new K3b::CdrecordWriter( d->doc->burner(), this, this );
1046
// cdrecord manpage says that "not all" writers are able to write
1047
// multisession disks in dao mode. That means there are writers that can.
1049
// Does it really make sence to write Data ms cds in DAO mode since writing the
1050
// first session of a cd-extra in DAO mode is no problem with my writer while
1051
// writing the second data session is only possible in TAO mode.
1052
if( d->usedWritingMode == K3b::WritingModeSao &&
1053
usedMultiSessionMode() != K3b::DataDoc::NONE )
1054
emit infoMessage( i18n("Most writers do not support writing "
1055
"multisession CDs in DAO mode."), MessageInfo );
1057
writer->setWritingMode( d->usedWritingMode );
1058
writer->setSimulate( d->doc->dummy() );
1059
writer->setBurnSpeed( d->doc->speed() );
1062
writer->setMulti( usedMultiSessionMode() == K3b::DataDoc::START ||
1063
usedMultiSessionMode() == K3b::DataDoc::CONTINUE );
1065
if( d->doc->onTheFly() &&
1066
( usedMultiSessionMode() == K3b::DataDoc::CONTINUE ||
1067
usedMultiSessionMode() == K3b::DataDoc::FINISH ) )
1068
writer->addArgument("-waiti");
1070
if( d->usedDataMode == K3b::DataMode1 )
1071
writer->addArgument( "-data" );
1073
if( k3bcore->externalBinManager()->binObject("cdrecord") &&
1074
k3bcore->externalBinManager()->binObject("cdrecord")->hasFeature( "xamix" ) )
1075
writer->addArgument( "-xa" );
1077
writer->addArgument( "-xa1" );
1080
writer->addArgument( QString("-tsize=%1s").arg(m_isoImager->size()) )->addArgument("-");
1082
setWriterJob( writer );
1088
bool K3b::DataJob::setupCdrdaoJob()
1090
// create cdrdao job
1091
K3b::CdrdaoWriter* writer = new K3b::CdrdaoWriter( d->doc->burner(), this, this );
1092
writer->setCommand( K3b::CdrdaoWriter::WRITE );
1093
writer->setSimulate( d->doc->dummy() );
1094
writer->setBurnSpeed( d->doc->speed() );
1096
writer->setMulti( usedMultiSessionMode() == K3b::DataDoc::START ||
1097
usedMultiSessionMode() == K3b::DataDoc::CONTINUE );
1099
// now write the tocfile
1100
if( d->tocFile ) delete d->tocFile;
1101
d->tocFile = new KTemporaryFile();
1102
d->tocFile->setSuffix( ".toc" );
1105
QTextStream s( d->tocFile );
1106
if( d->usedDataMode == K3b::DataMode1 ) {
1107
s << "CD_ROM" << "\n";
1109
s << "TRACK MODE1" << "\n";
1112
s << "CD_ROM_XA" << "\n";
1114
s << "TRACK MODE2_FORM1" << "\n";
1117
s << "DATAFILE \"-\" " << m_isoImager->size()*2048 << "\n";
1119
d->tocFile->close();
1121
writer->setTocFile( d->tocFile->fileName() );
1123
setWriterJob( writer );
1129
bool K3b::DataJob::setupGrowisofsJob()
1131
K3b::GrowisofsWriter* writer = new K3b::GrowisofsWriter( d->doc->burner(), this, this );
1133
// these do only make sense with DVD-R(W)
1134
writer->setSimulate( d->doc->dummy() );
1135
writer->setBurnSpeed( d->doc->speed() );
1137
// Andy said incremental sequential is the default mode and it seems uses have more problems with DAO anyway
1138
// BUT: I also had a report that incremental sequential produced unreadable media!
1139
if( d->doc->writingMode() == K3b::WritingModeSao )
1140
// || ( d->doc->writingMode() == K3b::WritingModeAuto &&
1141
// usedMultiSessionMode() == K3b::DataDoc::NONE ) )
1142
writer->setWritingMode( K3b::WritingModeSao );
1144
writer->setMultiSession( usedMultiSessionMode() == K3b::DataDoc::CONTINUE ||
1145
usedMultiSessionMode() == K3b::DataDoc::FINISH );
1147
writer->setCloseDvd( usedMultiSessionMode() == K3b::DataDoc::NONE ||
1148
usedMultiSessionMode() == K3b::DataDoc::FINISH );
1150
writer->setImageToWrite( QString() ); // read from stdin
1151
writer->setTrackSize( m_isoImager->size() );
1153
if( usedMultiSessionMode() != K3b::DataDoc::NONE ) {
1155
// growisofs wants a valid -C parameter for multisession, so we get it from the
1156
// K3b::MsInfoFetcher (see K3b::DataJob::prepareWriting)
1158
writer->setMultiSessionInfo( m_isoImager->multiSessionInfo() );
1161
setWriterJob( writer );
1166
#include "k3bdatajob.moc"