[network/kio-extras] sftp: sftp: ask a server that refuses permissions only once

Méven Car <[email protected]>
Newsgroups gmane.comp.kde.cvs
Message-ID <[email protected]>
Git commit 866e64354786f89ac154c3cd5948b63306771179 by Méven Car.
Committed on 18/08/2026 at 10:26.
Pushed by meven into branch 'master'.

sftp: ask a server that refuses permissions only once

A server exporting a filesystem that has no permissions of its own, an
e-reader for instance, refuses to set them on every single file written
to it. Every refusal was reported, so copying a folder of two hundred
files put two hundred message boxes on the screen, one per file, while
the files themselves had all been written correctly.

The refusal is a worker warning rather than a job error, so it goes
straight to a message box and none of the skipping CopyJob does applies
to it. There is no Skip All on it and no way to say enough.

Report the first refusal and take it as the answer for the rest of the
connection. That also saves a round trip per file on such a server. A
new connection asks again.

BUG: 524110

M  +10   -1    sftp/kio_sftp.cpp
M  +8    -0    sftp/kio_sftp.h

https://invent.kde.org/network/kio-extras/-/commit/866e64354786f89ac154c3cd5948b63306771179

diff --git a/sftp/kio_sftp.cpp b/sftp/kio_sftp.cpp
index 0c3804dd4..c01f92a03 100644
--- a/sftp/kio_sftp.cpp
+++ b/sftp/kio_sftp.cpp
@@ -1060,6 +1060,10 @@ Result SFTPWorker::openConnectionWithoutCloseOnError()
 
 Result SFTPWorker::openConnection()
 {
+    // Another server, or the same one after it was restarted, may well accept the permissions this
+    // one refused.
+    mCanSetPermissions = true;
+
     const Result result = openConnectionWithoutCloseOnError();
     if (!result.success()) {
         closeConnection();
@@ -1631,9 +1635,14 @@ Result SFTPWorker::sftpPut(const QUrl &url, int permissionsMode, JobFlags flags,
     }
 
     // set final permissions
-    if (permissions.has_value() && !(flags & KIO::Resume)) {
+    // The file was created with the write permission the worker needs on top of the ones asked
+    // for, so this is what takes those away again. A server that refuses is asked once and then
+    // left alone: it will refuse for every file of the copy, and each refusal costs a round trip
+    // and, worse, a message the user has to read and dismiss for every single file.
+    if (permissions.has_value() && !(flags & KIO::Resume) && mCanSetPermissions) {
         qCDebug(KIO_SFTP_LOG) << "Trying to set final permissions of " << dest_orig << " to " << Qt::oct << permsToPosix(permissions.value());
         if (sftp_chmod(mSftp, dest_orig_c.constData(), permsToPosix(permissions.value())) < 0) {
+            mCanSetPermissions = false;
             warning(i18n("Could not change permissions for\n%1", url.toString()));
             return Result::pass();
         }
diff --git a/sftp/kio_sftp.h b/sftp/kio_sftp.h
index 8d724100d..de1490e75 100644
--- a/sftp/kio_sftp.h
+++ b/sftp/kio_sftp.h
@@ -91,6 +91,14 @@ private: // Private variables
     /** True if worker is connected to sftp server. */
     bool mConnected = false;
 
+    /**
+     * False once the server has refused to set the permissions of a file that was just written.
+     * A server exporting a filesystem that has no permissions of its own, an e-reader for example,
+     * refuses every single one of them, so the refusal is reported for the first file and the rest
+     * are written without asking again. True again for a new connection.
+     */
+    bool mCanSetPermissions = true;
+
     /** Host we are connected to. */
     QString mHost;
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.