/* * SPDX-License-Identifier: Apache-2.0 * Copyright (C) 2020 Raspberry Pi (Trading) Limited */ #include "driveformatthread.h" #include "dependencies/drivelist/src/drivelist.hpp" #include "dependencies/mountutils/src/mountutils.hpp" #include #include #include #include #include #ifdef Q_OS_LINUX #include "linux/udisks2api.h" #include #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) { /* Not running as root, try to outsource formatting to udisks2 */ #ifndef QT_NO_DBUS UDisks2Api udisks2; if (udisks2.formatDrive(_device)) { emit success(); } else { #endif emit error(tr("Error formatting (through udisks2)")); #ifndef QT_NO_DBUS } #endif 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() ); 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 }