On Sat Oct 31, 2026 at 10:40:24AM -0300, Leonardo Santagostini wrote:
> Hi,
> 
> On OpenBSD 8.0 with kf6-kio-6.30.0, moving any file to the trash
> fails with "Access denied to <file>", both from Dolphin and with
> "kioclient move FILE trash:/". Deleting the same file works.
> 
> kio_trash checks write access in TrashImpl::createInfo() with
> faccessat(..., W_OK, AT_SYMLINK_NOFOLLOW). Our faccessat(2) only
> accepts 0 or AT_EACCESS as flag and returns EINVAL, which kio_trash
> reports as ERR_ACCESS_DENIED for every file:
> 
> kioworker CALL faccessat(AT_FDCWD,0x4ff41a1c10,0x2<W_OK>,
> 0x2<AT_SYMLINK_NOFOLLOW>)
> kioworker RET faccessat -1 errno 22 Invalid argument
> 
> The diff below retries without the flag when faccessat() fails with
> EINVAL, and skips the check for symlinks, whose own mode bits are
> meaningless (moving them depends on the parent directory). Other
> systems are unaffected, since the first call succeeds there.
> 
> The code is identical in 6.31.0, so the diff is against -current.
> I tested the same change on 8.0 by building kio_trash from the
> 6.30.0 sources and loading it instead of the packaged one: files are
> moved to the trash, show up under trash:/ with their .trashinfo, and
> can be removed from there. I have not built the port itself.
> 
> Full disclosure: I found the cause and wrote this diff with the help
> of an AI assistant. I reviewed it and tested
> it on my machine as described above.
> 
> The diff is inline below and also attached as kio-trash.diff, in case
> my mail client mangles the inline copy.
> 
> Comments, OK?
> 
> Index: Makefile
> --- Makefile
> +++ Makefile
> @@ -1,5 +1,6 @@
> COMMENT = network transparent access to files and data in KDE
> DISTNAME = kio-${VERSION}
> +REVISION = 0
> 
> SHARED_LIBS += KF6KIOCore 2.5 # 0.0
> SHARED_LIBS += KF6KIOFileWidgets 0.2 # 0.0
> Index: patches/patch-src_kioworkers_trash_trashimpl_cpp
> --- patches/patch-src_kioworkers_trash_trashimpl_cpp
> +++ patches/patch-src_kioworkers_trash_trashimpl_cpp
> @@ -0,0 +1,21 @@
> +faccessat(2) only accepts 0 or AT_EACCESS as flag. AT_SYMLINK_NOFOLLOW
> +returns EINVAL, and kio_trash turned that into "Access denied" for
> +every file, so moving anything to the trash always failed.
> +
> +Index: src/kioworkers/trash/trashimpl.cpp
> +--- src/kioworkers/trash/trashimpl.cpp.orig
> ++++ src/kioworkers/trash/trashimpl.cpp
> +@@ -246,7 +246,12 @@ bool TrashImpl::createInfo(const QString
> + }
> + return false;
> + }
> +- if (::faccessat(AT_FDCWD, origPath_c.constData(), W_OK,
> AT_SYMLINK_NOFOLLOW) == -1) {
> ++ int accessRet = ::faccessat(AT_FDCWD, origPath_c.constData(), W_OK,
> AT_SYMLINK_NOFOLLOW);
> ++ if (accessRet == -1 && errno == EINVAL) {
> ++ // Some systems (e.g. OpenBSD) only accept AT_EACCESS as flag for 
> faccessat()
> ++ accessRet = S_ISLNK(buff_src.st_mode) ? 0 : ::faccessat(AT_FDCWD,
> origPath_c.constData(), W_OK, 0);
> ++ }
> ++ if (accessRet == -1) {
> + error(KIO::ERR_ACCESS_DENIED, origPath);
> + return false;
> + }

> Index: Makefile
> --- Makefile
> +++ Makefile
> @@ -1,5 +1,6 @@
>  COMMENT =    network transparent access to files and data in KDE
>  DISTNAME =   kio-${VERSION}
> +REVISION =   0
>  
>  SHARED_LIBS +=  KF6KIOCore                2.5 # 0.0
>  SHARED_LIBS +=  KF6KIOFileWidgets         0.2 # 0.0
> Index: patches/patch-src_kioworkers_trash_trashimpl_cpp
> --- patches/patch-src_kioworkers_trash_trashimpl_cpp
> +++ patches/patch-src_kioworkers_trash_trashimpl_cpp
> @@ -0,0 +1,21 @@
> +faccessat(2) only accepts 0 or AT_EACCESS as flag. AT_SYMLINK_NOFOLLOW
> +returns EINVAL, and kio_trash turned that into "Access denied" for
> +every file, so moving anything to the trash always failed.
> +
> +Index: src/kioworkers/trash/trashimpl.cpp
> +--- src/kioworkers/trash/trashimpl.cpp.orig
> ++++ src/kioworkers/trash/trashimpl.cpp
> +@@ -246,7 +246,12 @@ bool TrashImpl::createInfo(const QString
> +         }
> +         return false;
> +     }
> +-    if (::faccessat(AT_FDCWD, origPath_c.constData(), W_OK, 
> AT_SYMLINK_NOFOLLOW) == -1) {
> ++    int accessRet = ::faccessat(AT_FDCWD, origPath_c.constData(), W_OK, 
> AT_SYMLINK_NOFOLLOW);
> ++    if (accessRet == -1 && errno == EINVAL) {
> ++        // Some systems (e.g. OpenBSD) only accept AT_EACCESS as flag for 
> faccessat()
> ++        accessRet = S_ISLNK(buff_src.st_mode) ? 0 : ::faccessat(AT_FDCWD, 
> origPath_c.constData(), W_OK, 0);
> ++    }
> ++    if (accessRet == -1) {
> +         error(KIO::ERR_ACCESS_DENIED, origPath);
> +         return false;
> +     }


Big thanks Leonardo (this was on my list), for raising this issue and
finding the right place to fix it.

Your analysis is also correct: our faccessat doesn't support
AT_SYMLINK_NOFOLLOW. I think the correct fix simply looks like this.

I've tested it and can confirm that it works, if there are no
objections, I'll commit it.

Rafael

Index: Makefile
===================================================================
RCS file: /cvs/ports/devel/kf6/kio/Makefile,v
diff -u -p -r1.21 Makefile
--- Makefile    15 Oct 2026 06:52:01 -0000      1.21
+++ Makefile    31 Oct 2026 20:39:22 -0000
@@ -1,5 +1,6 @@
 COMMENT =      network transparent access to files and data in KDE
 DISTNAME =     kio-${VERSION}
+REVISION =     0
 
 SHARED_LIBS +=  KF6KIOCore                2.5 # 0.0
 SHARED_LIBS +=  KF6KIOFileWidgets         0.2 # 0.0
Index: patches/patch-src_kioworkers_trash_trashimpl_cpp
===================================================================
RCS file: patches/patch-src_kioworkers_trash_trashimpl_cpp
diff -N patches/patch-src_kioworkers_trash_trashimpl_cpp
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ patches/patch-src_kioworkers_trash_trashimpl_cpp    31 Oct 2026 20:39:22 
-0000
@@ -0,0 +1,12 @@
+Index: src/kioworkers/trash/trashimpl.cpp
+--- src/kioworkers/trash/trashimpl.cpp.orig
++++ src/kioworkers/trash/trashimpl.cpp
+@@ -246,7 +246,7 @@ bool TrashImpl::createInfo(const QString &origPath, qu
+         }
+         return false;
+     }
+-    if (::faccessat(AT_FDCWD, origPath_c.constData(), W_OK, 
AT_SYMLINK_NOFOLLOW) == -1) {
++    if (!S_ISLNK(buff_src.st_mode) && ::faccessat(AT_FDCWD, 
origPath_c.constData(), W_OK, 0) == -1) {
+         error(KIO::ERR_ACCESS_DENIED, origPath);
+         return false;
+     }

Reply via email to