|
|
1.1 root 1: /*
2: * Virtio 9p Posix callback
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: */
13:
14: #include "hw/virtio.h"
15: #include "virtio-9p.h"
16: #include "virtio-9p-xattr.h"
17: #include <arpa/inet.h>
18: #include <pwd.h>
19: #include <grp.h>
20: #include <sys/socket.h>
21: #include <sys/un.h>
1.1.1.2 ! root 22: #include "qemu-xattr.h"
! 23: #include <linux/fs.h>
! 24: #ifdef CONFIG_LINUX_MAGIC_H
! 25: #include <linux/magic.h>
! 26: #endif
! 27: #include <sys/ioctl.h>
1.1 root 28:
1.1.1.2 ! root 29: #ifndef XFS_SUPER_MAGIC
! 30: #define XFS_SUPER_MAGIC 0x58465342
! 31: #endif
! 32: #ifndef EXT2_SUPER_MAGIC
! 33: #define EXT2_SUPER_MAGIC 0xEF53
! 34: #endif
! 35: #ifndef REISERFS_SUPER_MAGIC
! 36: #define REISERFS_SUPER_MAGIC 0x52654973
! 37: #endif
! 38: #ifndef BTRFS_SUPER_MAGIC
! 39: #define BTRFS_SUPER_MAGIC 0x9123683E
! 40: #endif
1.1 root 41:
1.1.1.2 ! root 42: static int local_lstat(FsContext *fs_ctx, V9fsPath *fs_path, struct stat *stbuf)
1.1 root 43: {
44: int err;
45: char buffer[PATH_MAX];
1.1.1.2 ! root 46: char *path = fs_path->data;
! 47:
1.1 root 48: err = lstat(rpath(fs_ctx, path, buffer), stbuf);
49: if (err) {
50: return err;
51: }
1.1.1.2 ! root 52: if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
1.1 root 53: /* Actual credentials are part of extended attrs */
54: uid_t tmp_uid;
55: gid_t tmp_gid;
56: mode_t tmp_mode;
57: dev_t tmp_dev;
58: if (getxattr(rpath(fs_ctx, path, buffer), "user.virtfs.uid", &tmp_uid,
59: sizeof(uid_t)) > 0) {
60: stbuf->st_uid = tmp_uid;
61: }
62: if (getxattr(rpath(fs_ctx, path, buffer), "user.virtfs.gid", &tmp_gid,
63: sizeof(gid_t)) > 0) {
64: stbuf->st_gid = tmp_gid;
65: }
66: if (getxattr(rpath(fs_ctx, path, buffer), "user.virtfs.mode",
67: &tmp_mode, sizeof(mode_t)) > 0) {
68: stbuf->st_mode = tmp_mode;
69: }
70: if (getxattr(rpath(fs_ctx, path, buffer), "user.virtfs.rdev", &tmp_dev,
71: sizeof(dev_t)) > 0) {
72: stbuf->st_rdev = tmp_dev;
73: }
74: }
75: return err;
76: }
77:
78: static int local_set_xattr(const char *path, FsCred *credp)
79: {
80: int err;
1.1.1.2 ! root 81:
1.1 root 82: if (credp->fc_uid != -1) {
83: err = setxattr(path, "user.virtfs.uid", &credp->fc_uid, sizeof(uid_t),
84: 0);
85: if (err) {
86: return err;
87: }
88: }
89: if (credp->fc_gid != -1) {
90: err = setxattr(path, "user.virtfs.gid", &credp->fc_gid, sizeof(gid_t),
91: 0);
92: if (err) {
93: return err;
94: }
95: }
96: if (credp->fc_mode != -1) {
97: err = setxattr(path, "user.virtfs.mode", &credp->fc_mode,
98: sizeof(mode_t), 0);
99: if (err) {
100: return err;
101: }
102: }
103: if (credp->fc_rdev != -1) {
104: err = setxattr(path, "user.virtfs.rdev", &credp->fc_rdev,
105: sizeof(dev_t), 0);
106: if (err) {
107: return err;
108: }
109: }
110: return 0;
111: }
112:
113: static int local_post_create_passthrough(FsContext *fs_ctx, const char *path,
1.1.1.2 ! root 114: FsCred *credp)
1.1 root 115: {
116: char buffer[PATH_MAX];
1.1.1.2 ! root 117:
1.1 root 118: if (chmod(rpath(fs_ctx, path, buffer), credp->fc_mode & 07777) < 0) {
119: return -1;
120: }
121: if (lchown(rpath(fs_ctx, path, buffer), credp->fc_uid,
122: credp->fc_gid) < 0) {
123: /*
124: * If we fail to change ownership and if we are
125: * using security model none. Ignore the error
126: */
1.1.1.2 ! root 127: if ((fs_ctx->export_flags & V9FS_SEC_MASK) != V9FS_SM_NONE) {
1.1 root 128: return -1;
129: }
130: }
131: return 0;
132: }
133:
1.1.1.2 ! root 134: static ssize_t local_readlink(FsContext *fs_ctx, V9fsPath *fs_path,
! 135: char *buf, size_t bufsz)
1.1 root 136: {
137: ssize_t tsize = -1;
138: char buffer[PATH_MAX];
1.1.1.2 ! root 139: char *path = fs_path->data;
! 140:
! 141: if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
1.1 root 142: int fd;
143: fd = open(rpath(fs_ctx, path, buffer), O_RDONLY);
144: if (fd == -1) {
145: return -1;
146: }
147: do {
148: tsize = read(fd, (void *)buf, bufsz);
149: } while (tsize == -1 && errno == EINTR);
150: close(fd);
151: return tsize;
1.1.1.2 ! root 152: } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
! 153: (fs_ctx->export_flags & V9FS_SM_NONE)) {
1.1 root 154: tsize = readlink(rpath(fs_ctx, path, buffer), buf, bufsz);
155: }
156: return tsize;
157: }
158:
1.1.1.2 ! root 159: static int local_close(FsContext *ctx, V9fsFidOpenState *fs)
1.1 root 160: {
1.1.1.2 ! root 161: return close(fs->fd);
1.1 root 162: }
163:
1.1.1.2 ! root 164: static int local_closedir(FsContext *ctx, V9fsFidOpenState *fs)
1.1 root 165: {
1.1.1.2 ! root 166: return closedir(fs->dir);
1.1 root 167: }
168:
1.1.1.2 ! root 169: static int local_open(FsContext *ctx, V9fsPath *fs_path,
! 170: int flags, V9fsFidOpenState *fs)
1.1 root 171: {
172: char buffer[PATH_MAX];
1.1.1.2 ! root 173: char *path = fs_path->data;
! 174:
! 175: fs->fd = open(rpath(ctx, path, buffer), flags);
! 176: return fs->fd;
1.1 root 177: }
178:
1.1.1.2 ! root 179: static int local_opendir(FsContext *ctx,
! 180: V9fsPath *fs_path, V9fsFidOpenState *fs)
1.1 root 181: {
182: char buffer[PATH_MAX];
1.1.1.2 ! root 183: char *path = fs_path->data;
! 184:
! 185: fs->dir = opendir(rpath(ctx, path, buffer));
! 186: if (!fs->dir) {
! 187: return -1;
! 188: }
! 189: return 0;
1.1 root 190: }
191:
1.1.1.2 ! root 192: static void local_rewinddir(FsContext *ctx, V9fsFidOpenState *fs)
1.1 root 193: {
1.1.1.2 ! root 194: return rewinddir(fs->dir);
1.1 root 195: }
196:
1.1.1.2 ! root 197: static off_t local_telldir(FsContext *ctx, V9fsFidOpenState *fs)
1.1 root 198: {
1.1.1.2 ! root 199: return telldir(fs->dir);
1.1 root 200: }
201:
1.1.1.2 ! root 202: static int local_readdir_r(FsContext *ctx, V9fsFidOpenState *fs,
! 203: struct dirent *entry,
! 204: struct dirent **result)
1.1 root 205: {
1.1.1.2 ! root 206: return readdir_r(fs->dir, entry, result);
1.1 root 207: }
208:
1.1.1.2 ! root 209: static void local_seekdir(FsContext *ctx, V9fsFidOpenState *fs, off_t off)
1.1 root 210: {
1.1.1.2 ! root 211: return seekdir(fs->dir, off);
1.1 root 212: }
213:
1.1.1.2 ! root 214: static ssize_t local_preadv(FsContext *ctx, V9fsFidOpenState *fs,
! 215: const struct iovec *iov,
1.1 root 216: int iovcnt, off_t offset)
217: {
218: #ifdef CONFIG_PREADV
1.1.1.2 ! root 219: return preadv(fs->fd, iov, iovcnt, offset);
1.1 root 220: #else
1.1.1.2 ! root 221: int err = lseek(fs->fd, offset, SEEK_SET);
1.1 root 222: if (err == -1) {
223: return err;
224: } else {
1.1.1.2 ! root 225: return readv(fs->fd, iov, iovcnt);
1.1 root 226: }
227: #endif
228: }
229:
1.1.1.2 ! root 230: static ssize_t local_pwritev(FsContext *ctx, V9fsFidOpenState *fs,
! 231: const struct iovec *iov,
! 232: int iovcnt, off_t offset)
1.1 root 233: {
1.1.1.2 ! root 234: ssize_t ret
! 235: ;
1.1 root 236: #ifdef CONFIG_PREADV
1.1.1.2 ! root 237: ret = pwritev(fs->fd, iov, iovcnt, offset);
1.1 root 238: #else
1.1.1.2 ! root 239: int err = lseek(fs->fd, offset, SEEK_SET);
1.1 root 240: if (err == -1) {
241: return err;
242: } else {
1.1.1.2 ! root 243: ret = writev(fs->fd, iov, iovcnt);
1.1 root 244: }
245: #endif
1.1.1.2 ! root 246: #ifdef CONFIG_SYNC_FILE_RANGE
! 247: if (ret > 0 && ctx->export_flags & V9FS_IMMEDIATE_WRITEOUT) {
! 248: /*
! 249: * Initiate a writeback. This is not a data integrity sync.
! 250: * We want to ensure that we don't leave dirty pages in the cache
! 251: * after write when writeout=immediate is sepcified.
! 252: */
! 253: sync_file_range(fs->fd, offset, ret,
! 254: SYNC_FILE_RANGE_WAIT_BEFORE | SYNC_FILE_RANGE_WRITE);
! 255: }
! 256: #endif
! 257: return ret;
1.1 root 258: }
259:
1.1.1.2 ! root 260: static int local_chmod(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
1.1 root 261: {
262: char buffer[PATH_MAX];
1.1.1.2 ! root 263: char *path = fs_path->data;
! 264:
! 265: if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
1.1 root 266: return local_set_xattr(rpath(fs_ctx, path, buffer), credp);
1.1.1.2 ! root 267: } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
! 268: (fs_ctx->export_flags & V9FS_SM_NONE)) {
1.1 root 269: return chmod(rpath(fs_ctx, path, buffer), credp->fc_mode);
270: }
271: return -1;
272: }
273:
1.1.1.2 ! root 274: static int local_mknod(FsContext *fs_ctx, V9fsPath *dir_path,
! 275: const char *name, FsCred *credp)
1.1 root 276: {
1.1.1.2 ! root 277: char *path;
1.1 root 278: int err = -1;
279: int serrno = 0;
1.1.1.2 ! root 280: V9fsString fullname;
1.1 root 281: char buffer[PATH_MAX];
282:
1.1.1.2 ! root 283: v9fs_string_init(&fullname);
! 284: v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
! 285: path = fullname.data;
! 286:
1.1 root 287: /* Determine the security model */
1.1.1.2 ! root 288: if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
1.1 root 289: err = mknod(rpath(fs_ctx, path, buffer),
290: SM_LOCAL_MODE_BITS|S_IFREG, 0);
291: if (err == -1) {
1.1.1.2 ! root 292: goto out;
1.1 root 293: }
1.1.1.2 ! root 294: err = local_set_xattr(rpath(fs_ctx, path, buffer), credp);
1.1 root 295: if (err == -1) {
296: serrno = errno;
297: goto err_end;
298: }
1.1.1.2 ! root 299: } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
! 300: (fs_ctx->export_flags & V9FS_SM_NONE)) {
1.1 root 301: err = mknod(rpath(fs_ctx, path, buffer), credp->fc_mode,
302: credp->fc_rdev);
303: if (err == -1) {
1.1.1.2 ! root 304: goto out;
1.1 root 305: }
306: err = local_post_create_passthrough(fs_ctx, path, credp);
307: if (err == -1) {
308: serrno = errno;
309: goto err_end;
310: }
311: }
1.1.1.2 ! root 312: goto out;
1.1 root 313:
314: err_end:
315: remove(rpath(fs_ctx, path, buffer));
316: errno = serrno;
1.1.1.2 ! root 317: out:
! 318: v9fs_string_free(&fullname);
1.1 root 319: return err;
320: }
321:
1.1.1.2 ! root 322: static int local_mkdir(FsContext *fs_ctx, V9fsPath *dir_path,
! 323: const char *name, FsCred *credp)
1.1 root 324: {
1.1.1.2 ! root 325: char *path;
1.1 root 326: int err = -1;
327: int serrno = 0;
1.1.1.2 ! root 328: V9fsString fullname;
1.1 root 329: char buffer[PATH_MAX];
330:
1.1.1.2 ! root 331: v9fs_string_init(&fullname);
! 332: v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
! 333: path = fullname.data;
! 334:
1.1 root 335: /* Determine the security model */
1.1.1.2 ! root 336: if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
1.1 root 337: err = mkdir(rpath(fs_ctx, path, buffer), SM_LOCAL_DIR_MODE_BITS);
338: if (err == -1) {
1.1.1.2 ! root 339: goto out;
1.1 root 340: }
341: credp->fc_mode = credp->fc_mode|S_IFDIR;
342: err = local_set_xattr(rpath(fs_ctx, path, buffer), credp);
343: if (err == -1) {
344: serrno = errno;
345: goto err_end;
346: }
1.1.1.2 ! root 347: } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
! 348: (fs_ctx->export_flags & V9FS_SM_NONE)) {
1.1 root 349: err = mkdir(rpath(fs_ctx, path, buffer), credp->fc_mode);
350: if (err == -1) {
1.1.1.2 ! root 351: goto out;
1.1 root 352: }
353: err = local_post_create_passthrough(fs_ctx, path, credp);
354: if (err == -1) {
355: serrno = errno;
356: goto err_end;
357: }
358: }
1.1.1.2 ! root 359: goto out;
1.1 root 360:
361: err_end:
362: remove(rpath(fs_ctx, path, buffer));
363: errno = serrno;
1.1.1.2 ! root 364: out:
! 365: v9fs_string_free(&fullname);
1.1 root 366: return err;
367: }
368:
1.1.1.2 ! root 369: static int local_fstat(FsContext *fs_ctx, int fid_type,
! 370: V9fsFidOpenState *fs, struct stat *stbuf)
1.1 root 371: {
1.1.1.2 ! root 372: int err, fd;
! 373:
! 374: if (fid_type == P9_FID_DIR) {
! 375: fd = dirfd(fs->dir);
! 376: } else {
! 377: fd = fs->fd;
! 378: }
! 379:
1.1 root 380: err = fstat(fd, stbuf);
381: if (err) {
382: return err;
383: }
1.1.1.2 ! root 384: if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
1.1 root 385: /* Actual credentials are part of extended attrs */
386: uid_t tmp_uid;
387: gid_t tmp_gid;
388: mode_t tmp_mode;
389: dev_t tmp_dev;
390:
1.1.1.2 ! root 391: if (fgetxattr(fd, "user.virtfs.uid",
! 392: &tmp_uid, sizeof(uid_t)) > 0) {
1.1 root 393: stbuf->st_uid = tmp_uid;
394: }
1.1.1.2 ! root 395: if (fgetxattr(fd, "user.virtfs.gid",
! 396: &tmp_gid, sizeof(gid_t)) > 0) {
1.1 root 397: stbuf->st_gid = tmp_gid;
398: }
1.1.1.2 ! root 399: if (fgetxattr(fd, "user.virtfs.mode",
! 400: &tmp_mode, sizeof(mode_t)) > 0) {
1.1 root 401: stbuf->st_mode = tmp_mode;
402: }
1.1.1.2 ! root 403: if (fgetxattr(fd, "user.virtfs.rdev",
! 404: &tmp_dev, sizeof(dev_t)) > 0) {
1.1 root 405: stbuf->st_rdev = tmp_dev;
406: }
407: }
408: return err;
409: }
410:
1.1.1.2 ! root 411: static int local_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name,
! 412: int flags, FsCred *credp, V9fsFidOpenState *fs)
1.1 root 413: {
1.1.1.2 ! root 414: char *path;
1.1 root 415: int fd = -1;
416: int err = -1;
417: int serrno = 0;
1.1.1.2 ! root 418: V9fsString fullname;
1.1 root 419: char buffer[PATH_MAX];
420:
1.1.1.2 ! root 421: v9fs_string_init(&fullname);
! 422: v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
! 423: path = fullname.data;
! 424:
1.1 root 425: /* Determine the security model */
1.1.1.2 ! root 426: if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
1.1 root 427: fd = open(rpath(fs_ctx, path, buffer), flags, SM_LOCAL_MODE_BITS);
428: if (fd == -1) {
1.1.1.2 ! root 429: err = fd;
! 430: goto out;
1.1 root 431: }
432: credp->fc_mode = credp->fc_mode|S_IFREG;
433: /* Set cleint credentials in xattr */
434: err = local_set_xattr(rpath(fs_ctx, path, buffer), credp);
435: if (err == -1) {
436: serrno = errno;
437: goto err_end;
438: }
1.1.1.2 ! root 439: } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
! 440: (fs_ctx->export_flags & V9FS_SM_NONE)) {
1.1 root 441: fd = open(rpath(fs_ctx, path, buffer), flags, credp->fc_mode);
442: if (fd == -1) {
1.1.1.2 ! root 443: err = fd;
! 444: goto out;
1.1 root 445: }
446: err = local_post_create_passthrough(fs_ctx, path, credp);
447: if (err == -1) {
448: serrno = errno;
449: goto err_end;
450: }
451: }
1.1.1.2 ! root 452: err = fd;
! 453: fs->fd = fd;
! 454: goto out;
1.1 root 455:
456: err_end:
457: close(fd);
458: remove(rpath(fs_ctx, path, buffer));
459: errno = serrno;
1.1.1.2 ! root 460: out:
! 461: v9fs_string_free(&fullname);
1.1 root 462: return err;
463: }
464:
465:
466: static int local_symlink(FsContext *fs_ctx, const char *oldpath,
1.1.1.2 ! root 467: V9fsPath *dir_path, const char *name, FsCred *credp)
1.1 root 468: {
469: int err = -1;
470: int serrno = 0;
1.1.1.2 ! root 471: char *newpath;
! 472: V9fsString fullname;
1.1 root 473: char buffer[PATH_MAX];
474:
1.1.1.2 ! root 475: v9fs_string_init(&fullname);
! 476: v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
! 477: newpath = fullname.data;
! 478:
1.1 root 479: /* Determine the security model */
1.1.1.2 ! root 480: if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
1.1 root 481: int fd;
482: ssize_t oldpath_size, write_size;
483: fd = open(rpath(fs_ctx, newpath, buffer), O_CREAT|O_EXCL|O_RDWR,
484: SM_LOCAL_MODE_BITS);
485: if (fd == -1) {
1.1.1.2 ! root 486: err = fd;
! 487: goto out;
1.1 root 488: }
489: /* Write the oldpath (target) to the file. */
490: oldpath_size = strlen(oldpath);
491: do {
492: write_size = write(fd, (void *)oldpath, oldpath_size);
493: } while (write_size == -1 && errno == EINTR);
494:
495: if (write_size != oldpath_size) {
496: serrno = errno;
497: close(fd);
498: err = -1;
499: goto err_end;
500: }
501: close(fd);
502: /* Set cleint credentials in symlink's xattr */
503: credp->fc_mode = credp->fc_mode|S_IFLNK;
504: err = local_set_xattr(rpath(fs_ctx, newpath, buffer), credp);
505: if (err == -1) {
506: serrno = errno;
507: goto err_end;
508: }
1.1.1.2 ! root 509: } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
! 510: (fs_ctx->export_flags & V9FS_SM_NONE)) {
1.1 root 511: err = symlink(oldpath, rpath(fs_ctx, newpath, buffer));
512: if (err) {
1.1.1.2 ! root 513: goto out;
1.1 root 514: }
515: err = lchown(rpath(fs_ctx, newpath, buffer), credp->fc_uid,
1.1.1.2 ! root 516: credp->fc_gid);
1.1 root 517: if (err == -1) {
518: /*
519: * If we fail to change ownership and if we are
520: * using security model none. Ignore the error
521: */
1.1.1.2 ! root 522: if ((fs_ctx->export_flags & V9FS_SEC_MASK) != V9FS_SM_NONE) {
1.1 root 523: serrno = errno;
524: goto err_end;
525: } else
526: err = 0;
527: }
528: }
1.1.1.2 ! root 529: goto out;
1.1 root 530:
531: err_end:
532: remove(rpath(fs_ctx, newpath, buffer));
533: errno = serrno;
1.1.1.2 ! root 534: out:
! 535: v9fs_string_free(&fullname);
1.1 root 536: return err;
537: }
538:
1.1.1.2 ! root 539: static int local_link(FsContext *ctx, V9fsPath *oldpath,
! 540: V9fsPath *dirpath, const char *name)
1.1 root 541: {
1.1.1.2 ! root 542: int ret;
! 543: V9fsString newpath;
1.1 root 544: char buffer[PATH_MAX], buffer1[PATH_MAX];
545:
1.1.1.2 ! root 546: v9fs_string_init(&newpath);
! 547: v9fs_string_sprintf(&newpath, "%s/%s", dirpath->data, name);
! 548:
! 549: ret = link(rpath(ctx, oldpath->data, buffer),
! 550: rpath(ctx, newpath.data, buffer1));
! 551: v9fs_string_free(&newpath);
! 552: return ret;
1.1 root 553: }
554:
1.1.1.2 ! root 555: static int local_truncate(FsContext *ctx, V9fsPath *fs_path, off_t size)
1.1 root 556: {
557: char buffer[PATH_MAX];
1.1.1.2 ! root 558: char *path = fs_path->data;
! 559:
1.1 root 560: return truncate(rpath(ctx, path, buffer), size);
561: }
562:
563: static int local_rename(FsContext *ctx, const char *oldpath,
564: const char *newpath)
565: {
566: char buffer[PATH_MAX], buffer1[PATH_MAX];
567:
568: return rename(rpath(ctx, oldpath, buffer), rpath(ctx, newpath, buffer1));
569: }
570:
1.1.1.2 ! root 571: static int local_chown(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
1.1 root 572: {
573: char buffer[PATH_MAX];
1.1.1.2 ! root 574: char *path = fs_path->data;
! 575:
1.1 root 576: if ((credp->fc_uid == -1 && credp->fc_gid == -1) ||
1.1.1.2 ! root 577: (fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
! 578: (fs_ctx->export_flags & V9FS_SM_NONE)) {
! 579: return lchown(rpath(fs_ctx, path, buffer),
! 580: credp->fc_uid, credp->fc_gid);
! 581: } else if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
1.1 root 582: return local_set_xattr(rpath(fs_ctx, path, buffer), credp);
583: }
584: return -1;
585: }
586:
1.1.1.2 ! root 587: static int local_utimensat(FsContext *s, V9fsPath *fs_path,
1.1 root 588: const struct timespec *buf)
589: {
590: char buffer[PATH_MAX];
1.1.1.2 ! root 591: char *path = fs_path->data;
! 592:
! 593: return qemu_utimens(rpath(s, path, buffer), buf);
1.1 root 594: }
595:
596: static int local_remove(FsContext *ctx, const char *path)
597: {
598: char buffer[PATH_MAX];
599: return remove(rpath(ctx, path, buffer));
600: }
601:
1.1.1.2 ! root 602: static int local_fsync(FsContext *ctx, int fid_type,
! 603: V9fsFidOpenState *fs, int datasync)
1.1 root 604: {
1.1.1.2 ! root 605: int fd;
! 606:
! 607: if (fid_type == P9_FID_DIR) {
! 608: fd = dirfd(fs->dir);
! 609: } else {
! 610: fd = fs->fd;
! 611: }
! 612:
1.1 root 613: if (datasync) {
614: return qemu_fdatasync(fd);
615: } else {
616: return fsync(fd);
617: }
618: }
619:
1.1.1.2 ! root 620: static int local_statfs(FsContext *s, V9fsPath *fs_path, struct statfs *stbuf)
1.1 root 621: {
622: char buffer[PATH_MAX];
1.1.1.2 ! root 623: char *path = fs_path->data;
! 624:
! 625: return statfs(rpath(s, path, buffer), stbuf);
1.1 root 626: }
627:
1.1.1.2 ! root 628: static ssize_t local_lgetxattr(FsContext *ctx, V9fsPath *fs_path,
1.1 root 629: const char *name, void *value, size_t size)
630: {
1.1.1.2 ! root 631: char *path = fs_path->data;
! 632:
1.1 root 633: return v9fs_get_xattr(ctx, path, name, value, size);
634: }
635:
1.1.1.2 ! root 636: static ssize_t local_llistxattr(FsContext *ctx, V9fsPath *fs_path,
1.1 root 637: void *value, size_t size)
638: {
1.1.1.2 ! root 639: char *path = fs_path->data;
! 640:
1.1 root 641: return v9fs_list_xattr(ctx, path, value, size);
642: }
643:
1.1.1.2 ! root 644: static int local_lsetxattr(FsContext *ctx, V9fsPath *fs_path, const char *name,
1.1 root 645: void *value, size_t size, int flags)
646: {
1.1.1.2 ! root 647: char *path = fs_path->data;
! 648:
1.1 root 649: return v9fs_set_xattr(ctx, path, name, value, size, flags);
650: }
651:
1.1.1.2 ! root 652: static int local_lremovexattr(FsContext *ctx, V9fsPath *fs_path,
! 653: const char *name)
1.1 root 654: {
1.1.1.2 ! root 655: char *path = fs_path->data;
! 656:
1.1 root 657: return v9fs_remove_xattr(ctx, path, name);
658: }
659:
1.1.1.2 ! root 660: static int local_name_to_path(FsContext *ctx, V9fsPath *dir_path,
! 661: const char *name, V9fsPath *target)
! 662: {
! 663: if (dir_path) {
! 664: v9fs_string_sprintf((V9fsString *)target, "%s/%s",
! 665: dir_path->data, name);
! 666: } else {
! 667: v9fs_string_sprintf((V9fsString *)target, "%s", name);
! 668: }
! 669: /* Bump the size for including terminating NULL */
! 670: target->size++;
! 671: return 0;
! 672: }
! 673:
! 674: static int local_renameat(FsContext *ctx, V9fsPath *olddir,
! 675: const char *old_name, V9fsPath *newdir,
! 676: const char *new_name)
! 677: {
! 678: int ret;
! 679: V9fsString old_full_name, new_full_name;
! 680:
! 681: v9fs_string_init(&old_full_name);
! 682: v9fs_string_init(&new_full_name);
! 683:
! 684: v9fs_string_sprintf(&old_full_name, "%s/%s", olddir->data, old_name);
! 685: v9fs_string_sprintf(&new_full_name, "%s/%s", newdir->data, new_name);
! 686:
! 687: ret = local_rename(ctx, old_full_name.data, new_full_name.data);
! 688: v9fs_string_free(&old_full_name);
! 689: v9fs_string_free(&new_full_name);
! 690: return ret;
! 691: }
! 692:
! 693: static int local_unlinkat(FsContext *ctx, V9fsPath *dir,
! 694: const char *name, int flags)
! 695: {
! 696: int ret;
! 697: V9fsString fullname;
! 698: char buffer[PATH_MAX];
! 699: v9fs_string_init(&fullname);
! 700:
! 701: v9fs_string_sprintf(&fullname, "%s/%s", dir->data, name);
! 702: ret = remove(rpath(ctx, fullname.data, buffer));
! 703: v9fs_string_free(&fullname);
! 704:
! 705: return ret;
! 706: }
! 707:
! 708: static int local_ioc_getversion(FsContext *ctx, V9fsPath *path,
! 709: mode_t st_mode, uint64_t *st_gen)
! 710: {
! 711: int err;
! 712: #ifdef FS_IOC_GETVERSION
! 713: V9fsFidOpenState fid_open;
! 714:
! 715: /*
! 716: * Do not try to open special files like device nodes, fifos etc
! 717: * We can get fd for regular files and directories only
! 718: */
! 719: if (!S_ISREG(st_mode) && !S_ISDIR(st_mode)) {
! 720: return 0;
! 721: }
! 722: err = local_open(ctx, path, O_RDONLY, &fid_open);
! 723: if (err < 0) {
! 724: return err;
! 725: }
! 726: err = ioctl(fid_open.fd, FS_IOC_GETVERSION, st_gen);
! 727: local_close(ctx, &fid_open);
! 728: #else
! 729: err = -ENOTTY;
! 730: #endif
! 731: return err;
! 732: }
! 733:
! 734: static int local_init(FsContext *ctx)
! 735: {
! 736: int err = 0;
! 737: struct statfs stbuf;
! 738:
! 739: ctx->export_flags |= V9FS_PATHNAME_FSCONTEXT;
! 740: #ifdef FS_IOC_GETVERSION
! 741: /*
! 742: * use ioc_getversion only if the iocl is definied
! 743: */
! 744: err = statfs(ctx->fs_root, &stbuf);
! 745: if (!err) {
! 746: switch (stbuf.f_type) {
! 747: case EXT2_SUPER_MAGIC:
! 748: case BTRFS_SUPER_MAGIC:
! 749: case REISERFS_SUPER_MAGIC:
! 750: case XFS_SUPER_MAGIC:
! 751: ctx->exops.get_st_gen = local_ioc_getversion;
! 752: break;
! 753: }
! 754: }
! 755: #endif
! 756: return err;
! 757: }
1.1 root 758:
759: FileOperations local_ops = {
1.1.1.2 ! root 760: .init = local_init,
1.1 root 761: .lstat = local_lstat,
762: .readlink = local_readlink,
763: .close = local_close,
764: .closedir = local_closedir,
765: .open = local_open,
766: .opendir = local_opendir,
767: .rewinddir = local_rewinddir,
768: .telldir = local_telldir,
1.1.1.2 ! root 769: .readdir_r = local_readdir_r,
1.1 root 770: .seekdir = local_seekdir,
771: .preadv = local_preadv,
772: .pwritev = local_pwritev,
773: .chmod = local_chmod,
774: .mknod = local_mknod,
775: .mkdir = local_mkdir,
776: .fstat = local_fstat,
777: .open2 = local_open2,
778: .symlink = local_symlink,
779: .link = local_link,
780: .truncate = local_truncate,
781: .rename = local_rename,
782: .chown = local_chown,
783: .utimensat = local_utimensat,
784: .remove = local_remove,
785: .fsync = local_fsync,
786: .statfs = local_statfs,
787: .lgetxattr = local_lgetxattr,
788: .llistxattr = local_llistxattr,
789: .lsetxattr = local_lsetxattr,
790: .lremovexattr = local_lremovexattr,
1.1.1.2 ! root 791: .name_to_path = local_name_to_path,
! 792: .renameat = local_renameat,
! 793: .unlinkat = local_unlinkat,
1.1 root 794: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.