libfuse
test_want_conversion.c
1#define FUSE_USE_VERSION FUSE_MAKE_VERSION(3, 17)
2
3#include "util.h"
4#include "fuse_i.h"
5#include "fuse_lowlevel.h"
6#include <stdio.h>
7#include <assert.h>
8#include <inttypes.h>
9#include <stdbool.h>
10#include <err.h>
11
12static void print_conn_info(const char *prefix, struct fuse_conn_info *conn)
13{
14 struct fuse_session *se = container_of(conn, struct fuse_session, conn);
15
16 printf("%s: want=0x%" PRIx32 " want_ext=0x%" PRIx64
17 " want_default=0x%" PRIx32 " want_ext_default=0x%" PRIx64 "\n",
18 prefix, conn->want, conn->want_ext, se->conn_want,
19 se->conn_want_ext);
20}
21
22static void application_init_old_style(struct fuse_conn_info *conn)
23{
24 /* Simulate application init the old style */
26 conn->want &= ~FUSE_CAP_SPLICE_READ;
27
28 /*
29 * Also use new style API, as that might happen through
30 * fuse_apply_conn_info_opts()
31 */
33}
34
35static void application_init_new_style(struct fuse_conn_info *conn)
36{
37 /* Simulate application init the new style */
41}
42
43static void test_fuse_fs_init(struct fuse_conn_info *conn, bool new_style)
44{
45 /* High-level init */
47
48 if (new_style)
49 application_init_new_style(conn);
50 else
51 application_init_old_style(conn);
52}
53
54static void test_do_init(struct fuse_conn_info *conn, bool new_style)
55{
56 /* Initial setup */
61 conn->capable = fuse_lower_32_bits(conn->capable_ext);
62
66
67 print_conn_info("Initial state", conn);
68
69 int rc;
70
71 test_fuse_fs_init(conn, new_style);
72 print_conn_info("After init", conn);
73
75 assert(rc == 0);
76
77 /* Verify all expected flags are set */
78 assert(!(conn->want_ext & FUSE_CAP_SPLICE_READ));
79 assert(conn->want_ext & FUSE_CAP_SPLICE_WRITE);
80 assert(conn->want_ext & FUSE_CAP_SPLICE_MOVE);
81 assert(conn->want_ext & FUSE_CAP_EXPORT_SUPPORT);
82 assert(conn->want_ext & FUSE_CAP_ASYNC_READ);
83 assert(conn->want_ext & FUSE_CAP_IOCTL_DIR);
84
85 /* Verify no other flags are set */
86 assert(conn->want_ext ==
90
91 print_conn_info("After init", conn);
92}
93
94static void test_want_conversion_basic(void)
95{
96 const struct fuse_lowlevel_ops ops = { 0 };
97 struct fuse_args args = FUSE_ARGS_INIT(0, NULL);
98 struct fuse_session *se;
99 struct fuse_conn_info *conn;
100
101 /* Add the program name to arg[0] */
102 if (fuse_opt_add_arg(&args, "test_signals")) {
103 fprintf(stderr, "Failed to add argument\n");
104 errx(1, "Failed to add argument");
105 }
106
107
108 se = fuse_session_new(&args, &ops, sizeof(ops), NULL);
109 assert(se);
110 conn = &se->conn;
111 printf("\nTesting basic want conversion, old style:\n");
112 test_do_init(conn, false);
114
115 se = fuse_session_new(&args, &ops, sizeof(ops), NULL);
116 assert(se);
117 conn = &se->conn;
118 printf("\nTesting basic want conversion, new style:\n");
119 test_do_init(conn, true);
120 print_conn_info("After init", conn);
122
123 fuse_opt_free_args(&args);
124
125}
126
127static void test_want_conversion_conflict(void)
128{
129 struct fuse_conn_info conn = { 0 };
130 int rc;
131
132 printf("\nTesting want conversion conflict:\n");
133
134 /* Test conflicting values */
135 /* Initialize like fuse_lowlevel.c does */
139 conn.capable = fuse_lower_32_bits(conn.capable_ext);
140 conn.want_ext = conn.capable_ext;
141 conn.want = fuse_lower_32_bits(conn.want_ext);
142 print_conn_info("Test conflict initial", &conn);
143
144 /* Simulate application init modifying capabilities */
145 conn.want_ext |= FUSE_CAP_ATOMIC_O_TRUNC; /* Add new capability */
146 conn.want &= ~FUSE_CAP_SPLICE_READ; /* Remove a capability */
147
149 assert(rc == -EINVAL);
150 print_conn_info("Test conflict after", &conn);
151
152 printf("Want conversion conflict test passed\n");
153}
154
155static void test_want_conversion_high_bits(void)
156{
157 struct fuse_conn_info conn = { 0 };
158 int rc;
159
160 printf("\nTesting want conversion high bits preservation:\n");
161
162 /* Test high bits preservation */
163 conn.want_ext = (1ULL << 33) | FUSE_CAP_ASYNC_READ;
164 conn.want = fuse_lower_32_bits(conn.want_ext);
165 print_conn_info("Test high bits initial", &conn);
166
168 assert(rc == 0);
169 assert(conn.want_ext == ((1ULL << 33) | FUSE_CAP_ASYNC_READ));
170 print_conn_info("Test high bits after", &conn);
171
172 printf("Want conversion high bits test passed\n");
173}
174
175int main(void)
176{
177 test_want_conversion_basic();
178 test_want_conversion_conflict();
179 test_want_conversion_high_bits();
180 return 0;
181}
#define FUSE_CAP_IOCTL_DIR
void fuse_unset_feature_flag(struct fuse_conn_info *conn, uint64_t flag)
int fuse_convert_to_conn_want_ext(struct fuse_conn_info *conn)
bool fuse_set_feature_flag(struct fuse_conn_info *conn, uint64_t flag)
#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
void fuse_session_destroy(struct fuse_session *se)
int fuse_opt_add_arg(struct fuse_args *args, const char *arg)
Definition fuse_opt.c:55
void fuse_opt_free_args(struct fuse_args *args)
Definition fuse_opt.c:34
#define FUSE_ARGS_INIT(argc, argv)
Definition fuse_opt.h:123
uint64_t capable_ext
uint32_t capable
uint64_t want_ext