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 1142c30dd74SAneesh Kumar K.V #define ATTR_MAX 100 1152c30dd74SAneesh Kumar K.V static void local_mapped_file_attr(FsContext *ctx, const char *path, 1162c30dd74SAneesh Kumar K.V struct stat *stbuf) 1172c30dd74SAneesh Kumar K.V { 1182c30dd74SAneesh Kumar K.V FILE *fp; 1192c30dd74SAneesh Kumar K.V char buf[ATTR_MAX]; 1204fa4ce71SChen Gang char *attr_path; 1212c30dd74SAneesh Kumar K.V 1224fa4ce71SChen Gang attr_path = local_mapped_attr_path(ctx, path); 1230ceb092eSAneesh Kumar K.V fp = local_fopen(attr_path, "r"); 1244fa4ce71SChen Gang g_free(attr_path); 1252c30dd74SAneesh Kumar K.V if (!fp) { 1262c30dd74SAneesh Kumar K.V return; 1272c30dd74SAneesh Kumar K.V } 1282c30dd74SAneesh Kumar K.V memset(buf, 0, ATTR_MAX); 1292c30dd74SAneesh Kumar K.V while (fgets(buf, ATTR_MAX, fp)) { 1302c30dd74SAneesh Kumar K.V if (!strncmp(buf, "virtfs.uid", 10)) { 1312c30dd74SAneesh Kumar K.V stbuf->st_uid = atoi(buf+11); 1322c30dd74SAneesh Kumar K.V } else if (!strncmp(buf, "virtfs.gid", 10)) { 1332c30dd74SAneesh Kumar K.V stbuf->st_gid = atoi(buf+11); 1342c30dd74SAneesh Kumar K.V } else if (!strncmp(buf, "virtfs.mode", 11)) { 1352c30dd74SAneesh Kumar K.V stbuf->st_mode = atoi(buf+12); 1362c30dd74SAneesh Kumar K.V } else if (!strncmp(buf, "virtfs.rdev", 11)) { 1372c30dd74SAneesh Kumar K.V stbuf->st_rdev = atoi(buf+12); 1382c30dd74SAneesh Kumar K.V } 1392c30dd74SAneesh Kumar K.V memset(buf, 0, ATTR_MAX); 1402c30dd74SAneesh Kumar K.V } 1412c30dd74SAneesh Kumar K.V fclose(fp); 1422c30dd74SAneesh Kumar K.V } 1432c30dd74SAneesh Kumar K.V 1442289be19SAneesh Kumar K.V static int local_lstat(FsContext *fs_ctx, V9fsPath *fs_path, struct stat *stbuf) 145131dcb25SAnthony Liguori { 1461237ad76SVenkateswararao Jujjuri (JV) int err; 1474fa4ce71SChen Gang char *buffer; 1482289be19SAneesh Kumar K.V char *path = fs_path->data; 1492289be19SAneesh Kumar K.V 1504fa4ce71SChen Gang buffer = rpath(fs_ctx, path); 1514fa4ce71SChen Gang err = lstat(buffer, stbuf); 1521237ad76SVenkateswararao Jujjuri (JV) if (err) { 1534fa4ce71SChen Gang goto err_out; 1541237ad76SVenkateswararao Jujjuri (JV) } 155b97400caSAneesh Kumar K.V if (fs_ctx->export_flags & V9FS_SM_MAPPED) { 1561237ad76SVenkateswararao Jujjuri (JV) /* Actual credentials are part of extended attrs */ 1571237ad76SVenkateswararao Jujjuri (JV) uid_t tmp_uid; 1581237ad76SVenkateswararao Jujjuri (JV) gid_t tmp_gid; 1591237ad76SVenkateswararao Jujjuri (JV) mode_t tmp_mode; 1601237ad76SVenkateswararao Jujjuri (JV) dev_t tmp_dev; 1614fa4ce71SChen Gang if (getxattr(buffer, "user.virtfs.uid", &tmp_uid, sizeof(uid_t)) > 0) { 162f8ad4a89SAneesh Kumar K.V stbuf->st_uid = le32_to_cpu(tmp_uid); 1631237ad76SVenkateswararao Jujjuri (JV) } 1644fa4ce71SChen Gang if (getxattr(buffer, "user.virtfs.gid", &tmp_gid, sizeof(gid_t)) > 0) { 165f8ad4a89SAneesh Kumar K.V stbuf->st_gid = le32_to_cpu(tmp_gid); 1661237ad76SVenkateswararao Jujjuri (JV) } 1674fa4ce71SChen Gang if (getxattr(buffer, "user.virtfs.mode", 168faa44e3dSVenkateswararao Jujjuri (JV) &tmp_mode, sizeof(mode_t)) > 0) { 169f8ad4a89SAneesh Kumar K.V stbuf->st_mode = le32_to_cpu(tmp_mode); 1701237ad76SVenkateswararao Jujjuri (JV) } 1714fa4ce71SChen Gang if (getxattr(buffer, "user.virtfs.rdev", &tmp_dev, sizeof(dev_t)) > 0) { 172f8ad4a89SAneesh Kumar K.V stbuf->st_rdev = le64_to_cpu(tmp_dev); 1731237ad76SVenkateswararao Jujjuri (JV) } 1742c30dd74SAneesh Kumar K.V } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) { 1752c30dd74SAneesh Kumar K.V local_mapped_file_attr(fs_ctx, path, stbuf); 1761237ad76SVenkateswararao Jujjuri (JV) } 1774fa4ce71SChen Gang 1784fa4ce71SChen Gang err_out: 1794fa4ce71SChen Gang g_free(buffer); 1801237ad76SVenkateswararao Jujjuri (JV) return err; 181131dcb25SAnthony Liguori } 182131dcb25SAnthony Liguori 1832c30dd74SAneesh Kumar K.V static int local_create_mapped_attr_dir(FsContext *ctx, const char *path) 1842c30dd74SAneesh Kumar K.V { 1852c30dd74SAneesh Kumar K.V int err; 1864fa4ce71SChen Gang char *attr_dir; 187d3f8e138SMarkus Armbruster char *tmp_path = g_strdup(path); 1882c30dd74SAneesh Kumar K.V 1894fa4ce71SChen Gang attr_dir = g_strdup_printf("%s/%s/%s", 1902c30dd74SAneesh Kumar K.V ctx->fs_root, dirname(tmp_path), VIRTFS_META_DIR); 1912c30dd74SAneesh Kumar K.V 1922c30dd74SAneesh Kumar K.V err = mkdir(attr_dir, 0700); 1932c30dd74SAneesh Kumar K.V if (err < 0 && errno == EEXIST) { 1942c30dd74SAneesh Kumar K.V err = 0; 1952c30dd74SAneesh Kumar K.V } 1964fa4ce71SChen Gang g_free(attr_dir); 197d3f8e138SMarkus Armbruster g_free(tmp_path); 1982c30dd74SAneesh Kumar K.V return err; 1992c30dd74SAneesh Kumar K.V } 2002c30dd74SAneesh Kumar K.V 2012c30dd74SAneesh Kumar K.V static int local_set_mapped_file_attr(FsContext *ctx, 2022c30dd74SAneesh Kumar K.V const char *path, FsCred *credp) 2032c30dd74SAneesh Kumar K.V { 2042c30dd74SAneesh Kumar K.V FILE *fp; 2052c30dd74SAneesh Kumar K.V int ret = 0; 2062c30dd74SAneesh Kumar K.V char buf[ATTR_MAX]; 2074fa4ce71SChen Gang char *attr_path; 2082c30dd74SAneesh Kumar K.V int uid = -1, gid = -1, mode = -1, rdev = -1; 2092c30dd74SAneesh Kumar K.V 2104fa4ce71SChen Gang attr_path = local_mapped_attr_path(ctx, path); 2114fa4ce71SChen Gang fp = local_fopen(attr_path, "r"); 2122c30dd74SAneesh Kumar K.V if (!fp) { 2132c30dd74SAneesh Kumar K.V goto create_map_file; 2142c30dd74SAneesh Kumar K.V } 2152c30dd74SAneesh Kumar K.V memset(buf, 0, ATTR_MAX); 2162c30dd74SAneesh Kumar K.V while (fgets(buf, ATTR_MAX, fp)) { 2172c30dd74SAneesh Kumar K.V if (!strncmp(buf, "virtfs.uid", 10)) { 2182c30dd74SAneesh Kumar K.V uid = atoi(buf+11); 2192c30dd74SAneesh Kumar K.V } else if (!strncmp(buf, "virtfs.gid", 10)) { 2202c30dd74SAneesh Kumar K.V gid = atoi(buf+11); 2212c30dd74SAneesh Kumar K.V } else if (!strncmp(buf, "virtfs.mode", 11)) { 2222c30dd74SAneesh Kumar K.V mode = atoi(buf+12); 2232c30dd74SAneesh Kumar K.V } else if (!strncmp(buf, "virtfs.rdev", 11)) { 2242c30dd74SAneesh Kumar K.V rdev = atoi(buf+12); 2252c30dd74SAneesh Kumar K.V } 2262c30dd74SAneesh Kumar K.V memset(buf, 0, ATTR_MAX); 2272c30dd74SAneesh Kumar K.V } 2282c30dd74SAneesh Kumar K.V fclose(fp); 2292c30dd74SAneesh Kumar K.V goto update_map_file; 2302c30dd74SAneesh Kumar K.V 2312c30dd74SAneesh Kumar K.V create_map_file: 2322c30dd74SAneesh Kumar K.V ret = local_create_mapped_attr_dir(ctx, path); 2332c30dd74SAneesh Kumar K.V if (ret < 0) { 2342c30dd74SAneesh Kumar K.V goto err_out; 2352c30dd74SAneesh Kumar K.V } 2362c30dd74SAneesh Kumar K.V 2372c30dd74SAneesh Kumar K.V update_map_file: 2380ceb092eSAneesh Kumar K.V fp = local_fopen(attr_path, "w"); 2392c30dd74SAneesh Kumar K.V if (!fp) { 2402c30dd74SAneesh Kumar K.V ret = -1; 2412c30dd74SAneesh Kumar K.V goto err_out; 2422c30dd74SAneesh Kumar K.V } 2432c30dd74SAneesh Kumar K.V 2442c30dd74SAneesh Kumar K.V if (credp->fc_uid != -1) { 2452c30dd74SAneesh Kumar K.V uid = credp->fc_uid; 2462c30dd74SAneesh Kumar K.V } 2472c30dd74SAneesh Kumar K.V if (credp->fc_gid != -1) { 2482c30dd74SAneesh Kumar K.V gid = credp->fc_gid; 2492c30dd74SAneesh Kumar K.V } 2502c30dd74SAneesh Kumar K.V if (credp->fc_mode != -1) { 2512c30dd74SAneesh Kumar K.V mode = credp->fc_mode; 2522c30dd74SAneesh Kumar K.V } 2532c30dd74SAneesh Kumar K.V if (credp->fc_rdev != -1) { 2542c30dd74SAneesh Kumar K.V rdev = credp->fc_rdev; 2552c30dd74SAneesh Kumar K.V } 2562c30dd74SAneesh Kumar K.V 2572c30dd74SAneesh Kumar K.V 2582c30dd74SAneesh Kumar K.V if (uid != -1) { 2592c30dd74SAneesh Kumar K.V fprintf(fp, "virtfs.uid=%d\n", uid); 2602c30dd74SAneesh Kumar K.V } 2612c30dd74SAneesh Kumar K.V if (gid != -1) { 2622c30dd74SAneesh Kumar K.V fprintf(fp, "virtfs.gid=%d\n", gid); 2632c30dd74SAneesh Kumar K.V } 2642c30dd74SAneesh Kumar K.V if (mode != -1) { 2652c30dd74SAneesh Kumar K.V fprintf(fp, "virtfs.mode=%d\n", mode); 2662c30dd74SAneesh Kumar K.V } 2672c30dd74SAneesh Kumar K.V if (rdev != -1) { 2682c30dd74SAneesh Kumar K.V fprintf(fp, "virtfs.rdev=%d\n", rdev); 2692c30dd74SAneesh Kumar K.V } 2702c30dd74SAneesh Kumar K.V fclose(fp); 2712c30dd74SAneesh Kumar K.V 2722c30dd74SAneesh Kumar K.V err_out: 2734fa4ce71SChen Gang g_free(attr_path); 2742c30dd74SAneesh Kumar K.V return ret; 2752c30dd74SAneesh Kumar K.V } 2762c30dd74SAneesh Kumar K.V 277758e8e38SVenkateswararao Jujjuri (JV) static int local_set_xattr(const char *path, FsCred *credp) 278131dcb25SAnthony Liguori { 279758e8e38SVenkateswararao Jujjuri (JV) int err; 2802289be19SAneesh Kumar K.V 281758e8e38SVenkateswararao Jujjuri (JV) if (credp->fc_uid != -1) { 282f8ad4a89SAneesh Kumar K.V uint32_t tmp_uid = cpu_to_le32(credp->fc_uid); 283f8ad4a89SAneesh Kumar K.V err = setxattr(path, "user.virtfs.uid", &tmp_uid, sizeof(uid_t), 0); 284758e8e38SVenkateswararao Jujjuri (JV) if (err) { 285758e8e38SVenkateswararao Jujjuri (JV) return err; 286131dcb25SAnthony Liguori } 287131dcb25SAnthony Liguori } 288758e8e38SVenkateswararao Jujjuri (JV) if (credp->fc_gid != -1) { 289f8ad4a89SAneesh Kumar K.V uint32_t tmp_gid = cpu_to_le32(credp->fc_gid); 290f8ad4a89SAneesh Kumar K.V err = setxattr(path, "user.virtfs.gid", &tmp_gid, sizeof(gid_t), 0); 291758e8e38SVenkateswararao Jujjuri (JV) if (err) { 292758e8e38SVenkateswararao Jujjuri (JV) return err; 293131dcb25SAnthony Liguori } 294131dcb25SAnthony Liguori } 295758e8e38SVenkateswararao Jujjuri (JV) if (credp->fc_mode != -1) { 296f8ad4a89SAneesh Kumar K.V uint32_t tmp_mode = cpu_to_le32(credp->fc_mode); 297f8ad4a89SAneesh Kumar K.V err = setxattr(path, "user.virtfs.mode", &tmp_mode, sizeof(mode_t), 0); 298758e8e38SVenkateswararao Jujjuri (JV) if (err) { 299758e8e38SVenkateswararao Jujjuri (JV) return err; 300131dcb25SAnthony Liguori } 301131dcb25SAnthony Liguori } 302758e8e38SVenkateswararao Jujjuri (JV) if (credp->fc_rdev != -1) { 303f8ad4a89SAneesh Kumar K.V uint64_t tmp_rdev = cpu_to_le64(credp->fc_rdev); 304f8ad4a89SAneesh Kumar K.V err = setxattr(path, "user.virtfs.rdev", &tmp_rdev, sizeof(dev_t), 0); 305758e8e38SVenkateswararao Jujjuri (JV) if (err) { 306758e8e38SVenkateswararao Jujjuri (JV) return err; 307131dcb25SAnthony Liguori } 308758e8e38SVenkateswararao Jujjuri (JV) } 309131dcb25SAnthony Liguori return 0; 310131dcb25SAnthony Liguori } 311131dcb25SAnthony Liguori 3124750a96fSVenkateswararao Jujjuri (JV) static int local_post_create_passthrough(FsContext *fs_ctx, const char *path, 3134750a96fSVenkateswararao Jujjuri (JV) FsCred *credp) 3144750a96fSVenkateswararao Jujjuri (JV) { 3154fa4ce71SChen Gang char *buffer; 3162289be19SAneesh Kumar K.V 3174fa4ce71SChen Gang buffer = rpath(fs_ctx, path); 3184fa4ce71SChen Gang if (lchown(buffer, credp->fc_uid, credp->fc_gid) < 0) { 31912848bfcSAneesh Kumar K.V /* 32012848bfcSAneesh Kumar K.V * If we fail to change ownership and if we are 32112848bfcSAneesh Kumar K.V * using security model none. Ignore the error 32212848bfcSAneesh Kumar K.V */ 323b97400caSAneesh Kumar K.V if ((fs_ctx->export_flags & V9FS_SEC_MASK) != V9FS_SM_NONE) { 3244fa4ce71SChen Gang goto err; 3254750a96fSVenkateswararao Jujjuri (JV) } 32612848bfcSAneesh Kumar K.V } 3272d40564aSM. Mohan Kumar 3284fa4ce71SChen Gang if (chmod(buffer, credp->fc_mode & 07777) < 0) { 3294fa4ce71SChen Gang goto err; 3302d40564aSM. Mohan Kumar } 3314fa4ce71SChen Gang 3324fa4ce71SChen Gang g_free(buffer); 3334750a96fSVenkateswararao Jujjuri (JV) return 0; 3344fa4ce71SChen Gang err: 3354fa4ce71SChen Gang g_free(buffer); 3364fa4ce71SChen Gang return -1; 3374750a96fSVenkateswararao Jujjuri (JV) } 3384750a96fSVenkateswararao Jujjuri (JV) 3392289be19SAneesh Kumar K.V static ssize_t local_readlink(FsContext *fs_ctx, V9fsPath *fs_path, 340131dcb25SAnthony Liguori char *buf, size_t bufsz) 341131dcb25SAnthony Liguori { 342879c2813SVenkateswararao Jujjuri (JV) ssize_t tsize = -1; 3432289be19SAneesh Kumar K.V 3442c30dd74SAneesh Kumar K.V if ((fs_ctx->export_flags & V9FS_SM_MAPPED) || 3452c30dd74SAneesh Kumar K.V (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE)) { 346879c2813SVenkateswararao Jujjuri (JV) int fd; 347*bec1e954SGreg Kurz 348*bec1e954SGreg Kurz fd = local_open_nofollow(fs_ctx, fs_path->data, O_RDONLY, 0); 349879c2813SVenkateswararao Jujjuri (JV) if (fd == -1) { 350879c2813SVenkateswararao Jujjuri (JV) return -1; 351879c2813SVenkateswararao Jujjuri (JV) } 352879c2813SVenkateswararao Jujjuri (JV) do { 353879c2813SVenkateswararao Jujjuri (JV) tsize = read(fd, (void *)buf, bufsz); 354879c2813SVenkateswararao Jujjuri (JV) } while (tsize == -1 && errno == EINTR); 355*bec1e954SGreg Kurz close_preserve_errno(fd); 356b97400caSAneesh Kumar K.V } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) || 357b97400caSAneesh Kumar K.V (fs_ctx->export_flags & V9FS_SM_NONE)) { 358*bec1e954SGreg Kurz char *dirpath = g_path_get_dirname(fs_path->data); 359*bec1e954SGreg Kurz char *name = g_path_get_basename(fs_path->data); 360*bec1e954SGreg Kurz int dirfd; 361*bec1e954SGreg Kurz 362*bec1e954SGreg Kurz dirfd = local_opendir_nofollow(fs_ctx, dirpath); 363*bec1e954SGreg Kurz if (dirfd == -1) { 364*bec1e954SGreg Kurz goto out; 365*bec1e954SGreg Kurz } 366*bec1e954SGreg Kurz 367*bec1e954SGreg Kurz tsize = readlinkat(dirfd, name, buf, bufsz); 368*bec1e954SGreg Kurz close_preserve_errno(dirfd); 369*bec1e954SGreg Kurz out: 370*bec1e954SGreg Kurz g_free(name); 371*bec1e954SGreg Kurz g_free(dirpath); 372879c2813SVenkateswararao Jujjuri (JV) } 373879c2813SVenkateswararao Jujjuri (JV) return tsize; 374131dcb25SAnthony Liguori } 375131dcb25SAnthony Liguori 376cc720ddbSAneesh Kumar K.V static int local_close(FsContext *ctx, V9fsFidOpenState *fs) 377131dcb25SAnthony Liguori { 378cc720ddbSAneesh Kumar K.V return close(fs->fd); 379131dcb25SAnthony Liguori } 380131dcb25SAnthony Liguori 381cc720ddbSAneesh Kumar K.V static int local_closedir(FsContext *ctx, V9fsFidOpenState *fs) 382131dcb25SAnthony Liguori { 383f314ea4eSGreg Kurz return closedir(fs->dir.stream); 384131dcb25SAnthony Liguori } 3859f107513SAnthony Liguori 386cc720ddbSAneesh Kumar K.V static int local_open(FsContext *ctx, V9fsPath *fs_path, 387cc720ddbSAneesh Kumar K.V int flags, V9fsFidOpenState *fs) 388a6568fe2SAnthony Liguori { 38921328e1eSGreg Kurz int fd; 3902289be19SAneesh Kumar K.V 391996a0d76SGreg Kurz fd = local_open_nofollow(ctx, fs_path->data, flags, 0); 39221328e1eSGreg Kurz if (fd == -1) { 39321328e1eSGreg Kurz return -1; 39421328e1eSGreg Kurz } 39521328e1eSGreg Kurz fs->fd = fd; 396cc720ddbSAneesh Kumar K.V return fs->fd; 397a6568fe2SAnthony Liguori } 398a6568fe2SAnthony Liguori 399cc720ddbSAneesh Kumar K.V static int local_opendir(FsContext *ctx, 400cc720ddbSAneesh Kumar K.V V9fsPath *fs_path, V9fsFidOpenState *fs) 401a6568fe2SAnthony Liguori { 402996a0d76SGreg Kurz int dirfd; 40321328e1eSGreg Kurz DIR *stream; 4042289be19SAneesh Kumar K.V 405996a0d76SGreg Kurz dirfd = local_opendir_nofollow(ctx, fs_path->data); 406996a0d76SGreg Kurz if (dirfd == -1) { 407996a0d76SGreg Kurz return -1; 408996a0d76SGreg Kurz } 409996a0d76SGreg Kurz 410996a0d76SGreg Kurz stream = fdopendir(dirfd); 41121328e1eSGreg Kurz if (!stream) { 412cc720ddbSAneesh Kumar K.V return -1; 413cc720ddbSAneesh Kumar K.V } 41421328e1eSGreg Kurz fs->dir.stream = stream; 415cc720ddbSAneesh Kumar K.V return 0; 416a6568fe2SAnthony Liguori } 417a6568fe2SAnthony Liguori 418cc720ddbSAneesh Kumar K.V static void local_rewinddir(FsContext *ctx, V9fsFidOpenState *fs) 419a9231555SAnthony Liguori { 420f314ea4eSGreg Kurz rewinddir(fs->dir.stream); 421a9231555SAnthony Liguori } 422a9231555SAnthony Liguori 423cc720ddbSAneesh Kumar K.V static off_t local_telldir(FsContext *ctx, V9fsFidOpenState *fs) 424a9231555SAnthony Liguori { 425f314ea4eSGreg Kurz return telldir(fs->dir.stream); 426a9231555SAnthony Liguori } 427a9231555SAnthony Liguori 428635324e8SGreg Kurz static struct dirent *local_readdir(FsContext *ctx, V9fsFidOpenState *fs) 429a9231555SAnthony Liguori { 430635324e8SGreg Kurz struct dirent *entry; 4312c30dd74SAneesh Kumar K.V 4322c30dd74SAneesh Kumar K.V again: 433635324e8SGreg Kurz entry = readdir(fs->dir.stream); 434635324e8SGreg Kurz if (!entry) { 435635324e8SGreg Kurz return NULL; 436635324e8SGreg Kurz } 437635324e8SGreg Kurz 438840a1bf2SBastian Blank if (ctx->export_flags & V9FS_SM_MAPPED) { 439840a1bf2SBastian Blank entry->d_type = DT_UNKNOWN; 440840a1bf2SBastian Blank } else if (ctx->export_flags & V9FS_SM_MAPPED_FILE) { 441635324e8SGreg Kurz if (!strcmp(entry->d_name, VIRTFS_META_DIR)) { 4422c30dd74SAneesh Kumar K.V /* skp the meta data directory */ 4432c30dd74SAneesh Kumar K.V goto again; 4442c30dd74SAneesh Kumar K.V } 445840a1bf2SBastian Blank entry->d_type = DT_UNKNOWN; 4462c30dd74SAneesh Kumar K.V } 447635324e8SGreg Kurz 448635324e8SGreg Kurz return entry; 449a9231555SAnthony Liguori } 450a9231555SAnthony Liguori 451cc720ddbSAneesh Kumar K.V static void local_seekdir(FsContext *ctx, V9fsFidOpenState *fs, off_t off) 452a9231555SAnthony Liguori { 453f314ea4eSGreg Kurz seekdir(fs->dir.stream, off); 454a9231555SAnthony Liguori } 455a9231555SAnthony Liguori 456cc720ddbSAneesh Kumar K.V static ssize_t local_preadv(FsContext *ctx, V9fsFidOpenState *fs, 457cc720ddbSAneesh Kumar K.V const struct iovec *iov, 45856d15a53SSanchit Garg int iovcnt, off_t offset) 459a9231555SAnthony Liguori { 46056d15a53SSanchit Garg #ifdef CONFIG_PREADV 461cc720ddbSAneesh Kumar K.V return preadv(fs->fd, iov, iovcnt, offset); 46256d15a53SSanchit Garg #else 463cc720ddbSAneesh Kumar K.V int err = lseek(fs->fd, offset, SEEK_SET); 46456d15a53SSanchit Garg if (err == -1) { 46556d15a53SSanchit Garg return err; 46656d15a53SSanchit Garg } else { 467cc720ddbSAneesh Kumar K.V return readv(fs->fd, iov, iovcnt); 468a9231555SAnthony Liguori } 46956d15a53SSanchit Garg #endif 470a9231555SAnthony Liguori } 471a9231555SAnthony Liguori 472cc720ddbSAneesh Kumar K.V static ssize_t local_pwritev(FsContext *ctx, V9fsFidOpenState *fs, 473cc720ddbSAneesh Kumar K.V const struct iovec *iov, 47456d15a53SSanchit Garg int iovcnt, off_t offset) 4758449360cSAnthony Liguori { 4766fe76accSGreg Kurz ssize_t ret; 47756d15a53SSanchit Garg #ifdef CONFIG_PREADV 478cc720ddbSAneesh Kumar K.V ret = pwritev(fs->fd, iov, iovcnt, offset); 47956d15a53SSanchit Garg #else 480cc720ddbSAneesh Kumar K.V int err = lseek(fs->fd, offset, SEEK_SET); 48156d15a53SSanchit Garg if (err == -1) { 48256d15a53SSanchit Garg return err; 48356d15a53SSanchit Garg } else { 484cc720ddbSAneesh Kumar K.V ret = writev(fs->fd, iov, iovcnt); 4858449360cSAnthony Liguori } 48656d15a53SSanchit Garg #endif 487d3ab98e6SAneesh Kumar K.V #ifdef CONFIG_SYNC_FILE_RANGE 488d3ab98e6SAneesh Kumar K.V if (ret > 0 && ctx->export_flags & V9FS_IMMEDIATE_WRITEOUT) { 489d3ab98e6SAneesh Kumar K.V /* 490d3ab98e6SAneesh Kumar K.V * Initiate a writeback. This is not a data integrity sync. 491d3ab98e6SAneesh Kumar K.V * We want to ensure that we don't leave dirty pages in the cache 492d3ab98e6SAneesh Kumar K.V * after write when writeout=immediate is sepcified. 493d3ab98e6SAneesh Kumar K.V */ 494cc720ddbSAneesh Kumar K.V sync_file_range(fs->fd, offset, ret, 495d3ab98e6SAneesh Kumar K.V SYNC_FILE_RANGE_WAIT_BEFORE | SYNC_FILE_RANGE_WRITE); 496d3ab98e6SAneesh Kumar K.V } 497d3ab98e6SAneesh Kumar K.V #endif 498d3ab98e6SAneesh Kumar K.V return ret; 49956d15a53SSanchit Garg } 5008449360cSAnthony Liguori 5012289be19SAneesh Kumar K.V static int local_chmod(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp) 502c494dd6fSAnthony Liguori { 5034fa4ce71SChen Gang char *buffer; 5044fa4ce71SChen Gang int ret = -1; 5052289be19SAneesh Kumar K.V char *path = fs_path->data; 5062289be19SAneesh Kumar K.V 507b97400caSAneesh Kumar K.V if (fs_ctx->export_flags & V9FS_SM_MAPPED) { 5084fa4ce71SChen Gang buffer = rpath(fs_ctx, path); 5094fa4ce71SChen Gang ret = local_set_xattr(buffer, credp); 5104fa4ce71SChen Gang g_free(buffer); 5112c30dd74SAneesh Kumar K.V } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) { 5122c30dd74SAneesh Kumar K.V return local_set_mapped_file_attr(fs_ctx, path, credp); 513b97400caSAneesh Kumar K.V } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) || 514b97400caSAneesh Kumar K.V (fs_ctx->export_flags & V9FS_SM_NONE)) { 5154fa4ce71SChen Gang buffer = rpath(fs_ctx, path); 5164fa4ce71SChen Gang ret = chmod(buffer, credp->fc_mode); 5174fa4ce71SChen Gang g_free(buffer); 518e95ead32SVenkateswararao Jujjuri (JV) } 5194fa4ce71SChen Gang return ret; 520c494dd6fSAnthony Liguori } 521c494dd6fSAnthony Liguori 5222289be19SAneesh Kumar K.V static int local_mknod(FsContext *fs_ctx, V9fsPath *dir_path, 5232289be19SAneesh Kumar K.V const char *name, FsCred *credp) 524c494dd6fSAnthony Liguori { 5252289be19SAneesh Kumar K.V char *path; 5261c293312SVenkateswararao Jujjuri (JV) int err = -1; 5271c293312SVenkateswararao Jujjuri (JV) int serrno = 0; 5282289be19SAneesh Kumar K.V V9fsString fullname; 5294ed7b2c3SStefan Weil char *buffer = NULL; 5301c293312SVenkateswararao Jujjuri (JV) 5312289be19SAneesh Kumar K.V v9fs_string_init(&fullname); 5322289be19SAneesh Kumar K.V v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name); 5332289be19SAneesh Kumar K.V path = fullname.data; 5342289be19SAneesh Kumar K.V 5351c293312SVenkateswararao Jujjuri (JV) /* Determine the security model */ 536b97400caSAneesh Kumar K.V if (fs_ctx->export_flags & V9FS_SM_MAPPED) { 5374fa4ce71SChen Gang buffer = rpath(fs_ctx, path); 5384fa4ce71SChen Gang err = mknod(buffer, SM_LOCAL_MODE_BITS|S_IFREG, 0); 5391c293312SVenkateswararao Jujjuri (JV) if (err == -1) { 5402289be19SAneesh Kumar K.V goto out; 5411c293312SVenkateswararao Jujjuri (JV) } 5424fa4ce71SChen Gang err = local_set_xattr(buffer, credp); 5431c293312SVenkateswararao Jujjuri (JV) if (err == -1) { 5441c293312SVenkateswararao Jujjuri (JV) serrno = errno; 5451c293312SVenkateswararao Jujjuri (JV) goto err_end; 5461c293312SVenkateswararao Jujjuri (JV) } 5472c30dd74SAneesh Kumar K.V } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) { 5482c30dd74SAneesh Kumar K.V 5494fa4ce71SChen Gang buffer = rpath(fs_ctx, path); 5504fa4ce71SChen Gang err = mknod(buffer, SM_LOCAL_MODE_BITS|S_IFREG, 0); 5512c30dd74SAneesh Kumar K.V if (err == -1) { 5522c30dd74SAneesh Kumar K.V goto out; 5532c30dd74SAneesh Kumar K.V } 5542c30dd74SAneesh Kumar K.V err = local_set_mapped_file_attr(fs_ctx, path, credp); 5552c30dd74SAneesh Kumar K.V if (err == -1) { 5562c30dd74SAneesh Kumar K.V serrno = errno; 5572c30dd74SAneesh Kumar K.V goto err_end; 5582c30dd74SAneesh Kumar K.V } 559b97400caSAneesh Kumar K.V } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) || 560b97400caSAneesh Kumar K.V (fs_ctx->export_flags & V9FS_SM_NONE)) { 5614fa4ce71SChen Gang buffer = rpath(fs_ctx, path); 5624fa4ce71SChen Gang err = mknod(buffer, credp->fc_mode, credp->fc_rdev); 5631c293312SVenkateswararao Jujjuri (JV) if (err == -1) { 5642289be19SAneesh Kumar K.V goto out; 5651c293312SVenkateswararao Jujjuri (JV) } 5661c293312SVenkateswararao Jujjuri (JV) err = local_post_create_passthrough(fs_ctx, path, credp); 5671c293312SVenkateswararao Jujjuri (JV) if (err == -1) { 5681c293312SVenkateswararao Jujjuri (JV) serrno = errno; 5691c293312SVenkateswararao Jujjuri (JV) goto err_end; 5701c293312SVenkateswararao Jujjuri (JV) } 5711c293312SVenkateswararao Jujjuri (JV) } 5722289be19SAneesh Kumar K.V goto out; 5731c293312SVenkateswararao Jujjuri (JV) 5741c293312SVenkateswararao Jujjuri (JV) err_end: 5754fa4ce71SChen Gang remove(buffer); 5761c293312SVenkateswararao Jujjuri (JV) errno = serrno; 5772289be19SAneesh Kumar K.V out: 5784ed7b2c3SStefan Weil g_free(buffer); 5792289be19SAneesh Kumar K.V v9fs_string_free(&fullname); 5801c293312SVenkateswararao Jujjuri (JV) return err; 581c494dd6fSAnthony Liguori } 582c494dd6fSAnthony Liguori 5832289be19SAneesh Kumar K.V static int local_mkdir(FsContext *fs_ctx, V9fsPath *dir_path, 5842289be19SAneesh Kumar K.V const char *name, FsCred *credp) 585c494dd6fSAnthony Liguori { 5862289be19SAneesh Kumar K.V char *path; 58700ec5c37SVenkateswararao Jujjuri (JV) int err = -1; 58800ec5c37SVenkateswararao Jujjuri (JV) int serrno = 0; 5892289be19SAneesh Kumar K.V V9fsString fullname; 5904ed7b2c3SStefan Weil char *buffer = NULL; 59100ec5c37SVenkateswararao Jujjuri (JV) 5922289be19SAneesh Kumar K.V v9fs_string_init(&fullname); 5932289be19SAneesh Kumar K.V v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name); 5942289be19SAneesh Kumar K.V path = fullname.data; 5952289be19SAneesh Kumar K.V 59600ec5c37SVenkateswararao Jujjuri (JV) /* Determine the security model */ 597b97400caSAneesh Kumar K.V if (fs_ctx->export_flags & V9FS_SM_MAPPED) { 5984fa4ce71SChen Gang buffer = rpath(fs_ctx, path); 5994fa4ce71SChen Gang err = mkdir(buffer, SM_LOCAL_DIR_MODE_BITS); 60000ec5c37SVenkateswararao Jujjuri (JV) if (err == -1) { 6012289be19SAneesh Kumar K.V goto out; 60200ec5c37SVenkateswararao Jujjuri (JV) } 60300ec5c37SVenkateswararao Jujjuri (JV) credp->fc_mode = credp->fc_mode|S_IFDIR; 6044fa4ce71SChen Gang err = local_set_xattr(buffer, credp); 60500ec5c37SVenkateswararao Jujjuri (JV) if (err == -1) { 60600ec5c37SVenkateswararao Jujjuri (JV) serrno = errno; 60700ec5c37SVenkateswararao Jujjuri (JV) goto err_end; 60800ec5c37SVenkateswararao Jujjuri (JV) } 6092c30dd74SAneesh Kumar K.V } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) { 6104fa4ce71SChen Gang buffer = rpath(fs_ctx, path); 6114fa4ce71SChen Gang err = mkdir(buffer, SM_LOCAL_DIR_MODE_BITS); 6122c30dd74SAneesh Kumar K.V if (err == -1) { 6132c30dd74SAneesh Kumar K.V goto out; 6142c30dd74SAneesh Kumar K.V } 6152c30dd74SAneesh Kumar K.V credp->fc_mode = credp->fc_mode|S_IFDIR; 6162c30dd74SAneesh Kumar K.V err = local_set_mapped_file_attr(fs_ctx, path, credp); 6172c30dd74SAneesh Kumar K.V if (err == -1) { 6182c30dd74SAneesh Kumar K.V serrno = errno; 6192c30dd74SAneesh Kumar K.V goto err_end; 6202c30dd74SAneesh Kumar K.V } 621b97400caSAneesh Kumar K.V } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) || 622b97400caSAneesh Kumar K.V (fs_ctx->export_flags & V9FS_SM_NONE)) { 6234fa4ce71SChen Gang buffer = rpath(fs_ctx, path); 6244fa4ce71SChen Gang err = mkdir(buffer, credp->fc_mode); 62500ec5c37SVenkateswararao Jujjuri (JV) if (err == -1) { 6262289be19SAneesh Kumar K.V goto out; 62700ec5c37SVenkateswararao Jujjuri (JV) } 62800ec5c37SVenkateswararao Jujjuri (JV) err = local_post_create_passthrough(fs_ctx, path, credp); 62900ec5c37SVenkateswararao Jujjuri (JV) if (err == -1) { 63000ec5c37SVenkateswararao Jujjuri (JV) serrno = errno; 63100ec5c37SVenkateswararao Jujjuri (JV) goto err_end; 63200ec5c37SVenkateswararao Jujjuri (JV) } 63300ec5c37SVenkateswararao Jujjuri (JV) } 6342289be19SAneesh Kumar K.V goto out; 63500ec5c37SVenkateswararao Jujjuri (JV) 63600ec5c37SVenkateswararao Jujjuri (JV) err_end: 6374fa4ce71SChen Gang remove(buffer); 63800ec5c37SVenkateswararao Jujjuri (JV) errno = serrno; 6392289be19SAneesh Kumar K.V out: 6404ed7b2c3SStefan Weil g_free(buffer); 6412289be19SAneesh Kumar K.V v9fs_string_free(&fullname); 64200ec5c37SVenkateswararao Jujjuri (JV) return err; 643c494dd6fSAnthony Liguori } 644c494dd6fSAnthony Liguori 6458b888272SAneesh Kumar K.V static int local_fstat(FsContext *fs_ctx, int fid_type, 646cc720ddbSAneesh Kumar K.V V9fsFidOpenState *fs, struct stat *stbuf) 647c494dd6fSAnthony Liguori { 6488b888272SAneesh Kumar K.V int err, fd; 6498b888272SAneesh Kumar K.V 6508b888272SAneesh Kumar K.V if (fid_type == P9_FID_DIR) { 651f314ea4eSGreg Kurz fd = dirfd(fs->dir.stream); 6528b888272SAneesh Kumar K.V } else { 6538b888272SAneesh Kumar K.V fd = fs->fd; 6548b888272SAneesh Kumar K.V } 6558b888272SAneesh Kumar K.V 6568b888272SAneesh Kumar K.V err = fstat(fd, stbuf); 6571237ad76SVenkateswararao Jujjuri (JV) if (err) { 6581237ad76SVenkateswararao Jujjuri (JV) return err; 6591237ad76SVenkateswararao Jujjuri (JV) } 660b97400caSAneesh Kumar K.V if (fs_ctx->export_flags & V9FS_SM_MAPPED) { 6611237ad76SVenkateswararao Jujjuri (JV) /* Actual credentials are part of extended attrs */ 6621237ad76SVenkateswararao Jujjuri (JV) uid_t tmp_uid; 6631237ad76SVenkateswararao Jujjuri (JV) gid_t tmp_gid; 6641237ad76SVenkateswararao Jujjuri (JV) mode_t tmp_mode; 6651237ad76SVenkateswararao Jujjuri (JV) dev_t tmp_dev; 6661237ad76SVenkateswararao Jujjuri (JV) 667f8ad4a89SAneesh Kumar K.V if (fgetxattr(fd, "user.virtfs.uid", &tmp_uid, sizeof(uid_t)) > 0) { 668f8ad4a89SAneesh Kumar K.V stbuf->st_uid = le32_to_cpu(tmp_uid); 6691237ad76SVenkateswararao Jujjuri (JV) } 670f8ad4a89SAneesh Kumar K.V if (fgetxattr(fd, "user.virtfs.gid", &tmp_gid, sizeof(gid_t)) > 0) { 671f8ad4a89SAneesh Kumar K.V stbuf->st_gid = le32_to_cpu(tmp_gid); 6721237ad76SVenkateswararao Jujjuri (JV) } 673f8ad4a89SAneesh Kumar K.V if (fgetxattr(fd, "user.virtfs.mode", &tmp_mode, sizeof(mode_t)) > 0) { 674f8ad4a89SAneesh Kumar K.V stbuf->st_mode = le32_to_cpu(tmp_mode); 6751237ad76SVenkateswararao Jujjuri (JV) } 676f8ad4a89SAneesh Kumar K.V if (fgetxattr(fd, "user.virtfs.rdev", &tmp_dev, sizeof(dev_t)) > 0) { 677f8ad4a89SAneesh Kumar K.V stbuf->st_rdev = le64_to_cpu(tmp_dev); 6781237ad76SVenkateswararao Jujjuri (JV) } 6792c30dd74SAneesh Kumar K.V } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) { 6802c30dd74SAneesh Kumar K.V errno = EOPNOTSUPP; 6812c30dd74SAneesh Kumar K.V return -1; 6821237ad76SVenkateswararao Jujjuri (JV) } 6831237ad76SVenkateswararao Jujjuri (JV) return err; 684c494dd6fSAnthony Liguori } 685c494dd6fSAnthony Liguori 6862289be19SAneesh Kumar K.V static int local_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name, 687cc720ddbSAneesh Kumar K.V int flags, FsCred *credp, V9fsFidOpenState *fs) 688c494dd6fSAnthony Liguori { 6892289be19SAneesh Kumar K.V char *path; 6904750a96fSVenkateswararao Jujjuri (JV) int fd = -1; 6914750a96fSVenkateswararao Jujjuri (JV) int err = -1; 6924750a96fSVenkateswararao Jujjuri (JV) int serrno = 0; 6932289be19SAneesh Kumar K.V V9fsString fullname; 6944ed7b2c3SStefan Weil char *buffer = NULL; 6954750a96fSVenkateswararao Jujjuri (JV) 6960ceb092eSAneesh Kumar K.V /* 6970ceb092eSAneesh Kumar K.V * Mark all the open to not follow symlinks 6980ceb092eSAneesh Kumar K.V */ 6990ceb092eSAneesh Kumar K.V flags |= O_NOFOLLOW; 7000ceb092eSAneesh Kumar K.V 7012289be19SAneesh Kumar K.V v9fs_string_init(&fullname); 7022289be19SAneesh Kumar K.V v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name); 7032289be19SAneesh Kumar K.V path = fullname.data; 7042289be19SAneesh Kumar K.V 7054750a96fSVenkateswararao Jujjuri (JV) /* Determine the security model */ 706b97400caSAneesh Kumar K.V if (fs_ctx->export_flags & V9FS_SM_MAPPED) { 7074fa4ce71SChen Gang buffer = rpath(fs_ctx, path); 7084fa4ce71SChen Gang fd = open(buffer, flags, SM_LOCAL_MODE_BITS); 7094750a96fSVenkateswararao Jujjuri (JV) if (fd == -1) { 7102289be19SAneesh Kumar K.V err = fd; 7112289be19SAneesh Kumar K.V goto out; 7124750a96fSVenkateswararao Jujjuri (JV) } 7134750a96fSVenkateswararao Jujjuri (JV) credp->fc_mode = credp->fc_mode|S_IFREG; 7144750a96fSVenkateswararao Jujjuri (JV) /* Set cleint credentials in xattr */ 7154fa4ce71SChen Gang err = local_set_xattr(buffer, credp); 7164750a96fSVenkateswararao Jujjuri (JV) if (err == -1) { 7174750a96fSVenkateswararao Jujjuri (JV) serrno = errno; 7184750a96fSVenkateswararao Jujjuri (JV) goto err_end; 7194750a96fSVenkateswararao Jujjuri (JV) } 7202c30dd74SAneesh Kumar K.V } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) { 7214fa4ce71SChen Gang buffer = rpath(fs_ctx, path); 7224fa4ce71SChen Gang fd = open(buffer, flags, SM_LOCAL_MODE_BITS); 7232c30dd74SAneesh Kumar K.V if (fd == -1) { 7242c30dd74SAneesh Kumar K.V err = fd; 7252c30dd74SAneesh Kumar K.V goto out; 7262c30dd74SAneesh Kumar K.V } 7272c30dd74SAneesh Kumar K.V credp->fc_mode = credp->fc_mode|S_IFREG; 7282c30dd74SAneesh Kumar K.V /* Set client credentials in .virtfs_metadata directory files */ 7292c30dd74SAneesh Kumar K.V err = local_set_mapped_file_attr(fs_ctx, path, credp); 7302c30dd74SAneesh Kumar K.V if (err == -1) { 7312c30dd74SAneesh Kumar K.V serrno = errno; 7322c30dd74SAneesh Kumar K.V goto err_end; 7332c30dd74SAneesh Kumar K.V } 734b97400caSAneesh Kumar K.V } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) || 735b97400caSAneesh Kumar K.V (fs_ctx->export_flags & V9FS_SM_NONE)) { 7364fa4ce71SChen Gang buffer = rpath(fs_ctx, path); 7374fa4ce71SChen Gang fd = open(buffer, flags, credp->fc_mode); 7384750a96fSVenkateswararao Jujjuri (JV) if (fd == -1) { 7392289be19SAneesh Kumar K.V err = fd; 7402289be19SAneesh Kumar K.V goto out; 7414750a96fSVenkateswararao Jujjuri (JV) } 7424750a96fSVenkateswararao Jujjuri (JV) err = local_post_create_passthrough(fs_ctx, path, credp); 7434750a96fSVenkateswararao Jujjuri (JV) if (err == -1) { 7444750a96fSVenkateswararao Jujjuri (JV) serrno = errno; 7454750a96fSVenkateswararao Jujjuri (JV) goto err_end; 7464750a96fSVenkateswararao Jujjuri (JV) } 7474750a96fSVenkateswararao Jujjuri (JV) } 7482289be19SAneesh Kumar K.V err = fd; 749cc720ddbSAneesh Kumar K.V fs->fd = fd; 7502289be19SAneesh Kumar K.V goto out; 7514750a96fSVenkateswararao Jujjuri (JV) 7524750a96fSVenkateswararao Jujjuri (JV) err_end: 7534750a96fSVenkateswararao Jujjuri (JV) close(fd); 7544fa4ce71SChen Gang remove(buffer); 7554750a96fSVenkateswararao Jujjuri (JV) errno = serrno; 7562289be19SAneesh Kumar K.V out: 7574ed7b2c3SStefan Weil g_free(buffer); 7582289be19SAneesh Kumar K.V v9fs_string_free(&fullname); 7594750a96fSVenkateswararao Jujjuri (JV) return err; 760c494dd6fSAnthony Liguori } 761c494dd6fSAnthony Liguori 762758e8e38SVenkateswararao Jujjuri (JV) 763879c2813SVenkateswararao Jujjuri (JV) static int local_symlink(FsContext *fs_ctx, const char *oldpath, 7642289be19SAneesh Kumar K.V V9fsPath *dir_path, const char *name, FsCred *credp) 765c494dd6fSAnthony Liguori { 766879c2813SVenkateswararao Jujjuri (JV) int err = -1; 767879c2813SVenkateswararao Jujjuri (JV) int serrno = 0; 7682289be19SAneesh Kumar K.V char *newpath; 7692289be19SAneesh Kumar K.V V9fsString fullname; 7704ed7b2c3SStefan Weil char *buffer = NULL; 771879c2813SVenkateswararao Jujjuri (JV) 7722289be19SAneesh Kumar K.V v9fs_string_init(&fullname); 7732289be19SAneesh Kumar K.V v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name); 7742289be19SAneesh Kumar K.V newpath = fullname.data; 7752289be19SAneesh Kumar K.V 776879c2813SVenkateswararao Jujjuri (JV) /* Determine the security model */ 777b97400caSAneesh Kumar K.V if (fs_ctx->export_flags & V9FS_SM_MAPPED) { 778879c2813SVenkateswararao Jujjuri (JV) int fd; 779879c2813SVenkateswararao Jujjuri (JV) ssize_t oldpath_size, write_size; 7804fa4ce71SChen Gang buffer = rpath(fs_ctx, newpath); 7814fa4ce71SChen Gang fd = open(buffer, O_CREAT|O_EXCL|O_RDWR|O_NOFOLLOW, SM_LOCAL_MODE_BITS); 782879c2813SVenkateswararao Jujjuri (JV) if (fd == -1) { 7832289be19SAneesh Kumar K.V err = fd; 7842289be19SAneesh Kumar K.V goto out; 785879c2813SVenkateswararao Jujjuri (JV) } 786879c2813SVenkateswararao Jujjuri (JV) /* Write the oldpath (target) to the file. */ 787f35bde2fSHarsh Prateek Bora oldpath_size = strlen(oldpath); 788879c2813SVenkateswararao Jujjuri (JV) do { 789879c2813SVenkateswararao Jujjuri (JV) write_size = write(fd, (void *)oldpath, oldpath_size); 790879c2813SVenkateswararao Jujjuri (JV) } while (write_size == -1 && errno == EINTR); 791879c2813SVenkateswararao Jujjuri (JV) 792879c2813SVenkateswararao Jujjuri (JV) if (write_size != oldpath_size) { 793879c2813SVenkateswararao Jujjuri (JV) serrno = errno; 794879c2813SVenkateswararao Jujjuri (JV) close(fd); 795879c2813SVenkateswararao Jujjuri (JV) err = -1; 796879c2813SVenkateswararao Jujjuri (JV) goto err_end; 797879c2813SVenkateswararao Jujjuri (JV) } 798879c2813SVenkateswararao Jujjuri (JV) close(fd); 799879c2813SVenkateswararao Jujjuri (JV) /* Set cleint credentials in symlink's xattr */ 800879c2813SVenkateswararao Jujjuri (JV) credp->fc_mode = credp->fc_mode|S_IFLNK; 8014fa4ce71SChen Gang err = local_set_xattr(buffer, credp); 802879c2813SVenkateswararao Jujjuri (JV) if (err == -1) { 803879c2813SVenkateswararao Jujjuri (JV) serrno = errno; 804879c2813SVenkateswararao Jujjuri (JV) goto err_end; 805879c2813SVenkateswararao Jujjuri (JV) } 8062c30dd74SAneesh Kumar K.V } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) { 8072c30dd74SAneesh Kumar K.V int fd; 8082c30dd74SAneesh Kumar K.V ssize_t oldpath_size, write_size; 8094fa4ce71SChen Gang buffer = rpath(fs_ctx, newpath); 8104fa4ce71SChen Gang fd = open(buffer, O_CREAT|O_EXCL|O_RDWR|O_NOFOLLOW, SM_LOCAL_MODE_BITS); 8112c30dd74SAneesh Kumar K.V if (fd == -1) { 8122c30dd74SAneesh Kumar K.V err = fd; 8132c30dd74SAneesh Kumar K.V goto out; 8142c30dd74SAneesh Kumar K.V } 8152c30dd74SAneesh Kumar K.V /* Write the oldpath (target) to the file. */ 8162c30dd74SAneesh Kumar K.V oldpath_size = strlen(oldpath); 8172c30dd74SAneesh Kumar K.V do { 8182c30dd74SAneesh Kumar K.V write_size = write(fd, (void *)oldpath, oldpath_size); 8192c30dd74SAneesh Kumar K.V } while (write_size == -1 && errno == EINTR); 8202c30dd74SAneesh Kumar K.V 8212c30dd74SAneesh Kumar K.V if (write_size != oldpath_size) { 8222c30dd74SAneesh Kumar K.V serrno = errno; 8232c30dd74SAneesh Kumar K.V close(fd); 8242c30dd74SAneesh Kumar K.V err = -1; 8252c30dd74SAneesh Kumar K.V goto err_end; 8262c30dd74SAneesh Kumar K.V } 8272c30dd74SAneesh Kumar K.V close(fd); 8282c30dd74SAneesh Kumar K.V /* Set cleint credentials in symlink's xattr */ 8292c30dd74SAneesh Kumar K.V credp->fc_mode = credp->fc_mode|S_IFLNK; 8302c30dd74SAneesh Kumar K.V err = local_set_mapped_file_attr(fs_ctx, newpath, credp); 8312c30dd74SAneesh Kumar K.V if (err == -1) { 8322c30dd74SAneesh Kumar K.V serrno = errno; 8332c30dd74SAneesh Kumar K.V goto err_end; 8342c30dd74SAneesh Kumar K.V } 835b97400caSAneesh Kumar K.V } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) || 836b97400caSAneesh Kumar K.V (fs_ctx->export_flags & V9FS_SM_NONE)) { 8374fa4ce71SChen Gang buffer = rpath(fs_ctx, newpath); 8384fa4ce71SChen Gang err = symlink(oldpath, buffer); 839879c2813SVenkateswararao Jujjuri (JV) if (err) { 8402289be19SAneesh Kumar K.V goto out; 841879c2813SVenkateswararao Jujjuri (JV) } 8424fa4ce71SChen Gang err = lchown(buffer, credp->fc_uid, credp->fc_gid); 843879c2813SVenkateswararao Jujjuri (JV) if (err == -1) { 84412848bfcSAneesh Kumar K.V /* 84512848bfcSAneesh Kumar K.V * If we fail to change ownership and if we are 84612848bfcSAneesh Kumar K.V * using security model none. Ignore the error 84712848bfcSAneesh Kumar K.V */ 848b97400caSAneesh Kumar K.V if ((fs_ctx->export_flags & V9FS_SEC_MASK) != V9FS_SM_NONE) { 849879c2813SVenkateswararao Jujjuri (JV) serrno = errno; 850879c2813SVenkateswararao Jujjuri (JV) goto err_end; 85112848bfcSAneesh Kumar K.V } else 85212848bfcSAneesh Kumar K.V err = 0; 853879c2813SVenkateswararao Jujjuri (JV) } 854879c2813SVenkateswararao Jujjuri (JV) } 8552289be19SAneesh Kumar K.V goto out; 856879c2813SVenkateswararao Jujjuri (JV) 857879c2813SVenkateswararao Jujjuri (JV) err_end: 8584fa4ce71SChen Gang remove(buffer); 859879c2813SVenkateswararao Jujjuri (JV) errno = serrno; 8602289be19SAneesh Kumar K.V out: 8614ed7b2c3SStefan Weil g_free(buffer); 8622289be19SAneesh Kumar K.V v9fs_string_free(&fullname); 863879c2813SVenkateswararao Jujjuri (JV) return err; 864c494dd6fSAnthony Liguori } 865c494dd6fSAnthony Liguori 8662289be19SAneesh Kumar K.V static int local_link(FsContext *ctx, V9fsPath *oldpath, 8672289be19SAneesh Kumar K.V V9fsPath *dirpath, const char *name) 868c494dd6fSAnthony Liguori { 8692289be19SAneesh Kumar K.V int ret; 8702289be19SAneesh Kumar K.V V9fsString newpath; 8714fa4ce71SChen Gang char *buffer, *buffer1; 872c494dd6fSAnthony Liguori 8732289be19SAneesh Kumar K.V v9fs_string_init(&newpath); 8742289be19SAneesh Kumar K.V v9fs_string_sprintf(&newpath, "%s/%s", dirpath->data, name); 8752289be19SAneesh Kumar K.V 8764fa4ce71SChen Gang buffer = rpath(ctx, oldpath->data); 8774fa4ce71SChen Gang buffer1 = rpath(ctx, newpath.data); 8784fa4ce71SChen Gang ret = link(buffer, buffer1); 8794fa4ce71SChen Gang g_free(buffer); 8804fa4ce71SChen Gang g_free(buffer1); 8812c30dd74SAneesh Kumar K.V 8822c30dd74SAneesh Kumar K.V /* now link the virtfs_metadata files */ 8832c30dd74SAneesh Kumar K.V if (!ret && (ctx->export_flags & V9FS_SM_MAPPED_FILE)) { 8842c30dd74SAneesh Kumar K.V /* Link the .virtfs_metadata files. Create the metada directory */ 8852c30dd74SAneesh Kumar K.V ret = local_create_mapped_attr_dir(ctx, newpath.data); 8862c30dd74SAneesh Kumar K.V if (ret < 0) { 8872c30dd74SAneesh Kumar K.V goto err_out; 8882c30dd74SAneesh Kumar K.V } 8894fa4ce71SChen Gang buffer = local_mapped_attr_path(ctx, oldpath->data); 8904fa4ce71SChen Gang buffer1 = local_mapped_attr_path(ctx, newpath.data); 8914fa4ce71SChen Gang ret = link(buffer, buffer1); 8924fa4ce71SChen Gang g_free(buffer); 8934fa4ce71SChen Gang g_free(buffer1); 8942c30dd74SAneesh Kumar K.V if (ret < 0 && errno != ENOENT) { 8952c30dd74SAneesh Kumar K.V goto err_out; 8962c30dd74SAneesh Kumar K.V } 8972c30dd74SAneesh Kumar K.V } 8982c30dd74SAneesh Kumar K.V err_out: 8992289be19SAneesh Kumar K.V v9fs_string_free(&newpath); 9002289be19SAneesh Kumar K.V return ret; 901c494dd6fSAnthony Liguori } 902c494dd6fSAnthony Liguori 9032289be19SAneesh Kumar K.V static int local_truncate(FsContext *ctx, V9fsPath *fs_path, off_t size) 9048cf89e00SAnthony Liguori { 905ac125d99SGreg Kurz int fd, ret; 9062289be19SAneesh Kumar K.V 907ac125d99SGreg Kurz fd = local_open_nofollow(ctx, fs_path->data, O_WRONLY, 0); 908ac125d99SGreg Kurz if (fd == -1) { 909ac125d99SGreg Kurz return -1; 910ac125d99SGreg Kurz } 911ac125d99SGreg Kurz ret = ftruncate(fd, size); 912ac125d99SGreg Kurz close_preserve_errno(fd); 9134fa4ce71SChen Gang return ret; 9148cf89e00SAnthony Liguori } 9158cf89e00SAnthony Liguori 9168cf89e00SAnthony Liguori static int local_rename(FsContext *ctx, const char *oldpath, 9178cf89e00SAnthony Liguori const char *newpath) 9188cf89e00SAnthony Liguori { 9192c30dd74SAneesh Kumar K.V int err; 9204fa4ce71SChen Gang char *buffer, *buffer1; 9218cf89e00SAnthony Liguori 9222c30dd74SAneesh Kumar K.V if (ctx->export_flags & V9FS_SM_MAPPED_FILE) { 9232c30dd74SAneesh Kumar K.V err = local_create_mapped_attr_dir(ctx, newpath); 9242c30dd74SAneesh Kumar K.V if (err < 0) { 9252c30dd74SAneesh Kumar K.V return err; 9262c30dd74SAneesh Kumar K.V } 9272c30dd74SAneesh Kumar K.V /* rename the .virtfs_metadata files */ 9284fa4ce71SChen Gang buffer = local_mapped_attr_path(ctx, oldpath); 9294fa4ce71SChen Gang buffer1 = local_mapped_attr_path(ctx, newpath); 9304fa4ce71SChen Gang err = rename(buffer, buffer1); 9314fa4ce71SChen Gang g_free(buffer); 9324fa4ce71SChen Gang g_free(buffer1); 9332c30dd74SAneesh Kumar K.V if (err < 0 && errno != ENOENT) { 9342c30dd74SAneesh Kumar K.V return err; 9352c30dd74SAneesh Kumar K.V } 9362c30dd74SAneesh Kumar K.V } 9374fa4ce71SChen Gang 9384fa4ce71SChen Gang buffer = rpath(ctx, oldpath); 9394fa4ce71SChen Gang buffer1 = rpath(ctx, newpath); 9404fa4ce71SChen Gang err = rename(buffer, buffer1); 9414fa4ce71SChen Gang g_free(buffer); 9424fa4ce71SChen Gang g_free(buffer1); 9434fa4ce71SChen Gang return err; 9448cf89e00SAnthony Liguori } 9458cf89e00SAnthony Liguori 9462289be19SAneesh Kumar K.V static int local_chown(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp) 9478cf89e00SAnthony Liguori { 9484fa4ce71SChen Gang char *buffer; 9494fa4ce71SChen Gang int ret = -1; 9502289be19SAneesh Kumar K.V char *path = fs_path->data; 9512289be19SAneesh Kumar K.V 952c79ce737SSripathi Kodi if ((credp->fc_uid == -1 && credp->fc_gid == -1) || 95317b1971fSAneesh Kumar K.V (fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) || 95417b1971fSAneesh Kumar K.V (fs_ctx->export_flags & V9FS_SM_NONE)) { 9554fa4ce71SChen Gang buffer = rpath(fs_ctx, path); 9564fa4ce71SChen Gang ret = lchown(buffer, credp->fc_uid, credp->fc_gid); 9574fa4ce71SChen Gang g_free(buffer); 958b97400caSAneesh Kumar K.V } else if (fs_ctx->export_flags & V9FS_SM_MAPPED) { 9594fa4ce71SChen Gang buffer = rpath(fs_ctx, path); 9604fa4ce71SChen Gang ret = local_set_xattr(buffer, credp); 9614fa4ce71SChen Gang g_free(buffer); 9622c30dd74SAneesh Kumar K.V } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) { 9632c30dd74SAneesh Kumar K.V return local_set_mapped_file_attr(fs_ctx, path, credp); 964f7613beeSVenkateswararao Jujjuri (JV) } 9654fa4ce71SChen Gang return ret; 9668cf89e00SAnthony Liguori } 9678cf89e00SAnthony Liguori 9682289be19SAneesh Kumar K.V static int local_utimensat(FsContext *s, V9fsPath *fs_path, 96974bc02b2SM. Mohan Kumar const struct timespec *buf) 9708cf89e00SAnthony Liguori { 971a33eda0dSGreg Kurz char *dirpath = g_path_get_dirname(fs_path->data); 972a33eda0dSGreg Kurz char *name = g_path_get_basename(fs_path->data); 973a33eda0dSGreg Kurz int dirfd, ret = -1; 9742289be19SAneesh Kumar K.V 975a33eda0dSGreg Kurz dirfd = local_opendir_nofollow(s, dirpath); 976a33eda0dSGreg Kurz if (dirfd == -1) { 977a33eda0dSGreg Kurz goto out; 978a33eda0dSGreg Kurz } 979a33eda0dSGreg Kurz 980a33eda0dSGreg Kurz ret = utimensat(dirfd, name, buf, AT_SYMLINK_NOFOLLOW); 981a33eda0dSGreg Kurz close_preserve_errno(dirfd); 982a33eda0dSGreg Kurz out: 983a33eda0dSGreg Kurz g_free(dirpath); 984a33eda0dSGreg Kurz g_free(name); 9854fa4ce71SChen Gang return ret; 9868cf89e00SAnthony Liguori } 9878cf89e00SAnthony Liguori 988df4938a6SGreg Kurz static int local_unlinkat_common(FsContext *ctx, int dirfd, const char *name, 989df4938a6SGreg Kurz int flags) 990df4938a6SGreg Kurz { 991df4938a6SGreg Kurz int ret = -1; 992df4938a6SGreg Kurz 993df4938a6SGreg Kurz if (ctx->export_flags & V9FS_SM_MAPPED_FILE) { 994df4938a6SGreg Kurz int map_dirfd; 995df4938a6SGreg Kurz 996df4938a6SGreg Kurz if (flags == AT_REMOVEDIR) { 997df4938a6SGreg Kurz int fd; 998df4938a6SGreg Kurz 999df4938a6SGreg Kurz fd = openat(dirfd, name, O_RDONLY | O_DIRECTORY | O_PATH); 1000df4938a6SGreg Kurz if (fd == -1) { 1001df4938a6SGreg Kurz goto err_out; 1002df4938a6SGreg Kurz } 1003df4938a6SGreg Kurz /* 1004df4938a6SGreg Kurz * If directory remove .virtfs_metadata contained in the 1005df4938a6SGreg Kurz * directory 1006df4938a6SGreg Kurz */ 1007df4938a6SGreg Kurz ret = unlinkat(fd, VIRTFS_META_DIR, AT_REMOVEDIR); 1008df4938a6SGreg Kurz close_preserve_errno(fd); 1009df4938a6SGreg Kurz if (ret < 0 && errno != ENOENT) { 1010df4938a6SGreg Kurz /* 1011df4938a6SGreg Kurz * We didn't had the .virtfs_metadata file. May be file created 1012df4938a6SGreg Kurz * in non-mapped mode ?. Ignore ENOENT. 1013df4938a6SGreg Kurz */ 1014df4938a6SGreg Kurz goto err_out; 1015df4938a6SGreg Kurz } 1016df4938a6SGreg Kurz } 1017df4938a6SGreg Kurz /* 1018df4938a6SGreg Kurz * Now remove the name from parent directory 1019df4938a6SGreg Kurz * .virtfs_metadata directory. 1020df4938a6SGreg Kurz */ 1021df4938a6SGreg Kurz map_dirfd = openat_dir(dirfd, VIRTFS_META_DIR); 1022df4938a6SGreg Kurz ret = unlinkat(map_dirfd, name, 0); 1023df4938a6SGreg Kurz close_preserve_errno(map_dirfd); 1024df4938a6SGreg Kurz if (ret < 0 && errno != ENOENT) { 1025df4938a6SGreg Kurz /* 1026df4938a6SGreg Kurz * We didn't had the .virtfs_metadata file. May be file created 1027df4938a6SGreg Kurz * in non-mapped mode ?. Ignore ENOENT. 1028df4938a6SGreg Kurz */ 1029df4938a6SGreg Kurz goto err_out; 1030df4938a6SGreg Kurz } 1031df4938a6SGreg Kurz } 1032df4938a6SGreg Kurz 1033df4938a6SGreg Kurz ret = unlinkat(dirfd, name, flags); 1034df4938a6SGreg Kurz err_out: 1035df4938a6SGreg Kurz return ret; 1036df4938a6SGreg Kurz } 1037df4938a6SGreg Kurz 10385bae1900SAnthony Liguori static int local_remove(FsContext *ctx, const char *path) 10395bae1900SAnthony Liguori { 10402c30dd74SAneesh Kumar K.V struct stat stbuf; 1041a0e640a8SGreg Kurz char *dirpath = g_path_get_dirname(path); 1042a0e640a8SGreg Kurz char *name = g_path_get_basename(path); 1043a0e640a8SGreg Kurz int flags = 0; 1044a0e640a8SGreg Kurz int dirfd; 1045a0e640a8SGreg Kurz int err = -1; 10462c30dd74SAneesh Kumar K.V 1047a0e640a8SGreg Kurz dirfd = local_opendir_nofollow(ctx, dirpath); 1048a0e640a8SGreg Kurz if (dirfd) { 1049a0e640a8SGreg Kurz goto out; 1050a0e640a8SGreg Kurz } 1051a0e640a8SGreg Kurz 1052a0e640a8SGreg Kurz if (fstatat(dirfd, path, &stbuf, AT_SYMLINK_NOFOLLOW) < 0) { 10532c30dd74SAneesh Kumar K.V goto err_out; 10542c30dd74SAneesh Kumar K.V } 1055a0e640a8SGreg Kurz 10562c30dd74SAneesh Kumar K.V if (S_ISDIR(stbuf.st_mode)) { 1057a0e640a8SGreg Kurz flags |= AT_REMOVEDIR; 10582c30dd74SAneesh Kumar K.V } 10594fa4ce71SChen Gang 1060a0e640a8SGreg Kurz err = local_unlinkat_common(ctx, dirfd, name, flags); 10612c30dd74SAneesh Kumar K.V err_out: 1062a0e640a8SGreg Kurz close_preserve_errno(dirfd); 1063a0e640a8SGreg Kurz out: 1064a0e640a8SGreg Kurz g_free(name); 1065a0e640a8SGreg Kurz g_free(dirpath); 10662c30dd74SAneesh Kumar K.V return err; 10675bae1900SAnthony Liguori } 10685bae1900SAnthony Liguori 10698b888272SAneesh Kumar K.V static int local_fsync(FsContext *ctx, int fid_type, 10708b888272SAneesh Kumar K.V V9fsFidOpenState *fs, int datasync) 10718cf89e00SAnthony Liguori { 10728b888272SAneesh Kumar K.V int fd; 10738b888272SAneesh Kumar K.V 10748b888272SAneesh Kumar K.V if (fid_type == P9_FID_DIR) { 1075f314ea4eSGreg Kurz fd = dirfd(fs->dir.stream); 107649594973SVenkateswararao Jujjuri (JV) } else { 10778b888272SAneesh Kumar K.V fd = fs->fd; 10788b888272SAneesh Kumar K.V } 10798b888272SAneesh Kumar K.V 10808b888272SAneesh Kumar K.V if (datasync) { 10818b888272SAneesh Kumar K.V return qemu_fdatasync(fd); 10828b888272SAneesh Kumar K.V } else { 10838b888272SAneesh Kumar K.V return fsync(fd); 10848cf89e00SAnthony Liguori } 108549594973SVenkateswararao Jujjuri (JV) } 10868cf89e00SAnthony Liguori 10872289be19SAneesh Kumar K.V static int local_statfs(FsContext *s, V9fsPath *fs_path, struct statfs *stbuf) 1088be940c87SM. Mohan Kumar { 108931e51d1cSGreg Kurz int fd, ret; 10902289be19SAneesh Kumar K.V 109131e51d1cSGreg Kurz fd = local_open_nofollow(s, fs_path->data, O_RDONLY, 0); 109231e51d1cSGreg Kurz ret = fstatfs(fd, stbuf); 109331e51d1cSGreg Kurz close_preserve_errno(fd); 10944fa4ce71SChen Gang return ret; 1095be940c87SM. Mohan Kumar } 1096be940c87SM. Mohan Kumar 10972289be19SAneesh Kumar K.V static ssize_t local_lgetxattr(FsContext *ctx, V9fsPath *fs_path, 1098fa32ef88SAneesh Kumar K.V const char *name, void *value, size_t size) 1099fa32ef88SAneesh Kumar K.V { 11002289be19SAneesh Kumar K.V char *path = fs_path->data; 11012289be19SAneesh Kumar K.V 1102fc22118dSAneesh Kumar K.V return v9fs_get_xattr(ctx, path, name, value, size); 1103fa32ef88SAneesh Kumar K.V } 1104fa32ef88SAneesh Kumar K.V 11052289be19SAneesh Kumar K.V static ssize_t local_llistxattr(FsContext *ctx, V9fsPath *fs_path, 1106fa32ef88SAneesh Kumar K.V void *value, size_t size) 1107fa32ef88SAneesh Kumar K.V { 11082289be19SAneesh Kumar K.V char *path = fs_path->data; 11092289be19SAneesh Kumar K.V 1110fc22118dSAneesh Kumar K.V return v9fs_list_xattr(ctx, path, value, size); 111161b6c499SAneesh Kumar K.V } 111261b6c499SAneesh Kumar K.V 11132289be19SAneesh Kumar K.V static int local_lsetxattr(FsContext *ctx, V9fsPath *fs_path, const char *name, 111410b468bdSAneesh Kumar K.V void *value, size_t size, int flags) 111510b468bdSAneesh Kumar K.V { 11162289be19SAneesh Kumar K.V char *path = fs_path->data; 11172289be19SAneesh Kumar K.V 1118fc22118dSAneesh Kumar K.V return v9fs_set_xattr(ctx, path, name, value, size, flags); 111910b468bdSAneesh Kumar K.V } 112010b468bdSAneesh Kumar K.V 11212289be19SAneesh Kumar K.V static int local_lremovexattr(FsContext *ctx, V9fsPath *fs_path, 11222289be19SAneesh Kumar K.V const char *name) 11239ed3ef26SAneesh Kumar K.V { 11242289be19SAneesh Kumar K.V char *path = fs_path->data; 11252289be19SAneesh Kumar K.V 1126fc22118dSAneesh Kumar K.V return v9fs_remove_xattr(ctx, path, name); 11279ed3ef26SAneesh Kumar K.V } 11289ed3ef26SAneesh Kumar K.V 11292289be19SAneesh Kumar K.V static int local_name_to_path(FsContext *ctx, V9fsPath *dir_path, 11302289be19SAneesh Kumar K.V const char *name, V9fsPath *target) 11312289be19SAneesh Kumar K.V { 11322289be19SAneesh Kumar K.V if (dir_path) { 1133e3e83f2eSGreg Kurz v9fs_path_sprintf(target, "%s/%s", dir_path->data, name); 11342289be19SAneesh Kumar K.V } else { 1135e3e83f2eSGreg Kurz v9fs_path_sprintf(target, "%s", name); 11362289be19SAneesh Kumar K.V } 11372289be19SAneesh Kumar K.V return 0; 11382289be19SAneesh Kumar K.V } 11392289be19SAneesh Kumar K.V 11402289be19SAneesh Kumar K.V static int local_renameat(FsContext *ctx, V9fsPath *olddir, 11412289be19SAneesh Kumar K.V const char *old_name, V9fsPath *newdir, 11422289be19SAneesh Kumar K.V const char *new_name) 11432289be19SAneesh Kumar K.V { 11442289be19SAneesh Kumar K.V int ret; 11452289be19SAneesh Kumar K.V V9fsString old_full_name, new_full_name; 11462289be19SAneesh Kumar K.V 11472289be19SAneesh Kumar K.V v9fs_string_init(&old_full_name); 11482289be19SAneesh Kumar K.V v9fs_string_init(&new_full_name); 11492289be19SAneesh Kumar K.V 11502289be19SAneesh Kumar K.V v9fs_string_sprintf(&old_full_name, "%s/%s", olddir->data, old_name); 11512289be19SAneesh Kumar K.V v9fs_string_sprintf(&new_full_name, "%s/%s", newdir->data, new_name); 11522289be19SAneesh Kumar K.V 11532289be19SAneesh Kumar K.V ret = local_rename(ctx, old_full_name.data, new_full_name.data); 11542289be19SAneesh Kumar K.V v9fs_string_free(&old_full_name); 11552289be19SAneesh Kumar K.V v9fs_string_free(&new_full_name); 11562289be19SAneesh Kumar K.V return ret; 11572289be19SAneesh Kumar K.V } 11582289be19SAneesh Kumar K.V 11592289be19SAneesh Kumar K.V static int local_unlinkat(FsContext *ctx, V9fsPath *dir, 11602289be19SAneesh Kumar K.V const char *name, int flags) 11612289be19SAneesh Kumar K.V { 11622289be19SAneesh Kumar K.V int ret; 1163df4938a6SGreg Kurz int dirfd; 11642c30dd74SAneesh Kumar K.V 1165df4938a6SGreg Kurz dirfd = local_opendir_nofollow(ctx, dir->data); 1166df4938a6SGreg Kurz if (dirfd == -1) { 1167df4938a6SGreg Kurz return -1; 1168df4938a6SGreg Kurz } 11692289be19SAneesh Kumar K.V 1170df4938a6SGreg Kurz ret = local_unlinkat_common(ctx, dirfd, name, flags); 1171df4938a6SGreg Kurz close_preserve_errno(dirfd); 11722289be19SAneesh Kumar K.V return ret; 11732289be19SAneesh Kumar K.V } 11749ed3ef26SAneesh Kumar K.V 1175e06a765eSHarsh Prateek Bora static int local_ioc_getversion(FsContext *ctx, V9fsPath *path, 1176e06a765eSHarsh Prateek Bora mode_t st_mode, uint64_t *st_gen) 1177e06a765eSHarsh Prateek Bora { 1178ae0f940eSPaolo Bonzini #ifdef FS_IOC_GETVERSION 11790e5fc994SKirill A. Shutemov int err; 1180cc720ddbSAneesh Kumar K.V V9fsFidOpenState fid_open; 1181cc720ddbSAneesh Kumar K.V 1182e06a765eSHarsh Prateek Bora /* 1183e06a765eSHarsh Prateek Bora * Do not try to open special files like device nodes, fifos etc 1184e06a765eSHarsh Prateek Bora * We can get fd for regular files and directories only 1185e06a765eSHarsh Prateek Bora */ 1186e06a765eSHarsh Prateek Bora if (!S_ISREG(st_mode) && !S_ISDIR(st_mode)) { 11871a9978a5SKirill A. Shutemov errno = ENOTTY; 11881a9978a5SKirill A. Shutemov return -1; 1189e06a765eSHarsh Prateek Bora } 1190cc720ddbSAneesh Kumar K.V err = local_open(ctx, path, O_RDONLY, &fid_open); 1191cc720ddbSAneesh Kumar K.V if (err < 0) { 1192cc720ddbSAneesh Kumar K.V return err; 1193e06a765eSHarsh Prateek Bora } 1194cc720ddbSAneesh Kumar K.V err = ioctl(fid_open.fd, FS_IOC_GETVERSION, st_gen); 1195cc720ddbSAneesh Kumar K.V local_close(ctx, &fid_open); 1196e06a765eSHarsh Prateek Bora return err; 11970e5fc994SKirill A. Shutemov #else 11980e5fc994SKirill A. Shutemov errno = ENOTTY; 11990e5fc994SKirill A. Shutemov return -1; 12000e5fc994SKirill A. Shutemov #endif 1201e06a765eSHarsh Prateek Bora } 1202e06a765eSHarsh Prateek Bora 12030174fe73SAneesh Kumar K.V static int local_init(FsContext *ctx) 12040174fe73SAneesh Kumar K.V { 1205e06a765eSHarsh Prateek Bora struct statfs stbuf; 12060e35a378SGreg Kurz LocalData *data = g_malloc(sizeof(*data)); 12070e35a378SGreg Kurz 12080e35a378SGreg Kurz data->mountfd = open(ctx->fs_root, O_DIRECTORY | O_RDONLY); 12090e35a378SGreg Kurz if (data->mountfd == -1) { 12100e35a378SGreg Kurz goto err; 12110e35a378SGreg Kurz } 1212e06a765eSHarsh Prateek Bora 121300c90bd1SGreg Kurz #ifdef FS_IOC_GETVERSION 121400c90bd1SGreg Kurz /* 121500c90bd1SGreg Kurz * use ioc_getversion only if the ioctl is definied 121600c90bd1SGreg Kurz */ 12170e35a378SGreg Kurz if (fstatfs(data->mountfd, &stbuf) < 0) { 12180e35a378SGreg Kurz close_preserve_errno(data->mountfd); 12190e35a378SGreg Kurz goto err; 122000c90bd1SGreg Kurz } 122100c90bd1SGreg Kurz switch (stbuf.f_type) { 122200c90bd1SGreg Kurz case EXT2_SUPER_MAGIC: 122300c90bd1SGreg Kurz case BTRFS_SUPER_MAGIC: 122400c90bd1SGreg Kurz case REISERFS_SUPER_MAGIC: 122500c90bd1SGreg Kurz case XFS_SUPER_MAGIC: 122600c90bd1SGreg Kurz ctx->exops.get_st_gen = local_ioc_getversion; 122700c90bd1SGreg Kurz break; 122800c90bd1SGreg Kurz } 122900c90bd1SGreg Kurz #endif 123000c90bd1SGreg Kurz 12312c30dd74SAneesh Kumar K.V if (ctx->export_flags & V9FS_SM_PASSTHROUGH) { 12322c30dd74SAneesh Kumar K.V ctx->xops = passthrough_xattr_ops; 12332c30dd74SAneesh Kumar K.V } else if (ctx->export_flags & V9FS_SM_MAPPED) { 12342c30dd74SAneesh Kumar K.V ctx->xops = mapped_xattr_ops; 12352c30dd74SAneesh Kumar K.V } else if (ctx->export_flags & V9FS_SM_NONE) { 12362c30dd74SAneesh Kumar K.V ctx->xops = none_xattr_ops; 12372c30dd74SAneesh Kumar K.V } else if (ctx->export_flags & V9FS_SM_MAPPED_FILE) { 12382c30dd74SAneesh Kumar K.V /* 12392c30dd74SAneesh Kumar K.V * xattr operation for mapped-file and passthrough 12402c30dd74SAneesh Kumar K.V * remain same. 12412c30dd74SAneesh Kumar K.V */ 12422c30dd74SAneesh Kumar K.V ctx->xops = passthrough_xattr_ops; 12432c30dd74SAneesh Kumar K.V } 1244c98f1d4aSAneesh Kumar K.V ctx->export_flags |= V9FS_PATHNAME_FSCONTEXT; 124500c90bd1SGreg Kurz 12460e35a378SGreg Kurz ctx->private = data; 124700c90bd1SGreg Kurz return 0; 12480e35a378SGreg Kurz 12490e35a378SGreg Kurz err: 12500e35a378SGreg Kurz g_free(data); 12510e35a378SGreg Kurz return -1; 12520e35a378SGreg Kurz } 12530e35a378SGreg Kurz 12540e35a378SGreg Kurz static void local_cleanup(FsContext *ctx) 12550e35a378SGreg Kurz { 12560e35a378SGreg Kurz LocalData *data = ctx->private; 12570e35a378SGreg Kurz 12580e35a378SGreg Kurz close(data->mountfd); 12590e35a378SGreg Kurz g_free(data); 12600174fe73SAneesh Kumar K.V } 12610174fe73SAneesh Kumar K.V 126299519f0aSAneesh Kumar K.V static int local_parse_opts(QemuOpts *opts, struct FsDriverEntry *fse) 126399519f0aSAneesh Kumar K.V { 126499519f0aSAneesh Kumar K.V const char *sec_model = qemu_opt_get(opts, "security_model"); 126599519f0aSAneesh Kumar K.V const char *path = qemu_opt_get(opts, "path"); 126699519f0aSAneesh Kumar K.V 126799519f0aSAneesh Kumar K.V if (!sec_model) { 126863325b18SGreg Kurz error_report("Security model not specified, local fs needs security model"); 126963325b18SGreg Kurz error_printf("valid options are:" 127063325b18SGreg Kurz "\tsecurity_model=[passthrough|mapped-xattr|mapped-file|none]\n"); 127199519f0aSAneesh Kumar K.V return -1; 127299519f0aSAneesh Kumar K.V } 127399519f0aSAneesh Kumar K.V 127499519f0aSAneesh Kumar K.V if (!strcmp(sec_model, "passthrough")) { 127599519f0aSAneesh Kumar K.V fse->export_flags |= V9FS_SM_PASSTHROUGH; 12762c30dd74SAneesh Kumar K.V } else if (!strcmp(sec_model, "mapped") || 12772c30dd74SAneesh Kumar K.V !strcmp(sec_model, "mapped-xattr")) { 127899519f0aSAneesh Kumar K.V fse->export_flags |= V9FS_SM_MAPPED; 127999519f0aSAneesh Kumar K.V } else if (!strcmp(sec_model, "none")) { 128099519f0aSAneesh Kumar K.V fse->export_flags |= V9FS_SM_NONE; 12812c30dd74SAneesh Kumar K.V } else if (!strcmp(sec_model, "mapped-file")) { 12822c30dd74SAneesh Kumar K.V fse->export_flags |= V9FS_SM_MAPPED_FILE; 128399519f0aSAneesh Kumar K.V } else { 128463325b18SGreg Kurz error_report("Invalid security model %s specified", sec_model); 128563325b18SGreg Kurz error_printf("valid options are:" 128663325b18SGreg Kurz "\t[passthrough|mapped-xattr|mapped-file|none]\n"); 128799519f0aSAneesh Kumar K.V return -1; 128899519f0aSAneesh Kumar K.V } 128999519f0aSAneesh Kumar K.V 129099519f0aSAneesh Kumar K.V if (!path) { 129163325b18SGreg Kurz error_report("fsdev: No path specified"); 129299519f0aSAneesh Kumar K.V return -1; 129399519f0aSAneesh Kumar K.V } 129499519f0aSAneesh Kumar K.V fse->path = g_strdup(path); 129599519f0aSAneesh Kumar K.V 129699519f0aSAneesh Kumar K.V return 0; 129799519f0aSAneesh Kumar K.V } 129899519f0aSAneesh Kumar K.V 12999f107513SAnthony Liguori FileOperations local_ops = { 130099519f0aSAneesh Kumar K.V .parse_opts = local_parse_opts, 13010174fe73SAneesh Kumar K.V .init = local_init, 13020e35a378SGreg Kurz .cleanup = local_cleanup, 1303131dcb25SAnthony Liguori .lstat = local_lstat, 1304131dcb25SAnthony Liguori .readlink = local_readlink, 1305131dcb25SAnthony Liguori .close = local_close, 1306131dcb25SAnthony Liguori .closedir = local_closedir, 1307a6568fe2SAnthony Liguori .open = local_open, 1308a6568fe2SAnthony Liguori .opendir = local_opendir, 1309a9231555SAnthony Liguori .rewinddir = local_rewinddir, 1310a9231555SAnthony Liguori .telldir = local_telldir, 1311635324e8SGreg Kurz .readdir = local_readdir, 1312a9231555SAnthony Liguori .seekdir = local_seekdir, 131356d15a53SSanchit Garg .preadv = local_preadv, 131456d15a53SSanchit Garg .pwritev = local_pwritev, 1315c494dd6fSAnthony Liguori .chmod = local_chmod, 1316c494dd6fSAnthony Liguori .mknod = local_mknod, 1317c494dd6fSAnthony Liguori .mkdir = local_mkdir, 1318c494dd6fSAnthony Liguori .fstat = local_fstat, 1319c494dd6fSAnthony Liguori .open2 = local_open2, 1320c494dd6fSAnthony Liguori .symlink = local_symlink, 1321c494dd6fSAnthony Liguori .link = local_link, 13228cf89e00SAnthony Liguori .truncate = local_truncate, 13238cf89e00SAnthony Liguori .rename = local_rename, 13248cf89e00SAnthony Liguori .chown = local_chown, 132574bc02b2SM. Mohan Kumar .utimensat = local_utimensat, 13265bae1900SAnthony Liguori .remove = local_remove, 13278cf89e00SAnthony Liguori .fsync = local_fsync, 1328be940c87SM. Mohan Kumar .statfs = local_statfs, 1329fa32ef88SAneesh Kumar K.V .lgetxattr = local_lgetxattr, 1330fa32ef88SAneesh Kumar K.V .llistxattr = local_llistxattr, 133110b468bdSAneesh Kumar K.V .lsetxattr = local_lsetxattr, 13329ed3ef26SAneesh Kumar K.V .lremovexattr = local_lremovexattr, 13332289be19SAneesh Kumar K.V .name_to_path = local_name_to_path, 13342289be19SAneesh Kumar K.V .renameat = local_renameat, 13352289be19SAneesh Kumar K.V .unlinkat = local_unlinkat, 13369f107513SAnthony Liguori }; 1337