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