diff --git a/src/core/partition.cpp b/src/core/partition.cpp index 5feaf85..36b4a94 100644 --- a/src/core/partition.cpp +++ b/src/core/partition.cpp @@ -1,393 +1,394 @@ /************************************************************************* * 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 "core/partition.h" #include "core/device.h" #include "fs/filesystem.h" #include "fs/filesystemfactory.h" #include "util/externalcommand.h" #include "util/report.h" #include #include #include #include #include /** Creates a new Partition object. @param parent the Partition's parent. May be another Partition (for logicals) or a PartitionTable. Must not be nullptr. @param device the Device this Partition is on. @param role the Partition's role(s) @param fs pointer to the Partition's FileSystem object. The Partition object will take ownership of this. @param sectorStart the first sector of the Partition on its Device @param sectorEnd the last sector of the Partition on its Device @param partitionPath the Partition's path, e.g. /dev/sda4 or /dev/mmcblk0p1 @param availableFlags the flags available for this Partition @param mountPoint mount point for this Partition @param mounted true if the Partition is mounted @param activeFlags active flags for this Partition @param state the Partition's state */ Partition::Partition(PartitionNode* parent, const Device& device, const PartitionRole& role, FileSystem* fs, qint64 sectorStart, qint64 sectorEnd, QString partitionPath, PartitionTable::Flags availableFlags, const QString& mountPoint, bool mounted, PartitionTable::Flags activeFlags, State state) : PartitionNode(), m_Children(), m_Parent(parent), m_FileSystem(fs), m_Roles(role), m_FirstSector(sectorStart), m_LastSector(sectorEnd), m_DevicePath(device.deviceNode()), m_MountPoint(mountPoint), m_AvailableFlags(availableFlags), m_ActiveFlags(activeFlags), m_IsMounted(mounted), m_SectorSize(device.logicalSectorSize()), m_State(state) { setPartitionPath(partitionPath); Q_ASSERT(m_Parent); } /** Destroys a Partition, destroying its children and its FileSystem */ Partition::~Partition() { // FIXME: Design flaw: Currently, there are two ways a partition node can get children: Either // they're created and inserted as unallocated in PartitionTable (these unallocated then get // "converted" to real, new partitions in the GUI) or they're created and appended in the // backend plugin. There is however no defined way to remove partitions from parents. This might // either cause leaks (a partition is removed from the parent's list of children but never // deleted) or, worse, crashes (a partition is deleted but not removed from the parent's // list of children). As a workaround, always remove a partition from its parent here in the dtor. // This presumably fixes 232092, but backporting is too risky until we're sure this doesn't cause // side-effects. - parent()->remove(this); + if (m_Parent) + parent()->remove(this); clearChildren(); deleteFileSystem(); } /** @param other Partition to copy */ Partition::Partition(const Partition& other) : PartitionNode(), m_Children(), m_Parent(other.m_Parent), m_FileSystem(FileSystemFactory::create(other.fileSystem())), m_Roles(other.m_Roles), m_FirstSector(other.m_FirstSector), m_LastSector(other.m_LastSector), m_DevicePath(other.m_DevicePath), m_MountPoint(other.m_MountPoint), m_AvailableFlags(other.m_AvailableFlags), m_ActiveFlags(other.m_ActiveFlags), m_IsMounted(other.m_IsMounted), m_SectorSize(other.m_SectorSize), m_State(other.m_State) { setPartitionPath(other.m_PartitionPath); foreach(const Partition * child, other.children()) { Partition* p = new Partition(*child); p->setParent(this); m_Children.append(p); } } /** @param other Partition to assign from */ Partition& Partition::operator=(const Partition& other) { if (&other == this) return *this; clearChildren(); foreach(const Partition * child, other.children()) { Partition* p = new Partition(*child); p->setParent(this); m_Children.append(p); } m_Number = other.m_Number; m_FileSystem = FileSystemFactory::create(other.fileSystem()); m_Roles = other.m_Roles; m_FirstSector = other.m_FirstSector; m_LastSector = other.m_LastSector; m_DevicePath = other.m_DevicePath; m_PartitionPath = other.m_PartitionPath; m_MountPoint = other.m_MountPoint; m_AvailableFlags = other.m_AvailableFlags; m_ActiveFlags = other.m_ActiveFlags; m_IsMounted = other.m_IsMounted; m_SectorSize = other.m_SectorSize; m_State = other.m_State; return *this; } bool Partition::operator==(const Partition& other) const { return other.deviceNode() == deviceNode(); } bool Partition::operator!=(const Partition& other) const { return !(other == *this); } /** @return a short descriptive text or, in case the Partition has StateNone, its device node. */ QString Partition::deviceNode() const { if (roles().has(PartitionRole::None) || roles().has(PartitionRole::Unallocated)) return i18nc("@item partition name", "unallocated"); if (state() == StateNew) return i18nc("@item partition name", "New Partition"); if (state() == StateRestore) return i18nc("@item partition name", "Restored Partition"); if (state() == StateCopy) return i18nc("@item partition name", "Copy of %1", partitionPath()); return partitionPath(); } /** @return the sectors used in the Partition's FileSystem or, in case of an extended partition, the sum of used sectors of the Partition's children */ qint64 Partition::sectorsUsed() const { if (!roles().has(PartitionRole::Extended)) return fileSystem().sectorsUsed(); qint64 result = 0; foreach(const Partition * p, children()) if (!p->roles().has(PartitionRole::Unallocated)) result += p->length(); return result; } /** @return the minimum number of sectors this Partition must be long */ qint64 Partition::minimumSectors() const { return fileSystem().minCapacity() / sectorSize(); } /** @return the maximum number of sectors this Partition may be long */ qint64 Partition::maximumSectors() const { return fileSystem().maxCapacity() / sectorSize(); } /** Adjusts the numbers of logical Partitions for an extended Partition. This is required if a logical Partition is deleted or inserted because logicals must be numberd from 5 onwards without a gap. So if the user deletes Partition number 7 and there is a number 8, 8 becomes the "new" 7. And since this happens somewhere in the middle of a DeleteOperation, we have to adjust to that so the next Job still finds the Partition it wants to deal with. @param deletedNumber the number of a deleted logical or -1 if none has been deleted @param insertedNumber the number of an inserted logical or -1 if none has been inserted */ void Partition::adjustLogicalNumbers(qint32 deletedNumber, qint32 insertedNumber) { if (!roles().has(PartitionRole::Extended)) return; foreach(Partition * p, children()) { QString path = p->partitionPath(); path.remove(QRegExp(QStringLiteral("([0-9]+$)"))); if (deletedNumber > 4 && p->number() > deletedNumber) p->setPartitionPath(path + QString::number(p->number() - 1)); else if (insertedNumber > 4 && p->number() >= insertedNumber) p->setPartitionPath(path + QString::number(p->number() + 1)); } } /** @return the highest sector number an extended Partition can begin at */ qint64 Partition::maxFirstSector() const { qint64 rval = -1; foreach(const Partition * child, children()) if (!child->roles().has(PartitionRole::Unallocated) && (child->firstSector() < rval || rval == -1)) rval = child->firstSector(); return rval; } /** @return the lowest sector number an extended Partition can end at */ qint64 Partition::minLastSector() const { qint64 rval = -1; foreach(const Partition * child, children()) if (!child->roles().has(PartitionRole::Unallocated) && child->lastSector() > rval) rval = child->lastSector(); return rval; } /** @return true if the Partition has children */ bool Partition::hasChildren() const { foreach(const Partition * child, children()) if (!child->roles().has(PartitionRole::Unallocated)) return true; return false; } /** Sets an extended Partition to mounted if any of its children are mounted */ void Partition::checkChildrenMounted() { setMounted(isChildMounted()); } /** @return true if this Partition can be mounted */ bool Partition::canMount() const { // cannot mount if already mounted if (isMounted()) return false; // if the file system says we can mount without mount points, that's fine // (this is the case for swap only, actually) if (fileSystem().canMount(deviceNode())) return true; // cannot mount if we have no mount points return !mountPoint().isEmpty(); } /** @return true if this Partition can be unmounted */ bool Partition::canUnmount() const { return !roles().has(PartitionRole::Extended) && isMounted(); } /** Tries to mount a Partition. @return true on success */ bool Partition::mount(Report& report) { if (isMounted()) return false; bool success = false; if (fileSystem().canMount(deviceNode())) success = fileSystem().mount(deviceNode()); else { ExternalCommand mountCmd(report, QStringLiteral("mount"), QStringList() << QStringLiteral("-v") << deviceNode() << mountPoint()); if (mountCmd.run() && mountCmd.exitCode() == 0) success = true; } setMounted(success); return success; } /** Tries to unmount a Partition. @return true on success */ bool Partition::unmount(Report& report) { if (!isMounted()) return false; bool success = true; while (success) { if (fileSystem().canUnmount(deviceNode())) { success = fileSystem().unmount(deviceNode()); if (success) setMountPoint(QString()); } else { ExternalCommand umountCmd(report, QStringLiteral("umount"), QStringList() << QStringLiteral("-v") << deviceNode()); if (!umountCmd.run() || umountCmd.exitCode() != 0) success = false; } KMountPoint::List mountPoints = KMountPoint::currentMountPoints(KMountPoint::NeedRealDeviceName); if (!mountPoints.findByDevice(deviceNode())) break; } setMounted(!success); return success; } void Partition::deleteFileSystem() { delete m_FileSystem; m_FileSystem = nullptr; } void Partition::setPartitionPath(const QString& s) { m_PartitionPath = s; QRegExp rxPartitionNumber(QStringLiteral("([0-9]+$)")); if (rxPartitionNumber.indexIn(partitionPath()) > -1) { setNumber(rxPartitionNumber.cap().toInt()); return; } setNumber(-1); } void Partition::setFileSystem(FileSystem* fs) { m_FileSystem = fs; } void Partition::move(qint64 newStartSector) { const qint64 savedLength = length(); setFirstSector(newStartSector); setLastSector(newStartSector + savedLength - 1); } QTextStream& operator<<(QTextStream& stream, const Partition& p) { QStringList flagList; foreach(const PartitionTable::Flag & f, PartitionTable::flagList()) { if (p.activeFlags() & f) flagList.append(PartitionTable::flagName(f)); } const QString sep(QStringLiteral(";")); // number - start - end - type - roles - label - flags stream << p.number() << sep << p.firstSector() << sep << p.lastSector() << sep << p.fileSystem().name() << sep << p.roles().toString() << sep << "\"" << p.fileSystem().label() << QStringLiteral("\"") << sep << "\"" << flagList.join(QStringLiteral(",")) << QStringLiteral("\"") << "\n"; return stream; } diff --git a/src/core/partition.h b/src/core/partition.h index 0464f37..bbda5a3 100644 --- a/src/core/partition.h +++ b/src/core/partition.h @@ -1,291 +1,292 @@ /************************************************************************* * Copyright (C) 2008 by Volker Lanz * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License as * * published by the Free Software Foundation; either version 3 of * * the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see .* *************************************************************************/ #if !defined(PARTITION__H) #define PARTITION__H #include "../core/partitionnode.h" #include "../core/partitionrole.h" #include "../core/partitiontable.h" #include "../util/libpartitionmanagerexport.h" #include #include +#include class Device; class OperationStack; class CoreBackendPartitionTable; class PartitionAlignment; class PartResizerWidget; class ResizeDialog; class InsertDialog; class NewDialog; class EditMountPointDialog; class PartPropsDialog; class SizeDialogBase; class CreateFileSystemOperation; class RestoreOperation; class SetPartFlagsOperation; class CopyOperation; class NewOperation; class ResizeOperation; class SetPartGeometryJob; class CreatePartitionJob; class SetPartFlagsJob; class RestoreFileSystemJob; class FileSystem; class Report; class QString; class QTextStream; /** A partition or some unallocated space on a Device. Repesent partitions in a PartitionTable on a Device. Partitions can be unallocated, thus not all instances really are partitions in the way the user would see them. Extended partitions have child objects that represent the logicals inside them. @see PartitionTable, Device, FileSystem @author Volker Lanz */ class LIBKPMCORE_EXPORT Partition : public PartitionNode { friend class PartitionTable; friend class OperationStack; friend class Device; friend class PartitionNode; friend class CoreBackendPartitionTable; friend class PartitionAlignment; friend class PartResizerWidget; friend class ResizeDialog; friend class InsertDialog; friend class NewDialog; friend class EditMountPointDialog; friend class PartPropsDialog; friend class SizeDialogBase; friend class CreateFileSystemOperation; friend class RestoreOperation; friend class SetPartFlagsOperation; friend class CopyOperation; friend class NewOperation; friend class ResizeOperation; friend class SetPartGeometryJob; friend class CreatePartitionJob; friend class SetPartFlagsJob; friend class RestoreFileSystemJob; friend QTextStream& operator<<(QTextStream& stream, const Partition& p); public: /** A Partition state -- where did it come from? */ enum State { StateNone = 0, /**< exists on disk */ StateNew = 1, /**< from a NewOperation */ StateCopy = 2, /**< from a CopyOperation */ StateRestore = 3 /**< from a RestoreOperation */ }; Partition(PartitionNode* parent, const Device& device, const PartitionRole& role, FileSystem* fs, qint64 sectorStart, qint64 sectorEnd, QString partitionPath, PartitionTable::Flags availableFlags = PartitionTable::FlagNone, const QString& mountPoint = QString(), bool mounted = false, PartitionTable::Flags activeFlags = PartitionTable::FlagNone, State state = StateNone); ~Partition(); Partition(const Partition&); Partition& operator=(const Partition&); bool operator==(const Partition& other) const; bool operator!=(const Partition& other) const; qint32 number() const { return m_Number; /**< @return the Partition's device number, e.g. 7 for /dev/sdd7 */ } bool isRoot() const { return false; /**< @return always false for Partition */ } PartitionNode* parent() { return m_Parent; /**< @return the Partition's parent PartitionNode */ } const PartitionNode* parent() const { return m_Parent; /**< @return the Partition's parent PartitionNode */ } Partitions& children() { return m_Children; /**< @return the Partition's children. empty for non-extended. */ } const Partitions& children() const { return m_Children; /**< @return the Partition's children. empty for non-extended. */ } const QString& devicePath() const { return m_DevicePath; /**< @return the Partition's device path, e.g. /dev/sdd */ } const QString& partitionPath() const { return m_PartitionPath; /**< @return the Partition's path, e.g. /dev/sdd1 */ } qint64 firstSector() const { return m_FirstSector; /**< @return the Partition's first sector on the Device */ } qint64 lastSector() const { return m_LastSector; /**< @return the Partition's last sector on the Device */ } qint64 sectorsUsed() const; qint32 sectorSize() const { return m_SectorSize; /**< @return the sector size on the Partition's Device */ } qint64 length() const { return lastSector() - firstSector() + 1; /**< @return the length of the Partition */ } qint64 capacity() const { return length() * sectorSize(); /**< @return the capacity of the Partition in bytes */ } qint64 used() const { return sectorsUsed() < 0 ? -1 : sectorsUsed() * sectorSize(); /**< @return the number of used sectors in the Partition's FileSystem */ } qint64 available() const { return sectorsUsed() < 0 ? -1 : capacity() - used(); /**< @return the number of free sectors in the Partition's FileSystem */ } qint64 minimumSectors() const; qint64 maximumSectors() const; qint64 maxFirstSector() const; qint64 minLastSector() const; QString deviceNode() const; const PartitionRole& roles() const { return m_Roles; /**< @return the Partition's role(s) */ } const QString& mountPoint() const { return m_MountPoint; /**< @return the Partition's mount point */ } PartitionTable::Flags activeFlags() const { return m_ActiveFlags; /**< @return the flags currently set for this Partition */ } PartitionTable::Flags availableFlags() const { return m_AvailableFlags; /**< @return the flags available for this Partition */ } bool isMounted() const { return m_IsMounted; /**< @return true if Partition is mounted */ } FileSystem& fileSystem() { return *m_FileSystem; /**< @return the Partition's FileSystem */ } const FileSystem& fileSystem() const { return *m_FileSystem; /**< @return the Partition's FileSystem */ } State state() const { return m_State; /**< @return the Partition's state */ } bool hasChildren() const; bool mount(Report& report); bool unmount(Report& report); bool canMount() const; bool canUnmount() const; void adjustLogicalNumbers(qint32 deletedNumber, qint32 insertedNumber); void checkChildrenMounted(); void setFirstSector(qint64 s) { m_FirstSector = s; } void setLastSector(qint64 s) { m_LastSector = s; } protected: void append(Partition* p) { m_Children.append(p); } void setDevicePath(const QString& s) { m_DevicePath = s; } void setPartitionPath(const QString& s); void setRoles(const PartitionRole& r) { m_Roles = r; } void setMountPoint(const QString& s) { m_MountPoint = s; } void setFlags(PartitionTable::Flags f) { m_ActiveFlags = f; } void setSectorSize(qint32 s) { m_SectorSize = s; } void move(qint64 newStartSector); void setMounted(bool b) { m_IsMounted = b; } void setFlag(PartitionTable::Flag f) { m_ActiveFlags |= f; } void unsetFlag(PartitionTable::Flag f) { m_ActiveFlags &= ~f; } void setParent(PartitionNode* p) { m_Parent = p; } void setFileSystem(FileSystem* fs); void setState(State s) { m_State = s; } void deleteFileSystem(); private: void setNumber(qint32 n) { m_Number = n; } qint32 m_Number; Partitions m_Children; - PartitionNode* m_Parent; + QPointer< PartitionNode > m_Parent; FileSystem* m_FileSystem; PartitionRole m_Roles; qint64 m_FirstSector; qint64 m_LastSector; QString m_DevicePath; QString m_PartitionPath; QString m_MountPoint; PartitionTable::Flags m_AvailableFlags; PartitionTable::Flags m_ActiveFlags; bool m_IsMounted; qint32 m_SectorSize; State m_State; }; QTextStream& operator<<(QTextStream& stream, const Partition& p); #endif diff --git a/src/ops/deleteoperation.h b/src/ops/deleteoperation.h index 6330f99..73972dd 100644 --- a/src/ops/deleteoperation.h +++ b/src/ops/deleteoperation.h @@ -1,111 +1,110 @@ /************************************************************************* * Copyright (C) 2008, 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 .* *************************************************************************/ #if !defined(DELETEOPERATION__H) #define DELETEOPERATION__H #include "../util/libpartitionmanagerexport.h" #include "../ops/operation.h" -#include #include class Device; class OperationStack; class Partition; class Job; class DeletePartitionJob; /** Delete a Partition. @author Volker Lanz */ class LIBKPMCORE_EXPORT DeleteOperation : public Operation { friend class OperationStack; Q_OBJECT Q_DISABLE_COPY(DeleteOperation) public: enum ShredAction { NoShred = 0, ZeroShred, RandomShred }; DeleteOperation(Device& d, Partition* p, ShredAction shred = NoShred); ~DeleteOperation(); public: QString iconName() const { return shredAction() == NoShred ? QStringLiteral("edit-delete") : QStringLiteral("edit-delete-shred"); } QString description() const; void preview(); void undo(); ShredAction shredAction() const { return m_ShredAction; } virtual bool targets(const Device& d) const; virtual bool targets(const Partition& p) const; static bool canDelete(const Partition* p); protected: Device& targetDevice() { return m_TargetDevice; } const Device& targetDevice() const { return m_TargetDevice; } Partition& deletedPartition() { return *m_DeletedPartition; } const Partition& deletedPartition() const { return *m_DeletedPartition; } void checkAdjustLogicalNumbers(Partition& p, bool undo); void setDeletedPartition(Partition* p) { m_DeletedPartition = p; } Job* deleteFileSystemJob() { return m_DeleteFileSystemJob; } DeletePartitionJob* deletePartitionJob() { return m_DeletePartitionJob; } private: Device& m_TargetDevice; - QPointer< Partition > m_DeletedPartition; + Partition* m_DeletedPartition; ShredAction m_ShredAction; Job* m_DeleteFileSystemJob; DeletePartitionJob* m_DeletePartitionJob; }; #endif