diff --git a/src/core/lvmdevice.cpp b/src/core/lvmdevice.cpp index 1ae5f31..4852dec 100644 --- a/src/core/lvmdevice.cpp +++ b/src/core/lvmdevice.cpp @@ -1,468 +1,468 @@ /************************************************************************* * Copyright (C) 2016 by Chantara Tith * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License as * * published by the Free Software Foundation; either version 3 of * * the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see .* *************************************************************************/ #include "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 #include #include #include /** 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_LVPathList = new QStringList(getLVs(vgName)); m_LVSizeMap = new QMap(); 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_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 LvmDevice::scanPartitions(PartitionTable* pTable) const { QList pList; for (const auto &lvPath : partitionNodes()) { pList.append(scanPartition(lvPath, pTable)); } return pList; } /** scan and construct a partition(LV) at a given path * * NOTE: * LVM partition has 2 different start and end sector values * 1. representing the actual LV start from 0 -> size of LV - 1 * 2. representing abstract LV's sector inside a VG partitionTable * start from last sector + 1 of last Partitions -> size of LV - 1 * Reason for this is for the LV Partition to work nicely with other parts of the codebase * without too many special cases. * * @param lvPath LVM Logical Volume path * @param pTable Abstract partition table representing partitions of LVM Volume Group * @return initialized Partition(LV) */ Partition* LvmDevice::scanPartition(const QString& lvPath, PartitionTable* pTable) const { activateLV(lvPath); qint64 lvSize = getTotalLE(lvPath); qint64 startSector = mappedSector(lvPath, 0); qint64 endSector = startSector + lvSize - 1; FileSystem::Type type = FileSystem::detectFileSystem(lvPath); FileSystem* fs = FileSystemFactory::create(type, 0, lvSize - 1); fs->scan(lvPath); PartitionRole::Roles r = PartitionRole::Lvm_Lv; QString mountPoint; bool mounted; // Handle LUKS partition if (fs->type() == FileSystem::Luks) { r |= PartitionRole::Luks; - initLuks(fs, this); + FS::luks::initLUKS(fs); QString mapperNode = static_cast(fs)->mapperName(); mountPoint = FileSystem::detectMountPoint(fs, mapperNode); mounted = FileSystem::detectMountStatus(fs, mapperNode); } else { mountPoint = FileSystem::detectMountPoint(fs, lvPath); mounted = FileSystem::detectMountStatus(fs, lvPath); const KDiskFreeSpaceInfo freeSpaceInfo = KDiskFreeSpaceInfo::freeSpaceInfo(mountPoint); if (logicalSize() > 0 && fs->type() != FileSystem::Luks) { if (mounted && freeSpaceInfo.isValid() && mountPoint != QString()) { fs->setSectorsUsed(freeSpaceInfo.used() / logicalSize()); } else if (fs->supportGetUsed() == FileSystem::cmdSupportFileSystem) { fs->setSectorsUsed(qCeil(fs->readUsedCapacity(lvPath) / static_cast(logicalSize()))); } } } if (fs->supportGetLabel() != FileSystem::cmdSupportNone) { fs->setLabel(fs->readLabel(lvPath)); } if (fs->supportGetUUID() != FileSystem::cmdSupportNone) fs->setUUID(fs->readUUID(lvPath)); Partition* part = new Partition(pTable, *this, PartitionRole(r), fs, startSector, endSector, lvPath, PartitionTable::Flag::FlagNone, mountPoint, mounted); return part; } /** scan and contruct list of initialized LvmDevice objects. * * @return list of initialized LvmDevices */ QList LvmDevice::scanSystemLVM() { QList 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 lvpathList = partitionNodes(); qint32 devIndex = lvpathList.indexOf(lvPath); if (devIndex) { for (int i = 0; i < devIndex; i++) { mSector += LVSizeMap()->value(lvpathList[i]); } mSector += sector; } return mSector; } const QStringList LvmDevice::deviceNodes() const { QStringList pvList; for (const auto &p : physicalVolumes()) pvList << p->partitionPath(); return pvList; } const QStringList LvmDevice::partitionNodes() const { return *LVPathList(); } qint64 LvmDevice::partitionSize(QString& partitionPath) const { return LVSizeMap()->value(partitionPath); } const QStringList LvmDevice::getVGs() { QStringList vgList; QString output = getField(QStringLiteral("vg_name")); if (!output.isEmpty()) { const QStringList vgNameList = output.split(QStringLiteral("\n"), QString::SkipEmptyParts); for (const auto &vgName : vgNameList) { vgList.append(vgName.trimmed()); } } return vgList; } const QStringList LvmDevice::getLVs(const QString& vgName) { QStringList lvPathList; QString cmdOutput = getField(QStringLiteral("lv_path"), vgName); if (cmdOutput.size()) { const QStringList tempPathList = cmdOutput.split(QStringLiteral("\n"), QString::SkipEmptyParts); for (const auto &lvPath : tempPathList) { lvPathList.append(lvPath.trimmed()); } } return lvPathList; } qint64 LvmDevice::getPeSize(const QString& vgName) { QString val = getField(QStringLiteral("vg_extent_size"), vgName); return val.isEmpty() ? -1 : val.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) { d.partitionTable()->remove(&p); return true; } return false; } bool LvmDevice::createLV(Report& report, LvmDevice& d, Partition& p, const QString& lvName) { ExternalCommand cmd(report, QStringLiteral("lvm"), { QStringLiteral("lvcreate"), QStringLiteral("--yes"), QStringLiteral("--extents"), QString::number(p.length()), QStringLiteral("--name"), lvName, d.name()}); return (cmd.run(-1) && cmd.exitCode() == 0); } bool LvmDevice::createLVSnapshot(Report& report, Partition& p, const QString& name, const qint64 extents) { QString numExtents = (extents > 0) ? QString::number(extents) : QString::number(p.length()); ExternalCommand cmd(report, QStringLiteral("lvm"), { QStringLiteral("lvcreate"), QStringLiteral("--yes"), QStringLiteral("--extents"), numExtents, QStringLiteral("--snapshot"), QStringLiteral("--name"), name, p.partitionPath() }); return (cmd.run(-1) && cmd.exitCode() == 0); } bool LvmDevice::resizeLV(Report& report, Partition& p) { ExternalCommand cmd(report, QStringLiteral("lvm"), { QStringLiteral("lvresize"), QStringLiteral("--force"), QStringLiteral("--yes"), QStringLiteral("--extents"), QString::number(p.length()), p.partitionPath()}); return (cmd.run(-1) && cmd.exitCode() == 0); } bool LvmDevice::removePV(Report& report, LvmDevice& d, const QString& pvPath) { ExternalCommand cmd(report, QStringLiteral("lvm"), { QStringLiteral("vgreduce"), d.name(), pvPath}); return (cmd.run(-1) && cmd.exitCode() == 0); } bool LvmDevice::insertPV(Report& report, LvmDevice& d, const QString& pvPath) { ExternalCommand cmd(report, QStringLiteral("lvm"), { QStringLiteral("vgextend"), QStringLiteral("--yes"), d.name(), pvPath}); return (cmd.run(-1) && cmd.exitCode() == 0); } bool LvmDevice::movePV(Report& report, const QString& pvPath, const QStringList& destinations) { if (FS::lvm2_pv::getAllocatedPE(pvPath) <= 0) return true; QStringList args = QStringList(); args << QStringLiteral("pvmove"); args << pvPath; if (!destinations.isEmpty()) for (const auto &destPath : destinations) args << destPath.trimmed(); ExternalCommand cmd(report, QStringLiteral("lvm"), args); return (cmd.run(-1) && cmd.exitCode() == 0); } bool LvmDevice::createVG(Report& report, const QString vgName, const 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; } diff --git a/src/fs/luks.cpp b/src/fs/luks.cpp index 2da62d1..c244296 100644 --- a/src/fs/luks.cpp +++ b/src/fs/luks.cpp @@ -1,619 +1,634 @@ /************************************************************************* * Copyright (C) 2012 by Volker Lanz * * Copyright (C) 2013 by Andrius Štikonas * * Copyright (C) 2015-2016 by Teo Mrnjavac * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License as * * published by the Free Software Foundation; either version 3 of * * the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see .* *************************************************************************/ #include "fs/luks.h" #include "fs/filesystemfactory.h" -#include "util/capacity.h" #include "util/externalcommand.h" +#include "util/capacity.h" +#include "util/helpers.h" #include "util/report.h" #include #include #include #include #include #include #include #include #include namespace FS { FileSystem::CommandSupportType luks::m_GetUsed = FileSystem::cmdSupportNone; FileSystem::CommandSupportType luks::m_GetLabel = FileSystem::cmdSupportNone; FileSystem::CommandSupportType luks::m_Create = FileSystem::cmdSupportNone; FileSystem::CommandSupportType luks::m_Grow = FileSystem::cmdSupportNone; FileSystem::CommandSupportType luks::m_Shrink = FileSystem::cmdSupportNone; FileSystem::CommandSupportType luks::m_Move = FileSystem::cmdSupportNone; FileSystem::CommandSupportType luks::m_Check = FileSystem::cmdSupportNone; FileSystem::CommandSupportType luks::m_Copy = FileSystem::cmdSupportNone; FileSystem::CommandSupportType luks::m_Backup = FileSystem::cmdSupportNone; FileSystem::CommandSupportType luks::m_SetLabel = FileSystem::cmdSupportNone; FileSystem::CommandSupportType luks::m_UpdateUUID = FileSystem::cmdSupportNone; FileSystem::CommandSupportType luks::m_GetUUID = FileSystem::cmdSupportNone; luks::luks(qint64 firstsector, qint64 lastsector, qint64 sectorsused, const QString& label) : FileSystem(firstsector, lastsector, sectorsused, label, FileSystem::Luks) , m_innerFs(nullptr) , m_isCryptOpen(false) , m_cryptsetupFound(m_Create != cmdSupportNone) , m_isMounted(false) , m_logicalSectorSize(512) { } luks::~luks() { delete m_innerFs; } void luks::init() { 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_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 } void luks::scan(const QString& deviceNode) { getMapperName(deviceNode); getLuksInfo(deviceNode); } bool luks::supportToolFound() const { return m_cryptsetupFound && ((m_isCryptOpen && m_innerFs) ? m_innerFs->supportToolFound() : true); } FileSystem::SupportTool luks::supportToolName() const { if (m_isCryptOpen && m_innerFs && m_cryptsetupFound) return m_innerFs->supportToolName(); return SupportTool(QStringLiteral("cryptsetup"), QUrl(QStringLiteral("https://code.google.com/p/cryptsetup/"))); } bool luks::create(Report& report, const QString& deviceNode) { Q_ASSERT(m_innerFs); Q_ASSERT(!m_passphrase.isEmpty()); ExternalCommand createCmd(report, QStringLiteral("cryptsetup"), { QStringLiteral("-s"), QStringLiteral("512"), QStringLiteral("--batch-mode"), QStringLiteral("luksFormat"), deviceNode }); if (!( createCmd.start(-1) && createCmd.write(m_passphrase.toUtf8() + '\n') == m_passphrase.toUtf8().length() + 1 && createCmd.waitFor() && createCmd.exitCode() == 0)) { return false; } ExternalCommand openCmd(report, QStringLiteral("cryptsetup"), { QStringLiteral("open"), deviceNode, suggestedMapperName(deviceNode) }); if (!( openCmd.start(-1) && openCmd.write(m_passphrase.toUtf8() + '\n') == m_passphrase.toUtf8().length() + 1 && openCmd.waitFor())) return false; scan(deviceNode); if (mapperName().isEmpty()) return false; if (!m_innerFs->create(report, mapperName())) return false; return true; } QString luks::mountTitle() const { return xi18nc("@title:menu", "Mount"); } QString luks::unmountTitle() const { return xi18nc("@title:menu", "Unmount"); } QString luks::cryptOpenTitle() const { return xi18nc("@title:menu", "Decrypt"); } QString luks::cryptCloseTitle() const { return xi18nc("@title:menu", "Deactivate"); } void luks::setPassphrase(const QString& passphrase) { m_passphrase = passphrase; } QString luks::passphrase() const { return m_passphrase; } bool luks::canMount(const QString&, const QString& mountPoint) const { return m_isCryptOpen && !m_isMounted && m_innerFs && m_innerFs->canMount(mapperName(), mountPoint); } bool luks::canUnmount(const QString&) const { return m_isCryptOpen && m_isMounted && m_innerFs && m_innerFs->canUnmount(mapperName()); } bool luks::isMounted() const { return m_isCryptOpen && m_isMounted; } void luks::setMounted(bool mounted) { m_isMounted = mounted; } bool luks::canCryptOpen(const QString&) const { return !m_isCryptOpen && !m_isMounted && supportToolFound(); } bool luks::canCryptClose(const QString&) const { return m_isCryptOpen && !m_isMounted && m_cryptsetupFound; } bool luks::isCryptOpen() const { return m_isCryptOpen; } void luks::setCryptOpen(bool cryptOpen) { m_isCryptOpen = cryptOpen; } bool luks::cryptOpen(QWidget* parent, const QString& deviceNode) { if (m_isCryptOpen) { if (!mapperName().isEmpty()) { qWarning() << "LUKS device" << deviceNode << "already decrypted." << "Cannot decrypt again."; return false; } else { qWarning() << "LUKS device" << deviceNode << "reportedly decrypted but mapper node not found." << "Marking device as NOT decrypted and trying to " "decrypt again anyway."; m_isCryptOpen = false; } } KPasswordDialog dlg( parent ); dlg.setPrompt(i18n("Enter passphrase for %1:", deviceNode)); if( !dlg.exec() ) return false; QString passphrase = dlg.password(); ExternalCommand openCmd(QStringLiteral("cryptsetup"), { QStringLiteral("open"), deviceNode, suggestedMapperName(deviceNode) }); if (!( openCmd.start(-1) && openCmd.write(passphrase.toUtf8() + '\n') == passphrase.toUtf8().length() + 1 && openCmd.waitFor() && openCmd.exitCode() == 0) ) return false; if (m_innerFs) { delete m_innerFs; m_innerFs = nullptr; } scan(deviceNode); if (mapperName().isEmpty()) return false; loadInnerFileSystem(mapperName()); m_isCryptOpen = (m_innerFs != nullptr); if (!m_isCryptOpen) return false; m_passphrase = passphrase; return true; } bool luks::cryptClose(const QString& deviceNode) { if (!m_isCryptOpen) { qWarning() << "Cannot close LUKS device" << deviceNode << "because it's not open."; return false; } if (m_isMounted) { qWarning() << "Cannot close LUKS device" << deviceNode << "because the filesystem is mounted."; return false; } ExternalCommand cmd(QStringLiteral("cryptsetup"), { QStringLiteral("close"), mapperName() }); if (!(cmd.run(-1) && cmd.exitCode() == 0)) return false; delete m_innerFs; m_innerFs = nullptr; m_passphrase.clear(); setLabel({}); setUUID(readUUID(deviceNode)); setSectorsUsed(-1); m_isCryptOpen = (m_innerFs != nullptr); if (m_isCryptOpen) return false; return true; } void luks::loadInnerFileSystem(const QString& mapperNode) { Q_ASSERT(!m_innerFs); FileSystem::Type innerFsType = detectFileSystem(mapperNode); m_innerFs = FileSystemFactory::cloneWithNewType(innerFsType, *this); setLabel(m_innerFs->readLabel(mapperNode)); setUUID(m_innerFs->readUUID(mapperNode)); if (m_innerFs->supportGetUsed() == FileSystem::cmdSupportFileSystem) setSectorsUsed((m_innerFs->readUsedCapacity(mapperNode) + payloadOffset()) / m_logicalSectorSize ); m_innerFs->scan(mapperNode); } void luks::createInnerFileSystem(FileSystem::Type type) { Q_ASSERT(!m_innerFs); m_innerFs = FileSystemFactory::cloneWithNewType(type, *this); } bool luks::check(Report& report, const QString&) const { Q_ASSERT(m_innerFs); if (mapperName().isEmpty()) return false; return m_innerFs->check(report, mapperName()); } qint64 luks::readUsedCapacity(const QString& deviceNode) const { if (!m_isCryptOpen) return -1; if (m_innerFs) return m_innerFs->readUsedCapacity(deviceNode); return -1; } bool luks::mount(Report& report, const QString& deviceNode, const QString& mountPoint) { if (!m_isCryptOpen) { qWarning() << "Cannot mount device" << deviceNode << "before decrypting it first."; return false; } if (m_isMounted) { qWarning() << "Cannot mount device" << deviceNode << "because it's already mounted."; return false; } Q_ASSERT(m_innerFs); if (mapperName().isEmpty()) return false; if (m_innerFs->canMount(mapperName(), mountPoint)) { if (m_innerFs->mount(report, mapperName(), mountPoint)) { m_isMounted = true; const KDiskFreeSpaceInfo freeSpaceInfo = KDiskFreeSpaceInfo::freeSpaceInfo(mountPoint); if (freeSpaceInfo.isValid() && mountPoint != QString()) setSectorsUsed((freeSpaceInfo.used() + payloadOffset()) / m_logicalSectorSize); return true; } } else { ExternalCommand mountCmd( report, QStringLiteral("mount"), { QStringLiteral("--verbose"), mapperName(), mountPoint }); if (mountCmd.run() && mountCmd.exitCode() == 0) { m_isMounted = true; return true; } } return false; } bool luks::unmount(Report& report, const QString& deviceNode) { if (!m_isCryptOpen) { qWarning() << "Cannot unmount device" << deviceNode << "before decrypting it first."; return false; } if (!m_isMounted) { qWarning() << "Cannot unmount device" << deviceNode << "because it's not mounted."; return false; } Q_ASSERT(m_innerFs); if (mapperName().isEmpty()) return false; if (m_innerFs->canUnmount(mapperName())) { if (m_innerFs->unmount(report, mapperName())) { m_isMounted = false; return true; } } else { ExternalCommand unmountCmd( report, QStringLiteral("umount"), { QStringLiteral("--verbose"), QStringLiteral("--all-targets"), mapperName() }); if (unmountCmd.run() && unmountCmd.exitCode() == 0) { m_isMounted = false; return true; } } return false; } FileSystem::Type luks::type() const { if (m_isCryptOpen && m_innerFs) return m_innerFs->type(); return FileSystem::Luks; } QString luks::suggestedMapperName(const QString& deviceNode) const { return QStringLiteral("luks-") + readOuterUUID(deviceNode); } QString luks::readLabel(const QString&) const { if (m_isCryptOpen && m_innerFs) return m_innerFs->readLabel(mapperName()); return QString(); } bool luks::writeLabel(Report& report, const QString&, const QString& newLabel) { Q_ASSERT(m_innerFs); return m_innerFs->writeLabel(report, mapperName(), newLabel); } bool luks::resize(Report& report, const QString& deviceNode, qint64 newLength) const { Q_ASSERT(m_innerFs); if (mapperName().isEmpty()) return false; qint64 payloadLength = newLength - payloadOffset(); if ( newLength - length() * m_logicalSectorSize > 0 ) { ExternalCommand cryptResizeCmd(report, QStringLiteral("cryptsetup"), { QStringLiteral("resize"), mapperName() }); report.line() << xi18nc("@info:progress", "Resizing LUKS crypt on partition %1.", deviceNode); if (cryptResizeCmd.run(-1) && cryptResizeCmd.exitCode() == 0) return m_innerFs->resize(report, mapperName(), payloadLength); } else if (m_innerFs->resize(report, mapperName(), payloadLength)) { ExternalCommand cryptResizeCmd(report, QStringLiteral("cryptsetup"), { QStringLiteral("--size"), QString::number(payloadLength / /*m_logicalSectorSize*/ 512), // LUKS assume 512 bytes sector QStringLiteral("resize"), mapperName() }); report.line() << xi18nc("@info:progress", "Resizing LUKS crypt on partition %1.", deviceNode); if (cryptResizeCmd.run(-1) && cryptResizeCmd.exitCode() == 0) return true; } report.line() << xi18nc("@info:progress", "Resizing encrypted file system on partition %1 failed.", deviceNode); return false; } QString luks::readUUID(const QString& deviceNode) const { if (m_isCryptOpen && m_innerFs) return m_innerFs->readUUID(mapperName()); return readOuterUUID(deviceNode); } QString luks::readOuterUUID(const QString &deviceNode) const { ExternalCommand cmd(QStringLiteral("cryptsetup"), { QStringLiteral("luksUUID"), deviceNode }); if (cmd.run()) { return cmd.output().trimmed(); } return QStringLiteral("---"); } bool luks::updateUUID(Report& report, const QString& deviceNode) const { const QString uuid = QUuid::createUuid().toString().remove(QRegularExpression(QStringLiteral("\\{|\\}"))); ExternalCommand cmd(report, QStringLiteral("cryptsetup"), { QStringLiteral("luksUUID"), deviceNode, QStringLiteral("--uuid"), uuid }); return cmd.run(-1) && cmd.exitCode() == 0; } void luks::getMapperName(const QString& deviceNode) { ExternalCommand cmd(QStringLiteral("lsblk"), { QStringLiteral("--list"), QStringLiteral("--noheadings"), QStringLiteral("--output"), QStringLiteral("name"), deviceNode }); if (cmd.run(-1) && cmd.exitCode() == 0) { QStringList output=cmd.output().split(QStringLiteral("\n")); output.removeFirst(); if (!output.first().isEmpty()) m_MapperName = QStringLiteral("/dev/mapper/") + output.first(); } else m_MapperName = QString(); } void luks::getLuksInfo(const QString& deviceNode) { ExternalCommand cmd(QStringLiteral("cryptsetup"), { QStringLiteral("luksDump"), deviceNode }); if (cmd.run(-1) && cmd.exitCode() == 0) { QRegularExpression re(QStringLiteral("Cipher name:\\s+(\\w+)")); QRegularExpressionMatch rem = re.match(cmd.output()); if (rem.hasMatch()) m_CipherName = rem.captured(1); else m_CipherName = QLatin1String("---"); re.setPattern(QStringLiteral("Cipher mode:\\s+(\\w+)")); rem = re.match(cmd.output()); if (rem.hasMatch()) m_CipherMode = rem.captured(1); else m_CipherMode = QLatin1String("---"); re.setPattern(QStringLiteral("Hash spec:\\s+(\\w+)")); rem = re.match(cmd.output()); if (rem.hasMatch()) m_HashName = rem.captured(1); else m_HashName = QLatin1String("---"); re.setPattern(QStringLiteral("MK bits:\\s+(\\d+)")); rem = re.match(cmd.output()); if (rem.hasMatch()) m_KeySize = rem.captured(1).toLongLong(); else m_KeySize = -1; re.setPattern(QStringLiteral("Payload offset:\\s+(\\d+)")); rem = re.match(cmd.output()); if (rem.hasMatch()) m_PayloadOffset = rem.captured(1).toLongLong() * 512; // assuming LUKS sector size is 512; else m_PayloadOffset = -1; } else { m_CipherName = QLatin1String("---"); m_CipherMode = QLatin1String("---"); m_HashName = QLatin1String("---"); m_KeySize = -1; m_PayloadOffset = -1; } } bool luks::canEncryptType(FileSystem::Type type) { switch (type) { case Btrfs: case F2fs: case Ext2: case Ext3: case Ext4: case Jfs: case LinuxSwap: case Lvm2_PV: case Nilfs2: case ReiserFS: case Reiser4: case Xfs: case Zfs: return true; default: return false; } } +void luks::initLUKS(FileSystem* fs) +{ + if (fs->type() == FileSystem::Luks) { + FS::luks* luksFS = static_cast(fs); + QString mapperNode = luksFS->mapperName(); + bool isCryptOpen = !mapperNode.isEmpty(); + luksFS->setCryptOpen(isCryptOpen); + if (isCryptOpen) { + luksFS->loadInnerFileSystem(mapperNode); + luksFS->setMounted(::isMounted(mapperNode)); //isMounted from helpers.h + } + } +} + } diff --git a/src/fs/luks.h b/src/fs/luks.h index 73b380b..3c65ec3 100644 --- a/src/fs/luks.h +++ b/src/fs/luks.h @@ -1,202 +1,203 @@ /************************************************************************* * Copyright (C) 2012 by Volker Lanz * * Copyright (C) 2013 by Andrius Štikonas * * Copyright (C) 2015-2016 by Teo Mrnjavac * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License as * * published by the Free Software Foundation; either version 3 of * * the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see .* *************************************************************************/ #if !defined(LUKS__H) #define LUKS__H #include "util/libpartitionmanagerexport.h" #include "fs/filesystem.h" #include #include class Report; class QString; namespace FS { /** A LUKS crypto file system. @author Andrius Štikonas */ class LIBKPMCORE_EXPORT luks : public FileSystem { public: luks(qint64 firstsector, qint64 lastsector, qint64 sectorsused, const QString& label); virtual ~luks(); public: void init() override; void scan(const QString& deviceNode) override; qint64 readUsedCapacity(const QString& deviceNode) const override; CommandSupportType supportGetUsed() const override { return m_GetUsed; } CommandSupportType supportGetLabel() const override { return m_GetLabel; } CommandSupportType supportCreate() const override { return m_Create; } CommandSupportType supportGrow() const override { if (!m_isCryptOpen) return cmdSupportNone; if (m_Grow && m_innerFs) return m_innerFs->supportGrow(); return cmdSupportNone; } CommandSupportType supportShrink() const override { if (!m_isCryptOpen) return cmdSupportNone; if (m_Shrink && m_innerFs) return m_innerFs->supportShrink(); return cmdSupportNone; } CommandSupportType supportMove() const override { if (m_isCryptOpen) return cmdSupportNone; return m_Move; } CommandSupportType supportCheck() const override { if (!m_isCryptOpen) return cmdSupportNone; if (m_Check && m_innerFs) return m_innerFs->supportCheck(); return cmdSupportNone; } CommandSupportType supportCopy() const override { if (m_isCryptOpen) return cmdSupportNone; return m_Copy; } CommandSupportType supportBackup() const override { return m_Backup; } CommandSupportType supportSetLabel() const override { if (!m_isCryptOpen) return cmdSupportNone; if (m_Check && m_innerFs) return m_innerFs->supportSetLabel(); return cmdSupportNone; } CommandSupportType supportUpdateUUID() const override { return m_UpdateUUID; } CommandSupportType supportGetUUID() const override { return m_GetUUID; } void setLogicalSectorSize(unsigned int logicalSectorSize) { m_logicalSectorSize = logicalSectorSize; } bool check(Report& report, const QString& deviceNode) const override; bool create(Report& report, const QString& deviceNode) override; SupportTool supportToolName() const override; bool supportToolFound() const override; QString readUUID(const QString& deviceNode) const override; bool updateUUID(Report& report, const QString& deviceNode) const override; bool resize(Report& report, const QString& deviceNode, qint64 length) const override; QString readLabel(const QString& deviceNode) const override; bool writeLabel(Report& report, const QString& deviceNode, const QString& newLabel) override; QString mountTitle() const override; QString unmountTitle() const override; QString cryptOpenTitle() const; QString cryptCloseTitle() const; void setPassphrase(const QString&); QString passphrase() const; bool canMount(const QString&, const QString&) const override; bool canUnmount(const QString&) const override; bool isMounted() const; void setMounted(bool mounted); bool canCryptOpen(const QString& deviceNode) const; bool canCryptClose(const QString& deviceNode) const; bool isCryptOpen() const; void setCryptOpen(bool cryptOpen); bool cryptOpen(QWidget* parent, const QString& deviceNode); bool cryptClose(const QString& deviceNode); void loadInnerFileSystem(const QString& mapperNode); void createInnerFileSystem(Type type); bool mount(Report& report, const QString& deviceNode, const QString& mountPoint) override; bool unmount(Report& report, const QString& deviceNode) override; FileSystem::Type type() const override; QString suggestedMapperName(const QString& deviceNode) const; void getMapperName(const QString& deviceNode); void getLuksInfo(const QString& deviceNode); FileSystem* innerFS() const { return m_innerFs; }; // avoid calling this unless necessary QString mapperName() const { return m_MapperName; }; QString cipherName() const { return m_CipherName; }; QString cipherMode() const { return m_CipherMode; }; QString hashName() const { return m_HashName; }; qint64 keySize() const { return m_KeySize; }; qint64 payloadOffset() const { return m_PayloadOffset; }; static bool canEncryptType(FileSystem::Type type); + static void initLUKS(FileSystem* fs); protected: virtual QString readOuterUUID(const QString& deviceNode) const; public: static CommandSupportType m_GetUsed; static CommandSupportType m_GetLabel; static CommandSupportType m_Create; static CommandSupportType m_Grow; static CommandSupportType m_Shrink; static CommandSupportType m_Move; static CommandSupportType m_Check; static CommandSupportType m_Copy; static CommandSupportType m_Backup; static CommandSupportType m_SetLabel; static CommandSupportType m_UpdateUUID; static CommandSupportType m_GetUUID; private: mutable FileSystem* m_innerFs; mutable bool m_isCryptOpen; mutable bool m_cryptsetupFound; QString m_passphrase; bool m_isMounted; unsigned int m_logicalSectorSize; QString m_MapperName; QString m_CipherName; QString m_CipherMode; QString m_HashName; qint64 m_KeySize; qint64 m_PayloadOffset; }; } #endif diff --git a/src/plugins/libparted/libpartedbackend.cpp b/src/plugins/libparted/libpartedbackend.cpp index e73bfaa..3b36af0 100644 --- a/src/plugins/libparted/libpartedbackend.cpp +++ b/src/plugins/libparted/libpartedbackend.cpp @@ -1,422 +1,422 @@ /************************************************************************* * Copyright (C) 2008-2012 by Volker Lanz * * Copyright (C) 2015-2016 by Teo Mrnjavac * * Copyright (C) 2016 by Andrius Štikonas * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License as * * published by the Free Software Foundation; either version 3 of * * the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see .* *************************************************************************/ /** @file */ #include "plugins/libparted/libpartedbackend.h" #include "plugins/libparted/libparteddevice.h" #include "plugins/libparted/pedflags.h" #include "core/diskdevice.h" #include "core/partition.h" #include "core/partitiontable.h" #include "core/partitionalignment.h" #include "fs/filesystem.h" #include "fs/filesystemfactory.h" #include "fs/fat16.h" #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 #include #include #include #include #include #include #include #include K_PLUGIN_FACTORY_WITH_JSON(LibPartedBackendFactory, "pmlibpartedbackendplugin.json", registerPlugin();) static QString s_lastPartedExceptionMessage; /** Callback to handle exceptions from libparted @param e the libparted exception to handle */ static PedExceptionOption pedExceptionHandler(PedException* e) { Log(Log::error) << xi18nc("@info:status", "LibParted Exception: %1", QString::fromLocal8Bit(e->message)); s_lastPartedExceptionMessage = QString::fromLocal8Bit(e->message); return PED_EXCEPTION_UNHANDLED; } /** Reads sectors used on a FileSystem using libparted functions. @param pedDisk pointer to pedDisk where the Partition and its FileSystem are @param p the Partition the FileSystem is on @return the number of sectors used */ #if defined LIBPARTED_FS_RESIZE_LIBRARY_SUPPORT static qint64 readSectorsUsedLibParted(const Partition& p) { 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()) { qWarning() << "KAuth returned an error code: " << job->errorString(); return -1; } return job->data()[QLatin1String("sectorsUsed")].toLongLong(); } #endif /** Reads the sectors used in a FileSystem and stores the result in the Partition's FileSystem object. @param p the Partition the FileSystem is on @param mountPoint mount point of the partition in question */ static void readSectorsUsed(const DiskDevice& d, Partition& p, const QString& mountPoint) { const KDiskFreeSpaceInfo freeSpaceInfo = KDiskFreeSpaceInfo::freeSpaceInfo(mountPoint); if (p.isMounted() && freeSpaceInfo.isValid() && mountPoint != QString()) p.fileSystem().setSectorsUsed(freeSpaceInfo.used() / d.logicalSectorSize()); else if (p.fileSystem().supportGetUsed() == FileSystem::cmdSupportFileSystem) p.fileSystem().setSectorsUsed(p.fileSystem().readUsedCapacity(p.deviceNode()) / d.logicalSectorSize()); #if defined LIBPARTED_FS_RESIZE_LIBRARY_SUPPORT else if (p.fileSystem().supportGetUsed() == FileSystem::cmdSupportBackend) p.fileSystem().setSectorsUsed(readSectorsUsedLibParted(p)); #endif } /** Constructs a LibParted object. */ LibPartedBackend::LibPartedBackend(QObject*, const QList&) : CoreBackend() { ped_exception_set_handler(pedExceptionHandler); } void LibPartedBackend::initFSSupport() { #if defined LIBPARTED_FS_RESIZE_LIBRARY_SUPPORT if (FS::fat16::m_Shrink == FileSystem::cmdSupportNone) FS::fat16::m_Shrink = FileSystem::cmdSupportBackend; if (FS::fat16::m_Grow == FileSystem::cmdSupportNone) FS::fat16::m_Grow = FileSystem::cmdSupportBackend; if (FS::hfs::m_Shrink == FileSystem::cmdSupportNone) FS::hfs::m_Shrink = FileSystem::cmdSupportBackend; if (FS::hfsplus::m_Shrink == FileSystem::cmdSupportNone) FS::hfsplus::m_Shrink = FileSystem::cmdSupportBackend; if (FS::hfs::m_GetUsed == FileSystem::cmdSupportNone) FS::hfs::m_GetUsed = FileSystem::cmdSupportBackend; if (FS::hfsplus::m_GetUsed == FileSystem::cmdSupportNone) FS::hfsplus::m_GetUsed = FileSystem::cmdSupportBackend; #endif } /** Create a Device for the given deviceNode and scan it for partitions. @param deviceNode the device node (e.g. "/dev/sda") @return the created Device object. callers need to free this. */ Device* LibPartedBackend::scanDevice(const QString& 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()) { qWarning() << "KAuth returned an error code: " << job->errorString(); return nullptr; } bool pedDeviceError = job->data()[QLatin1String("pedDeviceError")].toBool(); if (pedDeviceError) { Log(Log::warning) << xi18nc("@info:status", "Could not access device %1", deviceNode); return nullptr; } QString model = job->data()[QLatin1String("model")].toString(); QString path = job->data()[QLatin1String("path")].toString(); int heads = job->data()[QLatin1String("heads")].toInt(); int sectors = job->data()[QLatin1String("sectors")].toInt(); int cylinders = job->data()[QLatin1String("cylinders")].toInt(); int sectorSize = job->data()[QLatin1String("sectorSize")].toInt(); bool pedDiskError = job->data()[QLatin1String("pedDiskError")].toBool(); Log(Log::information) << xi18nc("@info:status", "Device found: %1", model); DiskDevice* d = new DiskDevice(model, path, heads, sectors, cylinders, sectorSize); if (pedDiskError) return d; QString typeName = job->data()[QLatin1String("typeName")].toString(); qint32 maxPrimaryPartitionCount = job->data()[QLatin1String("maxPrimaryPartitionCount")].toInt(); quint64 firstUsableSector = job->data()[QLatin1String("firstUsableSector")].toULongLong(); quint64 lastUsableSector = job->data()[QLatin1String("lastUsableSector")].toULongLong(); const PartitionTable::TableType type = PartitionTable::nameToTableType(typeName); CoreBackend::setPartitionTableForDevice(*d, new PartitionTable(type, firstUsableSector, lastUsableSector)); CoreBackend::setPartitionTableMaxPrimaries(*d->partitionTable(), maxPrimaryPartitionCount); QList partitionPath = job->data()[QLatin1String("partitionPath")].toList(); QList partitionType = job->data()[QLatin1String("partitionType")].toList(); QList partitionStart = job->data()[QLatin1String("partitionStart")].toList(); QList partitionEnd = job->data()[QLatin1String("partitionEnd")].toList(); QList partitionBusy = job->data()[QLatin1String("partitionBusy")].toList(); quint32 totalPartitions = partitionPath.size(); QList partitions; for (quint32 i = 0; i < totalPartitions; ++i) { QString partitionNode = partitionPath[i].toString(); int type = partitionType[i].toInt(); qint64 start = partitionStart[i].toLongLong(); qint64 end = partitionEnd[i].toLongLong(); PartitionRole::Roles r = PartitionRole::None; FileSystem::Type fsType = detectFileSystem(partitionNode); switch (type) { case PED_PARTITION_NORMAL: r = PartitionRole::Primary; break; case PED_PARTITION_EXTENDED: r = PartitionRole::Extended; type = FileSystem::Extended; break; case PED_PARTITION_LOGICAL: r = PartitionRole::Logical; break; default: continue; } // Find an extended partition this partition is in. PartitionNode* parent = d->partitionTable()->findPartitionBySector(start, PartitionRole(PartitionRole::Extended)); // None found, so it's a primary in the device's partition table. if (parent == nullptr) parent = d->partitionTable(); FileSystem* fs = FileSystemFactory::create(fsType, start, end); fs->scan(partitionNode); QString mountPoint; bool mounted; // libparted does not handle LUKS partitions if (fs->type() == FileSystem::Luks) { r |= PartitionRole::Luks; - initLuks(fs, d); + FS::luks::initLUKS(fs); QString mapperNode = static_cast(fs)->mapperName(); mountPoint = FileSystem::detectMountPoint(fs, mapperNode); mounted = FileSystem::detectMountStatus(fs, mapperNode); } else { mountPoint = FileSystem::detectMountPoint(fs, partitionNode); mounted = FileSystem::detectMountStatus(fs, partitionNode); } QList availableFlags = job->data()[QLatin1String("availableFlags")].toList(); PartitionTable::Flags available = static_cast(availableFlags[i].toInt()); QList activeFlags = job->data()[QLatin1String("activeFlags")].toList(); PartitionTable::Flags active = static_cast(activeFlags[i].toInt()); Partition* part = new Partition(parent, *d, PartitionRole(r), fs, start, end, partitionNode, available, mountPoint, mounted, active); if (!part->roles().has(PartitionRole::Luks)) readSectorsUsed(*d, *part, mountPoint); if (fs->supportGetLabel() != FileSystem::cmdSupportNone) fs->setLabel(fs->readLabel(part->deviceNode())); if (fs->supportGetUUID() != FileSystem::cmdSupportNone) fs->setUUID(fs->readUUID(part->deviceNode())); parent->append(part); partitions.append(part); } d->partitionTable()->updateUnallocated(*d); if (d->partitionTable()->isSectorBased(*d)) d->partitionTable()->setType(*d, PartitionTable::msdos_sectorbased); foreach(const Partition * part, partitions) PartitionAlignment::isAligned(*d, *part); return d; } QList LibPartedBackend::scanDevices(bool excludeReadOnly) { QList result; // 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 "7," // loop devices "8,65,66,67,68,69,70,71," // SCSI disk devices "80,81,82,83,84,85,86,87," // I2O hard disk "179," // MMC block devices "259" // Block Extended Major (include NVMe) ); ExternalCommand cmd(QStringLiteral("lsblk"), { QStringLiteral("--nodeps"), QStringLiteral("--noheadings"), QStringLiteral("--output"), QString::fromLatin1("name"), QStringLiteral("--paths"), QStringLiteral("--include"), blockDeviceMajorNumbers}); if (cmd.run(-1) && cmd.exitCode() == 0) { QStringList devices = cmd.output().split(QString::fromLatin1("\n")); devices.removeLast(); quint32 totalDevices = devices.length(); for (quint32 i = 0; i < totalDevices; ++i) { if (excludeReadOnly) { QFile f(QStringLiteral("/sys/block/%1/ro").arg(QString(devices[i]).remove(QStringLiteral("/dev/")))); if (f.open(QIODevice::ReadOnly)) if (f.readLine().trimmed().toInt() == 1) continue; } emitScanProgress(devices[i], i * 100 / totalDevices); result.append(scanDevice(devices[i])); } } return result; } /** Detects the type of a FileSystem given a PedDevice and a PedPartition @param partitionPath path to the partition @return the detected FileSystem type (FileSystem::Unknown if not detected) */ FileSystem::Type LibPartedBackend::detectFileSystem(const QString& partitionPath) { FileSystem::Type rval = FileSystem::Unknown; blkid_cache cache; if (blkid_get_cache(&cache, nullptr) == 0) { blkid_dev dev; 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); } return rval; } CoreBackendDevice* LibPartedBackend::openDevice(const QString& deviceNode) { LibPartedDevice* device = new LibPartedDevice(deviceNode); if (device == nullptr || !device->open()) { delete device; device = nullptr; } return device; } CoreBackendDevice* LibPartedBackend::openDeviceExclusive(const QString& deviceNode) { LibPartedDevice* device = new LibPartedDevice(deviceNode); if (device == nullptr || !device->openExclusive()) { delete device; device = nullptr; } return device; } bool LibPartedBackend::closeDevice(CoreBackendDevice* core_device) { return core_device->close(); } PedPartitionFlag LibPartedBackend::getPedFlag(PartitionTable::Flag flag) { for (const auto &f : flagmap) if (f.flag == flag) return f.pedFlag; return static_cast(-1); } QString LibPartedBackend::lastPartedExceptionMessage() { return s_lastPartedExceptionMessage; } #include "libpartedbackend.moc" diff --git a/src/util/helpers.cpp b/src/util/helpers.cpp index 1fac96d..d175edb 100644 --- a/src/util/helpers.cpp +++ b/src/util/helpers.cpp @@ -1,120 +1,103 @@ /************************************************************************* * Copyright (C) 2008, 2009, 2010 by Volker Lanz * * Copyright (C) 2016 by Andrius Štikonas * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License as * * published by the Free Software Foundation; either version 3 of * * the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see .* *************************************************************************/ #include "util/helpers.h" #include "util/externalcommand.h" #include "util/globallog.h" -#include "fs/luks.h" -#include "core/device.h" #include "ops/operation.h" #include #include #include #include #include #include #include void registerMetaTypes() { qRegisterMetaType("Operation*"); qRegisterMetaType("Log::Level"); } bool caseInsensitiveLessThan(const QString& s1, const QString& s2) { return s1.toLower() < s2.toLower(); } void showColumnsContextMenu(const QPoint& p, QTreeWidget& tree) { QMenu headerMenu(xi18nc("@title:menu", "Columns")); QHeaderView* header = tree.header(); for (qint32 i = 0; i < tree.model()->columnCount(); i++) { const int idx = header->logicalIndex(i); const QString text = tree.model()->headerData(idx, Qt::Horizontal).toString(); QAction* action = headerMenu.addAction(text); action->setCheckable(true); action->setChecked(!header->isSectionHidden(idx)); action->setData(idx); action->setEnabled(idx > 0); } QAction* action = headerMenu.exec(tree.header()->mapToGlobal(p)); if (action != nullptr) { const bool hidden = !action->isChecked(); tree.setColumnHidden(action->data().toInt(), hidden); if (!hidden) tree.resizeColumnToContents(action->data().toInt()); } } bool isMounted(const QString& deviceNode) { ExternalCommand cmd(QStringLiteral("lsblk"), { QStringLiteral("--noheadings"), QStringLiteral("--nodeps"), QStringLiteral("--output"), QStringLiteral("mountpoint"), deviceNode }); if (cmd.run(-1) && cmd.exitCode() == 0) { return !cmd.output().trimmed().isEmpty(); } return false; } -void initLuks(FileSystem* fs, const Device* dev) -{ - if (fs->type() == FileSystem::Luks) { - FS::luks* luksFS = static_cast(fs); - QString mapperNode = luksFS->mapperName(); - bool isCryptOpen = !mapperNode.isEmpty(); - luksFS->setCryptOpen(isCryptOpen); - luksFS->setLogicalSectorSize(dev->logicalSize()); - if (isCryptOpen) { - luksFS->loadInnerFileSystem(mapperNode); - } - luksFS->setMounted(isMounted(mapperNode)); - } -} - KAboutData aboutKPMcore() { KAboutData aboutData( QStringLiteral("kpmcore"), xi18nc("@title", "KPMcore"), QStringLiteral(VERSION), xi18nc("@title", "Library for managing partitions"), KAboutLicense::GPL_V3, xi18nc("@info:credit", "© 2008-2016 KPMcore developers" ) ); aboutData.setOrganizationDomain(QByteArray("kde.org")); aboutData.setProductName(QByteArray("kpmcore")); aboutData.setHomepage(QStringLiteral("https://quickgit.kde.org/?p=kpmcore.git")); aboutData.addAuthor(xi18nc("@info:credit", "Volker Lanz"), xi18nc("@info:credit", "Former maintainer")); aboutData.addAuthor(xi18nc("@info:credit", "Andrius Štikonas"), xi18nc("@info:credit", "Maintainer"), QStringLiteral("andrius@stikonas.eu")); aboutData.addAuthor(xi18nc("@info:credit", "Teo Mrnjavac"), i18nc("@info:credit", "Calamares maintainer"), QStringLiteral("teo@kde.org")); aboutData.addAuthor(xi18nc("@info:credit", "Chantara Tith"), i18nc("@info:credit", "LVM support"), QStringLiteral("tith.chantara@gmail.com")); return aboutData; } diff --git a/src/util/helpers.h b/src/util/helpers.h index b4b2769..39b95e8 100644 --- a/src/util/helpers.h +++ b/src/util/helpers.h @@ -1,46 +1,44 @@ /************************************************************************* * Copyright (C) 2008 by Volker Lanz * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License as * * published by the Free Software Foundation; either version 3 of * * the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see .* *************************************************************************/ #if !defined(HELPERS__H) #define HELPERS__H #include "fs/filesystem.h" #include "util/libpartitionmanagerexport.h" class KAboutData; class QString; class QPoint; class QTreeWidget; LIBKPMCORE_EXPORT void registerMetaTypes(); LIBKPMCORE_EXPORT bool caseInsensitiveLessThan(const QString& s1, const QString& s2); LIBKPMCORE_EXPORT void showColumnsContextMenu(const QPoint& p, QTreeWidget& tree); LIBKPMCORE_EXPORT bool checkAccessibleDevices(); LIBKPMCORE_EXPORT bool isMounted(const QString& deviceNode); -LIBKPMCORE_EXPORT void initLuks(FileSystem* fs, const Device* dev); - LIBKPMCORE_EXPORT KAboutData aboutKPMcore(); #endif