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-2019 Andrius Štikonas <andrius@stikonas.eu>
0004     SPDX-FileCopyrightText: 2015 Teo Mrnjavac <teo@kde.org>
0005     SPDX-FileCopyrightText: 2020 Gaël PORTAY <gael.portay@collabora.com>
0006 
0007     SPDX-License-Identifier: GPL-3.0-or-later
0008 */
0009 
0010 #include "ops/newoperation.h"
0011 
0012 #include "core/partition.h"
0013 #include "core/device.h"
0014 #include "core/partitionnode.h"
0015 
0016 #include "jobs/createpartitionjob.h"
0017 #include "jobs/createfilesystemjob.h"
0018 #include "jobs/setpartitionlabeljob.h"
0019 #include "jobs/setpartitionuuidjob.h"
0020 #include "jobs/setpartitionattributesjob.h"
0021 #include "jobs/setfilesystemlabeljob.h"
0022 #include "jobs/setpartflagsjob.h"
0023 #include "jobs/checkfilesystemjob.h"
0024 #include "jobs/changepermissionsjob.h"
0025 
0026 #include "fs/filesystem.h"
0027 #include "fs/filesystemfactory.h"
0028 
0029 #include "util/capacity.h"
0030 
0031 #include <QString>
0032 
0033 #include <KLocalizedString>
0034 
0035 struct NewOperationPrivate
0036 {
0037     NewOperationPrivate(Device& d, Partition* p) :
0038         m_TargetDevice(d),
0039         m_NewPartition(p),
0040         m_CreatePartitionJob(new CreatePartitionJob(d, *p)),
0041         m_SetPartitionLabelJob(nullptr),
0042         m_SetPartitionUUIDJob(nullptr),
0043         m_SetPartitionAttributesJob(nullptr),
0044         m_CreateFileSystemJob(nullptr),
0045         m_SetPartFlagsJob(nullptr),
0046         m_SetFileSystemLabelJob(nullptr),
0047         m_CheckFileSystemJob(nullptr)
0048     {
0049     }
0050 
0051     Device& m_TargetDevice;
0052     Partition* m_NewPartition;
0053     CreatePartitionJob* m_CreatePartitionJob;
0054     SetPartitionLabelJob* m_SetPartitionLabelJob;
0055     SetPartitionUUIDJob* m_SetPartitionUUIDJob;
0056     SetPartitionAttributesJob* m_SetPartitionAttributesJob;
0057     CreateFileSystemJob* m_CreateFileSystemJob;
0058     SetPartFlagsJob* m_SetPartFlagsJob;
0059     SetFileSystemLabelJob* m_SetFileSystemLabelJob;
0060     CheckFileSystemJob* m_CheckFileSystemJob;
0061 };
0062 
0063 /** Creates a new NewOperation.
0064     @param d the Device to create a new Partition on
0065     @param p pointer to the new Partition to create. May not be nullptr.
0066 */
0067 NewOperation::NewOperation(Device& d, Partition* p) :
0068     Operation(),
0069     d_ptr(std::make_unique<NewOperationPrivate>(d, p))
0070 {
0071     addJob(createPartitionJob());
0072 
0073     if (!p->label().isEmpty()) {
0074         d_ptr->m_SetPartitionLabelJob = new SetPartitionLabelJob(targetDevice(), newPartition(), p->label());
0075         addJob(setPartitionLabelJob());
0076     }
0077 
0078     if (!p->uuid().isEmpty()) {
0079         d_ptr->m_SetPartitionUUIDJob = new SetPartitionUUIDJob(targetDevice(), newPartition(), p->uuid());
0080         addJob(setPartitionUUIDJob());
0081     }
0082 
0083     if (p->attributes()) {
0084         d_ptr->m_SetPartitionAttributesJob = new SetPartitionAttributesJob(targetDevice(), newPartition(), p->attributes());
0085         addJob(setPartitionAttributesJob());
0086     }
0087 
0088     const FileSystem& fs = newPartition().fileSystem();
0089 
0090     if (fs.type() != FileSystem::Type::Extended) {
0091         // It would seem tempting to skip the CreateFileSystemJob or the
0092         // SetFileSystemLabelJob if either has nothing to do (unformatted FS or
0093         // empty label). However, the user might later on decide to change FS or
0094         // label. The operation stack will merge these operations with this one here
0095         // and if the jobs don't exist things will break.
0096 
0097         d_ptr->m_CreateFileSystemJob = new CreateFileSystemJob(targetDevice(), newPartition(), fs.label());
0098         addJob(createFileSystemJob());
0099 
0100         if (fs.type() == FileSystem::Type::Lvm2_PV) {
0101             d_ptr->m_SetPartFlagsJob = new SetPartFlagsJob(targetDevice(), newPartition(), PartitionTable::Flag::Lvm);
0102             addJob(setPartFlagsJob());
0103         }
0104 
0105         d_ptr->m_SetFileSystemLabelJob = new SetFileSystemLabelJob(newPartition(), fs.label());
0106         addJob(setLabelJob());
0107 
0108         d_ptr->m_CheckFileSystemJob = new CheckFileSystemJob(newPartition());
0109         addJob(checkJob());
0110 
0111         // if the user never configured a new permission, nothing will run, if he did,
0112         // then we change the permissions on the newly created partition.
0113         addJob(new ChangePermissionJob(newPartition()));
0114     }
0115 }
0116 
0117 NewOperation::~NewOperation()
0118 {
0119     if (status() == StatusPending)
0120         delete d_ptr->m_NewPartition;
0121 }
0122 
0123 Partition& NewOperation::newPartition()
0124 {
0125     return *d_ptr->m_NewPartition;
0126 }
0127 
0128 const Partition& NewOperation::newPartition() const
0129 {
0130     return *d_ptr->m_NewPartition;
0131 }
0132 
0133 Device& NewOperation::targetDevice()
0134 {
0135     return d_ptr->m_TargetDevice;
0136 }
0137 
0138 const Device& NewOperation::targetDevice() const
0139 {
0140     return d_ptr->m_TargetDevice;
0141 }
0142 
0143 CreatePartitionJob* NewOperation::createPartitionJob()
0144 {
0145     return d_ptr->m_CreatePartitionJob;
0146 }
0147 
0148 SetPartitionLabelJob* NewOperation::setPartitionLabelJob()
0149 {
0150     return d_ptr->m_SetPartitionLabelJob;
0151 }
0152 
0153 SetPartitionUUIDJob* NewOperation::setPartitionUUIDJob()
0154 {
0155     return d_ptr->m_SetPartitionUUIDJob;
0156 }
0157 
0158 SetPartitionAttributesJob* NewOperation::setPartitionAttributesJob()
0159 {
0160     return d_ptr->m_SetPartitionAttributesJob;
0161 }
0162 
0163 CreateFileSystemJob* NewOperation::createFileSystemJob()
0164 {
0165     return d_ptr->m_CreateFileSystemJob;
0166 }
0167 
0168 SetPartFlagsJob* NewOperation::setPartFlagsJob()
0169 {
0170     return d_ptr->m_SetPartFlagsJob;
0171 }
0172 
0173 SetFileSystemLabelJob* NewOperation::setLabelJob()
0174 {
0175     return d_ptr->m_SetFileSystemLabelJob;
0176 }
0177 
0178 CheckFileSystemJob* NewOperation::checkJob()
0179 {
0180     return d_ptr->m_CheckFileSystemJob;
0181 }
0182 
0183 bool NewOperation::targets(const Device& d) const
0184 {
0185     return d == targetDevice();
0186 }
0187 
0188 bool NewOperation::targets(const Partition& p) const
0189 {
0190     return p == newPartition();
0191 }
0192 
0193 void NewOperation::preview()
0194 {
0195     insertPreviewPartition(targetDevice(), newPartition());
0196 }
0197 
0198 void NewOperation::undo()
0199 {
0200     removePreviewPartition(targetDevice(), newPartition());
0201 }
0202 
0203 QString NewOperation::description() const
0204 {
0205     return xi18nc("@info:status", "Create a new partition (%1, %2) on <filename>%3</filename>", Capacity::formatByteSize(newPartition().capacity()), newPartition().fileSystem().name(), targetDevice().deviceNode());
0206 }
0207 
0208 /** Can a Partition be created somewhere?
0209     @param p the Partition where a new Partition is to be created, may be nullptr
0210     @return true if a new Partition can be created in @p p
0211  */
0212 bool NewOperation::canCreateNew(const Partition* p)
0213 {
0214     return p != nullptr && p->roles().has(PartitionRole::Unallocated);
0215 }
0216 
0217 Partition* NewOperation::createNew(const Partition& cloneFrom,
0218                                    FileSystem::Type type)
0219 {
0220     Partition* p = new Partition(cloneFrom);
0221 
0222     p->deleteFileSystem();
0223     p->setFileSystem(FileSystemFactory::create(type,
0224                      p->firstSector(),
0225                      p->lastSector(),
0226                      p->sectorSize()));
0227     p->setState(Partition::State::New);
0228     p->setPartitionPath(QString());
0229     p->setAttributes(0);
0230 
0231     return p;
0232 }