File indexing completed on 2024-04-28 05:46:32

0001 /*
0002     SPDX-FileCopyrightText: 2010 Volker Lanz <vl@fidra.de>
0003     SPDX-FileCopyrightText: 2014-2020 Andrius Štikonas <andrius@stikonas.eu>
0004     SPDX-FileCopyrightText: 2018 Abhijeet Sharma <sharma.abhijeet2096@gmail.com>
0005 
0006     SPDX-License-Identifier: GPL-3.0-or-later
0007 */
0008 
0009 #include "gui/editmountpointdialogwidget.h"
0010 #include "gui/editmountoptionsdialog.h"
0011 
0012 #include <core/partition.h>
0013 
0014 #include <fs/filesystem.h>
0015 #include <fs/luks.h>
0016 
0017 #include <KLocalizedString>
0018 #include <KMessageBox>
0019 
0020 #include <QDebug>
0021 #include <QFile>
0022 #include <QFileDialog>
0023 #include <QPointer>
0024 #include <QString>
0025 
0026 EditMountPointDialogWidget::EditMountPointDialogWidget(QWidget* parent, Partition& p) :
0027     QWidget(parent),
0028     m_Partition(p)
0029 {
0030     m_fstabEntries = readFstabEntries();
0031 
0032     setupUi(this);
0033 
0034     m_deviceNode = partition().deviceNode();
0035     if (partition().roles().has(PartitionRole::Luks) && partition().fileSystem().type() != FileSystem::Type::Luks) {
0036         const FS::luks* luksFs = dynamic_cast<const FS::luks*>(&partition().fileSystem());
0037         m_deviceNode = luksFs->mapperName();
0038     }
0039     labelName().setText(m_deviceNode);
0040     labelType().setText(partition().fileSystem().name());
0041 
0042     bool entryFound = false;
0043     editPath().setEditable(true);
0044     for (auto &e : m_fstabEntries) {
0045         QString canonicalEntryPath = QFileInfo(e.deviceNode()).canonicalFilePath();
0046         QString canonicalDevicePath = QFileInfo(m_deviceNode).canonicalFilePath();
0047         if (canonicalEntryPath == canonicalDevicePath) {
0048             entryFound = true;
0049             entry.push_back(&e);
0050             mountPointList = possibleMountPoints(e.deviceNode());
0051         }
0052     }
0053 
0054     if (!entryFound) {
0055         FileSystem::Type type = partition().fileSystem().type();
0056         QString fsName;
0057         switch (type) {
0058         case FileSystem::Type::LinuxSwap:
0059             fsName = QStringLiteral("swap");
0060             break;
0061         case FileSystem::Type::Fat16:
0062         case FileSystem::Type::Fat32:
0063             fsName = QStringLiteral("vfat");
0064             break;
0065         default:
0066             fsName = partition().fileSystem().name({QStringLiteral("C")});
0067         }
0068 
0069         m_fstabEntries.push_back(FstabEntry(m_deviceNode, QString(), fsName, QString()));
0070         entry.push_back(&m_fstabEntries.back());
0071     }
0072     currentEntry = entry[0];
0073     editPath().addItems(mountPointList);
0074     spinDumpFreq().setValue(currentEntry->dumpFreq());
0075     spinPassNumber().setValue(currentEntry->passNumber());
0076 
0077     boxOptions()[QStringLiteral("ro")] = m_CheckReadOnly;
0078     boxOptions()[QStringLiteral("users")] = m_CheckUsers;
0079     boxOptions()[QStringLiteral("noauto")] = m_CheckNoAuto;
0080     boxOptions()[QStringLiteral("noatime")] = m_CheckNoAtime;
0081     boxOptions()[QStringLiteral("nodiratime")] = m_CheckNoDirAtime;
0082     boxOptions()[QStringLiteral("sync")] = m_CheckSync;
0083     boxOptions()[QStringLiteral("noexec")] = m_CheckNoExec;
0084     boxOptions()[QStringLiteral("relatime")] = m_CheckRelAtime;
0085 
0086     setupRadio(currentEntry->entryType());
0087     setupOptions(currentEntry->options());
0088 
0089     connect(m_ButtonMore, &QPushButton::clicked, this, &EditMountPointDialogWidget::buttonMoreClicked);
0090     connect(m_ButtonSelect, &QPushButton::clicked, this, &EditMountPointDialogWidget::buttonSelectClicked);
0091     connect(m_EditPath, QOverload<int>::of(&QComboBox::currentIndexChanged),
0092         [=](int index){ currentEntry = entry[index];
0093                         spinDumpFreq().setValue(currentEntry->dumpFreq());
0094                         spinPassNumber().setValue(currentEntry->passNumber());
0095                         setupRadio(currentEntry->entryType());
0096                         for (iterator_BoxOptions = boxOptions().begin(); iterator_BoxOptions != boxOptions().end(); ++iterator_BoxOptions){
0097                             boxOptions()[iterator_BoxOptions->first]->setChecked(false);
0098                         }
0099                         setupOptions(currentEntry->options());
0100                       });
0101     connect(m_EditPath, &QComboBox::currentTextChanged, this, &EditMountPointDialogWidget::currentPathChanged);
0102     currentPathChanged(m_EditPath->currentText());
0103 }
0104 
0105 EditMountPointDialogWidget::~EditMountPointDialogWidget()
0106 {
0107 }
0108 
0109 bool EditMountPointDialogWidget::isValid() const
0110 {
0111     return m_valid;
0112 }
0113 
0114 void EditMountPointDialogWidget::setupOptions(const QStringList& options)
0115 {
0116     QStringList optTmpList;
0117     for (const auto &o : options) {
0118         if (boxOptions().find(o) != boxOptions().end())
0119             boxOptions()[o]->setChecked(true);
0120         else
0121             optTmpList.append(o);
0122     }
0123 
0124     m_Options = optTmpList.join(QLatin1Char(','));
0125 }
0126 
0127 void EditMountPointDialogWidget::setupRadio(const FstabEntry::Type entryType)
0128 {
0129     if (partition().fileSystem().uuid().isEmpty()) {
0130         radioUUID().setEnabled(false);
0131         if (radioUUID().isChecked())
0132             radioDeviceNode().setChecked(true);
0133     }
0134 
0135     if (partition().fileSystem().label().isEmpty()) {
0136         radioLabel().setEnabled(false);
0137         if (radioLabel().isChecked())
0138             radioDeviceNode().setChecked(true);
0139     }
0140     switch (entryType) {
0141     case FstabEntry::Type::uuid:
0142         radioUUID().setChecked(true);
0143         break;
0144 
0145     case FstabEntry::Type::label:
0146         radioLabel().setChecked(true);
0147         break;
0148 
0149     case FstabEntry::Type::partuuid:
0150         radioUUID().setChecked(true);
0151         break;
0152 
0153     case FstabEntry::Type::partlabel:
0154         radioLabel().setChecked(true);
0155         break;
0156 
0157     case FstabEntry::Type::deviceNode:
0158         radioDeviceNode().setChecked(true);
0159         break;
0160     case FstabEntry::Type::comment:
0161         break;
0162     default:
0163         break;
0164     }
0165 }
0166 
0167 void EditMountPointDialogWidget::buttonSelectClicked(bool)
0168 {
0169     const QString s = QFileDialog::getExistingDirectory(this, editPath().currentText());
0170     if (!s.isEmpty())
0171         editPath().setCurrentText(s);
0172 }
0173 
0174 void EditMountPointDialogWidget::removeMountPoint()
0175 {
0176     for (auto it = fstabEntries().begin(); it != fstabEntries().end(); ++it) {
0177         if (editPath().count() <= 1 && (
0178                 (it->fsSpec().contains(partition().deviceNode()) && !partition().deviceNode().isEmpty() ) ||
0179                 (it->fsSpec().contains(partition().fileSystem().uuid()) && !partition().fileSystem().uuid().isEmpty() ) ||
0180                 (it->fsSpec().contains(partition().fileSystem().label()) && !partition().fileSystem().label().isEmpty()) || 
0181                 (it->fsSpec().contains(partition().label()) && !partition().label().isEmpty() ) ||
0182                 (it->fsSpec().contains(partition().uuid()) && !partition().uuid().isEmpty() )))
0183         {
0184             fstabEntries().erase(it);
0185             partition().setMountPoint(QString());
0186         }
0187         else if (editPath().count() > 1 && (&*it == currentEntry))
0188         {
0189             fstabEntries().erase(it);
0190             editPath().removeItem(editPath().currentIndex());
0191             partition().setMountPoint(editPath().itemText(editPath().currentIndex()));
0192             break;
0193         }
0194     }
0195 
0196 }
0197 
0198 void EditMountPointDialogWidget::buttonMoreClicked(bool)
0199 {
0200     QPointer<EditMountOptionsDialog>  dlg = new EditMountOptionsDialog(this, m_Options.split(QLatin1Char(',')));
0201 
0202     if (dlg->exec() == QDialog::Accepted)
0203         setupOptions(dlg->options());
0204 
0205     delete dlg;
0206 }
0207 
0208 QStringList EditMountPointDialogWidget::options() const
0209 {
0210     QStringList optList = m_Options.split(QLatin1Char(','), Qt::SkipEmptyParts);
0211 
0212     const auto keys = boxOptions();
0213     for (const auto &s : keys)
0214         if (s.second->isChecked())
0215             optList.append(s.first);
0216 
0217     return optList;
0218 }
0219 
0220 void EditMountPointDialogWidget::acceptChanges()
0221 {
0222     currentEntry->setDumpFreq(spinDumpFreq().value());
0223     currentEntry->setPassNumber(spinPassNumber().value());
0224     currentEntry->setMountPoint(editPath().currentText());
0225     currentEntry->setOptions(options());
0226 
0227     if (radioUUID().isChecked() && !partition().fileSystem().uuid().isEmpty())
0228         currentEntry->setFsSpec(QStringLiteral("UUID=") + partition().fileSystem().uuid());
0229     else if (radioLabel().isChecked() && !partition().fileSystem().label().isEmpty())
0230         currentEntry->setFsSpec(QStringLiteral("LABEL=") + partition().fileSystem().label());
0231     else
0232         currentEntry->setFsSpec(m_deviceNode);
0233 }
0234 
0235 void EditMountPointDialogWidget::currentPathChanged(const QString &newPath)
0236 {
0237     auto path = newPath.trimmed().toLower();
0238     if (path.isEmpty() || path == QStringLiteral("none")) {
0239         m_valid = false;
0240         m_PathMessage->setVisible(true);
0241     } else {
0242         m_valid = true;
0243         m_PathMessage->setVisible(false);
0244     }
0245     Q_EMIT isValidChanged(m_valid);
0246 }