]>
Commit | Line | Data |
---|---|---|
86e42d74 | 1 | /* |
af8b38b0 | 2 | * 9p backend |
86e42d74 VJ |
3 | * |
4 | * Copyright IBM, Corp. 2011 | |
5 | * | |
6 | * Authors: | |
7 | * Aneesh Kumar K.V <[email protected]> | |
8 | * | |
9 | * This work is licensed under the terms of the GNU GPL, version 2. See | |
10 | * the COPYING file in the top-level directory. | |
11 | * | |
12 | */ | |
13 | ||
fbc04127 | 14 | #include "qemu/osdep.h" |
86e42d74 | 15 | #include "fsdev/qemu-fsdev.h" |
1de7afc9 | 16 | #include "qemu/thread.h" |
10817bf0 | 17 | #include "qemu/coroutine.h" |
fe52840c | 18 | #include "coth.h" |
86e42d74 | 19 | |
4fa4ce71 CG |
20 | static ssize_t __readlink(V9fsState *s, V9fsPath *path, V9fsString *buf) |
21 | { | |
22 | ssize_t len, maxlen = PATH_MAX; | |
23 | ||
24 | buf->data = g_malloc(PATH_MAX); | |
25 | for(;;) { | |
26 | len = s->ops->readlink(&s->ctx, path, buf->data, maxlen); | |
27 | if (len < 0) { | |
28 | g_free(buf->data); | |
29 | buf->data = NULL; | |
30 | buf->size = 0; | |
31 | break; | |
32 | } else if (len == maxlen) { | |
33 | /* | |
34 | * We dodn't have space to put the NULL or we have more | |
35 | * to read. Increase the size and try again | |
36 | */ | |
37 | maxlen *= 2; | |
38 | g_free(buf->data); | |
39 | buf->data = g_malloc(maxlen); | |
40 | continue; | |
41 | } | |
42 | /* | |
43 | * Null terminate the readlink output | |
44 | */ | |
45 | buf->data[len] = '\0'; | |
46 | buf->size = len; | |
47 | break; | |
48 | } | |
49 | return len; | |
50 | } | |
51 | ||
5bdade66 | 52 | int coroutine_fn v9fs_co_readlink(V9fsPDU *pdu, V9fsPath *path, V9fsString *buf) |
86e42d74 VJ |
53 | { |
54 | int err; | |
bccacf6c | 55 | V9fsState *s = pdu->s; |
86e42d74 | 56 | |
bccacf6c AK |
57 | if (v9fs_request_cancelled(pdu)) { |
58 | return -EINTR; | |
59 | } | |
532decb7 | 60 | v9fs_path_read_lock(s); |
86e42d74 VJ |
61 | v9fs_co_run_in_worker( |
62 | { | |
4fa4ce71 CG |
63 | err = __readlink(s, path, buf); |
64 | if (err < 0) { | |
86e42d74 VJ |
65 | err = -errno; |
66 | } | |
67 | }); | |
532decb7 | 68 | v9fs_path_unlock(s); |
86e42d74 VJ |
69 | return err; |
70 | } | |
94840ff9 | 71 | |
5bdade66 GK |
72 | int coroutine_fn v9fs_co_statfs(V9fsPDU *pdu, V9fsPath *path, |
73 | struct statfs *stbuf) | |
94840ff9 AK |
74 | { |
75 | int err; | |
bccacf6c | 76 | V9fsState *s = pdu->s; |
94840ff9 | 77 | |
bccacf6c AK |
78 | if (v9fs_request_cancelled(pdu)) { |
79 | return -EINTR; | |
80 | } | |
532decb7 | 81 | v9fs_path_read_lock(s); |
94840ff9 AK |
82 | v9fs_co_run_in_worker( |
83 | { | |
2289be19 | 84 | err = s->ops->statfs(&s->ctx, path, stbuf); |
94840ff9 AK |
85 | if (err < 0) { |
86 | err = -errno; | |
87 | } | |
88 | }); | |
532decb7 | 89 | v9fs_path_unlock(s); |
94840ff9 AK |
90 | return err; |
91 | } | |
4011ead2 | 92 | |
5bdade66 | 93 | int coroutine_fn v9fs_co_chmod(V9fsPDU *pdu, V9fsPath *path, mode_t mode) |
4011ead2 AK |
94 | { |
95 | int err; | |
96 | FsCred cred; | |
bccacf6c | 97 | V9fsState *s = pdu->s; |
4011ead2 | 98 | |
bccacf6c AK |
99 | if (v9fs_request_cancelled(pdu)) { |
100 | return -EINTR; | |
101 | } | |
4011ead2 AK |
102 | cred_init(&cred); |
103 | cred.fc_mode = mode; | |
532decb7 | 104 | v9fs_path_read_lock(s); |
4011ead2 AK |
105 | v9fs_co_run_in_worker( |
106 | { | |
2289be19 | 107 | err = s->ops->chmod(&s->ctx, path, &cred); |
4011ead2 AK |
108 | if (err < 0) { |
109 | err = -errno; | |
110 | } | |
111 | }); | |
532decb7 | 112 | v9fs_path_unlock(s); |
4011ead2 AK |
113 | return err; |
114 | } | |
115 | ||
5bdade66 GK |
116 | int coroutine_fn v9fs_co_utimensat(V9fsPDU *pdu, V9fsPath *path, |
117 | struct timespec times[2]) | |
4011ead2 AK |
118 | { |
119 | int err; | |
bccacf6c | 120 | V9fsState *s = pdu->s; |
4011ead2 | 121 | |
bccacf6c AK |
122 | if (v9fs_request_cancelled(pdu)) { |
123 | return -EINTR; | |
124 | } | |
532decb7 | 125 | v9fs_path_read_lock(s); |
4011ead2 AK |
126 | v9fs_co_run_in_worker( |
127 | { | |
2289be19 | 128 | err = s->ops->utimensat(&s->ctx, path, times); |
4011ead2 AK |
129 | if (err < 0) { |
130 | err = -errno; | |
131 | } | |
132 | }); | |
532decb7 | 133 | v9fs_path_unlock(s); |
4011ead2 AK |
134 | return err; |
135 | } | |
136 | ||
5bdade66 GK |
137 | int coroutine_fn v9fs_co_chown(V9fsPDU *pdu, V9fsPath *path, uid_t uid, |
138 | gid_t gid) | |
4011ead2 AK |
139 | { |
140 | int err; | |
141 | FsCred cred; | |
bccacf6c | 142 | V9fsState *s = pdu->s; |
4011ead2 | 143 | |
bccacf6c AK |
144 | if (v9fs_request_cancelled(pdu)) { |
145 | return -EINTR; | |
146 | } | |
4011ead2 AK |
147 | cred_init(&cred); |
148 | cred.fc_uid = uid; | |
149 | cred.fc_gid = gid; | |
532decb7 | 150 | v9fs_path_read_lock(s); |
4011ead2 AK |
151 | v9fs_co_run_in_worker( |
152 | { | |
2289be19 | 153 | err = s->ops->chown(&s->ctx, path, &cred); |
4011ead2 AK |
154 | if (err < 0) { |
155 | err = -errno; | |
156 | } | |
157 | }); | |
532decb7 | 158 | v9fs_path_unlock(s); |
4011ead2 AK |
159 | return err; |
160 | } | |
161 | ||
5bdade66 | 162 | int coroutine_fn v9fs_co_truncate(V9fsPDU *pdu, V9fsPath *path, off_t size) |
4011ead2 AK |
163 | { |
164 | int err; | |
bccacf6c | 165 | V9fsState *s = pdu->s; |
4011ead2 | 166 | |
bccacf6c AK |
167 | if (v9fs_request_cancelled(pdu)) { |
168 | return -EINTR; | |
169 | } | |
532decb7 | 170 | v9fs_path_read_lock(s); |
4011ead2 AK |
171 | v9fs_co_run_in_worker( |
172 | { | |
2289be19 | 173 | err = s->ops->truncate(&s->ctx, path, size); |
4011ead2 AK |
174 | if (err < 0) { |
175 | err = -errno; | |
176 | } | |
177 | }); | |
532decb7 | 178 | v9fs_path_unlock(s); |
4011ead2 AK |
179 | return err; |
180 | } | |
00ace8c5 | 181 | |
5bdade66 GK |
182 | int coroutine_fn v9fs_co_mknod(V9fsPDU *pdu, V9fsFidState *fidp, |
183 | V9fsString *name, uid_t uid, gid_t gid, | |
184 | dev_t dev, mode_t mode, struct stat *stbuf) | |
00ace8c5 AK |
185 | { |
186 | int err; | |
2289be19 | 187 | V9fsPath path; |
00ace8c5 | 188 | FsCred cred; |
bccacf6c | 189 | V9fsState *s = pdu->s; |
00ace8c5 | 190 | |
bccacf6c AK |
191 | if (v9fs_request_cancelled(pdu)) { |
192 | return -EINTR; | |
193 | } | |
00ace8c5 AK |
194 | cred_init(&cred); |
195 | cred.fc_uid = uid; | |
196 | cred.fc_gid = gid; | |
197 | cred.fc_mode = mode; | |
198 | cred.fc_rdev = dev; | |
532decb7 | 199 | v9fs_path_read_lock(s); |
00ace8c5 AK |
200 | v9fs_co_run_in_worker( |
201 | { | |
2289be19 | 202 | err = s->ops->mknod(&s->ctx, &fidp->path, name->data, &cred); |
00ace8c5 AK |
203 | if (err < 0) { |
204 | err = -errno; | |
02cb7f3a | 205 | } else { |
2289be19 AK |
206 | v9fs_path_init(&path); |
207 | err = v9fs_name_to_path(s, &fidp->path, name->data, &path); | |
208 | if (!err) { | |
209 | err = s->ops->lstat(&s->ctx, &path, stbuf); | |
210 | if (err < 0) { | |
211 | err = -errno; | |
212 | } | |
02cb7f3a | 213 | } |
2289be19 | 214 | v9fs_path_free(&path); |
00ace8c5 AK |
215 | } |
216 | }); | |
532decb7 | 217 | v9fs_path_unlock(s); |
00ace8c5 AK |
218 | return err; |
219 | } | |
b4b1537b | 220 | |
2289be19 | 221 | /* Only works with path name based fid */ |
5bdade66 | 222 | int coroutine_fn v9fs_co_remove(V9fsPDU *pdu, V9fsPath *path) |
b4b1537b VJ |
223 | { |
224 | int err; | |
bccacf6c | 225 | V9fsState *s = pdu->s; |
b4b1537b | 226 | |
bccacf6c AK |
227 | if (v9fs_request_cancelled(pdu)) { |
228 | return -EINTR; | |
229 | } | |
532decb7 | 230 | v9fs_path_read_lock(s); |
b4b1537b VJ |
231 | v9fs_co_run_in_worker( |
232 | { | |
233 | err = s->ops->remove(&s->ctx, path->data); | |
234 | if (err < 0) { | |
235 | err = -errno; | |
236 | } | |
237 | }); | |
532decb7 | 238 | v9fs_path_unlock(s); |
b4b1537b VJ |
239 | return err; |
240 | } | |
2a487e05 | 241 | |
5bdade66 GK |
242 | int coroutine_fn v9fs_co_unlinkat(V9fsPDU *pdu, V9fsPath *path, |
243 | V9fsString *name, int flags) | |
2289be19 AK |
244 | { |
245 | int err; | |
bccacf6c | 246 | V9fsState *s = pdu->s; |
2289be19 | 247 | |
bccacf6c AK |
248 | if (v9fs_request_cancelled(pdu)) { |
249 | return -EINTR; | |
250 | } | |
532decb7 | 251 | v9fs_path_read_lock(s); |
2289be19 AK |
252 | v9fs_co_run_in_worker( |
253 | { | |
254 | err = s->ops->unlinkat(&s->ctx, path, name->data, flags); | |
255 | if (err < 0) { | |
256 | err = -errno; | |
257 | } | |
258 | }); | |
532decb7 | 259 | v9fs_path_unlock(s); |
2289be19 AK |
260 | return err; |
261 | } | |
262 | ||
263 | /* Only work with path name based fid */ | |
5bdade66 GK |
264 | int coroutine_fn v9fs_co_rename(V9fsPDU *pdu, V9fsPath *oldpath, |
265 | V9fsPath *newpath) | |
2a487e05 AK |
266 | { |
267 | int err; | |
bccacf6c | 268 | V9fsState *s = pdu->s; |
2a487e05 | 269 | |
bccacf6c AK |
270 | if (v9fs_request_cancelled(pdu)) { |
271 | return -EINTR; | |
272 | } | |
2a487e05 AK |
273 | v9fs_co_run_in_worker( |
274 | { | |
275 | err = s->ops->rename(&s->ctx, oldpath->data, newpath->data); | |
276 | if (err < 0) { | |
277 | err = -errno; | |
278 | } | |
279 | }); | |
280 | return err; | |
281 | } | |
02ac7a34 | 282 | |
5bdade66 GK |
283 | int coroutine_fn v9fs_co_renameat(V9fsPDU *pdu, V9fsPath *olddirpath, |
284 | V9fsString *oldname, V9fsPath *newdirpath, | |
285 | V9fsString *newname) | |
2289be19 AK |
286 | { |
287 | int err; | |
bccacf6c | 288 | V9fsState *s = pdu->s; |
2289be19 | 289 | |
bccacf6c AK |
290 | if (v9fs_request_cancelled(pdu)) { |
291 | return -EINTR; | |
292 | } | |
2289be19 AK |
293 | v9fs_co_run_in_worker( |
294 | { | |
295 | err = s->ops->renameat(&s->ctx, olddirpath, oldname->data, | |
296 | newdirpath, newname->data); | |
297 | if (err < 0) { | |
298 | err = -errno; | |
299 | } | |
300 | }); | |
301 | return err; | |
302 | } | |
303 | ||
5bdade66 GK |
304 | int coroutine_fn v9fs_co_symlink(V9fsPDU *pdu, V9fsFidState *dfidp, |
305 | V9fsString *name, const char *oldpath, | |
306 | gid_t gid, struct stat *stbuf) | |
02ac7a34 VJ |
307 | { |
308 | int err; | |
309 | FsCred cred; | |
2289be19 | 310 | V9fsPath path; |
bccacf6c | 311 | V9fsState *s = pdu->s; |
02cb7f3a | 312 | |
bccacf6c AK |
313 | if (v9fs_request_cancelled(pdu)) { |
314 | return -EINTR; | |
315 | } | |
02ac7a34 | 316 | cred_init(&cred); |
02cb7f3a | 317 | cred.fc_uid = dfidp->uid; |
02ac7a34 VJ |
318 | cred.fc_gid = gid; |
319 | cred.fc_mode = 0777; | |
532decb7 | 320 | v9fs_path_read_lock(s); |
02ac7a34 VJ |
321 | v9fs_co_run_in_worker( |
322 | { | |
2289be19 AK |
323 | err = s->ops->symlink(&s->ctx, oldpath, &dfidp->path, |
324 | name->data, &cred); | |
02ac7a34 VJ |
325 | if (err < 0) { |
326 | err = -errno; | |
02cb7f3a | 327 | } else { |
2289be19 AK |
328 | v9fs_path_init(&path); |
329 | err = v9fs_name_to_path(s, &dfidp->path, name->data, &path); | |
330 | if (!err) { | |
331 | err = s->ops->lstat(&s->ctx, &path, stbuf); | |
332 | if (err < 0) { | |
333 | err = -errno; | |
334 | } | |
02cb7f3a | 335 | } |
2289be19 | 336 | v9fs_path_free(&path); |
02ac7a34 VJ |
337 | } |
338 | }); | |
532decb7 | 339 | v9fs_path_unlock(s); |
2289be19 AK |
340 | return err; |
341 | } | |
342 | ||
343 | /* | |
344 | * For path name based fid we don't block. So we can | |
345 | * directly call the fs driver ops. | |
346 | */ | |
5bdade66 GK |
347 | int coroutine_fn v9fs_co_name_to_path(V9fsPDU *pdu, V9fsPath *dirpath, |
348 | const char *name, V9fsPath *path) | |
2289be19 AK |
349 | { |
350 | int err; | |
bccacf6c | 351 | V9fsState *s = pdu->s; |
532decb7 | 352 | |
c98f1d4a | 353 | if (s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT) { |
532decb7 AK |
354 | err = s->ops->name_to_path(&s->ctx, dirpath, name, path); |
355 | if (err < 0) { | |
356 | err = -errno; | |
357 | } | |
358 | } else { | |
bccacf6c AK |
359 | if (v9fs_request_cancelled(pdu)) { |
360 | return -EINTR; | |
361 | } | |
532decb7 AK |
362 | v9fs_co_run_in_worker( |
363 | { | |
364 | err = s->ops->name_to_path(&s->ctx, dirpath, name, path); | |
365 | if (err < 0) { | |
366 | err = -errno; | |
367 | } | |
368 | }); | |
2289be19 | 369 | } |
02ac7a34 VJ |
370 | return err; |
371 | } |