diff --git a/src/core/partition.h b/src/core/partition.h index 63f604d..c675c10 100644 --- a/src/core/partition.h +++ b/src/core/partition.h @@ -1,281 +1,281 @@ /************************************************************************* * Copyright (C) 2008 by Volker Lanz * * * * 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 .* *************************************************************************/ #ifndef KPMCORE_PARTITION_H #define KPMCORE_PARTITION_H #include "core/partitionnode.h" #include "core/partitionrole.h" #include "core/partitiontable.h" #include "util/libpartitionmanagerexport.h" #include #include #include class Device; class OperationStack; class CoreBackendPartitionTable; class PartitionAlignment; class PartResizerWidget; class ResizeDialog; class InsertDialog; class NewDialog; class EditMountPointDialog; class PartPropsDialog; class SizeDialogBase; class CreateFileSystemOperation; class RestoreOperation; class SetPartFlagsOperation; class CopyOperation; class NewOperation; class ResizeOperation; class SetPartGeometryJob; class CreatePartitionJob; class SetPartFlagsJob; class RestoreFileSystemJob; class FileSystem; class Report; class QString; class QTextStream; /** A partition or some unallocated space on a Device. Represent partitions in a PartitionTable on a Device. Partitions can be unallocated, thus not all instances really are partitions in the way the user would see them. Extended partitions have child objects that represent the logicals inside them. @see PartitionTable, Device, FileSystem @author Volker Lanz */ class LIBKPMCORE_EXPORT Partition : public PartitionNode { public: /** A Partition state -- where did it come from? */ enum State { None, /**< exists on disk */ New, /**< from a NewOperation */ Copy, /**< from a CopyOperation */ Restore, /**< from a RestoreOperation */ - StateNone __attribute__((deprecated("Use Partition::State::None"))) = None, - StateNew __attribute__((deprecated("Use Partition::State::New"))) = New, - StateCopy __attribute__((deprecated("Use Partition::State::Copy"))) = Copy, - StateRestore __attribute__((deprecated("Use Partition::State::Restore"))) = Restore + StateNone = None, + StateNew = New, + StateCopy = Copy, + StateRestore = Restore }; Partition(PartitionNode* parent, const Device& device, const PartitionRole& role, FileSystem* fs, qint64 sectorStart, qint64 sectorEnd, QString partitionPath, PartitionTable::Flags availableFlags = PartitionTable::FlagNone, const QString& mountPoint = QString(), bool mounted = false, PartitionTable::Flags activeFlags = PartitionTable::FlagNone, State state = State::None); ~Partition() override; Partition(const Partition& other, PartitionNode* parent = nullptr); Partition& operator=(const Partition&); bool operator==(const Partition& other) const; bool operator!=(const Partition& other) const; qint32 number() const { return m_Number; /**< @return the Partition's device number, e.g. 7 for /dev/sdd7 */ } bool isRoot() const override { return false; /**< @return always false for Partition */ } PartitionNode* parent() override { return m_Parent; /**< @return the Partition's parent PartitionNode */ } const PartitionNode* parent() const override { return m_Parent; /**< @return the Partition's parent PartitionNode */ } Partitions& children() override { return m_Children; /**< @return the Partition's children. empty for non-extended. */ } const Partitions& children() const override { return m_Children; /**< @return the Partition's children. empty for non-extended. */ } const QString& devicePath() const { return m_DevicePath; /**< @return the Partition's device path, e.g. /dev/sdd */ } const QString& partitionPath() const { return m_PartitionPath; /**< @return the Partition's path, e.g. /dev/sdd1 */ } const QString& label() const { return m_Label; /**< @return the GPT Partition label */ } const QString& uuid() const { return m_UUID; /**< @return the GPT Partition UUID */ } qint64 firstSector() const { return m_FirstSector; /**< @return the Partition's first sector on the Device */ } qint64 lastSector() const { return m_LastSector; /**< @return the Partition's last sector on the Device */ } qint64 firstByte() const { return firstSector() * sectorSize(); /**< @return the Partition's first byte on the Device */ } qint64 lastByte() const { return firstByte() + length() * sectorSize() - 1; /**< @return the Partition's last byte on the Device */ } qint64 sectorsUsed() const; qint64 sectorSize() const { return m_SectorSize; /**< @return the sector size on the Partition's Device */ } qint64 length() const { return lastSector() - firstSector() + 1; /**< @return the length of the Partition */ } qint64 capacity() const { return length() * sectorSize(); /**< @return the capacity of the Partition in bytes */ } qint64 used() const { return sectorsUsed() < 0 ? -1 : sectorsUsed() * sectorSize(); /**< @return the number of used sectors in the Partition's FileSystem */ } qint64 available() const { return sectorsUsed() < 0 ? -1 : capacity() - used(); /**< @return the number of free sectors in the Partition's FileSystem */ } qint64 minimumSectors() const; qint64 maximumSectors() const; qint64 maxFirstSector() const; qint64 minLastSector() const; QString deviceNode() const; const PartitionRole& roles() const { return m_Roles; /**< @return the Partition's role(s) */ } const QString& mountPoint() const { return m_MountPoint; /**< @return the Partition's mount point */ } PartitionTable::Flags activeFlags() const { return m_ActiveFlags; /**< @return the flags currently set for this Partition */ } PartitionTable::Flags availableFlags() const { return m_AvailableFlags; /**< @return the flags available for this Partition */ } bool isMounted() const { return m_IsMounted; /**< @return true if Partition is mounted */ } FileSystem& fileSystem() { return *m_FileSystem; /**< @return the Partition's FileSystem */ } const FileSystem& fileSystem() const { return *m_FileSystem; /**< @return the Partition's FileSystem */ } State state() const { return m_State; /**< @return the Partition's state */ } bool hasChildren() const; bool mount(Report& report); bool unmount(Report& report); bool canMount() const; bool canUnmount() const; void adjustLogicalNumbers(qint32 deletedNumber, qint32 insertedNumber) const; void checkChildrenMounted(); void setFirstSector(qint64 s) { m_FirstSector = s; } void setLastSector(qint64 s) { m_LastSector = s; } void setLabel(const QString& s) { m_Label = s; /**< @param s the new label */ } void setUUID(const QString& s) { m_UUID = s; /**< @param s the new UUID */ } void append(Partition* p) override { m_Children.append(p); std::sort(m_Children.begin(), m_Children.end(), [] (const Partition *a, const Partition *b) -> bool {return a->firstSector() < b->firstSector();}); } void setDevicePath(const QString& s) { m_DevicePath = s; } void setPartitionPath(const QString& s); void setRoles(const PartitionRole& r) { m_Roles = r; } void setMountPoint(const QString& s) { m_MountPoint = s; } void setFlags(PartitionTable::Flags f) { m_ActiveFlags = f; } void setSectorSize(qint32 s) { m_SectorSize = s; } void move(qint64 newStartSector); void setMounted(bool b); void setFlag(PartitionTable::Flag f) { m_ActiveFlags |= f; } void unsetFlag(PartitionTable::Flag f) { m_ActiveFlags &= ~f; } void setParent(PartitionNode* p) { m_Parent = p; } void setFileSystem(FileSystem* fs); void setState(State s) { m_State = s; } void deleteFileSystem(); private: void setNumber(qint32 n) { m_Number = n; } qint32 m_Number; Partitions m_Children; QPointer< PartitionNode > m_Parent; FileSystem* m_FileSystem; PartitionRole m_Roles; qint64 m_FirstSector; qint64 m_LastSector; QString m_DevicePath; QString m_Label; QString m_UUID; QString m_PartitionPath; QString m_MountPoint; PartitionTable::Flags m_AvailableFlags; PartitionTable::Flags m_ActiveFlags; bool m_IsMounted; qint64 m_SectorSize; State m_State; }; QTextStream& operator<<(QTextStream& stream, const Partition& p); #endif diff --git a/src/plugins/dummy/pmdummybackendplugin.json b/src/plugins/dummy/pmdummybackendplugin.json index f79b94b..055d483 100644 --- a/src/plugins/dummy/pmdummybackendplugin.json +++ b/src/plugins/dummy/pmdummybackendplugin.json @@ -1,51 +1,54 @@ { "KPlugin": { "Authors": [ { "Email": "vl@fidra.de", "Name": "Volker Lanz", "Name[x-test]": "xxVolker Lanzxx" } ], "Category": "BackendPlugin", "Description": "A KDE Partition Manager dummy backend for testing purposes.", "Description[ca@valencia]": "Un dorsal fals del gestor de particions del KDE amb la finalitat de fer proves.", "Description[ca]": "Un dorsal fals del gestor de particions del KDE amb la finalitat de fer proves.", "Description[de]": "Ein Dummy-Backend für die KDE-Partitionsverwaltung zu Testzwecken.", "Description[es]": "Un motor de simulación para el gestor de particiones de KDE para hacer pruebas.", + "Description[gl]": "Unha infraestrutura de probas para o xestor de particións de KDE.", + "Description[it]": "Un motore fittizio del gestore delle partizioni di KDE per scopi di prova.", "Description[nl]": "Dummy backend van KDE-partitiebeheerder voor testdoeleinden", "Description[pt]": "Uma infra-estrutura de testes para o Gestor de Partições do KDE.", "Description[sk]": "Testovací program v pozadí KDE Správcu partícií", "Description[sv]": "Ett bakgrundsprogram till KDE:s partitionshanterare i testsyfte.", "Description[uk]": "Тестовий додаток сервера Керування розділами KDE.", "Description[x-test]": "xxA KDE Partition Manager dummy backend for testing purposes.xx", "Description[zh_CN]": "测试用的 KDE 分区管理器的虚拟后端", "EnabledByDefault": true, "Icon": "preferences-plugin", "Id": "pmdummybackendplugin", "License": "GPL", "Name": "KDE Partition Manager Dummy Backend", "Name[ca@valencia]": "Dorsal fals del gestor de particions del KDE", "Name[ca]": "Dorsal fals del gestor de particions del KDE", "Name[cs]": "Podpůrná vrstva pro správce diskových oddílů pro KDE", "Name[de]": "KDE-Partitionsverwaltung Dummy-Backend", "Name[es]": "Motor de simulación para el gestor de particiones de KDE", "Name[fi]": "KDE:n osionhallinnan valetaustaosa", "Name[fr]": "Moteur de test pour le gestionnaire de partitions de KDE", + "Name[gl]": "Infraestrutura de probas para o xestor de particións de KDE", "Name[id]": "Backend Tiruan Pengelola Partisi KDE", "Name[it]": "Motore fittizio del gestore delle partizioni di KDE", "Name[nb]": "Attrapp-motor for KDE partisjonsbehandler", "Name[nl]": "Dummy backend van KDE-partitiebeheerder", "Name[pt]": "Infra-Estrutura de Testes para o Gestor de Partições do KDE", "Name[sk]": "Testovací program v pozadí KDE Správcu partícií", "Name[sv]": "KDE:s partitionshanterare bakgrundsprogram för test", "Name[uk]": "Тестовий додаток сервера Керування розділами KDE", "Name[x-test]": "xxKDE Partition Manager Dummy Backendxx", "Name[zh_CN]": "KDE 分区管理器虚拟后端", "ServiceTypes": [ "PartitionManager/Plugin" ], "Version": "1", "Website": "http://www.partitionmanager.org" } } diff --git a/src/plugins/sfdisk/pmsfdiskbackendplugin.json b/src/plugins/sfdisk/pmsfdiskbackendplugin.json index 94274dd..e2009db 100644 --- a/src/plugins/sfdisk/pmsfdiskbackendplugin.json +++ b/src/plugins/sfdisk/pmsfdiskbackendplugin.json @@ -1,44 +1,47 @@ { "KPlugin": { "Authors": [ { "Email": "andrius@stikonas.eu", "Name": "Andrius Štikonas", "Name[x-test]": "xxAndrius Štikonasxx" } ], "Category": "BackendPlugin", "Description": "A KDE Partition Manager sfdisk backend.", "Description[ca@valencia]": "Un dorsal «sfdisk» del gestor de particions del KDE.", "Description[ca]": "Un dorsal «sfdisk» del gestor de particions del KDE.", "Description[de]": "Ein sfdisk-Backend für die KDE-Partitionsverwaltung.", "Description[es]": "Motor sfdisk para el gestor de particiones de KDE.", + "Description[gl]": "Unha infraestrutura de sfdisk para o xestor de particións de KDE.", + "Description[it]": "Un motore sfdisk del gestore delle partizioni di KDE.", "Description[nl]": "Een sfdisk backend van KDE-partitiebeheerder.", "Description[pt]": "A infra-estrutura do 'sfdisk' para o Gestor de Partições do KDE.", "Description[sk]": "Backend KDE správcu partícií sfdisk.", "Description[sv]": "Ett sfdisk bakgrundsprogram till KDE:s partitionshanterare", "Description[uk]": "Додаток sfdisk сервера Керування розділами KDE.", "Description[x-test]": "xxA KDE Partition Manager sfdisk backend.xx", "EnabledByDefault": true, "Icon": "preferences-plugin", "Id": "pmsfdiskbackendplugin", "License": "GPL", "Name": "KDE Partition Manager sfdisk Backend", "Name[ca@valencia]": "Dorsal «sfdisk» del gestor de particions del KDE", "Name[ca]": "Dorsal «sfdisk» del gestor de particions del KDE", "Name[de]": "KDE-Partitionsverwaltung sfdisk-Backend", "Name[es]": "Motor sfdisk para el gestor de particiones de KDE", + "Name[gl]": "Infraestrutura de sfdisk para o xestor de particións de KDE", "Name[it]": "Motore sfdisk del gestore delle partizioni di KDE", "Name[nl]": "Sfdisk backend van KDE-partitiebeheerder", "Name[pt]": "Infra-Estrutura do Sfdisk para o Gestor de Partições do KDE", "Name[sk]": "Backend KDE správcu partícií sfdisk", "Name[sv]": "KDE:s partitionshanterare sfdisk bakgrundsprogram", "Name[uk]": "Додаток sfdisk сервера Керування розділами KDE", "Name[x-test]": "xxKDE Partition Manager sfdisk Backendxx", "ServiceTypes": [ "PartitionManager/Plugin" ], "Version": "1", "Website": "http://www.partitionmanager.org" } } diff --git a/src/plugins/sfdisk/sfdiskbackend.cpp b/src/plugins/sfdisk/sfdiskbackend.cpp index 5d9648d..33f8ed0 100644 --- a/src/plugins/sfdisk/sfdiskbackend.cpp +++ b/src/plugins/sfdisk/sfdiskbackend.cpp @@ -1,431 +1,448 @@ /************************************************************************* * 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::Level::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; } + else + { + // Look if this device is a LVM VG + ExternalCommand checkVG(QStringLiteral("lvm"), { QStringLiteral("vgdisplay"), deviceNode }); + + if (checkVG.run(-1) && checkVG.exitCode() == 0) + { + qDebug() << "Trying to find LVM VG"; + QList availableDevices = scanDevices(); + + LvmDevice::scanSystemLVM(availableDevices); + + for (Device *device : qAsConst(availableDevices)) + if (device->deviceNode() == deviceNode) + return device; + } + } 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::Type::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::Type::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::Type::Luks || fs->type() == FileSystem::Type::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::Type::LinuxSwap && p.fileSystem().type() != FileSystem::Type::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::Type::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::Type::Ext2; else if (s == QStringLiteral("ext3")) rval = FileSystem::Type::Ext3; else if (s.startsWith(QStringLiteral("ext4"))) rval = FileSystem::Type::Ext4; else if (s == QStringLiteral("swap")) rval = FileSystem::Type::LinuxSwap; else if (s == QStringLiteral("ntfs-3g")) rval = FileSystem::Type::Ntfs; else if (s == QStringLiteral("reiserfs")) rval = FileSystem::Type::ReiserFS; else if (s == QStringLiteral("reiser4")) rval = FileSystem::Type::Reiser4; else if (s == QStringLiteral("xfs")) rval = FileSystem::Type::Xfs; else if (s == QStringLiteral("jfs")) rval = FileSystem::Type::Jfs; else if (s == QStringLiteral("hfs")) rval = FileSystem::Type::Hfs; else if (s == QStringLiteral("hfsplus")) rval = FileSystem::Type::HfsPlus; else if (s == QStringLiteral("ufs")) rval = FileSystem::Type::Ufs; else if (s == QStringLiteral("vfat")) { if (version == QStringLiteral("FAT32")) rval = FileSystem::Type::Fat32; else if (version == QStringLiteral("FAT16")) rval = FileSystem::Type::Fat16; else if (version == QStringLiteral("FAT12")) rval = FileSystem::Type::Fat12; } else if (s == QStringLiteral("btrfs")) rval = FileSystem::Type::Btrfs; else if (s == QStringLiteral("ocfs2")) rval = FileSystem::Type::Ocfs2; else if (s == QStringLiteral("zfs_member")) rval = FileSystem::Type::Zfs; else if (s == QStringLiteral("hpfs")) rval = FileSystem::Type::Hpfs; else if (s == QStringLiteral("crypto_LUKS")) { if (version == QStringLiteral("1")) rval = FileSystem::Type::Luks; else if (version == QStringLiteral("2")) { rval = FileSystem::Type::Luks2; } } else if (s == QStringLiteral("exfat")) rval = FileSystem::Type::Exfat; else if (s == QStringLiteral("nilfs2")) rval = FileSystem::Type::Nilfs2; else if (s == QStringLiteral("LVM2_member")) rval = FileSystem::Type::Lvm2_PV; else if (s == QStringLiteral("f2fs")) rval = FileSystem::Type::F2fs; else if (s == QStringLiteral("udf")) rval = FileSystem::Type::Udf; else if (s == QStringLiteral("iso9660")) rval = FileSystem::Type::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=(.*)")); 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=(.*)")); 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; } std::unique_ptr SfdiskBackend::openDevice(const Device& d) { std::unique_ptr device = std::make_unique(d); if (!device->open()) device = nullptr; return device; } std::unique_ptr SfdiskBackend::openDeviceExclusive(const Device& d) { std::unique_ptr device = std::make_unique(d); if (!device->openExclusive()) device = nullptr; return device; } bool SfdiskBackend::closeDevice(std::unique_ptr coreDevice) { return coreDevice->close(); } #include "sfdiskbackend.moc"