1
2
3
4
5
6
7
8
9
10
11
12
13
14
15#include "fsdev/qemu-fsdev.h"
16#include "qemu/thread.h"
17#include "block/coroutine.h"
18#include "virtio-9p-coth.h"
19
20static 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
35
36
37 maxlen *= 2;
38 g_free(buf->data);
39 buf->data = g_malloc(maxlen);
40 continue;
41 }
42
43
44
45 buf->data[len] = '\0';
46 buf->size = len;
47 break;
48 }
49 return len;
50}
51
52int v9fs_co_readlink(V9fsPDU *pdu, V9fsPath *path, V9fsString *buf)
53{
54 int err;
55 V9fsState *s = pdu->s;
56
57 if (v9fs_request_cancelled(pdu)) {
58 return -EINTR;
59 }
60 v9fs_path_read_lock(s);
61 v9fs_co_run_in_worker(
62 {
63 err = __readlink(s, path, buf);
64 if (err < 0) {
65 err = -errno;
66 }
67 });
68 v9fs_path_unlock(s);
69 return err;
70}
71
72int v9fs_co_statfs(V9fsPDU *pdu, V9fsPath *path, struct statfs *stbuf)
73{
74 int err;
75 V9fsState *s = pdu->s;
76
77 if (v9fs_request_cancelled(pdu)) {
78 return -EINTR;
79 }
80 v9fs_path_read_lock(s);
81 v9fs_co_run_in_worker(
82 {
83 err = s->ops->statfs(&s->ctx, path, stbuf);
84 if (err < 0) {
85 err = -errno;
86 }
87 });
88 v9fs_path_unlock(s);
89 return err;
90}
91
92int v9fs_co_chmod(V9fsPDU *pdu, V9fsPath *path, mode_t mode)
93{
94 int err;
95 FsCred cred;
96 V9fsState *s = pdu->s;
97
98 if (v9fs_request_cancelled(pdu)) {
99 return -EINTR;
100 }
101 cred_init(&cred);
102 cred.fc_mode = mode;
103 v9fs_path_read_lock(s);
104 v9fs_co_run_in_worker(
105 {
106 err = s->ops->chmod(&s->ctx, path, &cred);
107 if (err < 0) {
108 err = -errno;
109 }
110 });
111 v9fs_path_unlock(s);
112 return err;
113}
114
115int v9fs_co_utimensat(V9fsPDU *pdu, V9fsPath *path,
116 struct timespec times[2])
117{
118 int err;
119 V9fsState *s = pdu->s;
120
121 if (v9fs_request_cancelled(pdu)) {
122 return -EINTR;
123 }
124 v9fs_path_read_lock(s);
125 v9fs_co_run_in_worker(
126 {
127 err = s->ops->utimensat(&s->ctx, path, times);
128 if (err < 0) {
129 err = -errno;
130 }
131 });
132 v9fs_path_unlock(s);
133 return err;
134}
135
136int v9fs_co_chown(V9fsPDU *pdu, V9fsPath *path, uid_t uid, gid_t gid)
137{
138 int err;
139 FsCred cred;
140 V9fsState *s = pdu->s;
141
142 if (v9fs_request_cancelled(pdu)) {
143 return -EINTR;
144 }
145 cred_init(&cred);
146 cred.fc_uid = uid;
147 cred.fc_gid = gid;
148 v9fs_path_read_lock(s);
149 v9fs_co_run_in_worker(
150 {
151 err = s->ops->chown(&s->ctx, path, &cred);
152 if (err < 0) {
153 err = -errno;
154 }
155 });
156 v9fs_path_unlock(s);
157 return err;
158}
159
160int v9fs_co_truncate(V9fsPDU *pdu, V9fsPath *path, off_t size)
161{
162 int err;
163 V9fsState *s = pdu->s;
164
165 if (v9fs_request_cancelled(pdu)) {
166 return -EINTR;
167 }
168 v9fs_path_read_lock(s);
169 v9fs_co_run_in_worker(
170 {
171 err = s->ops->truncate(&s->ctx, path, size);
172 if (err < 0) {
173 err = -errno;
174 }
175 });
176 v9fs_path_unlock(s);
177 return err;
178}
179
180int v9fs_co_mknod(V9fsPDU *pdu, V9fsFidState *fidp, V9fsString *name, uid_t uid,
181 gid_t gid, dev_t dev, mode_t mode, struct stat *stbuf)
182{
183 int err;
184 V9fsPath path;
185 FsCred cred;
186 V9fsState *s = pdu->s;
187
188 if (v9fs_request_cancelled(pdu)) {
189 return -EINTR;
190 }
191 cred_init(&cred);
192 cred.fc_uid = uid;
193 cred.fc_gid = gid;
194 cred.fc_mode = mode;
195 cred.fc_rdev = dev;
196 v9fs_path_read_lock(s);
197 v9fs_co_run_in_worker(
198 {
199 err = s->ops->mknod(&s->ctx, &fidp->path, name->data, &cred);
200 if (err < 0) {
201 err = -errno;
202 } else {
203 v9fs_path_init(&path);
204 err = v9fs_name_to_path(s, &fidp->path, name->data, &path);
205 if (!err) {
206 err = s->ops->lstat(&s->ctx, &path, stbuf);
207 if (err < 0) {
208 err = -errno;
209 }
210 }
211 v9fs_path_free(&path);
212 }
213 });
214 v9fs_path_unlock(s);
215 return err;
216}
217
218
219int v9fs_co_remove(V9fsPDU *pdu, V9fsPath *path)
220{
221 int err;
222 V9fsState *s = pdu->s;
223
224 if (v9fs_request_cancelled(pdu)) {
225 return -EINTR;
226 }
227 v9fs_path_read_lock(s);
228 v9fs_co_run_in_worker(
229 {
230 err = s->ops->remove(&s->ctx, path->data);
231 if (err < 0) {
232 err = -errno;
233 }
234 });
235 v9fs_path_unlock(s);
236 return err;
237}
238
239int v9fs_co_unlinkat(V9fsPDU *pdu, V9fsPath *path, V9fsString *name, int flags)
240{
241 int err;
242 V9fsState *s = pdu->s;
243
244 if (v9fs_request_cancelled(pdu)) {
245 return -EINTR;
246 }
247 v9fs_path_read_lock(s);
248 v9fs_co_run_in_worker(
249 {
250 err = s->ops->unlinkat(&s->ctx, path, name->data, flags);
251 if (err < 0) {
252 err = -errno;
253 }
254 });
255 v9fs_path_unlock(s);
256 return err;
257}
258
259
260int v9fs_co_rename(V9fsPDU *pdu, V9fsPath *oldpath, V9fsPath *newpath)
261{
262 int err;
263 V9fsState *s = pdu->s;
264
265 if (v9fs_request_cancelled(pdu)) {
266 return -EINTR;
267 }
268 v9fs_co_run_in_worker(
269 {
270 err = s->ops->rename(&s->ctx, oldpath->data, newpath->data);
271 if (err < 0) {
272 err = -errno;
273 }
274 });
275 return err;
276}
277
278int v9fs_co_renameat(V9fsPDU *pdu, V9fsPath *olddirpath, V9fsString *oldname,
279 V9fsPath *newdirpath, V9fsString *newname)
280{
281 int err;
282 V9fsState *s = pdu->s;
283
284 if (v9fs_request_cancelled(pdu)) {
285 return -EINTR;
286 }
287 v9fs_co_run_in_worker(
288 {
289 err = s->ops->renameat(&s->ctx, olddirpath, oldname->data,
290 newdirpath, newname->data);
291 if (err < 0) {
292 err = -errno;
293 }
294 });
295 return err;
296}
297
298int v9fs_co_symlink(V9fsPDU *pdu, V9fsFidState *dfidp, V9fsString *name,
299 const char *oldpath, gid_t gid, struct stat *stbuf)
300{
301 int err;
302 FsCred cred;
303 V9fsPath path;
304 V9fsState *s = pdu->s;
305
306 if (v9fs_request_cancelled(pdu)) {
307 return -EINTR;
308 }
309 cred_init(&cred);
310 cred.fc_uid = dfidp->uid;
311 cred.fc_gid = gid;
312 cred.fc_mode = 0777;
313 v9fs_path_read_lock(s);
314 v9fs_co_run_in_worker(
315 {
316 err = s->ops->symlink(&s->ctx, oldpath, &dfidp->path,
317 name->data, &cred);
318 if (err < 0) {
319 err = -errno;
320 } else {
321 v9fs_path_init(&path);
322 err = v9fs_name_to_path(s, &dfidp->path, name->data, &path);
323 if (!err) {
324 err = s->ops->lstat(&s->ctx, &path, stbuf);
325 if (err < 0) {
326 err = -errno;
327 }
328 }
329 v9fs_path_free(&path);
330 }
331 });
332 v9fs_path_unlock(s);
333 return err;
334}
335
336
337
338
339
340int v9fs_co_name_to_path(V9fsPDU *pdu, V9fsPath *dirpath,
341 const char *name, V9fsPath *path)
342{
343 int err;
344 V9fsState *s = pdu->s;
345
346 if (s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT) {
347 err = s->ops->name_to_path(&s->ctx, dirpath, name, path);
348 if (err < 0) {
349 err = -errno;
350 }
351 } else {
352 if (v9fs_request_cancelled(pdu)) {
353 return -EINTR;
354 }
355 v9fs_co_run_in_worker(
356 {
357 err = s->ops->name_to_path(&s->ctx, dirpath, name, path);
358 if (err < 0) {
359 err = -errno;
360 }
361 });
362 }
363 return err;
364}
365