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 }