Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
SUSE:SLE-12-SP2:GA
qemu-linux-user.7445
0328-9pfs-rename-virtio-9p-local.c-to-9p.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File 0328-9pfs-rename-virtio-9p-local.c-to-9p.patch of Package qemu-linux-user.7445
From 35cd67a37fb5d5756b6cbdbde3588a8b4d58d5d5 Mon Sep 17 00:00:00 2001 From: Wei Liu <wei.liu2@citrix.com> Date: Wed, 18 Nov 2015 18:05:29 +0000 Subject: [PATCH] 9pfs: rename virtio-9p-local.c to 9p-local.c This file is not virtio specific. Rename it to use generic name. Fix comment and remove unneeded inclusion of virtio.h. Signed-off-by: Wei Liu <wei.liu2@citrix.com> Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com> (cherry picked from commit f00d4f596b1c85cf9449ef4b65fca46148bcc9bb) [BR: Fix and/or infrastructure for BSC#1020427 CVE-2016-9602] Signed-off-by: Bruce Rogers <brogers@suse.com> --- hw/9pfs/9p-local.c | 1294 ++++++++++++++++++++++++++++++++++++++++++++ hw/9pfs/Makefile.objs | 2 +- hw/9pfs/virtio-9p-local.c | 1295 --------------------------------------------- 3 files changed, 1295 insertions(+), 1296 deletions(-) create mode 100644 hw/9pfs/9p-local.c delete mode 100644 hw/9pfs/virtio-9p-local.c diff --git a/hw/9pfs/9p-local.c b/hw/9pfs/9p-local.c new file mode 100644 index 0000000000..093698600d --- /dev/null +++ b/hw/9pfs/9p-local.c @@ -0,0 +1,1294 @@ +/* + * 9p Posix callback + * + * Copyright IBM, Corp. 2010 + * + * Authors: + * Anthony Liguori <aliguori@us.ibm.com> + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + */ + +#include "virtio-9p.h" +#include "virtio-9p-xattr.h" +#include <arpa/inet.h> +#include <pwd.h> +#include <grp.h> +#include <sys/socket.h> +#include <sys/un.h> +#include "qemu/xattr.h" +#include <libgen.h> +#include <linux/fs.h> +#ifdef CONFIG_LINUX_MAGIC_H +#include <linux/magic.h> +#endif +#include <sys/ioctl.h> + +#ifndef XFS_SUPER_MAGIC +#define XFS_SUPER_MAGIC 0x58465342 +#endif +#ifndef EXT2_SUPER_MAGIC +#define EXT2_SUPER_MAGIC 0xEF53 +#endif +#ifndef REISERFS_SUPER_MAGIC +#define REISERFS_SUPER_MAGIC 0x52654973 +#endif +#ifndef BTRFS_SUPER_MAGIC +#define BTRFS_SUPER_MAGIC 0x9123683E +#endif + +#define VIRTFS_META_DIR ".virtfs_metadata" + +static char *local_mapped_attr_path(FsContext *ctx, const char *path) +{ + char *dir_name; + char *tmp_path = g_strdup(path); + char *base_name = basename(tmp_path); + char *buffer; + + /* NULL terminate the directory */ + dir_name = tmp_path; + *(base_name - 1) = '\0'; + + buffer = g_strdup_printf("%s/%s/%s/%s", + ctx->fs_root, dir_name, VIRTFS_META_DIR, base_name); + g_free(tmp_path); + return buffer; +} + +static FILE *local_fopen(const char *path, const char *mode) +{ + int fd, o_mode = 0; + FILE *fp; + int flags = O_NOFOLLOW; + /* + * only supports two modes + */ + if (mode[0] == 'r') { + flags |= O_RDONLY; + } else if (mode[0] == 'w') { + flags |= O_WRONLY | O_TRUNC | O_CREAT; + o_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; + } else { + return NULL; + } + fd = open(path, flags, o_mode); + if (fd == -1) { + return NULL; + } + fp = fdopen(fd, mode); + if (!fp) { + close(fd); + } + return fp; +} + +#define ATTR_MAX 100 +static void local_mapped_file_attr(FsContext *ctx, const char *path, + struct stat *stbuf) +{ + FILE *fp; + char buf[ATTR_MAX]; + char *attr_path; + + attr_path = local_mapped_attr_path(ctx, path); + fp = local_fopen(attr_path, "r"); + g_free(attr_path); + if (!fp) { + return; + } + memset(buf, 0, ATTR_MAX); + while (fgets(buf, ATTR_MAX, fp)) { + if (!strncmp(buf, "virtfs.uid", 10)) { + stbuf->st_uid = atoi(buf+11); + } else if (!strncmp(buf, "virtfs.gid", 10)) { + stbuf->st_gid = atoi(buf+11); + } else if (!strncmp(buf, "virtfs.mode", 11)) { + stbuf->st_mode = atoi(buf+12); + } else if (!strncmp(buf, "virtfs.rdev", 11)) { + stbuf->st_rdev = atoi(buf+12); + } + memset(buf, 0, ATTR_MAX); + } + fclose(fp); +} + +static int local_lstat(FsContext *fs_ctx, V9fsPath *fs_path, struct stat *stbuf) +{ + int err; + char *buffer; + char *path = fs_path->data; + + buffer = rpath(fs_ctx, path); + err = lstat(buffer, stbuf); + if (err) { + goto err_out; + } + if (fs_ctx->export_flags & V9FS_SM_MAPPED) { + /* Actual credentials are part of extended attrs */ + uid_t tmp_uid; + gid_t tmp_gid; + mode_t tmp_mode; + dev_t tmp_dev; + if (getxattr(buffer, "user.virtfs.uid", &tmp_uid, sizeof(uid_t)) > 0) { + stbuf->st_uid = tmp_uid; + } + if (getxattr(buffer, "user.virtfs.gid", &tmp_gid, sizeof(gid_t)) > 0) { + stbuf->st_gid = tmp_gid; + } + if (getxattr(buffer, "user.virtfs.mode", + &tmp_mode, sizeof(mode_t)) > 0) { + stbuf->st_mode = tmp_mode; + } + if (getxattr(buffer, "user.virtfs.rdev", &tmp_dev, sizeof(dev_t)) > 0) { + stbuf->st_rdev = tmp_dev; + } + } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) { + local_mapped_file_attr(fs_ctx, path, stbuf); + } + +err_out: + g_free(buffer); + return err; +} + +static int local_create_mapped_attr_dir(FsContext *ctx, const char *path) +{ + int err; + char *attr_dir; + char *tmp_path = g_strdup(path); + + attr_dir = g_strdup_printf("%s/%s/%s", + ctx->fs_root, dirname(tmp_path), VIRTFS_META_DIR); + + err = mkdir(attr_dir, 0700); + if (err < 0 && errno == EEXIST) { + err = 0; + } + g_free(attr_dir); + g_free(tmp_path); + return err; +} + +static int local_set_mapped_file_attr(FsContext *ctx, + const char *path, FsCred *credp) +{ + FILE *fp; + int ret = 0; + char buf[ATTR_MAX]; + char *attr_path; + int uid = -1, gid = -1, mode = -1, rdev = -1; + + attr_path = local_mapped_attr_path(ctx, path); + fp = local_fopen(attr_path, "r"); + if (!fp) { + goto create_map_file; + } + memset(buf, 0, ATTR_MAX); + while (fgets(buf, ATTR_MAX, fp)) { + if (!strncmp(buf, "virtfs.uid", 10)) { + uid = atoi(buf+11); + } else if (!strncmp(buf, "virtfs.gid", 10)) { + gid = atoi(buf+11); + } else if (!strncmp(buf, "virtfs.mode", 11)) { + mode = atoi(buf+12); + } else if (!strncmp(buf, "virtfs.rdev", 11)) { + rdev = atoi(buf+12); + } + memset(buf, 0, ATTR_MAX); + } + fclose(fp); + goto update_map_file; + +create_map_file: + ret = local_create_mapped_attr_dir(ctx, path); + if (ret < 0) { + goto err_out; + } + +update_map_file: + fp = local_fopen(attr_path, "w"); + if (!fp) { + ret = -1; + goto err_out; + } + + if (credp->fc_uid != -1) { + uid = credp->fc_uid; + } + if (credp->fc_gid != -1) { + gid = credp->fc_gid; + } + if (credp->fc_mode != -1) { + mode = credp->fc_mode; + } + if (credp->fc_rdev != -1) { + rdev = credp->fc_rdev; + } + + + if (uid != -1) { + fprintf(fp, "virtfs.uid=%d\n", uid); + } + if (gid != -1) { + fprintf(fp, "virtfs.gid=%d\n", gid); + } + if (mode != -1) { + fprintf(fp, "virtfs.mode=%d\n", mode); + } + if (rdev != -1) { + fprintf(fp, "virtfs.rdev=%d\n", rdev); + } + fclose(fp); + +err_out: + g_free(attr_path); + return ret; +} + +static int local_set_xattr(const char *path, FsCred *credp) +{ + int err; + + if (credp->fc_uid != -1) { + err = setxattr(path, "user.virtfs.uid", &credp->fc_uid, sizeof(uid_t), + 0); + if (err) { + return err; + } + } + if (credp->fc_gid != -1) { + err = setxattr(path, "user.virtfs.gid", &credp->fc_gid, sizeof(gid_t), + 0); + if (err) { + return err; + } + } + if (credp->fc_mode != -1) { + err = setxattr(path, "user.virtfs.mode", &credp->fc_mode, + sizeof(mode_t), 0); + if (err) { + return err; + } + } + if (credp->fc_rdev != -1) { + err = setxattr(path, "user.virtfs.rdev", &credp->fc_rdev, + sizeof(dev_t), 0); + if (err) { + return err; + } + } + return 0; +} + +static int local_post_create_passthrough(FsContext *fs_ctx, const char *path, + FsCred *credp) +{ + char *buffer; + + buffer = rpath(fs_ctx, path); + if (lchown(buffer, credp->fc_uid, credp->fc_gid) < 0) { + /* + * If we fail to change ownership and if we are + * using security model none. Ignore the error + */ + if ((fs_ctx->export_flags & V9FS_SEC_MASK) != V9FS_SM_NONE) { + goto err; + } + } + + if (chmod(buffer, credp->fc_mode & 07777) < 0) { + goto err; + } + + g_free(buffer); + return 0; +err: + g_free(buffer); + return -1; +} + +static ssize_t local_readlink(FsContext *fs_ctx, V9fsPath *fs_path, + char *buf, size_t bufsz) +{ + ssize_t tsize = -1; + char *buffer; + char *path = fs_path->data; + + if ((fs_ctx->export_flags & V9FS_SM_MAPPED) || + (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE)) { + int fd; + buffer = rpath(fs_ctx, path); + fd = open(buffer, O_RDONLY | O_NOFOLLOW); + g_free(buffer); + if (fd == -1) { + return -1; + } + do { + tsize = read(fd, (void *)buf, bufsz); + } while (tsize == -1 && errno == EINTR); + close(fd); + return tsize; + } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) || + (fs_ctx->export_flags & V9FS_SM_NONE)) { + buffer = rpath(fs_ctx, path); + tsize = readlink(buffer, buf, bufsz); + g_free(buffer); + } + return tsize; +} + +static int local_close(FsContext *ctx, V9fsFidOpenState *fs) +{ + return close(fs->fd); +} + +static int local_closedir(FsContext *ctx, V9fsFidOpenState *fs) +{ + return closedir(fs->dir); +} + +static int local_open(FsContext *ctx, V9fsPath *fs_path, + int flags, V9fsFidOpenState *fs) +{ + char *buffer; + char *path = fs_path->data; + + buffer = rpath(ctx, path); + fs->fd = open(buffer, flags | O_NOFOLLOW); + g_free(buffer); + return fs->fd; +} + +static int local_opendir(FsContext *ctx, + V9fsPath *fs_path, V9fsFidOpenState *fs) +{ + char *buffer; + char *path = fs_path->data; + + buffer = rpath(ctx, path); + fs->dir = opendir(buffer); + g_free(buffer); + if (!fs->dir) { + return -1; + } + return 0; +} + +static void local_rewinddir(FsContext *ctx, V9fsFidOpenState *fs) +{ + return rewinddir(fs->dir); +} + +static off_t local_telldir(FsContext *ctx, V9fsFidOpenState *fs) +{ + return telldir(fs->dir); +} + +static int local_readdir_r(FsContext *ctx, V9fsFidOpenState *fs, + struct dirent *entry, + struct dirent **result) +{ + int ret; + +again: + ret = readdir_r(fs->dir, entry, result); + if (ctx->export_flags & V9FS_SM_MAPPED_FILE) { + if (!ret && *result != NULL && + !strcmp(entry->d_name, VIRTFS_META_DIR)) { + /* skp the meta data directory */ + goto again; + } + } + return ret; +} + +static void local_seekdir(FsContext *ctx, V9fsFidOpenState *fs, off_t off) +{ + return seekdir(fs->dir, off); +} + +static ssize_t local_preadv(FsContext *ctx, V9fsFidOpenState *fs, + const struct iovec *iov, + int iovcnt, off_t offset) +{ +#ifdef CONFIG_PREADV + return preadv(fs->fd, iov, iovcnt, offset); +#else + int err = lseek(fs->fd, offset, SEEK_SET); + if (err == -1) { + return err; + } else { + return readv(fs->fd, iov, iovcnt); + } +#endif +} + +static ssize_t local_pwritev(FsContext *ctx, V9fsFidOpenState *fs, + const struct iovec *iov, + int iovcnt, off_t offset) +{ + ssize_t ret +; +#ifdef CONFIG_PREADV + ret = pwritev(fs->fd, iov, iovcnt, offset); +#else + int err = lseek(fs->fd, offset, SEEK_SET); + if (err == -1) { + return err; + } else { + ret = writev(fs->fd, iov, iovcnt); + } +#endif +#ifdef CONFIG_SYNC_FILE_RANGE + if (ret > 0 && ctx->export_flags & V9FS_IMMEDIATE_WRITEOUT) { + /* + * Initiate a writeback. This is not a data integrity sync. + * We want to ensure that we don't leave dirty pages in the cache + * after write when writeout=immediate is sepcified. + */ + sync_file_range(fs->fd, offset, ret, + SYNC_FILE_RANGE_WAIT_BEFORE | SYNC_FILE_RANGE_WRITE); + } +#endif + return ret; +} + +static int local_chmod(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp) +{ + char *buffer; + int ret = -1; + char *path = fs_path->data; + + if (fs_ctx->export_flags & V9FS_SM_MAPPED) { + buffer = rpath(fs_ctx, path); + ret = local_set_xattr(buffer, credp); + g_free(buffer); + } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) { + return local_set_mapped_file_attr(fs_ctx, path, credp); + } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) || + (fs_ctx->export_flags & V9FS_SM_NONE)) { + buffer = rpath(fs_ctx, path); + ret = chmod(buffer, credp->fc_mode); + g_free(buffer); + } + return ret; +} + +static int local_mknod(FsContext *fs_ctx, V9fsPath *dir_path, + const char *name, FsCred *credp) +{ + char *path; + int err = -1; + int serrno = 0; + V9fsString fullname; + char *buffer; + + v9fs_string_init(&fullname); + v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name); + path = fullname.data; + + /* Determine the security model */ + if (fs_ctx->export_flags & V9FS_SM_MAPPED) { + buffer = rpath(fs_ctx, path); + err = mknod(buffer, SM_LOCAL_MODE_BITS|S_IFREG, 0); + if (err == -1) { + g_free(buffer); + goto out; + } + err = local_set_xattr(buffer, credp); + if (err == -1) { + serrno = errno; + goto err_end; + } + } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) { + + buffer = rpath(fs_ctx, path); + err = mknod(buffer, SM_LOCAL_MODE_BITS|S_IFREG, 0); + if (err == -1) { + g_free(buffer); + goto out; + } + err = local_set_mapped_file_attr(fs_ctx, path, credp); + if (err == -1) { + serrno = errno; + goto err_end; + } + } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) || + (fs_ctx->export_flags & V9FS_SM_NONE)) { + buffer = rpath(fs_ctx, path); + err = mknod(buffer, credp->fc_mode, credp->fc_rdev); + if (err == -1) { + g_free(buffer); + goto out; + } + err = local_post_create_passthrough(fs_ctx, path, credp); + if (err == -1) { + serrno = errno; + goto err_end; + } + } + goto out; + +err_end: + remove(buffer); + errno = serrno; + g_free(buffer); +out: + v9fs_string_free(&fullname); + return err; +} + +static int local_mkdir(FsContext *fs_ctx, V9fsPath *dir_path, + const char *name, FsCred *credp) +{ + char *path; + int err = -1; + int serrno = 0; + V9fsString fullname; + char *buffer; + + v9fs_string_init(&fullname); + v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name); + path = fullname.data; + + /* Determine the security model */ + if (fs_ctx->export_flags & V9FS_SM_MAPPED) { + buffer = rpath(fs_ctx, path); + err = mkdir(buffer, SM_LOCAL_DIR_MODE_BITS); + if (err == -1) { + g_free(buffer); + goto out; + } + credp->fc_mode = credp->fc_mode|S_IFDIR; + err = local_set_xattr(buffer, credp); + if (err == -1) { + serrno = errno; + goto err_end; + } + } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) { + buffer = rpath(fs_ctx, path); + err = mkdir(buffer, SM_LOCAL_DIR_MODE_BITS); + if (err == -1) { + g_free(buffer); + goto out; + } + credp->fc_mode = credp->fc_mode|S_IFDIR; + err = local_set_mapped_file_attr(fs_ctx, path, credp); + if (err == -1) { + serrno = errno; + goto err_end; + } + } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) || + (fs_ctx->export_flags & V9FS_SM_NONE)) { + buffer = rpath(fs_ctx, path); + err = mkdir(buffer, credp->fc_mode); + if (err == -1) { + g_free(buffer); + goto out; + } + err = local_post_create_passthrough(fs_ctx, path, credp); + if (err == -1) { + serrno = errno; + goto err_end; + } + } + goto out; + +err_end: + remove(buffer); + errno = serrno; + g_free(buffer); +out: + v9fs_string_free(&fullname); + return err; +} + +static int local_fstat(FsContext *fs_ctx, int fid_type, + V9fsFidOpenState *fs, struct stat *stbuf) +{ + int err, fd; + + if (fid_type == P9_FID_DIR) { + fd = dirfd(fs->dir); + } else { + fd = fs->fd; + } + + err = fstat(fd, stbuf); + if (err) { + return err; + } + if (fs_ctx->export_flags & V9FS_SM_MAPPED) { + /* Actual credentials are part of extended attrs */ + uid_t tmp_uid; + gid_t tmp_gid; + mode_t tmp_mode; + dev_t tmp_dev; + + if (fgetxattr(fd, "user.virtfs.uid", + &tmp_uid, sizeof(uid_t)) > 0) { + stbuf->st_uid = tmp_uid; + } + if (fgetxattr(fd, "user.virtfs.gid", + &tmp_gid, sizeof(gid_t)) > 0) { + stbuf->st_gid = tmp_gid; + } + if (fgetxattr(fd, "user.virtfs.mode", + &tmp_mode, sizeof(mode_t)) > 0) { + stbuf->st_mode = tmp_mode; + } + if (fgetxattr(fd, "user.virtfs.rdev", + &tmp_dev, sizeof(dev_t)) > 0) { + stbuf->st_rdev = tmp_dev; + } + } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) { + errno = EOPNOTSUPP; + return -1; + } + return err; +} + +static int local_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name, + int flags, FsCred *credp, V9fsFidOpenState *fs) +{ + char *path; + int fd = -1; + int err = -1; + int serrno = 0; + V9fsString fullname; + char *buffer; + + /* + * Mark all the open to not follow symlinks + */ + flags |= O_NOFOLLOW; + + v9fs_string_init(&fullname); + v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name); + path = fullname.data; + + /* Determine the security model */ + if (fs_ctx->export_flags & V9FS_SM_MAPPED) { + buffer = rpath(fs_ctx, path); + fd = open(buffer, flags, SM_LOCAL_MODE_BITS); + if (fd == -1) { + g_free(buffer); + err = fd; + goto out; + } + credp->fc_mode = credp->fc_mode|S_IFREG; + /* Set cleint credentials in xattr */ + err = local_set_xattr(buffer, credp); + if (err == -1) { + serrno = errno; + goto err_end; + } + } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) { + buffer = rpath(fs_ctx, path); + fd = open(buffer, flags, SM_LOCAL_MODE_BITS); + if (fd == -1) { + g_free(buffer); + err = fd; + goto out; + } + credp->fc_mode = credp->fc_mode|S_IFREG; + /* Set client credentials in .virtfs_metadata directory files */ + err = local_set_mapped_file_attr(fs_ctx, path, credp); + if (err == -1) { + serrno = errno; + goto err_end; + } + } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) || + (fs_ctx->export_flags & V9FS_SM_NONE)) { + buffer = rpath(fs_ctx, path); + fd = open(buffer, flags, credp->fc_mode); + if (fd == -1) { + g_free(buffer); + err = fd; + goto out; + } + err = local_post_create_passthrough(fs_ctx, path, credp); + if (err == -1) { + serrno = errno; + goto err_end; + } + } + err = fd; + fs->fd = fd; + goto out; + +err_end: + close(fd); + remove(buffer); + errno = serrno; + g_free(buffer); +out: + v9fs_string_free(&fullname); + return err; +} + + +static int local_symlink(FsContext *fs_ctx, const char *oldpath, + V9fsPath *dir_path, const char *name, FsCred *credp) +{ + int err = -1; + int serrno = 0; + char *newpath; + V9fsString fullname; + char *buffer; + + v9fs_string_init(&fullname); + v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name); + newpath = fullname.data; + + /* Determine the security model */ + if (fs_ctx->export_flags & V9FS_SM_MAPPED) { + int fd; + ssize_t oldpath_size, write_size; + buffer = rpath(fs_ctx, newpath); + fd = open(buffer, O_CREAT|O_EXCL|O_RDWR|O_NOFOLLOW, SM_LOCAL_MODE_BITS); + if (fd == -1) { + g_free(buffer); + err = fd; + goto out; + } + /* Write the oldpath (target) to the file. */ + oldpath_size = strlen(oldpath); + do { + write_size = write(fd, (void *)oldpath, oldpath_size); + } while (write_size == -1 && errno == EINTR); + + if (write_size != oldpath_size) { + serrno = errno; + close(fd); + err = -1; + goto err_end; + } + close(fd); + /* Set cleint credentials in symlink's xattr */ + credp->fc_mode = credp->fc_mode|S_IFLNK; + err = local_set_xattr(buffer, credp); + if (err == -1) { + serrno = errno; + goto err_end; + } + } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) { + int fd; + ssize_t oldpath_size, write_size; + buffer = rpath(fs_ctx, newpath); + fd = open(buffer, O_CREAT|O_EXCL|O_RDWR|O_NOFOLLOW, SM_LOCAL_MODE_BITS); + if (fd == -1) { + g_free(buffer); + err = fd; + goto out; + } + /* Write the oldpath (target) to the file. */ + oldpath_size = strlen(oldpath); + do { + write_size = write(fd, (void *)oldpath, oldpath_size); + } while (write_size == -1 && errno == EINTR); + + if (write_size != oldpath_size) { + serrno = errno; + close(fd); + err = -1; + goto err_end; + } + close(fd); + /* Set cleint credentials in symlink's xattr */ + credp->fc_mode = credp->fc_mode|S_IFLNK; + err = local_set_mapped_file_attr(fs_ctx, newpath, credp); + if (err == -1) { + serrno = errno; + goto err_end; + } + } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) || + (fs_ctx->export_flags & V9FS_SM_NONE)) { + buffer = rpath(fs_ctx, newpath); + err = symlink(oldpath, buffer); + if (err) { + g_free(buffer); + goto out; + } + err = lchown(buffer, credp->fc_uid, credp->fc_gid); + if (err == -1) { + /* + * If we fail to change ownership and if we are + * using security model none. Ignore the error + */ + if ((fs_ctx->export_flags & V9FS_SEC_MASK) != V9FS_SM_NONE) { + serrno = errno; + goto err_end; + } else + err = 0; + } + } + goto out; + +err_end: + remove(buffer); + errno = serrno; + g_free(buffer); +out: + v9fs_string_free(&fullname); + return err; +} + +static int local_link(FsContext *ctx, V9fsPath *oldpath, + V9fsPath *dirpath, const char *name) +{ + int ret; + V9fsString newpath; + char *buffer, *buffer1; + + v9fs_string_init(&newpath); + v9fs_string_sprintf(&newpath, "%s/%s", dirpath->data, name); + + buffer = rpath(ctx, oldpath->data); + buffer1 = rpath(ctx, newpath.data); + ret = link(buffer, buffer1); + g_free(buffer); + g_free(buffer1); + + /* now link the virtfs_metadata files */ + if (!ret && (ctx->export_flags & V9FS_SM_MAPPED_FILE)) { + /* Link the .virtfs_metadata files. Create the metada directory */ + ret = local_create_mapped_attr_dir(ctx, newpath.data); + if (ret < 0) { + goto err_out; + } + buffer = local_mapped_attr_path(ctx, oldpath->data); + buffer1 = local_mapped_attr_path(ctx, newpath.data); + ret = link(buffer, buffer1); + g_free(buffer); + g_free(buffer1); + if (ret < 0 && errno != ENOENT) { + goto err_out; + } + } +err_out: + v9fs_string_free(&newpath); + return ret; +} + +static int local_truncate(FsContext *ctx, V9fsPath *fs_path, off_t size) +{ + char *buffer; + int ret; + char *path = fs_path->data; + + buffer = rpath(ctx, path); + ret = truncate(buffer, size); + g_free(buffer); + return ret; +} + +static int local_rename(FsContext *ctx, const char *oldpath, + const char *newpath) +{ + int err; + char *buffer, *buffer1; + + if (ctx->export_flags & V9FS_SM_MAPPED_FILE) { + err = local_create_mapped_attr_dir(ctx, newpath); + if (err < 0) { + return err; + } + /* rename the .virtfs_metadata files */ + buffer = local_mapped_attr_path(ctx, oldpath); + buffer1 = local_mapped_attr_path(ctx, newpath); + err = rename(buffer, buffer1); + g_free(buffer); + g_free(buffer1); + if (err < 0 && errno != ENOENT) { + return err; + } + } + + buffer = rpath(ctx, oldpath); + buffer1 = rpath(ctx, newpath); + err = rename(buffer, buffer1); + g_free(buffer); + g_free(buffer1); + return err; +} + +static int local_chown(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp) +{ + char *buffer; + int ret = -1; + char *path = fs_path->data; + + if ((credp->fc_uid == -1 && credp->fc_gid == -1) || + (fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) || + (fs_ctx->export_flags & V9FS_SM_NONE)) { + buffer = rpath(fs_ctx, path); + ret = lchown(buffer, credp->fc_uid, credp->fc_gid); + g_free(buffer); + } else if (fs_ctx->export_flags & V9FS_SM_MAPPED) { + buffer = rpath(fs_ctx, path); + ret = local_set_xattr(buffer, credp); + g_free(buffer); + } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) { + return local_set_mapped_file_attr(fs_ctx, path, credp); + } + return ret; +} + +static int local_utimensat(FsContext *s, V9fsPath *fs_path, + const struct timespec *buf) +{ + char *buffer; + int ret; + char *path = fs_path->data; + + buffer = rpath(s, path); + ret = qemu_utimens(buffer, buf); + g_free(buffer); + return ret; +} + +static int local_remove(FsContext *ctx, const char *path) +{ + int err; + struct stat stbuf; + char *buffer; + + if (ctx->export_flags & V9FS_SM_MAPPED_FILE) { + buffer = rpath(ctx, path); + err = lstat(buffer, &stbuf); + g_free(buffer); + if (err) { + goto err_out; + } + /* + * If directory remove .virtfs_metadata contained in the + * directory + */ + if (S_ISDIR(stbuf.st_mode)) { + buffer = g_strdup_printf("%s/%s/%s", ctx->fs_root, + path, VIRTFS_META_DIR); + err = remove(buffer); + g_free(buffer); + if (err < 0 && errno != ENOENT) { + /* + * We didn't had the .virtfs_metadata file. May be file created + * in non-mapped mode ?. Ignore ENOENT. + */ + goto err_out; + } + } + /* + * Now remove the name from parent directory + * .virtfs_metadata directory + */ + buffer = local_mapped_attr_path(ctx, path); + err = remove(buffer); + g_free(buffer); + if (err < 0 && errno != ENOENT) { + /* + * We didn't had the .virtfs_metadata file. May be file created + * in non-mapped mode ?. Ignore ENOENT. + */ + goto err_out; + } + } + + buffer = rpath(ctx, path); + err = remove(buffer); + g_free(buffer); +err_out: + return err; +} + +static int local_fsync(FsContext *ctx, int fid_type, + V9fsFidOpenState *fs, int datasync) +{ + int fd; + + if (fid_type == P9_FID_DIR) { + fd = dirfd(fs->dir); + } else { + fd = fs->fd; + } + + if (datasync) { + return qemu_fdatasync(fd); + } else { + return fsync(fd); + } +} + +static int local_statfs(FsContext *s, V9fsPath *fs_path, struct statfs *stbuf) +{ + char *buffer; + int ret; + char *path = fs_path->data; + + buffer = rpath(s, path); + ret = statfs(buffer, stbuf); + g_free(buffer); + return ret; +} + +static ssize_t local_lgetxattr(FsContext *ctx, V9fsPath *fs_path, + const char *name, void *value, size_t size) +{ + char *path = fs_path->data; + + return v9fs_get_xattr(ctx, path, name, value, size); +} + +static ssize_t local_llistxattr(FsContext *ctx, V9fsPath *fs_path, + void *value, size_t size) +{ + char *path = fs_path->data; + + return v9fs_list_xattr(ctx, path, value, size); +} + +static int local_lsetxattr(FsContext *ctx, V9fsPath *fs_path, const char *name, + void *value, size_t size, int flags) +{ + char *path = fs_path->data; + + return v9fs_set_xattr(ctx, path, name, value, size, flags); +} + +static int local_lremovexattr(FsContext *ctx, V9fsPath *fs_path, + const char *name) +{ + char *path = fs_path->data; + + return v9fs_remove_xattr(ctx, path, name); +} + +static int local_name_to_path(FsContext *ctx, V9fsPath *dir_path, + const char *name, V9fsPath *target) +{ + if (dir_path) { + v9fs_string_sprintf((V9fsString *)target, "%s/%s", + dir_path->data, name); + } else { + v9fs_string_sprintf((V9fsString *)target, "%s", name); + } + /* Bump the size for including terminating NULL */ + target->size++; + return 0; +} + +static int local_renameat(FsContext *ctx, V9fsPath *olddir, + const char *old_name, V9fsPath *newdir, + const char *new_name) +{ + int ret; + V9fsString old_full_name, new_full_name; + + v9fs_string_init(&old_full_name); + v9fs_string_init(&new_full_name); + + v9fs_string_sprintf(&old_full_name, "%s/%s", olddir->data, old_name); + v9fs_string_sprintf(&new_full_name, "%s/%s", newdir->data, new_name); + + ret = local_rename(ctx, old_full_name.data, new_full_name.data); + v9fs_string_free(&old_full_name); + v9fs_string_free(&new_full_name); + return ret; +} + +static int local_unlinkat(FsContext *ctx, V9fsPath *dir, + const char *name, int flags) +{ + int ret; + V9fsString fullname; + char *buffer; + + v9fs_string_init(&fullname); + + v9fs_string_sprintf(&fullname, "%s/%s", dir->data, name); + if (ctx->export_flags & V9FS_SM_MAPPED_FILE) { + if (flags == AT_REMOVEDIR) { + /* + * If directory remove .virtfs_metadata contained in the + * directory + */ + buffer = g_strdup_printf("%s/%s/%s", ctx->fs_root, + fullname.data, VIRTFS_META_DIR); + ret = remove(buffer); + g_free(buffer); + if (ret < 0 && errno != ENOENT) { + /* + * We didn't had the .virtfs_metadata file. May be file created + * in non-mapped mode ?. Ignore ENOENT. + */ + goto err_out; + } + } + /* + * Now remove the name from parent directory + * .virtfs_metadata directory. + */ + buffer = local_mapped_attr_path(ctx, fullname.data); + ret = remove(buffer); + g_free(buffer); + if (ret < 0 && errno != ENOENT) { + /* + * We didn't had the .virtfs_metadata file. May be file created + * in non-mapped mode ?. Ignore ENOENT. + */ + goto err_out; + } + } + /* Remove the name finally */ + buffer = rpath(ctx, fullname.data); + ret = remove(buffer); + g_free(buffer); + +err_out: + v9fs_string_free(&fullname); + return ret; +} + +static int local_ioc_getversion(FsContext *ctx, V9fsPath *path, + mode_t st_mode, uint64_t *st_gen) +{ +#ifdef FS_IOC_GETVERSION + int err; + V9fsFidOpenState fid_open; + + /* + * Do not try to open special files like device nodes, fifos etc + * We can get fd for regular files and directories only + */ + if (!S_ISREG(st_mode) && !S_ISDIR(st_mode)) { + errno = ENOTTY; + return -1; + } + err = local_open(ctx, path, O_RDONLY, &fid_open); + if (err < 0) { + return err; + } + err = ioctl(fid_open.fd, FS_IOC_GETVERSION, st_gen); + local_close(ctx, &fid_open); + return err; +#else + errno = ENOTTY; + return -1; +#endif +} + +static int local_init(FsContext *ctx) +{ + int err = 0; + struct statfs stbuf; + + if (ctx->export_flags & V9FS_SM_PASSTHROUGH) { + ctx->xops = passthrough_xattr_ops; + } else if (ctx->export_flags & V9FS_SM_MAPPED) { + ctx->xops = mapped_xattr_ops; + } else if (ctx->export_flags & V9FS_SM_NONE) { + ctx->xops = none_xattr_ops; + } else if (ctx->export_flags & V9FS_SM_MAPPED_FILE) { + /* + * xattr operation for mapped-file and passthrough + * remain same. + */ + ctx->xops = passthrough_xattr_ops; + } + ctx->export_flags |= V9FS_PATHNAME_FSCONTEXT; +#ifdef FS_IOC_GETVERSION + /* + * use ioc_getversion only if the iocl is definied + */ + err = statfs(ctx->fs_root, &stbuf); + if (!err) { + switch (stbuf.f_type) { + case EXT2_SUPER_MAGIC: + case BTRFS_SUPER_MAGIC: + case REISERFS_SUPER_MAGIC: + case XFS_SUPER_MAGIC: + ctx->exops.get_st_gen = local_ioc_getversion; + break; + } + } +#endif + return err; +} + +static int local_parse_opts(QemuOpts *opts, struct FsDriverEntry *fse) +{ + const char *sec_model = qemu_opt_get(opts, "security_model"); + const char *path = qemu_opt_get(opts, "path"); + + if (!sec_model) { + fprintf(stderr, "security model not specified, " + "local fs needs security model\nvalid options are:" + "\tsecurity_model=[passthrough|mapped|none]\n"); + return -1; + } + + if (!strcmp(sec_model, "passthrough")) { + fse->export_flags |= V9FS_SM_PASSTHROUGH; + } else if (!strcmp(sec_model, "mapped") || + !strcmp(sec_model, "mapped-xattr")) { + fse->export_flags |= V9FS_SM_MAPPED; + } else if (!strcmp(sec_model, "none")) { + fse->export_flags |= V9FS_SM_NONE; + } else if (!strcmp(sec_model, "mapped-file")) { + fse->export_flags |= V9FS_SM_MAPPED_FILE; + } else { + fprintf(stderr, "Invalid security model %s specified, valid options are" + "\n\t [passthrough|mapped-xattr|mapped-file|none]\n", + sec_model); + return -1; + } + + if (!path) { + fprintf(stderr, "fsdev: No path specified.\n"); + return -1; + } + fse->path = g_strdup(path); + + return 0; +} + +FileOperations local_ops = { + .parse_opts = local_parse_opts, + .init = local_init, + .lstat = local_lstat, + .readlink = local_readlink, + .close = local_close, + .closedir = local_closedir, + .open = local_open, + .opendir = local_opendir, + .rewinddir = local_rewinddir, + .telldir = local_telldir, + .readdir_r = local_readdir_r, + .seekdir = local_seekdir, + .preadv = local_preadv, + .pwritev = local_pwritev, + .chmod = local_chmod, + .mknod = local_mknod, + .mkdir = local_mkdir, + .fstat = local_fstat, + .open2 = local_open2, + .symlink = local_symlink, + .link = local_link, + .truncate = local_truncate, + .rename = local_rename, + .chown = local_chown, + .utimensat = local_utimensat, + .remove = local_remove, + .fsync = local_fsync, + .statfs = local_statfs, + .lgetxattr = local_lgetxattr, + .llistxattr = local_llistxattr, + .lsetxattr = local_lsetxattr, + .lremovexattr = local_lremovexattr, + .name_to_path = local_name_to_path, + .renameat = local_renameat, + .unlinkat = local_unlinkat, +}; diff --git a/hw/9pfs/Makefile.objs b/hw/9pfs/Makefile.objs index 5efd4993f6..7342c76341 100644 --- a/hw/9pfs/Makefile.objs +++ b/hw/9pfs/Makefile.objs @@ -1,5 +1,5 @@ common-obj-y = virtio-9p.o -common-obj-y += virtio-9p-local.o virtio-9p-xattr.o +common-obj-y += 9p-local.o virtio-9p-xattr.o common-obj-y += virtio-9p-xattr-user.o virtio-9p-posix-acl.o common-obj-y += virtio-9p-coth.o cofs.o codir.o cofile.o common-obj-y += coxattr.o virtio-9p-synth.o diff --git a/hw/9pfs/virtio-9p-local.c b/hw/9pfs/virtio-9p-local.c deleted file mode 100644 index 56b302c122..0000000000 --- a/hw/9pfs/virtio-9p-local.c +++ /dev/null @@ -1,1295 +0,0 @@ -/* - * Virtio 9p Posix callback - * - * Copyright IBM, Corp. 2010 - * - * Authors: - * Anthony Liguori <aliguori@us.ibm.com> - * - * This work is licensed under the terms of the GNU GPL, version 2. See - * the COPYING file in the top-level directory. - * - */ - -#include "hw/virtio/virtio.h" -#include "virtio-9p.h" -#include "virtio-9p-xattr.h" -#include <arpa/inet.h> -#include <pwd.h> -#include <grp.h> -#include <sys/socket.h> -#include <sys/un.h> -#include "qemu/xattr.h" -#include <libgen.h> -#include <linux/fs.h> -#ifdef CONFIG_LINUX_MAGIC_H -#include <linux/magic.h> -#endif -#include <sys/ioctl.h> - -#ifndef XFS_SUPER_MAGIC -#define XFS_SUPER_MAGIC 0x58465342 -#endif -#ifndef EXT2_SUPER_MAGIC -#define EXT2_SUPER_MAGIC 0xEF53 -#endif -#ifndef REISERFS_SUPER_MAGIC -#define REISERFS_SUPER_MAGIC 0x52654973 -#endif -#ifndef BTRFS_SUPER_MAGIC -#define BTRFS_SUPER_MAGIC 0x9123683E -#endif - -#define VIRTFS_META_DIR ".virtfs_metadata" - -static char *local_mapped_attr_path(FsContext *ctx, const char *path) -{ - char *dir_name; - char *tmp_path = g_strdup(path); - char *base_name = basename(tmp_path); - char *buffer; - - /* NULL terminate the directory */ - dir_name = tmp_path; - *(base_name - 1) = '\0'; - - buffer = g_strdup_printf("%s/%s/%s/%s", - ctx->fs_root, dir_name, VIRTFS_META_DIR, base_name); - g_free(tmp_path); - return buffer; -} - -static FILE *local_fopen(const char *path, const char *mode) -{ - int fd, o_mode = 0; - FILE *fp; - int flags = O_NOFOLLOW; - /* - * only supports two modes - */ - if (mode[0] == 'r') { - flags |= O_RDONLY; - } else if (mode[0] == 'w') { - flags |= O_WRONLY | O_TRUNC | O_CREAT; - o_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; - } else { - return NULL; - } - fd = open(path, flags, o_mode); - if (fd == -1) { - return NULL; - } - fp = fdopen(fd, mode); - if (!fp) { - close(fd); - } - return fp; -} - -#define ATTR_MAX 100 -static void local_mapped_file_attr(FsContext *ctx, const char *path, - struct stat *stbuf) -{ - FILE *fp; - char buf[ATTR_MAX]; - char *attr_path; - - attr_path = local_mapped_attr_path(ctx, path); - fp = local_fopen(attr_path, "r"); - g_free(attr_path); - if (!fp) { - return; - } - memset(buf, 0, ATTR_MAX); - while (fgets(buf, ATTR_MAX, fp)) { - if (!strncmp(buf, "virtfs.uid", 10)) { - stbuf->st_uid = atoi(buf+11); - } else if (!strncmp(buf, "virtfs.gid", 10)) { - stbuf->st_gid = atoi(buf+11); - } else if (!strncmp(buf, "virtfs.mode", 11)) { - stbuf->st_mode = atoi(buf+12); - } else if (!strncmp(buf, "virtfs.rdev", 11)) { - stbuf->st_rdev = atoi(buf+12); - } - memset(buf, 0, ATTR_MAX); - } - fclose(fp); -} - -static int local_lstat(FsContext *fs_ctx, V9fsPath *fs_path, struct stat *stbuf) -{ - int err; - char *buffer; - char *path = fs_path->data; - - buffer = rpath(fs_ctx, path); - err = lstat(buffer, stbuf); - if (err) { - goto err_out; - } - if (fs_ctx->export_flags & V9FS_SM_MAPPED) { - /* Actual credentials are part of extended attrs */ - uid_t tmp_uid; - gid_t tmp_gid; - mode_t tmp_mode; - dev_t tmp_dev; - if (getxattr(buffer, "user.virtfs.uid", &tmp_uid, sizeof(uid_t)) > 0) { - stbuf->st_uid = tmp_uid; - } - if (getxattr(buffer, "user.virtfs.gid", &tmp_gid, sizeof(gid_t)) > 0) { - stbuf->st_gid = tmp_gid; - } - if (getxattr(buffer, "user.virtfs.mode", - &tmp_mode, sizeof(mode_t)) > 0) { - stbuf->st_mode = tmp_mode; - } - if (getxattr(buffer, "user.virtfs.rdev", &tmp_dev, sizeof(dev_t)) > 0) { - stbuf->st_rdev = tmp_dev; - } - } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) { - local_mapped_file_attr(fs_ctx, path, stbuf); - } - -err_out: - g_free(buffer); - return err; -} - -static int local_create_mapped_attr_dir(FsContext *ctx, const char *path) -{ - int err; - char *attr_dir; - char *tmp_path = g_strdup(path); - - attr_dir = g_strdup_printf("%s/%s/%s", - ctx->fs_root, dirname(tmp_path), VIRTFS_META_DIR); - - err = mkdir(attr_dir, 0700); - if (err < 0 && errno == EEXIST) { - err = 0; - } - g_free(attr_dir); - g_free(tmp_path); - return err; -} - -static int local_set_mapped_file_attr(FsContext *ctx, - const char *path, FsCred *credp) -{ - FILE *fp; - int ret = 0; - char buf[ATTR_MAX]; - char *attr_path; - int uid = -1, gid = -1, mode = -1, rdev = -1; - - attr_path = local_mapped_attr_path(ctx, path); - fp = local_fopen(attr_path, "r"); - if (!fp) { - goto create_map_file; - } - memset(buf, 0, ATTR_MAX); - while (fgets(buf, ATTR_MAX, fp)) { - if (!strncmp(buf, "virtfs.uid", 10)) { - uid = atoi(buf+11); - } else if (!strncmp(buf, "virtfs.gid", 10)) { - gid = atoi(buf+11); - } else if (!strncmp(buf, "virtfs.mode", 11)) { - mode = atoi(buf+12); - } else if (!strncmp(buf, "virtfs.rdev", 11)) { - rdev = atoi(buf+12); - } - memset(buf, 0, ATTR_MAX); - } - fclose(fp); - goto update_map_file; - -create_map_file: - ret = local_create_mapped_attr_dir(ctx, path); - if (ret < 0) { - goto err_out; - } - -update_map_file: - fp = local_fopen(attr_path, "w"); - if (!fp) { - ret = -1; - goto err_out; - } - - if (credp->fc_uid != -1) { - uid = credp->fc_uid; - } - if (credp->fc_gid != -1) { - gid = credp->fc_gid; - } - if (credp->fc_mode != -1) { - mode = credp->fc_mode; - } - if (credp->fc_rdev != -1) { - rdev = credp->fc_rdev; - } - - - if (uid != -1) { - fprintf(fp, "virtfs.uid=%d\n", uid); - } - if (gid != -1) { - fprintf(fp, "virtfs.gid=%d\n", gid); - } - if (mode != -1) { - fprintf(fp, "virtfs.mode=%d\n", mode); - } - if (rdev != -1) { - fprintf(fp, "virtfs.rdev=%d\n", rdev); - } - fclose(fp); - -err_out: - g_free(attr_path); - return ret; -} - -static int local_set_xattr(const char *path, FsCred *credp) -{ - int err; - - if (credp->fc_uid != -1) { - err = setxattr(path, "user.virtfs.uid", &credp->fc_uid, sizeof(uid_t), - 0); - if (err) { - return err; - } - } - if (credp->fc_gid != -1) { - err = setxattr(path, "user.virtfs.gid", &credp->fc_gid, sizeof(gid_t), - 0); - if (err) { - return err; - } - } - if (credp->fc_mode != -1) { - err = setxattr(path, "user.virtfs.mode", &credp->fc_mode, - sizeof(mode_t), 0); - if (err) { - return err; - } - } - if (credp->fc_rdev != -1) { - err = setxattr(path, "user.virtfs.rdev", &credp->fc_rdev, - sizeof(dev_t), 0); - if (err) { - return err; - } - } - return 0; -} - -static int local_post_create_passthrough(FsContext *fs_ctx, const char *path, - FsCred *credp) -{ - char *buffer; - - buffer = rpath(fs_ctx, path); - if (lchown(buffer, credp->fc_uid, credp->fc_gid) < 0) { - /* - * If we fail to change ownership and if we are - * using security model none. Ignore the error - */ - if ((fs_ctx->export_flags & V9FS_SEC_MASK) != V9FS_SM_NONE) { - goto err; - } - } - - if (chmod(buffer, credp->fc_mode & 07777) < 0) { - goto err; - } - - g_free(buffer); - return 0; -err: - g_free(buffer); - return -1; -} - -static ssize_t local_readlink(FsContext *fs_ctx, V9fsPath *fs_path, - char *buf, size_t bufsz) -{ - ssize_t tsize = -1; - char *buffer; - char *path = fs_path->data; - - if ((fs_ctx->export_flags & V9FS_SM_MAPPED) || - (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE)) { - int fd; - buffer = rpath(fs_ctx, path); - fd = open(buffer, O_RDONLY | O_NOFOLLOW); - g_free(buffer); - if (fd == -1) { - return -1; - } - do { - tsize = read(fd, (void *)buf, bufsz); - } while (tsize == -1 && errno == EINTR); - close(fd); - return tsize; - } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) || - (fs_ctx->export_flags & V9FS_SM_NONE)) { - buffer = rpath(fs_ctx, path); - tsize = readlink(buffer, buf, bufsz); - g_free(buffer); - } - return tsize; -} - -static int local_close(FsContext *ctx, V9fsFidOpenState *fs) -{ - return close(fs->fd); -} - -static int local_closedir(FsContext *ctx, V9fsFidOpenState *fs) -{ - return closedir(fs->dir); -} - -static int local_open(FsContext *ctx, V9fsPath *fs_path, - int flags, V9fsFidOpenState *fs) -{ - char *buffer; - char *path = fs_path->data; - - buffer = rpath(ctx, path); - fs->fd = open(buffer, flags | O_NOFOLLOW); - g_free(buffer); - return fs->fd; -} - -static int local_opendir(FsContext *ctx, - V9fsPath *fs_path, V9fsFidOpenState *fs) -{ - char *buffer; - char *path = fs_path->data; - - buffer = rpath(ctx, path); - fs->dir = opendir(buffer); - g_free(buffer); - if (!fs->dir) { - return -1; - } - return 0; -} - -static void local_rewinddir(FsContext *ctx, V9fsFidOpenState *fs) -{ - return rewinddir(fs->dir); -} - -static off_t local_telldir(FsContext *ctx, V9fsFidOpenState *fs) -{ - return telldir(fs->dir); -} - -static int local_readdir_r(FsContext *ctx, V9fsFidOpenState *fs, - struct dirent *entry, - struct dirent **result) -{ - int ret; - -again: - ret = readdir_r(fs->dir, entry, result); - if (ctx->export_flags & V9FS_SM_MAPPED_FILE) { - if (!ret && *result != NULL && - !strcmp(entry->d_name, VIRTFS_META_DIR)) { - /* skp the meta data directory */ - goto again; - } - } - return ret; -} - -static void local_seekdir(FsContext *ctx, V9fsFidOpenState *fs, off_t off) -{ - return seekdir(fs->dir, off); -} - -static ssize_t local_preadv(FsContext *ctx, V9fsFidOpenState *fs, - const struct iovec *iov, - int iovcnt, off_t offset) -{ -#ifdef CONFIG_PREADV - return preadv(fs->fd, iov, iovcnt, offset); -#else - int err = lseek(fs->fd, offset, SEEK_SET); - if (err == -1) { - return err; - } else { - return readv(fs->fd, iov, iovcnt); - } -#endif -} - -static ssize_t local_pwritev(FsContext *ctx, V9fsFidOpenState *fs, - const struct iovec *iov, - int iovcnt, off_t offset) -{ - ssize_t ret -; -#ifdef CONFIG_PREADV - ret = pwritev(fs->fd, iov, iovcnt, offset); -#else - int err = lseek(fs->fd, offset, SEEK_SET); - if (err == -1) { - return err; - } else { - ret = writev(fs->fd, iov, iovcnt); - } -#endif -#ifdef CONFIG_SYNC_FILE_RANGE - if (ret > 0 && ctx->export_flags & V9FS_IMMEDIATE_WRITEOUT) { - /* - * Initiate a writeback. This is not a data integrity sync. - * We want to ensure that we don't leave dirty pages in the cache - * after write when writeout=immediate is sepcified. - */ - sync_file_range(fs->fd, offset, ret, - SYNC_FILE_RANGE_WAIT_BEFORE | SYNC_FILE_RANGE_WRITE); - } -#endif - return ret; -} - -static int local_chmod(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp) -{ - char *buffer; - int ret = -1; - char *path = fs_path->data; - - if (fs_ctx->export_flags & V9FS_SM_MAPPED) { - buffer = rpath(fs_ctx, path); - ret = local_set_xattr(buffer, credp); - g_free(buffer); - } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) { - return local_set_mapped_file_attr(fs_ctx, path, credp); - } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) || - (fs_ctx->export_flags & V9FS_SM_NONE)) { - buffer = rpath(fs_ctx, path); - ret = chmod(buffer, credp->fc_mode); - g_free(buffer); - } - return ret; -} - -static int local_mknod(FsContext *fs_ctx, V9fsPath *dir_path, - const char *name, FsCred *credp) -{ - char *path; - int err = -1; - int serrno = 0; - V9fsString fullname; - char *buffer; - - v9fs_string_init(&fullname); - v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name); - path = fullname.data; - - /* Determine the security model */ - if (fs_ctx->export_flags & V9FS_SM_MAPPED) { - buffer = rpath(fs_ctx, path); - err = mknod(buffer, SM_LOCAL_MODE_BITS|S_IFREG, 0); - if (err == -1) { - g_free(buffer); - goto out; - } - err = local_set_xattr(buffer, credp); - if (err == -1) { - serrno = errno; - goto err_end; - } - } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) { - - buffer = rpath(fs_ctx, path); - err = mknod(buffer, SM_LOCAL_MODE_BITS|S_IFREG, 0); - if (err == -1) { - g_free(buffer); - goto out; - } - err = local_set_mapped_file_attr(fs_ctx, path, credp); - if (err == -1) { - serrno = errno; - goto err_end; - } - } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) || - (fs_ctx->export_flags & V9FS_SM_NONE)) { - buffer = rpath(fs_ctx, path); - err = mknod(buffer, credp->fc_mode, credp->fc_rdev); - if (err == -1) { - g_free(buffer); - goto out; - } - err = local_post_create_passthrough(fs_ctx, path, credp); - if (err == -1) { - serrno = errno; - goto err_end; - } - } - goto out; - -err_end: - remove(buffer); - errno = serrno; - g_free(buffer); -out: - v9fs_string_free(&fullname); - return err; -} - -static int local_mkdir(FsContext *fs_ctx, V9fsPath *dir_path, - const char *name, FsCred *credp) -{ - char *path; - int err = -1; - int serrno = 0; - V9fsString fullname; - char *buffer; - - v9fs_string_init(&fullname); - v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name); - path = fullname.data; - - /* Determine the security model */ - if (fs_ctx->export_flags & V9FS_SM_MAPPED) { - buffer = rpath(fs_ctx, path); - err = mkdir(buffer, SM_LOCAL_DIR_MODE_BITS); - if (err == -1) { - g_free(buffer); - goto out; - } - credp->fc_mode = credp->fc_mode|S_IFDIR; - err = local_set_xattr(buffer, credp); - if (err == -1) { - serrno = errno; - goto err_end; - } - } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) { - buffer = rpath(fs_ctx, path); - err = mkdir(buffer, SM_LOCAL_DIR_MODE_BITS); - if (err == -1) { - g_free(buffer); - goto out; - } - credp->fc_mode = credp->fc_mode|S_IFDIR; - err = local_set_mapped_file_attr(fs_ctx, path, credp); - if (err == -1) { - serrno = errno; - goto err_end; - } - } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) || - (fs_ctx->export_flags & V9FS_SM_NONE)) { - buffer = rpath(fs_ctx, path); - err = mkdir(buffer, credp->fc_mode); - if (err == -1) { - g_free(buffer); - goto out; - } - err = local_post_create_passthrough(fs_ctx, path, credp); - if (err == -1) { - serrno = errno; - goto err_end; - } - } - goto out; - -err_end: - remove(buffer); - errno = serrno; - g_free(buffer); -out: - v9fs_string_free(&fullname); - return err; -} - -static int local_fstat(FsContext *fs_ctx, int fid_type, - V9fsFidOpenState *fs, struct stat *stbuf) -{ - int err, fd; - - if (fid_type == P9_FID_DIR) { - fd = dirfd(fs->dir); - } else { - fd = fs->fd; - } - - err = fstat(fd, stbuf); - if (err) { - return err; - } - if (fs_ctx->export_flags & V9FS_SM_MAPPED) { - /* Actual credentials are part of extended attrs */ - uid_t tmp_uid; - gid_t tmp_gid; - mode_t tmp_mode; - dev_t tmp_dev; - - if (fgetxattr(fd, "user.virtfs.uid", - &tmp_uid, sizeof(uid_t)) > 0) { - stbuf->st_uid = tmp_uid; - } - if (fgetxattr(fd, "user.virtfs.gid", - &tmp_gid, sizeof(gid_t)) > 0) { - stbuf->st_gid = tmp_gid; - } - if (fgetxattr(fd, "user.virtfs.mode", - &tmp_mode, sizeof(mode_t)) > 0) { - stbuf->st_mode = tmp_mode; - } - if (fgetxattr(fd, "user.virtfs.rdev", - &tmp_dev, sizeof(dev_t)) > 0) { - stbuf->st_rdev = tmp_dev; - } - } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) { - errno = EOPNOTSUPP; - return -1; - } - return err; -} - -static int local_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name, - int flags, FsCred *credp, V9fsFidOpenState *fs) -{ - char *path; - int fd = -1; - int err = -1; - int serrno = 0; - V9fsString fullname; - char *buffer; - - /* - * Mark all the open to not follow symlinks - */ - flags |= O_NOFOLLOW; - - v9fs_string_init(&fullname); - v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name); - path = fullname.data; - - /* Determine the security model */ - if (fs_ctx->export_flags & V9FS_SM_MAPPED) { - buffer = rpath(fs_ctx, path); - fd = open(buffer, flags, SM_LOCAL_MODE_BITS); - if (fd == -1) { - g_free(buffer); - err = fd; - goto out; - } - credp->fc_mode = credp->fc_mode|S_IFREG; - /* Set cleint credentials in xattr */ - err = local_set_xattr(buffer, credp); - if (err == -1) { - serrno = errno; - goto err_end; - } - } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) { - buffer = rpath(fs_ctx, path); - fd = open(buffer, flags, SM_LOCAL_MODE_BITS); - if (fd == -1) { - g_free(buffer); - err = fd; - goto out; - } - credp->fc_mode = credp->fc_mode|S_IFREG; - /* Set client credentials in .virtfs_metadata directory files */ - err = local_set_mapped_file_attr(fs_ctx, path, credp); - if (err == -1) { - serrno = errno; - goto err_end; - } - } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) || - (fs_ctx->export_flags & V9FS_SM_NONE)) { - buffer = rpath(fs_ctx, path); - fd = open(buffer, flags, credp->fc_mode); - if (fd == -1) { - g_free(buffer); - err = fd; - goto out; - } - err = local_post_create_passthrough(fs_ctx, path, credp); - if (err == -1) { - serrno = errno; - goto err_end; - } - } - err = fd; - fs->fd = fd; - goto out; - -err_end: - close(fd); - remove(buffer); - errno = serrno; - g_free(buffer); -out: - v9fs_string_free(&fullname); - return err; -} - - -static int local_symlink(FsContext *fs_ctx, const char *oldpath, - V9fsPath *dir_path, const char *name, FsCred *credp) -{ - int err = -1; - int serrno = 0; - char *newpath; - V9fsString fullname; - char *buffer; - - v9fs_string_init(&fullname); - v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name); - newpath = fullname.data; - - /* Determine the security model */ - if (fs_ctx->export_flags & V9FS_SM_MAPPED) { - int fd; - ssize_t oldpath_size, write_size; - buffer = rpath(fs_ctx, newpath); - fd = open(buffer, O_CREAT|O_EXCL|O_RDWR|O_NOFOLLOW, SM_LOCAL_MODE_BITS); - if (fd == -1) { - g_free(buffer); - err = fd; - goto out; - } - /* Write the oldpath (target) to the file. */ - oldpath_size = strlen(oldpath); - do { - write_size = write(fd, (void *)oldpath, oldpath_size); - } while (write_size == -1 && errno == EINTR); - - if (write_size != oldpath_size) { - serrno = errno; - close(fd); - err = -1; - goto err_end; - } - close(fd); - /* Set cleint credentials in symlink's xattr */ - credp->fc_mode = credp->fc_mode|S_IFLNK; - err = local_set_xattr(buffer, credp); - if (err == -1) { - serrno = errno; - goto err_end; - } - } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) { - int fd; - ssize_t oldpath_size, write_size; - buffer = rpath(fs_ctx, newpath); - fd = open(buffer, O_CREAT|O_EXCL|O_RDWR|O_NOFOLLOW, SM_LOCAL_MODE_BITS); - if (fd == -1) { - g_free(buffer); - err = fd; - goto out; - } - /* Write the oldpath (target) to the file. */ - oldpath_size = strlen(oldpath); - do { - write_size = write(fd, (void *)oldpath, oldpath_size); - } while (write_size == -1 && errno == EINTR); - - if (write_size != oldpath_size) { - serrno = errno; - close(fd); - err = -1; - goto err_end; - } - close(fd); - /* Set cleint credentials in symlink's xattr */ - credp->fc_mode = credp->fc_mode|S_IFLNK; - err = local_set_mapped_file_attr(fs_ctx, newpath, credp); - if (err == -1) { - serrno = errno; - goto err_end; - } - } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) || - (fs_ctx->export_flags & V9FS_SM_NONE)) { - buffer = rpath(fs_ctx, newpath); - err = symlink(oldpath, buffer); - if (err) { - g_free(buffer); - goto out; - } - err = lchown(buffer, credp->fc_uid, credp->fc_gid); - if (err == -1) { - /* - * If we fail to change ownership and if we are - * using security model none. Ignore the error - */ - if ((fs_ctx->export_flags & V9FS_SEC_MASK) != V9FS_SM_NONE) { - serrno = errno; - goto err_end; - } else - err = 0; - } - } - goto out; - -err_end: - remove(buffer); - errno = serrno; - g_free(buffer); -out: - v9fs_string_free(&fullname); - return err; -} - -static int local_link(FsContext *ctx, V9fsPath *oldpath, - V9fsPath *dirpath, const char *name) -{ - int ret; - V9fsString newpath; - char *buffer, *buffer1; - - v9fs_string_init(&newpath); - v9fs_string_sprintf(&newpath, "%s/%s", dirpath->data, name); - - buffer = rpath(ctx, oldpath->data); - buffer1 = rpath(ctx, newpath.data); - ret = link(buffer, buffer1); - g_free(buffer); - g_free(buffer1); - - /* now link the virtfs_metadata files */ - if (!ret && (ctx->export_flags & V9FS_SM_MAPPED_FILE)) { - /* Link the .virtfs_metadata files. Create the metada directory */ - ret = local_create_mapped_attr_dir(ctx, newpath.data); - if (ret < 0) { - goto err_out; - } - buffer = local_mapped_attr_path(ctx, oldpath->data); - buffer1 = local_mapped_attr_path(ctx, newpath.data); - ret = link(buffer, buffer1); - g_free(buffer); - g_free(buffer1); - if (ret < 0 && errno != ENOENT) { - goto err_out; - } - } -err_out: - v9fs_string_free(&newpath); - return ret; -} - -static int local_truncate(FsContext *ctx, V9fsPath *fs_path, off_t size) -{ - char *buffer; - int ret; - char *path = fs_path->data; - - buffer = rpath(ctx, path); - ret = truncate(buffer, size); - g_free(buffer); - return ret; -} - -static int local_rename(FsContext *ctx, const char *oldpath, - const char *newpath) -{ - int err; - char *buffer, *buffer1; - - if (ctx->export_flags & V9FS_SM_MAPPED_FILE) { - err = local_create_mapped_attr_dir(ctx, newpath); - if (err < 0) { - return err; - } - /* rename the .virtfs_metadata files */ - buffer = local_mapped_attr_path(ctx, oldpath); - buffer1 = local_mapped_attr_path(ctx, newpath); - err = rename(buffer, buffer1); - g_free(buffer); - g_free(buffer1); - if (err < 0 && errno != ENOENT) { - return err; - } - } - - buffer = rpath(ctx, oldpath); - buffer1 = rpath(ctx, newpath); - err = rename(buffer, buffer1); - g_free(buffer); - g_free(buffer1); - return err; -} - -static int local_chown(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp) -{ - char *buffer; - int ret = -1; - char *path = fs_path->data; - - if ((credp->fc_uid == -1 && credp->fc_gid == -1) || - (fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) || - (fs_ctx->export_flags & V9FS_SM_NONE)) { - buffer = rpath(fs_ctx, path); - ret = lchown(buffer, credp->fc_uid, credp->fc_gid); - g_free(buffer); - } else if (fs_ctx->export_flags & V9FS_SM_MAPPED) { - buffer = rpath(fs_ctx, path); - ret = local_set_xattr(buffer, credp); - g_free(buffer); - } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) { - return local_set_mapped_file_attr(fs_ctx, path, credp); - } - return ret; -} - -static int local_utimensat(FsContext *s, V9fsPath *fs_path, - const struct timespec *buf) -{ - char *buffer; - int ret; - char *path = fs_path->data; - - buffer = rpath(s, path); - ret = qemu_utimens(buffer, buf); - g_free(buffer); - return ret; -} - -static int local_remove(FsContext *ctx, const char *path) -{ - int err; - struct stat stbuf; - char *buffer; - - if (ctx->export_flags & V9FS_SM_MAPPED_FILE) { - buffer = rpath(ctx, path); - err = lstat(buffer, &stbuf); - g_free(buffer); - if (err) { - goto err_out; - } - /* - * If directory remove .virtfs_metadata contained in the - * directory - */ - if (S_ISDIR(stbuf.st_mode)) { - buffer = g_strdup_printf("%s/%s/%s", ctx->fs_root, - path, VIRTFS_META_DIR); - err = remove(buffer); - g_free(buffer); - if (err < 0 && errno != ENOENT) { - /* - * We didn't had the .virtfs_metadata file. May be file created - * in non-mapped mode ?. Ignore ENOENT. - */ - goto err_out; - } - } - /* - * Now remove the name from parent directory - * .virtfs_metadata directory - */ - buffer = local_mapped_attr_path(ctx, path); - err = remove(buffer); - g_free(buffer); - if (err < 0 && errno != ENOENT) { - /* - * We didn't had the .virtfs_metadata file. May be file created - * in non-mapped mode ?. Ignore ENOENT. - */ - goto err_out; - } - } - - buffer = rpath(ctx, path); - err = remove(buffer); - g_free(buffer); -err_out: - return err; -} - -static int local_fsync(FsContext *ctx, int fid_type, - V9fsFidOpenState *fs, int datasync) -{ - int fd; - - if (fid_type == P9_FID_DIR) { - fd = dirfd(fs->dir); - } else { - fd = fs->fd; - } - - if (datasync) { - return qemu_fdatasync(fd); - } else { - return fsync(fd); - } -} - -static int local_statfs(FsContext *s, V9fsPath *fs_path, struct statfs *stbuf) -{ - char *buffer; - int ret; - char *path = fs_path->data; - - buffer = rpath(s, path); - ret = statfs(buffer, stbuf); - g_free(buffer); - return ret; -} - -static ssize_t local_lgetxattr(FsContext *ctx, V9fsPath *fs_path, - const char *name, void *value, size_t size) -{ - char *path = fs_path->data; - - return v9fs_get_xattr(ctx, path, name, value, size); -} - -static ssize_t local_llistxattr(FsContext *ctx, V9fsPath *fs_path, - void *value, size_t size) -{ - char *path = fs_path->data; - - return v9fs_list_xattr(ctx, path, value, size); -} - -static int local_lsetxattr(FsContext *ctx, V9fsPath *fs_path, const char *name, - void *value, size_t size, int flags) -{ - char *path = fs_path->data; - - return v9fs_set_xattr(ctx, path, name, value, size, flags); -} - -static int local_lremovexattr(FsContext *ctx, V9fsPath *fs_path, - const char *name) -{ - char *path = fs_path->data; - - return v9fs_remove_xattr(ctx, path, name); -} - -static int local_name_to_path(FsContext *ctx, V9fsPath *dir_path, - const char *name, V9fsPath *target) -{ - if (dir_path) { - v9fs_string_sprintf((V9fsString *)target, "%s/%s", - dir_path->data, name); - } else { - v9fs_string_sprintf((V9fsString *)target, "%s", name); - } - /* Bump the size for including terminating NULL */ - target->size++; - return 0; -} - -static int local_renameat(FsContext *ctx, V9fsPath *olddir, - const char *old_name, V9fsPath *newdir, - const char *new_name) -{ - int ret; - V9fsString old_full_name, new_full_name; - - v9fs_string_init(&old_full_name); - v9fs_string_init(&new_full_name); - - v9fs_string_sprintf(&old_full_name, "%s/%s", olddir->data, old_name); - v9fs_string_sprintf(&new_full_name, "%s/%s", newdir->data, new_name); - - ret = local_rename(ctx, old_full_name.data, new_full_name.data); - v9fs_string_free(&old_full_name); - v9fs_string_free(&new_full_name); - return ret; -} - -static int local_unlinkat(FsContext *ctx, V9fsPath *dir, - const char *name, int flags) -{ - int ret; - V9fsString fullname; - char *buffer; - - v9fs_string_init(&fullname); - - v9fs_string_sprintf(&fullname, "%s/%s", dir->data, name); - if (ctx->export_flags & V9FS_SM_MAPPED_FILE) { - if (flags == AT_REMOVEDIR) { - /* - * If directory remove .virtfs_metadata contained in the - * directory - */ - buffer = g_strdup_printf("%s/%s/%s", ctx->fs_root, - fullname.data, VIRTFS_META_DIR); - ret = remove(buffer); - g_free(buffer); - if (ret < 0 && errno != ENOENT) { - /* - * We didn't had the .virtfs_metadata file. May be file created - * in non-mapped mode ?. Ignore ENOENT. - */ - goto err_out; - } - } - /* - * Now remove the name from parent directory - * .virtfs_metadata directory. - */ - buffer = local_mapped_attr_path(ctx, fullname.data); - ret = remove(buffer); - g_free(buffer); - if (ret < 0 && errno != ENOENT) { - /* - * We didn't had the .virtfs_metadata file. May be file created - * in non-mapped mode ?. Ignore ENOENT. - */ - goto err_out; - } - } - /* Remove the name finally */ - buffer = rpath(ctx, fullname.data); - ret = remove(buffer); - g_free(buffer); - -err_out: - v9fs_string_free(&fullname); - return ret; -} - -static int local_ioc_getversion(FsContext *ctx, V9fsPath *path, - mode_t st_mode, uint64_t *st_gen) -{ -#ifdef FS_IOC_GETVERSION - int err; - V9fsFidOpenState fid_open; - - /* - * Do not try to open special files like device nodes, fifos etc - * We can get fd for regular files and directories only - */ - if (!S_ISREG(st_mode) && !S_ISDIR(st_mode)) { - errno = ENOTTY; - return -1; - } - err = local_open(ctx, path, O_RDONLY, &fid_open); - if (err < 0) { - return err; - } - err = ioctl(fid_open.fd, FS_IOC_GETVERSION, st_gen); - local_close(ctx, &fid_open); - return err; -#else - errno = ENOTTY; - return -1; -#endif -} - -static int local_init(FsContext *ctx) -{ - int err = 0; - struct statfs stbuf; - - if (ctx->export_flags & V9FS_SM_PASSTHROUGH) { - ctx->xops = passthrough_xattr_ops; - } else if (ctx->export_flags & V9FS_SM_MAPPED) { - ctx->xops = mapped_xattr_ops; - } else if (ctx->export_flags & V9FS_SM_NONE) { - ctx->xops = none_xattr_ops; - } else if (ctx->export_flags & V9FS_SM_MAPPED_FILE) { - /* - * xattr operation for mapped-file and passthrough - * remain same. - */ - ctx->xops = passthrough_xattr_ops; - } - ctx->export_flags |= V9FS_PATHNAME_FSCONTEXT; -#ifdef FS_IOC_GETVERSION - /* - * use ioc_getversion only if the iocl is definied - */ - err = statfs(ctx->fs_root, &stbuf); - if (!err) { - switch (stbuf.f_type) { - case EXT2_SUPER_MAGIC: - case BTRFS_SUPER_MAGIC: - case REISERFS_SUPER_MAGIC: - case XFS_SUPER_MAGIC: - ctx->exops.get_st_gen = local_ioc_getversion; - break; - } - } -#endif - return err; -} - -static int local_parse_opts(QemuOpts *opts, struct FsDriverEntry *fse) -{ - const char *sec_model = qemu_opt_get(opts, "security_model"); - const char *path = qemu_opt_get(opts, "path"); - - if (!sec_model) { - fprintf(stderr, "security model not specified, " - "local fs needs security model\nvalid options are:" - "\tsecurity_model=[passthrough|mapped|none]\n"); - return -1; - } - - if (!strcmp(sec_model, "passthrough")) { - fse->export_flags |= V9FS_SM_PASSTHROUGH; - } else if (!strcmp(sec_model, "mapped") || - !strcmp(sec_model, "mapped-xattr")) { - fse->export_flags |= V9FS_SM_MAPPED; - } else if (!strcmp(sec_model, "none")) { - fse->export_flags |= V9FS_SM_NONE; - } else if (!strcmp(sec_model, "mapped-file")) { - fse->export_flags |= V9FS_SM_MAPPED_FILE; - } else { - fprintf(stderr, "Invalid security model %s specified, valid options are" - "\n\t [passthrough|mapped-xattr|mapped-file|none]\n", - sec_model); - return -1; - } - - if (!path) { - fprintf(stderr, "fsdev: No path specified.\n"); - return -1; - } - fse->path = g_strdup(path); - - return 0; -} - -FileOperations local_ops = { - .parse_opts = local_parse_opts, - .init = local_init, - .lstat = local_lstat, - .readlink = local_readlink, - .close = local_close, - .closedir = local_closedir, - .open = local_open, - .opendir = local_opendir, - .rewinddir = local_rewinddir, - .telldir = local_telldir, - .readdir_r = local_readdir_r, - .seekdir = local_seekdir, - .preadv = local_preadv, - .pwritev = local_pwritev, - .chmod = local_chmod, - .mknod = local_mknod, - .mkdir = local_mkdir, - .fstat = local_fstat, - .open2 = local_open2, - .symlink = local_symlink, - .link = local_link, - .truncate = local_truncate, - .rename = local_rename, - .chown = local_chown, - .utimensat = local_utimensat, - .remove = local_remove, - .fsync = local_fsync, - .statfs = local_statfs, - .lgetxattr = local_lgetxattr, - .llistxattr = local_llistxattr, - .lsetxattr = local_lsetxattr, - .lremovexattr = local_lremovexattr, - .name_to_path = local_name_to_path, - .renameat = local_renameat, - .unlinkat = local_unlinkat, -};
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor