diff --git a/src/fs/jfs.cpp b/src/fs/jfs.cpp index 7246e4c..bf6a906 100644 --- a/src/fs/jfs.cpp +++ b/src/fs/jfs.cpp @@ -1,195 +1,193 @@ /************************************************************************* * 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 .* *************************************************************************/ #include "fs/jfs.h" #include "util/externalcommand.h" #include "util/report.h" #include "util/capacity.h" #include #include #include #include -#include - namespace FS { FileSystem::CommandSupportType jfs::m_GetUsed = FileSystem::cmdSupportNone; FileSystem::CommandSupportType jfs::m_GetLabel = FileSystem::cmdSupportNone; FileSystem::CommandSupportType jfs::m_Create = FileSystem::cmdSupportNone; FileSystem::CommandSupportType jfs::m_Grow = FileSystem::cmdSupportNone; FileSystem::CommandSupportType jfs::m_Move = FileSystem::cmdSupportNone; FileSystem::CommandSupportType jfs::m_Check = FileSystem::cmdSupportNone; FileSystem::CommandSupportType jfs::m_Copy = FileSystem::cmdSupportNone; FileSystem::CommandSupportType jfs::m_Backup = FileSystem::cmdSupportNone; FileSystem::CommandSupportType jfs::m_SetLabel = FileSystem::cmdSupportNone; jfs::jfs(qint64 firstsector, qint64 lastsector, qint64 sectorsused, const QString& label) : FileSystem(firstsector, lastsector, sectorsused, label, FileSystem::Jfs) { } void jfs::init() { m_GetUsed = findExternal(QStringLiteral("jfs_debugfs")) ? cmdSupportFileSystem : cmdSupportNone; m_GetLabel = cmdSupportCore; m_SetLabel = findExternal(QStringLiteral("jfs_tune"), { QStringLiteral("-V") }) ? cmdSupportFileSystem : cmdSupportNone; m_Create = findExternal(QStringLiteral("mkfs.jfs"),{ QStringLiteral("-V") }) ? cmdSupportFileSystem : cmdSupportNone; m_Grow = m_Check = findExternal(QStringLiteral("fsck.jfs"), { QStringLiteral("-V") }) ? cmdSupportFileSystem : cmdSupportNone; m_Copy = m_Move = (m_Check != cmdSupportNone) ? cmdSupportCore : cmdSupportNone; m_Backup = cmdSupportCore; } bool jfs::supportToolFound() const { return m_GetUsed != cmdSupportNone && m_GetLabel != cmdSupportNone && m_SetLabel != cmdSupportNone && m_Create != cmdSupportNone && m_Check != cmdSupportNone && // m_UpdateUUID != cmdSupportNone && m_Grow != cmdSupportNone && // m_Shrink != cmdSupportNone && m_Copy != cmdSupportNone && m_Move != cmdSupportNone && m_Backup != cmdSupportNone; // m_GetUUID != cmdSupportNone; } FileSystem::SupportTool jfs::supportToolName() const { return SupportTool(QStringLiteral("jfsutils"), QUrl(QStringLiteral("http://jfs.sourceforge.net/"))); } qint64 jfs::minCapacity() const { return 16 * Capacity::unitFactor(Capacity::Byte, Capacity::MiB); } qint64 jfs::maxCapacity() const { return 16 * Capacity::unitFactor(Capacity::Byte, Capacity::TiB); } qint64 jfs::maxLabelLength() const { return 11; } qint64 jfs::readUsedCapacity(const QString& deviceNode) const { ExternalCommand cmd(QStringLiteral("jfs_debugfs"), QStringList() << deviceNode); if (cmd.start() && cmd.write("dm") == 2 && cmd.waitFor()) { qint64 blockSize = -1; QRegularExpression re(QStringLiteral("Block Size: (\\d+)")); QRegularExpressionMatch reBlockSize = re.match(cmd.output()); if (reBlockSize.hasMatch()) blockSize = reBlockSize.captured(1).toLongLong(); qint64 nBlocks = -1; re.setPattern(QStringLiteral("dn_mapsize:\\s+0x(\\x+)")); QRegularExpressionMatch renBlocks = re.match(cmd.output()); bool ok = false; if (renBlocks.hasMatch()) { nBlocks = renBlocks.captured(1).toLongLong(&ok, 16); if (!ok) nBlocks = -1; } qint64 nFree = -1; re.setPattern(QStringLiteral("dn_nfree:\\s+0x(\\x+)")); QRegularExpressionMatch renFree = re.match(cmd.output()); if (renFree.hasMatch()) { nFree = renFree.captured(1).toLongLong(&ok, 16); if (!ok) nFree = -1; } if (nBlocks > -1 && blockSize > -1 && nFree > -1) return (nBlocks - nFree) * blockSize; } return -1; } bool jfs::writeLabel(Report& report, const QString& deviceNode, const QString& newLabel) { ExternalCommand cmd(report, QStringLiteral("jfs_tune"), { QStringLiteral("-L"), newLabel, deviceNode }); return cmd.run(-1) && cmd.exitCode() == 0; } bool jfs::check(Report& report, const QString& deviceNode) const { ExternalCommand cmd(report, QStringLiteral("fsck.jfs"), { QStringLiteral("-f"), deviceNode }); return cmd.run(-1) && (cmd.exitCode() == 0 || cmd.exitCode() == 1); } bool jfs::create(Report& report, const QString& deviceNode) { ExternalCommand cmd(report, QStringLiteral("mkfs.jfs"), { QStringLiteral("-q"), deviceNode }); return cmd.run(-1) && cmd.exitCode() == 0; } bool jfs::resize(Report& report, const QString& deviceNode, qint64) const { QTemporaryDir tempDir; if (!tempDir.isValid()) { report.line() << xi18nc("@info:progress", "Resizing JFS file system on partition %1 failed: Could not create temp dir.", deviceNode); return false; } bool rval = false; ExternalCommand mountCmd(report, QStringLiteral("mount"), { QStringLiteral("--verbose"), QStringLiteral("--type"), QStringLiteral("jfs"), deviceNode, tempDir.path() }); if (mountCmd.run(-1)) { ExternalCommand resizeMountCmd(report, QStringLiteral("mount"), { QStringLiteral("--verbose"), QStringLiteral("--type"), QStringLiteral("jfs"), QStringLiteral("--options"), QStringLiteral("remount,resize"), deviceNode, tempDir.path() }); if (resizeMountCmd.run(-1) && resizeMountCmd.exitCode() == 0) rval = true; else report.line() << xi18nc("@info:progress", "Resizing JFS file system on partition %1 failed: Remount failed.", deviceNode); ExternalCommand unmountCmd(report, QStringLiteral("umount"), { tempDir.path() }); if (!unmountCmd.run(-1)) report.line() << xi18nc("@info:progress", "Resizing JFS file system on partition %1: Unmount failed.", deviceNode); } else report.line() << xi18nc("@info:progress", "Resizing JFS file system on partition %1 failed: Initial mount failed.", deviceNode); return rval; } bool jfs::resizeOnline(Report& report, const QString& deviceNode, const QString& mountPoint, qint64) const { ExternalCommand resizeMountCmd(report, QStringLiteral("mount"), { QStringLiteral("--verbose"), QStringLiteral("--type"), QStringLiteral("jfs"), QStringLiteral("--options"), QStringLiteral("remount,resize"), deviceNode, mountPoint }); if (resizeMountCmd.run(-1) && resizeMountCmd.exitCode() == 0) return true; report.line() << xi18nc("@info:progress", "Resizing JFS file system on partition %1 failed: Remount failed.", deviceNode); return false; } } diff --git a/src/fs/xfs.cpp b/src/fs/xfs.cpp index e399de0..a109086 100644 --- a/src/fs/xfs.cpp +++ b/src/fs/xfs.cpp @@ -1,205 +1,203 @@ /************************************************************************* * Copyright (C) 2008 by Volker Lanz * * Copyright (C) 2016 by Andrius Štikonas * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License as * * published by the Free Software Foundation; either version 3 of * * the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see .* *************************************************************************/ #include "fs/xfs.h" #include "util/externalcommand.h" #include "util/capacity.h" #include "util/report.h" #include #include #include #include #include -#include - namespace FS { FileSystem::CommandSupportType xfs::m_GetUsed = FileSystem::cmdSupportNone; FileSystem::CommandSupportType xfs::m_GetLabel = FileSystem::cmdSupportNone; FileSystem::CommandSupportType xfs::m_Create = FileSystem::cmdSupportNone; FileSystem::CommandSupportType xfs::m_Grow = FileSystem::cmdSupportNone; FileSystem::CommandSupportType xfs::m_Move = FileSystem::cmdSupportNone; FileSystem::CommandSupportType xfs::m_Check = FileSystem::cmdSupportNone; FileSystem::CommandSupportType xfs::m_Copy = FileSystem::cmdSupportNone; FileSystem::CommandSupportType xfs::m_Backup = FileSystem::cmdSupportNone; FileSystem::CommandSupportType xfs::m_SetLabel = FileSystem::cmdSupportNone; xfs::xfs(qint64 firstsector, qint64 lastsector, qint64 sectorsused, const QString& label) : FileSystem(firstsector, lastsector, sectorsused, label, FileSystem::Xfs) { } void xfs::init() { m_GetLabel = cmdSupportCore; m_SetLabel = m_GetUsed = findExternal(QStringLiteral("xfs_db")) ? cmdSupportFileSystem : cmdSupportNone; m_Create = findExternal(QStringLiteral("mkfs.xfs")) ? cmdSupportFileSystem : cmdSupportNone; m_Check = findExternal(QStringLiteral("xfs_repair")) ? cmdSupportFileSystem : cmdSupportNone; m_Grow = (findExternal(QStringLiteral("xfs_growfs"), { QStringLiteral("-V") }) && m_Check != cmdSupportNone) ? cmdSupportFileSystem : cmdSupportNone; m_Copy = findExternal(QStringLiteral("xfs_copy")) ? cmdSupportFileSystem : cmdSupportNone; m_Move = (m_Check != cmdSupportNone) ? cmdSupportCore : cmdSupportNone; m_Backup = cmdSupportCore; } bool xfs::supportToolFound() const { return m_GetUsed != cmdSupportNone && m_GetLabel != cmdSupportNone && m_SetLabel != cmdSupportNone && m_Create != cmdSupportNone && m_Check != cmdSupportNone && // m_UpdateUUID != cmdSupportNone && m_Grow != cmdSupportNone && // m_Shrink != cmdSupportNone && m_Copy != cmdSupportNone && m_Move != cmdSupportNone && m_Backup != cmdSupportNone; // m_GetUUID != cmdSupportNone; } FileSystem::SupportTool xfs::supportToolName() const { return SupportTool(QStringLiteral("xfsprogs"), QUrl(QStringLiteral("http://oss.sgi.com/projects/xfs/"))); } qint64 xfs::minCapacity() const { return 32 * Capacity::unitFactor(Capacity::Byte, Capacity::MiB); } qint64 xfs::maxCapacity() const { return Capacity::unitFactor(Capacity::Byte, Capacity::EiB); } qint64 xfs::maxLabelLength() const { return 12; } qint64 xfs::readUsedCapacity(const QString& deviceNode) const { ExternalCommand cmd(QStringLiteral("xfs_db"), { QStringLiteral("-c"), QStringLiteral("sb 0"), QStringLiteral("-c"), QStringLiteral("print"), deviceNode }); if (cmd.run(-1) && cmd.exitCode() == 0) { qint64 dBlocks = -1; QRegularExpression re(QStringLiteral("dblocks = (\\d+)")); QRegularExpressionMatch reDBlocks = re.match(cmd.output()); if (reDBlocks.hasMatch()) dBlocks = reDBlocks.captured(1).toLongLong(); qint64 blockSize = -1; re.setPattern(QStringLiteral("blocksize = (\\d+)")); QRegularExpressionMatch reBlockSize = re.match(cmd.output()); if (reBlockSize.hasMatch()) blockSize = reBlockSize.captured(1).toLongLong(); qint64 fdBlocks = -1; re.setPattern(QStringLiteral("fdblocks = (\\d+)")); QRegularExpressionMatch reFdBlocks = re.match(cmd.output()); if (reFdBlocks.hasMatch()) fdBlocks = reFdBlocks.captured(1).toLongLong(); if (dBlocks > -1 && blockSize > -1 && fdBlocks > -1) return (dBlocks - fdBlocks) * blockSize; } return -1; } bool xfs::writeLabel(Report& report, const QString& deviceNode, const QString& newLabel) { ExternalCommand cmd(report, QStringLiteral("xfs_db"), { QStringLiteral("-x"), QStringLiteral("-c"), QStringLiteral("sb 0"), QStringLiteral("-c"), QStringLiteral("label ") + newLabel, deviceNode }); return cmd.run(-1) && cmd.exitCode() == 0; } bool xfs::check(Report& report, const QString& deviceNode) const { ExternalCommand cmd(report, QStringLiteral("xfs_repair"), { QStringLiteral("-v"), deviceNode }); return cmd.run(-1) && cmd.exitCode() == 0; } bool xfs::create(Report& report, const QString& deviceNode) { ExternalCommand cmd(report, QStringLiteral("mkfs.xfs"), { QStringLiteral("-f"), deviceNode }); return cmd.run(-1) && cmd.exitCode() == 0; } bool xfs::copy(Report& report, const QString& targetDeviceNode, const QString& sourceDeviceNode) const { ExternalCommand cmd(report, QStringLiteral("xfs_copy"), { sourceDeviceNode, targetDeviceNode }); // xfs_copy behaves a little strangely. It apparently kills itself at the end of main, causing QProcess // to report that it crashed. // See http://oss.sgi.com/archives/xfs/2004-11/msg00169.html // So we cannot rely on QProcess::exitStatus() and thus not on ExternalCommand::run() returning true. cmd.run(-1); return cmd.exitCode() == 0; } bool xfs::resize(Report& report, const QString& deviceNode, qint64) const { QTemporaryDir tempDir; if (!tempDir.isValid()) { report.line() << xi18nc("@info:progress", "Resizing XFS file system on partition %1 failed: Could not create temp dir.", deviceNode); return false; } bool rval = false; ExternalCommand mountCmd(report, QStringLiteral("mount"), { QStringLiteral("--verbose"), QStringLiteral("--types"), QStringLiteral("xfs"), deviceNode, tempDir.path() }); if (mountCmd.run(-1)) { ExternalCommand resizeCmd(report, QStringLiteral("xfs_growfs"), { tempDir.path() }); if (resizeCmd.run(-1) && resizeCmd.exitCode() == 0) rval = true; else report.line() << xi18nc("@info:progress", "Resizing XFS file system on partition %1 failed: xfs_growfs failed.", deviceNode); ExternalCommand unmountCmd(report, QStringLiteral("umount"), { tempDir.path() }); if (!unmountCmd.run(-1)) report.line() << xi18nc("@info:progress", "Resizing XFS file system on partition %1 failed: Unmount failed.", deviceNode); } else report.line() << xi18nc("@info:progress", "Resizing XFS file system on partition %1 failed: Initial mount failed.", deviceNode); return rval; } bool xfs::resizeOnline(Report& report, const QString& deviceNode, const QString& mountPoint, qint64) const { ExternalCommand resizeCmd(report, QStringLiteral("xfs_growfs"), { mountPoint }); if (resizeCmd.run(-1) && resizeCmd.exitCode() == 0) return true; report.line() << xi18nc("@info:progress", "Resizing XFS file system on partition %1 failed: xfs_growfs failed.", deviceNode); return false; } } diff --git a/src/plugins/dummy/dummypartitiontable.cpp b/src/plugins/dummy/dummypartitiontable.cpp index e83055e..8c21d25 100644 --- a/src/plugins/dummy/dummypartitiontable.cpp +++ b/src/plugins/dummy/dummypartitiontable.cpp @@ -1,124 +1,122 @@ /************************************************************************* * Copyright (C) 2010, 2012 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 .* *************************************************************************/ #include "plugins/dummy/dummypartitiontable.h" #include "plugins/dummy/dummypartition.h" #include "plugins/dummy/dummybackend.h" #include "core/partition.h" #include "core/device.h" #include "fs/filesystem.h" #include "util/report.h" -#include - DummyPartitionTable::DummyPartitionTable() : CoreBackendPartitionTable() { } DummyPartitionTable::~DummyPartitionTable() { } bool DummyPartitionTable::open() { return true; } bool DummyPartitionTable::commit(quint32 timeout) { Q_UNUSED(timeout); return true; } CoreBackendPartition* DummyPartitionTable::getExtendedPartition() { return new DummyPartition(); } CoreBackendPartition* DummyPartitionTable::getPartitionBySector(qint64 sector) { Q_UNUSED(sector); return new DummyPartition(); } QString DummyPartitionTable::createPartition(Report& report, const Partition& partition) { Q_UNUSED(report); Q_UNUSED(partition); return QStringLiteral("dummy"); } bool DummyPartitionTable::deletePartition(Report& report, const Partition& partition) { Q_UNUSED(report); Q_UNUSED(partition); return true; } bool DummyPartitionTable::updateGeometry(Report& report, const Partition& partition, qint64 sector_start, qint64 sector_end) { Q_UNUSED(report); Q_UNUSED(partition); Q_UNUSED(sector_start); Q_UNUSED(sector_end); return true; } bool DummyPartitionTable::clobberFileSystem(Report& report, const Partition& partition) { Q_UNUSED(report); Q_UNUSED(partition); return true; } bool DummyPartitionTable::resizeFileSystem(Report& report, const Partition& partition, qint64 newLength) { Q_UNUSED(report); Q_UNUSED(partition); Q_UNUSED(newLength); return true; } FileSystem::Type DummyPartitionTable::detectFileSystemBySector(Report& report, const Device& device, qint64 sector) { Q_UNUSED(report); Q_UNUSED(device); Q_UNUSED(sector); FileSystem::Type rval = FileSystem::Unknown; return rval; } bool DummyPartitionTable::setPartitionSystemType(Report& report, const Partition& partition) { Q_UNUSED(report); Q_UNUSED(partition); return true; } diff --git a/src/plugins/libparted/libpartedbackend.cpp b/src/plugins/libparted/libpartedbackend.cpp index a6276a4..dc5262a 100644 --- a/src/plugins/libparted/libpartedbackend.cpp +++ b/src/plugins/libparted/libpartedbackend.cpp @@ -1,552 +1,551 @@ /************************************************************************* * 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; } // -------------------------------------------------------------------------- // The following structs and the typedef come from libparted's internal gpt sources. // It's very unfortunate there is no public API to get at the first and last usable // sector for GPT a partition table, so this is the only (libparted) way to get that // information (another way would be to read the GPT header and parse the // information ourselves; if the libparted devs begin changing these internal // structs for each point release and break our code, we'll have to do just that). typedef struct { uint32_t time_low; uint16_t time_mid; uint16_t time_hi_and_version; uint8_t clock_seq_hi_and_reserved; uint8_t clock_seq_low; uint8_t node[6]; } /* __attribute__ ((packed)) */ efi_guid_t; struct __attribute__((packed)) _GPTDiskData { PedGeometry data_area; int entry_count; efi_guid_t uuid; }; typedef struct _GPTDiskData GPTDiskData; // -------------------------------------------------------------------------- /** Get the first sector a Partition may cover on a given Device @param d the Device in question @return the first sector usable by a Partition */ static quint64 firstUsableSector(const Device& d) { PedDevice* pedDevice = ped_device_get(d.deviceNode().toLatin1().constData()); PedDisk* pedDisk = pedDevice ? ped_disk_new(pedDevice) : nullptr; quint64 rval = 0; if (pedDisk) rval = pedDisk->dev->bios_geom.sectors; if (pedDisk && strcmp(pedDisk->type->name, "gpt") == 0) { GPTDiskData* gpt_disk_data = reinterpret_cast(pedDisk->disk_specific); PedGeometry* geom = reinterpret_cast(&gpt_disk_data->data_area); if (geom) rval = geom->start; else rval += 32; } ped_disk_destroy(pedDisk); return rval; } /** Get the last sector a Partition may cover on a given Device @param d the Device in question @return the last sector usable by a Partition */ static quint64 lastUsableSector(const Device& d) { PedDevice* pedDevice = ped_device_get(d.deviceNode().toLatin1().constData()); PedDisk* pedDisk = pedDevice ? ped_disk_new(pedDevice) : nullptr; quint64 rval = 0; if (pedDisk) rval = static_cast< quint64 >( pedDisk->dev->bios_geom.sectors ) * pedDisk->dev->bios_geom.heads * pedDisk->dev->bios_geom.cylinders - 1; if (pedDisk && strcmp(pedDisk->type->name, "gpt") == 0) { GPTDiskData* gpt_disk_data = reinterpret_cast(pedDisk->disk_specific); PedGeometry* geom = reinterpret_cast(&gpt_disk_data->data_area); if (geom) rval = geom->end; else rval -= 32; } ped_disk_destroy(pedDisk); return rval; } /** 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(PedDisk* pedDisk, const Partition& p) { Q_ASSERT(pedDisk); qint64 rval = -1; PedPartition* pedPartition = ped_disk_get_partition_by_sector(pedDisk, p.firstSector()); if (pedPartition) { PedFileSystem* pedFileSystem = ped_file_system_open(&pedPartition->geom); if (pedFileSystem) { if (PedConstraint* pedConstraint = ped_file_system_get_resize_constraint(pedFileSystem)) { rval = pedConstraint->min_size; ped_constraint_destroy(pedConstraint); } ped_file_system_close(pedFileSystem); } } return rval; } #endif /** Reads the sectors used in a FileSystem and stores the result in the Partition's FileSystem object. @param pedDisk pointer to pedDisk where the Partition and its FileSystem are @param p the Partition the FileSystem is on @param mountPoint mount point of the partition in question */ static void readSectorsUsed(PedDisk* pedDisk, const Device& d, Partition& p, const QString& mountPoint) { if (mountPoint != QString()) { const KDiskFreeSpaceInfo freeSpaceInfo = KDiskFreeSpaceInfo::freeSpaceInfo(mountPoint); // KDiskFreeSpaceInfo does not work with swap if (p.isMounted() && freeSpaceInfo.isValid() && mountPoint != QString() && p.fileSystem().type() != FileSystem::LinuxSwap) p.fileSystem().setSectorsUsed(freeSpaceInfo.used() / d.logicalSize()); else if (p.fileSystem().supportGetUsed() == FileSystem::cmdSupportFileSystem) p.fileSystem().setSectorsUsed(p.fileSystem().readUsedCapacity(p.deviceNode()) / d.logicalSize()); } #if defined LIBPARTED_FS_RESIZE_LIBRARY_SUPPORT else if (p.fileSystem().supportGetUsed() == FileSystem::cmdSupportCore) p.fileSystem().setSectorsUsed(readSectorsUsedLibParted(pedDisk, p)); #else Q_UNUSED(pedDisk); #endif } static PartitionTable::Flags activeFlags(PedPartition* p) { PartitionTable::Flags flags = PartitionTable::FlagNone; // We might get here with a pedPartition just picked up from libparted that is // unallocated. Libparted doesn't like it if we ask for flags for unallocated // space. if (p->num <= 0) return flags; for (const auto &flag : flagmap) if (ped_partition_is_flag_available(p, flag.pedFlag) && ped_partition_get_flag(p, flag.pedFlag)) flags |= flag.flag; return flags; } static PartitionTable::Flags availableFlags(PedPartition* p) { PartitionTable::Flags flags; // see above. if (p->num <= 0) return flags; for (const auto &flag : flagmap) { if (ped_partition_is_flag_available(p, flag.pedFlag)) { // Workaround: libparted claims the hidden flag is available for extended partitions, but // throws an error when we try to set or clear it. So skip this combination. Also see setFlag. if (p->type != PED_PARTITION_EXTENDED || flag.flag != PartitionTable::FlagHidden) flags |= flag.flag; } } return flags; } /** 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 } /** Scans a Device for Partitions. This method will scan a Device for all Partitions on it, detect the FileSystem for each Partition, try to determine the FileSystem usage, read the FileSystem label and store it all in newly created objects that are in the end added to the Device's PartitionTable. @param d Device @param pedDisk libparted pointer to the partition table */ void LibPartedBackend::scanDevicePartitions(Device& d, PedDisk* pedDisk) { Q_ASSERT(pedDisk); Q_ASSERT(d.partitionTable()); PedPartition* pedPartition = nullptr; QList partitions; while ((pedPartition = ped_disk_next_partition(pedDisk, pedPartition))) { if (pedPartition->num < 1) continue; PartitionRole::Roles r = PartitionRole::None; FileSystem::Type type = FileSystem::Unknown; char* pedPath = ped_partition_get_path(pedPartition); const QString partitionNode = pedPath ? QString::fromUtf8(pedPath) : QString(); free(pedPath); type = detectFileSystem(partitionNode); switch (pedPartition->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(pedPartition->geom.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(type, pedPartition->geom.start, pedPartition->geom.end); fs->scan(partitionNode); QString mountPoint; bool mounted; // libparted does not handle LUKS partitions if (fs->type() == FileSystem::Luks) { r |= PartitionRole::Luks; 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); } Partition* part = new Partition(parent, d, PartitionRole(r), fs, pedPartition->geom.start, pedPartition->geom.end, partitionNode, availableFlags(pedPartition), mountPoint, mounted, activeFlags(pedPartition)); if (!part->roles().has(PartitionRole::Luks)) readSectorsUsed(pedDisk, d, *part, mountPoint); if (fs->supportGetLabel() != FileSystem::cmdSupportNone) fs->setLabel(fs->readLabel(part->deviceNode())); // GPT partitions support partition labels and partition UUIDs if(d.partitionTable()->type() == PartitionTable::TableType::gpt) 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); } /** Create a Device for the given device_node and scan it for partitions. @param deviceNode the device node (e.g. "/dev/sda") @return the created Device object. callers need to free this. */ Device* LibPartedBackend::scanDevice(const QString& deviceNode) { PedDevice* pedDevice = ped_device_get(deviceNode.toLocal8Bit().constData()); if (pedDevice == nullptr) { Log(Log::warning) << xi18nc("@info:status", "Could not access device %1", deviceNode); return nullptr; } Log(Log::information) << xi18nc("@info:status", "Device found: %1", QString::fromUtf8(pedDevice->model)); DiskDevice* d = new DiskDevice(QString::fromUtf8(pedDevice->model), QString::fromUtf8(pedDevice->path), pedDevice->bios_geom.heads, pedDevice->bios_geom.sectors, pedDevice->bios_geom.cylinders, pedDevice->sector_size); PedDisk* pedDisk = ped_disk_new(pedDevice); if (pedDisk) { const PartitionTable::TableType type = PartitionTable::nameToTableType(QString::fromUtf8(pedDisk->type->name)); CoreBackend::setPartitionTableForDevice(*d, new PartitionTable(type, firstUsableSector(*d), lastUsableSector(*d))); CoreBackend::setPartitionTableMaxPrimaries(*d->partitionTable(), ped_disk_get_max_primary_partition_count(pedDisk)); scanDevicePartitions(*d, pedDisk); } ped_device_destroy(pedDevice); 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 TODO: add another bool option for loopDevices "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/plugins/libparted/libparteddevice.cpp b/src/plugins/libparted/libparteddevice.cpp index 5a4b33b..f508017 100644 --- a/src/plugins/libparted/libparteddevice.cpp +++ b/src/plugins/libparted/libparteddevice.cpp @@ -1,130 +1,128 @@ /************************************************************************* * Copyright (C) 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 "plugins/libparted/libparteddevice.h" #include "plugins/libparted/libpartedpartitiontable.h" #include "core/partitiontable.h" #include "util/globallog.h" #include "util/report.h" #include -#include - LibPartedDevice::LibPartedDevice(const QString& deviceNode) : CoreBackendDevice(deviceNode), m_PedDevice(nullptr) { } LibPartedDevice::~LibPartedDevice() { if (pedDevice()) close(); } bool LibPartedDevice::open() { Q_ASSERT(pedDevice() == nullptr); if (pedDevice()) return false; m_PedDevice = ped_device_get(deviceNode().toLatin1().constData()); return m_PedDevice != nullptr; } bool LibPartedDevice::openExclusive() { bool rval = open() && ped_device_open(pedDevice()); if (rval) setExclusive(true); return rval; } bool LibPartedDevice::close() { Q_ASSERT(pedDevice()); if (pedDevice() && isExclusive()) { ped_device_close(pedDevice()); setExclusive(false); } m_PedDevice = nullptr; return true; } CoreBackendPartitionTable* LibPartedDevice::openPartitionTable() { CoreBackendPartitionTable* ptable = new LibPartedPartitionTable(pedDevice()); if (ptable == nullptr || !ptable->open()) { delete ptable; ptable = nullptr; } return ptable; } bool LibPartedDevice::createPartitionTable(Report& report, const PartitionTable& ptable) { PedDiskType* pedDiskType = ped_disk_type_get(ptable.typeName().toLatin1().constData()); if (pedDiskType == nullptr) { report.line() << xi18nc("@info:progress", "Creating partition table failed: Could not retrieve partition table type \"%1\" for %2.", ptable.typeName(), deviceNode()); return false; } PedDevice* dev = ped_device_get(deviceNode().toLatin1().constData()); if (dev == nullptr) { report.line() << xi18nc("@info:progress", "Creating partition table failed: Could not open backend device %1.", deviceNode()); return false; } PedDisk* disk = ped_disk_new_fresh(dev, pedDiskType); if (disk == nullptr) { report.line() << xi18nc("@info:progress", "Creating partition table failed: Could not create a new partition table in the backend for device %1.", deviceNode()); return false; } return LibPartedPartitionTable::commit(disk); } bool LibPartedDevice::readSectors(void* buffer, qint64 offset, qint64 numSectors) { if (!isExclusive()) return false; return ped_device_read(pedDevice(), buffer, offset, numSectors); } bool LibPartedDevice::writeSectors(void* buffer, qint64 offset, qint64 numSectors) { if (!isExclusive()) return false; return ped_device_write(pedDevice(), buffer, offset, numSectors); } diff --git a/src/util/htmlreport.cpp b/src/util/htmlreport.cpp index 02b4022..20c8f7f 100644 --- a/src/util/htmlreport.cpp +++ b/src/util/htmlreport.cpp @@ -1,95 +1,94 @@ /************************************************************************* * Copyright (C) 2008 by Volker Lanz * * Copyright (C) 2016 by Andrius Štikonas * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License as * * published by the Free Software Foundation; either version 3 of * * the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see .* *************************************************************************/ #include "util/htmlreport.h" #include "backend/corebackend.h" #include "backend/corebackendmanager.h" #include #include #include #include #include #include #include #include #include -#include QString HtmlReport::tableLine(const QString& label, const QString contents) { QString rval; QTextStream s(&rval); s << "\n" << QStringLiteral("%1\n").arg(QString(label).toHtmlEscaped()) << QStringLiteral("%1\n").arg(QString(contents).toHtmlEscaped()) << "\n"; s.flush(); return rval; } QString HtmlReport::header() { QString rval; QTextStream s(&rval); s << "\n" "\n" "\n" " " << i18n("%1: SMART Status Report", QGuiApplication::applicationDisplayName().toHtmlEscaped()) << "\n" " \n" "\n\n" "\n"; s << "

" << i18n("%1: SMART Status Report", QGuiApplication::applicationDisplayName().toHtmlEscaped()) << "

\n\n"; struct utsname info; uname(&info); const QString unameString = QString::fromUtf8(info.sysname) + QStringLiteral(" ") + QString::fromUtf8(info.nodename) + QStringLiteral(" ") + QString::fromUtf8(info.release) + QStringLiteral(" ") + QString::fromUtf8(info.version) + QStringLiteral(" ") + QString::fromUtf8(info.machine); s << "\n" << tableLine(i18n("Date:"), QLocale().toString(QDateTime::currentDateTime(), QLocale::ShortFormat)) << tableLine(i18n("Program version:"), QCoreApplication::applicationVersion()) << tableLine(i18n("Backend:"), QStringLiteral("%1 (%2)").arg(CoreBackendManager::self()->backend()->id()).arg(CoreBackendManager::self()->backend()->version())) << tableLine(i18n("KDE Frameworks version:"), QStringLiteral(KIO_VERSION_STRING)) << tableLine(i18n("Machine:"), unameString) << "
\n
\n"; s << "\n"; s.flush(); return rval; } QString HtmlReport::footer() { return QStringLiteral("\n\n\n\n"); } diff --git a/src/util/report.cpp b/src/util/report.cpp index 30b9cd4..e688d32 100644 --- a/src/util/report.cpp +++ b/src/util/report.cpp @@ -1,165 +1,164 @@ /************************************************************************* * Copyright (C) 2008 by Volker Lanz * * Copyright (C) 2016 by Andrius Štikonas * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License as * * published by the Free Software Foundation; either version 3 of * * the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see .* *************************************************************************/ #include "util/report.h" #include "util/htmlreport.h" #include "backend/corebackend.h" #include "backend/corebackendmanager.h" #include #include -#include /** Creates a new Report instance. @param p pointer to the parent instance. May be nullptr ig this is a new root Report. @param cmd the command */ Report::Report(Report* p, const QString& cmd) : QObject(), m_Parent(p), m_Children(), m_Command(cmd), m_Output(), m_Status() { } /** Destroys a Report instance and all its children. */ Report::~Report() { qDeleteAll(children()); } /** Creates a new child for this Report and appends it to its list of children. @param cmd the command @return pointer to a new Report child */ Report* Report::newChild(const QString& cmd) { Report* r = new Report(this, cmd); m_Children.append(r); return r; } /** @return the Report converted to HTML @see toText() */ QString Report::toHtml() const { QString s; if (parent() == root()) s += QStringLiteral("
\n"); else if (parent() != nullptr) s += QStringLiteral("
\n"); if (!command().isEmpty()) s += QStringLiteral("\n") + command().toHtmlEscaped() + QStringLiteral("\n\n"); if (!output().isEmpty()) s += QStringLiteral("
") + output().toHtmlEscaped() + QStringLiteral("
\n\n"); if (children().size() == 0) s += QStringLiteral("
\n"); else for (const auto &child : children()) s += child->toHtml(); if (!status().isEmpty()) s += QStringLiteral("") + status().toHtmlEscaped() + QStringLiteral("
\n\n"); if (parent() != nullptr) s += QStringLiteral("
\n\n"); return s; } /** @return the Report converted to plain text @see toHtml() */ QString Report::toText() const { QString s; if (!command().isEmpty()) { s += QStringLiteral("==========================================================================================\n"); s += command() + QStringLiteral("\n"); s += QStringLiteral("==========================================================================================\n"); } if (!output().isEmpty()) s += output() + QStringLiteral("\n"); for (const auto &child : children()) s += child->toText(); return s; } /** Adds a string to this Report's output. This is usually not what you want. In most cases, you will want to create a new child Report. @param s the string to add to the output @see newChild() */ void Report::addOutput(const QString& s) { m_Output += s; root()->emitOutputChanged(); } void Report::emitOutputChanged() { emit outputChanged(); } /** @return the root Report */ Report* Report::root() { Report* rval = this; while (rval->parent() != nullptr) rval = rval->parent(); return rval; } /** @overload */ const Report* Report::root() const { const Report* rval = this; while (rval->parent() != nullptr) rval = rval->parent(); return rval; } /** @return a Report line to write to */ ReportLine Report::line() { return ReportLine(*this); }