]> Git Repo - qemu.git/blame - hw/9pfs/9p-local.c
Merge remote-tracking branch 'remotes/thibault/tags/samuel-thibault' into staging
[qemu.git] / hw / 9pfs / 9p-local.c
CommitLineData
9f107513 1/*
f00d4f59 2 * 9p Posix callback
9f107513
AL
3 *
4 * Copyright IBM, Corp. 2010
5 *
6 * Authors:
7 * Anthony Liguori <[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 */
873c3213 13
fbc04127 14#include "qemu/osdep.h"
ebe74f8b 15#include "9p.h"
267ae092 16#include "9p-xattr.h"
69b15212 17#include "fsdev/qemu-fsdev.h" /* local_ops */
c494dd6f 18#include <arpa/inet.h>
131dcb25
AL
19#include <pwd.h>
20#include <grp.h>
c494dd6f
AL
21#include <sys/socket.h>
22#include <sys/un.h>
1de7afc9 23#include "qemu/xattr.h"
f348b6d1 24#include "qemu/cutils.h"
63325b18 25#include "qemu/error-report.h"
2c30dd74 26#include <libgen.h>
e06a765e
HPB
27#include <linux/fs.h>
28#ifdef CONFIG_LINUX_MAGIC_H
29#include <linux/magic.h>
30#endif
31#include <sys/ioctl.h>
32
33#ifndef XFS_SUPER_MAGIC
34#define XFS_SUPER_MAGIC 0x58465342
35#endif
36#ifndef EXT2_SUPER_MAGIC
37#define EXT2_SUPER_MAGIC 0xEF53
38#endif
39#ifndef REISERFS_SUPER_MAGIC
40#define REISERFS_SUPER_MAGIC 0x52654973
41#endif
42#ifndef BTRFS_SUPER_MAGIC
43#define BTRFS_SUPER_MAGIC 0x9123683E
44#endif
131dcb25 45
2c30dd74
AK
46#define VIRTFS_META_DIR ".virtfs_metadata"
47
4fa4ce71 48static char *local_mapped_attr_path(FsContext *ctx, const char *path)
2c30dd74 49{
1b6f85e2
MT
50 int dirlen;
51 const char *name = strrchr(path, '/');
52 if (name) {
53 dirlen = name - path;
54 ++name;
55 } else {
56 name = path;
57 dirlen = 0;
58 }
59 return g_strdup_printf("%s/%.*s/%s/%s", ctx->fs_root,
60 dirlen, path, VIRTFS_META_DIR, name);
2c30dd74
AK
61}
62
0ceb092e
AK
63static FILE *local_fopen(const char *path, const char *mode)
64{
65 int fd, o_mode = 0;
66 FILE *fp;
67 int flags = O_NOFOLLOW;
68 /*
69 * only supports two modes
70 */
71 if (mode[0] == 'r') {
72 flags |= O_RDONLY;
73 } else if (mode[0] == 'w') {
74 flags |= O_WRONLY | O_TRUNC | O_CREAT;
75 o_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
76 } else {
77 return NULL;
78 }
79 fd = open(path, flags, o_mode);
80 if (fd == -1) {
81 return NULL;
82 }
83 fp = fdopen(fd, mode);
84 if (!fp) {
85 close(fd);
86 }
87 return fp;
88}
89
2c30dd74
AK
90#define ATTR_MAX 100
91static void local_mapped_file_attr(FsContext *ctx, const char *path,
92 struct stat *stbuf)
93{
94 FILE *fp;
95 char buf[ATTR_MAX];
4fa4ce71 96 char *attr_path;
2c30dd74 97
4fa4ce71 98 attr_path = local_mapped_attr_path(ctx, path);
0ceb092e 99 fp = local_fopen(attr_path, "r");
4fa4ce71 100 g_free(attr_path);
2c30dd74
AK
101 if (!fp) {
102 return;
103 }
104 memset(buf, 0, ATTR_MAX);
105 while (fgets(buf, ATTR_MAX, fp)) {
106 if (!strncmp(buf, "virtfs.uid", 10)) {
107 stbuf->st_uid = atoi(buf+11);
108 } else if (!strncmp(buf, "virtfs.gid", 10)) {
109 stbuf->st_gid = atoi(buf+11);
110 } else if (!strncmp(buf, "virtfs.mode", 11)) {
111 stbuf->st_mode = atoi(buf+12);
112 } else if (!strncmp(buf, "virtfs.rdev", 11)) {
113 stbuf->st_rdev = atoi(buf+12);
114 }
115 memset(buf, 0, ATTR_MAX);
116 }
117 fclose(fp);
118}
119
2289be19 120static int local_lstat(FsContext *fs_ctx, V9fsPath *fs_path, struct stat *stbuf)
131dcb25 121{
1237ad76 122 int err;
4fa4ce71 123 char *buffer;
2289be19
AK
124 char *path = fs_path->data;
125
4fa4ce71
CG
126 buffer = rpath(fs_ctx, path);
127 err = lstat(buffer, stbuf);
1237ad76 128 if (err) {
4fa4ce71 129 goto err_out;
1237ad76 130 }
b97400ca 131 if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
1237ad76
VJ
132 /* Actual credentials are part of extended attrs */
133 uid_t tmp_uid;
134 gid_t tmp_gid;
135 mode_t tmp_mode;
136 dev_t tmp_dev;
4fa4ce71 137 if (getxattr(buffer, "user.virtfs.uid", &tmp_uid, sizeof(uid_t)) > 0) {
f8ad4a89 138 stbuf->st_uid = le32_to_cpu(tmp_uid);
1237ad76 139 }
4fa4ce71 140 if (getxattr(buffer, "user.virtfs.gid", &tmp_gid, sizeof(gid_t)) > 0) {
f8ad4a89 141 stbuf->st_gid = le32_to_cpu(tmp_gid);
1237ad76 142 }
4fa4ce71 143 if (getxattr(buffer, "user.virtfs.mode",
faa44e3d 144 &tmp_mode, sizeof(mode_t)) > 0) {
f8ad4a89 145 stbuf->st_mode = le32_to_cpu(tmp_mode);
1237ad76 146 }
4fa4ce71 147 if (getxattr(buffer, "user.virtfs.rdev", &tmp_dev, sizeof(dev_t)) > 0) {
f8ad4a89 148 stbuf->st_rdev = le64_to_cpu(tmp_dev);
1237ad76 149 }
2c30dd74
AK
150 } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
151 local_mapped_file_attr(fs_ctx, path, stbuf);
152 }
4fa4ce71
CG
153
154err_out:
155 g_free(buffer);
2c30dd74
AK
156 return err;
157}
158
159static int local_create_mapped_attr_dir(FsContext *ctx, const char *path)
160{
161 int err;
4fa4ce71 162 char *attr_dir;
d3f8e138 163 char *tmp_path = g_strdup(path);
2c30dd74 164
4fa4ce71 165 attr_dir = g_strdup_printf("%s/%s/%s",
2c30dd74
AK
166 ctx->fs_root, dirname(tmp_path), VIRTFS_META_DIR);
167
168 err = mkdir(attr_dir, 0700);
169 if (err < 0 && errno == EEXIST) {
170 err = 0;
1237ad76 171 }
4fa4ce71 172 g_free(attr_dir);
d3f8e138 173 g_free(tmp_path);
1237ad76 174 return err;
131dcb25
AL
175}
176
2c30dd74
AK
177static int local_set_mapped_file_attr(FsContext *ctx,
178 const char *path, FsCred *credp)
179{
180 FILE *fp;
181 int ret = 0;
182 char buf[ATTR_MAX];
4fa4ce71 183 char *attr_path;
2c30dd74
AK
184 int uid = -1, gid = -1, mode = -1, rdev = -1;
185
4fa4ce71
CG
186 attr_path = local_mapped_attr_path(ctx, path);
187 fp = local_fopen(attr_path, "r");
2c30dd74
AK
188 if (!fp) {
189 goto create_map_file;
190 }
191 memset(buf, 0, ATTR_MAX);
192 while (fgets(buf, ATTR_MAX, fp)) {
193 if (!strncmp(buf, "virtfs.uid", 10)) {
194 uid = atoi(buf+11);
195 } else if (!strncmp(buf, "virtfs.gid", 10)) {
196 gid = atoi(buf+11);
197 } else if (!strncmp(buf, "virtfs.mode", 11)) {
198 mode = atoi(buf+12);
199 } else if (!strncmp(buf, "virtfs.rdev", 11)) {
200 rdev = atoi(buf+12);
201 }
202 memset(buf, 0, ATTR_MAX);
203 }
204 fclose(fp);
205 goto update_map_file;
206
207create_map_file:
208 ret = local_create_mapped_attr_dir(ctx, path);
209 if (ret < 0) {
210 goto err_out;
211 }
212
213update_map_file:
0ceb092e 214 fp = local_fopen(attr_path, "w");
2c30dd74
AK
215 if (!fp) {
216 ret = -1;
217 goto err_out;
218 }
219
220 if (credp->fc_uid != -1) {
221 uid = credp->fc_uid;
222 }
223 if (credp->fc_gid != -1) {
224 gid = credp->fc_gid;
225 }
226 if (credp->fc_mode != -1) {
227 mode = credp->fc_mode;
228 }
229 if (credp->fc_rdev != -1) {
230 rdev = credp->fc_rdev;
231 }
232
233
234 if (uid != -1) {
235 fprintf(fp, "virtfs.uid=%d\n", uid);
236 }
237 if (gid != -1) {
238 fprintf(fp, "virtfs.gid=%d\n", gid);
239 }
240 if (mode != -1) {
241 fprintf(fp, "virtfs.mode=%d\n", mode);
242 }
243 if (rdev != -1) {
244 fprintf(fp, "virtfs.rdev=%d\n", rdev);
245 }
246 fclose(fp);
247
248err_out:
4fa4ce71 249 g_free(attr_path);
2c30dd74
AK
250 return ret;
251}
252
758e8e38 253static int local_set_xattr(const char *path, FsCred *credp)
131dcb25 254{
758e8e38 255 int err;
2289be19 256
758e8e38 257 if (credp->fc_uid != -1) {
f8ad4a89
AK
258 uint32_t tmp_uid = cpu_to_le32(credp->fc_uid);
259 err = setxattr(path, "user.virtfs.uid", &tmp_uid, sizeof(uid_t), 0);
758e8e38
VJ
260 if (err) {
261 return err;
262 }
131dcb25 263 }
758e8e38 264 if (credp->fc_gid != -1) {
f8ad4a89
AK
265 uint32_t tmp_gid = cpu_to_le32(credp->fc_gid);
266 err = setxattr(path, "user.virtfs.gid", &tmp_gid, sizeof(gid_t), 0);
758e8e38
VJ
267 if (err) {
268 return err;
269 }
131dcb25 270 }
758e8e38 271 if (credp->fc_mode != -1) {
f8ad4a89
AK
272 uint32_t tmp_mode = cpu_to_le32(credp->fc_mode);
273 err = setxattr(path, "user.virtfs.mode", &tmp_mode, sizeof(mode_t), 0);
758e8e38
VJ
274 if (err) {
275 return err;
276 }
131dcb25 277 }
758e8e38 278 if (credp->fc_rdev != -1) {
f8ad4a89
AK
279 uint64_t tmp_rdev = cpu_to_le64(credp->fc_rdev);
280 err = setxattr(path, "user.virtfs.rdev", &tmp_rdev, sizeof(dev_t), 0);
758e8e38
VJ
281 if (err) {
282 return err;
283 }
131dcb25 284 }
131dcb25
AL
285 return 0;
286}
287
4750a96f 288static int local_post_create_passthrough(FsContext *fs_ctx, const char *path,
2289be19 289 FsCred *credp)
4750a96f 290{
4fa4ce71 291 char *buffer;
2289be19 292
4fa4ce71
CG
293 buffer = rpath(fs_ctx, path);
294 if (lchown(buffer, credp->fc_uid, credp->fc_gid) < 0) {
12848bfc
AK
295 /*
296 * If we fail to change ownership and if we are
297 * using security model none. Ignore the error
298 */
b97400ca 299 if ((fs_ctx->export_flags & V9FS_SEC_MASK) != V9FS_SM_NONE) {
4fa4ce71 300 goto err;
12848bfc 301 }
4750a96f 302 }
2d40564a 303
4fa4ce71
CG
304 if (chmod(buffer, credp->fc_mode & 07777) < 0) {
305 goto err;
2d40564a 306 }
4fa4ce71
CG
307
308 g_free(buffer);
4750a96f 309 return 0;
4fa4ce71
CG
310err:
311 g_free(buffer);
312 return -1;
4750a96f
VJ
313}
314
2289be19
AK
315static ssize_t local_readlink(FsContext *fs_ctx, V9fsPath *fs_path,
316 char *buf, size_t bufsz)
131dcb25 317{
879c2813 318 ssize_t tsize = -1;
4fa4ce71 319 char *buffer;
2289be19
AK
320 char *path = fs_path->data;
321
2c30dd74
AK
322 if ((fs_ctx->export_flags & V9FS_SM_MAPPED) ||
323 (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE)) {
879c2813 324 int fd;
4fa4ce71
CG
325 buffer = rpath(fs_ctx, path);
326 fd = open(buffer, O_RDONLY | O_NOFOLLOW);
327 g_free(buffer);
879c2813
VJ
328 if (fd == -1) {
329 return -1;
330 }
331 do {
332 tsize = read(fd, (void *)buf, bufsz);
333 } while (tsize == -1 && errno == EINTR);
334 close(fd);
b97400ca
AK
335 } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
336 (fs_ctx->export_flags & V9FS_SM_NONE)) {
4fa4ce71
CG
337 buffer = rpath(fs_ctx, path);
338 tsize = readlink(buffer, buf, bufsz);
339 g_free(buffer);
879c2813
VJ
340 }
341 return tsize;
131dcb25
AL
342}
343
cc720ddb 344static int local_close(FsContext *ctx, V9fsFidOpenState *fs)
131dcb25 345{
cc720ddb 346 return close(fs->fd);
131dcb25
AL
347}
348
cc720ddb 349static int local_closedir(FsContext *ctx, V9fsFidOpenState *fs)
131dcb25 350{
cc720ddb 351 return closedir(fs->dir);
131dcb25 352}
9f107513 353
cc720ddb
AK
354static int local_open(FsContext *ctx, V9fsPath *fs_path,
355 int flags, V9fsFidOpenState *fs)
a6568fe2 356{
4fa4ce71 357 char *buffer;
2289be19
AK
358 char *path = fs_path->data;
359
4fa4ce71
CG
360 buffer = rpath(ctx, path);
361 fs->fd = open(buffer, flags | O_NOFOLLOW);
362 g_free(buffer);
cc720ddb 363 return fs->fd;
a6568fe2
AL
364}
365
cc720ddb
AK
366static int local_opendir(FsContext *ctx,
367 V9fsPath *fs_path, V9fsFidOpenState *fs)
a6568fe2 368{
4fa4ce71 369 char *buffer;
2289be19
AK
370 char *path = fs_path->data;
371
4fa4ce71
CG
372 buffer = rpath(ctx, path);
373 fs->dir = opendir(buffer);
374 g_free(buffer);
cc720ddb
AK
375 if (!fs->dir) {
376 return -1;
377 }
378 return 0;
a6568fe2
AL
379}
380
cc720ddb 381static void local_rewinddir(FsContext *ctx, V9fsFidOpenState *fs)
a9231555 382{
0289a412 383 rewinddir(fs->dir);
a9231555
AL
384}
385
cc720ddb 386static off_t local_telldir(FsContext *ctx, V9fsFidOpenState *fs)
a9231555 387{
cc720ddb 388 return telldir(fs->dir);
a9231555
AL
389}
390
cc720ddb
AK
391static int local_readdir_r(FsContext *ctx, V9fsFidOpenState *fs,
392 struct dirent *entry,
2289be19 393 struct dirent **result)
a9231555 394{
2c30dd74
AK
395 int ret;
396
397again:
398 ret = readdir_r(fs->dir, entry, result);
840a1bf2
BB
399 if (ctx->export_flags & V9FS_SM_MAPPED) {
400 entry->d_type = DT_UNKNOWN;
401 } else if (ctx->export_flags & V9FS_SM_MAPPED_FILE) {
2c30dd74
AK
402 if (!ret && *result != NULL &&
403 !strcmp(entry->d_name, VIRTFS_META_DIR)) {
404 /* skp the meta data directory */
405 goto again;
406 }
840a1bf2 407 entry->d_type = DT_UNKNOWN;
2c30dd74
AK
408 }
409 return ret;
a9231555
AL
410}
411
cc720ddb 412static void local_seekdir(FsContext *ctx, V9fsFidOpenState *fs, off_t off)
a9231555 413{
0289a412 414 seekdir(fs->dir, off);
a9231555
AL
415}
416
cc720ddb
AK
417static ssize_t local_preadv(FsContext *ctx, V9fsFidOpenState *fs,
418 const struct iovec *iov,
56d15a53 419 int iovcnt, off_t offset)
a9231555 420{
56d15a53 421#ifdef CONFIG_PREADV
cc720ddb 422 return preadv(fs->fd, iov, iovcnt, offset);
56d15a53 423#else
cc720ddb 424 int err = lseek(fs->fd, offset, SEEK_SET);
56d15a53
SG
425 if (err == -1) {
426 return err;
427 } else {
cc720ddb 428 return readv(fs->fd, iov, iovcnt);
56d15a53
SG
429 }
430#endif
a9231555
AL
431}
432
cc720ddb
AK
433static ssize_t local_pwritev(FsContext *ctx, V9fsFidOpenState *fs,
434 const struct iovec *iov,
2289be19 435 int iovcnt, off_t offset)
8449360c 436{
d3ab98e6
AK
437 ssize_t ret
438;
56d15a53 439#ifdef CONFIG_PREADV
cc720ddb 440 ret = pwritev(fs->fd, iov, iovcnt, offset);
56d15a53 441#else
cc720ddb 442 int err = lseek(fs->fd, offset, SEEK_SET);
56d15a53
SG
443 if (err == -1) {
444 return err;
445 } else {
cc720ddb 446 ret = writev(fs->fd, iov, iovcnt);
56d15a53
SG
447 }
448#endif
d3ab98e6
AK
449#ifdef CONFIG_SYNC_FILE_RANGE
450 if (ret > 0 && ctx->export_flags & V9FS_IMMEDIATE_WRITEOUT) {
451 /*
452 * Initiate a writeback. This is not a data integrity sync.
453 * We want to ensure that we don't leave dirty pages in the cache
454 * after write when writeout=immediate is sepcified.
455 */
cc720ddb 456 sync_file_range(fs->fd, offset, ret,
d3ab98e6
AK
457 SYNC_FILE_RANGE_WAIT_BEFORE | SYNC_FILE_RANGE_WRITE);
458 }
459#endif
460 return ret;
8449360c
AL
461}
462
2289be19 463static int local_chmod(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
c494dd6f 464{
4fa4ce71
CG
465 char *buffer;
466 int ret = -1;
2289be19
AK
467 char *path = fs_path->data;
468
b97400ca 469 if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
4fa4ce71
CG
470 buffer = rpath(fs_ctx, path);
471 ret = local_set_xattr(buffer, credp);
472 g_free(buffer);
2c30dd74
AK
473 } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
474 return local_set_mapped_file_attr(fs_ctx, path, credp);
b97400ca
AK
475 } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
476 (fs_ctx->export_flags & V9FS_SM_NONE)) {
4fa4ce71
CG
477 buffer = rpath(fs_ctx, path);
478 ret = chmod(buffer, credp->fc_mode);
479 g_free(buffer);
e95ead32 480 }
4fa4ce71 481 return ret;
c494dd6f
AL
482}
483
2289be19
AK
484static int local_mknod(FsContext *fs_ctx, V9fsPath *dir_path,
485 const char *name, FsCred *credp)
c494dd6f 486{
2289be19 487 char *path;
1c293312
VJ
488 int err = -1;
489 int serrno = 0;
2289be19 490 V9fsString fullname;
4ed7b2c3 491 char *buffer = NULL;
1c293312 492
2289be19
AK
493 v9fs_string_init(&fullname);
494 v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
495 path = fullname.data;
496
1c293312 497 /* Determine the security model */
b97400ca 498 if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
4fa4ce71
CG
499 buffer = rpath(fs_ctx, path);
500 err = mknod(buffer, SM_LOCAL_MODE_BITS|S_IFREG, 0);
1c293312 501 if (err == -1) {
2289be19 502 goto out;
1c293312 503 }
4fa4ce71 504 err = local_set_xattr(buffer, credp);
1c293312
VJ
505 if (err == -1) {
506 serrno = errno;
507 goto err_end;
508 }
2c30dd74
AK
509 } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
510
4fa4ce71
CG
511 buffer = rpath(fs_ctx, path);
512 err = mknod(buffer, SM_LOCAL_MODE_BITS|S_IFREG, 0);
2c30dd74
AK
513 if (err == -1) {
514 goto out;
515 }
516 err = local_set_mapped_file_attr(fs_ctx, path, credp);
517 if (err == -1) {
518 serrno = errno;
519 goto err_end;
520 }
b97400ca
AK
521 } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
522 (fs_ctx->export_flags & V9FS_SM_NONE)) {
4fa4ce71
CG
523 buffer = rpath(fs_ctx, path);
524 err = mknod(buffer, credp->fc_mode, credp->fc_rdev);
1c293312 525 if (err == -1) {
2289be19 526 goto out;
1c293312
VJ
527 }
528 err = local_post_create_passthrough(fs_ctx, path, credp);
529 if (err == -1) {
530 serrno = errno;
531 goto err_end;
532 }
533 }
2289be19 534 goto out;
1c293312
VJ
535
536err_end:
4fa4ce71 537 remove(buffer);
1c293312 538 errno = serrno;
2289be19 539out:
4ed7b2c3 540 g_free(buffer);
2289be19 541 v9fs_string_free(&fullname);
1c293312 542 return err;
c494dd6f
AL
543}
544
2289be19
AK
545static int local_mkdir(FsContext *fs_ctx, V9fsPath *dir_path,
546 const char *name, FsCred *credp)
c494dd6f 547{
2289be19 548 char *path;
00ec5c37
VJ
549 int err = -1;
550 int serrno = 0;
2289be19 551 V9fsString fullname;
4ed7b2c3 552 char *buffer = NULL;
00ec5c37 553
2289be19
AK
554 v9fs_string_init(&fullname);
555 v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
556 path = fullname.data;
557
00ec5c37 558 /* Determine the security model */
b97400ca 559 if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
4fa4ce71
CG
560 buffer = rpath(fs_ctx, path);
561 err = mkdir(buffer, SM_LOCAL_DIR_MODE_BITS);
00ec5c37 562 if (err == -1) {
2289be19 563 goto out;
00ec5c37
VJ
564 }
565 credp->fc_mode = credp->fc_mode|S_IFDIR;
4fa4ce71 566 err = local_set_xattr(buffer, credp);
00ec5c37
VJ
567 if (err == -1) {
568 serrno = errno;
569 goto err_end;
570 }
2c30dd74 571 } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
4fa4ce71
CG
572 buffer = rpath(fs_ctx, path);
573 err = mkdir(buffer, SM_LOCAL_DIR_MODE_BITS);
2c30dd74
AK
574 if (err == -1) {
575 goto out;
576 }
577 credp->fc_mode = credp->fc_mode|S_IFDIR;
578 err = local_set_mapped_file_attr(fs_ctx, path, credp);
579 if (err == -1) {
580 serrno = errno;
581 goto err_end;
582 }
b97400ca
AK
583 } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
584 (fs_ctx->export_flags & V9FS_SM_NONE)) {
4fa4ce71
CG
585 buffer = rpath(fs_ctx, path);
586 err = mkdir(buffer, credp->fc_mode);
00ec5c37 587 if (err == -1) {
2289be19 588 goto out;
00ec5c37
VJ
589 }
590 err = local_post_create_passthrough(fs_ctx, path, credp);
591 if (err == -1) {
592 serrno = errno;
593 goto err_end;
594 }
595 }
2289be19 596 goto out;
00ec5c37
VJ
597
598err_end:
4fa4ce71 599 remove(buffer);
00ec5c37 600 errno = serrno;
2289be19 601out:
4ed7b2c3 602 g_free(buffer);
2289be19 603 v9fs_string_free(&fullname);
00ec5c37 604 return err;
c494dd6f
AL
605}
606
8b888272 607static int local_fstat(FsContext *fs_ctx, int fid_type,
cc720ddb 608 V9fsFidOpenState *fs, struct stat *stbuf)
c494dd6f 609{
8b888272
AK
610 int err, fd;
611
612 if (fid_type == P9_FID_DIR) {
613 fd = dirfd(fs->dir);
614 } else {
615 fd = fs->fd;
616 }
617
618 err = fstat(fd, stbuf);
1237ad76
VJ
619 if (err) {
620 return err;
621 }
b97400ca 622 if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
1237ad76
VJ
623 /* Actual credentials are part of extended attrs */
624 uid_t tmp_uid;
625 gid_t tmp_gid;
626 mode_t tmp_mode;
627 dev_t tmp_dev;
628
f8ad4a89
AK
629 if (fgetxattr(fd, "user.virtfs.uid", &tmp_uid, sizeof(uid_t)) > 0) {
630 stbuf->st_uid = le32_to_cpu(tmp_uid);
1237ad76 631 }
f8ad4a89
AK
632 if (fgetxattr(fd, "user.virtfs.gid", &tmp_gid, sizeof(gid_t)) > 0) {
633 stbuf->st_gid = le32_to_cpu(tmp_gid);
1237ad76 634 }
f8ad4a89
AK
635 if (fgetxattr(fd, "user.virtfs.mode", &tmp_mode, sizeof(mode_t)) > 0) {
636 stbuf->st_mode = le32_to_cpu(tmp_mode);
1237ad76 637 }
f8ad4a89
AK
638 if (fgetxattr(fd, "user.virtfs.rdev", &tmp_dev, sizeof(dev_t)) > 0) {
639 stbuf->st_rdev = le64_to_cpu(tmp_dev);
1237ad76 640 }
2c30dd74
AK
641 } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
642 errno = EOPNOTSUPP;
643 return -1;
1237ad76
VJ
644 }
645 return err;
c494dd6f
AL
646}
647
2289be19 648static int local_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name,
cc720ddb 649 int flags, FsCred *credp, V9fsFidOpenState *fs)
c494dd6f 650{
2289be19 651 char *path;
4750a96f
VJ
652 int fd = -1;
653 int err = -1;
654 int serrno = 0;
2289be19 655 V9fsString fullname;
4ed7b2c3 656 char *buffer = NULL;
4750a96f 657
0ceb092e
AK
658 /*
659 * Mark all the open to not follow symlinks
660 */
661 flags |= O_NOFOLLOW;
662
2289be19
AK
663 v9fs_string_init(&fullname);
664 v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
665 path = fullname.data;
666
4750a96f 667 /* Determine the security model */
b97400ca 668 if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
4fa4ce71
CG
669 buffer = rpath(fs_ctx, path);
670 fd = open(buffer, flags, SM_LOCAL_MODE_BITS);
4750a96f 671 if (fd == -1) {
2289be19
AK
672 err = fd;
673 goto out;
4750a96f
VJ
674 }
675 credp->fc_mode = credp->fc_mode|S_IFREG;
676 /* Set cleint credentials in xattr */
4fa4ce71 677 err = local_set_xattr(buffer, credp);
4750a96f
VJ
678 if (err == -1) {
679 serrno = errno;
680 goto err_end;
681 }
2c30dd74 682 } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
4fa4ce71
CG
683 buffer = rpath(fs_ctx, path);
684 fd = open(buffer, flags, SM_LOCAL_MODE_BITS);
2c30dd74
AK
685 if (fd == -1) {
686 err = fd;
687 goto out;
688 }
689 credp->fc_mode = credp->fc_mode|S_IFREG;
690 /* Set client credentials in .virtfs_metadata directory files */
691 err = local_set_mapped_file_attr(fs_ctx, path, credp);
692 if (err == -1) {
693 serrno = errno;
694 goto err_end;
695 }
b97400ca
AK
696 } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
697 (fs_ctx->export_flags & V9FS_SM_NONE)) {
4fa4ce71
CG
698 buffer = rpath(fs_ctx, path);
699 fd = open(buffer, flags, credp->fc_mode);
4750a96f 700 if (fd == -1) {
2289be19
AK
701 err = fd;
702 goto out;
4750a96f
VJ
703 }
704 err = local_post_create_passthrough(fs_ctx, path, credp);
705 if (err == -1) {
706 serrno = errno;
707 goto err_end;
708 }
709 }
2289be19 710 err = fd;
cc720ddb 711 fs->fd = fd;
2289be19 712 goto out;
4750a96f
VJ
713
714err_end:
715 close(fd);
4fa4ce71 716 remove(buffer);
4750a96f 717 errno = serrno;
2289be19 718out:
4ed7b2c3 719 g_free(buffer);
2289be19 720 v9fs_string_free(&fullname);
4750a96f 721 return err;
c494dd6f
AL
722}
723
758e8e38 724
879c2813 725static int local_symlink(FsContext *fs_ctx, const char *oldpath,
2289be19 726 V9fsPath *dir_path, const char *name, FsCred *credp)
c494dd6f 727{
879c2813
VJ
728 int err = -1;
729 int serrno = 0;
2289be19
AK
730 char *newpath;
731 V9fsString fullname;
4ed7b2c3 732 char *buffer = NULL;
879c2813 733
2289be19
AK
734 v9fs_string_init(&fullname);
735 v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
736 newpath = fullname.data;
737
879c2813 738 /* Determine the security model */
b97400ca 739 if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
879c2813
VJ
740 int fd;
741 ssize_t oldpath_size, write_size;
4fa4ce71
CG
742 buffer = rpath(fs_ctx, newpath);
743 fd = open(buffer, O_CREAT|O_EXCL|O_RDWR|O_NOFOLLOW, SM_LOCAL_MODE_BITS);
879c2813 744 if (fd == -1) {
2289be19
AK
745 err = fd;
746 goto out;
879c2813
VJ
747 }
748 /* Write the oldpath (target) to the file. */
f35bde2f 749 oldpath_size = strlen(oldpath);
879c2813
VJ
750 do {
751 write_size = write(fd, (void *)oldpath, oldpath_size);
752 } while (write_size == -1 && errno == EINTR);
753
754 if (write_size != oldpath_size) {
755 serrno = errno;
756 close(fd);
757 err = -1;
758 goto err_end;
759 }
760 close(fd);
761 /* Set cleint credentials in symlink's xattr */
762 credp->fc_mode = credp->fc_mode|S_IFLNK;
4fa4ce71 763 err = local_set_xattr(buffer, credp);
879c2813
VJ
764 if (err == -1) {
765 serrno = errno;
766 goto err_end;
767 }
2c30dd74
AK
768 } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
769 int fd;
770 ssize_t oldpath_size, write_size;
4fa4ce71
CG
771 buffer = rpath(fs_ctx, newpath);
772 fd = open(buffer, O_CREAT|O_EXCL|O_RDWR|O_NOFOLLOW, SM_LOCAL_MODE_BITS);
2c30dd74
AK
773 if (fd == -1) {
774 err = fd;
775 goto out;
776 }
777 /* Write the oldpath (target) to the file. */
778 oldpath_size = strlen(oldpath);
779 do {
780 write_size = write(fd, (void *)oldpath, oldpath_size);
781 } while (write_size == -1 && errno == EINTR);
782
783 if (write_size != oldpath_size) {
784 serrno = errno;
785 close(fd);
786 err = -1;
787 goto err_end;
788 }
789 close(fd);
790 /* Set cleint credentials in symlink's xattr */
791 credp->fc_mode = credp->fc_mode|S_IFLNK;
792 err = local_set_mapped_file_attr(fs_ctx, newpath, credp);
793 if (err == -1) {
794 serrno = errno;
795 goto err_end;
796 }
b97400ca
AK
797 } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
798 (fs_ctx->export_flags & V9FS_SM_NONE)) {
4fa4ce71
CG
799 buffer = rpath(fs_ctx, newpath);
800 err = symlink(oldpath, buffer);
879c2813 801 if (err) {
2289be19 802 goto out;
879c2813 803 }
4fa4ce71 804 err = lchown(buffer, credp->fc_uid, credp->fc_gid);
879c2813 805 if (err == -1) {
12848bfc
AK
806 /*
807 * If we fail to change ownership and if we are
808 * using security model none. Ignore the error
809 */
b97400ca 810 if ((fs_ctx->export_flags & V9FS_SEC_MASK) != V9FS_SM_NONE) {
12848bfc
AK
811 serrno = errno;
812 goto err_end;
813 } else
814 err = 0;
879c2813
VJ
815 }
816 }
2289be19 817 goto out;
879c2813
VJ
818
819err_end:
4fa4ce71 820 remove(buffer);
879c2813 821 errno = serrno;
2289be19 822out:
4ed7b2c3 823 g_free(buffer);
2289be19 824 v9fs_string_free(&fullname);
879c2813 825 return err;
c494dd6f
AL
826}
827
2289be19
AK
828static int local_link(FsContext *ctx, V9fsPath *oldpath,
829 V9fsPath *dirpath, const char *name)
c494dd6f 830{
2289be19
AK
831 int ret;
832 V9fsString newpath;
4fa4ce71 833 char *buffer, *buffer1;
c494dd6f 834
2289be19
AK
835 v9fs_string_init(&newpath);
836 v9fs_string_sprintf(&newpath, "%s/%s", dirpath->data, name);
837
4fa4ce71
CG
838 buffer = rpath(ctx, oldpath->data);
839 buffer1 = rpath(ctx, newpath.data);
840 ret = link(buffer, buffer1);
841 g_free(buffer);
842 g_free(buffer1);
2c30dd74
AK
843
844 /* now link the virtfs_metadata files */
845 if (!ret && (ctx->export_flags & V9FS_SM_MAPPED_FILE)) {
846 /* Link the .virtfs_metadata files. Create the metada directory */
847 ret = local_create_mapped_attr_dir(ctx, newpath.data);
848 if (ret < 0) {
849 goto err_out;
850 }
4fa4ce71
CG
851 buffer = local_mapped_attr_path(ctx, oldpath->data);
852 buffer1 = local_mapped_attr_path(ctx, newpath.data);
853 ret = link(buffer, buffer1);
854 g_free(buffer);
855 g_free(buffer1);
2c30dd74
AK
856 if (ret < 0 && errno != ENOENT) {
857 goto err_out;
858 }
859 }
860err_out:
2289be19
AK
861 v9fs_string_free(&newpath);
862 return ret;
c494dd6f
AL
863}
864
2289be19 865static int local_truncate(FsContext *ctx, V9fsPath *fs_path, off_t size)
8cf89e00 866{
4fa4ce71
CG
867 char *buffer;
868 int ret;
2289be19
AK
869 char *path = fs_path->data;
870
4fa4ce71
CG
871 buffer = rpath(ctx, path);
872 ret = truncate(buffer, size);
873 g_free(buffer);
874 return ret;
8cf89e00
AL
875}
876
877static int local_rename(FsContext *ctx, const char *oldpath,
878 const char *newpath)
879{
2c30dd74 880 int err;
4fa4ce71 881 char *buffer, *buffer1;
8cf89e00 882
2c30dd74
AK
883 if (ctx->export_flags & V9FS_SM_MAPPED_FILE) {
884 err = local_create_mapped_attr_dir(ctx, newpath);
885 if (err < 0) {
886 return err;
887 }
888 /* rename the .virtfs_metadata files */
4fa4ce71
CG
889 buffer = local_mapped_attr_path(ctx, oldpath);
890 buffer1 = local_mapped_attr_path(ctx, newpath);
891 err = rename(buffer, buffer1);
892 g_free(buffer);
893 g_free(buffer1);
2c30dd74
AK
894 if (err < 0 && errno != ENOENT) {
895 return err;
896 }
897 }
4fa4ce71
CG
898
899 buffer = rpath(ctx, oldpath);
900 buffer1 = rpath(ctx, newpath);
901 err = rename(buffer, buffer1);
902 g_free(buffer);
903 g_free(buffer1);
904 return err;
8cf89e00
AL
905}
906
2289be19 907static int local_chown(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
8cf89e00 908{
4fa4ce71
CG
909 char *buffer;
910 int ret = -1;
2289be19
AK
911 char *path = fs_path->data;
912
c79ce737 913 if ((credp->fc_uid == -1 && credp->fc_gid == -1) ||
17b1971f
AK
914 (fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
915 (fs_ctx->export_flags & V9FS_SM_NONE)) {
4fa4ce71
CG
916 buffer = rpath(fs_ctx, path);
917 ret = lchown(buffer, credp->fc_uid, credp->fc_gid);
918 g_free(buffer);
b97400ca 919 } else if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
4fa4ce71
CG
920 buffer = rpath(fs_ctx, path);
921 ret = local_set_xattr(buffer, credp);
922 g_free(buffer);
2c30dd74
AK
923 } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
924 return local_set_mapped_file_attr(fs_ctx, path, credp);
f7613bee 925 }
4fa4ce71 926 return ret;
8cf89e00
AL
927}
928
2289be19 929static int local_utimensat(FsContext *s, V9fsPath *fs_path,
38671423 930 const struct timespec *buf)
8cf89e00 931{
4fa4ce71
CG
932 char *buffer;
933 int ret;
2289be19
AK
934 char *path = fs_path->data;
935
4fa4ce71
CG
936 buffer = rpath(s, path);
937 ret = qemu_utimens(buffer, buf);
938 g_free(buffer);
939 return ret;
8cf89e00
AL
940}
941
5bae1900
AL
942static int local_remove(FsContext *ctx, const char *path)
943{
2c30dd74
AK
944 int err;
945 struct stat stbuf;
4fa4ce71 946 char *buffer;
2c30dd74
AK
947
948 if (ctx->export_flags & V9FS_SM_MAPPED_FILE) {
4fa4ce71
CG
949 buffer = rpath(ctx, path);
950 err = lstat(buffer, &stbuf);
951 g_free(buffer);
2c30dd74
AK
952 if (err) {
953 goto err_out;
954 }
955 /*
956 * If directory remove .virtfs_metadata contained in the
957 * directory
958 */
959 if (S_ISDIR(stbuf.st_mode)) {
4fa4ce71
CG
960 buffer = g_strdup_printf("%s/%s/%s", ctx->fs_root,
961 path, VIRTFS_META_DIR);
2c30dd74 962 err = remove(buffer);
4fa4ce71 963 g_free(buffer);
2c30dd74
AK
964 if (err < 0 && errno != ENOENT) {
965 /*
966 * We didn't had the .virtfs_metadata file. May be file created
967 * in non-mapped mode ?. Ignore ENOENT.
968 */
969 goto err_out;
970 }
971 }
972 /*
973 * Now remove the name from parent directory
974 * .virtfs_metadata directory
975 */
4fa4ce71
CG
976 buffer = local_mapped_attr_path(ctx, path);
977 err = remove(buffer);
978 g_free(buffer);
2c30dd74
AK
979 if (err < 0 && errno != ENOENT) {
980 /*
981 * We didn't had the .virtfs_metadata file. May be file created
982 * in non-mapped mode ?. Ignore ENOENT.
983 */
984 goto err_out;
985 }
986 }
4fa4ce71
CG
987
988 buffer = rpath(ctx, path);
989 err = remove(buffer);
990 g_free(buffer);
2c30dd74
AK
991err_out:
992 return err;
5bae1900
AL
993}
994
8b888272
AK
995static int local_fsync(FsContext *ctx, int fid_type,
996 V9fsFidOpenState *fs, int datasync)
8cf89e00 997{
8b888272
AK
998 int fd;
999
1000 if (fid_type == P9_FID_DIR) {
1001 fd = dirfd(fs->dir);
1002 } else {
1003 fd = fs->fd;
1004 }
1005
49594973 1006 if (datasync) {
8b888272 1007 return qemu_fdatasync(fd);
49594973 1008 } else {
8b888272 1009 return fsync(fd);
49594973 1010 }
8cf89e00
AL
1011}
1012
2289be19 1013static int local_statfs(FsContext *s, V9fsPath *fs_path, struct statfs *stbuf)
be940c87 1014{
4fa4ce71
CG
1015 char *buffer;
1016 int ret;
2289be19
AK
1017 char *path = fs_path->data;
1018
4fa4ce71
CG
1019 buffer = rpath(s, path);
1020 ret = statfs(buffer, stbuf);
1021 g_free(buffer);
1022 return ret;
be940c87
MK
1023}
1024
2289be19 1025static ssize_t local_lgetxattr(FsContext *ctx, V9fsPath *fs_path,
fa32ef88
AK
1026 const char *name, void *value, size_t size)
1027{
2289be19
AK
1028 char *path = fs_path->data;
1029
fc22118d 1030 return v9fs_get_xattr(ctx, path, name, value, size);
fa32ef88
AK
1031}
1032
2289be19 1033static ssize_t local_llistxattr(FsContext *ctx, V9fsPath *fs_path,
fa32ef88
AK
1034 void *value, size_t size)
1035{
2289be19
AK
1036 char *path = fs_path->data;
1037
fc22118d 1038 return v9fs_list_xattr(ctx, path, value, size);
fa32ef88
AK
1039}
1040
2289be19 1041static int local_lsetxattr(FsContext *ctx, V9fsPath *fs_path, const char *name,
10b468bd
AK
1042 void *value, size_t size, int flags)
1043{
2289be19
AK
1044 char *path = fs_path->data;
1045
fc22118d 1046 return v9fs_set_xattr(ctx, path, name, value, size, flags);
10b468bd
AK
1047}
1048
2289be19
AK
1049static int local_lremovexattr(FsContext *ctx, V9fsPath *fs_path,
1050 const char *name)
9ed3ef26 1051{
2289be19
AK
1052 char *path = fs_path->data;
1053
fc22118d 1054 return v9fs_remove_xattr(ctx, path, name);
9ed3ef26
AK
1055}
1056
2289be19
AK
1057static int local_name_to_path(FsContext *ctx, V9fsPath *dir_path,
1058 const char *name, V9fsPath *target)
1059{
1060 if (dir_path) {
1061 v9fs_string_sprintf((V9fsString *)target, "%s/%s",
1062 dir_path->data, name);
1063 } else {
1064 v9fs_string_sprintf((V9fsString *)target, "%s", name);
1065 }
1066 /* Bump the size for including terminating NULL */
1067 target->size++;
1068 return 0;
1069}
1070
1071static int local_renameat(FsContext *ctx, V9fsPath *olddir,
1072 const char *old_name, V9fsPath *newdir,
1073 const char *new_name)
1074{
1075 int ret;
1076 V9fsString old_full_name, new_full_name;
1077
1078 v9fs_string_init(&old_full_name);
1079 v9fs_string_init(&new_full_name);
1080
1081 v9fs_string_sprintf(&old_full_name, "%s/%s", olddir->data, old_name);
1082 v9fs_string_sprintf(&new_full_name, "%s/%s", newdir->data, new_name);
1083
1084 ret = local_rename(ctx, old_full_name.data, new_full_name.data);
1085 v9fs_string_free(&old_full_name);
1086 v9fs_string_free(&new_full_name);
1087 return ret;
1088}
1089
1090static int local_unlinkat(FsContext *ctx, V9fsPath *dir,
1091 const char *name, int flags)
1092{
1093 int ret;
1094 V9fsString fullname;
4fa4ce71 1095 char *buffer;
2c30dd74 1096
2289be19
AK
1097 v9fs_string_init(&fullname);
1098
1099 v9fs_string_sprintf(&fullname, "%s/%s", dir->data, name);
2c30dd74
AK
1100 if (ctx->export_flags & V9FS_SM_MAPPED_FILE) {
1101 if (flags == AT_REMOVEDIR) {
1102 /*
1103 * If directory remove .virtfs_metadata contained in the
1104 * directory
1105 */
4fa4ce71
CG
1106 buffer = g_strdup_printf("%s/%s/%s", ctx->fs_root,
1107 fullname.data, VIRTFS_META_DIR);
2c30dd74 1108 ret = remove(buffer);
4fa4ce71 1109 g_free(buffer);
2c30dd74
AK
1110 if (ret < 0 && errno != ENOENT) {
1111 /*
1112 * We didn't had the .virtfs_metadata file. May be file created
1113 * in non-mapped mode ?. Ignore ENOENT.
1114 */
1115 goto err_out;
1116 }
1117 }
1118 /*
1119 * Now remove the name from parent directory
1120 * .virtfs_metadata directory.
1121 */
4fa4ce71
CG
1122 buffer = local_mapped_attr_path(ctx, fullname.data);
1123 ret = remove(buffer);
1124 g_free(buffer);
2c30dd74
AK
1125 if (ret < 0 && errno != ENOENT) {
1126 /*
1127 * We didn't had the .virtfs_metadata file. May be file created
1128 * in non-mapped mode ?. Ignore ENOENT.
1129 */
1130 goto err_out;
1131 }
1132 }
1133 /* Remove the name finally */
4fa4ce71
CG
1134 buffer = rpath(ctx, fullname.data);
1135 ret = remove(buffer);
1136 g_free(buffer);
2289be19 1137
2c30dd74 1138err_out:
75b7931e 1139 v9fs_string_free(&fullname);
2289be19
AK
1140 return ret;
1141}
9ed3ef26 1142
e06a765e
HPB
1143static int local_ioc_getversion(FsContext *ctx, V9fsPath *path,
1144 mode_t st_mode, uint64_t *st_gen)
1145{
ae0f940e 1146#ifdef FS_IOC_GETVERSION
0e5fc994 1147 int err;
cc720ddb
AK
1148 V9fsFidOpenState fid_open;
1149
e06a765e
HPB
1150 /*
1151 * Do not try to open special files like device nodes, fifos etc
1152 * We can get fd for regular files and directories only
1153 */
1154 if (!S_ISREG(st_mode) && !S_ISDIR(st_mode)) {
1a9978a5
KS
1155 errno = ENOTTY;
1156 return -1;
e06a765e 1157 }
cc720ddb
AK
1158 err = local_open(ctx, path, O_RDONLY, &fid_open);
1159 if (err < 0) {
1160 return err;
e06a765e 1161 }
cc720ddb
AK
1162 err = ioctl(fid_open.fd, FS_IOC_GETVERSION, st_gen);
1163 local_close(ctx, &fid_open);
0e5fc994 1164 return err;
ae0f940e 1165#else
0e5fc994
KS
1166 errno = ENOTTY;
1167 return -1;
ae0f940e 1168#endif
e06a765e
HPB
1169}
1170
0174fe73
AK
1171static int local_init(FsContext *ctx)
1172{
2507718b 1173 int err = 0;
e06a765e
HPB
1174 struct statfs stbuf;
1175
2c30dd74
AK
1176 if (ctx->export_flags & V9FS_SM_PASSTHROUGH) {
1177 ctx->xops = passthrough_xattr_ops;
1178 } else if (ctx->export_flags & V9FS_SM_MAPPED) {
1179 ctx->xops = mapped_xattr_ops;
1180 } else if (ctx->export_flags & V9FS_SM_NONE) {
1181 ctx->xops = none_xattr_ops;
1182 } else if (ctx->export_flags & V9FS_SM_MAPPED_FILE) {
1183 /*
1184 * xattr operation for mapped-file and passthrough
1185 * remain same.
1186 */
1187 ctx->xops = passthrough_xattr_ops;
1188 }
c98f1d4a 1189 ctx->export_flags |= V9FS_PATHNAME_FSCONTEXT;
2507718b
AK
1190#ifdef FS_IOC_GETVERSION
1191 /*
1192 * use ioc_getversion only if the iocl is definied
1193 */
e06a765e
HPB
1194 err = statfs(ctx->fs_root, &stbuf);
1195 if (!err) {
1196 switch (stbuf.f_type) {
1197 case EXT2_SUPER_MAGIC:
1198 case BTRFS_SUPER_MAGIC:
1199 case REISERFS_SUPER_MAGIC:
1200 case XFS_SUPER_MAGIC:
1201 ctx->exops.get_st_gen = local_ioc_getversion;
1202 break;
1203 }
1204 }
2507718b 1205#endif
e06a765e 1206 return err;
0174fe73
AK
1207}
1208
99519f0a
AK
1209static int local_parse_opts(QemuOpts *opts, struct FsDriverEntry *fse)
1210{
1211 const char *sec_model = qemu_opt_get(opts, "security_model");
1212 const char *path = qemu_opt_get(opts, "path");
1213
1214 if (!sec_model) {
63325b18
GK
1215 error_report("Security model not specified, local fs needs security model");
1216 error_printf("valid options are:"
1217 "\tsecurity_model=[passthrough|mapped-xattr|mapped-file|none]\n");
99519f0a
AK
1218 return -1;
1219 }
1220
1221 if (!strcmp(sec_model, "passthrough")) {
1222 fse->export_flags |= V9FS_SM_PASSTHROUGH;
2c30dd74
AK
1223 } else if (!strcmp(sec_model, "mapped") ||
1224 !strcmp(sec_model, "mapped-xattr")) {
99519f0a
AK
1225 fse->export_flags |= V9FS_SM_MAPPED;
1226 } else if (!strcmp(sec_model, "none")) {
1227 fse->export_flags |= V9FS_SM_NONE;
2c30dd74
AK
1228 } else if (!strcmp(sec_model, "mapped-file")) {
1229 fse->export_flags |= V9FS_SM_MAPPED_FILE;
99519f0a 1230 } else {
63325b18
GK
1231 error_report("Invalid security model %s specified", sec_model);
1232 error_printf("valid options are:"
1233 "\t[passthrough|mapped-xattr|mapped-file|none]\n");
99519f0a
AK
1234 return -1;
1235 }
1236
1237 if (!path) {
63325b18 1238 error_report("fsdev: No path specified");
99519f0a
AK
1239 return -1;
1240 }
1241 fse->path = g_strdup(path);
1242
1243 return 0;
1244}
1245
9f107513 1246FileOperations local_ops = {
99519f0a 1247 .parse_opts = local_parse_opts,
0174fe73 1248 .init = local_init,
131dcb25 1249 .lstat = local_lstat,
131dcb25
AL
1250 .readlink = local_readlink,
1251 .close = local_close,
1252 .closedir = local_closedir,
a6568fe2
AL
1253 .open = local_open,
1254 .opendir = local_opendir,
a9231555
AL
1255 .rewinddir = local_rewinddir,
1256 .telldir = local_telldir,
5f524c1e 1257 .readdir_r = local_readdir_r,
a9231555 1258 .seekdir = local_seekdir,
56d15a53
SG
1259 .preadv = local_preadv,
1260 .pwritev = local_pwritev,
c494dd6f
AL
1261 .chmod = local_chmod,
1262 .mknod = local_mknod,
c494dd6f
AL
1263 .mkdir = local_mkdir,
1264 .fstat = local_fstat,
1265 .open2 = local_open2,
1266 .symlink = local_symlink,
1267 .link = local_link,
8cf89e00
AL
1268 .truncate = local_truncate,
1269 .rename = local_rename,
1270 .chown = local_chown,
74bc02b2 1271 .utimensat = local_utimensat,
5bae1900 1272 .remove = local_remove,
8cf89e00 1273 .fsync = local_fsync,
be940c87 1274 .statfs = local_statfs,
fa32ef88
AK
1275 .lgetxattr = local_lgetxattr,
1276 .llistxattr = local_llistxattr,
10b468bd 1277 .lsetxattr = local_lsetxattr,
9ed3ef26 1278 .lremovexattr = local_lremovexattr,
2289be19
AK
1279 .name_to_path = local_name_to_path,
1280 .renameat = local_renameat,
1281 .unlinkat = local_unlinkat,
9f107513 1282};
This page took 0.620752 seconds and 4 git commands to generate.