diff --git a/src/ops/restoreoperation.cpp b/src/ops/restoreoperation.cpp index 2862908..e94cbf4 100644 --- a/src/ops/restoreoperation.cpp +++ b/src/ops/restoreoperation.cpp @@ -1,226 +1,226 @@ /************************************************************************* * 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 .* *************************************************************************/ #include "ops/restoreoperation.h" #include "core/partition.h" #include "core/device.h" #include "core/partitiontable.h" #include "core/partitionnode.h" #include "jobs/createpartitionjob.h" #include "jobs/deletepartitionjob.h" #include "jobs/checkfilesystemjob.h" #include "jobs/restorefilesystemjob.h" #include "jobs/resizefilesystemjob.h" #include "fs/filesystem.h" #include "fs/filesystemfactory.h" #include "util/capacity.h" #include "util/report.h" #include #include #include #include /** Creates a new RestoreOperation. @param d the Device to restore the Partition to @param p pointer to the Partition that will be restored. May not be nullptr. @param filename name of the image file to restore from */ RestoreOperation::RestoreOperation(Device& d, Partition* p, const QString& filename) : Operation(), m_TargetDevice(d), m_RestorePartition(p), m_FileName(filename), m_OverwrittenPartition(nullptr), m_MustDeleteOverwritten(false), m_ImageLength(QFileInfo(filename).size() / 512), // 512 being the "sector size" of an image file. m_CreatePartitionJob(nullptr), m_RestoreJob(nullptr), m_CheckTargetJob(nullptr), m_MaximizeJob(nullptr) { restorePartition().setState(Partition::StateRestore); Q_ASSERT(targetDevice().partitionTable()); Partition* dest = targetDevice().partitionTable()->findPartitionBySector(restorePartition().firstSector(), PartitionRole(PartitionRole::Primary | PartitionRole::Logical | PartitionRole::Unallocated)); - Q_ASSERT(dest); - if (dest == nullptr) qWarning() << "destination partition not found at sector " << restorePartition().firstSector(); + Q_ASSERT(dest); + if (dest && !dest->roles().has(PartitionRole::Unallocated)) { restorePartition().setLastSector(dest->lastSector()); setOverwrittenPartition(dest); removePreviewPartition(targetDevice(), *dest); } if (!overwrittenPartition()) addJob(m_CreatePartitionJob = new CreatePartitionJob(targetDevice(), restorePartition())); addJob(m_RestoreJob = new RestoreFileSystemJob(targetDevice(), restorePartition(), fileName())); addJob(m_CheckTargetJob = new CheckFileSystemJob(restorePartition())); addJob(m_MaximizeJob = new ResizeFileSystemJob(targetDevice(), restorePartition())); } RestoreOperation::~RestoreOperation() { if (status() == StatusPending) delete m_RestorePartition; if (status() == StatusFinishedSuccess || status() == StatusFinishedWarning || status() == StatusError) cleanupOverwrittenPartition(); } bool RestoreOperation::targets(const Device& d) const { return d == targetDevice(); } bool RestoreOperation::targets(const Partition& p) const { return p == restorePartition(); } void RestoreOperation::preview() { insertPreviewPartition(targetDevice(), restorePartition()); } void RestoreOperation::undo() { removePreviewPartition(targetDevice(), restorePartition()); if (overwrittenPartition()) insertPreviewPartition(targetDevice(), *overwrittenPartition()); } bool RestoreOperation::execute(Report& parent) { bool rval = false; bool warning = false; Report* report = parent.newChild(description()); if (overwrittenPartition()) restorePartition().setPartitionPath(overwrittenPartition()->devicePath()); if (overwrittenPartition() || (rval = createPartitionJob()->run(*report))) { restorePartition().setState(Partition::StateNone); if ((rval = restoreJob()->run(*report))) { if ((rval = checkTargetJob()->run(*report))) { // If the partition was written over an existing one, the partition itself may now // be larger than the filesystem, so maximize the filesystem to the partition's size // or the image length, whichever is larger. If this fails, don't return an error, just // warn the user. if ((warning = !maximizeJob()->run(*report))) report->line() << xi18nc("@info/plain", "Warning: Maximizing file system on target partition %1 to the size of the partition failed.", restorePartition().deviceNode()); } else report->line() << xi18nc("@info/plain", "Checking target file system on partition %1 after the restore failed.", restorePartition().deviceNode()); } else { if (!overwrittenPartition()) DeletePartitionJob(targetDevice(), restorePartition()).run(*report); report->line() << i18nc("@info/plain", "Restoring file system failed."); } } else report->line() << i18nc("@info/plain", "Creating the destination partition to restore to failed."); if (rval) setStatus(warning ? StatusFinishedWarning : StatusFinishedSuccess); else setStatus(StatusError); report->setStatus(i18nc("@info/plain status (success, error, warning...) of operation", "%1: %2", description(), statusText())); return rval; } QString RestoreOperation::description() const { if (overwrittenPartition()) return xi18nc("@info/plain", "Restore partition from %1 to %2", fileName(), overwrittenPartition()->deviceNode()); return xi18nc("@info/plain", "Restore partition on %1 at %2 from %3", targetDevice().deviceNode(), Capacity::formatByteSize(restorePartition().firstSector() * targetDevice().logicalSectorSize()), fileName()); } void RestoreOperation::setOverwrittenPartition(Partition* p) { // This is copied from CopyOperation. One day we might create a common base class ;-) cleanupOverwrittenPartition(); m_OverwrittenPartition = p; m_MustDeleteOverwritten = (p && p->state() == Partition::StateNone); } void RestoreOperation::cleanupOverwrittenPartition() { if (mustDeleteOverwritten()) { delete overwrittenPartition(); m_OverwrittenPartition = nullptr; } } /** Can a Partition be restored to somewhere? @param p the Partition in question, may be nullptr. @return true if a Partition can be restored to @p p. */ bool RestoreOperation::canRestore(const Partition* p) { if (p == nullptr) return false; if (p->isMounted()) return false; if (p->roles().has(PartitionRole::Extended)) return false; return true; } /** Creates a new Partition to restore to. @param device the Device to create the Partition on @param parent the parent PartitionNode @param start start sector of the Partition @param filename name of the image file to restore from */ Partition* RestoreOperation::createRestorePartition(const Device& device, PartitionNode& parent, qint64 start, const QString& filename) { PartitionRole::Roles r = PartitionRole::Primary; if (!parent.isRoot()) r = PartitionRole::Logical; QFileInfo fileInfo(filename); if (!fileInfo.exists()) return nullptr; const qint64 end = start + fileInfo.size() / device.logicalSectorSize() - 1; Partition* p = new Partition(&parent, device, PartitionRole(r), FileSystemFactory::create(FileSystem::Unknown, start, end), start, end, QString()); p->setState(Partition::StateRestore); return p; }