/* SPDX-FileCopyrightText: 2008-2010 Volker Lanz SPDX-FileCopyrightText: 2012-2019 Andrius Štikonas SPDX-FileCopyrightText: 2015 Teo Mrnjavac SPDX-FileCopyrightText: 2020 Gaël PORTAY SPDX-License-Identifier: GPL-3.0-or-later */ #include "ops/newoperation.h" #include "core/partition.h" #include "core/device.h" #include "core/partitionnode.h" #include "jobs/createpartitionjob.h" #include "jobs/createfilesystemjob.h" #include "jobs/setpartitionlabeljob.h" #include "jobs/setpartitionuuidjob.h" #include "jobs/setpartitionattributesjob.h" #include "jobs/setfilesystemlabeljob.h" #include "jobs/setpartflagsjob.h" #include "jobs/checkfilesystemjob.h" #include "fs/filesystem.h" #include "fs/filesystemfactory.h" #include "util/capacity.h" #include #include struct NewOperationPrivate { NewOperationPrivate(Device& d, Partition* p) : m_TargetDevice(d), m_NewPartition(p), m_CreatePartitionJob(new CreatePartitionJob(d, *p)), m_SetPartitionLabelJob(nullptr), m_SetPartitionUUIDJob(nullptr), m_SetPartitionAttributesJob(nullptr), m_CreateFileSystemJob(nullptr), m_SetPartFlagsJob(nullptr), m_SetFileSystemLabelJob(nullptr), m_CheckFileSystemJob(nullptr) { } Device& m_TargetDevice; Partition* m_NewPartition; CreatePartitionJob* m_CreatePartitionJob; SetPartitionLabelJob* m_SetPartitionLabelJob; SetPartitionUUIDJob* m_SetPartitionUUIDJob; SetPartitionAttributesJob* m_SetPartitionAttributesJob; CreateFileSystemJob* m_CreateFileSystemJob; SetPartFlagsJob* m_SetPartFlagsJob; SetFileSystemLabelJob* m_SetFileSystemLabelJob; CheckFileSystemJob* m_CheckFileSystemJob; }; /** Creates a new NewOperation. @param d the Device to create a new Partition on @param p pointer to the new Partition to create. May not be nullptr. */ NewOperation::NewOperation(Device& d, Partition* p) : Operation(), d_ptr(std::make_unique(d, p)) { addJob(createPartitionJob()); if (!p->label().isEmpty()) { d_ptr->m_SetPartitionLabelJob = new SetPartitionLabelJob(targetDevice(), newPartition(), p->label()); addJob(setPartitionLabelJob()); } if (!p->uuid().isEmpty()) { d_ptr->m_SetPartitionUUIDJob = new SetPartitionUUIDJob(targetDevice(), newPartition(), p->uuid()); addJob(setPartitionUUIDJob()); } if (p->attributes()) { d_ptr->m_SetPartitionAttributesJob = new SetPartitionAttributesJob(targetDevice(), newPartition(), p->attributes()); addJob(setPartitionAttributesJob()); } const FileSystem& fs = newPartition().fileSystem(); if (fs.type() != FileSystem::Type::Extended) { // It would seem tempting to skip the CreateFileSystemJob or the // SetFileSystemLabelJob if either has nothing to do (unformatted FS or // empty label). However, the user might later on decide to change FS or // label. The operation stack will merge these operations with this one here // and if the jobs don't exist things will break. d_ptr->m_CreateFileSystemJob = new CreateFileSystemJob(targetDevice(), newPartition(), fs.label()); addJob(createFileSystemJob()); if (fs.type() == FileSystem::Type::Lvm2_PV) { d_ptr->m_SetPartFlagsJob = new SetPartFlagsJob(targetDevice(), newPartition(), PartitionTable::Flag::Lvm); addJob(setPartFlagsJob()); } d_ptr->m_SetFileSystemLabelJob = new SetFileSystemLabelJob(newPartition(), fs.label()); addJob(setLabelJob()); d_ptr->m_CheckFileSystemJob = new CheckFileSystemJob(newPartition()); addJob(checkJob()); } } NewOperation::~NewOperation() { if (status() == StatusPending) delete d_ptr->m_NewPartition; } Partition& NewOperation::newPartition() { return *d_ptr->m_NewPartition; } const Partition& NewOperation::newPartition() const { return *d_ptr->m_NewPartition; } Device& NewOperation::targetDevice() { return d_ptr->m_TargetDevice; } const Device& NewOperation::targetDevice() const { return d_ptr->m_TargetDevice; } CreatePartitionJob* NewOperation::createPartitionJob() { return d_ptr->m_CreatePartitionJob; } SetPartitionLabelJob* NewOperation::setPartitionLabelJob() { return d_ptr->m_SetPartitionLabelJob; } SetPartitionUUIDJob* NewOperation::setPartitionUUIDJob() { return d_ptr->m_SetPartitionUUIDJob; } SetPartitionAttributesJob* NewOperation::setPartitionAttributesJob() { return d_ptr->m_SetPartitionAttributesJob; } CreateFileSystemJob* NewOperation::createFileSystemJob() { return d_ptr->m_CreateFileSystemJob; } SetPartFlagsJob* NewOperation::setPartFlagsJob() { return d_ptr->m_SetPartFlagsJob; } SetFileSystemLabelJob* NewOperation::setLabelJob() { return d_ptr->m_SetFileSystemLabelJob; } CheckFileSystemJob* NewOperation::checkJob() { return d_ptr->m_CheckFileSystemJob; } bool NewOperation::targets(const Device& d) const { return d == targetDevice(); } bool NewOperation::targets(const Partition& p) const { return p == newPartition(); } void NewOperation::preview() { insertPreviewPartition(targetDevice(), newPartition()); } void NewOperation::undo() { removePreviewPartition(targetDevice(), newPartition()); } QString NewOperation::description() const { return xi18nc("@info:status", "Create a new partition (%1, %2) on %3", Capacity::formatByteSize(newPartition().capacity()), newPartition().fileSystem().name(), targetDevice().deviceNode()); } /** Can a Partition be created somewhere? @param p the Partition where a new Partition is to be created, may be nullptr @return true if a new Partition can be created in @p p */ bool NewOperation::canCreateNew(const Partition* p) { return p != nullptr && p->roles().has(PartitionRole::Unallocated); } Partition* NewOperation::createNew(const Partition& cloneFrom, FileSystem::Type type) { Partition* p = new Partition(cloneFrom); p->deleteFileSystem(); p->setFileSystem(FileSystemFactory::create(type, p->firstSector(), p->lastSector(), p->sectorSize())); p->setState(Partition::State::New); p->setPartitionPath(QString()); return p; }