Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package kio-fuse for openSUSE:Factory checked in at 2023-12-14 22:02:45 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/kio-fuse (Old) and /work/SRC/openSUSE:Factory/.kio-fuse.new.25432 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "kio-fuse" Thu Dec 14 22:02:45 2023 rev:8 rq:1132928 version:5.1.0 Changes: -------- --- /work/SRC/openSUSE:Factory/kio-fuse/kio-fuse.changes 2023-11-02 20:19:58.788545900 +0100 +++ /work/SRC/openSUSE:Factory/.kio-fuse.new.25432/kio-fuse.changes 2023-12-14 22:02:46.679282682 +0100 @@ -1,0 +2,13 @@ +Sat Dec 9 22:14:57 UTC 2023 - Fabian Vogt <fab...@ritter-vogt.de> + +- Update to version 5.1.0: + * Support for building against Qt 6 and KF6 + * Minimum versions of dependencies got raised: + CMake 3.16, Qt 5.15, KIO 5.96.0 + * Minor bug fixes and optimizations + * Don't include the password in the generated VFS path + * Mounting admin: is blocked now +- Drop patch, now upstream: + * 0001-Initialize-m_lastChildrenRefresh-to-be-really-in-the.patch + +------------------------------------------------------------------- Old: ---- 0001-Initialize-m_lastChildrenRefresh-to-be-really-in-the.patch kio-fuse-5.0.1.tar.xz kio-fuse-5.0.1.tar.xz.sig New: ---- kio-fuse-5.1.0.tar.xz kio-fuse-5.1.0.tar.xz.sig BETA DEBUG BEGIN: Old:- Drop patch, now upstream: * 0001-Initialize-m_lastChildrenRefresh-to-be-really-in-the.patch BETA DEBUG END: ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ kio-fuse.spec ++++++ --- /var/tmp/diff_new_pack.YDm4rj/_old 2023-12-14 22:02:47.663318175 +0100 +++ /var/tmp/diff_new_pack.YDm4rj/_new 2023-12-14 22:02:47.667318320 +0100 @@ -1,7 +1,7 @@ # # spec file for package kio-fuse # -# Copyright (c) 2021 SUSE LLC +# Copyright (c) 2023 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -16,25 +16,23 @@ # -%bcond_without lang +%bcond_without released Name: kio-fuse -Version: 5.0.1 +Version: 5.1.0 Release: 0 Summary: Access KIO over the regular filesystem License: GPL-3.0-or-later Group: System/GUI/KDE URL: https://www.kde.org -Source0: https://download.kde.org/stable/%{name}/%{version}/%{name}-%{version}.tar.xz -%if %{with lang} -Source1: https://download.kde.org/stable/%{name}/%{version}/%{name}-%{version}.tar.xz.sig +Source0: https://download.kde.org/stable/%{name}/%{name}-%{version}.tar.xz +%if %{with released} +Source1: https://download.kde.org/stable/%{name}/%{name}-%{version}.tar.xz.sig Source2: kio-fuse.keyring %endif -# PATCH-FIX-UPSTREAM -Patch1: 0001-Initialize-m_lastChildrenRefresh-to-be-really-in-the.patch BuildRequires: extra-cmake-modules BuildRequires: pkgconfig -BuildRequires: cmake(KF5KIO) >= 5.66.0 -BuildRequires: cmake(Qt5DBus) >= 5.12.0 +BuildRequires: cmake(KF5KIO) >= 5.96.0 +BuildRequires: cmake(Qt5DBus) >= 5.15.0 BuildRequires: cmake(Qt5Test) BuildRequires: pkgconfig(fuse3) %if 0%{?suse_version} > 1599 @@ -78,8 +76,7 @@ chmod a+x fusermount3 export PATH=$PWD:$PATH -export CTEST_OUTPUT_ON_FAILURE=1 -make %{?_smp_mflags} -C build VERBOSE=1 test +%ctest %endif %files ++++++ kio-fuse-5.0.1.tar.xz -> kio-fuse-5.1.0.tar.xz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kio-fuse-5.0.1/.gitignore new/kio-fuse-5.1.0/.gitignore --- old/kio-fuse-5.0.1/.gitignore 2021-03-21 15:14:52.000000000 +0100 +++ new/kio-fuse-5.1.0/.gitignore 2023-12-09 21:26:39.000000000 +0100 @@ -62,6 +62,8 @@ # Visual Studio Code auto generated files .vscode +.clangd/ +compile_commands.json # MinGW generated files *.Debug @@ -75,3 +77,4 @@ *.dll *.exe +*.clazy.yaml diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kio-fuse-5.0.1/.gitlab-ci.yml new/kio-fuse-5.1.0/.gitlab-ci.yml --- old/kio-fuse-5.0.1/.gitlab-ci.yml 1970-01-01 01:00:00.000000000 +0100 +++ new/kio-fuse-5.1.0/.gitlab-ci.yml 2023-12-09 21:26:39.000000000 +0100 @@ -0,0 +1,10 @@ +# SPDX-FileCopyrightText: 2020 Volker Krause <vkra...@kde.org> +# SPDX-License-Identifier: CC0-1.0 + +include: + - project: sysadmin/ci-utilities + file: + - /gitlab-templates/linux.yml + - /gitlab-templates/freebsd.yml + - /gitlab-templates/linux-qt6.yml + - /gitlab-templates/freebsd-qt6.yml diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kio-fuse-5.0.1/.kde-ci.yml new/kio-fuse-5.1.0/.kde-ci.yml --- old/kio-fuse-5.0.1/.kde-ci.yml 1970-01-01 01:00:00.000000000 +0100 +++ new/kio-fuse-5.1.0/.kde-ci.yml 2023-12-09 21:26:39.000000000 +0100 @@ -0,0 +1,15 @@ +Dependencies: +- 'on': ['Linux', 'FreeBSD'] + 'require': + 'frameworks/extra-cmake-modules': '@stable' + 'frameworks/kcoreaddons' : '@stable' + 'frameworks/kio' : '@stable' + +- 'on': ['Linux/Qt6', 'FreeBSD/Qt6'] + 'require': + 'frameworks/extra-cmake-modules': '@latest-kf6' + 'frameworks/kcoreaddons' : '@latest-kf6' + 'frameworks/kio' : '@latest-kf6' + +Options: + run-tests: False diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kio-fuse-5.0.1/CMakeLists.txt new/kio-fuse-5.1.0/CMakeLists.txt --- old/kio-fuse-5.0.1/CMakeLists.txt 2021-03-21 15:14:52.000000000 +0100 +++ new/kio-fuse-5.1.0/CMakeLists.txt 2023-12-09 21:26:39.000000000 +0100 @@ -1,32 +1,32 @@ -cmake_minimum_required(VERSION 3.1) +cmake_minimum_required(VERSION 3.16) project(kio-fuse VERSION 5.0.0) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) -set(Qt5_MIN_VERSION 5.12) -# Use ecm_generate_dbus_service_file + ecm_install_configured_files once bumped to 5.73+ -set(KF5_MIN_VERSION 5.66) +set(QT_MIN_VERSION 5.15) +set(KF_MIN_VERSION 5.96) -find_package(ECM ${KF5_MIN_VERSION} CONFIG REQUIRED) +find_package(ECM ${KF_MIN_VERSION} CONFIG REQUIRED) set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${CMAKE_SOURCE_DIR}/cmake) +include(QtVersionOption) include(ECMSetupVersion) include(ECMGenerateHeaders) include(CMakePackageConfigHelpers) include(FeatureSummary) include(KDEInstallDirs) include(KDECMakeSettings) -include(KDEFrameworkCompilerSettings NO_POLICY_SCOPE) +include(KDECompilerSettings NO_POLICY_SCOPE) include(ECMQtDeclareLoggingCategory) include(ECMSetupVersion) -#include(ECMGenerateDBusServiceFile) -#include(ECMConfiguredInstall) +include(ECMGenerateDBusServiceFile) +include(ECMConfiguredInstall) find_package(PkgConfig REQUIRED) -find_package(Qt5 ${Qt5_MIN_VERSION} COMPONENTS Core REQUIRED) -find_package(KF5 ${KF5_MIN_VERSION} REQUIRED COMPONENTS +find_package(Qt${QT_MAJOR_VERSION} ${QT_MIN_VERSION} COMPONENTS Core REQUIRED) +find_package(KF${QT_MAJOR_VERSION} ${KF_MIN_VERSION} REQUIRED COMPONENTS CoreAddons KIO ) @@ -57,30 +57,25 @@ add_executable(kio-fuse ${KIOFUSE_SOURCES}) target_include_directories(kio-fuse PRIVATE ${FUSE3_INCLUDE_DIRS}) target_compile_definitions(kio-fuse PRIVATE FUSE_USE_VERSION=31 ${FUSE3_CFLAGS_OTHER}) -target_link_libraries(kio-fuse PRIVATE Qt5::Core KF5::KIOCore ${FUSE3_LIBRARIES} ${FUSE3_LDFLAGS}) +target_link_libraries(kio-fuse PRIVATE Qt::Core KF${QT_MAJOR_VERSION}::KIOCore ${FUSE3_LIBRARIES} ${FUSE3_LDFLAGS}) install(TARGETS kio-fuse DESTINATION ${KDE_INSTALL_FULL_LIBEXECDIR}) -install(FILES kio-fuse-tmpfiles.conf DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/tmpfiles.d) +if(CMAKE_SYSTEM_NAME MATCHES "Linux") + # We could argue that this needs a separate "if(LINUX_WITH_TMPFILES_D)". + # or a "if(LINUX_WITH_SYSTEMD)". + install(FILES kio-fuse-tmpfiles.conf DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/tmpfiles.d) +endif() -# Once KF5 5.73 is required -# -#ecm_generate_dbus_service_file( -# NAME org.kde.KIOFuse -# EXECUTABLE "${KDE_INSTALL_FULL_LIBEXECDIR}/kio-fuse -f" -# SYSTEMD_SERVICE kio-fuse.service -# DESTINATION ${KDE_INSTALL_DBUSSERVICEDIR} -#) -# -#ecm_install_configured_files(INPUT kio-fuse.service.in DESTINATION ${SYSTEMD_USER_UNIT_INSTALL_DIR}) - -file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/org.kde.KIOFuse.service -"[D-BUS Service] -Name=org.kde.KIOFuse -Exec=${KDE_INSTALL_FULL_LIBEXECDIR}/kio-fuse -f -SystemdService=kio-fuse.service -") -install(FILES ${CMAKE_CURRENT_BINARY_DIR}/org.kde.KIOFuse.service DESTINATION ${KDE_INSTALL_DBUSSERVICEDIR}) +ecm_generate_dbus_service_file( + NAME org.kde.KIOFuse + EXECUTABLE "${KDE_INSTALL_FULL_LIBEXECDIR}/kio-fuse -f" + SYSTEMD_SERVICE kio-fuse.service + DESTINATION ${KDE_INSTALL_DBUSSERVICEDIR} +) -configure_file(kio-fuse.service.in ${CMAKE_CURRENT_BINARY_DIR}/kio-fuse.service) -install(FILES ${CMAKE_CURRENT_BINARY_DIR}/kio-fuse.service DESTINATION ${SYSTEMD_USER_UNIT_INSTALL_DIR}) +if(DEFINED KDE_INSTALL_SYSTEMDUSERUNITDIR) + ecm_install_configured_files(INPUT kio-fuse.service.in DESTINATION ${KDE_INSTALL_SYSTEMDUSERUNITDIR}) +else() + ecm_install_configured_files(INPUT kio-fuse.service.in DESTINATION ${SYSTEMD_USER_UNIT_INSTALL_DIR}) +endif() feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kio-fuse-5.0.1/DESIGN new/kio-fuse-5.1.0/DESIGN --- old/kio-fuse-5.0.1/DESIGN 2021-03-21 15:14:52.000000000 +0100 +++ new/kio-fuse-5.1.0/DESIGN 1970-01-01 01:00:00.000000000 +0100 @@ -1,282 +0,0 @@ -Design of kio-fuse -================== - -This file explains the internal implementation only, please read the README -first to learn about the external interface. - -Goals ------ - -kio-fuse's design is based on these requirements: -* Maximum compatibility with applications (as far as KIO allows) -* Work with most slaves: The minimum set of operations a slave must support are - KIO::stat and KIO::get -* Good usability: This means mostly acceptable speed (using caching whereever - possible), but also having a simple API to the outside world -* Security: The password of mounted URLs is not obviously visible -* KISS - -Use of the libfuse lowlevel API -------------------------------- - -Compared to the "old" version of kiofuse in SVN, this implementation has a -major difference in the implementation: Instead of the high level libfuse API, -which translates the inode numbers passed from the kernel to paths for calling -the operations, the lowlevel libfuse API is used. - -While it may look like translating paths to URLs is much easier than keeping -track of inode numbers, the high-level API has actually completely different -behaviour in many other ways, which actually makes it much more complex to use. -The most important difference is that the lowlevel API can be used -asynchronously, which makes it possible to process multiple requests in one -thread. This matches the Qt (and thus KIO) event processing model perfectly. -This means that multithreading is not required (KIO works on the main thread -anyway), resulting in no need for locking and passing queues around. - -Additonally, a design flaw in libfuse means that it's impossible to keep track -of the lookup count correctly/race-free when using multiple threads: -https://github.com/python-llfuse/python-llfuse/blob/master/developer-notes/lookup_counts.rst - -The additional "lookup" lowlevel operation makes it possible to avoid calling -readdir on all path elements when opening a file for the first time. -Example: "smb://host/dir/subdir/file" is mounted as smb/host/dir/subdir/file. -When opening that for the first time with the high-level API, it would result in -these calls: opendir(/) -> readdir(/) -> closedir(/) -> opendir(smb) -> ... -This is because libfuse has to build an internal tree model for mapping inode -numbers to path elements. -With the lowlevel API, lookup is enough: lookup(/, smb) -> lookup(smb, host)... -This can be implemented using KIO::stat instead of a full KIO::listDir, both on -the initial access and when the node already exists locally, to recheck whether -the local representation still matches. -With the high-level API, lookup on existing nodes is not passed to the FS -implementation if the node is part of the internal tree already. This makes -it harder (if not infeasible) to react to changes on the remote side, e.g. -deletes or renames. - -Not using inode numbers in the high-level API means that implementing unlink -properly (i.e. already opened file handles are still valid) is not possible, -so instead of calling unlink directly, libfuse renames deleted files as -".fuse_hiddenXXX" and deletes them when their lookup count drops to zero. -By using the lowlevel API, implementing deletion is up to the filesystem. - -The VFS node tree ------------------ - -Downside of the lowlevel API is that the inode number -> path mapping has to be -implemented by the filesystem. For implementing local caching of nodes having -a tree structure is necessary anyway though, so this does not actually make it -more complex. - -The tree is implemented as a std::unordered_map of fuse_ino_t to KIOFuseNode. -Each node knows about its parent and children inode numbers. The two root nodes -have an invalid inode number (0) set as parent. -For details on the class hierarchy and their members, read kiofusenode.h. - -For carrying out special operations depending on the node type, RTTI is used, -by either querying the typeid or doing a dynamic_cast. - -During runtime, the tree can look like this: - -"" (ino: 1) -KIOFuseDirNode - | - | "smb" - |------> KIOFuseDirNode - | \ - | \ "user@fileserver01" "a file" - | ------> KIOFuseRemoteDirNode -----> KIOFuseRemoteFileNode - | "user:pass@fileserver01" - | \ - | \ "directory" - | ------> KIOFuseRemoteDirNode - | \ - | \ "another file" - | ------> KIOFuseRemoteFileNode - | - | "sftp" - ------> KIOFuseDirNode - \ - \ "user@someserver" "a file" - ------> KIOFuseRemoteDirNode -----> KIOFuseRemoteFileNode - "user:pass@someserver" - -"" (ino: 2) "deleted file" -KIOFuseDirNode ----> KIOFuseRemoteFileNode - -The root node with inode number 1 represents the root of the VFS. -Only files below are visible in the VFS hierarchy. - -Note that RemoteFileNode is an abstract class. At runtime, it will actually be -instantiated as one of its subclasses (KIOFuseRemoteCacheBasedNode or -KIOFuseRemoteFileJobBasedNode). The type of class instantiated will depend on -the URL of the file. Please see the "File I/O" section to learn more. - -Remote nodes (KIOFuseRemote*Node) are derived from KIOFuseRemoteFileInfo in -addition to the base node type, which contains some members specific for remote -access. - -m_overrideUrl is used to implement URL mountpoints and redirections. To get the -remote URL of a node, the tree is traversed upwards until an override is found -and the path is appended. - -m_lastStatRefresh stores the time when m_stat was updated last. It's updated -on node construction and by updateNodeFromUDSEntry and queried by the -awaitAttrRefreshed method. - -Mounting a URL --------------- - -Goal of mounting a URL is to make the target file/directory reachable over the -FUSE filesystem. The first step is to verify that the target actually exists, -if that is not the case an error is returned without doing any changes. - -If the target is reachable, the next step is to find which part of the URL -(from left to right) is the first accessible one. This is needed as ioslaves -like tar do not support listing tar:/// and instead need some part of the path -to return results. This minimum URL is the "origin" and a KIOFuseRemoteDirNode -with the origin as m_overrideUrl is created, with the parents as plain -KIOFuseDirNodes. - -The local path to this origin node with the path from the origin to the target -node is returned. Note that at this point this node doesn't actually exist -locally though, only everything up until (including) the origin. To reach the -rest, the kernel does lookup operations which trigger KIO::stat and node -creation for each path component. - -Initially, mounting was implemented in a different way, to only require a -single KIO::stat call for determining accessibility and the target node's -attributes. All path components except the final one were assumed to be -traversable directories, but this assumption doesn't hold for symlinks. By -letting the kernel deal with path traversal, symlinks returned by lookup are -handled correctly. - -Unlinking a node ----------------- - -The root node with inode number 2 is used as a parent for deleted, but still -opened (non-zero lookup count) nodes. This is used for proper unlinking. -When the loopup count of a node below the "deleted root" drops to zero, the -node is deleted, i.e. the inode number can be reused and memory is freed. -When unlinking a node which already has a lookup count of zero, it is directly -deleted. - -General anatomy of a write operation ------------------------------------- - -All write operations are implemented by verifying the parameters locally (if -possible at all) and then starting the operation to KIO. Once the operation -completes, either an error is sent or the change is done in the local VFS tree -and the result is sent. - -void KIOFuseVFS::operation(fuse_req_t req, fuse_ino_t inode, ...) -{ - KIOFuseVFS *that = reinterpret_cast<KIOFuseVFS*>(fuse_req_userdata(req)); - auto node = that->nodeForIno(parent); - if(!node) complain and return; - - auto job = KIO::operation(that->remoteUrl(node), ...); - connect(job, &finished, [=] { - if(job->error()) - fuse_reply_err(req, kioErrorToFuseError(job->error())); - else - { - that->doOperation(node); - fuse_reply_result(req, ...); - } - }); -} - -Permissions ------------ - -While the st_uid/st_gid/st_mode fields of nodes are used from KIO if possible, -access is not checked by kio-fuse at all. Instead, KIO returns errors if an -operation fails because of missing permissions and those are simply forwarded. - -Node attributes ---------------- - -For every node in the VFS, the full struct stat is already available when -inserting it into the tree. This happens when mounting a URL (uses KIO::stat) -and when requesting the children of a URL (using KIO::listDir with details). -The same is true of the symlink's target path. - -As a result, getattr and readlink are non-blocking if the node's attributes -have not timed out. - -setattr instead does block, it only returns if all of the requested operations -(e.g. SET_ATTR_MTIME, SET_ATTR_MODE, SET_ATTR_UID) completed. - -Directory operations --------------------- - -To support the optimization possibility the lookup operation in the lowlevel -API offers, children of KIOFuseRemoteDirNode are loaded lazily. This means -that the full list of children is only requested (using KIO::listDir) if -required, so if lookup on the directory fails or if readdir is executed. - -A node's children are considered valid for 30 seconds. The last time a node -was dir listed via KIO::listDir is stored in m_lastChildrenRefreshed. -Each readdir request checks if they have timed out via the -haveChildrenTimedOut() method and updates the children (and consequently, their -attributes) as appropriate. This is implemented in awaitChildrenComplete. - -Node Expiration ---------------- - -Each remote node has a timeout on its attributes and its children, which is -currently set to 30 seconds. - -When a node's attributes are requested, the awaitAttrRefreshed method checks -whether the attributes expired and if so, calls mountUrl to refresh it via -updateNodeFromUDSEntry. If the result of KIO::stat indicates that the node does -not exist on the remote side anymore it is (recursively) marked as deleted. -Otherwise, a new node based on the fresh attributes is created and if the type -matches, used to update the existing node. If the type does not match, the old -node is marked as deleted and the new node inserted into the tree. - -For directories, awaitChildrenComplete calls KIO::listDir for refreshing the -list of children, either removing vanished nodes, creating new nodes or -updating existing ones using the same method as outlined above. - -File IO -------- - -File IO is done in either of two ways, depending on what the protocol supports. -If the protocol supports KIO::open (and all of its operations, which at the time -of writing is read/write/seek/truncate) then IO will be based upon KIO's FileJob. -KIO's FileJob interface allows random-access IO, and hence all read, write and -truncate requests are simply forwarded to the corresponding FileJob functions. - -Whilst improving performance for larger files compared to the cache-based IO -described below, the performance of individual read/write/truncate requests -if significantly reduced. - -The protocols that currently support KIO::open are file/sftp/smb. - -Otherwise, file IO is implemented completely on top of a file based cache. -On the first read or write access to a non truncated file, the whole file is -downloaded into a new temporary file and all readers are notified on cache -completeness changes (see awaitBytesAvailable). - -Therefore the read and write ops itself are trivial, they just forward the -IO operation to the temporary file once enough data is available. - -On each write to a file, the file is marked as dirty and added to the set -of dirty nodes. On various occasions, awaitNodeFlushed is called which removes -the node from the dirty set and starts a KIO::put for the file. On success, -it is checked whether a write occured during flushing and if so, another -flush is started. This is repeated until the node was still marked as clean -on finish. - -When there a no open file descriptors to a node anymore, the cache is flushed -if necessary and then dropped. - -Hardlinks ---------- - -Hardlinks are not supported well in the current design of KIO so they were -simply not considered during kio-fuse development either. - -While inode and device numbers can be returned are part of UDSEntries returned -from slaves, neither stat.st_link nor ::link are accessible. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kio-fuse-5.0.1/DESIGN.md new/kio-fuse-5.1.0/DESIGN.md --- old/kio-fuse-5.0.1/DESIGN.md 1970-01-01 01:00:00.000000000 +0100 +++ new/kio-fuse-5.1.0/DESIGN.md 2023-12-09 21:26:39.000000000 +0100 @@ -0,0 +1,275 @@ +# Design of KIO FUSE + +This file explains the internal implementation only, please read the README +first to learn about the external interface. + +## Goals + +KIO FUSE's design is based on these requirements: + +* Maximum compatibility with applications (as far as KIO allows). +* Work with most protocols: The minimum set of operations a worker must support + are `KIO::stat` and `KIO::get`. +* Good usability: this means mostly acceptable speed (using caching whereever + possible), but also having a simple API to the outside world. +* Security: the password of mounted URLs is not obviously visible. +* Keep It Simple Stupid (KISS). + +## Use of the `libfuse` low-level API + +Compared to the "old" version of KIO FUSE in SVN, this implementation has a +major difference in the implementation: instead of the high-level `libfuse` API, +which translates the inode numbers passed from the kernel to paths for calling +the operations, the lowlevel `libfuse` API is used. + +While it may look like translating paths to URLs is much easier than keeping +track of inode numbers, the high-level API has actually completely different +behaviour in many other ways, which actually makes it much more complex to use. +The most important difference is that the lowlevel API can be used +asynchronously, which makes it possible to process multiple requests in one +thread. This matches the Qt (and thus KIO) event processing model perfectly. +This means that multithreading is not required (KIO works on the main thread +anyway), resulting in no need for locking and passing queues around. + +Additonally, a design flaw in `libfuse` means that it's impossible to keep track +of the lookup count correctly/race-free when using multiple threads: +[Move Lookup Count Management into LLFUSE?](https://github.com/python-llfuse/python-llfuse/blob/master/developer-notes/lookup_counts.rst) + +The additional `lookup` lowlevel operation makes it possible to avoid calling +`readdir` on all path elements when opening a file for the first time. +Example: `smb://host/dir/subdir/file` is mounted as `smb/host/dir/subdir/file`. +When opening that for the first time with the high-level API, it would result in +these calls: `opendir(/) -> readdir(/) -> closedir(/) -> opendir(smb) -> ...` +This is because `libfuse` has to build an internal tree model for mapping inode +numbers to path elements. +With the lowlevel API, lookup is enough: `lookup(/, smb) -> lookup(smb, host)...` +This can be implemented using `KIO::stat` instead of a full `KIO::listDir`, both on +the initial access and when the node already exists locally, to recheck whether +the local representation still matches. +With the high-level API, lookup on existing nodes is not passed to the FS +implementation if the node is part of the internal tree already. This makes +it harder (if not infeasible) to react to changes on the remote side, e.g. +deletes or renames. + +Not using inode numbers in the high-level API means that implementing unlink +properly (i.e. already opened file handles are still valid) is not possible, +so instead of calling unlink directly, `libfuse` renames deleted files as +`.fuse_hiddenXXX` and deletes them when their lookup count drops to zero. +By using the low-level API, implementing deletion is up to the filesystem. + +## The VFS node tree + +Downside of the lowlevel API is that the inode number → path mapping has to be +implemented by the filesystem. For implementing local caching of nodes having +a tree structure is necessary anyway though, so this does not actually make it +more complex. + +The tree is implemented as a `std::unordered_map` of `fuse_ino_t` to `KIOFuseNode`. +Each node knows about its parent and children inode numbers. The two root nodes +have an invalid inode number (0) set as parent. +For details on the class hierarchy and their members, read +[kiofusenode.h](./kiofusenode.h). + +For carrying out special operations depending on the node type, RTTI is used, +by either querying the typeid or doing a `dynamic_cast`. + +During runtime, the tree can look like this: + +``` +"" (ino: 1) +KIOFuseDirNode + | + | "smb" + |------> KIOFuseDirNode + | \ + | \ "user@fileserver01" "a file" + | ------> KIOFuseRemoteDirNode -----> KIOFuseRemoteFileNode + | "user:pass@fileserver01" + | \ + | \ "directory" + | ------> KIOFuseRemoteDirNode + | \ + | \ "another file" + | ------> KIOFuseRemoteFileNode + | + | "sftp" + ------> KIOFuseDirNode + \ + \ "user@someserver" "a file" + ------> KIOFuseRemoteDirNode -----> KIOFuseRemoteFileNode + "user:pass@someserver" + +"" (ino: 2) "deleted file" +KIOFuseDirNode ----> KIOFuseRemoteFileNode +``` + +The root node with inode number 1 represents the root of the VFS. +Only files below are visible in the VFS hierarchy. + +Note that `RemoteFileNode` is an abstract class. At runtime, it will actually be +instantiated as one of its subclasses (`KIOFuseRemoteCacheBasedNode` or +`KIOFuseRemoteFileJobBasedNode`). The type of class instantiated will depend on +the URL of the file. Please see the [File IO](#file-io) section to learn more. + +Remote nodes (`KIOFuseRemote*Node`) are derived from `KIOFuseRemoteFileInfo` in +addition to the base node type, which contains some members specific for remote +access. + +`m_overrideUrl` is used to implement URL mountpoints and redirections. To get the +remote URL of a node, the tree is traversed upwards until an override is found +and the path is appended. + +`m_lastStatRefresh` stores the time when `m_stat` was updated last. It's updated +on node construction and by `updateNodeFromUDSEntry` and queried by the +`awaitAttrRefreshed` method. + +## Mounting a URL + +Goal of mounting a URL is to make the target file/directory reachable over the +FUSE filesystem. The first step is to verify that the target actually exists, +if that is not the case an error is returned without doing any changes. + +If the target is reachable, the next step is to find which part of the URL +(from left to right) is the first accessible one. This is needed as ioworkers +like `tar` do not support listing `tar:///` and instead need some part of the path +to return results. This minimum URL is the "origin" and a `KIOFuseRemoteDirNode` +with the origin as `m_overrideUrl` is created, with the parents as plain +`KIOFuseDirNode`s. + +The local path to this origin node with the path from the origin to the target +node is returned. Note that at this point this node doesn't actually exist +locally though, only everything up until (including) the origin. To reach the +rest, the kernel does lookup operations which trigger `KIO::stat` and node +creation for each path component. + +Initially, mounting was implemented in a different way, to only require a +single `KIO::stat` call for determining accessibility and the target node's +attributes. All path components except the final one were assumed to be +traversable directories, but this assumption doesn't hold for symlinks. By +letting the kernel deal with path traversal, symlinks returned by lookup are +handled correctly. + +## Unlinking a node + +The root node with inode number 2 is used as a parent for deleted, but still +opened (non-zero lookup count) nodes. This is used for proper unlinking. +When the loopup count of a node below the "deleted root" drops to zero, the +node is deleted, i.e. the inode number can be reused and memory is freed. +When unlinking a node which already has a lookup count of zero, it is directly +deleted. + +## General anatomy of a write operation + +All write operations are implemented by verifying the parameters locally (if +possible at all) and then starting the operation to KIO. Once the operation +completes, either an error is sent or the change is done in the local VFS tree +and the result is sent. + +```cpp +void KIOFuseVFS::operation(fuse_req_t req, fuse_ino_t inode, ...) +{ + KIOFuseVFS *that = reinterpret_cast<KIOFuseVFS*>(fuse_req_userdata(req)); + auto node = that->nodeForIno(parent); + if(!node) complain and return; + + auto job = KIO::operation(that->remoteUrl(node), ...); + connect(job, &finished, [=] { + if(job->error()) + fuse_reply_err(req, kioErrorToFuseError(job->error())); + else + { + that->doOperation(node); + fuse_reply_result(req, ...); + } + }); +} +``` + +## Permissions + +While the `st_uid`/`st_gid`/`st_mode` fields of nodes are used from KIO if possible, +access is not checked by `kio-fuse` at all. Instead, KIO returns errors if an +operation fails because of missing permissions and those are simply forwarded. + +## Node attributes + +For every node in the VFS, the full `struct stat` is already available when +inserting it into the tree. This happens when mounting a URL (uses `KIO::stat`) +and when requesting the children of a URL (using `KIO::listDir` with details). +The same is true of the symlink's target path. + +As a result, `getattr` and `readlink` are non-blocking if the node's attributes +have not timed out. + +`setattr` instead does block, it only returns if all of the requested operations +(e.g. `SET_ATTR_MTIME`, `SET_ATTR_MODE`, `SET_ATTR_UID`) completed. + +## Directory operations + +To support the optimization possibility the lookup operation in the low-level +API offers, children of `KIOFuseRemoteDirNode` are loaded lazily. This means +that the full list of children is only requested (using `KIO::listDir`) if +required, so if lookup on the directory fails or if readdir is executed. + +A node's children are considered valid for 30 seconds. The last time a node +was dir listed via `KIO::listDir` is stored in `m_lastChildrenRefreshed`. +Each readdir request checks if they have timed out via the +`haveChildrenTimedOut()` method and updates the children (and consequently, their +attributes) as appropriate. This is implemented in `awaitChildrenComplete`. + +## Node Expiration + +Each remote node has a timeout on its attributes and its children, which is +currently set to 30 seconds. + +When a node's attributes are requested, the `awaitAttrRefreshed` method checks +whether the attributes expired and if so, calls `mountUrl` to refresh it via +`updateNodeFromUDSEntry`. If the result of `KIO::stat` indicates that the node does +not exist on the remote side anymore it is (recursively) marked as deleted. +Otherwise, a new node based on the fresh attributes is created and if the type +matches, used to update the existing node. If the type does not match, the old +node is marked as deleted and the new node inserted into the tree. + +For directories, `awaitChildrenComplete` calls `KIO::listDir` for refreshing the +list of children, either removing vanished nodes, creating new nodes or +updating existing ones using the same method as outlined above. + +## File IO + +File IO is done in either of two ways, depending on what the protocol supports. +If the protocol supports `KIO::open` (and all of its operations, which at the time +of writing is `read`/`write`/`seek`/`truncate`) then IO will be based upon KIO's `FileJob`. +KIO's `FileJob` interface allows random-access IO, and hence all `read`, `write` and +`truncate` requests are simply forwarded to the corresponding `FileJob` functions. + +Whilst improving performance for larger files compared to the cache-based IO +described below, the performance of individual `read`/`write`/`truncate` requests +if significantly reduced. + +The protocols that currently support `KIO::open` are `file`/`sftp`/`smb`. + +Otherwise, file IO is implemented completely on top of a file based cache. +On the first read or write access to a non truncated file, the whole file is +downloaded into a new temporary file and all readers are notified on cache +completeness changes (see `awaitBytesAvailable`). + +Therefore the read and write ops itself are trivial, they just forward the +IO operation to the temporary file once enough data is available. + +On each write to a file, the file is marked as dirty and added to the set +of dirty nodes. On various occasions, `awaitNodeFlushed` is called which removes +the node from the dirty set and starts a `KIO::put` for the file. On success, +it is checked whether a write occured during flushing and if so, another +flush is started. This is repeated until the node was still marked as clean +on finish. + +When there a no open file descriptors to a node anymore, the cache is flushed +if necessary and then dropped. + +## Hardlinks + +Hardlinks are not supported well in the current design of KIO so they were +simply not considered during KIO FUSE development either. + +While inode and device numbers can be returned are part of UDSEntries returned +from workers, neither `stat.st_link` nor `::link` are accessible. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kio-fuse-5.0.1/README new/kio-fuse-5.1.0/README --- old/kio-fuse-5.0.1/README 2021-03-21 15:14:52.000000000 +0100 +++ new/kio-fuse-5.1.0/README 1970-01-01 01:00:00.000000000 +0100 @@ -1,86 +0,0 @@ -How to use kio-fuse -=================== - -Building --------- - -Very simple: Install build dependencies, run cmake, make and you're done! - -To install build dependencies on Arch Linux: - - pacman -S base-devel fuse3 cmake extra-cmake-modules qt5base kio - - (and kio-extras for running certain tests) - -To install build dependencies on Fedora 32: - - dnf install cmake extra-cmake-modules kf5-kio-devel fuse3-devel - qt5-qtbase-devel pkg-config - - (and kio-extras for running certain tests) - -To install build dependencies on openSUSE Tumbleweed: - - zypper install extra-cmake-modules 'cmake(KF5KIO)' 'pkgconfig(fuse3)' - kio-devel 'cmake(Qt5Test)' 'cmake(Qt5Dbus)' - - (and kio-extras5 for running certain tests) - -To install build dependencies on Ubuntu 19.04: - - apt install fuse3 libfuse3-dev build-essential cmake extra-cmake-modules - pkg-config libkf5kio-dev - - (and kio-extras for running certain tests) - -To run the tests, run make test. To install, run make install. - -Using ------ - -kio-fuse is a DBus activated service, so for permanent installation the -installed service file has to be in a directory used by dbus-daemon. -If you're installing into a custom prefix, you may want to link -[prefix]/share/dbus-1/services/org.kde.KIOFuse.service into -~/.local/share/dbus-1/services/ and -[prefix]/lib/systemd/user/kio-fuse.service into -~/.local/share/systemd/user/. - -To make sure that the installed version is actually used, stop any already -running instance with "killall kio-fuse" and log out and in again. - -For quick testing, installation and DBus activation can be skipped. Instead, -after stopping any previously running instance, start the built kio-fuse binary -with the -f parameter and possibly other options. - -The DBus service is automatically used by KIO (5.66+) when opening a file on a -KIO URL with a KIO-unaware application. - -Running it manually -------------------- - -Create a new directory somewhere, make sure that no daemon is going to clean -up after it (like systemd-tmpfiles in /run/user/...) and run kio-fuse -d $dir. -The "-d" means that it shows debug output and does not daemonize - that makes it -easier to use it at first. - -In your session bus you'll find a org.kde.KIOFuse service with an interface that -allows one to communicate with the kio-fuse process. - -Let's assume you want to make the files at -ftp://user:password@server/directory accessible in your local file system. -To send the corresponding mount command, type the following in the command line: -dbus-send --session --print-reply --type=method_call \ - --dest=org.kde.KIOFuse \ - /org/kde/KIOFuse \ - org.kde.KIOFuse.VFS.mountUrl string:ftp://user:password@server/directory - -If it failed, kio-fuse will reply with an appropriate error message. If it -succeeded, you will get the location that the URL is mounted on as a reply. In -this case it would be $dir/ftp/user@server/directory and the directory will be -accessibly at that URL. - -After your work is done, simply run "fusermount3 -u $dir" to unmount the URL and -exit kio-fuse. - -Have a lot of fun! diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kio-fuse-5.0.1/README.md new/kio-fuse-5.1.0/README.md --- old/kio-fuse-5.0.1/README.md 1970-01-01 01:00:00.000000000 +0100 +++ new/kio-fuse-5.1.0/README.md 2023-12-09 21:26:39.000000000 +0100 @@ -0,0 +1,129 @@ +# KIO FUSE + +[FUSE](https://www.kernel.org/doc/html/latest/filesystems/fuse.html) +interface for [KIO](https://api.kde.org/frameworks/kio/html/). + +## Build and Install KIO FUSE + +Here we describe how to compile, test, run and install KIO FUSE from source. + +### Build Dependencies + +To install build dependencies on Arch Linux: + + pacman -S base-devel fuse3 cmake extra-cmake-modules qt5base kio + +(and `kio-extras` for running certain tests) + +To install build dependencies on Fedora 32: + + dnf install cmake extra-cmake-modules kf5-kio-devel fuse3-devel + qt5-qtbase-devel pkg-config + +(and `kio-extras` for running certain tests) + +To install build dependencies on openSUSE Tumbleweed: + + zypper install extra-cmake-modules 'cmake(KF5KIO)' 'pkgconfig(fuse3)' + kio-devel 'cmake(Qt5Test)' 'cmake(Qt5Dbus)' + +(and `kio-extras5` for running certain tests) + +To install build dependencies on Ubuntu 19.04: + + apt install fuse3 libfuse3-dev build-essential cmake extra-cmake-modules + pkg-config libkf5kio-dev + +(and `kio-extras` for running certain tests) + +### Build Steps + +Once you have installed the build dependencies one can build KIO FUSE +itself. + +In the root of the git repository run the following: + +``` +mkdir build; cd build; cmake .. && make` +``` + +### Running Tests + +In the build directory run the following: + +``` +make test +``` + +For more verbose output run the following: + +``` +make tests ARGS=-V +``` + +### Installing KIO FUSE + +In the build directory run the following: + +``` +make install +``` + +## Usage + +This section describes how to start KIO FUSE via DBus activation and +by simply running it manually. + +### KIO FUSE DBus Activation + +KIO FUSE is a DBus activated service, so for permanent installation the +installed service file has to be in a directory used by `dbus-daemon`. +If you're installing into a custom prefix, you may want to link +`[prefix]/share/dbus-1/services/org.kde.KIOFuse.service` into +`~/.local/share/dbus-1/services/` and +`[prefix]/lib/systemd/user/kio-fuse.service` into +`~/.local/share/systemd/user/`. + +To make sure that the installed version is actually used, stop any already +running instance with `killall kio-fuse` and log out and in again. + +For quick testing, installation and DBus activation can be skipped. Instead, +after stopping any previously running instance, start the built `kio-fuse` binary +with the `-f` parameter and possibly other options. + +The DBus service is automatically used by KIO (5.66+) when opening a file on a +KIO URL with a KIO-unaware application. + +### Running KIO FUSE manually + +Create a new directory somewhere, make sure that no daemon is going to clean +up after it (like `systemd-tmpfiles` in `/run/user/...`) and run `kio-fuse -d $dir`. +The `-d` means that it shows debug output and does not daemonize - that makes it +easier to use it at first. + +In your session bus you'll find a `org.kde.KIOFuse` service with an interface that +allows one to communicate with the `kio-fuse` process. + +Let's assume you want to make the files at +`ftp://user:password@server/directory` accessible in your local file system. +To send the corresponding mount command, you can use our utility script [`utils/mount-url.sh`](./utils/mount-url.sh) as follows: +``` +mount-url.sh ftp://user:password@server/directory +``` +Alternatively, you can simply use `dbus-send` (which is what `mount-url.sh` uses anyway): +``` +dbus-send --session --print-reply --type=method_call \ + --dest=org.kde.KIOFuse \ + /org/kde/KIOFuse \ + org.kde.KIOFuse.VFS.mountUrl string:ftp://user:password@server/directory +``` + +If it failed, KIO FUSE will reply with an appropriate error message. If it +succeeded, you will get the location that the URL is mounted on as a reply. In +this case it would be `$dir/ftp/user@server/directory` and the directory will be +accessibly at that URL. + +After your work is done, simply run `fusermount3 -u $dir` to unmount the URL and +exit `kio-fuse`. + +Have a lot of fun! diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kio-fuse-5.0.1/TODO new/kio-fuse-5.1.0/TODO --- old/kio-fuse-5.0.1/TODO 2021-03-21 15:14:52.000000000 +0100 +++ new/kio-fuse-5.1.0/TODO 2023-12-09 21:26:39.000000000 +0100 @@ -4,8 +4,8 @@ * statvfs (?) * interrupting requests (just killing the KIO Job would also break other requests for the same resource) -KIO Slave support: -- Deal with invalid size reporting slaves (http/gdrive/...)? +KIO Worker support: +- Deal with workers reporting invalid sizes (http/gdrive/...)? Performance/usability improvements: - Better error reporting: * Flushing happens on close(), which can't report errors, so it might be a good idea to show diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kio-fuse-5.0.1/kiofusenode.h new/kio-fuse-5.1.0/kiofusenode.h --- old/kio-fuse-5.0.1/kiofusenode.h 2021-03-21 15:14:52.000000000 +0100 +++ new/kio-fuse-5.1.0/kiofusenode.h 2023-12-09 21:26:39.000000000 +0100 @@ -21,7 +21,7 @@ class KIOFuseNode { public: // Creates a new node. Make sure to set the node's m_stat.st_ino once inserted. - KIOFuseNode(const fuse_ino_t parentIno, QString nodeName, const struct stat &stat) : + KIOFuseNode(const fuse_ino_t parentIno, const QString &nodeName, const struct stat &stat) : m_parentIno(parentIno), m_nodeName(nodeName), m_stat(stat) @@ -76,7 +76,7 @@ // be emitted on finish. bool m_childrenRequested = false; // Stores the last time a node's children were refreshed via KIO::listDir. - std::chrono::steady_clock::time_point m_lastChildrenRefresh; + std::chrono::steady_clock::time_point m_lastChildrenRefresh = decltype(m_lastChildrenRefresh)::min(); // Returns true if a node is due for a readdir refresh, false otherwise. bool haveChildrenTimedOut() { return m_lastChildrenRefresh < g_timeoutEpoch || (std::chrono::steady_clock::now() - m_lastChildrenRefresh) >= ATTR_TIMEOUT; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kio-fuse-5.0.1/kiofuseservice.cpp new/kio-fuse-5.1.0/kiofuseservice.cpp --- old/kio-fuse-5.0.1/kiofuseservice.cpp 2021-03-21 15:14:52.000000000 +0100 +++ new/kio-fuse-5.1.0/kiofuseservice.cpp 2023-12-09 21:26:39.000000000 +0100 @@ -17,11 +17,12 @@ #include "kiofusevfs.h" const QStringList KIOFuseService::m_blacklist { - QStringLiteral("gdrive"), // @see #1 - QStringLiteral("mtp"), // @see #2 - // http(s) is buggy and gives back invalid sizes (similar to gdrive). - QStringLiteral("https"), - QStringLiteral("http") + QStringLiteral("gdrive"), // @see #1 + QStringLiteral("mtp"), // @see #2 + // http(s) is buggy and gives back invalid sizes (similar to gdrive). + QStringLiteral("https"), + QStringLiteral("http"), + QStringLiteral("admin"), }; KIOFuseService::~KIOFuseService() @@ -31,7 +32,7 @@ kiofusevfs.stop(); } -bool KIOFuseService::start(struct fuse_args &args, QString mountpoint, bool foreground) +bool KIOFuseService::start(struct fuse_args &args, const QString &mountpoint, bool foreground) { if(!m_mountpoint.isEmpty()) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kio-fuse-5.0.1/kiofuseservice.h new/kio-fuse-5.1.0/kiofuseservice.h --- old/kio-fuse-5.0.1/kiofuseservice.h 2021-03-21 15:14:52.000000000 +0100 +++ new/kio-fuse-5.1.0/kiofuseservice.h 2023-12-09 21:26:39.000000000 +0100 @@ -38,7 +38,7 @@ virtual ~KIOFuseService(); /** Attempts to register the service and start kiofusevfs. If both succeed, * returns true, false otherwise. */ - bool start(struct fuse_args &args, QString mountpoint, bool foreground); + bool start(struct fuse_args &args, const QString &mountpoint, bool foreground); KIOFuseVFS kiofusevfs; public Q_SLOTS: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kio-fuse-5.0.1/kiofusevfs.cpp new/kio-fuse-5.1.0/kiofusevfs.cpp --- old/kio-fuse-5.0.1/kiofusevfs.cpp 2021-03-21 15:14:52.000000000 +0100 +++ new/kio-fuse-5.1.0/kiofusevfs.cpp 2023-12-09 21:26:39.000000000 +0100 @@ -295,14 +295,29 @@ m_useFileJob = useFileJob; } -void KIOFuseVFS::mountUrl(QUrl url, std::function<void (const QString &, int)> callback) +void KIOFuseVFS::mountUrl(const QUrl &url, const std::function<void (const QString &, int)> &callback) { + qDebug(KIOFUSE_LOG) << "Trying to mount" << url; + + if(!url.isValid()) { + qDebug(KIOFUSE_LOG) << "Got invalid URL"; + return callback({}, EINVAL); + } + + const auto vfsPath = mapUrlToVfs(url).join(QLatin1Char('/')); + // If it's not mounted, this returns an empty QUrl. + // Checking with the target URL is done to detect password changes. + if(localPathToRemoteUrl(vfsPath) == url) { + qDebug(KIOFUSE_LOG) << "Already mounted"; + return callback(vfsPath, 0); + } + // First make sure it actually exists qDebug(KIOFUSE_LOG) << "Stating" << url.toDisplayString() << "for mount"; auto statJob = KIO::stat(url); statJob->setSide(KIO::StatJob::SourceSide); // Be "optimistic" to allow accessing // files over plain HTTP - connect(statJob, &KIO::StatJob::result, [=] { + connect(statJob, &KIO::StatJob::result, this, [=] { if(statJob->error()) { qDebug(KIOFUSE_LOG) << statJob->errorString(); @@ -317,10 +332,12 @@ }); } -QStringList KIOFuseVFS::mapUrlToVfs(QUrl url) +QStringList KIOFuseVFS::mapUrlToVfs(const QUrl &url) { // Build the path where it will appear in the VFS - auto targetPathComponents = QStringList{url.scheme(), url.authority()}; + auto urlWithoutPassword = url; + urlWithoutPassword.setPassword({}); + auto targetPathComponents = QStringList{urlWithoutPassword.scheme(), urlWithoutPassword.authority()}; targetPathComponents.append(url.path().split(QLatin1Char('/'))); // Strip empty path elements, for instance in @@ -332,13 +349,13 @@ return targetPathComponents; } -void KIOFuseVFS::findAndCreateOrigin(QUrl url, QStringList pathElements, std::function<void (const QString &, int)> callback) +void KIOFuseVFS::findAndCreateOrigin(const QUrl &url, const QStringList &pathElements, const std::function<void (const QString &, int)> &callback) { qDebug(KIOFUSE_LOG) << "Trying origin" << url.toDisplayString(); auto statJob = KIO::stat(url); statJob->setSide(KIO::StatJob::SourceSide); // Be "optimistic" to allow accessing // files over plain HTTP - connect(statJob, &KIO::StatJob::result, [=] { + connect(statJob, &KIO::StatJob::result, this, [=] { if(statJob->error()) { qDebug(KIOFUSE_LOG) << statJob->errorString(); @@ -395,7 +412,7 @@ return callback({}, EIO); } - // Some ioslaves like man:/ implement "index files" for folders (including /) by making + // Some ioworkers like man:/ implement "index files" for folders (including /) by making // them look as regular file when stating, but they also support listDir for directory // functionality. This behaviour is not compatible, so just reject it outright. if((url.path().isEmpty() || url.path() == QStringLiteral("/")) @@ -602,7 +619,7 @@ fileJob->truncate(sharedState->value.st_size); connect(fileJob, &KIO::FileJob::truncated, [=] { fileJob->close(); - connect(fileJob, qOverload<KIO::Job*>(&KIO::FileJob::close), [=] { + connect(fileJob, qOverload<KIO::Job*>(&KIO::FileJob::fileClosed), [=] { fileJobBasedFileNode->m_stat.st_size = sharedState->value.st_size; markOperationCompleted(FUSE_SET_ATTR_SIZE); }); @@ -748,7 +765,7 @@ auto url = addPathElements(that->remoteUrl(node), {nameStr}); auto *job = KIO::put(url, mode & ~S_IFMT); // Not connecting to the dataReq signal at all results in an empty file - that->connect(job, &KIO::SimpleJob::finished, [=] { + that->connect(job, &KIO::SimpleJob::finished, that, [=] { if(job->error()) { fuse_reply_err(req, kioErrorToFuseError(job->error())); @@ -784,7 +801,7 @@ auto namestr = QString::fromUtf8(name); auto url = addPathElements(that->remoteUrl(node), {namestr}); auto *job = KIO::mkdir(url, mode & ~S_IFMT); - that->connect(job, &KIO::SimpleJob::finished, [=] { + that->connect(job, &KIO::SimpleJob::finished, that, [=] { if(job->error()) { fuse_reply_err(req, kioErrorToFuseError(job->error())); @@ -857,7 +874,7 @@ } auto *job = KIO::del(that->remoteUrl(node)); - that->connect(job, &KIO::SimpleJob::finished, [=] { + that->connect(job, &KIO::SimpleJob::finished, that, [=] { if(job->error()) { fuse_reply_err(req, kioErrorToFuseError(job->error())); @@ -923,7 +940,7 @@ auto namestr = QString::fromUtf8(name); auto url = addPathElements(that->remoteUrl(node), {namestr}); auto *job = KIO::symlink(target, url); - that->connect(job, &KIO::SimpleJob::finished, [=] { + that->connect(job, &KIO::SimpleJob::finished, that, [=] { if(job->error()) { fuse_reply_err(req, kioErrorToFuseError(job->error())); @@ -1013,7 +1030,7 @@ newUrl = addPathElements(that->remoteUrl(remoteNewParent), {newNameStr}); auto *job = KIO::rename(url, newUrl, (flags & RENAME_NOREPLACE) ? KIO::DefaultFlags : KIO::Overwrite); - that->connect(job, &KIO::SimpleJob::finished, [=] { + that->connect(job, &KIO::SimpleJob::finished, that, [=] { if(job->error()) fuse_reply_err(req, kioErrorToFuseError(job->error())); else @@ -1231,7 +1248,7 @@ if(off_t(offset) != off) { fileJob->close(); - fileJob->connect(fileJob, qOverload<KIO::Job*>(&KIO::FileJob::close), [=] { + fileJob->connect(fileJob, qOverload<KIO::Job*>(&KIO::FileJob::fileClosed), [=] { fuse_reply_err(req, EIO); }); return; @@ -1257,7 +1274,7 @@ return; } fileJob->close(); - fileJob->connect(fileJob, qOverload<KIO::Job*>(&KIO::FileJob::close), [=] { + fileJob->connect(fileJob, qOverload<KIO::Job*>(&KIO::FileJob::fileClosed), [=] { fuse_reply_buf(req, buffer.constData(), buffer.size()); }); }); @@ -1353,12 +1370,12 @@ Q_UNUSED(job); if (off_t(offset) != off) { fileJob->close(); - fileJob->connect(fileJob, qOverload<KIO::Job*>(&KIO::FileJob::close), [=] { + fileJob->connect(fileJob, qOverload<KIO::Job*>(&KIO::FileJob::fileClosed), [=] { fuse_reply_err(req, EIO); }); return; } - // Limit write to avoid killing the slave. + // Limit write to avoid killing the worker. // @see https://phabricator.kde.org/D15448 fileJob->write(data.left(0xFFFFFF)); off_t bytesLeft = size; @@ -1372,7 +1389,7 @@ return; } fileJob->close(); - fileJob->connect(fileJob, qOverload<KIO::Job*>(&KIO::FileJob::close), [=] { + fileJob->connect(fileJob, qOverload<KIO::Job*>(&KIO::FileJob::fileClosed), [=] { // Wait till we've flushed first... remoteNode->m_stat.st_size = std::max(off_t(offset + data.size()), remoteNode->m_stat.st_size); fuse_reply_write(req, data.size()); @@ -1490,7 +1507,7 @@ return true; } -std::shared_ptr<KIOFuseNode> KIOFuseVFS::nodeByName(const std::shared_ptr<KIOFuseDirNode> &parent, const QString name) const +std::shared_ptr<KIOFuseNode> KIOFuseVFS::nodeByName(const std::shared_ptr<KIOFuseDirNode> &parent, const QString &name) const { for(auto ino : parent->m_childrenInos) { @@ -1739,7 +1756,7 @@ void KIOFuseVFS::replyAttr(fuse_req_t req, std::shared_ptr<KIOFuseNode> node) { // Set st_blocks accordingly - node->m_stat.st_blocks = (node->m_stat.st_size + node->m_stat.st_blksize - 1) / node->m_stat.st_blksize; + node->m_stat.st_blocks = (node->m_stat.st_size + 512 - 1) / 512; // TODO: Validity timeout? fuse_reply_attr(req, &node->m_stat, 0); @@ -1763,7 +1780,7 @@ fuse_reply_entry(req, &entry); } -std::shared_ptr<KIOFuseNode> KIOFuseVFS::createNodeFromUDSEntry(const KIO::UDSEntry &entry, const fuse_ino_t parentIno, QString nameOverride) +std::shared_ptr<KIOFuseNode> KIOFuseVFS::createNodeFromUDSEntry(const KIO::UDSEntry &entry, const fuse_ino_t parentIno, const QString &nameOverride) { QString name = nameOverride; if(name.isEmpty()) @@ -1949,7 +1966,7 @@ return node; } -void KIOFuseVFS::awaitBytesAvailable(const std::shared_ptr<KIOFuseRemoteCacheBasedFileNode> &node, off_t bytes, std::function<void(int error)> callback) +void KIOFuseVFS::awaitBytesAvailable(const std::shared_ptr<KIOFuseRemoteCacheBasedFileNode> &node, off_t bytes, const std::function<void(int error)> &callback) { if(bytes < 0) { @@ -1990,11 +2007,11 @@ int cacheFd = fileno(node->m_localCache); if(lseek(cacheFd, 0, SEEK_END) == -1 || !sane_write(cacheFd, data.data(), data.size())) - emit node->localCacheChanged(errno); + Q_EMIT node->localCacheChanged(errno); else { node->m_cacheSize += data.size(); - emit node->localCacheChanged(0); + Q_EMIT node->localCacheChanged(0); } }); connect(job, &KIO::TransferJob::result, [=] { @@ -2008,7 +2025,7 @@ node->m_cacheSize = 0; node->m_cacheComplete = false; node->m_localCache = nullptr; - emit node->localCacheChanged(kioErrorToFuseError(job->error())); + Q_EMIT node->localCacheChanged(kioErrorToFuseError(job->error())); } else { @@ -2016,7 +2033,7 @@ // This also ensures that the cache is seen as complete. node->m_stat.st_size = node->m_cacheSize; node->m_cacheComplete = true; - emit node->localCacheChanged(0); + Q_EMIT node->localCacheChanged(0); } }); } @@ -2047,7 +2064,7 @@ ); } -void KIOFuseVFS::awaitCacheComplete(const std::shared_ptr<KIOFuseRemoteCacheBasedFileNode> &node, std::function<void (int)> callback) +void KIOFuseVFS::awaitCacheComplete(const std::shared_ptr<KIOFuseRemoteCacheBasedFileNode> &node, const std::function<void (int)> &callback) { return awaitBytesAvailable(node, std::numeric_limits<off_t>::max(), [callback](int error) { // ESPIPE == cache complete, but less than the requested size, which is expected. @@ -2055,7 +2072,7 @@ }); } -void KIOFuseVFS::awaitChildrenComplete(const std::shared_ptr<KIOFuseDirNode> &node, std::function<void (int)> callback) +void KIOFuseVFS::awaitChildrenComplete(const std::shared_ptr<KIOFuseDirNode> &node, const std::function<void (int)> &callback) { auto remoteNode = std::dynamic_pointer_cast<KIOFuseRemoteDirNode>(node); if(!remoteNode) @@ -2074,7 +2091,7 @@ // List the remote dir auto refreshTime = std::chrono::steady_clock::now(); auto *job = KIO::listDir(remoteUrl(remoteNode)); - connect(job, &KIO::ListJob::entries, [=](auto *job, const KIO::UDSEntryList &entries) { + connect(job, &KIO::ListJob::entries, this, [=](auto *job, const KIO::UDSEntryList &entries) { for(auto &entry : entries) { // Inside the loop because refreshing "." might drop it @@ -2118,12 +2135,12 @@ insertNode(childrenNode); } }); - connect(job, &KIO::ListJob::result, [=] { + connect(job, &KIO::ListJob::result, this, [=] { remoteNode->m_childrenRequested = false; if(job->error() && job->error() != KJob::KilledJobError) { - emit remoteNode->gotChildren(kioErrorToFuseError(job->error())); + Q_EMIT remoteNode->gotChildren(kioErrorToFuseError(job->error())); return; } @@ -2136,7 +2153,7 @@ } remoteNode->m_lastChildrenRefresh = refreshTime; - emit remoteNode->gotChildren(0); + Q_EMIT remoteNode->gotChildren(0); }); remoteNode->m_childrenRequested = true; @@ -2162,7 +2179,7 @@ m_dirtyNodes.insert(node->m_stat.st_ino); } -void KIOFuseVFS::awaitNodeFlushed(const std::shared_ptr<KIOFuseRemoteCacheBasedFileNode> &node, std::function<void (int)> callback) +void KIOFuseVFS::awaitNodeFlushed(const std::shared_ptr<KIOFuseRemoteCacheBasedFileNode> &node, const std::function<void (int)> &callback) { if(!node->m_cacheDirty && !node->m_flushRunning) return callback(0); // Nothing to flush/wait for @@ -2198,7 +2215,7 @@ job->setTotalSize(node->m_cacheSize); off_t bytesSent = 0; // Modified inside the lambda - connect(job, &KIO::TransferJob::dataReq, [=](auto *job, QByteArray &data) mutable { + connect(job, &KIO::TransferJob::dataReq, this, [=](auto *job, QByteArray &data) mutable { Q_UNUSED(job); // Someone truncated the file? @@ -2232,14 +2249,14 @@ bytesSent += toSend; }); - connect(job, &KIO::TransferJob::result, [=] { + connect(job, &KIO::TransferJob::result, this, [=] { node->m_flushRunning = false; if(job->error()) { qWarning(KIOFUSE_LOG) << "Failed to send data:" << job->errorString(); markCacheDirty(node); // Try again - emit node->cacheFlushed(kioErrorToFuseError(job->error())); + Q_EMIT node->cacheFlushed(kioErrorToFuseError(job->error())); return; } @@ -2248,7 +2265,7 @@ // Nobody wrote to the cache while sending data m_dirtyNodes.extract(node->m_stat.st_ino); node->m_numKilledJobs = 0; - emit node->cacheFlushed(0); + Q_EMIT node->cacheFlushed(0); } else awaitNodeFlushed(node, [](int){}); @@ -2266,7 +2283,7 @@ ); } -void KIOFuseVFS::awaitAttrRefreshed(const std::shared_ptr<KIOFuseNode> &node, std::function<void (int)> callback) +void KIOFuseVFS::awaitAttrRefreshed(const std::shared_ptr<KIOFuseNode> &node, const std::function<void (int)> &callback) { auto remoteNode = std::dynamic_pointer_cast<KIOFuseRemoteNodeInfo>(node); if(!remoteNode || !remoteNode->hasStatTimedOut()) @@ -2289,7 +2306,7 @@ Q_UNUSED(mountedNode); remoteNode->m_statRequested = false; - emit remoteNode->statRefreshed(error); + Q_EMIT remoteNode->statRefreshed(error); }); } @@ -2304,7 +2321,7 @@ ); } -void KIOFuseVFS::awaitChildMounted(const std::shared_ptr<KIOFuseRemoteDirNode> &parent, const QString name, std::function<void (const std::shared_ptr<KIOFuseNode> &, int)> callback) +void KIOFuseVFS::awaitChildMounted(const std::shared_ptr<KIOFuseRemoteDirNode> &parent, const QString &name, const std::function<void (const std::shared_ptr<KIOFuseNode> &, int)> &callback) { auto url = addPathElements(remoteUrl(parent), {name}); if(url.isEmpty()) // Not remote? @@ -2319,7 +2336,7 @@ auto statJob = KIO::stat(url); statJob->setSide(KIO::StatJob::SourceSide); // Be "optimistic" to allow accessing // files over plain HTTP - connect(statJob, &KIO::StatJob::result, [=] { + connect(statJob, &KIO::StatJob::result, this, [=] { if(statJob->error()) { qDebug(KIOFUSE_LOG) << statJob->errorString(); @@ -2347,7 +2364,7 @@ }); } -QUrl KIOFuseVFS::originOfUrl(QUrl url) +QUrl KIOFuseVFS::originOfUrl(const QUrl &url) { QUrl originUrl = url; if(originUrl.path().startsWith(QLatin1Char('/'))) @@ -2461,7 +2478,7 @@ case KIO::ERR_CANNOT_RENAME : return EIO; case KIO::ERR_CANNOT_CHMOD : return EIO; case KIO::ERR_CANNOT_DELETE : return EIO; - case KIO::ERR_SLAVE_DIED : return EIO; + case KIO::ERR_WORKER_DIED : return EIO; case KIO::ERR_OUT_OF_MEMORY : return ENOMEM; case KIO::ERR_UNKNOWN_PROXY_HOST : return EHOSTUNREACH; case KIO::ERR_CANNOT_AUTHENTICATE : return EACCES; @@ -2477,10 +2494,10 @@ case KIO::ERR_CANNOT_RENAME_PARTIAL : return EIO; case KIO::ERR_NEED_PASSWD : return EACCES; case KIO::ERR_CANNOT_SYMLINK : return EIO; - case KIO::ERR_NO_CONTENT : return ENODATA; + case KIO::ERR_NO_CONTENT : return EIO; case KIO::ERR_DISK_FULL : return ENOSPC; case KIO::ERR_IDENTICAL_FILES : return EEXIST; - case KIO::ERR_SLAVE_DEFINED : return EIO; + case KIO::ERR_WORKER_DEFINED : return EIO; case KIO::ERR_UPGRADE_REQUIRED : return EPROTOTYPE; case KIO::ERR_POST_DENIED : return EACCES; case KIO::ERR_CANNOT_SEEK : return EIO; @@ -2490,7 +2507,7 @@ case KIO::ERR_DROP_ON_ITSELF : return EINVAL; case KIO::ERR_CANNOT_MOVE_INTO_ITSELF : return EINVAL; case KIO::ERR_PASSWD_SERVER : return EIO; - case KIO::ERR_CANNOT_CREATE_SLAVE : return EIO; + case KIO::ERR_CANNOT_CREATE_WORKER : return EIO; case KIO::ERR_FILE_TOO_LARGE_FOR_FAT32 : return EFBIG; case KIO::ERR_OWNER_DIED : return EIO; default : return EIO; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kio-fuse-5.0.1/kiofusevfs.h new/kio-fuse-5.1.0/kiofusevfs.h --- old/kio-fuse-5.0.1/kiofusevfs.h 2021-03-21 15:14:52.000000000 +0100 +++ new/kio-fuse-5.1.0/kiofusevfs.h 2023-12-09 21:26:39.000000000 +0100 @@ -51,7 +51,7 @@ void setUseFileJob(bool useFileJob); /** Runs KIO::stat on url and (if successful) creates an origin node at the lowest possible level. * Returns the relative path to where url is reachable in the callback. */ - void mountUrl(QUrl url, std::function<void(const QString&, int)> callback); + void mountUrl(const QUrl &url, const std::function<void(const QString&, int)> &callback); /** Converts a local path into a remote URL if it is mounted within the VFS */ QUrl localPathToRemoteUrl(const QString &localPath) const; /** Returns the path upwards until a root node. */ @@ -101,7 +101,7 @@ static void signalHandler(int signal); /** Returns a pointer to a child node of parent with m_nodeName == name or nullptr. */ - std::shared_ptr<KIOFuseNode> nodeByName(const std::shared_ptr<KIOFuseDirNode> &parent, const QString name) const; + std::shared_ptr<KIOFuseNode> nodeByName(const std::shared_ptr<KIOFuseDirNode> &parent, const QString &name) const; /** Returns a pointer to the KIOFuseNode with inode number ino or nullptr. */ std::shared_ptr<KIOFuseNode> nodeForIno(const fuse_ino_t ino) const; /** Removes the node from the old parent's children list (if any) and adds it to the new parent's list.*/ @@ -123,7 +123,7 @@ /** Depending on the lookup count, it makes the node a child of DeletedRoot or deletes it directly. */ void markNodeDeleted(const std::shared_ptr<KIOFuseNode> &node); /** Creates a new node with the matching type and fills m_stat fields. */ - std::shared_ptr<KIOFuseNode> createNodeFromUDSEntry(const KIO::UDSEntry &entry, const fuse_ino_t parentIno, QString nameOverride); + std::shared_ptr<KIOFuseNode> createNodeFromUDSEntry(const KIO::UDSEntry &entry, const fuse_ino_t parentIno, const QString &nameOverride); /** Applies a fresh KIO::UDSEntry to an existing node. If the type needs changing, * The old node is deleted and a new one inserted instead. The now fresh node is returned. */ std::shared_ptr<KIOFuseNode> updateNodeFromUDSEntry(const std::shared_ptr<KIOFuseNode> &node, const KIO::UDSEntry &entry); @@ -136,28 +136,28 @@ /** Invokes callback on error or when the bytes are available for reading/writing. * If the file is smaller than bytes, it sets error = ESPIPE. */ - void awaitBytesAvailable(const std::shared_ptr<KIOFuseRemoteCacheBasedFileNode> &node, off_t bytes, std::function<void(int error)> callback); + void awaitBytesAvailable(const std::shared_ptr<KIOFuseRemoteCacheBasedFileNode> &node, off_t bytes, const std::function<void(int error)> &callback); /** Invokes callback on error or when the cache is marked as complete. */ - void awaitCacheComplete(const std::shared_ptr<KIOFuseRemoteCacheBasedFileNode> &node, std::function<void(int error)> callback); + void awaitCacheComplete(const std::shared_ptr<KIOFuseRemoteCacheBasedFileNode> &node, const std::function<void(int error)> &callback); /** Invokes callback on error or when all children nodes are available */ - void awaitChildrenComplete(const std::shared_ptr<KIOFuseDirNode> &node, std::function<void(int error)> callback); + void awaitChildrenComplete(const std::shared_ptr<KIOFuseDirNode> &node, const std::function<void(int error)> &callback); /** Marks a node's cache as dirty and add it to m_dirtyNodes. */ void markCacheDirty(const std::shared_ptr<KIOFuseRemoteCacheBasedFileNode> &node); /** Calls the callback once the cache is not dirty anymore (no cache counts as clean as well). * If writes happen while a flush is sending data, a flush will be retriggered. */ - void awaitNodeFlushed(const std::shared_ptr<KIOFuseRemoteCacheBasedFileNode> &node, std::function<void(int error)> callback); + void awaitNodeFlushed(const std::shared_ptr<KIOFuseRemoteCacheBasedFileNode> &node, const std::function<void(int error)> &callback); /** Invokes callback on error or when a node has been refreshed (if its stat timed out) */ - void awaitAttrRefreshed(const std::shared_ptr<KIOFuseNode> &node, std::function<void(int error)> callback); + void awaitAttrRefreshed(const std::shared_ptr<KIOFuseNode> &node, const std::function<void(int error)> &callback); /** Invokes callback on error on when the child node was fetched and created/updated. */ - void awaitChildMounted(const std::shared_ptr<KIOFuseRemoteDirNode> &node, const QString name, std::function<void(const std::shared_ptr<KIOFuseNode>&, int)> callback); + void awaitChildMounted(const std::shared_ptr<KIOFuseRemoteDirNode> &node, const QString &name, const std::function<void(const std::shared_ptr<KIOFuseNode>&, int)> &callback); /** Returns the URL pointing to the origin of the linked resource, i.e. path set to / or empty. */ - QUrl originOfUrl(QUrl url); + QUrl originOfUrl(const QUrl &url); /** Returns the path elements where the URL url gets mapped to in this VFS. */ - QStringList mapUrlToVfs(QUrl url); + QStringList mapUrlToVfs(const QUrl &url); /** Stats url. If successful, returns the path where url + pathElements is reachable in callback. * If it failed, it moves one part of pathElements to url and tries again, recursively. */ - void findAndCreateOrigin(QUrl url, QStringList pathElements, std::function<void(const QString&, int)> callback); + void findAndCreateOrigin(const QUrl &url, const QStringList &pathElements, const std::function<void(const QString&, int)> &callback); /** Returns the corresponding FUSE error to the given KIO Job error */ static int kioErrorToFuseError(const int kioError); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kio-fuse-5.0.1/tests/CMakeLists.txt new/kio-fuse-5.1.0/tests/CMakeLists.txt --- old/kio-fuse-5.0.1/tests/CMakeLists.txt 2021-03-21 15:14:52.000000000 +0100 +++ new/kio-fuse-5.1.0/tests/CMakeLists.txt 2023-12-09 21:26:39.000000000 +0100 @@ -2,19 +2,17 @@ set(KIOFUSE_TEST_SOURCES fileopstest.cpp) -find_package(Qt5Test CONFIG REQUIRED) -find_package(Qt5DBus CONFIG REQUIRED) +find_package(Qt${QT_MAJOR_VERSION}Test CONFIG REQUIRED) +find_package(Qt${QT_MAJOR_VERSION}DBus CONFIG REQUIRED) -qt5_add_dbus_interface(KIOFUSE_TEST_SOURCES org.kde.KIOFuse.VFS.xml kiofuse_interface) -qt5_add_dbus_interface(KIOFUSE_TEST_SOURCES org.kde.KIOFuse.Private.xml kiofuseprivate_interface) +qt_add_dbus_interface(KIOFUSE_TEST_SOURCES org.kde.KIOFuse.VFS.xml kiofuse_interface) +qt_add_dbus_interface(KIOFUSE_TEST_SOURCES org.kde.KIOFuse.Private.xml kiofuseprivate_interface) add_executable(fileopstest-cache ${KIOFUSE_TEST_SOURCES}) -target_link_libraries(fileopstest-cache PRIVATE Qt5::Test Qt5::DBus KF5::KIOCore) +target_link_libraries(fileopstest-cache PRIVATE Qt::Test Qt::DBus KF${QT_MAJOR_VERSION}::KIOCore) target_compile_definitions(fileopstest-cache PRIVATE -DTEST_CACHE_BASED_IO) add_test(NAME fileopstest-cache COMMAND dbus-run-session ${CMAKE_BINARY_DIR}/bin/fileopstest-cache) -set_tests_properties(fileopstest-cache PROPERTIES ENVIRONMENT KDE_FORK_SLAVES=1) add_executable(fileopstest-filejob ${KIOFUSE_TEST_SOURCES}) -target_link_libraries(fileopstest-filejob PRIVATE Qt5::Test Qt5::DBus KF5::KIOCore) +target_link_libraries(fileopstest-filejob PRIVATE Qt::Test Qt::DBus KF${QT_MAJOR_VERSION}::KIOCore) add_test(NAME fileopstest-filejob COMMAND dbus-run-session ${CMAKE_BINARY_DIR}/bin/fileopstest-filejob) -set_tests_properties(fileopstest-filejob PROPERTIES ENVIRONMENT KDE_FORK_SLAVES=1) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kio-fuse-5.0.1/tests/fileopstest.cpp new/kio-fuse-5.1.0/tests/fileopstest.cpp --- old/kio-fuse-5.0.1/tests/fileopstest.cpp 2021-03-21 15:14:52.000000000 +0100 +++ new/kio-fuse-5.1.0/tests/fileopstest.cpp 2023-12-09 21:26:39.000000000 +0100 @@ -56,12 +56,12 @@ #endif // WASTE_DISK_SPACE private: - QDateTime roundDownToSecond(QDateTime dt); + QDateTime roundDownToSecond(const QDateTime &dt); bool forceNodeTimeout(); /** Unlike QFileInfo::symLinkTarget, which returns absolute paths only, * this returns the raw link content. On failure or truncation, a null * QString is returned instead. */ - QString readlink(QString symlink); + QString readlink(const QString &symlink); org::kde::KIOFuse::VFS m_kiofuse_iface{QStringLiteral("org.kde.KIOFuse"), QStringLiteral("/org/kde/KIOFuse"), @@ -131,7 +131,7 @@ // mtp:/ -> Remote URL can't possibly be location of KIOFuse mount. // / -> Root can't possibly be location of KIOFuse mount. // m_mountDir -> Whilst this is in the KIOFuse mount, no remote URL exists for it - for(auto url : {QStringLiteral("mtp:/"), QStringLiteral("/"), m_mountDir.path()}) + for(const auto &url : {QStringLiteral("mtp:/"), QStringLiteral("/"), m_mountDir.path()}) { errorReply = m_kiofuse_iface.remoteUrl(url); errorReply.waitForFinished(); @@ -683,7 +683,7 @@ void FileOpsTest::testManWorkaround() { - // The man ioslave has "hybrid" directories which stat as regular files but also support + // The man ioworker has "hybrid" directories which stat as regular files but also support // listDir. This behaviour is not supported and mounting has to fail. if (!KProtocolInfo::isKnownProtocol(QStringLiteral("man"))) @@ -1029,9 +1029,9 @@ } #endif // WASTE_DISK_SPACE -QDateTime FileOpsTest::roundDownToSecond(QDateTime dt) +QDateTime FileOpsTest::roundDownToSecond(const QDateTime &dt) { - return QDateTime::fromTime_t(dt.toTime_t()); + return dt.addMSecs(-dt.time().msec()); } bool FileOpsTest::forceNodeTimeout() @@ -1041,7 +1041,7 @@ return !reply.isError(); } -QString FileOpsTest::readlink(QString symlink) +QString FileOpsTest::readlink(const QString &symlink) { char buf[PATH_MAX]; int len = ::readlink(qPrintable(symlink), buf, sizeof(buf)); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kio-fuse-5.0.1/utils/mount-url.sh new/kio-fuse-5.1.0/utils/mount-url.sh --- old/kio-fuse-5.0.1/utils/mount-url.sh 1970-01-01 01:00:00.000000000 +0100 +++ new/kio-fuse-5.1.0/utils/mount-url.sh 2023-12-09 21:26:39.000000000 +0100 @@ -0,0 +1,10 @@ +#!/bin/sh +# +# SPDX-FileCopyrightText: 2022 Alexander Saoutkin <a.saout...@gmail.com> +# SPDX-License-Identifier: GPL-3.0-or-later +# + +dbus-send --session --print-reply --type=method_call \ + --dest=org.kde.KIOFuse \ + /org/kde/KIOFuse \ + org.kde.KIOFuse.VFS.mountUrl "string:$1"