LVM support #6

Closed
andrius wants to merge 109 commits from (deleted):lvm-support-rebase into master
83 changed files with 3152 additions and 549 deletions

View File

@ -16,6 +16,9 @@ set(CORE_SRC
core/partitionnode.cpp
core/partitionalignment.cpp
core/device.cpp
core/diskdevice.cpp
core/volumemanagerdevice.cpp
core/lvmdevice.cpp
core/operationstack.cpp
core/partitionrole.cpp
)
@ -26,6 +29,9 @@ set(CORE_LIB_HDRS
core/copytarget.h
core/copytargetdevice.h
core/device.h
core/diskdevice.h
core/volumemanagerdevice.h
core/lvmdevice.h
core/devicescanner.h
core/mountentry.h
core/operationrunner.h

View File

@ -60,7 +60,7 @@ bool CopySourceDevice::open()
*/
qint32 CopySourceDevice::sectorSize() const
{
return device().logicalSectorSize();
return device().logicalSize();
}
/** Returns the length of this CopySource

View File

@ -56,7 +56,7 @@ bool CopyTargetDevice::open()
/** @return the Device's sector size */
qint32 CopyTargetDevice::sectorSize() const
{
return device().logicalSectorSize();
return device().logicalSize();
}
/** Writes the given number of sectors to the Device.

View File

@ -17,7 +17,6 @@
*************************************************************************/
#include "core/device.h"
#include "core/partitiontable.h"
#include "core/smartstatus.h"
@ -25,73 +24,25 @@
#include <KLocalizedString>
#include <QFile>
#include <QByteArray>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/fs.h>
#if !defined(BLKPBSZGET)
#define BLKPBSZGET _IO(0x12,123)/* get block physical sector size */
#endif
static qint32 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-ng 2.17 or later
* TODO: implement the blkid method
*/
#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 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
@param deviceNode the Device's node, for example "/dev/sda"
*/
Device::Device(const QString& name, const QString& devicenode, qint32 heads, qint32 numSectors, qint32 cylinders, qint64 sectorSize, const QString& iconname) :
QObject(),
m_Name(name.length() > 0 ? name : i18n("Unknown Device")),
m_DeviceNode(devicenode),
m_PartitionTable(nullptr),
m_Heads(heads),
m_SectorsPerTrack(numSectors),
m_Cylinders(cylinders),
m_LogicalSectorSize(sectorSize),
m_PhysicalSectorSize(getPhysicalSectorSize(devicenode)),
m_IconName(iconname.isEmpty() ? QStringLiteral("drive-harddisk") : iconname),
m_SmartStatus(new SmartStatus(devicenode))
Device::Device(const QString& name,
const QString& deviceNode,
const qint32 logicalSize,
const qint64 totalLogical,
const QString& iconName,
Device::Type type)
: QObject()
, m_Name(name.length() > 0 ? name : i18n("Unknown Device"))
, m_DeviceNode(deviceNode)
, m_LogicalSize(logicalSize)
, m_TotalLogical(totalLogical)
, m_PartitionTable(nullptr)
, m_IconName(iconName.isEmpty() ? QStringLiteral("drive-harddisk") : iconName)
, m_SmartStatus(type == Device::Disk_Device ? new SmartStatus(deviceNode) : nullptr)
, m_Type(type)
{
}

View File

@ -23,14 +23,13 @@
#include <QString>
#include <QObject>
#include <QtGlobal>
class PartitionTable;
class CreatePartitionTableOperation;
class CoreBackend;
class SmartStatus;
/** A device.
/** A abstract device interface.
Represents a device like /dev/sda.
@ -47,81 +46,81 @@ class LIBKPMCORE_EXPORT Device : public QObject
friend class CoreBackend;
public:
Device(const QString& name, const QString& devicenode, qint32 heads, qint32 numSectors, qint32 cylinders, qint64 sectorSize, const QString& iconname = QString());
~Device();
enum Type {
Disk_Device = 0,
LVM_Device = 1, /* VG */
RAID_Device = 2, /* software RAID device */
Unknown_Device = 4
};
protected:
Device(const QString& name, const QString& deviceNode, const qint32 logicalSize, const qint64 totalLogical, const QString& iconName = QString(), Device::Type type = Device::Disk_Device);
public:
bool operator==(const Device& other) const;
bool operator!=(const Device& other) const;
virtual ~Device();
const QString& name() const {
public:
virtual bool operator==(const Device& other) const;
virtual bool operator!=(const Device& other) const;
virtual const QString& name() const {
return m_Name; /**< @return the Device's name, usually some manufacturer string */
}
const QString& deviceNode() const {
virtual const QString& deviceNode() const {
return m_DeviceNode; /**< @return the Device's node, for example "/dev/sda" */
}
PartitionTable* partitionTable() {
virtual PartitionTable* partitionTable() {
return m_PartitionTable; /**< @return the Device's PartitionTable */
}
const PartitionTable* partitionTable() const {
virtual const PartitionTable* partitionTable() const {
return m_PartitionTable; /**< @return the Device's PartitionTable */
}
qint32 heads() const {
return m_Heads; /**< @return the number of heads on the Device in CHS notation */
}
qint32 cylinders() const {
return m_Cylinders; /**< @return the number of cylinders on the Device in CHS notation */
}
qint32 sectorsPerTrack() const {
return m_SectorsPerTrack; /**< @return the number of sectors on the Device in CHS notation */
}
qint32 physicalSectorSize() const {
return m_PhysicalSectorSize; /**< @return the physical sector size the Device uses or -1 if unknown */
}
qint32 logicalSectorSize() const {
return m_LogicalSectorSize; /**< @return the logical sector size the Device uses */
}
qint64 totalSectors() const {
return static_cast<qint64>(heads()) * cylinders() * sectorsPerTrack(); /**< @return the total number of sectors on the device */
}
qint64 capacity() const {
return totalSectors() * logicalSectorSize(); /**< @return the Device's capacity in bytes */
}
qint64 cylinderSize() const {
return static_cast<qint64>(heads()) * sectorsPerTrack(); /**< @return the size of a cylinder on this Device in sectors */
}
void setIconName(const QString& name) {
virtual qint64 capacity() const { /**< @return the Device's capacity in bytes */
return logicalSize() * totalLogical();
}
virtual void setIconName(const QString& name) {
m_IconName = name;
}
const QString& iconName() const {
virtual const QString& iconName() const {
return m_IconName; /**< @return suggested icon name for this Device */
}
SmartStatus& smartStatus() {
virtual SmartStatus& smartStatus() {
return *m_SmartStatus;
}
const SmartStatus& smartStatus() const {
virtual const SmartStatus& smartStatus() const {
return *m_SmartStatus;
}
QString prettyName() const;
void setPartitionTable(PartitionTable* ptable) {
virtual void setPartitionTable(PartitionTable* ptable) {
m_PartitionTable = ptable;
}
private:
virtual qint32 logicalSize() const {
return m_LogicalSize;
}
virtual qint64 totalLogical() const {
return m_TotalLogical;
}
virtual Device::Type type() const {
return m_Type;
}
virtual QString prettyName() const;
protected:
QString m_Name;
QString m_DeviceNode;
qint32 m_LogicalSize;
qint64 m_TotalLogical;
PartitionTable* m_PartitionTable;
qint32 m_Heads;
qint32 m_SectorsPerTrack;
qint32 m_Cylinders;
qint32 m_LogicalSectorSize;
qint32 m_PhysicalSectorSize;
QString m_IconName;
SmartStatus* m_SmartStatus;
Device::Type m_Type;
};
#endif

View File

@ -23,6 +23,12 @@
#include "core/operationstack.h"
#include "core/device.h"
#include "core/lvmdevice.h"
#include "core/diskdevice.h"
#include "util/externalcommand.h"
#include <QRegularExpression>
#include <QDebug>
/** Constructs a DeviceScanner
@param ostack the OperationStack where the devices will be created
@ -56,10 +62,16 @@ void DeviceScanner::scan()
clear();
QList<Device*> deviceList = CoreBackendManager::self()->backend()->scanDevices();
const QList<Device*> deviceList = CoreBackendManager::self()->backend()->scanDevices();
const QList<LvmDevice*> lvmList = LvmDevice::scanSystemLVM();
foreach(Device * d, deviceList)
for (const auto &d : deviceList)
operationStack().addDevice(d);
operationStack().sortDevices();
for (const auto &d : lvmList)
operationStack().addDevice(d);
}

View File

@ -43,7 +43,7 @@ public:
void setupConnections();
Q_SIGNALS:
void progress(const QString& device_node, int progress);
void progress(const QString& deviceNode, int progress);
protected:
void run() override;

95
src/core/diskdevice.cpp Normal file
View File

@ -0,0 +1,95 @@
/*************************************************************************
* Copyright (C) 2008 by Volker Lanz <vl@fidra.de> *
* Copyright (C) 2016 by Andrius Štikonas <andrius@stikonas.eu> *
* *
* 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 <http://www.gnu.org/licenses/>.*
*************************************************************************/
#include "core/diskdevice.h"
#include "core/partitiontable.h"
#include "core/smartstatus.h"
#include <KLocalizedString>
#include <QFile>
#include <QByteArray>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/fs.h>
#if !defined(BLKPBSZGET)
#define BLKPBSZGET _IO(0x12,123)/* get block physical sector size */
#endif
static qint32 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-ng 2.17 or later
* TODO: implement the blkid method
*/
#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,
qint32 sectorSize,
const QString& iconName)
: Device(name, deviceNode, sectorSize, (static_cast<qint64>(heads) * cylinders * numSectors), iconName, Device::Disk_Device)
, m_Heads(heads)
, m_SectorsPerTrack(numSectors)
, m_Cylinders(cylinders)
, m_LogicalSectorSize(sectorSize)
, m_PhysicalSectorSize(getPhysicalSectorSize(deviceNode))
{
}

84
src/core/diskdevice.h Normal file
View File

@ -0,0 +1,84 @@
/*************************************************************************
* Copyright (C) 2008 by Volker Lanz <vl@fidra.de> *
* *
* 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 <http://www.gnu.org/licenses/>.*
*************************************************************************/
#if !defined(DISKDEVICE__H)
#define DISKDEVICE__H
#include "util/libpartitionmanagerexport.h"
#include "core/device.h"
#include <QString>
#include <QObject>
#include <QtGlobal>
class PartitionTable;
class CreatePartitionTableOperation;
class CoreBackend;
class SmartStatus;
/** A disk device.
Represents a device like /dev/sda.
Devices are the outermost entity; they contain a PartitionTable that itself contains Partitions.
@see PartitionTable, Partition
@author Volker Lanz <vl@fidra.de>
*/
class LIBKPMCORE_EXPORT DiskDevice : public Device
{
Q_DISABLE_COPY(DiskDevice)
friend class CreatePartitionTableOperation;
friend class CoreBackend;
public:
DiskDevice(const QString& name, const QString& deviceNode, qint32 heads, qint32 numSectors, qint32 cylinders, qint32 sectorSize, const QString& iconName = QString());
public:
qint32 heads() const {
return m_Heads; /**< @return the number of heads on the Device in CHS notation */
}
qint32 cylinders() const {
return m_Cylinders; /**< @return the number of cylinders on the Device in CHS notation */
}
qint32 sectorsPerTrack() const {
return m_SectorsPerTrack; /**< @return the number of sectors on the Device in CHS notation */
}
qint32 physicalSectorSize() const {
return m_PhysicalSectorSize; /**< @return the physical sector size the Device uses or -1 if unknown */
}
qint32 logicalSectorSize() const {
return m_LogicalSectorSize; /**< @return the logical sector size the Device uses */
}
qint64 totalSectors() const {
return static_cast<qint64>(heads()) * cylinders() * sectorsPerTrack(); /**< @return the total number of sectors on the device */
}
qint64 cylinderSize() const {
return static_cast<qint64>(heads()) * sectorsPerTrack(); /**< @return the size of a cylinder on this Device in sectors */
}
private:
qint32 m_Heads;
qint32 m_SectorsPerTrack;
qint32 m_Cylinders;
qint32 m_LogicalSectorSize;
qint32 m_PhysicalSectorSize;
};
#endif

507
src/core/lvmdevice.cpp Normal file
View File

@ -0,0 +1,507 @@
/*************************************************************************
* Copyright (C) 2016 by Chantara Tith <tith.chantara@gmail.com> *
* *
* 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 <http://www.gnu.org/licenses/>.*
*************************************************************************/
#include "core/lvmdevice.h"
#include "core/partition.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 <QRegularExpression>
#include <KDiskFreeSpaceInfo>
#include <KLocalizedString>
#include <KMountPoint>
/** 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(vgName,
(QStringLiteral("/dev/") + vgName),
getPeSize(vgName),
getTotalPE(vgName),
iconName,
Device::LVM_Device)
{
m_peSize = logicalSize();
m_totalPE = totalLogical();
m_freePE = getFreePE(vgName);
m_allocPE = m_totalPE - m_freePE;
m_UUID = getUUID(vgName);
m_PVPathList = new QStringList(getPVs(vgName));
m_LVPathList = new QStringList(getLVs(vgName));
m_LVSizeMap = new QMap<QString, qint64>();
initPartitions();
}
/**
* shared list of PV's paths that will be added to any VGs.
* (have been added to an operation, but not yet applied)
*/
QStringList LvmDevice::s_DirtyPVs;
LvmDevice::~LvmDevice()
{
delete m_PVPathList;
delete m_LVPathList;
delete 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 a initialized Partition(LV) list
*/
const QList<Partition*> LvmDevice::scanPartitions(PartitionTable* pTable) const
{
QList<Partition*> 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);
bool mounted = isMounted(lvPath);
QString mountPoint = QString();
KMountPoint::List mountPointList = KMountPoint::currentMountPoints(KMountPoint::NeedRealDeviceName);
mountPointList.append(KMountPoint::possibleMountPoints(KMountPoint::NeedRealDeviceName));
PartitionRole::Roles r = PartitionRole::Lvm_Lv;
if (type == FileSystem::Luks) {
r |= PartitionRole::Luks;
FS::luks* luksFs = static_cast<FS::luks*>(fs);
QString mapperNode = FS::luks::mapperName(lvPath);
bool isCryptOpen = !mapperNode.isEmpty();
luksFs->setCryptOpen(isCryptOpen);
luksFs->setLogicalSectorSize(logicalSize());
if (isCryptOpen) {
luksFs->loadInnerFileSystem(lvPath, mapperNode);
mountPoint = mountPointList.findByDevice(mapperNode) ?
mountPointList.findByDevice(mapperNode)->mountPoint() :
QString();
mounted = isMounted(mapperNode);
if (mounted) {
const KDiskFreeSpaceInfo freeSpaceInfo = KDiskFreeSpaceInfo::freeSpaceInfo(mountPoint);
if (freeSpaceInfo.isValid() && mountPoint != QString())
luksFs->setSectorsUsed((freeSpaceInfo.used() + luksFs->getPayloadOffset(lvPath)) / logicalSize());
}
} else {
mounted = false;
}
luksFs->setMounted(mounted);
} else {
mountPoint = mountPointList.findByDevice(lvPath) ?
mountPointList.findByDevice(lvPath)->mountPoint() :
QString();
const KDiskFreeSpaceInfo freeSpaceInfo = KDiskFreeSpaceInfo::freeSpaceInfo(mountPoint);
//TODO: test used space report. probably incorrect
if (logicalSize() > 0) {
if (mounted && freeSpaceInfo.isValid() && mountPoint != QString()) {
fs->setSectorsUsed(freeSpaceInfo.used() / logicalSize());
} else if (fs->supportGetUsed() == FileSystem::cmdSupportFileSystem) {
fs->setSectorsUsed(fs->readUsedCapacity(lvPath) / 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 contruct list of initialized LvmDevice objects.
*
* @return list of initialized LvmDevice
*/
QList<LvmDevice*> LvmDevice::scanSystemLVM()
{
QList<LvmDevice*> lvmList;
for (const auto &vgName : getVGs()) {
lvmList.append(new LvmDevice(vgName));
}
return lvmList;
}
qint64 LvmDevice::mappedSector(const QString& lvPath, qint64 sector) const
{
qint64 mSector = 0;
QList<QString> 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
{
return *PVPathList();
}
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::getPVs(const QString& vgName)
{
QStringList devPathList;
QString cmdOutput = getField(QStringLiteral("pv_name"), vgName);
if (cmdOutput.size()) {
const QStringList tempPathList = cmdOutput.split(QStringLiteral("\n"), QString::SkipEmptyParts);
for (const auto &devPath : tempPathList) {
devPathList.append(devPath.trimmed());
}
}
return devPathList;
}
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.toInt();
}
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, usully 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);
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) {
//TODO: remove Partition from PartitionTable and delete from memory ??
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)
{
//TODO: thorough tests and add warning that it could currupt the user data.
ExternalCommand cmd(report, QStringLiteral("lvm"),
{ QStringLiteral("lvresize"),
QStringLiteral("--force"), // this command could corrupt user data
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"),
//QStringLiteral("--yes"), // potentially corrupt user data
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"), // potentially corrupt user data
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 QStringList pvList, const qint32 peSize)
{
QStringList args = QStringList();
args << QStringLiteral("vgcreate") << QStringLiteral("--physicalextentsize") << QString::number(peSize);
args << vgName;
for (const auto &pvNode : pvList) {
args << pvNode.trimmed();
}
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"),
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;
}

138
src/core/lvmdevice.h Normal file
View File

@ -0,0 +1,138 @@
/*************************************************************************
* Copyright (C) 2016 by Chantara Tith <tith.chantara@gmail.com> *
* *
* 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 <http://www.gnu.org/licenses/>.*
*************************************************************************/
#if !defined(LVMDEVICE__H)
#define LVMDEVICE__H
#include "core/volumemanagerdevice.h"
#include "util/libpartitionmanagerexport.h"
#include <QString>
#include <QObject>
#include <QtGlobal>
#include <QStringList>
class PartitionTable;
class Report;
class Partition;
class SmartStatus;
/** Representation of LVM Volume Group(VG).
Devices are the outermost entity; they contain a PartitionTable that itself contains Partitions.
@see Device, VolumeManagerDevice, PartitionTable, Partition
*/
class LIBKPMCORE_EXPORT LvmDevice : public VolumeManagerDevice
{
Q_DISABLE_COPY(LvmDevice)
public:
LvmDevice(const QString& name, const QString& iconName = QString());
~LvmDevice();
public:
const QStringList deviceNodes() const override;
const QStringList partitionNodes() const override;
qint64 partitionSize(QString& partitionPath) const override;
static QStringList s_DirtyPVs;
public:
static QList<LvmDevice*> scanSystemLVM();
static const QStringList getVGs();
static const QStringList getPVs(const QString& vgName);
static const QStringList getLVs(const QString& vgName);
static qint64 getPeSize(const QString& vgName);
static qint64 getTotalPE(const QString& vgName);
static qint64 getAllocatedPE(const QString& vgName);
static qint64 getFreePE(const QString& vgName);
static QString getUUID(const QString& vgName);
static QString getField(const QString& fieldName, const QString& vgName = QString());
static qint64 getTotalLE(const QString& lvPath);
static bool removeLV(Report& report, LvmDevice& d, Partition& p);
static bool createLV(Report& report, LvmDevice& d, Partition& p, const QString& lvName);
static bool createLVSnapshot(Report& report, Partition& p, const QString& name, const qint64 extents = 0);
static bool resizeLV(Report& report, Partition& p);
static bool deactivateLV(Report& report, const Partition& p);
static bool activateLV(const QString& deviceNode);
static bool removePV(Report& report, LvmDevice& d, const QString& pvPath);
static bool insertPV(Report& report, LvmDevice& d, const QString& pvPath);
static bool movePV(Report& report, const QString& pvPath, const QStringList& destinations = QStringList());
static bool removeVG(Report& report, LvmDevice& d);
static bool createVG(Report& report, const QString vgName, const QStringList pvList, const qint32 peSize = 4); // peSize in megabytes
static bool deactivateVG(Report& report, const LvmDevice& d);
static bool activateVG(Report& report, const LvmDevice& d);
protected:
void initPartitions() override;
const QList<Partition*> scanPartitions(PartitionTable* pTable) const;
Partition* scanPartition(const QString& lvPath, PartitionTable* pTable) const;
qint64 mappedSector(const QString& lvPath, qint64 sector) const override;
public:
qint64 peSize() const {
return m_peSize;
}
qint64 totalPE() const {
return m_totalPE;
}
qint64 allocatedPE() const {
return m_allocPE;
}
qint64 freePE() const {
return m_freePE;
}
QString UUID() const {
return m_UUID;
}
protected:
QStringList* LVPathList() const {
return m_LVPathList;
}
QStringList* PVPathList() const {
return m_PVPathList;
}
QMap<QString, qint64>* LVSizeMap() const {
return m_LVSizeMap;
}
private:
qint64 m_peSize;
qint64 m_totalPE;
qint64 m_allocPE;
qint64 m_freePE;
QString m_UUID;
mutable QStringList* m_LVPathList;
mutable QStringList* m_PVPathList;
mutable QMap<QString, qint64>* m_LVSizeMap;
};
#endif

View File

@ -96,8 +96,8 @@ qint32 OperationRunner::numJobs() const
{
qint32 result = 0;
foreach(const Operation * op, operationStack().operations())
result += op->jobs().size();
for (const auto &op : operationStack().operations())
result += op->jobs().size();
return result;
}

View File

@ -457,7 +457,7 @@ bool OperationStack::contains(const Partition* p) const
{
Q_ASSERT(p);
foreach(Operation * o, operations()) {
for (const auto &o : operations()) {
if (o->targets(*p))
return true;
@ -503,17 +503,19 @@ Device* OperationStack::findDeviceForPartition(const Partition* p)
{
QReadLocker lockDevices(&lock());
foreach(Device * d, previewDevices()) {
const auto devices = previewDevices();
for (Device *d : devices) {
if (d->partitionTable() == nullptr)
continue;
foreach(const Partition * part, d->partitionTable()->children()) {
const auto partitions = d->partitionTable()->children();
for (const auto *part : partitions) {
if (part == p)
return d;
foreach(const Partition * child, part->children())
if (child == p)
return d;
for (const auto &child : part->children())
if (child == p)
return d;
}
}

View File

@ -62,11 +62,11 @@ Partition::Partition(PartitionNode* parent, const Device& device, const Partitio
m_AvailableFlags(availableFlags),
m_ActiveFlags(activeFlags),
m_IsMounted(mounted),
m_SectorSize(device.logicalSectorSize()),
m_State(state)
{
setPartitionPath(partitionPath);
Q_ASSERT(m_Parent);
m_SectorSize = device.logicalSize();
}
/** Destroys a Partition, destroying its children and its FileSystem */
@ -106,7 +106,7 @@ Partition::Partition(const Partition& other) :
m_State(other.m_State)
{
setPartitionPath(other.m_PartitionPath);
foreach(const Partition * child, other.children()) {
for (const auto &child : other.children()) {
Partition* p = new Partition(*child);
p->setParent(this);
m_Children.append(p);
@ -121,7 +121,7 @@ Partition& Partition::operator=(const Partition& other)
clearChildren();
foreach(const Partition * child, other.children()) {
for (const auto &child : other.children()) {
Partition* p = new Partition(*child);
p->setParent(this);
m_Children.append(p);
@ -179,7 +179,7 @@ qint64 Partition::sectorsUsed() const
return fileSystem().sectorsUsed();
qint64 result = 0;
foreach(const Partition * p, children())
for (const auto &p : children())
if (!p->roles().has(PartitionRole::Unallocated))
result += p->length();
@ -190,7 +190,7 @@ qint64 Partition::sectorsUsed() const
qint64 Partition::minimumSectors() const
{
if (roles().has(PartitionRole::Luks))
return fileSystem().minCapacity() / sectorSize() + 4096; // 4096 is the default cryptsetup payload offset
return ( fileSystem().minCapacity() + (4096 * 512) ) / sectorSize(); // 4096 is the default cryptsetup payload offset
return fileSystem().minCapacity() / sectorSize();
}
@ -210,12 +210,12 @@ qint64 Partition::maximumSectors() const
@param deletedNumber the number of a deleted logical or -1 if none has been deleted
@param insertedNumber the number of an inserted logical or -1 if none has been inserted
*/
void Partition::adjustLogicalNumbers(qint32 deletedNumber, qint32 insertedNumber)
void Partition::adjustLogicalNumbers(qint32 deletedNumber, qint32 insertedNumber) const
{
if (!roles().has(PartitionRole::Extended))
return;
foreach(Partition * p, children()) {
for (const auto &p : children()) {
QString path = p->partitionPath();
path.remove(QRegularExpression(QStringLiteral("(\\d+$)")));
if (deletedNumber > 4 && p->number() > deletedNumber)
@ -230,7 +230,7 @@ qint64 Partition::maxFirstSector() const
{
qint64 rval = -1;
foreach(const Partition * child, children())
for (const auto &child : children())
if (!child->roles().has(PartitionRole::Unallocated) && (child->firstSector() < rval || rval == -1))
rval = child->firstSector();
@ -242,7 +242,7 @@ qint64 Partition::minLastSector() const
{
qint64 rval = -1;
foreach(const Partition * child, children())
for (const auto &child : children())
if (!child->roles().has(PartitionRole::Unallocated) && child->lastSector() > rval)
rval = child->lastSector();
@ -252,7 +252,7 @@ qint64 Partition::minLastSector() const
/** @return true if the Partition has children */
bool Partition::hasChildren() const
{
foreach(const Partition * child, children())
for (const auto &child : children())
if (!child->roles().has(PartitionRole::Unallocated))
return true;
@ -365,7 +365,7 @@ QTextStream& operator<<(QTextStream& stream, const Partition& p)
{
QStringList flagList;
foreach(const PartitionTable::Flag & f, PartitionTable::flagList()) {
for (const auto &f : PartitionTable::flagList()) {
if (p.activeFlags() & f)
flagList.append(PartitionTable::flagName(f));
}

View File

@ -215,7 +215,7 @@ public:
bool canMount() const;
bool canUnmount() const;
void adjustLogicalNumbers(qint32 deletedNumber, qint32 insertedNumber);
void adjustLogicalNumbers(qint32 deletedNumber, qint32 insertedNumber) const;
void checkChildrenMounted();
void setFirstSector(qint64 s) {

View File

@ -21,6 +21,7 @@
#include "core/partition.h"
#include "core/partitiontable.h"
#include "core/device.h"
#include "core/diskdevice.h"
#include "fs/filesystem.h"
@ -33,11 +34,12 @@ int PartitionAlignment::s_sectorAlignment = 2048;
qint64 PartitionAlignment::firstDelta(const Device& d, const Partition& p, qint64 s)
{
if (d.partitionTable()->type() == PartitionTable::msdos) {
if (p.roles().has(PartitionRole::Logical) && s == 2 * d.sectorsPerTrack())
return (s - (2 * d.sectorsPerTrack())) % sectorAlignment(d);
const DiskDevice& diskDevice = dynamic_cast<const DiskDevice&>(d);
if (p.roles().has(PartitionRole::Logical) && s == 2 * diskDevice.sectorsPerTrack())
return (s - (2 * diskDevice.sectorsPerTrack())) % sectorAlignment(d);
if (p.roles().has(PartitionRole::Logical) || s == d.sectorsPerTrack())
return (s - d.sectorsPerTrack()) % sectorAlignment(d);
if (p.roles().has(PartitionRole::Logical) || s == diskDevice.sectorsPerTrack())
return (s - diskDevice.sectorsPerTrack()) % sectorAlignment(d);
}
return s % sectorAlignment(d);
@ -51,11 +53,12 @@ qint64 PartitionAlignment::lastDelta(const Device& d, const Partition&, qint64 s
bool PartitionAlignment::isLengthAligned(const Device& d, const Partition& p)
{
if (d.partitionTable()->type() == PartitionTable::msdos) {
if (p.roles().has(PartitionRole::Logical) && p.firstSector() == 2 * d.sectorsPerTrack())
return (p.length() + (2 * d.sectorsPerTrack())) % sectorAlignment(d) == 0;
const DiskDevice& diskDevice = dynamic_cast<const DiskDevice&>(d);
if (p.roles().has(PartitionRole::Logical) && p.firstSector() == 2 * diskDevice.sectorsPerTrack())
return (p.length() + (2 * diskDevice.sectorsPerTrack())) % sectorAlignment(d) == 0;
if (p.roles().has(PartitionRole::Logical) || p.firstSector() == d.sectorsPerTrack())
return (p.length() + d.sectorsPerTrack()) % sectorAlignment(d) == 0;
if (p.roles().has(PartitionRole::Logical) || p.firstSector() == diskDevice.sectorsPerTrack())
return (p.length() + diskDevice.sectorsPerTrack()) % sectorAlignment(d) == 0;
}
return p.length() % sectorAlignment(d) == 0;

View File

@ -139,11 +139,13 @@ void PartitionNode::clearChildren()
*/
Partition* PartitionNode::findPartitionBySector(qint64 s, const PartitionRole& role)
{
foreach(Partition * p, children()) {
const auto partitions = children();
for (auto &p : partitions) {
// (women and) children first. ;-)
foreach(Partition * child, p->children())
if ((child->roles().roles() & role.roles()) && s >= child->firstSector() && s <= child->lastSector())
return child;
const auto pChildren = p->children();
for (auto &child : pChildren)
if ((child->roles().roles() & role.roles()) && s >= child->firstSector() && s <= child->lastSector())
return child;
if ((p->roles().roles() & role.roles()) && s >= p->firstSector() && s <= p->lastSector())
return p;
@ -157,10 +159,10 @@ Partition* PartitionNode::findPartitionBySector(qint64 s, const PartitionRole& r
*/
const Partition* PartitionNode::findPartitionBySector(qint64 s, const PartitionRole& role) const
{
foreach(const Partition * p, children()) {
foreach(const Partition * child, p->children())
if ((child->roles().roles() & role.roles()) && s >= child->firstSector() && s <= child->lastSector())
return child;
for (const auto *p : children()) {
for (const auto &child : p->children())
if ((child->roles().roles() & role.roles()) && s >= child->firstSector() && s <= child->lastSector())
return child;
if ((p->roles().roles() & role.roles()) && s >= p->firstSector() && s <= p->lastSector())
return p;
@ -190,9 +192,9 @@ qint32 PartitionNode::highestMountedChild() const
{
qint32 result = -1;
foreach(const Partition * p, children())
if (p->number() > result && p->isMounted())
result = p->number();
for (const auto * p : children())
if (p->number() > result && p->isMounted())
result = p->number();
return result;
}
@ -200,9 +202,9 @@ qint32 PartitionNode::highestMountedChild() const
/** @return true if any of the partition's children are mounted */
bool PartitionNode::isChildMounted() const
{
foreach(const Partition * child, children())
if (child->isMounted() || (child->hasChildren() && child->isChildMounted()))
return true;
for (const auto * child : children())
if (child->isMounted() || (child->hasChildren() && child->isChildMounted()))
return true;
return false;
}

View File

@ -43,6 +43,7 @@ public:
Logical = 4, /**< Logical inside an extended */
Unallocated = 8, /**< No real Partition, just unallocated space */
Luks = 16, /**< Encrypted partition with LUKS key management */
Lvm_Lv = 32, /**< Logical Volume of LVM */
Any = 255 /**< In case we're looking for a Partition with a PartitionRole, any will do */
};

View File

@ -23,8 +23,9 @@
#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"
@ -38,13 +39,13 @@
/** 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 first_usable, qint64 last_usable) :
PartitionTable::PartitionTable(TableType type, qint64 firstUsable, qint64 lastUsable) :
PartitionNode(),
m_Children(),
m_MaxPrimaries(maxPrimariesForTableType(type)),
m_Type(type),
m_FirstUsable(first_usable),
m_LastUsable(last_usable)
m_FirstUsable(firstUsable),
m_LastUsable(lastUsable)
{
}
@ -88,11 +89,23 @@ qint64 PartitionTable::freeSectorsAfter(const Partition& p) const
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 (int i = 0; i < children().size(); i++)
if (children()[i]->roles().has(PartitionRole::Extended))
for (const auto &p : children())
if (p->roles().has(PartitionRole::Extended))
return true;
return false;
@ -101,9 +114,9 @@ bool PartitionTable::hasExtended() const
/** @return pointer to the PartitionTable's extended Partition or nullptr if none exists */
Partition* PartitionTable::extended() const
{
for (int i = 0; i < children().size(); i++)
if (children()[i]->roles().has(PartitionRole::Extended))
return children()[i];
for (const auto &p : children())
if (p->roles().has(PartitionRole::Extended))
return p;
return nullptr;
}
@ -129,7 +142,7 @@ int PartitionTable::numPrimaries() const
{
int result = 0;
foreach(const Partition * p, children())
for (const auto &p : children())
if (p->roles().has(PartitionRole::Primary) || p->roles().has(PartitionRole::Extended))
result++;
@ -194,7 +207,7 @@ QString PartitionTable::flagName(Flag f)
}
/** @return list of all flags */
QList<PartitionTable::Flag> PartitionTable::flagList()
const QList<PartitionTable::Flag> PartitionTable::flagList()
{
QList<PartitionTable::Flag> rval;
@ -240,29 +253,38 @@ QStringList PartitionTable::flagNames(Flags flags)
return rval;
}
bool PartitionTable::getUnallocatedRange(const Device& device, PartitionNode& parent, qint64& start, qint64& end)
bool PartitionTable::getUnallocatedRange(const Device& d, PartitionNode& parent, qint64& start, qint64& end)
{
if (!parent.isRoot()) {
Partition* extended = dynamic_cast<Partition*>(&parent);
if (d.type() == Device::Disk_Device) {
const DiskDevice& device = dynamic_cast<const DiskDevice&>(d);
if (!parent.isRoot()) {
Partition* extended = dynamic_cast<Partition*>(&parent);
if (extended == nullptr) {
qWarning() << "extended is null. start: " << start << ", end: " << end << ", device: " << device.deviceNode();
return false;
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);
}
// 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) {
if (end - start + 1 > 0) {
return true;
}
}
return end - start + 1 >= PartitionAlignment::sectorAlignment(device);
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
@ -334,13 +356,26 @@ void PartitionTable::insertUnallocated(const Device& d, PartitionNode* p, qint64
qint64 lastEnd = start;
foreach(Partition * child, p->children()) {
p->insert(createUnallocated(d, *p, lastEnd, child->firstSector() - 1));
if (d.type() == Device::LVM_Device && !p->children().isEmpty()) {
// rearranging all the partitions sector to keep all the unallocated space at the end
lastEnd = 0;
for (const auto &child : children()) {
qint64 totalSector = child->length();
child->setFirstSector(lastEnd);
child->setLastSector(lastEnd + totalSector - 1);
if (child->roles().has(PartitionRole::Extended))
insertUnallocated(d, child, child->firstSector());
lastEnd += totalSector;
}
} else {
const auto pChildren = p->children();
for (const auto &child : pChildren) {
p->insert(createUnallocated(d, *p, lastEnd, child->firstSector() - 1));
lastEnd = child->lastSector() + 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
@ -353,7 +388,7 @@ void PartitionTable::insertUnallocated(const Device& d, PartitionNode* p, qint64
Q_ASSERT(extended);
}
if (parentEnd >= firstUsable())
if (parentEnd >= firstUsable() && parentEnd >= lastEnd)
p->insert(createUnallocated(d, *p, lastEnd, parentEnd));
}
@ -369,15 +404,20 @@ void PartitionTable::updateUnallocated(const Device& d)
qint64 PartitionTable::defaultFirstUsable(const Device& d, TableType t)
{
Q_UNUSED(t)
return PartitionAlignment::sectorAlignment(d);
if (d.type() == Device::LVM_Device) {
return 0;
}
const DiskDevice& diskDevice = dynamic_cast<const DiskDevice&>(d);
return PartitionAlignment::sectorAlignment(diskDevice);
}
qint64 PartitionTable::defaultLastUsable(const Device& d, TableType t)
{
if (t == gpt)
return d.totalSectors() - 1 - 32 - 1;
return d.totalLogical() - 1 - 32 - 1;
return d.totalSectors() - 1;
return d.totalLogical() - 1;
}
static struct {
@ -398,50 +438,51 @@ static struct {
{ QStringLiteral("mac"), 0xffff, false, true, PartitionTable::mac },
{ QStringLiteral("pc98"), 16, false, true, PartitionTable::pc98 },
{ QStringLiteral("amiga"), 128, false, true, PartitionTable::amiga },
{ QStringLiteral("sun"), 8, false, true, PartitionTable::sun }
{ QStringLiteral("sun"), 8, false, true, PartitionTable::sun },
{ QStringLiteral("vmd"), 0xffff, false, false, PartitionTable::vmd }
};
PartitionTable::TableType PartitionTable::nameToTableType(const QString& n)
{
for (size_t i = 0; i < sizeof(tableTypes) / sizeof(tableTypes[0]); i++)
if (n == tableTypes[i].name)
return tableTypes[i].type;
for (const auto &type : tableTypes)
if (n == type.name)
return type.type;
return PartitionTable::unknownTableType;
}
QString PartitionTable::tableTypeToName(TableType l)
{
for (size_t i = 0; i < sizeof(tableTypes) / sizeof(tableTypes[0]); i++)
if (l == tableTypes[i].type)
return tableTypes[i].name;
for (const auto &type : tableTypes)
if (l == type.type)
return type.name;
return xi18nc("@item partition table name", "unknown");
}
qint64 PartitionTable::maxPrimariesForTableType(TableType l)
{
for (size_t i = 0; i < sizeof(tableTypes) / sizeof(tableTypes[0]); i++)
if (l == tableTypes[i].type)
return tableTypes[i].maxPrimaries;
for (const auto &type : tableTypes)
if (l == type.type)
return type.maxPrimaries;
return 1;
}
bool PartitionTable::tableTypeSupportsExtended(TableType l)
{
for (size_t i = 0; i < sizeof(tableTypes) / sizeof(tableTypes[0]); i++)
if (l == tableTypes[i].type)
return tableTypes[i].canHaveExtended;
for (const auto &type : tableTypes)
if (l == type.type)
return type.canHaveExtended;
return false;
}
bool PartitionTable::tableTypeIsReadOnly(TableType l)
{
for (size_t i = 0; i < sizeof(tableTypes) / sizeof(tableTypes[0]); i++)
if (l == tableTypes[i].type)
return tableTypes[i].isReadOnly;
for (const auto &type : tableTypes)
if (l == type.type)
return type.isReadOnly;
return false;
}
@ -452,26 +493,32 @@ bool PartitionTable::tableTypeIsReadOnly(TableType l)
*/
bool PartitionTable::isSectorBased(const Device& d) const
{
if (type() == PartitionTable::msdos) {
// the default for empty partition tables is sector based
if (numPrimaries() == 0)
return true;
if (d.type() == Device::Disk_Device) {
const DiskDevice& diskDevice = dynamic_cast<const DiskDevice&>(d);
quint32 numCylinderAligned = 0;
quint32 numSectorAligned = 0;
if (type() == PartitionTable::msdos) {
// the default for empty partition tables is sector based
if (numPrimaries() == 0)
return true;
// see if we have more cylinder aligned partitions than sector
// aligned ones.
foreach(const Partition * p, children())
if (p->firstSector() % PartitionAlignment::sectorAlignment(d) == 0)
numSectorAligned++;
else if (p->firstSector() % d.cylinderSize() == 0)
numCylinderAligned++;
quint32 numCylinderAligned = 0;
quint32 numSectorAligned = 0;
return numSectorAligned >= numCylinderAligned;
// 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 type() == PartitionTable::msdos_sectorbased;
return false;
}
void PartitionTable::setType(const Device& d, TableType t)
@ -497,19 +544,21 @@ QTextStream& operator<<(QTextStream& stream, const PartitionTable& ptable)
QList<const Partition*> partitions;
foreach(const Partition * p, ptable.children())
for (const auto &p : ptable.children()) {
if (!p->roles().has(PartitionRole::Unallocated)) {
partitions.append(p);
if (p->roles().has(PartitionRole::Extended))
foreach(const Partition * child, p->children())
if (!child->roles().has(PartitionRole::Unallocated))
partitions.append(child);
for (const auto &child : p->children()) {
if (!child->roles().has(PartitionRole::Unallocated))
partitions.append(child);
}
}
}
qSort(partitions.begin(), partitions.end(), isPartitionLessThan);
foreach(const Partition * p, partitions)
foreach(const auto &p, partitions)
stream << *p;
return stream;

View File

@ -64,7 +64,8 @@ public:
mac,
pc98,
amiga,
sun
sun,
vmd /* Volume Manager Device */
};
/** Partition flags */
@ -94,7 +95,7 @@ public:
Q_FLAG(Flag)
public:
PartitionTable(TableType type, qint64 first_usable, qint64 last_usable);
PartitionTable(TableType type, qint64 firstUsable, qint64 lastUsable);
~PartitionTable();
public:
@ -125,6 +126,7 @@ public:
qint64 freeSectorsBefore(const Partition& p) const;
qint64 freeSectorsAfter(const Partition& p) const;
qint64 freeSectors() const;
bool hasExtended() const;
Partition* extended() const;
@ -150,12 +152,19 @@ public:
return m_LastUsable;
}
void setFirstUsableSector(qint64 s) {
m_FirstUsable = s;
}
void setLastUsableSector(qint64 s) {
m_LastUsable = s;
}
void updateUnallocated(const Device& d);
void insertUnallocated(const Device& d, PartitionNode* p, qint64 start) const;
bool isSectorBased(const Device& d) const;
static QList<Flag> flagList();
static const QList<Flag> flagList();
static QString flagName(Flag f);
static QStringList flagNames(Flags f);
@ -177,12 +186,6 @@ protected:
void setMaxPrimaries(qint32 n) {
m_MaxPrimaries = n;
}
void setFirstUsableSector(qint64 s) {
m_FirstUsable = s;
}
void setLastUsableSector(qint64 s) {
m_LastUsable = s;
}
private:
Partitions m_Children;

View File

@ -0,0 +1,45 @@
/*************************************************************************
* Copyright (C) 2016 by Chantara Tith <tith.chantara@gmail.com> *
* *
* 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 <http://www.gnu.org/licenses/>.*
*************************************************************************/
#include "core/volumemanagerdevice.h"
/** Constructs an abstract Volume Manager Device with an empty PartitionTable.
*
*/
VolumeManagerDevice::VolumeManagerDevice(const QString& name,
const QString& deviceNode,
const qint32 logicalSize,
const qint64 totalLogical,
const QString& iconName,
Device::Type type)
: Device(name, deviceNode, logicalSize, totalLogical, iconName, type)
{
}
QString VolumeManagerDevice::prettyDeviceNodeList() const
{
QString rval;
for (const auto &devNode : deviceNodes()) {
rval += devNode + QStringLiteral(",");
}
if (rval.size()) {
//chop off the trailing colon
rval.chop(1);
}
return rval;
}

View File

@ -0,0 +1,99 @@
/*************************************************************************
* Copyright (C) 2016 by Chantara Tith <tith.chantara@gmail.com> *
* *
* 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 <http://www.gnu.org/licenses/>.*
*************************************************************************/
#if !defined(VOLUMEMANAGERDEVICE__H)
#define VOLUMEMANAGERDEVICE__H
#include "util/libpartitionmanagerexport.h"
#include "core/device.h"
#include <QString>
#include <QStringList>
#include <QObject>
#include <QtGlobal>
/** 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(const QString& name, const QString& deviceNode, const qint32 logicalSize, const qint64 totalLogical, const QString& iconName = QString(), Device::Type type = Device::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:
/** string deviceNodes together into comma-sperated list
*
* @return comma-seperated list of deviceNodes
*/
virtual QString prettyDeviceNodeList() const;
/** Resize device total number of logical sectors.
*
* @param n Number of sectors.
*/
void setTotalLogical(qint64 n) {
Q_ASSERT(n > 0);
m_TotalLogical = n;
}
};
#endif

View File

@ -1,6 +1,6 @@
/*************************************************************************
* Copyright (C) 2008,2009 by Volker Lanz <vl@fidra.de> *
* Copyright (C) 2016 by Andrius Štikonas <andrius@stikonas.eu> *
* Copyright (C) 2016 by Andrius Štikonas <andrius@stikonas.eu> *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License as *

View File

@ -154,8 +154,10 @@ bool fat16::updateUUID(Report& report, const QString& deviceNode) const
qint32 t = time(nullptr);
char uuid[4];
for (quint32 i = 0; i < sizeof(uuid); i++, t >>= 8)
uuid[i] = t & 0xff;
for (auto &u : uuid) {
u = t & 0xff;
t >>= 8;
}
ExternalCommand cmd(report, QStringLiteral("dd"), { QStringLiteral("of=") + deviceNode , QStringLiteral("bs=1"), QStringLiteral("count=4"), QStringLiteral("seek=39") });

View File

@ -51,8 +51,10 @@ bool fat32::updateUUID(Report& report, const QString& deviceNode) const
qint32 t = time(nullptr);
char uuid[4];
for (quint32 i = 0; i < sizeof(uuid); i++, t >>= 8)
uuid[i] = t & 0xff;
for (auto &u : uuid) {
u = t & 0xff;
t >>= 8;
}
ExternalCommand cmd(report, QStringLiteral("dd"), { QStringLiteral("of=") + deviceNode, QStringLiteral("bs=1"), QStringLiteral("count=4"), QStringLiteral("seek=67") });

View File

@ -84,9 +84,8 @@ void FileSystemFactory::init()
m_FileSystems.insert(FileSystem::Xfs, new FS::xfs(-1, -1, -1, QString()));
m_FileSystems.insert(FileSystem::Zfs, new FS::zfs(-1, -1, -1, QString()));
foreach(FileSystem * fs, FileSystemFactory::map()) {
for (const auto &fs : FileSystemFactory::map())
fs->init();
}
CoreBackendManager::self()->backend()->initFSSupport();
}

View File

@ -69,18 +69,21 @@ luks::~luks()
void luks::init()
{
m_Create = findExternal(QStringLiteral("cryptsetup")) ? cmdSupportFileSystem : cmdSupportNone;
CommandSupportType cryptsetupFound = findExternal(QStringLiteral("cryptsetup")) ? cmdSupportFileSystem : cmdSupportNone;
m_Create = cryptsetupFound;
m_UpdateUUID = cryptsetupFound;
m_GetUUID = cryptsetupFound;
m_Grow = cryptsetupFound;
m_Shrink = cryptsetupFound;
m_SetLabel = cmdSupportNone;
m_GetLabel = cmdSupportFileSystem;
m_UpdateUUID = findExternal(QStringLiteral("cryptsetup")) ? cmdSupportFileSystem : cmdSupportNone;
m_Grow = findExternal(QStringLiteral("cryptsetup")) ? cmdSupportFileSystem : cmdSupportNone;
m_Shrink = m_Grow;
m_Check = cmdSupportCore;
m_Copy = cmdSupportCore;
m_Move = cmdSupportCore;
m_Backup = cmdSupportCore;
m_GetUsed = cmdSupportNone; // libparted does not support LUKS, we do this as a special case
m_GetUUID = findExternal(QStringLiteral("cryptsetup")) ? cmdSupportFileSystem : cmdSupportNone;
}
bool luks::supportToolFound() const
@ -319,7 +322,7 @@ void luks::loadInnerFileSystem(const QString& deviceNode, const QString& mapperN
setLabel(m_innerFs->readLabel(mapperNode));
setUUID(m_innerFs->readUUID(mapperNode));
if (m_innerFs->supportGetUsed() == FileSystem::cmdSupportFileSystem)
setSectorsUsed(m_innerFs->readUsedCapacity(mapperNode)/m_logicalSectorSize + getPayloadOffset(deviceNode));
setSectorsUsed((m_innerFs->readUsedCapacity(mapperNode) + getPayloadOffset(deviceNode)) / m_logicalSectorSize );
}
void luks::createInnerFileSystem(FileSystem::Type type)
@ -378,7 +381,7 @@ bool luks::mount(Report& report, const QString& deviceNode, const QString& mount
const KDiskFreeSpaceInfo freeSpaceInfo = KDiskFreeSpaceInfo::freeSpaceInfo(mountPoint);
if (freeSpaceInfo.isValid() && mountPoint != QString())
setSectorsUsed(freeSpaceInfo.used() / m_logicalSectorSize + getPayloadOffset(deviceNode));
setSectorsUsed((freeSpaceInfo.used() + getPayloadOffset(deviceNode)) / m_logicalSectorSize);
return true;
}
@ -473,7 +476,7 @@ bool luks::resize(Report& report, const QString& deviceNode, qint64 newLength) c
if (mapperNode.isEmpty())
return false;
qint64 payloadLength = newLength - getPayloadOffset(deviceNode) * m_logicalSectorSize;
qint64 payloadLength = newLength - getPayloadOffset(deviceNode);
if ( newLength - length() * m_logicalSectorSize > 0 )
{
ExternalCommand cryptResizeCmd(report, QStringLiteral("cryptsetup"), { QStringLiteral("resize"), mapperNode });
@ -481,12 +484,14 @@ bool luks::resize(Report& report, const QString& deviceNode, qint64 newLength) c
if (cryptResizeCmd.run(-1) && cryptResizeCmd.exitCode() == 0)
{
return m_innerFs->resize(report, mapperNode, newLength - getPayloadOffset(deviceNode) * m_logicalSectorSize);
return m_innerFs->resize(report, mapperNode, payloadLength);
}
}
else if (m_innerFs->resize(report, mapperNode, payloadLength))
{
ExternalCommand cryptResizeCmd(report, QStringLiteral("cryptsetup"), { QStringLiteral("--size"), QString::number(payloadLength / m_logicalSectorSize), QStringLiteral("resize"), mapperNode });
ExternalCommand cryptResizeCmd(report, QStringLiteral("cryptsetup"),
{ QStringLiteral("--size"), QString::number(payloadLength / /*m_logicalSectorSize*/ 512), // LUKS assume 512 bytes sector
QStringLiteral("resize"), mapperNode });
report.line() << xi18nc("@info:progress", "Resizing LUKS crypt on partition <filename>%1</filename>.", deviceNode);
if (cryptResizeCmd.run(-1) && cryptResizeCmd.exitCode() == 0)
{
@ -596,6 +601,9 @@ qint64 luks::getKeySize(const QString& deviceNode) const
return -1;
}
/*
* @return size of payload offset in bytes.
*/
qint64 luks::getPayloadOffset(const QString& deviceNode) const
{
ExternalCommand cmd(QStringLiteral("cryptsetup"),
@ -604,7 +612,7 @@ qint64 luks::getPayloadOffset(const QString& deviceNode) const
QRegularExpression re(QStringLiteral("Payload offset:\\s+(\\d+)"));
QRegularExpressionMatch rePayloadOffset = re.match(cmd.output());
if (rePayloadOffset.hasMatch())
return rePayloadOffset.captured(1).toLongLong();
return rePayloadOffset.captured(1).toLongLong() * 512; // assuming LUKS sector size is 512
}
return -1;
}

View File

@ -23,6 +23,8 @@
#include <QString>
#include <KLocalizedString>
namespace FS
{
FileSystem::CommandSupportType lvm2_pv::m_GetUsed = FileSystem::cmdSupportNone;
@ -45,31 +47,36 @@ lvm2_pv::lvm2_pv(qint64 firstsector, qint64 lastsector, qint64 sectorsused, cons
void lvm2_pv::init()
{
m_Create = findExternal(QStringLiteral("lvm")) ? cmdSupportFileSystem : cmdSupportNone;
m_Check = findExternal(QStringLiteral("lvm")) ? cmdSupportFileSystem : cmdSupportNone;
CommandSupportType lvmFound = findExternal(QStringLiteral("lvm")) ? cmdSupportFileSystem : cmdSupportNone;
m_GetLabel = cmdSupportCore;
m_UpdateUUID = findExternal(QStringLiteral("lvm")) ? cmdSupportFileSystem : cmdSupportNone;
m_Create = lvmFound;
m_Check = lvmFound;
m_Grow = lvmFound;
m_Shrink = lvmFound;
m_UpdateUUID = lvmFound;
m_GetUsed = lvmFound;
m_Copy = cmdSupportNone; // Copying PV can confuse LVM
m_Move = (m_Check != cmdSupportNone) ? cmdSupportCore : cmdSupportNone;
m_GetLabel = cmdSupportCore;
m_Backup = cmdSupportCore;
m_GetUUID = cmdSupportCore;
m_GetLabel = cmdSupportNone;
m_Backup = cmdSupportCore;
m_GetUUID = cmdSupportCore;
m_Copy = cmdSupportNone; // Copying PV can confuse LVM
}
bool lvm2_pv::supportToolFound() const
{
return
// m_GetUsed != cmdSupportNone &&
m_GetUsed != cmdSupportNone &&
// m_GetLabel != cmdSupportNone &&
// m_SetLabel != cmdSupportNone &&
m_Create != cmdSupportNone &&
m_Check != cmdSupportNone &&
m_UpdateUUID != cmdSupportNone &&
// m_Grow != cmdSupportNone &&
// m_Shrink != cmdSupportNone &&
m_Grow != cmdSupportNone &&
m_Shrink != cmdSupportNone &&
// m_Copy != cmdSupportNone &&
m_Move != cmdSupportNone &&
m_Backup != cmdSupportNone &&
@ -86,6 +93,13 @@ qint64 lvm2_pv::maxCapacity() const
return Capacity::unitFactor(Capacity::Byte, Capacity::EiB);
}
qint64 lvm2_pv::readUsedCapacity(const QString& deviceNode) const
{
QString val = getpvField(QStringLiteral("pv_used"), deviceNode);
QString metadataOffset = getpvField(QStringLiteral("pe_start"), deviceNode);
return val.isEmpty() ? -1 : val.toLongLong() + metadataOffset.toLongLong();
}
bool lvm2_pv::check(Report& report, const QString& deviceNode) const
{
ExternalCommand cmd(report, QStringLiteral("lvm"), { QStringLiteral("pvck"), QStringLiteral("--verbose"), deviceNode });
@ -94,7 +108,7 @@ bool lvm2_pv::check(Report& report, const QString& deviceNode) const
bool lvm2_pv::create(Report& report, const QString& deviceNode) const
{
ExternalCommand cmd(report, QStringLiteral("lvm"), { QStringLiteral("pvcreate"), deviceNode });
ExternalCommand cmd(report, QStringLiteral("lvm"), { QStringLiteral("pvcreate"), QStringLiteral("--force"), deviceNode });
return cmd.run(-1) && cmd.exitCode() == 0;
}
@ -105,16 +119,222 @@ bool lvm2_pv::remove(Report& report, const QString& deviceNode) const
return cmd.run(-1) && cmd.exitCode() == 0;
}
bool lvm2_pv::resize(Report& report, const QString& deviceNode, qint64 length) const
{
bool rval = true;
qint64 metadataOffset = getpvField(QStringLiteral("pe_start"), deviceNode).toLongLong();
qint64 lastPE = getTotalPE(deviceNode) - 1; // starts from 0
if (lastPE > 0) { // make sure that the PV is already in a VG
qint64 targetPE = (length - metadataOffset)/ getPESize(deviceNode) - 1; // starts from 0
if (targetPE < lastPE) { //shrinking FS
qint64 firstMovedPE = qMax(targetPE + 1, getAllocatedPE(deviceNode)); // starts from 1
ExternalCommand moveCmd(report,
QStringLiteral("lvm"), {
QStringLiteral("pvmove"),
QStringLiteral("--alloc"),
QStringLiteral("anywhere"),
deviceNode + QStringLiteral(":") + QString::number(firstMovedPE) + QStringLiteral("-") + QString::number(lastPE),
deviceNode + QStringLiteral(":") + QStringLiteral("0-") + QString::number(firstMovedPE - 1)
});
rval = moveCmd.run(-1) && (moveCmd.exitCode() == 0 || moveCmd.exitCode() == 5); // FIXME: exit code 5: NO data to move
}
}
ExternalCommand cmd(report, QStringLiteral("lvm"), {
QStringLiteral("pvresize"),
QStringLiteral("--yes"),
QStringLiteral("--setphysicalvolumesize"),
QString::number(length) + QStringLiteral("B"),
deviceNode });
return rval && cmd.run(-1) && cmd.exitCode() == 0;
}
bool lvm2_pv::updateUUID(Report& report, const QString& deviceNode) const
{
ExternalCommand cmd(report, QStringLiteral("lvm"), { QStringLiteral("pvchange"), QStringLiteral("--uuid"), deviceNode });
return cmd.run(-1) && cmd.exitCode() == 0;
}
bool lvm2_pv::canMount(const QString & deviceNode, const QString & mountPoint) const
QString lvm2_pv::readUUID(const QString& deviceNode) const
{
Q_UNUSED(deviceNode)
Q_UNUSED(mountPoint)
return getpvField(QStringLiteral("pv_uuid"), deviceNode);
}
bool lvm2_pv::mount(Report& report, const QString& deviceNode, const QString& mountPoint)
{
Q_UNUSED(report);
Q_UNUSED(deviceNode);
Q_UNUSED(mountPoint);
return false;
}
bool lvm2_pv::unmount(Report& report, const QString& deviceNode)
{
Q_UNUSED(deviceNode);
Q_UNUSED(report);
return false;
}
bool lvm2_pv::canMount(const QString & deviceNode, const QString & mountPoint) const
{
Q_UNUSED(mountPoint);
QString rval = getpvField(QStringLiteral("pv_in_use"), deviceNode); // this field return "used" when in use otherwise empty string
if (rval.isEmpty()) {
return true;
}
return false;
}
bool lvm2_pv::canUnmount(const QString& deviceNode) const
{
QString rval = getpvField(QStringLiteral("pv_in_use"), deviceNode);
if (rval.isEmpty()) {
return false;
}
return true;
}
qint64 lvm2_pv::getTotalPE(const QString& deviceNode)
{
QString val = getpvField(QStringLiteral("pv_pe_count"), deviceNode);
return val.isEmpty() ? -1 : val.toLongLong();
}
qint64 lvm2_pv::getTotalPE(const QStringList& deviceNodeList)
{
qint64 sum = 0;
for (const auto &deviceNode : deviceNodeList) {
qint64 totalPE = getTotalPE(deviceNode);
if (totalPE < 0) {
sum = -1;
break;
}
sum += totalPE;
}
return sum;
}
qint64 lvm2_pv::getFreePE(const QString& deviceNode)
{
return getTotalPE(deviceNode) - getAllocatedPE(deviceNode);
}
qint64 lvm2_pv::getFreePE(const QStringList& deviceNodeList)
{
qint64 sum = 0;
for (QString deviceNode :deviceNodeList) {
qint64 freePE = getFreePE(deviceNode);
if (freePE < 0) {
sum = -1;
break;
}
sum += freePE;
}
return sum;
}
qint64 lvm2_pv::getAllocatedPE(const QString& deviceNode)
{
QString val = getpvField(QStringLiteral("pv_pe_alloc_count"), deviceNode);
return val.isEmpty() ? -1 : val.toLongLong();
}
qint64 lvm2_pv::getAllocatedPE(const QStringList& deviceNodeList)
{
qint64 sum = 0;
for (QString deviceNode : deviceNodeList) {
qint64 allocatedPE = getAllocatedPE(deviceNode);
if (allocatedPE < 0) {
sum = -1;
break;
}
sum += allocatedPE;
}
return sum;
}
qint64 lvm2_pv::getPVSize(const QString& deviceNode)
{
QString val = getpvField(QStringLiteral("pv_size"), deviceNode);
return val.isEmpty() ? -1 : val.toLongLong();
}
qint64 lvm2_pv::getPVSize(const QStringList& deviceNodeList)
{
qint64 sum = 0;
for (QString deviceNode : deviceNodeList) {
qint64 pvsize = getPVSize(deviceNode);
if (pvsize < 0) {
sum = -1;
break;
}
sum += pvsize;
}
return sum;
}
qint64 lvm2_pv::getPESize(const QString& deviceNode)
{
QString val = getpvField(QStringLiteral("vg_extent_size"), deviceNode);
return val.isEmpty() ? -1 : val.toLongLong();
}
/** Get pvs command output with field name
*
* @param fieldName LVM field name
* @param deviceNode path to PV
* @return raw output of pvs command, usually with many spaces
*/
QString lvm2_pv::getpvField(const QString& fieldName, const QString& deviceNode)
{
QStringList args = { QStringLiteral("pvs"),
QStringLiteral("--foreign"),
QStringLiteral("--readonly"),
QStringLiteral("--noheadings"),
QStringLiteral("--units"),
QStringLiteral("B"),
QStringLiteral("--nosuffix"),
QStringLiteral("--options"),
fieldName };
if (!deviceNode.isEmpty()) {
args << deviceNode;
}
ExternalCommand cmd(QStringLiteral("lvm"), args);
if (cmd.run(-1) && cmd.exitCode() == 0) {
return cmd.output().trimmed();
}
return QString();
}
QString lvm2_pv::getVGName(const QString& deviceNode)
{
return getpvField(QStringLiteral("vg_name"), deviceNode);
}
const QStringList lvm2_pv::getFreePV()
{
QStringList rlist;
QString output = getpvField(QStringLiteral("pv_name"));
const QStringList pvList = output.split(QStringLiteral("\n"), QString::SkipEmptyParts);
for (QString pvnode : pvList) {
if (!isUsed(pvnode.trimmed())) {
rlist.append(pvnode.trimmed());
}
}
return rlist;
}
bool lvm2_pv::isUsed(const QString& deviceNode)
{
QString output = getpvField(QStringLiteral("pv_in_use"), deviceNode.trimmed());
if (output.trimmed() == QStringLiteral("used")) {
return true;
}
return false;
}
}

View File

@ -43,14 +43,21 @@ public:
public:
void init() override;
// qint64 readUsedCapacity(const QString& deviceNode) const override;
qint64 readUsedCapacity(const QString& deviceNode) const override;
bool check(Report& report, const QString& deviceNode) const override;
bool create(Report& report, const QString& deviceNode) const override;
bool remove(Report& report, const QString& deviceNode) const override;
// bool resize(Report& report, const QString& deviceNode, qint64 length) const override;
bool resize(Report& report, const QString& deviceNode, qint64 length) const override;
// bool writeLabel(Report& report, const QString& deviceNode, const QString& newLabel) override;
bool updateUUID(Report& report, const QString& deviceNode) const override;
QString readUUID(const QString& deviceNode) const override;
bool canMount(const QString & deviceNode, const QString & mountPoint) const override;
bool canUnmount(const QString& deviceNode) const override;
bool mount(Report& report, const QString& deviceNode, const QString& mountPoint) override; // mountPoint == VG name
bool unmount(Report& report, const QString& deviceNode) override;
CommandSupportType supportGetUsed() const override {
return m_GetUsed;
@ -93,6 +100,23 @@ public:
SupportTool supportToolName() const override;
bool supportToolFound() const override;
static qint64 getTotalPE(const QString& deviceNode);
static qint64 getTotalPE(const QStringList& deviceNodeList);
static qint64 getFreePE(const QString& deviceNode);
static qint64 getFreePE(const QStringList& deviceNodeList);
static qint64 getAllocatedPE(const QString& deviceNode);
static qint64 getAllocatedPE(const QStringList& deviceNodeList);
static qint64 getPESize(const QString& deviceNode); // return PE size in bytes
static qint64 getPVSize(const QString& deviceNode); // return PV size in bytes
static qint64 getPVSize(const QStringList& deviceNodeList);
static bool isUsed(const QString& pvNode);
static QString getVGName(const QString& deviceNode);
static QString getpvField(const QString& fieldName, const QString& deviceNode = QString());
static const QStringList getFreePV();
public:
static CommandSupportType m_GetUsed;
static CommandSupportType m_GetLabel;

View File

@ -133,9 +133,9 @@ qint32 PartResizerWidget::handleWidth() const
return style()->pixelMetric(QStyle::PM_SplitterWidth);
}
qint64 PartResizerWidget::sectorsPerPixel() const
long double PartResizerWidget::sectorsPerPixel() const
{
return totalSectors() / (width() - 2 * handleWidth());
return totalSectors() / (width() - 2.0L * handleWidth());
}
int PartResizerWidget::partWidgetStart() const
@ -285,13 +285,13 @@ void PartResizerWidget::mouseMoveEvent(QMouseEvent* event)
int x = event->pos().x() - m_Hotspot;
if (draggedWidget() == &leftHandle()) {
const qint64 newFirstSector = qMax(minimumFirstSector() + x * sectorsPerPixel(), 0LL);
const qint64 newFirstSector = qMax(minimumFirstSector() + x * sectorsPerPixel(), 0.0L);
updateFirstSector(newFirstSector);
} else if (draggedWidget() == &rightHandle()) {
const qint64 newLastSector = qMin(minimumFirstSector() + (x - rightHandle().width()) * sectorsPerPixel(), maximumLastSector());
const qint64 newLastSector = qMin(static_cast<qint64>(minimumFirstSector() + (x - rightHandle().width()) * sectorsPerPixel()), maximumLastSector());
updateLastSector(newLastSector);
} else if (draggedWidget() == &partWidget() && moveAllowed()) {
const qint64 newFirstSector = qMax(minimumFirstSector() + (x - handleWidth()) * sectorsPerPixel(), 0LL);
const qint64 newFirstSector = qMax(minimumFirstSector() + (x - handleWidth()) * sectorsPerPixel(), 0.0L);
movePartition(newFirstSector);
}
}

View File

@ -169,7 +169,7 @@ protected:
return m_RightHandle;
}
qint64 sectorsPerPixel() const;
long double sectorsPerPixel() const;
void set(qint64 newCap, qint64 newFreeBefore, qint64 newFreeAfter);

View File

@ -56,13 +56,13 @@ void PartWidget::init(const Partition* p)
void PartWidget::updateChildren()
{
if (partition()) {
foreach(QWidget * w, childWidgets()) {
for (const auto &w : childWidgets()) {
w->setVisible(false);
w->deleteLater();
w->setParent(nullptr);
}
foreach(const Partition * child, partition()->children()) {
for (const auto &child : partition()->children()) {
QWidget* w = new PartWidget(this, child);
w->setVisible(true);
}

View File

@ -31,7 +31,7 @@ template<typename T>
T sum(const QList<T>& list)
{
T rval = 0;
foreach(const T & val, list)
for (const T & val : list)
rval += val;
return rval;
}
@ -107,21 +107,21 @@ void PartWidgetBase::positionChildren(const QWidget* destWidget, const Partition
return;
qint64 totalLength = 0;
foreach(const Partition * p, partitions)
for (const auto &p : partitions)
totalLength += p->length();
if (totalLength < 1)
return;
// calculate unleveled width for each child and store it
for (int i = 0; i < partitions.size(); i++) {
childrenWidth.append(partitions[i]->length() * destWidgetWidth / totalLength);
for (const auto &p : partitions) {
childrenWidth.append(p->length() * destWidgetWidth / totalLength);
// Calculate the minimum width for the widget. This is easy for primary and logical partitions: they
// just have a fixed min width (configured in m_MinWidth). But for extended partitions things
// are not quite as simple. We need to calc the sum of the min widths for each child, taking
// spacing and borders into account, and add our own min width.
qint32 min = (minWidth() + 2 * borderWidth() + spacing()) * partitions[i]->children().size() - spacing() + 2 * borderWidth();
qint32 min = (minWidth() + 2 * borderWidth() + spacing()) * p->children().size() - spacing() + 2 * borderWidth();
// if it's too small, this partition is a primary or logical so just use the configured value
if (min < minWidth())
@ -142,11 +142,11 @@ void PartWidgetBase::positionChildren(const QWidget* destWidget, const Partition
}
}
QList<PartWidget*> PartWidgetBase::childWidgets()
const QList<PartWidget*> PartWidgetBase::childWidgets() const
{
QList<PartWidget*> rval;
foreach(QObject * o, children())
for (auto &o : children())
if (PartWidget* w = qobject_cast<PartWidget*>(o))
rval.append(w);

View File

@ -55,7 +55,7 @@ public:
return m_MinWidth; /**< @return minimum width for a Partition widget */
}
virtual QList<PartWidget*> childWidgets();
virtual const QList<PartWidget*> childWidgets() const;
protected:
virtual void positionChildren(const QWidget* destWidget, const PartitionNode::Partitions& partitions, QList<PartWidget*> widgets) const;

View File

@ -6,6 +6,12 @@ set(JOBS_SRC
jobs/shredfilesystemjob.cpp
jobs/createpartitionjob.cpp
jobs/createpartitiontablejob.cpp
jobs/createvolumegroupjob.cpp
jobs/removevolumegroupjob.cpp
jobs/deactivatevolumegroupjob.cpp
jobs/deactivatelogicalvolumejob.cpp
jobs/resizevolumegroupjob.cpp
jobs/movephysicalvolumejob.cpp
jobs/setfilesystemlabeljob.cpp
jobs/deletepartitionjob.cpp
jobs/restorefilesystemjob.cpp

View File

@ -57,7 +57,7 @@ bool BackupFileSystemJob::run(Report& parent)
rval = sourcePartition().fileSystem().backup(*report, sourceDevice(), sourcePartition().deviceNode(), fileName());
else if (sourcePartition().fileSystem().supportBackup() == FileSystem::cmdSupportCore) {
CopySourceDevice copySource(sourceDevice(), sourcePartition().fileSystem().firstSector(), sourcePartition().fileSystem().lastSector());
CopyTargetFile copyTarget(fileName(), sourceDevice().logicalSectorSize());
CopyTargetFile copyTarget(fileName(), sourceDevice().logicalSize());
if (!copySource.open())
report->line() << xi18nc("@info:progress", "Could not open file system on source partition <filename>%1</filename> for backup.", sourcePartition().deviceNode());

View File

@ -53,25 +53,29 @@ bool CreateFileSystemJob::run(Report& parent)
if (partition().fileSystem().supportCreate() == FileSystem::cmdSupportFileSystem) {
if (partition().fileSystem().create(*report, partition().deviceNode())) {
CoreBackendDevice* backendDevice = CoreBackendManager::self()->backend()->openDevice(device().deviceNode());
if (device().type() == Device::Disk_Device) {
CoreBackendDevice* backendDevice = CoreBackendManager::self()->backend()->openDevice(device().deviceNode());
if (backendDevice) {
CoreBackendPartitionTable* backendPartitionTable = backendDevice->openPartitionTable();
if (backendDevice) {
CoreBackendPartitionTable* backendPartitionTable = backendDevice->openPartitionTable();
if (backendPartitionTable) {
if (backendPartitionTable->setPartitionSystemType(*report, partition())) {
rval = true;
backendPartitionTable->commit();
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 <filename>%1</filename>.", partition().deviceNode());
delete backendPartitionTable;
} else
report->line() << xi18nc("@info:progress", "Failed to set the system type for the file system on partition <filename>%1</filename>.", partition().deviceNode());
report->line() << xi18nc("@info:progress", "Could not open partition table on device <filename>%1</filename> to set the system type for partition <filename>%2</filename>.", device().deviceNode(), partition().deviceNode());
delete backendPartitionTable;
delete backendDevice;
} else
report->line() << xi18nc("@info:progress", "Could not open partition table on device <filename>%1</filename> to set the system type for partition <filename>%2</filename>.", device().deviceNode(), partition().deviceNode());
delete backendDevice;
} else
report->line() << xi18nc("@info:progress", "Could not open device <filename>%1</filename> to set the system type for partition <filename>%2</filename>.", device().deviceNode(), partition().deviceNode());
report->line() << xi18nc("@info:progress", "Could not open device <filename>%1</filename> to set the system type for partition <filename>%2</filename>.", device().deviceNode(), partition().deviceNode());
} else if (device().type() == Device::LVM_Device) {
rval = true;
}
}
}

View File

@ -25,6 +25,7 @@
#include "core/partition.h"
#include "core/device.h"
#include "core/lvmdevice.h"
#include "util/report.h"
@ -49,29 +50,38 @@ bool CreatePartitionJob::run(Report& parent)
Report* report = jobStarted(parent);
CoreBackendDevice* backendDevice = CoreBackendManager::self()->backend()->openDevice(device().deviceNode());
if (device().type() == Device::Disk_Device) {
CoreBackendDevice* backendDevice = CoreBackendManager::self()->backend()->openDevice(device().deviceNode());
if (backendDevice) {
CoreBackendPartitionTable* backendPartitionTable = backendDevice->openPartitionTable();
if (backendDevice) {
CoreBackendPartitionTable* backendPartitionTable = backendDevice->openPartitionTable();
if (backendPartitionTable) {
QString partitionPath = backendPartitionTable->createPartition(*report, partition());
if (backendPartitionTable) {
QString partitionPath = backendPartitionTable->createPartition(*report, partition());
if (partitionPath != QString()) {
rval = true;
partition().setPartitionPath(partitionPath);
partition().setState(Partition::StateNone);
backendPartitionTable->commit();
if (partitionPath != QString()) {
rval = true;
partition().setPartitionPath(partitionPath);
partition().setState(Partition::StateNone);
backendPartitionTable->commit();
} else
report->line() << xi18nc("@info/plain", "Failed to add partition <filename>%1</filename> to device <filename>%2</filename>.", partition().deviceNode(), device().deviceNode());
delete backendPartitionTable;
} else
report->line() << xi18nc("@info:progress", "Failed to add partition <filename>%1</filename> to device <filename>%2</filename>.", partition().deviceNode(), device().deviceNode());
report->line() << xi18nc("@info:progress", "Could not open partition table on device <filename>%1</filename> to create new partition <filename>%2</filename>.", device().deviceNode(), partition().deviceNode());
delete backendPartitionTable;
delete backendDevice;
} else
report->line() << xi18nc("@info:progress", "Could not open partition table on device <filename>%1</filename> to create new partition <filename>%2</filename>.", device().deviceNode(), partition().deviceNode());
report->line() << xi18nc("@info:progress", "Could not open device <filename>%1</filename> to create new partition <filename>%2</filename>.", device().deviceNode(), partition().deviceNode());
} else if (device().type() == Device::LVM_Device) {
LvmDevice& dev = dynamic_cast<LvmDevice&>(device());
partition().setState(Partition::StateNone);
delete backendDevice;
} else
report->line() << xi18nc("@info:progress", "Could not open device <filename>%1</filename> to create new partition <filename>%2</filename>.", device().deviceNode(), partition().deviceNode());
QString partPath = partition().partitionPath();
QString lvname = partPath.right(partPath.length() - partPath.lastIndexOf(QStringLiteral("/")) - 1);
rval = LvmDevice::createLV(*report, dev, partition(), lvname);
}
jobFinished(*report, rval);

View File

@ -44,16 +44,20 @@ bool CreatePartitionTableJob::run(Report& parent)
Report* report = jobStarted(parent);
CoreBackendDevice* backendDevice = CoreBackendManager::self()->backend()->openDevice(device().deviceNode());
if (device().type() == Device::Disk_Device) {
CoreBackendDevice* backendDevice = CoreBackendManager::self()->backend()->openDevice(device().deviceNode());
if (backendDevice != nullptr) {
Q_ASSERT(device().partitionTable());
if (backendDevice != nullptr) {
Q_ASSERT(device().partitionTable());
rval = backendDevice->createPartitionTable(*report, *device().partitionTable());
rval = backendDevice->createPartitionTable(*report, *device().partitionTable());
delete backendDevice;
} else
report->line() << xi18nc("@info:progress", "Creating partition table failed: Could not open device <filename>%1</filename>.", device().deviceNode());
delete backendDevice;
} else
report->line() << xi18nc("@info:progress", "Creating partition table failed: Could not open device <filename>%1</filename>.", device().deviceNode());
} else if (device().type() == Device::LVM_Device) {
//TODO: figure what to do wit LVM partitionTable
}
jobFinished(*report, rval);

View File

@ -0,0 +1,59 @@
/*************************************************************************
* Copyright (C) 2016 by Chantara Tith <tith.chantara@gmail.com> *
* *
* 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 <http://www.gnu.org/licenses/>.*
*************************************************************************/
#include "jobs/createvolumegroupjob.h"
#include "core/lvmdevice.h"
#include "util/report.h"
#include <KLocalizedString>
/** Creates a new CreateVolumeGroupJob
* @param vgName LVM Volume Group name
* @param pvList List of LVM Physical Volumes used to create Volume Group
* @param peSize LVM Physical Extent size in MiB
*/
CreateVolumeGroupJob::CreateVolumeGroupJob(const QString& vgName, const QStringList& pvList, const qint32 peSize) :
Job(),
m_vgName(vgName),
m_pvList(pvList),
m_PESize(peSize)
{
}
bool CreateVolumeGroupJob::run(Report& parent)
{
bool rval = false;
Report* report = jobStarted(parent);
rval = LvmDevice::createVG(*report, vgName(), pvList(), peSize());
jobFinished(*report, rval);
return rval;
}
QString CreateVolumeGroupJob::description() const
{
QString tmp = QString();
for (const auto &name : pvList()) {
tmp += QStringLiteral("\n") + name;
}
return xi18nc("@info/plain", "Create new Volume Group: <filename>%1</filename> with PV: %2", vgName(), tmp);
}

View File

@ -0,0 +1,63 @@
/*************************************************************************
* Copyright (C) 2016 by Chantara Tith <tith.chantara@gmail.com> *
* *
* 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 <http://www.gnu.org/licenses/>.*
*************************************************************************/
#if !defined(CREATEVOLUMEGROUPJOB_H)
#define CREATEVOLUMEGROUPJOB_H
#include "jobs/job.h"
class LvmDevice;
class Partition;
class Report;
class QString;
class CreateVolumeGroupJob : public Job
{
public:
CreateVolumeGroupJob(const QString& vgName, const QStringList& pvList, const qint32 peSize);
public:
bool run(Report& parent) override;
QString description() const override;
protected:
QString vgName() {
return m_vgName;
}
const QString vgName() const {
return m_vgName;
}
QStringList pvList() {
return m_pvList;
}
const QStringList pvList() const {
return m_pvList;
}
qint32 peSize() {
return m_PESize;
}
private:
QString m_vgName;
QStringList m_pvList;
qint32 m_PESize;
};
#endif

View File

@ -0,0 +1,61 @@
/*************************************************************************
* Copyright (C) 2016 by Chantara Tith <tith.chantara@gmail.com> *
* *
* 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 <http://www.gnu.org/licenses/>.*
*************************************************************************/
#include "jobs/deactivatelogicalvolumejob.h"
#include "core/lvmdevice.h"
#include "core/partition.h"
#include "core/partitiontable.h"
#include "util/report.h"
#include <KLocalizedString>
/** 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) {
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: <filename>%1</filename>", device().prettyDeviceNodeList());
}

View File

@ -0,0 +1,53 @@
/*************************************************************************
* Copyright (C) 2016 by Chantara Tith <tith.chantara@gmail.com> *
* *
* 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 <http://www.gnu.org/licenses/>.*
*************************************************************************/
#if !defined(DEACTIVATELOGICALVOLUMEJOB_H)
#define DEACTIVATELOGICALVOLUMEJOB_H
#include "jobs/job.h"
class VolumeManagerDevice;
class Partition;
class Report;
class QString;
class DeactivateLogicalVolumeJob : public Job
{
public:
DeactivateLogicalVolumeJob(const VolumeManagerDevice& dev, const QStringList lvPaths = {});
public:
bool run(Report& parent) override;
QString description() const override;
protected:
const VolumeManagerDevice& device() const {
return m_Device;
}
QStringList LVList() const {
return m_LVList;
}
private:
const VolumeManagerDevice& m_Device;
const QStringList m_LVList;
};
#endif

View File

@ -0,0 +1,52 @@
/*************************************************************************
* Copyright (C) 2016 by Chantara Tith <tith.chantara@gmail.com> *
* *
* 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 <http://www.gnu.org/licenses/>.*
*************************************************************************/
#include "jobs/deactivatevolumegroupjob.h"
#include "core/lvmdevice.h"
#include "util/report.h"
#include <KLocalizedString>
/** 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) {
rval = LvmDevice::deactivateVG(*report, dynamic_cast<LvmDevice&>(device()));
}
jobFinished(*report, rval);
return rval;
}
QString DeactivateVolumeGroupJob::description() const
{
return xi18nc("@info/plain", "Deactivate Volume Group: <filename>%1</filename>", device().name());
}

View File

@ -0,0 +1,51 @@
/*************************************************************************
* Copyright (C) 2016 by Chantara Tith <tith.chantara@gmail.com> *
* *
* 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 <http://www.gnu.org/licenses/>.*
*************************************************************************/
#if !defined(DEACTIVATEVOLUMEGROUPJOB_H)
#define DEACTIVATEVOLUMEGROUPJOB_H
#include "jobs/job.h"
class VolumeManagerDevice;
class Partition;
class Report;
class QString;
class DeactivateVolumeGroupJob : public Job
{
public:
DeactivateVolumeGroupJob(VolumeManagerDevice& dev);
public:
bool run(Report& parent) override;
QString description() const override;
protected:
VolumeManagerDevice& device() {
return m_Device;
}
const VolumeManagerDevice& device() const {
return m_Device;
}
private:
VolumeManagerDevice& m_Device;
};
#endif

View File

@ -63,8 +63,11 @@ bool DeleteFileSystemJob::run(Report& parent)
return false;
}
if (partition().roles().has(PartitionRole::Extended))
if (partition().roles().has(PartitionRole::Extended)) {
rval = true;
} else if (device().type() == Device::LVM_Device) {
rval = true;
}
else {
if (!partition().fileSystem().remove(*report, partition().deviceNode())) {
jobFinished(*report, rval);

View File

@ -25,6 +25,7 @@
#include "core/partition.h"
#include "core/device.h"
#include "core/lvmdevice.h"
#include "util/report.h"
@ -56,27 +57,32 @@ bool DeletePartitionJob::run(Report& parent)
Report* report = jobStarted(parent);
CoreBackendDevice* backendDevice = CoreBackendManager::self()->backend()->openDevice(device().deviceNode());
if (device().type() == Device::Disk_Device) {
CoreBackendDevice* backendDevice = CoreBackendManager::self()->backend()->openDevice(device().deviceNode());
if (backendDevice) {
CoreBackendPartitionTable* backendPartitionTable = backendDevice->openPartitionTable();
if (backendDevice) {
CoreBackendPartitionTable* backendPartitionTable = backendDevice->openPartitionTable();
if (backendPartitionTable) {
rval = backendPartitionTable->deletePartition(*report, partition());
if (backendPartitionTable) {
rval = backendPartitionTable->deletePartition(*report, partition());
if (!rval)
report->line() << xi18nc("@info:progress", "Could not delete partition <filename>%1</filename>.", partition().deviceNode());
else
backendPartitionTable->commit();
if (!rval)
report->line() << xi18nc("@info:progress", "Could not delete partition <filename>%1</filename>.", partition().deviceNode());
else
backendPartitionTable->commit();
delete backendPartitionTable;
delete backendPartitionTable;
} else
report->line() << xi18nc("@info:progress", "Could not open partition table on device <filename>%1</filename> to delete partition <filename>%2</filename>.", device().deviceNode(), partition().deviceNode());
delete backendDevice;
} else
report->line() << xi18nc("@info:progress", "Could not open partition table on device <filename>%1</filename> to delete partition <filename>%2</filename>.", device().deviceNode(), partition().deviceNode());
delete backendDevice;
} else
report->line() << xi18nc("@info:progress", "Deleting partition failed: Could not open device <filename>%1</filename>.", device().deviceNode());
report->line() << xi18nc("@info:progress", "Deleting partition failed: Could not open device <filename>%1</filename>.", device().deviceNode());
} else if (device().type() == Device::LVM_Device) {
LvmDevice& dev = dynamic_cast<LvmDevice&>(device());
rval = LvmDevice::removeLV(*report, dev, partition());
}
jobFinished(*report, rval);

View File

@ -0,0 +1,64 @@
/*************************************************************************
* Copyright (C) 2016 by Chantara Tith <tith.chantara@gmail.com> *
* *
* 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 <http://www.gnu.org/licenses/>.*
*************************************************************************/
#include "jobs/movephysicalvolumejob.h"
#include "core/lvmdevice.h"
#include "util/report.h"
#include <KLocalizedString>
/** Creates a new MovePhysicalVolumeJob
* @param d Device representing LVM Volume Group
*/
MovePhysicalVolumeJob::MovePhysicalVolumeJob(LvmDevice& d, const QStringList partList) :
Job(),
m_Device(d),
m_PartList(partList)
{
}
bool MovePhysicalVolumeJob::run(Report& parent)
{
bool rval = false;
Report* report = jobStarted(parent);
QStringList destinations = LvmDevice::getPVs(device().name());
for (const auto &partPath : partList()) {
if (destinations.contains(partPath)) {
destinations.removeAll(partPath);
}
}
for (const auto &partPath : partList()) {
rval = LvmDevice::movePV(*report, partPath, destinations);
if (rval == false) {
break;
}
}
jobFinished(*report, rval);
return rval;
}
QString MovePhysicalVolumeJob::description() const
{
return xi18nc("@info/plain", "Move used PE in %1 on %2 to other available Physical Volumes", partList().join(QStringLiteral(", ")), device().name());
}

View File

@ -0,0 +1,55 @@
/*************************************************************************
* Copyright (C) 2016 by Chantara Tith <tith.chantara@gmail.com> *
* *
* 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 <http://www.gnu.org/licenses/>.*
*************************************************************************/
#if !defined(MOVEPHYSICALVOLUMEJOB_H)
#define MOVEPHYSICALVOLUMEJOB_H
#include "jobs/job.h"
class LvmDevice;
class Report;
class QString;
class MovePhysicalVolumeJob : public Job
{
public:
MovePhysicalVolumeJob(LvmDevice& dev, const QStringList partlist);
public:
bool run(Report& parent) override;
QString description() const override;
protected:
LvmDevice& device() {
return m_Device;
}
const LvmDevice& device() const {
return m_Device;
}
const QStringList partList() const {
return m_PartList;
}
private:
LvmDevice& m_Device;
const QStringList m_PartList;
};
#endif

View File

@ -0,0 +1,52 @@
/*************************************************************************
* Copyright (C) 2016 by Chantara Tith <tith.chantara@gmail.com> *
* *
* 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 <http://www.gnu.org/licenses/>.*
*************************************************************************/
#include "jobs/removevolumegroupjob.h"
#include "core/lvmdevice.h"
#include "util/report.h"
#include <KLocalizedString>
/** 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) {
rval = LvmDevice::removeVG(*report, dynamic_cast<LvmDevice&>(device()));
}
jobFinished(*report, rval);
return rval;
}
QString RemoveVolumeGroupJob::description() const
{
return xi18nc("@info/plain", "Remove Volume Group: <filename>%1</filename>", device().name());
}

View File

@ -0,0 +1,51 @@
/*************************************************************************
* Copyright (C) 2016 by Chantara Tith <tith.chantara@gmail.com> *
* *
* 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 <http://www.gnu.org/licenses/>.*
*************************************************************************/
#if !defined(REMOVEVOLUMEGROUPJOB_H)
#define REMOVEVOLUMEGROUPJOB_H
#include "jobs/job.h"
class VolumeManagerDevice;
class Partition;
class Report;
class QString;
class RemoveVolumeGroupJob : public Job
{
public:
RemoveVolumeGroupJob(VolumeManagerDevice& dev);
public:
bool run(Report& parent) override;
QString description() const override;
protected:
VolumeManagerDevice& device() {
return m_Device;
}
const VolumeManagerDevice& device() const {
return m_Device;
}
private:
VolumeManagerDevice& m_Device;
};
#endif

View File

@ -86,7 +86,7 @@ bool ResizeFileSystemJob::run(Report& parent)
}
case FileSystem::cmdSupportFileSystem: {
const qint64 newLengthInByte = Capacity(newLength() * device().logicalSectorSize()).toInt(Capacity::Byte);
const qint64 newLengthInByte = Capacity(newLength() * device().logicalSize()).toInt(Capacity::Byte);
rval = partition().fileSystem().resize(*report, partition().deviceNode(), newLengthInByte);
break;
}

View File

@ -0,0 +1,69 @@
/*************************************************************************
* Copyright (C) 2016 by Chantara Tith <tith.chantara@gmail.com> *
* *
* 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 <http://www.gnu.org/licenses/>.*
*************************************************************************/
#include "jobs/resizevolumegroupjob.h"
#include "core/lvmdevice.h"
#include "util/report.h"
#include <KLocalizedString>
/** Creates a new ResizeVolumeGroupJob
*/
ResizeVolumeGroupJob::ResizeVolumeGroupJob(LvmDevice& dev, const QStringList partlist, const Type type) :
Job(),
m_Device(dev),
m_PartList(partlist),
m_Type(type)
{
}
bool ResizeVolumeGroupJob::run(Report& parent)
{
bool rval = false;
Report* report = jobStarted(parent);
for (const auto &pvpath : partList()) {
if (type() == ResizeVolumeGroupJob::Grow) {
rval = LvmDevice::insertPV(*report, device(), pvpath);
} else if (type() == ResizeVolumeGroupJob::Shrink) {
rval = LvmDevice::removePV(*report, device(), pvpath);
}
if (rval == false) {
break;
}
}
jobFinished(*report, rval);
return rval;
}
QString ResizeVolumeGroupJob::description() const
{
const QString partitionList = partList().join(QStringLiteral(", "));
if (type() == ResizeVolumeGroupJob::Grow) {
return xi18nc("@info/plain", "Inserting Volume: %1 to %2.", partitionList, device().name());
}
if (type() == ResizeVolumeGroupJob::Shrink) {
return xi18nc("@info/plain", "Removing Volume: %1 from %2.", partitionList, device().name());
}
return xi18nc("@info/plain", "Resizing Volume: %1 to %2.", device().name(), partitionList);
}

View File

@ -0,0 +1,67 @@
/*************************************************************************
* Copyright (C) 2016 by Chantara Tith <tith.chantara@gmail.com> *
* *
* 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 <http://www.gnu.org/licenses/>.*
*************************************************************************/
#if !defined(RESIZEVOLUMEGROUPJOB_H)
#define RESIZEVOLUMEGROUPJOB_H
#include "jobs/job.h"
class LvmDevice;
class Report;
class QString;
class ResizeVolumeGroupJob : public Job
{
public:
enum Type {
Grow = 0,
Shrink = 1
};
public:
ResizeVolumeGroupJob(LvmDevice& dev, const QStringList partlist, const Type type);
public:
bool run(Report& parent) override;
QString description() const override;
protected:
LvmDevice& device() {
return m_Device;
}
const LvmDevice& device() const {
return m_Device;
}
const QStringList partList() const {
return m_PartList;
}
ResizeVolumeGroupJob::Type type() const {
return m_Type;
}
private:
LvmDevice& m_Device;
const QStringList m_PartList;
ResizeVolumeGroupJob::Type m_Type;
};
#endif

View File

@ -70,7 +70,7 @@ bool SetPartFlagsJob::run(Report& parent)
if (backendPartition) {
quint32 count = 0;
foreach(const PartitionTable::Flag & f, PartitionTable::flagList()) {
for (const auto &f : PartitionTable::flagList()) {
emit progress(++count);
const bool state = (flags() & f) ? true : false;

View File

@ -25,6 +25,7 @@
#include "core/partition.h"
#include "core/device.h"
#include "core/lvmdevice.h"
#include "util/report.h"
@ -54,26 +55,35 @@ bool SetPartGeometryJob::run(Report& parent)
Report* report = jobStarted(parent);
CoreBackendDevice* backendDevice = CoreBackendManager::self()->backend()->openDevice(device().deviceNode());
if(device().type() == Device::Disk_Device) {
CoreBackendDevice* backendDevice = CoreBackendManager::self()->backend()->openDevice(device().deviceNode());
if (backendDevice) {
CoreBackendPartitionTable* backendPartitionTable = backendDevice->openPartitionTable();
if (backendDevice) {
CoreBackendPartitionTable* backendPartitionTable = backendDevice->openPartitionTable();
if (backendPartitionTable) {
rval = backendPartitionTable->updateGeometry(*report, partition(), newStart(), newStart() + newLength() - 1);
if (backendPartitionTable) {
rval = backendPartitionTable->updateGeometry(*report, partition(), newStart(), newStart() + newLength() - 1);
if (rval) {
partition().setFirstSector(newStart());
partition().setLastSector(newStart() + newLength() - 1);
backendPartitionTable->commit();
if (rval) {
partition().setFirstSector(newStart());
partition().setLastSector(newStart() + newLength() - 1);
backendPartitionTable->commit();
}
delete backendPartitionTable;
}
delete backendPartitionTable;
}
delete backendDevice;
} else
report->line() << xi18nc("@info:progress", "Could not open device <filename>%1</filename> while trying to resize/move partition <filename>%2</filename>.", device().deviceNode(), partition().deviceNode());
delete backendDevice;
} else
report->line() << xi18nc("@info:progress", "Could not open device <filename>%1</filename> while trying to resize/move partition <filename>%2</filename>.", device().deviceNode(), partition().deviceNode());
} else if (device().type() == Device::LVM_Device) {
partition().setFirstSector(newStart());
partition().setLastSector(newStart() + newLength() - 1);
rval = LvmDevice::resizeLV(*report, partition());
}
jobFinished(*report, rval);

View File

@ -6,6 +6,10 @@ set(OPS_SRC
ops/newoperation.cpp
ops/createfilesystemoperation.cpp
ops/createpartitiontableoperation.cpp
ops/createvolumegroupoperation.cpp
ops/removevolumegroupoperation.cpp
ops/deactivatevolumegroupoperation.cpp
ops/resizevolumegroupoperation.cpp
ops/setfilesystemlabeloperation.cpp
ops/setpartflagsoperation.cpp
ops/checkoperation.cpp
@ -19,6 +23,10 @@ set(OPS_LIB_HDRS
ops/copyoperation.h
ops/createfilesystemoperation.h
ops/createpartitiontableoperation.h
ops/createvolumegroupoperation.h
ops/removevolumegroupoperation.h
ops/deactivatevolumegroupoperation.h
ops/resizevolumegroupoperation.h
ops/deleteoperation.h
ops/newoperation.h
ops/operation.h

View File

@ -211,7 +211,7 @@ QString CopyOperation::updateDescription() const
sourcePartition().deviceNode(),
Capacity::formatByteSize(sourcePartition().capacity()),
sourcePartition().fileSystem().name(),
Capacity::formatByteSize(copiedPartition().firstSector() * targetDevice().logicalSectorSize()),
Capacity::formatByteSize(copiedPartition().firstSector() * targetDevice().logicalSize()),
targetDevice().deviceNode()
);
@ -219,7 +219,7 @@ QString CopyOperation::updateDescription() const
sourcePartition().deviceNode(),
Capacity::formatByteSize(sourcePartition().capacity()),
sourcePartition().fileSystem().name(),
Capacity::formatByteSize(copiedPartition().firstSector() * targetDevice().logicalSectorSize()),
Capacity::formatByteSize(copiedPartition().firstSector() * targetDevice().logicalSize()),
targetDevice().deviceNode(),
Capacity::formatByteSize(copiedPartition().capacity())
);

View File

@ -93,7 +93,7 @@ bool CreatePartitionTableOperation::execute(Report& parent)
*/
bool CreatePartitionTableOperation::canCreate(const Device* device)
{
return device != nullptr && (device->partitionTable() == nullptr || !device->partitionTable()->isChildMounted());
return (device != nullptr) && (device->partitionTable() == nullptr || !device->partitionTable()->isChildMounted()) && (device->type() != Device::LVM_Device);
}
QString CreatePartitionTableOperation::description() const

View File

@ -0,0 +1,69 @@
/*************************************************************************
* Copyright (C) 2016 by Chantara Tith <tith.chantara@gmail.com> *
* *
* 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 <http://www.gnu.org/licenses/>.*
*************************************************************************/
#include "ops/createvolumegroupoperation.h"
#include "core/lvmdevice.h"
#include "fs/lvm2_pv.h"
#include "jobs/createvolumegroupjob.h"
#include <QString>
#include <KLocalizedString>
/** Creates a new CreateVolumeGroupOperation.
* @param vgName LVM Volume Group name
* @param pvList List of LVM Physical Volumes used to create Volume Group
* @param peSize LVM Physical Extent size in MiB
*/
CreateVolumeGroupOperation::CreateVolumeGroupOperation(const QString& vgName, const QStringList& pvList, const qint32 peSize) :
Operation(),
m_CreateVolumeGroupJob(new CreateVolumeGroupJob(vgName, pvList, peSize)),
m_PVList(pvList)
{
addJob(createVolumeGroupJob());
}
QString CreateVolumeGroupOperation::description() const
{
return xi18nc("@info/plain", "Create a new LVM volume group.");
}
bool CreateVolumeGroupOperation::targets(const Partition&) const
{
return false;
}
void CreateVolumeGroupOperation::preview()
{
LvmDevice::s_DirtyPVs << PVList();
}
void CreateVolumeGroupOperation::undo()
{
for (const auto &pvPath : PVList()) {
if (LvmDevice::s_DirtyPVs.contains(pvPath)) {
LvmDevice::s_DirtyPVs.removeAll(pvPath);
}
}
}
bool CreateVolumeGroupOperation::canCreate()
{
return true;
}

View File

@ -0,0 +1,73 @@
/*************************************************************************
* Copyright (C) 2016 by Chantara Tith <tith.chantara@gmail.com> *
* *
* 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 <http://www.gnu.org/licenses/>.*
*************************************************************************/
#if !defined(CREATEVOLUMEGROUPOPERATION_H)
#define CREATEVOLUMEGROUPOPERATION_H
#include "util/libpartitionmanagerexport.h"
#include "ops/operation.h"
#include "core/lvmdevice.h"
#include <QString>
class CreateVolumeGroupJob;
class OperationStack;
class LIBKPMCORE_EXPORT CreateVolumeGroupOperation : public Operation
{
Q_DISABLE_COPY(CreateVolumeGroupOperation)
friend class OperationStack;
public:
CreateVolumeGroupOperation(const QString& vgName, const QStringList& pvList, const qint32 peSize = 4);
public:
QString iconName() const override {
return QStringLiteral("document-new");
}
QString description() const override;
virtual bool targets(const Device&) const override {
return true;
}
virtual bool targets(const Partition&) const override;
virtual void preview() override;
virtual void undo() override;
static bool canCreate();
protected:
CreateVolumeGroupJob* createVolumeGroupJob() {
return m_CreateVolumeGroupJob;
}
const QStringList PVList() {
return m_PVList;
}
private:
CreateVolumeGroupJob* m_CreateVolumeGroupJob;
QStringList m_PVList;
};
#endif

View File

@ -0,0 +1,79 @@
/*************************************************************************
* Copyright (C) 2016 by Chantara Tith <tith.chantara@gmail.com> *
* *
* 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 <http://www.gnu.org/licenses/>.*
*************************************************************************/
#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 <QString>
#include <KLocalizedString>
/** 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()
{
device().setPartitionTable(new PartitionTable(PartitionTable::vmd, 0, device().totalLogical() - 1));
}
void DeactivateVolumeGroupOperation::undo()
{
PartitionTable* tmp = device().partitionTable();
if (tmp != partitionTable()) {
device().setPartitionTable(partitionTable());
delete tmp;
}
}
/** loop through given device's partitions to check if any is mounted.
*
* @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) {
for (const auto &p : dev->partitionTable()->children()) {
if (p->isMounted()) {
return false;
}
}
return true;
}
return false;
}

View File

@ -0,0 +1,87 @@
/*************************************************************************
* Copyright (C) 2016 by Chantara Tith <tith.chantara@gmail.com> *
* *
* 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 <http://www.gnu.org/licenses/>.*
*************************************************************************/
#if !defined(DEACTIVATEVOLUMEGROUPOPERATION_H)
#define DEACTIVATEVOLUMEGROUPOPERATION_H
#include "util/libpartitionmanagerexport.h"
#include "ops/operation.h"
#include <QString>
class DeactivateLogicalVolumeJob;
class DeactivateVolumeGroupJob;
class VolumeManagerDevice;
class OperationStack;
class PartitionTable;
class LIBKPMCORE_EXPORT DeactivateVolumeGroupOperation : public Operation
{
Q_DISABLE_COPY(DeactivateVolumeGroupOperation)
friend class OperationStack;
public:
DeactivateVolumeGroupOperation(VolumeManagerDevice& d);
public:
QString iconName() const override {
return QStringLiteral("edit-delete");
}
QString description() const override;
virtual bool targets(const Device&) const override {
return true;
}
virtual bool targets(const Partition&) const override {
return false;
}
virtual void preview() override;
virtual void undo() override;
static bool isDeactivatable(const VolumeManagerDevice* dev);
protected:
DeactivateVolumeGroupJob* deactivateVolumeGroupJob() {
return m_DeactivateVolumeGroupJob;
}
DeactivateLogicalVolumeJob* deactivateLogicalVolumeJob() {
return m_DeactivateLogicalVolumeJob;
}
VolumeManagerDevice& device() {
return m_Device;
}
PartitionTable* partitionTable() {
return m_PartitionTable;
}
private:
DeactivateVolumeGroupJob* m_DeactivateVolumeGroupJob;
DeactivateLogicalVolumeJob* m_DeactivateLogicalVolumeJob;
VolumeManagerDevice& m_Device;
PartitionTable* m_PartitionTable;
};
#endif

View File

@ -146,7 +146,7 @@ qint32 Operation::totalProgress() const
{
qint32 result = 0;
foreach(const Job * job, jobs())
for (const auto &job : jobs())
result += job->numSteps();
return result;
@ -162,7 +162,8 @@ bool Operation::execute(Report& parent)
Report* report = parent.newChild(description());
foreach(Job * job, jobs())
const auto Jobs = jobs();
for (const auto &job : Jobs)
if (!(rval = job->run(*report)))
break;

View File

@ -0,0 +1,48 @@
/*************************************************************************
* Copyright (C) 2016 by Chantara Tith <tith.chantara@gmail.com> *
* *
* 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 <http://www.gnu.org/licenses/>.*
*************************************************************************/
#include "ops/removevolumegroupoperation.h"
#include "jobs/removevolumegroupjob.h"
#include "core/volumemanagerdevice.h"
#include <QString>
#include <KLocalizedString>
/** Creates a new RemoveVolumeGroupOperation.
*/
RemoveVolumeGroupOperation::RemoveVolumeGroupOperation(VolumeManagerDevice& d) :
Operation(),
m_RemoveVolumeGroupJob(new RemoveVolumeGroupJob(d)),
m_Device(d)
{
addJob(removeVolumeGroupJob());
}
QString RemoveVolumeGroupOperation::description() const
{
return xi18nc("@info/plain", "Remove a new LVM volume group.");
}
void RemoveVolumeGroupOperation::preview()
{
}
void RemoveVolumeGroupOperation::undo()
{
}

View File

@ -0,0 +1,72 @@
/*************************************************************************
* Copyright (C) 2016 by Chantara Tith <tith.chantara@gmail.com> *
* *
* 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 <http://www.gnu.org/licenses/>.*
*************************************************************************/
#if !defined(REMOVEVOLUMEGROUPOPERATION_H)
#define REMOVEVOLUMEGROUPOPERATION_H
#include "util/libpartitionmanagerexport.h"
#include "ops/operation.h"
#include <QString>
class RemoveVolumeGroupJob;
class VolumeManagerDevice;
class OperationStack;
class LIBKPMCORE_EXPORT RemoveVolumeGroupOperation : public Operation
{
Q_DISABLE_COPY(RemoveVolumeGroupOperation)
friend class OperationStack;
public:
RemoveVolumeGroupOperation(VolumeManagerDevice& d);
public:
QString iconName() const override {
return QStringLiteral("edit-delete");
}
QString description() const override;
virtual bool targets(const Device&) const override {
return true;
}
virtual bool targets(const Partition&) const override {
return false;
}
virtual void preview() override;
virtual void undo() override;
protected:
RemoveVolumeGroupJob* removeVolumeGroupJob() {
return m_RemoveVolumeGroupJob;
}
VolumeManagerDevice& device() {
return m_Device;
}
private:
RemoveVolumeGroupJob* m_RemoveVolumeGroupJob;
VolumeManagerDevice& m_Device;
};
#endif

View File

@ -187,10 +187,10 @@ QString ResizeOperation::description() const
// Each of these needs a different description. And for reasons of i18n, we cannot
// just concatenate strings together...
const QString moveDelta = Capacity::formatByteSize(qAbs(newFirstSector() - origFirstSector()) * targetDevice().logicalSectorSize());
const QString moveDelta = Capacity::formatByteSize(qAbs(newFirstSector() - origFirstSector()) * targetDevice().logicalSize());
const QString origCapacity = Capacity::formatByteSize(origLength() * targetDevice().logicalSectorSize());
const QString newCapacity = Capacity::formatByteSize(newLength() * targetDevice().logicalSectorSize());
const QString origCapacity = Capacity::formatByteSize(origLength() * targetDevice().logicalSize());
const QString newCapacity = Capacity::formatByteSize(newLength() * targetDevice().logicalSize());
switch (resizeAction()) {
case MoveLeft:

View File

@ -0,0 +1,122 @@
/*************************************************************************
* Copyright (C) 2016 by Chantara Tith <tith.chantara@gmail.com> *
* *
* 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 <http://www.gnu.org/licenses/>.*
*************************************************************************/
#include "ops/resizevolumegroupoperation.h"
#include "core/lvmdevice.h"
#include "fs/lvm2_pv.h"
#include "core/partition.h"
#include "jobs/resizevolumegroupjob.h"
#include "jobs/movephysicalvolumejob.h"
#include <QString>
#include <KLocalizedString>
/** Creates a new ResizeVolumeGroupOperation.
@param d the Device to create the new PartitionTable on
@param partlist list of LVM Physical Volumes that should be in LVM Volume Group
*/
ResizeVolumeGroupOperation::ResizeVolumeGroupOperation(LvmDevice& d, const QStringList partlist) :
Operation(),
m_Device(d),
m_TargetList(partlist),
m_CurrentList(LvmDevice::getPVs(d.name())),
m_GrowVolumeGroupJob(nullptr),
m_ShrinkVolumeGroupJob(nullptr),
m_MovePhysicalVolumeJob(nullptr)
{
const QStringList curList = currentList();
m_TargetSize = FS::lvm2_pv::getPVSize(targetList());
m_CurrentSize = FS::lvm2_pv::getPVSize(currentList());
QStringList toRemoveList = curList;
for (QString path : partlist) {
if (toRemoveList.contains(path)) {
toRemoveList.removeAll(path);
}
}
QStringList toInsertList = partlist;
for (QString path : curList) {
if (toInsertList.contains(path)) {
toInsertList.removeAll(path);
}
}
qint64 freePE = FS::lvm2_pv::getFreePE(curList) - FS::lvm2_pv::getFreePE(toRemoveList);
qint64 movePE = FS::lvm2_pv::getAllocatedPE(toRemoveList);
qint64 growPE = FS::lvm2_pv::getPVSize(toInsertList) / LvmDevice::getPeSize(d.name());
if ( movePE > (freePE + growPE)) {
// *ABORT* can't move
} else if (partlist == curList) {
// *DO NOTHING*
} else {
if (!toInsertList.isEmpty()) {
m_GrowVolumeGroupJob = new ResizeVolumeGroupJob(d, toInsertList, ResizeVolumeGroupJob::Grow);
addJob(growVolumeGroupJob());
}
if (!toRemoveList.isEmpty()) {
m_MovePhysicalVolumeJob = new MovePhysicalVolumeJob(d, toRemoveList);
m_ShrinkVolumeGroupJob = new ResizeVolumeGroupJob(d, toRemoveList, ResizeVolumeGroupJob::Shrink);
addJob(movePhysicalVolumeJob());
addJob(shrinkvolumegroupjob());
}
}
}
QString ResizeVolumeGroupOperation::description() const
{
QString tList = targetList().join(QStringLiteral(", "));
QString curList = currentList().join(QStringLiteral(", "));
return xi18nc("@info/plain", "Resize volume %1 from %2 to %3", device().name(), curList, tList);
}
bool ResizeVolumeGroupOperation::targets(const Device& d) const
{
return d == device();
}
bool ResizeVolumeGroupOperation::targets(const Partition& p) const
{
for (QString partPath : targetList()) {
if (partPath == p.partitionPath()) {
return true;
}
}
return false;
}
void ResizeVolumeGroupOperation::preview()
{
//asumming that targetSize is larger than the allocated space.
device().setTotalLogical(targetSize() / device().logicalSize());
device().partitionTable()->setFirstUsableSector(PartitionTable::defaultFirstUsable(device(), PartitionTable::vmd));
device().partitionTable()->setLastUsableSector(PartitionTable::defaultLastUsable(device(), PartitionTable::vmd));
device().partitionTable()->updateUnallocated(device());
}
void ResizeVolumeGroupOperation::undo()
{
device().setTotalLogical(currentSize() / device().logicalSize());
device().partitionTable()->setFirstUsableSector(PartitionTable::defaultFirstUsable(device(), PartitionTable::vmd));
device().partitionTable()->setLastUsableSector(PartitionTable::defaultLastUsable(device(), PartitionTable::vmd));
device().partitionTable()->updateUnallocated(device());
}

View File

@ -0,0 +1,108 @@
/*************************************************************************
* Copyright (C) 2016 by Chantara Tith <tith.chantara@gmail.com> *
* *
* 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 <http://www.gnu.org/licenses/>.*
*************************************************************************/
#if !defined(RESIZEVOLUMEGROUPOPERATION_H)
#define RESIZEVOLUMEGROUPOPERATION_H
#include "util/libpartitionmanagerexport.h"
#include "ops/operation.h"
#include "core/lvmdevice.h"
#include <QString>
class ResizeVolumeGroupJob;
class MovePhysicalVolumeJob;
class OperationStack;
class LvmDevice;
class LIBKPMCORE_EXPORT ResizeVolumeGroupOperation : public Operation
{
Q_DISABLE_COPY(ResizeVolumeGroupOperation)
friend class OperationStack;
public:
ResizeVolumeGroupOperation(LvmDevice& dev, const QStringList partlist);
public:
QString iconName() const override {
return QStringLiteral("arrow-right-double");
}
QString description() const override;
virtual bool targets(const Device&) const override;
virtual bool targets(const Partition&) const override;
virtual void preview() override;
virtual void undo() override;
QStringList getToRemoveList();
QStringList getToInsertList();
protected:
LvmDevice& device() {
return m_Device;
}
const LvmDevice& device() const {
return m_Device;
}
const QStringList targetList() const {
return m_TargetList;
}
const QStringList currentList() const {
return m_CurrentList;
}
qint64 targetSize() const {
return m_TargetSize;
}
qint64 currentSize() const {
return m_CurrentSize;
}
ResizeVolumeGroupJob* growVolumeGroupJob() {
return m_GrowVolumeGroupJob;
}
ResizeVolumeGroupJob* shrinkvolumegroupjob() {
return m_ShrinkVolumeGroupJob;
}
MovePhysicalVolumeJob* movePhysicalVolumeJob() {
return m_MovePhysicalVolumeJob;
}
private:
LvmDevice& m_Device;
const QStringList m_TargetList;
const QStringList m_CurrentList;
qint64 m_TargetSize;
qint64 m_CurrentSize;
ResizeVolumeGroupJob *m_GrowVolumeGroupJob;
ResizeVolumeGroupJob *m_ShrinkVolumeGroupJob;
MovePhysicalVolumeJob *m_MovePhysicalVolumeJob;
};
#endif

View File

@ -164,7 +164,7 @@ QString RestoreOperation::description() const
if (overwrittenPartition())
return xi18nc("@info:status", "Restore partition from <filename>%1</filename> to <filename>%2</filename>", fileName(), overwrittenPartition()->deviceNode());
return xi18nc("@info:status", "Restore partition on <filename>%1</filename> at %2 from <filename>%3</filename>", targetDevice().deviceNode(), Capacity::formatByteSize(restorePartition().firstSector() * targetDevice().logicalSectorSize()), fileName());
return xi18nc("@info:status", "Restore partition on <filename>%1</filename> at %2 from <filename>%3</filename>", targetDevice().deviceNode(), Capacity::formatByteSize(restorePartition().firstSector() * targetDevice().logicalSize()), fileName());
}
void RestoreOperation::setOverwrittenPartition(Partition* p)
@ -222,7 +222,7 @@ Partition* RestoreOperation::createRestorePartition(const Device& device, Partit
if (!fileInfo.exists())
return nullptr;
const qint64 end = start + fileInfo.size() / device.logicalSectorSize() - 1;
const qint64 end = start + fileInfo.size() / device.logicalSize() - 1;
Partition* p = new Partition(&parent, device, PartitionRole(r), FileSystemFactory::create(FileSystem::Unknown, start, end), start, end, QString());
p->setState(Partition::StateRestore);

View File

@ -22,7 +22,7 @@
#include "plugins/dummy/dummybackend.h"
#include "plugins/dummy/dummydevice.h"
#include "core/device.h"
#include "core/diskdevice.h"
#include "core/partition.h"
#include "core/partitiontable.h"
@ -59,7 +59,7 @@ QList<Device*> DummyBackend::scanDevices(bool excludeLoop)
Device* DummyBackend::scanDevice(const QString& device_node)
{
Device* d = new Device(QStringLiteral("Dummy Device"), QStringLiteral("/tmp") + device_node, 255, 30, 63, 512);
DiskDevice* d = new DiskDevice(QStringLiteral("Dummy Device"), QStringLiteral("/tmp") + device_node, 255, 30, 63, 512);
CoreBackend::setPartitionTableForDevice(*d, new PartitionTable(PartitionTable::msdos_sectorbased, 2048, d->totalSectors() - 2048));
CoreBackend::setPartitionTableMaxPrimaries(*d->partitionTable(), 128);
d->partitionTable()->updateUnallocated(*d);

View File

@ -1,5 +1,5 @@
add_executable(kpmcore_scan scan.cpp)
target_link_libraries(kpmcore_scan ${LIBPARTED_LIBS} ${BLKID_LIBRARIES} KF5::Auth)
target_link_libraries(kpmcore_scan ${LIBPARTED_LIBS} KF5::Auth)
install(TARGETS kpmcore_scan DESTINATION ${KAUTH_HELPER_INSTALL_DIR})
kauth_install_helper_files(kpmcore_scan org.kde.kpmcore.scan root)

View File

@ -45,23 +45,3 @@ Description[uk]=Читання даних щодо використаних се
Description[x-test]=xxRead used sectorsxx
Policy=yes
Persistence=session
[org.kde.kpmcore.scan.detectfilesystem]
Name=Detect file system type action
Name[ca]=Acció de detecció del tipus de sistema de fitxers
Name[nl]=Actie voor type bestandssysteem detecteren
Name[pt]=Acção de detecção do tipo de sistema de ficheiros
Name[sl]=Dejanje zaznavanja vrste datotečnega sistema
Name[sv]=Åtgärd för att detektera typ av filsystem
Name[uk]=Дія із визначення типу файлової системи
Name[x-test]=xxDetect file system type actionxx
Description=Detect file system type
Description[ca]=Detecta el tipus de sistema de fitxers
Description[nl]=Type bestandssysteem detecteren
Description[pt]=Detectar o tipo de sistema de ficheiros
Description[sl]=Zaznaj vrsto datotečnega sistema
Description[sv]=Detektera typ av filsystem
Description[uk]=Визначення типу файлової системи
Description[x-test]=xxDetect file system typexx
Policy=yes
Persistence=session

View File

@ -19,34 +19,28 @@
#include "core/partitiontable.h"
#include "plugins/libparted/pedflags.h"
#include <blkid/blkid.h>
ActionReply Scan::scandevice(const QVariantMap& args)
{
ActionReply reply;
QString deviceNode = args[QLatin1String("deviceNode")].toString();
PedDevice* pedDevice = ped_device_get(deviceNode.toLocal8Bit().constData());
PedDevice* pedDevice = ped_device_get(args[QStringLiteral("deviceNode")].toString().toLocal8Bit().constData());
QVariantMap returnArgs;
if (!pedDevice) {
returnArgs[QLatin1String("pedDeviceError")] = true;
reply.setData(returnArgs);
reply.addData(QStringLiteral("pedDeviceError"), true);
return reply;
}
returnArgs[QLatin1String("model")] = QString::fromUtf8(pedDevice->model);
returnArgs[QLatin1String("path")] = QString::fromUtf8(pedDevice->path);
returnArgs[QLatin1String("heads")] = pedDevice->bios_geom.heads;
returnArgs[QLatin1String("sectors")] = pedDevice->bios_geom.sectors;
returnArgs[QLatin1String("cylinders")] = pedDevice->bios_geom.cylinders;
returnArgs[QLatin1String("sectorSize")] = pedDevice->sector_size;
reply.addData(QStringLiteral("model"), QString::fromUtf8(pedDevice->model));
reply.addData(QStringLiteral("path"), QString::fromUtf8(pedDevice->path));
reply.addData(QStringLiteral("heads"), pedDevice->bios_geom.heads);
reply.addData(QStringLiteral("sectors"), pedDevice->bios_geom.sectors);
reply.addData(QStringLiteral("cylinders"), pedDevice->bios_geom.cylinders);
reply.addData(QStringLiteral("sectorSize"), pedDevice->sector_size);
PedDisk* pedDisk = ped_disk_new(pedDevice);
if (!pedDisk) {
returnArgs[QLatin1String("pedDiskError")] = true;
reply.setData(returnArgs);
reply.addData(QStringLiteral("pedDiskError"), true);
return reply;
}
@ -77,13 +71,13 @@ ActionReply Scan::scandevice(const QVariantMap& args)
lastUsableSector -= 32;
}
returnArgs[QLatin1String("pedDeviceError")] = false;
returnArgs[QLatin1String("pedDiskError")] = false;
reply.addData(QStringLiteral("pedDeviceError"), false);
reply.addData(QStringLiteral("pedDiskError"), false);
returnArgs[QLatin1String("typeName")] = QString::fromUtf8(pedDisk->type->name);
returnArgs[QLatin1String("maxPrimaryPartitionCount")] = ped_disk_get_max_primary_partition_count(pedDisk);
returnArgs[QLatin1String("firstUsableSector")] = firstUsableSector;
returnArgs[QLatin1String("lastUsableSector")] = lastUsableSector;
reply.addData(QStringLiteral("typeName"), QString::fromUtf8(pedDisk->type->name));
reply.addData(QStringLiteral("maxPrimaryPartitionCount"), ped_disk_get_max_primary_partition_count(pedDisk));
reply.addData(QStringLiteral("firstUsableSector"), firstUsableSector);
reply.addData(QStringLiteral("lastUsableSector"), lastUsableSector);
PedPartition* pedPartition = nullptr;
QList<QVariant> partitionPath;
@ -98,7 +92,7 @@ ActionReply Scan::scandevice(const QVariantMap& args)
if (pedPartition->num < 1)
continue;
partitionPath.append(QLatin1String(ped_partition_get_path(pedPartition)));
partitionPath.append(QString::fromLatin1(ped_partition_get_path(pedPartition)));
partitionType.append(pedPartition->type);
partitionStart.append(pedPartition->geom.start);
partitionEnd.append(pedPartition->geom.end);
@ -113,12 +107,12 @@ ActionReply Scan::scandevice(const QVariantMap& args)
// unallocated. Libparted doesn't like it if we ask for flags for unallocated
// space.
if (pedPartition->num > 0)
for (quint32 i = 0; i < sizeof(flagmap) / sizeof(flagmap[0]); i++)
if (ped_partition_is_flag_available(pedPartition, flagmap[i].pedFlag))
for (const auto &flag : flagmap)
if (ped_partition_is_flag_available(pedPartition, flag.pedFlag))
// Workaround: libparted claims the hidden flag is available for extended partitions, but
// throws an error when we try to set or clear it. So skip this combination. Also see setFlag.
if (pedPartition->type != PED_PARTITION_EXTENDED || flagmap[i].flag != PartitionTable::FlagHidden)
flags |= flagmap[i].flag;
if (pedPartition->type != PED_PARTITION_EXTENDED || flag.flag != PartitionTable::FlagHidden)
flags |= flag.flag;
availableFlags.append(static_cast<qint32>(flags));
// --------------------------------------------------------------------------
@ -126,80 +120,38 @@ ActionReply Scan::scandevice(const QVariantMap& args)
flags = PartitionTable::FlagNone;
if (pedPartition->num > 0)
for (quint32 i = 0; i < sizeof(flagmap) / sizeof(flagmap[0]); i++)
if (ped_partition_is_flag_available(pedPartition, flagmap[i].pedFlag) && ped_partition_get_flag(pedPartition, flagmap[i].pedFlag))
flags |= flagmap[i].flag;
for (const auto &flag : flagmap)
if (ped_partition_is_flag_available(pedPartition, flag.pedFlag) && ped_partition_get_flag(pedPartition, flag.pedFlag))
flags |= flag.flag;
activeFlags.append(static_cast<qint32>(flags));
// --------------------------------------------------------------------------
}
returnArgs[QLatin1String("availableFlags")] = availableFlags;
returnArgs[QLatin1String("activeFlags")] = activeFlags;
returnArgs[QLatin1String("partitionPath")] = partitionPath;
returnArgs[QLatin1String("partitionType")] = partitionType;
returnArgs[QLatin1String("partitionStart")] = partitionStart;
returnArgs[QLatin1String("partitionEnd")] = partitionEnd;
returnArgs[QLatin1String("partitionBusy")] = partitionBusy;
reply.addData(QStringLiteral("availableFlags"), availableFlags);
reply.addData(QStringLiteral("activeFlags"), activeFlags);
reply.addData(QStringLiteral("partitionPath"), partitionPath);
reply.addData(QStringLiteral("partitionType"), partitionType);
reply.addData(QStringLiteral("partitionStart"), partitionStart);
reply.addData(QStringLiteral("partitionEnd"), partitionEnd);
reply.addData(QStringLiteral("partitionBusy"), partitionBusy);
reply.setData(returnArgs);
return reply;
}
ActionReply Scan::readsectorsused(const QVariantMap& args)
{
ActionReply reply;
QString deviceNode = args[QLatin1String("deviceNode")].toString();
qint64 firstSector = args[QLatin1String("firstSector")].toLongLong();
qint64 rval = -1;
if (PedDevice* pedDevice = ped_device_get(deviceNode.toLocal8Bit().constData()))
if (PedDevice* pedDevice = ped_device_get(args[QStringLiteral("deviceNode")].toString().toLocal8Bit().constData()))
if (PedDisk* pedDisk = ped_disk_new(pedDevice))
if (PedPartition* pedPartition = ped_disk_get_partition_by_sector(pedDisk, firstSector))
if (PedPartition* pedPartition = ped_disk_get_partition_by_sector(pedDisk, args[QStringLiteral("firstSector")].toLongLong()))
if (PedFileSystem* pedFileSystem = ped_file_system_open(&pedPartition->geom))
if (PedConstraint* pedConstraint = ped_file_system_get_resize_constraint(pedFileSystem))
rval = pedConstraint->min_size;
QVariantMap returnArgs;
returnArgs[QLatin1String("sectorsUsed")] = rval;
reply.setData(returnArgs);
return reply;
}
ActionReply Scan::detectfilesystem(const QVariantMap& args)
{
ActionReply reply;
QVariantMap returnArgs;
QString deviceNode = args[QLatin1String("deviceNode")].toString();
blkid_cache cache;
if (blkid_get_cache(&cache, nullptr) == 0) {
blkid_dev dev;
if ((dev = blkid_get_dev(cache, deviceNode.toLocal8Bit().constData(), BLKID_DEV_NORMAL)) != nullptr) {
char *string = blkid_get_tag_value(cache, "TYPE", deviceNode.toLocal8Bit().constData());
QString s = QString::fromUtf8(string);
free(string);
if (s == QStringLiteral("vfat")) {
// libblkid uses SEC_TYPE to distinguish between FAT16 and FAT32
string = blkid_get_tag_value(cache, "SEC_TYPE", deviceNode.toLocal8Bit().constData());
QString st = QString::fromUtf8(string);
free(string);
if (st == QStringLiteral("msdos"))
returnArgs[QLatin1String("fileSystem")] = QStringLiteral("fat16");
else
returnArgs[QLatin1String("fileSystem")] = QStringLiteral("fat32");
}
else
returnArgs[QLatin1String("fileSystem")] = s;
}
blkid_put_cache(cache);
}
reply.setData(returnArgs);
reply.addData(QStringLiteral("sectorsUsed"), rval);
return reply;
}

View File

@ -31,7 +31,6 @@ class Scan : public QObject
public Q_SLOTS:
ActionReply scandevice(const QVariantMap& args);
ActionReply readsectorsused(const QVariantMap& args);
ActionReply detectfilesystem(const QVariantMap& args);
};
// --------------------------------------------------------------------------

View File

@ -24,7 +24,7 @@
#include "plugins/libparted/libparteddevice.h"
#include "plugins/libparted/pedflags.h"
#include "core/device.h"
#include "core/diskdevice.h"
#include "core/partition.h"
#include "core/partitiontable.h"
#include "core/partitionalignment.h"
@ -36,11 +36,14 @@
#include "fs/hfs.h"
#include "fs/hfsplus.h"
#include "fs/luks.h"
#include "fs/lvm2_pv.h"
#include "util/globallog.h"
#include "util/externalcommand.h"
#include "util/helpers.h"
#include <blkid/blkid.h>
#include <QDebug>
#include <QString>
#include <QStringList>
@ -75,12 +78,12 @@ static PedExceptionOption pedExceptionHandler(PedException* e)
#if defined LIBPARTED_FS_RESIZE_LIBRARY_SUPPORT
static qint64 readSectorsUsedLibParted(const Partition& p)
{
QVariantMap args;
args[QLatin1String("deviceNode")] = p.deviceNode();
args[QLatin1String("firstSector")] = p.firstSector();
KAuth::Action action = QStringLiteral("org.kde.kpmcore.scan.readsectorsused");
action.setHelperId(QStringLiteral("org.kde.kpmcore.scan"));
QVariantMap args = {
{ QStringLiteral("deviceNode"), p.deviceNode() },
{ QStringLiteral("firstSector"), p.firstSector() }
};
action.setArguments(args);
KAuth::ExecuteJob *job = action.execute();
if (!job->exec()) {
@ -96,7 +99,7 @@ static qint64 readSectorsUsedLibParted(const Partition& p)
@param p the Partition the FileSystem is on
@param mountPoint mount point of the partition in question
*/
static void readSectorsUsed(const Device& d, Partition& p, const QString& mountPoint)
static void readSectorsUsed(const DiskDevice& d, Partition& p, const QString& mountPoint)
{
const KDiskFreeSpaceInfo freeSpaceInfo = KDiskFreeSpaceInfo::freeSpaceInfo(mountPoint);
@ -146,11 +149,9 @@ void LibPartedBackend::initFSSupport()
*/
Device* LibPartedBackend::scanDevice(const QString& deviceNode)
{
QVariantMap args;
args[QLatin1String("deviceNode")] = deviceNode;
KAuth::Action scanAction = QStringLiteral("org.kde.kpmcore.scan.scandevice");
scanAction.setHelperId(QStringLiteral("org.kde.kpmcore.scan"));
QVariantMap args = {{ QStringLiteral("deviceNode"), deviceNode }};
scanAction.setArguments(args);
KAuth::ExecuteJob *job = scanAction.execute();
if (!job->exec()) {
@ -175,7 +176,7 @@ Device* LibPartedBackend::scanDevice(const QString& deviceNode)
Log(Log::information) << xi18nc("@info:status", "Device found: %1", model);
Device* d = new Device(model, path, heads, sectors, cylinders, sectorSize);
DiskDevice* d = new DiskDevice(model, path, heads, sectors, cylinders, sectorSize);
if (pedDiskError)
return d;
@ -198,9 +199,6 @@ Device* LibPartedBackend::scanDevice(const QString& deviceNode)
QList<QVariant> partitionEnd = job->data()[QLatin1String("partitionEnd")].toList();
QList<QVariant> partitionBusy = job->data()[QLatin1String("partitionBusy")].toList();
QList<QVariant> availableFlags = job->data()[QLatin1String("availableFlags")].toList();
QList<QVariant> activeFlags = job->data()[QLatin1String("activeFlags")].toList();
quint32 totalPartitions = partitionPath.size();
QList<Partition*> partitions;
for (quint32 i = 0; i < totalPartitions; ++i) {
@ -255,22 +253,32 @@ Device* LibPartedBackend::scanDevice(const QString& deviceNode)
if (isCryptOpen) {
luksFs->loadInnerFileSystem(partitionNode, mapperNode);
mountPoint = mountPoints.findByDevice(mapperNode) ?
mountPoints.findByDevice(mapperNode)->mountPoint() :
QString();
// We cannot use libparted to check the mounted status because
// we don't have a PedPartition for the mapper device, so we use lsblk
mounted = isMounted(mapperNode);
if (luksFs->type() == FileSystem::Lvm2_PV) {
mountPoint = FS::lvm2_pv::getVGName(mapperNode);
mounted = false;
} else {
mountPoint = mountPoints.findByDevice(mapperNode) ?
mountPoints.findByDevice(mapperNode)->mountPoint() :
QString();
// We cannot use libparted to check the mounted status because
// we don't have a PedPartition for the mapper device, so we use lsblk
mounted = isMounted(mapperNode);
}
if (mounted) {
const KDiskFreeSpaceInfo freeSpaceInfo = KDiskFreeSpaceInfo::freeSpaceInfo(mountPoint);
if (freeSpaceInfo.isValid() && mountPoint != QString())
luksFs->setSectorsUsed(freeSpaceInfo.used() / d->logicalSectorSize() + luksFs->getPayloadOffset(partitionNode));
luksFs->setSectorsUsed((freeSpaceInfo.used() + luksFs->getPayloadOffset(partitionNode)) / d->logicalSectorSize());
}
} else {
mounted = false;
}
luksFs->setMounted(mounted);
} else if (fsType == FileSystem::Lvm2_PV) {
r |= PartitionRole::Lvm_Lv;
mountPoint = FS::lvm2_pv::getVGName(partitionNode);
mounted = false;
} else {
mountPoint = mountPoints.findByDevice(partitionNode) ?
mountPoints.findByDevice(partitionNode)->mountPoint() :
@ -278,7 +286,9 @@ Device* LibPartedBackend::scanDevice(const QString& deviceNode)
mounted = busy;
}
QList<QVariant> availableFlags = job->data()[QLatin1String("availableFlags")].toList();
PartitionTable::Flags available = static_cast<PartitionTable::Flag>(availableFlags[i].toInt());
QList<QVariant> activeFlags = job->data()[QLatin1String("activeFlags")].toList();
PartitionTable::Flags active = static_cast<PartitionTable::Flag>(activeFlags[i].toInt());
Partition* part = new Partition(parent, *d, PartitionRole(r), fs, start, end, partitionNode, available, mountPoint, mounted, active);
@ -310,7 +320,6 @@ Device* LibPartedBackend::scanDevice(const QString& deviceNode)
QList<Device*> LibPartedBackend::scanDevices(bool excludeReadOnly)
{
QList<Device*> result;
// FIXME: cat /sys/block/loop0/ro
// linux.git/tree/Documentation/devices.txt
QString blockDeviceMajorNumbers = QStringLiteral(
"3,22,33,34,56,57,88,89,90,91,128,129,130,131,132,133,134,135," // MFM, RLL and IDE hard disk/CD-ROM interface
@ -347,53 +356,61 @@ QList<Device*> LibPartedBackend::scanDevices(bool excludeReadOnly)
}
/** Detects the type of a FileSystem given a PedDevice and a PedPartition
@param deviceNode path to the partition
@param partitionPath path to the partition
@return the detected FileSystem type (FileSystem::Unknown if not detected)
*/
FileSystem::Type LibPartedBackend::detectFileSystem(const QString& deviceNode)
FileSystem::Type LibPartedBackend::detectFileSystem(const QString& partitionPath)
{
FileSystem::Type rval = FileSystem::Unknown;
QVariantMap args;
args[QLatin1String("deviceNode")] = deviceNode;
blkid_cache cache;
if (blkid_get_cache(&cache, nullptr) == 0) {
blkid_dev dev;
KAuth::Action action = QStringLiteral("org.kde.kpmcore.scan.detectfilesystem");
action.setHelperId(QStringLiteral("org.kde.kpmcore.scan"));
action.setArguments(args);
KAuth::ExecuteJob *job = action.execute();
if (!job->exec()) {
qWarning() << "KAuth returned an error code: " << job->errorString();
return rval;
if ((dev = blkid_get_dev(cache,
partitionPath.toLocal8Bit().constData(),
BLKID_DEV_NORMAL)) != nullptr) {
char *string = blkid_get_tag_value(cache, "TYPE", partitionPath.toLocal8Bit().constData());
QString s = QString::fromUtf8(string);
free(string);
if (s == QStringLiteral("ext2")) rval = FileSystem::Ext2;
else if (s == QStringLiteral("ext3")) rval = FileSystem::Ext3;
else if (s.startsWith(QStringLiteral("ext4"))) rval = FileSystem::Ext4;
else if (s == QStringLiteral("swap")) rval = FileSystem::LinuxSwap;
else if (s == QStringLiteral("ntfs")) rval = FileSystem::Ntfs;
else if (s == QStringLiteral("reiserfs")) rval = FileSystem::ReiserFS;
else if (s == QStringLiteral("reiser4")) rval = FileSystem::Reiser4;
else if (s == QStringLiteral("xfs")) rval = FileSystem::Xfs;
else if (s == QStringLiteral("jfs")) rval = FileSystem::Jfs;
else if (s == QStringLiteral("hfs")) rval = FileSystem::Hfs;
else if (s == QStringLiteral("hfsplus")) rval = FileSystem::HfsPlus;
else if (s == QStringLiteral("ufs")) rval = FileSystem::Ufs;
else if (s == QStringLiteral("vfat")) {
// libblkid uses SEC_TYPE to distinguish between FAT16 and FAT32
string = blkid_get_tag_value(cache, "SEC_TYPE", partitionPath.toLocal8Bit().constData());
QString st = QString::fromUtf8(string);
free(string);
if (st == QStringLiteral("msdos"))
rval = FileSystem::Fat16;
else
rval = FileSystem::Fat32;
} else if (s == QStringLiteral("btrfs")) rval = FileSystem::Btrfs;
else if (s == QStringLiteral("ocfs2")) rval = FileSystem::Ocfs2;
else if (s == QStringLiteral("zfs_member")) rval = FileSystem::Zfs;
else if (s == QStringLiteral("hpfs")) rval = FileSystem::Hpfs;
else if (s == QStringLiteral("crypto_LUKS")) rval = FileSystem::Luks;
else if (s == QStringLiteral("exfat")) rval = FileSystem::Exfat;
else if (s == QStringLiteral("nilfs2")) rval = FileSystem::Nilfs2;
else if (s == QStringLiteral("LVM2_member")) rval = FileSystem::Lvm2_PV;
else if (s == QStringLiteral("f2fs")) rval = FileSystem::F2fs;
else
qWarning() << "blkid: unknown file system type " << s << " on " << partitionPath;
}
blkid_put_cache(cache);
}
QString s = job->data()[QLatin1String("fileSystem")].toString();
if (s == QStringLiteral("ext2")) rval = FileSystem::Ext2;
else if (s == QStringLiteral("ext3")) rval = FileSystem::Ext3;
else if (s.startsWith(QStringLiteral("ext4"))) rval = FileSystem::Ext4;
else if (s == QStringLiteral("swap")) rval = FileSystem::LinuxSwap;
else if (s == QStringLiteral("ntfs")) rval = FileSystem::Ntfs;
else if (s == QStringLiteral("reiserfs")) rval = FileSystem::ReiserFS;
else if (s == QStringLiteral("reiser4")) rval = FileSystem::Reiser4;
else if (s == QStringLiteral("xfs")) rval = FileSystem::Xfs;
else if (s == QStringLiteral("jfs")) rval = FileSystem::Jfs;
else if (s == QStringLiteral("hfs")) rval = FileSystem::Hfs;
else if (s == QStringLiteral("hfsplus")) rval = FileSystem::HfsPlus;
else if (s == QStringLiteral("ufs")) rval = FileSystem::Ufs;
else if (s == QStringLiteral("fat16")) rval = FileSystem::Fat16;
else if (s == QStringLiteral("fat32")) rval = FileSystem::Fat32;
else if (s == QStringLiteral("btrfs")) rval = FileSystem::Btrfs;
else if (s == QStringLiteral("ocfs2")) rval = FileSystem::Ocfs2;
else if (s == QStringLiteral("zfs_member")) rval = FileSystem::Zfs;
else if (s == QStringLiteral("hpfs")) rval = FileSystem::Hpfs;
else if (s == QStringLiteral("crypto_LUKS")) rval = FileSystem::Luks;
else if (s == QStringLiteral("exfat")) rval = FileSystem::Exfat;
else if (s == QStringLiteral("nilfs2")) rval = FileSystem::Nilfs2;
else if (s == QStringLiteral("LVM2_member")) rval = FileSystem::Lvm2_PV;
else if (s == QStringLiteral("f2fs")) rval = FileSystem::F2fs;
else
qWarning() << "blkid: unknown file system type " << s << " on " << deviceNode;
return rval;
}
@ -428,9 +445,9 @@ bool LibPartedBackend::closeDevice(CoreBackendDevice* core_device)
PedPartitionFlag LibPartedBackend::getPedFlag(PartitionTable::Flag flag)
{
for (quint32 i = 0; i < sizeof(flagmap) / sizeof(flagmap[0]); i++)
if (flagmap[i].flag == flag)
return flagmap[i].pedFlag;
for (const auto &f : flagmap)
if (f.flag == flag)
return f.pedFlag;
return static_cast<PedPartitionFlag>(-1);
}

View File

@ -38,7 +38,6 @@ class LibPartedPartitionTable;
class LibPartedPartition;
class OperationStack;
class Device;
class KPluginFactory;
class QString;
@ -66,7 +65,7 @@ public:
bool closeDevice(CoreBackendDevice* core_device) override;
Device* scanDevice(const QString& deviceNode) override;
QList<Device*> scanDevices(bool excludeReadOnly = true) override;
FileSystem::Type detectFileSystem(const QString& deviceNode) override;
FileSystem::Type detectFileSystem(const QString& partitionPath) override;
static QString lastPartedExceptionMessage();

View File

@ -28,8 +28,8 @@
#include <unistd.h>
LibPartedDevice::LibPartedDevice(const QString& device_node) :
CoreBackendDevice(device_node),
LibPartedDevice::LibPartedDevice(const QString& deviceNode) :
CoreBackendDevice(deviceNode),
m_PedDevice(nullptr)
{
}

View File

@ -35,7 +35,7 @@ class LibPartedDevice : public CoreBackendDevice
Q_DISABLE_COPY(LibPartedDevice);
public:
LibPartedDevice(const QString& device_node);
LibPartedDevice(const QString& deviceNode);
~LibPartedDevice();
public:

View File

@ -51,4 +51,3 @@ bool LibPartedPartition::setFlag(Report& report, PartitionTable::Flag partitionM
return true;
}

View File

@ -46,5 +46,4 @@ private:
PedPartition* m_PedPartition;
};
#endif

View File

@ -60,8 +60,8 @@ ExternalCommand::ExternalCommand(Report& report, const QString& cmd, const QStri
void ExternalCommand::setup()
{
setEnvironment(QStringList() << QStringLiteral("LC_ALL=C") << QStringLiteral("PATH=") + QString::fromUtf8(getenv("PATH")));
setProcessChannelMode(MergedChannels);
setEnvironment(QStringList() << QStringLiteral("LC_ALL=C") << QStringLiteral("PATH=") + QString::fromUtf8(getenv("PATH")) << QStringLiteral("LVM_SUPPRESS_FD_WARNINGS=1"));
setProcessChannelMode(SeparateChannels);
connect(this, static_cast<void(QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished), this, &ExternalCommand::onFinished);
connect(this, &ExternalCommand::readyReadStandardOutput, this, &ExternalCommand::onReadOutput);

View File

@ -80,7 +80,7 @@ QString Report::toHtml() const
if (children().size() == 0)
s += QStringLiteral("<br/>\n");
else
foreach(Report * child, children())
for (const auto &child : children())
s += child->toHtml();
if (!status().isEmpty())
@ -109,7 +109,7 @@ QString Report::toText() const
if (!output().isEmpty())
s += output() + QStringLiteral("\n");
foreach(Report * child, children())
for (const auto &child : children())
s += child->toText();
return s;