1 /* SPDX-License-Identifier: MIT */
2 /*
3 * Description: run various unlink tests
4 *
5 */
6 #include <errno.h>
7 #include <stdio.h>
8 #include <unistd.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <fcntl.h>
12 #include <sys/stat.h>
13
14 #include "liburing.h"
15
test_rmdir(struct io_uring * ring)16 static int test_rmdir(struct io_uring *ring)
17 {
18 struct io_uring_cqe *cqe;
19 struct io_uring_sqe *sqe;
20 char buf[32];
21 int ret;
22
23 sprintf(buf, ".tmp.dir.%d", getpid());
24 if (mkdir(buf, 0755) < 0) {
25 perror("mkdir");
26 return 1;
27 }
28
29 sqe = io_uring_get_sqe(ring);
30 if (!sqe) {
31 fprintf(stderr, "get sqe failed\n");
32 goto err;
33 }
34 io_uring_prep_unlink(sqe, buf, AT_REMOVEDIR);
35
36 ret = io_uring_submit(ring);
37 if (ret <= 0) {
38 fprintf(stderr, "sqe submit failed: %d\n", ret);
39 goto err;
40 }
41
42 ret = io_uring_wait_cqe(ring, &cqe);
43 if (ret < 0) {
44 fprintf(stderr, "wait completion %d\n", ret);
45 goto err;
46 }
47 ret = cqe->res;
48 io_uring_cqe_seen(ring, cqe);
49
50 if (!ret) {
51 struct stat sb;
52
53 if (!stat(buf, &sb)) {
54 fprintf(stderr, "dir unlinked but still there\n");
55 goto err;
56 }
57 }
58 unlink(buf);
59 return ret;
60 err:
61 unlink(buf);
62 return 1;
63 }
64
test_unlink_badaddr(struct io_uring * ring)65 static int test_unlink_badaddr(struct io_uring *ring)
66 {
67 const char *old = (const char *) (uintptr_t) 0x1234;
68 struct io_uring_cqe *cqe;
69 struct io_uring_sqe *sqe;
70 int ret;
71
72 sqe = io_uring_get_sqe(ring);
73 if (!sqe) {
74 fprintf(stderr, "get sqe failed\n");
75 goto err;
76 }
77 io_uring_prep_unlink(sqe, old, 0);
78
79 ret = io_uring_submit(ring);
80 if (ret <= 0) {
81 fprintf(stderr, "sqe submit failed: %d\n", ret);
82 goto err;
83 }
84
85 ret = io_uring_wait_cqe(ring, &cqe);
86 if (ret < 0) {
87 fprintf(stderr, "wait completion %d\n", ret);
88 goto err;
89 }
90 ret = cqe->res;
91 io_uring_cqe_seen(ring, cqe);
92 return ret;
93 err:
94 return 1;
95 }
96
test_unlink(struct io_uring * ring,const char * old)97 static int test_unlink(struct io_uring *ring, const char *old)
98 {
99 struct io_uring_cqe *cqe;
100 struct io_uring_sqe *sqe;
101 int ret;
102
103 sqe = io_uring_get_sqe(ring);
104 if (!sqe) {
105 fprintf(stderr, "get sqe failed\n");
106 goto err;
107 }
108 io_uring_prep_unlink(sqe, old, 0);
109
110 ret = io_uring_submit(ring);
111 if (ret <= 0) {
112 fprintf(stderr, "sqe submit failed: %d\n", ret);
113 goto err;
114 }
115
116 ret = io_uring_wait_cqe(ring, &cqe);
117 if (ret < 0) {
118 fprintf(stderr, "wait completion %d\n", ret);
119 goto err;
120 }
121 ret = cqe->res;
122 io_uring_cqe_seen(ring, cqe);
123 return ret;
124 err:
125 return 1;
126 }
127
stat_file(const char * buf)128 static int stat_file(const char *buf)
129 {
130 struct stat sb;
131
132 if (!stat(buf, &sb))
133 return 0;
134
135 return errno;
136 }
137
main(int argc,char * argv[])138 int main(int argc, char *argv[])
139 {
140 struct io_uring ring;
141 char buf[32] = "./XXXXXX";
142 int ret;
143
144 if (argc > 1)
145 return 0;
146
147 ret = io_uring_queue_init(1, &ring, 0);
148 if (ret) {
149 fprintf(stderr, "ring setup failed: %d\n", ret);
150 return 1;
151 }
152
153 ret = mkstemp(buf);
154 if (ret < 0) {
155 perror("mkstemp");
156 return 1;
157 }
158 close(ret);
159
160 if (stat_file(buf) != 0) {
161 perror("stat");
162 return 1;
163 }
164
165 ret = test_unlink(&ring, buf);
166 if (ret < 0) {
167 if (ret == -EBADF || ret == -EINVAL) {
168 fprintf(stdout, "Unlink not supported, skipping\n");
169 unlink(buf);
170 return 0;
171 }
172 fprintf(stderr, "rename: %s\n", strerror(-ret));
173 goto err;
174 } else if (ret)
175 goto err;
176
177 ret = stat_file(buf);
178 if (ret != ENOENT) {
179 fprintf(stderr, "stat got %s\n", strerror(ret));
180 return 1;
181 }
182
183 ret = test_unlink(&ring, "/3/2/3/1/z/y");
184 if (ret != -ENOENT) {
185 fprintf(stderr, "invalid unlink got %s\n", strerror(-ret));
186 return 1;
187 }
188
189 ret = test_unlink_badaddr(&ring);
190 if (ret != -EFAULT) {
191 fprintf(stderr, "badaddr unlink got %s\n", strerror(-ret));
192 return 1;
193 }
194
195 ret = test_rmdir(&ring);
196 if (ret) {
197 fprintf(stderr, "rmdir failed: %s\n", strerror(-ret));
198 return 1;
199 }
200
201 return 0;
202 err:
203 unlink(buf);
204 return 1;
205 }
206