Compare commits
131 Commits
Author | SHA1 | Date |
---|---|---|
Andrius Štikonas | 83a865411d | |
A. Wilcox | 26e069d6cd | |
l10n daemon script | eb50358b72 | |
ivan tkachenko | 9b015661aa | |
Andrius Štikonas | fd4a330887 | |
l10n daemon script | 6204041935 | |
Andrius Štikonas | 36881cde62 | |
l10n daemon script | d247e027a1 | |
Andrius Štikonas | 5afe143a19 | |
Andrius Štikonas | c9d7e0cd6e | |
Andrius Štikonas | 7c299857c8 | |
Andrius Štikonas | 0c1af38e5e | |
Andrius Štikonas | 6b260fa84e | |
l10n daemon script | e112ebe944 | |
l10n daemon script | 05a96c874f | |
Albert Astals Cid | 76ede03bd2 | |
l10n daemon script | bbcfd8202b | |
l10n daemon script | 1006a8daeb | |
l10n daemon script | b6a52fe2b1 | |
l10n daemon script | 0681ebd790 | |
Andrius Štikonas | 858f8d9bae | |
Andrius Štikonas | d92ebc0b76 | |
Andrius Štikonas | e483bab0d5 | |
Andrius Štikonas | 27b85117c4 | |
Andrius Štikonas | d9ceb50238 | |
l10n daemon script | 237d246457 | |
Laurent Montel | 8a209e9616 | |
l10n daemon script | 3f1949f477 | |
Andrius Štikonas | c05bb54bc5 | |
Andrius Štikonas | fb1708b958 | |
l10n daemon script | 94c1ff7133 | |
l10n daemon script | b4f5faed58 | |
l10n daemon script | 49900e80bf | |
l10n daemon script | e0d6c1ce43 | |
l10n daemon script | cff0f16a7d | |
Andrius Štikonas | 5717c3aa0b | |
Andrius Štikonas | 1c87b494ef | |
Andrius Štikonas | fd7f9b87a9 | |
Andrius Štikonas | eddbd7a301 | |
Andrius Štikonas | fb11a02d24 | |
Andrius Štikonas | 4ef17463ff | |
Andrius Štikonas | 81a5eae665 | |
Andrius Štikonas | 3903ae1b83 | |
Andrius Štikonas | 949ce01ae4 | |
Andrius Štikonas | 5d1c03b9d8 | |
Andrius Štikonas | 1502494eda | |
Andrius Štikonas | e2f097fce8 | |
Andrius Štikonas | 04170918bc | |
Andrius Štikonas | c6e37dbd8e | |
Andrius Štikonas | deb82fe2f9 | |
Andrius Štikonas | 19cda738bd | |
Andrius Štikonas | cbea744bb3 | |
Andrius Štikonas | a69bbb559d | |
Andrius Štikonas | 72b4142bcb | |
Andrius Štikonas | 5174dce64f | |
Andrius Štikonas | 67550ca2f7 | |
Andrius Štikonas | 73de1709e2 | |
Andrius Štikonas | 08d2e3dc2c | |
Andrius Štikonas | 7eb2ceed17 | |
Andrius Štikonas | b0cd5def42 | |
Andrius Štikonas | d7912e21d8 | |
Andrius Štikonas | c31eabc842 | |
Andrius Štikonas | 1d7a4e4010 | |
Andrius Štikonas | 30d428c697 | |
Andrius Štikonas | 5ffc5c6f23 | |
Andrius Štikonas | e58ab02bac | |
Andrius Štikonas | d2fb56bcd2 | |
Tomaz Canabrava | 770e16eb02 | |
Tomaz Canabrava | 36bb57c0dd | |
Tomaz Canabrava | e1774d4026 | |
Tomaz Canabrava | 9093b27bd8 | |
Tomaz Canabrava | 6c14ddb043 | |
Andrius Štikonas | 68c8fecffd | |
Andrius Štikonas | a5bdd5a4eb | |
Andrius Štikonas | 31921c59fa | |
Tomaz Canabrava | 65f986dc29 | |
Albert Astals Cid | 259f562698 | |
Harald Sitter | c79f5831ff | |
Harald Sitter | b3d0cfccaf | |
Ben Cooksley | d9339e4833 | |
Ben Cooksley | 702b30ee3a | |
l10n daemon script | 172b76fe9b | |
Andrius Štikonas | e9fc875c5e | |
l10n daemon script | a9998425fd | |
l10n daemon script | 74218e12d6 | |
Heiko Becker | 644db18c75 | |
Andrius Štikonas | 282cfdcde1 | |
Andrius Štikonas | 6f2be13f68 | |
l10n daemon script | 2734c58069 | |
l10n daemon script | d31f1733b6 | |
Artem Grinev | 00e6b77c29 | |
Artem Grinev | f4664671d6 | |
Albert Astals Cid | c47ee6cae7 | |
l10n daemon script | 4c32c38655 | |
l10n daemon script | b3050dc894 | |
l10n daemon script | f0188249e8 | |
l10n daemon script | ce39e14904 | |
Yaroslav Sidlovsky | 8746ef72fd | |
Albert Astals Cid | ad35460628 | |
l10n daemon script | c06a188d0e | |
Guillaume Girol | 0094461f60 | |
Andrius Štikonas | ad888767bb | |
Oxalica -- | eea84fb605 | |
Andrius Štikonas | 36dfae351f | |
Michael Weghorn | 813e574001 | |
Andrius Štikonas | 31706cffdc | |
Andrius Štikonas | 06f15334ec | |
l10n daemon script | 338811601b | |
Andrius Štikonas | a06d4ba0f7 | |
Andrius Štikonas | 73da1bc514 | |
Andrius Štikonas | b0e5fa66c4 | |
Andrius Štikonas | 502ebc0474 | |
Andrius Štikonas | 04a095a542 | |
Andrius Štikonas | 5da47c26e9 | |
Andrius Štikonas | 551654de0d | |
Andrius Štikonas | d34b617272 | |
Andrius Štikonas | ee0a1e1b41 | |
Andrius Štikonas | c556f39064 | |
Andrius Štikonas | 9dd38744c5 | |
Andrius Štikonas | 4fa91d75f3 | |
Andrius Štikonas | 32d146eed3 | |
Andrius Štikonas | d16d9e8019 | |
Andrius Štikonas | fae9f83451 | |
Andrius Štikonas | 4d3fcb7691 | |
Andrius Štikonas | 9d4ab0e6fd | |
Andrius Štikonas | 26acd7c10d | |
Andrius Štikonas | 70d4819aae | |
Andrius Štikonas | 2382b9e1c5 | |
Gaël PORTAY | 2012e01b88 | |
Gaël PORTAY | 82566e63e7 | |
Albert Astals Cid | 0ee1e958a0 |
|
@ -0,0 +1,8 @@
|
|||
# SPDX-FileCopyrightText: None
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
include:
|
||||
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/linux-qt6.yml
|
||||
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/linux.yml
|
||||
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/freebsd.yml
|
||||
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/reuse-lint.yml
|
|
@ -0,0 +1,11 @@
|
|||
# SPDX-FileCopyrightText: None
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
Dependencies:
|
||||
- 'on': ['@all']
|
||||
'require':
|
||||
'frameworks/extra-cmake-modules': '@latest'
|
||||
'frameworks/kcoreaddons': '@latest'
|
||||
'frameworks/ki18n': '@latest'
|
||||
'frameworks/kwidgetsaddons': '@latest'
|
||||
'libraries/polkit-qt-1': '@latest'
|
|
@ -17,3 +17,8 @@ Copyright: 2020 KDE translators
|
|||
Files: src/util/org.kde.kpmcore.helperinterface.conf
|
||||
License: MIT
|
||||
Copyright: 2018 Andrius Štikonas <andrius@stikonas.eu>
|
||||
|
||||
# Just list of directories
|
||||
Files: src/util/trustedprefixes
|
||||
License: CC0-1.0
|
||||
Copyright: None
|
||||
|
|
|
@ -1,37 +1,39 @@
|
|||
# SPDX-FileCopyrightText: 2008 Volker Lanz <vl@fidra.de>
|
||||
# SPDX-FileCopyrightText: 2015 Teo Mrnjavac <teo@kde.org>
|
||||
# SPDX-FileCopyrightText: 2014-2020 Andrius Štikonas <andrius@stikonas.eu>
|
||||
# SPDX-FileCopyrightText: 2014-2022 Andrius Štikonas <andrius@stikonas.eu>
|
||||
# SPDX-FileCopyrightText: 2020 David Edmundson <kde@davidedmundson.co.uk>
|
||||
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
cmake_minimum_required(VERSION 3.1 FATAL_ERROR)
|
||||
cmake_minimum_required(VERSION 3.16 FATAL_ERROR)
|
||||
|
||||
# KDE Application Version, managed by release script
|
||||
set (RELEASE_SERVICE_VERSION_MAJOR "20")
|
||||
set (RELEASE_SERVICE_VERSION_MINOR "11")
|
||||
set (RELEASE_SERVICE_VERSION_MICRO "80")
|
||||
set (RELEASE_SERVICE_VERSION_MAJOR "22")
|
||||
set (RELEASE_SERVICE_VERSION_MINOR "07")
|
||||
set (RELEASE_SERVICE_VERSION_MICRO "70")
|
||||
set (RELEASE_SERVICE_VERSION "${RELEASE_SERVICE_VERSION_MAJOR}.${RELEASE_SERVICE_VERSION_MINOR}.${RELEASE_SERVICE_VERSION_MICRO}")
|
||||
project(kpmcore VERSION ${RELEASE_SERVICE_VERSION})
|
||||
|
||||
set(SOVERSION "10")
|
||||
set(SOVERSION "12")
|
||||
add_definitions(-D'VERSION="${RELEASE_SERVICE_VERSION}"') #"
|
||||
|
||||
|
||||
set(CMAKE_USE_RELATIVE_PATHS OFF)
|
||||
set(CMAKE_BUILD_WITH_INSTALL_RPATH ON)
|
||||
|
||||
# Note that KPMcore is restricted to only run binaries installed into trusted prefixes
|
||||
# See src/util/trustedprefixes
|
||||
# By default this is set to / and /usr which is good for majority of distros
|
||||
|
||||
# Dependencies
|
||||
set(QT_MIN_VERSION "5.14.0")
|
||||
set(KF5_MIN_VERSION "5.73")
|
||||
set(QT_MIN_VERSION "5.15.0")
|
||||
set(KF5_MIN_VERSION "5.90")
|
||||
set(BLKID_MIN_VERSION "2.33.2")
|
||||
# PolkitQt5-1
|
||||
|
||||
# Runtime
|
||||
# smartmontools 7.0
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(KDE_COMPILERSETTINGS_LEVEL "5.85")
|
||||
|
||||
find_package(ECM ${KF5_MIN_VERSION} REQUIRED NO_MODULE)
|
||||
set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules/")
|
||||
|
@ -49,7 +51,11 @@ ecm_setup_version(${RELEASE_SERVICE_VERSION} VARIABLE_PREFIX KPMCORE
|
|||
PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/KPMcoreConfigVersion.cmake"
|
||||
SOVERSION ${SOVERSION})
|
||||
|
||||
find_package(Qt5 ${QT_MIN_VERSION} CONFIG REQUIRED COMPONENTS
|
||||
if (NOT QT_MAJOR_VERSION)
|
||||
set(QT_MAJOR_VERSION "5")
|
||||
endif()
|
||||
|
||||
find_package(Qt${QT_MAJOR_VERSION} ${QT_MIN_VERSION} COMPONENTS REQUIRED
|
||||
Core
|
||||
DBus
|
||||
Gui
|
||||
|
@ -63,20 +69,9 @@ find_package(KF5 ${KF5_MIN_VERSION} REQUIRED
|
|||
WidgetsAddons
|
||||
)
|
||||
|
||||
find_package(PolkitQt5-1 REQUIRED)
|
||||
find_package(PolkitQt${QT_MAJOR_VERSION}-1 REQUIRED)
|
||||
|
||||
# use sane compile flags
|
||||
add_definitions(
|
||||
-DQT_USE_QSTRINGBUILDER
|
||||
-DQT_NO_CAST_TO_ASCII
|
||||
-DQT_NO_CAST_FROM_ASCII
|
||||
-DQT_STRICT_ITERATORS
|
||||
-DQT_NO_URL_CAST_FROM_STRING
|
||||
-DQT_NO_CAST_FROM_BYTEARRAY
|
||||
-DQT_NO_CAST_TO_BYTEARRAY
|
||||
-DQT_USE_FAST_OPERATOR_PLUS
|
||||
-DQT_NO_KEYWORDS
|
||||
)
|
||||
add_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0x050f00)
|
||||
kde_enable_exceptions()
|
||||
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||
|
@ -87,13 +82,11 @@ endif()
|
|||
add_subdirectory(src)
|
||||
|
||||
# create a Config.cmake and a ConfigVersion.cmake file and install them
|
||||
set(INCLUDE_INSTALL_DIR "include/kpmcore/")
|
||||
set(CMAKECONFIG_INSTALL_DIR "${CMAKECONFIG_INSTALL_PREFIX}/KPMcore")
|
||||
set(CMAKECONFIG_INSTALL_DIR "${KDE_INSTALL_CMAKEPACKAGEDIR}/KPMcore")
|
||||
|
||||
configure_package_config_file("${CMAKE_CURRENT_SOURCE_DIR}/KPMcoreConfig.cmake.in"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/KPMcoreConfig.cmake"
|
||||
INSTALL_DESTINATION ${CMAKECONFIG_INSTALL_DIR}
|
||||
PATH_VARS INCLUDE_INSTALL_DIR
|
||||
)
|
||||
|
||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/KPMcoreConfig.cmake"
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
# SPDX-FileCopyrightText: 2015 Teo Mrnjavac <teo@kde.org>
|
||||
# SPDX-FileCopyrightText: 2016 Andrius Štikonas <andrius@stikonas.eu>
|
||||
# SPDX-FileCopyrightText: 2016-2022 Andrius Štikonas <andrius@stikonas.eu>
|
||||
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
@PACKAGE_INIT@
|
||||
|
||||
include(CMakeFindDependencyMacro)
|
||||
find_dependency(Qt5Core @QT_MIN_VERSION@)
|
||||
find_dependency(Qt@QT_MAJOR_VERSION@ @QT_MIN_VERSION@ COMPONENTS Core)
|
||||
|
||||
set_and_check(KPMCORE_INCLUDE_DIR "@PACKAGE_INCLUDE_INSTALL_DIR@")
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/KPMcoreTargets.cmake")
|
||||
|
|
|
@ -35,7 +35,6 @@ looks like this:
|
|||
|
||||
```cmake
|
||||
find_package( KPMcore 3.2 REQUIRED )
|
||||
include_directories( ${KPMCORE_INCLUDE_DIR} )
|
||||
target_link_libraries( target kpmcore )
|
||||
```
|
||||
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
# SPDX-FileCopyrightText: none
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
maintainer: stikonas
|
||||
description: KPMcore, the KDE Partition Manager core, is a library for examining and modifying partitions, disk devices, and filesystems.
|
||||
platforms:
|
||||
- name: Linux
|
||||
release: true
|
||||
public_lib: true
|
||||
public_source_dirs:
|
||||
- src
|
||||
libraries:
|
||||
- cmake: kpmcore
|
||||
cmakename: KPMcore
|
||||
irc: kde-devel
|
||||
mailinglist: kde-devel
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
# SPDX-FileCopyrightText: 2008,2012 Volker Lanz <vl@fidra.de>
|
||||
# SPDX-FileCopyrightText: 2015 Teo Mrnjavac <teo@kde.org>
|
||||
# SPDX-FileCopyrightText: 2014-2020 Andrius Štikonas <andrius@stikonas.eu>
|
||||
# SPDX-FileCopyrightText: 2021 Harald Sitter <sitter@kde.org>
|
||||
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
|
@ -32,11 +33,11 @@ ki18n_wrap_ui(kpmcore_SRCS ${gui_UIFILES})
|
|||
|
||||
add_library(kpmcore SHARED ${kpmcore_SRCS})
|
||||
target_link_libraries( kpmcore PUBLIC
|
||||
Qt5::Core
|
||||
Qt::Core
|
||||
PRIVATE
|
||||
${BLKID_LIBRARIES}
|
||||
Qt5::DBus
|
||||
Qt5::Gui
|
||||
Qt::DBus
|
||||
Qt::Gui
|
||||
KF5::I18n
|
||||
KF5::CoreAddons
|
||||
KF5::WidgetsAddons
|
||||
|
@ -47,14 +48,16 @@ generate_export_header(kpmcore
|
|||
)
|
||||
list(APPEND UTIL_LIB_HDRS ${CMAKE_CURRENT_BINARY_DIR}/util/libpartitionmanagerexport.h)
|
||||
|
||||
install(TARGETS kpmcore EXPORT KPMcoreTargets ${INSTALL_TARGETS_DEFAULT_ARGS})
|
||||
install(FILES ${CORE_LIB_HDRS} DESTINATION ${INCLUDE_INSTALL_DIR}/kpmcore/core/ COMPONENT Devel)
|
||||
install(FILES ${BACKEND_LIB_HDRS} DESTINATION ${INCLUDE_INSTALL_DIR}/kpmcore/backend/ COMPONENT Devel)
|
||||
install(FILES ${FS_LIB_HDRS} DESTINATION ${INCLUDE_INSTALL_DIR}/kpmcore/fs/ COMPONENT Devel)
|
||||
install(FILES ${JOBS_LIB_HDRS} DESTINATION ${INCLUDE_INSTALL_DIR}/kpmcore/jobs/ COMPONENT Devel)
|
||||
install(FILES ${OPS_LIB_HDRS} DESTINATION ${INCLUDE_INSTALL_DIR}/kpmcore/ops/ COMPONENT Devel)
|
||||
install(FILES ${UTIL_LIB_HDRS} DESTINATION ${INCLUDE_INSTALL_DIR}/kpmcore/util/ COMPONENT Devel)
|
||||
install(FILES ${GUI_LIB_HDRS} DESTINATION ${INCLUDE_INSTALL_DIR}/kpmcore/gui/ COMPONENT Devel)
|
||||
target_include_directories(kpmcore INTERFACE "$<INSTALL_INTERFACE:${KDE_INSTALL_INCLUDEDIR}/kpmcore>")
|
||||
|
||||
install(TARGETS kpmcore EXPORT KPMcoreTargets ${KDE_INSTALL_TARGETS_DEFAULT_ARGS})
|
||||
install(FILES ${CORE_LIB_HDRS} DESTINATION ${KDE_INSTALL_INCLUDEDIR}/kpmcore/core/ COMPONENT Devel)
|
||||
install(FILES ${BACKEND_LIB_HDRS} DESTINATION ${KDE_INSTALL_INCLUDEDIR}/kpmcore/backend/ COMPONENT Devel)
|
||||
install(FILES ${FS_LIB_HDRS} DESTINATION ${KDE_INSTALL_INCLUDEDIR}/kpmcore/fs/ COMPONENT Devel)
|
||||
install(FILES ${JOBS_LIB_HDRS} DESTINATION ${KDE_INSTALL_INCLUDEDIR}/kpmcore/jobs/ COMPONENT Devel)
|
||||
install(FILES ${OPS_LIB_HDRS} DESTINATION ${KDE_INSTALL_INCLUDEDIR}/kpmcore/ops/ COMPONENT Devel)
|
||||
install(FILES ${UTIL_LIB_HDRS} DESTINATION ${KDE_INSTALL_INCLUDEDIR}/kpmcore/util/ COMPONENT Devel)
|
||||
install(FILES ${GUI_LIB_HDRS} DESTINATION ${KDE_INSTALL_INCLUDEDIR}/kpmcore/gui/ COMPONENT Devel)
|
||||
|
||||
############################################
|
||||
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
#include "util/globallog.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QFileInfo>
|
||||
#include <KLocalizedString>
|
||||
|
||||
struct CoreBackendPrivate
|
||||
{
|
||||
|
@ -29,6 +31,20 @@ CoreBackend::~CoreBackend()
|
|||
{
|
||||
}
|
||||
|
||||
bool CoreBackend::isPolkitInstalledCorrectly() {
|
||||
// Assume PACKAGE_DATA_DIR is /usr/share, this is defined on polkit on buildtime so this might be wrong.
|
||||
// This is a warning, not a hard failure, so it does not matter much.
|
||||
QFileInfo fInfo(QStringLiteral("/usr/share/polkit-1/actions/org.kde.kpmcore.externalcommand.policy"));
|
||||
|
||||
// TODO: Port kpm to qCDebug, currently everything is debug.
|
||||
if (!fInfo.exists()) {
|
||||
qDebug() << "Installation might be wrong, we can't locate `org.kde.kpmcore.externalcommand.policy` on the polkit actions folder.";
|
||||
qDebug() << "Please check if your Installation is on a different prefix and copy it to /usr/share/polkit-1/actions";
|
||||
qDebug() << "That's specified for your distro. Since this is distro specific, you need to look at your distribution documentation.";
|
||||
}
|
||||
return fInfo.exists();
|
||||
}
|
||||
|
||||
void CoreBackend::emitProgress(int i)
|
||||
{
|
||||
Q_EMIT progress(i);
|
||||
|
|
|
@ -170,6 +170,8 @@ public:
|
|||
*/
|
||||
virtual void emitScanProgress(const QString& deviceNode, int i);
|
||||
|
||||
static bool isPolkitInstalledCorrectly();
|
||||
|
||||
protected:
|
||||
static void setPartitionTableForDevice(Device& d, PartitionTable* p);
|
||||
static void setPartitionTableMaxPrimaries(PartitionTable& p, qint32 max_primaries);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2010 Volker Lanz <vl@fidra.de>
|
||||
SPDX-FileCopyrightText: 2014-2018 Andrius Štikonas <andrius@stikonas.eu>
|
||||
SPDX-FileCopyrightText: 2014-2021 Andrius Štikonas <andrius@stikonas.eu>
|
||||
SPDX-FileCopyrightText: 2015 Teo Mrnjavac <teo@kde.org>
|
||||
SPDX-FileCopyrightText: 2018 Caio Jordão Carvalho <caiojcarvalho@gmail.com>
|
||||
|
||||
|
@ -17,7 +17,6 @@
|
|||
|
||||
#include <KLocalizedString>
|
||||
#include <KPluginFactory>
|
||||
#include <KPluginLoader>
|
||||
#include <KPluginMetaData>
|
||||
|
||||
struct CoreBackendManagerPrivate
|
||||
|
@ -51,13 +50,7 @@ CoreBackend* CoreBackendManager::backend()
|
|||
|
||||
QVector<KPluginMetaData> CoreBackendManager::list() const
|
||||
{
|
||||
auto filter = [&](const KPluginMetaData &metaData) {
|
||||
return metaData.serviceTypes().contains(QStringLiteral("PartitionManager/Plugin")) &&
|
||||
metaData.category().contains(QStringLiteral("BackendPlugin"));
|
||||
};
|
||||
|
||||
// find backend plugins in standard path (e.g. /usr/lib64/qt5/plugins) using filter from above
|
||||
return KPluginLoader::findPlugins(QString(), filter);
|
||||
return KPluginMetaData::findPlugins(QStringLiteral("kpmcore"));
|
||||
}
|
||||
|
||||
bool CoreBackendManager::load(const QString& name)
|
||||
|
@ -65,29 +58,25 @@ bool CoreBackendManager::load(const QString& name)
|
|||
if (backend())
|
||||
unload();
|
||||
|
||||
KPluginLoader loader(name);
|
||||
QString path = QStringLiteral("kpmcore/") + name;
|
||||
|
||||
KPluginFactory* factory = loader.factory();
|
||||
KPluginMetaData metadata(path);
|
||||
d->m_Backend = KPluginFactory::instantiatePlugin<CoreBackend>(metadata).plugin;
|
||||
|
||||
if (factory != nullptr) {
|
||||
d->m_Backend = factory->create<CoreBackend>(nullptr);
|
||||
if (!backend()) {
|
||||
qWarning() << "Could not create instance of plugin " << name;
|
||||
return false;
|
||||
}
|
||||
|
||||
QString id = loader.metaData().toVariantMap().value(QStringLiteral("MetaData"))
|
||||
.toMap().value(QStringLiteral("KPlugin")).toMap().value(QStringLiteral("Id")).toString();
|
||||
QString version = loader.metaData().toVariantMap().value(QStringLiteral("MetaData"))
|
||||
.toMap().value(QStringLiteral("KPlugin")).toMap().value(QStringLiteral("Version")).toString();
|
||||
QString id = metadata.pluginId();
|
||||
QString version = metadata.version();
|
||||
if (id.isEmpty())
|
||||
return false;
|
||||
|
||||
backend()->setId(id);
|
||||
backend()->setVersion(version);
|
||||
qDebug() << "Loaded backend plugin: " << backend()->id();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
qWarning() << "Could not load plugin for core backend " << name << ": " << loader.errorString();
|
||||
return false;
|
||||
}
|
||||
|
||||
void CoreBackendManager::unload()
|
||||
|
|
|
@ -14,10 +14,10 @@
|
|||
|
||||
#include <memory>
|
||||
|
||||
#include <QStringList>
|
||||
#include <QVector>
|
||||
|
||||
class QString;
|
||||
class QStringList;
|
||||
class KPluginMetaData;
|
||||
class CoreBackend;
|
||||
struct CoreBackendManagerPrivate;
|
||||
|
|
|
@ -82,10 +82,17 @@ FstabEntryList readFstabEntries( const QString& fstabPath )
|
|||
// (4) dump frequency (optional, defaults to 0), no comment is allowed if omitted,
|
||||
// (5) pass number (optional, defaults to 0), no comment is allowed if omitted,
|
||||
// (#) comment (optional).
|
||||
|
||||
// Handle deprecated subtypes, e.g. sshfs#example. They are not relevant for partitioning, ignore them.
|
||||
if (splitLine.size() < 3) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto fsSpec = splitLine.at(0);
|
||||
auto mountPoint = unescapeSpaces(splitLine.at(1));
|
||||
auto fsType = splitLine.at(2);
|
||||
auto options = splitLine.at(3);
|
||||
// Options may be omitted in some rare cases like NixOS generated fstab.
|
||||
auto options = splitLine.length() >= 4 ? splitLine.at(3) : QStringLiteral("defaults");
|
||||
|
||||
switch (splitLine.length()) {
|
||||
case 4:
|
||||
|
@ -224,8 +231,8 @@ static QString findBlkIdDevice(const char *token, const QString& value)
|
|||
free(c);
|
||||
}
|
||||
#else
|
||||
Q_UNUSED(token);
|
||||
Q_UNUSED(value);
|
||||
Q_UNUSED(token)
|
||||
Q_UNUSED(value)
|
||||
#endif
|
||||
|
||||
return rval;
|
||||
|
@ -233,7 +240,8 @@ static QString findBlkIdDevice(const char *token, const QString& value)
|
|||
|
||||
static void parseFsSpec(const QString& m_fsSpec, FstabEntry::Type& m_entryType, QString& m_deviceNode)
|
||||
{
|
||||
m_entryType = FstabEntry::Type::comment;
|
||||
m_entryType = FstabEntry::Type::other;
|
||||
m_deviceNode = m_fsSpec;
|
||||
if (m_fsSpec.startsWith(QStringLiteral("UUID="))) {
|
||||
m_entryType = FstabEntry::Type::uuid;
|
||||
m_deviceNode = findBlkIdDevice("UUID", QString(m_fsSpec).remove(QStringLiteral("UUID=")));
|
||||
|
@ -248,7 +256,8 @@ static void parseFsSpec(const QString& m_fsSpec, FstabEntry::Type& m_entryType,
|
|||
m_deviceNode = findBlkIdDevice("PARTLABEL", QString(m_fsSpec).remove(QStringLiteral("PARTLABEL=")));
|
||||
} else if (m_fsSpec.startsWith(QStringLiteral("/"))) {
|
||||
m_entryType = FstabEntry::Type::deviceNode;
|
||||
m_deviceNode = m_fsSpec;
|
||||
} else if (m_fsSpec.isEmpty()) {
|
||||
m_entryType = FstabEntry::Type::comment;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -258,7 +267,7 @@ std::array<unsigned int, 4> fstabColumnWidth(const FstabEntryList& fstabEntries)
|
|||
{
|
||||
std::array<unsigned int, 4> columnWidth;
|
||||
|
||||
#define FIELD_WIDTH(x) 3 + std::max_element(fstabEntries.begin(), fstabEntries.end(), [](const FstabEntry& a, const FstabEntry& b) {return a.x().length() < b.x().length(); })->x().length();
|
||||
#define FIELD_WIDTH(x) 3 + escapeSpaces(std::max_element(fstabEntries.begin(), fstabEntries.end(), [](const FstabEntry& a, const FstabEntry& b) {return escapeSpaces(a.x()).length() < escapeSpaces(b.x()).length(); })->x()).length();
|
||||
|
||||
columnWidth[0] = FIELD_WIDTH(fsSpec);
|
||||
columnWidth[1] = FIELD_WIDTH(mountPoint);
|
||||
|
@ -286,7 +295,7 @@ static void writeEntry(QTextStream& s, const FstabEntry& entry, std::array<unsig
|
|||
<< entry.comment() << "\n";
|
||||
}
|
||||
|
||||
bool writeMountpoints(const FstabEntryList& fstabEntries, const QString& filename)
|
||||
bool writeMountpoints(const FstabEntryList& fstabEntries)
|
||||
{
|
||||
QString fstabContents;
|
||||
QTextStream out(&fstabContents);
|
||||
|
@ -297,5 +306,5 @@ bool writeMountpoints(const FstabEntryList& fstabEntries, const QString& filenam
|
|||
writeEntry(out, e, columnWidth);
|
||||
|
||||
ExternalCommand cmd;
|
||||
return cmd.createFile(fstabContents.toLocal8Bit(), filename);
|
||||
return cmd.writeFstab(fstabContents.toLocal8Bit());
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ struct FstabEntryPrivate;
|
|||
class LIBKPMCORE_EXPORT FstabEntry
|
||||
{
|
||||
public:
|
||||
enum class Type { deviceNode, uuid, label, partlabel, partuuid, comment };
|
||||
enum class Type { deviceNode, uuid, label, partlabel, partuuid, comment, other };
|
||||
|
||||
FstabEntry(const QString& fsSpec, const QString& mountPoint, const QString& type, const QString& options, int dumpFreq = 0, int passNumber = 0, const QString& comment = QString());
|
||||
|
||||
|
@ -116,6 +116,6 @@ QString unescapeSpaces(const QString& mountPoint);
|
|||
|
||||
LIBKPMCORE_EXPORT FstabEntryList readFstabEntries(const QString& fstabPath = QStringLiteral("/etc/fstab"));
|
||||
LIBKPMCORE_EXPORT QStringList possibleMountPoints(const QString& deviceNode, const QString& fstabPath = QStringLiteral("/etc/fstab"));
|
||||
LIBKPMCORE_EXPORT bool writeMountpoints(const FstabEntryList& fstabEntries, const QString& filename = QStringLiteral("/etc/fstab"));
|
||||
LIBKPMCORE_EXPORT bool writeMountpoints(const FstabEntryList& fstabEntries);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
class PartitionTable;
|
||||
class Report;
|
||||
class Partition;
|
||||
class SmartStatus;
|
||||
|
||||
/** Representation of LVM Volume Group(VG).
|
||||
|
||||
|
|
|
@ -264,25 +264,25 @@ private:
|
|||
m_Number = n;
|
||||
}
|
||||
|
||||
qint32 m_Number;
|
||||
qint32 m_Number = 0;
|
||||
Partitions m_Children;
|
||||
QPointer< PartitionNode > m_Parent;
|
||||
FileSystem* m_FileSystem;
|
||||
QPointer< PartitionNode > m_Parent = nullptr;
|
||||
FileSystem* m_FileSystem = nullptr;
|
||||
PartitionRole m_Roles;
|
||||
qint64 m_FirstSector;
|
||||
qint64 m_LastSector;
|
||||
qint64 m_FirstSector = 0;
|
||||
qint64 m_LastSector = 0;
|
||||
QString m_DevicePath;
|
||||
QString m_Label;
|
||||
QString m_Type;
|
||||
QString m_UUID;
|
||||
quint64 m_Attributes;
|
||||
quint64 m_Attributes = 0;
|
||||
QString m_PartitionPath;
|
||||
QString m_MountPoint;
|
||||
PartitionTable::Flags m_AvailableFlags;
|
||||
PartitionTable::Flags m_ActiveFlags;
|
||||
bool m_IsMounted;
|
||||
qint64 m_SectorSize;
|
||||
State m_State;
|
||||
bool m_IsMounted = false;
|
||||
qint64 m_SectorSize = 0;
|
||||
State m_State = None;
|
||||
};
|
||||
|
||||
QTextStream& operator<<(QTextStream& stream, const Partition& p);
|
||||
|
|
|
@ -65,7 +65,7 @@ static QString getPrettyValue(quint64 value, SmartAttributeUnit unit)
|
|||
|
||||
switch (unit) {
|
||||
case SmartAttributeUnit::Miliseconds:
|
||||
rval = KFormat().formatDuration(value);
|
||||
rval = KFormat().formatSpelloutDuration(value);
|
||||
break;
|
||||
|
||||
case SmartAttributeUnit::Sectors:
|
||||
|
|
|
@ -117,7 +117,11 @@ void SmartParser::loadSmartOutput()
|
|||
if (m_SmartOutput.isEmpty()) {
|
||||
ExternalCommand smartctl(QStringLiteral("smartctl"), { QStringLiteral("--all"), QStringLiteral("--json"), devicePath() });
|
||||
|
||||
if (smartctl.run() && smartctl.exitCode() == 0) {
|
||||
// Exit status of smartctl is a bitfield, check that bits 0 and 1 are not set:
|
||||
// - bit 0: command line did not parse;
|
||||
// - bit 1: device open failed.
|
||||
// See `man 8 smartctl` for more details.
|
||||
if (smartctl.run() && (smartctl.exitCode() & 1) == 0 && (smartctl.exitCode() & 2) == 0) {
|
||||
QByteArray output = smartctl.rawOutput();
|
||||
|
||||
m_SmartOutput = QJsonDocument::fromJson(output);
|
||||
|
|
|
@ -42,6 +42,8 @@ public:
|
|||
bool writeLabel(Report& report, const QString& deviceNode, const QString& newLabel) override;
|
||||
bool writeLabelOnline(Report& report, const QString& deviceNode, const QString& mountPoint, const QString& newLabel) override;
|
||||
bool updateUUID(Report& report, const QString& deviceNode) const override;
|
||||
QString posixPermissions() const override { return implPosixPermissions(); };
|
||||
void setPosixPermissions(const QString& permissions) override { implSetPosixPermissions(permissions); };
|
||||
|
||||
CommandSupportType supportGetUsed() const override {
|
||||
return m_GetUsed;
|
||||
|
|
|
@ -28,6 +28,7 @@ FileSystem::CommandSupportType exfat::m_Backup = FileSystem::cmdSupportNone;
|
|||
FileSystem::CommandSupportType exfat::m_SetLabel = FileSystem::cmdSupportNone;
|
||||
FileSystem::CommandSupportType exfat::m_UpdateUUID = FileSystem::cmdSupportNone;
|
||||
FileSystem::CommandSupportType exfat::m_GetUUID = FileSystem::cmdSupportNone;
|
||||
bool exfat::exfatUtils = false;
|
||||
|
||||
exfat::exfat(qint64 firstsector, qint64 lastsector, qint64 sectorsused, const QString& label, const QVariantMap& features) :
|
||||
FileSystem(firstsector, lastsector, sectorsused, label, features, FileSystem::Type::Exfat)
|
||||
|
@ -36,11 +37,20 @@ exfat::exfat(qint64 firstsector, qint64 lastsector, qint64 sectorsused, const QS
|
|||
|
||||
void exfat::init()
|
||||
{
|
||||
m_Create = findExternal(QStringLiteral("mkfs.exfat")) ? cmdSupportFileSystem : cmdSupportNone;
|
||||
m_Check = findExternal(QStringLiteral("exfatfsck"), QStringList(), 1) ? cmdSupportFileSystem : cmdSupportNone;
|
||||
// Check if we are using exfat-utils or exfatprogs
|
||||
exfatUtils = findExternal(QStringLiteral("mkexfatfs"));
|
||||
if (exfatUtils) {
|
||||
m_Create = cmdSupportFileSystem;
|
||||
m_Check = findExternal(QStringLiteral("fsck.exfat"), {}, 1) ? cmdSupportFileSystem : cmdSupportNone;
|
||||
m_SetLabel = findExternal(QStringLiteral("exfatlabel")) ? cmdSupportFileSystem : cmdSupportNone;
|
||||
}
|
||||
else {
|
||||
m_Create = findExternal(QStringLiteral("mkfs.exfat"), {}, 1) ? cmdSupportFileSystem : cmdSupportNone;
|
||||
m_Check = findExternal(QStringLiteral("fsck.exfat"), {}, 16) ? cmdSupportFileSystem : cmdSupportNone;
|
||||
m_SetLabel = findExternal(QStringLiteral("tune.exfat")) ? cmdSupportFileSystem : cmdSupportNone;
|
||||
}
|
||||
|
||||
m_GetLabel = cmdSupportCore;
|
||||
m_SetLabel = findExternal(QStringLiteral("exfatlabel")) ? cmdSupportFileSystem : cmdSupportNone;
|
||||
m_UpdateUUID = cmdSupportNone;
|
||||
|
||||
m_Copy = (m_Check != cmdSupportNone) ? cmdSupportCore : cmdSupportNone;
|
||||
|
@ -70,7 +80,7 @@ bool exfat::supportToolFound() const
|
|||
|
||||
FileSystem::SupportTool exfat::supportToolName() const
|
||||
{
|
||||
return SupportTool(QStringLiteral("exfat-utils"), QUrl(QStringLiteral("https://github.com/relan/exfat")));
|
||||
return SupportTool(QStringLiteral("exfatprogs"), QUrl(QStringLiteral("https://github.com/exfatprogs/exfatprogs")));
|
||||
}
|
||||
|
||||
qint64 exfat::maxCapacity() const
|
||||
|
@ -85,7 +95,7 @@ int exfat::maxLabelLength() const
|
|||
|
||||
bool exfat::check(Report& report, const QString& deviceNode) const
|
||||
{
|
||||
ExternalCommand cmd(report, QStringLiteral("exfatfsck"), { deviceNode });
|
||||
ExternalCommand cmd(report, QStringLiteral("fsck.exfat"), { deviceNode });
|
||||
return cmd.run(-1) && cmd.exitCode() == 0;
|
||||
}
|
||||
|
||||
|
@ -97,7 +107,16 @@ bool exfat::create(Report& report, const QString& deviceNode)
|
|||
|
||||
bool exfat::writeLabel(Report& report, const QString& deviceNode, const QString& newLabel)
|
||||
{
|
||||
ExternalCommand cmd(report, QStringLiteral("exfatlabel"), { deviceNode, newLabel });
|
||||
ExternalCommand cmd(report);
|
||||
if (exfatUtils) {
|
||||
cmd.setCommand(QStringLiteral("exfatlabel"));
|
||||
cmd.setArgs({ deviceNode, newLabel });
|
||||
}
|
||||
else {
|
||||
cmd.setCommand(QStringLiteral("tune.exfat"));
|
||||
cmd.setArgs({ deviceNode, QStringLiteral("-L"), newLabel });
|
||||
}
|
||||
|
||||
return cmd.run(-1) && cmd.exitCode() == 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -96,6 +96,9 @@ public:
|
|||
static CommandSupportType m_SetLabel;
|
||||
static CommandSupportType m_UpdateUUID;
|
||||
static CommandSupportType m_GetUUID;
|
||||
|
||||
private:
|
||||
static bool exfatUtils;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -91,6 +91,9 @@ public:
|
|||
SupportTool supportToolName() const override;
|
||||
bool supportToolFound() const override;
|
||||
|
||||
QString posixPermissions() const override { return implPosixPermissions(); };
|
||||
void setPosixPermissions(const QString& permissions) override { implSetPosixPermissions(permissions); };
|
||||
|
||||
public:
|
||||
static CommandSupportType m_GetUsed;
|
||||
static CommandSupportType m_GetLabel;
|
||||
|
|
|
@ -42,6 +42,9 @@ public:
|
|||
CommandSupportType supportGrowOnline() const override {
|
||||
return m_Grow;
|
||||
}
|
||||
|
||||
QString posixPermissions() const override { return implPosixPermissions(); };
|
||||
void setPosixPermissions(const QString& permissions) override { implSetPosixPermissions(permissions); };
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -42,6 +42,9 @@ public:
|
|||
CommandSupportType supportGrowOnline() const override {
|
||||
return m_Grow;
|
||||
}
|
||||
|
||||
QString posixPermissions() const override { return implPosixPermissions(); };
|
||||
void setPosixPermissions(const QString& permissions) override { implSetPosixPermissions(permissions); };
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -40,6 +40,8 @@ public:
|
|||
bool resize(Report& report, const QString& deviceNode, qint64 length) const override;
|
||||
// bool writeLabel(Report& report, const QString& deviceNode, const QString& newLabel) override;
|
||||
// bool updateUUID(Report& report, const QString& deviceNode) const override;
|
||||
QString posixPermissions() const override { return implPosixPermissions(); };
|
||||
void setPosixPermissions(const QString& permissions) override { implSetPosixPermissions(permissions); };
|
||||
|
||||
CommandSupportType supportGetUsed() const override {
|
||||
return m_GetUsed;
|
||||
|
|
|
@ -140,7 +140,8 @@ bool fat12::writeLabel(Report& report, const QString& deviceNode, const QString&
|
|||
{
|
||||
report.line() << xi18nc("@info:progress", "Setting label for partition <filename>%1</filename> to %2", deviceNode, newLabel.toUpper());
|
||||
|
||||
ExternalCommand cmd(report, QStringLiteral("fatlabel"), { deviceNode, newLabel.toUpper() });
|
||||
const QString label = newLabel.isEmpty() ? QStringLiteral("-r") : newLabel.toUpper();
|
||||
ExternalCommand cmd(report, QStringLiteral("fatlabel"), { deviceNode, label });
|
||||
return cmd.run(-1) && cmd.exitCode() == 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include <QFileInfo>
|
||||
#include <QStandardPaths>
|
||||
#include <QStorageInfo>
|
||||
#include <QTemporaryDir>
|
||||
|
||||
const std::vector<QColor> FileSystem::defaultColorCode =
|
||||
{
|
||||
|
@ -80,6 +81,7 @@ struct FileSystemPrivate {
|
|||
qint64 m_SectorsUsed;
|
||||
QString m_Label;
|
||||
QString m_UUID;
|
||||
QString m_posixPermissions;
|
||||
QStringList m_AvailableFeatures;
|
||||
QVariantMap m_Features;
|
||||
};
|
||||
|
@ -126,6 +128,67 @@ FileSystem::~FileSystem()
|
|||
{
|
||||
}
|
||||
|
||||
QString FileSystem::implPosixPermissions() const
|
||||
{
|
||||
return d->m_posixPermissions;
|
||||
}
|
||||
|
||||
void FileSystem::implSetPosixPermissions(const QString& permissions)
|
||||
{
|
||||
d->m_posixPermissions = permissions;
|
||||
}
|
||||
|
||||
|
||||
bool FileSystem::execChangePosixPermission(Report& report, const QString& deviceNode)
|
||||
{
|
||||
// do nothing if the posix permissions is not used here.
|
||||
if (d->m_posixPermissions.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
QTemporaryDir tmpDir;
|
||||
|
||||
ExternalCommand mountCmd(report, QStringLiteral("mount"),
|
||||
{ deviceNode, tmpDir.path() });
|
||||
|
||||
bool step = mountCmd.run() && mountCmd.exitCode() == 0;
|
||||
if (!step) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ExternalCommand chmodCmd(report, QStringLiteral("chmod"),
|
||||
// forcing recursive, should be empty but
|
||||
// programming is weird.
|
||||
{
|
||||
d->m_posixPermissions,
|
||||
tmpDir.path(),
|
||||
QStringLiteral("--recursive")
|
||||
});
|
||||
|
||||
const bool chmodStep = chmodCmd.run() && chmodCmd.exitCode() == 0;
|
||||
|
||||
ExternalCommand umountCmd(report, QStringLiteral("umount"),
|
||||
// forcing recursive, should be empty but
|
||||
// programming is weird.
|
||||
{
|
||||
deviceNode,
|
||||
});
|
||||
|
||||
const bool umountStep = umountCmd.run() && umountCmd.exitCode() == 0;
|
||||
|
||||
// we can't return false if chmodStep fails because we still need to umount
|
||||
// the drive.
|
||||
if (!chmodStep) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!umountStep) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Reads the capacity in use on this FileSystem
|
||||
@param deviceNode the device node for the Partition the FileSystem is on
|
||||
@return the used capacity in bytes or -1 in case of an error
|
||||
|
|
|
@ -113,6 +113,9 @@ protected:
|
|||
FileSystem(qint64 firstsector, qint64 lastsector, qint64 sectorsused, const QString& label, FileSystem::Type type);
|
||||
FileSystem(qint64 firstsector, qint64 lastsector, qint64 sectorsused, const QString& label, const QVariantMap& features, FileSystem::Type type);
|
||||
|
||||
QString implPosixPermissions() const;
|
||||
void implSetPosixPermissions(const QString& permissions);
|
||||
|
||||
public:
|
||||
virtual ~FileSystem();
|
||||
|
||||
|
@ -199,6 +202,14 @@ public:
|
|||
virtual SupportTool supportToolName() const;
|
||||
virtual bool supportToolFound() const;
|
||||
|
||||
virtual QString posixPermissions() const { return QString{}; };
|
||||
virtual void setPosixPermissions(const QString& permissions) { Q_UNUSED(permissions); };
|
||||
|
||||
// Tries to change the posix permission on the filesystem, if the
|
||||
// filesystem supports it. by supports I mean reimplements `posixPermissions()`
|
||||
// and setPosixPermissions.
|
||||
bool execChangePosixPermission(Report& report, const QString& deviceNode);
|
||||
|
||||
/**
|
||||
* Returns the (possibly translated) name of the type of this filesystem.
|
||||
* @see nameForType()
|
||||
|
|
|
@ -37,6 +37,8 @@ public:
|
|||
|
||||
bool check(Report& report, const QString& deviceNode) const override;
|
||||
bool create(Report& report, const QString& deviceNode) override;
|
||||
QString posixPermissions() const override { return implPosixPermissions(); };
|
||||
void setPosixPermissions(const QString& permissions) override { implSetPosixPermissions(permissions); };
|
||||
|
||||
CommandSupportType supportGetLabel() const override {
|
||||
return m_GetLabel;
|
||||
|
|
|
@ -41,6 +41,8 @@ public:
|
|||
bool resizeOnline(Report& report, const QString& deviceNode, const QString& mountPoint, qint64 length) const override;
|
||||
bool writeLabel(Report& report, const QString& deviceNode, const QString& newLabel) override;
|
||||
bool writeLabelOnline(Report& report, const QString& deviceNode, const QString& mountPoint, const QString& newLabel) override;
|
||||
QString posixPermissions() const override { return implPosixPermissions(); };
|
||||
void setPosixPermissions(const QString& permissions) override { implSetPosixPermissions(permissions); };
|
||||
|
||||
CommandSupportType supportGetUsed() const override {
|
||||
return m_GetUsed;
|
||||
|
|
|
@ -122,12 +122,6 @@ bool linuxswap::writeLabel(Report& report, const QString& deviceNode, const QStr
|
|||
return cmd.run(-1) && cmd.exitCode() == 0;
|
||||
}
|
||||
|
||||
bool linuxswap::writeLabelOnline(Report& report, const QString& deviceNode, const QString& mountPoint, const QString& newLabel)
|
||||
{
|
||||
Q_UNUSED(mountPoint)
|
||||
return writeLabel(report, deviceNode, newLabel);
|
||||
}
|
||||
|
||||
QString linuxswap::mountTitle() const
|
||||
{
|
||||
return xi18nc("@title:menu", "Activate swap");
|
||||
|
|
|
@ -40,7 +40,6 @@ public:
|
|||
bool create(Report& report, const QString& deviceNode) override;
|
||||
bool resize(Report& report, const QString& deviceNode, qint64 length) const override;
|
||||
bool writeLabel(Report& report, const QString& deviceNode, const QString& newLabel) override;
|
||||
bool writeLabelOnline(Report& report, const QString& deviceNode, const QString& mountPoint, const QString& newLabel) override;
|
||||
bool copy(Report& report, const QString& targetDeviceNode, const QString& sourceDeviceNode) const override;
|
||||
bool updateUUID(Report& report, const QString& deviceNode) const override;
|
||||
qint64 readUsedCapacity(const QString& deviceNode) const override;
|
||||
|
@ -76,9 +75,6 @@ public:
|
|||
CommandSupportType supportSetLabel() const override {
|
||||
return m_SetLabel;
|
||||
}
|
||||
CommandSupportType supportSetLabelOnline() const override {
|
||||
return m_SetLabel;
|
||||
}
|
||||
CommandSupportType supportUpdateUUID() const override {
|
||||
return m_UpdateUUID;
|
||||
}
|
||||
|
|
|
@ -46,7 +46,7 @@ lvm2_pv::lvm2_pv(qint64 firstsector, qint64 lastsector,
|
|||
|
||||
void lvm2_pv::init()
|
||||
{
|
||||
CommandSupportType lvmFound = findExternal(QStringLiteral("lvm")) ? cmdSupportFileSystem : cmdSupportNone;
|
||||
CommandSupportType lvmFound = findExternal(QStringLiteral("lvm"), {}, 3) ? cmdSupportFileSystem : cmdSupportNone;
|
||||
|
||||
m_Create = lvmFound;
|
||||
m_Check = lvmFound;
|
||||
|
|
|
@ -32,6 +32,9 @@ public:
|
|||
bool check(Report& report, const QString&deviceNode) const override;
|
||||
bool create(Report& report, const QString&deviceNode) override;
|
||||
|
||||
QString posixPermissions() const override { return implPosixPermissions(); };
|
||||
void setPosixPermissions(const QString& permissions) override { implSetPosixPermissions(permissions); };
|
||||
|
||||
CommandSupportType supportGetLabel() const override {
|
||||
return m_GetLabel;
|
||||
}
|
||||
|
|
|
@ -41,6 +41,8 @@ public:
|
|||
bool resizeOnline(Report& report, const QString& deviceNode, const QString& mountPoint, qint64 length) const override;
|
||||
bool writeLabel(Report& report, const QString& deviceNode, const QString& newLabel) override;
|
||||
bool updateUUID(Report& report, const QString& deviceNode) const override;
|
||||
QString posixPermissions() const override { return implPosixPermissions(); };
|
||||
void setPosixPermissions(const QString& permissions) override { implSetPosixPermissions(permissions); };
|
||||
|
||||
CommandSupportType supportGetUsed() const override {
|
||||
return m_GetUsed;
|
||||
|
|
|
@ -47,7 +47,8 @@ ntfs::ntfs(qint64 firstsector, qint64 lastsector, qint64 sectorsused, const QStr
|
|||
|
||||
void ntfs::init()
|
||||
{
|
||||
m_Shrink = m_Grow = m_Check = m_GetUsed = findExternal(QStringLiteral("ntfsresize")) ? cmdSupportFileSystem : cmdSupportNone;
|
||||
m_Shrink = m_Grow = m_Check = findExternal(QStringLiteral("ntfsresize")) ? cmdSupportFileSystem : cmdSupportNone;
|
||||
m_GetUsed = findExternal(QStringLiteral("ntfsinfo")) ? cmdSupportFileSystem : cmdSupportNone;
|
||||
m_GetLabel = cmdSupportCore;
|
||||
m_SetLabel = findExternal(QStringLiteral("ntfslabel")) ? cmdSupportFileSystem : cmdSupportNone;
|
||||
m_Create = findExternal(QStringLiteral("mkfs.ntfs")) ? cmdSupportFileSystem : cmdSupportNone;
|
||||
|
@ -97,17 +98,26 @@ int ntfs::maxLabelLength() const
|
|||
|
||||
qint64 ntfs::readUsedCapacity(const QString& deviceNode) const
|
||||
{
|
||||
ExternalCommand cmd(QStringLiteral("ntfsresize"), { QStringLiteral("--info"), QStringLiteral("--force"), QStringLiteral("--no-progress-bar"), deviceNode });
|
||||
ExternalCommand cmd(QStringLiteral("ntfsinfo"), { QStringLiteral("--mft"), QStringLiteral("--force"), deviceNode });
|
||||
|
||||
if (cmd.run(-1) && cmd.exitCode() == 0) {
|
||||
QRegularExpression re(QStringLiteral("Cluster Size: (\\d+)"));
|
||||
QRegularExpressionMatch reClusterSize = re.match(cmd.output());
|
||||
qint64 clusterSize = reClusterSize.hasMatch() ? reClusterSize.captured(1).toLongLong() : -1;
|
||||
|
||||
QRegularExpression re2(QStringLiteral("Free Clusters: (\\d+)"));
|
||||
QRegularExpressionMatch reFreeClusters = re2.match(cmd.output());
|
||||
qint64 freeClusters = reFreeClusters.hasMatch() ? reFreeClusters.captured(1).toLongLong() : -1;
|
||||
|
||||
QRegularExpression re3(QStringLiteral("Volume Size in Clusters: (\\d+)"));
|
||||
QRegularExpressionMatch reVolumeSize = re3.match(cmd.output());
|
||||
qint64 volumeSize = reVolumeSize.hasMatch() ? reVolumeSize.captured(1).toLongLong() : -1;
|
||||
|
||||
qint64 usedBytes = -1;
|
||||
QRegularExpression re(QStringLiteral("resize at (\\d+) bytes"));
|
||||
QRegularExpressionMatch reUsedBytes = re.match(cmd.output());
|
||||
|
||||
if (reUsedBytes.hasMatch())
|
||||
usedBytes = reUsedBytes.captured(1).toLongLong();
|
||||
|
||||
if (usedBytes > -1)
|
||||
qDebug () << volumeSize << freeClusters << clusterSize;
|
||||
if (clusterSize > -1 && freeClusters > -1 && volumeSize > -1) {
|
||||
usedBytes = (volumeSize - freeClusters) * clusterSize;
|
||||
}
|
||||
return usedBytes;
|
||||
}
|
||||
|
||||
|
|
|
@ -40,6 +40,8 @@ public:
|
|||
bool resize(Report& report, const QString& deviceNode, qint64 length) const override;
|
||||
bool writeLabel(Report& report, const QString& deviceNode, const QString& newLabel) override;
|
||||
bool updateUUID(Report& report, const QString& deviceNode) const override;
|
||||
QString posixPermissions() const override { return implPosixPermissions(); };
|
||||
void setPosixPermissions(const QString& permissions) override { implSetPosixPermissions(permissions); };
|
||||
|
||||
CommandSupportType supportGetUsed() const override {
|
||||
return m_GetUsed;
|
||||
|
|
|
@ -38,6 +38,8 @@ public:
|
|||
qint64 readUsedCapacity(const QString& deviceNode) const override;
|
||||
bool check(Report& report, const QString& deviceNode) const override;
|
||||
bool create(Report& report, const QString& deviceNode) override;
|
||||
QString posixPermissions() const override { return implPosixPermissions(); };
|
||||
void setPosixPermissions(const QString& permissions) override { implSetPosixPermissions(permissions); };
|
||||
|
||||
CommandSupportType supportGetUsed() const override {
|
||||
return m_GetUsed;
|
||||
|
|
|
@ -44,6 +44,8 @@ public:
|
|||
bool resizeOnline(Report& report, const QString& deviceNode, const QString& mountPoint, qint64 length) const override;
|
||||
bool writeLabel(Report& report, const QString& deviceNode, const QString& newLabel) override;
|
||||
bool updateUUID(Report& report, const QString& deviceNode) const override;
|
||||
QString posixPermissions() const override { return implPosixPermissions(); };
|
||||
void setPosixPermissions(const QString& permissions) override { implSetPosixPermissions(permissions); };
|
||||
|
||||
CommandSupportType supportGetUsed() const override {
|
||||
return m_GetUsed;
|
||||
|
|
|
@ -38,6 +38,8 @@ public:
|
|||
bool createWithLabel(Report& report, const QString& deviceNode, const QString& label) override;
|
||||
bool writeLabel(Report& report, const QString& deviceNode, const QString& newLabel) override;
|
||||
bool updateUUID(Report& report, const QString& deviceNode) const override;
|
||||
QString posixPermissions() const override { return implPosixPermissions(); };
|
||||
void setPosixPermissions(const QString& permissions) override { implSetPosixPermissions(permissions); };
|
||||
|
||||
CommandSupportType supportGetUsed() const override {
|
||||
return m_GetUsed;
|
||||
|
|
|
@ -13,6 +13,7 @@ namespace FS
|
|||
{
|
||||
|
||||
FileSystem::CommandSupportType unknown::m_Move = FileSystem::cmdSupportCore;
|
||||
FileSystem::CommandSupportType unknown::m_Copy = FileSystem::cmdSupportCore;
|
||||
|
||||
unknown::unknown(qint64 firstsector, qint64 lastsector, qint64 sectorsused, const QString& label, const QVariantMap& features) :
|
||||
FileSystem(firstsector, lastsector, sectorsused, label, features, FileSystem::Type::Unknown)
|
||||
|
|
|
@ -37,7 +37,12 @@ public:
|
|||
return m_Move;
|
||||
}
|
||||
|
||||
CommandSupportType supportCopy() const override {
|
||||
return m_Copy;
|
||||
}
|
||||
|
||||
static CommandSupportType m_Move;
|
||||
static CommandSupportType m_Copy;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -41,6 +41,8 @@ public:
|
|||
bool resize(Report& report, const QString& deviceNode, qint64 length) const override;
|
||||
bool resizeOnline(Report& report, const QString& deviceNode, const QString& mountPoint, qint64 length) const override;
|
||||
bool writeLabel(Report& report, const QString& deviceNode, const QString& newLabel) override;
|
||||
QString posixPermissions() const override { return implPosixPermissions(); };
|
||||
void setPosixPermissions(const QString& permissions) override { implSetPosixPermissions(permissions); };
|
||||
|
||||
CommandSupportType supportGetUsed() const override {
|
||||
return m_GetUsed;
|
||||
|
|
|
@ -77,13 +77,6 @@ qint64 zfs::maxCapacity() const
|
|||
return Capacity::unitFactor(Capacity::Unit::Byte, Capacity::Unit::EiB);
|
||||
}
|
||||
|
||||
bool zfs::remove(Report& report, const QString& deviceNode) const
|
||||
{
|
||||
Q_UNUSED(deviceNode)
|
||||
ExternalCommand cmd(report, QStringLiteral("zpool"), { QStringLiteral("destroy"), QStringLiteral("-f"), label() });
|
||||
return cmd.run(-1) && cmd.exitCode() == 0;
|
||||
}
|
||||
|
||||
bool zfs::writeLabel(Report& report, const QString& deviceNode, const QString& newLabel)
|
||||
{
|
||||
Q_UNUSED(deviceNode)
|
||||
|
|
|
@ -35,8 +35,9 @@ public:
|
|||
public:
|
||||
void init() override;
|
||||
|
||||
bool remove(Report& report, const QString& deviceNode) const override;
|
||||
bool writeLabel(Report& report, const QString& deviceNode, const QString& newLabel) override;
|
||||
QString posixPermissions() const override { return implPosixPermissions(); };
|
||||
void setPosixPermissions(const QString& permissions) override { implSetPosixPermissions(permissions); };
|
||||
|
||||
CommandSupportType supportGetUsed() const override {
|
||||
return m_GetUsed;
|
||||
|
|
|
@ -31,6 +31,7 @@ set(JOBS_SRC
|
|||
jobs/setpartflagsjob.cpp
|
||||
jobs/copyfilesystemjob.cpp
|
||||
jobs/movefilesystemjob.cpp
|
||||
jobs/changepermissionsjob.cpp
|
||||
)
|
||||
|
||||
set(JOBS_LIB_HDRS
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: Tomaz Canabrava <tcanabrava@kde.org>
|
||||
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include "jobs/changepermissionsjob.h"
|
||||
|
||||
#include "core/lvmdevice.h"
|
||||
#include "core/partition.h"
|
||||
|
||||
#include "util/report.h"
|
||||
|
||||
#include <KLocalizedString>
|
||||
|
||||
/** Creates a new CreateVolumeGroupJob
|
||||
* @param permission the new permission for the partition, in chmod style.
|
||||
* @param partition the partition to change the permission.
|
||||
*/
|
||||
ChangePermissionJob::ChangePermissionJob(Partition& partition) :
|
||||
Job(),
|
||||
m_Partition(partition)
|
||||
{
|
||||
}
|
||||
|
||||
bool ChangePermissionJob::run(Report& parent)
|
||||
{
|
||||
bool rval = false;
|
||||
|
||||
auto &fs = m_Partition.fileSystem();
|
||||
|
||||
Report* report = jobStarted(parent);
|
||||
|
||||
rval = fs.execChangePosixPermission(*report, m_Partition.deviceNode());
|
||||
|
||||
jobFinished(*report, rval);
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
QString ChangePermissionJob::description() const
|
||||
{
|
||||
return xi18nc("@info/plain", "Change the permissions of: <filename>%1</filename> to %2", m_Partition.deviceNode(), m_permissions);
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2021 Tomaz Canabrava <tcanabrava@kde.org>
|
||||
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef KPMCORE_CHANGEPERMISSIONJOB_H
|
||||
#define KPMCORE_CHANGEPERMISSIONJOB_H
|
||||
|
||||
#include "jobs/job.h"
|
||||
|
||||
class Partition;
|
||||
class Report;
|
||||
|
||||
class QString;
|
||||
|
||||
/** Check a FileSystem.
|
||||
@author Volker Lanz <vl@fidra.de>
|
||||
*/
|
||||
class ChangePermissionJob : public Job
|
||||
{
|
||||
public:
|
||||
/* Permission should be set in the partition. */
|
||||
explicit ChangePermissionJob(Partition& p);
|
||||
|
||||
public:
|
||||
bool run(Report& parent) override;
|
||||
QString description() const override;
|
||||
|
||||
protected:
|
||||
Partition& partition() {
|
||||
return m_Partition;
|
||||
}
|
||||
const Partition& partition() const {
|
||||
return m_Partition;
|
||||
}
|
||||
|
||||
private:
|
||||
Partition& m_Partition;
|
||||
QString m_permissions;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -13,6 +13,7 @@
|
|||
#include "jobs/deletefilesystemjob.h"
|
||||
#include "jobs/createfilesystemjob.h"
|
||||
#include "jobs/checkfilesystemjob.h"
|
||||
#include "jobs/changepermissionsjob.h"
|
||||
|
||||
#include "fs/filesystem.h"
|
||||
#include "fs/filesystemfactory.h"
|
||||
|
@ -42,6 +43,10 @@ CreateFileSystemOperation::CreateFileSystemOperation(Device& d, Partition& p, Fi
|
|||
addJob(deleteJob());
|
||||
addJob(createJob());
|
||||
addJob(checkJob());
|
||||
|
||||
// if the user never configured a new permission, nothing will run, if he did,
|
||||
// then we change the permissions on the newly created partition.
|
||||
addJob(new ChangePermissionJob(p));
|
||||
}
|
||||
|
||||
CreateFileSystemOperation::~CreateFileSystemOperation()
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "jobs/setfilesystemlabeljob.h"
|
||||
#include "jobs/setpartflagsjob.h"
|
||||
#include "jobs/checkfilesystemjob.h"
|
||||
#include "jobs/changepermissionsjob.h"
|
||||
|
||||
#include "fs/filesystem.h"
|
||||
#include "fs/filesystemfactory.h"
|
||||
|
@ -31,15 +32,12 @@
|
|||
|
||||
#include <KLocalizedString>
|
||||
|
||||
/** 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(),
|
||||
struct NewOperationPrivate
|
||||
{
|
||||
NewOperationPrivate(Device& d, Partition* p) :
|
||||
m_TargetDevice(d),
|
||||
m_NewPartition(p),
|
||||
m_CreatePartitionJob(new CreatePartitionJob(targetDevice(), newPartition())),
|
||||
m_CreatePartitionJob(new CreatePartitionJob(d, *p)),
|
||||
m_SetPartitionLabelJob(nullptr),
|
||||
m_SetPartitionUUIDJob(nullptr),
|
||||
m_SetPartitionAttributesJob(nullptr),
|
||||
|
@ -47,21 +45,43 @@ NewOperation::NewOperation(Device& d, Partition* p) :
|
|||
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<NewOperationPrivate>(d, p))
|
||||
{
|
||||
addJob(createPartitionJob());
|
||||
|
||||
if (!p->label().isEmpty()) {
|
||||
m_SetPartitionLabelJob = new SetPartitionLabelJob(targetDevice(), newPartition(), p->label());
|
||||
d_ptr->m_SetPartitionLabelJob = new SetPartitionLabelJob(targetDevice(), newPartition(), p->label());
|
||||
addJob(setPartitionLabelJob());
|
||||
}
|
||||
|
||||
if (!p->uuid().isEmpty()) {
|
||||
m_SetPartitionUUIDJob = new SetPartitionUUIDJob(targetDevice(), newPartition(), p->uuid());
|
||||
d_ptr->m_SetPartitionUUIDJob = new SetPartitionUUIDJob(targetDevice(), newPartition(), p->uuid());
|
||||
addJob(setPartitionUUIDJob());
|
||||
}
|
||||
|
||||
if (p->attributes()) {
|
||||
m_SetPartitionAttributesJob = new SetPartitionAttributesJob(targetDevice(), newPartition(), p->attributes());
|
||||
d_ptr->m_SetPartitionAttributesJob = new SetPartitionAttributesJob(targetDevice(), newPartition(), p->attributes());
|
||||
addJob(setPartitionAttributesJob());
|
||||
}
|
||||
|
||||
|
@ -74,26 +94,90 @@ NewOperation::NewOperation(Device& d, Partition* p) :
|
|||
// label. The operation stack will merge these operations with this one here
|
||||
// and if the jobs don't exist things will break.
|
||||
|
||||
m_CreateFileSystemJob = new CreateFileSystemJob(targetDevice(), newPartition(), fs.label());
|
||||
d_ptr->m_CreateFileSystemJob = new CreateFileSystemJob(targetDevice(), newPartition(), fs.label());
|
||||
addJob(createFileSystemJob());
|
||||
|
||||
if (fs.type() == FileSystem::Type::Lvm2_PV) {
|
||||
m_SetPartFlagsJob = new SetPartFlagsJob(targetDevice(), newPartition(), PartitionTable::Flag::Lvm);
|
||||
d_ptr->m_SetPartFlagsJob = new SetPartFlagsJob(targetDevice(), newPartition(), PartitionTable::Flag::Lvm);
|
||||
addJob(setPartFlagsJob());
|
||||
}
|
||||
|
||||
m_SetFileSystemLabelJob = new SetFileSystemLabelJob(newPartition(), fs.label());
|
||||
d_ptr->m_SetFileSystemLabelJob = new SetFileSystemLabelJob(newPartition(), fs.label());
|
||||
addJob(setLabelJob());
|
||||
|
||||
m_CheckFileSystemJob = new CheckFileSystemJob(newPartition());
|
||||
d_ptr->m_CheckFileSystemJob = new CheckFileSystemJob(newPartition());
|
||||
addJob(checkJob());
|
||||
|
||||
// if the user never configured a new permission, nothing will run, if he did,
|
||||
// then we change the permissions on the newly created partition.
|
||||
addJob(new ChangePermissionJob(newPartition()));
|
||||
}
|
||||
}
|
||||
|
||||
NewOperation::~NewOperation()
|
||||
{
|
||||
if (status() == StatusPending)
|
||||
delete m_NewPartition;
|
||||
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
|
||||
|
@ -142,6 +226,7 @@ Partition* NewOperation::createNew(const Partition& cloneFrom,
|
|||
p->sectorSize()));
|
||||
p->setState(Partition::State::New);
|
||||
p->setPartitionPath(QString());
|
||||
p->setAttributes(0);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
#include <QString>
|
||||
|
||||
struct NewOperationPrivate;
|
||||
class Device;
|
||||
class OperationStack;
|
||||
|
||||
|
@ -60,56 +61,23 @@ public:
|
|||
static Partition* createNew(const Partition& cloneFrom, FileSystem::Type type);
|
||||
|
||||
protected:
|
||||
Partition& newPartition() {
|
||||
return *m_NewPartition;
|
||||
}
|
||||
const Partition& newPartition() const {
|
||||
return *m_NewPartition;
|
||||
}
|
||||
Partition& newPartition();
|
||||
const Partition& newPartition() const;
|
||||
|
||||
Device& targetDevice() {
|
||||
return m_TargetDevice;
|
||||
}
|
||||
const Device& targetDevice() const {
|
||||
return m_TargetDevice;
|
||||
}
|
||||
Device& targetDevice();
|
||||
const Device& targetDevice() const;
|
||||
|
||||
CreatePartitionJob* createPartitionJob() {
|
||||
return m_CreatePartitionJob;
|
||||
}
|
||||
SetPartitionLabelJob* setPartitionLabelJob() {
|
||||
return m_SetPartitionLabelJob;
|
||||
}
|
||||
SetPartitionUUIDJob* setPartitionUUIDJob() {
|
||||
return m_SetPartitionUUIDJob;
|
||||
}
|
||||
SetPartitionAttributesJob* setPartitionAttributesJob() {
|
||||
return m_SetPartitionAttributesJob;
|
||||
}
|
||||
CreateFileSystemJob* createFileSystemJob() {
|
||||
return m_CreateFileSystemJob;
|
||||
}
|
||||
SetPartFlagsJob* setPartFlagsJob() {
|
||||
return m_SetPartFlagsJob;
|
||||
}
|
||||
SetFileSystemLabelJob* setLabelJob() {
|
||||
return m_SetFileSystemLabelJob;
|
||||
}
|
||||
CheckFileSystemJob* checkJob() {
|
||||
return m_CheckFileSystemJob;
|
||||
}
|
||||
CreatePartitionJob* createPartitionJob();
|
||||
SetPartitionLabelJob* setPartitionLabelJob();
|
||||
SetPartitionUUIDJob* setPartitionUUIDJob();
|
||||
SetPartitionAttributesJob* setPartitionAttributesJob();
|
||||
CreateFileSystemJob* createFileSystemJob();
|
||||
SetPartFlagsJob* setPartFlagsJob();
|
||||
SetFileSystemLabelJob* setLabelJob();
|
||||
CheckFileSystemJob* checkJob();
|
||||
|
||||
private:
|
||||
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;
|
||||
std::unique_ptr<NewOperationPrivate> d_ptr;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -3,6 +3,11 @@
|
|||
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
function(kpmcore_add_plugin name)
|
||||
kcoreaddons_add_plugin(${name} INSTALL_NAMESPACE "kpmcore")
|
||||
endfunction()
|
||||
|
||||
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||
option(PARTMAN_SFDISKBACKEND "Build the sfdisk backend plugin." ON)
|
||||
|
||||
|
|
|
@ -1,17 +1,15 @@
|
|||
# SPDX-FileCopyrightText: 2010 Volker Lanz <vl@fidra.de>
|
||||
# SPDX-FileCopyrightText: 2016-2018 Andrius Štikonas <andrius@stikonas.eu>
|
||||
# SPDX-FileCopyrightText: 2016-2021 Andrius Štikonas <andrius@stikonas.eu>
|
||||
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
set (pmdummybackendplugin_SRCS
|
||||
kpmcore_add_plugin(pmdummybackendplugin)
|
||||
|
||||
target_sources(pmdummybackendplugin PRIVATE
|
||||
dummybackend.cpp
|
||||
dummydevice.cpp
|
||||
dummypartitiontable.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/backend/corebackenddevice.cpp
|
||||
)
|
||||
|
||||
add_library(pmdummybackendplugin SHARED ${pmdummybackendplugin_SRCS})
|
||||
|
||||
target_link_libraries(pmdummybackendplugin kpmcore KF5::I18n KF5::CoreAddons)
|
||||
|
||||
install(TARGETS pmdummybackendplugin DESTINATION ${KDE_INSTALL_PLUGINDIR})
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
#include <KLocalizedString>
|
||||
#include <KPluginFactory>
|
||||
|
||||
K_PLUGIN_FACTORY_WITH_JSON(DummyBackendFactory, "pmdummybackendplugin.json", registerPlugin<DummyBackend>();)
|
||||
K_PLUGIN_CLASS_WITH_JSON(DummyBackend, "pmdummybackendplugin.json")
|
||||
|
||||
|
||||
DummyBackend::DummyBackend(QObject*, const QList<QVariant>&) :
|
||||
|
@ -51,7 +51,7 @@ QList<Device*> DummyBackend::scanDevices(const ScanFlags scanFlags)
|
|||
|
||||
emitScanProgress(QStringLiteral("/dev/sda"), 100);
|
||||
|
||||
return scanDevices(false);
|
||||
return result;
|
||||
}
|
||||
|
||||
Device* DummyBackend::scanDevice(const QString& deviceNode)
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
"Name[fi]": "Volker Lanz",
|
||||
"Name[fr]": "Volker Lanz",
|
||||
"Name[gl]": "Volker Lanz",
|
||||
"Name[hu]": "Volker Lanz",
|
||||
"Name[id]": "Volker Lanz",
|
||||
"Name[it]": "Volker Lanz",
|
||||
"Name[ko]": "Volker Lanz",
|
||||
|
@ -39,7 +40,7 @@
|
|||
],
|
||||
"Category": "BackendPlugin",
|
||||
"Description": "A KDE Partition Manager dummy backend for testing purposes.",
|
||||
"Description[ca@valencia]": "Un dorsal fals per al gestor de particions del KDE amb la finalitat de fer proves.",
|
||||
"Description[ca@valencia]": "Un dorsal fals per al gestor de particions de KDE amb la finalitat de fer proves.",
|
||||
"Description[ca]": "Un dorsal fals per al gestor de particions del KDE amb la finalitat de fer proves.",
|
||||
"Description[cs]": "Falešná podpůrná vrstva pro správce diskových oddílů KDE pro testovací účely.",
|
||||
"Description[da]": "En KDE-partitionshåndtering med attrap-backend til testformål.",
|
||||
|
@ -52,6 +53,7 @@
|
|||
"Description[fi]": "KDE:n osionhallinnan valetaustaosa testaustarkoituksiin.",
|
||||
"Description[fr]": "Un moteur de test pour le gestionnaire de partitions de KDE pour faire des essais.",
|
||||
"Description[gl]": "Unha infraestrutura de probas para o xestor de particións de KDE.",
|
||||
"Description[hu]": "KDE partíciókezelő üres modul tesztelési célokra.",
|
||||
"Description[id]": "Sebuah backend dumi Pengelola Partisi KDE untuk tujuan pengujian.",
|
||||
"Description[it]": "Un motore fittizio del gestore delle partizioni di KDE per scopi di prova.",
|
||||
"Description[ko]": "테스트용 KDE 파티션 관리자 더미 백엔드입니다.",
|
||||
|
@ -66,15 +68,15 @@
|
|||
"Description[sv]": "Ett bakgrundsprogram till KDE:s partitionshanterare i testsyfte.",
|
||||
"Description[uk]": "Тестовий додаток сервера Керування розділами KDE.",
|
||||
"Description[x-test]": "xxA KDE Partition Manager dummy backend for testing purposes.xx",
|
||||
"Description[zh_CN]": "测试用的 KDE 分区管理器的虚拟后端",
|
||||
"Description[zh_CN]": "用于测试的 KDE 分区管理器虚拟后端程序。",
|
||||
"Description[zh_TW]": "使用虛設後端的 KDE 磁碟分割區管理員,可用來測試。",
|
||||
"EnabledByDefault": true,
|
||||
"Icon": "preferences-plugin",
|
||||
"Id": "pmdummybackendplugin",
|
||||
"License": "GPL",
|
||||
"Name": "KDE Partition Manager Dummy Backend",
|
||||
"Name[ca@valencia]": "Dorsal fals per al gestor de particions del KDE",
|
||||
"Name[ca]": "Dorsal fals per al gestor de particions del KDE",
|
||||
"Name[ca@valencia]": "Dorsal fals del gestor de particions de KDE",
|
||||
"Name[ca]": "Dorsal fals del gestor de particions del KDE",
|
||||
"Name[cs]": "Podpůrná vrstva pro správce diskových oddílů pro KDE",
|
||||
"Name[da]": "KDE-partitionshåndtering med attrap-backend",
|
||||
"Name[de]": "KDE-Partitionsverwaltung Dummy-Backend",
|
||||
|
@ -86,6 +88,7 @@
|
|||
"Name[fi]": "KDE:n osionhallinnan valetaustaosa",
|
||||
"Name[fr]": "Moteur de test pour le gestionnaire de partitions de KDE",
|
||||
"Name[gl]": "Infraestrutura de probas para o xestor de particións de KDE",
|
||||
"Name[hu]": "KDE partíciókezelő üres modul",
|
||||
"Name[id]": "Backend Dumi Pengelola Partisi KDE",
|
||||
"Name[it]": "Motore fittizio del gestore delle partizioni di KDE",
|
||||
"Name[ko]": "KDE 파티션 관리자 더미 백엔드",
|
||||
|
@ -101,11 +104,8 @@
|
|||
"Name[sv]": "KDE:s partitionshanterare bakgrundsprogram för test",
|
||||
"Name[uk]": "Тестовий додаток сервера Керування розділами KDE",
|
||||
"Name[x-test]": "xxKDE Partition Manager Dummy Backendxx",
|
||||
"Name[zh_CN]": "KDE 分区管理器虚拟后端",
|
||||
"Name[zh_CN]": "KDE 分区管理器虚拟后端程序",
|
||||
"Name[zh_TW]": "KDE 磁碟分割區管理員 (虛設後端)",
|
||||
"ServiceTypes": [
|
||||
"PartitionManager/Plugin"
|
||||
],
|
||||
"Version": "1",
|
||||
"Website": "http://www.partitionmanager.org"
|
||||
}
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
# SPDX-FileCopyrightText: 2020 Gaël PORTAY <gael.portay@collabora.com>
|
||||
# SPDX-FileCopyrightText: 2018 Andrius Štikonas <andrius@stikonas.eu>
|
||||
# SPDX-FileCopyrightText: 2021 Andrius Štikonas <andrius@stikonas.eu>
|
||||
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
set (pmsfdiskbackendplugin_SRCS
|
||||
kpmcore_add_plugin(pmsfdiskbackendplugin)
|
||||
|
||||
target_sources(pmsfdiskbackendplugin PRIVATE
|
||||
sfdiskbackend.cpp
|
||||
sfdiskdevice.cpp
|
||||
sfdiskgptattributes.cpp
|
||||
|
@ -14,8 +16,4 @@ set (pmsfdiskbackendplugin_SRCS
|
|||
${CMAKE_SOURCE_DIR}/src/core/copytargetbytearray.cpp
|
||||
)
|
||||
|
||||
add_library(pmsfdiskbackendplugin SHARED ${pmsfdiskbackendplugin_SRCS})
|
||||
|
||||
target_link_libraries(pmsfdiskbackendplugin kpmcore KF5::I18n KF5::CoreAddons)
|
||||
|
||||
install(TARGETS pmsfdiskbackendplugin DESTINATION ${KDE_INSTALL_PLUGINDIR})
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
"Name[fi]": "Andrius Štikonas",
|
||||
"Name[fr]": "Andrius Štikonas",
|
||||
"Name[gl]": "Andrius Štikonas",
|
||||
"Name[hu]": "Andrius Štikonas",
|
||||
"Name[id]": "Andrius Štikonas",
|
||||
"Name[it]": "Andrius Štikonas",
|
||||
"Name[ko]": "Andrius Štikonas",
|
||||
|
@ -39,7 +40,7 @@
|
|||
],
|
||||
"Category": "BackendPlugin",
|
||||
"Description": "A KDE Partition Manager sfdisk backend.",
|
||||
"Description[ca@valencia]": "Un dorsal «sfdisk» del gestor de particions del KDE.",
|
||||
"Description[ca@valencia]": "Un dorsal «sfdisk» del gestor de particions de KDE.",
|
||||
"Description[ca]": "Un dorsal «sfdisk» del gestor de particions del KDE.",
|
||||
"Description[cs]": "Podpůrná vrstva sfdisk pro správce diskových oddílů pro KDE.",
|
||||
"Description[da]": "En KDE-partitionshåndtering med sfdisk-backend.",
|
||||
|
@ -52,6 +53,7 @@
|
|||
"Description[fi]": "KDE:n osionhallinnan sfdisk-taustaosa",
|
||||
"Description[fr]": "Moteur sfdisk pour le gestionnaire de partitions de KDE.",
|
||||
"Description[gl]": "Unha infraestrutura de sfdisk para o xestor de particións de KDE.",
|
||||
"Description[hu]": "KDE partíciókezelő sfdisk modul.",
|
||||
"Description[id]": "Sebuah backend sfdisk Pengelola Partisi KDE",
|
||||
"Description[it]": "Un motore sfdisk del gestore delle partizioni di KDE.",
|
||||
"Description[ko]": "KDE 파티션 관리자 sfdisk 백엔드입니다.",
|
||||
|
@ -66,13 +68,14 @@
|
|||
"Description[sv]": "Ett sfdisk bakgrundsprogram till KDE:s partitionshanterare",
|
||||
"Description[uk]": "Додаток sfdisk сервера Керування розділами KDE.",
|
||||
"Description[x-test]": "xxA KDE Partition Manager sfdisk backend.xx",
|
||||
"Description[zh_CN]": "KDE 分区管理器 sfdisk 后端程序。",
|
||||
"Description[zh_TW]": "使用 sfdisk 作為後端的 KDE 磁碟分割區管理員。",
|
||||
"EnabledByDefault": true,
|
||||
"Icon": "preferences-plugin",
|
||||
"Id": "pmsfdiskbackendplugin",
|
||||
"License": "GPL",
|
||||
"Name": "KDE Partition Manager sfdisk Backend",
|
||||
"Name[ca@valencia]": "Dorsal «sfdisk» del gestor de particions del KDE",
|
||||
"Name[ca@valencia]": "Dorsal «sfdisk» del gestor de particions de KDE",
|
||||
"Name[ca]": "Dorsal «sfdisk» del gestor de particions del KDE",
|
||||
"Name[cs]": "Podpůrná vrstva sfdisk pro správce diskových oddílů pro KDE",
|
||||
"Name[da]": "KDE-partitionshåndtering med sfdisk-backend",
|
||||
|
@ -85,6 +88,7 @@
|
|||
"Name[fi]": "KDE:n osionhallinnan sfdisk-taustaosa",
|
||||
"Name[fr]": "Moteur sfdisk pour le gestionnaire de partitions de KDE",
|
||||
"Name[gl]": "Infraestrutura de sfdisk para o xestor de particións de KDE",
|
||||
"Name[hu]": "KDE partíciókezelő sfdisk modul",
|
||||
"Name[id]": "Backend sfdisk Pengelola Partisi KDE",
|
||||
"Name[it]": "Motore sfdisk del gestore delle partizioni di KDE",
|
||||
"Name[ko]": "KDE 파티션 관리자 sfdisk 백엔드",
|
||||
|
@ -99,10 +103,8 @@
|
|||
"Name[sv]": "KDE:s partitionshanterare sfdisk bakgrundsprogram",
|
||||
"Name[uk]": "Додаток sfdisk сервера Керування розділами KDE",
|
||||
"Name[x-test]": "xxKDE Partition Manager sfdisk Backendxx",
|
||||
"Name[zh_CN]": "KDE 分区管理器 sfdisk 后端程序",
|
||||
"Name[zh_TW]": "KDE 磁碟分割區管理員 (sfdisk 後端)",
|
||||
"ServiceTypes": [
|
||||
"PartitionManager/Plugin"
|
||||
],
|
||||
"Version": "1",
|
||||
"Website": "http://www.partitionmanager.org"
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@
|
|||
#include <KLocalizedString>
|
||||
#include <KPluginFactory>
|
||||
|
||||
K_PLUGIN_FACTORY_WITH_JSON(SfdiskBackendFactory, "pmsfdiskbackendplugin.json", registerPlugin<SfdiskBackend>();)
|
||||
K_PLUGIN_CLASS_WITH_JSON(SfdiskBackend, "pmsfdiskbackendplugin.json")
|
||||
|
||||
SfdiskBackend::SfdiskBackend(QObject*, const QList<QVariant>&) :
|
||||
CoreBackend()
|
||||
|
@ -451,11 +451,12 @@ bool SfdiskBackend::updateDevicePartitionTable(Device &d, const QJsonObject &jso
|
|||
// Read the maximum number of GPT partitions
|
||||
qint32 maxEntries;
|
||||
QByteArray gptHeader;
|
||||
CopySourceDevice source(d, 512, 1023);
|
||||
CopyTargetByteArray target(gptHeader);
|
||||
qint64 sectorSize = d.logicalSize();
|
||||
CopySourceDevice source(d, sectorSize, sectorSize * 2 - 1);
|
||||
|
||||
ExternalCommand copyCmd;
|
||||
if (copyCmd.copyBlocks(source, target)) {
|
||||
ExternalCommand readCmd;
|
||||
gptHeader = readCmd.readData(source);
|
||||
if (gptHeader != QByteArray()) {
|
||||
QByteArray gptMaxEntries = gptHeader.mid(80, 4);
|
||||
QDataStream stream(&gptMaxEntries, QIODevice::ReadOnly);
|
||||
stream.setByteOrder(QDataStream::LittleEndian);
|
||||
|
|
|
@ -60,7 +60,7 @@ bool SfdiskDevice::createPartitionTable(Report& report, const PartitionTable& pt
|
|||
else
|
||||
tableType = ptable.typeName().toLocal8Bit();
|
||||
|
||||
ExternalCommand createCommand(report, QStringLiteral("sfdisk"), { m_device->deviceNode() } );
|
||||
ExternalCommand createCommand(report, QStringLiteral("sfdisk"), { QStringLiteral("--wipe=always"), m_device->deviceNode() } );
|
||||
if ( createCommand.write(QByteArrayLiteral("label: ") + tableType +
|
||||
QByteArrayLiteral("\nwrite\n")) && createCommand.start(-1) ) {
|
||||
return createCommand.output().contains(QStringLiteral("Script header accepted."));
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QStringView>
|
||||
|
||||
const static QString requiredPartition = QStringLiteral("RequiredPartition");
|
||||
const static QString noBlockIoProtocol = QStringLiteral("NoBlockIOProtocol");
|
||||
|
@ -25,7 +26,7 @@ quint64 SfdiskGptAttributes::toULongLong(const QStringList& attrs)
|
|||
else if (attr.compare(legacyBiosBootable) == 0)
|
||||
attributes |= 0x4ULL;
|
||||
else if (attr.startsWith(guid))
|
||||
attributes |= 1ULL << QStringRef(&attr, guid.length(), attr.length() - guid.length()).toULongLong();
|
||||
attributes |= 1ULL << QStringView{ attr }.mid(guid.length(), attr.length() - guid.length()).toULongLong();
|
||||
|
||||
return attributes;
|
||||
}
|
||||
|
|
|
@ -8,8 +8,7 @@
|
|||
#define SFDISKGPTATTRIBUTES__H
|
||||
|
||||
#include <QtGlobal>
|
||||
|
||||
class QStringList;
|
||||
#include <QStringList>
|
||||
|
||||
/** Sfdisk GPT Attributes helpers.
|
||||
@author Gaël PORTAY <gael.portay@collabora.com>
|
||||
|
|
|
@ -11,19 +11,29 @@
|
|||
|
||||
set(helper_interface_xml org.kde.kpmcore.helperinterface.xml)
|
||||
|
||||
qt5_generate_dbus_interface(
|
||||
file(READ "util/trustedprefixes" TRUSTED_PREFIXES)
|
||||
string(REGEX REPLACE ";" "\\\\;" TRUSTED_PREFIXES "${TRUSTED_PREFIXES}")
|
||||
string(REGEX REPLACE "\n" ";" TRUSTED_PREFIXES "${TRUSTED_PREFIXES}")
|
||||
foreach(TRUSTED_PREFIX ${TRUSTED_PREFIXES})
|
||||
list(APPEND TRUSTED_PREFIXES_LIST " QStringLiteral(\"${TRUSTED_PREFIX}\")")
|
||||
endforeach()
|
||||
string(REPLACE "; QStringLiteral(" ",\n QStringLiteral(" TRUSTED_PREFIXES_LIST "${TRUSTED_PREFIXES_LIST}")
|
||||
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS util/trustedprefixes)
|
||||
configure_file(util/externalcommand_trustedprefixes.h.in util/externalcommand_trustedprefixes.h)
|
||||
|
||||
qt_generate_dbus_interface(
|
||||
util/externalcommand.h
|
||||
${application_interface_xml}
|
||||
OPTIONS -a
|
||||
)
|
||||
|
||||
qt5_generate_dbus_interface(
|
||||
qt_generate_dbus_interface(
|
||||
util/externalcommandhelper.h
|
||||
${helper_interface_xml}
|
||||
OPTIONS -a
|
||||
)
|
||||
|
||||
qt5_add_dbus_interface(HelperInterface_SRCS ${CMAKE_CURRENT_BINARY_DIR}/${helper_interface_xml} externalcommandhelper_interface)
|
||||
qt_add_dbus_interface(HelperInterface_SRCS ${CMAKE_CURRENT_BINARY_DIR}/${helper_interface_xml} externalcommandhelper_interface)
|
||||
|
||||
set(UTIL_SRC
|
||||
${HelperInterface_SRCS}
|
||||
|
@ -49,10 +59,10 @@ add_executable(kpmcore_externalcommand
|
|||
)
|
||||
|
||||
target_link_libraries(kpmcore_externalcommand
|
||||
Qt5::Core
|
||||
Qt5::DBus
|
||||
Qt${QT_MAJOR_VERSION}::Core
|
||||
Qt${QT_MAJOR_VERSION}::DBus
|
||||
KF5::I18n
|
||||
PolkitQt5-1::Core
|
||||
PolkitQt${QT_MAJOR_VERSION}-1::Core
|
||||
)
|
||||
|
||||
install(TARGETS kpmcore_externalcommand DESTINATION ${KDE_INSTALL_LIBEXECDIR})
|
||||
|
|
|
@ -160,7 +160,7 @@ bool ExternalCommand::copyBlocks(const CopySource& source, CopyTarget& target)
|
|||
connect(interface, &OrgKdeKpmcoreExternalcommandInterface::progress, this, &ExternalCommand::progress);
|
||||
connect(interface, &OrgKdeKpmcoreExternalcommandInterface::report, this, &ExternalCommand::reportSignal);
|
||||
|
||||
QDBusPendingCall pcall = interface->CopyBlocks(source.path(), source.firstByte(), source.length(),
|
||||
QDBusPendingCall pcall = interface->CopyFileData(source.path(), source.firstByte(), source.length(),
|
||||
target.path(), target.firstByte(), blockSize);
|
||||
|
||||
QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pcall, this);
|
||||
|
@ -187,6 +187,38 @@ bool ExternalCommand::copyBlocks(const CopySource& source, CopyTarget& target)
|
|||
return rval;
|
||||
}
|
||||
|
||||
QByteArray ExternalCommand::readData(const CopySourceDevice& source)
|
||||
{
|
||||
auto interface = helperInterface();
|
||||
if (!interface)
|
||||
return {};
|
||||
|
||||
// Helper is restricted not to resolve symlinks
|
||||
QFileInfo sourceInfo(source.path());
|
||||
QDBusPendingCall pcall = interface->ReadData(sourceInfo.canonicalFilePath(), source.firstByte(), source.length());
|
||||
|
||||
QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pcall, this);
|
||||
|
||||
QEventLoop loop;
|
||||
QByteArray target;
|
||||
auto exitLoop = [&] (QDBusPendingCallWatcher *watcher) {
|
||||
loop.exit();
|
||||
|
||||
if (watcher->isError())
|
||||
qWarning() << watcher->error();
|
||||
else {
|
||||
QDBusPendingReply<QByteArray> reply = *watcher;
|
||||
|
||||
target = reply.value();
|
||||
}
|
||||
};
|
||||
|
||||
connect(watcher, &QDBusPendingCallWatcher::finished, exitLoop);
|
||||
loop.exec();
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
bool ExternalCommand::writeData(Report& commandReport, const QByteArray& buffer, const QString& deviceNode, const quint64 firstByte)
|
||||
{
|
||||
d->m_Report = commandReport.newChild();
|
||||
|
@ -201,13 +233,13 @@ bool ExternalCommand::writeData(Report& commandReport, const QByteArray& buffer,
|
|||
return waitForDbusReply(pcall);
|
||||
}
|
||||
|
||||
bool ExternalCommand::createFile(const QByteArray& fileContents, const QString& filePath)
|
||||
bool ExternalCommand::writeFstab(const QByteArray& fileContents)
|
||||
{
|
||||
auto interface = helperInterface();
|
||||
if (!interface)
|
||||
return false;
|
||||
|
||||
QDBusPendingCall pcall = interface->CreateFile(filePath, fileContents);
|
||||
QDBusPendingCall pcall = interface->WriteFstab(fileContents);
|
||||
return waitForDbusReply(pcall);
|
||||
}
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
class KJob;
|
||||
class Report;
|
||||
class CopySource;
|
||||
class CopySourceDevice;
|
||||
class CopyTarget;
|
||||
class QDBusInterface;
|
||||
class QDBusPendingCall;
|
||||
|
@ -54,8 +55,9 @@ public:
|
|||
|
||||
public:
|
||||
bool copyBlocks(const CopySource& source, CopyTarget& target);
|
||||
QByteArray readData(const CopySourceDevice& source);
|
||||
bool writeData(Report& commandReport, const QByteArray& buffer, const QString& deviceNode, const quint64 firstByte); // same as copyBlocks but from QByteArray
|
||||
bool createFile(const QByteArray& filePath, const QString& fileContents); // similar to writeData but creates a new file
|
||||
bool writeFstab(const QByteArray& fileContents);
|
||||
|
||||
/**< @param cmd the command to run */
|
||||
void setCommand(const QString& cmd);
|
||||
|
@ -72,7 +74,6 @@ public:
|
|||
|
||||
bool write(const QByteArray& input); /**< @param input the input for the program */
|
||||
|
||||
bool startCopyBlocks();
|
||||
bool start(int timeout = 30000);
|
||||
bool run(int timeout = 30000);
|
||||
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2022 Andrius Štikonas <andrius@stikonas.eu>
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
const std::unordered_set<QString> trustedPrefixes {
|
||||
@TRUSTED_PREFIXES_LIST@
|
||||
};
|
|
@ -8,7 +8,10 @@
|
|||
#ifndef KPMCORE_EXTERNALCOMMAND_WHITELIST_H
|
||||
#define KPMCORE_EXTERNALCOMMAND_WHITELIST_H
|
||||
|
||||
QString allowedCommands[] = {
|
||||
#include <unordered_set>
|
||||
#include "util/externalcommand_trustedprefixes.h"
|
||||
|
||||
const std::unordered_set<QString> allowedCommands {
|
||||
// TODO no root needed
|
||||
QStringLiteral("lsblk"),
|
||||
QStringLiteral("udevadm"),
|
||||
|
@ -16,6 +19,7 @@ QStringLiteral("udevadm"),
|
|||
//Core programs
|
||||
QStringLiteral("blockdev"),
|
||||
QStringLiteral("blkid"),
|
||||
QStringLiteral("chmod"),
|
||||
QStringLiteral("partx"),
|
||||
QStringLiteral("sfdisk"),
|
||||
QStringLiteral("wipefs"),
|
||||
|
@ -29,9 +33,11 @@ QStringLiteral("smartctl"),
|
|||
QStringLiteral("btrfs"),
|
||||
QStringLiteral("mkfs.btrfs"),
|
||||
QStringLiteral("btrfstune"),
|
||||
QStringLiteral("exfatfsck"),
|
||||
QStringLiteral("fsck.exfat"),
|
||||
QStringLiteral("mkexfatfs"),
|
||||
QStringLiteral("mkfs.exfat"),
|
||||
QStringLiteral("exfatlabel"),
|
||||
QStringLiteral("tune.exfat"),
|
||||
QStringLiteral("dumpe2fs"),
|
||||
QStringLiteral("e2fsck"),
|
||||
QStringLiteral("mkfs.ext2"),
|
||||
|
@ -70,6 +76,7 @@ QStringLiteral("nilfs-resize"),
|
|||
QStringLiteral("ntfsresize"),
|
||||
QStringLiteral("mkfs.ntfs"),
|
||||
QStringLiteral("ntfsclone"),
|
||||
QStringLiteral("ntfsinfo"),
|
||||
QStringLiteral("ntfslabel"),
|
||||
QStringLiteral("fsck.ocfs2"),
|
||||
QStringLiteral("mkfs.ocfs2"),
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2017-2020 Andrius Štikonas <andrius@stikonas.eu>
|
||||
SPDX-FileCopyrightText: 2017-2022 Andrius Štikonas <andrius@stikonas.eu>
|
||||
SPDX-FileCopyrightText: 2018 Huzaifa Faruqui <huzaifafaruqui@gmail.com>
|
||||
SPDX-FileCopyrightText: 2018 Caio Jordão Carvalho <caiojcarvalho@gmail.com>
|
||||
SPDX-FileCopyrightText: 2018-2019 Harald Sitter <sitter@kde.org>
|
||||
|
@ -13,12 +13,16 @@
|
|||
#include "externalcommandhelper.h"
|
||||
#include "externalcommand_whitelist.h"
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
#include <QtDBus>
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QDebug>
|
||||
#include <QDir>
|
||||
#include <QElapsedTimer>
|
||||
#include <QFile>
|
||||
#include <QFileInfo>
|
||||
#include <QString>
|
||||
#include <QVariant>
|
||||
|
||||
|
@ -42,11 +46,11 @@
|
|||
ExternalCommandHelper::ExternalCommandHelper()
|
||||
{
|
||||
if (!QDBusConnection::systemBus().registerObject(QStringLiteral("/Helper"), this, QDBusConnection::ExportAllSlots | QDBusConnection::ExportAllSignals)) {
|
||||
::exit(-1);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (!QDBusConnection::systemBus().registerService(QStringLiteral("org.kde.kpmcore.helperinterface"))) {
|
||||
::exit(-1);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
// we know this service must be registered already as DBus policy blocks calls from anyone else
|
||||
|
@ -69,24 +73,25 @@ ExternalCommandHelper::ExternalCommandHelper()
|
|||
@param size the number of bytes to read
|
||||
@return true on success
|
||||
*/
|
||||
bool ExternalCommandHelper::readData(const QString& sourceDevice, QByteArray& buffer, const qint64 offset, const qint64 size)
|
||||
bool ExternalCommandHelper::readData(QFile& device, QByteArray& buffer, const qint64 offset, const qint64 size)
|
||||
{
|
||||
QFile device(sourceDevice);
|
||||
|
||||
if (!device.isOpen()) {
|
||||
if (!device.open(QIODevice::ReadOnly | QIODevice::Unbuffered)) {
|
||||
qCritical() << xi18n("Could not open device <filename>%1</filename> for reading.", sourceDevice);
|
||||
qCritical() << xi18n("Could not open device <filename>%1</filename> for reading.", device.fileName());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!device.seek(offset)) {
|
||||
qCritical() << xi18n("Could not seek position %1 on device <filename>%2</filename>.", offset, sourceDevice);
|
||||
// Sequential devices such as /dev/zero or /dev/urandom return false on seek().
|
||||
if (!device.isSequential() && !device.seek(offset)) {
|
||||
qCritical() << xi18n("Could not seek position %1 on device <filename>%2</filename>.", offset, device.fileName());
|
||||
return false;
|
||||
}
|
||||
|
||||
buffer = device.read(size);
|
||||
|
||||
if (size != buffer.size()) {
|
||||
qCritical() << xi18n("Could not read from device <filename>%1</filename>.", sourceDevice);
|
||||
qCritical() << xi18n("Could not read from device <filename>%1</filename>.", device.fileName());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -94,58 +99,59 @@ bool ExternalCommandHelper::readData(const QString& sourceDevice, QByteArray& bu
|
|||
}
|
||||
|
||||
/** Writes the data from buffer to a given device.
|
||||
@param targetDevice device or file to write to
|
||||
@param device device or file to write to
|
||||
@param buffer the data that we write
|
||||
@param offset offset where to begin writing
|
||||
@return true on success
|
||||
*/
|
||||
bool ExternalCommandHelper::writeData(const QString &targetDevice, const QByteArray& buffer, const qint64 offset)
|
||||
bool ExternalCommandHelper::writeData(QFile& device, const QByteArray& buffer, const qint64 offset)
|
||||
{
|
||||
QFile device(targetDevice);
|
||||
|
||||
auto flags = QIODevice::WriteOnly | QIODevice::Unbuffered | QIODevice::Append;
|
||||
auto flags = QIODevice::WriteOnly | QIODevice::Unbuffered;
|
||||
if (!device.isOpen()) {
|
||||
if (!device.open(flags)) {
|
||||
qCritical() << xi18n("Could not open device <filename>%1</filename> for writing.", targetDevice);
|
||||
qCritical() << xi18n("Could not open device <filename>%1</filename> for writing.", device.fileName());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!device.seek(offset)) {
|
||||
qCritical() << xi18n("Could not seek position %1 on device <filename>%2</filename>.", offset, targetDevice);
|
||||
qCritical() << xi18n("Could not seek position %1 on device <filename>%2</filename>.", offset, device.fileName());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (device.write(buffer) != buffer.size()) {
|
||||
qCritical() << xi18n("Could not write to device <filename>%1</filename>.", targetDevice);
|
||||
qCritical() << xi18n("Could not write to device <filename>%1</filename>.", device.fileName());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Creates a new file with given contents.
|
||||
@param filePath file to write to
|
||||
@param fileContents the data that we write
|
||||
/** Creates a new fstab file with given contents.
|
||||
@param Contents the data that we write
|
||||
@return true on success
|
||||
*/
|
||||
bool ExternalCommandHelper::CreateFile(const QString &filePath, const QByteArray& fileContents)
|
||||
bool ExternalCommandHelper::WriteFstab(const QByteArray& fstabContents)
|
||||
{
|
||||
if (!isCallerAuthorized()) {
|
||||
return false;
|
||||
}
|
||||
// Do not allow using this helper for writing to arbitrary location
|
||||
if ( !filePath.contains(QStringLiteral("/etc/fstab")) )
|
||||
if (fstabContents.size() > MiB) {
|
||||
qCritical() << QStringLiteral("/etc/fstab size limit exceeded.");
|
||||
return false;
|
||||
}
|
||||
QString fstabPath = QStringLiteral("/etc/fstab");
|
||||
QFile fstabFile(fstabPath);
|
||||
|
||||
QFile device(filePath);
|
||||
|
||||
// WriteOnly implies O_TRUNC
|
||||
auto flags = QIODevice::WriteOnly | QIODevice::Unbuffered;
|
||||
if (!device.open(flags)) {
|
||||
qCritical() << xi18n("Could not open file <filename>%1</filename> for writing.", filePath);
|
||||
if (!fstabFile.open(flags)) {
|
||||
qCritical() << xi18n("Could not open file <filename>%1</filename> for writing.", fstabPath);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (device.write(fileContents) != fileContents.size()) {
|
||||
qCritical() << xi18n("Could not write to file <filename>%1</filename>.", filePath);
|
||||
if (fstabFile.write(fstabContents) != fstabContents.size()) {
|
||||
qCritical() << xi18n("Could not write to file <filename>%1</filename>.", fstabPath);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -153,29 +159,72 @@ bool ExternalCommandHelper::CreateFile(const QString &filePath, const QByteArray
|
|||
}
|
||||
|
||||
// If targetDevice is empty then return QByteArray with data that was read from disk.
|
||||
QVariantMap ExternalCommandHelper::CopyBlocks(const QString& sourceDevice, const qint64 sourceFirstByte, const qint64 sourceLength, const QString& targetDevice, const qint64 targetFirstByte, const qint64 blockSize)
|
||||
QVariantMap ExternalCommandHelper::CopyFileData(const QString& sourceDevice, const qint64 sourceOffset, const qint64 sourceLength, const QString& targetDevice, const qint64 targetOffset, const qint64 chunkSize)
|
||||
{
|
||||
if (!isCallerAuthorized()) {
|
||||
return QVariantMap();
|
||||
return {};
|
||||
}
|
||||
|
||||
// Avoid division by zero further down
|
||||
if (!chunkSize) {
|
||||
return {};
|
||||
}
|
||||
|
||||
// Prevent some out of memory situations
|
||||
if (chunkSize > 100 * MiB) {
|
||||
return {};
|
||||
}
|
||||
|
||||
// Check for relative paths
|
||||
std::filesystem::path sourcePath(sourceDevice.toStdU16String());
|
||||
std::filesystem::path targetPath(targetDevice.toStdU16String());
|
||||
if(sourcePath.is_relative() || targetPath.is_relative()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
// Only allow writing to existing files.
|
||||
if(!std::filesystem::exists(targetPath)) {
|
||||
return {};
|
||||
}
|
||||
|
||||
QVariantMap reply;
|
||||
reply[QStringLiteral("success")] = true;
|
||||
|
||||
const qint64 blocksToCopy = sourceLength / blockSize;
|
||||
qint64 readOffset = sourceFirstByte;
|
||||
qint64 writeOffset = targetFirstByte;
|
||||
qint32 copyDirection = 1;
|
||||
// This enum specified whether individual data chunks are moved left or right
|
||||
// When source and target devices are the same we have to be careful not to overwrite
|
||||
// source data with newly written data. We don't have to do this if sourceDevice is not
|
||||
// targetDevice but there are no disadvantages in applying the same scheme.
|
||||
// When partition is moved to the left, we start with the leftmost chunk,
|
||||
// and move it further left, then second leftmost chunk and so on.
|
||||
// But when we move partition to the right, we start with rightmost chunk.
|
||||
// To account for this difference, we introduce CopyDirection variable which takes
|
||||
// care of some of the differences in offset calculation between these two cases.
|
||||
enum CopyDirection : qint8 {
|
||||
Left = 1,
|
||||
Right = -1,
|
||||
};
|
||||
qint8 copyDirection = targetOffset > sourceOffset ? CopyDirection::Right : CopyDirection::Left;
|
||||
|
||||
if (targetFirstByte > sourceFirstByte) {
|
||||
readOffset = sourceFirstByte + sourceLength - blockSize;
|
||||
writeOffset = targetFirstByte + sourceLength - blockSize;
|
||||
copyDirection = -1;
|
||||
// Let readOffset (r) and writeOffset (w) be the offsets of the first chunk that we move.
|
||||
// When we move data to the left:
|
||||
// ______target______ ______source______
|
||||
// r <- w=================
|
||||
qint64 readOffset = sourceOffset;
|
||||
qint64 writeOffset = targetOffset;
|
||||
|
||||
// When we move data to the right, we start moving data from the last chunk
|
||||
// ______source______ ______target______
|
||||
// =================r -> w
|
||||
if (copyDirection == CopyDirection::Right) {
|
||||
readOffset = sourceOffset + sourceLength - chunkSize;
|
||||
writeOffset = targetOffset + sourceLength - chunkSize;
|
||||
}
|
||||
|
||||
const qint64 lastBlock = sourceLength % blockSize;
|
||||
const qint64 chunksToCopy = sourceLength / chunkSize;
|
||||
const qint64 lastBlock = sourceLength % chunkSize;
|
||||
|
||||
qint64 bytesWritten = 0;
|
||||
qint64 blocksCopied = 0;
|
||||
qint64 chunksCopied = 0;
|
||||
|
||||
QByteArray buffer;
|
||||
int percent = 0;
|
||||
|
@ -183,27 +232,29 @@ QVariantMap ExternalCommandHelper::CopyBlocks(const QString& sourceDevice, const
|
|||
|
||||
timer.start();
|
||||
|
||||
QString reportText = xi18nc("@info:progress", "Copying %1 blocks (%2 bytes) from %3 to %4, direction: %5.", blocksToCopy,
|
||||
sourceLength, readOffset, writeOffset, copyDirection == 1 ? i18nc("direction: left", "left")
|
||||
QString reportText = xi18nc("@info:progress", "Copying %1 chunks (%2 bytes) from %3 to %4, direction: %5.", chunksToCopy,
|
||||
sourceLength, readOffset, writeOffset, copyDirection == CopyDirection::Left ? i18nc("direction: left", "left")
|
||||
: i18nc("direction: right", "right"));
|
||||
Q_EMIT report(reportText);
|
||||
|
||||
bool rval = true;
|
||||
|
||||
while (blocksCopied < blocksToCopy && !targetDevice.isEmpty()) {
|
||||
if (!(rval = readData(sourceDevice, buffer, readOffset + blockSize * blocksCopied * copyDirection, blockSize)))
|
||||
QFile target(targetDevice);
|
||||
QFile source(sourceDevice);
|
||||
while (chunksCopied < chunksToCopy) {
|
||||
if (!(rval = readData(source, buffer, readOffset + chunkSize * chunksCopied * copyDirection, chunkSize)))
|
||||
break;
|
||||
|
||||
if (!(rval = writeData(targetDevice, buffer, writeOffset + blockSize * blocksCopied * copyDirection)))
|
||||
if (!(rval = writeData(target, buffer, writeOffset + chunkSize * chunksCopied * copyDirection)))
|
||||
break;
|
||||
|
||||
bytesWritten += buffer.size();
|
||||
|
||||
if (++blocksCopied * 100 / blocksToCopy != percent) {
|
||||
percent = blocksCopied * 100 / blocksToCopy;
|
||||
if (++chunksCopied * 100 / chunksToCopy != percent) {
|
||||
percent = chunksCopied * 100 / chunksToCopy;
|
||||
|
||||
if (percent % 5 == 0 && timer.elapsed() > 1000) {
|
||||
const qint64 mibsPerSec = (blocksCopied * blockSize / 1024 / 1024) / (timer.elapsed() / 1000);
|
||||
const qint64 mibsPerSec = (chunksCopied * chunkSize / 1024 / 1024) / (timer.elapsed() / 1000);
|
||||
const qint64 estSecsLeft = (100 - percent) * timer.elapsed() / percent / 1000;
|
||||
reportText = xi18nc("@info:progress", "Copying %1 MiB/second, estimated time left: %2", mibsPerSec, QTime(0, 0).addSecs(estSecsLeft).toString());
|
||||
Q_EMIT report(reportText);
|
||||
|
@ -214,19 +265,16 @@ QVariantMap ExternalCommandHelper::CopyBlocks(const QString& sourceDevice, const
|
|||
|
||||
// copy the remainder
|
||||
if (rval && lastBlock > 0) {
|
||||
Q_ASSERT(lastBlock < blockSize);
|
||||
Q_ASSERT(lastBlock < chunkSize);
|
||||
|
||||
const qint64 lastBlockReadOffset = copyDirection > 0 ? readOffset + blockSize * blocksCopied : sourceFirstByte;
|
||||
const qint64 lastBlockWriteOffset = copyDirection > 0 ? writeOffset + blockSize * blocksCopied : targetFirstByte;
|
||||
reportText = xi18nc("@info:progress", "Copying remainder of block size %1 from %2 to %3.", lastBlock, lastBlockReadOffset, lastBlockWriteOffset);
|
||||
const qint64 lastBlockReadOffset = copyDirection == CopyDirection::Left ? readOffset + chunkSize * chunksCopied : sourceOffset;
|
||||
const qint64 lastBlockWriteOffset = copyDirection == CopyDirection::Left ? writeOffset + chunkSize * chunksCopied : targetOffset;
|
||||
reportText = xi18nc("@info:progress", "Copying remainder of chunk size %1 from %2 to %3.", lastBlock, lastBlockReadOffset, lastBlockWriteOffset);
|
||||
Q_EMIT report(reportText);
|
||||
rval = readData(sourceDevice, buffer, lastBlockReadOffset, lastBlock);
|
||||
rval = readData(source, buffer, lastBlockReadOffset, lastBlock);
|
||||
|
||||
if (rval) {
|
||||
if (targetDevice.isEmpty())
|
||||
reply[QStringLiteral("targetByteArray")] = buffer;
|
||||
else
|
||||
rval = writeData(targetDevice, buffer, lastBlockWriteOffset);
|
||||
rval = writeData(target, buffer, lastBlockWriteOffset);
|
||||
}
|
||||
|
||||
if (rval) {
|
||||
|
@ -235,14 +283,48 @@ QVariantMap ExternalCommandHelper::CopyBlocks(const QString& sourceDevice, const
|
|||
}
|
||||
}
|
||||
|
||||
reportText = xi18ncp("@info:progress argument 2 is a string such as 7 bytes (localized accordingly)", "Copying 1 block (%2) finished.", "Copying %1 blocks (%2) finished.", blocksCopied, i18np("1 byte", "%1 bytes", bytesWritten));
|
||||
reportText = xi18ncp("@info:progress argument 2 is a string such as 7 bytes (localized accordingly)", "Copying 1 chunk (%2) finished.", "Copying %1 chunks (%2) finished.", chunksCopied, i18np("1 byte", "%1 bytes", bytesWritten));
|
||||
Q_EMIT report(reportText);
|
||||
|
||||
reply[QStringLiteral("success")] = rval;
|
||||
return reply;
|
||||
}
|
||||
|
||||
bool ExternalCommandHelper::WriteData(const QByteArray& buffer, const QString& targetDevice, const qint64 targetFirstByte)
|
||||
QByteArray ExternalCommandHelper::ReadData(const QString& device, const qint64 offset, const qint64 length)
|
||||
{
|
||||
if (!isCallerAuthorized()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
if (length > MiB) {
|
||||
return {};
|
||||
}
|
||||
if (!std::filesystem::is_block_file(device.toStdU16String())) {
|
||||
qWarning() << "Not a block device";
|
||||
return {};
|
||||
}
|
||||
|
||||
// Do not follow symlinks
|
||||
QFileInfo info(device);
|
||||
if (info.isSymbolicLink()) {
|
||||
qWarning() << "ReadData: device should not be symbolic link";
|
||||
return {};
|
||||
}
|
||||
if (device.left(5) != QStringLiteral("/dev/") || device.left(9) != QStringLiteral("/dev/shm/")) {
|
||||
qWarning() << "Error: trying to read data from device not in /dev";
|
||||
return {};
|
||||
}
|
||||
|
||||
QByteArray buffer;
|
||||
QFile sourceDevice(device);
|
||||
bool rval = readData(sourceDevice, buffer, offset, length);
|
||||
if (rval) {
|
||||
return buffer;
|
||||
}
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
bool ExternalCommandHelper::WriteData(const QByteArray& buffer, const QString& targetDevice, const qint64 targetOffset)
|
||||
{
|
||||
if (!isCallerAuthorized()) {
|
||||
return false;
|
||||
|
@ -251,44 +333,74 @@ bool ExternalCommandHelper::WriteData(const QByteArray& buffer, const QString& t
|
|||
if ( targetDevice.left(5) != QStringLiteral("/dev/") )
|
||||
return false;
|
||||
|
||||
return writeData(targetDevice, buffer, targetFirstByte);
|
||||
auto targetPath = std::filesystem::path(targetDevice.toStdU16String());
|
||||
if (!std::filesystem::is_block_file(targetDevice.toStdU16String())) {
|
||||
qWarning() << "Not a block device";
|
||||
return {};
|
||||
}
|
||||
|
||||
auto canonicalTargetPath = std::filesystem::canonical(targetPath);
|
||||
// TODO: Qt6 supports std::filesystem::path
|
||||
QFile device(QLatin1String(canonicalTargetPath.c_str()));
|
||||
return writeData(device, buffer, targetOffset);
|
||||
}
|
||||
|
||||
QVariantMap ExternalCommandHelper::RunCommand(const QString& command, const QStringList& arguments, const QByteArray& input, const int processChannelMode)
|
||||
{
|
||||
if (!isCallerAuthorized()) {
|
||||
return QVariantMap();
|
||||
return {};
|
||||
}
|
||||
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||
QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8"));
|
||||
#endif
|
||||
|
||||
QVariantMap reply;
|
||||
reply[QStringLiteral("success")] = true;
|
||||
reply[QStringLiteral("success")] = false;
|
||||
|
||||
if (command.isEmpty()) {
|
||||
reply[QStringLiteral("success")] = false;
|
||||
return reply;
|
||||
}
|
||||
|
||||
// Compare with command whitelist
|
||||
QString basename = command.mid(command.lastIndexOf(QLatin1Char('/')) + 1);
|
||||
if (std::find(std::begin(allowedCommands), std::end(allowedCommands), basename) == std::end(allowedCommands)) {
|
||||
qInfo() << command <<" command is not one of the whitelisted command";
|
||||
qApp->quit();
|
||||
QFileInfo fileInfo(command);
|
||||
QString basename = fileInfo.fileName();
|
||||
if (allowedCommands.find(basename) == allowedCommands.end()) { // TODO: C++20: replace with contains
|
||||
qInfo() << command << "command is not one of the whitelisted commands";
|
||||
reply[QStringLiteral("success")] = false;
|
||||
return reply;
|
||||
}
|
||||
|
||||
// Make sure command is located in the trusted prefix
|
||||
QDir prefix = fileInfo.absoluteDir();
|
||||
QString dirname = prefix.dirName();
|
||||
if (dirname == QStringLiteral("bin") || dirname == QStringLiteral("sbin")) {
|
||||
prefix.cdUp();
|
||||
}
|
||||
if (trustedPrefixes.find(prefix.path()) == trustedPrefixes.end()) { // TODO: C++20: replace with contains
|
||||
qInfo() << prefix.path() << "prefix is not one of the trusted command prefixes";
|
||||
reply[QStringLiteral("success")] = false;
|
||||
return reply;
|
||||
}
|
||||
|
||||
// connect(&cmd, &QProcess::readyReadStandardOutput, this, &ExternalCommandHelper::onReadOutput);
|
||||
|
||||
m_cmd.setEnvironment( { QStringLiteral("LVM_SUPPRESS_FD_WARNINGS=1") } );
|
||||
m_cmd.setProcessChannelMode(static_cast<QProcess::ProcessChannelMode>(processChannelMode));
|
||||
m_cmd.start(command, arguments);
|
||||
m_cmd.write(input);
|
||||
m_cmd.closeWriteChannel();
|
||||
m_cmd.waitForFinished(-1);
|
||||
QByteArray output = m_cmd.readAllStandardOutput();
|
||||
reply[QStringLiteral("output")] = output;
|
||||
reply[QStringLiteral("exitCode")] = m_cmd.exitCode();
|
||||
QProcess cmd;
|
||||
cmd.setEnvironment( { QStringLiteral("LVM_SUPPRESS_FD_WARNINGS=1") } );
|
||||
|
||||
if((processChannelMode != QProcess::SeparateChannels) && (processChannelMode != QProcess::MergedChannels)) {
|
||||
return reply;
|
||||
}
|
||||
cmd.setProcessChannelMode(static_cast<QProcess::ProcessChannelMode>(processChannelMode));
|
||||
cmd.start(command, arguments);
|
||||
cmd.write(input);
|
||||
cmd.closeWriteChannel();
|
||||
cmd.waitForFinished(-1);
|
||||
QByteArray output = cmd.readAllStandardOutput();
|
||||
reply[QStringLiteral("output")] = output;
|
||||
reply[QStringLiteral("exitCode")] = cmd.exitCode();
|
||||
|
||||
reply[QStringLiteral("success")] = true;
|
||||
return reply;
|
||||
}
|
||||
|
||||
|
@ -316,6 +428,9 @@ bool ExternalCommandHelper::isCallerAuthorized()
|
|||
|
||||
// Cache successful authentication requests, so that clients don't need
|
||||
// to authenticate multiple times during long partitioning operations.
|
||||
// auth_admin_keep is not used intentionally because with current architecture
|
||||
// it might lead to data loss if user cancels sfdisk partition boundary adjustment
|
||||
// after partition data was moved.
|
||||
if (m_serviceWatcher->watchedServices().contains(message().service())) {
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -14,12 +14,14 @@
|
|||
#include <memory>
|
||||
#include <unordered_set>
|
||||
|
||||
#include <QEventLoop>
|
||||
#include <QString>
|
||||
#include <QProcess>
|
||||
#include <QDBusContext>
|
||||
#include <QEventLoop>
|
||||
#include <QFile>
|
||||
#include <QProcess>
|
||||
#include <QString>
|
||||
|
||||
class QDBusServiceWatcher;
|
||||
constexpr qint64 MiB = 1 << 20;
|
||||
|
||||
class ExternalCommandHelper : public QObject, public QDBusContext
|
||||
{
|
||||
|
@ -32,21 +34,21 @@ Q_SIGNALS:
|
|||
|
||||
public:
|
||||
ExternalCommandHelper();
|
||||
bool readData(const QString& sourceDevice, QByteArray& buffer, const qint64 offset, const qint64 size);
|
||||
bool writeData(const QString& targetDevice, const QByteArray& buffer, const qint64 offset);
|
||||
bool readData(QFile& device, QByteArray& buffer, const qint64 offset, const qint64 size);
|
||||
bool writeData(QFile& device, const QByteArray& buffer, const qint64 offset);
|
||||
|
||||
public Q_SLOTS:
|
||||
Q_SCRIPTABLE QVariantMap RunCommand(const QString& command, const QStringList& arguments, const QByteArray& input, const int processChannelMode);
|
||||
Q_SCRIPTABLE QVariantMap CopyBlocks(const QString& sourceDevice, const qint64 sourceFirstByte, const qint64 sourceLength, const QString& targetDevice, const qint64 targetFirstByte, const qint64 blockSize);
|
||||
Q_SCRIPTABLE bool WriteData(const QByteArray& buffer, const QString& targetDevice, const qint64 targetFirstByte);
|
||||
Q_SCRIPTABLE bool CreateFile(const QString& filePath, const QByteArray& fileContents);
|
||||
Q_SCRIPTABLE QVariantMap CopyFileData(const QString& sourceDevice, const qint64 sourceOffset, const qint64 sourceLength,
|
||||
const QString& targetDevice, const qint64 targetOffset, const qint64 blockSize);
|
||||
Q_SCRIPTABLE QByteArray ReadData(const QString& device, const qint64 offset, const qint64 length);
|
||||
Q_SCRIPTABLE bool WriteData(const QByteArray& buffer, const QString& targetDevice, const qint64 targetOffset);
|
||||
Q_SCRIPTABLE bool WriteFstab(const QByteArray& fstabContents);
|
||||
|
||||
private:
|
||||
|
||||
bool isCallerAuthorized();
|
||||
|
||||
void onReadOutput();
|
||||
QProcess m_cmd;
|
||||
QDBusServiceWatcher *m_serviceWatcher = nullptr;
|
||||
};
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@ KAboutData aboutKPMcore()
|
|||
KAboutData aboutData( QStringLiteral("kpmcore"),
|
||||
xi18nc("@title", "<application>KPMcore</application>"), QStringLiteral(VERSION),
|
||||
xi18nc("@title", "Library for managing partitions"),
|
||||
KAboutLicense::GPL_V3, xi18nc("@info:credit", "© 2008-2020 KPMcore developers" ) );
|
||||
KAboutLicense::GPL_V3, xi18nc("@info:credit", "© 2008-2022 KPMcore developers" ) );
|
||||
aboutData.setOrganizationDomain(QByteArray("kde.org"));
|
||||
aboutData.setProductName(QByteArray("kpmcore"));
|
||||
aboutData.setHomepage(QStringLiteral("https://commits.kde.org/kpmcore"));
|
||||
|
|
|
@ -9,38 +9,45 @@ SPDX-License-Identifier: CC0-1.0
|
|||
<policyconfig>
|
||||
<icon_name>partitionmanager</icon_name>
|
||||
<action id="org.kde.kpmcore.externalcommand.init" >
|
||||
<description>Start external command daemon</description>
|
||||
<description xml:lang="ast">Aniciu del degorriu de comandos esternos</description>
|
||||
<description xml:lang="ca">Inicia el dimoni d'ordres externes</description>
|
||||
<description xml:lang="ca@valencia">Inicia el dimoni d'ordres externes</description>
|
||||
<description xml:lang="el">Εκκίνηση διεργασίας με εξωτερική εντολή</description>
|
||||
<description xml:lang="en_GB">Start external command daemon</description>
|
||||
<description xml:lang="es">Iniciar el demonio de órdenes externas</description>
|
||||
<description xml:lang="fr">Lancer le démon externe de commandes</description>
|
||||
<description xml:lang="it">Avvia demone per comando esterno</description>
|
||||
<description xml:lang="lt">Paleisti išorinių komandų tarnybą</description>
|
||||
<description xml:lang="nl">Start externe opdrachtdaemon</description>
|
||||
<description xml:lang="pt">Iniciar o servidor de comandos externos</description>
|
||||
<description xml:lang="pt_BR">Iniciar comando externo do daemon</description>
|
||||
<description xml:lang="sl">Zaženi demon za zunanje ukaze</description>
|
||||
<description xml:lang="sv">Starta extern kommandodemon</description>
|
||||
<description xml:lang="uk">Запуск фонової служби зовнішньої команди</description>
|
||||
<description>Run privileged partition manager helper</description>
|
||||
<description xml:lang="ca">Executa l'ajudant del gestor de particions amb privilegis</description>
|
||||
<description xml:lang="ca@valencia">Executa l'ajudant del gestor de particions amb privilegis</description>
|
||||
<description xml:lang="en_GB">Run privileged partition manager helper</description>
|
||||
<description xml:lang="es">Ejecutar la aplicación auxiliar de gestión de particiones con privilegios</description>
|
||||
<description xml:lang="fr">Lancer l'assistant de gestionnaire de partition en mode administrateur</description>
|
||||
<description xml:lang="it">Esegui l'helper per la gestione delle partizioni privilegiate</description>
|
||||
<description xml:lang="ko">상위 권한으로 파티션 관리자 도우미 실행</description>
|
||||
<description xml:lang="nl">Hulpprogramma voor partitiebeheerder met extra rechten uitvoeren</description>
|
||||
<description xml:lang="pl">Uruchom uprzywilejowane zarządzanie partycjami</description>
|
||||
<description xml:lang="pt">Executar o utilitário privilegiado do gestor de partições</description>
|
||||
<description xml:lang="pt_BR">Executa o auxiliar do gerenciador de partições com privilégios</description>
|
||||
<description xml:lang="sl">Zaženi pooblaščenega pomočnika skrbnika particij</description>
|
||||
<description xml:lang="sv">Kör hjälpverktyg för privilegierad partitionshanterare</description>
|
||||
<description xml:lang="uk">Запуск привілейованої допоміжної програми з керування розділами</description>
|
||||
<description xml:lang="zh_CN">使用管理员权限运行分区管理器辅助程序</description>
|
||||
<message>Administrative privileges are required to manage disks</message>
|
||||
<message xml:lang="ast">Ríquense los privilexos alministrativos pa xestionar discos</message>
|
||||
<message xml:lang="ca">Es requereixen privilegis d'administrador per a gestionar els discs</message>
|
||||
<message xml:lang="ca@valencia">Es requereixen privilegis d'administrador per a gestionar els discs</message>
|
||||
<message xml:lang="ca@valencia">Es requerixen privilegis d'administrador per a gestionar els discs</message>
|
||||
<message xml:lang="cs">Pro správu disků jsou potřeba práva administrátora</message>
|
||||
<message xml:lang="de">Systemverwalterrechte sind zur Verwaltung von Festplatten erforderlich</message>
|
||||
<message xml:lang="el">Απαιτούνται δικαιώματα διαχειριστή για τη διαχείριση των δίσκων</message>
|
||||
<message xml:lang="en_GB">Administrative privileges are required to manage disks</message>
|
||||
<message xml:lang="es">Se necesitan permisos de administrador para gestionar discos</message>
|
||||
<message xml:lang="fr">Vous devez disposer des privilèges d'administrateur pour gérer les disques.</message>
|
||||
<message xml:lang="hu">A lemzek kezeléséhez adminisztrátori jogosultságok szükségesek</message>
|
||||
<message xml:lang="it">Per gestire il disco sono richiesti privilegi amministrativi</message>
|
||||
<message xml:lang="ko">디스크를 관리하려면 권한이 필요함</message>
|
||||
<message xml:lang="lt">Diskų tvarkymui reikalingos administratoriaus teisės</message>
|
||||
<message xml:lang="nl">Er zijn administratieve rechten vereist om schijven te beheren</message>
|
||||
<message xml:lang="pl">Do zarządzania dyskami wymagane są uprawnienia administratora</message>
|
||||
<message xml:lang="pt">São necessários privilégios de administração para gerir os discos</message>
|
||||
<message xml:lang="pt_BR">São necessários privilégios administrativos para gerenciar discos</message>
|
||||
<message xml:lang="sk">Na správu diskov sa vyžadujú oprávnenia správcu</message>
|
||||
<message xml:lang="sl">Za upravljanje diskov so potrebne pravice upravljavca računalnika</message>
|
||||
<message xml:lang="sv">Administratörsprivilegier krävs för att hantera diskar</message>
|
||||
<message xml:lang="uk">Для керування дисками потрібні права доступу адміністратора (root)</message>
|
||||
<message xml:lang="zh_CN">管理磁盘需要管理员权限</message>
|
||||
<defaults>
|
||||
<allow_inactive>no</allow_inactive>
|
||||
<allow_active>auth_admin_keep</allow_active>
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
/
|
||||
/usr
|
|
@ -26,7 +26,7 @@ target_link_libraries(testhelpers PRIVATE kpmcore)
|
|||
|
||||
macro (kpm_test name)
|
||||
add_executable(${name} ${ARGN})
|
||||
target_link_libraries(${name} testhelpers kpmcore Qt5::Core)
|
||||
target_link_libraries(${name} testhelpers kpmcore Qt${QT_MAJOR_VERSION}::Core)
|
||||
endmacro()
|
||||
|
||||
###
|
||||
|
@ -34,15 +34,15 @@ endmacro()
|
|||
# Tests of initialization: try explicitly loading some backends
|
||||
kpm_test(testinit testinit.cpp) # Default backend
|
||||
if(TARGET pmdummybackendplugin)
|
||||
add_test(NAME testinit-dummy COMMAND testinit $<TARGET_FILE:pmdummybackendplugin>)
|
||||
add_test(NAME testinit-dummy COMMAND testinit $<TARGET_FILE_NAME:pmdummybackendplugin>)
|
||||
endif()
|
||||
if(TARGET pmsfdiskbackendplugin)
|
||||
add_test(NAME testinit-sfdisk COMMAND testinit $<TARGET_FILE:pmsfdiskbackendplugin>)
|
||||
add_test(NAME testinit-sfdisk COMMAND testinit $<TARGET_FILE_NAME:pmsfdiskbackendplugin>)
|
||||
else()
|
||||
return() # All the rest really needs a working backend
|
||||
endif()
|
||||
|
||||
set(BACKEND $<TARGET_FILE:pmsfdiskbackendplugin>)
|
||||
set(BACKEND $<TARGET_FILE_NAME:pmsfdiskbackendplugin>)
|
||||
|
||||
###
|
||||
#
|
||||
|
|
Loading…
Reference in New Issue