retro-imager/driveformatthread.cpp

228 lines
6.2 KiB
C++
Raw Normal View History

2020-03-04 16:55:40 +01:00
/*
* SPDX-License-Identifier: Apache-2.0
* Copyright (C) 2020 Raspberry Pi Ltd
2020-03-04 16:55:40 +01:00
*/
#include "driveformatthread.h"
#include "dependencies/drivelist/src/drivelist.hpp"
#include "dependencies/mountutils/src/mountutils.hpp"
#include <regex>
#include <QDebug>
#include <QProcess>
#include <QTemporaryFile>
#include <QCoreApplication>
#ifdef Q_OS_LINUX
#include "linux/udisks2api.h"
#include <unistd.h>
#endif
DriveFormatThread::DriveFormatThread(const QByteArray &device, QObject *parent)
: QThread(parent), _device(device)
{
}
DriveFormatThread::~DriveFormatThread()
{
wait();
}
void DriveFormatThread::run()
{
#ifdef Q_OS_WIN
std::regex windriveregex("\\\\\\\\.\\\\PHYSICALDRIVE([0-9]+)", std::regex_constants::icase);
std::cmatch m;
if (std::regex_match(_device.constData(), m, windriveregex))
{
QByteArray nr = QByteArray::fromStdString(m[1]);
qDebug() << "Formatting Windows drive #" << nr << "(" << _device << ")";
QProcess proc;
QByteArray diskpartCmds =
"select disk "+nr+"\r\n"
"clean\r\n"
"create partition primary\r\n"
"select partition 1\r\n"
"set id=0e\r\n"
"assign\r\n";
proc.start("diskpart");
proc.waitForStarted();
proc.write(diskpartCmds);
proc.closeWriteChannel();
proc.waitForFinished();
QByteArray output = proc.readAllStandardError();
qDebug() << output;
qDebug() << "Done running diskpart. Exit status code =" << proc.exitCode();
if (proc.exitCode())
{
emit error(tr("Error partitioning: %1").arg(QString(output)));
}
else
{
auto l = Drivelist::ListStorageDevices();
QByteArray devlower = _device.toLower();
for (auto i : l)
{
if (QByteArray::fromStdString(i.device).toLower() == devlower && i.mountpoints.size() == 1)
{
QByteArray driveLetter = QByteArray::fromStdString(i.mountpoints.front());
if (driveLetter.endsWith("\\"))
driveLetter.chop(1);
qDebug() << "Drive letter of device:" << driveLetter;
QProcess f32format;
QStringList args;
args << "-y" << driveLetter;
f32format.start(QCoreApplication::applicationDirPath()+"/fat32format.exe", args);
if (!f32format.waitForStarted())
{
emit error(tr("Error starting fat32format"));
return;
}
//f32format.write("y\r\n");
f32format.closeWriteChannel();
f32format.waitForFinished(120000);
if (f32format.exitStatus() || f32format.exitCode())
{
emit error(tr("Error running fat32format: %1").arg(QString(f32format.readAll())));
}
else
{
emit success();
}
return;
}
}
emit error(tr("Error determining new drive letter"));
}
}
else
{
emit error(tr("Invalid device: %1").arg(QString(_device)));
}
#elif defined(Q_OS_DARWIN)
QProcess proc;
QStringList args;
args << "eraseDisk" << "FAT32" << "SDCARD" << "MBRFormat" << _device;
proc.start("diskutil", args);
proc.waitForFinished();
QByteArray output = proc.readAllStandardError();
qDebug() << args;
qDebug() << "diskutil output:" << output;
if (proc.exitCode())
{
emit error(tr("Error partitioning: %1").arg(QString(output)));
}
else
{
emit success();
}
#elif defined(Q_OS_LINUX)
if (::access(_device.constData(), W_OK) != 0)
2020-03-04 16:55:40 +01:00
{
/* Not running as root, try to outsource formatting to udisks2 */
#ifndef QT_NO_DBUS
2020-03-04 16:55:40 +01:00
UDisks2Api udisks2;
if (udisks2.formatDrive(_device))
{
emit success();
}
else
{
#endif
2020-03-04 16:55:40 +01:00
emit error(tr("Error formatting (through udisks2)"));
#ifndef QT_NO_DBUS
2020-03-04 16:55:40 +01:00
}
#endif
2020-03-04 16:55:40 +01:00
return;
}
QProcess proc;
QByteArray partitionTable;
QStringList args;
QByteArray fatpartition = _device;
partitionTable = "8192,,0E\n"
"0,0\n"
"0,0\n"
"0,0\n";
args << "-uS" << _device;
if (isdigit(fatpartition.at(fatpartition.length()-1)))
fatpartition += "p1";
else
fatpartition += "1";
unmount_disk(_device);
proc.setProcessChannelMode(proc.MergedChannels);
proc.start("sfdisk", args);
if (!proc.waitForStarted())
{
emit error(tr("Error starting sfdisk"));
return;
}
proc.write(partitionTable);
proc.closeWriteChannel();
proc.waitForFinished();
QByteArray output = proc.readAll();
qDebug() << "sfdisk:" << output;
if (proc.exitCode())
{
emit error(tr("Error partitioning: %1").arg(QString(output)));
return;
}
proc.execute("partprobe", QStringList() );
for (int tries = 0; tries < 30; tries++)
{
if (QFile::exists(fatpartition))
break;
QThread::msleep(100);
}
if (!QFile::exists(fatpartition))
{
emit error(tr("Partitioning did not create expected FAT partition %1").arg(QString(fatpartition)));
return;
}
2020-03-04 16:55:40 +01:00
args.clear();
args << fatpartition;
proc.start("mkfs.fat", args);
if (!proc.waitForStarted())
{
emit error(tr("Error starting mkfs.fat"));
return;
}
proc.waitForFinished();
output = proc.readAll();
qDebug() << "mkfs.fat:" << output;
if (proc.exitCode())
{
emit error(tr("Error running mkfs.fat: %1").arg(QString(output)));
return;
}
emit success();
#else
emit error(tr("Formatting not implemented for this platform"));
#endif
}