diff --git a/include/dfm-burn/dfm-burn/dopticaldiscmanager.h b/include/dfm-burn/dfm-burn/dopticaldiscmanager.h index d14e1517..b3e9c5ba 100644 --- a/include/dfm-burn/dfm-burn/dopticaldiscmanager.h +++ b/include/dfm-burn/dfm-burn/dopticaldiscmanager.h @@ -38,6 +38,9 @@ class DOpticalDiscManager : public QObject Q_SIGNALS: void jobStatusChanged(JobStatus status, int progress, QString speed, QStringList message); +private: + bool eraseWithGrowisofs(); + private: QScopedPointer dptr; }; diff --git a/src/dfm-burn/dfm-burn-lib/dopticaldiscmanager.cpp b/src/dfm-burn/dfm-burn-lib/dopticaldiscmanager.cpp index b350a715..f566b772 100644 --- a/src/dfm-burn/dfm-burn-lib/dopticaldiscmanager.cpp +++ b/src/dfm-burn/dfm-burn-lib/dopticaldiscmanager.cpp @@ -12,6 +12,8 @@ #include #include #include +#include +#include DFM_BURN_USE_NS @@ -104,23 +106,83 @@ bool DOpticalDiscManager::commit(const BurnOptions &opts, int speed, const QStri bool DOpticalDiscManager::erase() { bool ret { false }; - QScopedPointer engine { new DXorrisoEngine }; - connect(engine.data(), &DXorrisoEngine::jobStatusChanged, this, - [this, ptr = QPointer(engine.data())](JobStatus status, int progress, QString speed) { - if (ptr) - Q_EMIT jobStatusChanged(status, progress, speed, ptr->takeInfoMessages()); - }, - Qt::DirectConnection); - if (!engine->acquireDevice(dptr->curDev)) - qWarning() << "[dfm-burn] Cannot acquire device"; + // Determine media type to dispatch the appropriate erasure tool. + // DVD-RW requires growisofs for a complete erase; xorriso's "as_needed" + // mode leaves residual filesystem structures on certain drive+media combos. + MediaType mediaType { MediaType::kNoMedia }; + { + QScopedPointer info { DOpticalDiscManager::createOpticalInfo(dptr->curDev) }; + if (info) + mediaType = info->mediaType(); + } + + if (mediaType == MediaType::kDVD_RW) { + ret = eraseWithGrowisofs(); + } else { + QScopedPointer engine { new DXorrisoEngine }; + connect(engine.data(), &DXorrisoEngine::jobStatusChanged, this, + [this, ptr = QPointer(engine.data())](JobStatus status, int progress, QString speed) { + if (ptr) + Q_EMIT jobStatusChanged(status, progress, speed, ptr->takeInfoMessages()); + }, + Qt::DirectConnection); - ret = engine->doErase(); + if (!engine->acquireDevice(dptr->curDev)) + qWarning() << "[dfm-burn] Cannot acquire device"; + + ret = engine->doErase(); + + engine->releaseDevice(); + } - engine->releaseDevice(); return ret; } +bool DOpticalDiscManager::eraseWithGrowisofs() +{ + Q_EMIT jobStatusChanged(JobStatus::kRunning, 0, {}, {}); + + QProcess growisofs; + growisofs.setProcessChannelMode(QProcess::MergedChannels); + + // growisofs -Z =/dev/zero overwrites the entire disc with zeros, + // performing a complete erase that reliably clears DVD-RW media. + growisofs.start("growisofs", { "-Z", dptr->curDev + "=/dev/zero" }); + + if (!growisofs.waitForStarted()) { + dptr->errorMsg = "[dfm-burn] Failed to start growisofs for DVD-RW erase"; + Q_EMIT jobStatusChanged(JobStatus::kFailed, -1, {}, { dptr->errorMsg }); + return false; + } + + // Parse progress output (e.g. " 10.0% done (223670/2236704 KiB)"). + QRegularExpression re(R"((\d+\.\d+)%\s*done)"); + while (growisofs.state() != QProcess::NotRunning) { + if (!growisofs.waitForReadyRead(30000)) + break; + QByteArray output = growisofs.readAllStandardOutput(); + auto match = re.match(QString::fromLocal8Bit(output)); + if (match.hasMatch()) { + int percentage = static_cast(match.captured(1).toDouble()); + Q_EMIT jobStatusChanged(JobStatus::kRunning, percentage, {}, {}); + } + } + + growisofs.waitForFinished(-1); + + if (growisofs.exitCode() != 0) { + QString errMsg = QString("[dfm-burn] growisofs DVD-RW erase failed: %1") + .arg(QString::fromLocal8Bit(growisofs.readAllStandardOutput()).trimmed()); + dptr->errorMsg = errMsg; + Q_EMIT jobStatusChanged(JobStatus::kFailed, -1, {}, { errMsg }); + return false; + } + + Q_EMIT jobStatusChanged(JobStatus::kFinished, 0, {}, {}); + return true; +} + bool DOpticalDiscManager::checkmedia(double *qgood, double *qslow, double *qbad) { bool ret { false }; diff --git a/src/dfm-burn/dfm-burn-lib/private/dxorrisoengine.cpp b/src/dfm-burn/dfm-burn-lib/private/dxorrisoengine.cpp index 8ac7ea92..cd40258c 100644 --- a/src/dfm-burn/dfm-burn-lib/private/dxorrisoengine.cpp +++ b/src/dfm-burn/dfm-burn-lib/private/dxorrisoengine.cpp @@ -296,6 +296,12 @@ bool DXorrisoEngine::doErase() r = XORRISO_OPT(xorriso, [this]() { return Xorriso_option_blank(xorriso, PCHAR("full"), 1); }); + } else if (mediaTypeProperty() == MediaType::kDVD_RW) { + // DVD-RW should be erased via growisofs (see DOpticalDiscManager::erase). + // xorriso's "as_needed" mode does not reliably blank DVD-RW media. + qWarning() << "[dfm-burn] DVD-RW should be erased with growisofs, not xorriso"; + Q_EMIT jobStatusChanged(JobStatus::kFailed, -1, ""); + return false; } else { r = XORRISO_OPT(xorriso, [this]() { return Xorriso_option_blank(xorriso, PCHAR("as_needed"), 0);