diff --git a/src/fs/CMakeLists.txt b/src/fs/CMakeLists.txt index 93661a6..147f83d 100644 --- a/src/fs/CMakeLists.txt +++ b/src/fs/CMakeLists.txt @@ -1,71 +1,73 @@ set(FS_SRC + fs/bitlocker.cpp fs/btrfs.cpp fs/exfat.cpp fs/ext2.cpp fs/ext3.cpp fs/ext4.cpp fs/extended.cpp fs/f2fs.cpp fs/fat12.cpp fs/fat16.cpp fs/fat32.cpp fs/filesystem.cpp fs/filesystemfactory.cpp fs/hfs.cpp fs/hfsplus.cpp fs/hpfs.cpp fs/iso9660.cpp fs/jfs.cpp fs/linuxraidmember.cpp fs/linuxswap.cpp fs/luks.cpp fs/luks2.cpp fs/lvm2_pv.cpp fs/nilfs2.cpp fs/ntfs.cpp fs/ocfs2.cpp fs/reiser4.cpp fs/reiserfs.cpp fs/udf.cpp fs/ufs.cpp fs/unformatted.cpp fs/unknown.cpp fs/xfs.cpp fs/zfs.cpp ) set(FS_LIB_HDRS + fs/bitlocker.h fs/btrfs.h fs/exfat.h fs/ext2.h fs/ext3.h fs/ext4.h fs/extended.h fs/f2fs.h fs/fat12.h fs/fat16.h fs/fat32.h fs/filesystem.h fs/filesystemfactory.h fs/hfs.h fs/hfsplus.h fs/hpfs.h fs/iso9660.h fs/jfs.h fs/linuxraidmember.h fs/linuxswap.h fs/luks.h fs/luks2.h fs/lvm2_pv.h fs/nilfs2.h fs/ntfs.h fs/ocfs2.h fs/reiser4.h fs/reiserfs.h fs/udf.h fs/ufs.h fs/unformatted.h fs/unknown.h fs/xfs.h fs/zfs.h ) diff --git a/src/fs/bitlocker.cpp b/src/fs/bitlocker.cpp new file mode 100644 index 0000000..15280cf --- /dev/null +++ b/src/fs/bitlocker.cpp @@ -0,0 +1,30 @@ +/************************************************************************* + * Copyright (C) 2019 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/bitlocker.h" + +namespace FS +{ +FileSystem::CommandSupportType bitlocker::m_Move = FileSystem::cmdSupportCore; +FileSystem::CommandSupportType bitlocker::m_Copy = FileSystem::cmdSupportCore; +FileSystem::CommandSupportType bitlocker::m_Backup = FileSystem::cmdSupportCore; + +bitlocker::bitlocker(qint64 firstsector, qint64 lastsector, qint64 sectorsused, const QString& label) : + FileSystem(firstsector, lastsector, sectorsused, label, FileSystem::Type::BitLocker) +{ +} +} diff --git a/src/fs/bitlocker.h b/src/fs/bitlocker.h new file mode 100644 index 0000000..493eb4d --- /dev/null +++ b/src/fs/bitlocker.h @@ -0,0 +1,61 @@ +/************************************************************************* + * Copyright (C) 2019 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 .* + *************************************************************************/ + +#ifndef KPMCORE_BITLOCKER_H +#define KPMCORE_BITLOCKER_H + +#include "util/libpartitionmanagerexport.h" + +#include "fs/filesystem.h" + +#include + +class QString; + +namespace FS +{ +/** A Bitlocker encrypted file system. + @author Andrius Štikonas + */ +class LIBKPMCORE_EXPORT bitlocker : public FileSystem +{ +public: + bitlocker(qint64 firstsector, qint64 lastsector, qint64 sectorsused, const QString& label); + +public: + CommandSupportType supportMove() const override { + return m_Move; + } + CommandSupportType supportCopy() const override { + return m_Copy; + } + CommandSupportType supportBackup() const override { + return m_Backup; + } + + bool supportToolFound() const override { + return true; + } + +public: + static CommandSupportType m_Move; + static CommandSupportType m_Copy; + static CommandSupportType m_Backup; +}; +} + +#endif diff --git a/src/fs/filesystem.cpp b/src/fs/filesystem.cpp index 8de5ee4..c304bd2 100644 --- a/src/fs/filesystem.cpp +++ b/src/fs/filesystem.cpp @@ -1,637 +1,639 @@ /************************************************************************* * Copyright (C) 2012 by Volker Lanz * * Copyright (C) 2015 by Teo Mrnjavac * * Copyright (C) 2016-2018 by Andrius Štikonas * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License as * * published by the Free Software Foundation; either version 3 of * * the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see .* *************************************************************************/ #include "core/fstab.h" #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 #include const std::vector FileSystem::defaultColorCode = { { QColor( 220,205,175 ), // unknown QColor( 187,249,207 ), // extended QColor( 102,121,150 ), // ext2 QColor( 122,145,180 ), // ext3 QColor( 143,170,210 ), // ext4 QColor( 155,155,130 ), // swap QColor( 204,179,215 ), // fat16 QColor( 229,201,240 ), // fat32 QColor( 244,214,255 ), // ntfs QColor( 216,220,135 ), // reiser QColor( 251,255,157 ), // reiser4 QColor( 200,255,254 ), // xfs QColor( 137,200,198 ), // jfs QColor( 210,136,142 ), // hfs QColor( 240,165,171 ), // hfs+ QColor( 151,220,134 ), // ufs QColor( 220,205,175 ), // unformatted QColor( 173,205,255 ), // btrfs QColor( 176,155,185 ), // hpfs QColor( 170,30,77 ), // luks QColor( 96,140,85 ), // ocfs2 QColor( 33,137,108 ), // zfs QColor( 250,230,255 ), // exfat QColor( 242,155,104 ), // nilfs2 QColor( 160,210,180 ), // lvm2 pv QColor( 255,170,0 ), // f2fs QColor( 170,120,255 ), // udf QColor( 177,82,69 ), // iso9660 QColor( 223,39,104 ), // luks2 - QColor( 204,179,255 ), // fat12 - QColor( 255,100,100 ) // linux_raid_member + QColor( 204,179,255 ), // fat12 + QColor( 255,100,100 ), // linux_raid_member + QColor( 110,20,50 ), // bitlocker } }; struct FileSystemPrivate { FileSystem::Type m_Type; qint64 m_FirstSector; qint64 m_LastSector; qint64 m_SectorSize; qint64 m_SectorsUsed; QString m_Label; QString m_UUID; }; /** 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 label the FileSystem label @param type the FileSystem type */ FileSystem::FileSystem(qint64 firstsector, qint64 lastsector, qint64 sectorsused, const QString& label, FileSystem::Type type) : d(std::make_unique()) { d->m_Type = type; d->m_FirstSector = firstsector; d->m_LastSector = lastsector; d->m_SectorsUsed = sectorsused; d->m_Label = label; d->m_UUID = QString(); } FileSystem::~FileSystem() { } /** 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; } FileSystem::Type FileSystem::detectFileSystem(const QString& partitionPath) { return CoreBackendManager::self()->backend()->detectFileSystem(partitionPath); } QString FileSystem::detectMountPoint(FileSystem* fs, const QString& partitionPath) { if (fs->type() == FileSystem::Type::Lvm2_PV) return FS::lvm2_pv::getVGName(partitionPath); if (partitionPath.isEmpty()) // Happens when during initial scan LUKS is closed return QString(); QStringList mountPoints; QFileInfo partitionPathFileInfo(partitionPath); QString partitionCanonicalPath = partitionPathFileInfo.canonicalFilePath(); const QList mountedVolumes = QStorageInfo::mountedVolumes(); for (const QStorageInfo &storage : mountedVolumes) { if (partitionCanonicalPath == QFileInfo(QString::fromLocal8Bit(storage.device())).canonicalFilePath() ) { mountPoints.append(storage.rootPath()); } } mountPoints.append(possibleMountPoints(partitionPath)); return mountPoints.isEmpty() ? QString() : mountPoints.first(); } bool FileSystem::detectMountStatus(FileSystem* fs, const QString& partitionPath) { bool mounted = false; if (fs->type() == FileSystem::Type::Lvm2_PV) { mounted = FS::lvm2_pv::getVGName(partitionPath) != QString(); } 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 CoreBackendManager::self()->backend()->readLabel(deviceNode); } /** 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; } /** Creates a new FileSystem with a specified Label @param report Report to write status information to @param deviceNode the device node for the Partition to create the FileSystem on @param label the new label for the FileSystem @return true if successful */ bool FileSystem::createWithLabel(Report& report, const QString& deviceNode, const QString& label) { Q_UNUSED(report) Q_UNUSED(deviceNode) Q_UNUSED(label) 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; } /** 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 mountPoint the mount point where FileSystem is mounted on @param newLabel the new label for the FileSystem @return true on success */ bool FileSystem::writeLabelOnline(Report& report, const QString& deviceNode, const QString& mountPoint, const QString& newLabel) { Q_UNUSED(report) Q_UNUSED(deviceNode) Q_UNUSED(mountPoint) 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 CoreBackendManager::self()->backend()->readUUID(deviceNode); } /** 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::Unit::Byte, Capacity::Unit::MiB); } /** @return the maximum capacity valid for this FileSystem in bytes */ qint64 FileSystem::maxCapacity() const { return Capacity::unitFactor(Capacity::Unit::Byte, Capacity::Unit::EiB); } /** @return the maximum label length valid for this FileSystem */ int FileSystem::maxLabelLength() const { return 16; } /** Validates the label for this FileSystem * @param parent the parent widget passed to the QObject constructor * @return QValidator to validate the file system label line edit input */ QValidator* FileSystem::labelValidator(QObject *parent) const { Q_UNUSED(parent) return nullptr; } /** @return this FileSystem's type as printable name */ QString FileSystem::name(const QStringList& languages) const { return nameForType(type(), languages); } FileSystem::Type FileSystem::type() const { return d->m_Type; } /** @return a pointer to a QString C array with all FileSystem names */ static const KLocalizedString* typeNames() { static const KLocalizedString s[] = { kxi18nc("@item filesystem name", "unknown"), kxi18nc("@item filesystem name", "extended"), kxi18nc("@item filesystem name", "ext2"), kxi18nc("@item filesystem name", "ext3"), kxi18nc("@item filesystem name", "ext4"), kxi18nc("@item filesystem name", "linuxswap"), kxi18nc("@item filesystem name", "fat16"), kxi18nc("@item filesystem name", "fat32"), kxi18nc("@item filesystem name", "ntfs"), kxi18nc("@item filesystem name", "reiser"), kxi18nc("@item filesystem name", "reiser4"), kxi18nc("@item filesystem name", "xfs"), kxi18nc("@item filesystem name", "jfs"), kxi18nc("@item filesystem name", "hfs"), kxi18nc("@item filesystem name", "hfsplus"), kxi18nc("@item filesystem name", "ufs"), kxi18nc("@item filesystem name", "unformatted"), kxi18nc("@item filesystem name", "btrfs"), kxi18nc("@item filesystem name", "hpfs"), kxi18nc("@item filesystem name", "luks"), kxi18nc("@item filesystem name", "ocfs2"), kxi18nc("@item filesystem name", "zfs"), kxi18nc("@item filesystem name", "exfat"), kxi18nc("@item filesystem name", "nilfs2"), kxi18nc("@item filesystem name", "lvm2 pv"), kxi18nc("@item filesystem name", "f2fs"), kxi18nc("@item filesystem name", "udf"), kxi18nc("@item filesystem name", "iso9660"), kxi18nc("@item filesystem name", "luks2"), kxi18nc("@item filesystem name", "fat12"), kxi18nc("@item filesystem name", "linux_raid_member"), + kxi18nc("@item filesystem name", "BitLocker"), }; 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, const QStringList& languages) { Q_ASSERT(t < Type::__lastType); return typeNames()[static_cast(t)].toString(languages); } /** @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, const QStringList& languages ) { for (quint32 i = 0; i < static_cast(Type::__lastType); i++) if (typeNames()[i].toString(languages) == s) return static_cast(i); return Type::Unknown; } /** @return a QList of all known types */ QList FileSystem::types() { QList result; int i = static_cast(Type::Ext2); // first "real" filesystem while (i != static_cast(Type::__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; } qint64 FileSystem::firstSector() const { return d->m_FirstSector; } qint64 FileSystem::lastSector() const { return d->m_LastSector; } bool FileSystem::findExternal(const QString& cmdName, const QStringList& args, int expectedCode) { QString cmdFullPath = QStandardPaths::findExecutable(cmdName); if (cmdFullPath.isEmpty()) cmdFullPath = QStandardPaths::findExecutable(cmdName, { QStringLiteral("/sbin/"), QStringLiteral("/usr/sbin/"), QStringLiteral("/usr/local/sbin/") }); if (cmdFullPath.isEmpty()) return false; ExternalCommand cmd(cmdFullPath, 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(); } void FileSystem::setFirstSector(qint64 s) { d->m_FirstSector = s; } void FileSystem::setLastSector(qint64 s) { d->m_LastSector = s; } const QString& FileSystem::label() const { return d->m_Label; } qint64 FileSystem::sectorSize() const { return d->m_SectorSize; } qint64 FileSystem::sectorsUsed() const { return d->m_SectorsUsed; } const QString& FileSystem::uuid() const { return d->m_UUID; } void FileSystem::setSectorSize(qint64 s) { d->m_SectorSize = s; } void FileSystem::setSectorsUsed(qint64 s) { d->m_SectorsUsed = s; } void FileSystem::setLabel(const QString& s) { d->m_Label = s; } void FileSystem::setUUID(const QString& s) { d->m_UUID = s; } diff --git a/src/fs/filesystem.h b/src/fs/filesystem.h index a411b24..674773c 100644 --- a/src/fs/filesystem.h +++ b/src/fs/filesystem.h @@ -1,292 +1,293 @@ /************************************************************************* * Copyright (C) 2012 by Volker Lanz * * Copyright (C) 2015 by Teo Mrnjavac * * Copyright (C) 2016-2018 by Andrius Štikonas * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License as * * published by the Free Software Foundation; either version 3 of * * the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see .* *************************************************************************/ #ifndef KPMCORE_FILESYSTEM_H #define KPMCORE_FILESYSTEM_H #include "util/libpartitionmanagerexport.h" #include #include #include #include #include #include #include class QColor; class QValidator; class Device; class Report; struct FileSystemPrivate; /** 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 : int { Unknown, Extended, Ext2, Ext3, Ext4, LinuxSwap, Fat16, Fat32, Ntfs, ReiserFS, Reiser4, Xfs, Jfs, Hfs, HfsPlus, Ufs, Unformatted, Btrfs, Hpfs, Luks, Ocfs2, Zfs, Exfat, Nilfs2, Lvm2_PV, F2fs, Udf, Iso9660, Luks2, Fat12, LinuxRaidMember, + BitLocker, __lastType }; /** 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::vector defaultColorCode; Q_DECLARE_FLAGS(CommandSupportTypes, CommandSupportType) protected: FileSystem(qint64 firstsector, qint64 lastsector, qint64 sectorsused, const QString& label, FileSystem::Type type); 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 createWithLabel(Report& report, const QString& deviceNode, const QString& label); 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 writeLabelOnline(Report& report, const QString& deviceNode, const QString& mountPoint, 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 supportCreateWithLabel() 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 supportCheckOnline() 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 int maxLabelLength() const; virtual QValidator* labelValidator(QObject *parent = nullptr) const; virtual SupportTool supportToolName() const; virtual bool supportToolFound() const; /** * Returns the (possibly translated) name of the type of this filesystem. * @see nameForType() */ virtual QString name(const QStringList& languages = {}) const; /** * @return the FileSystem's type */ virtual FileSystem::Type type() const; /** * Returns the name of the given filesystem type. If @p languages * is an empty list, uses the translated name of the filesystem, * in the default locale. If languages is {"C"}, an untranslated * string is returned. Passing other lists of language identifiers * may yield unpredicatable results -- see the documentation of * KLocalizedString() for details on the way toString() is used. * Returns a single QString with the name. */ static QString nameForType(FileSystem::Type t, const QStringList& languages = {}); static QList types(); static FileSystem::Type typeForName(const QString& s, const QStringList& languages = {}); 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); /**< @return the FileSystem's first sector */ qint64 firstSector() const; /**< @return the FileSystem's last sector */ qint64 lastSector() const; qint64 length() const { return lastSector() - firstSector() + 1; /**< @return the FileSystem's length */ } qint64 firstByte() const { return firstSector() * sectorSize(); /**< @return the FileSystem's first byte */ } qint64 lastByte() const { return firstByte() + length() * sectorSize() - 1; /**< @return the FileSystem's last byte */ } /**< @param s the new first sector */ void setFirstSector(qint64 s); /**< @param s the new last sector */ void setLastSector(qint64 s); void move(qint64 newStartSector); /**< @return the FileSystem's label */ const QString& label() const; /**< @return the sector size in the underlying Device */ qint64 sectorSize() const; /**< @return the sectors in use on the FileSystem */ qint64 sectorsUsed() const; /**< @return the FileSystem's UUID */ const QString& uuid() const; /**< @param s the new value for sector size */ void setSectorSize(qint64 s); /**< @param s the new value for sectors in use */ void setSectorsUsed(qint64 s); /**< @param s the new label */ void setLabel(const QString& s); /**< @param s the new UUID */ void setUUID(const QString& s); protected: static bool findExternal(const QString& cmdName, const QStringList& args = QStringList(), int exptectedCode = 1); std::unique_ptr d; }; Q_DECLARE_OPERATORS_FOR_FLAGS(FileSystem::CommandSupportTypes) #endif diff --git a/src/fs/filesystemfactory.cpp b/src/fs/filesystemfactory.cpp index 6f99054..5e3658b 100644 --- a/src/fs/filesystemfactory.cpp +++ b/src/fs/filesystemfactory.cpp @@ -1,180 +1,183 @@ /************************************************************************* * Copyright (C) 2012 by Volker Lanz * * Copyright (C) 2016 by Andrius Štikonas * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License as * * published by the Free Software Foundation; either version 3 of * * the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see .* *************************************************************************/ #include "fs/filesystemfactory.h" #include "fs/filesystem.h" +#include "fs/bitlocker.h" #include "fs/btrfs.h" #include "fs/exfat.h" #include "fs/ext2.h" #include "fs/ext3.h" #include "fs/ext4.h" #include "fs/extended.h" #include "fs/f2fs.h" #include "fs/fat12.h" #include "fs/fat16.h" #include "fs/fat32.h" #include "fs/hfs.h" #include "fs/hfsplus.h" #include "fs/hpfs.h" #include "fs/iso9660.h" #include "fs/jfs.h" #include "fs/linuxraidmember.h" #include "fs/linuxswap.h" #include "fs/luks.h" #include "fs/luks2.h" #include "fs/lvm2_pv.h" #include "fs/nilfs2.h" #include "fs/ntfs.h" #include "fs/ocfs2.h" #include "fs/reiser4.h" #include "fs/reiserfs.h" #include "fs/udf.h" #include "fs/ufs.h" #include "fs/unformatted.h" #include "fs/unknown.h" #include "fs/xfs.h" #include "fs/zfs.h" #include "backend/corebackendmanager.h" #include "backend/corebackend.h" FileSystemFactory::FileSystems FileSystemFactory::m_FileSystems; /** Initializes the instance. */ void FileSystemFactory::init() { qDeleteAll(m_FileSystems); m_FileSystems.clear(); + m_FileSystems.insert(FileSystem::Type::BitLocker, new FS::btrfs(-1, -1, -1, QString())); m_FileSystems.insert(FileSystem::Type::Btrfs, new FS::btrfs(-1, -1, -1, QString())); m_FileSystems.insert(FileSystem::Type::Exfat, new FS::exfat(-1, -1, -1, QString())); m_FileSystems.insert(FileSystem::Type::Ext2, new FS::ext2(-1, -1, -1, QString())); m_FileSystems.insert(FileSystem::Type::Ext3, new FS::ext3(-1, -1, -1, QString())); m_FileSystems.insert(FileSystem::Type::Ext4, new FS::ext4(-1, -1, -1, QString())); m_FileSystems.insert(FileSystem::Type::Extended, new FS::extended(-1, -1, -1, QString())); m_FileSystems.insert(FileSystem::Type::F2fs, new FS::f2fs(-1, -1, -1, QString())); m_FileSystems.insert(FileSystem::Type::Fat12, new FS::fat12(-1, -1, -1, QString())); m_FileSystems.insert(FileSystem::Type::Fat16, new FS::fat16(-1, -1, -1, QString())); m_FileSystems.insert(FileSystem::Type::Fat32, new FS::fat32(-1, -1, -1, QString())); m_FileSystems.insert(FileSystem::Type::Hfs, new FS::hfs(-1, -1, -1, QString())); m_FileSystems.insert(FileSystem::Type::HfsPlus, new FS::hfsplus(-1, -1, -1, QString())); m_FileSystems.insert(FileSystem::Type::Hpfs, new FS::hpfs(-1, -1, -1, QString())); m_FileSystems.insert(FileSystem::Type::Iso9660, new FS::iso9660(-1, -1, -1, QString())); m_FileSystems.insert(FileSystem::Type::Jfs, new FS::jfs(-1, -1, -1, QString())); m_FileSystems.insert(FileSystem::Type::LinuxRaidMember, new FS::linuxraidmember(-1, -1, -1, QString())); m_FileSystems.insert(FileSystem::Type::LinuxSwap, new FS::linuxswap(-1, -1, -1, QString())); m_FileSystems.insert(FileSystem::Type::Luks, new FS::luks(-1, -1, -1, QString())); m_FileSystems.insert(FileSystem::Type::Luks2, new FS::luks2(-1, -1, -1, QString())); m_FileSystems.insert(FileSystem::Type::Lvm2_PV, new FS::lvm2_pv(-1, -1, -1, QString())); m_FileSystems.insert(FileSystem::Type::Nilfs2, new FS::nilfs2(-1, -1, -1, QString())); m_FileSystems.insert(FileSystem::Type::Ntfs, new FS::ntfs(-1, -1, -1, QString())); m_FileSystems.insert(FileSystem::Type::Ocfs2, new FS::ocfs2(-1, -1, -1, QString())); m_FileSystems.insert(FileSystem::Type::ReiserFS, new FS::reiserfs(-1, -1, -1, QString())); m_FileSystems.insert(FileSystem::Type::Reiser4, new FS::reiser4(-1, -1, -1, QString())); m_FileSystems.insert(FileSystem::Type::Udf, new FS::udf(-1, -1, -1, QString())); m_FileSystems.insert(FileSystem::Type::Ufs, new FS::ufs(-1, -1, -1, QString())); m_FileSystems.insert(FileSystem::Type::Unformatted, new FS::unformatted(-1, -1, -1, QString())); m_FileSystems.insert(FileSystem::Type::Unknown, new FS::unknown(-1, -1, -1, QString())); m_FileSystems.insert(FileSystem::Type::Xfs, new FS::xfs(-1, -1, -1, QString())); m_FileSystems.insert(FileSystem::Type::Zfs, new FS::zfs(-1, -1, -1, QString())); for (const auto &fs : FileSystemFactory::map()) fs->init(); CoreBackendManager::self()->backend()->initFSSupport(); } /** Creates a new FileSystem @param t the FileSystem's type @param firstsector the FileSystem's first sector relative to the Device @param lastsector the FileSystem's last sector relative to the Device @param sectorsused the number of used sectors in the FileSystem @param label the FileSystem's label @return pointer to the newly created FileSystem object or nullptr if FileSystem could not be created */ FileSystem* FileSystemFactory::create(FileSystem::Type t, qint64 firstsector, qint64 lastsector, qint64 sectorSize, qint64 sectorsused, const QString& label, const QString& uuid) { FileSystem* fs = nullptr; switch (t) { + case FileSystem::Type::BitLocker: fs = new FS::bitlocker(firstsector, lastsector, sectorsused, label); break; case FileSystem::Type::Btrfs: fs = new FS::btrfs(firstsector, lastsector, sectorsused, label); break; case FileSystem::Type::Exfat: fs = new FS::exfat(firstsector, lastsector, sectorsused, label); break; case FileSystem::Type::Ext2: fs = new FS::ext2(firstsector, lastsector, sectorsused, label); break; case FileSystem::Type::Ext3: fs = new FS::ext3(firstsector, lastsector, sectorsused, label); break; case FileSystem::Type::Ext4: fs = new FS::ext4(firstsector, lastsector, sectorsused, label); break; case FileSystem::Type::Extended: fs = new FS::extended(firstsector, lastsector, sectorsused, label); break; case FileSystem::Type::F2fs: fs = new FS::f2fs(firstsector, lastsector, sectorsused, label); break; case FileSystem::Type::Fat12: fs = new FS::fat12(firstsector, lastsector, sectorsused, label); break; case FileSystem::Type::Fat16: fs = new FS::fat16(firstsector, lastsector, sectorsused, label); break; case FileSystem::Type::Fat32: fs = new FS::fat32(firstsector, lastsector, sectorsused, label); break; case FileSystem::Type::Hfs: fs = new FS::hfs(firstsector, lastsector, sectorsused, label); break; case FileSystem::Type::HfsPlus: fs = new FS::hfsplus(firstsector, lastsector, sectorsused, label); break; case FileSystem::Type::Hpfs: fs = new FS::hpfs(firstsector, lastsector, sectorsused, label); break; case FileSystem::Type::Iso9660: fs = new FS::iso9660(firstsector, lastsector, sectorsused, label); break; case FileSystem::Type::Jfs: fs = new FS::jfs(firstsector, lastsector, sectorsused, label); break; case FileSystem::Type::LinuxRaidMember: fs = new FS::linuxraidmember(firstsector, lastsector, sectorsused, label); break; case FileSystem::Type::LinuxSwap: fs = new FS::linuxswap(firstsector, lastsector, sectorsused, label); break; case FileSystem::Type::Luks: fs = new FS::luks(firstsector, lastsector, sectorsused, label); break; case FileSystem::Type::Luks2: fs = new FS::luks2(firstsector, lastsector, sectorsused, label); break; case FileSystem::Type::Lvm2_PV: fs = new FS::lvm2_pv(firstsector, lastsector, sectorsused, label); break; case FileSystem::Type::Nilfs2: fs = new FS::nilfs2(firstsector, lastsector, sectorsused, label); break; case FileSystem::Type::Ntfs: fs = new FS::ntfs(firstsector, lastsector, sectorsused, label); break; case FileSystem::Type::Ocfs2: fs = new FS::ocfs2(firstsector, lastsector, sectorsused, label); break; case FileSystem::Type::ReiserFS: fs = new FS::reiserfs(firstsector, lastsector, sectorsused, label); break; case FileSystem::Type::Reiser4: fs = new FS::reiser4(firstsector, lastsector, sectorsused, label); break; case FileSystem::Type::Udf: fs = new FS::udf(firstsector, lastsector, sectorsused, label); break; case FileSystem::Type::Ufs: fs = new FS::ufs(firstsector, lastsector, sectorsused, label); break; case FileSystem::Type::Unformatted: fs = new FS::unformatted(firstsector, lastsector, sectorsused, label); break; case FileSystem::Type::Unknown: fs = new FS::unknown(firstsector, lastsector, sectorsused, label); break; case FileSystem::Type::Xfs: fs = new FS::xfs(firstsector, lastsector, sectorsused, label); break; case FileSystem::Type::Zfs: fs = new FS::zfs(firstsector, lastsector, sectorsused, label); break; default: break; } if (fs != nullptr) { fs->setUUID(uuid); fs->setSectorSize(sectorSize); } return fs; } /** @overload */ FileSystem* FileSystemFactory::create(const FileSystem& other) { return create(other.type(), other.firstSector(), other.lastSector(), other.sectorSize(), other.sectorsUsed(), other.label(), other.uuid()); } /** @return the map of FileSystems */ const FileSystemFactory::FileSystems& FileSystemFactory::map() { return m_FileSystems; } /** Clones a FileSystem from another one, but with a new type. @param newType the new FileSystem's type @param other the old FileSystem to clone @return pointer to the newly created FileSystem or nullptr in case of errors */ FileSystem* FileSystemFactory::cloneWithNewType(FileSystem::Type newType, const FileSystem& other) { return create(newType, other.firstSector(), other.lastSector(), other.sectorSize(), other.sectorsUsed(), other.label()); } diff --git a/src/plugins/sfdisk/sfdiskbackend.cpp b/src/plugins/sfdisk/sfdiskbackend.cpp index 8110617..15f7d5a 100644 --- a/src/plugins/sfdisk/sfdiskbackend.cpp +++ b/src/plugins/sfdisk/sfdiskbackend.cpp @@ -1,529 +1,530 @@ /************************************************************************* * Copyright (C) 2017 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/sfdisk/sfdiskbackend.h" #include "plugins/sfdisk/sfdiskdevice.h" #include "core/copysourcedevice.h" #include "core/copytargetbytearray.h" #include "core/diskdevice.h" #include "core/lvmdevice.h" #include "core/partitiontable.h" #include "core/partitionalignment.h" #include "core/raid/softwareraid.h" #include "fs/filesystemfactory.h" #include "fs/luks.h" #include "fs/luks2.h" #include "util/globallog.h" #include "util/externalcommand.h" #include "util/helpers.h" #include #include #include #include #include #include #include #include #include #include #include #include K_PLUGIN_FACTORY_WITH_JSON(SfdiskBackendFactory, "pmsfdiskbackendplugin.json", registerPlugin();) SfdiskBackend::SfdiskBackend(QObject*, const QList&) : CoreBackend() { } void SfdiskBackend::initFSSupport() { } QList SfdiskBackend::scanDevices(bool excludeReadOnly) { // TODO: add another bool option for loopDevices QList result; QStringList deviceNodes; ExternalCommand cmd(QStringLiteral("lsblk"), { QStringLiteral("--nodeps"), QStringLiteral("--paths"), QStringLiteral("--sort"), QStringLiteral("name"), QStringLiteral("--json"), QStringLiteral("--output"), QStringLiteral("type,name") }); if (cmd.run(-1) && cmd.exitCode() == 0) { const QJsonDocument jsonDocument = QJsonDocument::fromJson(cmd.rawOutput()); const QJsonObject jsonObject = jsonDocument.object(); const QJsonArray jsonArray = jsonObject[QLatin1String("blockdevices")].toArray(); for (const auto &deviceLine : jsonArray) { QJsonObject deviceObject = deviceLine.toObject(); if (deviceObject[QLatin1String("type")].toString() != QLatin1String("disk")) continue; const QString deviceNode = deviceObject[QLatin1String("name")].toString(); if (excludeReadOnly) { QString deviceName = deviceNode; deviceName.remove(QStringLiteral("/dev/")); QFile f(QStringLiteral("/sys/block/%1/ro").arg(deviceName)); if (f.open(QIODevice::ReadOnly)) if (f.readLine().trimmed().toInt() == 1) continue; } deviceNodes << deviceNode; } int totalDevices = deviceNodes.length(); for (int i = 0; i < totalDevices; ++i) { const QString deviceNode = deviceNodes[i]; emitScanProgress(deviceNode, i * 100 / totalDevices); Device* device = scanDevice(deviceNode); if (device != nullptr) { result.append(device); } } SoftwareRAID::scanSoftwareRAID(result); LvmDevice::scanSystemLVM(result); // LVM scanner needs all other devices, so should be last } return result; } /** 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* SfdiskBackend::scanDevice(const QString& deviceNode) { ExternalCommand modelCommand(QStringLiteral("lsblk"), { QStringLiteral("--nodeps"), QStringLiteral("--noheadings"), QStringLiteral("--output"), QStringLiteral("model"), deviceNode }); ExternalCommand sizeCommand(QStringLiteral("blockdev"), { QStringLiteral("--getsize64"), deviceNode }); ExternalCommand sizeCommand2(QStringLiteral("blockdev"), { QStringLiteral("--getss"), deviceNode }); ExternalCommand jsonCommand(QStringLiteral("sfdisk"), { QStringLiteral("--json"), deviceNode }, QProcess::ProcessChannelMode::SeparateChannels ); if ( sizeCommand.run(-1) && sizeCommand.exitCode() == 0 && sizeCommand2.run(-1) && sizeCommand2.exitCode() == 0 && jsonCommand.run(-1) ) { Device* d = nullptr; qint64 deviceSize = sizeCommand.output().trimmed().toLongLong(); int logicalSectorSize = sizeCommand2.output().trimmed().toLongLong(); QFile mdstat(QStringLiteral("/proc/mdstat")); if (mdstat.open(QIODevice::ReadOnly)) { QTextStream stream(&mdstat); QString content = stream.readAll(); mdstat.close(); QRegularExpression re(QStringLiteral("md([\\/\\w]+)\\s+:")); QRegularExpressionMatchIterator i = re.globalMatch(content); while (i.hasNext()) { QRegularExpressionMatch reMatch = i.next(); QString name = reMatch.captured(1); if ((QStringLiteral("/dev/md") + name) == deviceNode) { Log(Log::Level::information) << xi18nc("@info:status", "Software RAID Device found: %1", deviceNode); d = new SoftwareRAID( QStringLiteral("md") + name, SoftwareRAID::Status::Active ); break; } } } if ( d == nullptr && modelCommand.run(-1) && modelCommand.exitCode() == 0 ) { QString name = modelCommand.output(); name = name.left(name.length() - 1).replace(QLatin1Char('_'), QLatin1Char(' ')); if (name.trimmed().isEmpty()) { // Get 'lsblk --output kname' in the cases where the model name is not available. // As lsblk doesn't have an option to include a separator in its output, it is // necessary to run it again getting only the kname as output. ExternalCommand kname(QStringLiteral("lsblk"), {QStringLiteral("--nodeps"), QStringLiteral("--noheadings"), QStringLiteral("--output"), QStringLiteral("kname"), deviceNode}); if (kname.run(-1) && kname.exitCode() == 0) name = kname.output().trimmed(); } ExternalCommand transport(QStringLiteral("lsblk"), {QStringLiteral("--nodeps"), QStringLiteral("--noheadings"), QStringLiteral("--output"), QStringLiteral("tran"), deviceNode}); QString icon; if (transport.run(-1) && transport.exitCode() == 0) if (transport.output().trimmed() == QStringLiteral("usb")) icon = QStringLiteral("drive-removable-media-usb"); Log(Log::Level::information) << xi18nc("@info:status", "Device found: %1", name); d = new DiskDevice(name, deviceNode, 255, 63, deviceSize / logicalSectorSize / 255 / 63, logicalSectorSize, icon); } if ( d ) { if (jsonCommand.exitCode() != 0) return d; const QJsonObject jsonObject = QJsonDocument::fromJson(jsonCommand.rawOutput()).object(); const QJsonObject partitionTable = jsonObject[QLatin1String("partitiontable")].toObject(); if (!updateDevicePartitionTable(*d, partitionTable)) return nullptr; return d; } } else { // Look if this device is a LVM VG ExternalCommand checkVG(QStringLiteral("lvm"), { QStringLiteral("vgdisplay"), deviceNode }); if (checkVG.run(-1) && checkVG.exitCode() == 0) { QList availableDevices = scanDevices(); LvmDevice::scanSystemLVM(availableDevices); for (Device *device : qAsConst(availableDevices)) if (device->deviceNode() == deviceNode) return device; } } return nullptr; } /** 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. */ void SfdiskBackend::scanDevicePartitions(Device& d, const QJsonArray& jsonPartitions) { Q_ASSERT(d.partitionTable()); QList partitions; for (const auto &partition : jsonPartitions) { const QJsonObject partitionObject = partition.toObject(); const QString partitionNode = partitionObject[QLatin1String("node")].toString(); const qint64 start = partitionObject[QLatin1String("start")].toVariant().toLongLong(); const qint64 size = partitionObject[QLatin1String("size")].toVariant().toLongLong(); const QString partitionType = partitionObject[QLatin1String("type")].toString(); PartitionTable::Flags activeFlags = partitionObject[QLatin1String("bootable")].toBool() ? PartitionTable::FlagBoot : PartitionTable::FlagNone; if (partitionType == QStringLiteral("C12A7328-F81F-11D2-BA4B-00A0C93EC93B")) activeFlags |= PartitionTable::FlagBoot; else if (partitionType == QStringLiteral("21686148-6449-6E6F-744E-656564454649")) activeFlags |= PartitionTable::FlagBiosGrub; FileSystem::Type type = FileSystem::Type::Unknown; type = detectFileSystem(partitionNode); PartitionRole::Roles r = PartitionRole::Primary; if ( (d.partitionTable()->type() == PartitionTable::msdos || d.partitionTable()->type() == PartitionTable::msdos_sectorbased) && partitionType.toInt() == 5 ) { r = PartitionRole::Extended; type = FileSystem::Type::Extended; } // 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(); else r = PartitionRole::Logical; FileSystem* fs = FileSystemFactory::create(type, start, start + size - 1, d.logicalSize()); fs->scan(partitionNode); QString mountPoint; bool mounted; // sfdisk does not handle LUKS partitions if (fs->type() == FileSystem::Type::Luks || fs->type() == FileSystem::Type::Luks2) { r |= PartitionRole::Luks; FS::luks* luksFs = static_cast(fs); luksFs->initLUKS(); QString mapperNode = luksFs->mapperName(); mountPoint = FileSystem::detectMountPoint(fs, mapperNode); mounted = FileSystem::detectMountStatus(fs, mapperNode); } else { mountPoint = FileSystem::detectMountPoint(fs, partitionNode); mounted = FileSystem::detectMountStatus(fs, partitionNode); } Partition* part = new Partition(parent, d, PartitionRole(r), fs, start, start + size - 1, partitionNode, availableFlags(d.partitionTable()->type()), mountPoint, mounted, activeFlags); if (!part->roles().has(PartitionRole::Luks)) readSectorsUsed(d, *part, mountPoint); if (fs->supportGetLabel() != FileSystem::cmdSupportNone) fs->setLabel(fs->readLabel(part->deviceNode())); if (d.partitionTable()->type() == PartitionTable::TableType::gpt) { part->setLabel(partitionObject[QLatin1String("name")].toString()); part->setUUID(partitionObject[QLatin1String("uuid")].toString()); } 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); for (const Partition * part : qAsConst(partitions)) PartitionAlignment::isAligned(d, *part); } bool SfdiskBackend::updateDevicePartitionTable(Device &d, const QJsonObject &jsonPartitionTable) { QString tableType = jsonPartitionTable[QLatin1String("label")].toString(); const PartitionTable::TableType type = PartitionTable::nameToTableType(tableType); qint64 firstUsableSector = 0, lastUsableSector; if ( d.type() == Device::Type::Disk_Device ) { const DiskDevice* diskDevice = static_cast(&d); lastUsableSector = diskDevice->totalSectors(); } else if ( d.type() == Device::Type::SoftwareRAID_Device ) { const SoftwareRAID* raidDevice = static_cast(&d); lastUsableSector = raidDevice->totalLogical() - 1; } if (type == PartitionTable::gpt) { firstUsableSector = jsonPartitionTable[QLatin1String("firstlba")].toVariant().toLongLong(); lastUsableSector = jsonPartitionTable[QLatin1String("lastlba")].toVariant().toLongLong(); } if (lastUsableSector < firstUsableSector) { return false; } setPartitionTableForDevice(d, new PartitionTable(type, firstUsableSector, lastUsableSector)); switch (type) { case PartitionTable::gpt: { // Read the maximum number of GPT partitions qint32 maxEntries; QByteArray gptHeader; CopySourceDevice source(d, 512, 1023); CopyTargetByteArray target(gptHeader); ExternalCommand copyCmd; if (copyCmd.copyBlocks(source, target)) { QByteArray gptMaxEntries = gptHeader.mid(80, 4); QDataStream stream(&gptMaxEntries, QIODevice::ReadOnly); stream.setByteOrder(QDataStream::LittleEndian); stream >> maxEntries; } else maxEntries = 128; CoreBackend::setPartitionTableMaxPrimaries(*d.partitionTable(), maxEntries); } default: break; } scanDevicePartitions(d, jsonPartitionTable[QLatin1String("partitions")].toArray()); return true; } /** 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 */ void SfdiskBackend::readSectorsUsed(const Device& d, Partition& p, const QString& mountPoint) { if (!mountPoint.isEmpty() && p.fileSystem().type() != FileSystem::Type::LinuxSwap && p.fileSystem().type() != FileSystem::Type::Lvm2_PV) { const QStorageInfo storage = QStorageInfo(mountPoint); if (p.isMounted() && storage.isValid()) p.fileSystem().setSectorsUsed( (storage.bytesTotal() - storage.bytesFree()) / d.logicalSize()); } else if (p.fileSystem().supportGetUsed() == FileSystem::cmdSupportFileSystem) p.fileSystem().setSectorsUsed(p.fileSystem().readUsedCapacity(p.deviceNode()) / d.logicalSize()); } FileSystem::Type SfdiskBackend::detectFileSystem(const QString& partitionPath) { FileSystem::Type rval = FileSystem::Type::Unknown; ExternalCommand udevCommand(QStringLiteral("udevadm"), { QStringLiteral("info"), QStringLiteral("--query=property"), partitionPath }); if (udevCommand.run(-1) && udevCommand.exitCode() == 0) { QRegularExpression re(QStringLiteral("ID_FS_TYPE=(\\w+)")); QRegularExpression re2(QStringLiteral("ID_FS_VERSION=(\\w+)")); QRegularExpressionMatch reFileSystemType = re.match(udevCommand.output()); QRegularExpressionMatch reFileSystemVersion = re2.match(udevCommand.output()); QString s; if (reFileSystemType.hasMatch()) { s = reFileSystemType.captured(1); } QString version; if (reFileSystemVersion.hasMatch()) { version = reFileSystemVersion.captured(1); } if (s == QStringLiteral("ext2")) rval = FileSystem::Type::Ext2; else if (s == QStringLiteral("ext3")) rval = FileSystem::Type::Ext3; else if (s.startsWith(QStringLiteral("ext4"))) rval = FileSystem::Type::Ext4; else if (s == QStringLiteral("swap")) rval = FileSystem::Type::LinuxSwap; else if (s == QStringLiteral("ntfs")) rval = FileSystem::Type::Ntfs; else if (s == QStringLiteral("reiserfs")) rval = FileSystem::Type::ReiserFS; else if (s == QStringLiteral("reiser4")) rval = FileSystem::Type::Reiser4; else if (s == QStringLiteral("xfs")) rval = FileSystem::Type::Xfs; else if (s == QStringLiteral("jfs")) rval = FileSystem::Type::Jfs; else if (s == QStringLiteral("hfs")) rval = FileSystem::Type::Hfs; else if (s == QStringLiteral("hfsplus")) rval = FileSystem::Type::HfsPlus; else if (s == QStringLiteral("ufs")) rval = FileSystem::Type::Ufs; else if (s == QStringLiteral("vfat")) { if (version == QStringLiteral("FAT32")) rval = FileSystem::Type::Fat32; else if (version == QStringLiteral("FAT16")) rval = FileSystem::Type::Fat16; else if (version == QStringLiteral("FAT12")) rval = FileSystem::Type::Fat12; } else if (s == QStringLiteral("btrfs")) rval = FileSystem::Type::Btrfs; else if (s == QStringLiteral("ocfs2")) rval = FileSystem::Type::Ocfs2; else if (s == QStringLiteral("zfs_member")) rval = FileSystem::Type::Zfs; else if (s == QStringLiteral("hpfs")) rval = FileSystem::Type::Hpfs; else if (s == QStringLiteral("crypto_LUKS")) { if (version == QStringLiteral("1")) rval = FileSystem::Type::Luks; else if (version == QStringLiteral("2")) { rval = FileSystem::Type::Luks2; } } else if (s == QStringLiteral("exfat")) rval = FileSystem::Type::Exfat; else if (s == QStringLiteral("nilfs2")) rval = FileSystem::Type::Nilfs2; else if (s == QStringLiteral("LVM2_member")) rval = FileSystem::Type::Lvm2_PV; else if (s == QStringLiteral("f2fs")) rval = FileSystem::Type::F2fs; else if (s == QStringLiteral("udf")) rval = FileSystem::Type::Udf; else if (s == QStringLiteral("iso9660")) rval = FileSystem::Type::Iso9660; else if (s == QStringLiteral("linux_raid_member")) rval = FileSystem::Type::LinuxRaidMember; + else if (s == QStringLiteral("BitLocker")) rval = FileSystem::Type::BitLocker; else qWarning() << "unknown file system type " << s << " on " << partitionPath; } return rval; } QString SfdiskBackend::readLabel(const QString& deviceNode) const { ExternalCommand udevCommand(QStringLiteral("udevadm"), { QStringLiteral("info"), QStringLiteral("--query=property"), deviceNode }); udevCommand.run(); QRegularExpression re(QStringLiteral("ID_FS_LABEL=(.*)")); QRegularExpressionMatch reFileSystemLabel = re.match(udevCommand.output()); if (reFileSystemLabel.hasMatch()) return reFileSystemLabel.captured(1); return QString(); } QString SfdiskBackend::readUUID(const QString& deviceNode) const { ExternalCommand udevCommand(QStringLiteral("udevadm"), { QStringLiteral("info"), QStringLiteral("--query=property"), deviceNode }); udevCommand.run(); QRegularExpression re(QStringLiteral("ID_FS_UUID=(.*)")); QRegularExpressionMatch reFileSystemUUID = re.match(udevCommand.output()); if (reFileSystemUUID.hasMatch()) return reFileSystemUUID.captured(1); return QString(); } PartitionTable::Flags SfdiskBackend::availableFlags(PartitionTable::TableType type) { PartitionTable::Flags flags; if (type == PartitionTable::gpt) { // These are not really flags but for now keep them for compatibility // We should implement changing partition type flags = PartitionTable::Flag::FlagBiosGrub | PartitionTable::Flag::FlagBoot; } else if (type == PartitionTable::msdos || type == PartitionTable::msdos_sectorbased) flags = PartitionTable::FlagBoot; return flags; } std::unique_ptr SfdiskBackend::openDevice(const Device& d) { std::unique_ptr device = std::make_unique(d); if (!device->open()) device = nullptr; return device; } std::unique_ptr SfdiskBackend::openDeviceExclusive(const Device& d) { std::unique_ptr device = std::make_unique(d); if (!device->openExclusive()) device = nullptr; return device; } bool SfdiskBackend::closeDevice(std::unique_ptr coreDevice) { return coreDevice->close(); } #include "sfdiskbackend.moc"