19f107513SAnthony Liguori /* 2f00d4f59SWei Liu * 9p Posix callback 39f107513SAnthony Liguori * 49f107513SAnthony Liguori * Copyright IBM, Corp. 2010 59f107513SAnthony Liguori * 69f107513SAnthony Liguori * Authors: 79f107513SAnthony Liguori * Anthony Liguori <aliguori@us.ibm.com> 89f107513SAnthony Liguori * 99f107513SAnthony Liguori * This work is licensed under the terms of the GNU GPL, version 2. See 109f107513SAnthony Liguori * the COPYING file in the top-level directory. 119f107513SAnthony Liguori * 129f107513SAnthony Liguori */ 13873c3213SStefan Weil 14fbc04127SPeter Maydell #include "qemu/osdep.h" 15ebe74f8bSWei Liu #include "9p.h" 16996a0d76SGreg Kurz #include "9p-local.h" 17267ae092SWei Liu #include "9p-xattr.h" 180e35a378SGreg Kurz #include "9p-util.h" 1969b15212SStefan Weil #include "fsdev/qemu-fsdev.h" /* local_ops */ 20c494dd6fSAnthony Liguori #include <arpa/inet.h> 21131dcb25SAnthony Liguori #include <pwd.h> 22131dcb25SAnthony Liguori #include <grp.h> 23c494dd6fSAnthony Liguori #include <sys/socket.h> 24c494dd6fSAnthony Liguori #include <sys/un.h> 251de7afc9SPaolo Bonzini #include "qemu/xattr.h" 26f348b6d1SVeronia Bahaa #include "qemu/cutils.h" 2763325b18SGreg Kurz #include "qemu/error-report.h" 282c30dd74SAneesh Kumar K.V #include <libgen.h> 29e06a765eSHarsh Prateek Bora #include <linux/fs.h> 30e06a765eSHarsh Prateek Bora #ifdef CONFIG_LINUX_MAGIC_H 31e06a765eSHarsh Prateek Bora #include <linux/magic.h> 32e06a765eSHarsh Prateek Bora #endif 33e06a765eSHarsh Prateek Bora #include <sys/ioctl.h> 34e06a765eSHarsh Prateek Bora 35e06a765eSHarsh Prateek Bora #ifndef XFS_SUPER_MAGIC 36e06a765eSHarsh Prateek Bora #define XFS_SUPER_MAGIC 0x58465342 37e06a765eSHarsh Prateek Bora #endif 38e06a765eSHarsh Prateek Bora #ifndef EXT2_SUPER_MAGIC 39e06a765eSHarsh Prateek Bora #define EXT2_SUPER_MAGIC 0xEF53 40e06a765eSHarsh Prateek Bora #endif 41e06a765eSHarsh Prateek Bora #ifndef REISERFS_SUPER_MAGIC 42e06a765eSHarsh Prateek Bora #define REISERFS_SUPER_MAGIC 0x52654973 43e06a765eSHarsh Prateek Bora #endif 44e06a765eSHarsh Prateek Bora #ifndef BTRFS_SUPER_MAGIC 45e06a765eSHarsh Prateek Bora #define BTRFS_SUPER_MAGIC 0x9123683E 46e06a765eSHarsh Prateek Bora #endif 47131dcb25SAnthony Liguori 480e35a378SGreg Kurz typedef struct { 490e35a378SGreg Kurz int mountfd; 500e35a378SGreg Kurz } LocalData; 510e35a378SGreg Kurz 52996a0d76SGreg Kurz int local_open_nofollow(FsContext *fs_ctx, const char *path, int flags, 53996a0d76SGreg Kurz mode_t mode) 54996a0d76SGreg Kurz { 55996a0d76SGreg Kurz LocalData *data = fs_ctx->private; 56996a0d76SGreg Kurz 57996a0d76SGreg Kurz /* All paths are relative to the path data->mountfd points to */ 58996a0d76SGreg Kurz while (*path == '/') { 59996a0d76SGreg Kurz path++; 60996a0d76SGreg Kurz } 61996a0d76SGreg Kurz 62996a0d76SGreg Kurz return relative_openat_nofollow(data->mountfd, path, flags, mode); 63996a0d76SGreg Kurz } 64996a0d76SGreg Kurz 65996a0d76SGreg Kurz int local_opendir_nofollow(FsContext *fs_ctx, const char *path) 66996a0d76SGreg Kurz { 67996a0d76SGreg Kurz return local_open_nofollow(fs_ctx, path, O_DIRECTORY | O_RDONLY, 0); 68996a0d76SGreg Kurz } 69996a0d76SGreg Kurz 702c30dd74SAneesh Kumar K.V #define VIRTFS_META_DIR ".virtfs_metadata" 712c30dd74SAneesh Kumar K.V 724fa4ce71SChen Gang static char *local_mapped_attr_path(FsContext *ctx, const char *path) 732c30dd74SAneesh Kumar K.V { 741b6f85e2SMichael Tokarev int dirlen; 751b6f85e2SMichael Tokarev const char *name = strrchr(path, '/'); 761b6f85e2SMichael Tokarev if (name) { 771b6f85e2SMichael Tokarev dirlen = name - path; 781b6f85e2SMichael Tokarev ++name; 791b6f85e2SMichael Tokarev } else { 801b6f85e2SMichael Tokarev name = path; 811b6f85e2SMichael Tokarev dirlen = 0; 821b6f85e2SMichael Tokarev } 831b6f85e2SMichael Tokarev return g_strdup_printf("%s/%.*s/%s/%s", ctx->fs_root, 841b6f85e2SMichael Tokarev dirlen, path, VIRTFS_META_DIR, name); 852c30dd74SAneesh Kumar K.V } 862c30dd74SAneesh Kumar K.V 870ceb092eSAneesh Kumar K.V static FILE *local_fopen(const char *path, const char *mode) 880ceb092eSAneesh Kumar K.V { 890ceb092eSAneesh Kumar K.V int fd, o_mode = 0; 900ceb092eSAneesh Kumar K.V FILE *fp; 910ceb092eSAneesh Kumar K.V int flags = O_NOFOLLOW; 920ceb092eSAneesh Kumar K.V /* 930ceb092eSAneesh Kumar K.V * only supports two modes 940ceb092eSAneesh Kumar K.V */ 950ceb092eSAneesh Kumar K.V if (mode[0] == 'r') { 960ceb092eSAneesh Kumar K.V flags |= O_RDONLY; 970ceb092eSAneesh Kumar K.V } else if (mode[0] == 'w') { 980ceb092eSAneesh Kumar K.V flags |= O_WRONLY | O_TRUNC | O_CREAT; 990ceb092eSAneesh Kumar K.V o_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; 1000ceb092eSAneesh Kumar K.V } else { 1010ceb092eSAneesh Kumar K.V return NULL; 1020ceb092eSAneesh Kumar K.V } 1030ceb092eSAneesh Kumar K.V fd = open(path, flags, o_mode); 1040ceb092eSAneesh Kumar K.V if (fd == -1) { 1050ceb092eSAneesh Kumar K.V return NULL; 1060ceb092eSAneesh Kumar K.V } 1070ceb092eSAneesh Kumar K.V fp = fdopen(fd, mode); 1080ceb092eSAneesh Kumar K.V if (!fp) { 1090ceb092eSAneesh Kumar K.V close(fd); 1100ceb092eSAneesh Kumar K.V } 1110ceb092eSAneesh Kumar K.V return fp; 1120ceb092eSAneesh Kumar K.V } 1130ceb092eSAneesh Kumar K.V 114*f9aef99bSGreg Kurz static FILE *local_fopenat(int dirfd, const char *name, const char *mode) 115*f9aef99bSGreg Kurz { 116*f9aef99bSGreg Kurz int fd, o_mode = 0; 117*f9aef99bSGreg Kurz FILE *fp; 118*f9aef99bSGreg Kurz int flags; 119*f9aef99bSGreg Kurz /* 120*f9aef99bSGreg Kurz * only supports two modes 121*f9aef99bSGreg Kurz */ 122*f9aef99bSGreg Kurz if (mode[0] == 'r') { 123*f9aef99bSGreg Kurz flags = O_RDONLY; 124*f9aef99bSGreg Kurz } else if (mode[0] == 'w') { 125*f9aef99bSGreg Kurz flags = O_WRONLY | O_TRUNC | O_CREAT; 126*f9aef99bSGreg Kurz o_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; 127*f9aef99bSGreg Kurz } else { 128*f9aef99bSGreg Kurz return NULL; 129*f9aef99bSGreg Kurz } 130*f9aef99bSGreg Kurz fd = openat_file(dirfd, name, flags, o_mode); 131*f9aef99bSGreg Kurz if (fd == -1) { 132*f9aef99bSGreg Kurz return NULL; 133*f9aef99bSGreg Kurz } 134*f9aef99bSGreg Kurz fp = fdopen(fd, mode); 135*f9aef99bSGreg Kurz if (!fp) { 136*f9aef99bSGreg Kurz close(fd); 137*f9aef99bSGreg Kurz } 138*f9aef99bSGreg Kurz return fp; 139*f9aef99bSGreg Kurz } 140*f9aef99bSGreg Kurz 1412c30dd74SAneesh Kumar K.V #define ATTR_MAX 100 142*f9aef99bSGreg Kurz static void local_mapped_file_attr(int dirfd, const char *name, 1432c30dd74SAneesh Kumar K.V struct stat *stbuf) 1442c30dd74SAneesh Kumar K.V { 1452c30dd74SAneesh Kumar K.V FILE *fp; 1462c30dd74SAneesh Kumar K.V char buf[ATTR_MAX]; 147*f9aef99bSGreg Kurz int map_dirfd; 1482c30dd74SAneesh Kumar K.V 149*f9aef99bSGreg Kurz map_dirfd = openat(dirfd, VIRTFS_META_DIR, 150*f9aef99bSGreg Kurz O_RDONLY | O_DIRECTORY | O_NOFOLLOW); 151*f9aef99bSGreg Kurz if (map_dirfd == -1) { 152*f9aef99bSGreg Kurz return; 153*f9aef99bSGreg Kurz } 154*f9aef99bSGreg Kurz 155*f9aef99bSGreg Kurz fp = local_fopenat(map_dirfd, name, "r"); 156*f9aef99bSGreg Kurz close_preserve_errno(map_dirfd); 1572c30dd74SAneesh Kumar K.V if (!fp) { 1582c30dd74SAneesh Kumar K.V return; 1592c30dd74SAneesh Kumar K.V } 1602c30dd74SAneesh Kumar K.V memset(buf, 0, ATTR_MAX); 1612c30dd74SAneesh Kumar K.V while (fgets(buf, ATTR_MAX, fp)) { 1622c30dd74SAneesh Kumar K.V if (!strncmp(buf, "virtfs.uid", 10)) { 1632c30dd74SAneesh Kumar K.V stbuf->st_uid = atoi(buf+11); 1642c30dd74SAneesh Kumar K.V } else if (!strncmp(buf, "virtfs.gid", 10)) { 1652c30dd74SAneesh Kumar K.V stbuf->st_gid = atoi(buf+11); 1662c30dd74SAneesh Kumar K.V } else if (!strncmp(buf, "virtfs.mode", 11)) { 1672c30dd74SAneesh Kumar K.V stbuf->st_mode = atoi(buf+12); 1682c30dd74SAneesh Kumar K.V } else if (!strncmp(buf, "virtfs.rdev", 11)) { 1692c30dd74SAneesh Kumar K.V stbuf->st_rdev = atoi(buf+12); 1702c30dd74SAneesh Kumar K.V } 1712c30dd74SAneesh Kumar K.V memset(buf, 0, ATTR_MAX); 1722c30dd74SAneesh Kumar K.V } 1732c30dd74SAneesh Kumar K.V fclose(fp); 1742c30dd74SAneesh Kumar K.V } 1752c30dd74SAneesh Kumar K.V 1762289be19SAneesh Kumar K.V static int local_lstat(FsContext *fs_ctx, V9fsPath *fs_path, struct stat *stbuf) 177131dcb25SAnthony Liguori { 178*f9aef99bSGreg Kurz int err = -1; 179*f9aef99bSGreg Kurz char *dirpath = g_path_get_dirname(fs_path->data); 180*f9aef99bSGreg Kurz char *name = g_path_get_basename(fs_path->data); 181*f9aef99bSGreg Kurz int dirfd; 1822289be19SAneesh Kumar K.V 183*f9aef99bSGreg Kurz dirfd = local_opendir_nofollow(fs_ctx, dirpath); 184*f9aef99bSGreg Kurz if (dirfd == -1) { 185*f9aef99bSGreg Kurz goto out; 186*f9aef99bSGreg Kurz } 187*f9aef99bSGreg Kurz 188*f9aef99bSGreg Kurz err = fstatat(dirfd, name, stbuf, AT_SYMLINK_NOFOLLOW); 1891237ad76SVenkateswararao Jujjuri (JV) if (err) { 1904fa4ce71SChen Gang goto err_out; 1911237ad76SVenkateswararao Jujjuri (JV) } 192b97400caSAneesh Kumar K.V if (fs_ctx->export_flags & V9FS_SM_MAPPED) { 1931237ad76SVenkateswararao Jujjuri (JV) /* Actual credentials are part of extended attrs */ 1941237ad76SVenkateswararao Jujjuri (JV) uid_t tmp_uid; 1951237ad76SVenkateswararao Jujjuri (JV) gid_t tmp_gid; 1961237ad76SVenkateswararao Jujjuri (JV) mode_t tmp_mode; 1971237ad76SVenkateswararao Jujjuri (JV) dev_t tmp_dev; 198*f9aef99bSGreg Kurz 199*f9aef99bSGreg Kurz if (fgetxattrat_nofollow(dirfd, name, "user.virtfs.uid", &tmp_uid, 200*f9aef99bSGreg Kurz sizeof(uid_t)) > 0) { 201f8ad4a89SAneesh Kumar K.V stbuf->st_uid = le32_to_cpu(tmp_uid); 2021237ad76SVenkateswararao Jujjuri (JV) } 203*f9aef99bSGreg Kurz if (fgetxattrat_nofollow(dirfd, name, "user.virtfs.gid", &tmp_gid, 204*f9aef99bSGreg Kurz sizeof(gid_t)) > 0) { 205f8ad4a89SAneesh Kumar K.V stbuf->st_gid = le32_to_cpu(tmp_gid); 2061237ad76SVenkateswararao Jujjuri (JV) } 207*f9aef99bSGreg Kurz if (fgetxattrat_nofollow(dirfd, name, "user.virtfs.mode", &tmp_mode, 208*f9aef99bSGreg Kurz sizeof(mode_t)) > 0) { 209f8ad4a89SAneesh Kumar K.V stbuf->st_mode = le32_to_cpu(tmp_mode); 2101237ad76SVenkateswararao Jujjuri (JV) } 211*f9aef99bSGreg Kurz if (fgetxattrat_nofollow(dirfd, name, "user.virtfs.rdev", &tmp_dev, 212*f9aef99bSGreg Kurz sizeof(dev_t)) > 0) { 213f8ad4a89SAneesh Kumar K.V stbuf->st_rdev = le64_to_cpu(tmp_dev); 2141237ad76SVenkateswararao Jujjuri (JV) } 2152c30dd74SAneesh Kumar K.V } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) { 216*f9aef99bSGreg Kurz local_mapped_file_attr(dirfd, name, stbuf); 2171237ad76SVenkateswararao Jujjuri (JV) } 2184fa4ce71SChen Gang 2194fa4ce71SChen Gang err_out: 220*f9aef99bSGreg Kurz close_preserve_errno(dirfd); 221*f9aef99bSGreg Kurz out: 222*f9aef99bSGreg Kurz g_free(name); 223*f9aef99bSGreg Kurz g_free(dirpath); 2241237ad76SVenkateswararao Jujjuri (JV) return err; 225131dcb25SAnthony Liguori } 226131dcb25SAnthony Liguori 2272c30dd74SAneesh Kumar K.V static int local_create_mapped_attr_dir(FsContext *ctx, const char *path) 2282c30dd74SAneesh Kumar K.V { 2292c30dd74SAneesh Kumar K.V int err; 2304fa4ce71SChen Gang char *attr_dir; 231d3f8e138SMarkus Armbruster char *tmp_path = g_strdup(path); 2322c30dd74SAneesh Kumar K.V 2334fa4ce71SChen Gang attr_dir = g_strdup_printf("%s/%s/%s", 2342c30dd74SAneesh Kumar K.V ctx->fs_root, dirname(tmp_path), VIRTFS_META_DIR); 2352c30dd74SAneesh Kumar K.V 2362c30dd74SAneesh Kumar K.V err = mkdir(attr_dir, 0700); 2372c30dd74SAneesh Kumar K.V if (err < 0 && errno == EEXIST) { 2382c30dd74SAneesh Kumar K.V err = 0; 2392c30dd74SAneesh Kumar K.V } 2404fa4ce71SChen Gang g_free(attr_dir); 241d3f8e138SMarkus Armbruster g_free(tmp_path); 2422c30dd74SAneesh Kumar K.V return err; 2432c30dd74SAneesh Kumar K.V } 2442c30dd74SAneesh Kumar K.V 2452c30dd74SAneesh Kumar K.V static int local_set_mapped_file_attr(FsContext *ctx, 2462c30dd74SAneesh Kumar K.V const char *path, FsCred *credp) 2472c30dd74SAneesh Kumar K.V { 2482c30dd74SAneesh Kumar K.V FILE *fp; 2492c30dd74SAneesh Kumar K.V int ret = 0; 2502c30dd74SAneesh Kumar K.V char buf[ATTR_MAX]; 2514fa4ce71SChen Gang char *attr_path; 2522c30dd74SAneesh Kumar K.V int uid = -1, gid = -1, mode = -1, rdev = -1; 2532c30dd74SAneesh Kumar K.V 2544fa4ce71SChen Gang attr_path = local_mapped_attr_path(ctx, path); 2554fa4ce71SChen Gang fp = local_fopen(attr_path, "r"); 2562c30dd74SAneesh Kumar K.V if (!fp) { 2572c30dd74SAneesh Kumar K.V goto create_map_file; 2582c30dd74SAneesh Kumar K.V } 2592c30dd74SAneesh Kumar K.V memset(buf, 0, ATTR_MAX); 2602c30dd74SAneesh Kumar K.V while (fgets(buf, ATTR_MAX, fp)) { 2612c30dd74SAneesh Kumar K.V if (!strncmp(buf, "virtfs.uid", 10)) { 2622c30dd74SAneesh Kumar K.V uid = atoi(buf+11); 2632c30dd74SAneesh Kumar K.V } else if (!strncmp(buf, "virtfs.gid", 10)) { 2642c30dd74SAneesh Kumar K.V gid = atoi(buf+11); 2652c30dd74SAneesh Kumar K.V } else if (!strncmp(buf, "virtfs.mode", 11)) { 2662c30dd74SAneesh Kumar K.V mode = atoi(buf+12); 2672c30dd74SAneesh Kumar K.V } else if (!strncmp(buf, "virtfs.rdev", 11)) { 2682c30dd74SAneesh Kumar K.V rdev = atoi(buf+12); 2692c30dd74SAneesh Kumar K.V } 2702c30dd74SAneesh Kumar K.V memset(buf, 0, ATTR_MAX); 2712c30dd74SAneesh Kumar K.V } 2722c30dd74SAneesh Kumar K.V fclose(fp); 2732c30dd74SAneesh Kumar K.V goto update_map_file; 2742c30dd74SAneesh Kumar K.V 2752c30dd74SAneesh Kumar K.V create_map_file: 2762c30dd74SAneesh Kumar K.V ret = local_create_mapped_attr_dir(ctx, path); 2772c30dd74SAneesh Kumar K.V if (ret < 0) { 2782c30dd74SAneesh Kumar K.V goto err_out; 2792c30dd74SAneesh Kumar K.V } 2802c30dd74SAneesh Kumar K.V 2812c30dd74SAneesh Kumar K.V update_map_file: 2820ceb092eSAneesh Kumar K.V fp = local_fopen(attr_path, "w"); 2832c30dd74SAneesh Kumar K.V if (!fp) { 2842c30dd74SAneesh Kumar K.V ret = -1; 2852c30dd74SAneesh Kumar K.V goto err_out; 2862c30dd74SAneesh Kumar K.V } 2872c30dd74SAneesh Kumar K.V 2882c30dd74SAneesh Kumar K.V if (credp->fc_uid != -1) { 2892c30dd74SAneesh Kumar K.V uid = credp->fc_uid; 2902c30dd74SAneesh Kumar K.V } 2912c30dd74SAneesh Kumar K.V if (credp->fc_gid != -1) { 2922c30dd74SAneesh Kumar K.V gid = credp->fc_gid; 2932c30dd74SAneesh Kumar K.V } 2942c30dd74SAneesh Kumar K.V if (credp->fc_mode != -1) { 2952c30dd74SAneesh Kumar K.V mode = credp->fc_mode; 2962c30dd74SAneesh Kumar K.V } 2972c30dd74SAneesh Kumar K.V if (credp->fc_rdev != -1) { 2982c30dd74SAneesh Kumar K.V rdev = credp->fc_rdev; 2992c30dd74SAneesh Kumar K.V } 3002c30dd74SAneesh Kumar K.V 3012c30dd74SAneesh Kumar K.V 3022c30dd74SAneesh Kumar K.V if (uid != -1) { 3032c30dd74SAneesh Kumar K.V fprintf(fp, "virtfs.uid=%d\n", uid); 3042c30dd74SAneesh Kumar K.V } 3052c30dd74SAneesh Kumar K.V if (gid != -1) { 3062c30dd74SAneesh Kumar K.V fprintf(fp, "virtfs.gid=%d\n", gid); 3072c30dd74SAneesh Kumar K.V } 3082c30dd74SAneesh Kumar K.V if (mode != -1) { 3092c30dd74SAneesh Kumar K.V fprintf(fp, "virtfs.mode=%d\n", mode); 3102c30dd74SAneesh Kumar K.V } 3112c30dd74SAneesh Kumar K.V if (rdev != -1) { 3122c30dd74SAneesh Kumar K.V fprintf(fp, "virtfs.rdev=%d\n", rdev); 3132c30dd74SAneesh Kumar K.V } 3142c30dd74SAneesh Kumar K.V fclose(fp); 3152c30dd74SAneesh Kumar K.V 3162c30dd74SAneesh Kumar K.V err_out: 3174fa4ce71SChen Gang g_free(attr_path); 3182c30dd74SAneesh Kumar K.V return ret; 3192c30dd74SAneesh Kumar K.V } 3202c30dd74SAneesh Kumar K.V 321758e8e38SVenkateswararao Jujjuri (JV) static int local_set_xattr(const char *path, FsCred *credp) 322131dcb25SAnthony Liguori { 323758e8e38SVenkateswararao Jujjuri (JV) int err; 3242289be19SAneesh Kumar K.V 325758e8e38SVenkateswararao Jujjuri (JV) if (credp->fc_uid != -1) { 326f8ad4a89SAneesh Kumar K.V uint32_t tmp_uid = cpu_to_le32(credp->fc_uid); 327f8ad4a89SAneesh Kumar K.V err = setxattr(path, "user.virtfs.uid", &tmp_uid, sizeof(uid_t), 0); 328758e8e38SVenkateswararao Jujjuri (JV) if (err) { 329758e8e38SVenkateswararao Jujjuri (JV) return err; 330131dcb25SAnthony Liguori } 331131dcb25SAnthony Liguori } 332758e8e38SVenkateswararao Jujjuri (JV) if (credp->fc_gid != -1) { 333f8ad4a89SAneesh Kumar K.V uint32_t tmp_gid = cpu_to_le32(credp->fc_gid); 334f8ad4a89SAneesh Kumar K.V err = setxattr(path, "user.virtfs.gid", &tmp_gid, sizeof(gid_t), 0); 335758e8e38SVenkateswararao Jujjuri (JV) if (err) { 336758e8e38SVenkateswararao Jujjuri (JV) return err; 337131dcb25SAnthony Liguori } 338131dcb25SAnthony Liguori } 339758e8e38SVenkateswararao Jujjuri (JV) if (credp->fc_mode != -1) { 340f8ad4a89SAneesh Kumar K.V uint32_t tmp_mode = cpu_to_le32(credp->fc_mode); 341f8ad4a89SAneesh Kumar K.V err = setxattr(path, "user.virtfs.mode", &tmp_mode, sizeof(mode_t), 0); 342758e8e38SVenkateswararao Jujjuri (JV) if (err) { 343758e8e38SVenkateswararao Jujjuri (JV) return err; 344131dcb25SAnthony Liguori } 345131dcb25SAnthony Liguori } 346758e8e38SVenkateswararao Jujjuri (JV) if (credp->fc_rdev != -1) { 347f8ad4a89SAneesh Kumar K.V uint64_t tmp_rdev = cpu_to_le64(credp->fc_rdev); 348f8ad4a89SAneesh Kumar K.V err = setxattr(path, "user.virtfs.rdev", &tmp_rdev, sizeof(dev_t), 0); 349758e8e38SVenkateswararao Jujjuri (JV) if (err) { 350758e8e38SVenkateswararao Jujjuri (JV) return err; 351131dcb25SAnthony Liguori } 352758e8e38SVenkateswararao Jujjuri (JV) } 353131dcb25SAnthony Liguori return 0; 354131dcb25SAnthony Liguori } 355131dcb25SAnthony Liguori 3564750a96fSVenkateswararao Jujjuri (JV) static int local_post_create_passthrough(FsContext *fs_ctx, const char *path, 3574750a96fSVenkateswararao Jujjuri (JV) FsCred *credp) 3584750a96fSVenkateswararao Jujjuri (JV) { 3594fa4ce71SChen Gang char *buffer; 3602289be19SAneesh Kumar K.V 3614fa4ce71SChen Gang buffer = rpath(fs_ctx, path); 3624fa4ce71SChen Gang if (lchown(buffer, credp->fc_uid, credp->fc_gid) < 0) { 36312848bfcSAneesh Kumar K.V /* 36412848bfcSAneesh Kumar K.V * If we fail to change ownership and if we are 36512848bfcSAneesh Kumar K.V * using security model none. Ignore the error 36612848bfcSAneesh Kumar K.V */ 367b97400caSAneesh Kumar K.V if ((fs_ctx->export_flags & V9FS_SEC_MASK) != V9FS_SM_NONE) { 3684fa4ce71SChen Gang goto err; 3694750a96fSVenkateswararao Jujjuri (JV) } 37012848bfcSAneesh Kumar K.V } 3712d40564aSM. Mohan Kumar 3724fa4ce71SChen Gang if (chmod(buffer, credp->fc_mode & 07777) < 0) { 3734fa4ce71SChen Gang goto err; 3742d40564aSM. Mohan Kumar } 3754fa4ce71SChen Gang 3764fa4ce71SChen Gang g_free(buffer); 3774750a96fSVenkateswararao Jujjuri (JV) return 0; 3784fa4ce71SChen Gang err: 3794fa4ce71SChen Gang g_free(buffer); 3804fa4ce71SChen Gang return -1; 3814750a96fSVenkateswararao Jujjuri (JV) } 3824750a96fSVenkateswararao Jujjuri (JV) 3832289be19SAneesh Kumar K.V static ssize_t local_readlink(FsContext *fs_ctx, V9fsPath *fs_path, 384131dcb25SAnthony Liguori char *buf, size_t bufsz) 385131dcb25SAnthony Liguori { 386879c2813SVenkateswararao Jujjuri (JV) ssize_t tsize = -1; 3872289be19SAneesh Kumar K.V 3882c30dd74SAneesh Kumar K.V if ((fs_ctx->export_flags & V9FS_SM_MAPPED) || 3892c30dd74SAneesh Kumar K.V (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE)) { 390879c2813SVenkateswararao Jujjuri (JV) int fd; 391bec1e954SGreg Kurz 392bec1e954SGreg Kurz fd = local_open_nofollow(fs_ctx, fs_path->data, O_RDONLY, 0); 393879c2813SVenkateswararao Jujjuri (JV) if (fd == -1) { 394879c2813SVenkateswararao Jujjuri (JV) return -1; 395879c2813SVenkateswararao Jujjuri (JV) } 396879c2813SVenkateswararao Jujjuri (JV) do { 397879c2813SVenkateswararao Jujjuri (JV) tsize = read(fd, (void *)buf, bufsz); 398879c2813SVenkateswararao Jujjuri (JV) } while (tsize == -1 && errno == EINTR); 399bec1e954SGreg Kurz close_preserve_errno(fd); 400b97400caSAneesh Kumar K.V } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) || 401b97400caSAneesh Kumar K.V (fs_ctx->export_flags & V9FS_SM_NONE)) { 402bec1e954SGreg Kurz char *dirpath = g_path_get_dirname(fs_path->data); 403bec1e954SGreg Kurz char *name = g_path_get_basename(fs_path->data); 404bec1e954SGreg Kurz int dirfd; 405bec1e954SGreg Kurz 406bec1e954SGreg Kurz dirfd = local_opendir_nofollow(fs_ctx, dirpath); 407bec1e954SGreg Kurz if (dirfd == -1) { 408bec1e954SGreg Kurz goto out; 409bec1e954SGreg Kurz } 410bec1e954SGreg Kurz 411bec1e954SGreg Kurz tsize = readlinkat(dirfd, name, buf, bufsz); 412bec1e954SGreg Kurz close_preserve_errno(dirfd); 413bec1e954SGreg Kurz out: 414bec1e954SGreg Kurz g_free(name); 415bec1e954SGreg Kurz g_free(dirpath); 416879c2813SVenkateswararao Jujjuri (JV) } 417879c2813SVenkateswararao Jujjuri (JV) return tsize; 418131dcb25SAnthony Liguori } 419131dcb25SAnthony Liguori 420cc720ddbSAneesh Kumar K.V static int local_close(FsContext *ctx, V9fsFidOpenState *fs) 421131dcb25SAnthony Liguori { 422cc720ddbSAneesh Kumar K.V return close(fs->fd); 423131dcb25SAnthony Liguori } 424131dcb25SAnthony Liguori 425cc720ddbSAneesh Kumar K.V static int local_closedir(FsContext *ctx, V9fsFidOpenState *fs) 426131dcb25SAnthony Liguori { 427f314ea4eSGreg Kurz return closedir(fs->dir.stream); 428131dcb25SAnthony Liguori } 4299f107513SAnthony Liguori 430cc720ddbSAneesh Kumar K.V static int local_open(FsContext *ctx, V9fsPath *fs_path, 431cc720ddbSAneesh Kumar K.V int flags, V9fsFidOpenState *fs) 432a6568fe2SAnthony Liguori { 43321328e1eSGreg Kurz int fd; 4342289be19SAneesh Kumar K.V 435996a0d76SGreg Kurz fd = local_open_nofollow(ctx, fs_path->data, flags, 0); 43621328e1eSGreg Kurz if (fd == -1) { 43721328e1eSGreg Kurz return -1; 43821328e1eSGreg Kurz } 43921328e1eSGreg Kurz fs->fd = fd; 440cc720ddbSAneesh Kumar K.V return fs->fd; 441a6568fe2SAnthony Liguori } 442a6568fe2SAnthony Liguori 443cc720ddbSAneesh Kumar K.V static int local_opendir(FsContext *ctx, 444cc720ddbSAneesh Kumar K.V V9fsPath *fs_path, V9fsFidOpenState *fs) 445a6568fe2SAnthony Liguori { 446996a0d76SGreg Kurz int dirfd; 44721328e1eSGreg Kurz DIR *stream; 4482289be19SAneesh Kumar K.V 449996a0d76SGreg Kurz dirfd = local_opendir_nofollow(ctx, fs_path->data); 450996a0d76SGreg Kurz if (dirfd == -1) { 451996a0d76SGreg Kurz return -1; 452996a0d76SGreg Kurz } 453996a0d76SGreg Kurz 454996a0d76SGreg Kurz stream = fdopendir(dirfd); 45521328e1eSGreg Kurz if (!stream) { 456cc720ddbSAneesh Kumar K.V return -1; 457cc720ddbSAneesh Kumar K.V } 45821328e1eSGreg Kurz fs->dir.stream = stream; 459cc720ddbSAneesh Kumar K.V return 0; 460a6568fe2SAnthony Liguori } 461a6568fe2SAnthony Liguori 462cc720ddbSAneesh Kumar K.V static void local_rewinddir(FsContext *ctx, V9fsFidOpenState *fs) 463a9231555SAnthony Liguori { 464f314ea4eSGreg Kurz rewinddir(fs->dir.stream); 465a9231555SAnthony Liguori } 466a9231555SAnthony Liguori 467cc720ddbSAneesh Kumar K.V static off_t local_telldir(FsContext *ctx, V9fsFidOpenState *fs) 468a9231555SAnthony Liguori { 469f314ea4eSGreg Kurz return telldir(fs->dir.stream); 470a9231555SAnthony Liguori } 471a9231555SAnthony Liguori 472635324e8SGreg Kurz static struct dirent *local_readdir(FsContext *ctx, V9fsFidOpenState *fs) 473a9231555SAnthony Liguori { 474635324e8SGreg Kurz struct dirent *entry; 4752c30dd74SAneesh Kumar K.V 4762c30dd74SAneesh Kumar K.V again: 477635324e8SGreg Kurz entry = readdir(fs->dir.stream); 478635324e8SGreg Kurz if (!entry) { 479635324e8SGreg Kurz return NULL; 480635324e8SGreg Kurz } 481635324e8SGreg Kurz 482840a1bf2SBastian Blank if (ctx->export_flags & V9FS_SM_MAPPED) { 483840a1bf2SBastian Blank entry->d_type = DT_UNKNOWN; 484840a1bf2SBastian Blank } else if (ctx->export_flags & V9FS_SM_MAPPED_FILE) { 485635324e8SGreg Kurz if (!strcmp(entry->d_name, VIRTFS_META_DIR)) { 4862c30dd74SAneesh Kumar K.V /* skp the meta data directory */ 4872c30dd74SAneesh Kumar K.V goto again; 4882c30dd74SAneesh Kumar K.V } 489840a1bf2SBastian Blank entry->d_type = DT_UNKNOWN; 4902c30dd74SAneesh Kumar K.V } 491635324e8SGreg Kurz 492635324e8SGreg Kurz return entry; 493a9231555SAnthony Liguori } 494a9231555SAnthony Liguori 495cc720ddbSAneesh Kumar K.V static void local_seekdir(FsContext *ctx, V9fsFidOpenState *fs, off_t off) 496a9231555SAnthony Liguori { 497f314ea4eSGreg Kurz seekdir(fs->dir.stream, off); 498a9231555SAnthony Liguori } 499a9231555SAnthony Liguori 500cc720ddbSAneesh Kumar K.V static ssize_t local_preadv(FsContext *ctx, V9fsFidOpenState *fs, 501cc720ddbSAneesh Kumar K.V const struct iovec *iov, 50256d15a53SSanchit Garg int iovcnt, off_t offset) 503a9231555SAnthony Liguori { 50456d15a53SSanchit Garg #ifdef CONFIG_PREADV 505cc720ddbSAneesh Kumar K.V return preadv(fs->fd, iov, iovcnt, offset); 50656d15a53SSanchit Garg #else 507cc720ddbSAneesh Kumar K.V int err = lseek(fs->fd, offset, SEEK_SET); 50856d15a53SSanchit Garg if (err == -1) { 50956d15a53SSanchit Garg return err; 51056d15a53SSanchit Garg } else { 511cc720ddbSAneesh Kumar K.V return readv(fs->fd, iov, iovcnt); 512a9231555SAnthony Liguori } 51356d15a53SSanchit Garg #endif 514a9231555SAnthony Liguori } 515a9231555SAnthony Liguori 516cc720ddbSAneesh Kumar K.V static ssize_t local_pwritev(FsContext *ctx, V9fsFidOpenState *fs, 517cc720ddbSAneesh Kumar K.V const struct iovec *iov, 51856d15a53SSanchit Garg int iovcnt, off_t offset) 5198449360cSAnthony Liguori { 5206fe76accSGreg Kurz ssize_t ret; 52156d15a53SSanchit Garg #ifdef CONFIG_PREADV 522cc720ddbSAneesh Kumar K.V ret = pwritev(fs->fd, iov, iovcnt, offset); 52356d15a53SSanchit Garg #else 524cc720ddbSAneesh Kumar K.V int err = lseek(fs->fd, offset, SEEK_SET); 52556d15a53SSanchit Garg if (err == -1) { 52656d15a53SSanchit Garg return err; 52756d15a53SSanchit Garg } else { 528cc720ddbSAneesh Kumar K.V ret = writev(fs->fd, iov, iovcnt); 5298449360cSAnthony Liguori } 53056d15a53SSanchit Garg #endif 531d3ab98e6SAneesh Kumar K.V #ifdef CONFIG_SYNC_FILE_RANGE 532d3ab98e6SAneesh Kumar K.V if (ret > 0 && ctx->export_flags & V9FS_IMMEDIATE_WRITEOUT) { 533d3ab98e6SAneesh Kumar K.V /* 534d3ab98e6SAneesh Kumar K.V * Initiate a writeback. This is not a data integrity sync. 535d3ab98e6SAneesh Kumar K.V * We want to ensure that we don't leave dirty pages in the cache 536d3ab98e6SAneesh Kumar K.V * after write when writeout=immediate is sepcified. 537d3ab98e6SAneesh Kumar K.V */ 538cc720ddbSAneesh Kumar K.V sync_file_range(fs->fd, offset, ret, 539d3ab98e6SAneesh Kumar K.V SYNC_FILE_RANGE_WAIT_BEFORE | SYNC_FILE_RANGE_WRITE); 540d3ab98e6SAneesh Kumar K.V } 541d3ab98e6SAneesh Kumar K.V #endif 542d3ab98e6SAneesh Kumar K.V return ret; 54356d15a53SSanchit Garg } 5448449360cSAnthony Liguori 5452289be19SAneesh Kumar K.V static int local_chmod(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp) 546c494dd6fSAnthony Liguori { 5474fa4ce71SChen Gang char *buffer; 5484fa4ce71SChen Gang int ret = -1; 5492289be19SAneesh Kumar K.V char *path = fs_path->data; 5502289be19SAneesh Kumar K.V 551b97400caSAneesh Kumar K.V if (fs_ctx->export_flags & V9FS_SM_MAPPED) { 5524fa4ce71SChen Gang buffer = rpath(fs_ctx, path); 5534fa4ce71SChen Gang ret = local_set_xattr(buffer, credp); 5544fa4ce71SChen Gang g_free(buffer); 5552c30dd74SAneesh Kumar K.V } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) { 5562c30dd74SAneesh Kumar K.V return local_set_mapped_file_attr(fs_ctx, path, credp); 557b97400caSAneesh Kumar K.V } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) || 558b97400caSAneesh Kumar K.V (fs_ctx->export_flags & V9FS_SM_NONE)) { 5594fa4ce71SChen Gang buffer = rpath(fs_ctx, path); 5604fa4ce71SChen Gang ret = chmod(buffer, credp->fc_mode); 5614fa4ce71SChen Gang g_free(buffer); 562e95ead32SVenkateswararao Jujjuri (JV) } 5634fa4ce71SChen Gang return ret; 564c494dd6fSAnthony Liguori } 565c494dd6fSAnthony Liguori 5662289be19SAneesh Kumar K.V static int local_mknod(FsContext *fs_ctx, V9fsPath *dir_path, 5672289be19SAneesh Kumar K.V const char *name, FsCred *credp) 568c494dd6fSAnthony Liguori { 5692289be19SAneesh Kumar K.V char *path; 5701c293312SVenkateswararao Jujjuri (JV) int err = -1; 5711c293312SVenkateswararao Jujjuri (JV) int serrno = 0; 5722289be19SAneesh Kumar K.V V9fsString fullname; 5734ed7b2c3SStefan Weil char *buffer = NULL; 5741c293312SVenkateswararao Jujjuri (JV) 5752289be19SAneesh Kumar K.V v9fs_string_init(&fullname); 5762289be19SAneesh Kumar K.V v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name); 5772289be19SAneesh Kumar K.V path = fullname.data; 5782289be19SAneesh Kumar K.V 5791c293312SVenkateswararao Jujjuri (JV) /* Determine the security model */ 580b97400caSAneesh Kumar K.V if (fs_ctx->export_flags & V9FS_SM_MAPPED) { 5814fa4ce71SChen Gang buffer = rpath(fs_ctx, path); 5824fa4ce71SChen Gang err = mknod(buffer, SM_LOCAL_MODE_BITS|S_IFREG, 0); 5831c293312SVenkateswararao Jujjuri (JV) if (err == -1) { 5842289be19SAneesh Kumar K.V goto out; 5851c293312SVenkateswararao Jujjuri (JV) } 5864fa4ce71SChen Gang err = local_set_xattr(buffer, credp); 5871c293312SVenkateswararao Jujjuri (JV) if (err == -1) { 5881c293312SVenkateswararao Jujjuri (JV) serrno = errno; 5891c293312SVenkateswararao Jujjuri (JV) goto err_end; 5901c293312SVenkateswararao Jujjuri (JV) } 5912c30dd74SAneesh Kumar K.V } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) { 5922c30dd74SAneesh Kumar K.V 5934fa4ce71SChen Gang buffer = rpath(fs_ctx, path); 5944fa4ce71SChen Gang err = mknod(buffer, SM_LOCAL_MODE_BITS|S_IFREG, 0); 5952c30dd74SAneesh Kumar K.V if (err == -1) { 5962c30dd74SAneesh Kumar K.V goto out; 5972c30dd74SAneesh Kumar K.V } 5982c30dd74SAneesh Kumar K.V err = local_set_mapped_file_attr(fs_ctx, path, credp); 5992c30dd74SAneesh Kumar K.V if (err == -1) { 6002c30dd74SAneesh Kumar K.V serrno = errno; 6012c30dd74SAneesh Kumar K.V goto err_end; 6022c30dd74SAneesh Kumar K.V } 603b97400caSAneesh Kumar K.V } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) || 604b97400caSAneesh Kumar K.V (fs_ctx->export_flags & V9FS_SM_NONE)) { 6054fa4ce71SChen Gang buffer = rpath(fs_ctx, path); 6064fa4ce71SChen Gang err = mknod(buffer, credp->fc_mode, credp->fc_rdev); 6071c293312SVenkateswararao Jujjuri (JV) if (err == -1) { 6082289be19SAneesh Kumar K.V goto out; 6091c293312SVenkateswararao Jujjuri (JV) } 6101c293312SVenkateswararao Jujjuri (JV) err = local_post_create_passthrough(fs_ctx, path, credp); 6111c293312SVenkateswararao Jujjuri (JV) if (err == -1) { 6121c293312SVenkateswararao Jujjuri (JV) serrno = errno; 6131c293312SVenkateswararao Jujjuri (JV) goto err_end; 6141c293312SVenkateswararao Jujjuri (JV) } 6151c293312SVenkateswararao Jujjuri (JV) } 6162289be19SAneesh Kumar K.V goto out; 6171c293312SVenkateswararao Jujjuri (JV) 6181c293312SVenkateswararao Jujjuri (JV) err_end: 6194fa4ce71SChen Gang remove(buffer); 6201c293312SVenkateswararao Jujjuri (JV) errno = serrno; 6212289be19SAneesh Kumar K.V out: 6224ed7b2c3SStefan Weil g_free(buffer); 6232289be19SAneesh Kumar K.V v9fs_string_free(&fullname); 6241c293312SVenkateswararao Jujjuri (JV) return err; 625c494dd6fSAnthony Liguori } 626c494dd6fSAnthony Liguori 6272289be19SAneesh Kumar K.V static int local_mkdir(FsContext *fs_ctx, V9fsPath *dir_path, 6282289be19SAneesh Kumar K.V const char *name, FsCred *credp) 629c494dd6fSAnthony Liguori { 6302289be19SAneesh Kumar K.V char *path; 63100ec5c37SVenkateswararao Jujjuri (JV) int err = -1; 63200ec5c37SVenkateswararao Jujjuri (JV) int serrno = 0; 6332289be19SAneesh Kumar K.V V9fsString fullname; 6344ed7b2c3SStefan Weil char *buffer = NULL; 63500ec5c37SVenkateswararao Jujjuri (JV) 6362289be19SAneesh Kumar K.V v9fs_string_init(&fullname); 6372289be19SAneesh Kumar K.V v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name); 6382289be19SAneesh Kumar K.V path = fullname.data; 6392289be19SAneesh Kumar K.V 64000ec5c37SVenkateswararao Jujjuri (JV) /* Determine the security model */ 641b97400caSAneesh Kumar K.V if (fs_ctx->export_flags & V9FS_SM_MAPPED) { 6424fa4ce71SChen Gang buffer = rpath(fs_ctx, path); 6434fa4ce71SChen Gang err = mkdir(buffer, SM_LOCAL_DIR_MODE_BITS); 64400ec5c37SVenkateswararao Jujjuri (JV) if (err == -1) { 6452289be19SAneesh Kumar K.V goto out; 64600ec5c37SVenkateswararao Jujjuri (JV) } 64700ec5c37SVenkateswararao Jujjuri (JV) credp->fc_mode = credp->fc_mode|S_IFDIR; 6484fa4ce71SChen Gang err = local_set_xattr(buffer, credp); 64900ec5c37SVenkateswararao Jujjuri (JV) if (err == -1) { 65000ec5c37SVenkateswararao Jujjuri (JV) serrno = errno; 65100ec5c37SVenkateswararao Jujjuri (JV) goto err_end; 65200ec5c37SVenkateswararao Jujjuri (JV) } 6532c30dd74SAneesh Kumar K.V } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) { 6544fa4ce71SChen Gang buffer = rpath(fs_ctx, path); 6554fa4ce71SChen Gang err = mkdir(buffer, SM_LOCAL_DIR_MODE_BITS); 6562c30dd74SAneesh Kumar K.V if (err == -1) { 6572c30dd74SAneesh Kumar K.V goto out; 6582c30dd74SAneesh Kumar K.V } 6592c30dd74SAneesh Kumar K.V credp->fc_mode = credp->fc_mode|S_IFDIR; 6602c30dd74SAneesh Kumar K.V err = local_set_mapped_file_attr(fs_ctx, path, credp); 6612c30dd74SAneesh Kumar K.V if (err == -1) { 6622c30dd74SAneesh Kumar K.V serrno = errno; 6632c30dd74SAneesh Kumar K.V goto err_end; 6642c30dd74SAneesh Kumar K.V } 665b97400caSAneesh Kumar K.V } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) || 666b97400caSAneesh Kumar K.V (fs_ctx->export_flags & V9FS_SM_NONE)) { 6674fa4ce71SChen Gang buffer = rpath(fs_ctx, path); 6684fa4ce71SChen Gang err = mkdir(buffer, credp->fc_mode); 66900ec5c37SVenkateswararao Jujjuri (JV) if (err == -1) { 6702289be19SAneesh Kumar K.V goto out; 67100ec5c37SVenkateswararao Jujjuri (JV) } 67200ec5c37SVenkateswararao Jujjuri (JV) err = local_post_create_passthrough(fs_ctx, path, credp); 67300ec5c37SVenkateswararao Jujjuri (JV) if (err == -1) { 67400ec5c37SVenkateswararao Jujjuri (JV) serrno = errno; 67500ec5c37SVenkateswararao Jujjuri (JV) goto err_end; 67600ec5c37SVenkateswararao Jujjuri (JV) } 67700ec5c37SVenkateswararao Jujjuri (JV) } 6782289be19SAneesh Kumar K.V goto out; 67900ec5c37SVenkateswararao Jujjuri (JV) 68000ec5c37SVenkateswararao Jujjuri (JV) err_end: 6814fa4ce71SChen Gang remove(buffer); 68200ec5c37SVenkateswararao Jujjuri (JV) errno = serrno; 6832289be19SAneesh Kumar K.V out: 6844ed7b2c3SStefan Weil g_free(buffer); 6852289be19SAneesh Kumar K.V v9fs_string_free(&fullname); 68600ec5c37SVenkateswararao Jujjuri (JV) return err; 687c494dd6fSAnthony Liguori } 688c494dd6fSAnthony Liguori 6898b888272SAneesh Kumar K.V static int local_fstat(FsContext *fs_ctx, int fid_type, 690cc720ddbSAneesh Kumar K.V V9fsFidOpenState *fs, struct stat *stbuf) 691c494dd6fSAnthony Liguori { 6928b888272SAneesh Kumar K.V int err, fd; 6938b888272SAneesh Kumar K.V 6948b888272SAneesh Kumar K.V if (fid_type == P9_FID_DIR) { 695f314ea4eSGreg Kurz fd = dirfd(fs->dir.stream); 6968b888272SAneesh Kumar K.V } else { 6978b888272SAneesh Kumar K.V fd = fs->fd; 6988b888272SAneesh Kumar K.V } 6998b888272SAneesh Kumar K.V 7008b888272SAneesh Kumar K.V err = fstat(fd, stbuf); 7011237ad76SVenkateswararao Jujjuri (JV) if (err) { 7021237ad76SVenkateswararao Jujjuri (JV) return err; 7031237ad76SVenkateswararao Jujjuri (JV) } 704b97400caSAneesh Kumar K.V if (fs_ctx->export_flags & V9FS_SM_MAPPED) { 7051237ad76SVenkateswararao Jujjuri (JV) /* Actual credentials are part of extended attrs */ 7061237ad76SVenkateswararao Jujjuri (JV) uid_t tmp_uid; 7071237ad76SVenkateswararao Jujjuri (JV) gid_t tmp_gid; 7081237ad76SVenkateswararao Jujjuri (JV) mode_t tmp_mode; 7091237ad76SVenkateswararao Jujjuri (JV) dev_t tmp_dev; 7101237ad76SVenkateswararao Jujjuri (JV) 711f8ad4a89SAneesh Kumar K.V if (fgetxattr(fd, "user.virtfs.uid", &tmp_uid, sizeof(uid_t)) > 0) { 712f8ad4a89SAneesh Kumar K.V stbuf->st_uid = le32_to_cpu(tmp_uid); 7131237ad76SVenkateswararao Jujjuri (JV) } 714f8ad4a89SAneesh Kumar K.V if (fgetxattr(fd, "user.virtfs.gid", &tmp_gid, sizeof(gid_t)) > 0) { 715f8ad4a89SAneesh Kumar K.V stbuf->st_gid = le32_to_cpu(tmp_gid); 7161237ad76SVenkateswararao Jujjuri (JV) } 717f8ad4a89SAneesh Kumar K.V if (fgetxattr(fd, "user.virtfs.mode", &tmp_mode, sizeof(mode_t)) > 0) { 718f8ad4a89SAneesh Kumar K.V stbuf->st_mode = le32_to_cpu(tmp_mode); 7191237ad76SVenkateswararao Jujjuri (JV) } 720f8ad4a89SAneesh Kumar K.V if (fgetxattr(fd, "user.virtfs.rdev", &tmp_dev, sizeof(dev_t)) > 0) { 721f8ad4a89SAneesh Kumar K.V stbuf->st_rdev = le64_to_cpu(tmp_dev); 7221237ad76SVenkateswararao Jujjuri (JV) } 7232c30dd74SAneesh Kumar K.V } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) { 7242c30dd74SAneesh Kumar K.V errno = EOPNOTSUPP; 7252c30dd74SAneesh Kumar K.V return -1; 7261237ad76SVenkateswararao Jujjuri (JV) } 7271237ad76SVenkateswararao Jujjuri (JV) return err; 728c494dd6fSAnthony Liguori } 729c494dd6fSAnthony Liguori 7302289be19SAneesh Kumar K.V static int local_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name, 731cc720ddbSAneesh Kumar K.V int flags, FsCred *credp, V9fsFidOpenState *fs) 732c494dd6fSAnthony Liguori { 7332289be19SAneesh Kumar K.V char *path; 7344750a96fSVenkateswararao Jujjuri (JV) int fd = -1; 7354750a96fSVenkateswararao Jujjuri (JV) int err = -1; 7364750a96fSVenkateswararao Jujjuri (JV) int serrno = 0; 7372289be19SAneesh Kumar K.V V9fsString fullname; 7384ed7b2c3SStefan Weil char *buffer = NULL; 7394750a96fSVenkateswararao Jujjuri (JV) 7400ceb092eSAneesh Kumar K.V /* 7410ceb092eSAneesh Kumar K.V * Mark all the open to not follow symlinks 7420ceb092eSAneesh Kumar K.V */ 7430ceb092eSAneesh Kumar K.V flags |= O_NOFOLLOW; 7440ceb092eSAneesh Kumar K.V 7452289be19SAneesh Kumar K.V v9fs_string_init(&fullname); 7462289be19SAneesh Kumar K.V v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name); 7472289be19SAneesh Kumar K.V path = fullname.data; 7482289be19SAneesh Kumar K.V 7494750a96fSVenkateswararao Jujjuri (JV) /* Determine the security model */ 750b97400caSAneesh Kumar K.V if (fs_ctx->export_flags & V9FS_SM_MAPPED) { 7514fa4ce71SChen Gang buffer = rpath(fs_ctx, path); 7524fa4ce71SChen Gang fd = open(buffer, flags, SM_LOCAL_MODE_BITS); 7534750a96fSVenkateswararao Jujjuri (JV) if (fd == -1) { 7542289be19SAneesh Kumar K.V err = fd; 7552289be19SAneesh Kumar K.V goto out; 7564750a96fSVenkateswararao Jujjuri (JV) } 7574750a96fSVenkateswararao Jujjuri (JV) credp->fc_mode = credp->fc_mode|S_IFREG; 7584750a96fSVenkateswararao Jujjuri (JV) /* Set cleint credentials in xattr */ 7594fa4ce71SChen Gang err = local_set_xattr(buffer, credp); 7604750a96fSVenkateswararao Jujjuri (JV) if (err == -1) { 7614750a96fSVenkateswararao Jujjuri (JV) serrno = errno; 7624750a96fSVenkateswararao Jujjuri (JV) goto err_end; 7634750a96fSVenkateswararao Jujjuri (JV) } 7642c30dd74SAneesh Kumar K.V } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) { 7654fa4ce71SChen Gang buffer = rpath(fs_ctx, path); 7664fa4ce71SChen Gang fd = open(buffer, flags, SM_LOCAL_MODE_BITS); 7672c30dd74SAneesh Kumar K.V if (fd == -1) { 7682c30dd74SAneesh Kumar K.V err = fd; 7692c30dd74SAneesh Kumar K.V goto out; 7702c30dd74SAneesh Kumar K.V } 7712c30dd74SAneesh Kumar K.V credp->fc_mode = credp->fc_mode|S_IFREG; 7722c30dd74SAneesh Kumar K.V /* Set client credentials in .virtfs_metadata directory files */ 7732c30dd74SAneesh Kumar K.V err = local_set_mapped_file_attr(fs_ctx, path, credp); 7742c30dd74SAneesh Kumar K.V if (err == -1) { 7752c30dd74SAneesh Kumar K.V serrno = errno; 7762c30dd74SAneesh Kumar K.V goto err_end; 7772c30dd74SAneesh Kumar K.V } 778b97400caSAneesh Kumar K.V } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) || 779b97400caSAneesh Kumar K.V (fs_ctx->export_flags & V9FS_SM_NONE)) { 7804fa4ce71SChen Gang buffer = rpath(fs_ctx, path); 7814fa4ce71SChen Gang fd = open(buffer, flags, credp->fc_mode); 7824750a96fSVenkateswararao Jujjuri (JV) if (fd == -1) { 7832289be19SAneesh Kumar K.V err = fd; 7842289be19SAneesh Kumar K.V goto out; 7854750a96fSVenkateswararao Jujjuri (JV) } 7864750a96fSVenkateswararao Jujjuri (JV) err = local_post_create_passthrough(fs_ctx, path, credp); 7874750a96fSVenkateswararao Jujjuri (JV) if (err == -1) { 7884750a96fSVenkateswararao Jujjuri (JV) serrno = errno; 7894750a96fSVenkateswararao Jujjuri (JV) goto err_end; 7904750a96fSVenkateswararao Jujjuri (JV) } 7914750a96fSVenkateswararao Jujjuri (JV) } 7922289be19SAneesh Kumar K.V err = fd; 793cc720ddbSAneesh Kumar K.V fs->fd = fd; 7942289be19SAneesh Kumar K.V goto out; 7954750a96fSVenkateswararao Jujjuri (JV) 7964750a96fSVenkateswararao Jujjuri (JV) err_end: 7974750a96fSVenkateswararao Jujjuri (JV) close(fd); 7984fa4ce71SChen Gang remove(buffer); 7994750a96fSVenkateswararao Jujjuri (JV) errno = serrno; 8002289be19SAneesh Kumar K.V out: 8014ed7b2c3SStefan Weil g_free(buffer); 8022289be19SAneesh Kumar K.V v9fs_string_free(&fullname); 8034750a96fSVenkateswararao Jujjuri (JV) return err; 804c494dd6fSAnthony Liguori } 805c494dd6fSAnthony Liguori 806758e8e38SVenkateswararao Jujjuri (JV) 807879c2813SVenkateswararao Jujjuri (JV) static int local_symlink(FsContext *fs_ctx, const char *oldpath, 8082289be19SAneesh Kumar K.V V9fsPath *dir_path, const char *name, FsCred *credp) 809c494dd6fSAnthony Liguori { 810879c2813SVenkateswararao Jujjuri (JV) int err = -1; 811879c2813SVenkateswararao Jujjuri (JV) int serrno = 0; 8122289be19SAneesh Kumar K.V char *newpath; 8132289be19SAneesh Kumar K.V V9fsString fullname; 8144ed7b2c3SStefan Weil char *buffer = NULL; 815879c2813SVenkateswararao Jujjuri (JV) 8162289be19SAneesh Kumar K.V v9fs_string_init(&fullname); 8172289be19SAneesh Kumar K.V v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name); 8182289be19SAneesh Kumar K.V newpath = fullname.data; 8192289be19SAneesh Kumar K.V 820879c2813SVenkateswararao Jujjuri (JV) /* Determine the security model */ 821b97400caSAneesh Kumar K.V if (fs_ctx->export_flags & V9FS_SM_MAPPED) { 822879c2813SVenkateswararao Jujjuri (JV) int fd; 823879c2813SVenkateswararao Jujjuri (JV) ssize_t oldpath_size, write_size; 8244fa4ce71SChen Gang buffer = rpath(fs_ctx, newpath); 8254fa4ce71SChen Gang fd = open(buffer, O_CREAT|O_EXCL|O_RDWR|O_NOFOLLOW, SM_LOCAL_MODE_BITS); 826879c2813SVenkateswararao Jujjuri (JV) if (fd == -1) { 8272289be19SAneesh Kumar K.V err = fd; 8282289be19SAneesh Kumar K.V goto out; 829879c2813SVenkateswararao Jujjuri (JV) } 830879c2813SVenkateswararao Jujjuri (JV) /* Write the oldpath (target) to the file. */ 831f35bde2fSHarsh Prateek Bora oldpath_size = strlen(oldpath); 832879c2813SVenkateswararao Jujjuri (JV) do { 833879c2813SVenkateswararao Jujjuri (JV) write_size = write(fd, (void *)oldpath, oldpath_size); 834879c2813SVenkateswararao Jujjuri (JV) } while (write_size == -1 && errno == EINTR); 835879c2813SVenkateswararao Jujjuri (JV) 836879c2813SVenkateswararao Jujjuri (JV) if (write_size != oldpath_size) { 837879c2813SVenkateswararao Jujjuri (JV) serrno = errno; 838879c2813SVenkateswararao Jujjuri (JV) close(fd); 839879c2813SVenkateswararao Jujjuri (JV) err = -1; 840879c2813SVenkateswararao Jujjuri (JV) goto err_end; 841879c2813SVenkateswararao Jujjuri (JV) } 842879c2813SVenkateswararao Jujjuri (JV) close(fd); 843879c2813SVenkateswararao Jujjuri (JV) /* Set cleint credentials in symlink's xattr */ 844879c2813SVenkateswararao Jujjuri (JV) credp->fc_mode = credp->fc_mode|S_IFLNK; 8454fa4ce71SChen Gang err = local_set_xattr(buffer, credp); 846879c2813SVenkateswararao Jujjuri (JV) if (err == -1) { 847879c2813SVenkateswararao Jujjuri (JV) serrno = errno; 848879c2813SVenkateswararao Jujjuri (JV) goto err_end; 849879c2813SVenkateswararao Jujjuri (JV) } 8502c30dd74SAneesh Kumar K.V } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) { 8512c30dd74SAneesh Kumar K.V int fd; 8522c30dd74SAneesh Kumar K.V ssize_t oldpath_size, write_size; 8534fa4ce71SChen Gang buffer = rpath(fs_ctx, newpath); 8544fa4ce71SChen Gang fd = open(buffer, O_CREAT|O_EXCL|O_RDWR|O_NOFOLLOW, SM_LOCAL_MODE_BITS); 8552c30dd74SAneesh Kumar K.V if (fd == -1) { 8562c30dd74SAneesh Kumar K.V err = fd; 8572c30dd74SAneesh Kumar K.V goto out; 8582c30dd74SAneesh Kumar K.V } 8592c30dd74SAneesh Kumar K.V /* Write the oldpath (target) to the file. */ 8602c30dd74SAneesh Kumar K.V oldpath_size = strlen(oldpath); 8612c30dd74SAneesh Kumar K.V do { 8622c30dd74SAneesh Kumar K.V write_size = write(fd, (void *)oldpath, oldpath_size); 8632c30dd74SAneesh Kumar K.V } while (write_size == -1 && errno == EINTR); 8642c30dd74SAneesh Kumar K.V 8652c30dd74SAneesh Kumar K.V if (write_size != oldpath_size) { 8662c30dd74SAneesh Kumar K.V serrno = errno; 8672c30dd74SAneesh Kumar K.V close(fd); 8682c30dd74SAneesh Kumar K.V err = -1; 8692c30dd74SAneesh Kumar K.V goto err_end; 8702c30dd74SAneesh Kumar K.V } 8712c30dd74SAneesh Kumar K.V close(fd); 8722c30dd74SAneesh Kumar K.V /* Set cleint credentials in symlink's xattr */ 8732c30dd74SAneesh Kumar K.V credp->fc_mode = credp->fc_mode|S_IFLNK; 8742c30dd74SAneesh Kumar K.V err = local_set_mapped_file_attr(fs_ctx, newpath, credp); 8752c30dd74SAneesh Kumar K.V if (err == -1) { 8762c30dd74SAneesh Kumar K.V serrno = errno; 8772c30dd74SAneesh Kumar K.V goto err_end; 8782c30dd74SAneesh Kumar K.V } 879b97400caSAneesh Kumar K.V } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) || 880b97400caSAneesh Kumar K.V (fs_ctx->export_flags & V9FS_SM_NONE)) { 8814fa4ce71SChen Gang buffer = rpath(fs_ctx, newpath); 8824fa4ce71SChen Gang err = symlink(oldpath, buffer); 883879c2813SVenkateswararao Jujjuri (JV) if (err) { 8842289be19SAneesh Kumar K.V goto out; 885879c2813SVenkateswararao Jujjuri (JV) } 8864fa4ce71SChen Gang err = lchown(buffer, credp->fc_uid, credp->fc_gid); 887879c2813SVenkateswararao Jujjuri (JV) if (err == -1) { 88812848bfcSAneesh Kumar K.V /* 88912848bfcSAneesh Kumar K.V * If we fail to change ownership and if we are 89012848bfcSAneesh Kumar K.V * using security model none. Ignore the error 89112848bfcSAneesh Kumar K.V */ 892b97400caSAneesh Kumar K.V if ((fs_ctx->export_flags & V9FS_SEC_MASK) != V9FS_SM_NONE) { 893879c2813SVenkateswararao Jujjuri (JV) serrno = errno; 894879c2813SVenkateswararao Jujjuri (JV) goto err_end; 89512848bfcSAneesh Kumar K.V } else 89612848bfcSAneesh Kumar K.V err = 0; 897879c2813SVenkateswararao Jujjuri (JV) } 898879c2813SVenkateswararao Jujjuri (JV) } 8992289be19SAneesh Kumar K.V goto out; 900879c2813SVenkateswararao Jujjuri (JV) 901879c2813SVenkateswararao Jujjuri (JV) err_end: 9024fa4ce71SChen Gang remove(buffer); 903879c2813SVenkateswararao Jujjuri (JV) errno = serrno; 9042289be19SAneesh Kumar K.V out: 9054ed7b2c3SStefan Weil g_free(buffer); 9062289be19SAneesh Kumar K.V v9fs_string_free(&fullname); 907879c2813SVenkateswararao Jujjuri (JV) return err; 908c494dd6fSAnthony Liguori } 909c494dd6fSAnthony Liguori 9102289be19SAneesh Kumar K.V static int local_link(FsContext *ctx, V9fsPath *oldpath, 9112289be19SAneesh Kumar K.V V9fsPath *dirpath, const char *name) 912c494dd6fSAnthony Liguori { 9132289be19SAneesh Kumar K.V int ret; 9142289be19SAneesh Kumar K.V V9fsString newpath; 9154fa4ce71SChen Gang char *buffer, *buffer1; 916c494dd6fSAnthony Liguori 9172289be19SAneesh Kumar K.V v9fs_string_init(&newpath); 9182289be19SAneesh Kumar K.V v9fs_string_sprintf(&newpath, "%s/%s", dirpath->data, name); 9192289be19SAneesh Kumar K.V 9204fa4ce71SChen Gang buffer = rpath(ctx, oldpath->data); 9214fa4ce71SChen Gang buffer1 = rpath(ctx, newpath.data); 9224fa4ce71SChen Gang ret = link(buffer, buffer1); 9234fa4ce71SChen Gang g_free(buffer); 9244fa4ce71SChen Gang g_free(buffer1); 9252c30dd74SAneesh Kumar K.V 9262c30dd74SAneesh Kumar K.V /* now link the virtfs_metadata files */ 9272c30dd74SAneesh Kumar K.V if (!ret && (ctx->export_flags & V9FS_SM_MAPPED_FILE)) { 9282c30dd74SAneesh Kumar K.V /* Link the .virtfs_metadata files. Create the metada directory */ 9292c30dd74SAneesh Kumar K.V ret = local_create_mapped_attr_dir(ctx, newpath.data); 9302c30dd74SAneesh Kumar K.V if (ret < 0) { 9312c30dd74SAneesh Kumar K.V goto err_out; 9322c30dd74SAneesh Kumar K.V } 9334fa4ce71SChen Gang buffer = local_mapped_attr_path(ctx, oldpath->data); 9344fa4ce71SChen Gang buffer1 = local_mapped_attr_path(ctx, newpath.data); 9354fa4ce71SChen Gang ret = link(buffer, buffer1); 9364fa4ce71SChen Gang g_free(buffer); 9374fa4ce71SChen Gang g_free(buffer1); 9382c30dd74SAneesh Kumar K.V if (ret < 0 && errno != ENOENT) { 9392c30dd74SAneesh Kumar K.V goto err_out; 9402c30dd74SAneesh Kumar K.V } 9412c30dd74SAneesh Kumar K.V } 9422c30dd74SAneesh Kumar K.V err_out: 9432289be19SAneesh Kumar K.V v9fs_string_free(&newpath); 9442289be19SAneesh Kumar K.V return ret; 945c494dd6fSAnthony Liguori } 946c494dd6fSAnthony Liguori 9472289be19SAneesh Kumar K.V static int local_truncate(FsContext *ctx, V9fsPath *fs_path, off_t size) 9488cf89e00SAnthony Liguori { 949ac125d99SGreg Kurz int fd, ret; 9502289be19SAneesh Kumar K.V 951ac125d99SGreg Kurz fd = local_open_nofollow(ctx, fs_path->data, O_WRONLY, 0); 952ac125d99SGreg Kurz if (fd == -1) { 953ac125d99SGreg Kurz return -1; 954ac125d99SGreg Kurz } 955ac125d99SGreg Kurz ret = ftruncate(fd, size); 956ac125d99SGreg Kurz close_preserve_errno(fd); 9574fa4ce71SChen Gang return ret; 9588cf89e00SAnthony Liguori } 9598cf89e00SAnthony Liguori 9608cf89e00SAnthony Liguori static int local_rename(FsContext *ctx, const char *oldpath, 9618cf89e00SAnthony Liguori const char *newpath) 9628cf89e00SAnthony Liguori { 9632c30dd74SAneesh Kumar K.V int err; 9644fa4ce71SChen Gang char *buffer, *buffer1; 9658cf89e00SAnthony Liguori 9662c30dd74SAneesh Kumar K.V if (ctx->export_flags & V9FS_SM_MAPPED_FILE) { 9672c30dd74SAneesh Kumar K.V err = local_create_mapped_attr_dir(ctx, newpath); 9682c30dd74SAneesh Kumar K.V if (err < 0) { 9692c30dd74SAneesh Kumar K.V return err; 9702c30dd74SAneesh Kumar K.V } 9712c30dd74SAneesh Kumar K.V /* rename the .virtfs_metadata files */ 9724fa4ce71SChen Gang buffer = local_mapped_attr_path(ctx, oldpath); 9734fa4ce71SChen Gang buffer1 = local_mapped_attr_path(ctx, newpath); 9744fa4ce71SChen Gang err = rename(buffer, buffer1); 9754fa4ce71SChen Gang g_free(buffer); 9764fa4ce71SChen Gang g_free(buffer1); 9772c30dd74SAneesh Kumar K.V if (err < 0 && errno != ENOENT) { 9782c30dd74SAneesh Kumar K.V return err; 9792c30dd74SAneesh Kumar K.V } 9802c30dd74SAneesh Kumar K.V } 9814fa4ce71SChen Gang 9824fa4ce71SChen Gang buffer = rpath(ctx, oldpath); 9834fa4ce71SChen Gang buffer1 = rpath(ctx, newpath); 9844fa4ce71SChen Gang err = rename(buffer, buffer1); 9854fa4ce71SChen Gang g_free(buffer); 9864fa4ce71SChen Gang g_free(buffer1); 9874fa4ce71SChen Gang return err; 9888cf89e00SAnthony Liguori } 9898cf89e00SAnthony Liguori 9902289be19SAneesh Kumar K.V static int local_chown(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp) 9918cf89e00SAnthony Liguori { 9924fa4ce71SChen Gang char *buffer; 9934fa4ce71SChen Gang int ret = -1; 9942289be19SAneesh Kumar K.V char *path = fs_path->data; 9952289be19SAneesh Kumar K.V 996c79ce737SSripathi Kodi if ((credp->fc_uid == -1 && credp->fc_gid == -1) || 99717b1971fSAneesh Kumar K.V (fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) || 99817b1971fSAneesh Kumar K.V (fs_ctx->export_flags & V9FS_SM_NONE)) { 9994fa4ce71SChen Gang buffer = rpath(fs_ctx, path); 10004fa4ce71SChen Gang ret = lchown(buffer, credp->fc_uid, credp->fc_gid); 10014fa4ce71SChen Gang g_free(buffer); 1002b97400caSAneesh Kumar K.V } else if (fs_ctx->export_flags & V9FS_SM_MAPPED) { 10034fa4ce71SChen Gang buffer = rpath(fs_ctx, path); 10044fa4ce71SChen Gang ret = local_set_xattr(buffer, credp); 10054fa4ce71SChen Gang g_free(buffer); 10062c30dd74SAneesh Kumar K.V } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) { 10072c30dd74SAneesh Kumar K.V return local_set_mapped_file_attr(fs_ctx, path, credp); 1008f7613beeSVenkateswararao Jujjuri (JV) } 10094fa4ce71SChen Gang return ret; 10108cf89e00SAnthony Liguori } 10118cf89e00SAnthony Liguori 10122289be19SAneesh Kumar K.V static int local_utimensat(FsContext *s, V9fsPath *fs_path, 101374bc02b2SM. Mohan Kumar const struct timespec *buf) 10148cf89e00SAnthony Liguori { 1015a33eda0dSGreg Kurz char *dirpath = g_path_get_dirname(fs_path->data); 1016a33eda0dSGreg Kurz char *name = g_path_get_basename(fs_path->data); 1017a33eda0dSGreg Kurz int dirfd, ret = -1; 10182289be19SAneesh Kumar K.V 1019a33eda0dSGreg Kurz dirfd = local_opendir_nofollow(s, dirpath); 1020a33eda0dSGreg Kurz if (dirfd == -1) { 1021a33eda0dSGreg Kurz goto out; 1022a33eda0dSGreg Kurz } 1023a33eda0dSGreg Kurz 1024a33eda0dSGreg Kurz ret = utimensat(dirfd, name, buf, AT_SYMLINK_NOFOLLOW); 1025a33eda0dSGreg Kurz close_preserve_errno(dirfd); 1026a33eda0dSGreg Kurz out: 1027a33eda0dSGreg Kurz g_free(dirpath); 1028a33eda0dSGreg Kurz g_free(name); 10294fa4ce71SChen Gang return ret; 10308cf89e00SAnthony Liguori } 10318cf89e00SAnthony Liguori 1032df4938a6SGreg Kurz static int local_unlinkat_common(FsContext *ctx, int dirfd, const char *name, 1033df4938a6SGreg Kurz int flags) 1034df4938a6SGreg Kurz { 1035df4938a6SGreg Kurz int ret = -1; 1036df4938a6SGreg Kurz 1037df4938a6SGreg Kurz if (ctx->export_flags & V9FS_SM_MAPPED_FILE) { 1038df4938a6SGreg Kurz int map_dirfd; 1039df4938a6SGreg Kurz 1040df4938a6SGreg Kurz if (flags == AT_REMOVEDIR) { 1041df4938a6SGreg Kurz int fd; 1042df4938a6SGreg Kurz 1043df4938a6SGreg Kurz fd = openat(dirfd, name, O_RDONLY | O_DIRECTORY | O_PATH); 1044df4938a6SGreg Kurz if (fd == -1) { 1045df4938a6SGreg Kurz goto err_out; 1046df4938a6SGreg Kurz } 1047df4938a6SGreg Kurz /* 1048df4938a6SGreg Kurz * If directory remove .virtfs_metadata contained in the 1049df4938a6SGreg Kurz * directory 1050df4938a6SGreg Kurz */ 1051df4938a6SGreg Kurz ret = unlinkat(fd, VIRTFS_META_DIR, AT_REMOVEDIR); 1052df4938a6SGreg Kurz close_preserve_errno(fd); 1053df4938a6SGreg Kurz if (ret < 0 && errno != ENOENT) { 1054df4938a6SGreg Kurz /* 1055df4938a6SGreg Kurz * We didn't had the .virtfs_metadata file. May be file created 1056df4938a6SGreg Kurz * in non-mapped mode ?. Ignore ENOENT. 1057df4938a6SGreg Kurz */ 1058df4938a6SGreg Kurz goto err_out; 1059df4938a6SGreg Kurz } 1060df4938a6SGreg Kurz } 1061df4938a6SGreg Kurz /* 1062df4938a6SGreg Kurz * Now remove the name from parent directory 1063df4938a6SGreg Kurz * .virtfs_metadata directory. 1064df4938a6SGreg Kurz */ 1065df4938a6SGreg Kurz map_dirfd = openat_dir(dirfd, VIRTFS_META_DIR); 1066df4938a6SGreg Kurz ret = unlinkat(map_dirfd, name, 0); 1067df4938a6SGreg Kurz close_preserve_errno(map_dirfd); 1068df4938a6SGreg Kurz if (ret < 0 && errno != ENOENT) { 1069df4938a6SGreg Kurz /* 1070df4938a6SGreg Kurz * We didn't had the .virtfs_metadata file. May be file created 1071df4938a6SGreg Kurz * in non-mapped mode ?. Ignore ENOENT. 1072df4938a6SGreg Kurz */ 1073df4938a6SGreg Kurz goto err_out; 1074df4938a6SGreg Kurz } 1075df4938a6SGreg Kurz } 1076df4938a6SGreg Kurz 1077df4938a6SGreg Kurz ret = unlinkat(dirfd, name, flags); 1078df4938a6SGreg Kurz err_out: 1079df4938a6SGreg Kurz return ret; 1080df4938a6SGreg Kurz } 1081df4938a6SGreg Kurz 10825bae1900SAnthony Liguori static int local_remove(FsContext *ctx, const char *path) 10835bae1900SAnthony Liguori { 10842c30dd74SAneesh Kumar K.V struct stat stbuf; 1085a0e640a8SGreg Kurz char *dirpath = g_path_get_dirname(path); 1086a0e640a8SGreg Kurz char *name = g_path_get_basename(path); 1087a0e640a8SGreg Kurz int flags = 0; 1088a0e640a8SGreg Kurz int dirfd; 1089a0e640a8SGreg Kurz int err = -1; 10902c30dd74SAneesh Kumar K.V 1091a0e640a8SGreg Kurz dirfd = local_opendir_nofollow(ctx, dirpath); 1092a0e640a8SGreg Kurz if (dirfd) { 1093a0e640a8SGreg Kurz goto out; 1094a0e640a8SGreg Kurz } 1095a0e640a8SGreg Kurz 1096a0e640a8SGreg Kurz if (fstatat(dirfd, path, &stbuf, AT_SYMLINK_NOFOLLOW) < 0) { 10972c30dd74SAneesh Kumar K.V goto err_out; 10982c30dd74SAneesh Kumar K.V } 1099a0e640a8SGreg Kurz 11002c30dd74SAneesh Kumar K.V if (S_ISDIR(stbuf.st_mode)) { 1101a0e640a8SGreg Kurz flags |= AT_REMOVEDIR; 11022c30dd74SAneesh Kumar K.V } 11034fa4ce71SChen Gang 1104a0e640a8SGreg Kurz err = local_unlinkat_common(ctx, dirfd, name, flags); 11052c30dd74SAneesh Kumar K.V err_out: 1106a0e640a8SGreg Kurz close_preserve_errno(dirfd); 1107a0e640a8SGreg Kurz out: 1108a0e640a8SGreg Kurz g_free(name); 1109a0e640a8SGreg Kurz g_free(dirpath); 11102c30dd74SAneesh Kumar K.V return err; 11115bae1900SAnthony Liguori } 11125bae1900SAnthony Liguori 11138b888272SAneesh Kumar K.V static int local_fsync(FsContext *ctx, int fid_type, 11148b888272SAneesh Kumar K.V V9fsFidOpenState *fs, int datasync) 11158cf89e00SAnthony Liguori { 11168b888272SAneesh Kumar K.V int fd; 11178b888272SAneesh Kumar K.V 11188b888272SAneesh Kumar K.V if (fid_type == P9_FID_DIR) { 1119f314ea4eSGreg Kurz fd = dirfd(fs->dir.stream); 112049594973SVenkateswararao Jujjuri (JV) } else { 11218b888272SAneesh Kumar K.V fd = fs->fd; 11228b888272SAneesh Kumar K.V } 11238b888272SAneesh Kumar K.V 11248b888272SAneesh Kumar K.V if (datasync) { 11258b888272SAneesh Kumar K.V return qemu_fdatasync(fd); 11268b888272SAneesh Kumar K.V } else { 11278b888272SAneesh Kumar K.V return fsync(fd); 11288cf89e00SAnthony Liguori } 112949594973SVenkateswararao Jujjuri (JV) } 11308cf89e00SAnthony Liguori 11312289be19SAneesh Kumar K.V static int local_statfs(FsContext *s, V9fsPath *fs_path, struct statfs *stbuf) 1132be940c87SM. Mohan Kumar { 113331e51d1cSGreg Kurz int fd, ret; 11342289be19SAneesh Kumar K.V 113531e51d1cSGreg Kurz fd = local_open_nofollow(s, fs_path->data, O_RDONLY, 0); 113631e51d1cSGreg Kurz ret = fstatfs(fd, stbuf); 113731e51d1cSGreg Kurz close_preserve_errno(fd); 11384fa4ce71SChen Gang return ret; 1139be940c87SM. Mohan Kumar } 1140be940c87SM. Mohan Kumar 11412289be19SAneesh Kumar K.V static ssize_t local_lgetxattr(FsContext *ctx, V9fsPath *fs_path, 1142fa32ef88SAneesh Kumar K.V const char *name, void *value, size_t size) 1143fa32ef88SAneesh Kumar K.V { 11442289be19SAneesh Kumar K.V char *path = fs_path->data; 11452289be19SAneesh Kumar K.V 1146fc22118dSAneesh Kumar K.V return v9fs_get_xattr(ctx, path, name, value, size); 1147fa32ef88SAneesh Kumar K.V } 1148fa32ef88SAneesh Kumar K.V 11492289be19SAneesh Kumar K.V static ssize_t local_llistxattr(FsContext *ctx, V9fsPath *fs_path, 1150fa32ef88SAneesh Kumar K.V void *value, size_t size) 1151fa32ef88SAneesh Kumar K.V { 11522289be19SAneesh Kumar K.V char *path = fs_path->data; 11532289be19SAneesh Kumar K.V 1154fc22118dSAneesh Kumar K.V return v9fs_list_xattr(ctx, path, value, size); 115561b6c499SAneesh Kumar K.V } 115661b6c499SAneesh Kumar K.V 11572289be19SAneesh Kumar K.V static int local_lsetxattr(FsContext *ctx, V9fsPath *fs_path, const char *name, 115810b468bdSAneesh Kumar K.V void *value, size_t size, int flags) 115910b468bdSAneesh Kumar K.V { 11602289be19SAneesh Kumar K.V char *path = fs_path->data; 11612289be19SAneesh Kumar K.V 1162fc22118dSAneesh Kumar K.V return v9fs_set_xattr(ctx, path, name, value, size, flags); 116310b468bdSAneesh Kumar K.V } 116410b468bdSAneesh Kumar K.V 11652289be19SAneesh Kumar K.V static int local_lremovexattr(FsContext *ctx, V9fsPath *fs_path, 11662289be19SAneesh Kumar K.V const char *name) 11679ed3ef26SAneesh Kumar K.V { 11682289be19SAneesh Kumar K.V char *path = fs_path->data; 11692289be19SAneesh Kumar K.V 1170fc22118dSAneesh Kumar K.V return v9fs_remove_xattr(ctx, path, name); 11719ed3ef26SAneesh Kumar K.V } 11729ed3ef26SAneesh Kumar K.V 11732289be19SAneesh Kumar K.V static int local_name_to_path(FsContext *ctx, V9fsPath *dir_path, 11742289be19SAneesh Kumar K.V const char *name, V9fsPath *target) 11752289be19SAneesh Kumar K.V { 11762289be19SAneesh Kumar K.V if (dir_path) { 1177e3e83f2eSGreg Kurz v9fs_path_sprintf(target, "%s/%s", dir_path->data, name); 11782289be19SAneesh Kumar K.V } else { 1179e3e83f2eSGreg Kurz v9fs_path_sprintf(target, "%s", name); 11802289be19SAneesh Kumar K.V } 11812289be19SAneesh Kumar K.V return 0; 11822289be19SAneesh Kumar K.V } 11832289be19SAneesh Kumar K.V 11842289be19SAneesh Kumar K.V static int local_renameat(FsContext *ctx, V9fsPath *olddir, 11852289be19SAneesh Kumar K.V const char *old_name, V9fsPath *newdir, 11862289be19SAneesh Kumar K.V const char *new_name) 11872289be19SAneesh Kumar K.V { 11882289be19SAneesh Kumar K.V int ret; 11892289be19SAneesh Kumar K.V V9fsString old_full_name, new_full_name; 11902289be19SAneesh Kumar K.V 11912289be19SAneesh Kumar K.V v9fs_string_init(&old_full_name); 11922289be19SAneesh Kumar K.V v9fs_string_init(&new_full_name); 11932289be19SAneesh Kumar K.V 11942289be19SAneesh Kumar K.V v9fs_string_sprintf(&old_full_name, "%s/%s", olddir->data, old_name); 11952289be19SAneesh Kumar K.V v9fs_string_sprintf(&new_full_name, "%s/%s", newdir->data, new_name); 11962289be19SAneesh Kumar K.V 11972289be19SAneesh Kumar K.V ret = local_rename(ctx, old_full_name.data, new_full_name.data); 11982289be19SAneesh Kumar K.V v9fs_string_free(&old_full_name); 11992289be19SAneesh Kumar K.V v9fs_string_free(&new_full_name); 12002289be19SAneesh Kumar K.V return ret; 12012289be19SAneesh Kumar K.V } 12022289be19SAneesh Kumar K.V 12032289be19SAneesh Kumar K.V static int local_unlinkat(FsContext *ctx, V9fsPath *dir, 12042289be19SAneesh Kumar K.V const char *name, int flags) 12052289be19SAneesh Kumar K.V { 12062289be19SAneesh Kumar K.V int ret; 1207df4938a6SGreg Kurz int dirfd; 12082c30dd74SAneesh Kumar K.V 1209df4938a6SGreg Kurz dirfd = local_opendir_nofollow(ctx, dir->data); 1210df4938a6SGreg Kurz if (dirfd == -1) { 1211df4938a6SGreg Kurz return -1; 1212df4938a6SGreg Kurz } 12132289be19SAneesh Kumar K.V 1214df4938a6SGreg Kurz ret = local_unlinkat_common(ctx, dirfd, name, flags); 1215df4938a6SGreg Kurz close_preserve_errno(dirfd); 12162289be19SAneesh Kumar K.V return ret; 12172289be19SAneesh Kumar K.V } 12189ed3ef26SAneesh Kumar K.V 1219e06a765eSHarsh Prateek Bora static int local_ioc_getversion(FsContext *ctx, V9fsPath *path, 1220e06a765eSHarsh Prateek Bora mode_t st_mode, uint64_t *st_gen) 1221e06a765eSHarsh Prateek Bora { 1222ae0f940eSPaolo Bonzini #ifdef FS_IOC_GETVERSION 12230e5fc994SKirill A. Shutemov int err; 1224cc720ddbSAneesh Kumar K.V V9fsFidOpenState fid_open; 1225cc720ddbSAneesh Kumar K.V 1226e06a765eSHarsh Prateek Bora /* 1227e06a765eSHarsh Prateek Bora * Do not try to open special files like device nodes, fifos etc 1228e06a765eSHarsh Prateek Bora * We can get fd for regular files and directories only 1229e06a765eSHarsh Prateek Bora */ 1230e06a765eSHarsh Prateek Bora if (!S_ISREG(st_mode) && !S_ISDIR(st_mode)) { 12311a9978a5SKirill A. Shutemov errno = ENOTTY; 12321a9978a5SKirill A. Shutemov return -1; 1233e06a765eSHarsh Prateek Bora } 1234cc720ddbSAneesh Kumar K.V err = local_open(ctx, path, O_RDONLY, &fid_open); 1235cc720ddbSAneesh Kumar K.V if (err < 0) { 1236cc720ddbSAneesh Kumar K.V return err; 1237e06a765eSHarsh Prateek Bora } 1238cc720ddbSAneesh Kumar K.V err = ioctl(fid_open.fd, FS_IOC_GETVERSION, st_gen); 1239cc720ddbSAneesh Kumar K.V local_close(ctx, &fid_open); 1240e06a765eSHarsh Prateek Bora return err; 12410e5fc994SKirill A. Shutemov #else 12420e5fc994SKirill A. Shutemov errno = ENOTTY; 12430e5fc994SKirill A. Shutemov return -1; 12440e5fc994SKirill A. Shutemov #endif 1245e06a765eSHarsh Prateek Bora } 1246e06a765eSHarsh Prateek Bora 12470174fe73SAneesh Kumar K.V static int local_init(FsContext *ctx) 12480174fe73SAneesh Kumar K.V { 1249e06a765eSHarsh Prateek Bora struct statfs stbuf; 12500e35a378SGreg Kurz LocalData *data = g_malloc(sizeof(*data)); 12510e35a378SGreg Kurz 12520e35a378SGreg Kurz data->mountfd = open(ctx->fs_root, O_DIRECTORY | O_RDONLY); 12530e35a378SGreg Kurz if (data->mountfd == -1) { 12540e35a378SGreg Kurz goto err; 12550e35a378SGreg Kurz } 1256e06a765eSHarsh Prateek Bora 125700c90bd1SGreg Kurz #ifdef FS_IOC_GETVERSION 125800c90bd1SGreg Kurz /* 125900c90bd1SGreg Kurz * use ioc_getversion only if the ioctl is definied 126000c90bd1SGreg Kurz */ 12610e35a378SGreg Kurz if (fstatfs(data->mountfd, &stbuf) < 0) { 12620e35a378SGreg Kurz close_preserve_errno(data->mountfd); 12630e35a378SGreg Kurz goto err; 126400c90bd1SGreg Kurz } 126500c90bd1SGreg Kurz switch (stbuf.f_type) { 126600c90bd1SGreg Kurz case EXT2_SUPER_MAGIC: 126700c90bd1SGreg Kurz case BTRFS_SUPER_MAGIC: 126800c90bd1SGreg Kurz case REISERFS_SUPER_MAGIC: 126900c90bd1SGreg Kurz case XFS_SUPER_MAGIC: 127000c90bd1SGreg Kurz ctx->exops.get_st_gen = local_ioc_getversion; 127100c90bd1SGreg Kurz break; 127200c90bd1SGreg Kurz } 127300c90bd1SGreg Kurz #endif 127400c90bd1SGreg Kurz 12752c30dd74SAneesh Kumar K.V if (ctx->export_flags & V9FS_SM_PASSTHROUGH) { 12762c30dd74SAneesh Kumar K.V ctx->xops = passthrough_xattr_ops; 12772c30dd74SAneesh Kumar K.V } else if (ctx->export_flags & V9FS_SM_MAPPED) { 12782c30dd74SAneesh Kumar K.V ctx->xops = mapped_xattr_ops; 12792c30dd74SAneesh Kumar K.V } else if (ctx->export_flags & V9FS_SM_NONE) { 12802c30dd74SAneesh Kumar K.V ctx->xops = none_xattr_ops; 12812c30dd74SAneesh Kumar K.V } else if (ctx->export_flags & V9FS_SM_MAPPED_FILE) { 12822c30dd74SAneesh Kumar K.V /* 12832c30dd74SAneesh Kumar K.V * xattr operation for mapped-file and passthrough 12842c30dd74SAneesh Kumar K.V * remain same. 12852c30dd74SAneesh Kumar K.V */ 12862c30dd74SAneesh Kumar K.V ctx->xops = passthrough_xattr_ops; 12872c30dd74SAneesh Kumar K.V } 1288c98f1d4aSAneesh Kumar K.V ctx->export_flags |= V9FS_PATHNAME_FSCONTEXT; 128900c90bd1SGreg Kurz 12900e35a378SGreg Kurz ctx->private = data; 129100c90bd1SGreg Kurz return 0; 12920e35a378SGreg Kurz 12930e35a378SGreg Kurz err: 12940e35a378SGreg Kurz g_free(data); 12950e35a378SGreg Kurz return -1; 12960e35a378SGreg Kurz } 12970e35a378SGreg Kurz 12980e35a378SGreg Kurz static void local_cleanup(FsContext *ctx) 12990e35a378SGreg Kurz { 13000e35a378SGreg Kurz LocalData *data = ctx->private; 13010e35a378SGreg Kurz 13020e35a378SGreg Kurz close(data->mountfd); 13030e35a378SGreg Kurz g_free(data); 13040174fe73SAneesh Kumar K.V } 13050174fe73SAneesh Kumar K.V 130699519f0aSAneesh Kumar K.V static int local_parse_opts(QemuOpts *opts, struct FsDriverEntry *fse) 130799519f0aSAneesh Kumar K.V { 130899519f0aSAneesh Kumar K.V const char *sec_model = qemu_opt_get(opts, "security_model"); 130999519f0aSAneesh Kumar K.V const char *path = qemu_opt_get(opts, "path"); 131099519f0aSAneesh Kumar K.V 131199519f0aSAneesh Kumar K.V if (!sec_model) { 131263325b18SGreg Kurz error_report("Security model not specified, local fs needs security model"); 131363325b18SGreg Kurz error_printf("valid options are:" 131463325b18SGreg Kurz "\tsecurity_model=[passthrough|mapped-xattr|mapped-file|none]\n"); 131599519f0aSAneesh Kumar K.V return -1; 131699519f0aSAneesh Kumar K.V } 131799519f0aSAneesh Kumar K.V 131899519f0aSAneesh Kumar K.V if (!strcmp(sec_model, "passthrough")) { 131999519f0aSAneesh Kumar K.V fse->export_flags |= V9FS_SM_PASSTHROUGH; 13202c30dd74SAneesh Kumar K.V } else if (!strcmp(sec_model, "mapped") || 13212c30dd74SAneesh Kumar K.V !strcmp(sec_model, "mapped-xattr")) { 132299519f0aSAneesh Kumar K.V fse->export_flags |= V9FS_SM_MAPPED; 132399519f0aSAneesh Kumar K.V } else if (!strcmp(sec_model, "none")) { 132499519f0aSAneesh Kumar K.V fse->export_flags |= V9FS_SM_NONE; 13252c30dd74SAneesh Kumar K.V } else if (!strcmp(sec_model, "mapped-file")) { 13262c30dd74SAneesh Kumar K.V fse->export_flags |= V9FS_SM_MAPPED_FILE; 132799519f0aSAneesh Kumar K.V } else { 132863325b18SGreg Kurz error_report("Invalid security model %s specified", sec_model); 132963325b18SGreg Kurz error_printf("valid options are:" 133063325b18SGreg Kurz "\t[passthrough|mapped-xattr|mapped-file|none]\n"); 133199519f0aSAneesh Kumar K.V return -1; 133299519f0aSAneesh Kumar K.V } 133399519f0aSAneesh Kumar K.V 133499519f0aSAneesh Kumar K.V if (!path) { 133563325b18SGreg Kurz error_report("fsdev: No path specified"); 133699519f0aSAneesh Kumar K.V return -1; 133799519f0aSAneesh Kumar K.V } 133899519f0aSAneesh Kumar K.V fse->path = g_strdup(path); 133999519f0aSAneesh Kumar K.V 134099519f0aSAneesh Kumar K.V return 0; 134199519f0aSAneesh Kumar K.V } 134299519f0aSAneesh Kumar K.V 13439f107513SAnthony Liguori FileOperations local_ops = { 134499519f0aSAneesh Kumar K.V .parse_opts = local_parse_opts, 13450174fe73SAneesh Kumar K.V .init = local_init, 13460e35a378SGreg Kurz .cleanup = local_cleanup, 1347131dcb25SAnthony Liguori .lstat = local_lstat, 1348131dcb25SAnthony Liguori .readlink = local_readlink, 1349131dcb25SAnthony Liguori .close = local_close, 1350131dcb25SAnthony Liguori .closedir = local_closedir, 1351a6568fe2SAnthony Liguori .open = local_open, 1352a6568fe2SAnthony Liguori .opendir = local_opendir, 1353a9231555SAnthony Liguori .rewinddir = local_rewinddir, 1354a9231555SAnthony Liguori .telldir = local_telldir, 1355635324e8SGreg Kurz .readdir = local_readdir, 1356a9231555SAnthony Liguori .seekdir = local_seekdir, 135756d15a53SSanchit Garg .preadv = local_preadv, 135856d15a53SSanchit Garg .pwritev = local_pwritev, 1359c494dd6fSAnthony Liguori .chmod = local_chmod, 1360c494dd6fSAnthony Liguori .mknod = local_mknod, 1361c494dd6fSAnthony Liguori .mkdir = local_mkdir, 1362c494dd6fSAnthony Liguori .fstat = local_fstat, 1363c494dd6fSAnthony Liguori .open2 = local_open2, 1364c494dd6fSAnthony Liguori .symlink = local_symlink, 1365c494dd6fSAnthony Liguori .link = local_link, 13668cf89e00SAnthony Liguori .truncate = local_truncate, 13678cf89e00SAnthony Liguori .rename = local_rename, 13688cf89e00SAnthony Liguori .chown = local_chown, 136974bc02b2SM. Mohan Kumar .utimensat = local_utimensat, 13705bae1900SAnthony Liguori .remove = local_remove, 13718cf89e00SAnthony Liguori .fsync = local_fsync, 1372be940c87SM. Mohan Kumar .statfs = local_statfs, 1373fa32ef88SAneesh Kumar K.V .lgetxattr = local_lgetxattr, 1374fa32ef88SAneesh Kumar K.V .llistxattr = local_llistxattr, 137510b468bdSAneesh Kumar K.V .lsetxattr = local_lsetxattr, 13769ed3ef26SAneesh Kumar K.V .lremovexattr = local_lremovexattr, 13772289be19SAneesh Kumar K.V .name_to_path = local_name_to_path, 13782289be19SAneesh Kumar K.V .renameat = local_renameat, 13792289be19SAneesh Kumar K.V .unlinkat = local_unlinkat, 13809f107513SAnthony Liguori }; 1381