From aa70baed334295dc92305d5aa155db3f3f552a97 Mon Sep 17 00:00:00 2001 From: Dmitry Degtyarev Date: Thu, 22 Apr 2021 16:49:58 +0400 Subject: [PATCH] fix delayed write authenticate when delayed write is checked cancel helper when delayed write is unchecked uncheck delayed write when dialog is closed --- app/dialogs/DownloadDialog.qml | 6 ++++ app/drivemanager.cpp | 4 ++- app/linuxdrivemanager.cpp | 5 ++++ app/variant.cpp | 17 ++++++----- app/windrivemanager.cpp | 4 +++ helper/linux/writejob.cpp | 45 +++++++++++++++++++++++++--- helper/linux/writejob.h | 4 +++ helper/win/writejob.cpp | 55 ++++++++++++++++++++++++++++++---- helper/win/writejob.h | 3 ++ 9 files changed, 124 insertions(+), 19 deletions(-) diff --git a/app/dialogs/DownloadDialog.qml b/app/dialogs/DownloadDialog.qml index 36d734a..ebe262f 100644 --- a/app/dialogs/DownloadDialog.qml +++ b/app/dialogs/DownloadDialog.qml @@ -345,7 +345,12 @@ Dialog { value: 0.0 } } + // TODO: need to uncheck when drive + // changes because delayedwrite + // starts a helper that is setup for + // one specific drive AdwaitaCheckBox { + id: delayedWriteCheck text: qsTr("Write the image after downloading") enabled: drives.selected && ((releases.selected.variant.status == Variant.DOWNLOADING) || (releases.selected.variant.status == Variant.DOWNLOAD_RESUMING)) && releases.selected.variant.canWrite visible: enabled @@ -454,6 +459,7 @@ Dialog { text: qsTr("Cancel") enabled: true onClicked: { + delayedWriteCheck.checked = false dialog.close() } } diff --git a/app/drivemanager.cpp b/app/drivemanager.cpp index d44acc2..dfae751 100644 --- a/app/drivemanager.cpp +++ b/app/drivemanager.cpp @@ -294,8 +294,10 @@ bool Drive::write(Variant *variant) { m_variant->setErrorString(QString()); const QFile file(m_variant->filePath()); - m_progress->setMax(file.size()); + // TODO: this won't work for delayed write. When delayed + // write is turned on, this write() f-n is called and + // file size is not known yet. if (file.size() > size()) { m_variant->setErrorString(tr("This drive is not large enough.")); cancel(); diff --git a/app/linuxdrivemanager.cpp b/app/linuxdrivemanager.cpp index a19c241..eaec7be 100644 --- a/app/linuxdrivemanager.cpp +++ b/app/linuxdrivemanager.cpp @@ -278,7 +278,12 @@ void LinuxDrive::onReadyRead() { while (m_process->bytesAvailable() > 0) { QString line = m_process->readLine().trimmed(); + qDebug() << "helper:" << line; if (line == "WRITE") { + // Set progress bar max value at start of writing + const QFile file(m_variant->filePath()); + m_progress->setMax(file.size()); + m_progress->setCurrent(0); } else if (line == "DONE") { diff --git a/app/variant.cpp b/app/variant.cpp index 3419ef7..23686b2 100644 --- a/app/variant.cpp +++ b/app/variant.cpp @@ -103,6 +103,15 @@ Progress *Variant::progress() { void Variant::setDelayedWrite(const bool value) { delayedWrite = value; + + Drive *drive = DriveManager::instance()->selected(); + if (drive != nullptr) { + if (value) { + drive->write(this); + } else { + drive->cancel(); + } + } } Variant::Status Variant::status() const { @@ -128,14 +137,6 @@ void Variant::onImageDownloadFinished() { qDebug() << this->metaObject()->className() << "Image is ready"; setStatus(READY_FOR_WRITING); - if (delayedWrite) { - Drive *drive = DriveManager::instance()->selected(); - - if (drive != nullptr) { - drive->write(this); - } - } - break; } case ImageDownload::DiskError: { diff --git a/app/windrivemanager.cpp b/app/windrivemanager.cpp index 5972441..cea6ce2 100644 --- a/app/windrivemanager.cpp +++ b/app/windrivemanager.cpp @@ -378,6 +378,10 @@ void WinDrive::onReadyRead() { QString line = m_child->readLine().trimmed(); if (line == "WRITE") { m_progress->setCurrent(0); + + // Set progress bar max value at start of writing + const QFile file(m_variant->filePath()); + m_progress->setMax(file.size()); } else if (line == "DONE") { m_variant->setStatus(Variant::WRITING_FINISHED); diff --git a/helper/linux/writejob.cpp b/helper/linux/writejob.cpp index d2fb5e8..300826f 100644 --- a/helper/linux/writejob.cpp +++ b/helper/linux/writejob.cpp @@ -54,6 +54,9 @@ WriteJob::WriteJob(const QString &what, const QString &where) qDBusRegisterMetaType(); qDBusRegisterMetaType(); qDBusRegisterMetaType(); + connect( + &watcher, &QFileSystemWatcher::fileChanged, + this, &WriteJob::onFileChanged); QTimer::singleShot(0, this, SLOT(work())); } @@ -251,12 +254,46 @@ void WriteJob::work() { if (fd.fileDescriptor() < 0) return; - if (!write(fd.fileDescriptor())) + const bool delayed_write = + [&]() { + const QString part_path = what + ".part"; + + return (QFile::exists(part_path) && !QFile::exists(what)); + }(); + + if (delayed_write) { + watcher.addPath(what + ".part"); + + return; + } + + // NOTE: let the app know that writing started + out << "WRITE\n"; + out.flush(); + + const bool write_success = write(fd.fileDescriptor()); + + if (write_success) { + out.flush(); + err << "DONE\n"; + qApp->exit(0); + } else { + qApp->exit(4); + } +} + +void WriteJob::onFileChanged(const QString &path) { + const bool still_downloading = QFile::exists(path); + if (still_downloading) return; - err << "DONE\n"; - out.flush(); - qApp->exit(0); + const bool downloaded_file_exists = QFile::exists(what); + if (!downloaded_file_exists) { + qApp->exit(4); + return; + } + + work(); } std::tuple, char*, std::size_t> pageAlignedBuffer(std::size_t pages) { diff --git a/helper/linux/writejob.h b/helper/linux/writejob.h index 636e3b5..f443395 100644 --- a/helper/linux/writejob.h +++ b/helper/linux/writejob.h @@ -28,6 +28,7 @@ #include #include #include +#include #include @@ -52,12 +53,15 @@ public: bool writePlain(int fd); public slots: void work(); +private slots: + void onFileChanged(const QString &path); private: QString what; QString where; QTextStream out { stdout }; QTextStream err { stderr }; QDBusUnixFileDescriptor fd { -1 }; + QFileSystemWatcher watcher; }; std::tuple, char*, std::size_t> pageAlignedBuffer(std::size_t pages = 1024); diff --git a/helper/win/writejob.cpp b/helper/win/writejob.cpp index f07d89f..0f5e913 100644 --- a/helper/win/writejob.cpp +++ b/helper/win/writejob.cpp @@ -41,6 +41,10 @@ WriteJob::WriteJob(const QString &what, const QString &where) bool ok = false; this->where = where.toInt(&ok); + connect( + &watcher, &QFileSystemWatcher::fileChanged, + this, &WriteJob::onFileChanged); + QTimer::singleShot(0, this, &WriteJob::work); } @@ -194,17 +198,42 @@ void WriteJob::unlockDrive(HANDLE drive) { } void WriteJob::work() { - if (!write()) { + const bool delayed_write = + [&]() { + const QString part_path = what + ".part"; + + return (QFile::exists(part_path) && !QFile::exists(what)); + }(); + + if (delayed_write) { + watcher.addPath(what + ".part"); + + return; + } + + // NOTE: let the app know that writing started + out << "WRITE\n"; + out.flush(); + + bool write_success = write(); + + // NOTE: try to write 2 times and sleep between + // attempts. Apparently needed on windows. + if (!write_success) { out << "0\n"; out.flush(); QThread::sleep(5); - if (!write()) - return; + + write_success = write(); } - err << "DONE\n"; - out.flush(); - qApp->exit(0); + if (write_success) { + out.flush(); + err << "DONE\n"; + qApp->exit(0); + } else { + qApp->exit(4); + } } bool WriteJob::write() { @@ -361,3 +390,17 @@ bool WriteJob::writePlain(HANDLE drive) { return true; } + +void WriteJob::onFileChanged(const QString &path) { + const bool still_downloading = QFile::exists(path); + if (still_downloading) + return; + + const bool downloaded_file_exists = QFile::exists(what); + if (!downloaded_file_exists) { + qApp->exit(4); + return; + } + + work(); +} diff --git a/helper/win/writejob.h b/helper/win/writejob.h index d2d9baf..254f25a 100644 --- a/helper/win/writejob.h +++ b/helper/win/writejob.h @@ -25,6 +25,7 @@ #include #include +#include #include @@ -57,12 +58,14 @@ private slots: bool write(); bool writeCompressed(HANDLE drive); bool writePlain(HANDLE drive); + void onFileChanged(const QString &path); private: QString what; uint where; QTextStream out { stdout }; QTextStream err { stderr }; + QFileSystemWatcher watcher; const int BLOCK_SIZE { 512 * 128 }; };