xref: /aosp_15_r20/external/liburing/test/xattr.c (revision 25da2bea747f3a93b4c30fd9708b0618ef55a0e6)
1 #include <assert.h>
2 #include <fcntl.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <sys/xattr.h>
7 #include <unistd.h>
8 
9 #include "helpers.h"
10 #include "liburing.h"
11 
12 static int no_xattr;
13 
14 /* Define constants. */
15 #define XATTR_SIZE  255
16 #define QUEUE_DEPTH 32
17 
18 #define FILENAME    "xattr.test"
19 #define KEY1        "user.val1"
20 #define KEY2        "user.val2"
21 #define VALUE1      "value1"
22 #define VALUE2      "value2-a-lot-longer"
23 
24 
25 /* Call fsetxattr. */
io_uring_fsetxattr(struct io_uring * ring,int fd,const char * name,const void * value,size_t size,int flags)26 static int io_uring_fsetxattr(struct io_uring *ring, int fd, const char *name,
27 			      const void *value, size_t size, int flags)
28 {
29 	struct io_uring_sqe *sqe;
30 	struct io_uring_cqe *cqe;
31 	int ret;
32 
33 	sqe = io_uring_get_sqe(ring);
34 	if (!sqe) {
35 		fprintf(stderr, "Error cannot get sqe\n");
36 		return -1;
37 	}
38 
39 	io_uring_prep_fsetxattr(sqe, fd, name, value, flags, size);
40 
41 	ret = io_uring_submit(ring);
42 	if (ret != 1) {
43 		fprintf(stderr, "Error io_uring_submit_and_wait: ret=%d\n", ret);
44 		return -1;
45 	}
46 
47 	ret = io_uring_wait_cqe(ring, &cqe);
48 	if (ret) {
49 		fprintf(stderr, "Error io_uring_wait_cqe: ret=%d\n", ret);
50 		return -1;
51 	}
52 
53 	ret = cqe->res;
54 	if (ret == -EINVAL)
55 		no_xattr = 1;
56 	io_uring_cqe_seen(ring, cqe);
57 
58 	return ret;
59 }
60 
61 /* Submit fgetxattr request. */
io_uring_fgetxattr(struct io_uring * ring,int fd,const char * name,void * value,size_t size)62 static int io_uring_fgetxattr(struct io_uring *ring, int fd, const char *name,
63 			      void *value, size_t size)
64 {
65 	struct io_uring_sqe *sqe;
66 	struct io_uring_cqe *cqe;
67 	int ret;
68 
69 	sqe = io_uring_get_sqe(ring);
70 	if (!sqe) {
71 		fprintf(stderr, "Error cannot get sqe\n");
72 		return -1;
73 	}
74 
75 	io_uring_prep_fgetxattr(sqe, fd, name, value, size);
76 
77 	ret = io_uring_submit(ring);
78 	if (ret != 1) {
79 		fprintf(stderr, "Error io_uring_submit_and_wait: ret=%d\n", ret);
80 		return -1;
81 	}
82 
83 	ret = io_uring_wait_cqe(ring, &cqe);
84 	if (ret) {
85 		fprintf(stderr, "Error io_uring_wait_cqe: ret=%d\n", ret);
86 		return -1;
87 	}
88 
89 	ret = cqe->res;
90 	if (ret == -1) {
91 		fprintf(stderr, "Error couldn'tget value\n");
92 		return -1;
93 	}
94 
95 	io_uring_cqe_seen(ring, cqe);
96 	return ret;
97 }
98 
99 /* Call setxattr. */
io_uring_setxattr(struct io_uring * ring,const char * path,const char * name,const void * value,size_t size,int flags)100 static int io_uring_setxattr(struct io_uring *ring, const char *path,
101 			     const char *name, const void *value, size_t size,
102 			     int flags)
103 {
104 	struct io_uring_sqe *sqe;
105 	struct io_uring_cqe *cqe;
106 	int ret;
107 
108 	sqe = io_uring_get_sqe(ring);
109 	if (!sqe) {
110 		fprintf(stderr, "Error cannot get sqe\n");
111 		return -1;
112 	}
113 
114 	io_uring_prep_setxattr(sqe, name, value, path, flags, size);
115 
116 	ret = io_uring_submit_and_wait(ring, 1);
117 	if (ret != 1) {
118 		fprintf(stderr, "Error io_uring_submit_and_wait: ret=%d\n", ret);
119 		return -1;
120 	}
121 
122 	ret = io_uring_wait_cqe(ring, &cqe);
123 	if (ret) {
124 		fprintf(stderr, "Error io_uring_wait_cqe: ret=%d\n", ret);
125 		return -1;
126 	}
127 
128 	ret = cqe->res;
129 	io_uring_cqe_seen(ring, cqe);
130 
131 	return ret;
132 }
133 
134 /* Submit getxattr request. */
io_uring_getxattr(struct io_uring * ring,const char * path,const char * name,void * value,size_t size)135 static int io_uring_getxattr(struct io_uring *ring, const char *path,
136 			     const char *name, void *value, size_t size)
137 {
138 	struct io_uring_sqe *sqe;
139 	struct io_uring_cqe *cqe;
140 	int ret;
141 
142 	sqe = io_uring_get_sqe(ring);
143 	if (!sqe) {
144 		fprintf(stderr, "Error cannot get sqe\n");
145 		return -1;
146 	}
147 
148 	io_uring_prep_getxattr(sqe, name, value, path, size);
149 
150 	ret = io_uring_submit(ring);
151 	if (ret != 1) {
152 		fprintf(stderr, "Error io_uring_submit_and_wait: ret=%d\n", ret);
153 		return -1;
154 	}
155 
156 	ret = io_uring_wait_cqe(ring, &cqe);
157 	if (ret) {
158 		fprintf(stderr, "Error io_uring_wait_cqe: ret=%d\n", ret);
159 		return -1;
160 	}
161 
162 	ret = cqe->res;
163 	if (ret == -1) {
164 		fprintf(stderr, "Error couldn'tget value\n");
165 		return -1;
166 	}
167 
168 	io_uring_cqe_seen(ring, cqe);
169 	return ret;
170 }
171 
172 /* Test driver for fsetxattr and fgetxattr. */
test_fxattr(void)173 static int test_fxattr(void)
174 {
175 	int rc = 0;
176 	size_t value_len;
177 	struct io_uring ring;
178 	char value[XATTR_SIZE];
179 
180 	/* Init io-uring queue. */
181 	int ret = io_uring_queue_init(QUEUE_DEPTH, &ring, 0);
182 	if (ret) {
183 		fprintf(stderr, "child: ring setup failed: %d\n", ret);
184 		return -1;
185 	}
186 
187 	/* Create the test file. */
188 	int fd = open(FILENAME, O_CREAT | O_RDWR, 0644);
189 	if (fd < 0) {
190 		fprintf(stderr, "Error: cannot open file: ret=%d\n", fd);
191 		return -1;
192 	}
193 
194 	/* Test writing attributes. */
195 	if (io_uring_fsetxattr(&ring, fd, KEY1, VALUE1, strlen(VALUE1), 0) < 0) {
196 		if (no_xattr) {
197 			fprintf(stdout, "No xattr support, skipping\n");
198 			goto Exit;
199 		}
200 		fprintf(stderr, "Error fsetxattr cannot write key1\n");
201 		rc = -1;
202 		goto Exit;
203 	}
204 
205 	if (io_uring_fsetxattr(&ring, fd, KEY2, VALUE2, strlen(VALUE2), 0) < 0) {
206 		fprintf(stderr, "Error fsetxattr cannot write key1\n");
207 		rc = -1;
208 		goto Exit;
209 	}
210 
211 	/* Test reading attributes. */
212 	value_len = io_uring_fgetxattr(&ring, fd, KEY1, value, XATTR_SIZE);
213 	if (value_len != strlen(value) || strncmp(value, VALUE1, value_len)) {
214 		fprintf(stderr, "Error: fgetxattr expected value: %s, returned value: %s\n", VALUE1, value);
215 		rc = -1;
216 		goto Exit;
217 	}
218 
219 	value_len = io_uring_fgetxattr(&ring, fd, KEY2, value, XATTR_SIZE);
220 	if (value_len != strlen(value)|| strncmp(value, VALUE2, value_len)) {
221 		fprintf(stderr, "Error: fgetxattr expected value: %s, returned value: %s\n", VALUE2, value);
222 		rc = -1;
223 		goto Exit;
224 	}
225 
226 	/* Cleanup. */
227 Exit:
228 	close(fd);
229 	unlink(FILENAME);
230 
231 	io_uring_queue_exit(&ring);
232 
233 	return rc;
234 }
235 
236 /* Test driver for setxattr and getxattr. */
test_xattr(void)237 static int test_xattr(void)
238 {
239 	int rc = 0;
240 	int value_len;
241 	struct io_uring ring;
242 	char value[XATTR_SIZE];
243 
244 	/* Init io-uring queue. */
245 	int ret = io_uring_queue_init(QUEUE_DEPTH, &ring, 0);
246 	if (ret) {
247 		fprintf(stderr, "child: ring setup failed: %d\n", ret);
248 		return -1;
249 	}
250 
251 	/* Create the test file. */
252 	t_create_file(FILENAME, 0);
253 
254 	/* Test writing attributes. */
255 	if (io_uring_setxattr(&ring, FILENAME, KEY1, VALUE1, strlen(VALUE1), 0) < 0) {
256 		fprintf(stderr, "Error setxattr cannot write key1\n");
257 		rc = -1;
258 		goto Exit;
259 	}
260 
261 	if (io_uring_setxattr(&ring, FILENAME, KEY2, VALUE2, strlen(VALUE2), 0) < 0) {
262 		fprintf(stderr, "Error setxattr cannot write key1\n");
263 		rc = -1;
264 		goto Exit;
265 	}
266 
267 	/* Test reading attributes. */
268 	value_len = io_uring_getxattr(&ring, FILENAME, KEY1, value, XATTR_SIZE);
269 	if (value_len != strlen(VALUE1) || strncmp(value, VALUE1, value_len)) {
270 		fprintf(stderr, "Error: getxattr expected value: %s, returned value: %s\n", VALUE1, value);
271 		rc = -1;
272 		goto Exit;
273 	}
274 
275 	value_len = io_uring_getxattr(&ring, FILENAME, KEY2, value, XATTR_SIZE);
276 	if (value_len != strlen(VALUE2) || strncmp(value, VALUE2, value_len)) {
277 		fprintf(stderr, "Error: getxattr expected value: %s, returned value: %s\n", VALUE2, value);
278 		rc = -1;
279 		goto Exit;
280 	}
281 
282 	/* Cleanup. */
283 Exit:
284 	io_uring_queue_exit(&ring);
285 	unlink(FILENAME);
286 
287 	return rc;
288 }
289 
290 /* Test driver for failure cases of fsetxattr and fgetxattr. */
test_failure_fxattr(void)291 static int test_failure_fxattr(void)
292 {
293 	int rc = 0;
294 	struct io_uring ring;
295 	char value[XATTR_SIZE];
296 
297 	/* Init io-uring queue. */
298 	int ret = io_uring_queue_init(QUEUE_DEPTH, &ring, 0);
299 	if (ret) {
300 		fprintf(stderr, "child: ring setup failed: %d\n", ret);
301 		return -1;
302 	}
303 
304 	/* Create the test file. */
305 	int fd = open(FILENAME, O_CREAT | O_RDWR, 0644);
306 	if (fd < 0) {
307 		fprintf(stderr, "Error: cannot open file: ret=%d\n", fd);
308 		return -1;
309 	}
310 
311 	/* Test writing attributes. */
312 	assert(io_uring_fsetxattr(&ring, -1, KEY1, VALUE1, strlen(VALUE1), 0) < 0);
313 	assert(io_uring_fsetxattr(&ring, fd, NULL, VALUE1, strlen(VALUE1), 0) < 0);
314 	assert(io_uring_fsetxattr(&ring, fd, KEY1, NULL,   strlen(VALUE1), 0) < 0);
315 	assert(io_uring_fsetxattr(&ring, fd, KEY1, VALUE1, 0,              0) == 0);
316 	assert(io_uring_fsetxattr(&ring, fd, KEY1, VALUE1, -1,             0) < 0);
317 
318 	/* Test reading attributes. */
319 	assert(io_uring_fgetxattr(&ring, -1, KEY1, value, XATTR_SIZE) < 0);
320 	assert(io_uring_fgetxattr(&ring, fd, NULL, value, XATTR_SIZE) < 0);
321 	assert(io_uring_fgetxattr(&ring, fd, KEY1, value, 0)          == 0);
322 
323 	/* Cleanup. */
324 	close(fd);
325 	unlink(FILENAME);
326 
327 	io_uring_queue_exit(&ring);
328 
329 	return rc;
330 }
331 
332 
333 /* Test driver for failure cases for setxattr and getxattr. */
test_failure_xattr(void)334 static int test_failure_xattr(void)
335 {
336 	int rc = 0;
337 	struct io_uring ring;
338 	char value[XATTR_SIZE];
339 
340 	/* Init io-uring queue. */
341 	int ret = io_uring_queue_init(QUEUE_DEPTH, &ring, 0);
342 	if (ret) {
343 		fprintf(stderr, "child: ring setup failed: %d\n", ret);
344 		return -1;
345 	}
346 
347 	/* Create the test file. */
348 	t_create_file(FILENAME, 0);
349 
350 	/* Test writing attributes. */
351 	assert(io_uring_setxattr(&ring, "complete garbage", KEY1, VALUE1, strlen(VALUE1), 0) < 0);
352 	assert(io_uring_setxattr(&ring, NULL,     KEY1, VALUE1, strlen(VALUE1), 0) < 0);
353 	assert(io_uring_setxattr(&ring, FILENAME, NULL, VALUE1, strlen(VALUE1), 0) < 0);
354 	assert(io_uring_setxattr(&ring, FILENAME, KEY1, NULL,   strlen(VALUE1), 0) < 0);
355 	assert(io_uring_setxattr(&ring, FILENAME, KEY1, VALUE1, 0,              0) == 0);
356 
357 	/* Test reading attributes. */
358 	assert(io_uring_getxattr(&ring, "complete garbage", KEY1, value, XATTR_SIZE) < 0);
359 	assert(io_uring_getxattr(&ring, NULL,     KEY1, value, XATTR_SIZE) < 0);
360 	assert(io_uring_getxattr(&ring, FILENAME, NULL, value, XATTR_SIZE) < 0);
361 	assert(io_uring_getxattr(&ring, FILENAME, KEY1, NULL,  XATTR_SIZE) == 0);
362 	assert(io_uring_getxattr(&ring, FILENAME, KEY1, value, 0)          == 0);
363 
364 	/* Cleanup. */
365 	io_uring_queue_exit(&ring);
366 	unlink(FILENAME);
367 
368 	return rc;
369 }
370 
371 /* Test for invalid SQE, this will cause a segmentation fault if enabled. */
test_invalid_sqe(void)372 static int test_invalid_sqe(void)
373 {
374 #ifdef DESTRUCTIVE_TEST
375 	struct io_uring_sqe *sqe = NULL;
376 	struct io_uring_cqe *cqe = NULL;
377 	struct io_uring ring;
378 
379 	/* Init io-uring queue. */
380 	int ret = io_uring_queue_init(QUEUE_DEPTH, &ring, 0);
381 	if (ret) {
382 		fprintf(stderr, "child: ring setup failed: %d\n", ret);
383 		return -1;
384 	}
385 
386 	/* Pass invalid SQE. */
387 	io_uring_prep_setxattr(sqe, FILENAME, KEY1, VALUE1, strlen(VALUE1), 0);
388 
389 	ret = io_uring_submit(&ring);
390 	if (ret != 1) {
391 		fprintf(stderr, "Error io_uring_submit_and_wait: ret=%d\n", ret);
392 		return -1;
393 	}
394 
395 	ret = io_uring_wait_cqe(&ring, &cqe);
396 	if (ret) {
397 		fprintf(stderr, "Error io_uring_wait_cqe: ret=%d\n", ret);
398 		return -1;
399 	}
400 
401 	ret = cqe->res;
402 	io_uring_cqe_seen(&ring, cqe);
403 
404 	return ret;
405 #else
406 	return 0;
407 #endif
408 }
409 
410 /* Test driver. */
main(int argc,char * argv[])411 int main(int argc, char *argv[])
412 {
413 	if (argc > 1)
414 		return 0;
415 
416 	if (test_fxattr())
417 		return EXIT_FAILURE;
418 	if (no_xattr)
419 		return EXIT_SUCCESS;
420 	if (test_xattr() || test_failure_fxattr() || test_failure_xattr() ||
421 	    test_invalid_sqe())
422 		return EXIT_FAILURE;
423 
424 	return EXIT_SUCCESS;
425 }
426