libfuse

test_want_conversion.c
1#include "util.h"
2#include <string.h>
3#define FUSE_USE_VERSION FUSE_MAKE_VERSION(3, 17)
4
5#include "fuse_i.h"
6#include <stdio.h>
7#include <assert.h>
8#include <inttypes.h>
9
10 static 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
16 static void application_init(struct fuse_conn_info *conn)
17{
18 /* Simulate application init */
19 conn->want |= FUSE_CAP_ASYNC_READ;
20 conn->want &= ~FUSE_CAP_SPLICE_READ;
21}
22
23 static void test_fuse_fs_init(struct fuse_conn_info *conn)
24{
25 uint64_t want_ext_default = conn->want_ext;
26 uint32_t want_default = fuse_lower_32_bits(conn->want_ext);
27 int rc;
28
29 /* High-level init */
30 fuse_set_feature_flag(conn, FUSE_CAP_EXPORT_SUPPORT);
31
32 conn->want = want_default;
33
34 application_init(conn);
35
36 rc = convert_to_conn_want_ext(conn, want_ext_default, want_default);
37 assert(rc == 0);
38}
39
40 static void test_do_init(struct fuse_conn_info *conn)
41{
42 /* Initial setup */
43 conn->capable_ext = FUSE_CAP_SPLICE_READ | FUSE_CAP_SPLICE_WRITE |
44 FUSE_CAP_SPLICE_MOVE | FUSE_CAP_POSIX_LOCKS |
45 FUSE_CAP_FLOCK_LOCKS | FUSE_CAP_EXPORT_SUPPORT;
46 conn->capable = fuse_lower_32_bits(conn->capable_ext);
47 conn->want_ext = conn->capable_ext;
48
49 print_conn_info("Initial state", conn);
50
51 uint64_t want_ext_default = conn->want_ext;
52 uint32_t want_default = fuse_lower_32_bits(conn->want_ext);
53 int rc;
54
55 conn->want = want_default;
56 conn->capable = fuse_lower_32_bits(conn->capable_ext);
57
58 test_fuse_fs_init(conn);
59
60 rc = convert_to_conn_want_ext(conn, want_ext_default, want_default);
61 assert(rc == 0);
62
63 /* Verify all expected flags are set */
64 assert(!(conn->want_ext & FUSE_CAP_SPLICE_READ));
65 assert(conn->want_ext & FUSE_CAP_SPLICE_WRITE);
66 assert(conn->want_ext & FUSE_CAP_SPLICE_MOVE);
67 assert(conn->want_ext & FUSE_CAP_POSIX_LOCKS);
68 assert(conn->want_ext & FUSE_CAP_FLOCK_LOCKS);
69 assert(conn->want_ext & FUSE_CAP_EXPORT_SUPPORT);
70 assert(conn->want_ext & FUSE_CAP_ASYNC_READ);
71 /* Verify no other flags are set */
72 assert(conn->want_ext ==
73 (FUSE_CAP_SPLICE_WRITE | FUSE_CAP_SPLICE_MOVE |
74 FUSE_CAP_POSIX_LOCKS | FUSE_CAP_FLOCK_LOCKS |
75 FUSE_CAP_EXPORT_SUPPORT | FUSE_CAP_ASYNC_READ));
76
77 print_conn_info("After init", conn);
78}
79
80 static void test_want_conversion_basic(void)
81{
82 struct fuse_conn_info conn = { 0 };
83
84 printf("\nTesting basic want conversion:\n");
85 test_do_init(&conn);
86 print_conn_info("After init", &conn);
87}
88
89 static void test_want_conversion_conflict(void)
90{
91 struct fuse_conn_info conn = { 0 };
92 int rc;
93
94 printf("\nTesting want conversion conflict:\n");
95
96 /* Test conflicting values */
97 /* Initialize like fuse_lowlevel.c does */
98 conn.capable_ext = FUSE_CAP_SPLICE_READ | FUSE_CAP_SPLICE_WRITE |
99 FUSE_CAP_SPLICE_MOVE | FUSE_CAP_POSIX_LOCKS |
100 FUSE_CAP_FLOCK_LOCKS;
101 conn.capable = fuse_lower_32_bits(conn.capable_ext);
102 conn.want_ext = conn.capable_ext;
103 conn.want = fuse_lower_32_bits(conn.want_ext);
104 print_conn_info("Test conflict initial", &conn);
105
106 /* Initialize default values like in basic test */
107 uint64_t want_ext_default_ll = conn.want_ext;
108 uint32_t want_default_ll = fuse_lower_32_bits(want_ext_default_ll);
109
110 /* Simulate application init modifying capabilities */
111 conn.want_ext |= FUSE_CAP_ATOMIC_O_TRUNC; /* Add new capability */
112 conn.want &= ~FUSE_CAP_SPLICE_READ; /* Remove a capability */
113
114 rc = convert_to_conn_want_ext(&conn, want_ext_default_ll,
115 want_default_ll);
116 assert(rc == -EINVAL);
117 print_conn_info("Test conflict after", &conn);
118
119 printf("Want conversion conflict test passed\n");
120}
121
122 static void test_want_conversion_high_bits(void)
123{
124 struct fuse_conn_info conn = { 0 };
125 int rc;
126
127 printf("\nTesting want conversion high bits preservation:\n");
128
129 /* Test high bits preservation */
130 conn.want_ext = (1ULL << 33) | FUSE_CAP_ASYNC_READ;
131 conn.want = fuse_lower_32_bits(conn.want_ext);
132 print_conn_info("Test high bits initial", &conn);
133
134 uint64_t want_ext_default_ll = conn.want_ext;
135 uint32_t want_default_ll = fuse_lower_32_bits(want_ext_default_ll);
136
137 rc = convert_to_conn_want_ext(&conn, want_ext_default_ll,
138 want_default_ll);
139 assert(rc == 0);
140 assert(conn.want_ext == ((1ULL << 33) | FUSE_CAP_ASYNC_READ));
141 print_conn_info("Test high bits after", &conn);
142
143 printf("Want conversion high bits test passed\n");
144}
145
146 int main(void)
147{
148 test_want_conversion_basic();
149 test_want_conversion_conflict();
150 test_want_conversion_high_bits();
151 return 0;
152}
FUSE_CAP_SPLICE_READ
#define FUSE_CAP_SPLICE_READ
Definition fuse_common.h:249
FUSE_CAP_ATOMIC_O_TRUNC
#define FUSE_CAP_ATOMIC_O_TRUNC
Definition fuse_common.h:204
FUSE_CAP_ASYNC_READ
#define FUSE_CAP_ASYNC_READ
Definition fuse_common.h:187
FUSE_CAP_SPLICE_WRITE
#define FUSE_CAP_SPLICE_WRITE
Definition fuse_common.h:232
FUSE_CAP_EXPORT_SUPPORT
#define FUSE_CAP_EXPORT_SUPPORT
Definition fuse_common.h:216
FUSE_CAP_POSIX_LOCKS
#define FUSE_CAP_POSIX_LOCKS
Definition fuse_common.h:195
FUSE_CAP_SPLICE_MOVE
#define FUSE_CAP_SPLICE_MOVE
Definition fuse_common.h:240
FUSE_CAP_FLOCK_LOCKS
#define FUSE_CAP_FLOCK_LOCKS
Definition fuse_common.h:262
fuse_conn_info
Definition fuse_common.h:555
fuse_conn_info::want
uint32_t want
Definition fuse_common.h:607
fuse_conn_info::capable_ext
uint64_t capable_ext
Definition fuse_common.h:703
fuse_conn_info::capable
uint32_t capable
Definition fuse_common.h:595
fuse_conn_info::want_ext
uint64_t want_ext
Definition fuse_common.h:713