libfuse: fuse-3.18.1/test/test_want_conversion.c Source File

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 */
25 conn->want |= FUSE_CAP_ASYNC_READ;
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 */
32 fuse_set_feature_flag(conn, FUSE_CAP_IOCTL_DIR);
33}
34
35static void application_init_new_style(struct fuse_conn_info *conn)
36{
37 /* Simulate application init the new style */
38 fuse_set_feature_flag(conn, FUSE_CAP_ASYNC_READ);
39 fuse_set_feature_flag(conn, FUSE_CAP_IOCTL_DIR);
40 fuse_unset_feature_flag(conn, FUSE_CAP_SPLICE_READ);
41}
42
43static void test_fuse_fs_init(struct fuse_conn_info *conn, bool new_style)
44{
45 /* High-level init */
46 fuse_set_feature_flag(conn, FUSE_CAP_EXPORT_SUPPORT);
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 */
57 conn->capable_ext = FUSE_CAP_SPLICE_READ | FUSE_CAP_SPLICE_WRITE |
58 FUSE_CAP_SPLICE_MOVE | FUSE_CAP_POSIX_LOCKS |
59 FUSE_CAP_FLOCK_LOCKS | FUSE_CAP_EXPORT_SUPPORT |
60 FUSE_CAP_ASYNC_READ | FUSE_CAP_IOCTL_DIR;
61 conn->capable = fuse_lower_32_bits(conn->capable_ext);
62
63 fuse_set_feature_flag(conn, FUSE_CAP_SPLICE_READ |
64 FUSE_CAP_SPLICE_WRITE |
65 FUSE_CAP_SPLICE_MOVE);
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
74 rc = fuse_convert_to_conn_want_ext(conn);
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 ==
87 (FUSE_CAP_SPLICE_WRITE | FUSE_CAP_SPLICE_MOVE |
88 FUSE_CAP_EXPORT_SUPPORT | FUSE_CAP_ASYNC_READ |
89 FUSE_CAP_IOCTL_DIR));
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);
113 fuse_session_destroy(se);
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);
121 fuse_session_destroy(se);
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 */
136 conn.capable_ext = FUSE_CAP_SPLICE_READ | FUSE_CAP_SPLICE_WRITE |
137 FUSE_CAP_SPLICE_MOVE | FUSE_CAP_POSIX_LOCKS |
138 FUSE_CAP_FLOCK_LOCKS;
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
148 rc = fuse_convert_to_conn_want_ext(&conn);
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
167 rc = fuse_convert_to_conn_want_ext(&conn);
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}
FUSE_CAP_IOCTL_DIR
#define FUSE_CAP_IOCTL_DIR
Definition fuse_common.h:259
fuse_unset_feature_flag
void fuse_unset_feature_flag(struct fuse_conn_info *conn, uint64_t flag)
Definition fuse_lowlevel.c:2050
fuse_convert_to_conn_want_ext
int fuse_convert_to_conn_want_ext(struct fuse_conn_info *conn)
Definition fuse_lowlevel.c:2000
fuse_set_feature_flag
bool fuse_set_feature_flag(struct fuse_conn_info *conn, uint64_t flag)
Definition fuse_lowlevel.c:2035
FUSE_CAP_SPLICE_READ
#define FUSE_CAP_SPLICE_READ
Definition fuse_common.h:239
FUSE_CAP_ATOMIC_O_TRUNC
#define FUSE_CAP_ATOMIC_O_TRUNC
Definition fuse_common.h:194
FUSE_CAP_ASYNC_READ
#define FUSE_CAP_ASYNC_READ
Definition fuse_common.h:177
FUSE_CAP_SPLICE_WRITE
#define FUSE_CAP_SPLICE_WRITE
Definition fuse_common.h:222
FUSE_CAP_EXPORT_SUPPORT
#define FUSE_CAP_EXPORT_SUPPORT
Definition fuse_common.h:206
FUSE_CAP_POSIX_LOCKS
#define FUSE_CAP_POSIX_LOCKS
Definition fuse_common.h:185
FUSE_CAP_SPLICE_MOVE
#define FUSE_CAP_SPLICE_MOVE
Definition fuse_common.h:230
FUSE_CAP_FLOCK_LOCKS
#define FUSE_CAP_FLOCK_LOCKS
Definition fuse_common.h:252
fuse_session_destroy
void fuse_session_destroy(struct fuse_session *se)
Definition fuse_lowlevel.c:3010
fuse_opt_add_arg
int fuse_opt_add_arg(struct fuse_args *args, const char *arg)
Definition fuse_opt.c:55
fuse_opt_free_args
void fuse_opt_free_args(struct fuse_args *args)
Definition fuse_opt.c:34
FUSE_ARGS_INIT
#define FUSE_ARGS_INIT(argc, argv)
Definition fuse_opt.h:123
fuse_args
Definition fuse_opt.h:109
fuse_conn_info
Definition fuse_common.h:538
fuse_conn_info::want
uint32_t want
Definition fuse_common.h:590
fuse_conn_info::capable_ext
uint64_t capable_ext
Definition fuse_common.h:686
fuse_conn_info::capable
uint32_t capable
Definition fuse_common.h:578
fuse_conn_info::want_ext
uint64_t want_ext
Definition fuse_common.h:696
fuse_lowlevel_ops
Definition fuse_lowlevel.h:206