libfuse
test_want_conversion.c
1#include "util.h"
2#define FUSE_USE_VERSION FUSE_MAKE_VERSION(3, 17)
3
4#include "fuse_i.h"
5#include <stdio.h>
6#include <assert.h>
7#include <inttypes.h>
8#include <stdbool.h>
9
10static void print_conn_info(const char *prefix, struct fuse_conn_info *conn)
11{
12 printf("%s: want=0x%" PRIx32 " want_ext=0x%" PRIx64 "\n", prefix,
13 conn->want, conn->want_ext);
14}
15
16static void application_init_old_style(struct fuse_conn_info *conn)
17{
18 /* Simulate application init the old style */
20 conn->want &= ~FUSE_CAP_SPLICE_READ;
21}
22
23static void application_init_new_style(struct fuse_conn_info *conn)
24{
25 /* Simulate application init the new style */
26 fuse_set_feature_flag(conn, FUSE_CAP_ASYNC_READ);
27 fuse_unset_feature_flag(conn, FUSE_CAP_SPLICE_READ);
28}
29
30static void test_fuse_fs_init(struct fuse_conn_info *conn, bool new_style)
31{
32 uint64_t want_ext_default = conn->want_ext;
33 uint32_t want_default = fuse_lower_32_bits(conn->want_ext);
34 int rc;
35
36 /* High-level init */
37 fuse_set_feature_flag(conn, FUSE_CAP_EXPORT_SUPPORT);
38
39 conn->want = want_default;
40
41 if (new_style)
42 application_init_new_style(conn);
43 else
44 application_init_old_style(conn);
45
46 rc = convert_to_conn_want_ext(conn, want_ext_default, want_default);
47 assert(rc == 0);
48}
49
50static void test_do_init(struct fuse_conn_info *conn, bool new_style)
51{
52 /* Initial setup */
57 conn->capable = fuse_lower_32_bits(conn->capable_ext);
58 conn->want_ext = conn->capable_ext;
59
60 print_conn_info("Initial state", conn);
61
62 uint64_t want_ext_default = conn->want_ext;
63 uint32_t want_default = fuse_lower_32_bits(conn->want_ext);
64 int rc;
65
66 conn->want = want_default;
67 conn->capable = fuse_lower_32_bits(conn->capable_ext);
68
69 test_fuse_fs_init(conn, new_style);
70
71 rc = convert_to_conn_want_ext(conn, want_ext_default, want_default);
72 assert(rc == 0);
73
74 /* Verify all expected flags are set */
75 assert(!(conn->want_ext & FUSE_CAP_SPLICE_READ));
76 assert(conn->want_ext & FUSE_CAP_SPLICE_WRITE);
77 assert(conn->want_ext & FUSE_CAP_SPLICE_MOVE);
78 assert(conn->want_ext & FUSE_CAP_POSIX_LOCKS);
79 assert(conn->want_ext & FUSE_CAP_FLOCK_LOCKS);
80 assert(conn->want_ext & FUSE_CAP_EXPORT_SUPPORT);
81 assert(conn->want_ext & FUSE_CAP_ASYNC_READ);
82 /* Verify no other flags are set */
83 assert(conn->want_ext ==
87
88 print_conn_info("After init", conn);
89}
90
91static void test_want_conversion_basic(void)
92{
93 struct fuse_conn_info conn = { 0 };
94
95 printf("\nTesting basic want conversion:\n");
96 test_do_init(&conn, false);
97 test_do_init(&conn, true);
98 print_conn_info("After init", &conn);
99}
100
101static void test_want_conversion_conflict(void)
102{
103 struct fuse_conn_info conn = { 0 };
104 int rc;
105
106 printf("\nTesting want conversion conflict:\n");
107
108 /* Test conflicting values */
109 /* Initialize like fuse_lowlevel.c does */
113 conn.capable = fuse_lower_32_bits(conn.capable_ext);
114 conn.want_ext = conn.capable_ext;
115 conn.want = fuse_lower_32_bits(conn.want_ext);
116 print_conn_info("Test conflict initial", &conn);
117
118 /* Initialize default values like in basic test */
119 uint64_t want_ext_default_ll = conn.want_ext;
120 uint32_t want_default_ll = fuse_lower_32_bits(want_ext_default_ll);
121
122 /* Simulate application init modifying capabilities */
123 conn.want_ext |= FUSE_CAP_ATOMIC_O_TRUNC; /* Add new capability */
124 conn.want &= ~FUSE_CAP_SPLICE_READ; /* Remove a capability */
125
126 rc = convert_to_conn_want_ext(&conn, want_ext_default_ll,
127 want_default_ll);
128 assert(rc == -EINVAL);
129 print_conn_info("Test conflict after", &conn);
130
131 printf("Want conversion conflict test passed\n");
132}
133
134static void test_want_conversion_high_bits(void)
135{
136 struct fuse_conn_info conn = { 0 };
137 int rc;
138
139 printf("\nTesting want conversion high bits preservation:\n");
140
141 /* Test high bits preservation */
142 conn.want_ext = (1ULL << 33) | FUSE_CAP_ASYNC_READ;
143 conn.want = fuse_lower_32_bits(conn.want_ext);
144 print_conn_info("Test high bits initial", &conn);
145
146 uint64_t want_ext_default_ll = conn.want_ext;
147 uint32_t want_default_ll = fuse_lower_32_bits(want_ext_default_ll);
148
149 rc = convert_to_conn_want_ext(&conn, want_ext_default_ll,
150 want_default_ll);
151 assert(rc == 0);
152 assert(conn.want_ext == ((1ULL << 33) | FUSE_CAP_ASYNC_READ));
153 print_conn_info("Test high bits after", &conn);
154
155 printf("Want conversion high bits test passed\n");
156}
157
158int main(void)
159{
160 test_want_conversion_basic();
161 test_want_conversion_conflict();
162 test_want_conversion_high_bits();
163 return 0;
164}
#define FUSE_CAP_SPLICE_READ
#define FUSE_CAP_ATOMIC_O_TRUNC
#define FUSE_CAP_ASYNC_READ
#define FUSE_CAP_SPLICE_WRITE
#define FUSE_CAP_EXPORT_SUPPORT
#define FUSE_CAP_POSIX_LOCKS
#define FUSE_CAP_SPLICE_MOVE
#define FUSE_CAP_FLOCK_LOCKS
uint64_t capable_ext
uint32_t capable
uint64_t want_ext