xref: /qemu/hw/9pfs/9p-local.c (revision e3e83f2e2130a3afbd41a2893d23397f03f6d9d0)
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;
3592289be19SAneesh Kumar K.V 
3604fa4ce71SChen Gang     buffer = rpath(ctx, path);
3614fa4ce71SChen Gang     fs->fd = open(buffer, flags | O_NOFOLLOW);
3624fa4ce71SChen Gang     g_free(buffer);
363cc720ddbSAneesh Kumar K.V     return fs->fd;
364a6568fe2SAnthony Liguori }
365a6568fe2SAnthony Liguori 
366cc720ddbSAneesh Kumar K.V static int local_opendir(FsContext *ctx,
367cc720ddbSAneesh Kumar K.V                          V9fsPath *fs_path, V9fsFidOpenState *fs)
368a6568fe2SAnthony Liguori {
3694fa4ce71SChen Gang     char *buffer;
3702289be19SAneesh Kumar K.V     char *path = fs_path->data;
3712289be19SAneesh Kumar K.V 
3724fa4ce71SChen Gang     buffer = rpath(ctx, path);
373f314ea4eSGreg Kurz     fs->dir.stream = opendir(buffer);
3744fa4ce71SChen Gang     g_free(buffer);
375f314ea4eSGreg Kurz     if (!fs->dir.stream) {
376cc720ddbSAneesh Kumar K.V         return -1;
377cc720ddbSAneesh Kumar K.V     }
378cc720ddbSAneesh Kumar K.V     return 0;
379a6568fe2SAnthony Liguori }
380a6568fe2SAnthony Liguori 
381cc720ddbSAneesh Kumar K.V static void local_rewinddir(FsContext *ctx, V9fsFidOpenState *fs)
382a9231555SAnthony Liguori {
383f314ea4eSGreg Kurz     rewinddir(fs->dir.stream);
384a9231555SAnthony Liguori }
385a9231555SAnthony Liguori 
386cc720ddbSAneesh Kumar K.V static off_t local_telldir(FsContext *ctx, V9fsFidOpenState *fs)
387a9231555SAnthony Liguori {
388f314ea4eSGreg Kurz     return telldir(fs->dir.stream);
389a9231555SAnthony Liguori }
390a9231555SAnthony Liguori 
391635324e8SGreg Kurz static struct dirent *local_readdir(FsContext *ctx, V9fsFidOpenState *fs)
392a9231555SAnthony Liguori {
393635324e8SGreg Kurz     struct dirent *entry;
3942c30dd74SAneesh Kumar K.V 
3952c30dd74SAneesh Kumar K.V again:
396635324e8SGreg Kurz     entry = readdir(fs->dir.stream);
397635324e8SGreg Kurz     if (!entry) {
398635324e8SGreg Kurz         return NULL;
399635324e8SGreg Kurz     }
400635324e8SGreg Kurz 
401840a1bf2SBastian Blank     if (ctx->export_flags & V9FS_SM_MAPPED) {
402840a1bf2SBastian Blank         entry->d_type = DT_UNKNOWN;
403840a1bf2SBastian Blank     } else if (ctx->export_flags & V9FS_SM_MAPPED_FILE) {
404635324e8SGreg Kurz         if (!strcmp(entry->d_name, VIRTFS_META_DIR)) {
4052c30dd74SAneesh Kumar K.V             /* skp the meta data directory */
4062c30dd74SAneesh Kumar K.V             goto again;
4072c30dd74SAneesh Kumar K.V         }
408840a1bf2SBastian Blank         entry->d_type = DT_UNKNOWN;
4092c30dd74SAneesh Kumar K.V     }
410635324e8SGreg Kurz 
411635324e8SGreg Kurz     return entry;
412a9231555SAnthony Liguori }
413a9231555SAnthony Liguori 
414cc720ddbSAneesh Kumar K.V static void local_seekdir(FsContext *ctx, V9fsFidOpenState *fs, off_t off)
415a9231555SAnthony Liguori {
416f314ea4eSGreg Kurz     seekdir(fs->dir.stream, off);
417a9231555SAnthony Liguori }
418a9231555SAnthony Liguori 
419cc720ddbSAneesh Kumar K.V static ssize_t local_preadv(FsContext *ctx, V9fsFidOpenState *fs,
420cc720ddbSAneesh Kumar K.V                             const struct iovec *iov,
42156d15a53SSanchit Garg                             int iovcnt, off_t offset)
422a9231555SAnthony Liguori {
42356d15a53SSanchit Garg #ifdef CONFIG_PREADV
424cc720ddbSAneesh Kumar K.V     return preadv(fs->fd, iov, iovcnt, offset);
42556d15a53SSanchit Garg #else
426cc720ddbSAneesh Kumar K.V     int err = lseek(fs->fd, offset, SEEK_SET);
42756d15a53SSanchit Garg     if (err == -1) {
42856d15a53SSanchit Garg         return err;
42956d15a53SSanchit Garg     } else {
430cc720ddbSAneesh Kumar K.V         return readv(fs->fd, iov, iovcnt);
431a9231555SAnthony Liguori     }
43256d15a53SSanchit Garg #endif
433a9231555SAnthony Liguori }
434a9231555SAnthony Liguori 
435cc720ddbSAneesh Kumar K.V static ssize_t local_pwritev(FsContext *ctx, V9fsFidOpenState *fs,
436cc720ddbSAneesh Kumar K.V                              const struct iovec *iov,
43756d15a53SSanchit Garg                              int iovcnt, off_t offset)
4388449360cSAnthony Liguori {
439d3ab98e6SAneesh Kumar K.V     ssize_t ret
440d3ab98e6SAneesh Kumar K.V ;
44156d15a53SSanchit Garg #ifdef CONFIG_PREADV
442cc720ddbSAneesh Kumar K.V     ret = pwritev(fs->fd, iov, iovcnt, offset);
44356d15a53SSanchit Garg #else
444cc720ddbSAneesh Kumar K.V     int err = lseek(fs->fd, offset, SEEK_SET);
44556d15a53SSanchit Garg     if (err == -1) {
44656d15a53SSanchit Garg         return err;
44756d15a53SSanchit Garg     } else {
448cc720ddbSAneesh Kumar K.V         ret = writev(fs->fd, iov, iovcnt);
4498449360cSAnthony Liguori     }
45056d15a53SSanchit Garg #endif
451d3ab98e6SAneesh Kumar K.V #ifdef CONFIG_SYNC_FILE_RANGE
452d3ab98e6SAneesh Kumar K.V     if (ret > 0 && ctx->export_flags & V9FS_IMMEDIATE_WRITEOUT) {
453d3ab98e6SAneesh Kumar K.V         /*
454d3ab98e6SAneesh Kumar K.V          * Initiate a writeback. This is not a data integrity sync.
455d3ab98e6SAneesh Kumar K.V          * We want to ensure that we don't leave dirty pages in the cache
456d3ab98e6SAneesh Kumar K.V          * after write when writeout=immediate is sepcified.
457d3ab98e6SAneesh Kumar K.V          */
458cc720ddbSAneesh Kumar K.V         sync_file_range(fs->fd, offset, ret,
459d3ab98e6SAneesh Kumar K.V                         SYNC_FILE_RANGE_WAIT_BEFORE | SYNC_FILE_RANGE_WRITE);
460d3ab98e6SAneesh Kumar K.V     }
461d3ab98e6SAneesh Kumar K.V #endif
462d3ab98e6SAneesh Kumar K.V     return ret;
46356d15a53SSanchit Garg }
4648449360cSAnthony Liguori 
4652289be19SAneesh Kumar K.V static int local_chmod(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
466c494dd6fSAnthony Liguori {
4674fa4ce71SChen Gang     char *buffer;
4684fa4ce71SChen Gang     int ret = -1;
4692289be19SAneesh Kumar K.V     char *path = fs_path->data;
4702289be19SAneesh Kumar K.V 
471b97400caSAneesh Kumar K.V     if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
4724fa4ce71SChen Gang         buffer = rpath(fs_ctx, path);
4734fa4ce71SChen Gang         ret = local_set_xattr(buffer, credp);
4744fa4ce71SChen Gang         g_free(buffer);
4752c30dd74SAneesh Kumar K.V     } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
4762c30dd74SAneesh Kumar K.V         return local_set_mapped_file_attr(fs_ctx, path, credp);
477b97400caSAneesh Kumar K.V     } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
478b97400caSAneesh Kumar K.V                (fs_ctx->export_flags & V9FS_SM_NONE)) {
4794fa4ce71SChen Gang         buffer = rpath(fs_ctx, path);
4804fa4ce71SChen Gang         ret = chmod(buffer, credp->fc_mode);
4814fa4ce71SChen Gang         g_free(buffer);
482e95ead32SVenkateswararao Jujjuri (JV)     }
4834fa4ce71SChen Gang     return ret;
484c494dd6fSAnthony Liguori }
485c494dd6fSAnthony Liguori 
4862289be19SAneesh Kumar K.V static int local_mknod(FsContext *fs_ctx, V9fsPath *dir_path,
4872289be19SAneesh Kumar K.V                        const char *name, FsCred *credp)
488c494dd6fSAnthony Liguori {
4892289be19SAneesh Kumar K.V     char *path;
4901c293312SVenkateswararao Jujjuri (JV)     int err = -1;
4911c293312SVenkateswararao Jujjuri (JV)     int serrno = 0;
4922289be19SAneesh Kumar K.V     V9fsString fullname;
4934ed7b2c3SStefan Weil     char *buffer = NULL;
4941c293312SVenkateswararao Jujjuri (JV) 
4952289be19SAneesh Kumar K.V     v9fs_string_init(&fullname);
4962289be19SAneesh Kumar K.V     v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
4972289be19SAneesh Kumar K.V     path = fullname.data;
4982289be19SAneesh Kumar K.V 
4991c293312SVenkateswararao Jujjuri (JV)     /* Determine the security model */
500b97400caSAneesh Kumar K.V     if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
5014fa4ce71SChen Gang         buffer = rpath(fs_ctx, path);
5024fa4ce71SChen Gang         err = mknod(buffer, SM_LOCAL_MODE_BITS|S_IFREG, 0);
5031c293312SVenkateswararao Jujjuri (JV)         if (err == -1) {
5042289be19SAneesh Kumar K.V             goto out;
5051c293312SVenkateswararao Jujjuri (JV)         }
5064fa4ce71SChen Gang         err = local_set_xattr(buffer, credp);
5071c293312SVenkateswararao Jujjuri (JV)         if (err == -1) {
5081c293312SVenkateswararao Jujjuri (JV)             serrno = errno;
5091c293312SVenkateswararao Jujjuri (JV)             goto err_end;
5101c293312SVenkateswararao Jujjuri (JV)         }
5112c30dd74SAneesh Kumar K.V     } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
5122c30dd74SAneesh Kumar K.V 
5134fa4ce71SChen Gang         buffer = rpath(fs_ctx, path);
5144fa4ce71SChen Gang         err = mknod(buffer, SM_LOCAL_MODE_BITS|S_IFREG, 0);
5152c30dd74SAneesh Kumar K.V         if (err == -1) {
5162c30dd74SAneesh Kumar K.V             goto out;
5172c30dd74SAneesh Kumar K.V         }
5182c30dd74SAneesh Kumar K.V         err = local_set_mapped_file_attr(fs_ctx, path, credp);
5192c30dd74SAneesh Kumar K.V         if (err == -1) {
5202c30dd74SAneesh Kumar K.V             serrno = errno;
5212c30dd74SAneesh Kumar K.V             goto err_end;
5222c30dd74SAneesh Kumar K.V         }
523b97400caSAneesh Kumar K.V     } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
524b97400caSAneesh Kumar K.V                (fs_ctx->export_flags & V9FS_SM_NONE)) {
5254fa4ce71SChen Gang         buffer = rpath(fs_ctx, path);
5264fa4ce71SChen Gang         err = mknod(buffer, credp->fc_mode, credp->fc_rdev);
5271c293312SVenkateswararao Jujjuri (JV)         if (err == -1) {
5282289be19SAneesh Kumar K.V             goto out;
5291c293312SVenkateswararao Jujjuri (JV)         }
5301c293312SVenkateswararao Jujjuri (JV)         err = local_post_create_passthrough(fs_ctx, path, credp);
5311c293312SVenkateswararao Jujjuri (JV)         if (err == -1) {
5321c293312SVenkateswararao Jujjuri (JV)             serrno = errno;
5331c293312SVenkateswararao Jujjuri (JV)             goto err_end;
5341c293312SVenkateswararao Jujjuri (JV)         }
5351c293312SVenkateswararao Jujjuri (JV)     }
5362289be19SAneesh Kumar K.V     goto out;
5371c293312SVenkateswararao Jujjuri (JV) 
5381c293312SVenkateswararao Jujjuri (JV) err_end:
5394fa4ce71SChen Gang     remove(buffer);
5401c293312SVenkateswararao Jujjuri (JV)     errno = serrno;
5412289be19SAneesh Kumar K.V out:
5424ed7b2c3SStefan Weil     g_free(buffer);
5432289be19SAneesh Kumar K.V     v9fs_string_free(&fullname);
5441c293312SVenkateswararao Jujjuri (JV)     return err;
545c494dd6fSAnthony Liguori }
546c494dd6fSAnthony Liguori 
5472289be19SAneesh Kumar K.V static int local_mkdir(FsContext *fs_ctx, V9fsPath *dir_path,
5482289be19SAneesh Kumar K.V                        const char *name, FsCred *credp)
549c494dd6fSAnthony Liguori {
5502289be19SAneesh Kumar K.V     char *path;
55100ec5c37SVenkateswararao Jujjuri (JV)     int err = -1;
55200ec5c37SVenkateswararao Jujjuri (JV)     int serrno = 0;
5532289be19SAneesh Kumar K.V     V9fsString fullname;
5544ed7b2c3SStefan Weil     char *buffer = NULL;
55500ec5c37SVenkateswararao Jujjuri (JV) 
5562289be19SAneesh Kumar K.V     v9fs_string_init(&fullname);
5572289be19SAneesh Kumar K.V     v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
5582289be19SAneesh Kumar K.V     path = fullname.data;
5592289be19SAneesh Kumar K.V 
56000ec5c37SVenkateswararao Jujjuri (JV)     /* Determine the security model */
561b97400caSAneesh Kumar K.V     if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
5624fa4ce71SChen Gang         buffer = rpath(fs_ctx, path);
5634fa4ce71SChen Gang         err = mkdir(buffer, SM_LOCAL_DIR_MODE_BITS);
56400ec5c37SVenkateswararao Jujjuri (JV)         if (err == -1) {
5652289be19SAneesh Kumar K.V             goto out;
56600ec5c37SVenkateswararao Jujjuri (JV)         }
56700ec5c37SVenkateswararao Jujjuri (JV)         credp->fc_mode = credp->fc_mode|S_IFDIR;
5684fa4ce71SChen Gang         err = local_set_xattr(buffer, credp);
56900ec5c37SVenkateswararao Jujjuri (JV)         if (err == -1) {
57000ec5c37SVenkateswararao Jujjuri (JV)             serrno = errno;
57100ec5c37SVenkateswararao Jujjuri (JV)             goto err_end;
57200ec5c37SVenkateswararao Jujjuri (JV)         }
5732c30dd74SAneesh Kumar K.V     } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
5744fa4ce71SChen Gang         buffer = rpath(fs_ctx, path);
5754fa4ce71SChen Gang         err = mkdir(buffer, SM_LOCAL_DIR_MODE_BITS);
5762c30dd74SAneesh Kumar K.V         if (err == -1) {
5772c30dd74SAneesh Kumar K.V             goto out;
5782c30dd74SAneesh Kumar K.V         }
5792c30dd74SAneesh Kumar K.V         credp->fc_mode = credp->fc_mode|S_IFDIR;
5802c30dd74SAneesh Kumar K.V         err = local_set_mapped_file_attr(fs_ctx, path, credp);
5812c30dd74SAneesh Kumar K.V         if (err == -1) {
5822c30dd74SAneesh Kumar K.V             serrno = errno;
5832c30dd74SAneesh Kumar K.V             goto err_end;
5842c30dd74SAneesh Kumar K.V         }
585b97400caSAneesh Kumar K.V     } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
586b97400caSAneesh Kumar K.V                (fs_ctx->export_flags & V9FS_SM_NONE)) {
5874fa4ce71SChen Gang         buffer = rpath(fs_ctx, path);
5884fa4ce71SChen Gang         err = mkdir(buffer, credp->fc_mode);
58900ec5c37SVenkateswararao Jujjuri (JV)         if (err == -1) {
5902289be19SAneesh Kumar K.V             goto out;
59100ec5c37SVenkateswararao Jujjuri (JV)         }
59200ec5c37SVenkateswararao Jujjuri (JV)         err = local_post_create_passthrough(fs_ctx, path, credp);
59300ec5c37SVenkateswararao Jujjuri (JV)         if (err == -1) {
59400ec5c37SVenkateswararao Jujjuri (JV)             serrno = errno;
59500ec5c37SVenkateswararao Jujjuri (JV)             goto err_end;
59600ec5c37SVenkateswararao Jujjuri (JV)         }
59700ec5c37SVenkateswararao Jujjuri (JV)     }
5982289be19SAneesh Kumar K.V     goto out;
59900ec5c37SVenkateswararao Jujjuri (JV) 
60000ec5c37SVenkateswararao Jujjuri (JV) err_end:
6014fa4ce71SChen Gang     remove(buffer);
60200ec5c37SVenkateswararao Jujjuri (JV)     errno = serrno;
6032289be19SAneesh Kumar K.V out:
6044ed7b2c3SStefan Weil     g_free(buffer);
6052289be19SAneesh Kumar K.V     v9fs_string_free(&fullname);
60600ec5c37SVenkateswararao Jujjuri (JV)     return err;
607c494dd6fSAnthony Liguori }
608c494dd6fSAnthony Liguori 
6098b888272SAneesh Kumar K.V static int local_fstat(FsContext *fs_ctx, int fid_type,
610cc720ddbSAneesh Kumar K.V                        V9fsFidOpenState *fs, struct stat *stbuf)
611c494dd6fSAnthony Liguori {
6128b888272SAneesh Kumar K.V     int err, fd;
6138b888272SAneesh Kumar K.V 
6148b888272SAneesh Kumar K.V     if (fid_type == P9_FID_DIR) {
615f314ea4eSGreg Kurz         fd = dirfd(fs->dir.stream);
6168b888272SAneesh Kumar K.V     } else {
6178b888272SAneesh Kumar K.V         fd = fs->fd;
6188b888272SAneesh Kumar K.V     }
6198b888272SAneesh Kumar K.V 
6208b888272SAneesh Kumar K.V     err = fstat(fd, stbuf);
6211237ad76SVenkateswararao Jujjuri (JV)     if (err) {
6221237ad76SVenkateswararao Jujjuri (JV)         return err;
6231237ad76SVenkateswararao Jujjuri (JV)     }
624b97400caSAneesh Kumar K.V     if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
6251237ad76SVenkateswararao Jujjuri (JV)         /* Actual credentials are part of extended attrs */
6261237ad76SVenkateswararao Jujjuri (JV)         uid_t tmp_uid;
6271237ad76SVenkateswararao Jujjuri (JV)         gid_t tmp_gid;
6281237ad76SVenkateswararao Jujjuri (JV)         mode_t tmp_mode;
6291237ad76SVenkateswararao Jujjuri (JV)         dev_t tmp_dev;
6301237ad76SVenkateswararao Jujjuri (JV) 
631f8ad4a89SAneesh Kumar K.V         if (fgetxattr(fd, "user.virtfs.uid", &tmp_uid, sizeof(uid_t)) > 0) {
632f8ad4a89SAneesh Kumar K.V             stbuf->st_uid = le32_to_cpu(tmp_uid);
6331237ad76SVenkateswararao Jujjuri (JV)         }
634f8ad4a89SAneesh Kumar K.V         if (fgetxattr(fd, "user.virtfs.gid", &tmp_gid, sizeof(gid_t)) > 0) {
635f8ad4a89SAneesh Kumar K.V             stbuf->st_gid = le32_to_cpu(tmp_gid);
6361237ad76SVenkateswararao Jujjuri (JV)         }
637f8ad4a89SAneesh Kumar K.V         if (fgetxattr(fd, "user.virtfs.mode", &tmp_mode, sizeof(mode_t)) > 0) {
638f8ad4a89SAneesh Kumar K.V             stbuf->st_mode = le32_to_cpu(tmp_mode);
6391237ad76SVenkateswararao Jujjuri (JV)         }
640f8ad4a89SAneesh Kumar K.V         if (fgetxattr(fd, "user.virtfs.rdev", &tmp_dev, sizeof(dev_t)) > 0) {
641f8ad4a89SAneesh Kumar K.V             stbuf->st_rdev = le64_to_cpu(tmp_dev);
6421237ad76SVenkateswararao Jujjuri (JV)         }
6432c30dd74SAneesh Kumar K.V     } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
6442c30dd74SAneesh Kumar K.V         errno = EOPNOTSUPP;
6452c30dd74SAneesh Kumar K.V         return -1;
6461237ad76SVenkateswararao Jujjuri (JV)     }
6471237ad76SVenkateswararao Jujjuri (JV)     return err;
648c494dd6fSAnthony Liguori }
649c494dd6fSAnthony Liguori 
6502289be19SAneesh Kumar K.V static int local_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name,
651cc720ddbSAneesh Kumar K.V                        int flags, FsCred *credp, V9fsFidOpenState *fs)
652c494dd6fSAnthony Liguori {
6532289be19SAneesh Kumar K.V     char *path;
6544750a96fSVenkateswararao Jujjuri (JV)     int fd = -1;
6554750a96fSVenkateswararao Jujjuri (JV)     int err = -1;
6564750a96fSVenkateswararao Jujjuri (JV)     int serrno = 0;
6572289be19SAneesh Kumar K.V     V9fsString fullname;
6584ed7b2c3SStefan Weil     char *buffer = NULL;
6594750a96fSVenkateswararao Jujjuri (JV) 
6600ceb092eSAneesh Kumar K.V     /*
6610ceb092eSAneesh Kumar K.V      * Mark all the open to not follow symlinks
6620ceb092eSAneesh Kumar K.V      */
6630ceb092eSAneesh Kumar K.V     flags |= O_NOFOLLOW;
6640ceb092eSAneesh Kumar K.V 
6652289be19SAneesh Kumar K.V     v9fs_string_init(&fullname);
6662289be19SAneesh Kumar K.V     v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
6672289be19SAneesh Kumar K.V     path = fullname.data;
6682289be19SAneesh Kumar K.V 
6694750a96fSVenkateswararao Jujjuri (JV)     /* Determine the security model */
670b97400caSAneesh Kumar K.V     if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
6714fa4ce71SChen Gang         buffer = rpath(fs_ctx, path);
6724fa4ce71SChen Gang         fd = open(buffer, flags, SM_LOCAL_MODE_BITS);
6734750a96fSVenkateswararao Jujjuri (JV)         if (fd == -1) {
6742289be19SAneesh Kumar K.V             err = fd;
6752289be19SAneesh Kumar K.V             goto out;
6764750a96fSVenkateswararao Jujjuri (JV)         }
6774750a96fSVenkateswararao Jujjuri (JV)         credp->fc_mode = credp->fc_mode|S_IFREG;
6784750a96fSVenkateswararao Jujjuri (JV)         /* Set cleint credentials in xattr */
6794fa4ce71SChen Gang         err = local_set_xattr(buffer, credp);
6804750a96fSVenkateswararao Jujjuri (JV)         if (err == -1) {
6814750a96fSVenkateswararao Jujjuri (JV)             serrno = errno;
6824750a96fSVenkateswararao Jujjuri (JV)             goto err_end;
6834750a96fSVenkateswararao Jujjuri (JV)         }
6842c30dd74SAneesh Kumar K.V     } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
6854fa4ce71SChen Gang         buffer = rpath(fs_ctx, path);
6864fa4ce71SChen Gang         fd = open(buffer, flags, SM_LOCAL_MODE_BITS);
6872c30dd74SAneesh Kumar K.V         if (fd == -1) {
6882c30dd74SAneesh Kumar K.V             err = fd;
6892c30dd74SAneesh Kumar K.V             goto out;
6902c30dd74SAneesh Kumar K.V         }
6912c30dd74SAneesh Kumar K.V         credp->fc_mode = credp->fc_mode|S_IFREG;
6922c30dd74SAneesh Kumar K.V         /* Set client credentials in .virtfs_metadata directory files */
6932c30dd74SAneesh Kumar K.V         err = local_set_mapped_file_attr(fs_ctx, path, credp);
6942c30dd74SAneesh Kumar K.V         if (err == -1) {
6952c30dd74SAneesh Kumar K.V             serrno = errno;
6962c30dd74SAneesh Kumar K.V             goto err_end;
6972c30dd74SAneesh Kumar K.V         }
698b97400caSAneesh Kumar K.V     } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
699b97400caSAneesh Kumar K.V                (fs_ctx->export_flags & V9FS_SM_NONE)) {
7004fa4ce71SChen Gang         buffer = rpath(fs_ctx, path);
7014fa4ce71SChen Gang         fd = open(buffer, flags, credp->fc_mode);
7024750a96fSVenkateswararao Jujjuri (JV)         if (fd == -1) {
7032289be19SAneesh Kumar K.V             err = fd;
7042289be19SAneesh Kumar K.V             goto out;
7054750a96fSVenkateswararao Jujjuri (JV)         }
7064750a96fSVenkateswararao Jujjuri (JV)         err = local_post_create_passthrough(fs_ctx, path, credp);
7074750a96fSVenkateswararao Jujjuri (JV)         if (err == -1) {
7084750a96fSVenkateswararao Jujjuri (JV)             serrno = errno;
7094750a96fSVenkateswararao Jujjuri (JV)             goto err_end;
7104750a96fSVenkateswararao Jujjuri (JV)         }
7114750a96fSVenkateswararao Jujjuri (JV)     }
7122289be19SAneesh Kumar K.V     err = fd;
713cc720ddbSAneesh Kumar K.V     fs->fd = fd;
7142289be19SAneesh Kumar K.V     goto out;
7154750a96fSVenkateswararao Jujjuri (JV) 
7164750a96fSVenkateswararao Jujjuri (JV) err_end:
7174750a96fSVenkateswararao Jujjuri (JV)     close(fd);
7184fa4ce71SChen Gang     remove(buffer);
7194750a96fSVenkateswararao Jujjuri (JV)     errno = serrno;
7202289be19SAneesh Kumar K.V out:
7214ed7b2c3SStefan Weil     g_free(buffer);
7222289be19SAneesh Kumar K.V     v9fs_string_free(&fullname);
7234750a96fSVenkateswararao Jujjuri (JV)     return err;
724c494dd6fSAnthony Liguori }
725c494dd6fSAnthony Liguori 
726758e8e38SVenkateswararao Jujjuri (JV) 
727879c2813SVenkateswararao Jujjuri (JV) static int local_symlink(FsContext *fs_ctx, const char *oldpath,
7282289be19SAneesh Kumar K.V                          V9fsPath *dir_path, const char *name, FsCred *credp)
729c494dd6fSAnthony Liguori {
730879c2813SVenkateswararao Jujjuri (JV)     int err = -1;
731879c2813SVenkateswararao Jujjuri (JV)     int serrno = 0;
7322289be19SAneesh Kumar K.V     char *newpath;
7332289be19SAneesh Kumar K.V     V9fsString fullname;
7344ed7b2c3SStefan Weil     char *buffer = NULL;
735879c2813SVenkateswararao Jujjuri (JV) 
7362289be19SAneesh Kumar K.V     v9fs_string_init(&fullname);
7372289be19SAneesh Kumar K.V     v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
7382289be19SAneesh Kumar K.V     newpath = fullname.data;
7392289be19SAneesh Kumar K.V 
740879c2813SVenkateswararao Jujjuri (JV)     /* Determine the security model */
741b97400caSAneesh Kumar K.V     if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
742879c2813SVenkateswararao Jujjuri (JV)         int fd;
743879c2813SVenkateswararao Jujjuri (JV)         ssize_t oldpath_size, write_size;
7444fa4ce71SChen Gang         buffer = rpath(fs_ctx, newpath);
7454fa4ce71SChen Gang         fd = open(buffer, O_CREAT|O_EXCL|O_RDWR|O_NOFOLLOW, SM_LOCAL_MODE_BITS);
746879c2813SVenkateswararao Jujjuri (JV)         if (fd == -1) {
7472289be19SAneesh Kumar K.V             err = fd;
7482289be19SAneesh Kumar K.V             goto out;
749879c2813SVenkateswararao Jujjuri (JV)         }
750879c2813SVenkateswararao Jujjuri (JV)         /* Write the oldpath (target) to the file. */
751f35bde2fSHarsh Prateek Bora         oldpath_size = strlen(oldpath);
752879c2813SVenkateswararao Jujjuri (JV)         do {
753879c2813SVenkateswararao Jujjuri (JV)             write_size = write(fd, (void *)oldpath, oldpath_size);
754879c2813SVenkateswararao Jujjuri (JV)         } while (write_size == -1 && errno == EINTR);
755879c2813SVenkateswararao Jujjuri (JV) 
756879c2813SVenkateswararao Jujjuri (JV)         if (write_size != oldpath_size) {
757879c2813SVenkateswararao Jujjuri (JV)             serrno = errno;
758879c2813SVenkateswararao Jujjuri (JV)             close(fd);
759879c2813SVenkateswararao Jujjuri (JV)             err = -1;
760879c2813SVenkateswararao Jujjuri (JV)             goto err_end;
761879c2813SVenkateswararao Jujjuri (JV)         }
762879c2813SVenkateswararao Jujjuri (JV)         close(fd);
763879c2813SVenkateswararao Jujjuri (JV)         /* Set cleint credentials in symlink's xattr */
764879c2813SVenkateswararao Jujjuri (JV)         credp->fc_mode = credp->fc_mode|S_IFLNK;
7654fa4ce71SChen Gang         err = local_set_xattr(buffer, credp);
766879c2813SVenkateswararao Jujjuri (JV)         if (err == -1) {
767879c2813SVenkateswararao Jujjuri (JV)             serrno = errno;
768879c2813SVenkateswararao Jujjuri (JV)             goto err_end;
769879c2813SVenkateswararao Jujjuri (JV)         }
7702c30dd74SAneesh Kumar K.V     } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
7712c30dd74SAneesh Kumar K.V         int fd;
7722c30dd74SAneesh Kumar K.V         ssize_t oldpath_size, write_size;
7734fa4ce71SChen Gang         buffer = rpath(fs_ctx, newpath);
7744fa4ce71SChen Gang         fd = open(buffer, O_CREAT|O_EXCL|O_RDWR|O_NOFOLLOW, SM_LOCAL_MODE_BITS);
7752c30dd74SAneesh Kumar K.V         if (fd == -1) {
7762c30dd74SAneesh Kumar K.V             err = fd;
7772c30dd74SAneesh Kumar K.V             goto out;
7782c30dd74SAneesh Kumar K.V         }
7792c30dd74SAneesh Kumar K.V         /* Write the oldpath (target) to the file. */
7802c30dd74SAneesh Kumar K.V         oldpath_size = strlen(oldpath);
7812c30dd74SAneesh Kumar K.V         do {
7822c30dd74SAneesh Kumar K.V             write_size = write(fd, (void *)oldpath, oldpath_size);
7832c30dd74SAneesh Kumar K.V         } while (write_size == -1 && errno == EINTR);
7842c30dd74SAneesh Kumar K.V 
7852c30dd74SAneesh Kumar K.V         if (write_size != oldpath_size) {
7862c30dd74SAneesh Kumar K.V             serrno = errno;
7872c30dd74SAneesh Kumar K.V             close(fd);
7882c30dd74SAneesh Kumar K.V             err = -1;
7892c30dd74SAneesh Kumar K.V             goto err_end;
7902c30dd74SAneesh Kumar K.V         }
7912c30dd74SAneesh Kumar K.V         close(fd);
7922c30dd74SAneesh Kumar K.V         /* Set cleint credentials in symlink's xattr */
7932c30dd74SAneesh Kumar K.V         credp->fc_mode = credp->fc_mode|S_IFLNK;
7942c30dd74SAneesh Kumar K.V         err = local_set_mapped_file_attr(fs_ctx, newpath, credp);
7952c30dd74SAneesh Kumar K.V         if (err == -1) {
7962c30dd74SAneesh Kumar K.V             serrno = errno;
7972c30dd74SAneesh Kumar K.V             goto err_end;
7982c30dd74SAneesh Kumar K.V         }
799b97400caSAneesh Kumar K.V     } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
800b97400caSAneesh Kumar K.V                (fs_ctx->export_flags & V9FS_SM_NONE)) {
8014fa4ce71SChen Gang         buffer = rpath(fs_ctx, newpath);
8024fa4ce71SChen Gang         err = symlink(oldpath, buffer);
803879c2813SVenkateswararao Jujjuri (JV)         if (err) {
8042289be19SAneesh Kumar K.V             goto out;
805879c2813SVenkateswararao Jujjuri (JV)         }
8064fa4ce71SChen Gang         err = lchown(buffer, credp->fc_uid, credp->fc_gid);
807879c2813SVenkateswararao Jujjuri (JV)         if (err == -1) {
80812848bfcSAneesh Kumar K.V             /*
80912848bfcSAneesh Kumar K.V              * If we fail to change ownership and if we are
81012848bfcSAneesh Kumar K.V              * using security model none. Ignore the error
81112848bfcSAneesh Kumar K.V              */
812b97400caSAneesh Kumar K.V             if ((fs_ctx->export_flags & V9FS_SEC_MASK) != V9FS_SM_NONE) {
813879c2813SVenkateswararao Jujjuri (JV)                 serrno = errno;
814879c2813SVenkateswararao Jujjuri (JV)                 goto err_end;
81512848bfcSAneesh Kumar K.V             } else
81612848bfcSAneesh Kumar K.V                 err = 0;
817879c2813SVenkateswararao Jujjuri (JV)         }
818879c2813SVenkateswararao Jujjuri (JV)     }
8192289be19SAneesh Kumar K.V     goto out;
820879c2813SVenkateswararao Jujjuri (JV) 
821879c2813SVenkateswararao Jujjuri (JV) err_end:
8224fa4ce71SChen Gang     remove(buffer);
823879c2813SVenkateswararao Jujjuri (JV)     errno = serrno;
8242289be19SAneesh Kumar K.V out:
8254ed7b2c3SStefan Weil     g_free(buffer);
8262289be19SAneesh Kumar K.V     v9fs_string_free(&fullname);
827879c2813SVenkateswararao Jujjuri (JV)     return err;
828c494dd6fSAnthony Liguori }
829c494dd6fSAnthony Liguori 
8302289be19SAneesh Kumar K.V static int local_link(FsContext *ctx, V9fsPath *oldpath,
8312289be19SAneesh Kumar K.V                       V9fsPath *dirpath, const char *name)
832c494dd6fSAnthony Liguori {
8332289be19SAneesh Kumar K.V     int ret;
8342289be19SAneesh Kumar K.V     V9fsString newpath;
8354fa4ce71SChen Gang     char *buffer, *buffer1;
836c494dd6fSAnthony Liguori 
8372289be19SAneesh Kumar K.V     v9fs_string_init(&newpath);
8382289be19SAneesh Kumar K.V     v9fs_string_sprintf(&newpath, "%s/%s", dirpath->data, name);
8392289be19SAneesh Kumar K.V 
8404fa4ce71SChen Gang     buffer = rpath(ctx, oldpath->data);
8414fa4ce71SChen Gang     buffer1 = rpath(ctx, newpath.data);
8424fa4ce71SChen Gang     ret = link(buffer, buffer1);
8434fa4ce71SChen Gang     g_free(buffer);
8444fa4ce71SChen Gang     g_free(buffer1);
8452c30dd74SAneesh Kumar K.V 
8462c30dd74SAneesh Kumar K.V     /* now link the virtfs_metadata files */
8472c30dd74SAneesh Kumar K.V     if (!ret && (ctx->export_flags & V9FS_SM_MAPPED_FILE)) {
8482c30dd74SAneesh Kumar K.V         /* Link the .virtfs_metadata files. Create the metada directory */
8492c30dd74SAneesh Kumar K.V         ret = local_create_mapped_attr_dir(ctx, newpath.data);
8502c30dd74SAneesh Kumar K.V         if (ret < 0) {
8512c30dd74SAneesh Kumar K.V             goto err_out;
8522c30dd74SAneesh Kumar K.V         }
8534fa4ce71SChen Gang         buffer = local_mapped_attr_path(ctx, oldpath->data);
8544fa4ce71SChen Gang         buffer1 = local_mapped_attr_path(ctx, newpath.data);
8554fa4ce71SChen Gang         ret = link(buffer, buffer1);
8564fa4ce71SChen Gang         g_free(buffer);
8574fa4ce71SChen Gang         g_free(buffer1);
8582c30dd74SAneesh Kumar K.V         if (ret < 0 && errno != ENOENT) {
8592c30dd74SAneesh Kumar K.V             goto err_out;
8602c30dd74SAneesh Kumar K.V         }
8612c30dd74SAneesh Kumar K.V     }
8622c30dd74SAneesh Kumar K.V err_out:
8632289be19SAneesh Kumar K.V     v9fs_string_free(&newpath);
8642289be19SAneesh Kumar K.V     return ret;
865c494dd6fSAnthony Liguori }
866c494dd6fSAnthony Liguori 
8672289be19SAneesh Kumar K.V static int local_truncate(FsContext *ctx, V9fsPath *fs_path, off_t size)
8688cf89e00SAnthony Liguori {
8694fa4ce71SChen Gang     char *buffer;
8704fa4ce71SChen Gang     int ret;
8712289be19SAneesh Kumar K.V     char *path = fs_path->data;
8722289be19SAneesh Kumar K.V 
8734fa4ce71SChen Gang     buffer = rpath(ctx, path);
8744fa4ce71SChen Gang     ret = truncate(buffer, size);
8754fa4ce71SChen Gang     g_free(buffer);
8764fa4ce71SChen Gang     return ret;
8778cf89e00SAnthony Liguori }
8788cf89e00SAnthony Liguori 
8798cf89e00SAnthony Liguori static int local_rename(FsContext *ctx, const char *oldpath,
8808cf89e00SAnthony Liguori                         const char *newpath)
8818cf89e00SAnthony Liguori {
8822c30dd74SAneesh Kumar K.V     int err;
8834fa4ce71SChen Gang     char *buffer, *buffer1;
8848cf89e00SAnthony Liguori 
8852c30dd74SAneesh Kumar K.V     if (ctx->export_flags & V9FS_SM_MAPPED_FILE) {
8862c30dd74SAneesh Kumar K.V         err = local_create_mapped_attr_dir(ctx, newpath);
8872c30dd74SAneesh Kumar K.V         if (err < 0) {
8882c30dd74SAneesh Kumar K.V             return err;
8892c30dd74SAneesh Kumar K.V         }
8902c30dd74SAneesh Kumar K.V         /* rename the .virtfs_metadata files */
8914fa4ce71SChen Gang         buffer = local_mapped_attr_path(ctx, oldpath);
8924fa4ce71SChen Gang         buffer1 = local_mapped_attr_path(ctx, newpath);
8934fa4ce71SChen Gang         err = rename(buffer, buffer1);
8944fa4ce71SChen Gang         g_free(buffer);
8954fa4ce71SChen Gang         g_free(buffer1);
8962c30dd74SAneesh Kumar K.V         if (err < 0 && errno != ENOENT) {
8972c30dd74SAneesh Kumar K.V             return err;
8982c30dd74SAneesh Kumar K.V         }
8992c30dd74SAneesh Kumar K.V     }
9004fa4ce71SChen Gang 
9014fa4ce71SChen Gang     buffer = rpath(ctx, oldpath);
9024fa4ce71SChen Gang     buffer1 = rpath(ctx, newpath);
9034fa4ce71SChen Gang     err = rename(buffer, buffer1);
9044fa4ce71SChen Gang     g_free(buffer);
9054fa4ce71SChen Gang     g_free(buffer1);
9064fa4ce71SChen Gang     return err;
9078cf89e00SAnthony Liguori }
9088cf89e00SAnthony Liguori 
9092289be19SAneesh Kumar K.V static int local_chown(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
9108cf89e00SAnthony Liguori {
9114fa4ce71SChen Gang     char *buffer;
9124fa4ce71SChen Gang     int ret = -1;
9132289be19SAneesh Kumar K.V     char *path = fs_path->data;
9142289be19SAneesh Kumar K.V 
915c79ce737SSripathi Kodi     if ((credp->fc_uid == -1 && credp->fc_gid == -1) ||
91617b1971fSAneesh Kumar K.V         (fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
91717b1971fSAneesh Kumar K.V         (fs_ctx->export_flags & V9FS_SM_NONE)) {
9184fa4ce71SChen Gang         buffer = rpath(fs_ctx, path);
9194fa4ce71SChen Gang         ret = lchown(buffer, credp->fc_uid, credp->fc_gid);
9204fa4ce71SChen Gang         g_free(buffer);
921b97400caSAneesh Kumar K.V     } else if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
9224fa4ce71SChen Gang         buffer = rpath(fs_ctx, path);
9234fa4ce71SChen Gang         ret = local_set_xattr(buffer, credp);
9244fa4ce71SChen Gang         g_free(buffer);
9252c30dd74SAneesh Kumar K.V     } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
9262c30dd74SAneesh Kumar K.V         return local_set_mapped_file_attr(fs_ctx, path, credp);
927f7613beeSVenkateswararao Jujjuri (JV)     }
9284fa4ce71SChen Gang     return ret;
9298cf89e00SAnthony Liguori }
9308cf89e00SAnthony Liguori 
9312289be19SAneesh Kumar K.V static int local_utimensat(FsContext *s, V9fsPath *fs_path,
93274bc02b2SM. Mohan Kumar                            const struct timespec *buf)
9338cf89e00SAnthony Liguori {
9344fa4ce71SChen Gang     char *buffer;
9354fa4ce71SChen Gang     int ret;
9362289be19SAneesh Kumar K.V     char *path = fs_path->data;
9372289be19SAneesh Kumar K.V 
9384fa4ce71SChen Gang     buffer = rpath(s, path);
9394fa4ce71SChen Gang     ret = qemu_utimens(buffer, buf);
9404fa4ce71SChen Gang     g_free(buffer);
9414fa4ce71SChen Gang     return ret;
9428cf89e00SAnthony Liguori }
9438cf89e00SAnthony Liguori 
9445bae1900SAnthony Liguori static int local_remove(FsContext *ctx, const char *path)
9455bae1900SAnthony Liguori {
9462c30dd74SAneesh Kumar K.V     int err;
9472c30dd74SAneesh Kumar K.V     struct stat stbuf;
9484fa4ce71SChen Gang     char *buffer;
9492c30dd74SAneesh Kumar K.V 
9502c30dd74SAneesh Kumar K.V     if (ctx->export_flags & V9FS_SM_MAPPED_FILE) {
9514fa4ce71SChen Gang         buffer = rpath(ctx, path);
9524fa4ce71SChen Gang         err =  lstat(buffer, &stbuf);
9534fa4ce71SChen Gang         g_free(buffer);
9542c30dd74SAneesh Kumar K.V         if (err) {
9552c30dd74SAneesh Kumar K.V             goto err_out;
9562c30dd74SAneesh Kumar K.V         }
9572c30dd74SAneesh Kumar K.V         /*
9582c30dd74SAneesh Kumar K.V          * If directory remove .virtfs_metadata contained in the
9592c30dd74SAneesh Kumar K.V          * directory
9602c30dd74SAneesh Kumar K.V          */
9612c30dd74SAneesh Kumar K.V         if (S_ISDIR(stbuf.st_mode)) {
9624fa4ce71SChen Gang             buffer = g_strdup_printf("%s/%s/%s", ctx->fs_root,
9634fa4ce71SChen Gang                                      path, VIRTFS_META_DIR);
9642c30dd74SAneesh Kumar K.V             err = remove(buffer);
9654fa4ce71SChen Gang             g_free(buffer);
9662c30dd74SAneesh Kumar K.V             if (err < 0 && errno != ENOENT) {
9672c30dd74SAneesh Kumar K.V                 /*
9682c30dd74SAneesh Kumar K.V                  * We didn't had the .virtfs_metadata file. May be file created
9692c30dd74SAneesh Kumar K.V                  * in non-mapped mode ?. Ignore ENOENT.
9702c30dd74SAneesh Kumar K.V                  */
9712c30dd74SAneesh Kumar K.V                 goto err_out;
9722c30dd74SAneesh Kumar K.V             }
9732c30dd74SAneesh Kumar K.V         }
9742c30dd74SAneesh Kumar K.V         /*
9752c30dd74SAneesh Kumar K.V          * Now remove the name from parent directory
9762c30dd74SAneesh Kumar K.V          * .virtfs_metadata directory
9772c30dd74SAneesh Kumar K.V          */
9784fa4ce71SChen Gang         buffer = local_mapped_attr_path(ctx, path);
9794fa4ce71SChen Gang         err = remove(buffer);
9804fa4ce71SChen Gang         g_free(buffer);
9812c30dd74SAneesh Kumar K.V         if (err < 0 && errno != ENOENT) {
9822c30dd74SAneesh Kumar K.V             /*
9832c30dd74SAneesh Kumar K.V              * We didn't had the .virtfs_metadata file. May be file created
9842c30dd74SAneesh Kumar K.V              * in non-mapped mode ?. Ignore ENOENT.
9852c30dd74SAneesh Kumar K.V              */
9862c30dd74SAneesh Kumar K.V             goto err_out;
9872c30dd74SAneesh Kumar K.V         }
9882c30dd74SAneesh Kumar K.V     }
9894fa4ce71SChen Gang 
9904fa4ce71SChen Gang     buffer = rpath(ctx, path);
9914fa4ce71SChen Gang     err = remove(buffer);
9924fa4ce71SChen Gang     g_free(buffer);
9932c30dd74SAneesh Kumar K.V err_out:
9942c30dd74SAneesh Kumar K.V     return err;
9955bae1900SAnthony Liguori }
9965bae1900SAnthony Liguori 
9978b888272SAneesh Kumar K.V static int local_fsync(FsContext *ctx, int fid_type,
9988b888272SAneesh Kumar K.V                        V9fsFidOpenState *fs, int datasync)
9998cf89e00SAnthony Liguori {
10008b888272SAneesh Kumar K.V     int fd;
10018b888272SAneesh Kumar K.V 
10028b888272SAneesh Kumar K.V     if (fid_type == P9_FID_DIR) {
1003f314ea4eSGreg Kurz         fd = dirfd(fs->dir.stream);
100449594973SVenkateswararao Jujjuri (JV)     } else {
10058b888272SAneesh Kumar K.V         fd = fs->fd;
10068b888272SAneesh Kumar K.V     }
10078b888272SAneesh Kumar K.V 
10088b888272SAneesh Kumar K.V     if (datasync) {
10098b888272SAneesh Kumar K.V         return qemu_fdatasync(fd);
10108b888272SAneesh Kumar K.V     } else {
10118b888272SAneesh Kumar K.V         return fsync(fd);
10128cf89e00SAnthony Liguori     }
101349594973SVenkateswararao Jujjuri (JV) }
10148cf89e00SAnthony Liguori 
10152289be19SAneesh Kumar K.V static int local_statfs(FsContext *s, V9fsPath *fs_path, struct statfs *stbuf)
1016be940c87SM. Mohan Kumar {
10174fa4ce71SChen Gang     char *buffer;
10184fa4ce71SChen Gang     int ret;
10192289be19SAneesh Kumar K.V     char *path = fs_path->data;
10202289be19SAneesh Kumar K.V 
10214fa4ce71SChen Gang     buffer = rpath(s, path);
10224fa4ce71SChen Gang     ret = statfs(buffer, stbuf);
10234fa4ce71SChen Gang     g_free(buffer);
10244fa4ce71SChen Gang     return ret;
1025be940c87SM. Mohan Kumar }
1026be940c87SM. Mohan Kumar 
10272289be19SAneesh Kumar K.V static ssize_t local_lgetxattr(FsContext *ctx, V9fsPath *fs_path,
1028fa32ef88SAneesh Kumar K.V                                const char *name, void *value, size_t size)
1029fa32ef88SAneesh Kumar K.V {
10302289be19SAneesh Kumar K.V     char *path = fs_path->data;
10312289be19SAneesh Kumar K.V 
1032fc22118dSAneesh Kumar K.V     return v9fs_get_xattr(ctx, path, name, value, size);
1033fa32ef88SAneesh Kumar K.V }
1034fa32ef88SAneesh Kumar K.V 
10352289be19SAneesh Kumar K.V static ssize_t local_llistxattr(FsContext *ctx, V9fsPath *fs_path,
1036fa32ef88SAneesh Kumar K.V                                 void *value, size_t size)
1037fa32ef88SAneesh Kumar K.V {
10382289be19SAneesh Kumar K.V     char *path = fs_path->data;
10392289be19SAneesh Kumar K.V 
1040fc22118dSAneesh Kumar K.V     return v9fs_list_xattr(ctx, path, value, size);
104161b6c499SAneesh Kumar K.V }
104261b6c499SAneesh Kumar K.V 
10432289be19SAneesh Kumar K.V static int local_lsetxattr(FsContext *ctx, V9fsPath *fs_path, const char *name,
104410b468bdSAneesh Kumar K.V                            void *value, size_t size, int flags)
104510b468bdSAneesh Kumar K.V {
10462289be19SAneesh Kumar K.V     char *path = fs_path->data;
10472289be19SAneesh Kumar K.V 
1048fc22118dSAneesh Kumar K.V     return v9fs_set_xattr(ctx, path, name, value, size, flags);
104910b468bdSAneesh Kumar K.V }
105010b468bdSAneesh Kumar K.V 
10512289be19SAneesh Kumar K.V static int local_lremovexattr(FsContext *ctx, V9fsPath *fs_path,
10522289be19SAneesh Kumar K.V                               const char *name)
10539ed3ef26SAneesh Kumar K.V {
10542289be19SAneesh Kumar K.V     char *path = fs_path->data;
10552289be19SAneesh Kumar K.V 
1056fc22118dSAneesh Kumar K.V     return v9fs_remove_xattr(ctx, path, name);
10579ed3ef26SAneesh Kumar K.V }
10589ed3ef26SAneesh Kumar K.V 
10592289be19SAneesh Kumar K.V static int local_name_to_path(FsContext *ctx, V9fsPath *dir_path,
10602289be19SAneesh Kumar K.V                               const char *name, V9fsPath *target)
10612289be19SAneesh Kumar K.V {
10622289be19SAneesh Kumar K.V     if (dir_path) {
1063*e3e83f2eSGreg Kurz         v9fs_path_sprintf(target, "%s/%s", dir_path->data, name);
10642289be19SAneesh Kumar K.V     } else {
1065*e3e83f2eSGreg Kurz         v9fs_path_sprintf(target, "%s", name);
10662289be19SAneesh Kumar K.V     }
10672289be19SAneesh Kumar K.V     return 0;
10682289be19SAneesh Kumar K.V }
10692289be19SAneesh Kumar K.V 
10702289be19SAneesh Kumar K.V static int local_renameat(FsContext *ctx, V9fsPath *olddir,
10712289be19SAneesh Kumar K.V                           const char *old_name, V9fsPath *newdir,
10722289be19SAneesh Kumar K.V                           const char *new_name)
10732289be19SAneesh Kumar K.V {
10742289be19SAneesh Kumar K.V     int ret;
10752289be19SAneesh Kumar K.V     V9fsString old_full_name, new_full_name;
10762289be19SAneesh Kumar K.V 
10772289be19SAneesh Kumar K.V     v9fs_string_init(&old_full_name);
10782289be19SAneesh Kumar K.V     v9fs_string_init(&new_full_name);
10792289be19SAneesh Kumar K.V 
10802289be19SAneesh Kumar K.V     v9fs_string_sprintf(&old_full_name, "%s/%s", olddir->data, old_name);
10812289be19SAneesh Kumar K.V     v9fs_string_sprintf(&new_full_name, "%s/%s", newdir->data, new_name);
10822289be19SAneesh Kumar K.V 
10832289be19SAneesh Kumar K.V     ret = local_rename(ctx, old_full_name.data, new_full_name.data);
10842289be19SAneesh Kumar K.V     v9fs_string_free(&old_full_name);
10852289be19SAneesh Kumar K.V     v9fs_string_free(&new_full_name);
10862289be19SAneesh Kumar K.V     return ret;
10872289be19SAneesh Kumar K.V }
10882289be19SAneesh Kumar K.V 
10892289be19SAneesh Kumar K.V static int local_unlinkat(FsContext *ctx, V9fsPath *dir,
10902289be19SAneesh Kumar K.V                           const char *name, int flags)
10912289be19SAneesh Kumar K.V {
10922289be19SAneesh Kumar K.V     int ret;
10932289be19SAneesh Kumar K.V     V9fsString fullname;
10944fa4ce71SChen Gang     char *buffer;
10952c30dd74SAneesh Kumar K.V 
10962289be19SAneesh Kumar K.V     v9fs_string_init(&fullname);
10972289be19SAneesh Kumar K.V 
10982289be19SAneesh Kumar K.V     v9fs_string_sprintf(&fullname, "%s/%s", dir->data, name);
10992c30dd74SAneesh Kumar K.V     if (ctx->export_flags & V9FS_SM_MAPPED_FILE) {
11002c30dd74SAneesh Kumar K.V         if (flags == AT_REMOVEDIR) {
11012c30dd74SAneesh Kumar K.V             /*
11022c30dd74SAneesh Kumar K.V              * If directory remove .virtfs_metadata contained in the
11032c30dd74SAneesh Kumar K.V              * directory
11042c30dd74SAneesh Kumar K.V              */
11054fa4ce71SChen Gang             buffer = g_strdup_printf("%s/%s/%s", ctx->fs_root,
11062c30dd74SAneesh Kumar K.V                                      fullname.data, VIRTFS_META_DIR);
11072c30dd74SAneesh Kumar K.V             ret = remove(buffer);
11084fa4ce71SChen Gang             g_free(buffer);
11092c30dd74SAneesh Kumar K.V             if (ret < 0 && errno != ENOENT) {
11102c30dd74SAneesh Kumar K.V                 /*
11112c30dd74SAneesh Kumar K.V                  * We didn't had the .virtfs_metadata file. May be file created
11122c30dd74SAneesh Kumar K.V                  * in non-mapped mode ?. Ignore ENOENT.
11132c30dd74SAneesh Kumar K.V                  */
11142c30dd74SAneesh Kumar K.V                 goto err_out;
11152c30dd74SAneesh Kumar K.V             }
11162c30dd74SAneesh Kumar K.V         }
11172c30dd74SAneesh Kumar K.V         /*
11182c30dd74SAneesh Kumar K.V          * Now remove the name from parent directory
11192c30dd74SAneesh Kumar K.V          * .virtfs_metadata directory.
11202c30dd74SAneesh Kumar K.V          */
11214fa4ce71SChen Gang         buffer = local_mapped_attr_path(ctx, fullname.data);
11224fa4ce71SChen Gang         ret = remove(buffer);
11234fa4ce71SChen Gang         g_free(buffer);
11242c30dd74SAneesh Kumar K.V         if (ret < 0 && errno != ENOENT) {
11252c30dd74SAneesh Kumar K.V             /*
11262c30dd74SAneesh Kumar K.V              * We didn't had the .virtfs_metadata file. May be file created
11272c30dd74SAneesh Kumar K.V              * in non-mapped mode ?. Ignore ENOENT.
11282c30dd74SAneesh Kumar K.V              */
11292c30dd74SAneesh Kumar K.V             goto err_out;
11302c30dd74SAneesh Kumar K.V         }
11312c30dd74SAneesh Kumar K.V     }
11322c30dd74SAneesh Kumar K.V     /* Remove the name finally */
11334fa4ce71SChen Gang     buffer = rpath(ctx, fullname.data);
11344fa4ce71SChen Gang     ret = remove(buffer);
11354fa4ce71SChen Gang     g_free(buffer);
11362289be19SAneesh Kumar K.V 
11372c30dd74SAneesh Kumar K.V err_out:
113875b7931eSChen Gang     v9fs_string_free(&fullname);
11392289be19SAneesh Kumar K.V     return ret;
11402289be19SAneesh Kumar K.V }
11419ed3ef26SAneesh Kumar K.V 
1142e06a765eSHarsh Prateek Bora static int local_ioc_getversion(FsContext *ctx, V9fsPath *path,
1143e06a765eSHarsh Prateek Bora                                 mode_t st_mode, uint64_t *st_gen)
1144e06a765eSHarsh Prateek Bora {
1145ae0f940eSPaolo Bonzini #ifdef FS_IOC_GETVERSION
11460e5fc994SKirill A. Shutemov     int err;
1147cc720ddbSAneesh Kumar K.V     V9fsFidOpenState fid_open;
1148cc720ddbSAneesh Kumar K.V 
1149e06a765eSHarsh Prateek Bora     /*
1150e06a765eSHarsh Prateek Bora      * Do not try to open special files like device nodes, fifos etc
1151e06a765eSHarsh Prateek Bora      * We can get fd for regular files and directories only
1152e06a765eSHarsh Prateek Bora      */
1153e06a765eSHarsh Prateek Bora     if (!S_ISREG(st_mode) && !S_ISDIR(st_mode)) {
11541a9978a5SKirill A. Shutemov         errno = ENOTTY;
11551a9978a5SKirill A. Shutemov         return -1;
1156e06a765eSHarsh Prateek Bora     }
1157cc720ddbSAneesh Kumar K.V     err = local_open(ctx, path, O_RDONLY, &fid_open);
1158cc720ddbSAneesh Kumar K.V     if (err < 0) {
1159cc720ddbSAneesh Kumar K.V         return err;
1160e06a765eSHarsh Prateek Bora     }
1161cc720ddbSAneesh Kumar K.V     err = ioctl(fid_open.fd, FS_IOC_GETVERSION, st_gen);
1162cc720ddbSAneesh Kumar K.V     local_close(ctx, &fid_open);
1163e06a765eSHarsh Prateek Bora     return err;
11640e5fc994SKirill A. Shutemov #else
11650e5fc994SKirill A. Shutemov     errno = ENOTTY;
11660e5fc994SKirill A. Shutemov     return -1;
11670e5fc994SKirill A. Shutemov #endif
1168e06a765eSHarsh Prateek Bora }
1169e06a765eSHarsh Prateek Bora 
11700174fe73SAneesh Kumar K.V static int local_init(FsContext *ctx)
11710174fe73SAneesh Kumar K.V {
11722507718bSAneesh Kumar K.V     int err = 0;
1173e06a765eSHarsh Prateek Bora     struct statfs stbuf;
1174e06a765eSHarsh Prateek Bora 
11752c30dd74SAneesh Kumar K.V     if (ctx->export_flags & V9FS_SM_PASSTHROUGH) {
11762c30dd74SAneesh Kumar K.V         ctx->xops = passthrough_xattr_ops;
11772c30dd74SAneesh Kumar K.V     } else if (ctx->export_flags & V9FS_SM_MAPPED) {
11782c30dd74SAneesh Kumar K.V         ctx->xops = mapped_xattr_ops;
11792c30dd74SAneesh Kumar K.V     } else if (ctx->export_flags & V9FS_SM_NONE) {
11802c30dd74SAneesh Kumar K.V         ctx->xops = none_xattr_ops;
11812c30dd74SAneesh Kumar K.V     } else if (ctx->export_flags & V9FS_SM_MAPPED_FILE) {
11822c30dd74SAneesh Kumar K.V         /*
11832c30dd74SAneesh Kumar K.V          * xattr operation for mapped-file and passthrough
11842c30dd74SAneesh Kumar K.V          * remain same.
11852c30dd74SAneesh Kumar K.V          */
11862c30dd74SAneesh Kumar K.V         ctx->xops = passthrough_xattr_ops;
11872c30dd74SAneesh Kumar K.V     }
1188c98f1d4aSAneesh Kumar K.V     ctx->export_flags |= V9FS_PATHNAME_FSCONTEXT;
11892507718bSAneesh Kumar K.V #ifdef FS_IOC_GETVERSION
11902507718bSAneesh Kumar K.V     /*
11912507718bSAneesh Kumar K.V      * use ioc_getversion only if the iocl is definied
11922507718bSAneesh Kumar K.V      */
1193e06a765eSHarsh Prateek Bora     err = statfs(ctx->fs_root, &stbuf);
1194e06a765eSHarsh Prateek Bora     if (!err) {
1195e06a765eSHarsh Prateek Bora         switch (stbuf.f_type) {
1196e06a765eSHarsh Prateek Bora         case EXT2_SUPER_MAGIC:
1197e06a765eSHarsh Prateek Bora         case BTRFS_SUPER_MAGIC:
1198e06a765eSHarsh Prateek Bora         case REISERFS_SUPER_MAGIC:
1199e06a765eSHarsh Prateek Bora         case XFS_SUPER_MAGIC:
1200e06a765eSHarsh Prateek Bora             ctx->exops.get_st_gen = local_ioc_getversion;
1201e06a765eSHarsh Prateek Bora             break;
1202e06a765eSHarsh Prateek Bora         }
1203e06a765eSHarsh Prateek Bora     }
12042507718bSAneesh Kumar K.V #endif
1205e06a765eSHarsh Prateek Bora     return err;
12060174fe73SAneesh Kumar K.V }
12070174fe73SAneesh Kumar K.V 
120899519f0aSAneesh Kumar K.V static int local_parse_opts(QemuOpts *opts, struct FsDriverEntry *fse)
120999519f0aSAneesh Kumar K.V {
121099519f0aSAneesh Kumar K.V     const char *sec_model = qemu_opt_get(opts, "security_model");
121199519f0aSAneesh Kumar K.V     const char *path = qemu_opt_get(opts, "path");
121299519f0aSAneesh Kumar K.V 
121399519f0aSAneesh Kumar K.V     if (!sec_model) {
121463325b18SGreg Kurz         error_report("Security model not specified, local fs needs security model");
121563325b18SGreg Kurz         error_printf("valid options are:"
121663325b18SGreg Kurz                      "\tsecurity_model=[passthrough|mapped-xattr|mapped-file|none]\n");
121799519f0aSAneesh Kumar K.V         return -1;
121899519f0aSAneesh Kumar K.V     }
121999519f0aSAneesh Kumar K.V 
122099519f0aSAneesh Kumar K.V     if (!strcmp(sec_model, "passthrough")) {
122199519f0aSAneesh Kumar K.V         fse->export_flags |= V9FS_SM_PASSTHROUGH;
12222c30dd74SAneesh Kumar K.V     } else if (!strcmp(sec_model, "mapped") ||
12232c30dd74SAneesh Kumar K.V                !strcmp(sec_model, "mapped-xattr")) {
122499519f0aSAneesh Kumar K.V         fse->export_flags |= V9FS_SM_MAPPED;
122599519f0aSAneesh Kumar K.V     } else if (!strcmp(sec_model, "none")) {
122699519f0aSAneesh Kumar K.V         fse->export_flags |= V9FS_SM_NONE;
12272c30dd74SAneesh Kumar K.V     } else if (!strcmp(sec_model, "mapped-file")) {
12282c30dd74SAneesh Kumar K.V         fse->export_flags |= V9FS_SM_MAPPED_FILE;
122999519f0aSAneesh Kumar K.V     } else {
123063325b18SGreg Kurz         error_report("Invalid security model %s specified", sec_model);
123163325b18SGreg Kurz         error_printf("valid options are:"
123263325b18SGreg Kurz                      "\t[passthrough|mapped-xattr|mapped-file|none]\n");
123399519f0aSAneesh Kumar K.V         return -1;
123499519f0aSAneesh Kumar K.V     }
123599519f0aSAneesh Kumar K.V 
123699519f0aSAneesh Kumar K.V     if (!path) {
123763325b18SGreg Kurz         error_report("fsdev: No path specified");
123899519f0aSAneesh Kumar K.V         return -1;
123999519f0aSAneesh Kumar K.V     }
124099519f0aSAneesh Kumar K.V     fse->path = g_strdup(path);
124199519f0aSAneesh Kumar K.V 
124299519f0aSAneesh Kumar K.V     return 0;
124399519f0aSAneesh Kumar K.V }
124499519f0aSAneesh Kumar K.V 
12459f107513SAnthony Liguori FileOperations local_ops = {
124699519f0aSAneesh Kumar K.V     .parse_opts = local_parse_opts,
12470174fe73SAneesh Kumar K.V     .init  = local_init,
1248131dcb25SAnthony Liguori     .lstat = local_lstat,
1249131dcb25SAnthony Liguori     .readlink = local_readlink,
1250131dcb25SAnthony Liguori     .close = local_close,
1251131dcb25SAnthony Liguori     .closedir = local_closedir,
1252a6568fe2SAnthony Liguori     .open = local_open,
1253a6568fe2SAnthony Liguori     .opendir = local_opendir,
1254a9231555SAnthony Liguori     .rewinddir = local_rewinddir,
1255a9231555SAnthony Liguori     .telldir = local_telldir,
1256635324e8SGreg Kurz     .readdir = local_readdir,
1257a9231555SAnthony Liguori     .seekdir = local_seekdir,
125856d15a53SSanchit Garg     .preadv = local_preadv,
125956d15a53SSanchit Garg     .pwritev = local_pwritev,
1260c494dd6fSAnthony Liguori     .chmod = local_chmod,
1261c494dd6fSAnthony Liguori     .mknod = local_mknod,
1262c494dd6fSAnthony Liguori     .mkdir = local_mkdir,
1263c494dd6fSAnthony Liguori     .fstat = local_fstat,
1264c494dd6fSAnthony Liguori     .open2 = local_open2,
1265c494dd6fSAnthony Liguori     .symlink = local_symlink,
1266c494dd6fSAnthony Liguori     .link = local_link,
12678cf89e00SAnthony Liguori     .truncate = local_truncate,
12688cf89e00SAnthony Liguori     .rename = local_rename,
12698cf89e00SAnthony Liguori     .chown = local_chown,
127074bc02b2SM. Mohan Kumar     .utimensat = local_utimensat,
12715bae1900SAnthony Liguori     .remove = local_remove,
12728cf89e00SAnthony Liguori     .fsync = local_fsync,
1273be940c87SM. Mohan Kumar     .statfs = local_statfs,
1274fa32ef88SAneesh Kumar K.V     .lgetxattr = local_lgetxattr,
1275fa32ef88SAneesh Kumar K.V     .llistxattr = local_llistxattr,
127610b468bdSAneesh Kumar K.V     .lsetxattr = local_lsetxattr,
12779ed3ef26SAneesh Kumar K.V     .lremovexattr = local_lremovexattr,
12782289be19SAneesh Kumar K.V     .name_to_path = local_name_to_path,
12792289be19SAneesh Kumar K.V     .renameat  = local_renameat,
12802289be19SAneesh Kumar K.V     .unlinkat = local_unlinkat,
12819f107513SAnthony Liguori };
1282