mirror of
https://github.com/cmclark00/retro-imager.git
synced 2025-05-18 07:55:21 +01:00
Switch to using FAT classes for advanced settings
- No longer relies on operating system for mounting FAT partition when applying 'advanced settings' - change '__attribute__ ((packed))' to '#pragma pack()' as the mingw version we are using for Windows has a bug with the former
This commit is contained in:
parent
ebc6edc0c3
commit
5fa3fbe8dc
5 changed files with 142 additions and 321 deletions
12
debian/changelog
vendored
12
debian/changelog
vendored
|
@ -1,3 +1,15 @@
|
||||||
|
rpi-imager (1.7.4) unstable; urgency=medium
|
||||||
|
|
||||||
|
* Advanced settings: fix escaping single quotes
|
||||||
|
* Advanced settings: default to using username of logged-in user
|
||||||
|
* Now uses a different method to edit files on the FAT partition
|
||||||
|
to apply advanced settings. Imager now understands the FAT16/FAT32
|
||||||
|
file system format and can edit files by itself using the raw
|
||||||
|
disk device, without having to rely on the operating system
|
||||||
|
to mount the partition first.
|
||||||
|
|
||||||
|
-- Floris Bos <bos@je-eigen-domein.nl> Mon, 14 Nov 2022 21:49:27 +0100
|
||||||
|
|
||||||
rpi-imager (1.7.3) unstable; urgency=medium
|
rpi-imager (1.7.3) unstable; urgency=medium
|
||||||
|
|
||||||
* Linux: use GnuTLS instead of OpenSSL for computing SHA256
|
* Linux: use GnuTLS instead of OpenSSL for computing SHA256
|
||||||
|
|
|
@ -12,8 +12,8 @@ OPTION (ENABLE_TELEMETRY "Enable sending telemetry" ON)
|
||||||
project(rpi-imager LANGUAGES CXX C)
|
project(rpi-imager LANGUAGES CXX C)
|
||||||
set(IMAGER_VERSION_MAJOR 1)
|
set(IMAGER_VERSION_MAJOR 1)
|
||||||
set(IMAGER_VERSION_MINOR 7)
|
set(IMAGER_VERSION_MINOR 7)
|
||||||
set(IMAGER_VERSION_STR "${IMAGER_VERSION_MAJOR}.${IMAGER_VERSION_MINOR}.3")
|
set(IMAGER_VERSION_STR "${IMAGER_VERSION_MAJOR}.${IMAGER_VERSION_MINOR}.4")
|
||||||
set(IMAGER_VERSION_CSV "${IMAGER_VERSION_MAJOR},${IMAGER_VERSION_MINOR},3,0")
|
set(IMAGER_VERSION_CSV "${IMAGER_VERSION_MAJOR},${IMAGER_VERSION_MINOR},4,0")
|
||||||
add_definitions(-DIMAGER_VERSION_STR="${IMAGER_VERSION_STR}")
|
add_definitions(-DIMAGER_VERSION_STR="${IMAGER_VERSION_STR}")
|
||||||
add_definitions(-DIMAGER_VERSION_CSV=${IMAGER_VERSION_CSV})
|
add_definitions(-DIMAGER_VERSION_CSV=${IMAGER_VERSION_CSV})
|
||||||
|
|
||||||
|
|
|
@ -483,7 +483,7 @@ bool DeviceWrapperFatPartition::dirNameExists(const QByteArray dirname)
|
||||||
while (readDir(&entry))
|
while (readDir(&entry))
|
||||||
{
|
{
|
||||||
if (!(entry.DIR_Attr & ATTR_LONG_NAME)
|
if (!(entry.DIR_Attr & ATTR_LONG_NAME)
|
||||||
&& dirname == QByteArray(entry.DIR_Name, sizeof(entry.DIR_Name)))
|
&& dirname == QByteArray((char *) entry.DIR_Name, sizeof(entry.DIR_Name)))
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,10 @@
|
||||||
* Copyright (C) 2022 Raspberry Pi Ltd
|
* Copyright (C) 2022 Raspberry Pi Ltd
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#pragma pack(push, 1)
|
||||||
|
|
||||||
/* MBR on-disk structures */
|
/* MBR on-disk structures */
|
||||||
|
|
||||||
struct mbr_partition_entry {
|
struct mbr_partition_entry {
|
||||||
|
@ -15,7 +19,7 @@ struct mbr_partition_entry {
|
||||||
char end_hsc[3];
|
char end_hsc[3];
|
||||||
unsigned int starting_sector;
|
unsigned int starting_sector;
|
||||||
unsigned int nr_of_sectors;
|
unsigned int nr_of_sectors;
|
||||||
} __attribute__ ((packed));
|
};
|
||||||
|
|
||||||
struct mbr_table {
|
struct mbr_table {
|
||||||
char bootcode[440];
|
char bootcode[440];
|
||||||
|
@ -23,7 +27,7 @@ struct mbr_table {
|
||||||
unsigned char flags[2];
|
unsigned char flags[2];
|
||||||
mbr_partition_entry part[4];
|
mbr_partition_entry part[4];
|
||||||
unsigned char signature[2];
|
unsigned char signature[2];
|
||||||
} __attribute__ ((packed));
|
};
|
||||||
|
|
||||||
|
|
||||||
/* File Allocation Table
|
/* File Allocation Table
|
||||||
|
@ -55,7 +59,7 @@ struct fat16_bpb {
|
||||||
|
|
||||||
uint8_t Zeroes[448];
|
uint8_t Zeroes[448];
|
||||||
uint8_t Signature[2]; /* 0x55aa */
|
uint8_t Signature[2]; /* 0x55aa */
|
||||||
} __attribute__ ((packed));
|
};
|
||||||
|
|
||||||
struct fat32_bpb {
|
struct fat32_bpb {
|
||||||
uint8_t BS_jmpBoot[3];
|
uint8_t BS_jmpBoot[3];
|
||||||
|
@ -89,7 +93,7 @@ struct fat32_bpb {
|
||||||
|
|
||||||
uint8_t Zeroes[420];
|
uint8_t Zeroes[420];
|
||||||
uint8_t Signature[2]; /* 0x55aa */
|
uint8_t Signature[2]; /* 0x55aa */
|
||||||
} __attribute__ ((packed));
|
};
|
||||||
|
|
||||||
union fat_bpb {
|
union fat_bpb {
|
||||||
struct fat16_bpb fat16;
|
struct fat16_bpb fat16;
|
||||||
|
@ -97,7 +101,7 @@ union fat_bpb {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct dir_entry {
|
struct dir_entry {
|
||||||
char DIR_Name[11];
|
unsigned char DIR_Name[11];
|
||||||
uint8_t DIR_Attr;
|
uint8_t DIR_Attr;
|
||||||
uint8_t DIR_NTRes;
|
uint8_t DIR_NTRes;
|
||||||
uint8_t DIR_CrtTimeTenth;
|
uint8_t DIR_CrtTimeTenth;
|
||||||
|
@ -109,7 +113,7 @@ struct dir_entry {
|
||||||
uint16_t DIR_WrtDate;
|
uint16_t DIR_WrtDate;
|
||||||
uint16_t DIR_FstClusLO;
|
uint16_t DIR_FstClusLO;
|
||||||
uint32_t DIR_FileSize;
|
uint32_t DIR_FileSize;
|
||||||
} __attribute__ ((packed));
|
};
|
||||||
|
|
||||||
struct longfn_entry {
|
struct longfn_entry {
|
||||||
uint8_t LDIR_Ord;
|
uint8_t LDIR_Ord;
|
||||||
|
@ -120,7 +124,7 @@ struct longfn_entry {
|
||||||
char LDIR_Name2[12];
|
char LDIR_Name2[12];
|
||||||
uint16_t LDIR_FstClusLO;
|
uint16_t LDIR_FstClusLO;
|
||||||
char LDIR_Name3[4];
|
char LDIR_Name3[4];
|
||||||
} __attribute__ ((packed));
|
};
|
||||||
|
|
||||||
#define LAST_LONG_ENTRY 0x40
|
#define LAST_LONG_ENTRY 0x40
|
||||||
|
|
||||||
|
@ -140,6 +144,8 @@ struct FSInfo {
|
||||||
uint32_t FSI_Nxt_Free;
|
uint32_t FSI_Nxt_Free;
|
||||||
uint8_t FSI_Reserved2[12];
|
uint8_t FSI_Reserved2[12];
|
||||||
uint8_t FSI_TrailSig[4]; /* 0x00 0x00 0x55 0xAA */
|
uint8_t FSI_TrailSig[4]; /* 0x00 0x00 0x55 0xAA */
|
||||||
} __attribute__ ((packed));
|
};
|
||||||
|
|
||||||
|
#pragma pack(pop)
|
||||||
|
|
||||||
#endif // DEVICEWRAPPERSTRUCTS_H
|
#endif // DEVICEWRAPPERSTRUCTS_H
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
|
|
||||||
#include "downloadthread.h"
|
#include "downloadthread.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
#include "devicewrapper.h"
|
||||||
|
#include "devicewrapperfatpartition.h"
|
||||||
#include "dependencies/mountutils/src/mountutils.hpp"
|
#include "dependencies/mountutils/src/mountutils.hpp"
|
||||||
#include "dependencies/drivelist/src/drivelist.hpp"
|
#include "dependencies/drivelist/src/drivelist.hpp"
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
@ -724,6 +726,15 @@ void DownloadThread::_writeComplete()
|
||||||
|
|
||||||
emit finalizing();
|
emit finalizing();
|
||||||
|
|
||||||
|
if (!_config.isEmpty() || !_cmdline.isEmpty() || !_firstrun.isEmpty())
|
||||||
|
{
|
||||||
|
if (!_customizeImage())
|
||||||
|
{
|
||||||
|
_closeFiles();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (_firstBlock)
|
if (_firstBlock)
|
||||||
{
|
{
|
||||||
qDebug() << "Writing first block (which we skipped at first)";
|
qDebug() << "Writing first block (which we skipped at first)";
|
||||||
|
@ -741,6 +752,21 @@ void DownloadThread::_writeComplete()
|
||||||
_firstBlock = nullptr;
|
_firstBlock = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!_file.flush())
|
||||||
|
{
|
||||||
|
DownloadThread::_onDownloadError(tr("Error writing to storage (while flushing)"));
|
||||||
|
_closeFiles();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef Q_OS_WIN
|
||||||
|
if (::fsync(_file.handle()) != 0) {
|
||||||
|
DownloadThread::_onDownloadError(tr("Error writing to storage (while fsync)"));
|
||||||
|
_closeFiles();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
_closeFiles();
|
_closeFiles();
|
||||||
|
|
||||||
#ifdef Q_OS_DARWIN
|
#ifdef Q_OS_DARWIN
|
||||||
|
@ -748,17 +774,8 @@ void DownloadThread::_writeComplete()
|
||||||
_filename.replace("/dev/rdisk", "/dev/disk");
|
_filename.replace("/dev/rdisk", "/dev/disk");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (_ejectEnabled && _config.isEmpty() && _cmdline.isEmpty() && _firstrun.isEmpty())
|
|
||||||
eject_disk(_filename.constData());
|
|
||||||
|
|
||||||
if (!_config.isEmpty() || !_cmdline.isEmpty() || !_firstrun.isEmpty())
|
|
||||||
{
|
|
||||||
if (!_customizeImage())
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (_ejectEnabled)
|
if (_ejectEnabled)
|
||||||
eject_disk(_filename.constData());
|
eject_disk(_filename.constData());
|
||||||
}
|
|
||||||
|
|
||||||
emit success();
|
emit success();
|
||||||
}
|
}
|
||||||
|
@ -865,169 +882,29 @@ void DownloadThread::setImageCustomization(const QByteArray &config, const QByte
|
||||||
|
|
||||||
bool DownloadThread::_customizeImage()
|
bool DownloadThread::_customizeImage()
|
||||||
{
|
{
|
||||||
QString folder;
|
|
||||||
std::vector<std::string> mountpoints;
|
|
||||||
QByteArray devlower = _filename.toLower();
|
|
||||||
|
|
||||||
emit preparationStatusUpdate(tr("Waiting for FAT partition to be mounted"));
|
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
|
||||||
qDebug() << "Running diskpart rescan";
|
|
||||||
QProcess proc;
|
|
||||||
proc.setProcessChannelMode(proc.MergedChannels);
|
|
||||||
proc.start("diskpart");
|
|
||||||
proc.waitForStarted();
|
|
||||||
proc.write("rescan\r\n");
|
|
||||||
proc.closeWriteChannel();
|
|
||||||
proc.waitForFinished();
|
|
||||||
qDebug() << proc.readAll();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* See if OS auto-mounted the device */
|
|
||||||
for (int tries = 0; tries < 3; tries++)
|
|
||||||
{
|
|
||||||
QThread::sleep(1);
|
|
||||||
auto l = Drivelist::ListStorageDevices();
|
|
||||||
for (const auto& i : l)
|
|
||||||
{
|
|
||||||
if (QByteArray::fromStdString(i.device).toLower() == devlower && i.mountpoints.size())
|
|
||||||
{
|
|
||||||
mountpoints = i.mountpoints;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
|
||||||
if (mountpoints.empty() && !_nr.isEmpty()) {
|
|
||||||
qDebug() << "Windows did not assign drive letter automatically. Ask diskpart to do so manually.";
|
|
||||||
proc.start("diskpart");
|
|
||||||
proc.waitForStarted();
|
|
||||||
proc.write("select disk "+_nr+"\r\n"
|
|
||||||
"select partition 1\r\n"
|
|
||||||
"assign\r\n");
|
|
||||||
proc.closeWriteChannel();
|
|
||||||
proc.waitForFinished();
|
|
||||||
qDebug() << proc.readAll();
|
|
||||||
|
|
||||||
auto l = Drivelist::ListStorageDevices();
|
|
||||||
for (auto i : l)
|
|
||||||
{
|
|
||||||
if (QByteArray::fromStdString(i.device).toLower() == devlower && i.mountpoints.size())
|
|
||||||
{
|
|
||||||
mountpoints = i.mountpoints;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef Q_OS_LINUX
|
|
||||||
bool manualmount = false;
|
|
||||||
|
|
||||||
if (mountpoints.empty())
|
|
||||||
{
|
|
||||||
/* Manually mount folder */
|
|
||||||
manualmount = true;
|
|
||||||
QByteArray fatpartition = _filename;
|
|
||||||
if (isdigit(fatpartition.at(fatpartition.length()-1)))
|
|
||||||
fatpartition += "p1";
|
|
||||||
else
|
|
||||||
fatpartition += "1";
|
|
||||||
|
|
||||||
if (::access(devlower.constData(), W_OK) != 0)
|
|
||||||
{
|
|
||||||
/* Not running as root, try to outsource mounting to udisks2 */
|
|
||||||
#ifndef QT_NO_DBUS
|
|
||||||
UDisks2Api udisks2;
|
|
||||||
QString mp = udisks2.mountDevice(fatpartition);
|
|
||||||
if (!mp.isEmpty())
|
|
||||||
mountpoints.push_back(mp.toStdString());
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Running as root, attempt running mount directly */
|
|
||||||
QTemporaryDir td;
|
|
||||||
QStringList args;
|
|
||||||
mountpoints.push_back(td.path().toStdString());
|
|
||||||
args << "-t" << "vfat" << fatpartition << td.path();
|
|
||||||
|
|
||||||
if (QProcess::execute("mount", args) != 0)
|
|
||||||
{
|
|
||||||
emit error(tr("Error mounting FAT32 partition"));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
td.setAutoRemove(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (mountpoints.empty())
|
|
||||||
{
|
|
||||||
//
|
|
||||||
qDebug() << "drive info. searching for:" << devlower;
|
|
||||||
auto l = Drivelist::ListStorageDevices();
|
|
||||||
for (const auto& i : l)
|
|
||||||
{
|
|
||||||
qDebug() << "drive" << QByteArray::fromStdString(i.device).toLower();
|
|
||||||
for (const auto& mp : i.mountpoints) {
|
|
||||||
qDebug() << "mountpoint:" << QByteArray::fromStdString(mp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//
|
|
||||||
|
|
||||||
emit error(tr("Operating system did not mount FAT32 partition"));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Some operating system take longer to complete mounting FAT32
|
|
||||||
wait up to 3 seconds for config.txt file to appear */
|
|
||||||
QString configFilename;
|
|
||||||
bool foundFile = false;
|
|
||||||
|
|
||||||
for (int tries = 0; tries < 3; tries++)
|
|
||||||
{
|
|
||||||
/* Search all mountpoints, as on some systems FAT partition
|
|
||||||
may not be first volume */
|
|
||||||
for (const auto& mp : mountpoints)
|
|
||||||
{
|
|
||||||
folder = QString::fromStdString(mp);
|
|
||||||
if (folder.right(1) == '\\')
|
|
||||||
folder.chop(1);
|
|
||||||
configFilename = folder+"/config.txt";
|
|
||||||
|
|
||||||
if (QFile::exists(configFilename))
|
|
||||||
{
|
|
||||||
foundFile = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (foundFile)
|
|
||||||
break;
|
|
||||||
QThread::sleep(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!foundFile)
|
|
||||||
{
|
|
||||||
emit error(tr("Unable to customize. File '%1' does not exist.").arg(configFilename));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
emit preparationStatusUpdate(tr("Customizing image"));
|
emit preparationStatusUpdate(tr("Customizing image"));
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
DeviceWrapper dw(&_file);
|
||||||
|
if (_firstBlock)
|
||||||
|
{
|
||||||
|
/* Outsource first block handling to DeviceWrapper.
|
||||||
|
It will still not actually be written out yet,
|
||||||
|
until we call sync(), and then it will
|
||||||
|
save the first 4k sector with MBR for last */
|
||||||
|
dw.pwrite(_firstBlock, _firstBlockSize, 0);
|
||||||
|
_bytesWritten += _firstBlockSize;
|
||||||
|
qFreeAligned(_firstBlock);
|
||||||
|
_firstBlock = nullptr;
|
||||||
|
}
|
||||||
|
DeviceWrapperFatPartition *fat = dw.fatPartition(1);
|
||||||
|
|
||||||
if (!_config.isEmpty())
|
if (!_config.isEmpty())
|
||||||
{
|
{
|
||||||
auto configItems = _config.split('\n');
|
auto configItems = _config.split('\n');
|
||||||
configItems.removeAll("");
|
configItems.removeAll("");
|
||||||
QByteArray config;
|
QByteArray config = fat->readFile("config.txt");
|
||||||
|
|
||||||
QFile f(configFilename);
|
|
||||||
if (f.open(f.ReadOnly))
|
|
||||||
{
|
|
||||||
config = f.readAll();
|
|
||||||
f.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const QByteArray& item : qAsConst(configItems))
|
for (const QByteArray& item : qAsConst(configItems))
|
||||||
{
|
{
|
||||||
|
@ -1045,30 +922,16 @@ bool DownloadThread::_customizeImage()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (f.open(f.WriteOnly) && f.write(config) == config.length())
|
fat->writeFile("config.txt", config);
|
||||||
{
|
|
||||||
f.close();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
emit error(tr("Error writing to config.txt on FAT partition"));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_initFormat == "auto")
|
if (_initFormat == "auto")
|
||||||
{
|
{
|
||||||
/* Do an attempt at auto-detecting what customization format a custom
|
/* Do an attempt at auto-detecting what customization format a custom
|
||||||
image provided by the user supports */
|
image provided by the user supports */
|
||||||
QByteArray issue;
|
QByteArray issue = fat->readFile("issue.txt");
|
||||||
QFile fi(folder+"/issue.txt");
|
|
||||||
if (fi.exists() && fi.open(fi.ReadOnly))
|
|
||||||
{
|
|
||||||
issue = fi.readAll();
|
|
||||||
fi.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (QFile::exists(folder+"/user-data"))
|
if (fat->fileExists("user-data"))
|
||||||
{
|
{
|
||||||
/* If we have user-data file on FAT partition, then it must be cloudinit */
|
/* If we have user-data file on FAT partition, then it must be cloudinit */
|
||||||
_initFormat = "cloudinit";
|
_initFormat = "cloudinit";
|
||||||
|
@ -1092,98 +955,38 @@ bool DownloadThread::_customizeImage()
|
||||||
|
|
||||||
if (!_firstrun.isEmpty() && _initFormat == "systemd")
|
if (!_firstrun.isEmpty() && _initFormat == "systemd")
|
||||||
{
|
{
|
||||||
QFile f(folder+"/firstrun.sh");
|
fat->writeFile("firstrun.sh", _firstrun);
|
||||||
if (f.open(f.WriteOnly) && f.write(_firstrun) == _firstrun.length())
|
|
||||||
{
|
|
||||||
f.close();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
emit error(tr("Error creating firstrun.sh on FAT partition"));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
_cmdline += " systemd.run=/boot/firstrun.sh systemd.run_success_action=reboot systemd.unit=kernel-command-line.target";
|
_cmdline += " systemd.run=/boot/firstrun.sh systemd.run_success_action=reboot systemd.unit=kernel-command-line.target";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_cloudinit.isEmpty() && _initFormat == "cloudinit")
|
if (!_cloudinit.isEmpty() && _initFormat == "cloudinit")
|
||||||
{
|
{
|
||||||
_cloudinit = "#cloud-config\n"+_cloudinit;
|
_cloudinit = "#cloud-config\n"+_cloudinit;
|
||||||
QFile f(folder+"/user-data");
|
fat->writeFile("user-data", _cloudinit);
|
||||||
if (f.open(f.WriteOnly) && f.write(_cloudinit) == _cloudinit.length())
|
|
||||||
{
|
|
||||||
f.close();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
emit error(tr("Error creating user-data cloudinit file on FAT partition"));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_cloudinitNetwork.isEmpty() && _initFormat == "cloudinit")
|
if (!_cloudinitNetwork.isEmpty() && _initFormat == "cloudinit")
|
||||||
{
|
{
|
||||||
QFile f(folder+"/network-config");
|
fat->writeFile("network-config", _cloudinitNetwork);
|
||||||
if (f.open(f.WriteOnly) && f.write(_cloudinitNetwork) == _cloudinitNetwork.length())
|
|
||||||
{
|
|
||||||
f.close();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
emit error(tr("Error creating network-config cloudinit file on FAT partition"));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_cmdline.isEmpty())
|
if (!_cmdline.isEmpty())
|
||||||
{
|
{
|
||||||
QByteArray cmdline;
|
QByteArray cmdline = fat->readFile("cmdline.txt").trimmed();
|
||||||
|
|
||||||
QFile f(folder+"/cmdline.txt");
|
|
||||||
if (f.exists() && f.open(f.ReadOnly))
|
|
||||||
{
|
|
||||||
cmdline = f.readAll().trimmed();
|
|
||||||
f.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
cmdline += _cmdline;
|
cmdline += _cmdline;
|
||||||
if (f.open(f.WriteOnly) && f.write(cmdline) == cmdline.length())
|
|
||||||
{
|
fat->writeFile("cmdline.txt", cmdline);
|
||||||
f.close();
|
|
||||||
}
|
}
|
||||||
else
|
dw.sync();
|
||||||
|
}
|
||||||
|
catch (std::runtime_error &err)
|
||||||
{
|
{
|
||||||
emit error(tr("Error writing to cmdline.txt on FAT partition"));
|
emit error(err.what());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
emit finalizing();
|
emit finalizing();
|
||||||
|
|
||||||
#ifdef Q_OS_LINUX
|
|
||||||
if (manualmount)
|
|
||||||
{
|
|
||||||
if (::access(devlower.constData(), W_OK) != 0)
|
|
||||||
{
|
|
||||||
#ifndef QT_NO_DBUS
|
|
||||||
UDisks2Api udisks2;
|
|
||||||
udisks2.unmountDrive(devlower);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
QStringList args;
|
|
||||||
args << folder;
|
|
||||||
QProcess::execute("umount", args);
|
|
||||||
QDir d;
|
|
||||||
d.rmdir(folder);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef Q_OS_WIN
|
|
||||||
::sync();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue