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