diff -Nru kio-fuse-5.0.0/debian/changelog kio-fuse-5.0.1/debian/changelog --- kio-fuse-5.0.0/debian/changelog 2021-02-28 22:05:10.000000000 +0000 +++ kio-fuse-5.0.1/debian/changelog 2021-08-21 06:07:15.000000000 +0000 @@ -1,3 +1,19 @@ +kio-fuse (5.0.1-1) unstable; urgency=medium + + * Team upload. + * New upstream release. + * Update the patches: + - upstream-1ee510ba-check-return-value-of-createNodeFromUDSEntry.patch: + drop, backported from upstream + - upstream-d69959e2-uds-url-target-use.patch: drop, backported from upstream + - upstream-3bb07481-improve-url-logging.patch: drop, backported from + upstream + - upstream-1dfbaa6-error-out-when-ioslaves-state-that-slash-is-a-regular-file.patch: + drop, backported from upstream + * Bump Standards-Version to 4.6.0, no changes required. + + -- Pino Toscano Sat, 21 Aug 2021 08:07:15 +0200 + kio-fuse (5.0.0-4) unstable; urgency=medium * Team upload. diff -Nru kio-fuse-5.0.0/debian/control kio-fuse-5.0.1/debian/control --- kio-fuse-5.0.0/debian/control 2021-02-28 20:56:12.000000000 +0000 +++ kio-fuse-5.0.1/debian/control 2021-08-21 05:57:16.000000000 +0000 @@ -14,7 +14,7 @@ pkg-config, pkg-kde-tools, qtbase5-dev (>= 5.12.0~) -Standards-Version: 4.5.1 +Standards-Version: 4.6.0 Rules-Requires-Root: no Vcs-Browser: https://salsa.debian.org/qt-kde-team/extras/kio-fuse Vcs-Git: https://salsa.debian.org/qt-kde-team/extras/kio-fuse.git diff -Nru kio-fuse-5.0.0/debian/patches/series kio-fuse-5.0.1/debian/patches/series --- kio-fuse-5.0.0/debian/patches/series 2021-02-28 21:43:49.000000000 +0000 +++ kio-fuse-5.0.1/debian/patches/series 1970-01-01 00:00:00.000000000 +0000 @@ -1,4 +0,0 @@ -upstream-1ee510ba-check-return-value-of-createNodeFromUDSEntry.patch -upstream-d69959e2-uds-url-target-use.patch -upstream-3bb07481-improve-url-logging.patch -upstream-1dfbaa6-error-out-when-ioslaves-state-that-slash-is-a-regular-file.patch diff -Nru kio-fuse-5.0.0/debian/patches/upstream-1dfbaa6-error-out-when-ioslaves-state-that-slash-is-a-regular-file.patch kio-fuse-5.0.1/debian/patches/upstream-1dfbaa6-error-out-when-ioslaves-state-that-slash-is-a-regular-file.patch --- kio-fuse-5.0.0/debian/patches/upstream-1dfbaa6-error-out-when-ioslaves-state-that-slash-is-a-regular-file.patch 2021-02-28 21:55:13.000000000 +0000 +++ kio-fuse-5.0.1/debian/patches/upstream-1dfbaa6-error-out-when-ioslaves-state-that-slash-is-a-regular-file.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,69 +0,0 @@ -Origin: backport, https://invent.kde.org/system/kio-fuse/-/commit/b1dfbaa60b3f38e0890cc4c17b0fd9d663e6eedd -From: Fabian Vogt -Date: Sun, 21 Feb 2021 21:52:51 +0100 -Subject: [PATCH] Error out when ioslaves state that / is a regular file - Reject mounting slaves with this incompatible behaviour, it can't be mapped - to FUSE semantics completely. - . - BUG: 433300 ---- - kiofusevfs.cpp | 11 +++++++++++ - tests/fileopstest.cpp | 20 ++++++++++++++++++++ - 2 files changed, 31 insertions(+) - ---- a/kiofusevfs.cpp -+++ b/kiofusevfs.cpp -@@ -392,6 +392,17 @@ - qWarning(KIOFUSE_LOG) << "Unable to create a valid final node for" << url.toDisplayString() << "from its UDS Entry"; - return callback({}, EIO); - } -+ -+ // Some ioslaves 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("/")) -+ && !S_ISDIR(finalNode->m_stat.st_mode)) -+ { -+ qWarning(KIOFUSE_LOG) << "Root of mount at" << url.toDisplayString() << "not a directory"; -+ return callback({}, ENOTDIR); -+ } -+ - insertNode(finalNode); - } - ---- a/tests/fileopstest.cpp -+++ b/tests/fileopstest.cpp -@@ -36,6 +36,7 @@ - void testRenameOps(); - void testDeletionOps(); - void testArchiveOps(); -+ void testManWorkaround(); - void testKioErrorMapping(); - void testRootLookup(); - void testFilenameEscaping(); -@@ -615,6 +616,25 @@ - innerfile.close(); - } - -+void FileOpsTest::testManWorkaround() -+{ -+ // The man ioslave 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"))) -+ QSKIP("Test requires man protocol to be supported. See README for packages required."); -+ -+ QDBusPendingReply reply = m_kiofuse_iface.mountUrl(QStringLiteral("man:foo")); -+ reply.waitForFinished(); -+ QVERIFY(reply.isError()); -+ QCOMPARE(reply.error().name(), QStringLiteral("org.kde.KIOFuse.VFS.Error.CannotMount")); -+ -+ reply = m_kiofuse_iface.mountUrl(QStringLiteral("man:/")); -+ reply.waitForFinished(); -+ QVERIFY(reply.isError()); -+ QCOMPARE(reply.error().name(), QStringLiteral("org.kde.KIOFuse.VFS.Error.CannotMount")); -+} -+ - void FileOpsTest::testKioErrorMapping() - { - QTemporaryFile localFile; diff -Nru kio-fuse-5.0.0/debian/patches/upstream-1ee510ba-check-return-value-of-createNodeFromUDSEntry.patch kio-fuse-5.0.1/debian/patches/upstream-1ee510ba-check-return-value-of-createNodeFromUDSEntry.patch --- kio-fuse-5.0.0/debian/patches/upstream-1ee510ba-check-return-value-of-createNodeFromUDSEntry.patch 2021-02-28 20:56:12.000000000 +0000 +++ kio-fuse-5.0.1/debian/patches/upstream-1ee510ba-check-return-value-of-createNodeFromUDSEntry.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,32 +0,0 @@ -From 1ee510baa80c834bbcf77a008e5668dbf3eccf4d Mon Sep 17 00:00:00 2001 -From: Alexander Saoutkin -Date: Sat, 2 Jan 2021 20:01:16 +0000 -Subject: [PATCH] Check return value of createNodeFromUDSEntry() - -createNodeFromUDSEntry() can return a nullptr, which it does when -passed any URL from the baloosearch protocol. - -BUG: 431079 ---- - kiofusevfs.cpp | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/kiofusevfs.cpp b/kiofusevfs.cpp -index 6f275cb..fbf6e27 100644 ---- a/kiofusevfs.cpp -+++ b/kiofusevfs.cpp -@@ -393,6 +393,11 @@ void KIOFuseVFS::findAndCreateOrigin(QUrl url, QStringList pathElements, std::fu - if(!finalNode) - { - finalNode = createNodeFromUDSEntry(statJob->statResult(), currentNode->m_stat.st_ino, targetPathComponents.last()); -+ if(!finalNode) -+ { -+ qWarning(KIOFUSE_LOG) << "Unable to create a valid final node for" << url << "from its UDS Entry"; -+ return callback({}, EIO); -+ } - insertNode(finalNode); - } - --- -GitLab - diff -Nru kio-fuse-5.0.0/debian/patches/upstream-3bb07481-improve-url-logging.patch kio-fuse-5.0.1/debian/patches/upstream-3bb07481-improve-url-logging.patch --- kio-fuse-5.0.0/debian/patches/upstream-3bb07481-improve-url-logging.patch 2021-02-28 21:53:56.000000000 +0000 +++ kio-fuse-5.0.1/debian/patches/upstream-3bb07481-improve-url-logging.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,74 +0,0 @@ -Origin: upstream, https://invent.kde.org/system/kio-fuse/-/commit/3bb07481aadf77029ef0b506d0abddc9be6ad7b4 -From: Fabian Vogt -Date: Wed, 13 Jan 2021 22:13:41 +0100 -Subject: [PATCH] Use QUrl::toDisplayString - Previously open-coded in various places, this commit simplifie those. - Additionally, this fixes a case where the url was logged directly. - . - The only purpose is basically to avoid the "QUrl()" around the URL in the log. ---- - kiofusevfs.cpp | 19 +++++-------------- - 1 file changed, 5 insertions(+), 14 deletions(-) - -diff --git a/kiofusevfs.cpp b/kiofusevfs.cpp -index 5c775b7..504a95e 100644 ---- a/kiofusevfs.cpp -+++ b/kiofusevfs.cpp -@@ -296,10 +296,7 @@ void KIOFuseVFS::setUseFileJob(bool useFileJob) - void KIOFuseVFS::mountUrl(QUrl url, std::function callback) - { - // First make sure it actually exists -- QUrl urlWithoutPassword = url; -- urlWithoutPassword.setPassword({}); -- -- qDebug(KIOFUSE_LOG) << "Stating" << urlWithoutPassword << "for mount"; -+ 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 -@@ -335,10 +332,7 @@ QStringList KIOFuseVFS::mapUrlToVfs(QUrl url) - - void KIOFuseVFS::findAndCreateOrigin(QUrl url, QStringList pathElements, std::function callback) - { -- QUrl urlWithoutPassword = url; -- urlWithoutPassword.setPassword({}); -- -- qDebug(KIOFUSE_LOG) << "Trying origin" << urlWithoutPassword; -+ 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 -@@ -354,7 +348,7 @@ void KIOFuseVFS::findAndCreateOrigin(QUrl url, QStringList pathElements, std::fu - return callback({}, kioErrorToFuseError(statJob->error())); - } - -- qDebug(KIOFUSE_LOG) << "Origin found at" << urlWithoutPassword; -+ qDebug(KIOFUSE_LOG) << "Origin found at" << url.toDisplayString(); - - auto targetPathComponents = mapUrlToVfs(url); - -@@ -395,7 +389,7 @@ void KIOFuseVFS::findAndCreateOrigin(QUrl url, QStringList pathElements, std::fu - finalNode = createNodeFromUDSEntry(statJob->statResult(), currentNode->m_stat.st_ino, targetPathComponents.last()); - if(!finalNode) - { -- qWarning(KIOFUSE_LOG) << "Unable to create a valid final node for" << url << "from its UDS Entry"; -+ qWarning(KIOFUSE_LOG) << "Unable to create a valid final node for" << url.toDisplayString() << "from its UDS Entry"; - return callback({}, EIO); - } - insertNode(finalNode); -@@ -2245,10 +2239,7 @@ void KIOFuseVFS::awaitChildMounted(const std::shared_ptr & - return callback({}, ENOENT); - } - -- QUrl urlWithoutPassword = url; -- urlWithoutPassword.setPassword({}); -- -- qDebug(KIOFUSE_LOG) << "Mounting" << urlWithoutPassword; -+ qDebug(KIOFUSE_LOG) << "Mounting" << url.toDisplayString(); - auto statJob = KIO::stat(url); - statJob->setSide(KIO::StatJob::SourceSide); // Be "optimistic" to allow accessing - // files over plain HTTP --- -GitLab - - diff -Nru kio-fuse-5.0.0/debian/patches/upstream-d69959e2-uds-url-target-use.patch kio-fuse-5.0.1/debian/patches/upstream-d69959e2-uds-url-target-use.patch --- kio-fuse-5.0.0/debian/patches/upstream-d69959e2-uds-url-target-use.patch 2021-02-28 20:56:12.000000000 +0000 +++ kio-fuse-5.0.1/debian/patches/upstream-d69959e2-uds-url-target-use.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,49 +0,0 @@ -From d69959e226b1b49a1fc2d1a566acd4fdde0f97c3 Mon Sep 17 00:00:00 2001 -From: Fabian Vogt -Date: Thu, 7 Jan 2021 22:46:19 +0100 -Subject: [PATCH] UDS_URL is not meant for links, Use UDS_TARGET_URL instead - -The KIO documentation for UDS_URL says: -`use UDS_TARGET_URL if you want "links" to unrelated urls.` -So the use of UDS_URL here was probably wrong. -Switching to UDS_TARGET_URL fixes mounting of some slaves such as baloosearch, -which set UDS_URL to the URL of the entry itself for some reason. - -BUG: 431079 ---- - kiofusevfs.cpp | 8 +++++--- - 1 file changed, 5 insertions(+), 3 deletions(-) - -diff --git a/kiofusevfs.cpp b/kiofusevfs.cpp -index fbf6e27..5c775b7 100644 ---- a/kiofusevfs.cpp -+++ b/kiofusevfs.cpp -@@ -1736,12 +1736,12 @@ std::shared_ptr KIOFuseVFS::createNodeFromUDSEntry(const KIO::UDSEn - attr.st_gid = gr->gr_gid; - } - -- if(entry.contains(KIO::UDSEntry::UDS_LOCAL_PATH) || entry.contains(KIO::UDSEntry::UDS_URL)) -+ if(entry.contains(KIO::UDSEntry::UDS_LOCAL_PATH) || entry.contains(KIO::UDSEntry::UDS_TARGET_URL)) - { - // Create as symlink if possible - QString target = entry.stringValue(KIO::UDSEntry::UDS_LOCAL_PATH); - if(target.isEmpty()) -- target = QUrl(entry.stringValue(KIO::UDSEntry::UDS_URL)).toLocalFile(); -+ target = QUrl(entry.stringValue(KIO::UDSEntry::UDS_TARGET_URL)).toLocalFile(); - - if(!target.isEmpty()) - { -@@ -1760,7 +1760,9 @@ std::shared_ptr KIOFuseVFS::createNodeFromUDSEntry(const KIO::UDSEn - { - attr.st_mode |= S_IFREG; - std::shared_ptr ret = nullptr; -- const QUrl nodeUrl = QUrl{entry.stringValue(KIO::UDSEntry::UDS_URL)}; -+ const QUrl nodeUrl = QUrl{entry.stringValue(KIO::UDSEntry::UDS_TARGET_URL)}; -+ if(nodeUrl.isEmpty()) -+ return nullptr; - if(m_useFileJob && KProtocolManager::supportsOpening(nodeUrl) && KProtocolManager::supportsTruncating(nodeUrl)) - ret = std::make_shared(parentIno, name, attr); - else --- -GitLab - diff -Nru kio-fuse-5.0.0/kiofusevfs.cpp kio-fuse-5.0.1/kiofusevfs.cpp --- kio-fuse-5.0.0/kiofusevfs.cpp 2020-12-27 11:52:28.000000000 +0000 +++ kio-fuse-5.0.1/kiofusevfs.cpp 2021-03-21 14:14:52.000000000 +0000 @@ -68,7 +68,9 @@ flush = &KIOFuseVFS::flush; release = &KIOFuseVFS::release; fsync = &KIOFuseVFS::fsync; + opendir = &KIOFuseVFS::opendir; readdir = &KIOFuseVFS::readdir; + releasedir = &KIOFuseVFS::releasedir; } }; @@ -296,10 +298,7 @@ void KIOFuseVFS::mountUrl(QUrl url, std::function callback) { // First make sure it actually exists - QUrl urlWithoutPassword = url; - urlWithoutPassword.setPassword({}); - - qDebug(KIOFUSE_LOG) << "Stating" << urlWithoutPassword << "for mount"; + 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 @@ -335,10 +334,7 @@ void KIOFuseVFS::findAndCreateOrigin(QUrl url, QStringList pathElements, std::function callback) { - QUrl urlWithoutPassword = url; - urlWithoutPassword.setPassword({}); - - qDebug(KIOFUSE_LOG) << "Trying origin" << urlWithoutPassword; + 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 @@ -354,7 +350,7 @@ return callback({}, kioErrorToFuseError(statJob->error())); } - qDebug(KIOFUSE_LOG) << "Origin found at" << urlWithoutPassword; + qDebug(KIOFUSE_LOG) << "Origin found at" << url.toDisplayString(); auto targetPathComponents = mapUrlToVfs(url); @@ -393,6 +389,22 @@ if(!finalNode) { finalNode = createNodeFromUDSEntry(statJob->statResult(), currentNode->m_stat.st_ino, targetPathComponents.last()); + if(!finalNode) + { + qWarning(KIOFUSE_LOG) << "Unable to create a valid final node for" << url.toDisplayString() << "from its UDS Entry"; + return callback({}, EIO); + } + + // Some ioslaves 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("/")) + && !S_ISDIR(finalNode->m_stat.st_mode)) + { + qWarning(KIOFUSE_LOG) << "Root of mount at" << url.toDisplayString() << "not a directory"; + return callback({}, ENOTDIR); + } + insertNode(finalNode); } @@ -1025,9 +1037,8 @@ fuse_add_direntry(req, dirbuf.data() + oldsize, dirbuf.size() + oldsize, name, stbuf, dirbuf.size()); } -void KIOFuseVFS::readdir(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, fuse_file_info *fi) +void KIOFuseVFS::opendir(fuse_req_t req, fuse_ino_t ino, fuse_file_info *fi) { - Q_UNUSED(fi); KIOFuseVFS *that = reinterpret_cast(fuse_req_userdata(req)); auto node = that->nodeForIno(ino); if(!node) @@ -1044,15 +1055,18 @@ return; } - that->awaitChildrenComplete(dirNode, [=](int error){ + node->m_openCount += 1; + + that->awaitChildrenComplete(dirNode, [=, myfi=*fi](int error) mutable { if(error) { fuse_reply_err(req, error); return; } - std::vector dirbuf; - appendDirentry(dirbuf, req, ".", &node->m_stat); + auto dirbuf = std::make_unique>(); + + appendDirentry(*dirbuf, req, ".", &node->m_stat); std::shared_ptr parentNode; if(node->m_parentIno != KIOFuseIno::DeletedRoot) @@ -1060,27 +1074,88 @@ if(!parentNode) parentNode = that->nodeForIno(KIOFuseIno::Root); if(parentNode) - appendDirentry(dirbuf, req, "..", &parentNode->m_stat); + appendDirentry(*dirbuf, req, "..", &parentNode->m_stat); for(auto ino : dirNode->m_childrenInos) { auto child = that->nodeForIno(ino); if(!child) { - qWarning(KIOFUSE_LOG) << "Node" << node->m_nodeName << "references nonexistant child"; + qWarning(KIOFUSE_LOG) << "Node" << node->m_nodeName << "references nonexistent child"; continue; } - appendDirentry(dirbuf, req, qPrintable(child->m_nodeName), &child->m_stat); + appendDirentry(*dirbuf, req, qPrintable(child->m_nodeName), &child->m_stat); } - if(off < off_t(dirbuf.size())) - fuse_reply_buf(req, dirbuf.data() + off, std::min(off_t(size), off_t(dirbuf.size()) - off)); - else - fuse_reply_buf(req, nullptr, 0); + myfi.fh = reinterpret_cast(dirbuf.release()); + + if (!(myfi.flags & O_NOATIME)) + clock_gettime(CLOCK_REALTIME, &node->m_stat.st_atim); + + fuse_reply_open(req, &myfi); }); } +void KIOFuseVFS::readdir(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi) +{ + KIOFuseVFS *that = reinterpret_cast(fuse_req_userdata(req)); + auto node = that->nodeForIno(ino); + if(!node) + { + fuse_reply_err(req, EIO); + return; + } + + auto dirNode = std::dynamic_pointer_cast(node); + if(!dirNode) + { + fuse_reply_err(req, ENOTDIR); + return; + } + + std::vector* dirbuf = reinterpret_cast*>(fi->fh); + if(!dirbuf) + { + fuse_reply_err(req, EIO); + return; + } + + if(off < off_t(dirbuf->size())) + fuse_reply_buf(req, dirbuf->data() + off, std::min(off_t(size), off_t(dirbuf->size()) - off)); + else + fuse_reply_buf(req, nullptr, 0); +} + +void KIOFuseVFS::releasedir(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) +{ + KIOFuseVFS *that = reinterpret_cast(fuse_req_userdata(req)); + auto node = that->nodeForIno(ino); + if(!node) + { + fuse_reply_err(req, EIO); + return; + } + + auto dirNode = std::dynamic_pointer_cast(node); + if(!dirNode) + { + fuse_reply_err(req, ENOTDIR); + return; + } + + node->m_openCount -= 1; + if(std::vector *ptr = reinterpret_cast*>(fi->fh)) + { + delete ptr; + } + else{ + qWarning(KIOFUSE_LOG) << "File handler of node" << node->m_nodeName << "already null"; + } + + fuse_reply_err(req, 0); +} + void KIOFuseVFS::read(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, fuse_file_info *fi) { Q_UNUSED(fi); @@ -1422,7 +1497,7 @@ auto child = nodeForIno(ino); if(!child) { - qWarning(KIOFUSE_LOG) << "Node" << parent->m_nodeName << "references nonexistant child"; + qWarning(KIOFUSE_LOG) << "Node" << parent->m_nodeName << "references nonexistent child"; continue; } @@ -1731,12 +1806,12 @@ attr.st_gid = gr->gr_gid; } - if(entry.contains(KIO::UDSEntry::UDS_LOCAL_PATH) || entry.contains(KIO::UDSEntry::UDS_URL)) + if(entry.contains(KIO::UDSEntry::UDS_LOCAL_PATH) || entry.contains(KIO::UDSEntry::UDS_TARGET_URL)) { // Create as symlink if possible QString target = entry.stringValue(KIO::UDSEntry::UDS_LOCAL_PATH); if(target.isEmpty()) - target = QUrl(entry.stringValue(KIO::UDSEntry::UDS_URL)).toLocalFile(); + target = QUrl(entry.stringValue(KIO::UDSEntry::UDS_TARGET_URL)).toLocalFile(); if(!target.isEmpty()) { @@ -1755,7 +1830,9 @@ { attr.st_mode |= S_IFREG; std::shared_ptr ret = nullptr; - const QUrl nodeUrl = QUrl{entry.stringValue(KIO::UDSEntry::UDS_URL)}; + const QUrl nodeUrl = QUrl{entry.stringValue(KIO::UDSEntry::UDS_TARGET_URL)}; + if(nodeUrl.isEmpty()) + return nullptr; if(m_useFileJob && KProtocolManager::supportsOpening(nodeUrl) && KProtocolManager::supportsTruncating(nodeUrl)) ret = std::make_shared(parentIno, name, attr); else @@ -2238,10 +2315,7 @@ return callback({}, ENOENT); } - QUrl urlWithoutPassword = url; - urlWithoutPassword.setPassword({}); - - qDebug(KIOFUSE_LOG) << "Mounting" << urlWithoutPassword; + qDebug(KIOFUSE_LOG) << "Mounting" << url.toDisplayString(); auto statJob = KIO::stat(url); statJob->setSide(KIO::StatJob::SourceSide); // Be "optimistic" to allow accessing // files over plain HTTP diff -Nru kio-fuse-5.0.0/kiofusevfs.h kio-fuse-5.0.1/kiofusevfs.h --- kio-fuse-5.0.0/kiofusevfs.h 2020-12-27 11:52:28.000000000 +0000 +++ kio-fuse-5.0.1/kiofusevfs.h 2021-03-21 14:14:52.000000000 +0000 @@ -78,8 +78,10 @@ static void open(fuse_req_t req, fuse_ino_t ino, fuse_file_info *fi); static void rename(fuse_req_t req, fuse_ino_t parent, const char *name, fuse_ino_t newparent, const char *newname, unsigned int flags); + static void opendir(fuse_req_t req, fuse_ino_t ino, fuse_file_info *fi); static void readdir(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi); + static void releasedir(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi); static void read(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi); static void write(fuse_req_t req, fuse_ino_t ino, const char *buf, diff -Nru kio-fuse-5.0.0/README kio-fuse-5.0.1/README --- kio-fuse-5.0.0/README 2020-12-27 11:52:28.000000000 +0000 +++ kio-fuse-5.0.1/README 2021-03-21 14:14:52.000000000 +0000 @@ -10,16 +10,29 @@ 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 diff -Nru kio-fuse-5.0.0/tests/CMakeLists.txt kio-fuse-5.0.1/tests/CMakeLists.txt --- kio-fuse-5.0.0/tests/CMakeLists.txt 2020-12-27 11:52:28.000000000 +0000 +++ kio-fuse-5.0.1/tests/CMakeLists.txt 2021-03-21 14:14:52.000000000 +0000 @@ -9,12 +9,12 @@ qt5_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) +target_link_libraries(fileopstest-cache PRIVATE Qt5::Test Qt5::DBus KF5::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) +target_link_libraries(fileopstest-filejob PRIVATE Qt5::Test Qt5::DBus KF5::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 -Nru kio-fuse-5.0.0/tests/fileopstest.cpp kio-fuse-5.0.1/tests/fileopstest.cpp --- kio-fuse-5.0.0/tests/fileopstest.cpp 2020-12-27 11:52:28.000000000 +0000 +++ kio-fuse-5.0.1/tests/fileopstest.cpp 2021-03-21 14:14:52.000000000 +0000 @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -17,6 +18,9 @@ #include #include #include + +#include + #include "kiofuse_interface.h" #include "kiofuseprivate_interface.h" @@ -32,10 +36,12 @@ void testLocalPathToRemoteUrl(); void testLocalFileOps(); void testLocalDirOps(); + void testReaddirOps(); void testCreationOps(); void testRenameOps(); void testDeletionOps(); void testArchiveOps(); + void testManWorkaround(); void testKioErrorMapping(); void testRootLookup(); void testFilenameEscaping(); @@ -394,6 +400,63 @@ QCOMPARE(mirrorEntryList, sourceEntryList); } +void FileOpsTest::testReaddirOps() +{ + QTemporaryDir localDir; + QVERIFY(localDir.isValid()); + + // Mount the temporary dir + QString testDirPath = m_kiofuse_iface.mountUrl(QStringLiteral("file://%1").arg(localDir.path())).value(); + QVERIFY(!testDirPath.isEmpty()); + + // Fill the directory with some files + for(unsigned int i=0; i<=10; i++) + { + QVERIFY(QFile(QStringLiteral("%1/tmpFile%2").arg(testDirPath).arg(i)).open(QIODevice::WriteOnly)); + } + + DIR *testDir = opendir(qPrintable(testDirPath)); + QVERIFY(testDir); + + auto opendirCleanup = qScopeGuard([&](){ closedir(testDir); }); + + QStringList testDirEntryList; + QStringList testDirEntryListUpdated; + + // Get the initial entry list to compare with + struct dirent *pDirent = nullptr; + while((pDirent = readdir(testDir)) != nullptr) + testDirEntryList.push_back(QString::fromUtf8(pDirent->d_name)); + testDirEntryList.sort(); + + // Verify that entries remain same even if we add new or remove existing entries + QVERIFY(QFile::remove(testDirPath + QStringLiteral("/tmpFile1"))); + QVERIFY(QFile(testDirPath + QStringLiteral("/addCaseFile")).open(QIODevice::WriteOnly)); + + rewinddir(testDir); + while((pDirent = readdir(testDir)) != nullptr) + testDirEntryListUpdated.push_back(QString::fromUtf8(pDirent->d_name)); + testDirEntryListUpdated.sort(); + + QCOMPARE(testDirEntryListUpdated, testDirEntryList); + + // Verify that entries remain same even if entries are modified while iterating + testDirEntryListUpdated.clear(); + rewinddir(testDir); + + unsigned int count = 1; + while((pDirent = readdir(testDir)) != nullptr) + { + QVERIFY(QFile(QStringLiteral("%1/iterCaseFile%2").arg(testDirPath).arg(count)).open(QIODevice::WriteOnly)); + + testDirEntryListUpdated.push_back(QString::fromUtf8(pDirent->d_name)); + count++; + } + testDirEntryListUpdated.sort(); + + QCOMPARE(testDirEntryListUpdated, testDirEntryList); +} + void FileOpsTest::testCreationOps() { QTemporaryDir localDir; @@ -583,6 +646,9 @@ void FileOpsTest::testArchiveOps() { + if (!KProtocolInfo::isKnownProtocol(QStringLiteral("tar"))) + QSKIP("Test requires tar protocol to be supported. See README for packages required."); + QString outerpath = QFINDTESTDATA(QStringLiteral("data/outerarchive.tar.gz")); // Mount a file inside the archive @@ -615,6 +681,25 @@ innerfile.close(); } +void FileOpsTest::testManWorkaround() +{ + // The man ioslave 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"))) + QSKIP("Test requires man protocol to be supported. See README for packages required."); + + QDBusPendingReply reply = m_kiofuse_iface.mountUrl(QStringLiteral("man:foo")); + reply.waitForFinished(); + QVERIFY(reply.isError()); + QCOMPARE(reply.error().name(), QStringLiteral("org.kde.KIOFuse.VFS.Error.CannotMount")); + + reply = m_kiofuse_iface.mountUrl(QStringLiteral("man:/")); + reply.waitForFinished(); + QVERIFY(reply.isError()); + QCOMPARE(reply.error().name(), QStringLiteral("org.kde.KIOFuse.VFS.Error.CannotMount")); +} + void FileOpsTest::testKioErrorMapping() { QTemporaryFile localFile; @@ -880,6 +965,9 @@ QCOMPARE(readlink(localDir.filePath(QStringLiteral("symlink"))), localDir.filePath(QStringLiteral("somedir/../somefile"))); + if (!KProtocolInfo::isKnownProtocol(QStringLiteral("tar"))) + QSKIP("Test requires tar protocol to be supported. See README for packages required."); + // Mount something with a different origin QString outerpath = QFINDTESTDATA(QStringLiteral("data/outerarchive.tar.gz")); reply = m_kiofuse_iface.mountUrl(QStringLiteral("tar://%1/outerarchive/").arg(outerpath)).value(); diff -Nru kio-fuse-5.0.0/TODO kio-fuse-5.0.1/TODO --- kio-fuse-5.0.0/TODO 2020-12-27 11:52:28.000000000 +0000 +++ kio-fuse-5.0.1/TODO 2021-03-21 14:14:52.000000000 +0000 @@ -1,6 +1,4 @@ Filesystem features: -- opendir/readdir/releasedir could be more POSIX compliant by increasing the lookup count of - children and storing a copy of childrenInos in fuse_file_info. - Handle more FUSE ops: * link (to allow relinking of deleted nodes only, like O_TMPFILE) * statvfs (?)