root / hw / 9pfs / virtio-9p-proxy.c @ 39f8c32c
History | View | Annotate | Download (19 kB)
1 |
/*
|
---|---|
2 |
* Virtio 9p Proxy callback
|
3 |
*
|
4 |
* Copyright IBM, Corp. 2011
|
5 |
*
|
6 |
* Authors:
|
7 |
* M. Mohan Kumar <mohan@in.ibm.com>
|
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 |
#include <sys/socket.h> |
13 |
#include <sys/un.h> |
14 |
#include "hw/virtio.h" |
15 |
#include "virtio-9p.h" |
16 |
#include "fsdev/qemu-fsdev.h" |
17 |
#include "virtio-9p-proxy.h" |
18 |
|
19 |
typedef struct V9fsProxy { |
20 |
int sockfd;
|
21 |
QemuMutex mutex; |
22 |
struct iovec in_iovec;
|
23 |
struct iovec out_iovec;
|
24 |
} V9fsProxy; |
25 |
|
26 |
/*
|
27 |
* Return received file descriptor on success in *status.
|
28 |
* errno is also returned on *status (which will be < 0)
|
29 |
* return < 0 on transport error.
|
30 |
*/
|
31 |
static int v9fs_receivefd(int sockfd, int *status) |
32 |
{ |
33 |
struct iovec iov;
|
34 |
struct msghdr msg;
|
35 |
struct cmsghdr *cmsg;
|
36 |
int retval, data, fd;
|
37 |
union MsgControl msg_control;
|
38 |
|
39 |
iov.iov_base = &data; |
40 |
iov.iov_len = sizeof(data);
|
41 |
|
42 |
memset(&msg, 0, sizeof(msg)); |
43 |
msg.msg_iov = &iov; |
44 |
msg.msg_iovlen = 1;
|
45 |
msg.msg_control = &msg_control; |
46 |
msg.msg_controllen = sizeof(msg_control);
|
47 |
|
48 |
do {
|
49 |
retval = recvmsg(sockfd, &msg, 0);
|
50 |
} while (retval < 0 && errno == EINTR); |
51 |
if (retval <= 0) { |
52 |
return retval;
|
53 |
} |
54 |
/*
|
55 |
* data is set to V9FS_FD_VALID, if ancillary data is sent. If this
|
56 |
* request doesn't need ancillary data (fd) or an error occurred,
|
57 |
* data is set to negative errno value.
|
58 |
*/
|
59 |
if (data != V9FS_FD_VALID) {
|
60 |
*status = data; |
61 |
return 0; |
62 |
} |
63 |
/*
|
64 |
* File descriptor (fd) is sent in the ancillary data. Check if we
|
65 |
* indeed received it. One of the reasons to fail to receive it is if
|
66 |
* we exceeded the maximum number of file descriptors!
|
67 |
*/
|
68 |
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
|
69 |
if (cmsg->cmsg_len != CMSG_LEN(sizeof(int)) || |
70 |
cmsg->cmsg_level != SOL_SOCKET || |
71 |
cmsg->cmsg_type != SCM_RIGHTS) { |
72 |
continue;
|
73 |
} |
74 |
fd = *((int *)CMSG_DATA(cmsg));
|
75 |
*status = fd; |
76 |
return 0; |
77 |
} |
78 |
*status = -ENFILE; /* Ancillary data sent but not received */
|
79 |
return 0; |
80 |
} |
81 |
|
82 |
static ssize_t socket_read(int sockfd, void *buff, size_t size) |
83 |
{ |
84 |
ssize_t retval, total = 0;
|
85 |
|
86 |
while (size) {
|
87 |
retval = read(sockfd, buff, size); |
88 |
if (retval == 0) { |
89 |
return -EIO;
|
90 |
} |
91 |
if (retval < 0) { |
92 |
if (errno == EINTR) {
|
93 |
continue;
|
94 |
} |
95 |
return -errno;
|
96 |
} |
97 |
size -= retval; |
98 |
buff += retval; |
99 |
total += retval; |
100 |
} |
101 |
return total;
|
102 |
} |
103 |
|
104 |
/*
|
105 |
* return < 0 on transport error.
|
106 |
* *status is valid only if return >= 0
|
107 |
*/
|
108 |
static int v9fs_receive_status(V9fsProxy *proxy, |
109 |
struct iovec *reply, int *status) |
110 |
{ |
111 |
int retval;
|
112 |
ProxyHeader header; |
113 |
|
114 |
*status = 0;
|
115 |
reply->iov_len = 0;
|
116 |
retval = socket_read(proxy->sockfd, reply->iov_base, PROXY_HDR_SZ); |
117 |
if (retval < 0) { |
118 |
return retval;
|
119 |
} |
120 |
reply->iov_len = PROXY_HDR_SZ; |
121 |
proxy_unmarshal(reply, 0, "dd", &header.type, &header.size); |
122 |
if (header.size != sizeof(int)) { |
123 |
*status = -ENOBUFS; |
124 |
return 0; |
125 |
} |
126 |
retval = socket_read(proxy->sockfd, |
127 |
reply->iov_base + PROXY_HDR_SZ, header.size); |
128 |
if (retval < 0) { |
129 |
return retval;
|
130 |
} |
131 |
reply->iov_len += header.size; |
132 |
proxy_unmarshal(reply, PROXY_HDR_SZ, "d", status);
|
133 |
return 0; |
134 |
} |
135 |
|
136 |
/*
|
137 |
* Proxy->header and proxy->request written to socket by QEMU process.
|
138 |
* This request read by proxy helper process
|
139 |
* returns 0 on success and -errno on error
|
140 |
*/
|
141 |
static int v9fs_request(V9fsProxy *proxy, int type, |
142 |
void *response, const char *fmt, ...) |
143 |
{ |
144 |
dev_t rdev; |
145 |
va_list ap; |
146 |
int retval = 0; |
147 |
ProxyHeader header = { 0, 0}; |
148 |
int flags, mode, uid, gid;
|
149 |
V9fsString *path, *oldpath; |
150 |
struct iovec *iovec = NULL, *reply = NULL; |
151 |
|
152 |
qemu_mutex_lock(&proxy->mutex); |
153 |
|
154 |
if (proxy->sockfd == -1) { |
155 |
retval = -EIO; |
156 |
goto err_out;
|
157 |
} |
158 |
iovec = &proxy->out_iovec; |
159 |
reply = &proxy->in_iovec; |
160 |
va_start(ap, fmt); |
161 |
switch (type) {
|
162 |
case T_OPEN:
|
163 |
path = va_arg(ap, V9fsString *); |
164 |
flags = va_arg(ap, int);
|
165 |
retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sd", path, flags);
|
166 |
if (retval > 0) { |
167 |
header.size = retval; |
168 |
header.type = T_OPEN; |
169 |
} |
170 |
break;
|
171 |
case T_CREATE:
|
172 |
path = va_arg(ap, V9fsString *); |
173 |
flags = va_arg(ap, int);
|
174 |
mode = va_arg(ap, int);
|
175 |
uid = va_arg(ap, int);
|
176 |
gid = va_arg(ap, int);
|
177 |
retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sdddd", path,
|
178 |
flags, mode, uid, gid); |
179 |
if (retval > 0) { |
180 |
header.size = retval; |
181 |
header.type = T_CREATE; |
182 |
} |
183 |
break;
|
184 |
case T_MKNOD:
|
185 |
path = va_arg(ap, V9fsString *); |
186 |
mode = va_arg(ap, int);
|
187 |
rdev = va_arg(ap, long int); |
188 |
uid = va_arg(ap, int);
|
189 |
gid = va_arg(ap, int);
|
190 |
retval = proxy_marshal(iovec, PROXY_HDR_SZ, "ddsdq",
|
191 |
uid, gid, path, mode, rdev); |
192 |
if (retval > 0) { |
193 |
header.size = retval; |
194 |
header.type = T_MKNOD; |
195 |
} |
196 |
break;
|
197 |
case T_MKDIR:
|
198 |
path = va_arg(ap, V9fsString *); |
199 |
mode = va_arg(ap, int);
|
200 |
uid = va_arg(ap, int);
|
201 |
gid = va_arg(ap, int);
|
202 |
retval = proxy_marshal(iovec, PROXY_HDR_SZ, "ddsd",
|
203 |
uid, gid, path, mode); |
204 |
if (retval > 0) { |
205 |
header.size = retval; |
206 |
header.type = T_MKDIR; |
207 |
} |
208 |
break;
|
209 |
case T_SYMLINK:
|
210 |
oldpath = va_arg(ap, V9fsString *); |
211 |
path = va_arg(ap, V9fsString *); |
212 |
uid = va_arg(ap, int);
|
213 |
gid = va_arg(ap, int);
|
214 |
retval = proxy_marshal(iovec, PROXY_HDR_SZ, "ddss",
|
215 |
uid, gid, oldpath, path); |
216 |
if (retval > 0) { |
217 |
header.size = retval; |
218 |
header.type = T_SYMLINK; |
219 |
} |
220 |
break;
|
221 |
case T_LINK:
|
222 |
oldpath = va_arg(ap, V9fsString *); |
223 |
path = va_arg(ap, V9fsString *); |
224 |
retval = proxy_marshal(iovec, PROXY_HDR_SZ, "ss",
|
225 |
oldpath, path); |
226 |
if (retval > 0) { |
227 |
header.size = retval; |
228 |
header.type = T_LINK; |
229 |
} |
230 |
break;
|
231 |
default:
|
232 |
error_report("Invalid type %d\n", type);
|
233 |
retval = -EINVAL; |
234 |
break;
|
235 |
} |
236 |
va_end(ap); |
237 |
|
238 |
if (retval < 0) { |
239 |
goto err_out;
|
240 |
} |
241 |
|
242 |
/* marshal the header details */
|
243 |
proxy_marshal(iovec, 0, "dd", header.type, header.size); |
244 |
header.size += PROXY_HDR_SZ; |
245 |
|
246 |
retval = qemu_write_full(proxy->sockfd, iovec->iov_base, header.size); |
247 |
if (retval != header.size) {
|
248 |
goto close_error;
|
249 |
} |
250 |
|
251 |
switch (type) {
|
252 |
case T_OPEN:
|
253 |
case T_CREATE:
|
254 |
/*
|
255 |
* A file descriptor is returned as response for
|
256 |
* T_OPEN,T_CREATE on success
|
257 |
*/
|
258 |
if (v9fs_receivefd(proxy->sockfd, &retval) < 0) { |
259 |
goto close_error;
|
260 |
} |
261 |
break;
|
262 |
case T_MKNOD:
|
263 |
case T_MKDIR:
|
264 |
case T_SYMLINK:
|
265 |
case T_LINK:
|
266 |
if (v9fs_receive_status(proxy, reply, &retval) < 0) { |
267 |
goto close_error;
|
268 |
} |
269 |
break;
|
270 |
} |
271 |
|
272 |
err_out:
|
273 |
qemu_mutex_unlock(&proxy->mutex); |
274 |
return retval;
|
275 |
|
276 |
close_error:
|
277 |
close(proxy->sockfd); |
278 |
proxy->sockfd = -1;
|
279 |
qemu_mutex_unlock(&proxy->mutex); |
280 |
return -EIO;
|
281 |
} |
282 |
|
283 |
static int proxy_lstat(FsContext *fs_ctx, V9fsPath *fs_path, struct stat *stbuf) |
284 |
{ |
285 |
errno = EOPNOTSUPP; |
286 |
return -1; |
287 |
} |
288 |
|
289 |
static ssize_t proxy_readlink(FsContext *fs_ctx, V9fsPath *fs_path,
|
290 |
char *buf, size_t bufsz)
|
291 |
{ |
292 |
errno = EOPNOTSUPP; |
293 |
return -1; |
294 |
} |
295 |
|
296 |
static int proxy_close(FsContext *ctx, V9fsFidOpenState *fs) |
297 |
{ |
298 |
return close(fs->fd);
|
299 |
} |
300 |
|
301 |
static int proxy_closedir(FsContext *ctx, V9fsFidOpenState *fs) |
302 |
{ |
303 |
return closedir(fs->dir);
|
304 |
} |
305 |
|
306 |
static int proxy_open(FsContext *ctx, V9fsPath *fs_path, |
307 |
int flags, V9fsFidOpenState *fs)
|
308 |
{ |
309 |
fs->fd = v9fs_request(ctx->private, T_OPEN, NULL, "sd", fs_path, flags); |
310 |
if (fs->fd < 0) { |
311 |
errno = -fs->fd; |
312 |
fs->fd = -1;
|
313 |
} |
314 |
return fs->fd;
|
315 |
} |
316 |
|
317 |
static int proxy_opendir(FsContext *ctx, |
318 |
V9fsPath *fs_path, V9fsFidOpenState *fs) |
319 |
{ |
320 |
int serrno, fd;
|
321 |
|
322 |
fs->dir = NULL;
|
323 |
fd = v9fs_request(ctx->private, T_OPEN, NULL, "sd", fs_path, O_DIRECTORY); |
324 |
if (fd < 0) { |
325 |
errno = -fd; |
326 |
return -1; |
327 |
} |
328 |
fs->dir = fdopendir(fd); |
329 |
if (!fs->dir) {
|
330 |
serrno = errno; |
331 |
close(fd); |
332 |
errno = serrno; |
333 |
return -1; |
334 |
} |
335 |
return 0; |
336 |
} |
337 |
|
338 |
static void proxy_rewinddir(FsContext *ctx, V9fsFidOpenState *fs) |
339 |
{ |
340 |
return rewinddir(fs->dir);
|
341 |
} |
342 |
|
343 |
static off_t proxy_telldir(FsContext *ctx, V9fsFidOpenState *fs)
|
344 |
{ |
345 |
return telldir(fs->dir);
|
346 |
} |
347 |
|
348 |
static int proxy_readdir_r(FsContext *ctx, V9fsFidOpenState *fs, |
349 |
struct dirent *entry,
|
350 |
struct dirent **result)
|
351 |
{ |
352 |
return readdir_r(fs->dir, entry, result);
|
353 |
} |
354 |
|
355 |
static void proxy_seekdir(FsContext *ctx, V9fsFidOpenState *fs, off_t off) |
356 |
{ |
357 |
return seekdir(fs->dir, off);
|
358 |
} |
359 |
|
360 |
static ssize_t proxy_preadv(FsContext *ctx, V9fsFidOpenState *fs,
|
361 |
const struct iovec *iov, |
362 |
int iovcnt, off_t offset)
|
363 |
{ |
364 |
#ifdef CONFIG_PREADV
|
365 |
return preadv(fs->fd, iov, iovcnt, offset);
|
366 |
#else
|
367 |
int err = lseek(fs->fd, offset, SEEK_SET);
|
368 |
if (err == -1) { |
369 |
return err;
|
370 |
} else {
|
371 |
return readv(fs->fd, iov, iovcnt);
|
372 |
} |
373 |
#endif
|
374 |
} |
375 |
|
376 |
static ssize_t proxy_pwritev(FsContext *ctx, V9fsFidOpenState *fs,
|
377 |
const struct iovec *iov, |
378 |
int iovcnt, off_t offset)
|
379 |
{ |
380 |
ssize_t ret; |
381 |
|
382 |
#ifdef CONFIG_PREADV
|
383 |
ret = pwritev(fs->fd, iov, iovcnt, offset); |
384 |
#else
|
385 |
int err = lseek(fs->fd, offset, SEEK_SET);
|
386 |
if (err == -1) { |
387 |
return err;
|
388 |
} else {
|
389 |
ret = writev(fs->fd, iov, iovcnt); |
390 |
} |
391 |
#endif
|
392 |
#ifdef CONFIG_SYNC_FILE_RANGE
|
393 |
if (ret > 0 && ctx->export_flags & V9FS_IMMEDIATE_WRITEOUT) { |
394 |
/*
|
395 |
* Initiate a writeback. This is not a data integrity sync.
|
396 |
* We want to ensure that we don't leave dirty pages in the cache
|
397 |
* after write when writeout=immediate is sepcified.
|
398 |
*/
|
399 |
sync_file_range(fs->fd, offset, ret, |
400 |
SYNC_FILE_RANGE_WAIT_BEFORE | SYNC_FILE_RANGE_WRITE); |
401 |
} |
402 |
#endif
|
403 |
return ret;
|
404 |
} |
405 |
|
406 |
static int proxy_chmod(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp) |
407 |
{ |
408 |
errno = EOPNOTSUPP; |
409 |
return -1; |
410 |
} |
411 |
|
412 |
static int proxy_mknod(FsContext *fs_ctx, V9fsPath *dir_path, |
413 |
const char *name, FsCred *credp) |
414 |
{ |
415 |
int retval;
|
416 |
V9fsString fullname; |
417 |
|
418 |
v9fs_string_init(&fullname); |
419 |
v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
|
420 |
|
421 |
retval = v9fs_request(fs_ctx->private, T_MKNOD, NULL, "sdqdd", |
422 |
&fullname, credp->fc_mode, credp->fc_rdev, |
423 |
credp->fc_uid, credp->fc_gid); |
424 |
v9fs_string_free(&fullname); |
425 |
if (retval < 0) { |
426 |
errno = -retval; |
427 |
retval = -1;
|
428 |
} |
429 |
return retval;
|
430 |
} |
431 |
|
432 |
static int proxy_mkdir(FsContext *fs_ctx, V9fsPath *dir_path, |
433 |
const char *name, FsCred *credp) |
434 |
{ |
435 |
int retval;
|
436 |
V9fsString fullname; |
437 |
|
438 |
v9fs_string_init(&fullname); |
439 |
v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
|
440 |
|
441 |
retval = v9fs_request(fs_ctx->private, T_MKDIR, NULL, "sddd", &fullname, |
442 |
credp->fc_mode, credp->fc_uid, credp->fc_gid); |
443 |
v9fs_string_free(&fullname); |
444 |
if (retval < 0) { |
445 |
errno = -retval; |
446 |
retval = -1;
|
447 |
} |
448 |
v9fs_string_free(&fullname); |
449 |
return retval;
|
450 |
} |
451 |
|
452 |
static int proxy_fstat(FsContext *fs_ctx, int fid_type, |
453 |
V9fsFidOpenState *fs, struct stat *stbuf)
|
454 |
{ |
455 |
int fd;
|
456 |
|
457 |
if (fid_type == P9_FID_DIR) {
|
458 |
fd = dirfd(fs->dir); |
459 |
} else {
|
460 |
fd = fs->fd; |
461 |
} |
462 |
return fstat(fd, stbuf);
|
463 |
} |
464 |
|
465 |
static int proxy_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name, |
466 |
int flags, FsCred *credp, V9fsFidOpenState *fs)
|
467 |
{ |
468 |
V9fsString fullname; |
469 |
|
470 |
v9fs_string_init(&fullname); |
471 |
v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
|
472 |
|
473 |
fs->fd = v9fs_request(fs_ctx->private, T_CREATE, NULL, "sdddd", |
474 |
&fullname, flags, credp->fc_mode, |
475 |
credp->fc_uid, credp->fc_gid); |
476 |
v9fs_string_free(&fullname); |
477 |
if (fs->fd < 0) { |
478 |
errno = -fs->fd; |
479 |
fs->fd = -1;
|
480 |
} |
481 |
return fs->fd;
|
482 |
} |
483 |
|
484 |
static int proxy_symlink(FsContext *fs_ctx, const char *oldpath, |
485 |
V9fsPath *dir_path, const char *name, FsCred *credp) |
486 |
{ |
487 |
int retval;
|
488 |
V9fsString fullname, target; |
489 |
|
490 |
v9fs_string_init(&fullname); |
491 |
v9fs_string_init(&target); |
492 |
|
493 |
v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
|
494 |
v9fs_string_sprintf(&target, "%s", oldpath);
|
495 |
|
496 |
retval = v9fs_request(fs_ctx->private, T_SYMLINK, NULL, "ssdd", |
497 |
&target, &fullname, credp->fc_uid, credp->fc_gid); |
498 |
v9fs_string_free(&fullname); |
499 |
v9fs_string_free(&target); |
500 |
if (retval < 0) { |
501 |
errno = -retval; |
502 |
retval = -1;
|
503 |
} |
504 |
return retval;
|
505 |
} |
506 |
|
507 |
static int proxy_link(FsContext *ctx, V9fsPath *oldpath, |
508 |
V9fsPath *dirpath, const char *name) |
509 |
{ |
510 |
int retval;
|
511 |
V9fsString newpath; |
512 |
|
513 |
v9fs_string_init(&newpath); |
514 |
v9fs_string_sprintf(&newpath, "%s/%s", dirpath->data, name);
|
515 |
|
516 |
retval = v9fs_request(ctx->private, T_LINK, NULL, "ss", |
517 |
oldpath, &newpath); |
518 |
v9fs_string_free(&newpath); |
519 |
if (retval < 0) { |
520 |
errno = -retval; |
521 |
retval = -1;
|
522 |
} |
523 |
return retval;
|
524 |
} |
525 |
|
526 |
static int proxy_truncate(FsContext *ctx, V9fsPath *fs_path, off_t size) |
527 |
{ |
528 |
errno = EOPNOTSUPP; |
529 |
return -1; |
530 |
} |
531 |
|
532 |
static int proxy_rename(FsContext *ctx, const char *oldpath, |
533 |
const char *newpath) |
534 |
{ |
535 |
errno = EOPNOTSUPP; |
536 |
return -1; |
537 |
} |
538 |
|
539 |
static int proxy_chown(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp) |
540 |
{ |
541 |
errno = EOPNOTSUPP; |
542 |
return -1; |
543 |
} |
544 |
|
545 |
static int proxy_utimensat(FsContext *s, V9fsPath *fs_path, |
546 |
const struct timespec *buf) |
547 |
{ |
548 |
errno = EOPNOTSUPP; |
549 |
return -1; |
550 |
} |
551 |
|
552 |
static int proxy_remove(FsContext *ctx, const char *path) |
553 |
{ |
554 |
errno = EOPNOTSUPP; |
555 |
return -1; |
556 |
} |
557 |
|
558 |
static int proxy_fsync(FsContext *ctx, int fid_type, |
559 |
V9fsFidOpenState *fs, int datasync)
|
560 |
{ |
561 |
int fd;
|
562 |
|
563 |
if (fid_type == P9_FID_DIR) {
|
564 |
fd = dirfd(fs->dir); |
565 |
} else {
|
566 |
fd = fs->fd; |
567 |
} |
568 |
|
569 |
if (datasync) {
|
570 |
return qemu_fdatasync(fd);
|
571 |
} else {
|
572 |
return fsync(fd);
|
573 |
} |
574 |
} |
575 |
|
576 |
static int proxy_statfs(FsContext *s, V9fsPath *fs_path, struct statfs *stbuf) |
577 |
{ |
578 |
errno = EOPNOTSUPP; |
579 |
return -1; |
580 |
} |
581 |
|
582 |
static ssize_t proxy_lgetxattr(FsContext *ctx, V9fsPath *fs_path,
|
583 |
const char *name, void *value, size_t size) |
584 |
{ |
585 |
errno = EOPNOTSUPP; |
586 |
return -1; |
587 |
} |
588 |
|
589 |
static ssize_t proxy_llistxattr(FsContext *ctx, V9fsPath *fs_path,
|
590 |
void *value, size_t size)
|
591 |
{ |
592 |
errno = EOPNOTSUPP; |
593 |
return -1; |
594 |
} |
595 |
|
596 |
static int proxy_lsetxattr(FsContext *ctx, V9fsPath *fs_path, const char *name, |
597 |
void *value, size_t size, int flags) |
598 |
{ |
599 |
errno = EOPNOTSUPP; |
600 |
return -1; |
601 |
} |
602 |
|
603 |
static int proxy_lremovexattr(FsContext *ctx, V9fsPath *fs_path, |
604 |
const char *name) |
605 |
{ |
606 |
errno = EOPNOTSUPP; |
607 |
return -1; |
608 |
} |
609 |
|
610 |
static int proxy_name_to_path(FsContext *ctx, V9fsPath *dir_path, |
611 |
const char *name, V9fsPath *target) |
612 |
{ |
613 |
if (dir_path) {
|
614 |
v9fs_string_sprintf((V9fsString *)target, "%s/%s",
|
615 |
dir_path->data, name); |
616 |
} else {
|
617 |
v9fs_string_sprintf((V9fsString *)target, "%s", name);
|
618 |
} |
619 |
/* Bump the size for including terminating NULL */
|
620 |
target->size++; |
621 |
return 0; |
622 |
} |
623 |
|
624 |
static int proxy_renameat(FsContext *ctx, V9fsPath *olddir, |
625 |
const char *old_name, V9fsPath *newdir, |
626 |
const char *new_name) |
627 |
{ |
628 |
int ret;
|
629 |
V9fsString old_full_name, new_full_name; |
630 |
|
631 |
v9fs_string_init(&old_full_name); |
632 |
v9fs_string_init(&new_full_name); |
633 |
|
634 |
v9fs_string_sprintf(&old_full_name, "%s/%s", olddir->data, old_name);
|
635 |
v9fs_string_sprintf(&new_full_name, "%s/%s", newdir->data, new_name);
|
636 |
|
637 |
ret = proxy_rename(ctx, old_full_name.data, new_full_name.data); |
638 |
v9fs_string_free(&old_full_name); |
639 |
v9fs_string_free(&new_full_name); |
640 |
return ret;
|
641 |
} |
642 |
|
643 |
static int proxy_unlinkat(FsContext *ctx, V9fsPath *dir, |
644 |
const char *name, int flags) |
645 |
{ |
646 |
int ret;
|
647 |
V9fsString fullname; |
648 |
v9fs_string_init(&fullname); |
649 |
|
650 |
v9fs_string_sprintf(&fullname, "%s/%s", dir->data, name);
|
651 |
ret = proxy_remove(ctx, fullname.data); |
652 |
v9fs_string_free(&fullname); |
653 |
|
654 |
return ret;
|
655 |
} |
656 |
|
657 |
static int proxy_parse_opts(QemuOpts *opts, struct FsDriverEntry *fs) |
658 |
{ |
659 |
const char *sock_fd = qemu_opt_get(opts, "sock_fd"); |
660 |
|
661 |
if (sock_fd) {
|
662 |
fprintf(stderr, "sock_fd option not specified\n");
|
663 |
return -1; |
664 |
} |
665 |
fs->path = g_strdup(sock_fd); |
666 |
return 0; |
667 |
} |
668 |
|
669 |
static int proxy_init(FsContext *ctx) |
670 |
{ |
671 |
V9fsProxy *proxy = g_malloc(sizeof(V9fsProxy));
|
672 |
int sock_id;
|
673 |
|
674 |
sock_id = atoi(ctx->fs_root); |
675 |
if (sock_id < 0) { |
676 |
fprintf(stderr, "socket descriptor not initialized\n");
|
677 |
return -1; |
678 |
} |
679 |
g_free(ctx->fs_root); |
680 |
|
681 |
proxy->in_iovec.iov_base = g_malloc(PROXY_MAX_IO_SZ + PROXY_HDR_SZ); |
682 |
proxy->in_iovec.iov_len = PROXY_MAX_IO_SZ + PROXY_HDR_SZ; |
683 |
proxy->out_iovec.iov_base = g_malloc(PROXY_MAX_IO_SZ + PROXY_HDR_SZ); |
684 |
proxy->out_iovec.iov_len = PROXY_MAX_IO_SZ + PROXY_HDR_SZ; |
685 |
|
686 |
ctx->private = proxy; |
687 |
proxy->sockfd = sock_id; |
688 |
qemu_mutex_init(&proxy->mutex); |
689 |
|
690 |
ctx->export_flags |= V9FS_PATHNAME_FSCONTEXT; |
691 |
return 0; |
692 |
} |
693 |
|
694 |
FileOperations proxy_ops = { |
695 |
.parse_opts = proxy_parse_opts, |
696 |
.init = proxy_init, |
697 |
.lstat = proxy_lstat, |
698 |
.readlink = proxy_readlink, |
699 |
.close = proxy_close, |
700 |
.closedir = proxy_closedir, |
701 |
.open = proxy_open, |
702 |
.opendir = proxy_opendir, |
703 |
.rewinddir = proxy_rewinddir, |
704 |
.telldir = proxy_telldir, |
705 |
.readdir_r = proxy_readdir_r, |
706 |
.seekdir = proxy_seekdir, |
707 |
.preadv = proxy_preadv, |
708 |
.pwritev = proxy_pwritev, |
709 |
.chmod = proxy_chmod, |
710 |
.mknod = proxy_mknod, |
711 |
.mkdir = proxy_mkdir, |
712 |
.fstat = proxy_fstat, |
713 |
.open2 = proxy_open2, |
714 |
.symlink = proxy_symlink, |
715 |
.link = proxy_link, |
716 |
.truncate = proxy_truncate, |
717 |
.rename = proxy_rename, |
718 |
.chown = proxy_chown, |
719 |
.utimensat = proxy_utimensat, |
720 |
.remove = proxy_remove, |
721 |
.fsync = proxy_fsync, |
722 |
.statfs = proxy_statfs, |
723 |
.lgetxattr = proxy_lgetxattr, |
724 |
.llistxattr = proxy_llistxattr, |
725 |
.lsetxattr = proxy_lsetxattr, |
726 |
.lremovexattr = proxy_lremovexattr, |
727 |
.name_to_path = proxy_name_to_path, |
728 |
.renameat = proxy_renameat, |
729 |
.unlinkat = proxy_unlinkat, |
730 |
}; |