aboutsummaryrefslogtreecommitdiffstats
path: root/lib/fuse.c
diff options
context:
space:
mode:
authorBernd Schubert <bernd@bsbernd.com>2025-03-22 23:57:55 +0100
committerBernd Schubert <bernd@bsbernd.com>2025-03-24 09:38:06 +0100
commitf68970cd235a7e14026ca0f6240428bbebe8223b (patch)
treec0a9821396c2f4b4b8a4e3636bf57196a31e85f0 /lib/fuse.c
parent5d1c49e54ca226f144b618a1623117e2a52e7e17 (diff)
downloadlibfuse-f68970cd235a7e14026ca0f6240428bbebe8223b.tar.gz
fuse: Fix want flag conversion
32-bit conn->want flags been left to be ABI compatible to 3.10, even though the so version was changed. The more recent way is to use fuse_set_feature_flag(), which will use conn->want_ext. Given that we now have two flags (want and want_ext), we need to convert and that brought several issues - If the application sets conn->want, that needs to be set into the lower 32 bit of conn->want_ext. As the application might actually unset values, it really has to be a copy and not just 'or' - fixed now. - convert_to_conn_want_ext() actually needs to check for _modified_ conn->want and conn->want_ext - convert_to_conn_want_ext() must consider being called from high and lowlevel interfact, with different want_ext_default and want_default values. It is only a failure, if the application changed both, conn->want and conn->want_ext. This function was failing in issue #1171, because high level fuse_fs_init() was changing values and then lowlevel do_init() was incorrectly failing on that. This also adds a new test (test_want_conversion) and sets values into example/{hello.c,hello_ll.c} Also some more internal users of conn->want are converted to fuse_{set,unset}_feature_flag(). Closes: https://github.com/libfuse/libfuse/issues/1171 Signed-off-by: Bernd Schubert <bernd@bsbernd.com>
Diffstat (limited to 'lib/fuse.c')
-rw-r--r--lib/fuse.c33
1 files changed, 29 insertions, 4 deletions
diff --git a/lib/fuse.c b/lib/fuse.c
index 9335429..136f0c2 100644
--- a/lib/fuse.c
+++ b/lib/fuse.c
@@ -10,6 +10,8 @@
*/
#define _GNU_SOURCE
+#include "fuse.h"
+#include <pthread.h>
#include "fuse_config.h"
#include "fuse_i.h"
@@ -17,7 +19,9 @@
#include "fuse_opt.h"
#include "fuse_misc.h"
#include "fuse_kernel.h"
+#include "util.h"
+#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
@@ -2606,13 +2610,34 @@ void fuse_fs_init(struct fuse_fs *fs, struct fuse_conn_info *conn,
{
fuse_get_context()->private_data = fs->user_data;
if (!fs->op.write_buf)
- conn->want &= ~FUSE_CAP_SPLICE_READ;
+ fuse_unset_feature_flag(conn, FUSE_CAP_SPLICE_READ);
if (!fs->op.lock)
- conn->want &= ~FUSE_CAP_POSIX_LOCKS;
+ fuse_unset_feature_flag(conn, FUSE_CAP_POSIX_LOCKS);
if (!fs->op.flock)
- conn->want &= ~FUSE_CAP_FLOCK_LOCKS;
- if (fs->op.init)
+ fuse_unset_feature_flag(conn, FUSE_CAP_FLOCK_LOCKS);
+ if (fs->op.init) {
+ uint64_t want_ext_default = conn->want_ext;
+ uint32_t want_default = fuse_lower_32_bits(conn->want_ext);
+ int rc;
+
+ conn->want = want_default;
fs->user_data = fs->op.init(conn, cfg);
+
+ rc = convert_to_conn_want_ext(conn, want_ext_default,
+ want_default);
+
+ if (rc != 0) {
+ /*
+ * This is a grave developer error, but
+ * we cannot return an error here, as the function
+ * signature does not allow it.
+ */
+ fuse_log(
+ FUSE_LOG_ERR,
+ "fuse: Aborting due to invalid conn want flags.\n");
+ _exit(EXIT_FAILURE);
+ }
+ }
}
static int fuse_init_intr_signal(int signum, int *installed);