forked from FedoraQt/MediaWriter
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Linux: overwrite start and end of the drive with zeroes when restoring
Similar to Windows, overwrite the beginning of the drive and the end of the drive with zeroes before creating a new partition table. This is to make sure there are no partition table residues after a Fedora image was written onto the drive. Resolves FedoraQt#575
- Loading branch information
Showing
7 changed files
with
228 additions
and
107 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,6 +8,7 @@ include_directories( | |
|
||
set(HELPER_SRCS | ||
main.cpp | ||
job.cpp | ||
restorejob.cpp | ||
writejob.cpp | ||
) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
/* | ||
* Fedora Media Writer | ||
* Copyright (C) 2024 Jan Grulich <[email protected]> | ||
* Copyright (C) 2016 Martin Bříza <[email protected]> | ||
* | ||
* This program is free software; you can redistribute it and/or | ||
* modify it under the terms of the GNU General Public License | ||
* as published by the Free Software Foundation; either version 2 | ||
* of the License, or (at your option) any later version. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU General Public License | ||
* along with this program; if not, write to the Free Software | ||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
*/ | ||
|
||
#include "job.h" | ||
|
||
#include <QtDBus> | ||
#include <QDBusArgument> | ||
#include <QDBusInterface> | ||
|
||
Q_DECLARE_METATYPE(Properties) | ||
Q_DECLARE_METATYPE(InterfacesAndProperties) | ||
Q_DECLARE_METATYPE(DBusIntrospection) | ||
|
||
Job::Job(const QString& where) | ||
: Job(QString(), where) { } | ||
|
||
Job::Job(const QString &what, const QString &where) | ||
: what(what), where(where) | ||
{ | ||
qDBusRegisterMetaType<Properties>(); | ||
qDBusRegisterMetaType<InterfacesAndProperties>(); | ||
qDBusRegisterMetaType<DBusIntrospection>(); | ||
} | ||
|
||
QDBusUnixFileDescriptor Job::getDescriptor() | ||
{ | ||
QDBusInterface device("org.freedesktop.UDisks2", where, "org.freedesktop.UDisks2.Block", QDBusConnection::systemBus(), this); | ||
QString drivePath = qvariant_cast<QDBusObjectPath>(device.property("Drive")).path(); | ||
QDBusInterface manager("org.freedesktop.UDisks2", "/org/freedesktop/UDisks2", "org.freedesktop.DBus.ObjectManager", QDBusConnection::systemBus()); | ||
QDBusMessage message = manager.call("GetManagedObjects"); | ||
|
||
if (message.arguments().length() == 1) { | ||
QDBusArgument arg = qvariant_cast<QDBusArgument>(message.arguments().first()); | ||
DBusIntrospection objects; | ||
arg >> objects; | ||
for (auto i : objects.keys()) { | ||
if (objects[i].contains("org.freedesktop.UDisks2.Filesystem")) { | ||
QString currentDrivePath = qvariant_cast<QDBusObjectPath>(objects[i]["org.freedesktop.UDisks2.Block"]["Drive"]).path(); | ||
if (currentDrivePath == drivePath) { | ||
QDBusInterface partition("org.freedesktop.UDisks2", i.path(), "org.freedesktop.UDisks2.Filesystem", QDBusConnection::systemBus()); | ||
message = partition.call("Unmount", Properties{{"force", true}}); | ||
} | ||
} | ||
} | ||
} else { | ||
err << message.errorMessage(); | ||
err.flush(); | ||
qApp->exit(2); | ||
return QDBusUnixFileDescriptor(-1); | ||
} | ||
|
||
QDBusReply<QDBusUnixFileDescriptor> reply = device.call(QDBus::Block, "OpenDevice", "rw", Properties{{"flags", O_DIRECT | O_SYNC | O_CLOEXEC}}); | ||
QDBusUnixFileDescriptor fd = reply.value(); | ||
|
||
if (!fd.isValid()) { | ||
err << reply.error().message(); | ||
err.flush(); | ||
qApp->exit(2); | ||
return QDBusUnixFileDescriptor(-1); | ||
} | ||
|
||
return fd; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
/* | ||
* Fedora Media Writer | ||
* Copyright (C) 2024 Jan Grulich <[email protected]> | ||
* Copyright (C) 2016 Martin Bříza <[email protected]> | ||
* | ||
* This program is free software; you can redistribute it and/or | ||
* modify it under the terms of the GNU General Public License | ||
* as published by the Free Software Foundation; either version 2 | ||
* of the License, or (at your option) any later version. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU General Public License | ||
* along with this program; if not, write to the Free Software | ||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
*/ | ||
|
||
#ifndef JOB_H | ||
#define JOB_H | ||
|
||
#include <QDBusUnixFileDescriptor> | ||
#include <QDBusObjectPath> | ||
#include <QObject> | ||
#include <QTextStream> | ||
|
||
#include <fcntl.h> | ||
#include <unistd.h> | ||
|
||
#include <memory> | ||
#include <tuple> | ||
|
||
typedef QHash<QString, QVariant> Properties; | ||
typedef QHash<QString, Properties> InterfacesAndProperties; | ||
typedef QHash<QDBusObjectPath, InterfacesAndProperties> DBusIntrospection; | ||
|
||
class Job : public QObject | ||
{ | ||
Q_OBJECT | ||
public: | ||
explicit Job(const QString &where); | ||
Job(const QString &what, const QString &where); | ||
|
||
QDBusUnixFileDescriptor getDescriptor(); | ||
|
||
public slots: | ||
virtual void work() = 0; | ||
|
||
protected: | ||
QString what; | ||
QString where; | ||
QTextStream out{stdout}; | ||
QTextStream err{stderr}; | ||
QDBusUnixFileDescriptor fd{-1}; | ||
}; | ||
|
||
std::tuple<std::unique_ptr<char[]>, char *, std::size_t> pageAlignedBuffer(std::size_t pages = 1024); | ||
|
||
#endif // JOB_H | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,6 @@ | ||
/* | ||
* Fedora Media Writer | ||
* Copyright (C) 2024 Jan Grulich <[email protected]> | ||
* Copyright (C) 2016 Martin Bříza <[email protected]> | ||
* | ||
* This program is free software; you can redistribute it and/or | ||
|
@@ -20,24 +21,19 @@ | |
#include "restorejob.h" | ||
|
||
#include <QCoreApplication> | ||
#include <QTextStream> | ||
#include <QThread> | ||
#include <QTimer> | ||
|
||
#include <QDBusArgument> | ||
#include <QDBusInterface> | ||
#include <QDBusUnixFileDescriptor> | ||
#include <QtDBus> | ||
#include <QDBusMessage> | ||
#include <QDBusReply> | ||
|
||
typedef QHash<QString, QVariant> Properties; | ||
typedef QHash<QString, Properties> InterfacesAndProperties; | ||
typedef QHash<QDBusObjectPath, InterfacesAndProperties> DBusIntrospection; | ||
Q_DECLARE_METATYPE(Properties) | ||
Q_DECLARE_METATYPE(InterfacesAndProperties) | ||
Q_DECLARE_METATYPE(DBusIntrospection) | ||
#include <stdio.h> | ||
#include <sys/types.h> | ||
|
||
RestoreJob::RestoreJob(const QString &where) | ||
: QObject(nullptr) | ||
, where(where) | ||
: Job(where) | ||
{ | ||
QTimer::singleShot(0, this, SLOT(work())); | ||
} | ||
|
@@ -65,7 +61,70 @@ void RestoreJob::work() | |
} | ||
} | ||
|
||
QDBusReply<void> formatReply = device.call("Format", "dos", Properties()); | ||
// Wipe out first and last 128 blocks with zeroes | ||
fd = getDescriptor(); | ||
if (fd.fileDescriptor() < 0) { | ||
err << tr("Failed to open device for writing"); | ||
err.flush(); | ||
qApp->exit(1); | ||
} | ||
|
||
auto bufferOwner = pageAlignedBuffer(); | ||
char *buffer = std::get<1>(bufferOwner); | ||
qint64 size = std::get<2>(bufferOwner); | ||
|
||
memset(buffer, '\0', size); | ||
|
||
// Overwrite first 128 blocks with zeroes | ||
for (int i = 0; i < 128; i++) { | ||
qint64 written = ::write(fd.fileDescriptor(), buffer, size); | ||
if (written != size) { | ||
err << tr("Destination drive is not writable"); | ||
err.flush(); | ||
qApp->exit(1); | ||
} | ||
} | ||
|
||
// Rewind the filepointer to the last 128 blocks | ||
off_t filesize = lseek(fd.fileDescriptor(), 0, SEEK_END); | ||
if (filesize == static_cast<off_t>(-1)) { | ||
err << tr("Failed to get file size"); | ||
err.flush(); | ||
qApp->exit(1); | ||
} | ||
|
||
off_t offset = filesize - (128 * size); | ||
if (offset < 0) { | ||
err << tr("File size is smaller than 128 blocks"); | ||
err.flush(); | ||
qApp->exit(1); | ||
} | ||
|
||
// Move the file pointer to the calculated offset | ||
if (lseek(fd.fileDescriptor(), offset, SEEK_SET) == static_cast<off_t>(-1)) { | ||
err << tr("Failed to move file pointer to the end region"); | ||
err.flush(); | ||
qApp->exit(1); | ||
} | ||
|
||
// Overwrite last 128 blocks with zeroes | ||
for (int i = 0; i < 128; i++) { | ||
qint64 written = ::write(fd.fileDescriptor(), buffer, size); | ||
if (written != size) { | ||
err << tr("Destination drive is not writable"); | ||
err.flush(); | ||
qApp->exit(1); | ||
} | ||
} | ||
|
||
// Ensure data is flushed to disk | ||
if (::fsync(fd.fileDescriptor()) == -1) { | ||
err << tr("Failed to sync data to disk"); | ||
err.flush(); | ||
qApp->exit(1); | ||
} | ||
|
||
QDBusReply<void> formatReply = device.call("Format", "gpt", Properties()); | ||
if (!formatReply.isValid() && formatReply.error().type() != QDBusError::NoReply) { | ||
err << formatReply.error().message() << "\n"; | ||
err.flush(); | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,6 @@ | ||
/* | ||
* Fedora Media Writer | ||
* Copyright (C) 2024 Jan Grulich <[email protected]> | ||
* Copyright (C) 2016 Martin Bříza <[email protected]> | ||
* | ||
* This program is free software; you can redistribute it and/or | ||
|
@@ -20,22 +21,16 @@ | |
#ifndef RESTOREJOB_H | ||
#define RESTOREJOB_H | ||
|
||
#include <QObject> | ||
#include <QTextStream> | ||
#include "job.h" | ||
|
||
class RestoreJob : public QObject | ||
class RestoreJob : public Job | ||
{ | ||
Q_OBJECT | ||
public: | ||
explicit RestoreJob(const QString &where); | ||
public slots: | ||
void work(); | ||
|
||
private: | ||
QTextStream out{stdout}; | ||
QTextStream err{stderr}; | ||
|
||
QString where; | ||
public slots: | ||
void work() override; | ||
}; | ||
|
||
#endif // RESTOREJOB_H |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,6 @@ | ||
/* | ||
* Fedora Media Writer | ||
* Copyright (C) 2024 Jan Grulich <[email protected]> | ||
* Copyright (C) 2016 Martin Bříza <[email protected]> | ||
* | ||
* This program is free software; you can redistribute it and/or | ||
|
@@ -21,41 +22,17 @@ | |
|
||
#include <QCoreApplication> | ||
#include <QProcess> | ||
#include <QTextStream> | ||
#include <QTimer> | ||
#include <QRegularExpression> | ||
#include <QtGlobal> | ||
|
||
#include <QDBusInterface> | ||
#include <QDBusUnixFileDescriptor> | ||
#include <QtDBus> | ||
|
||
#include <fcntl.h> | ||
#include <unistd.h> | ||
|
||
#include <tuple> | ||
#include <utility> | ||
|
||
#include <lzma.h> | ||
|
||
#include "isomd5/libcheckisomd5.h" | ||
|
||
#include <QDebug> | ||
|
||
typedef QHash<QString, QVariant> Properties; | ||
typedef QHash<QString, Properties> InterfacesAndProperties; | ||
typedef QHash<QDBusObjectPath, InterfacesAndProperties> DBusIntrospection; | ||
Q_DECLARE_METATYPE(Properties) | ||
Q_DECLARE_METATYPE(InterfacesAndProperties) | ||
Q_DECLARE_METATYPE(DBusIntrospection) | ||
|
||
WriteJob::WriteJob(const QString &what, const QString &where) | ||
: QObject(nullptr) | ||
, what(what) | ||
, where(where) | ||
: Job(what, where) | ||
{ | ||
qDBusRegisterMetaType<Properties>(); | ||
qDBusRegisterMetaType<InterfacesAndProperties>(); | ||
qDBusRegisterMetaType<DBusIntrospection>(); | ||
connect(&watcher, &QFileSystemWatcher::fileChanged, this, &WriteJob::onFileChanged); | ||
QTimer::singleShot(0, this, SLOT(work())); | ||
} | ||
|
@@ -73,46 +50,6 @@ int WriteJob::onMediaCheckAdvanced(long long offset, long long total) | |
return 0; | ||
} | ||
|
||
QDBusUnixFileDescriptor WriteJob::getDescriptor() | ||
{ | ||
QDBusInterface device("org.freedesktop.UDisks2", where, "org.freedesktop.UDisks2.Block", QDBusConnection::systemBus(), this); | ||
QString drivePath = qvariant_cast<QDBusObjectPath>(device.property("Drive")).path(); | ||
QDBusInterface manager("org.freedesktop.UDisks2", "/org/freedesktop/UDisks2", "org.freedesktop.DBus.ObjectManager", QDBusConnection::systemBus()); | ||
QDBusMessage message = manager.call("GetManagedObjects"); | ||
|
||
if (message.arguments().length() == 1) { | ||
QDBusArgument arg = qvariant_cast<QDBusArgument>(message.arguments().first()); | ||
DBusIntrospection objects; | ||
arg >> objects; | ||
for (auto i : objects.keys()) { | ||
if (objects[i].contains("org.freedesktop.UDisks2.Filesystem")) { | ||
QString currentDrivePath = qvariant_cast<QDBusObjectPath>(objects[i]["org.freedesktop.UDisks2.Block"]["Drive"]).path(); | ||
if (currentDrivePath == drivePath) { | ||
QDBusInterface partition("org.freedesktop.UDisks2", i.path(), "org.freedesktop.UDisks2.Filesystem", QDBusConnection::systemBus()); | ||
message = partition.call("Unmount", Properties{{"force", true}}); | ||
} | ||
} | ||
} | ||
} else { | ||
err << message.errorMessage(); | ||
err.flush(); | ||
qApp->exit(2); | ||
return QDBusUnixFileDescriptor(-1); | ||
} | ||
|
||
QDBusReply<QDBusUnixFileDescriptor> reply = device.call(QDBus::Block, "OpenDevice", "rw", Properties{{"flags", O_DIRECT | O_SYNC | O_CLOEXEC}}); | ||
QDBusUnixFileDescriptor fd = reply.value(); | ||
|
||
if (!fd.isValid()) { | ||
err << reply.error().message(); | ||
err.flush(); | ||
qApp->exit(2); | ||
return QDBusUnixFileDescriptor(-1); | ||
} | ||
|
||
return fd; | ||
} | ||
|
||
bool WriteJob::write(int fd) | ||
{ | ||
if (what.endsWith(".xz")) | ||
|
Oops, something went wrong.