diff --git a/src/core/partition.cpp b/src/core/partition.cpp index 5b7c3a0..7ca7d70 100644 --- a/src/core/partition.cpp +++ b/src/core/partition.cpp @@ -1,402 +1,406 @@ /************************************************************************* * Copyright (C) 2008 by Volker Lanz * * Copyright (C) 2015 by Teo Mrnjavac * * Copyright (C) 2016 by Andrius Štikonas * * * * 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 3 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, see .* *************************************************************************/ #include "core/partition.h" #include "core/device.h" #include "fs/filesystem.h" #include "fs/filesystemfactory.h" #include "fs/luks.h" #include "util/externalcommand.h" #include "util/report.h" #include #include #include #include #include #include /** Creates a new Partition object. @param parent the Partition's parent. May be another Partition (for logicals) or a PartitionTable. Must not be nullptr. @param device the Device this Partition is on. @param role the Partition's role(s) @param fs pointer to the Partition's FileSystem object. The Partition object will take ownership of this. @param sectorStart the first sector of the Partition on its Device @param sectorEnd the last sector of the Partition on its Device @param partitionPath the Partition's path, e.g. /dev/sda4 or /dev/mmcblk0p1 @param availableFlags the flags available for this Partition @param mountPoint mount point for this Partition @param mounted true if the Partition is mounted @param activeFlags active flags for this Partition @param state the Partition's state */ Partition::Partition(PartitionNode* parent, const Device& device, const PartitionRole& role, FileSystem* fs, qint64 sectorStart, qint64 sectorEnd, QString partitionPath, PartitionTable::Flags availableFlags, const QString& mountPoint, bool mounted, PartitionTable::Flags activeFlags, State state) : PartitionNode(), m_Children(), m_Parent(parent), m_FileSystem(fs), m_Roles(role), m_FirstSector(sectorStart), m_LastSector(sectorEnd), m_DevicePath(device.deviceNode()), m_MountPoint(mountPoint), m_AvailableFlags(availableFlags), m_ActiveFlags(activeFlags), m_IsMounted(mounted), m_State(state) { setPartitionPath(partitionPath); Q_ASSERT(m_Parent); m_SectorSize = device.logicalSize(); } /** Destroys a Partition, destroying its children and its FileSystem */ Partition::~Partition() { // FIXME: Design flaw: Currently, there are two ways a partition node can get children: Either // they're created and inserted as unallocated in PartitionTable (these unallocated then get // "converted" to real, new partitions in the GUI) or they're created and appended in the // backend plugin. There is however no defined way to remove partitions from parents. This might // either cause leaks (a partition is removed from the parent's list of children but never // deleted) or, worse, crashes (a partition is deleted but not removed from the parent's // list of children). As a workaround, always remove a partition from its parent here in the dtor. // This presumably fixes 232092, but backporting is too risky until we're sure this doesn't cause // side-effects. if (m_Parent) parent()->remove(this); clearChildren(); deleteFileSystem(); } /** @param other Partition to copy */ Partition::Partition(const Partition& other, PartitionNode* parent) : PartitionNode(), m_Children(), m_Parent(other.m_Parent), m_FileSystem(FileSystemFactory::create(other.fileSystem())), m_Roles(other.m_Roles), m_FirstSector(other.m_FirstSector), m_LastSector(other.m_LastSector), m_DevicePath(other.m_DevicePath), + m_Label(other.m_Label), + m_UUID(other.m_UUID), m_MountPoint(other.m_MountPoint), m_AvailableFlags(other.m_AvailableFlags), m_ActiveFlags(other.m_ActiveFlags), m_IsMounted(other.m_IsMounted), m_SectorSize(other.m_SectorSize), m_State(other.m_State) { if ( parent ) m_Parent = parent; setPartitionPath(other.m_PartitionPath); for (const auto &child : other.children()) { Partition* p = new Partition(*child, this); m_Children.append(p); } } /** @param other Partition to assign from */ Partition& Partition::operator=(const Partition& other) { if (&other == this) return *this; clearChildren(); for (const auto &child : other.children()) { Partition* p = new Partition(*child); p->setParent(this); m_Children.append(p); } m_Number = other.m_Number; m_FileSystem = FileSystemFactory::create(other.fileSystem()); m_Roles = other.m_Roles; m_FirstSector = other.m_FirstSector; m_LastSector = other.m_LastSector; m_DevicePath = other.m_DevicePath; + m_Label = other.m_Label; + m_UUID = other.m_UUID; m_PartitionPath = other.m_PartitionPath; m_MountPoint = other.m_MountPoint; m_AvailableFlags = other.m_AvailableFlags; m_ActiveFlags = other.m_ActiveFlags; m_IsMounted = other.m_IsMounted; m_SectorSize = other.m_SectorSize; m_State = other.m_State; return *this; } bool Partition::operator==(const Partition& other) const { return other.deviceNode() == deviceNode(); } bool Partition::operator!=(const Partition& other) const { return !(other == *this); } /** @return a short descriptive text or, in case the Partition has StateNone, its device node. */ QString Partition::deviceNode() const { if (roles().has(PartitionRole::None) || roles().has(PartitionRole::Unallocated)) return xi18nc("@item partition name", "unallocated"); if (state() == StateNew) return xi18nc("@item partition name", "New Partition"); if (state() == StateRestore) return xi18nc("@item partition name", "Restored Partition"); if (state() == StateCopy) return xi18nc("@item partition name", "Copy of %1", partitionPath()); return partitionPath(); } /** @return the sectors used in the Partition's FileSystem or, in case of an extended partition, the sum of used sectors of the Partition's children */ qint64 Partition::sectorsUsed() const { // Make sure file system exists. In some cases (due to bugs elsewhere?) file system pointer did not exist, especially for unallocated space. if (m_FileSystem == nullptr) return -1; if (!roles().has(PartitionRole::Extended)) return fileSystem().sectorsUsed(); qint64 result = 0; for (const auto &p : children()) if (!p->roles().has(PartitionRole::Unallocated)) result += p->length(); return result; } /** @return the minimum number of sectors this Partition must be long */ qint64 Partition::minimumSectors() const { if (roles().has(PartitionRole::Luks)) return ( fileSystem().minCapacity() + (4096 * 512) ) / sectorSize(); // 4096 is the default cryptsetup payload offset return fileSystem().minCapacity() / sectorSize(); } /** @return the maximum number of sectors this Partition may be long */ qint64 Partition::maximumSectors() const { return fileSystem().maxCapacity() / sectorSize(); } /** Adjusts the numbers of logical Partitions for an extended Partition. This is required if a logical Partition is deleted or inserted because logicals must be numberd from 5 onwards without a gap. So if the user deletes Partition number 7 and there is a number 8, 8 becomes the "new" 7. And since this happens somewhere in the middle of a DeleteOperation, we have to adjust to that so the next Job still finds the Partition it wants to deal with. @param deletedNumber the number of a deleted logical or -1 if none has been deleted @param insertedNumber the number of an inserted logical or -1 if none has been inserted */ void Partition::adjustLogicalNumbers(qint32 deletedNumber, qint32 insertedNumber) const { if (!roles().has(PartitionRole::Extended)) return; for (const auto &p : children()) { QString path = p->partitionPath(); path.remove(QRegularExpression(QStringLiteral("(\\d+$)"))); if (deletedNumber > 4 && p->number() > deletedNumber) p->setPartitionPath(path + QString::number(p->number() - 1)); else if (insertedNumber > 4 && p->number() >= insertedNumber) p->setPartitionPath(path + QString::number(p->number() + 1)); } } /** @return the highest sector number an extended Partition can begin at */ qint64 Partition::maxFirstSector() const { qint64 rval = -1; for (const auto &child : children()) if (!child->roles().has(PartitionRole::Unallocated) && (child->firstSector() < rval || rval == -1)) rval = child->firstSector(); return rval; } /** @return the lowest sector number an extended Partition can end at */ qint64 Partition::minLastSector() const { qint64 rval = -1; for (const auto &child : children()) if (!child->roles().has(PartitionRole::Unallocated) && child->lastSector() > rval) rval = child->lastSector(); return rval; } /** @return true if the Partition has children */ bool Partition::hasChildren() const { for (const auto &child : children()) if (!child->roles().has(PartitionRole::Unallocated)) return true; return false; } /** Sets an extended Partition to mounted if any of its children are mounted */ void Partition::checkChildrenMounted() { setMounted(isChildMounted()); } /** @return true if this Partition can be mounted */ bool Partition::canMount() const { // cannot mount if already mounted if (isMounted()) { return false; } if (fileSystem().canMount(deviceNode(), mountPoint())) { return true; } return false; } /** @return true if this Partition can be unmounted */ bool Partition::canUnmount() const { return !roles().has(PartitionRole::Extended) && isMounted() && fileSystem().canUnmount(deviceNode()); } void Partition::setMounted(bool b) { m_IsMounted = b; if (roles().has(PartitionRole::Luks)) static_cast(m_FileSystem)->setMounted(b); } /** Tries to mount a Partition. @return true on success */ bool Partition::mount(Report& report) { if (isMounted()) return false; bool success = false; if (fileSystem().canMount(deviceNode(), mountPoint())) { success = fileSystem().mount(report, deviceNode(), mountPoint()); } setMounted(success); return success; } /** Tries to unmount a Partition. @return true on success */ bool Partition::unmount(Report& report) { if (!isMounted()) return false; bool success = false; if (fileSystem().canUnmount(deviceNode())) { success = fileSystem().unmount(report, deviceNode()); } const QString canonicalDeviceNode = QFileInfo(deviceNode()).canonicalFilePath(); const QList mountedVolumes = QStorageInfo::mountedVolumes(); for (const QStorageInfo &storage : mountedVolumes) { if (QFileInfo(QString::fromLocal8Bit(storage.device())).canonicalFilePath() == canonicalDeviceNode ) { success = false; break; } } setMounted(!success); return success; } void Partition::deleteFileSystem() { delete m_FileSystem; m_FileSystem = nullptr; } void Partition::setPartitionPath(const QString& s) { m_PartitionPath = s; QRegularExpression re(QStringLiteral("(\\d+$)")); QRegularExpressionMatch rePartitionNumber = re.match(partitionPath()); if (rePartitionNumber.hasMatch()) { setNumber(rePartitionNumber.captured().toInt()); return; } setNumber(-1); } void Partition::setFileSystem(FileSystem* fs) { m_FileSystem = fs; } void Partition::move(qint64 newStartSector) { const qint64 savedLength = length(); setFirstSector(newStartSector); setLastSector(newStartSector + savedLength - 1); } QTextStream& operator<<(QTextStream& stream, const Partition& p) { QStringList flagList; for (const auto &f : PartitionTable::flagList()) { if (p.activeFlags() & f) flagList.append(PartitionTable::flagName(f)); } const QString sep(QStringLiteral(";")); // number - start - end - type - roles - label - flags stream << p.number() << sep << p.firstSector() << sep << p.lastSector() << sep << p.fileSystem().name({ QStringLiteral("C") }) << sep << p.roles().toString({ QStringLiteral("C") }) << sep << "\"" << p.fileSystem().label() << QStringLiteral("\"") << sep << "\"" << flagList.join(QStringLiteral(",")) << QStringLiteral("\"") << "\n"; return stream; } diff --git a/src/plugins/sfdisk/sfdiskbackend.cpp b/src/plugins/sfdisk/sfdiskbackend.cpp index 6571bec..57a510d 100644 --- a/src/plugins/sfdisk/sfdiskbackend.cpp +++ b/src/plugins/sfdisk/sfdiskbackend.cpp @@ -1,435 +1,435 @@ /************************************************************************* * Copyright (C) 2017 by Andrius Štikonas * * * * 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 3 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, see .* *************************************************************************/ /** @file */ #include "plugins/sfdisk/sfdiskbackend.h" #include "plugins/sfdisk/sfdiskdevice.h" #include "core/diskdevice.h" #include "core/lvmdevice.h" #include "core/partitiontable.h" #include "core/partitionalignment.h" #include "fs/filesystemfactory.h" #include "fs/luks.h" #include "fs/luks2.h" #include "util/globallog.h" #include "util/externalcommand.h" #include "util/helpers.h" #include #include #include #include #include #include #include #include #include #include #include #include K_PLUGIN_FACTORY_WITH_JSON(SfdiskBackendFactory, "pmsfdiskbackendplugin.json", registerPlugin();) SfdiskBackend::SfdiskBackend(QObject*, const QList&) : CoreBackend() { } void SfdiskBackend::initFSSupport() { } QList SfdiskBackend::scanDevices(bool excludeReadOnly) { // TODO: add another bool option for loopDevices QList result; QStringList deviceNodes; ExternalCommand cmd(QStringLiteral("lsblk"), { QStringLiteral("--nodeps"), QStringLiteral("--paths"), QStringLiteral("--sort"), QStringLiteral("name"), QStringLiteral("--json"), QStringLiteral("--output"), QStringLiteral("type,name") }); if (cmd.run(-1) && cmd.exitCode() == 0) { const QJsonDocument jsonDocument = QJsonDocument::fromJson(cmd.rawOutput()); const QJsonObject jsonObject = jsonDocument.object(); const QJsonArray jsonArray = jsonObject[QLatin1String("blockdevices")].toArray(); for (const auto &deviceLine : jsonArray) { QJsonObject deviceObject = deviceLine.toObject(); if (deviceObject[QLatin1String("type")].toString() != QLatin1String("disk")) continue; const QString deviceNode = deviceObject[QLatin1String("name")].toString(); if (excludeReadOnly) { QString deviceName = deviceNode; deviceName.remove(QStringLiteral("/dev/")); QFile f(QStringLiteral("/sys/block/%1/ro").arg(deviceName)); if (f.open(QIODevice::ReadOnly)) if (f.readLine().trimmed().toInt() == 1) continue; } deviceNodes << deviceNode; } int totalDevices = deviceNodes.length(); for (int i = 0; i < totalDevices; ++i) { const QString deviceNode = deviceNodes[i]; emitScanProgress(deviceNode, i * 100 / totalDevices); Device* device = scanDevice(deviceNode); if (device != nullptr) { result.append(device); } } LvmDevice::scanSystemLVM(result); } return result; } /** Create a Device for the given device_node and scan it for partitions. @param deviceNode the device node (e.g. "/dev/sda") @return the created Device object. callers need to free this. */ Device* SfdiskBackend::scanDevice(const QString& deviceNode) { ExternalCommand modelCommand(QStringLiteral("lsblk"), { QStringLiteral("--nodeps"), QStringLiteral("--noheadings"), QStringLiteral("--output"), QStringLiteral("model"), deviceNode }); ExternalCommand sizeCommand(QStringLiteral("blockdev"), { QStringLiteral("--getsize64"), deviceNode }); ExternalCommand sizeCommand2(QStringLiteral("blockdev"), { QStringLiteral("--getss"), deviceNode }); ExternalCommand jsonCommand(QStringLiteral("sfdisk"), { QStringLiteral("--json"), deviceNode } ); if ( modelCommand.run(-1) && modelCommand.exitCode() == 0 && sizeCommand.run(-1) && sizeCommand.exitCode() == 0 && sizeCommand2.run(-1) && sizeCommand2.exitCode() == 0 && jsonCommand.run(-1) ) { QString modelName = modelCommand.output(); modelName = modelName.left(modelName.length() - 1); qint64 deviceSize = sizeCommand.output().trimmed().toLongLong(); Log(Log::information) << xi18nc("@info:status", "Device found: %1", modelName); int logicalSectorSize = sizeCommand2.output().trimmed().toLongLong(); DiskDevice* d = new DiskDevice(modelName, deviceNode, 255, 63, deviceSize / logicalSectorSize / 255 / 63, logicalSectorSize); if (jsonCommand.exitCode() != 0) return d; const QJsonObject jsonObject = QJsonDocument::fromJson(jsonCommand.rawOutput()).object(); const QJsonObject partitionTable = jsonObject[QLatin1String("partitiontable")].toObject(); QString tableType = partitionTable[QLatin1String("label")].toString(); const PartitionTable::TableType type = PartitionTable::nameToTableType(tableType); qint64 firstUsableSector = 0, lastUsableSector = d->totalSectors(); if (type == PartitionTable::gpt) { firstUsableSector = partitionTable[QLatin1String("firstlba")].toVariant().toLongLong(); lastUsableSector = partitionTable[QLatin1String("lastlba")].toVariant().toLongLong(); } if (lastUsableSector < firstUsableSector) { return nullptr; } setPartitionTableForDevice(*d, new PartitionTable(type, firstUsableSector, lastUsableSector)); switch (type) { case PartitionTable::gpt: { // Read the maximum number of GPT partitions qint32 maxEntries; ExternalCommand ddCommand(QStringLiteral("dd"), { QStringLiteral("skip=1"), QStringLiteral("count=1"), QStringLiteral("if=") + deviceNode}, QProcess::SeparateChannels); if (ddCommand.run(-1) && ddCommand.exitCode() == 0 ) { QByteArray gptHeader = ddCommand.rawOutput(); QByteArray gptMaxEntries = gptHeader.mid(80, 4); QDataStream stream(&gptMaxEntries, QIODevice::ReadOnly); stream.setByteOrder(QDataStream::LittleEndian); stream >> maxEntries; } else maxEntries = 128; CoreBackend::setPartitionTableMaxPrimaries(*d->partitionTable(), maxEntries); } default: break; } scanDevicePartitions(*d, partitionTable[QLatin1String("partitions")].toArray()); return d; } return nullptr; } /** Scans a Device for Partitions. This method will scan a Device for all Partitions on it, detect the FileSystem for each Partition, try to determine the FileSystem usage, read the FileSystem label and store it all in newly created objects that are in the end added to the Device's PartitionTable. */ void SfdiskBackend::scanDevicePartitions(Device& d, const QJsonArray& jsonPartitions) { Q_ASSERT(d.partitionTable()); QList partitions; for (const auto &partition : jsonPartitions) { const QJsonObject partitionObject = partition.toObject(); const QString partitionNode = partitionObject[QLatin1String("node")].toString(); const qint64 start = partitionObject[QLatin1String("start")].toVariant().toLongLong(); const qint64 size = partitionObject[QLatin1String("size")].toVariant().toLongLong(); const QString partitionType = partitionObject[QLatin1String("type")].toString(); PartitionTable::Flag activeFlags = partitionObject[QLatin1String("bootable")].toBool() ? PartitionTable::FlagBoot : PartitionTable::FlagNone; if (partitionType == QStringLiteral("C12A7328-F81F-11D2-BA4B-00A0C93EC93B")) activeFlags = PartitionTable::FlagEsp; else if (partitionType == QStringLiteral("21686148-6449-6E6F-744E-656564454649")) activeFlags = PartitionTable::FlagBiosGrub; FileSystem::Type type = FileSystem::Unknown; type = detectFileSystem(partitionNode); PartitionRole::Roles r = PartitionRole::Primary; if ( (d.partitionTable()->type() == PartitionTable::msdos || d.partitionTable()->type() == PartitionTable::msdos_sectorbased) && partitionType.toInt() == 5 ) { r = PartitionRole::Extended; type = FileSystem::Extended; } // Find an extended partition this partition is in. PartitionNode* parent = d.partitionTable()->findPartitionBySector(start, PartitionRole(PartitionRole::Extended)); // None found, so it's a primary in the device's partition table. if (parent == nullptr) parent = d.partitionTable(); else r = PartitionRole::Logical; FileSystem* fs = FileSystemFactory::create(type, start, start + size - 1, d.logicalSize()); fs->scan(partitionNode); QString mountPoint; bool mounted; // sfdisk does not handle LUKS partitions if (fs->type() == FileSystem::Luks || fs->type() == FileSystem::Luks2) { r |= PartitionRole::Luks; FS::luks* luksFs = static_cast(fs); luksFs->initLUKS(); QString mapperNode = luksFs->mapperName(); mountPoint = FileSystem::detectMountPoint(fs, mapperNode); mounted = FileSystem::detectMountStatus(fs, mapperNode); } else { mountPoint = FileSystem::detectMountPoint(fs, partitionNode); mounted = FileSystem::detectMountStatus(fs, partitionNode); } Partition* part = new Partition(parent, d, PartitionRole(r), fs, start, start + size - 1, partitionNode, availableFlags(d.partitionTable()->type()), mountPoint, mounted, activeFlags); if (!part->roles().has(PartitionRole::Luks)) readSectorsUsed(d, *part, mountPoint); if (fs->supportGetLabel() != FileSystem::cmdSupportNone) fs->setLabel(fs->readLabel(part->deviceNode())); if (d.partitionTable()->type() == PartitionTable::TableType::gpt) { part->setLabel(partitionObject[QLatin1String("name")].toString()); part->setUUID(partitionObject[QLatin1String("uuid")].toString()); } if (fs->supportGetUUID() != FileSystem::cmdSupportNone) fs->setUUID(fs->readUUID(part->deviceNode())); parent->append(part); partitions.append(part); } d.partitionTable()->updateUnallocated(d); if (d.partitionTable()->isSectorBased(d)) d.partitionTable()->setType(d, PartitionTable::msdos_sectorbased); for (const Partition * part : qAsConst(partitions)) PartitionAlignment::isAligned(d, *part); } /** Reads the sectors used in a FileSystem and stores the result in the Partition's FileSystem object. @param p the Partition the FileSystem is on @param mountPoint mount point of the partition in question */ void SfdiskBackend::readSectorsUsed(const Device& d, Partition& p, const QString& mountPoint) { if (!mountPoint.isEmpty() && p.fileSystem().type() != FileSystem::LinuxSwap && p.fileSystem().type() != FileSystem::Lvm2_PV) { const QStorageInfo storage = QStorageInfo(mountPoint); if (p.isMounted() && storage.isValid()) p.fileSystem().setSectorsUsed( (storage.bytesTotal() - storage.bytesFree()) / d.logicalSize()); } else if (p.fileSystem().supportGetUsed() == FileSystem::cmdSupportFileSystem) p.fileSystem().setSectorsUsed(p.fileSystem().readUsedCapacity(p.deviceNode()) / d.logicalSize()); } FileSystem::Type SfdiskBackend::detectFileSystem(const QString& partitionPath) { FileSystem::Type rval = FileSystem::Unknown; ExternalCommand udevCommand(QStringLiteral("udevadm"), { QStringLiteral("info"), QStringLiteral("--query=property"), partitionPath }); if (udevCommand.run(-1) && udevCommand.exitCode() == 0) { QRegularExpression re(QStringLiteral("ID_FS_TYPE=(\\w+)")); QRegularExpression re2(QStringLiteral("ID_FS_VERSION=(\\w+)")); QRegularExpressionMatch reFileSystemType = re.match(udevCommand.output()); QRegularExpressionMatch reFileSystemVersion = re2.match(udevCommand.output()); QString s; if (reFileSystemType.hasMatch()) { s = reFileSystemType.captured(1); } QString version; if (reFileSystemVersion.hasMatch()) { version = reFileSystemVersion.captured(1); } if (s == QStringLiteral("ext2")) rval = FileSystem::Ext2; else if (s == QStringLiteral("ext3")) rval = FileSystem::Ext3; else if (s.startsWith(QStringLiteral("ext4"))) rval = FileSystem::Ext4; else if (s == QStringLiteral("swap")) rval = FileSystem::LinuxSwap; else if (s == QStringLiteral("ntfs-3g")) rval = FileSystem::Ntfs; else if (s == QStringLiteral("reiserfs")) rval = FileSystem::ReiserFS; else if (s == QStringLiteral("reiser4")) rval = FileSystem::Reiser4; else if (s == QStringLiteral("xfs")) rval = FileSystem::Xfs; else if (s == QStringLiteral("jfs")) rval = FileSystem::Jfs; else if (s == QStringLiteral("hfs")) rval = FileSystem::Hfs; else if (s == QStringLiteral("hfsplus")) rval = FileSystem::HfsPlus; else if (s == QStringLiteral("ufs")) rval = FileSystem::Ufs; else if (s == QStringLiteral("vfat")) { if (version == QStringLiteral("FAT32")) rval = FileSystem::Fat32; else if (version == QStringLiteral("FAT16")) rval = FileSystem::Fat16; else if (version == QStringLiteral("FAT12")) rval = FileSystem::Fat12; } else if (s == QStringLiteral("btrfs")) rval = FileSystem::Btrfs; else if (s == QStringLiteral("ocfs2")) rval = FileSystem::Ocfs2; else if (s == QStringLiteral("zfs_member")) rval = FileSystem::Zfs; else if (s == QStringLiteral("hpfs")) rval = FileSystem::Hpfs; else if (s == QStringLiteral("crypto_LUKS")) { if (version == QStringLiteral("1")) rval = FileSystem::Luks; else if (version == QStringLiteral("2")) { rval = FileSystem::Luks2; } } else if (s == QStringLiteral("exfat")) rval = FileSystem::Exfat; else if (s == QStringLiteral("nilfs2")) rval = FileSystem::Nilfs2; else if (s == QStringLiteral("LVM2_member")) rval = FileSystem::Lvm2_PV; else if (s == QStringLiteral("f2fs")) rval = FileSystem::F2fs; else if (s == QStringLiteral("udf")) rval = FileSystem::Udf; else if (s == QStringLiteral("iso9660")) rval = FileSystem::Iso9660; else qWarning() << "unknown file system type " << s << " on " << partitionPath; } return rval; } QString SfdiskBackend::readLabel(const QString& deviceNode) const { ExternalCommand udevCommand(QStringLiteral("udevadm"), { QStringLiteral("info"), QStringLiteral("--query=property"), deviceNode }); udevCommand.run(); - QRegularExpression re(QStringLiteral("ID_FS_LABEL=(\\w+)")); + QRegularExpression re(QStringLiteral("ID_FS_LABEL=(.*)")); QRegularExpressionMatch reFileSystemLabel = re.match(udevCommand.output()); if (reFileSystemLabel.hasMatch()) return reFileSystemLabel.captured(1); return QString(); } QString SfdiskBackend::readUUID(const QString& deviceNode) const { ExternalCommand udevCommand(QStringLiteral("udevadm"), { QStringLiteral("info"), QStringLiteral("--query=property"), deviceNode }); udevCommand.run(); - QRegularExpression re(QStringLiteral("ID_FS_UUID=(\\w+)")); + QRegularExpression re(QStringLiteral("ID_FS_UUID=(.*)")); QRegularExpressionMatch reFileSystemUUID = re.match(udevCommand.output()); if (reFileSystemUUID.hasMatch()) return reFileSystemUUID.captured(1); return QString(); } PartitionTable::Flags SfdiskBackend::availableFlags(PartitionTable::TableType type) { PartitionTable::Flags flags; if (type == PartitionTable::gpt) { // These are not really flags but for now keep them for compatibility // We should implement changing partition type flags = PartitionTable::FlagBiosGrub | PartitionTable::FlagEsp; } else if (type == PartitionTable::msdos || type == PartitionTable::msdos_sectorbased) flags = PartitionTable::FlagBoot; return flags; } CoreBackendDevice* SfdiskBackend::openDevice(const Device& d) { SfdiskDevice* device = new SfdiskDevice(d); if (device == nullptr || !device->open()) { delete device; device = nullptr; } return device; } CoreBackendDevice* SfdiskBackend::openDeviceExclusive(const Device& d) { SfdiskDevice* device = new SfdiskDevice(d); if (device == nullptr || !device->openExclusive()) { delete device; device = nullptr; } return device; } bool SfdiskBackend::closeDevice(CoreBackendDevice* coreDevice) { return coreDevice->close(); } #include "sfdiskbackend.moc"