File indexing completed on 2025-03-16 04:29:31
0001 /* 0002 SPDX-FileCopyrightText: 2011 Michal Malek <michalm@jabster.pl> 0003 SPDX-FileCopyrightText: 1998-2010 Sebastian Trueg <trueg@k3b.org> 0004 0005 SPDX-License-Identifier: GPL-2.0-or-later 0006 */ 0007 0008 0009 #include "k3biso9660imagewritingjob.h" 0010 #include "k3bverificationjob.h" 0011 #include "k3bmetawriter.h" 0012 0013 #include "k3bdevice.h" 0014 #include "k3bdiskinfo.h" 0015 #include "k3bdevicehandler.h" 0016 #include "k3bglobals.h" 0017 #include "k3bcore.h" 0018 #include "k3bversion.h" 0019 #include "k3bexternalbinmanager.h" 0020 #include "k3bchecksumpipe.h" 0021 #include "k3bfilesplitter.h" 0022 #include "k3bglobalsettings.h" 0023 #include "k3b_i18n.h" 0024 0025 #include <KIO/Global> 0026 0027 #include <QDebug> 0028 #include <QString> 0029 #include <QFile> 0030 0031 0032 class K3b::Iso9660ImageWritingJob::Private 0033 { 0034 public: 0035 K3b::ChecksumPipe checksumPipe; 0036 K3b::FileSplitter imageFile; 0037 0038 bool isDvdImage; 0039 int currentCopy; 0040 bool canceled; 0041 bool finished; 0042 0043 VerificationJob* verifyJob; 0044 MetaWriter* writer; 0045 }; 0046 0047 0048 K3b::Iso9660ImageWritingJob::Iso9660ImageWritingJob( K3b::JobHandler* hdl ) 0049 : K3b::BurnJob( hdl ), 0050 m_writingMode(K3b::WritingModeAuto), 0051 m_simulate(false), 0052 m_device(0), 0053 m_noFix(false), 0054 m_speed(2), 0055 m_dataMode(K3b::DataModeAuto), 0056 m_copies(1) 0057 { 0058 d = new Private; 0059 d->verifyJob = 0; 0060 d->writer = 0; 0061 } 0062 0063 0064 K3b::Iso9660ImageWritingJob::~Iso9660ImageWritingJob() 0065 { 0066 delete d->writer; 0067 delete d; 0068 } 0069 0070 0071 void K3b::Iso9660ImageWritingJob::start() 0072 { 0073 d->canceled = d->finished = false; 0074 d->currentCopy = 1; 0075 0076 jobStarted(); 0077 0078 if( m_simulate ) 0079 m_verifyData = false; 0080 0081 emit newTask( i18n("Preparing data") ); 0082 0083 if( !QFile::exists( m_imagePath ) ) { 0084 emit infoMessage( i18n("Could not find image %1", m_imagePath), K3b::Job::MessageError ); 0085 jobFinished( false ); 0086 return; 0087 } 0088 0089 KIO::filesize_t mb = K3b::imageFilesize( QUrl::fromLocalFile(m_imagePath) )/1024ULL/1024ULL; 0090 0091 // very rough test but since most dvd images are 4,x or 8,x GB it should be enough 0092 d->isDvdImage = ( mb > 900ULL ); 0093 0094 startWriting(); 0095 } 0096 0097 0098 void K3b::Iso9660ImageWritingJob::slotWriterJobFinished( bool success ) 0099 { 0100 if( d->canceled ) { 0101 d->finished = true; 0102 emit canceled(); 0103 jobFinished(false); 0104 return; 0105 } 0106 0107 d->checksumPipe.close(); 0108 0109 if( success ) { 0110 if( !m_simulate && m_verifyData ) { 0111 emit burning(false); 0112 0113 // alright 0114 // the writerJob should have emitted the "simulation/writing successful" signal 0115 0116 if( !d->verifyJob ) { 0117 d->verifyJob = new K3b::VerificationJob( this ); 0118 connectSubJob( d->verifyJob, 0119 SLOT(slotVerificationFinished(bool)), 0120 K3b::Job::DEFAULT_SIGNAL_CONNECTION, 0121 K3b::Job::DEFAULT_SIGNAL_CONNECTION, 0122 SLOT(slotVerificationProgress(int)), 0123 SIGNAL(subPercent(int)) ); 0124 } 0125 d->verifyJob->setDevice( m_device ); 0126 d->verifyJob->clear(); 0127 d->verifyJob->addTrack( 1, d->checksumPipe.checksum(), K3b::imageFilesize( QUrl::fromLocalFile(m_imagePath) )/2048 ); 0128 0129 if( m_copies == 1 ) 0130 emit newTask( i18n("Verifying written data") ); 0131 else 0132 emit newTask( i18n("Verifying written copy %1 of %2", d->currentCopy, m_copies) ); 0133 0134 d->verifyJob->start(); 0135 } 0136 else if( d->currentCopy >= m_copies ) { 0137 if ( k3bcore->globalSettings()->ejectMedia() ) { 0138 K3b::Device::eject( m_device ); 0139 } 0140 d->finished = true; 0141 jobFinished(true); 0142 } 0143 else { 0144 d->currentCopy++; 0145 if( !K3b::eject( m_device ) ) { 0146 blockingInformation( i18n("K3b was unable to eject the written medium. Please do so manually.") ); 0147 } 0148 startWriting(); 0149 } 0150 } 0151 else { 0152 if ( k3bcore->globalSettings()->ejectMedia() ) { 0153 K3b::Device::eject( m_device ); 0154 } 0155 d->finished = true; 0156 jobFinished(false); 0157 } 0158 } 0159 0160 0161 void K3b::Iso9660ImageWritingJob::slotVerificationFinished( bool success ) 0162 { 0163 if( d->canceled ) { 0164 d->finished = true; 0165 emit canceled(); 0166 jobFinished(false); 0167 return; 0168 } 0169 0170 if( success && d->currentCopy < m_copies ) { 0171 d->currentCopy++; 0172 connect( K3b::Device::eject( m_device ), SIGNAL(finished(bool)), 0173 this, SLOT(startWriting()) ); 0174 return; 0175 } 0176 0177 if( k3bcore->globalSettings()->ejectMedia() ) 0178 K3b::Device::eject( m_device ); 0179 0180 d->finished = true; 0181 jobFinished( success ); 0182 } 0183 0184 0185 void K3b::Iso9660ImageWritingJob::slotVerificationProgress( int p ) 0186 { 0187 emit percent( (int)(100.0 / (double)m_copies * ( (double)(d->currentCopy-1) + 0.5 + (double)p/200.0 )) ); 0188 } 0189 0190 0191 void K3b::Iso9660ImageWritingJob::slotWriterPercent( int p ) 0192 { 0193 emit subPercent( p ); 0194 0195 if( m_verifyData ) 0196 emit percent( (int)(100.0 / (double)m_copies * ( (double)(d->currentCopy-1) + ((double)p/200.0) )) ); 0197 else 0198 emit percent( (int)(100.0 / (double)m_copies * ( (double)(d->currentCopy-1) + ((double)p/100.0) )) ); 0199 } 0200 0201 0202 void K3b::Iso9660ImageWritingJob::slotNextTrack( int, int ) 0203 { 0204 if( m_copies == 1 ) 0205 emit newSubTask( i18n("Writing image") ); 0206 else 0207 emit newSubTask( i18n("Writing copy %1 of %2", d->currentCopy, m_copies) ); 0208 } 0209 0210 0211 void K3b::Iso9660ImageWritingJob::cancel() 0212 { 0213 if( !d->finished ) { 0214 d->canceled = true; 0215 0216 if( d->writer ) 0217 d->writer->cancel(); 0218 if( m_verifyData && d->verifyJob ) 0219 d->verifyJob->cancel(); 0220 } 0221 } 0222 0223 0224 void K3b::Iso9660ImageWritingJob::startWriting() 0225 { 0226 emit newSubTask( i18n("Waiting for medium") ); 0227 0228 // we wait for the following: 0229 // 1. If special CD features are requested: CD types only Special are: 0230 // K3b::WritingAppCdrdao with K3b::WritingModeAuto or K3b::WritingModeSao, 0231 // any WritingApp with K3b::WritingModeTao, 0232 // any WritingApp with K3b::WritingModeRaw 0233 // 2. If formatted DVD-RW is requested: formatted DVD-RW only Request is: 0234 // K3b::WritingModeRestrictedOverwrite 0235 // 3. If image is larger than 900 MiB (d->isDvdImage == true): DVD or BD 0236 // types See K3b::Iso9660ImageWritingJob::start() 0237 // 4. If image not larger than 900 MiB: All media types 0238 // 5. If not decided yet: DVD and BD media types. 0239 0240 Device::MediaTypes mt = Device::MediaTypes(); 0241 if (m_writingMode == K3b::WritingModeAuto || 0242 m_writingMode == K3b::WritingModeSao) { 0243 if (writingApp() == K3b::WritingAppCdrdao) 0244 mt = K3b::Device::MEDIA_WRITABLE_CD; 0245 else if (d->isDvdImage) 0246 mt = K3b::Device::MEDIA_WRITABLE_DVD | K3b::Device::MEDIA_WRITABLE_BD; 0247 else 0248 mt = K3b::Device::MEDIA_WRITABLE; 0249 } else if (m_writingMode == K3b::WritingModeTao || 0250 m_writingMode == K3b::WritingModeRaw) { 0251 mt = K3b::Device::MEDIA_WRITABLE_CD; 0252 } else if (m_writingMode == K3b::WritingModeRestrictedOverwrite) { 0253 mt = /*K3b::Device::MEDIA_DVD_PLUS_R | K3b::Device::MEDIA_DVD_PLUS_R_DL |*/ 0254 K3b::Device::MEDIA_DVD_PLUS_RW | K3b::Device::MEDIA_DVD_RW_OVWR; 0255 } else { 0256 mt = K3b::Device::MEDIA_WRITABLE_DVD | K3b::Device::MEDIA_WRITABLE_BD; 0257 } 0258 0259 // wait for the media 0260 Device::MediaType media = waitForMedium( m_device, K3b::Device::STATE_EMPTY, mt, K3b::imageFilesize( QUrl::fromLocalFile(m_imagePath) )/2048 ); 0261 if( media == Device::MEDIA_UNKNOWN ) { 0262 d->finished = true; 0263 emit canceled(); 0264 jobFinished(false); 0265 return; 0266 } 0267 0268 // we simply always calculate the checksum, thus making the code simpler 0269 d->imageFile.close(); 0270 d->imageFile.setName( m_imagePath ); 0271 d->imageFile.open( QIODevice::ReadOnly ); 0272 d->checksumPipe.close(); 0273 d->checksumPipe.readFrom( &d->imageFile, true ); 0274 0275 if( prepareWriter() ) { 0276 emit burning(true); 0277 d->writer->start(); 0278 #ifdef __GNUC__ 0279 #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? 0280 #endif 0281 d->checksumPipe.writeTo( d->writer->ioDevice(), d->writer->usedWritingApp() == K3b::WritingAppGrowisofs ); 0282 d->checksumPipe.open( K3b::ChecksumPipe::MD5, true ); 0283 } 0284 else { 0285 d->finished = true; 0286 jobFinished(false); 0287 } 0288 } 0289 0290 0291 bool K3b::Iso9660ImageWritingJob::prepareWriter() 0292 { 0293 delete d->writer; 0294 0295 d->writer = new MetaWriter( m_device, this ); 0296 0297 d->writer->setWritingMode( m_writingMode ); 0298 qDebug() << "DEBUG:" << __PRETTY_FUNCTION__ << writingApp(); 0299 d->writer->setWritingApp( writingApp() ); 0300 d->writer->setSimulate( m_simulate ); 0301 d->writer->setBurnSpeed( m_speed ); 0302 d->writer->setMultiSession( m_noFix ); 0303 0304 Device::Toc toc; 0305 toc << Device::Track( 0, Msf(K3b::imageFilesize( QUrl::fromLocalFile(m_imagePath) )/2048)-1, 0306 Device::Track::TYPE_DATA, 0307 ( m_dataMode == K3b::DataModeAuto && m_noFix ) || 0308 m_dataMode == K3b::DataMode2 0309 ? Device::Track::XA_FORM2 0310 : Device::Track::MODE1 ); 0311 d->writer->setSessionToWrite( toc ); 0312 0313 connect( d->writer, SIGNAL(infoMessage(QString,int)), this, SIGNAL(infoMessage(QString,int)) ); 0314 connect( d->writer, SIGNAL(nextTrack(int,int)), this, SLOT(slotNextTrack(int,int)) ); 0315 connect( d->writer, SIGNAL(percent(int)), this, SLOT(slotWriterPercent(int)) ); 0316 connect( d->writer, SIGNAL(processedSize(int,int)), this, SIGNAL(processedSize(int,int)) ); 0317 connect( d->writer, SIGNAL(buffer(int)), this, SIGNAL(bufferStatus(int)) ); 0318 connect( d->writer, SIGNAL(deviceBuffer(int)), this, SIGNAL(deviceBuffer(int)) ); 0319 connect( d->writer, SIGNAL(writeSpeed(int,K3b::Device::SpeedMultiplicator)), this, SIGNAL(writeSpeed(int,K3b::Device::SpeedMultiplicator)) ); 0320 connect( d->writer, SIGNAL(finished(bool)), this, SLOT(slotWriterJobFinished(bool)) ); 0321 connect( d->writer, SIGNAL(newTask(QString)), this, SIGNAL(newTask(QString)) ); 0322 connect( d->writer, SIGNAL(newSubTask(QString)), this, SIGNAL(newSubTask(QString)) ); 0323 connect( d->writer, SIGNAL(debuggingOutput(QString,QString)), 0324 this, SIGNAL(debuggingOutput(QString,QString)) ); 0325 0326 return true; 0327 } 0328 0329 0330 QString K3b::Iso9660ImageWritingJob::jobDescription() const 0331 { 0332 if( m_simulate ) 0333 return i18n("Simulating ISO 9660 Image"); 0334 else 0335 return ( i18n("Burning ISO 9660 Image") 0336 + ( m_copies > 1 0337 ? i18np(" - %1 Copy", " - %1 Copies", m_copies) 0338 : QString() ) ); 0339 } 0340 0341 0342 QString K3b::Iso9660ImageWritingJob::jobDetails() const 0343 { 0344 return m_imagePath.section('/', -1) + QString( " (%1)" ).arg(KIO::convertSize(K3b::filesize(QUrl::fromLocalFile(m_imagePath)))); 0345 } 0346 0347 0348 QString K3b::Iso9660ImageWritingJob::jobSource() const 0349 { 0350 return m_imagePath; 0351 } 0352 0353 0354 QString K3b::Iso9660ImageWritingJob::jobTarget() const 0355 { 0356 if( m_device ) 0357 return m_device->vendor() + ' ' + m_device->description(); 0358 else 0359 return QString (); 0360 } 0361 0362 #include "moc_k3biso9660imagewritingjob.cpp"