xref: /qemu/hw/9pfs/9p-local.c (revision 21328e1e57f526e3f0c2fcd00f10c8aa6e7bc07f)
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"
16267ae092SWei Liu #include "9p-xattr.h"
1769b15212SStefan Weil #include "fsdev/qemu-fsdev.h"   /* local_ops */
18c494dd6fSAnthony Liguori #include <arpa/inet.h>
19131dcb25SAnthony Liguori #include <pwd.h>
20131dcb25SAnthony Liguori #include <grp.h>
21c494dd6fSAnthony Liguori #include <sys/socket.h>
22c494dd6fSAnthony Liguori #include <sys/un.h>
231de7afc9SPaolo Bonzini #include "qemu/xattr.h"
24f348b6d1SVeronia Bahaa #include "qemu/cutils.h"
2563325b18SGreg Kurz #include "qemu/error-report.h"
262c30dd74SAneesh Kumar K.V #include <libgen.h>
27e06a765eSHarsh Prateek Bora #include <linux/fs.h>
28e06a765eSHarsh Prateek Bora #ifdef CONFIG_LINUX_MAGIC_H
29e06a765eSHarsh Prateek Bora #include <linux/magic.h>
30e06a765eSHarsh Prateek Bora #endif
31e06a765eSHarsh Prateek Bora #include <sys/ioctl.h>
32e06a765eSHarsh Prateek Bora 
33e06a765eSHarsh Prateek Bora #ifndef XFS_SUPER_MAGIC
34e06a765eSHarsh Prateek Bora #define XFS_SUPER_MAGIC  0x58465342
35e06a765eSHarsh Prateek Bora #endif
36e06a765eSHarsh Prateek Bora #ifndef EXT2_SUPER_MAGIC
37e06a765eSHarsh Prateek Bora #define EXT2_SUPER_MAGIC 0xEF53
38e06a765eSHarsh Prateek Bora #endif
39e06a765eSHarsh Prateek Bora #ifndef REISERFS_SUPER_MAGIC
40e06a765eSHarsh Prateek Bora #define REISERFS_SUPER_MAGIC 0x52654973
41e06a765eSHarsh Prateek Bora #endif
42e06a765eSHarsh Prateek Bora #ifndef BTRFS_SUPER_MAGIC
43e06a765eSHarsh Prateek Bora #define BTRFS_SUPER_MAGIC 0x9123683E
44e06a765eSHarsh Prateek Bora #endif
45131dcb25SAnthony Liguori 
462c30dd74SAneesh Kumar K.V #define VIRTFS_META_DIR ".virtfs_metadata"
472c30dd74SAneesh Kumar K.V 
484fa4ce71SChen Gang static char *local_mapped_attr_path(FsContext *ctx, const char *path)
492c30dd74SAneesh Kumar K.V {
501b6f85e2SMichael Tokarev     int dirlen;
511b6f85e2SMichael Tokarev     const char *name = strrchr(path, '/');
521b6f85e2SMichael Tokarev     if (name) {
531b6f85e2SMichael Tokarev         dirlen = name - path;
541b6f85e2SMichael Tokarev         ++name;
551b6f85e2SMichael Tokarev     } else {
561b6f85e2SMichael Tokarev         name = path;
571b6f85e2SMichael Tokarev         dirlen = 0;
581b6f85e2SMichael Tokarev     }
591b6f85e2SMichael Tokarev     return g_strdup_printf("%s/%.*s/%s/%s", ctx->fs_root,
601b6f85e2SMichael Tokarev                            dirlen, path, VIRTFS_META_DIR, name);
612c30dd74SAneesh Kumar K.V }
622c30dd74SAneesh Kumar K.V 
630ceb092eSAneesh Kumar K.V static FILE *local_fopen(const char *path, const char *mode)
640ceb092eSAneesh Kumar K.V {
650ceb092eSAneesh Kumar K.V     int fd, o_mode = 0;
660ceb092eSAneesh Kumar K.V     FILE *fp;
670ceb092eSAneesh Kumar K.V     int flags = O_NOFOLLOW;
680ceb092eSAneesh Kumar K.V     /*
690ceb092eSAneesh Kumar K.V      * only supports two modes
700ceb092eSAneesh Kumar K.V      */
710ceb092eSAneesh Kumar K.V     if (mode[0] == 'r') {
720ceb092eSAneesh Kumar K.V         flags |= O_RDONLY;
730ceb092eSAneesh Kumar K.V     } else if (mode[0] == 'w') {
740ceb092eSAneesh Kumar K.V         flags |= O_WRONLY | O_TRUNC | O_CREAT;
750ceb092eSAneesh Kumar K.V         o_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
760ceb092eSAneesh Kumar K.V     } else {
770ceb092eSAneesh Kumar K.V         return NULL;
780ceb092eSAneesh Kumar K.V     }
790ceb092eSAneesh Kumar K.V     fd = open(path, flags, o_mode);
800ceb092eSAneesh Kumar K.V     if (fd == -1) {
810ceb092eSAneesh Kumar K.V         return NULL;
820ceb092eSAneesh Kumar K.V     }
830ceb092eSAneesh Kumar K.V     fp = fdopen(fd, mode);
840ceb092eSAneesh Kumar K.V     if (!fp) {
850ceb092eSAneesh Kumar K.V         close(fd);
860ceb092eSAneesh Kumar K.V     }
870ceb092eSAneesh Kumar K.V     return fp;
880ceb092eSAneesh Kumar K.V }
890ceb092eSAneesh Kumar K.V 
902c30dd74SAneesh Kumar K.V #define ATTR_MAX 100
912c30dd74SAneesh Kumar K.V static void local_mapped_file_attr(FsContext *ctx, const char *path,
922c30dd74SAneesh Kumar K.V                                    struct stat *stbuf)
932c30dd74SAneesh Kumar K.V {
942c30dd74SAneesh Kumar K.V     FILE *fp;
952c30dd74SAneesh Kumar K.V     char buf[ATTR_MAX];
964fa4ce71SChen Gang     char *attr_path;
972c30dd74SAneesh Kumar K.V 
984fa4ce71SChen Gang     attr_path = local_mapped_attr_path(ctx, path);
990ceb092eSAneesh Kumar K.V     fp = local_fopen(attr_path, "r");
1004fa4ce71SChen Gang     g_free(attr_path);
1012c30dd74SAneesh Kumar K.V     if (!fp) {
1022c30dd74SAneesh Kumar K.V         return;
1032c30dd74SAneesh Kumar K.V     }
1042c30dd74SAneesh Kumar K.V     memset(buf, 0, ATTR_MAX);
1052c30dd74SAneesh Kumar K.V     while (fgets(buf, ATTR_MAX, fp)) {
1062c30dd74SAneesh Kumar K.V         if (!strncmp(buf, "virtfs.uid", 10)) {
1072c30dd74SAneesh Kumar K.V             stbuf->st_uid = atoi(buf+11);
1082c30dd74SAneesh Kumar K.V         } else if (!strncmp(buf, "virtfs.gid", 10)) {
1092c30dd74SAneesh Kumar K.V             stbuf->st_gid = atoi(buf+11);
1102c30dd74SAneesh Kumar K.V         } else if (!strncmp(buf, "virtfs.mode", 11)) {
1112c30dd74SAneesh Kumar K.V             stbuf->st_mode = atoi(buf+12);
1122c30dd74SAneesh Kumar K.V         } else if (!strncmp(buf, "virtfs.rdev", 11)) {
1132c30dd74SAneesh Kumar K.V             stbuf->st_rdev = atoi(buf+12);
1142c30dd74SAneesh Kumar K.V         }
1152c30dd74SAneesh Kumar K.V         memset(buf, 0, ATTR_MAX);
1162c30dd74SAneesh Kumar K.V     }
1172c30dd74SAneesh Kumar K.V     fclose(fp);
1182c30dd74SAneesh Kumar K.V }
1192c30dd74SAneesh Kumar K.V 
1202289be19SAneesh Kumar K.V static int local_lstat(FsContext *fs_ctx, V9fsPath *fs_path, struct stat *stbuf)
121131dcb25SAnthony Liguori {
1221237ad76SVenkateswararao Jujjuri (JV)     int err;
1234fa4ce71SChen Gang     char *buffer;
1242289be19SAneesh Kumar K.V     char *path = fs_path->data;
1252289be19SAneesh Kumar K.V 
1264fa4ce71SChen Gang     buffer = rpath(fs_ctx, path);
1274fa4ce71SChen Gang     err =  lstat(buffer, stbuf);
1281237ad76SVenkateswararao Jujjuri (JV)     if (err) {
1294fa4ce71SChen Gang         goto err_out;
1301237ad76SVenkateswararao Jujjuri (JV)     }
131b97400caSAneesh Kumar K.V     if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
1321237ad76SVenkateswararao Jujjuri (JV)         /* Actual credentials are part of extended attrs */
1331237ad76SVenkateswararao Jujjuri (JV)         uid_t tmp_uid;
1341237ad76SVenkateswararao Jujjuri (JV)         gid_t tmp_gid;
1351237ad76SVenkateswararao Jujjuri (JV)         mode_t tmp_mode;
1361237ad76SVenkateswararao Jujjuri (JV)         dev_t tmp_dev;
1374fa4ce71SChen Gang         if (getxattr(buffer, "user.virtfs.uid", &tmp_uid, sizeof(uid_t)) > 0) {
138f8ad4a89SAneesh Kumar K.V             stbuf->st_uid = le32_to_cpu(tmp_uid);
1391237ad76SVenkateswararao Jujjuri (JV)         }
1404fa4ce71SChen Gang         if (getxattr(buffer, "user.virtfs.gid", &tmp_gid, sizeof(gid_t)) > 0) {
141f8ad4a89SAneesh Kumar K.V             stbuf->st_gid = le32_to_cpu(tmp_gid);
1421237ad76SVenkateswararao Jujjuri (JV)         }
1434fa4ce71SChen Gang         if (getxattr(buffer, "user.virtfs.mode",
144faa44e3dSVenkateswararao Jujjuri (JV)                     &tmp_mode, sizeof(mode_t)) > 0) {
145f8ad4a89SAneesh Kumar K.V             stbuf->st_mode = le32_to_cpu(tmp_mode);
1461237ad76SVenkateswararao Jujjuri (JV)         }
1474fa4ce71SChen Gang         if (getxattr(buffer, "user.virtfs.rdev", &tmp_dev, sizeof(dev_t)) > 0) {
148f8ad4a89SAneesh Kumar K.V             stbuf->st_rdev = le64_to_cpu(tmp_dev);
1491237ad76SVenkateswararao Jujjuri (JV)         }
1502c30dd74SAneesh Kumar K.V     } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
1512c30dd74SAneesh Kumar K.V         local_mapped_file_attr(fs_ctx, path, stbuf);
1521237ad76SVenkateswararao Jujjuri (JV)     }
1534fa4ce71SChen Gang 
1544fa4ce71SChen Gang err_out:
1554fa4ce71SChen Gang     g_free(buffer);
1561237ad76SVenkateswararao Jujjuri (JV)     return err;
157131dcb25SAnthony Liguori }
158131dcb25SAnthony Liguori 
1592c30dd74SAneesh Kumar K.V static int local_create_mapped_attr_dir(FsContext *ctx, const char *path)
1602c30dd74SAneesh Kumar K.V {
1612c30dd74SAneesh Kumar K.V     int err;
1624fa4ce71SChen Gang     char *attr_dir;
163d3f8e138SMarkus Armbruster     char *tmp_path = g_strdup(path);
1642c30dd74SAneesh Kumar K.V 
1654fa4ce71SChen Gang     attr_dir = g_strdup_printf("%s/%s/%s",
1662c30dd74SAneesh Kumar K.V              ctx->fs_root, dirname(tmp_path), VIRTFS_META_DIR);
1672c30dd74SAneesh Kumar K.V 
1682c30dd74SAneesh Kumar K.V     err = mkdir(attr_dir, 0700);
1692c30dd74SAneesh Kumar K.V     if (err < 0 && errno == EEXIST) {
1702c30dd74SAneesh Kumar K.V         err = 0;
1712c30dd74SAneesh Kumar K.V     }
1724fa4ce71SChen Gang     g_free(attr_dir);
173d3f8e138SMarkus Armbruster     g_free(tmp_path);
1742c30dd74SAneesh Kumar K.V     return err;
1752c30dd74SAneesh Kumar K.V }
1762c30dd74SAneesh Kumar K.V 
1772c30dd74SAneesh Kumar K.V static int local_set_mapped_file_attr(FsContext *ctx,
1782c30dd74SAneesh Kumar K.V                                       const char *path, FsCred *credp)
1792c30dd74SAneesh Kumar K.V {
1802c30dd74SAneesh Kumar K.V     FILE *fp;
1812c30dd74SAneesh Kumar K.V     int ret = 0;
1822c30dd74SAneesh Kumar K.V     char buf[ATTR_MAX];
1834fa4ce71SChen Gang     char *attr_path;
1842c30dd74SAneesh Kumar K.V     int uid = -1, gid = -1, mode = -1, rdev = -1;
1852c30dd74SAneesh Kumar K.V 
1864fa4ce71SChen Gang     attr_path = local_mapped_attr_path(ctx, path);
1874fa4ce71SChen Gang     fp = local_fopen(attr_path, "r");
1882c30dd74SAneesh Kumar K.V     if (!fp) {
1892c30dd74SAneesh Kumar K.V         goto create_map_file;
1902c30dd74SAneesh Kumar K.V     }
1912c30dd74SAneesh Kumar K.V     memset(buf, 0, ATTR_MAX);
1922c30dd74SAneesh Kumar K.V     while (fgets(buf, ATTR_MAX, fp)) {
1932c30dd74SAneesh Kumar K.V         if (!strncmp(buf, "virtfs.uid", 10)) {
1942c30dd74SAneesh Kumar K.V             uid = atoi(buf+11);
1952c30dd74SAneesh Kumar K.V         } else if (!strncmp(buf, "virtfs.gid", 10)) {
1962c30dd74SAneesh Kumar K.V             gid = atoi(buf+11);
1972c30dd74SAneesh Kumar K.V         } else if (!strncmp(buf, "virtfs.mode", 11)) {
1982c30dd74SAneesh Kumar K.V             mode = atoi(buf+12);
1992c30dd74SAneesh Kumar K.V         } else if (!strncmp(buf, "virtfs.rdev", 11)) {
2002c30dd74SAneesh Kumar K.V             rdev = atoi(buf+12);
2012c30dd74SAneesh Kumar K.V         }
2022c30dd74SAneesh Kumar K.V         memset(buf, 0, ATTR_MAX);
2032c30dd74SAneesh Kumar K.V     }
2042c30dd74SAneesh Kumar K.V     fclose(fp);
2052c30dd74SAneesh Kumar K.V     goto update_map_file;
2062c30dd74SAneesh Kumar K.V 
2072c30dd74SAneesh Kumar K.V create_map_file:
2082c30dd74SAneesh Kumar K.V     ret = local_create_mapped_attr_dir(ctx, path);
2092c30dd74SAneesh Kumar K.V     if (ret < 0) {
2102c30dd74SAneesh Kumar K.V         goto err_out;
2112c30dd74SAneesh Kumar K.V     }
2122c30dd74SAneesh Kumar K.V 
2132c30dd74SAneesh Kumar K.V update_map_file:
2140ceb092eSAneesh Kumar K.V     fp = local_fopen(attr_path, "w");
2152c30dd74SAneesh Kumar K.V     if (!fp) {
2162c30dd74SAneesh Kumar K.V         ret = -1;
2172c30dd74SAneesh Kumar K.V         goto err_out;
2182c30dd74SAneesh Kumar K.V     }
2192c30dd74SAneesh Kumar K.V 
2202c30dd74SAneesh Kumar K.V     if (credp->fc_uid != -1) {
2212c30dd74SAneesh Kumar K.V         uid = credp->fc_uid;
2222c30dd74SAneesh Kumar K.V     }
2232c30dd74SAneesh Kumar K.V     if (credp->fc_gid != -1) {
2242c30dd74SAneesh Kumar K.V         gid = credp->fc_gid;
2252c30dd74SAneesh Kumar K.V     }
2262c30dd74SAneesh Kumar K.V     if (credp->fc_mode != -1) {
2272c30dd74SAneesh Kumar K.V         mode = credp->fc_mode;
2282c30dd74SAneesh Kumar K.V     }
2292c30dd74SAneesh Kumar K.V     if (credp->fc_rdev != -1) {
2302c30dd74SAneesh Kumar K.V         rdev = credp->fc_rdev;
2312c30dd74SAneesh Kumar K.V     }
2322c30dd74SAneesh Kumar K.V 
2332c30dd74SAneesh Kumar K.V 
2342c30dd74SAneesh Kumar K.V     if (uid != -1) {
2352c30dd74SAneesh Kumar K.V         fprintf(fp, "virtfs.uid=%d\n", uid);
2362c30dd74SAneesh Kumar K.V     }
2372c30dd74SAneesh Kumar K.V     if (gid != -1) {
2382c30dd74SAneesh Kumar K.V         fprintf(fp, "virtfs.gid=%d\n", gid);
2392c30dd74SAneesh Kumar K.V     }
2402c30dd74SAneesh Kumar K.V     if (mode != -1) {
2412c30dd74SAneesh Kumar K.V         fprintf(fp, "virtfs.mode=%d\n", mode);
2422c30dd74SAneesh Kumar K.V     }
2432c30dd74SAneesh Kumar K.V     if (rdev != -1) {
2442c30dd74SAneesh Kumar K.V         fprintf(fp, "virtfs.rdev=%d\n", rdev);
2452c30dd74SAneesh Kumar K.V     }
2462c30dd74SAneesh Kumar K.V     fclose(fp);
2472c30dd74SAneesh Kumar K.V 
2482c30dd74SAneesh Kumar K.V err_out:
2494fa4ce71SChen Gang     g_free(attr_path);
2502c30dd74SAneesh Kumar K.V     return ret;
2512c30dd74SAneesh Kumar K.V }
2522c30dd74SAneesh Kumar K.V 
253758e8e38SVenkateswararao Jujjuri (JV) static int local_set_xattr(const char *path, FsCred *credp)
254131dcb25SAnthony Liguori {
255758e8e38SVenkateswararao Jujjuri (JV)     int err;
2562289be19SAneesh Kumar K.V 
257758e8e38SVenkateswararao Jujjuri (JV)     if (credp->fc_uid != -1) {
258f8ad4a89SAneesh Kumar K.V         uint32_t tmp_uid = cpu_to_le32(credp->fc_uid);
259f8ad4a89SAneesh Kumar K.V         err = setxattr(path, "user.virtfs.uid", &tmp_uid, sizeof(uid_t), 0);
260758e8e38SVenkateswararao Jujjuri (JV)         if (err) {
261758e8e38SVenkateswararao Jujjuri (JV)             return err;
262131dcb25SAnthony Liguori         }
263131dcb25SAnthony Liguori     }
264758e8e38SVenkateswararao Jujjuri (JV)     if (credp->fc_gid != -1) {
265f8ad4a89SAneesh Kumar K.V         uint32_t tmp_gid = cpu_to_le32(credp->fc_gid);
266f8ad4a89SAneesh Kumar K.V         err = setxattr(path, "user.virtfs.gid", &tmp_gid, sizeof(gid_t), 0);
267758e8e38SVenkateswararao Jujjuri (JV)         if (err) {
268758e8e38SVenkateswararao Jujjuri (JV)             return err;
269131dcb25SAnthony Liguori         }
270131dcb25SAnthony Liguori     }
271758e8e38SVenkateswararao Jujjuri (JV)     if (credp->fc_mode != -1) {
272f8ad4a89SAneesh Kumar K.V         uint32_t tmp_mode = cpu_to_le32(credp->fc_mode);
273f8ad4a89SAneesh Kumar K.V         err = setxattr(path, "user.virtfs.mode", &tmp_mode, sizeof(mode_t), 0);
274758e8e38SVenkateswararao Jujjuri (JV)         if (err) {
275758e8e38SVenkateswararao Jujjuri (JV)             return err;
276131dcb25SAnthony Liguori         }
277131dcb25SAnthony Liguori     }
278758e8e38SVenkateswararao Jujjuri (JV)     if (credp->fc_rdev != -1) {
279f8ad4a89SAneesh Kumar K.V         uint64_t tmp_rdev = cpu_to_le64(credp->fc_rdev);
280f8ad4a89SAneesh Kumar K.V         err = setxattr(path, "user.virtfs.rdev", &tmp_rdev, sizeof(dev_t), 0);
281758e8e38SVenkateswararao Jujjuri (JV)         if (err) {
282758e8e38SVenkateswararao Jujjuri (JV)             return err;
283131dcb25SAnthony Liguori         }
284758e8e38SVenkateswararao Jujjuri (JV)     }
285131dcb25SAnthony Liguori     return 0;
286131dcb25SAnthony Liguori }
287131dcb25SAnthony Liguori 
2884750a96fSVenkateswararao Jujjuri (JV) static int local_post_create_passthrough(FsContext *fs_ctx, const char *path,
2894750a96fSVenkateswararao Jujjuri (JV)                                          FsCred *credp)
2904750a96fSVenkateswararao Jujjuri (JV) {
2914fa4ce71SChen Gang     char *buffer;
2922289be19SAneesh Kumar K.V 
2934fa4ce71SChen Gang     buffer = rpath(fs_ctx, path);
2944fa4ce71SChen Gang     if (lchown(buffer, credp->fc_uid, credp->fc_gid) < 0) {
29512848bfcSAneesh Kumar K.V         /*
29612848bfcSAneesh Kumar K.V          * If we fail to change ownership and if we are
29712848bfcSAneesh Kumar K.V          * using security model none. Ignore the error
29812848bfcSAneesh Kumar K.V          */
299b97400caSAneesh Kumar K.V         if ((fs_ctx->export_flags & V9FS_SEC_MASK) != V9FS_SM_NONE) {
3004fa4ce71SChen Gang             goto err;
3014750a96fSVenkateswararao Jujjuri (JV)         }
30212848bfcSAneesh Kumar K.V     }
3032d40564aSM. Mohan Kumar 
3044fa4ce71SChen Gang     if (chmod(buffer, credp->fc_mode & 07777) < 0) {
3054fa4ce71SChen Gang         goto err;
3062d40564aSM. Mohan Kumar     }
3074fa4ce71SChen Gang 
3084fa4ce71SChen Gang     g_free(buffer);
3094750a96fSVenkateswararao Jujjuri (JV)     return 0;
3104fa4ce71SChen Gang err:
3114fa4ce71SChen Gang     g_free(buffer);
3124fa4ce71SChen Gang     return -1;
3134750a96fSVenkateswararao Jujjuri (JV) }
3144750a96fSVenkateswararao Jujjuri (JV) 
3152289be19SAneesh Kumar K.V static ssize_t local_readlink(FsContext *fs_ctx, V9fsPath *fs_path,
316131dcb25SAnthony Liguori                               char *buf, size_t bufsz)
317131dcb25SAnthony Liguori {
318879c2813SVenkateswararao Jujjuri (JV)     ssize_t tsize = -1;
3194fa4ce71SChen Gang     char *buffer;
3202289be19SAneesh Kumar K.V     char *path = fs_path->data;
3212289be19SAneesh Kumar K.V 
3222c30dd74SAneesh Kumar K.V     if ((fs_ctx->export_flags & V9FS_SM_MAPPED) ||
3232c30dd74SAneesh Kumar K.V         (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE)) {
324879c2813SVenkateswararao Jujjuri (JV)         int fd;
3254fa4ce71SChen Gang         buffer = rpath(fs_ctx, path);
3264fa4ce71SChen Gang         fd = open(buffer, O_RDONLY | O_NOFOLLOW);
3274fa4ce71SChen Gang         g_free(buffer);
328879c2813SVenkateswararao Jujjuri (JV)         if (fd == -1) {
329879c2813SVenkateswararao Jujjuri (JV)             return -1;
330879c2813SVenkateswararao Jujjuri (JV)         }
331879c2813SVenkateswararao Jujjuri (JV)         do {
332879c2813SVenkateswararao Jujjuri (JV)             tsize = read(fd, (void *)buf, bufsz);
333879c2813SVenkateswararao Jujjuri (JV)         } while (tsize == -1 && errno == EINTR);
334879c2813SVenkateswararao Jujjuri (JV)         close(fd);
335b97400caSAneesh Kumar K.V     } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
336b97400caSAneesh Kumar K.V                (fs_ctx->export_flags & V9FS_SM_NONE)) {
3374fa4ce71SChen Gang         buffer = rpath(fs_ctx, path);
3384fa4ce71SChen Gang         tsize = readlink(buffer, buf, bufsz);
3394fa4ce71SChen Gang         g_free(buffer);
340879c2813SVenkateswararao Jujjuri (JV)     }
341879c2813SVenkateswararao Jujjuri (JV)     return tsize;
342131dcb25SAnthony Liguori }
343131dcb25SAnthony Liguori 
344cc720ddbSAneesh Kumar K.V static int local_close(FsContext *ctx, V9fsFidOpenState *fs)
345131dcb25SAnthony Liguori {
346cc720ddbSAneesh Kumar K.V     return close(fs->fd);
347131dcb25SAnthony Liguori }
348131dcb25SAnthony Liguori 
349cc720ddbSAneesh Kumar K.V static int local_closedir(FsContext *ctx, V9fsFidOpenState *fs)
350131dcb25SAnthony Liguori {
351f314ea4eSGreg Kurz     return closedir(fs->dir.stream);
352131dcb25SAnthony Liguori }
3539f107513SAnthony Liguori 
354cc720ddbSAneesh Kumar K.V static int local_open(FsContext *ctx, V9fsPath *fs_path,
355cc720ddbSAneesh Kumar K.V                       int flags, V9fsFidOpenState *fs)
356a6568fe2SAnthony Liguori {
3574fa4ce71SChen Gang     char *buffer;
3582289be19SAneesh Kumar K.V     char *path = fs_path->data;
359*21328e1eSGreg Kurz     int fd;
3602289be19SAneesh Kumar K.V 
3614fa4ce71SChen Gang     buffer = rpath(ctx, path);
362*21328e1eSGreg Kurz     fd = open(buffer, flags | O_NOFOLLOW);
3634fa4ce71SChen Gang     g_free(buffer);
364*21328e1eSGreg Kurz     if (fd == -1) {
365*21328e1eSGreg Kurz         return -1;
366*21328e1eSGreg Kurz     }
367*21328e1eSGreg Kurz     fs->fd = fd;
368cc720ddbSAneesh Kumar K.V     return fs->fd;
369a6568fe2SAnthony Liguori }
370a6568fe2SAnthony Liguori 
371cc720ddbSAneesh Kumar K.V static int local_opendir(FsContext *ctx,
372cc720ddbSAneesh Kumar K.V                          V9fsPath *fs_path, V9fsFidOpenState *fs)
373a6568fe2SAnthony Liguori {
3744fa4ce71SChen Gang     char *buffer;
3752289be19SAneesh Kumar K.V     char *path = fs_path->data;
376*21328e1eSGreg Kurz     DIR *stream;
3772289be19SAneesh Kumar K.V 
3784fa4ce71SChen Gang     buffer = rpath(ctx, path);
379*21328e1eSGreg Kurz     stream = opendir(buffer);
3804fa4ce71SChen Gang     g_free(buffer);
381*21328e1eSGreg Kurz     if (!stream) {
382cc720ddbSAneesh Kumar K.V         return -1;
383cc720ddbSAneesh Kumar K.V     }
384*21328e1eSGreg Kurz     fs->dir.stream = stream;
385cc720ddbSAneesh Kumar K.V     return 0;
386a6568fe2SAnthony Liguori }
387a6568fe2SAnthony Liguori 
388cc720ddbSAneesh Kumar K.V static void local_rewinddir(FsContext *ctx, V9fsFidOpenState *fs)
389a9231555SAnthony Liguori {
390f314ea4eSGreg Kurz     rewinddir(fs->dir.stream);
391a9231555SAnthony Liguori }
392a9231555SAnthony Liguori 
393cc720ddbSAneesh Kumar K.V static off_t local_telldir(FsContext *ctx, V9fsFidOpenState *fs)
394a9231555SAnthony Liguori {
395f314ea4eSGreg Kurz     return telldir(fs->dir.stream);
396a9231555SAnthony Liguori }
397a9231555SAnthony Liguori 
398635324e8SGreg Kurz static struct dirent *local_readdir(FsContext *ctx, V9fsFidOpenState *fs)
399a9231555SAnthony Liguori {
400635324e8SGreg Kurz     struct dirent *entry;
4012c30dd74SAneesh Kumar K.V 
4022c30dd74SAneesh Kumar K.V again:
403635324e8SGreg Kurz     entry = readdir(fs->dir.stream);
404635324e8SGreg Kurz     if (!entry) {
405635324e8SGreg Kurz         return NULL;
406635324e8SGreg Kurz     }
407635324e8SGreg Kurz 
408840a1bf2SBastian Blank     if (ctx->export_flags & V9FS_SM_MAPPED) {
409840a1bf2SBastian Blank         entry->d_type = DT_UNKNOWN;
410840a1bf2SBastian Blank     } else if (ctx->export_flags & V9FS_SM_MAPPED_FILE) {
411635324e8SGreg Kurz         if (!strcmp(entry->d_name, VIRTFS_META_DIR)) {
4122c30dd74SAneesh Kumar K.V             /* skp the meta data directory */
4132c30dd74SAneesh Kumar K.V             goto again;
4142c30dd74SAneesh Kumar K.V         }
415840a1bf2SBastian Blank         entry->d_type = DT_UNKNOWN;
4162c30dd74SAneesh Kumar K.V     }
417635324e8SGreg Kurz 
418635324e8SGreg Kurz     return entry;
419a9231555SAnthony Liguori }
420a9231555SAnthony Liguori 
421cc720ddbSAneesh Kumar K.V static void local_seekdir(FsContext *ctx, V9fsFidOpenState *fs, off_t off)
422a9231555SAnthony Liguori {
423f314ea4eSGreg Kurz     seekdir(fs->dir.stream, off);
424a9231555SAnthony Liguori }
425a9231555SAnthony Liguori 
426cc720ddbSAneesh Kumar K.V static ssize_t local_preadv(FsContext *ctx, V9fsFidOpenState *fs,
427cc720ddbSAneesh Kumar K.V                             const struct iovec *iov,
42856d15a53SSanchit Garg                             int iovcnt, off_t offset)
429a9231555SAnthony Liguori {
43056d15a53SSanchit Garg #ifdef CONFIG_PREADV
431cc720ddbSAneesh Kumar K.V     return preadv(fs->fd, iov, iovcnt, offset);
43256d15a53SSanchit Garg #else
433cc720ddbSAneesh Kumar K.V     int err = lseek(fs->fd, offset, SEEK_SET);
43456d15a53SSanchit Garg     if (err == -1) {
43556d15a53SSanchit Garg         return err;
43656d15a53SSanchit Garg     } else {
437cc720ddbSAneesh Kumar K.V         return readv(fs->fd, iov, iovcnt);
438a9231555SAnthony Liguori     }
43956d15a53SSanchit Garg #endif
440a9231555SAnthony Liguori }
441a9231555SAnthony Liguori 
442cc720ddbSAneesh Kumar K.V static ssize_t local_pwritev(FsContext *ctx, V9fsFidOpenState *fs,
443cc720ddbSAneesh Kumar K.V                              const struct iovec *iov,
44456d15a53SSanchit Garg                              int iovcnt, off_t offset)
4458449360cSAnthony Liguori {
4466fe76accSGreg Kurz     ssize_t ret;
44756d15a53SSanchit Garg #ifdef CONFIG_PREADV
448cc720ddbSAneesh Kumar K.V     ret = pwritev(fs->fd, iov, iovcnt, offset);
44956d15a53SSanchit Garg #else
450cc720ddbSAneesh Kumar K.V     int err = lseek(fs->fd, offset, SEEK_SET);
45156d15a53SSanchit Garg     if (err == -1) {
45256d15a53SSanchit Garg         return err;
45356d15a53SSanchit Garg     } else {
454cc720ddbSAneesh Kumar K.V         ret = writev(fs->fd, iov, iovcnt);
4558449360cSAnthony Liguori     }
45656d15a53SSanchit Garg #endif
457d3ab98e6SAneesh Kumar K.V #ifdef CONFIG_SYNC_FILE_RANGE
458d3ab98e6SAneesh Kumar K.V     if (ret > 0 && ctx->export_flags & V9FS_IMMEDIATE_WRITEOUT) {
459d3ab98e6SAneesh Kumar K.V         /*
460d3ab98e6SAneesh Kumar K.V          * Initiate a writeback. This is not a data integrity sync.
461d3ab98e6SAneesh Kumar K.V          * We want to ensure that we don't leave dirty pages in the cache
462d3ab98e6SAneesh Kumar K.V          * after write when writeout=immediate is sepcified.
463d3ab98e6SAneesh Kumar K.V          */
464cc720ddbSAneesh Kumar K.V         sync_file_range(fs->fd, offset, ret,
465d3ab98e6SAneesh Kumar K.V                         SYNC_FILE_RANGE_WAIT_BEFORE | SYNC_FILE_RANGE_WRITE);
466d3ab98e6SAneesh Kumar K.V     }
467d3ab98e6SAneesh Kumar K.V #endif
468d3ab98e6SAneesh Kumar K.V     return ret;
46956d15a53SSanchit Garg }
4708449360cSAnthony Liguori 
4712289be19SAneesh Kumar K.V static int local_chmod(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
472c494dd6fSAnthony Liguori {
4734fa4ce71SChen Gang     char *buffer;
4744fa4ce71SChen Gang     int ret = -1;
4752289be19SAneesh Kumar K.V     char *path = fs_path->data;
4762289be19SAneesh Kumar K.V 
477b97400caSAneesh Kumar K.V     if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
4784fa4ce71SChen Gang         buffer = rpath(fs_ctx, path);
4794fa4ce71SChen Gang         ret = local_set_xattr(buffer, credp);
4804fa4ce71SChen Gang         g_free(buffer);
4812c30dd74SAneesh Kumar K.V     } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
4822c30dd74SAneesh Kumar K.V         return local_set_mapped_file_attr(fs_ctx, path, credp);
483b97400caSAneesh Kumar K.V     } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
484b97400caSAneesh Kumar K.V                (fs_ctx->export_flags & V9FS_SM_NONE)) {
4854fa4ce71SChen Gang         buffer = rpath(fs_ctx, path);
4864fa4ce71SChen Gang         ret = chmod(buffer, credp->fc_mode);
4874fa4ce71SChen Gang         g_free(buffer);
488e95ead32SVenkateswararao Jujjuri (JV)     }
4894fa4ce71SChen Gang     return ret;
490c494dd6fSAnthony Liguori }
491c494dd6fSAnthony Liguori 
4922289be19SAneesh Kumar K.V static int local_mknod(FsContext *fs_ctx, V9fsPath *dir_path,
4932289be19SAneesh Kumar K.V                        const char *name, FsCred *credp)
494c494dd6fSAnthony Liguori {
4952289be19SAneesh Kumar K.V     char *path;
4961c293312SVenkateswararao Jujjuri (JV)     int err = -1;
4971c293312SVenkateswararao Jujjuri (JV)     int serrno = 0;
4982289be19SAneesh Kumar K.V     V9fsString fullname;
4994ed7b2c3SStefan Weil     char *buffer = NULL;
5001c293312SVenkateswararao Jujjuri (JV) 
5012289be19SAneesh Kumar K.V     v9fs_string_init(&fullname);
5022289be19SAneesh Kumar K.V     v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
5032289be19SAneesh Kumar K.V     path = fullname.data;
5042289be19SAneesh Kumar K.V 
5051c293312SVenkateswararao Jujjuri (JV)     /* Determine the security model */
506b97400caSAneesh Kumar K.V     if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
5074fa4ce71SChen Gang         buffer = rpath(fs_ctx, path);
5084fa4ce71SChen Gang         err = mknod(buffer, SM_LOCAL_MODE_BITS|S_IFREG, 0);
5091c293312SVenkateswararao Jujjuri (JV)         if (err == -1) {
5102289be19SAneesh Kumar K.V             goto out;
5111c293312SVenkateswararao Jujjuri (JV)         }
5124fa4ce71SChen Gang         err = local_set_xattr(buffer, credp);
5131c293312SVenkateswararao Jujjuri (JV)         if (err == -1) {
5141c293312SVenkateswararao Jujjuri (JV)             serrno = errno;
5151c293312SVenkateswararao Jujjuri (JV)             goto err_end;
5161c293312SVenkateswararao Jujjuri (JV)         }
5172c30dd74SAneesh Kumar K.V     } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
5182c30dd74SAneesh Kumar K.V 
5194fa4ce71SChen Gang         buffer = rpath(fs_ctx, path);
5204fa4ce71SChen Gang         err = mknod(buffer, SM_LOCAL_MODE_BITS|S_IFREG, 0);
5212c30dd74SAneesh Kumar K.V         if (err == -1) {
5222c30dd74SAneesh Kumar K.V             goto out;
5232c30dd74SAneesh Kumar K.V         }
5242c30dd74SAneesh Kumar K.V         err = local_set_mapped_file_attr(fs_ctx, path, credp);
5252c30dd74SAneesh Kumar K.V         if (err == -1) {
5262c30dd74SAneesh Kumar K.V             serrno = errno;
5272c30dd74SAneesh Kumar K.V             goto err_end;
5282c30dd74SAneesh Kumar K.V         }
529b97400caSAneesh Kumar K.V     } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
530b97400caSAneesh Kumar K.V                (fs_ctx->export_flags & V9FS_SM_NONE)) {
5314fa4ce71SChen Gang         buffer = rpath(fs_ctx, path);
5324fa4ce71SChen Gang         err = mknod(buffer, credp->fc_mode, credp->fc_rdev);
5331c293312SVenkateswararao Jujjuri (JV)         if (err == -1) {
5342289be19SAneesh Kumar K.V             goto out;
5351c293312SVenkateswararao Jujjuri (JV)         }
5361c293312SVenkateswararao Jujjuri (JV)         err = local_post_create_passthrough(fs_ctx, path, credp);
5371c293312SVenkateswararao Jujjuri (JV)         if (err == -1) {
5381c293312SVenkateswararao Jujjuri (JV)             serrno = errno;
5391c293312SVenkateswararao Jujjuri (JV)             goto err_end;
5401c293312SVenkateswararao Jujjuri (JV)         }
5411c293312SVenkateswararao Jujjuri (JV)     }
5422289be19SAneesh Kumar K.V     goto out;
5431c293312SVenkateswararao Jujjuri (JV) 
5441c293312SVenkateswararao Jujjuri (JV) err_end:
5454fa4ce71SChen Gang     remove(buffer);
5461c293312SVenkateswararao Jujjuri (JV)     errno = serrno;
5472289be19SAneesh Kumar K.V out:
5484ed7b2c3SStefan Weil     g_free(buffer);
5492289be19SAneesh Kumar K.V     v9fs_string_free(&fullname);
5501c293312SVenkateswararao Jujjuri (JV)     return err;
551c494dd6fSAnthony Liguori }
552c494dd6fSAnthony Liguori 
5532289be19SAneesh Kumar K.V static int local_mkdir(FsContext *fs_ctx, V9fsPath *dir_path,
5542289be19SAneesh Kumar K.V                        const char *name, FsCred *credp)
555c494dd6fSAnthony Liguori {
5562289be19SAneesh Kumar K.V     char *path;
55700ec5c37SVenkateswararao Jujjuri (JV)     int err = -1;
55800ec5c37SVenkateswararao Jujjuri (JV)     int serrno = 0;
5592289be19SAneesh Kumar K.V     V9fsString fullname;
5604ed7b2c3SStefan Weil     char *buffer = NULL;
56100ec5c37SVenkateswararao Jujjuri (JV) 
5622289be19SAneesh Kumar K.V     v9fs_string_init(&fullname);
5632289be19SAneesh Kumar K.V     v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
5642289be19SAneesh Kumar K.V     path = fullname.data;
5652289be19SAneesh Kumar K.V 
56600ec5c37SVenkateswararao Jujjuri (JV)     /* Determine the security model */
567b97400caSAneesh Kumar K.V     if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
5684fa4ce71SChen Gang         buffer = rpath(fs_ctx, path);
5694fa4ce71SChen Gang         err = mkdir(buffer, SM_LOCAL_DIR_MODE_BITS);
57000ec5c37SVenkateswararao Jujjuri (JV)         if (err == -1) {
5712289be19SAneesh Kumar K.V             goto out;
57200ec5c37SVenkateswararao Jujjuri (JV)         }
57300ec5c37SVenkateswararao Jujjuri (JV)         credp->fc_mode = credp->fc_mode|S_IFDIR;
5744fa4ce71SChen Gang         err = local_set_xattr(buffer, credp);
57500ec5c37SVenkateswararao Jujjuri (JV)         if (err == -1) {
57600ec5c37SVenkateswararao Jujjuri (JV)             serrno = errno;
57700ec5c37SVenkateswararao Jujjuri (JV)             goto err_end;
57800ec5c37SVenkateswararao Jujjuri (JV)         }
5792c30dd74SAneesh Kumar K.V     } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
5804fa4ce71SChen Gang         buffer = rpath(fs_ctx, path);
5814fa4ce71SChen Gang         err = mkdir(buffer, SM_LOCAL_DIR_MODE_BITS);
5822c30dd74SAneesh Kumar K.V         if (err == -1) {
5832c30dd74SAneesh Kumar K.V             goto out;
5842c30dd74SAneesh Kumar K.V         }
5852c30dd74SAneesh Kumar K.V         credp->fc_mode = credp->fc_mode|S_IFDIR;
5862c30dd74SAneesh Kumar K.V         err = local_set_mapped_file_attr(fs_ctx, path, credp);
5872c30dd74SAneesh Kumar K.V         if (err == -1) {
5882c30dd74SAneesh Kumar K.V             serrno = errno;
5892c30dd74SAneesh Kumar K.V             goto err_end;
5902c30dd74SAneesh Kumar K.V         }
591b97400caSAneesh Kumar K.V     } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
592b97400caSAneesh Kumar K.V                (fs_ctx->export_flags & V9FS_SM_NONE)) {
5934fa4ce71SChen Gang         buffer = rpath(fs_ctx, path);
5944fa4ce71SChen Gang         err = mkdir(buffer, credp->fc_mode);
59500ec5c37SVenkateswararao Jujjuri (JV)         if (err == -1) {
5962289be19SAneesh Kumar K.V             goto out;
59700ec5c37SVenkateswararao Jujjuri (JV)         }
59800ec5c37SVenkateswararao Jujjuri (JV)         err = local_post_create_passthrough(fs_ctx, path, credp);
59900ec5c37SVenkateswararao Jujjuri (JV)         if (err == -1) {
60000ec5c37SVenkateswararao Jujjuri (JV)             serrno = errno;
60100ec5c37SVenkateswararao Jujjuri (JV)             goto err_end;
60200ec5c37SVenkateswararao Jujjuri (JV)         }
60300ec5c37SVenkateswararao Jujjuri (JV)     }
6042289be19SAneesh Kumar K.V     goto out;
60500ec5c37SVenkateswararao Jujjuri (JV) 
60600ec5c37SVenkateswararao Jujjuri (JV) err_end:
6074fa4ce71SChen Gang     remove(buffer);
60800ec5c37SVenkateswararao Jujjuri (JV)     errno = serrno;
6092289be19SAneesh Kumar K.V out:
6104ed7b2c3SStefan Weil     g_free(buffer);
6112289be19SAneesh Kumar K.V     v9fs_string_free(&fullname);
61200ec5c37SVenkateswararao Jujjuri (JV)     return err;
613c494dd6fSAnthony Liguori }
614c494dd6fSAnthony Liguori 
6158b888272SAneesh Kumar K.V static int local_fstat(FsContext *fs_ctx, int fid_type,
616cc720ddbSAneesh Kumar K.V                        V9fsFidOpenState *fs, struct stat *stbuf)
617c494dd6fSAnthony Liguori {
6188b888272SAneesh Kumar K.V     int err, fd;
6198b888272SAneesh Kumar K.V 
6208b888272SAneesh Kumar K.V     if (fid_type == P9_FID_DIR) {
621f314ea4eSGreg Kurz         fd = dirfd(fs->dir.stream);
6228b888272SAneesh Kumar K.V     } else {
6238b888272SAneesh Kumar K.V         fd = fs->fd;
6248b888272SAneesh Kumar K.V     }
6258b888272SAneesh Kumar K.V 
6268b888272SAneesh Kumar K.V     err = fstat(fd, stbuf);
6271237ad76SVenkateswararao Jujjuri (JV)     if (err) {
6281237ad76SVenkateswararao Jujjuri (JV)         return err;
6291237ad76SVenkateswararao Jujjuri (JV)     }
630b97400caSAneesh Kumar K.V     if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
6311237ad76SVenkateswararao Jujjuri (JV)         /* Actual credentials are part of extended attrs */
6321237ad76SVenkateswararao Jujjuri (JV)         uid_t tmp_uid;
6331237ad76SVenkateswararao Jujjuri (JV)         gid_t tmp_gid;
6341237ad76SVenkateswararao Jujjuri (JV)         mode_t tmp_mode;
6351237ad76SVenkateswararao Jujjuri (JV)         dev_t tmp_dev;
6361237ad76SVenkateswararao Jujjuri (JV) 
637f8ad4a89SAneesh Kumar K.V         if (fgetxattr(fd, "user.virtfs.uid", &tmp_uid, sizeof(uid_t)) > 0) {
638f8ad4a89SAneesh Kumar K.V             stbuf->st_uid = le32_to_cpu(tmp_uid);
6391237ad76SVenkateswararao Jujjuri (JV)         }
640f8ad4a89SAneesh Kumar K.V         if (fgetxattr(fd, "user.virtfs.gid", &tmp_gid, sizeof(gid_t)) > 0) {
641f8ad4a89SAneesh Kumar K.V             stbuf->st_gid = le32_to_cpu(tmp_gid);
6421237ad76SVenkateswararao Jujjuri (JV)         }
643f8ad4a89SAneesh Kumar K.V         if (fgetxattr(fd, "user.virtfs.mode", &tmp_mode, sizeof(mode_t)) > 0) {
644f8ad4a89SAneesh Kumar K.V             stbuf->st_mode = le32_to_cpu(tmp_mode);
6451237ad76SVenkateswararao Jujjuri (JV)         }
646f8ad4a89SAneesh Kumar K.V         if (fgetxattr(fd, "user.virtfs.rdev", &tmp_dev, sizeof(dev_t)) > 0) {
647f8ad4a89SAneesh Kumar K.V             stbuf->st_rdev = le64_to_cpu(tmp_dev);
6481237ad76SVenkateswararao Jujjuri (JV)         }
6492c30dd74SAneesh Kumar K.V     } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
6502c30dd74SAneesh Kumar K.V         errno = EOPNOTSUPP;
6512c30dd74SAneesh Kumar K.V         return -1;
6521237ad76SVenkateswararao Jujjuri (JV)     }
6531237ad76SVenkateswararao Jujjuri (JV)     return err;
654c494dd6fSAnthony Liguori }
655c494dd6fSAnthony Liguori 
6562289be19SAneesh Kumar K.V static int local_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name,
657cc720ddbSAneesh Kumar K.V                        int flags, FsCred *credp, V9fsFidOpenState *fs)
658c494dd6fSAnthony Liguori {
6592289be19SAneesh Kumar K.V     char *path;
6604750a96fSVenkateswararao Jujjuri (JV)     int fd = -1;
6614750a96fSVenkateswararao Jujjuri (JV)     int err = -1;
6624750a96fSVenkateswararao Jujjuri (JV)     int serrno = 0;
6632289be19SAneesh Kumar K.V     V9fsString fullname;
6644ed7b2c3SStefan Weil     char *buffer = NULL;
6654750a96fSVenkateswararao Jujjuri (JV) 
6660ceb092eSAneesh Kumar K.V     /*
6670ceb092eSAneesh Kumar K.V      * Mark all the open to not follow symlinks
6680ceb092eSAneesh Kumar K.V      */
6690ceb092eSAneesh Kumar K.V     flags |= O_NOFOLLOW;
6700ceb092eSAneesh Kumar K.V 
6712289be19SAneesh Kumar K.V     v9fs_string_init(&fullname);
6722289be19SAneesh Kumar K.V     v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
6732289be19SAneesh Kumar K.V     path = fullname.data;
6742289be19SAneesh Kumar K.V 
6754750a96fSVenkateswararao Jujjuri (JV)     /* Determine the security model */
676b97400caSAneesh Kumar K.V     if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
6774fa4ce71SChen Gang         buffer = rpath(fs_ctx, path);
6784fa4ce71SChen Gang         fd = open(buffer, flags, SM_LOCAL_MODE_BITS);
6794750a96fSVenkateswararao Jujjuri (JV)         if (fd == -1) {
6802289be19SAneesh Kumar K.V             err = fd;
6812289be19SAneesh Kumar K.V             goto out;
6824750a96fSVenkateswararao Jujjuri (JV)         }
6834750a96fSVenkateswararao Jujjuri (JV)         credp->fc_mode = credp->fc_mode|S_IFREG;
6844750a96fSVenkateswararao Jujjuri (JV)         /* Set cleint credentials in xattr */
6854fa4ce71SChen Gang         err = local_set_xattr(buffer, credp);
6864750a96fSVenkateswararao Jujjuri (JV)         if (err == -1) {
6874750a96fSVenkateswararao Jujjuri (JV)             serrno = errno;
6884750a96fSVenkateswararao Jujjuri (JV)             goto err_end;
6894750a96fSVenkateswararao Jujjuri (JV)         }
6902c30dd74SAneesh Kumar K.V     } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
6914fa4ce71SChen Gang         buffer = rpath(fs_ctx, path);
6924fa4ce71SChen Gang         fd = open(buffer, flags, SM_LOCAL_MODE_BITS);
6932c30dd74SAneesh Kumar K.V         if (fd == -1) {
6942c30dd74SAneesh Kumar K.V             err = fd;
6952c30dd74SAneesh Kumar K.V             goto out;
6962c30dd74SAneesh Kumar K.V         }
6972c30dd74SAneesh Kumar K.V         credp->fc_mode = credp->fc_mode|S_IFREG;
6982c30dd74SAneesh Kumar K.V         /* Set client credentials in .virtfs_metadata directory files */
6992c30dd74SAneesh Kumar K.V         err = local_set_mapped_file_attr(fs_ctx, path, credp);
7002c30dd74SAneesh Kumar K.V         if (err == -1) {
7012c30dd74SAneesh Kumar K.V             serrno = errno;
7022c30dd74SAneesh Kumar K.V             goto err_end;
7032c30dd74SAneesh Kumar K.V         }
704b97400caSAneesh Kumar K.V     } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
705b97400caSAneesh Kumar K.V                (fs_ctx->export_flags & V9FS_SM_NONE)) {
7064fa4ce71SChen Gang         buffer = rpath(fs_ctx, path);
7074fa4ce71SChen Gang         fd = open(buffer, flags, credp->fc_mode);
7084750a96fSVenkateswararao Jujjuri (JV)         if (fd == -1) {
7092289be19SAneesh Kumar K.V             err = fd;
7102289be19SAneesh Kumar K.V             goto out;
7114750a96fSVenkateswararao Jujjuri (JV)         }
7124750a96fSVenkateswararao Jujjuri (JV)         err = local_post_create_passthrough(fs_ctx, path, credp);
7134750a96fSVenkateswararao Jujjuri (JV)         if (err == -1) {
7144750a96fSVenkateswararao Jujjuri (JV)             serrno = errno;
7154750a96fSVenkateswararao Jujjuri (JV)             goto err_end;
7164750a96fSVenkateswararao Jujjuri (JV)         }
7174750a96fSVenkateswararao Jujjuri (JV)     }
7182289be19SAneesh Kumar K.V     err = fd;
719cc720ddbSAneesh Kumar K.V     fs->fd = fd;
7202289be19SAneesh Kumar K.V     goto out;
7214750a96fSVenkateswararao Jujjuri (JV) 
7224750a96fSVenkateswararao Jujjuri (JV) err_end:
7234750a96fSVenkateswararao Jujjuri (JV)     close(fd);
7244fa4ce71SChen Gang     remove(buffer);
7254750a96fSVenkateswararao Jujjuri (JV)     errno = serrno;
7262289be19SAneesh Kumar K.V out:
7274ed7b2c3SStefan Weil     g_free(buffer);
7282289be19SAneesh Kumar K.V     v9fs_string_free(&fullname);
7294750a96fSVenkateswararao Jujjuri (JV)     return err;
730c494dd6fSAnthony Liguori }
731c494dd6fSAnthony Liguori 
732758e8e38SVenkateswararao Jujjuri (JV) 
733879c2813SVenkateswararao Jujjuri (JV) static int local_symlink(FsContext *fs_ctx, const char *oldpath,
7342289be19SAneesh Kumar K.V                          V9fsPath *dir_path, const char *name, FsCred *credp)
735c494dd6fSAnthony Liguori {
736879c2813SVenkateswararao Jujjuri (JV)     int err = -1;
737879c2813SVenkateswararao Jujjuri (JV)     int serrno = 0;
7382289be19SAneesh Kumar K.V     char *newpath;
7392289be19SAneesh Kumar K.V     V9fsString fullname;
7404ed7b2c3SStefan Weil     char *buffer = NULL;
741879c2813SVenkateswararao Jujjuri (JV) 
7422289be19SAneesh Kumar K.V     v9fs_string_init(&fullname);
7432289be19SAneesh Kumar K.V     v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
7442289be19SAneesh Kumar K.V     newpath = fullname.data;
7452289be19SAneesh Kumar K.V 
746879c2813SVenkateswararao Jujjuri (JV)     /* Determine the security model */
747b97400caSAneesh Kumar K.V     if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
748879c2813SVenkateswararao Jujjuri (JV)         int fd;
749879c2813SVenkateswararao Jujjuri (JV)         ssize_t oldpath_size, write_size;
7504fa4ce71SChen Gang         buffer = rpath(fs_ctx, newpath);
7514fa4ce71SChen Gang         fd = open(buffer, O_CREAT|O_EXCL|O_RDWR|O_NOFOLLOW, SM_LOCAL_MODE_BITS);
752879c2813SVenkateswararao Jujjuri (JV)         if (fd == -1) {
7532289be19SAneesh Kumar K.V             err = fd;
7542289be19SAneesh Kumar K.V             goto out;
755879c2813SVenkateswararao Jujjuri (JV)         }
756879c2813SVenkateswararao Jujjuri (JV)         /* Write the oldpath (target) to the file. */
757f35bde2fSHarsh Prateek Bora         oldpath_size = strlen(oldpath);
758879c2813SVenkateswararao Jujjuri (JV)         do {
759879c2813SVenkateswararao Jujjuri (JV)             write_size = write(fd, (void *)oldpath, oldpath_size);
760879c2813SVenkateswararao Jujjuri (JV)         } while (write_size == -1 && errno == EINTR);
761879c2813SVenkateswararao Jujjuri (JV) 
762879c2813SVenkateswararao Jujjuri (JV)         if (write_size != oldpath_size) {
763879c2813SVenkateswararao Jujjuri (JV)             serrno = errno;
764879c2813SVenkateswararao Jujjuri (JV)             close(fd);
765879c2813SVenkateswararao Jujjuri (JV)             err = -1;
766879c2813SVenkateswararao Jujjuri (JV)             goto err_end;
767879c2813SVenkateswararao Jujjuri (JV)         }
768879c2813SVenkateswararao Jujjuri (JV)         close(fd);
769879c2813SVenkateswararao Jujjuri (JV)         /* Set cleint credentials in symlink's xattr */
770879c2813SVenkateswararao Jujjuri (JV)         credp->fc_mode = credp->fc_mode|S_IFLNK;
7714fa4ce71SChen Gang         err = local_set_xattr(buffer, credp);
772879c2813SVenkateswararao Jujjuri (JV)         if (err == -1) {
773879c2813SVenkateswararao Jujjuri (JV)             serrno = errno;
774879c2813SVenkateswararao Jujjuri (JV)             goto err_end;
775879c2813SVenkateswararao Jujjuri (JV)         }
7762c30dd74SAneesh Kumar K.V     } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
7772c30dd74SAneesh Kumar K.V         int fd;
7782c30dd74SAneesh Kumar K.V         ssize_t oldpath_size, write_size;
7794fa4ce71SChen Gang         buffer = rpath(fs_ctx, newpath);
7804fa4ce71SChen Gang         fd = open(buffer, O_CREAT|O_EXCL|O_RDWR|O_NOFOLLOW, SM_LOCAL_MODE_BITS);
7812c30dd74SAneesh Kumar K.V         if (fd == -1) {
7822c30dd74SAneesh Kumar K.V             err = fd;
7832c30dd74SAneesh Kumar K.V             goto out;
7842c30dd74SAneesh Kumar K.V         }
7852c30dd74SAneesh Kumar K.V         /* Write the oldpath (target) to the file. */
7862c30dd74SAneesh Kumar K.V         oldpath_size = strlen(oldpath);
7872c30dd74SAneesh Kumar K.V         do {
7882c30dd74SAneesh Kumar K.V             write_size = write(fd, (void *)oldpath, oldpath_size);
7892c30dd74SAneesh Kumar K.V         } while (write_size == -1 && errno == EINTR);
7902c30dd74SAneesh Kumar K.V 
7912c30dd74SAneesh Kumar K.V         if (write_size != oldpath_size) {
7922c30dd74SAneesh Kumar K.V             serrno = errno;
7932c30dd74SAneesh Kumar K.V             close(fd);
7942c30dd74SAneesh Kumar K.V             err = -1;
7952c30dd74SAneesh Kumar K.V             goto err_end;
7962c30dd74SAneesh Kumar K.V         }
7972c30dd74SAneesh Kumar K.V         close(fd);
7982c30dd74SAneesh Kumar K.V         /* Set cleint credentials in symlink's xattr */
7992c30dd74SAneesh Kumar K.V         credp->fc_mode = credp->fc_mode|S_IFLNK;
8002c30dd74SAneesh Kumar K.V         err = local_set_mapped_file_attr(fs_ctx, newpath, credp);
8012c30dd74SAneesh Kumar K.V         if (err == -1) {
8022c30dd74SAneesh Kumar K.V             serrno = errno;
8032c30dd74SAneesh Kumar K.V             goto err_end;
8042c30dd74SAneesh Kumar K.V         }
805b97400caSAneesh Kumar K.V     } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
806b97400caSAneesh Kumar K.V                (fs_ctx->export_flags & V9FS_SM_NONE)) {
8074fa4ce71SChen Gang         buffer = rpath(fs_ctx, newpath);
8084fa4ce71SChen Gang         err = symlink(oldpath, buffer);
809879c2813SVenkateswararao Jujjuri (JV)         if (err) {
8102289be19SAneesh Kumar K.V             goto out;
811879c2813SVenkateswararao Jujjuri (JV)         }
8124fa4ce71SChen Gang         err = lchown(buffer, credp->fc_uid, credp->fc_gid);
813879c2813SVenkateswararao Jujjuri (JV)         if (err == -1) {
81412848bfcSAneesh Kumar K.V             /*
81512848bfcSAneesh Kumar K.V              * If we fail to change ownership and if we are
81612848bfcSAneesh Kumar K.V              * using security model none. Ignore the error
81712848bfcSAneesh Kumar K.V              */
818b97400caSAneesh Kumar K.V             if ((fs_ctx->export_flags & V9FS_SEC_MASK) != V9FS_SM_NONE) {
819879c2813SVenkateswararao Jujjuri (JV)                 serrno = errno;
820879c2813SVenkateswararao Jujjuri (JV)                 goto err_end;
82112848bfcSAneesh Kumar K.V             } else
82212848bfcSAneesh Kumar K.V                 err = 0;
823879c2813SVenkateswararao Jujjuri (JV)         }
824879c2813SVenkateswararao Jujjuri (JV)     }
8252289be19SAneesh Kumar K.V     goto out;
826879c2813SVenkateswararao Jujjuri (JV) 
827879c2813SVenkateswararao Jujjuri (JV) err_end:
8284fa4ce71SChen Gang     remove(buffer);
829879c2813SVenkateswararao Jujjuri (JV)     errno = serrno;
8302289be19SAneesh Kumar K.V out:
8314ed7b2c3SStefan Weil     g_free(buffer);
8322289be19SAneesh Kumar K.V     v9fs_string_free(&fullname);
833879c2813SVenkateswararao Jujjuri (JV)     return err;
834c494dd6fSAnthony Liguori }
835c494dd6fSAnthony Liguori 
8362289be19SAneesh Kumar K.V static int local_link(FsContext *ctx, V9fsPath *oldpath,
8372289be19SAneesh Kumar K.V                       V9fsPath *dirpath, const char *name)
838c494dd6fSAnthony Liguori {
8392289be19SAneesh Kumar K.V     int ret;
8402289be19SAneesh Kumar K.V     V9fsString newpath;
8414fa4ce71SChen Gang     char *buffer, *buffer1;
842c494dd6fSAnthony Liguori 
8432289be19SAneesh Kumar K.V     v9fs_string_init(&newpath);
8442289be19SAneesh Kumar K.V     v9fs_string_sprintf(&newpath, "%s/%s", dirpath->data, name);
8452289be19SAneesh Kumar K.V 
8464fa4ce71SChen Gang     buffer = rpath(ctx, oldpath->data);
8474fa4ce71SChen Gang     buffer1 = rpath(ctx, newpath.data);
8484fa4ce71SChen Gang     ret = link(buffer, buffer1);
8494fa4ce71SChen Gang     g_free(buffer);
8504fa4ce71SChen Gang     g_free(buffer1);
8512c30dd74SAneesh Kumar K.V 
8522c30dd74SAneesh Kumar K.V     /* now link the virtfs_metadata files */
8532c30dd74SAneesh Kumar K.V     if (!ret && (ctx->export_flags & V9FS_SM_MAPPED_FILE)) {
8542c30dd74SAneesh Kumar K.V         /* Link the .virtfs_metadata files. Create the metada directory */
8552c30dd74SAneesh Kumar K.V         ret = local_create_mapped_attr_dir(ctx, newpath.data);
8562c30dd74SAneesh Kumar K.V         if (ret < 0) {
8572c30dd74SAneesh Kumar K.V             goto err_out;
8582c30dd74SAneesh Kumar K.V         }
8594fa4ce71SChen Gang         buffer = local_mapped_attr_path(ctx, oldpath->data);
8604fa4ce71SChen Gang         buffer1 = local_mapped_attr_path(ctx, newpath.data);
8614fa4ce71SChen Gang         ret = link(buffer, buffer1);
8624fa4ce71SChen Gang         g_free(buffer);
8634fa4ce71SChen Gang         g_free(buffer1);
8642c30dd74SAneesh Kumar K.V         if (ret < 0 && errno != ENOENT) {
8652c30dd74SAneesh Kumar K.V             goto err_out;
8662c30dd74SAneesh Kumar K.V         }
8672c30dd74SAneesh Kumar K.V     }
8682c30dd74SAneesh Kumar K.V err_out:
8692289be19SAneesh Kumar K.V     v9fs_string_free(&newpath);
8702289be19SAneesh Kumar K.V     return ret;
871c494dd6fSAnthony Liguori }
872c494dd6fSAnthony Liguori 
8732289be19SAneesh Kumar K.V static int local_truncate(FsContext *ctx, V9fsPath *fs_path, off_t size)
8748cf89e00SAnthony Liguori {
8754fa4ce71SChen Gang     char *buffer;
8764fa4ce71SChen Gang     int ret;
8772289be19SAneesh Kumar K.V     char *path = fs_path->data;
8782289be19SAneesh Kumar K.V 
8794fa4ce71SChen Gang     buffer = rpath(ctx, path);
8804fa4ce71SChen Gang     ret = truncate(buffer, size);
8814fa4ce71SChen Gang     g_free(buffer);
8824fa4ce71SChen Gang     return ret;
8838cf89e00SAnthony Liguori }
8848cf89e00SAnthony Liguori 
8858cf89e00SAnthony Liguori static int local_rename(FsContext *ctx, const char *oldpath,
8868cf89e00SAnthony Liguori                         const char *newpath)
8878cf89e00SAnthony Liguori {
8882c30dd74SAneesh Kumar K.V     int err;
8894fa4ce71SChen Gang     char *buffer, *buffer1;
8908cf89e00SAnthony Liguori 
8912c30dd74SAneesh Kumar K.V     if (ctx->export_flags & V9FS_SM_MAPPED_FILE) {
8922c30dd74SAneesh Kumar K.V         err = local_create_mapped_attr_dir(ctx, newpath);
8932c30dd74SAneesh Kumar K.V         if (err < 0) {
8942c30dd74SAneesh Kumar K.V             return err;
8952c30dd74SAneesh Kumar K.V         }
8962c30dd74SAneesh Kumar K.V         /* rename the .virtfs_metadata files */
8974fa4ce71SChen Gang         buffer = local_mapped_attr_path(ctx, oldpath);
8984fa4ce71SChen Gang         buffer1 = local_mapped_attr_path(ctx, newpath);
8994fa4ce71SChen Gang         err = rename(buffer, buffer1);
9004fa4ce71SChen Gang         g_free(buffer);
9014fa4ce71SChen Gang         g_free(buffer1);
9022c30dd74SAneesh Kumar K.V         if (err < 0 && errno != ENOENT) {
9032c30dd74SAneesh Kumar K.V             return err;
9042c30dd74SAneesh Kumar K.V         }
9052c30dd74SAneesh Kumar K.V     }
9064fa4ce71SChen Gang 
9074fa4ce71SChen Gang     buffer = rpath(ctx, oldpath);
9084fa4ce71SChen Gang     buffer1 = rpath(ctx, newpath);
9094fa4ce71SChen Gang     err = rename(buffer, buffer1);
9104fa4ce71SChen Gang     g_free(buffer);
9114fa4ce71SChen Gang     g_free(buffer1);
9124fa4ce71SChen Gang     return err;
9138cf89e00SAnthony Liguori }
9148cf89e00SAnthony Liguori 
9152289be19SAneesh Kumar K.V static int local_chown(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
9168cf89e00SAnthony Liguori {
9174fa4ce71SChen Gang     char *buffer;
9184fa4ce71SChen Gang     int ret = -1;
9192289be19SAneesh Kumar K.V     char *path = fs_path->data;
9202289be19SAneesh Kumar K.V 
921c79ce737SSripathi Kodi     if ((credp->fc_uid == -1 && credp->fc_gid == -1) ||
92217b1971fSAneesh Kumar K.V         (fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
92317b1971fSAneesh Kumar K.V         (fs_ctx->export_flags & V9FS_SM_NONE)) {
9244fa4ce71SChen Gang         buffer = rpath(fs_ctx, path);
9254fa4ce71SChen Gang         ret = lchown(buffer, credp->fc_uid, credp->fc_gid);
9264fa4ce71SChen Gang         g_free(buffer);
927b97400caSAneesh Kumar K.V     } else if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
9284fa4ce71SChen Gang         buffer = rpath(fs_ctx, path);
9294fa4ce71SChen Gang         ret = local_set_xattr(buffer, credp);
9304fa4ce71SChen Gang         g_free(buffer);
9312c30dd74SAneesh Kumar K.V     } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
9322c30dd74SAneesh Kumar K.V         return local_set_mapped_file_attr(fs_ctx, path, credp);
933f7613beeSVenkateswararao Jujjuri (JV)     }
9344fa4ce71SChen Gang     return ret;
9358cf89e00SAnthony Liguori }
9368cf89e00SAnthony Liguori 
9372289be19SAneesh Kumar K.V static int local_utimensat(FsContext *s, V9fsPath *fs_path,
93874bc02b2SM. Mohan Kumar                            const struct timespec *buf)
9398cf89e00SAnthony Liguori {
9404fa4ce71SChen Gang     char *buffer;
9414fa4ce71SChen Gang     int ret;
9422289be19SAneesh Kumar K.V     char *path = fs_path->data;
9432289be19SAneesh Kumar K.V 
9444fa4ce71SChen Gang     buffer = rpath(s, path);
9454fa4ce71SChen Gang     ret = qemu_utimens(buffer, buf);
9464fa4ce71SChen Gang     g_free(buffer);
9474fa4ce71SChen Gang     return ret;
9488cf89e00SAnthony Liguori }
9498cf89e00SAnthony Liguori 
9505bae1900SAnthony Liguori static int local_remove(FsContext *ctx, const char *path)
9515bae1900SAnthony Liguori {
9522c30dd74SAneesh Kumar K.V     int err;
9532c30dd74SAneesh Kumar K.V     struct stat stbuf;
9544fa4ce71SChen Gang     char *buffer;
9552c30dd74SAneesh Kumar K.V 
9562c30dd74SAneesh Kumar K.V     if (ctx->export_flags & V9FS_SM_MAPPED_FILE) {
9574fa4ce71SChen Gang         buffer = rpath(ctx, path);
9584fa4ce71SChen Gang         err =  lstat(buffer, &stbuf);
9594fa4ce71SChen Gang         g_free(buffer);
9602c30dd74SAneesh Kumar K.V         if (err) {
9612c30dd74SAneesh Kumar K.V             goto err_out;
9622c30dd74SAneesh Kumar K.V         }
9632c30dd74SAneesh Kumar K.V         /*
9642c30dd74SAneesh Kumar K.V          * If directory remove .virtfs_metadata contained in the
9652c30dd74SAneesh Kumar K.V          * directory
9662c30dd74SAneesh Kumar K.V          */
9672c30dd74SAneesh Kumar K.V         if (S_ISDIR(stbuf.st_mode)) {
9684fa4ce71SChen Gang             buffer = g_strdup_printf("%s/%s/%s", ctx->fs_root,
9694fa4ce71SChen Gang                                      path, VIRTFS_META_DIR);
9702c30dd74SAneesh Kumar K.V             err = remove(buffer);
9714fa4ce71SChen Gang             g_free(buffer);
9722c30dd74SAneesh Kumar K.V             if (err < 0 && errno != ENOENT) {
9732c30dd74SAneesh Kumar K.V                 /*
9742c30dd74SAneesh Kumar K.V                  * We didn't had the .virtfs_metadata file. May be file created
9752c30dd74SAneesh Kumar K.V                  * in non-mapped mode ?. Ignore ENOENT.
9762c30dd74SAneesh Kumar K.V                  */
9772c30dd74SAneesh Kumar K.V                 goto err_out;
9782c30dd74SAneesh Kumar K.V             }
9792c30dd74SAneesh Kumar K.V         }
9802c30dd74SAneesh Kumar K.V         /*
9812c30dd74SAneesh Kumar K.V          * Now remove the name from parent directory
9822c30dd74SAneesh Kumar K.V          * .virtfs_metadata directory
9832c30dd74SAneesh Kumar K.V          */
9844fa4ce71SChen Gang         buffer = local_mapped_attr_path(ctx, path);
9854fa4ce71SChen Gang         err = remove(buffer);
9864fa4ce71SChen Gang         g_free(buffer);
9872c30dd74SAneesh Kumar K.V         if (err < 0 && errno != ENOENT) {
9882c30dd74SAneesh Kumar K.V             /*
9892c30dd74SAneesh Kumar K.V              * We didn't had the .virtfs_metadata file. May be file created
9902c30dd74SAneesh Kumar K.V              * in non-mapped mode ?. Ignore ENOENT.
9912c30dd74SAneesh Kumar K.V              */
9922c30dd74SAneesh Kumar K.V             goto err_out;
9932c30dd74SAneesh Kumar K.V         }
9942c30dd74SAneesh Kumar K.V     }
9954fa4ce71SChen Gang 
9964fa4ce71SChen Gang     buffer = rpath(ctx, path);
9974fa4ce71SChen Gang     err = remove(buffer);
9984fa4ce71SChen Gang     g_free(buffer);
9992c30dd74SAneesh Kumar K.V err_out:
10002c30dd74SAneesh Kumar K.V     return err;
10015bae1900SAnthony Liguori }
10025bae1900SAnthony Liguori 
10038b888272SAneesh Kumar K.V static int local_fsync(FsContext *ctx, int fid_type,
10048b888272SAneesh Kumar K.V                        V9fsFidOpenState *fs, int datasync)
10058cf89e00SAnthony Liguori {
10068b888272SAneesh Kumar K.V     int fd;
10078b888272SAneesh Kumar K.V 
10088b888272SAneesh Kumar K.V     if (fid_type == P9_FID_DIR) {
1009f314ea4eSGreg Kurz         fd = dirfd(fs->dir.stream);
101049594973SVenkateswararao Jujjuri (JV)     } else {
10118b888272SAneesh Kumar K.V         fd = fs->fd;
10128b888272SAneesh Kumar K.V     }
10138b888272SAneesh Kumar K.V 
10148b888272SAneesh Kumar K.V     if (datasync) {
10158b888272SAneesh Kumar K.V         return qemu_fdatasync(fd);
10168b888272SAneesh Kumar K.V     } else {
10178b888272SAneesh Kumar K.V         return fsync(fd);
10188cf89e00SAnthony Liguori     }
101949594973SVenkateswararao Jujjuri (JV) }
10208cf89e00SAnthony Liguori 
10212289be19SAneesh Kumar K.V static int local_statfs(FsContext *s, V9fsPath *fs_path, struct statfs *stbuf)
1022be940c87SM. Mohan Kumar {
10234fa4ce71SChen Gang     char *buffer;
10244fa4ce71SChen Gang     int ret;
10252289be19SAneesh Kumar K.V     char *path = fs_path->data;
10262289be19SAneesh Kumar K.V 
10274fa4ce71SChen Gang     buffer = rpath(s, path);
10284fa4ce71SChen Gang     ret = statfs(buffer, stbuf);
10294fa4ce71SChen Gang     g_free(buffer);
10304fa4ce71SChen Gang     return ret;
1031be940c87SM. Mohan Kumar }
1032be940c87SM. Mohan Kumar 
10332289be19SAneesh Kumar K.V static ssize_t local_lgetxattr(FsContext *ctx, V9fsPath *fs_path,
1034fa32ef88SAneesh Kumar K.V                                const char *name, void *value, size_t size)
1035fa32ef88SAneesh Kumar K.V {
10362289be19SAneesh Kumar K.V     char *path = fs_path->data;
10372289be19SAneesh Kumar K.V 
1038fc22118dSAneesh Kumar K.V     return v9fs_get_xattr(ctx, path, name, value, size);
1039fa32ef88SAneesh Kumar K.V }
1040fa32ef88SAneesh Kumar K.V 
10412289be19SAneesh Kumar K.V static ssize_t local_llistxattr(FsContext *ctx, V9fsPath *fs_path,
1042fa32ef88SAneesh Kumar K.V                                 void *value, size_t size)
1043fa32ef88SAneesh Kumar K.V {
10442289be19SAneesh Kumar K.V     char *path = fs_path->data;
10452289be19SAneesh Kumar K.V 
1046fc22118dSAneesh Kumar K.V     return v9fs_list_xattr(ctx, path, value, size);
104761b6c499SAneesh Kumar K.V }
104861b6c499SAneesh Kumar K.V 
10492289be19SAneesh Kumar K.V static int local_lsetxattr(FsContext *ctx, V9fsPath *fs_path, const char *name,
105010b468bdSAneesh Kumar K.V                            void *value, size_t size, int flags)
105110b468bdSAneesh Kumar K.V {
10522289be19SAneesh Kumar K.V     char *path = fs_path->data;
10532289be19SAneesh Kumar K.V 
1054fc22118dSAneesh Kumar K.V     return v9fs_set_xattr(ctx, path, name, value, size, flags);
105510b468bdSAneesh Kumar K.V }
105610b468bdSAneesh Kumar K.V 
10572289be19SAneesh Kumar K.V static int local_lremovexattr(FsContext *ctx, V9fsPath *fs_path,
10582289be19SAneesh Kumar K.V                               const char *name)
10599ed3ef26SAneesh Kumar K.V {
10602289be19SAneesh Kumar K.V     char *path = fs_path->data;
10612289be19SAneesh Kumar K.V 
1062fc22118dSAneesh Kumar K.V     return v9fs_remove_xattr(ctx, path, name);
10639ed3ef26SAneesh Kumar K.V }
10649ed3ef26SAneesh Kumar K.V 
10652289be19SAneesh Kumar K.V static int local_name_to_path(FsContext *ctx, V9fsPath *dir_path,
10662289be19SAneesh Kumar K.V                               const char *name, V9fsPath *target)
10672289be19SAneesh Kumar K.V {
10682289be19SAneesh Kumar K.V     if (dir_path) {
1069e3e83f2eSGreg Kurz         v9fs_path_sprintf(target, "%s/%s", dir_path->data, name);
10702289be19SAneesh Kumar K.V     } else {
1071e3e83f2eSGreg Kurz         v9fs_path_sprintf(target, "%s", name);
10722289be19SAneesh Kumar K.V     }
10732289be19SAneesh Kumar K.V     return 0;
10742289be19SAneesh Kumar K.V }
10752289be19SAneesh Kumar K.V 
10762289be19SAneesh Kumar K.V static int local_renameat(FsContext *ctx, V9fsPath *olddir,
10772289be19SAneesh Kumar K.V                           const char *old_name, V9fsPath *newdir,
10782289be19SAneesh Kumar K.V                           const char *new_name)
10792289be19SAneesh Kumar K.V {
10802289be19SAneesh Kumar K.V     int ret;
10812289be19SAneesh Kumar K.V     V9fsString old_full_name, new_full_name;
10822289be19SAneesh Kumar K.V 
10832289be19SAneesh Kumar K.V     v9fs_string_init(&old_full_name);
10842289be19SAneesh Kumar K.V     v9fs_string_init(&new_full_name);
10852289be19SAneesh Kumar K.V 
10862289be19SAneesh Kumar K.V     v9fs_string_sprintf(&old_full_name, "%s/%s", olddir->data, old_name);
10872289be19SAneesh Kumar K.V     v9fs_string_sprintf(&new_full_name, "%s/%s", newdir->data, new_name);
10882289be19SAneesh Kumar K.V 
10892289be19SAneesh Kumar K.V     ret = local_rename(ctx, old_full_name.data, new_full_name.data);
10902289be19SAneesh Kumar K.V     v9fs_string_free(&old_full_name);
10912289be19SAneesh Kumar K.V     v9fs_string_free(&new_full_name);
10922289be19SAneesh Kumar K.V     return ret;
10932289be19SAneesh Kumar K.V }
10942289be19SAneesh Kumar K.V 
10952289be19SAneesh Kumar K.V static int local_unlinkat(FsContext *ctx, V9fsPath *dir,
10962289be19SAneesh Kumar K.V                           const char *name, int flags)
10972289be19SAneesh Kumar K.V {
10982289be19SAneesh Kumar K.V     int ret;
10992289be19SAneesh Kumar K.V     V9fsString fullname;
11004fa4ce71SChen Gang     char *buffer;
11012c30dd74SAneesh Kumar K.V 
11022289be19SAneesh Kumar K.V     v9fs_string_init(&fullname);
11032289be19SAneesh Kumar K.V 
11042289be19SAneesh Kumar K.V     v9fs_string_sprintf(&fullname, "%s/%s", dir->data, name);
11052c30dd74SAneesh Kumar K.V     if (ctx->export_flags & V9FS_SM_MAPPED_FILE) {
11062c30dd74SAneesh Kumar K.V         if (flags == AT_REMOVEDIR) {
11072c30dd74SAneesh Kumar K.V             /*
11082c30dd74SAneesh Kumar K.V              * If directory remove .virtfs_metadata contained in the
11092c30dd74SAneesh Kumar K.V              * directory
11102c30dd74SAneesh Kumar K.V              */
11114fa4ce71SChen Gang             buffer = g_strdup_printf("%s/%s/%s", ctx->fs_root,
11122c30dd74SAneesh Kumar K.V                                      fullname.data, VIRTFS_META_DIR);
11132c30dd74SAneesh Kumar K.V             ret = remove(buffer);
11144fa4ce71SChen Gang             g_free(buffer);
11152c30dd74SAneesh Kumar K.V             if (ret < 0 && errno != ENOENT) {
11162c30dd74SAneesh Kumar K.V                 /*
11172c30dd74SAneesh Kumar K.V                  * We didn't had the .virtfs_metadata file. May be file created
11182c30dd74SAneesh Kumar K.V                  * in non-mapped mode ?. Ignore ENOENT.
11192c30dd74SAneesh Kumar K.V                  */
11202c30dd74SAneesh Kumar K.V                 goto err_out;
11212c30dd74SAneesh Kumar K.V             }
11222c30dd74SAneesh Kumar K.V         }
11232c30dd74SAneesh Kumar K.V         /*
11242c30dd74SAneesh Kumar K.V          * Now remove the name from parent directory
11252c30dd74SAneesh Kumar K.V          * .virtfs_metadata directory.
11262c30dd74SAneesh Kumar K.V          */
11274fa4ce71SChen Gang         buffer = local_mapped_attr_path(ctx, fullname.data);
11284fa4ce71SChen Gang         ret = remove(buffer);
11294fa4ce71SChen Gang         g_free(buffer);
11302c30dd74SAneesh Kumar K.V         if (ret < 0 && errno != ENOENT) {
11312c30dd74SAneesh Kumar K.V             /*
11322c30dd74SAneesh Kumar K.V              * We didn't had the .virtfs_metadata file. May be file created
11332c30dd74SAneesh Kumar K.V              * in non-mapped mode ?. Ignore ENOENT.
11342c30dd74SAneesh Kumar K.V              */
11352c30dd74SAneesh Kumar K.V             goto err_out;
11362c30dd74SAneesh Kumar K.V         }
11372c30dd74SAneesh Kumar K.V     }
11382c30dd74SAneesh Kumar K.V     /* Remove the name finally */
11394fa4ce71SChen Gang     buffer = rpath(ctx, fullname.data);
11404fa4ce71SChen Gang     ret = remove(buffer);
11414fa4ce71SChen Gang     g_free(buffer);
11422289be19SAneesh Kumar K.V 
11432c30dd74SAneesh Kumar K.V err_out:
114475b7931eSChen Gang     v9fs_string_free(&fullname);
11452289be19SAneesh Kumar K.V     return ret;
11462289be19SAneesh Kumar K.V }
11479ed3ef26SAneesh Kumar K.V 
1148e06a765eSHarsh Prateek Bora static int local_ioc_getversion(FsContext *ctx, V9fsPath *path,
1149e06a765eSHarsh Prateek Bora                                 mode_t st_mode, uint64_t *st_gen)
1150e06a765eSHarsh Prateek Bora {
1151ae0f940eSPaolo Bonzini #ifdef FS_IOC_GETVERSION
11520e5fc994SKirill A. Shutemov     int err;
1153cc720ddbSAneesh Kumar K.V     V9fsFidOpenState fid_open;
1154cc720ddbSAneesh Kumar K.V 
1155e06a765eSHarsh Prateek Bora     /*
1156e06a765eSHarsh Prateek Bora      * Do not try to open special files like device nodes, fifos etc
1157e06a765eSHarsh Prateek Bora      * We can get fd for regular files and directories only
1158e06a765eSHarsh Prateek Bora      */
1159e06a765eSHarsh Prateek Bora     if (!S_ISREG(st_mode) && !S_ISDIR(st_mode)) {
11601a9978a5SKirill A. Shutemov         errno = ENOTTY;
11611a9978a5SKirill A. Shutemov         return -1;
1162e06a765eSHarsh Prateek Bora     }
1163cc720ddbSAneesh Kumar K.V     err = local_open(ctx, path, O_RDONLY, &fid_open);
1164cc720ddbSAneesh Kumar K.V     if (err < 0) {
1165cc720ddbSAneesh Kumar K.V         return err;
1166e06a765eSHarsh Prateek Bora     }
1167cc720ddbSAneesh Kumar K.V     err = ioctl(fid_open.fd, FS_IOC_GETVERSION, st_gen);
1168cc720ddbSAneesh Kumar K.V     local_close(ctx, &fid_open);
1169e06a765eSHarsh Prateek Bora     return err;
11700e5fc994SKirill A. Shutemov #else
11710e5fc994SKirill A. Shutemov     errno = ENOTTY;
11720e5fc994SKirill A. Shutemov     return -1;
11730e5fc994SKirill A. Shutemov #endif
1174e06a765eSHarsh Prateek Bora }
1175e06a765eSHarsh Prateek Bora 
11760174fe73SAneesh Kumar K.V static int local_init(FsContext *ctx)
11770174fe73SAneesh Kumar K.V {
1178e06a765eSHarsh Prateek Bora     struct statfs stbuf;
1179e06a765eSHarsh Prateek Bora 
118000c90bd1SGreg Kurz #ifdef FS_IOC_GETVERSION
118100c90bd1SGreg Kurz     /*
118200c90bd1SGreg Kurz      * use ioc_getversion only if the ioctl is definied
118300c90bd1SGreg Kurz      */
118400c90bd1SGreg Kurz     if (statfs(ctx->fs_root, &stbuf) < 0) {
118500c90bd1SGreg Kurz         return -1;
118600c90bd1SGreg Kurz     }
118700c90bd1SGreg Kurz     switch (stbuf.f_type) {
118800c90bd1SGreg Kurz     case EXT2_SUPER_MAGIC:
118900c90bd1SGreg Kurz     case BTRFS_SUPER_MAGIC:
119000c90bd1SGreg Kurz     case REISERFS_SUPER_MAGIC:
119100c90bd1SGreg Kurz     case XFS_SUPER_MAGIC:
119200c90bd1SGreg Kurz         ctx->exops.get_st_gen = local_ioc_getversion;
119300c90bd1SGreg Kurz         break;
119400c90bd1SGreg Kurz     }
119500c90bd1SGreg Kurz #endif
119600c90bd1SGreg Kurz 
11972c30dd74SAneesh Kumar K.V     if (ctx->export_flags & V9FS_SM_PASSTHROUGH) {
11982c30dd74SAneesh Kumar K.V         ctx->xops = passthrough_xattr_ops;
11992c30dd74SAneesh Kumar K.V     } else if (ctx->export_flags & V9FS_SM_MAPPED) {
12002c30dd74SAneesh Kumar K.V         ctx->xops = mapped_xattr_ops;
12012c30dd74SAneesh Kumar K.V     } else if (ctx->export_flags & V9FS_SM_NONE) {
12022c30dd74SAneesh Kumar K.V         ctx->xops = none_xattr_ops;
12032c30dd74SAneesh Kumar K.V     } else if (ctx->export_flags & V9FS_SM_MAPPED_FILE) {
12042c30dd74SAneesh Kumar K.V         /*
12052c30dd74SAneesh Kumar K.V          * xattr operation for mapped-file and passthrough
12062c30dd74SAneesh Kumar K.V          * remain same.
12072c30dd74SAneesh Kumar K.V          */
12082c30dd74SAneesh Kumar K.V         ctx->xops = passthrough_xattr_ops;
12092c30dd74SAneesh Kumar K.V     }
1210c98f1d4aSAneesh Kumar K.V     ctx->export_flags |= V9FS_PATHNAME_FSCONTEXT;
121100c90bd1SGreg Kurz 
121200c90bd1SGreg Kurz     return 0;
12130174fe73SAneesh Kumar K.V }
12140174fe73SAneesh Kumar K.V 
121599519f0aSAneesh Kumar K.V static int local_parse_opts(QemuOpts *opts, struct FsDriverEntry *fse)
121699519f0aSAneesh Kumar K.V {
121799519f0aSAneesh Kumar K.V     const char *sec_model = qemu_opt_get(opts, "security_model");
121899519f0aSAneesh Kumar K.V     const char *path = qemu_opt_get(opts, "path");
121999519f0aSAneesh Kumar K.V 
122099519f0aSAneesh Kumar K.V     if (!sec_model) {
122163325b18SGreg Kurz         error_report("Security model not specified, local fs needs security model");
122263325b18SGreg Kurz         error_printf("valid options are:"
122363325b18SGreg Kurz                      "\tsecurity_model=[passthrough|mapped-xattr|mapped-file|none]\n");
122499519f0aSAneesh Kumar K.V         return -1;
122599519f0aSAneesh Kumar K.V     }
122699519f0aSAneesh Kumar K.V 
122799519f0aSAneesh Kumar K.V     if (!strcmp(sec_model, "passthrough")) {
122899519f0aSAneesh Kumar K.V         fse->export_flags |= V9FS_SM_PASSTHROUGH;
12292c30dd74SAneesh Kumar K.V     } else if (!strcmp(sec_model, "mapped") ||
12302c30dd74SAneesh Kumar K.V                !strcmp(sec_model, "mapped-xattr")) {
123199519f0aSAneesh Kumar K.V         fse->export_flags |= V9FS_SM_MAPPED;
123299519f0aSAneesh Kumar K.V     } else if (!strcmp(sec_model, "none")) {
123399519f0aSAneesh Kumar K.V         fse->export_flags |= V9FS_SM_NONE;
12342c30dd74SAneesh Kumar K.V     } else if (!strcmp(sec_model, "mapped-file")) {
12352c30dd74SAneesh Kumar K.V         fse->export_flags |= V9FS_SM_MAPPED_FILE;
123699519f0aSAneesh Kumar K.V     } else {
123763325b18SGreg Kurz         error_report("Invalid security model %s specified", sec_model);
123863325b18SGreg Kurz         error_printf("valid options are:"
123963325b18SGreg Kurz                      "\t[passthrough|mapped-xattr|mapped-file|none]\n");
124099519f0aSAneesh Kumar K.V         return -1;
124199519f0aSAneesh Kumar K.V     }
124299519f0aSAneesh Kumar K.V 
124399519f0aSAneesh Kumar K.V     if (!path) {
124463325b18SGreg Kurz         error_report("fsdev: No path specified");
124599519f0aSAneesh Kumar K.V         return -1;
124699519f0aSAneesh Kumar K.V     }
124799519f0aSAneesh Kumar K.V     fse->path = g_strdup(path);
124899519f0aSAneesh Kumar K.V 
124999519f0aSAneesh Kumar K.V     return 0;
125099519f0aSAneesh Kumar K.V }
125199519f0aSAneesh Kumar K.V 
12529f107513SAnthony Liguori FileOperations local_ops = {
125399519f0aSAneesh Kumar K.V     .parse_opts = local_parse_opts,
12540174fe73SAneesh Kumar K.V     .init  = local_init,
1255131dcb25SAnthony Liguori     .lstat = local_lstat,
1256131dcb25SAnthony Liguori     .readlink = local_readlink,
1257131dcb25SAnthony Liguori     .close = local_close,
1258131dcb25SAnthony Liguori     .closedir = local_closedir,
1259a6568fe2SAnthony Liguori     .open = local_open,
1260a6568fe2SAnthony Liguori     .opendir = local_opendir,
1261a9231555SAnthony Liguori     .rewinddir = local_rewinddir,
1262a9231555SAnthony Liguori     .telldir = local_telldir,
1263635324e8SGreg Kurz     .readdir = local_readdir,
1264a9231555SAnthony Liguori     .seekdir = local_seekdir,
126556d15a53SSanchit Garg     .preadv = local_preadv,
126656d15a53SSanchit Garg     .pwritev = local_pwritev,
1267c494dd6fSAnthony Liguori     .chmod = local_chmod,
1268c494dd6fSAnthony Liguori     .mknod = local_mknod,
1269c494dd6fSAnthony Liguori     .mkdir = local_mkdir,
1270c494dd6fSAnthony Liguori     .fstat = local_fstat,
1271c494dd6fSAnthony Liguori     .open2 = local_open2,
1272c494dd6fSAnthony Liguori     .symlink = local_symlink,
1273c494dd6fSAnthony Liguori     .link = local_link,
12748cf89e00SAnthony Liguori     .truncate = local_truncate,
12758cf89e00SAnthony Liguori     .rename = local_rename,
12768cf89e00SAnthony Liguori     .chown = local_chown,
127774bc02b2SM. Mohan Kumar     .utimensat = local_utimensat,
12785bae1900SAnthony Liguori     .remove = local_remove,
12798cf89e00SAnthony Liguori     .fsync = local_fsync,
1280be940c87SM. Mohan Kumar     .statfs = local_statfs,
1281fa32ef88SAneesh Kumar K.V     .lgetxattr = local_lgetxattr,
1282fa32ef88SAneesh Kumar K.V     .llistxattr = local_llistxattr,
128310b468bdSAneesh Kumar K.V     .lsetxattr = local_lsetxattr,
12849ed3ef26SAneesh Kumar K.V     .lremovexattr = local_lremovexattr,
12852289be19SAneesh Kumar K.V     .name_to_path = local_name_to_path,
12862289be19SAneesh Kumar K.V     .renameat  = local_renameat,
12872289be19SAneesh Kumar K.V     .unlinkat = local_unlinkat,
12889f107513SAnthony Liguori };
1289