diff options
Diffstat (limited to 'hw/9pfs/virtio-9p-local.c')
-rw-r--r-- | hw/9pfs/virtio-9p-local.c | 205 |
1 files changed, 165 insertions, 40 deletions
diff --git a/hw/9pfs/virtio-9p-local.c b/hw/9pfs/virtio-9p-local.c index 61cbf8db14..55f62f9570 100644 --- a/hw/9pfs/virtio-9p-local.c +++ b/hw/9pfs/virtio-9p-local.c @@ -22,10 +22,12 @@ #include <attr/xattr.h> -static int local_lstat(FsContext *fs_ctx, const char *path, struct stat *stbuf) +static int local_lstat(FsContext *fs_ctx, V9fsPath *fs_path, struct stat *stbuf) { int err; char buffer[PATH_MAX]; + char *path = fs_path->data; + err = lstat(rpath(fs_ctx, path, buffer), stbuf); if (err) { return err; @@ -59,6 +61,7 @@ static int local_lstat(FsContext *fs_ctx, const char *path, struct stat *stbuf) 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); @@ -91,9 +94,10 @@ static int local_set_xattr(const char *path, FsCred *credp) } static int local_post_create_passthrough(FsContext *fs_ctx, const char *path, - FsCred *credp) + FsCred *credp) { char buffer[PATH_MAX]; + if (chmod(rpath(fs_ctx, path, buffer), credp->fc_mode & 07777) < 0) { return -1; } @@ -110,11 +114,13 @@ static int local_post_create_passthrough(FsContext *fs_ctx, const char *path, return 0; } -static ssize_t local_readlink(FsContext *fs_ctx, const char *path, - char *buf, size_t bufsz) +static ssize_t local_readlink(FsContext *fs_ctx, V9fsPath *fs_path, + char *buf, size_t bufsz) { ssize_t tsize = -1; char buffer[PATH_MAX]; + char *path = fs_path->data; + if (fs_ctx->fs_sm == SM_MAPPED) { int fd; fd = open(rpath(fs_ctx, path, buffer), O_RDONLY); @@ -143,15 +149,19 @@ static int local_closedir(FsContext *ctx, DIR *dir) return closedir(dir); } -static int local_open(FsContext *ctx, const char *path, int flags) +static int local_open(FsContext *ctx, V9fsPath *fs_path, int flags) { char buffer[PATH_MAX]; + char *path = fs_path->data; + return open(rpath(ctx, path, buffer), flags); } -static DIR *local_opendir(FsContext *ctx, const char *path) +static DIR *local_opendir(FsContext *ctx, V9fsPath *fs_path) { char buffer[PATH_MAX]; + char *path = fs_path->data; + return opendir(rpath(ctx, path, buffer)); } @@ -166,7 +176,7 @@ static off_t local_telldir(FsContext *ctx, DIR *dir) } static int local_readdir_r(FsContext *ctx, DIR *dir, struct dirent *entry, - struct dirent **result) + struct dirent **result) { return readdir_r(dir, entry, result); } @@ -192,7 +202,7 @@ static ssize_t local_preadv(FsContext *ctx, int fd, const struct iovec *iov, } static ssize_t local_pwritev(FsContext *ctx, int fd, const struct iovec *iov, - int iovcnt, off_t offset) + int iovcnt, off_t offset) { #ifdef CONFIG_PREADV return pwritev(fd, iov, iovcnt, offset); @@ -206,9 +216,11 @@ static ssize_t local_pwritev(FsContext *ctx, int fd, const struct iovec *iov, #endif } -static int local_chmod(FsContext *fs_ctx, const char *path, FsCred *credp) +static int local_chmod(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp) { char buffer[PATH_MAX]; + char *path = fs_path->data; + if (fs_ctx->fs_sm == SM_MAPPED) { return local_set_xattr(rpath(fs_ctx, path, buffer), credp); } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) || @@ -218,18 +230,25 @@ static int local_chmod(FsContext *fs_ctx, const char *path, FsCred *credp) return -1; } -static int local_mknod(FsContext *fs_ctx, const char *path, FsCred *credp) +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[PATH_MAX]; + v9fs_string_init(&fullname); + v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name); + path = fullname.data; + /* Determine the security model */ if (fs_ctx->fs_sm == SM_MAPPED) { err = mknod(rpath(fs_ctx, path, buffer), SM_LOCAL_MODE_BITS|S_IFREG, 0); if (err == -1) { - return err; + goto out; } local_set_xattr(rpath(fs_ctx, path, buffer), credp); if (err == -1) { @@ -241,7 +260,7 @@ static int local_mknod(FsContext *fs_ctx, const char *path, FsCred *credp) err = mknod(rpath(fs_ctx, path, buffer), credp->fc_mode, credp->fc_rdev); if (err == -1) { - return err; + goto out; } err = local_post_create_passthrough(fs_ctx, path, credp); if (err == -1) { @@ -249,25 +268,34 @@ static int local_mknod(FsContext *fs_ctx, const char *path, FsCred *credp) goto err_end; } } - return err; + goto out; err_end: remove(rpath(fs_ctx, path, buffer)); errno = serrno; +out: + v9fs_string_free(&fullname); return err; } -static int local_mkdir(FsContext *fs_ctx, const char *path, FsCred *credp) +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[PATH_MAX]; + v9fs_string_init(&fullname); + v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name); + path = fullname.data; + /* Determine the security model */ if (fs_ctx->fs_sm == SM_MAPPED) { err = mkdir(rpath(fs_ctx, path, buffer), SM_LOCAL_DIR_MODE_BITS); if (err == -1) { - return err; + goto out; } credp->fc_mode = credp->fc_mode|S_IFDIR; err = local_set_xattr(rpath(fs_ctx, path, buffer), credp); @@ -279,7 +307,7 @@ static int local_mkdir(FsContext *fs_ctx, const char *path, FsCred *credp) (fs_ctx->fs_sm == SM_NONE)) { err = mkdir(rpath(fs_ctx, path, buffer), credp->fc_mode); if (err == -1) { - return err; + goto out; } err = local_post_create_passthrough(fs_ctx, path, credp); if (err == -1) { @@ -287,11 +315,13 @@ static int local_mkdir(FsContext *fs_ctx, const char *path, FsCred *credp) goto err_end; } } - return err; + goto out; err_end: remove(rpath(fs_ctx, path, buffer)); errno = serrno; +out: + v9fs_string_free(&fullname); return err; } @@ -325,19 +355,26 @@ static int local_fstat(FsContext *fs_ctx, int fd, struct stat *stbuf) return err; } -static int local_open2(FsContext *fs_ctx, const char *path, int flags, - FsCred *credp) +static int local_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name, + int flags, FsCred *credp) { + char *path; int fd = -1; int err = -1; int serrno = 0; + V9fsString fullname; char buffer[PATH_MAX]; + v9fs_string_init(&fullname); + v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name); + path = fullname.data; + /* Determine the security model */ if (fs_ctx->fs_sm == SM_MAPPED) { fd = open(rpath(fs_ctx, path, buffer), flags, SM_LOCAL_MODE_BITS); if (fd == -1) { - return fd; + err = fd; + goto out; } credp->fc_mode = credp->fc_mode|S_IFREG; /* Set cleint credentials in xattr */ @@ -350,7 +387,8 @@ static int local_open2(FsContext *fs_ctx, const char *path, int flags, (fs_ctx->fs_sm == SM_NONE)) { fd = open(rpath(fs_ctx, path, buffer), flags, credp->fc_mode); if (fd == -1) { - return fd; + err = fd; + goto out; } err = local_post_create_passthrough(fs_ctx, path, credp); if (err == -1) { @@ -358,23 +396,32 @@ static int local_open2(FsContext *fs_ctx, const char *path, int flags, goto err_end; } } - return fd; + err = fd; + goto out; err_end: close(fd); remove(rpath(fs_ctx, path, buffer)); errno = serrno; +out: + v9fs_string_free(&fullname); return err; } static int local_symlink(FsContext *fs_ctx, const char *oldpath, - const char *newpath, FsCred *credp) + V9fsPath *dir_path, const char *name, FsCred *credp) { int err = -1; int serrno = 0; + char *newpath; + V9fsString fullname; char buffer[PATH_MAX]; + v9fs_string_init(&fullname); + v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name); + newpath = fullname.data; + /* Determine the security model */ if (fs_ctx->fs_sm == SM_MAPPED) { int fd; @@ -382,7 +429,8 @@ static int local_symlink(FsContext *fs_ctx, const char *oldpath, fd = open(rpath(fs_ctx, newpath, buffer), O_CREAT|O_EXCL|O_RDWR, SM_LOCAL_MODE_BITS); if (fd == -1) { - return fd; + err = fd; + goto out; } /* Write the oldpath (target) to the file. */ oldpath_size = strlen(oldpath); @@ -408,10 +456,10 @@ static int local_symlink(FsContext *fs_ctx, const char *oldpath, (fs_ctx->fs_sm == SM_NONE)) { err = symlink(oldpath, rpath(fs_ctx, newpath, buffer)); if (err) { - return err; + goto out; } err = lchown(rpath(fs_ctx, newpath, buffer), credp->fc_uid, - credp->fc_gid); + credp->fc_gid); if (err == -1) { /* * If we fail to change ownership and if we are @@ -424,24 +472,37 @@ static int local_symlink(FsContext *fs_ctx, const char *oldpath, err = 0; } } - return err; + goto out; err_end: remove(rpath(fs_ctx, newpath, buffer)); errno = serrno; +out: + v9fs_string_free(&fullname); return err; } -static int local_link(FsContext *ctx, const char *oldpath, const char *newpath) +static int local_link(FsContext *ctx, V9fsPath *oldpath, + V9fsPath *dirpath, const char *name) { + int ret; + V9fsString newpath; char buffer[PATH_MAX], buffer1[PATH_MAX]; - return link(rpath(ctx, oldpath, buffer), rpath(ctx, newpath, buffer1)); + v9fs_string_init(&newpath); + v9fs_string_sprintf(&newpath, "%s/%s", dirpath->data, name); + + ret = link(rpath(ctx, oldpath->data, buffer), + rpath(ctx, newpath.data, buffer1)); + v9fs_string_free(&newpath); + return ret; } -static int local_truncate(FsContext *ctx, const char *path, off_t size) +static int local_truncate(FsContext *ctx, V9fsPath *fs_path, off_t size) { char buffer[PATH_MAX]; + char *path = fs_path->data; + return truncate(rpath(ctx, path, buffer), size); } @@ -453,9 +514,11 @@ static int local_rename(FsContext *ctx, const char *oldpath, return rename(rpath(ctx, oldpath, buffer), rpath(ctx, newpath, buffer1)); } -static int local_chown(FsContext *fs_ctx, const char *path, FsCred *credp) +static int local_chown(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp) { char buffer[PATH_MAX]; + char *path = fs_path->data; + if ((credp->fc_uid == -1 && credp->fc_gid == -1) || (fs_ctx->fs_sm == SM_PASSTHROUGH)) { return lchown(rpath(fs_ctx, path, buffer), credp->fc_uid, @@ -470,12 +533,14 @@ static int local_chown(FsContext *fs_ctx, const char *path, FsCred *credp) return -1; } -static int local_utimensat(FsContext *s, const char *path, +static int local_utimensat(FsContext *s, V9fsPath *fs_path, const struct timespec *buf) { char buffer[PATH_MAX]; + char *path = fs_path->data; + return qemu_utimensat(AT_FDCWD, rpath(s, path, buffer), buf, - AT_SYMLINK_NOFOLLOW); + AT_SYMLINK_NOFOLLOW); } static int local_remove(FsContext *ctx, const char *path) @@ -493,36 +558,93 @@ static int local_fsync(FsContext *ctx, int fd, int datasync) } } -static int local_statfs(FsContext *s, const char *path, struct statfs *stbuf) +static int local_statfs(FsContext *s, V9fsPath *fs_path, struct statfs *stbuf) { char buffer[PATH_MAX]; - return statfs(rpath(s, path, buffer), stbuf); + char *path = fs_path->data; + + return statfs(rpath(s, path, buffer), stbuf); } -static ssize_t local_lgetxattr(FsContext *ctx, const char *path, +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, const char *path, +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, const char *path, const char *name, +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, - const char *path, const char *name) +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[PATH_MAX]; + v9fs_string_init(&fullname); + + v9fs_string_sprintf(&fullname, "%s/%s", dir->data, name); + ret = remove(rpath(ctx, fullname.data, buffer)); + v9fs_string_free(&fullname); + + return ret; +} FileOperations local_ops = { .lstat = local_lstat, @@ -555,4 +677,7 @@ FileOperations local_ops = { .llistxattr = local_llistxattr, .lsetxattr = local_lsetxattr, .lremovexattr = local_lremovexattr, + .name_to_path = local_name_to_path, + .renameat = local_renameat, + .unlinkat = local_unlinkat, }; |