File indexing completed on 2024-04-28 05:45:54

0001 /*
0002     SPDX-FileCopyrightText: 2008-2010 Volker Lanz <vl@fidra.de>
0003     SPDX-FileCopyrightText: 2009 Andrew Coles <andrew.i.coles@googlemail.com>
0004     SPDX-FileCopyrightText: 2014-2018 Andrius Štikonas <andrius@stikonas.eu>
0005     SPDX-FileCopyrightText: 2016 Chantara Tith <tith.chantara@gmail.com>
0006 
0007     SPDX-License-Identifier: GPL-3.0-or-later
0008 */
0009 
0010 #include "jobs/resizefilesystemjob.h"
0011 
0012 #include "core/partition.h"
0013 #include "core/device.h"
0014 
0015 #include "backend/corebackend.h"
0016 #include "backend/corebackendmanager.h"
0017 #include "backend/corebackenddevice.h"
0018 #include "backend/corebackendpartitiontable.h"
0019 
0020 #include "fs/filesystem.h"
0021 
0022 #include "util/report.h"
0023 #include "util/capacity.h"
0024 
0025 #include <memory>
0026 
0027 #include <QDebug>
0028 
0029 #include <KLocalizedString>
0030 
0031 /** Creates a new ResizeFileSystemJob
0032     @param d the Device the FileSystem to be resized is on
0033     @param p the Partition the FileSystem to be resized is on
0034     @param newlength the new length for the FileSystem; if -1, the FileSystem will be resized to fill the entire Partition
0035 */
0036 ResizeFileSystemJob::ResizeFileSystemJob(Device& d, Partition& p, qint64 newlength) :
0037     Job(),
0038     m_Device(d),
0039     m_Partition(p),
0040     m_Maximize(newlength == -1),
0041     m_NewLength(isMaximizing() ? partition().length() : newlength)
0042 {
0043 }
0044 
0045 qint32 ResizeFileSystemJob::numSteps() const
0046 {
0047     return 100;
0048 }
0049 
0050 bool ResizeFileSystemJob::run(Report& parent)
0051 {
0052     Q_ASSERT(partition().fileSystem().firstSector() != -1);
0053     Q_ASSERT(partition().fileSystem().lastSector() != -1);
0054     Q_ASSERT(newLength() <= partition().length());
0055 
0056     if (partition().fileSystem().firstSector() == -1 || partition().fileSystem().lastSector() == -1 || newLength() > partition().length()) {
0057         qWarning() << "file system first sector: " << partition().fileSystem().firstSector() << ", last sector: " << partition().fileSystem().lastSector() << ", new length: " << newLength() << ", partition length: " << partition().length();
0058         return false;
0059     }
0060 
0061     bool rval = false;
0062 
0063     Report* report = jobStarted(parent);
0064 
0065     if (partition().fileSystem().length() == newLength()) {
0066         report->line() << xi18ncp("@info:progress", "The file system on partition <filename>%2</filename> already has the requested length of 1 sector.", "The file system on partition <filename>%2</filename> already has the requested length of %1 sectors.", newLength(), partition().deviceNode());
0067         rval = true;
0068     } else {
0069         report->line() << i18nc("@info:progress", "Resizing file system from %1 to %2 sectors.", partition().fileSystem().length(), newLength());
0070 
0071         FileSystem::CommandSupportType support = (newLength() < partition().fileSystem().length()) ? partition().fileSystem().supportShrink() : partition().fileSystem().supportGrow();
0072 
0073         switch (support) {
0074         case FileSystem::cmdSupportBackend: {
0075             Report* childReport = report->newChild();
0076             childReport->line() << xi18nc("@info:progress", "Resizing a %1 file system using internal backend functions.", partition().fileSystem().name());
0077             rval = resizeFileSystemBackend(*childReport);
0078             break;
0079         }
0080 
0081         case FileSystem::cmdSupportFileSystem: {
0082             const qint64 newLengthInByte = Capacity(newLength() * device().logicalSize()).toInt(Capacity::Unit::Byte);
0083             if (partition().isMounted())
0084                 rval = partition().fileSystem().resizeOnline(*report, partition().deviceNode(), partition().mountPoint(), newLengthInByte);
0085             else
0086                 rval = partition().fileSystem().resize(*report, partition().deviceNode(), newLengthInByte);
0087             break;
0088         }
0089 
0090         default:
0091             report->line() << xi18nc("@info:progress", "The file system on partition <filename>%1</filename> cannot be resized because there is no support for it.", partition().deviceNode());
0092             break;
0093         }
0094 
0095         if (rval)
0096             partition().fileSystem().setLastSector(partition().fileSystem().firstSector() + newLength() - 1);
0097     }
0098 
0099     jobFinished(*report, rval);
0100 
0101     return rval;
0102 }
0103 
0104 bool ResizeFileSystemJob::resizeFileSystemBackend(Report& report)
0105 {
0106     bool rval = false;
0107 
0108     std::unique_ptr<CoreBackendDevice> backendDevice = CoreBackendManager::self()->backend()->openDevice(device());
0109 
0110     if (backendDevice) {
0111         std::unique_ptr<CoreBackendPartitionTable> backendPartitionTable = backendDevice->openPartitionTable();
0112 
0113         if (backendPartitionTable) {
0114             connect(CoreBackendManager::self()->backend(), &CoreBackend::progress, this, &ResizeFileSystemJob::progress);
0115             rval = backendPartitionTable->resizeFileSystem(report, partition(), newLength());
0116             disconnect(CoreBackendManager::self()->backend(), &CoreBackend::progress, this, &ResizeFileSystemJob::progress);
0117 
0118             if (rval) {
0119                 report.line() << xi18nc("@info:progress", "Successfully resized file system using internal backend functions.");
0120                 backendPartitionTable->commit();
0121             }
0122         } else
0123             report.line() << xi18nc("@info:progress", "Could not open partition <filename>%1</filename> while trying to resize the file system.", partition().deviceNode());
0124 
0125     } else
0126         report.line() << xi18nc("@info:progress", "Could not read geometry for partition <filename>%1</filename> while trying to resize the file system.", partition().deviceNode());
0127 
0128     return rval;
0129 }
0130 
0131 QString ResizeFileSystemJob::description() const
0132 {
0133     if (isMaximizing())
0134         return xi18nc("@info:progress", "Maximize file system on <filename>%1</filename> to fill the partition", partition().deviceNode());
0135 
0136     return xi18ncp("@info:progress", "Resize file system on partition <filename>%2</filename> to 1 sector", "Resize file system on partition <filename>%2</filename> to %1 sectors", newLength(), partition().deviceNode());
0137 }