File indexing completed on 2024-05-05 05:48:51

0001 /*
0002     SPDX-FileCopyrightText: 2008-2010 Volker Lanz <vl@fidra.de>
0003     SPDX-FileCopyrightText: 2012-2018 Andrius Štikonas <andrius@stikonas.eu>
0004     SPDX-FileCopyrightText: 2015-2016 Teo Mrnjavac <teo@kde.org>
0005     SPDX-FileCopyrightText: 2018 Caio Jordão Carvalho <caiojcarvalho@gmail.com>
0006 
0007     SPDX-License-Identifier: GPL-3.0-or-later
0008 */
0009 
0010 #include "ops/deleteoperation.h"
0011 
0012 #include "core/partition.h"
0013 #include "core/device.h"
0014 #include "core/lvmdevice.h"
0015 #include "core/partitiontable.h"
0016 #include "core/raid/softwareraid.h"
0017 #include "fs/luks.h"
0018 
0019 #include "jobs/deletepartitionjob.h"
0020 #include "jobs/deletefilesystemjob.h"
0021 #include "jobs/shredfilesystemjob.h"
0022 
0023 #include "util/capacity.h"
0024 
0025 #include <QString>
0026 
0027 #include <KLocalizedString>
0028 
0029 /** Creates a new DeleteOperation
0030     @param d the Device to delete a Partition on
0031     @param p pointer to the Partition to delete. May not be nullptr
0032 */
0033 DeleteOperation::DeleteOperation(Device& d, Partition* p, ShredAction shred) :
0034     Operation(),
0035     m_TargetDevice(d),
0036     m_DeletedPartition(p),
0037     m_ShredAction(shred),
0038     m_DeletePartitionJob(new DeletePartitionJob(targetDevice(), deletedPartition()))
0039 {
0040     switch (shredAction()) {
0041     case ShredAction::NoShred:
0042         m_DeleteFileSystemJob = static_cast<Job*>(new DeleteFileSystemJob(targetDevice(), deletedPartition()));
0043         break;
0044     case ShredAction::ZeroShred:
0045         m_DeleteFileSystemJob = static_cast<Job*>(new ShredFileSystemJob(targetDevice(), deletedPartition(), false));
0046         break;
0047     case ShredAction::RandomShred:
0048         m_DeleteFileSystemJob = static_cast<Job*>(new ShredFileSystemJob(targetDevice(), deletedPartition(), true));
0049     }
0050 
0051     addJob(deleteFileSystemJob());
0052     if (d.partitionTable()->type() != PartitionTable::TableType::none)
0053         addJob(deletePartitionJob());
0054 }
0055 
0056 DeleteOperation::~DeleteOperation()
0057 {
0058     if (status() != StatusPending && status() != StatusNone) // don't delete the partition if we're being merged or undone
0059         delete m_DeletedPartition;
0060 }
0061 
0062 bool DeleteOperation::targets(const Device& d) const
0063 {
0064     return d == targetDevice();
0065 }
0066 
0067 bool DeleteOperation::targets(const Partition& p) const
0068 {
0069     return p == deletedPartition();
0070 }
0071 
0072 void DeleteOperation::preview()
0073 {
0074     removePreviewPartition(targetDevice(), deletedPartition());
0075     checkAdjustLogicalNumbers(deletedPartition(), false);
0076 }
0077 
0078 void DeleteOperation::undo()
0079 {
0080     checkAdjustLogicalNumbers(deletedPartition(), true);
0081     insertPreviewPartition(targetDevice(), deletedPartition());
0082 }
0083 
0084 QString DeleteOperation::description() const
0085 {
0086     if (shredAction() != ShredAction::NoShred)
0087         return xi18nc("@info:status", "Shred partition <filename>%1</filename> (%2, %3)", deletedPartition().deviceNode(), Capacity::formatByteSize(deletedPartition().capacity()), deletedPartition().fileSystem().name());
0088     else
0089         return xi18nc("@info:status", "Delete partition <filename>%1</filename> (%2, %3)", deletedPartition().deviceNode(), Capacity::formatByteSize(deletedPartition().capacity()), deletedPartition().fileSystem().name());
0090 }
0091 
0092 void DeleteOperation::checkAdjustLogicalNumbers(Partition& p, bool undo)
0093 {
0094     // If the deleted partition is a logical one, we need to adjust the numbers of the
0095     // other logical partitions in the extended one, if there are any, because the OS
0096     // will do that, too: Logicals must be numbered without gaps, i.e., a numbering like
0097     // sda5, sda6, sda8 (after sda7 is deleted) will become sda5, sda6, sda7
0098     Partition* parentPartition = dynamic_cast<Partition*>(p.parent());
0099     if (parentPartition && parentPartition->roles().has(PartitionRole::Extended))
0100         parentPartition->adjustLogicalNumbers(undo ? -1 : p.number(), undo ? p.number() : -1);
0101 }
0102 
0103 /** Can a Partition be deleted?
0104     @param p the Partition in question, may be nullptr.
0105     @return true if @p p can be deleted.
0106 */
0107 bool DeleteOperation::canDelete(const Partition* p)
0108 {
0109     if (p == nullptr)
0110         return false;
0111 
0112     if (p->isMounted())
0113         return false;
0114 
0115     if (p->fileSystem().type() == FileSystem::Type::Lvm2_PV) {
0116         if (LvmDevice::s_DirtyPVs.contains(p))
0117             return false;
0118     }
0119     else if (p->fileSystem().type() == FileSystem::Type::LinuxRaidMember) {
0120         if (SoftwareRAID::isRaidMember(p->partitionPath()))
0121             return false;
0122     }
0123     else if (p->fileSystem().type() == FileSystem::Type::Luks || p->fileSystem().type() == FileSystem::Type::Luks2) {
0124         // See if innerFS is LVM
0125         FileSystem *fs = static_cast<const FS::luks *>(&p->fileSystem())->innerFS();
0126 
0127         if (fs) {
0128             if (fs->type() == FileSystem::Type::Lvm2_PV) {
0129                 if (LvmDevice::s_DirtyPVs.contains(p))
0130                     return false;
0131             }
0132             else if (fs->type() == FileSystem::Type::LinuxRaidMember) {
0133                 if (SoftwareRAID::isRaidMember(p->partitionPath()))
0134                     return false;
0135             }
0136         }
0137     }
0138 
0139     if (p->roles().has(PartitionRole::Unallocated))
0140         return false;
0141 
0142     if (p->roles().has(PartitionRole::Extended))
0143         return p->children().size() == 1 && p->children()[0]->roles().has(PartitionRole::Unallocated);
0144 
0145     if (p->roles().has(PartitionRole::Luks))
0146     {
0147         const FS::luks* luksFs = static_cast<const FS::luks*>(&p->fileSystem());
0148         if (!luksFs)
0149             return false;
0150 
0151         if (luksFs->isCryptOpen() || luksFs->isMounted())
0152             return false;
0153     }
0154 
0155     return true;
0156 }