diff --git a/src/core/device.cpp b/src/core/device.cpp index cc1d29d..fce2f05 100644 --- a/src/core/device.cpp +++ b/src/core/device.cpp @@ -1,157 +1,157 @@ /************************************************************************* * Copyright (C) 2008 by Volker Lanz * * Copyright (C) 2016-2018 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/device.h" #include "core/device_p.h" #include "core/partitiontable.h" #include "core/smartstatus.h" #include "util/capacity.h" #include /** Constructs a Device with an empty PartitionTable. @param name the Device's name, usually some string defined by the manufacturer @param deviceNode the Device's node, for example "/dev/sda" */ Device::Device(std::shared_ptr d_ptr, const QString& name, const QString& deviceNode, const qint64 logicalSectorSize, const qint64 totalLogicalSectors, const QString& iconName, Device::Type type) : QObject() , d(d_ptr) { d->m_Name = name.length() > 0 ? name : i18n("Unknown Device"); d->m_DeviceNode = deviceNode; d->m_LogicalSectorSize = logicalSectorSize; d->m_TotalLogical = totalLogicalSectors; d->m_PartitionTable = nullptr; d->m_IconName = iconName.isEmpty() ? QStringLiteral("drive-harddisk") : iconName; - d->m_SmartStatus = type == Device::Disk_Device ? std::make_shared(deviceNode) : nullptr; + d->m_SmartStatus = type == Device::Type::Disk_Device ? std::make_shared(deviceNode) : nullptr; d->m_Type = type; } /** Copy constructor for Device. * @param other the other Device. */ Device::Device(const Device& other) : QObject() { d = std::make_shared(); d->m_Name = other.d->m_Name; d->m_DeviceNode = other.d->m_DeviceNode; d->m_LogicalSectorSize = other.d->m_LogicalSectorSize; d->m_TotalLogical = other.d->m_TotalLogical; d->m_PartitionTable = nullptr; d->m_IconName = other.d->m_IconName; d->m_SmartStatus = nullptr; d->m_Type = other.d->m_Type; d->m_SmartStatus = other.d->m_SmartStatus; if (other.d->m_PartitionTable) d->m_PartitionTable = new PartitionTable(*other.d->m_PartitionTable); } /** Destructs a Device. */ Device::~Device() { delete d->m_PartitionTable; } bool Device::operator==(const Device& other) const { return d->m_DeviceNode == other.d->m_DeviceNode; } bool Device::operator!=(const Device& other) const { return !(other == *this); } QString Device::prettyName() const { return xi18nc("@item:inlistbox Device name – Capacity (device node)", "%1 – %2 (%3)", name(), Capacity::formatByteSize(capacity()), deviceNode()); } QString& Device::name() { return d->m_Name; } const QString& Device::name() const { return d->m_Name; } const QString& Device::deviceNode() const { return d->m_DeviceNode; } qint64 Device::logicalSize() const { return d->m_LogicalSectorSize; } qint64 Device::totalLogical() const { return d->m_TotalLogical; } PartitionTable* Device::partitionTable() { return d->m_PartitionTable; } const PartitionTable* Device::partitionTable() const { return d->m_PartitionTable; } void Device::setPartitionTable(PartitionTable* ptable) { d->m_PartitionTable = ptable; } const QString& Device::iconName() const { return d->m_IconName; } void Device::setIconName(const QString& name) { d->m_IconName = name; } SmartStatus& Device::smartStatus() { return *(d->m_SmartStatus); } const SmartStatus& Device::smartStatus() const { return *(d->m_SmartStatus); } Device::Type Device::type() const { return d->m_Type; } diff --git a/src/core/device.h b/src/core/device.h index f99e642..5425539 100644 --- a/src/core/device.h +++ b/src/core/device.h @@ -1,115 +1,115 @@ /************************************************************************* * 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_DEVICE_H #define KPMCORE_DEVICE_H #include "util/libpartitionmanagerexport.h" #include #include #include class PartitionTable; class CreatePartitionTableOperation; class CoreBackend; class SmartStatus; class DevicePrivate; /** A device description. Represents a device like /dev/sda. Contains information about the device (name, status, size ..) but does not operate on the device itself. @see CoreBackendDevice Devices are the outermost entity; they contain a PartitionTable that itself contains Partitions. @see PartitionTable, Partition @author Volker Lanz */ class LIBKPMCORE_EXPORT Device : public QObject { Device &operator=(const Device &) = delete; friend class CreatePartitionTableOperation; friend class CoreBackend; public: - enum Type { - Disk_Device = 0, - LVM_Device = 1, /* VG */ - RAID_Device = 2, /* software RAID device */ - Unknown_Device = 4 + enum class Type { + Unknown_Device, + Disk_Device, + LVM_Device, /* VG */ + RAID_Device, /* software RAID device */ }; protected: - explicit Device(std::shared_ptr d_ptr, const QString& name, const QString& deviceNode, const qint64 logicalSectorSize, const qint64 totalLogicalSectors, const QString& iconName = QString(), Device::Type type = Device::Disk_Device); + explicit Device(std::shared_ptr d_ptr, const QString& name, const QString& deviceNode, const qint64 logicalSectorSize, const qint64 totalLogicalSectors, const QString& iconName = QString(), Device::Type type = Device::Type::Disk_Device); public: explicit Device(const Device& other); virtual ~Device(); virtual bool operator==(const Device& other) const; virtual bool operator!=(const Device& other) const; /**< @return the Device's name, usually some manufacturer string */ virtual QString& name(); virtual const QString& name() const; /**< @return the Device's node, for example "/dev/sda" */ virtual const QString& deviceNode() const; /**< @return the logical sector size the Device uses (would be extent size for e.g. LVM devices) */ virtual qint64 logicalSize() const; /**< @return the total number of logical sectors on the device */ virtual qint64 totalLogical() const; /**< @return the Device's PartitionTable */ virtual PartitionTable* partitionTable(); virtual const PartitionTable* partitionTable() const; /** * Change the description of the partition table for different one. * The device itself is not changed; use CreatePartitionTableOperation * for that. The Device instance becomes the owner of @p ptable . */ virtual void setPartitionTable(PartitionTable* ptable); virtual qint64 capacity() const { /**< @return the Device's capacity in bytes */ return logicalSize() * totalLogical(); } /**< @return suggested icon name for this Device */ virtual const QString& iconName() const; /**< @param name set the new Icon for this Device */ virtual void setIconName(const QString& name); virtual SmartStatus& smartStatus(); virtual const SmartStatus& smartStatus() const; virtual Device::Type type() const; virtual QString prettyName() const; protected: std::shared_ptr d; }; #endif diff --git a/src/core/diskdevice.cpp b/src/core/diskdevice.cpp index c23cb58..38c8175 100644 --- a/src/core/diskdevice.cpp +++ b/src/core/diskdevice.cpp @@ -1,144 +1,144 @@ /************************************************************************* * Copyright (C) 2008 by Volker Lanz * * Copyright (C) 2016-2018 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/diskdevice.h" #include "core/device_p.h" #include "core/partitiontable.h" #include "core/smartstatus.h" #include #include #include #include #include #include #include #include #ifdef __gnu_linux__ #include #endif #if !defined(BLKPBSZGET) #define BLKPBSZGET _IO(0x12,123)/* get block physical sector size */ #endif #define d_ptr std::static_pointer_cast(d) class DiskDevicePrivate : public DevicePrivate { public: qint32 m_Heads; qint32 m_SectorsPerTrack; qint32 m_Cylinders; qint64 m_LogicalSectorSize; qint64 m_PhysicalSectorSize; }; static qint64 getPhysicalSectorSize(const QString& device_node) { /* * possible ways of getting the physical sector size for a drive: * - ioctl(BLKPBSZGET) -- supported with Linux 2.6.32 and later * - /sys/block/sda/queue/physical_block_size * - libblkid from util-linux 2.17 or later (not implemented) */ #if defined(BLKPBSZGET) int phSectorSize = -1; int fd = open(device_node.toLocal8Bit().constData(), O_RDONLY); if (fd != -1) { if (ioctl(fd, BLKPBSZGET, &phSectorSize) >= 0) { close(fd); return phSectorSize; } close(fd); } #endif QFile f(QStringLiteral("/sys/block/%1/queue/physical_block_size").arg(QString(device_node).remove(QStringLiteral("/dev/")))); if (f.open(QIODevice::ReadOnly)) { QByteArray a = f.readLine(); return a.trimmed().toInt(); } return -1; } /** Constructs a Disk Device with an empty PartitionTable. @param name the Device's name, usually some string defined by the manufacturer @param deviceNode the Device's node, for example "/dev/sda" @param heads the number of heads in CHS notation @param numSectors the number of sectors in CHS notation @param cylinders the number of cylinders in CHS notation @param sectorSize the size of a sector in bytes */ DiskDevice::DiskDevice(const QString& name, const QString& deviceNode, qint32 heads, qint32 numSectors, qint32 cylinders, qint64 sectorSize, const QString& iconName) - : Device(std::make_shared(), name, deviceNode, sectorSize, (static_cast(heads) * cylinders * numSectors), iconName, Device::Disk_Device) + : Device(std::make_shared(), name, deviceNode, sectorSize, (static_cast(heads) * cylinders * numSectors), iconName, Device::Type::Disk_Device) { d_ptr->m_Heads = heads; d_ptr->m_SectorsPerTrack = numSectors; d_ptr->m_Cylinders = cylinders; d_ptr->m_LogicalSectorSize = sectorSize; d_ptr->m_PhysicalSectorSize = getPhysicalSectorSize(deviceNode); } qint32 DiskDevice::heads() const { return d_ptr->m_Heads; } qint32 DiskDevice::cylinders() const { return d_ptr->m_Cylinders; } qint32 DiskDevice::sectorsPerTrack() const { return d_ptr->m_SectorsPerTrack; } qint64 DiskDevice::physicalSectorSize() const { return d_ptr->m_PhysicalSectorSize; } qint64 DiskDevice::logicalSectorSize() const { return d_ptr->m_LogicalSectorSize; } qint64 DiskDevice::totalSectors() const { return static_cast(d_ptr->m_Heads) * d_ptr->m_Cylinders * d_ptr->m_SectorsPerTrack; } qint64 DiskDevice::cylinderSize() const { return static_cast(d_ptr->m_Heads) * d_ptr->m_SectorsPerTrack; } diff --git a/src/core/lvmdevice.cpp b/src/core/lvmdevice.cpp index 917410c..118cd4f 100644 --- a/src/core/lvmdevice.cpp +++ b/src/core/lvmdevice.cpp @@ -1,557 +1,557 @@ /************************************************************************* * Copyright (C) 2016 by Chantara Tith * * 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/lvmdevice.h" #include "core/partition.h" #include "core/volumemanagerdevice_p.h" #include "fs/filesystem.h" #include "fs/lvm2_pv.h" #include "fs/luks.h" #include "fs/filesystemfactory.h" #include "core/partitiontable.h" #include "util/externalcommand.h" #include "util/helpers.h" #include "util/report.h" #include #include #include #include #define d_ptr std::static_pointer_cast(d) class LvmDevicePrivate : public VolumeManagerDevicePrivate { public: qint64 m_peSize; qint64 m_totalPE; qint64 m_allocPE; qint64 m_freePE; QString m_UUID; mutable QStringList* m_LVPathList; QVector m_PVs; mutable QHash* m_LVSizeMap; }; /** Constructs a representation of LVM device with initialized LV as Partitions * * @param vgName Volume Group name * @param iconName Icon representing LVM Volume group */ LvmDevice::LvmDevice(const QString& vgName, const QString& iconName) : VolumeManagerDevice(std::make_shared(), vgName, (QStringLiteral("/dev/") + vgName), getPeSize(vgName), getTotalPE(vgName), iconName, - Device::LVM_Device) + Device::Type::LVM_Device) { d_ptr->m_peSize = logicalSize(); d_ptr->m_totalPE = totalLogical(); d_ptr->m_freePE = getFreePE(vgName); d_ptr->m_allocPE = d_ptr->m_totalPE - d_ptr->m_freePE; d_ptr->m_UUID = getUUID(vgName); d_ptr->m_LVPathList = new QStringList(getLVs(vgName)); d_ptr->m_LVSizeMap = new QHash(); initPartitions(); } /** * shared list of PV's paths that will be added to any VGs. * (have been added to an operation, but not yet applied) */ QVector LvmDevice::s_DirtyPVs; LvmDevice::~LvmDevice() { delete d_ptr->m_LVPathList; delete d_ptr->m_LVSizeMap; } void LvmDevice::initPartitions() { qint64 firstUsable = 0; qint64 lastusable = totalPE() - 1; PartitionTable* pTable = new PartitionTable(PartitionTable::vmd, firstUsable, lastusable); for (const auto &p : scanPartitions(pTable)) { LVSizeMap()->insert(p->partitionPath(), p->length()); pTable->append(p); } pTable->updateUnallocated(*this); setPartitionTable(pTable); } /** * @return an initialized Partition(LV) list */ const QList LvmDevice::scanPartitions(PartitionTable* pTable) const { QList pList; for (const auto &lvPath : partitionNodes()) { pList.append(scanPartition(lvPath, pTable)); } return pList; } /** scan and construct a partition(LV) at a given path * * NOTE: * LVM partition has 2 different start and end sector values * 1. representing the actual LV start from 0 -> size of LV - 1 * 2. representing abstract LV's sector inside a VG partitionTable * start from last sector + 1 of last Partitions -> size of LV - 1 * Reason for this is for the LV Partition to work nicely with other parts of the codebase * without too many special cases. * * @param lvPath LVM Logical Volume path * @param pTable Abstract partition table representing partitions of LVM Volume Group * @return initialized Partition(LV) */ Partition* LvmDevice::scanPartition(const QString& lvPath, PartitionTable* pTable) const { activateLV(lvPath); qint64 lvSize = getTotalLE(lvPath); qint64 startSector = mappedSector(lvPath, 0); qint64 endSector = startSector + lvSize - 1; FileSystem::Type type = FileSystem::detectFileSystem(lvPath); FileSystem* fs = FileSystemFactory::create(type, 0, lvSize - 1, logicalSize()); fs->scan(lvPath); PartitionRole::Roles r = PartitionRole::Lvm_Lv; QString mountPoint; bool mounted; // Handle LUKS partition if (fs->type() == FileSystem::Type::Luks) { 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, lvPath); mounted = FileSystem::detectMountStatus(fs, lvPath); if (mountPoint != QString() && fs->type() != FileSystem::Type::LinuxSwap) { const QStorageInfo storage = QStorageInfo(mountPoint); if (logicalSize() > 0 && fs->type() != FileSystem::Type::Luks && mounted && storage.isValid()) fs->setSectorsUsed( (storage.bytesTotal() - storage.bytesFree()) / logicalSize() ); } else if (fs->supportGetUsed() == FileSystem::cmdSupportFileSystem) fs->setSectorsUsed(qCeil(fs->readUsedCapacity(lvPath) / static_cast(logicalSize()))); } if (fs->supportGetLabel() != FileSystem::cmdSupportNone) { fs->setLabel(fs->readLabel(lvPath)); } if (fs->supportGetUUID() != FileSystem::cmdSupportNone) fs->setUUID(fs->readUUID(lvPath)); Partition* part = new Partition(pTable, *this, PartitionRole(r), fs, startSector, endSector, lvPath, PartitionTable::Flag::FlagNone, mountPoint, mounted); return part; } /** scan and construct list of initialized LvmDevice objects. * * @param devices list of initialized Devices */ void LvmDevice::scanSystemLVM(QList& devices) { QList lvmList; for (const auto &vgName : getVGs()) { lvmList.append(new LvmDevice(vgName)); } // Some LVM operations require additional information about LVM physical volumes which we store in LVM::pvList LVM::pvList = FS::lvm2_pv::getPVs(devices); // Look for LVM physical volumes in LVM VGs for (const auto &d : lvmList) { devices.append(d); LVM::pvList.append(FS::lvm2_pv::getPVinNode(d->partitionTable())); } // Inform LvmDevice about which physical volumes form that particular LvmDevice for (const auto &d : lvmList) for (const auto &p : qAsConst(LVM::pvList)) if (p.vgName() == d->name()) d->physicalVolumes().append(p.partition()); } qint64 LvmDevice::mappedSector(const QString& lvPath, qint64 sector) const { qint64 mSector = 0; QStringList lvpathList = partitionNodes(); qint32 devIndex = lvpathList.indexOf(lvPath); if (devIndex) { for (int i = 0; i < devIndex; i++) { mSector += LVSizeMap()->value(lvpathList[i]); } mSector += sector; } return mSector; } const QStringList LvmDevice::deviceNodes() const { QStringList pvList; for (const auto &p : physicalVolumes()) { if (p->roles().has(PartitionRole::Luks)) pvList << static_cast(&p->fileSystem())->mapperName(); else pvList << p->partitionPath(); } return pvList; } const QStringList LvmDevice::partitionNodes() const { return *LVPathList(); } qint64 LvmDevice::partitionSize(QString& partitionPath) const { return LVSizeMap()->value(partitionPath); } const QStringList LvmDevice::getVGs() { QStringList vgList; QString output = getField(QStringLiteral("vg_name")); if (!output.isEmpty()) { const QStringList vgNameList = output.split(QStringLiteral("\n"), QString::SkipEmptyParts); for (const auto &vgName : vgNameList) { vgList.append(vgName.trimmed()); } } return vgList; } const QStringList LvmDevice::getLVs(const QString& vgName) { QStringList lvPathList; QString cmdOutput = getField(QStringLiteral("lv_path"), vgName); if (cmdOutput.size()) { const QStringList tempPathList = cmdOutput.split(QStringLiteral("\n"), QString::SkipEmptyParts); for (const auto &lvPath : tempPathList) { lvPathList.append(lvPath.trimmed()); } } return lvPathList; } qint64 LvmDevice::getPeSize(const QString& vgName) { QString val = getField(QStringLiteral("vg_extent_size"), vgName); return val.isEmpty() ? -1 : val.toLongLong(); } qint64 LvmDevice::getTotalPE(const QString& vgName) { QString val = getField(QStringLiteral("vg_extent_count"), vgName); return val.isEmpty() ? -1 : val.toInt(); } qint64 LvmDevice::getAllocatedPE(const QString& vgName) { return getTotalPE(vgName) - getFreePE(vgName); } qint64 LvmDevice::getFreePE(const QString& vgName) { QString val = getField(QStringLiteral("vg_free_count"), vgName); return val.isEmpty() ? -1 : val.toInt(); } QString LvmDevice::getUUID(const QString& vgName) { QString val = getField(QStringLiteral("vg_uuid"), vgName); return val.isEmpty() ? QStringLiteral("---") : val; } /** Get LVM vgs command output with field name * * @param fieldName LVM field name * @param vgName the name of LVM Volume Group * @return raw output of command output, usually with many spaces within the returned string * */ QString LvmDevice::getField(const QString& fieldName, const QString& vgName) { QStringList args = { QStringLiteral("vgs"), QStringLiteral("--foreign"), QStringLiteral("--readonly"), QStringLiteral("--noheadings"), QStringLiteral("--units"), QStringLiteral("B"), QStringLiteral("--nosuffix"), QStringLiteral("--options"), fieldName }; if (!vgName.isEmpty()) { args << vgName; } ExternalCommand cmd(QStringLiteral("lvm"), args, QProcess::ProcessChannelMode::SeparateChannels); if (cmd.run(-1) && cmd.exitCode() == 0) { return cmd.output().trimmed(); } return QString(); } qint64 LvmDevice::getTotalLE(const QString& lvPath) { ExternalCommand cmd(QStringLiteral("lvm"), { QStringLiteral("lvdisplay"), lvPath}); if (cmd.run(-1) && cmd.exitCode() == 0) { QRegularExpression re(QStringLiteral("Current LE\\h+(\\d+)")); QRegularExpressionMatch match = re.match(cmd.output()); if (match.hasMatch()) { return match.captured(1).toInt(); } } return -1; } bool LvmDevice::removeLV(Report& report, LvmDevice& d, Partition& p) { ExternalCommand cmd(report, QStringLiteral("lvm"), { QStringLiteral("lvremove"), QStringLiteral("--yes"), p.partitionPath()}); if (cmd.run(-1) && cmd.exitCode() == 0) { d.partitionTable()->remove(&p); return true; } return false; } bool LvmDevice::createLV(Report& report, LvmDevice& d, Partition& p, const QString& lvName) { ExternalCommand cmd(report, QStringLiteral("lvm"), { QStringLiteral("lvcreate"), QStringLiteral("--yes"), QStringLiteral("--extents"), QString::number(p.length()), QStringLiteral("--name"), lvName, d.name()}); return (cmd.run(-1) && cmd.exitCode() == 0); } bool LvmDevice::createLVSnapshot(Report& report, Partition& p, const QString& name, const qint64 extents) { QString numExtents = (extents > 0) ? QString::number(extents) : QString::number(p.length()); ExternalCommand cmd(report, QStringLiteral("lvm"), { QStringLiteral("lvcreate"), QStringLiteral("--yes"), QStringLiteral("--extents"), numExtents, QStringLiteral("--snapshot"), QStringLiteral("--name"), name, p.partitionPath() }); return (cmd.run(-1) && cmd.exitCode() == 0); } bool LvmDevice::resizeLV(Report& report, Partition& p) { ExternalCommand cmd(report, QStringLiteral("lvm"), { QStringLiteral("lvresize"), QStringLiteral("--force"), QStringLiteral("--yes"), QStringLiteral("--extents"), QString::number(p.length()), p.partitionPath()}); return (cmd.run(-1) && cmd.exitCode() == 0); } bool LvmDevice::removePV(Report& report, LvmDevice& d, const QString& pvPath) { ExternalCommand cmd(report, QStringLiteral("lvm"), { QStringLiteral("vgreduce"), d.name(), pvPath}); return (cmd.run(-1) && cmd.exitCode() == 0); } bool LvmDevice::insertPV(Report& report, LvmDevice& d, const QString& pvPath) { ExternalCommand cmd(report, QStringLiteral("lvm"), { QStringLiteral("vgextend"), QStringLiteral("--yes"), d.name(), pvPath}); return (cmd.run(-1) && cmd.exitCode() == 0); } bool LvmDevice::movePV(Report& report, const QString& pvPath, const QStringList& destinations) { if (FS::lvm2_pv::getAllocatedPE(pvPath) <= 0) return true; QStringList args = QStringList(); args << QStringLiteral("pvmove"); args << pvPath; if (!destinations.isEmpty()) for (const auto &destPath : destinations) args << destPath.trimmed(); ExternalCommand cmd(report, QStringLiteral("lvm"), args); return (cmd.run(-1) && cmd.exitCode() == 0); } bool LvmDevice::createVG(Report& report, const QString vgName, const QVector& pvList, const qint32 peSize) { QStringList args = QStringList(); args << QStringLiteral("vgcreate") << QStringLiteral("--physicalextentsize") << QString::number(peSize); args << vgName; for (const auto &p : pvList) { if (p->roles().has(PartitionRole::Luks)) args << static_cast(&p->fileSystem())->mapperName(); else args << p->partitionPath(); } ExternalCommand cmd(report, QStringLiteral("lvm"), args); return (cmd.run(-1) && cmd.exitCode() == 0); } bool LvmDevice::removeVG(Report& report, LvmDevice& d) { bool deactivated = deactivateVG(report, d); ExternalCommand cmd(report, QStringLiteral("lvm"), { QStringLiteral("vgremove"), QStringLiteral("--force"), d.name() }); return (deactivated && cmd.run(-1) && cmd.exitCode() == 0); } bool LvmDevice::deactivateVG(Report& report, const LvmDevice& d) { ExternalCommand deactivate(report, QStringLiteral("lvm"), { QStringLiteral("vgchange"), QStringLiteral("--activate"), QStringLiteral("n"), d.name() }); return deactivate.run(-1) && deactivate.exitCode() == 0; } bool LvmDevice::deactivateLV(Report& report, const Partition& p) { ExternalCommand deactivate(report, QStringLiteral("lvm"), { QStringLiteral("lvchange"), QStringLiteral("--activate"), QStringLiteral("n"), p.partitionPath() }); return deactivate.run(-1) && deactivate.exitCode() == 0; } bool LvmDevice::activateVG(Report& report, const LvmDevice& d) { ExternalCommand deactivate(report, QStringLiteral("lvm"), { QStringLiteral("vgchange"), QStringLiteral("--activate"), QStringLiteral("y"), d.name() }); return deactivate.run(-1) && deactivate.exitCode() == 0; } bool LvmDevice::activateLV(const QString& lvPath) { ExternalCommand deactivate(QStringLiteral("lvm"), { QStringLiteral("lvchange"), QStringLiteral("--activate"), QStringLiteral("y"), lvPath }); return deactivate.run(-1) && deactivate.exitCode() == 0; } qint64 LvmDevice::peSize() const { return d_ptr->m_peSize; } qint64 LvmDevice::totalPE() const { return d_ptr->m_totalPE; } qint64 LvmDevice::allocatedPE() const { return d_ptr->m_allocPE; } qint64 LvmDevice::freePE() const { return d_ptr->m_freePE; } QString LvmDevice::UUID() const { return d_ptr->m_UUID; } QStringList* LvmDevice::LVPathList() const { return d_ptr->m_LVPathList; } QVector & LvmDevice::physicalVolumes() { return d_ptr->m_PVs; } const QVector & LvmDevice::physicalVolumes() const { return d_ptr->m_PVs; } QHash* LvmDevice::LVSizeMap() const { return d_ptr->m_LVSizeMap; } diff --git a/src/core/operationstack.cpp b/src/core/operationstack.cpp index 8e7bd57..0a9b9f5 100644 --- a/src/core/operationstack.cpp +++ b/src/core/operationstack.cpp @@ -1,571 +1,571 @@ /************************************************************************* * Copyright (C) 2008, 2011 by Volker Lanz * * 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/operationstack.h" #include "core/device.h" #include "core/partition.h" #include "core/partitiontable.h" #include "ops/operation.h" #include "ops/deleteoperation.h" #include "ops/newoperation.h" #include "ops/resizeoperation.h" #include "ops/copyoperation.h" #include "ops/restoreoperation.h" #include "ops/createfilesystemoperation.h" #include "ops/setpartflagsoperation.h" #include "ops/setfilesystemlabeloperation.h" #include "ops/createpartitiontableoperation.h" #include "ops/resizevolumegroupoperation.h" #include "ops/checkoperation.h" #include "jobs/setfilesystemlabeljob.h" #include "fs/filesystemfactory.h" #include "util/globallog.h" #include #include #include /** Constructs a new OperationStack */ OperationStack::OperationStack(QObject* parent) : QObject(parent), m_Operations(), m_PreviewDevices(), m_Lock(QReadWriteLock::Recursive) { } /** Destructs an OperationStack, cleaning up Operations and Devices */ OperationStack::~OperationStack() { clearOperations(); clearDevices(); } /** Tries to merge an existing NewOperation with a new Operation pushed on the OperationStack There are several cases what might need to be done:
  1. An existing operation created a Partition that is now being deleted: In this case, just remove the corresponding NewOperation from the OperationStack.
    This does not work for extended partitions.(#232092)
  2. An existing Operation created a Partition that is now being moved or resized. In this case, remove the original NewOperation and create a new NewOperation with updated start and end sectors. This new NewOperation is appended to the OperationStack.
    This does not work for extended partitions.(#232092)
  3. An existing NewOperation created a Partition that is now being copied. We're not copying but instead creating another new Partition in its place.
  4. The label for a new Partition's FileSystem is modified: Modify in NewOperation and forget it.
  5. File system is changed for a new Partition: Modify in NewOperation and forget it.
  6. A file system on a new Partition is about to be checked: Just delete the CheckOperation, because file systems are checked anyway when they're created. This fixes #275657.
@param currentOp the Operation already on the stack to try to merge with @param pushedOp the newly pushed Operation @return true if the OperationStack has been modified in a way that requires merging to stop */ bool OperationStack::mergeNewOperation(Operation*& currentOp, Operation*& pushedOp) { NewOperation* newOp = dynamic_cast(currentOp); if (newOp == nullptr) return false; DeleteOperation* pushedDeleteOp = dynamic_cast(pushedOp); ResizeOperation* pushedResizeOp = dynamic_cast(pushedOp); CopyOperation* pushedCopyOp = dynamic_cast(pushedOp); SetFileSystemLabelOperation* pushedLabelOp = dynamic_cast(pushedOp); CreateFileSystemOperation* pushedCreateFileSystemOp = dynamic_cast(pushedOp); CheckOperation* pushedCheckOp = dynamic_cast(pushedOp); // -- 1 -- if (pushedDeleteOp && &newOp->newPartition() == &pushedDeleteOp->deletedPartition() && !pushedDeleteOp->deletedPartition().roles().has(PartitionRole::Extended)) { Log() << xi18nc("@info:status", "Deleting a partition just created: Undoing the operation to create the partition."); delete pushedOp; pushedOp = nullptr; newOp->undo(); delete operations().takeAt(operations().indexOf(newOp)); return true; } // -- 2 -- if (pushedResizeOp && &newOp->newPartition() == &pushedResizeOp->partition() && !pushedResizeOp->partition().roles().has(PartitionRole::Extended)) { // NOTE: In theory it would be possible to merge resizing an extended as long as it has no children. // But that still doesn't save us: If we're not merging a resize on an extended that has children, // a resizeop is added to the stack. Next, the user deletes the child. Then he resizes the // extended again (a second resize): The ResizeOp still has the pointer to the original extended that // will now be deleted. Log() << xi18nc("@info:status", "Resizing a partition just created: Updating start and end in existing operation."); Partition* newPartition = new Partition(newOp->newPartition()); newPartition->setFirstSector(pushedResizeOp->newFirstSector()); newPartition->fileSystem().setFirstSector(pushedResizeOp->newFirstSector()); newPartition->setLastSector(pushedResizeOp->newLastSector()); newPartition->fileSystem().setLastSector(pushedResizeOp->newLastSector()); NewOperation* revisedNewOp = new NewOperation(newOp->targetDevice(), newPartition); delete pushedOp; pushedOp = revisedNewOp; newOp->undo(); delete operations().takeAt(operations().indexOf(newOp)); return true; } // -- 3 -- if (pushedCopyOp && &newOp->newPartition() == &pushedCopyOp->sourcePartition()) { Log() << xi18nc("@info:status", "Copying a new partition: Creating a new partition instead."); Partition* newPartition = new Partition(newOp->newPartition()); newPartition->setFirstSector(pushedCopyOp->copiedPartition().firstSector()); newPartition->fileSystem().setFirstSector(pushedCopyOp->copiedPartition().fileSystem().firstSector()); newPartition->setLastSector(pushedCopyOp->copiedPartition().lastSector()); newPartition->fileSystem().setLastSector(pushedCopyOp->copiedPartition().fileSystem().lastSector()); NewOperation* revisedNewOp = new NewOperation(pushedCopyOp->targetDevice(), newPartition); delete pushedOp; pushedOp = revisedNewOp; return true; } // -- 4 -- if (pushedLabelOp && &newOp->newPartition() == &pushedLabelOp->labeledPartition()) { Log() << xi18nc("@info:status", "Changing label for a new partition: No new operation required."); newOp->setLabelJob()->setLabel(pushedLabelOp->newLabel()); newOp->newPartition().fileSystem().setLabel(pushedLabelOp->newLabel()); delete pushedOp; pushedOp = nullptr; return true; } // -- 5 -- if (pushedCreateFileSystemOp && &newOp->newPartition() == &pushedCreateFileSystemOp->partition()) { Log() << xi18nc("@info:status", "Changing file system for a new partition: No new operation required."); FileSystem* oldFs = &newOp->newPartition().fileSystem(); newOp->newPartition().setFileSystem(FileSystemFactory::cloneWithNewType(pushedCreateFileSystemOp->newFileSystem()->type(), *oldFs)); delete oldFs; oldFs = nullptr; delete pushedOp; pushedOp = nullptr; return true; } // -- 6 -- if (pushedCheckOp && &newOp->newPartition() == &pushedCheckOp->checkedPartition()) { Log() << xi18nc("@info:status", "Checking file systems is automatically done when creating them: No new operation required."); delete pushedOp; pushedOp = nullptr; return true; } return false; } /** Tries to merge an existing CopyOperation with a new Operation pushed on the OperationStack. These are the cases to consider:
  1. An existing CopyOperation created a Partition that is now being deleted. Remove the CopyOperation, and, if the CopyOperation was an overwrite, carry on with the delete. Else also remove the DeleteOperation.
  2. An existing CopyOperation created a Partition that is now being copied. We're not copying the target of this existing CopyOperation, but its source instead. If this merge is not done, copied partitions will have misleading labels ("copy of sdXY" instead of "copy of copy of sdXY" for a second-generation copy) but the Operation itself will still work.
@param currentOp the Operation already on the stack to try to merge with @param pushedOp the newly pushed Operation @return true if the OperationStack has been modified in a way that requires merging to stop */ bool OperationStack::mergeCopyOperation(Operation*& currentOp, Operation*& pushedOp) { CopyOperation* copyOp = dynamic_cast(currentOp); if (copyOp == nullptr) return false; DeleteOperation* pushedDeleteOp = dynamic_cast(pushedOp); CopyOperation* pushedCopyOp = dynamic_cast(pushedOp); // -- 1 -- if (pushedDeleteOp && ©Op->copiedPartition() == &pushedDeleteOp->deletedPartition()) { // If the copy operation didn't overwrite, but create a new partition, just remove the // copy operation, forget the delete and be done. if (copyOp->overwrittenPartition() == nullptr) { Log() << xi18nc("@info:status", "Deleting a partition just copied: Removing the copy."); delete pushedOp; pushedOp = nullptr; } else { Log() << xi18nc("@info:status", "Deleting a partition just copied over an existing partition: Removing the copy and deleting the existing partition."); pushedDeleteOp->setDeletedPartition(copyOp->overwrittenPartition()); } copyOp->undo(); delete operations().takeAt(operations().indexOf(copyOp)); return true; } // -- 2 -- if (pushedCopyOp && ©Op->copiedPartition() == &pushedCopyOp->sourcePartition()) { Log() << xi18nc("@info:status", "Copying a partition that is itself a copy: Copying the original source partition instead."); pushedCopyOp->setSourcePartition(©Op->sourcePartition()); } return false; } /** Tries to merge an existing RestoreOperation with a new Operation pushed on the OperationStack. If an existing RestoreOperation created a Partition that is now being deleted, remove the RestoreOperation, and, if the RestoreOperation was an overwrite, carry on with the delete. Else also remove the DeleteOperation. @param currentOp the Operation already on the stack to try to merge with @param pushedOp the newly pushed Operation @return true if the OperationStack has been modified in a way that requires merging to stop */ bool OperationStack::mergeRestoreOperation(Operation*& currentOp, Operation*& pushedOp) { RestoreOperation* restoreOp = dynamic_cast(currentOp); if (restoreOp == nullptr) return false; DeleteOperation* pushedDeleteOp = dynamic_cast(pushedOp); if (pushedDeleteOp && &restoreOp->restorePartition() == &pushedDeleteOp->deletedPartition()) { if (restoreOp->overwrittenPartition() == nullptr) { Log() << xi18nc("@info:status", "Deleting a partition just restored: Removing the restore operation."); delete pushedOp; pushedOp = nullptr; } else { Log() << xi18nc("@info:status", "Deleting a partition just restored to an existing partition: Removing the restore operation and deleting the existing partition."); pushedDeleteOp->setDeletedPartition(restoreOp->overwrittenPartition()); } restoreOp->undo(); delete operations().takeAt(operations().indexOf(restoreOp)); return true; } return false; } /** Tries to merge an existing SetPartFlagsOperation with a new Operation pushed on the OperationStack. If the Partition flags for an existing Partition are modified look if there is an existing Operation for the same Partition and modify that one. @param currentOp the Operation already on the stack to try to merge with @param pushedOp the newly pushed Operation @return true if the OperationStack has been modified in a way that requires merging to stop */ bool OperationStack::mergePartFlagsOperation(Operation*& currentOp, Operation*& pushedOp) { SetPartFlagsOperation* partFlagsOp = dynamic_cast(currentOp); if (partFlagsOp == nullptr) return false; SetPartFlagsOperation* pushedFlagsOp = dynamic_cast(pushedOp); if (pushedFlagsOp && &partFlagsOp->flagPartition() == &pushedFlagsOp->flagPartition()) { Log() << xi18nc("@info:status", "Changing flags again for the same partition: Removing old operation."); pushedFlagsOp->setOldFlags(partFlagsOp->oldFlags()); partFlagsOp->undo(); delete operations().takeAt(operations().indexOf(partFlagsOp)); return true; } return false; } /** Tries to merge an existing SetFileSystemLabelOperation with a new Operation pushed on the OperationStack. If a FileSystem label for an existing Partition is modified look if there is an existing SetFileSystemLabelOperation for the same Partition. @param currentOp the Operation already on the stack to try to merge with @param pushedOp the newly pushed Operation @return true if the OperationStack has been modified in a way that requires merging to stop */ bool OperationStack::mergePartLabelOperation(Operation*& currentOp, Operation*& pushedOp) { SetFileSystemLabelOperation* partLabelOp = dynamic_cast(currentOp); if (partLabelOp == nullptr) return false; SetFileSystemLabelOperation* pushedLabelOp = dynamic_cast(pushedOp); if (pushedLabelOp && &partLabelOp->labeledPartition() == &pushedLabelOp->labeledPartition()) { Log() << xi18nc("@info:status", "Changing label again for the same partition: Removing old operation."); pushedLabelOp->setOldLabel(partLabelOp->oldLabel()); partLabelOp->undo(); delete operations().takeAt(operations().indexOf(partLabelOp)); return true; } return false; } /** Tries to merge an existing CreatePartitionTableOperation with a new Operation pushed on the OperationStack. If a new partition table is to be created on a device and a previous operation targets that device, remove this previous operation. @param currentOp the Operation already on the stack to try to merge with @param pushedOp the newly pushed Operation @return true if the OperationStack has been modified in a way that requires merging to stop */ bool OperationStack::mergeCreatePartitionTableOperation(Operation*& currentOp, Operation*& pushedOp) { CreatePartitionTableOperation* pushedCreatePartitionTableOp = dynamic_cast(pushedOp); if (pushedCreatePartitionTableOp && currentOp->targets(pushedCreatePartitionTableOp->targetDevice())) { Log() << xi18nc("@info:status", "Creating new partition table, discarding previous operation on device."); CreatePartitionTableOperation* createPartitionTableOp = dynamic_cast(currentOp); if (createPartitionTableOp != nullptr) pushedCreatePartitionTableOp->setOldPartitionTable(createPartitionTableOp->oldPartitionTable()); currentOp->undo(); delete operations().takeAt(operations().indexOf(currentOp)); return true; } return false; } bool OperationStack::mergeResizeVolumeGroupResizeOperation(Operation*& pushedOp) { ResizeVolumeGroupOperation* pushedResizeVolumeGroupOp = dynamic_cast(pushedOp); if (pushedResizeVolumeGroupOp && pushedResizeVolumeGroupOp->jobs().count() == 0) { Log() << xi18nc("@info:status", "Resizing Volume Group, nothing to do."); return true; } return false; } /** Pushes a new Operation on the OperationStack. This method will call all methods that try to merge the new Operation with the existing ones. It is not uncommon that any of these will delete the pushed Operation. Callers must not rely on the pushed Operation to exist after calling OperationStack::push(). @param o Pointer to the Operation. Must not be nullptr. */ void OperationStack::push(Operation* o) { Q_ASSERT(o); if (mergeResizeVolumeGroupResizeOperation(o)) return; for (auto currentOp = operations().rbegin(); currentOp != operations().rend(); ++currentOp) { if (mergeNewOperation(*currentOp, o)) break; if (mergeCopyOperation(*currentOp, o)) break; if (mergeRestoreOperation(*currentOp, o)) break; if (mergePartFlagsOperation(*currentOp, o)) break; if (mergePartLabelOperation(*currentOp, o)) break; if (mergeCreatePartitionTableOperation(*currentOp, o)) break; } if (o != nullptr) { Log() << xi18nc("@info:status", "Add operation: %1", o->description()); operations().append(o); o->preview(); o->setStatus(Operation::StatusPending); } // emit operationsChanged even if o is nullptr because it has been merged: merging might // have led to an existing operation changing. emit operationsChanged(); } /** Removes the topmost Operation from the OperationStack, calls Operation::undo() on it and deletes it. */ void OperationStack::pop() { Operation* o = operations().takeLast(); o->undo(); delete o; emit operationsChanged(); } /** Check whether previous operations involve given partition. @param p Pointer to the Partition. Must not be nullptr. */ bool OperationStack::contains(const Partition* p) const { Q_ASSERT(p); for (const auto &o : operations()) { if (o->targets(*p)) return true; CopyOperation* copyOp = dynamic_cast(o); if (copyOp) { const Partition* source = ©Op->sourcePartition(); if (source == p) return true; } } return false; } /** Removes all Operations from the OperationStack, calling Operation::undo() on them and deleting them. */ void OperationStack::clearOperations() { while (!operations().isEmpty()) { Operation* o = operations().takeLast(); if (o->status() == Operation::StatusPending) o->undo(); delete o; } emit operationsChanged(); } /** Clears the list of Devices. */ void OperationStack::clearDevices() { QWriteLocker lockDevices(&lock()); qDeleteAll(previewDevices()); previewDevices().clear(); emit devicesChanged(); } /** Finds a Device a Partition is on. @param p pointer to the Partition to find a Device for @return the Device or nullptr if none could be found */ Device* OperationStack::findDeviceForPartition(const Partition* p) { QReadLocker lockDevices(&lock()); const auto devices = previewDevices(); for (Device *d : devices) { if (d->partitionTable() == nullptr) continue; const auto partitions = d->partitionTable()->children(); for (const auto *part : partitions) { if (part == p) return d; for (const auto &child : part->children()) if (child == p) return d; } } return nullptr; } /** Adds a Device to the OperationStack @param d pointer to the Device to add. Must not be nullptr. */ void OperationStack::addDevice(Device* d) { Q_ASSERT(d); QWriteLocker lockDevices(&lock()); previewDevices().append(d); emit devicesChanged(); } static bool deviceLessThan(const Device* d1, const Device* d2) { // Display alphabetically sorted disk devices above LVM VGs - if (d1->type() == Device::LVM_Device && d2->type() == Device::Disk_Device ) + if (d1->type() == Device::Type::LVM_Device && d2->type() == Device::Type::Disk_Device ) return false; return d1->deviceNode() <= d2->deviceNode(); } void OperationStack::sortDevices() { QWriteLocker lockDevices(&lock()); std::sort(previewDevices().begin(), previewDevices().end(), deviceLessThan); emit devicesChanged(); } diff --git a/src/core/partitiontable.cpp b/src/core/partitiontable.cpp index aca5149..acc2080 100644 --- a/src/core/partitiontable.cpp +++ b/src/core/partitiontable.cpp @@ -1,587 +1,587 @@ /************************************************************************* * Copyright (C) 2008 by Volker Lanz * * Copyright (C) 2016 by Andrius Štikonas * * Copyright (C) 2016 by Teo Mrnjavac * * * * 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 "core/partitiontable.h" #include "core/partition.h" #include "core/device.h" #include "core/diskdevice.h" #include "core/lvmdevice.h" #include "core/partitionalignment.h" #include "fs/filesystem.h" #include "fs/filesystemfactory.h" #include "util/globallog.h" #include #include #include /** Creates a new PartitionTable object with type MSDOS @param type name of the PartitionTable type (e.g. "msdos" or "gpt") */ PartitionTable::PartitionTable(TableType type, qint64 firstUsable, qint64 lastUsable) : PartitionNode() , m_Children() , m_MaxPrimaries(maxPrimariesForTableType(type)) , m_Type(type) , m_FirstUsable(firstUsable) , m_LastUsable(lastUsable) { } /** Copy constructor for PartitionTable. * @param other the other PartitionTable. */ PartitionTable::PartitionTable(const PartitionTable& other) : PartitionNode() , m_Children() , m_MaxPrimaries(other.m_MaxPrimaries) , m_Type(other.m_Type) , m_FirstUsable(other.m_FirstUsable) , m_LastUsable(other.m_LastUsable) { for (Partitions::const_iterator it = other.m_Children.constBegin(); it != other.m_Children.constEnd(); ++it) { m_Children.append(new Partition(**it, this)); } } /** Destroys a PartitionTable object, destroying all children */ PartitionTable::~PartitionTable() { clearChildren(); } /** Gets the number of free sectors before a given child Partition in this PartitionTable. @param p the Partition for which to get the free sectors before @returns the number of free sectors before the Partition */ qint64 PartitionTable::freeSectorsBefore(const Partition& p) const { const Partition* pred = predecessor(p); // due to the space required for extended boot records the // below is NOT the same as pred->length() if (pred && pred->roles().has(PartitionRole::Unallocated)) return p.firstSector() - pred->firstSector(); return 0; } /** Gets the number of free sectors after a given child Partition in this PartitionTable. @param p the Partition for which to get the free sectors after @returns the number of free sectors after the Partition */ qint64 PartitionTable::freeSectorsAfter(const Partition& p) const { const Partition* succ = successor(p); // due to the space required for extended boot records the // below is NOT the same as succ->length() if (succ && succ->roles().has(PartitionRole::Unallocated)) return succ->lastSector() - p.lastSector(); return 0; } qint64 PartitionTable::freeSectors() const { qint64 sectors = 0; for (const auto &p : children()) { if (p->roles().has(PartitionRole::Unallocated)) { sectors += p->length(); } } return sectors; } /** @return true if the PartitionTable has an extended Partition */ bool PartitionTable::hasExtended() const { for (const auto &p : children()) if (p->roles().has(PartitionRole::Extended)) return true; return false; } /** @return pointer to the PartitionTable's extended Partition or nullptr if none exists */ Partition* PartitionTable::extended() const { for (const auto &p : children()) if (p->roles().has(PartitionRole::Extended)) return p; return nullptr; } /** Gets valid PartitionRoles for a Partition @param p the Partition @return valid roles for the given Partition */ PartitionRole::Roles PartitionTable::childRoles(const Partition& p) const { Q_ASSERT(p.parent()); PartitionRole::Roles r = p.parent()->isRoot() ? PartitionRole::Primary : PartitionRole::Logical; if (r == PartitionRole::Primary && hasExtended() == false && tableTypeSupportsExtended(type())) r |= PartitionRole::Extended; return r; } /** @return the number of primaries in this PartitionTable */ int PartitionTable::numPrimaries() const { int result = 0; for (const auto &p : children()) if (p->roles().has(PartitionRole::Primary) || p->roles().has(PartitionRole::Extended)) result++; return result; } /** Appends a Partition to this PartitionTable @param partition pointer of the partition to append. Must not be nullptr. */ void PartitionTable::append(Partition* partition) { children().append(partition); std::sort(children().begin(), children().end(), [] (const Partition *a, const Partition *b) -> bool {return a->firstSector() < b->firstSector();}); } /** @param f the flag to get the name for @returns the flags name or an empty QString if the flag is not known */ QString PartitionTable::flagName(Flag f) { switch (f) { case PartitionTable::FlagBoot: return xi18nc("@item partition flag", "boot"); case PartitionTable::FlagRoot: return xi18nc("@item partition flag", "root"); case PartitionTable::FlagSwap: return xi18nc("@item partition flag", "swap"); case PartitionTable::FlagHidden: return xi18nc("@item partition flag", "hidden"); case PartitionTable::FlagRaid: return xi18nc("@item partition flag", "raid"); case PartitionTable::FlagLvm: return xi18nc("@item partition flag", "lvm"); case PartitionTable::FlagLba: return xi18nc("@item partition flag", "lba"); case PartitionTable::FlagHpService: return xi18nc("@item partition flag", "hpservice"); case PartitionTable::FlagPalo: return xi18nc("@item partition flag", "palo"); case PartitionTable::FlagPrep: return xi18nc("@item partition flag", "prep"); case PartitionTable::FlagMsftReserved: return xi18nc("@item partition flag", "msft-reserved"); case PartitionTable::FlagBiosGrub: return xi18nc("@item partition flag", "bios-grub"); case PartitionTable::FlagAppleTvRecovery: return xi18nc("@item partition flag", "apple-tv-recovery"); case PartitionTable::FlagDiag: return xi18nc("@item partition flag", "diag"); case PartitionTable::FlagLegacyBoot: return xi18nc("@item partition flag", "legacy-boot"); case PartitionTable::FlagMsftData: return xi18nc("@item partition flag", "msft-data"); case PartitionTable::FlagIrst: return xi18nc("@item partition flag", "irst"); case PartitionTable::FlagEsp: return xi18nc("@item partition flag", "esp"); default: break; } return QString(); } /** @return list of all flags */ const QList PartitionTable::flagList() { QList rval; rval.append(PartitionTable::FlagBoot); rval.append(PartitionTable::FlagRoot); rval.append(PartitionTable::FlagSwap); rval.append(PartitionTable::FlagHidden); rval.append(PartitionTable::FlagRaid); rval.append(PartitionTable::FlagLvm); rval.append(PartitionTable::FlagLba); rval.append(PartitionTable::FlagHpService); rval.append(PartitionTable::FlagPalo); rval.append(PartitionTable::FlagPrep); rval.append(PartitionTable::FlagMsftReserved); rval.append(PartitionTable::FlagBiosGrub); rval.append(PartitionTable::FlagAppleTvRecovery); rval.append(PartitionTable::FlagDiag); rval.append(PartitionTable::FlagLegacyBoot); rval.append(PartitionTable::FlagMsftData); rval.append(PartitionTable::FlagIrst); rval.append(PartitionTable::FlagEsp); return rval; } /** @param flags the flags to get the names for @returns QStringList of the flags' names */ QStringList PartitionTable::flagNames(Flags flags) { QStringList rval; int f = 1; QString s; while (!(s = flagName(static_cast(f))).isEmpty()) { if (flags & f) rval.append(s); f <<= 1; } return rval; } bool PartitionTable::getUnallocatedRange(const Device& d, PartitionNode& parent, qint64& start, qint64& end) { - if (d.type() == Device::Disk_Device) { + if (d.type() == Device::Type::Disk_Device) { const DiskDevice& device = dynamic_cast(d); if (!parent.isRoot()) { Partition* extended = dynamic_cast(&parent); if (extended == nullptr) { qWarning() << "extended is null. start: " << start << ", end: " << end << ", device: " << device.deviceNode(); return false; } // Leave a track (cylinder aligned) or sector alignment sectors (sector based) free at the // start for a new partition's metadata start += device.partitionTable()->type() == PartitionTable::msdos ? device.sectorsPerTrack() : PartitionAlignment::sectorAlignment(device); // .. and also at the end for the metadata for a partition to follow us, if we're not // at the end of the extended partition if (end < extended->lastSector()) end -= device.partitionTable()->type() == PartitionTable::msdos ? device.sectorsPerTrack() : PartitionAlignment::sectorAlignment(device); } return end - start + 1 >= PartitionAlignment::sectorAlignment(device); - } else if (d.type() == Device::LVM_Device) { + } else if (d.type() == Device::Type::LVM_Device) { if (end - start + 1 > 0) { return true; } } return false; } /** Creates a new unallocated Partition on the given Device. @param device the Device to create the new Partition on @param parent the parent PartitionNode for the new Partition @param start the new Partition's start sector @param end the new Partition's end sector @return pointer to the newly created Partition object or nullptr if the Partition could not be created */ Partition* createUnallocated(const Device& device, PartitionNode& parent, qint64 start, qint64 end) { PartitionRole::Roles r = PartitionRole::Unallocated; if (!parent.isRoot()) r |= PartitionRole::Logical; // Mark unallocated space in LVM VG as LVM LV so that pasting can be easily disabled (it does not work yet) - if (device.type() == Device::LVM_Device) + if (device.type() == Device::Type::LVM_Device) r |= PartitionRole::Lvm_Lv; if (!PartitionTable::getUnallocatedRange(device, parent, start, end)) return nullptr; return new Partition(&parent, device, PartitionRole(r), FileSystemFactory::create(FileSystem::Type::Unknown, start, end, device.logicalSize()), start, end, QString()); } /** Removes all unallocated children from a PartitionNode @param p pointer to the parent to remove unallocated children from */ void PartitionTable::removeUnallocated(PartitionNode* p) { Q_ASSERT(p); qint32 i = 0; while (i < p->children().size()) { Partition* child = p->children()[i]; if (child->roles().has(PartitionRole::Unallocated)) { p->remove(child); delete child; continue; } if (child->roles().has(PartitionRole::Extended)) removeUnallocated(child); i++; } } /** @overload */ void PartitionTable::removeUnallocated() { removeUnallocated(this); } /** Inserts unallocated children for a Device's PartitionTable with the given parent. This method inserts unallocated Partitions for a parent, usually the Device this PartitionTable is on. It will also insert unallocated Partitions in any extended Partitions it finds. @warning This method assumes that no unallocated Partitions exist when it is called. @param d the Device this PartitionTable and @p p are on @param p the parent PartitionNode (may be this or an extended Partition) @param start the first sector to begin looking for free space */ void PartitionTable::insertUnallocated(const Device& d, PartitionNode* p, qint64 start) { Q_ASSERT(p); qint64 lastEnd = start; - if (d.type() == Device::LVM_Device && !p->children().isEmpty()) { + if (d.type() == Device::Type::LVM_Device && !p->children().isEmpty()) { // rearranging the sectors of all partitions to keep unallocated space at the end lastEnd = 0; std::sort(children().begin(), children().end(), [](const Partition* p1, const Partition* p2) { return p1->deviceNode() < p2->deviceNode(); }); for (const auto &child : children()) { qint64 totalSectors = child->length(); child->setFirstSector(lastEnd); child->setLastSector(lastEnd + totalSectors - 1); lastEnd += totalSectors; } } else { const auto pChildren = p->children(); for (const auto &child : pChildren) { p->insert(createUnallocated(d, *p, lastEnd, child->firstSector() - 1)); if (child->roles().has(PartitionRole::Extended)) insertUnallocated(d, child, child->firstSector()); lastEnd = child->lastSector() + 1; } } // Take care of the free space between the end of the last child and the end // of the device or the extended partition. qint64 parentEnd = lastUsable(); if (!p->isRoot()) { Partition* extended = dynamic_cast(p); parentEnd = extended ? extended->lastSector() : -1; Q_ASSERT(extended); } if (parentEnd >= firstUsable() && parentEnd >= lastEnd) p->insert(createUnallocated(d, *p, lastEnd, parentEnd)); } /** Updates the unallocated Partitions for this PartitionTable. @param d the Device this PartitionTable is on */ void PartitionTable::updateUnallocated(const Device& d) { removeUnallocated(); insertUnallocated(d, this, firstUsable()); } qint64 PartitionTable::defaultFirstUsable(const Device& d, TableType t) { Q_UNUSED(t) - if (d.type() == Device::LVM_Device) { + if (d.type() == Device::Type::LVM_Device) { return 0; } const DiskDevice& diskDevice = dynamic_cast(d); return PartitionAlignment::sectorAlignment(diskDevice); } qint64 PartitionTable::defaultLastUsable(const Device& d, TableType t) { if (t == gpt) return d.totalLogical() - 1 - 32 - 1; return d.totalLogical() - 1; } static struct { const QLatin1String name; /**< name of partition table type */ quint32 maxPrimaries; /**< max numbers of primary partitions supported */ bool canHaveExtended; /**< does partition table type support extended partitions */ bool isReadOnly; /**< does KDE Partition Manager support this only in read only mode */ PartitionTable::TableType type; /**< enum type */ } tableTypes[] = { { QLatin1String("aix"), 4, false, true, PartitionTable::aix }, { QLatin1String("bsd"), 8, false, true, PartitionTable::bsd }, { QLatin1String("dasd"), 1, false, true, PartitionTable::dasd }, { QLatin1String("msdos"), 4, true, false, PartitionTable::msdos }, { QLatin1String("msdos"), 4, true, false, PartitionTable::msdos_sectorbased }, { QLatin1String("dos"), 4, true, false, PartitionTable::msdos_sectorbased }, { QLatin1String("dvh"), 16, true, true, PartitionTable::dvh }, { QLatin1String("gpt"), 128, false, false, PartitionTable::gpt }, { QLatin1String("loop"), 1, false, true, PartitionTable::loop }, { QLatin1String("mac"), 0xffff, false, true, PartitionTable::mac }, { QLatin1String("pc98"), 16, false, true, PartitionTable::pc98 }, { QLatin1String("amiga"), 128, false, true, PartitionTable::amiga }, { QLatin1String("sun"), 8, false, true, PartitionTable::sun }, { QLatin1String("vmd"), 0xffff, false, false, PartitionTable::vmd } }; PartitionTable::TableType PartitionTable::nameToTableType(const QString& n) { for (const auto &type : tableTypes) if (n == type.name) return type.type; return PartitionTable::unknownTableType; } QString PartitionTable::tableTypeToName(TableType l) { for (const auto &type : tableTypes) if (l == type.type) return type.name; return xi18nc("@item partition table name", "unknown"); } qint32 PartitionTable::maxPrimariesForTableType(TableType l) { for (const auto &type : tableTypes) if (l == type.type) return type.maxPrimaries; return 1; } bool PartitionTable::tableTypeSupportsExtended(TableType l) { for (const auto &type : tableTypes) if (l == type.type) return type.canHaveExtended; return false; } bool PartitionTable::tableTypeIsReadOnly(TableType l) { for (const auto &type : tableTypes) if (l == type.type) return type.isReadOnly; return false; } /** Simple heuristic to determine if the PartitionTable is sector aligned (i.e. if its Partitions begin at sectors evenly divisable by PartitionAlignment::sectorAlignment(). @return true if is sector aligned, otherwise false */ bool PartitionTable::isSectorBased(const Device& d) const { - if (d.type() == Device::Disk_Device) { + if (d.type() == Device::Type::Disk_Device) { const DiskDevice& diskDevice = dynamic_cast(d); if (type() == PartitionTable::msdos) { // the default for empty partition tables is sector based if (numPrimaries() == 0) return true; quint32 numCylinderAligned = 0; quint32 numSectorAligned = 0; // see if we have more cylinder aligned partitions than sector // aligned ones. for (const auto &p : children()) { if (p->firstSector() % PartitionAlignment::sectorAlignment(diskDevice) == 0) numSectorAligned++; else if (p->firstSector() % diskDevice.cylinderSize() == 0) numCylinderAligned++; } return numSectorAligned >= numCylinderAligned; } return type() == PartitionTable::msdos_sectorbased; } return false; } void PartitionTable::setType(const Device& d, TableType t) { setFirstUsableSector(defaultFirstUsable(d, t)); setLastUsableSector(defaultLastUsable(d, t)); m_Type = t; updateUnallocated(d); } QTextStream& operator<<(QTextStream& stream, const PartitionTable& ptable) { stream << "type: \"" << ptable.typeName() << "\"\n" << "align: \"" << (ptable.type() == PartitionTable::msdos ? "cylinder" : "sector") << "\"\n" << "\n# number start end type roles label flags\n"; QList partitions; for (const auto &p : ptable.children()) { if (!p->roles().has(PartitionRole::Unallocated)) { partitions.append(p); if (p->roles().has(PartitionRole::Extended)) { const auto partChildren = p->children(); for (const auto &child : partChildren) { if (!child->roles().has(PartitionRole::Unallocated)) partitions.append(child); } } } } std::sort(partitions.begin(), partitions.end(), [](const Partition* p1, const Partition* p2) { return p1->number() < p2->number(); }); for (const auto &p : qAsConst(partitions)) stream << *p; return stream; } diff --git a/src/core/volumemanagerdevice.h b/src/core/volumemanagerdevice.h index 60dd4d3..891aa68 100644 --- a/src/core/volumemanagerdevice.h +++ b/src/core/volumemanagerdevice.h @@ -1,96 +1,96 @@ /************************************************************************* * Copyright (C) 2016 by Chantara Tith * * * * 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_VOLUMEMANAGERDEVICE_H #define KPMCORE_VOLUMEMANAGERDEVICE_H #include "util/libpartitionmanagerexport.h" #include "core/device.h" #include #include #include #include class VolumeManagerDevicePrivate; /** A Volume Manager of physical devices represented as an abstract device. * * VolumeManagerDevice is an abstract device class for volume manager. e.g: LVM, SoftRAID. * example of physical device: /dev/sda, /dev/sdb1. * * Devices are the outermost entity; they contain a PartitionTable that itself contains Partitions. * * @see Device, PartitionTable, Partition */ class LIBKPMCORE_EXPORT VolumeManagerDevice : public Device { Q_DISABLE_COPY(VolumeManagerDevice) public: - VolumeManagerDevice(std::shared_ptr d, const QString& name, const QString& deviceNode, const qint64 logicalSectorSize, const qint64 totalLogical, const QString& iconName = QString(), Device::Type type = Device::Unknown_Device); + VolumeManagerDevice(std::shared_ptr d, const QString& name, const QString& deviceNode, const qint64 logicalSectorSize, const qint64 totalLogical, const QString& iconName = QString(), Device::Type type = Device::Type::Unknown_Device); /** * @return list of physical device's path that makes up volumeManagerDevice.(e.g: /dev/sda, /dev/sdb1) */ virtual const QStringList deviceNodes() const = 0; /** * @return list of logical partition's path. */ virtual const QStringList partitionNodes() const = 0; /** * @return size of logical partition at the given path in bytes. */ virtual qint64 partitionSize(QString& partitionPath) const = 0; protected: /** Initialize device's partition table and partitions. * */ virtual void initPartitions() = 0; /** absolute sector as represented inside the device's partitionTable * * For VolumeMangerDevice to works with the rest of the codebase, partitions are stringed * one after another to create a representation of PartitionTable and partition just like * real disk device. * * @param partitionPath logical partition path * @sector sector value to be mapped (if 0, will return start sector of the partition) * @return absolute sector value as represented inside device's partitionTable */ virtual qint64 mappedSector(const QString& partitionPath, qint64 sector) const = 0; public: /** join deviceNodes together into comma-separated list * * @return comma-separated list of deviceNodes */ virtual QString prettyDeviceNodeList() const; /** Resize device total number of logical sectors. * * @param n Number of sectors. */ void setTotalLogical(qint64 n); }; #endif diff --git a/src/jobs/createfilesystemjob.cpp b/src/jobs/createfilesystemjob.cpp index c4894e3..264f219 100644 --- a/src/jobs/createfilesystemjob.cpp +++ b/src/jobs/createfilesystemjob.cpp @@ -1,92 +1,92 @@ /************************************************************************* * Copyright (C) 2008, 2011 by Volker Lanz * * 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 "jobs/createfilesystemjob.h" #include "backend/corebackend.h" #include "backend/corebackendmanager.h" #include "backend/corebackenddevice.h" #include "backend/corebackendpartitiontable.h" #include "core/device.h" #include "core/partition.h" #include "fs/filesystem.h" #include "util/report.h" #include /** Creates a new CreateFileSystemJob @param p the Partition the FileSystem to create is on */ CreateFileSystemJob::CreateFileSystemJob(Device& d, Partition& p, const QString& label) : Job(), m_Device(d), m_Partition(p), m_Label(label) { } bool CreateFileSystemJob::run(Report& parent) { bool rval = false; Report* report = jobStarted(parent); if (partition().fileSystem().type() == FileSystem::Type::Unformatted) return true; bool createResult; if (partition().fileSystem().supportCreate() == FileSystem::cmdSupportFileSystem) { if (partition().fileSystem().supportCreateWithLabel() == FileSystem::cmdSupportFileSystem) createResult = partition().fileSystem().createWithLabel(*report, partition().deviceNode(), m_Label); else createResult = partition().fileSystem().create(*report, partition().deviceNode()); if (createResult) { - if (device().type() == Device::Disk_Device) { + if (device().type() == Device::Type::Disk_Device) { std::unique_ptr backendDevice = CoreBackendManager::self()->backend()->openDevice(device()); if (backendDevice) { std::unique_ptr backendPartitionTable = backendDevice->openPartitionTable(); if (backendPartitionTable) { if (backendPartitionTable->setPartitionSystemType(*report, partition())) { rval = true; backendPartitionTable->commit(); } else report->line() << xi18nc("@info:progress", "Failed to set the system type for the file system on partition %1.", partition().deviceNode()); } else report->line() << xi18nc("@info:progress", "Could not open partition table on device %1 to set the system type for partition %2.", device().deviceNode(), partition().deviceNode()); } else report->line() << xi18nc("@info:progress", "Could not open device %1 to set the system type for partition %2.", device().deviceNode(), partition().deviceNode()); - } else if (device().type() == Device::LVM_Device) { + } else if (device().type() == Device::Type::LVM_Device) { rval = true; } } } jobFinished(*report, rval); return rval; } QString CreateFileSystemJob::description() const { return xi18nc("@info:progress", "Create file system %1 on partition %2", partition().fileSystem().name(), partition().deviceNode()); } diff --git a/src/jobs/createpartitionjob.cpp b/src/jobs/createpartitionjob.cpp index a67a132..79f635e 100644 --- a/src/jobs/createpartitionjob.cpp +++ b/src/jobs/createpartitionjob.cpp @@ -1,93 +1,93 @@ /************************************************************************* * Copyright (C) 2008 by Volker Lanz * * 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 "jobs/createpartitionjob.h" #include "backend/corebackend.h" #include "backend/corebackendmanager.h" #include "backend/corebackenddevice.h" #include "backend/corebackendpartitiontable.h" #include "core/partition.h" #include "core/device.h" #include "core/lvmdevice.h" #include "util/report.h" #include /** Creates a new CreatePartitionJob @param d the Device the Partition to be created will be on @param p the Partition to create */ CreatePartitionJob::CreatePartitionJob(Device& d, Partition& p) : Job(), m_Device(d), m_Partition(p) { } bool CreatePartitionJob::run(Report& parent) { Q_ASSERT(partition().devicePath() == device().deviceNode()); bool rval = false; Report* report = jobStarted(parent); - if (device().type() == Device::Disk_Device) { + if (device().type() == Device::Type::Disk_Device) { std::unique_ptr backendDevice = CoreBackendManager::self()->backend()->openDevice(device()); if (backendDevice) { std::unique_ptr backendPartitionTable = backendDevice->openPartitionTable(); if (backendPartitionTable) { QString partitionPath = backendPartitionTable->createPartition(*report, partition()); if (partitionPath != QString()) { rval = true; partition().setPartitionPath(partitionPath); partition().setState(Partition::StateNone); backendPartitionTable->commit(); } else report->line() << xi18nc("@info/plain", "Failed to add partition %1 to device %2.", partition().deviceNode(), device().deviceNode()); } else report->line() << xi18nc("@info:progress", "Could not open partition table on device %1 to create new partition %2.", device().deviceNode(), partition().deviceNode()); } else report->line() << xi18nc("@info:progress", "Could not open device %1 to create new partition %2.", device().deviceNode(), partition().deviceNode()); - } else if (device().type() == Device::LVM_Device) { + } else if (device().type() == Device::Type::LVM_Device) { LvmDevice& dev = dynamic_cast(device()); partition().setState(Partition::StateNone); QString partPath = partition().partitionPath(); QString lvname = partPath.right(partPath.length() - partPath.lastIndexOf(QStringLiteral("/")) - 1); rval = LvmDevice::createLV(*report, dev, partition(), lvname); } jobFinished(*report, rval); return rval; } QString CreatePartitionJob::description() const { if (partition().number() > 0) return xi18nc("@info:progress", "Create new partition %1", partition().deviceNode()); return xi18nc("@info:progress", "Create new partition on device %1", device().deviceNode()); } diff --git a/src/jobs/createpartitiontablejob.cpp b/src/jobs/createpartitiontablejob.cpp index 8ceb8b9..557a5e4 100644 --- a/src/jobs/createpartitiontablejob.cpp +++ b/src/jobs/createpartitiontablejob.cpp @@ -1,68 +1,68 @@ /************************************************************************* * Copyright (C) 2008 by Volker Lanz * * 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 "jobs/createpartitiontablejob.h" #include "backend/corebackendmanager.h" #include "backend/corebackenddevice.h" #include "backend/corebackend.h" #include "core/device.h" #include "core/partitiontable.h" #include "util/report.h" #include /** Creates a new CreatePartitionTableJob @param d the Device a new PartitionTable is to be created on */ CreatePartitionTableJob::CreatePartitionTableJob(Device& d) : Job(), m_Device(d) { } bool CreatePartitionTableJob::run(Report& parent) { bool rval = false; Report* report = jobStarted(parent); - if (device().type() == Device::Disk_Device) { + if (device().type() == Device::Type::Disk_Device) { std::unique_ptr backendDevice = CoreBackendManager::self()->backend()->openDevice(device()); if (backendDevice != nullptr) { Q_ASSERT(device().partitionTable()); rval = backendDevice->createPartitionTable(*report, *device().partitionTable()); } else report->line() << xi18nc("@info:progress", "Creating partition table failed: Could not open device %1.", device().deviceNode()); - } else if (device().type() == Device::LVM_Device) { + } else if (device().type() == Device::Type::LVM_Device) { //TODO: figure what to do with LVM partitionTable } jobFinished(*report, rval); return rval; } QString CreatePartitionTableJob::description() const { return xi18nc("@info:progress", "Create new partition table on device %1", device().deviceNode()); } diff --git a/src/jobs/deactivatelogicalvolumejob.cpp b/src/jobs/deactivatelogicalvolumejob.cpp index 327ad5c..5ce85da 100644 --- a/src/jobs/deactivatelogicalvolumejob.cpp +++ b/src/jobs/deactivatelogicalvolumejob.cpp @@ -1,62 +1,62 @@ /************************************************************************* * Copyright (C) 2016 by Chantara Tith * * 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 "jobs/deactivatelogicalvolumejob.h" #include "core/lvmdevice.h" #include "core/partition.h" #include "core/partitiontable.h" #include "util/report.h" #include /** Creates a new DeactivateLogicalVolumeJob */ DeactivateLogicalVolumeJob::DeactivateLogicalVolumeJob(const VolumeManagerDevice& d, const QStringList lvPaths) : Job(), m_Device(d), m_LVList(lvPaths) { } bool DeactivateLogicalVolumeJob::run(Report& parent) { bool rval = true; Report* report = jobStarted(parent); - if (device().type() == Device::LVM_Device) { + if (device().type() == Device::Type::LVM_Device) { for (const auto &p : device().partitionTable()->children()) { if (!p->roles().has(PartitionRole::Unallocated)) { if (!LvmDevice::deactivateLV(*report, *p)) { rval = false; } } } } jobFinished(*report, rval); return rval; } QString DeactivateLogicalVolumeJob::description() const { return xi18nc("@info/plain", "Deactivate Logical Volumes: %1", device().prettyDeviceNodeList()); } diff --git a/src/jobs/deactivatevolumegroupjob.cpp b/src/jobs/deactivatevolumegroupjob.cpp index ae56ac6..2cc2ea3 100644 --- a/src/jobs/deactivatevolumegroupjob.cpp +++ b/src/jobs/deactivatevolumegroupjob.cpp @@ -1,59 +1,59 @@ /************************************************************************* * Copyright (C) 2016 by Chantara Tith * * 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 "jobs/deactivatevolumegroupjob.h" #include "core/lvmdevice.h" #include "core/partition.h" #include "util/report.h" #include /** Deactivate LVM Volume Group */ DeactivateVolumeGroupJob::DeactivateVolumeGroupJob(VolumeManagerDevice& d) : Job(), m_Device(d) { } bool DeactivateVolumeGroupJob::run(Report& parent) { bool rval = false; Report* report = jobStarted(parent); - if (device().type() == Device::LVM_Device) { + if (device().type() == Device::Type::LVM_Device) { rval = LvmDevice::deactivateVG(*report, static_cast(device())); } const auto lvmPVs = static_cast(device()).physicalVolumes(); for (auto &p : lvmPVs) { Partition *partition = const_cast(p); partition->setMounted(false); } jobFinished(*report, rval); return rval; } QString DeactivateVolumeGroupJob::description() const { return xi18nc("@info/plain", "Deactivate Volume Group: %1", device().name()); } diff --git a/src/jobs/deletefilesystemjob.cpp b/src/jobs/deletefilesystemjob.cpp index 6ff797e..176f851 100644 --- a/src/jobs/deletefilesystemjob.cpp +++ b/src/jobs/deletefilesystemjob.cpp @@ -1,104 +1,104 @@ /************************************************************************* * Copyright (C) 2012 by Volker Lanz * * 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 "jobs/deletefilesystemjob.h" #include "backend/corebackend.h" #include "backend/corebackendmanager.h" #include "backend/corebackenddevice.h" #include "backend/corebackendpartitiontable.h" #include "core/partition.h" #include "core/device.h" #include "util/helpers.h" #include "util/report.h" #include #include /** Creates a new DeleteFileSystemJob @param d the Device the FileSystem to delete is on @param p the Partition the FileSystem to delete is on */ DeleteFileSystemJob::DeleteFileSystemJob(Device& d, Partition& p) : Job(), m_Device(d), m_Partition(p) { } bool DeleteFileSystemJob::run(Report& parent) { Q_ASSERT(device().deviceNode() == partition().devicePath()); if (device().deviceNode() != partition().devicePath()) { qWarning() << "deviceNode: " << device().deviceNode() << ", partition path: " << partition().devicePath(); return false; } bool rval = false; Report* report = jobStarted(parent); if (isMounted(partition().partitionPath())) { report->line() << xi18nc("@info:progress", "Could not delete file system: file system on %1 is mounted.", partition().deviceNode()); jobFinished(*report, rval); return false; } if (partition().roles().has(PartitionRole::Extended)) { rval = true; - } else if (device().type() == Device::LVM_Device) { + } else if (device().type() == Device::Type::LVM_Device) { rval = true; } else { if (!partition().fileSystem().remove(*report, partition().deviceNode())) { jobFinished(*report, rval); return false; } std::unique_ptr backendDevice = CoreBackendManager::self()->backend()->openDevice(device()); if (backendDevice) { std::unique_ptr backendPartitionTable = backendDevice->openPartitionTable(); if (backendPartitionTable) { rval = backendPartitionTable->clobberFileSystem(*report, partition()); if (!rval) report->line() << xi18nc("@info:progress", "Could not delete file system on %1.", partition().deviceNode()); else backendPartitionTable->commit(); } else report->line() << xi18nc("@info:progress", "Could not open partition table on device %1 to delete file system on %2.", device().deviceNode(), partition().deviceNode()); } else report->line() << xi18nc("@info:progress", "Could not delete file system signature for partition %1: Failed to open device %2.", partition().deviceNode(), device().deviceNode()); } jobFinished(*report, rval); return rval; } QString DeleteFileSystemJob::description() const { return xi18nc("@info:progress", "Delete file system on %1", partition().deviceNode()); } diff --git a/src/jobs/deletepartitionjob.cpp b/src/jobs/deletepartitionjob.cpp index 20bada2..07c30ff 100644 --- a/src/jobs/deletepartitionjob.cpp +++ b/src/jobs/deletepartitionjob.cpp @@ -1,90 +1,90 @@ /************************************************************************* * Copyright (C) 2008 by Volker Lanz * * 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 "jobs/deletepartitionjob.h" #include "backend/corebackend.h" #include "backend/corebackendmanager.h" #include "backend/corebackenddevice.h" #include "backend/corebackendpartitiontable.h" #include "core/partition.h" #include "core/device.h" #include "core/lvmdevice.h" #include "util/report.h" #include #include /** Creates a new DeletePartitionJob @param d the Device the Partition to delete is on @param p the Partition to delete */ DeletePartitionJob::DeletePartitionJob(Device& d, Partition& p) : Job(), m_Device(d), m_Partition(p) { } bool DeletePartitionJob::run(Report& parent) { Q_ASSERT(device().deviceNode() == partition().devicePath()); if (device().deviceNode() != partition().devicePath()) { qWarning() << "deviceNode: " << device().deviceNode() << ", partition path: " << partition().devicePath(); return false; } bool rval = false; Report* report = jobStarted(parent); - if (device().type() == Device::Disk_Device) { + if (device().type() == Device::Type::Disk_Device) { std::unique_ptr backendDevice = CoreBackendManager::self()->backend()->openDevice(device()); if (backendDevice) { std::unique_ptr backendPartitionTable = backendDevice->openPartitionTable(); if (backendPartitionTable) { rval = backendPartitionTable->deletePartition(*report, partition()); if (!rval) report->line() << xi18nc("@info:progress", "Could not delete partition %1.", partition().deviceNode()); else backendPartitionTable->commit(); } else report->line() << xi18nc("@info:progress", "Could not open partition table on device %1 to delete partition %2.", device().deviceNode(), partition().deviceNode()); } else report->line() << xi18nc("@info:progress", "Deleting partition failed: Could not open device %1.", device().deviceNode()); - } else if (device().type() == Device::LVM_Device) { + } else if (device().type() == Device::Type::LVM_Device) { LvmDevice& dev = dynamic_cast(device()); rval = LvmDevice::removeLV(*report, dev, partition()); } jobFinished(*report, rval); return rval; } QString DeletePartitionJob::description() const { return xi18nc("@info:progress", "Delete the partition %1", partition().deviceNode()); } diff --git a/src/jobs/removevolumegroupjob.cpp b/src/jobs/removevolumegroupjob.cpp index d5026ae..97792f7 100644 --- a/src/jobs/removevolumegroupjob.cpp +++ b/src/jobs/removevolumegroupjob.cpp @@ -1,52 +1,52 @@ /************************************************************************* * Copyright (C) 2016 by Chantara Tith * * * * 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 "jobs/removevolumegroupjob.h" #include "core/lvmdevice.h" #include "util/report.h" #include /** Creates a new RemoveVolumeGroupJob */ RemoveVolumeGroupJob::RemoveVolumeGroupJob(VolumeManagerDevice& d) : Job(), m_Device(d) { } bool RemoveVolumeGroupJob::run(Report& parent) { bool rval = false; Report* report = jobStarted(parent); - if (device().type() == Device::LVM_Device) { + if (device().type() == Device::Type::LVM_Device) { rval = LvmDevice::removeVG(*report, dynamic_cast(device())); } jobFinished(*report, rval); return rval; } QString RemoveVolumeGroupJob::description() const { return xi18nc("@info/plain", "Remove Volume Group: %1", device().name()); } diff --git a/src/jobs/setpartgeometryjob.cpp b/src/jobs/setpartgeometryjob.cpp index 153c352..30e218a 100644 --- a/src/jobs/setpartgeometryjob.cpp +++ b/src/jobs/setpartgeometryjob.cpp @@ -1,91 +1,91 @@ /************************************************************************* * Copyright (C) 2008 by Volker Lanz * * 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 "jobs/setpartgeometryjob.h" #include "backend/corebackend.h" #include "backend/corebackendmanager.h" #include "backend/corebackenddevice.h" #include "backend/corebackendpartitiontable.h" #include "core/partition.h" #include "core/device.h" #include "core/lvmdevice.h" #include "util/report.h" #include /** Creates a new SetPartGeometryJob @param d the Device the Partition whose geometry is to be set is on @param p the Partition whose geometry is to be set @param newstart the new start sector for the Partition @param newlength the new length for the Partition @todo Wouldn't it be better to have newfirst (new first sector) and newlast (new last sector) as args instead? Having a length here doesn't seem to be very consistent with the rest of the app, right? */ SetPartGeometryJob::SetPartGeometryJob(Device& d, Partition& p, qint64 newstart, qint64 newlength) : Job(), m_Device(d), m_Partition(p), m_NewStart(newstart), m_NewLength(newlength) { } bool SetPartGeometryJob::run(Report& parent) { bool rval = false; Report* report = jobStarted(parent); - if(device().type() == Device::Disk_Device) { + if(device().type() == Device::Type::Disk_Device) { std::unique_ptr backendDevice = CoreBackendManager::self()->backend()->openDevice(device()); if (backendDevice) { std::unique_ptr backendPartitionTable = backendDevice->openPartitionTable(); if (backendPartitionTable) { rval = backendPartitionTable->updateGeometry(*report, partition(), newStart(), newStart() + newLength() - 1); if (rval) { partition().setFirstSector(newStart()); partition().setLastSector(newStart() + newLength() - 1); backendPartitionTable->commit(); } } } else report->line() << xi18nc("@info:progress", "Could not open device %1 while trying to resize/move partition %2.", device().deviceNode(), partition().deviceNode()); - } else if (device().type() == Device::LVM_Device) { + } else if (device().type() == Device::Type::LVM_Device) { partition().setFirstSector(newStart()); partition().setLastSector(newStart() + newLength() - 1); rval = LvmDevice::resizeLV(*report, partition()); } jobFinished(*report, rval); return rval; } QString SetPartGeometryJob::description() const { return xi18nc("@info:progress", "Set geometry of partition %1: Start sector: %2, length: %3", partition().deviceNode(), newStart(), newLength()); } diff --git a/src/ops/createpartitiontableoperation.cpp b/src/ops/createpartitiontableoperation.cpp index 9260be6..f3ed270 100644 --- a/src/ops/createpartitiontableoperation.cpp +++ b/src/ops/createpartitiontableoperation.cpp @@ -1,102 +1,102 @@ /************************************************************************* * Copyright (C) 2008, 2010 by Volker Lanz * * 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 "ops/createpartitiontableoperation.h" #include "core/device.h" #include "core/partitiontable.h" #include "core/partition.h" #include "jobs/createpartitiontablejob.h" #include #include /** Creates a new CreatePartitionTableOperation. @param d the Device to create the new PartitionTable on @param t the type for the new PartitionTable */ CreatePartitionTableOperation::CreatePartitionTableOperation(Device& d, PartitionTable::TableType t) : Operation(), m_TargetDevice(d), m_OldPartitionTable(targetDevice().partitionTable()), m_PartitionTable(new PartitionTable(t, PartitionTable::defaultFirstUsable(d, t), PartitionTable::defaultLastUsable(d, t))), m_CreatePartitionTableJob(new CreatePartitionTableJob(targetDevice())) { addJob(createPartitionTableJob()); } /** Creates a new CreatePartitionTableOperation. @param d the Device to create the new PartitionTable on @param ptable pointer to the new partition table object. the operation takes ownership. */ CreatePartitionTableOperation::CreatePartitionTableOperation(Device& d, PartitionTable* ptable) : Operation(), m_TargetDevice(d), m_OldPartitionTable(targetDevice().partitionTable()), m_PartitionTable(ptable), m_CreatePartitionTableJob(new CreatePartitionTableJob(targetDevice())) { addJob(createPartitionTableJob()); } CreatePartitionTableOperation::~CreatePartitionTableOperation() { if (status() == StatusPending) delete m_PartitionTable; } bool CreatePartitionTableOperation::targets(const Device& d) const { return d == targetDevice(); } void CreatePartitionTableOperation::preview() { targetDevice().setPartitionTable(partitionTable()); targetDevice().partitionTable()->updateUnallocated(targetDevice()); } void CreatePartitionTableOperation::undo() { targetDevice().setPartitionTable(oldPartitionTable()); if (targetDevice().partitionTable()) targetDevice().partitionTable()->updateUnallocated(targetDevice()); } bool CreatePartitionTableOperation::execute(Report& parent) { targetDevice().setPartitionTable(partitionTable()); return Operation::execute(parent); } /** Can a new partition table be created on a device? @param device pointer to the device, can be nullptr @return true if a new partition table can be created on @p device */ bool CreatePartitionTableOperation::canCreate(const Device* device) { - return (device != nullptr) && (device->partitionTable() == nullptr || !device->partitionTable()->isChildMounted()) && (device->type() != Device::LVM_Device); + return (device != nullptr) && (device->partitionTable() == nullptr || !device->partitionTable()->isChildMounted()) && (device->type() != Device::Type::LVM_Device); } QString CreatePartitionTableOperation::description() const { return xi18nc("@info:status", "Create a new partition table (type: %1) on %2", partitionTable()->typeName(), targetDevice().deviceNode()); } diff --git a/src/ops/deactivatevolumegroupoperation.cpp b/src/ops/deactivatevolumegroupoperation.cpp index a002e84..2a2db83 100644 --- a/src/ops/deactivatevolumegroupoperation.cpp +++ b/src/ops/deactivatevolumegroupoperation.cpp @@ -1,76 +1,76 @@ /************************************************************************* * Copyright (C) 2016 by Chantara Tith * * * * 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 "ops/deactivatevolumegroupoperation.h" #include "jobs/deactivatevolumegroupjob.h" #include "jobs/deactivatelogicalvolumejob.h" #include "core/volumemanagerdevice.h" #include "core/partitiontable.h" #include "core/partition.h" #include #include /** Creates a new RemoveVolumeGroupOperation. */ DeactivateVolumeGroupOperation::DeactivateVolumeGroupOperation(VolumeManagerDevice& d) : Operation(), m_DeactivateVolumeGroupJob(new DeactivateVolumeGroupJob(d)), m_DeactivateLogicalVolumeJob(new DeactivateLogicalVolumeJob(d)), m_Device(d), m_PartitionTable(d.partitionTable()) { addJob(deactivateLogicalVolumeJob()); addJob(deactivateVolumeGroupJob()); } QString DeactivateVolumeGroupOperation::description() const { return xi18nc("@info/plain", "Deactivate volume group."); } void DeactivateVolumeGroupOperation::preview() { m_PartitionTable = device().partitionTable(); device().setPartitionTable(new PartitionTable(PartitionTable::vmd, 0, device().totalLogical() - 1)); } void DeactivateVolumeGroupOperation::undo() { device().setPartitionTable(m_PartitionTable); } /** loop through given device's partitions to check if any is mounted. * * @param dev VolumeManagerDevice with initialized partitions * @return false if any of the device's partition is mounted. */ bool DeactivateVolumeGroupOperation::isDeactivatable(const VolumeManagerDevice* dev) { - if (dev->type() == Device::LVM_Device) { + if (dev->type() == Device::Type::LVM_Device) { for (const auto &p : dev->partitionTable()->children()) { if (p->isMounted()) { return false; } } return true; } return false; } diff --git a/src/ops/removevolumegroupoperation.cpp b/src/ops/removevolumegroupoperation.cpp index b523c83..605de3b 100644 --- a/src/ops/removevolumegroupoperation.cpp +++ b/src/ops/removevolumegroupoperation.cpp @@ -1,75 +1,75 @@ /************************************************************************* * Copyright (C) 2016 by Chantara Tith * * * * 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 "ops/removevolumegroupoperation.h" #include "jobs/removevolumegroupjob.h" #include "core/partition.h" #include "core/partitiontable.h" #include "core/volumemanagerdevice.h" #include #include /** Creates a new RemoveVolumeGroupOperation. */ RemoveVolumeGroupOperation::RemoveVolumeGroupOperation(VolumeManagerDevice& d) : Operation(), m_RemoveVolumeGroupJob(new RemoveVolumeGroupJob(d)), m_Device(d), m_PartitionTable(nullptr) { addJob(removeVolumeGroupJob()); } QString RemoveVolumeGroupOperation::description() const { return xi18nc("@info/plain", "Remove a LVM volume group."); } void RemoveVolumeGroupOperation::preview() { m_PartitionTable = device().partitionTable(); device().setPartitionTable(new PartitionTable(PartitionTable::vmd, 0, device().totalLogical() - 1)); } void RemoveVolumeGroupOperation::undo() { device().setPartitionTable(m_PartitionTable); } /** Check if Volume Group can be safely removed * * @param dev VolumeManagerDevice with initialized partitions * @return true if there are no LVM partitions. */ bool RemoveVolumeGroupOperation::isRemovable(const VolumeManagerDevice* dev) { // TODO: allow removal when LVs are inactive. - if (dev->type() == Device::LVM_Device) { + if (dev->type() == Device::Type::LVM_Device) { if (dev->partitionTable()->children().count() == 0) // This is necessary to prevent a crash during applying of operations return true; else if (dev->partitionTable()->children().count() > 1) return false; else if (dev->partitionTable()->children().first()->fileSystem().type() == FileSystem::Type::Unknown) return true; } return false; }