Merge remote-tracking branch 'remotes/kraxel/tags/pull-usb-20160622-2' into staging
[qemu/kevin.git] / hw / 9pfs / cofs.c
blob70f584fcbd21da9107d38dd02a77a14fc2213b40
1 /*
2 * 9p backend
4 * Copyright IBM, Corp. 2011
6 * Authors:
7 * Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
9 * This work is licensed under the terms of the GNU GPL, version 2. See
10 * the COPYING file in the top-level directory.
14 #include "qemu/osdep.h"
15 #include "fsdev/qemu-fsdev.h"
16 #include "qemu/thread.h"
17 #include "qemu/coroutine.h"
18 #include "coth.h"
20 static ssize_t __readlink(V9fsState *s, V9fsPath *path, V9fsString *buf)
22 ssize_t len, maxlen = PATH_MAX;
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) {
34 * We dodn't have space to put the NULL or we have more
35 * to read. Increase the size and try again
37 maxlen *= 2;
38 g_free(buf->data);
39 buf->data = g_malloc(maxlen);
40 continue;
43 * Null terminate the readlink output
45 buf->data[len] = '\0';
46 buf->size = len;
47 break;
49 return len;
52 int v9fs_co_readlink(V9fsPDU *pdu, V9fsPath *path, V9fsString *buf)
54 int err;
55 V9fsState *s = pdu->s;
57 if (v9fs_request_cancelled(pdu)) {
58 return -EINTR;
60 v9fs_path_read_lock(s);
61 v9fs_co_run_in_worker(
63 err = __readlink(s, path, buf);
64 if (err < 0) {
65 err = -errno;
67 });
68 v9fs_path_unlock(s);
69 return err;
72 int v9fs_co_statfs(V9fsPDU *pdu, V9fsPath *path, struct statfs *stbuf)
74 int err;
75 V9fsState *s = pdu->s;
77 if (v9fs_request_cancelled(pdu)) {
78 return -EINTR;
80 v9fs_path_read_lock(s);
81 v9fs_co_run_in_worker(
83 err = s->ops->statfs(&s->ctx, path, stbuf);
84 if (err < 0) {
85 err = -errno;
87 });
88 v9fs_path_unlock(s);
89 return err;
92 int v9fs_co_chmod(V9fsPDU *pdu, V9fsPath *path, mode_t mode)
94 int err;
95 FsCred cred;
96 V9fsState *s = pdu->s;
98 if (v9fs_request_cancelled(pdu)) {
99 return -EINTR;
101 cred_init(&cred);
102 cred.fc_mode = mode;
103 v9fs_path_read_lock(s);
104 v9fs_co_run_in_worker(
106 err = s->ops->chmod(&s->ctx, path, &cred);
107 if (err < 0) {
108 err = -errno;
111 v9fs_path_unlock(s);
112 return err;
115 int v9fs_co_utimensat(V9fsPDU *pdu, V9fsPath *path,
116 struct timespec times[2])
118 int err;
119 V9fsState *s = pdu->s;
121 if (v9fs_request_cancelled(pdu)) {
122 return -EINTR;
124 v9fs_path_read_lock(s);
125 v9fs_co_run_in_worker(
127 err = s->ops->utimensat(&s->ctx, path, times);
128 if (err < 0) {
129 err = -errno;
132 v9fs_path_unlock(s);
133 return err;
136 int v9fs_co_chown(V9fsPDU *pdu, V9fsPath *path, uid_t uid, gid_t gid)
138 int err;
139 FsCred cred;
140 V9fsState *s = pdu->s;
142 if (v9fs_request_cancelled(pdu)) {
143 return -EINTR;
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(
151 err = s->ops->chown(&s->ctx, path, &cred);
152 if (err < 0) {
153 err = -errno;
156 v9fs_path_unlock(s);
157 return err;
160 int v9fs_co_truncate(V9fsPDU *pdu, V9fsPath *path, off_t size)
162 int err;
163 V9fsState *s = pdu->s;
165 if (v9fs_request_cancelled(pdu)) {
166 return -EINTR;
168 v9fs_path_read_lock(s);
169 v9fs_co_run_in_worker(
171 err = s->ops->truncate(&s->ctx, path, size);
172 if (err < 0) {
173 err = -errno;
176 v9fs_path_unlock(s);
177 return err;
180 int 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)
183 int err;
184 V9fsPath path;
185 FsCred cred;
186 V9fsState *s = pdu->s;
188 if (v9fs_request_cancelled(pdu)) {
189 return -EINTR;
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(
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;
211 v9fs_path_free(&path);
214 v9fs_path_unlock(s);
215 return err;
218 /* Only works with path name based fid */
219 int v9fs_co_remove(V9fsPDU *pdu, V9fsPath *path)
221 int err;
222 V9fsState *s = pdu->s;
224 if (v9fs_request_cancelled(pdu)) {
225 return -EINTR;
227 v9fs_path_read_lock(s);
228 v9fs_co_run_in_worker(
230 err = s->ops->remove(&s->ctx, path->data);
231 if (err < 0) {
232 err = -errno;
235 v9fs_path_unlock(s);
236 return err;
239 int v9fs_co_unlinkat(V9fsPDU *pdu, V9fsPath *path, V9fsString *name, int flags)
241 int err;
242 V9fsState *s = pdu->s;
244 if (v9fs_request_cancelled(pdu)) {
245 return -EINTR;
247 v9fs_path_read_lock(s);
248 v9fs_co_run_in_worker(
250 err = s->ops->unlinkat(&s->ctx, path, name->data, flags);
251 if (err < 0) {
252 err = -errno;
255 v9fs_path_unlock(s);
256 return err;
259 /* Only work with path name based fid */
260 int v9fs_co_rename(V9fsPDU *pdu, V9fsPath *oldpath, V9fsPath *newpath)
262 int err;
263 V9fsState *s = pdu->s;
265 if (v9fs_request_cancelled(pdu)) {
266 return -EINTR;
268 v9fs_co_run_in_worker(
270 err = s->ops->rename(&s->ctx, oldpath->data, newpath->data);
271 if (err < 0) {
272 err = -errno;
275 return err;
278 int v9fs_co_renameat(V9fsPDU *pdu, V9fsPath *olddirpath, V9fsString *oldname,
279 V9fsPath *newdirpath, V9fsString *newname)
281 int err;
282 V9fsState *s = pdu->s;
284 if (v9fs_request_cancelled(pdu)) {
285 return -EINTR;
287 v9fs_co_run_in_worker(
289 err = s->ops->renameat(&s->ctx, olddirpath, oldname->data,
290 newdirpath, newname->data);
291 if (err < 0) {
292 err = -errno;
295 return err;
298 int v9fs_co_symlink(V9fsPDU *pdu, V9fsFidState *dfidp, V9fsString *name,
299 const char *oldpath, gid_t gid, struct stat *stbuf)
301 int err;
302 FsCred cred;
303 V9fsPath path;
304 V9fsState *s = pdu->s;
306 if (v9fs_request_cancelled(pdu)) {
307 return -EINTR;
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(
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;
329 v9fs_path_free(&path);
332 v9fs_path_unlock(s);
333 return err;
337 * For path name based fid we don't block. So we can
338 * directly call the fs driver ops.
340 int v9fs_co_name_to_path(V9fsPDU *pdu, V9fsPath *dirpath,
341 const char *name, V9fsPath *path)
343 int err;
344 V9fsState *s = pdu->s;
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;
351 } else {
352 if (v9fs_request_cancelled(pdu)) {
353 return -EINTR;
355 v9fs_co_run_in_worker(
357 err = s->ops->name_to_path(&s->ctx, dirpath, name, path);
358 if (err < 0) {
359 err = -errno;
363 return err;