aboutsummaryrefslogtreecommitdiffstats
path: root/lib/fuse_lowlevel.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 10:29:15 +0100
commitf52f71df3373185c4d18414aad57c4e8995a4393 (patch)
treec29e5167670efc2d399e00cece46fc03e62b0c20 /lib/fuse_lowlevel.c
parentcdad7b6001036f1a33bddab59558eec099bcb278 (diff)
downloadlibfuse-f52f71df3373185c4d18414aad57c4e8995a4393.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> (cherry picked from commit f68970cd235a7e14026ca0f6240428bbebe8223b)
Diffstat (limited to 'lib/fuse_lowlevel.c')
-rw-r--r--lib/fuse_lowlevel.c30
1 files changed, 7 insertions, 23 deletions
diff --git a/lib/fuse_lowlevel.c b/lib/fuse_lowlevel.c
index d650944..c22b4a2 100644
--- a/lib/fuse_lowlevel.c
+++ b/lib/fuse_lowlevel.c
@@ -9,7 +9,6 @@
See the file COPYING.LIB
*/
-#include <stdbool.h>
#define _GNU_SOURCE
#include "fuse_config.h"
@@ -20,6 +19,8 @@
#include "mount_util.h"
#include "util.h"
+#include <stdint.h>
+#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
@@ -1997,25 +1998,6 @@ static bool want_flags_valid(uint64_t capable, uint64_t want)
return true;
}
-/**
- * Get the wanted capability flags, converting from old format if necessary
- */
-static inline int convert_to_conn_want_ext(struct fuse_conn_info *conn,
- uint64_t want_ext_default)
-{
- /* Convert want to want_ext if necessary */
- if (conn->want != 0) {
- if (conn->want_ext != want_ext_default) {
- fuse_log(FUSE_LOG_ERR,
- "fuse: both 'want' and 'want_ext' are set\n");
- return -EINVAL;
- }
- conn->want_ext |= conn->want;
- }
-
- return 0;
-}
-
/* Prevent bogus data races (bogus since "init" is called before
* multi-threading becomes relevant */
static __attribute__((no_sanitize("thread")))
@@ -2177,11 +2159,12 @@ void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
se->got_init = 1;
if (se->op.init) {
uint64_t want_ext_default = se->conn.want_ext;
+ uint32_t want_default = fuse_lower_32_bits(se->conn.want_ext);
int rc;
// Apply the first 32 bits of capable_ext to capable
- se->conn.capable =
- (uint32_t)(se->conn.capable_ext & 0xFFFFFFFF);
+ se->conn.capable = fuse_lower_32_bits(se->conn.capable_ext);
+ se->conn.want = want_default;
se->op.init(se->userdata, &se->conn);
@@ -2190,7 +2173,8 @@ void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
* se->conn.want_ext
* Userspace might still use conn.want - we need to convert it
*/
- rc = convert_to_conn_want_ext(&se->conn, want_ext_default);
+ rc = convert_to_conn_want_ext(&se->conn, want_ext_default,
+ want_default);
if (rc != 0) {
fuse_reply_err(req, EPROTO);
se->error = -EPROTO;