diff --git a/src/core/lvmdevice.cpp b/src/core/lvmdevice.cpp index 4bff050..1ae5f31 100644 --- a/src/core/lvmdevice.cpp +++ b/src/core/lvmdevice.cpp @@ -1,508 +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 -#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); - 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; + QString mountPoint; + bool mounted; - if (type == FileSystem::Luks) { + // Handle LUKS partition + if (fs->type() == FileSystem::Luks) { r |= PartitionRole::Luks; - FS::luks* luksFs = static_cast(fs); - QString mapperNode = luksFs->mapperName(); - bool isCryptOpen = !mapperNode.isEmpty(); - luksFs->setCryptOpen(isCryptOpen); - luksFs->setLogicalSectorSize(logicalSize()); - - if (isCryptOpen) { - luksFs->loadInnerFileSystem(mapperNode); - - if (luksFs->type() == FileSystem::Lvm2_PV) { - mountPoint = FS::lvm2_pv::getVGName(mapperNode); - mounted = false; - } - else { - mountPoint = mountPointList.findByDevice(mapperNode) ? - mountPointList.findByDevice(mapperNode)->mountPoint() : - QString(); - if (mountPoint == QStringLiteral("none")) - mountPoint = QString(); - mounted = isMounted(mapperNode); - if (mounted) { - const KDiskFreeSpaceInfo freeSpaceInfo = KDiskFreeSpaceInfo::freeSpaceInfo(mountPoint); - if (freeSpaceInfo.isValid() && mountPoint != QString()) - luksFs->setSectorsUsed((freeSpaceInfo.used() + luksFs->payloadOffset()) / logicalSize()); - } - } - } else { - mounted = false; - } - luksFs->setMounted(mounted); - } - else if (type == FileSystem::Lvm2_PV) { - r |= PartitionRole::Lvm_Lv; - mountPoint = FS::lvm2_pv::getVGName(lvPath); - mounted = false; - } - else { - mountPoint = mountPointList.findByDevice(lvPath) ? - mountPointList.findByDevice(lvPath)->mountPoint() : - QString(); - const KDiskFreeSpaceInfo freeSpaceInfo = KDiskFreeSpaceInfo::freeSpaceInfo(mountPoint); - - if (mountPoint == QStringLiteral("none")) - mountPoint = QString(); + initLuks(fs, this); + 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); - if (logicalSize() > 0) { + 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/filesystem.cpp b/src/fs/filesystem.cpp index 15a9b0c..d824b4d 100644 --- a/src/fs/filesystem.cpp +++ b/src/fs/filesystem.cpp @@ -1,483 +1,517 @@ /************************************************************************* * Copyright (C) 2012 by Volker Lanz * * Copyright (C) 2015 by Teo Mrnjavac * * Copyright (C) 2016 by Andrius Štikonas * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License as * * published by the Free Software Foundation; either version 3 of * * the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see .* *************************************************************************/ #include "fs/filesystem.h" +#include "fs/lvm2_pv.h" #include "backend/corebackend.h" #include "backend/corebackendmanager.h" #include "util/externalcommand.h" #include "util/capacity.h" +#include "util/helpers.h" #include +#include #include #include const std::array< QColor, FileSystem::__lastType > FileSystem::defaultColorCode = { { QColor( 220,205,175 ), QColor( 187,249,207 ), QColor( 102,121,150 ), QColor( 122,145,180 ), QColor( 143,170,210 ), QColor( 155,155,130 ), QColor( 204,179,215 ), QColor( 229,201,240 ), QColor( 244,214,255 ), QColor( 216,220,135 ), QColor( 251,255,157 ), QColor( 200,255,254 ), QColor( 137,200,198 ), QColor( 210,136,142 ), QColor( 240,165,171 ), QColor( 151,220,134 ), QColor( 220,205,175 ), QColor( 173,205,255 ), QColor( 176,155,185 ), QColor( 170,30,77 ), QColor( 96,140,85 ), QColor( 33,137,108 ), QColor( 250,230,255 ), QColor( 242,155,104 ), QColor( 160,210,180 ), QColor( 255,170,0 ) } }; /** Creates a new FileSystem object @param firstsector the first sector used by this FileSystem on the Device @param lastsector the last sector used by this FileSystem on the Device @param sectorsused the number of sectors in use on the FileSystem @param l the FileSystem label @param t the FileSystem type */ FileSystem::FileSystem(qint64 firstsector, qint64 lastsector, qint64 sectorsused, const QString& l, FileSystem::Type t) : m_Type(t), m_FirstSector(firstsector), m_LastSector(lastsector), m_SectorsUsed(sectorsused), m_Label(l), m_UUID() { } /** Reads the capacity in use on this FileSystem @param deviceNode the device node for the Partition the FileSystem is on @return the used capacity in bytes or -1 in case of an error */ qint64 FileSystem::readUsedCapacity(const QString& deviceNode) const { Q_UNUSED(deviceNode); return -1; } static QString readBlkIdValue(const QString& deviceNode, const QString& tag) { blkid_cache cache; QString rval; if (blkid_get_cache(&cache, nullptr) == 0) { blkid_dev dev; char* label = nullptr; if ((dev = blkid_get_dev(cache, deviceNode.toLocal8Bit().constData(), BLKID_DEV_NORMAL)) != nullptr && (label = blkid_get_tag_value(cache, tag.toLocal8Bit().constData(), deviceNode.toLocal8Bit().constData()))) { rval = QString::fromUtf8(label); free(label); } blkid_put_cache(cache); } return rval; } FileSystem::Type FileSystem::detectFileSystem(const QString& partitionPath) { return CoreBackendManager::self()->backend()->detectFileSystem(partitionPath); } +QString FileSystem::detectMountPoint(FileSystem* fs, const QString& partitionPath) +{ + QString mountPoint = QString(); + + KMountPoint::List mountPoints = KMountPoint::currentMountPoints(KMountPoint::NeedRealDeviceName); + mountPoints.append(KMountPoint::possibleMountPoints(KMountPoint::NeedRealDeviceName)); + + if (fs->type() == FileSystem::Lvm2_PV) { + mountPoint = FS::lvm2_pv::getVGName(partitionPath); + } else { + mountPoint = mountPoints.findByDevice(partitionPath) ? + mountPoints.findByDevice(partitionPath)->mountPoint() : + QString(); + if (mountPoint == QStringLiteral("none")) + mountPoint = QString(); + } + return mountPoint; +} + +bool FileSystem::detectMountStatus(FileSystem* fs, const QString& partitionPath) +{ + bool mounted = false; + + if (fs->type() == FileSystem::Lvm2_PV) { + mounted = false; + } else { + mounted = isMounted(partitionPath); + } + return mounted; +} + /** Reads the label for this FileSystem @param deviceNode the device node for the Partition the FileSystem is on @return the FileSystem label or an empty string in case of error */ QString FileSystem::readLabel(const QString& deviceNode) const { return readBlkIdValue(deviceNode, QStringLiteral("LABEL")); } /** Creates a new FileSystem @param report Report to write status information to @param deviceNode the device node for the Partition to create the FileSystem on @return true if successful */ bool FileSystem::create(Report& report, const QString& deviceNode) { Q_UNUSED(report); Q_UNUSED(deviceNode); return true; } /** Scans a new FileSystem and load file system specific class variables. * @param deviceNode the device node for the Partition to create the FileSystem on */ void FileSystem::scan(const QString& deviceNode) { Q_UNUSED(deviceNode); } /** Resize a FileSystem to a given new length @param report Report to write status information to @param deviceNode the device node for the Partition the FileSystem is on @param newLength the new length for the FileSystem in bytes @return true on success */ bool FileSystem::resize(Report& report, const QString& deviceNode, qint64 newLength) const { Q_UNUSED(report); Q_UNUSED(deviceNode); Q_UNUSED(newLength); return true; } /** Resize a mounted FileSystem to a given new length @param report Report to write status information to @param deviceNode the device node for the Partition the FileSystem is on @param mountPoint the mount point where FileSystem is mounted on @param newLength the new length for the FileSystem in bytes @return true on success */ bool FileSystem::resizeOnline(Report& report, const QString& deviceNode, const QString& mountPoint, qint64 newLength) const { Q_UNUSED(report); Q_UNUSED(deviceNode); Q_UNUSED(mountPoint); Q_UNUSED(newLength); return true; } /** Move a FileSystem to a new start sector @param report Report to write status information to @param deviceNode the device node for the Partition the FileSystem is on @param newStartSector the new start sector for the FileSystem @return true on success */ bool FileSystem::move(Report& report, const QString& deviceNode, qint64 newStartSector) const { Q_UNUSED(report); Q_UNUSED(deviceNode); Q_UNUSED(newStartSector); return true; } /** Writes a label for the FileSystem to disk @param report Report to write status information to @param deviceNode the device node for the Partition the FileSystem is on @param newLabel the new label for the FileSystem @return true on success */ bool FileSystem::writeLabel(Report& report, const QString& deviceNode, const QString& newLabel) { Q_UNUSED(report); Q_UNUSED(deviceNode); Q_UNUSED(newLabel); return true; } /** Copies a FileSystem from one Partition to another @param report Report to write status information to @param targetDeviceNode device node of the target Partition @param sourceDeviceNode device node of the source Partition @return true on success */ bool FileSystem::copy(Report& report, const QString& targetDeviceNode, const QString& sourceDeviceNode) const { Q_UNUSED(report); Q_UNUSED(targetDeviceNode); Q_UNUSED(sourceDeviceNode); return true; } /** Backs up a FileSystem to a file @param report Report to write status information to @param sourceDevice Device the source FileSystem is on @param deviceNode device node of the source Partition @param filename name of the file to backup to @return true on success */ bool FileSystem::backup(Report& report, const Device& sourceDevice, const QString& deviceNode, const QString& filename) const { Q_UNUSED(report); Q_UNUSED(sourceDevice); Q_UNUSED(deviceNode); Q_UNUSED(filename); return false; } /** Removes a FileSystem @param report Report to write status information to @param deviceNode the device node for the Partition the FileSystem is on @return true if FileSystem is removed */ bool FileSystem::remove(Report& report, const QString& deviceNode) const { Q_UNUSED(report); Q_UNUSED(deviceNode); return true; } /** Checks a FileSystem for errors @param report Report to write status information to @param deviceNode the device node for the Partition the FileSystem is on @return true if FileSystem is error-free */ bool FileSystem::check(Report& report, const QString& deviceNode) const { Q_UNUSED(report); Q_UNUSED(deviceNode); return true; } /** Updates a FileSystem UUID on disk @param report Report to write status information to @param deviceNode the device node for the Partition the FileSystem is on @return true on success */ bool FileSystem::updateUUID(Report& report, const QString& deviceNode) const { Q_UNUSED(report); Q_UNUSED(deviceNode); return true; } /** Returns the FileSystem UUID by calling a FileSystem-specific helper program @param deviceNode the device node for the Partition the FileSystem is on @return the UUID or an empty string if the FileSystem does not support UUIDs */ QString FileSystem::readUUID(const QString& deviceNode) const { return readBlkIdValue(deviceNode, QStringLiteral("UUID")); } /** Give implementations of FileSystem a chance to update the boot sector after the file system has been moved or copied. @param report Report to write status information to @param deviceNode the device node for the Partition the FileSystem is on @return true on success */ bool FileSystem::updateBootSector(Report& report, const QString& deviceNode) const { Q_UNUSED(report); Q_UNUSED(deviceNode); return true; } /** @return the minimum capacity valid for this FileSystem in bytes */ qint64 FileSystem::minCapacity() const { return 8 * Capacity::unitFactor(Capacity::Byte, Capacity::MiB); } /** @return the maximum capacity valid for this FileSystem in bytes */ qint64 FileSystem::maxCapacity() const { return Capacity::unitFactor(Capacity::Byte, Capacity::EiB); } /** @return the maximum label length valid for this FileSystem */ qint64 FileSystem::maxLabelLength() const { return 16; } /** @return this FileSystem's type as printable name */ QString FileSystem::name() const { return nameForType(type()); } /** @return a pointer to a QString C array with all FileSystem names */ static const QString* typeNames() { static const QString s[] = { xi18nc("@item filesystem name", "unknown"), xi18nc("@item filesystem name", "extended"), xi18nc("@item filesystem name", "ext2"), xi18nc("@item filesystem name", "ext3"), xi18nc("@item filesystem name", "ext4"), xi18nc("@item filesystem name", "linuxswap"), xi18nc("@item filesystem name", "fat16"), xi18nc("@item filesystem name", "fat32"), xi18nc("@item filesystem name", "ntfs"), xi18nc("@item filesystem name", "reiser"), xi18nc("@item filesystem name", "reiser4"), xi18nc("@item filesystem name", "xfs"), xi18nc("@item filesystem name", "jfs"), xi18nc("@item filesystem name", "hfs"), xi18nc("@item filesystem name", "hfsplus"), xi18nc("@item filesystem name", "ufs"), xi18nc("@item filesystem name", "unformatted"), xi18nc("@item filesystem name", "btrfs"), xi18nc("@item filesystem name", "hpfs"), xi18nc("@item filesystem name", "luks"), xi18nc("@item filesystem name", "ocfs2"), xi18nc("@item filesystem name", "zfs"), xi18nc("@item filesystem name", "exfat"), xi18nc("@item filesystem name", "nilfs2"), xi18nc("@item filesystem name", "lvm2 pv"), xi18nc("@item filesystem name", "f2fs"), }; return s; } /** @param t the type to get the name for @return the printable name for the given type */ QString FileSystem::nameForType(FileSystem::Type t) { Q_ASSERT(t >= 0); Q_ASSERT(t < __lastType); return typeNames()[t]; } /** @param s the name to get the type for @return the type for the name or FileSystem::Unknown if not found */ FileSystem::Type FileSystem::typeForName(const QString& s) { for (quint32 i = 0; i < __lastType; i++) if (typeNames()[i] == s) return static_cast(i); return Unknown; } /** @return a QList of all known types */ QList FileSystem::types() { QList result; int i = Ext2; // first "real" filesystem while (i != __lastType) result.append(static_cast(i++)); return result; } /** @return printable menu title for mounting this FileSystem */ QString FileSystem::mountTitle() const { return xi18nc("@title:menu", "Mount"); } /** @return printable menu title for unmounting this FileSystem */ QString FileSystem::unmountTitle() const { return xi18nc("@title:menu", "Unmount"); } /** Moves a FileSystem to a new start sector. @param newStartSector where the FileSystem should be moved to */ void FileSystem::move(qint64 newStartSector) { const qint64 savedLength = length(); setFirstSector(newStartSector); setLastSector(newStartSector + savedLength - 1); } bool FileSystem::canMount(const QString& deviceNode, const QString& mountPoint) const { Q_UNUSED(deviceNode); // cannot mount if we have no mount points return !mountPoint.isEmpty(); } /** Attempt to mount this FileSystem on a given mount point @param report the report to write information to @param deviceNode the path to the device that is to be unmounted @param mountPoint the mount point to mount the FileSystem on @return true on success */ bool FileSystem::mount(Report& report, const QString &deviceNode, const QString &mountPoint) { ExternalCommand mountCmd( report, QStringLiteral("mount"), { QStringLiteral("--verbose"), deviceNode, mountPoint }); if (mountCmd.run() && mountCmd.exitCode() == 0) { return true; } return false; } /** Attempt to unmount this FileSystem @param report the report to write information to @param deviceNode the path to the device that is to be unmounted @return true on success */ bool FileSystem::unmount(Report& report, const QString& deviceNode) { ExternalCommand umountCmd( report, QStringLiteral("umount"), { QStringLiteral("--verbose"), QStringLiteral("--all-targets"), deviceNode }); if ( umountCmd.run() && umountCmd.exitCode() == 0 ) return true; return false; } bool FileSystem::findExternal(const QString& cmdName, const QStringList& args, int expectedCode) { ExternalCommand cmd(cmdName, args); if (!cmd.run()) return false; return cmd.exitCode() == 0 || cmd.exitCode() == expectedCode; } bool FileSystem::supportToolFound() const { return false; } FileSystem::SupportTool FileSystem::supportToolName() const { return SupportTool(); } diff --git a/src/fs/filesystem.h b/src/fs/filesystem.h index 7d1457a..c886ead 100644 --- a/src/fs/filesystem.h +++ b/src/fs/filesystem.h @@ -1,255 +1,257 @@ /************************************************************************* * Copyright (C) 2012 by Volker Lanz * * Copyright (C) 2015 by Teo Mrnjavac * * Copyright (C) 2016 by Andrius Štikonas * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License as * * published by the Free Software Foundation; either version 3 of * * the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see .* *************************************************************************/ #if !defined(FILESYSTEM__H) #define FILESYSTEM__H #include "util/libpartitionmanagerexport.h" #include #include #include #include #include #include #include class Device; class Report; /** Base class for all FileSystems. Represents a file system and handles support for various types of operations that can be performed on those. @author Volker Lanz */ class LIBKPMCORE_EXPORT FileSystem { Q_DISABLE_COPY(FileSystem) public: class SupportTool { public: explicit SupportTool(const QString& n = QString(), const QUrl& u = QUrl()) : name(n), url(u) {} const QString name; const QUrl url; }; /** Supported FileSystem types */ enum Type { Unknown = 0, Extended = 1, Ext2 = 2, Ext3 = 3, Ext4 = 4, LinuxSwap = 5, Fat16 = 6, Fat32 = 7, Ntfs = 8, ReiserFS = 9, Reiser4 = 10, Xfs = 11, Jfs = 12, Hfs = 13, HfsPlus = 14, Ufs = 15, Unformatted = 16, Btrfs = 17, Hpfs = 18, Luks = 19, Ocfs2 = 20, Zfs = 21, Exfat = 22, Nilfs2 = 23, Lvm2_PV = 24, F2fs = 25, __lastType = 26 }; /** The type of support for a given FileSystem action */ enum CommandSupportType { cmdSupportNone = 0, /**< no support */ cmdSupportCore = 1, /**< internal support */ cmdSupportFileSystem = 2, /**< supported by some external command */ cmdSupportBackend = 4 /**< supported by the backend */ }; static const std::array< QColor, __lastType > defaultColorCode; Q_DECLARE_FLAGS(CommandSupportTypes, CommandSupportType) protected: FileSystem(qint64 firstsector, qint64 lastsector, qint64 sectorsused, const QString& label, FileSystem::Type t); public: virtual ~FileSystem() {} public: virtual void init() {}; virtual void scan(const QString& deviceNode); virtual qint64 readUsedCapacity(const QString& deviceNode) const; virtual QString readLabel(const QString& deviceNode) const; virtual bool create(Report& report, const QString& deviceNode); virtual bool resize(Report& report, const QString& deviceNode, qint64 newLength) const; virtual bool resizeOnline(Report& report, const QString& deviceNode, const QString& mountPoint, qint64 newLength) const; virtual bool move(Report& report, const QString& deviceNode, qint64 newStartSector) const; virtual bool writeLabel(Report& report, const QString& deviceNode, const QString& newLabel); virtual bool copy(Report& report, const QString& targetDeviceNode, const QString& sourceDeviceNode) const; virtual bool backup(Report& report, const Device& sourceDevice, const QString& deviceNode, const QString& filename) const; virtual bool remove(Report& report, const QString& deviceNode) const; virtual bool check(Report& report, const QString& deviceNode) const; virtual bool updateUUID(Report& report, const QString& deviceNode) const; virtual QString readUUID(const QString& deviceNode) const; virtual bool updateBootSector(Report& report, const QString& deviceNode) const; virtual CommandSupportType supportGetUsed() const { return cmdSupportNone; /**< @return CommandSupportType for getting used capacity */ } virtual CommandSupportType supportGetLabel() const { return cmdSupportNone; /**< @return CommandSupportType for reading label*/ } virtual CommandSupportType supportCreate() const { return cmdSupportNone; /**< @return CommandSupportType for creating */ } virtual CommandSupportType supportGrow() const { return cmdSupportNone; /**< @return CommandSupportType for growing */ } virtual CommandSupportType supportGrowOnline() const { return cmdSupportNone; /**< @return CommandSupportType for online growing */ } virtual CommandSupportType supportShrink() const { return cmdSupportNone; /**< @return CommandSupportType for shrinking */ } virtual CommandSupportType supportShrinkOnline() const { return cmdSupportNone; /**< @return CommandSupportType for shrinking */ } virtual CommandSupportType supportMove() const { return cmdSupportNone; /**< @return CommandSupportType for moving */ } virtual CommandSupportType supportCheck() const { return cmdSupportNone; /**< @return CommandSupportType for checking */ } virtual CommandSupportType supportCopy() const { return cmdSupportNone; /**< @return CommandSupportType for copying */ } virtual CommandSupportType supportBackup() const { return cmdSupportNone; /**< @return CommandSupportType for backing up */ } virtual CommandSupportType supportSetLabel() const { return cmdSupportNone; /**< @return CommandSupportType for setting label */ } virtual CommandSupportType supportSetLabelOnline() const { return cmdSupportNone; /**< @return CommandSupportType for setting label of mounted file systems */ } virtual CommandSupportType supportUpdateUUID() const { return cmdSupportNone; /**< @return CommandSupportType for updating the UUID */ } virtual CommandSupportType supportGetUUID() const { return cmdSupportNone; /**< @return CommandSupportType for reading the UUID */ } virtual qint64 minCapacity() const; virtual qint64 maxCapacity() const; virtual qint64 maxLabelLength() const; virtual SupportTool supportToolName() const; virtual bool supportToolFound() const; virtual QString name() const; virtual FileSystem::Type type() const { return m_Type; /**< @return the FileSystem's type */ } static QString nameForType(FileSystem::Type t); static QList types(); static FileSystem::Type typeForName(const QString& s); static FileSystem::Type detectFileSystem(const QString& partitionPath); + static QString detectMountPoint(FileSystem* fs, const QString& partitionPath); + static bool detectMountStatus(FileSystem* fs, const QString& partitionPath); /**< @return true if this FileSystem can be mounted */ virtual bool canMount(const QString& deviceNode, const QString& mountPoint) const; virtual bool canUnmount(const QString&) const { return true; /**< @return true if this FileSystem can be unmounted */ } virtual QString mountTitle() const; virtual QString unmountTitle() const; virtual bool mount(Report& report, const QString& deviceNode, const QString& mountPoint); virtual bool unmount(Report& report, const QString& deviceNode); qint64 firstSector() const { return m_FirstSector; /**< @return the FileSystem's first sector */ } qint64 lastSector() const { return m_LastSector; /**< @return the FileSystem's last sector */ } qint64 length() const { return lastSector() - firstSector() + 1; /**< @return the FileSystem's length */ } void setFirstSector(qint64 s) { m_FirstSector = s; /**< @param s the new first sector */ } void setLastSector(qint64 s) { m_LastSector = s; /**< @param s the new last sector */ } void move(qint64 newStartSector); const QString& label() const { return m_Label; /**< @return the FileSystem's label */ } qint64 sectorsUsed() const { return m_SectorsUsed; /**< @return the sectors in use on the FileSystem */ } const QString& uuid() const { return m_UUID; /**< @return the FileSystem's UUID */ } void setSectorsUsed(qint64 s) { m_SectorsUsed = s; /**< @param s the new value for sectors in use */ } void setLabel(const QString& s) { m_Label = s; /**< @param s the new label */ } void setUUID(const QString& s) { m_UUID = s; /**< @param s the new UUID */ } protected: static bool findExternal(const QString& cmdName, const QStringList& args = QStringList(), int exptectedCode = 1); protected: FileSystem::Type m_Type; qint64 m_FirstSector; qint64 m_LastSector; qint64 m_SectorsUsed; QString m_Label; QString m_UUID; }; Q_DECLARE_OPERATORS_FOR_FLAGS(FileSystem::CommandSupportTypes) #endif diff --git a/src/plugins/libparted/libpartedbackend.cpp b/src/plugins/libparted/libpartedbackend.cpp index e5def75..e73bfaa 100644 --- a/src/plugins/libparted/libpartedbackend.cpp +++ b/src/plugins/libparted/libpartedbackend.cpp @@ -1,464 +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 #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); - KMountPoint::List mountPoints = KMountPoint::currentMountPoints(KMountPoint::NeedRealDeviceName); - mountPoints.append(KMountPoint::possibleMountPoints(KMountPoint::NeedRealDeviceName)); - 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(); - bool busy = partitionBusy[i].toBool(); 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 - QString mountPoint; - bool mounted = false; - if (fsType == FileSystem::Luks) { + if (fs->type() == FileSystem::Luks) { r |= PartitionRole::Luks; - FS::luks* luksFs = static_cast(fs); - QString mapperNode = luksFs->mapperName(); - bool isCryptOpen = !mapperNode.isEmpty(); - luksFs->setCryptOpen(isCryptOpen); - luksFs->setLogicalSectorSize(d->logicalSectorSize()); - - if (isCryptOpen) { - luksFs->loadInnerFileSystem(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(); - if (mountPoint == QStringLiteral("none")) - 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() + luksFs->payloadOffset()) / 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; + initLuks(fs, d); + QString mapperNode = static_cast(fs)->mapperName(); + mountPoint = FileSystem::detectMountPoint(fs, mapperNode); + mounted = FileSystem::detectMountStatus(fs, mapperNode); } else { - mountPoint = mountPoints.findByDevice(partitionNode) ? - mountPoints.findByDevice(partitionNode)->mountPoint() : - QString(); - if (mountPoint == QStringLiteral("none")) - mountPoint = QString(); - mounted = busy; + 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 d175edb..1fac96d 100644 --- a/src/util/helpers.cpp +++ b/src/util/helpers.cpp @@ -1,103 +1,120 @@ /************************************************************************* * 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 39b95e8..b4b2769 100644 --- a/src/util/helpers.h +++ b/src/util/helpers.h @@ -1,44 +1,46 @@ /************************************************************************* * 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