Compare commits

...

131 Commits

Author SHA1 Message Date
Andrius Štikonas 83a865411d ExternalCommandHelper::ReadData should not follow symlinks.
Resolve all symlinks in the userspace application and make sure
that helper only deals with root owned path in /dev but not in
/dev/shm.
2022-06-20 00:03:18 +01:00
A. Wilcox 26e069d6cd
Tests: Fix backend loading for tests
Using $<TARGET_FILE> we receive the entire plugin file path, leading to
errors such as:

kf.coreaddons: no metadata found in "kpmcore//home/awilcox/Code/KDE/kpmcore/bin/kpmcore/pmdummybackendplugin.so" "The shared library was not found."

Using $<TARGET_FILE_NAME> instead we are able to have just the plugin
name, which does load properly.  The tests now pass.
2022-06-12 16:14:51 -05:00
l10n daemon script eb50358b72 GIT_SILENT made messages (after extraction) 2022-06-09 01:01:02 +00:00
ivan tkachenko 9b015661aa
Present SMART status duration in more human-readable spellout format
BUG: 449386
2022-05-29 16:56:27 +03:00
Andrius Štikonas fd4a330887 Allow setting empty FAT label.
This breaks compatibility with dosfstools 4.1

BUG: 453388
2022-05-15 23:20:25 +01:00
l10n daemon script 6204041935 GIT_SILENT made messages (after extraction) 2022-05-15 00:54:27 +00:00
Andrius Štikonas 36881cde62 Fix location of GPT header on 4K LBA devices.
BUG: 453333
2022-05-04 17:49:08 +01:00
l10n daemon script d247e027a1 GIT_SILENT made messages (after extraction) 2022-03-29 00:58:46 +00:00
Andrius Štikonas 5afe143a19 Add a maximum file size limit when writing to /etc/fstab file. 2022-03-27 14:19:56 +01:00
Andrius Štikonas c9d7e0cd6e Fix path to reuse-lint yaml file. 2022-03-21 18:54:53 +00:00
Andrius Štikonas 7c299857c8 Add reuse lint. 2022-03-21 18:54:01 +00:00
Andrius Štikonas 0c1af38e5e Use lowercase for cmake functions. 2022-03-20 21:10:17 +00:00
Andrius Štikonas 6b260fa84e Only run partitioning commands from trusted prefixes. 2022-03-20 21:07:17 +00:00
l10n daemon script e112ebe944 SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2022-03-20 02:14:59 +00:00
l10n daemon script 05a96c874f GIT_SILENT made messages (after extraction) 2022-03-20 00:55:56 +00:00
Albert Astals Cid 76ede03bd2 GIT_SILENT Upgrade release service version to 22.07.70. 2022-03-12 13:26:33 +01:00
l10n daemon script bbcfd8202b GIT_SILENT made messages (after extraction) 2022-03-05 00:47:19 +00:00
l10n daemon script 1006a8daeb SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2022-02-27 01:56:05 +00:00
l10n daemon script b6a52fe2b1 GIT_SILENT made messages (after extraction) 2022-02-27 00:52:28 +00:00
l10n daemon script 0681ebd790 GIT_SILENT made messages (after extraction) 2022-02-21 00:47:25 +00:00
Andrius Štikonas 858f8d9bae Add a comment about WriteOnly. 2022-02-20 20:49:57 +00:00
Andrius Štikonas d92ebc0b76 Rename variables into more appropriate fstabPath and fstabFile. 2022-02-20 20:47:43 +00:00
Andrius Štikonas e483bab0d5 Restrict CreateFile method to WriteFstab method in polkit helper. 2022-02-20 19:42:25 +00:00
Andrius Štikonas 27b85117c4 Rename blockSize to chunkSize to avoid confusion with physical blocks. 2022-02-20 14:41:31 +00:00
Andrius Štikonas d9ceb50238 Add a few more comments explaining copy direction. 2022-02-20 14:41:31 +00:00
l10n daemon script 237d246457 GIT_SILENT made messages (after extraction) 2022-02-20 00:48:23 +00:00
Laurent Montel 8a209e9616 Fix building against qt6 we need kf5.90 2022-02-18 07:22:57 +01:00
l10n daemon script 3f1949f477 GIT_SILENT made messages (after extraction) 2022-02-18 00:48:05 +00:00
Andrius Štikonas c05bb54bc5 Set "false" as the default return value and change it to "true" on success.
Please enter the commit message for your changes. Lines starting
2022-02-15 19:56:46 +00:00
Andrius Štikonas fb1708b958 Fix a typo in definition of MiB constant. 2022-02-15 19:14:19 +00:00
l10n daemon script 94c1ff7133 GIT_SILENT made messages (after extraction) 2022-02-13 00:46:08 +00:00
l10n daemon script b4f5faed58 GIT_SILENT made messages (after extraction) 2022-02-12 00:46:25 +00:00
l10n daemon script 49900e80bf GIT_SILENT made messages (after extraction) 2022-02-11 00:47:29 +00:00
l10n daemon script e0d6c1ce43 GIT_SILENT made messages (after extraction) 2022-02-10 00:46:44 +00:00
l10n daemon script cff0f16a7d GIT_SILENT made messages (after extraction) 2022-02-09 00:50:22 +00:00
Andrius Štikonas 5717c3aa0b Update description of polkit helper. 2022-02-08 21:39:18 +00:00
Andrius Štikonas 1c87b494ef Add a node for Qt6. 2022-02-06 21:18:29 +00:00
Andrius Štikonas fd7f9b87a9 Do not repeatedly open and close file when reading from it. 2022-02-06 21:18:29 +00:00
Andrius Štikonas eddbd7a301 Do not repeatedly open and close file when writing to it. 2022-02-06 21:06:39 +00:00
Andrius Štikonas fb11a02d24 It is no longer necessary to namespace exit function. 2022-02-06 01:27:09 +00:00
Andrius Štikonas 4ef17463ff Make sure that path passed to WriteData is block device. 2022-02-05 14:42:17 +00:00
Andrius Štikonas 81a5eae665 Restrict CopyFileData to writing to already existing files. 2022-02-05 14:12:38 +00:00
Andrius Štikonas 3903ae1b83 Rename CopyBlocks to CopyFileData. 2022-02-05 14:05:50 +00:00
Andrius Štikonas 949ce01ae4 Check for relative paths in ExternalCommandHelper::CopyBlocks. 2022-02-05 13:48:37 +00:00
Andrius Štikonas 5d1c03b9d8 Restrict QProcess::ProcessChannelMode to two used values.
Casting and passing the processChannel argument unfiltered to QProcess
could pose a security issue if future additions are made to
QProcess that introduce new behaviour.
2022-02-05 13:24:38 +00:00
Andrius Štikonas 1502494eda Be a bit more strict in root helper when checking path to /etc/fstab. 2022-02-05 13:13:12 +00:00
Andrius Štikonas e2f097fce8 Remove unnecessary or non-existing Qt flags. 2022-01-21 00:29:01 +00:00
Andrius Štikonas 04170918bc Set KDE_COMPILERSETTINGS_LEVEL to 5.85. 2022-01-20 22:31:06 +00:00
Andrius Štikonas c6e37dbd8e One more missed place with INCLUDE_INSTALL_DIR. 2022-01-20 19:13:02 +00:00
Andrius Štikonas deb82fe2f9 Also remove INCLUDE_INSTALL_DIR in KPMcoreConfig.cmake file. 2022-01-20 19:10:58 +00:00
Andrius Štikonas 19cda738bd Do not set INCLUDE_INSTALL_DIR variable. 2022-01-20 19:04:53 +00:00
Andrius Štikonas cbea744bb3 Fix obsolete ECM variables 2022-01-20 18:35:33 +00:00
Andrius Štikonas a69bbb559d Fix cmake config file template to work with Qt6. 2022-01-18 01:18:04 +00:00
Andrius Štikonas 72b4142bcb Fix infinite recursion in dummy backend.
BUG: 432704
2022-01-16 14:22:50 +00:00
Andrius Štikonas 5174dce64f Remove unused forward declaration. 2022-01-16 13:59:01 +00:00
Andrius Štikonas 67550ca2f7 Add Qt6 CI. 2022-01-16 00:21:21 +00:00
Andrius Štikonas 73de1709e2 Port to Qt6. 2022-01-16 00:17:46 +00:00
Andrius Štikonas 08d2e3dc2c Changing swap labels while swap is active does not seem to work anymore. 2022-01-15 23:14:49 +00:00
Andrius Štikonas 7eb2ceed17 Port QStringRef to QStringView. 2022-01-15 22:49:42 +00:00
Andrius Štikonas b0cd5def42 Remove unused variable. 2022-01-15 22:33:29 +00:00
Andrius Štikonas d7912e21d8 Port away from KPluginLoader::factory. 2022-01-10 01:16:20 +00:00
Andrius Štikonas c31eabc842 Port away from deprecated method. 2022-01-10 01:11:13 +00:00
Andrius Štikonas 1d7a4e4010 Port away from KPluginLoader::metaData. 2022-01-10 00:33:43 +00:00
Andrius Štikonas 30d428c697 Port away from KPluginMetaData::serviceTypes. 2022-01-10 00:24:53 +00:00
Andrius Štikonas 5ffc5c6f23 Fix davfs entries being omitted from fstab file.
BUG: 447961
2022-01-05 23:00:17 +00:00
Andrius Štikonas e58ab02bac Add support for copying unknown partitions.
BUG: 447784
2022-01-01 16:18:57 +00:00
Andrius Štikonas d2fb56bcd2 Allow running chmod in externalcommand helper. 2021-12-28 15:26:01 +00:00
Tomaz Canabrava 770e16eb02 Use --recursive instead of -r 2021-12-28 15:07:35 +00:00
Tomaz Canabrava 36bb57c0dd Add posix permissions on filesystems used in posix systems 2021-12-28 15:07:35 +00:00
Tomaz Canabrava e1774d4026 Remove unused member 2021-12-28 15:07:35 +00:00
Tomaz Canabrava 9093b27bd8 Move the changePosixPermission to the Filesystem
And implement it on ext2, 3, 4. I don't know all the filesystems
that can have posix permissions, those three will do. if we need
more in the future we implement them, it's two lines of code.
2021-12-28 15:07:35 +00:00
Tomaz Canabrava 6c14ddb043 Add new job to change permission of the newly created partition 2021-12-28 15:07:35 +00:00
Andrius Štikonas 68c8fecffd Simplify code using K_PLUGIN_CLASS_WITH_JSON macro.
Also move kpmcore plugins into separate namespace.
2021-12-24 18:58:41 +00:00
Andrius Štikonas a5bdd5a4eb Switch to ntfsinfo to read NTFS usage.
BUG: 447248
2021-12-24 00:03:05 +00:00
Andrius Štikonas 31921c59fa Fix broken fstab when mount point includes space.
fstab column width was calculated before spaces were escaped which would
result in no space between mount point and file system type columns.

BUG: 446218
2021-12-04 23:31:02 +00:00
Tomaz Canabrava 65f986dc29 Add method to query if polkit is installed correctly
The std::cout and qDebugs on the external command helper is
not visible to the user as it runs in another process via dbus
this is highly annoying if you want to be able to discover what's
wrong on the command line.

A method that checks if the file is in the right place should be
called by the users of this library
2021-11-29 11:16:33 -03:00
Albert Astals Cid 259f562698 Add CI 2021-11-28 12:55:05 +01:00
Harald Sitter c79f5831ff add metainfo file
requirement to get generated on api.kde.org
2021-11-24 10:31:41 +00:00
Harald Sitter b3d0cfccaf set cmake interface dir on the target
this carries through into the Targets.cmake file we install which in
turn means that the imported target for the consumer defines its include
directory. this removes the need to manually add the include dir

also updated the readme accordingly
2021-11-23 10:14:58 +01:00
Ben Cooksley d9339e4833 Add additional dependencies of KPMCore 2021-11-21 16:40:25 +13:00
Ben Cooksley 702b30ee3a Add CI definitions for the seed job 2021-11-21 16:24:08 +13:00
l10n daemon script 172b76fe9b GIT_SILENT made messages (after extraction) 2021-11-20 00:30:09 +00:00
Andrius Štikonas e9fc875c5e Fix seek error when filling device with random data or zeroes. 2021-11-12 01:02:34 +00:00
l10n daemon script a9998425fd SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2021-11-09 01:23:12 +00:00
l10n daemon script 74218e12d6 GIT_SILENT made messages (after extraction) 2021-11-09 00:19:35 +00:00
Heiko Becker 644db18c75 GIT_SILENT Upgrade release service version to 22.03.70. 2021-11-08 20:59:42 +01:00
Andrius Štikonas 282cfdcde1 Do not destroy zfs pool when removing zfs partition.
This can be dangerous, e.g. if partition is part of raid set.
So better be more cautious and in some cases fail to remove partition
than lose data.
2021-10-30 21:13:09 +01:00
Andrius Štikonas 6f2be13f68 Bump minimal cmake version to 3.16 2021-09-29 17:56:45 +01:00
l10n daemon script 2734c58069 SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2021-09-08 01:30:14 +00:00
l10n daemon script d31f1733b6 SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2021-09-06 01:28:56 +00:00
Artem Grinev 00e6b77c29 Initialize all fields in Partition 2021-08-29 00:16:57 +04:00
Artem Grinev f4664671d6 Clear attributes on new partition creation 2021-08-27 02:37:19 +04:00
Albert Astals Cid c47ee6cae7 GIT_SILENT Upgrade release service version to 21.11.70. 2021-07-10 20:29:09 +02:00
l10n daemon script 4c32c38655 SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2021-07-08 01:22:49 +00:00
l10n daemon script b3050dc894 GIT_SILENT made messages (after extraction) 2021-07-08 00:20:41 +00:00
l10n daemon script f0188249e8 GIT_SILENT made messages (after extraction) 2021-05-17 00:27:08 +00:00
l10n daemon script ce39e14904 GIT_SILENT made messages (after extraction) 2021-03-27 02:33:43 +01:00
Yaroslav Sidlovsky 8746ef72fd Fix smartctl exit status success check
According to the smartctl man page:
```
EXIT STATUS
The  exit  statuses of smartctl are defined by a bitmask.  If all is well with the disk, the exit status (return value) of smartctl is 0 (all bits turned off).  If a problem occurs, or an error, potential error, or fault is detected, then a non-zero status is
returned.  In this case, the eight different bits in the exit status have the following meanings for ATA disks; some of these values may also be returned for SCSI disks.

Bit 0: Command line did not parse.

Bit 1: Device open failed, device did not return an IDENTIFY DEVICE structure, or device is in a low-power mode (see '-n' option above).

Bit 2: Some SMART or other ATA command to the disk failed, or there was a checksum error in a SMART data structure (see '-b' option above).

Bit 3: SMART status check returned "DISK FAILING".

Bit 4: We found prefail Attributes <= threshold.

Bit 5: SMART status check returned "DISK OK" but we found that some (usage or prefail) Attributes have been <= threshold at some time in the past.

Bit 6: The device error log contains records of errors.

Bit 7: The device self-test log contains records of errors.  [ATA only] Failed self-tests outdated by a newer successful extended self-test are ignored.
```

BUG: 429028
2021-03-17 16:03:32 +03:00
Albert Astals Cid ad35460628 GIT_SILENT Upgrade release service version to 21.07.70. 2021-03-13 22:28:27 +01:00
l10n daemon script c06a188d0e GIT_SILENT made messages (after extraction) 2021-03-03 03:33:29 +01:00
Guillaume Girol 0094461f60 lvm without arguments has returncode 3 2021-02-27 12:00:00 +00:00
Andrius Štikonas ad888767bb Use QStringLiteral. 2021-02-23 21:39:41 +00:00
Oxalica -- eea84fb605 Fix out of bounds read when parsing fstab.
Some fstab files only have 3 fields and mount options are completely omitted.
2021-02-22 16:45:48 +00:00
Andrius Štikonas 36dfae351f Add initial support for dosfstools 4.2.
Empty labels are not allowed anymore.
One can reset them with -r flag but that is not supported in older
dosfstools. So for now we just manually set label to NO_LABEL.

BUG: 432941
2021-02-19 17:51:43 +00:00
Michael Weghorn 813e574001 Wipe existing signatures when creating partition table
As the sfdisk man page says on the option '--wipe' that
specifies whether or not to wipe signatures in order
to avoid collisions:

> When this option is not given, the default is auto,
> in which case signatures are wiped only when in interactive mode

but sfdisk is not run in interactive mode here, since
stdin does not refer to a terminal, and the sfdisk
man page says:

> It [i.e. sfdisk] runs in interactive mode if executed on terminal
> (stdin refers to a terminal).

Therefore, explicitly pass the '--wipe=always' option to
sfdisk so that old signatures are wiped when a new partition
table is created.

Bug: 431628
2021-01-15 09:53:20 +01:00
Andrius Štikonas 31706cffdc Fix out of bounds read when parsing fstab.
BUG: 429191
2021-01-07 01:25:12 +00:00
Andrius Štikonas 06f15334ec Add support for exfatprogs
Bug: 430907
2020-12-28 17:50:07 +00:00
l10n daemon script 338811601b GIT_SILENT made messages (after extraction) 2020-12-07 02:39:36 +01:00
Andrius Štikonas a06d4ba0f7 Return QByteArray instead of bool in readData. 2020-11-29 23:34:29 +00:00
Andrius Štikonas 73da1bc514 Only allow using ReadData on block devices. 2020-11-29 23:24:49 +00:00
Andrius Štikonas b0e5fa66c4 Add an explicit ReadData method to polkit helper instead of relying on copyblocks with empty target device. 2020-11-29 23:14:08 +00:00
Andrius Štikonas 502ebc0474 Remove declaration of non-existing method. 2020-11-29 22:42:19 +00:00
Andrius Štikonas 04a095a542 Simplify find syntax. 2020-11-29 13:49:50 +00:00
Andrius Štikonas 5da47c26e9 Replace array with unordered set for better performance. 2020-11-29 13:48:07 +00:00
Andrius Štikonas 551654de0d Also rename source/targetFirstByte ot offsets in function declarations. 2020-11-29 13:08:53 +00:00
Andrius Štikonas d34b617272 Rename source/targetFirstByte to source/targetOffset.
Add some diagrams explaining difference between
source/targetOffsets and read/writeOffset.
2020-11-29 01:54:48 +00:00
Andrius Štikonas ee0a1e1b41 Add a limit on the amount of data that can be passed back via DBus. 2020-11-29 01:08:43 +00:00
Andrius Štikonas c556f39064 Add a limit on blocksize to prevent out-of-memory situation. 2020-11-29 00:58:55 +00:00
Andrius Štikonas 9dd38744c5 Add a comment about auth_admin_keep. 2020-11-29 00:50:57 +00:00
Andrius Štikonas 4fa91d75f3 externalcommandhelper: Do not commit suicide when attempting to run non whitelisted command.
Simply returning failure should be sufficient.
2020-11-26 23:35:52 +00:00
Andrius Štikonas 32d146eed3 externalcommandhelper: Make copy direction an enum. 2020-11-26 23:26:31 +00:00
Andrius Štikonas d16d9e8019 Do not reuse QProcess object in externalcommandhelper for different invocations. 2020-11-26 22:05:25 +00:00
Andrius Štikonas fae9f83451 Fix division by zero. 2020-11-26 21:58:24 +00:00
Andrius Štikonas 4d3fcb7691 Merge branch 'release/20.12' 2020-11-17 11:25:44 +00:00
Andrius Štikonas 9d4ab0e6fd Merge branch 'release/20.12' 2020-11-16 16:18:14 +00:00
Andrius Štikonas 26acd7c10d Remove extra semicolon. 2020-11-14 01:09:23 +00:00
Andrius Štikonas 70d4819aae Merge branch 'release/20.12' 2020-11-14 01:04:31 +00:00
Andrius Štikonas 2382b9e1c5 Rename d pointer to d_ptr to disambiguate from Device d. 2020-11-12 01:04:47 +00:00
Gaël PORTAY 2012e01b88 Bump soversion of kpmcore. 2020-11-11 16:41:16 -05:00
Gaël PORTAY 82566e63e7 d-pointerize NewOperation class. 2020-11-11 16:41:14 -05:00
Albert Astals Cid 0ee1e958a0 GIT_SILENT Upgrade release service version to 21.03.70. 2020-11-08 19:04:47 +01:00
72 changed files with 878 additions and 361 deletions

8
.gitlab-ci.yml Normal file
View File

@ -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

11
.kde-ci.yml Normal file
View File

@ -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'

View File

@ -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

View File

@ -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"

View File

@ -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")

View File

@ -1,4 +1,4 @@
<!-- SPDX-FileCopyrightText: 2017 Adriaan de Groot <groot@kde.org>
<!-- SPDX-FileCopyrightText: 2017 Adriaan de Groot <groot@kde.org>
SPDX-FileCopyrightText: 2017-2020 Andrius Štikonas <andrius@stikonas.eu>
SPDX-License-Identifier: CC-BY-4.0
-->
@ -35,7 +35,6 @@ looks like this:
```cmake
find_package( KPMcore 3.2 REQUIRED )
include_directories( ${KPMCORE_INCLUDE_DIR} )
target_link_libraries( target kpmcore )
```

17
metainfo.yaml Normal file
View File

@ -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

View File

@ -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)
############################################

View File

@ -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);

View File

@ -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);

View File

@ -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);
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();
if (id.isEmpty())
return false;
backend()->setId(id);
backend()->setVersion(version);
qDebug() << "Loaded backend plugin: " << backend()->id();
return true;
if (!backend()) {
qWarning() << "Could not create instance of plugin " << name;
return false;
}
qWarning() << "Could not load plugin for core backend " << name << ": " << loader.errorString();
return false;
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;
}
void CoreBackendManager::unload()

View File

@ -14,10 +14,10 @@
#include <memory>
#include <QStringList>
#include <QVector>
class QString;
class QStringList;
class KPluginMetaData;
class CoreBackend;
struct CoreBackendManagerPrivate;

View File

@ -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());
}

View File

@ -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

View File

@ -24,7 +24,6 @@
class PartitionTable;
class Report;
class Partition;
class SmartStatus;
/** Representation of LVM Volume Group(VG).

View File

@ -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);

View File

@ -35,7 +35,7 @@ SmartAttribute::SmartAttribute(const SmartAttributeParsedData& a) :
m_Assessment(getAssessment(a)),
m_Value(getPrettyValue(a.prettyValue(), a.prettyUnit()))
{
}
QString SmartAttribute::assessmentToString(Assessment a)
@ -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:

View File

@ -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);

View File

@ -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;

View File

@ -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;
}

View File

@ -96,6 +96,9 @@ public:
static CommandSupportType m_SetLabel;
static CommandSupportType m_UpdateUUID;
static CommandSupportType m_GetUUID;
private:
static bool exfatUtils;
};
}

View File

@ -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;

View File

@ -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); };
};
}

View File

@ -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); };
};
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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

View File

@ -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()

View File

@ -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;

View File

@ -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;

View File

@ -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");

View File

@ -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;
}

View File

@ -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;

View File

@ -31,7 +31,10 @@ 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;
}

View File

@ -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;

View File

@ -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,18 +98,27 @@ 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)
return usedBytes;
qDebug () << volumeSize << freeClusters << clusterSize;
if (clusterSize > -1 && freeClusters > -1 && volumeSize > -1) {
usedBytes = (volumeSize - freeClusters) * clusterSize;
}
return usedBytes;
}
return -1;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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)

View File

@ -37,7 +37,12 @@ public:
return m_Move;
}
CommandSupportType supportCopy() const override {
return m_Copy;
}
static CommandSupportType m_Move;
static CommandSupportType m_Copy;
};
}

View File

@ -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;

View File

@ -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)

View File

@ -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;

View File

@ -31,6 +31,7 @@ set(JOBS_SRC
jobs/setpartflagsjob.cpp
jobs/copyfilesystemjob.cpp
jobs/movefilesystemjob.cpp
jobs/changepermissionsjob.cpp
)
set(JOBS_LIB_HDRS

View File

@ -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);
}

View File

@ -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

View File

@ -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()

View File

@ -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,37 +32,56 @@
#include <KLocalizedString>
struct NewOperationPrivate
{
NewOperationPrivate(Device& d, Partition* p) :
m_TargetDevice(d),
m_NewPartition(p),
m_CreatePartitionJob(new CreatePartitionJob(d, *p)),
m_SetPartitionLabelJob(nullptr),
m_SetPartitionUUIDJob(nullptr),
m_SetPartitionAttributesJob(nullptr),
m_CreateFileSystemJob(nullptr),
m_SetPartFlagsJob(nullptr),
m_SetFileSystemLabelJob(nullptr),
m_CheckFileSystemJob(nullptr)
{
}
Device& m_TargetDevice;
Partition* m_NewPartition;
CreatePartitionJob* m_CreatePartitionJob;
SetPartitionLabelJob* m_SetPartitionLabelJob;
SetPartitionUUIDJob* m_SetPartitionUUIDJob;
SetPartitionAttributesJob* m_SetPartitionAttributesJob;
CreateFileSystemJob* m_CreateFileSystemJob;
SetPartFlagsJob* m_SetPartFlagsJob;
SetFileSystemLabelJob* m_SetFileSystemLabelJob;
CheckFileSystemJob* m_CheckFileSystemJob;
};
/** Creates a new NewOperation.
@param d the Device to create a new Partition on
@param p pointer to the new Partition to create. May not be nullptr.
*/
NewOperation::NewOperation(Device& d, Partition* p) :
Operation(),
m_TargetDevice(d),
m_NewPartition(p),
m_CreatePartitionJob(new CreatePartitionJob(targetDevice(), newPartition())),
m_SetPartitionLabelJob(nullptr),
m_SetPartitionUUIDJob(nullptr),
m_SetPartitionAttributesJob(nullptr),
m_CreateFileSystemJob(nullptr),
m_SetPartFlagsJob(nullptr),
m_SetFileSystemLabelJob(nullptr),
m_CheckFileSystemJob(nullptr)
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;
}

View File

@ -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

View File

@ -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)

View File

@ -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})

View File

@ -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)

View File

@ -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"
}

View File

@ -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})

View File

@ -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"
}

View File

@ -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);

View File

@ -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."));

View File

@ -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;
}

View File

@ -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>

View File

@ -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})

View File

@ -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);
}

View File

@ -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);

View File

@ -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@
};

View File

@ -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"),

View File

@ -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,83 +73,85 @@ 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.open(QIODevice::ReadOnly | QIODevice::Unbuffered)) {
qCritical() << xi18n("Could not open device <filename>%1</filename> for reading.", sourceDevice);
return false;
if (!device.isOpen()) {
if (!device.open(QIODevice::ReadOnly | QIODevice::Unbuffered)) {
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);
return false;
qCritical() << xi18n("Could not read from device <filename>%1</filename>.", device.fileName());
return false;
}
return true;
}
/** 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;
if (!device.open(flags)) {
qCritical() << xi18n("Could not open device <filename>%1</filename> for writing.", targetDevice);
return false;
auto flags = QIODevice::WriteOnly | QIODevice::Unbuffered;
if (!device.isOpen()) {
if (!device.open(flags)) {
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;
}

View File

@ -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;
};

View File

@ -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", "&copy; 2008-2020 KPMcore developers" ) );
KAboutLicense::GPL_V3, xi18nc("@info:credit", "&copy; 2008-2022 KPMcore developers" ) );
aboutData.setOrganizationDomain(QByteArray("kde.org"));
aboutData.setProductName(QByteArray("kpmcore"));
aboutData.setHomepage(QStringLiteral("https://commits.kde.org/kpmcore"));

View File

@ -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>

2
src/util/trustedprefixes Normal file
View File

@ -0,0 +1,2 @@
/
/usr

View File

@ -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>)
###
#