xref: /qemu/hw/9pfs/9p-local.c (revision 63325b181f49d06bc2201cfdd52ba92c05939f13)
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 
14ebe74f8bSWei Liu #include "9p.h"
15267ae092SWei Liu #include "9p-xattr.h"
1669b15212SStefan Weil #include "fsdev/qemu-fsdev.h"   /* local_ops */
17c494dd6fSAnthony Liguori #include <arpa/inet.h>
18131dcb25SAnthony Liguori #include <pwd.h>
19131dcb25SAnthony Liguori #include <grp.h>
20c494dd6fSAnthony Liguori #include <sys/socket.h>
21c494dd6fSAnthony Liguori #include <sys/un.h>
221de7afc9SPaolo Bonzini #include "qemu/xattr.h"
23*63325b18SGreg Kurz #include "qemu/error-report.h"
242c30dd74SAneesh Kumar K.V #include <libgen.h>
25e06a765eSHarsh Prateek Bora #include <linux/fs.h>
26e06a765eSHarsh Prateek Bora #ifdef CONFIG_LINUX_MAGIC_H
27e06a765eSHarsh Prateek Bora #include <linux/magic.h>
28e06a765eSHarsh Prateek Bora #endif
29e06a765eSHarsh Prateek Bora #include <sys/ioctl.h>
30e06a765eSHarsh Prateek Bora 
31e06a765eSHarsh Prateek Bora #ifndef XFS_SUPER_MAGIC
32e06a765eSHarsh Prateek Bora #define XFS_SUPER_MAGIC  0x58465342
33e06a765eSHarsh Prateek Bora #endif
34e06a765eSHarsh Prateek Bora #ifndef EXT2_SUPER_MAGIC
35e06a765eSHarsh Prateek Bora #define EXT2_SUPER_MAGIC 0xEF53
36e06a765eSHarsh Prateek Bora #endif
37e06a765eSHarsh Prateek Bora #ifndef REISERFS_SUPER_MAGIC
38e06a765eSHarsh Prateek Bora #define REISERFS_SUPER_MAGIC 0x52654973
39e06a765eSHarsh Prateek Bora #endif
40e06a765eSHarsh Prateek Bora #ifndef BTRFS_SUPER_MAGIC
41e06a765eSHarsh Prateek Bora #define BTRFS_SUPER_MAGIC 0x9123683E
42e06a765eSHarsh Prateek Bora #endif
43131dcb25SAnthony Liguori 
442c30dd74SAneesh Kumar K.V #define VIRTFS_META_DIR ".virtfs_metadata"
452c30dd74SAneesh Kumar K.V 
464fa4ce71SChen Gang static char *local_mapped_attr_path(FsContext *ctx, const char *path)
472c30dd74SAneesh Kumar K.V {
481b6f85e2SMichael Tokarev     int dirlen;
491b6f85e2SMichael Tokarev     const char *name = strrchr(path, '/');
501b6f85e2SMichael Tokarev     if (name) {
511b6f85e2SMichael Tokarev         dirlen = name - path;
521b6f85e2SMichael Tokarev         ++name;
531b6f85e2SMichael Tokarev     } else {
541b6f85e2SMichael Tokarev         name = path;
551b6f85e2SMichael Tokarev         dirlen = 0;
561b6f85e2SMichael Tokarev     }
571b6f85e2SMichael Tokarev     return g_strdup_printf("%s/%.*s/%s/%s", ctx->fs_root,
581b6f85e2SMichael Tokarev                            dirlen, path, VIRTFS_META_DIR, name);
592c30dd74SAneesh Kumar K.V }
602c30dd74SAneesh Kumar K.V 
610ceb092eSAneesh Kumar K.V static FILE *local_fopen(const char *path, const char *mode)
620ceb092eSAneesh Kumar K.V {
630ceb092eSAneesh Kumar K.V     int fd, o_mode = 0;
640ceb092eSAneesh Kumar K.V     FILE *fp;
650ceb092eSAneesh Kumar K.V     int flags = O_NOFOLLOW;
660ceb092eSAneesh Kumar K.V     /*
670ceb092eSAneesh Kumar K.V      * only supports two modes
680ceb092eSAneesh Kumar K.V      */
690ceb092eSAneesh Kumar K.V     if (mode[0] == 'r') {
700ceb092eSAneesh Kumar K.V         flags |= O_RDONLY;
710ceb092eSAneesh Kumar K.V     } else if (mode[0] == 'w') {
720ceb092eSAneesh Kumar K.V         flags |= O_WRONLY | O_TRUNC | O_CREAT;
730ceb092eSAneesh Kumar K.V         o_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
740ceb092eSAneesh Kumar K.V     } else {
750ceb092eSAneesh Kumar K.V         return NULL;
760ceb092eSAneesh Kumar K.V     }
770ceb092eSAneesh Kumar K.V     fd = open(path, flags, o_mode);
780ceb092eSAneesh Kumar K.V     if (fd == -1) {
790ceb092eSAneesh Kumar K.V         return NULL;
800ceb092eSAneesh Kumar K.V     }
810ceb092eSAneesh Kumar K.V     fp = fdopen(fd, mode);
820ceb092eSAneesh Kumar K.V     if (!fp) {
830ceb092eSAneesh Kumar K.V         close(fd);
840ceb092eSAneesh Kumar K.V     }
850ceb092eSAneesh Kumar K.V     return fp;
860ceb092eSAneesh Kumar K.V }
870ceb092eSAneesh Kumar K.V 
882c30dd74SAneesh Kumar K.V #define ATTR_MAX 100
892c30dd74SAneesh Kumar K.V static void local_mapped_file_attr(FsContext *ctx, const char *path,
902c30dd74SAneesh Kumar K.V                                    struct stat *stbuf)
912c30dd74SAneesh Kumar K.V {
922c30dd74SAneesh Kumar K.V     FILE *fp;
932c30dd74SAneesh Kumar K.V     char buf[ATTR_MAX];
944fa4ce71SChen Gang     char *attr_path;
952c30dd74SAneesh Kumar K.V 
964fa4ce71SChen Gang     attr_path = local_mapped_attr_path(ctx, path);
970ceb092eSAneesh Kumar K.V     fp = local_fopen(attr_path, "r");
984fa4ce71SChen Gang     g_free(attr_path);
992c30dd74SAneesh Kumar K.V     if (!fp) {
1002c30dd74SAneesh Kumar K.V         return;
1012c30dd74SAneesh Kumar K.V     }
1022c30dd74SAneesh Kumar K.V     memset(buf, 0, ATTR_MAX);
1032c30dd74SAneesh Kumar K.V     while (fgets(buf, ATTR_MAX, fp)) {
1042c30dd74SAneesh Kumar K.V         if (!strncmp(buf, "virtfs.uid", 10)) {
1052c30dd74SAneesh Kumar K.V             stbuf->st_uid = atoi(buf+11);
1062c30dd74SAneesh Kumar K.V         } else if (!strncmp(buf, "virtfs.gid", 10)) {
1072c30dd74SAneesh Kumar K.V             stbuf->st_gid = atoi(buf+11);
1082c30dd74SAneesh Kumar K.V         } else if (!strncmp(buf, "virtfs.mode", 11)) {
1092c30dd74SAneesh Kumar K.V             stbuf->st_mode = atoi(buf+12);
1102c30dd74SAneesh Kumar K.V         } else if (!strncmp(buf, "virtfs.rdev", 11)) {
1112c30dd74SAneesh Kumar K.V             stbuf->st_rdev = atoi(buf+12);
1122c30dd74SAneesh Kumar K.V         }
1132c30dd74SAneesh Kumar K.V         memset(buf, 0, ATTR_MAX);
1142c30dd74SAneesh Kumar K.V     }
1152c30dd74SAneesh Kumar K.V     fclose(fp);
1162c30dd74SAneesh Kumar K.V }
1172c30dd74SAneesh Kumar K.V 
1182289be19SAneesh Kumar K.V static int local_lstat(FsContext *fs_ctx, V9fsPath *fs_path, struct stat *stbuf)
119131dcb25SAnthony Liguori {
1201237ad76SVenkateswararao Jujjuri (JV)     int err;
1214fa4ce71SChen Gang     char *buffer;
1222289be19SAneesh Kumar K.V     char *path = fs_path->data;
1232289be19SAneesh Kumar K.V 
1244fa4ce71SChen Gang     buffer = rpath(fs_ctx, path);
1254fa4ce71SChen Gang     err =  lstat(buffer, stbuf);
1261237ad76SVenkateswararao Jujjuri (JV)     if (err) {
1274fa4ce71SChen Gang         goto err_out;
1281237ad76SVenkateswararao Jujjuri (JV)     }
129b97400caSAneesh Kumar K.V     if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
1301237ad76SVenkateswararao Jujjuri (JV)         /* Actual credentials are part of extended attrs */
1311237ad76SVenkateswararao Jujjuri (JV)         uid_t tmp_uid;
1321237ad76SVenkateswararao Jujjuri (JV)         gid_t tmp_gid;
1331237ad76SVenkateswararao Jujjuri (JV)         mode_t tmp_mode;
1341237ad76SVenkateswararao Jujjuri (JV)         dev_t tmp_dev;
1354fa4ce71SChen Gang         if (getxattr(buffer, "user.virtfs.uid", &tmp_uid, sizeof(uid_t)) > 0) {
136f8ad4a89SAneesh Kumar K.V             stbuf->st_uid = le32_to_cpu(tmp_uid);
1371237ad76SVenkateswararao Jujjuri (JV)         }
1384fa4ce71SChen Gang         if (getxattr(buffer, "user.virtfs.gid", &tmp_gid, sizeof(gid_t)) > 0) {
139f8ad4a89SAneesh Kumar K.V             stbuf->st_gid = le32_to_cpu(tmp_gid);
1401237ad76SVenkateswararao Jujjuri (JV)         }
1414fa4ce71SChen Gang         if (getxattr(buffer, "user.virtfs.mode",
142faa44e3dSVenkateswararao Jujjuri (JV)                     &tmp_mode, sizeof(mode_t)) > 0) {
143f8ad4a89SAneesh Kumar K.V             stbuf->st_mode = le32_to_cpu(tmp_mode);
1441237ad76SVenkateswararao Jujjuri (JV)         }
1454fa4ce71SChen Gang         if (getxattr(buffer, "user.virtfs.rdev", &tmp_dev, sizeof(dev_t)) > 0) {
146f8ad4a89SAneesh Kumar K.V             stbuf->st_rdev = le64_to_cpu(tmp_dev);
1471237ad76SVenkateswararao Jujjuri (JV)         }
1482c30dd74SAneesh Kumar K.V     } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
1492c30dd74SAneesh Kumar K.V         local_mapped_file_attr(fs_ctx, path, stbuf);
1501237ad76SVenkateswararao Jujjuri (JV)     }
1514fa4ce71SChen Gang 
1524fa4ce71SChen Gang err_out:
1534fa4ce71SChen Gang     g_free(buffer);
1541237ad76SVenkateswararao Jujjuri (JV)     return err;
155131dcb25SAnthony Liguori }
156131dcb25SAnthony Liguori 
1572c30dd74SAneesh Kumar K.V static int local_create_mapped_attr_dir(FsContext *ctx, const char *path)
1582c30dd74SAneesh Kumar K.V {
1592c30dd74SAneesh Kumar K.V     int err;
1604fa4ce71SChen Gang     char *attr_dir;
161d3f8e138SMarkus Armbruster     char *tmp_path = g_strdup(path);
1622c30dd74SAneesh Kumar K.V 
1634fa4ce71SChen Gang     attr_dir = g_strdup_printf("%s/%s/%s",
1642c30dd74SAneesh Kumar K.V              ctx->fs_root, dirname(tmp_path), VIRTFS_META_DIR);
1652c30dd74SAneesh Kumar K.V 
1662c30dd74SAneesh Kumar K.V     err = mkdir(attr_dir, 0700);
1672c30dd74SAneesh Kumar K.V     if (err < 0 && errno == EEXIST) {
1682c30dd74SAneesh Kumar K.V         err = 0;
1692c30dd74SAneesh Kumar K.V     }
1704fa4ce71SChen Gang     g_free(attr_dir);
171d3f8e138SMarkus Armbruster     g_free(tmp_path);
1722c30dd74SAneesh Kumar K.V     return err;
1732c30dd74SAneesh Kumar K.V }
1742c30dd74SAneesh Kumar K.V 
1752c30dd74SAneesh Kumar K.V static int local_set_mapped_file_attr(FsContext *ctx,
1762c30dd74SAneesh Kumar K.V                                       const char *path, FsCred *credp)
1772c30dd74SAneesh Kumar K.V {
1782c30dd74SAneesh Kumar K.V     FILE *fp;
1792c30dd74SAneesh Kumar K.V     int ret = 0;
1802c30dd74SAneesh Kumar K.V     char buf[ATTR_MAX];
1814fa4ce71SChen Gang     char *attr_path;
1822c30dd74SAneesh Kumar K.V     int uid = -1, gid = -1, mode = -1, rdev = -1;
1832c30dd74SAneesh Kumar K.V 
1844fa4ce71SChen Gang     attr_path = local_mapped_attr_path(ctx, path);
1854fa4ce71SChen Gang     fp = local_fopen(attr_path, "r");
1862c30dd74SAneesh Kumar K.V     if (!fp) {
1872c30dd74SAneesh Kumar K.V         goto create_map_file;
1882c30dd74SAneesh Kumar K.V     }
1892c30dd74SAneesh Kumar K.V     memset(buf, 0, ATTR_MAX);
1902c30dd74SAneesh Kumar K.V     while (fgets(buf, ATTR_MAX, fp)) {
1912c30dd74SAneesh Kumar K.V         if (!strncmp(buf, "virtfs.uid", 10)) {
1922c30dd74SAneesh Kumar K.V             uid = atoi(buf+11);
1932c30dd74SAneesh Kumar K.V         } else if (!strncmp(buf, "virtfs.gid", 10)) {
1942c30dd74SAneesh Kumar K.V             gid = atoi(buf+11);
1952c30dd74SAneesh Kumar K.V         } else if (!strncmp(buf, "virtfs.mode", 11)) {
1962c30dd74SAneesh Kumar K.V             mode = atoi(buf+12);
1972c30dd74SAneesh Kumar K.V         } else if (!strncmp(buf, "virtfs.rdev", 11)) {
1982c30dd74SAneesh Kumar K.V             rdev = atoi(buf+12);
1992c30dd74SAneesh Kumar K.V         }
2002c30dd74SAneesh Kumar K.V         memset(buf, 0, ATTR_MAX);
2012c30dd74SAneesh Kumar K.V     }
2022c30dd74SAneesh Kumar K.V     fclose(fp);
2032c30dd74SAneesh Kumar K.V     goto update_map_file;
2042c30dd74SAneesh Kumar K.V 
2052c30dd74SAneesh Kumar K.V create_map_file:
2062c30dd74SAneesh Kumar K.V     ret = local_create_mapped_attr_dir(ctx, path);
2072c30dd74SAneesh Kumar K.V     if (ret < 0) {
2082c30dd74SAneesh Kumar K.V         goto err_out;
2092c30dd74SAneesh Kumar K.V     }
2102c30dd74SAneesh Kumar K.V 
2112c30dd74SAneesh Kumar K.V update_map_file:
2120ceb092eSAneesh Kumar K.V     fp = local_fopen(attr_path, "w");
2132c30dd74SAneesh Kumar K.V     if (!fp) {
2142c30dd74SAneesh Kumar K.V         ret = -1;
2152c30dd74SAneesh Kumar K.V         goto err_out;
2162c30dd74SAneesh Kumar K.V     }
2172c30dd74SAneesh Kumar K.V 
2182c30dd74SAneesh Kumar K.V     if (credp->fc_uid != -1) {
2192c30dd74SAneesh Kumar K.V         uid = credp->fc_uid;
2202c30dd74SAneesh Kumar K.V     }
2212c30dd74SAneesh Kumar K.V     if (credp->fc_gid != -1) {
2222c30dd74SAneesh Kumar K.V         gid = credp->fc_gid;
2232c30dd74SAneesh Kumar K.V     }
2242c30dd74SAneesh Kumar K.V     if (credp->fc_mode != -1) {
2252c30dd74SAneesh Kumar K.V         mode = credp->fc_mode;
2262c30dd74SAneesh Kumar K.V     }
2272c30dd74SAneesh Kumar K.V     if (credp->fc_rdev != -1) {
2282c30dd74SAneesh Kumar K.V         rdev = credp->fc_rdev;
2292c30dd74SAneesh Kumar K.V     }
2302c30dd74SAneesh Kumar K.V 
2312c30dd74SAneesh Kumar K.V 
2322c30dd74SAneesh Kumar K.V     if (uid != -1) {
2332c30dd74SAneesh Kumar K.V         fprintf(fp, "virtfs.uid=%d\n", uid);
2342c30dd74SAneesh Kumar K.V     }
2352c30dd74SAneesh Kumar K.V     if (gid != -1) {
2362c30dd74SAneesh Kumar K.V         fprintf(fp, "virtfs.gid=%d\n", gid);
2372c30dd74SAneesh Kumar K.V     }
2382c30dd74SAneesh Kumar K.V     if (mode != -1) {
2392c30dd74SAneesh Kumar K.V         fprintf(fp, "virtfs.mode=%d\n", mode);
2402c30dd74SAneesh Kumar K.V     }
2412c30dd74SAneesh Kumar K.V     if (rdev != -1) {
2422c30dd74SAneesh Kumar K.V         fprintf(fp, "virtfs.rdev=%d\n", rdev);
2432c30dd74SAneesh Kumar K.V     }
2442c30dd74SAneesh Kumar K.V     fclose(fp);
2452c30dd74SAneesh Kumar K.V 
2462c30dd74SAneesh Kumar K.V err_out:
2474fa4ce71SChen Gang     g_free(attr_path);
2482c30dd74SAneesh Kumar K.V     return ret;
2492c30dd74SAneesh Kumar K.V }
2502c30dd74SAneesh Kumar K.V 
251758e8e38SVenkateswararao Jujjuri (JV) static int local_set_xattr(const char *path, FsCred *credp)
252131dcb25SAnthony Liguori {
253758e8e38SVenkateswararao Jujjuri (JV)     int err;
2542289be19SAneesh Kumar K.V 
255758e8e38SVenkateswararao Jujjuri (JV)     if (credp->fc_uid != -1) {
256f8ad4a89SAneesh Kumar K.V         uint32_t tmp_uid = cpu_to_le32(credp->fc_uid);
257f8ad4a89SAneesh Kumar K.V         err = setxattr(path, "user.virtfs.uid", &tmp_uid, sizeof(uid_t), 0);
258758e8e38SVenkateswararao Jujjuri (JV)         if (err) {
259758e8e38SVenkateswararao Jujjuri (JV)             return err;
260131dcb25SAnthony Liguori         }
261131dcb25SAnthony Liguori     }
262758e8e38SVenkateswararao Jujjuri (JV)     if (credp->fc_gid != -1) {
263f8ad4a89SAneesh Kumar K.V         uint32_t tmp_gid = cpu_to_le32(credp->fc_gid);
264f8ad4a89SAneesh Kumar K.V         err = setxattr(path, "user.virtfs.gid", &tmp_gid, sizeof(gid_t), 0);
265758e8e38SVenkateswararao Jujjuri (JV)         if (err) {
266758e8e38SVenkateswararao Jujjuri (JV)             return err;
267131dcb25SAnthony Liguori         }
268131dcb25SAnthony Liguori     }
269758e8e38SVenkateswararao Jujjuri (JV)     if (credp->fc_mode != -1) {
270f8ad4a89SAneesh Kumar K.V         uint32_t tmp_mode = cpu_to_le32(credp->fc_mode);
271f8ad4a89SAneesh Kumar K.V         err = setxattr(path, "user.virtfs.mode", &tmp_mode, sizeof(mode_t), 0);
272758e8e38SVenkateswararao Jujjuri (JV)         if (err) {
273758e8e38SVenkateswararao Jujjuri (JV)             return err;
274131dcb25SAnthony Liguori         }
275131dcb25SAnthony Liguori     }
276758e8e38SVenkateswararao Jujjuri (JV)     if (credp->fc_rdev != -1) {
277f8ad4a89SAneesh Kumar K.V         uint64_t tmp_rdev = cpu_to_le64(credp->fc_rdev);
278f8ad4a89SAneesh Kumar K.V         err = setxattr(path, "user.virtfs.rdev", &tmp_rdev, sizeof(dev_t), 0);
279758e8e38SVenkateswararao Jujjuri (JV)         if (err) {
280758e8e38SVenkateswararao Jujjuri (JV)             return err;
281131dcb25SAnthony Liguori         }
282758e8e38SVenkateswararao Jujjuri (JV)     }
283131dcb25SAnthony Liguori     return 0;
284131dcb25SAnthony Liguori }
285131dcb25SAnthony Liguori 
2864750a96fSVenkateswararao Jujjuri (JV) static int local_post_create_passthrough(FsContext *fs_ctx, const char *path,
2874750a96fSVenkateswararao Jujjuri (JV)                                          FsCred *credp)
2884750a96fSVenkateswararao Jujjuri (JV) {
2894fa4ce71SChen Gang     char *buffer;
2902289be19SAneesh Kumar K.V 
2914fa4ce71SChen Gang     buffer = rpath(fs_ctx, path);
2924fa4ce71SChen Gang     if (lchown(buffer, credp->fc_uid, credp->fc_gid) < 0) {
29312848bfcSAneesh Kumar K.V         /*
29412848bfcSAneesh Kumar K.V          * If we fail to change ownership and if we are
29512848bfcSAneesh Kumar K.V          * using security model none. Ignore the error
29612848bfcSAneesh Kumar K.V          */
297b97400caSAneesh Kumar K.V         if ((fs_ctx->export_flags & V9FS_SEC_MASK) != V9FS_SM_NONE) {
2984fa4ce71SChen Gang             goto err;
2994750a96fSVenkateswararao Jujjuri (JV)         }
30012848bfcSAneesh Kumar K.V     }
3012d40564aSM. Mohan Kumar 
3024fa4ce71SChen Gang     if (chmod(buffer, credp->fc_mode & 07777) < 0) {
3034fa4ce71SChen Gang         goto err;
3042d40564aSM. Mohan Kumar     }
3054fa4ce71SChen Gang 
3064fa4ce71SChen Gang     g_free(buffer);
3074750a96fSVenkateswararao Jujjuri (JV)     return 0;
3084fa4ce71SChen Gang err:
3094fa4ce71SChen Gang     g_free(buffer);
3104fa4ce71SChen Gang     return -1;
3114750a96fSVenkateswararao Jujjuri (JV) }
3124750a96fSVenkateswararao Jujjuri (JV) 
3132289be19SAneesh Kumar K.V static ssize_t local_readlink(FsContext *fs_ctx, V9fsPath *fs_path,
314131dcb25SAnthony Liguori                               char *buf, size_t bufsz)
315131dcb25SAnthony Liguori {
316879c2813SVenkateswararao Jujjuri (JV)     ssize_t tsize = -1;
3174fa4ce71SChen Gang     char *buffer;
3182289be19SAneesh Kumar K.V     char *path = fs_path->data;
3192289be19SAneesh Kumar K.V 
3202c30dd74SAneesh Kumar K.V     if ((fs_ctx->export_flags & V9FS_SM_MAPPED) ||
3212c30dd74SAneesh Kumar K.V         (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE)) {
322879c2813SVenkateswararao Jujjuri (JV)         int fd;
3234fa4ce71SChen Gang         buffer = rpath(fs_ctx, path);
3244fa4ce71SChen Gang         fd = open(buffer, O_RDONLY | O_NOFOLLOW);
3254fa4ce71SChen Gang         g_free(buffer);
326879c2813SVenkateswararao Jujjuri (JV)         if (fd == -1) {
327879c2813SVenkateswararao Jujjuri (JV)             return -1;
328879c2813SVenkateswararao Jujjuri (JV)         }
329879c2813SVenkateswararao Jujjuri (JV)         do {
330879c2813SVenkateswararao Jujjuri (JV)             tsize = read(fd, (void *)buf, bufsz);
331879c2813SVenkateswararao Jujjuri (JV)         } while (tsize == -1 && errno == EINTR);
332879c2813SVenkateswararao Jujjuri (JV)         close(fd);
333b97400caSAneesh Kumar K.V     } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
334b97400caSAneesh Kumar K.V                (fs_ctx->export_flags & V9FS_SM_NONE)) {
3354fa4ce71SChen Gang         buffer = rpath(fs_ctx, path);
3364fa4ce71SChen Gang         tsize = readlink(buffer, buf, bufsz);
3374fa4ce71SChen Gang         g_free(buffer);
338879c2813SVenkateswararao Jujjuri (JV)     }
339879c2813SVenkateswararao Jujjuri (JV)     return tsize;
340131dcb25SAnthony Liguori }
341131dcb25SAnthony Liguori 
342cc720ddbSAneesh Kumar K.V static int local_close(FsContext *ctx, V9fsFidOpenState *fs)
343131dcb25SAnthony Liguori {
344cc720ddbSAneesh Kumar K.V     return close(fs->fd);
345131dcb25SAnthony Liguori }
346131dcb25SAnthony Liguori 
347cc720ddbSAneesh Kumar K.V static int local_closedir(FsContext *ctx, V9fsFidOpenState *fs)
348131dcb25SAnthony Liguori {
349cc720ddbSAneesh Kumar K.V     return closedir(fs->dir);
350131dcb25SAnthony Liguori }
3519f107513SAnthony Liguori 
352cc720ddbSAneesh Kumar K.V static int local_open(FsContext *ctx, V9fsPath *fs_path,
353cc720ddbSAneesh Kumar K.V                       int flags, V9fsFidOpenState *fs)
354a6568fe2SAnthony Liguori {
3554fa4ce71SChen Gang     char *buffer;
3562289be19SAneesh Kumar K.V     char *path = fs_path->data;
3572289be19SAneesh Kumar K.V 
3584fa4ce71SChen Gang     buffer = rpath(ctx, path);
3594fa4ce71SChen Gang     fs->fd = open(buffer, flags | O_NOFOLLOW);
3604fa4ce71SChen Gang     g_free(buffer);
361cc720ddbSAneesh Kumar K.V     return fs->fd;
362a6568fe2SAnthony Liguori }
363a6568fe2SAnthony Liguori 
364cc720ddbSAneesh Kumar K.V static int local_opendir(FsContext *ctx,
365cc720ddbSAneesh Kumar K.V                          V9fsPath *fs_path, V9fsFidOpenState *fs)
366a6568fe2SAnthony Liguori {
3674fa4ce71SChen Gang     char *buffer;
3682289be19SAneesh Kumar K.V     char *path = fs_path->data;
3692289be19SAneesh Kumar K.V 
3704fa4ce71SChen Gang     buffer = rpath(ctx, path);
3714fa4ce71SChen Gang     fs->dir = opendir(buffer);
3724fa4ce71SChen Gang     g_free(buffer);
373cc720ddbSAneesh Kumar K.V     if (!fs->dir) {
374cc720ddbSAneesh Kumar K.V         return -1;
375cc720ddbSAneesh Kumar K.V     }
376cc720ddbSAneesh Kumar K.V     return 0;
377a6568fe2SAnthony Liguori }
378a6568fe2SAnthony Liguori 
379cc720ddbSAneesh Kumar K.V static void local_rewinddir(FsContext *ctx, V9fsFidOpenState *fs)
380a9231555SAnthony Liguori {
3810289a412SStefan Weil     rewinddir(fs->dir);
382a9231555SAnthony Liguori }
383a9231555SAnthony Liguori 
384cc720ddbSAneesh Kumar K.V static off_t local_telldir(FsContext *ctx, V9fsFidOpenState *fs)
385a9231555SAnthony Liguori {
386cc720ddbSAneesh Kumar K.V     return telldir(fs->dir);
387a9231555SAnthony Liguori }
388a9231555SAnthony Liguori 
389cc720ddbSAneesh Kumar K.V static int local_readdir_r(FsContext *ctx, V9fsFidOpenState *fs,
390cc720ddbSAneesh Kumar K.V                            struct dirent *entry,
3915f524c1eSHarsh Prateek Bora                            struct dirent **result)
392a9231555SAnthony Liguori {
3932c30dd74SAneesh Kumar K.V     int ret;
3942c30dd74SAneesh Kumar K.V 
3952c30dd74SAneesh Kumar K.V again:
3962c30dd74SAneesh Kumar K.V     ret = readdir_r(fs->dir, entry, result);
397840a1bf2SBastian Blank     if (ctx->export_flags & V9FS_SM_MAPPED) {
398840a1bf2SBastian Blank         entry->d_type = DT_UNKNOWN;
399840a1bf2SBastian Blank     } else if (ctx->export_flags & V9FS_SM_MAPPED_FILE) {
4002c30dd74SAneesh Kumar K.V         if (!ret && *result != NULL &&
4012c30dd74SAneesh Kumar K.V             !strcmp(entry->d_name, VIRTFS_META_DIR)) {
4022c30dd74SAneesh Kumar K.V             /* skp the meta data directory */
4032c30dd74SAneesh Kumar K.V             goto again;
4042c30dd74SAneesh Kumar K.V         }
405840a1bf2SBastian Blank         entry->d_type = DT_UNKNOWN;
4062c30dd74SAneesh Kumar K.V     }
4072c30dd74SAneesh Kumar K.V     return ret;
408a9231555SAnthony Liguori }
409a9231555SAnthony Liguori 
410cc720ddbSAneesh Kumar K.V static void local_seekdir(FsContext *ctx, V9fsFidOpenState *fs, off_t off)
411a9231555SAnthony Liguori {
4120289a412SStefan Weil     seekdir(fs->dir, off);
413a9231555SAnthony Liguori }
414a9231555SAnthony Liguori 
415cc720ddbSAneesh Kumar K.V static ssize_t local_preadv(FsContext *ctx, V9fsFidOpenState *fs,
416cc720ddbSAneesh Kumar K.V                             const struct iovec *iov,
41756d15a53SSanchit Garg                             int iovcnt, off_t offset)
418a9231555SAnthony Liguori {
41956d15a53SSanchit Garg #ifdef CONFIG_PREADV
420cc720ddbSAneesh Kumar K.V     return preadv(fs->fd, iov, iovcnt, offset);
42156d15a53SSanchit Garg #else
422cc720ddbSAneesh Kumar K.V     int err = lseek(fs->fd, offset, SEEK_SET);
42356d15a53SSanchit Garg     if (err == -1) {
42456d15a53SSanchit Garg         return err;
42556d15a53SSanchit Garg     } else {
426cc720ddbSAneesh Kumar K.V         return readv(fs->fd, iov, iovcnt);
427a9231555SAnthony Liguori     }
42856d15a53SSanchit Garg #endif
429a9231555SAnthony Liguori }
430a9231555SAnthony Liguori 
431cc720ddbSAneesh Kumar K.V static ssize_t local_pwritev(FsContext *ctx, V9fsFidOpenState *fs,
432cc720ddbSAneesh Kumar K.V                              const struct iovec *iov,
43356d15a53SSanchit Garg                              int iovcnt, off_t offset)
4348449360cSAnthony Liguori {
435d3ab98e6SAneesh Kumar K.V     ssize_t ret
436d3ab98e6SAneesh Kumar K.V ;
43756d15a53SSanchit Garg #ifdef CONFIG_PREADV
438cc720ddbSAneesh Kumar K.V     ret = pwritev(fs->fd, iov, iovcnt, offset);
43956d15a53SSanchit Garg #else
440cc720ddbSAneesh Kumar K.V     int err = lseek(fs->fd, offset, SEEK_SET);
44156d15a53SSanchit Garg     if (err == -1) {
44256d15a53SSanchit Garg         return err;
44356d15a53SSanchit Garg     } else {
444cc720ddbSAneesh Kumar K.V         ret = writev(fs->fd, iov, iovcnt);
4458449360cSAnthony Liguori     }
44656d15a53SSanchit Garg #endif
447d3ab98e6SAneesh Kumar K.V #ifdef CONFIG_SYNC_FILE_RANGE
448d3ab98e6SAneesh Kumar K.V     if (ret > 0 && ctx->export_flags & V9FS_IMMEDIATE_WRITEOUT) {
449d3ab98e6SAneesh Kumar K.V         /*
450d3ab98e6SAneesh Kumar K.V          * Initiate a writeback. This is not a data integrity sync.
451d3ab98e6SAneesh Kumar K.V          * We want to ensure that we don't leave dirty pages in the cache
452d3ab98e6SAneesh Kumar K.V          * after write when writeout=immediate is sepcified.
453d3ab98e6SAneesh Kumar K.V          */
454cc720ddbSAneesh Kumar K.V         sync_file_range(fs->fd, offset, ret,
455d3ab98e6SAneesh Kumar K.V                         SYNC_FILE_RANGE_WAIT_BEFORE | SYNC_FILE_RANGE_WRITE);
456d3ab98e6SAneesh Kumar K.V     }
457d3ab98e6SAneesh Kumar K.V #endif
458d3ab98e6SAneesh Kumar K.V     return ret;
45956d15a53SSanchit Garg }
4608449360cSAnthony Liguori 
4612289be19SAneesh Kumar K.V static int local_chmod(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
462c494dd6fSAnthony Liguori {
4634fa4ce71SChen Gang     char *buffer;
4644fa4ce71SChen Gang     int ret = -1;
4652289be19SAneesh Kumar K.V     char *path = fs_path->data;
4662289be19SAneesh Kumar K.V 
467b97400caSAneesh Kumar K.V     if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
4684fa4ce71SChen Gang         buffer = rpath(fs_ctx, path);
4694fa4ce71SChen Gang         ret = local_set_xattr(buffer, credp);
4704fa4ce71SChen Gang         g_free(buffer);
4712c30dd74SAneesh Kumar K.V     } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
4722c30dd74SAneesh Kumar K.V         return local_set_mapped_file_attr(fs_ctx, path, credp);
473b97400caSAneesh Kumar K.V     } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
474b97400caSAneesh Kumar K.V                (fs_ctx->export_flags & V9FS_SM_NONE)) {
4754fa4ce71SChen Gang         buffer = rpath(fs_ctx, path);
4764fa4ce71SChen Gang         ret = chmod(buffer, credp->fc_mode);
4774fa4ce71SChen Gang         g_free(buffer);
478e95ead32SVenkateswararao Jujjuri (JV)     }
4794fa4ce71SChen Gang     return ret;
480c494dd6fSAnthony Liguori }
481c494dd6fSAnthony Liguori 
4822289be19SAneesh Kumar K.V static int local_mknod(FsContext *fs_ctx, V9fsPath *dir_path,
4832289be19SAneesh Kumar K.V                        const char *name, FsCred *credp)
484c494dd6fSAnthony Liguori {
4852289be19SAneesh Kumar K.V     char *path;
4861c293312SVenkateswararao Jujjuri (JV)     int err = -1;
4871c293312SVenkateswararao Jujjuri (JV)     int serrno = 0;
4882289be19SAneesh Kumar K.V     V9fsString fullname;
4894ed7b2c3SStefan Weil     char *buffer = NULL;
4901c293312SVenkateswararao Jujjuri (JV) 
4912289be19SAneesh Kumar K.V     v9fs_string_init(&fullname);
4922289be19SAneesh Kumar K.V     v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
4932289be19SAneesh Kumar K.V     path = fullname.data;
4942289be19SAneesh Kumar K.V 
4951c293312SVenkateswararao Jujjuri (JV)     /* Determine the security model */
496b97400caSAneesh Kumar K.V     if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
4974fa4ce71SChen Gang         buffer = rpath(fs_ctx, path);
4984fa4ce71SChen Gang         err = mknod(buffer, SM_LOCAL_MODE_BITS|S_IFREG, 0);
4991c293312SVenkateswararao Jujjuri (JV)         if (err == -1) {
5002289be19SAneesh Kumar K.V             goto out;
5011c293312SVenkateswararao Jujjuri (JV)         }
5024fa4ce71SChen Gang         err = local_set_xattr(buffer, credp);
5031c293312SVenkateswararao Jujjuri (JV)         if (err == -1) {
5041c293312SVenkateswararao Jujjuri (JV)             serrno = errno;
5051c293312SVenkateswararao Jujjuri (JV)             goto err_end;
5061c293312SVenkateswararao Jujjuri (JV)         }
5072c30dd74SAneesh Kumar K.V     } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
5082c30dd74SAneesh Kumar K.V 
5094fa4ce71SChen Gang         buffer = rpath(fs_ctx, path);
5104fa4ce71SChen Gang         err = mknod(buffer, SM_LOCAL_MODE_BITS|S_IFREG, 0);
5112c30dd74SAneesh Kumar K.V         if (err == -1) {
5122c30dd74SAneesh Kumar K.V             goto out;
5132c30dd74SAneesh Kumar K.V         }
5142c30dd74SAneesh Kumar K.V         err = local_set_mapped_file_attr(fs_ctx, path, credp);
5152c30dd74SAneesh Kumar K.V         if (err == -1) {
5162c30dd74SAneesh Kumar K.V             serrno = errno;
5172c30dd74SAneesh Kumar K.V             goto err_end;
5182c30dd74SAneesh Kumar K.V         }
519b97400caSAneesh Kumar K.V     } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
520b97400caSAneesh Kumar K.V                (fs_ctx->export_flags & V9FS_SM_NONE)) {
5214fa4ce71SChen Gang         buffer = rpath(fs_ctx, path);
5224fa4ce71SChen Gang         err = mknod(buffer, credp->fc_mode, credp->fc_rdev);
5231c293312SVenkateswararao Jujjuri (JV)         if (err == -1) {
5242289be19SAneesh Kumar K.V             goto out;
5251c293312SVenkateswararao Jujjuri (JV)         }
5261c293312SVenkateswararao Jujjuri (JV)         err = local_post_create_passthrough(fs_ctx, path, credp);
5271c293312SVenkateswararao Jujjuri (JV)         if (err == -1) {
5281c293312SVenkateswararao Jujjuri (JV)             serrno = errno;
5291c293312SVenkateswararao Jujjuri (JV)             goto err_end;
5301c293312SVenkateswararao Jujjuri (JV)         }
5311c293312SVenkateswararao Jujjuri (JV)     }
5322289be19SAneesh Kumar K.V     goto out;
5331c293312SVenkateswararao Jujjuri (JV) 
5341c293312SVenkateswararao Jujjuri (JV) err_end:
5354fa4ce71SChen Gang     remove(buffer);
5361c293312SVenkateswararao Jujjuri (JV)     errno = serrno;
5372289be19SAneesh Kumar K.V out:
5384ed7b2c3SStefan Weil     g_free(buffer);
5392289be19SAneesh Kumar K.V     v9fs_string_free(&fullname);
5401c293312SVenkateswararao Jujjuri (JV)     return err;
541c494dd6fSAnthony Liguori }
542c494dd6fSAnthony Liguori 
5432289be19SAneesh Kumar K.V static int local_mkdir(FsContext *fs_ctx, V9fsPath *dir_path,
5442289be19SAneesh Kumar K.V                        const char *name, FsCred *credp)
545c494dd6fSAnthony Liguori {
5462289be19SAneesh Kumar K.V     char *path;
54700ec5c37SVenkateswararao Jujjuri (JV)     int err = -1;
54800ec5c37SVenkateswararao Jujjuri (JV)     int serrno = 0;
5492289be19SAneesh Kumar K.V     V9fsString fullname;
5504ed7b2c3SStefan Weil     char *buffer = NULL;
55100ec5c37SVenkateswararao Jujjuri (JV) 
5522289be19SAneesh Kumar K.V     v9fs_string_init(&fullname);
5532289be19SAneesh Kumar K.V     v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
5542289be19SAneesh Kumar K.V     path = fullname.data;
5552289be19SAneesh Kumar K.V 
55600ec5c37SVenkateswararao Jujjuri (JV)     /* Determine the security model */
557b97400caSAneesh Kumar K.V     if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
5584fa4ce71SChen Gang         buffer = rpath(fs_ctx, path);
5594fa4ce71SChen Gang         err = mkdir(buffer, SM_LOCAL_DIR_MODE_BITS);
56000ec5c37SVenkateswararao Jujjuri (JV)         if (err == -1) {
5612289be19SAneesh Kumar K.V             goto out;
56200ec5c37SVenkateswararao Jujjuri (JV)         }
56300ec5c37SVenkateswararao Jujjuri (JV)         credp->fc_mode = credp->fc_mode|S_IFDIR;
5644fa4ce71SChen Gang         err = local_set_xattr(buffer, credp);
56500ec5c37SVenkateswararao Jujjuri (JV)         if (err == -1) {
56600ec5c37SVenkateswararao Jujjuri (JV)             serrno = errno;
56700ec5c37SVenkateswararao Jujjuri (JV)             goto err_end;
56800ec5c37SVenkateswararao Jujjuri (JV)         }
5692c30dd74SAneesh Kumar K.V     } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
5704fa4ce71SChen Gang         buffer = rpath(fs_ctx, path);
5714fa4ce71SChen Gang         err = mkdir(buffer, SM_LOCAL_DIR_MODE_BITS);
5722c30dd74SAneesh Kumar K.V         if (err == -1) {
5732c30dd74SAneesh Kumar K.V             goto out;
5742c30dd74SAneesh Kumar K.V         }
5752c30dd74SAneesh Kumar K.V         credp->fc_mode = credp->fc_mode|S_IFDIR;
5762c30dd74SAneesh Kumar K.V         err = local_set_mapped_file_attr(fs_ctx, path, credp);
5772c30dd74SAneesh Kumar K.V         if (err == -1) {
5782c30dd74SAneesh Kumar K.V             serrno = errno;
5792c30dd74SAneesh Kumar K.V             goto err_end;
5802c30dd74SAneesh Kumar K.V         }
581b97400caSAneesh Kumar K.V     } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
582b97400caSAneesh Kumar K.V                (fs_ctx->export_flags & V9FS_SM_NONE)) {
5834fa4ce71SChen Gang         buffer = rpath(fs_ctx, path);
5844fa4ce71SChen Gang         err = mkdir(buffer, credp->fc_mode);
58500ec5c37SVenkateswararao Jujjuri (JV)         if (err == -1) {
5862289be19SAneesh Kumar K.V             goto out;
58700ec5c37SVenkateswararao Jujjuri (JV)         }
58800ec5c37SVenkateswararao Jujjuri (JV)         err = local_post_create_passthrough(fs_ctx, path, credp);
58900ec5c37SVenkateswararao Jujjuri (JV)         if (err == -1) {
59000ec5c37SVenkateswararao Jujjuri (JV)             serrno = errno;
59100ec5c37SVenkateswararao Jujjuri (JV)             goto err_end;
59200ec5c37SVenkateswararao Jujjuri (JV)         }
59300ec5c37SVenkateswararao Jujjuri (JV)     }
5942289be19SAneesh Kumar K.V     goto out;
59500ec5c37SVenkateswararao Jujjuri (JV) 
59600ec5c37SVenkateswararao Jujjuri (JV) err_end:
5974fa4ce71SChen Gang     remove(buffer);
59800ec5c37SVenkateswararao Jujjuri (JV)     errno = serrno;
5992289be19SAneesh Kumar K.V out:
6004ed7b2c3SStefan Weil     g_free(buffer);
6012289be19SAneesh Kumar K.V     v9fs_string_free(&fullname);
60200ec5c37SVenkateswararao Jujjuri (JV)     return err;
603c494dd6fSAnthony Liguori }
604c494dd6fSAnthony Liguori 
6058b888272SAneesh Kumar K.V static int local_fstat(FsContext *fs_ctx, int fid_type,
606cc720ddbSAneesh Kumar K.V                        V9fsFidOpenState *fs, struct stat *stbuf)
607c494dd6fSAnthony Liguori {
6088b888272SAneesh Kumar K.V     int err, fd;
6098b888272SAneesh Kumar K.V 
6108b888272SAneesh Kumar K.V     if (fid_type == P9_FID_DIR) {
6118b888272SAneesh Kumar K.V         fd = dirfd(fs->dir);
6128b888272SAneesh Kumar K.V     } else {
6138b888272SAneesh Kumar K.V         fd = fs->fd;
6148b888272SAneesh Kumar K.V     }
6158b888272SAneesh Kumar K.V 
6168b888272SAneesh Kumar K.V     err = fstat(fd, stbuf);
6171237ad76SVenkateswararao Jujjuri (JV)     if (err) {
6181237ad76SVenkateswararao Jujjuri (JV)         return err;
6191237ad76SVenkateswararao Jujjuri (JV)     }
620b97400caSAneesh Kumar K.V     if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
6211237ad76SVenkateswararao Jujjuri (JV)         /* Actual credentials are part of extended attrs */
6221237ad76SVenkateswararao Jujjuri (JV)         uid_t tmp_uid;
6231237ad76SVenkateswararao Jujjuri (JV)         gid_t tmp_gid;
6241237ad76SVenkateswararao Jujjuri (JV)         mode_t tmp_mode;
6251237ad76SVenkateswararao Jujjuri (JV)         dev_t tmp_dev;
6261237ad76SVenkateswararao Jujjuri (JV) 
627f8ad4a89SAneesh Kumar K.V         if (fgetxattr(fd, "user.virtfs.uid", &tmp_uid, sizeof(uid_t)) > 0) {
628f8ad4a89SAneesh Kumar K.V             stbuf->st_uid = le32_to_cpu(tmp_uid);
6291237ad76SVenkateswararao Jujjuri (JV)         }
630f8ad4a89SAneesh Kumar K.V         if (fgetxattr(fd, "user.virtfs.gid", &tmp_gid, sizeof(gid_t)) > 0) {
631f8ad4a89SAneesh Kumar K.V             stbuf->st_gid = le32_to_cpu(tmp_gid);
6321237ad76SVenkateswararao Jujjuri (JV)         }
633f8ad4a89SAneesh Kumar K.V         if (fgetxattr(fd, "user.virtfs.mode", &tmp_mode, sizeof(mode_t)) > 0) {
634f8ad4a89SAneesh Kumar K.V             stbuf->st_mode = le32_to_cpu(tmp_mode);
6351237ad76SVenkateswararao Jujjuri (JV)         }
636f8ad4a89SAneesh Kumar K.V         if (fgetxattr(fd, "user.virtfs.rdev", &tmp_dev, sizeof(dev_t)) > 0) {
637f8ad4a89SAneesh Kumar K.V             stbuf->st_rdev = le64_to_cpu(tmp_dev);
6381237ad76SVenkateswararao Jujjuri (JV)         }
6392c30dd74SAneesh Kumar K.V     } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
6402c30dd74SAneesh Kumar K.V         errno = EOPNOTSUPP;
6412c30dd74SAneesh Kumar K.V         return -1;
6421237ad76SVenkateswararao Jujjuri (JV)     }
6431237ad76SVenkateswararao Jujjuri (JV)     return err;
644c494dd6fSAnthony Liguori }
645c494dd6fSAnthony Liguori 
6462289be19SAneesh Kumar K.V static int local_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name,
647cc720ddbSAneesh Kumar K.V                        int flags, FsCred *credp, V9fsFidOpenState *fs)
648c494dd6fSAnthony Liguori {
6492289be19SAneesh Kumar K.V     char *path;
6504750a96fSVenkateswararao Jujjuri (JV)     int fd = -1;
6514750a96fSVenkateswararao Jujjuri (JV)     int err = -1;
6524750a96fSVenkateswararao Jujjuri (JV)     int serrno = 0;
6532289be19SAneesh Kumar K.V     V9fsString fullname;
6544ed7b2c3SStefan Weil     char *buffer = NULL;
6554750a96fSVenkateswararao Jujjuri (JV) 
6560ceb092eSAneesh Kumar K.V     /*
6570ceb092eSAneesh Kumar K.V      * Mark all the open to not follow symlinks
6580ceb092eSAneesh Kumar K.V      */
6590ceb092eSAneesh Kumar K.V     flags |= O_NOFOLLOW;
6600ceb092eSAneesh Kumar K.V 
6612289be19SAneesh Kumar K.V     v9fs_string_init(&fullname);
6622289be19SAneesh Kumar K.V     v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
6632289be19SAneesh Kumar K.V     path = fullname.data;
6642289be19SAneesh Kumar K.V 
6654750a96fSVenkateswararao Jujjuri (JV)     /* Determine the security model */
666b97400caSAneesh Kumar K.V     if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
6674fa4ce71SChen Gang         buffer = rpath(fs_ctx, path);
6684fa4ce71SChen Gang         fd = open(buffer, flags, SM_LOCAL_MODE_BITS);
6694750a96fSVenkateswararao Jujjuri (JV)         if (fd == -1) {
6702289be19SAneesh Kumar K.V             err = fd;
6712289be19SAneesh Kumar K.V             goto out;
6724750a96fSVenkateswararao Jujjuri (JV)         }
6734750a96fSVenkateswararao Jujjuri (JV)         credp->fc_mode = credp->fc_mode|S_IFREG;
6744750a96fSVenkateswararao Jujjuri (JV)         /* Set cleint credentials in xattr */
6754fa4ce71SChen Gang         err = local_set_xattr(buffer, credp);
6764750a96fSVenkateswararao Jujjuri (JV)         if (err == -1) {
6774750a96fSVenkateswararao Jujjuri (JV)             serrno = errno;
6784750a96fSVenkateswararao Jujjuri (JV)             goto err_end;
6794750a96fSVenkateswararao Jujjuri (JV)         }
6802c30dd74SAneesh Kumar K.V     } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
6814fa4ce71SChen Gang         buffer = rpath(fs_ctx, path);
6824fa4ce71SChen Gang         fd = open(buffer, flags, SM_LOCAL_MODE_BITS);
6832c30dd74SAneesh Kumar K.V         if (fd == -1) {
6842c30dd74SAneesh Kumar K.V             err = fd;
6852c30dd74SAneesh Kumar K.V             goto out;
6862c30dd74SAneesh Kumar K.V         }
6872c30dd74SAneesh Kumar K.V         credp->fc_mode = credp->fc_mode|S_IFREG;
6882c30dd74SAneesh Kumar K.V         /* Set client credentials in .virtfs_metadata directory files */
6892c30dd74SAneesh Kumar K.V         err = local_set_mapped_file_attr(fs_ctx, path, credp);
6902c30dd74SAneesh Kumar K.V         if (err == -1) {
6912c30dd74SAneesh Kumar K.V             serrno = errno;
6922c30dd74SAneesh Kumar K.V             goto err_end;
6932c30dd74SAneesh Kumar K.V         }
694b97400caSAneesh Kumar K.V     } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
695b97400caSAneesh Kumar K.V                (fs_ctx->export_flags & V9FS_SM_NONE)) {
6964fa4ce71SChen Gang         buffer = rpath(fs_ctx, path);
6974fa4ce71SChen Gang         fd = open(buffer, flags, credp->fc_mode);
6984750a96fSVenkateswararao Jujjuri (JV)         if (fd == -1) {
6992289be19SAneesh Kumar K.V             err = fd;
7002289be19SAneesh Kumar K.V             goto out;
7014750a96fSVenkateswararao Jujjuri (JV)         }
7024750a96fSVenkateswararao Jujjuri (JV)         err = local_post_create_passthrough(fs_ctx, path, credp);
7034750a96fSVenkateswararao Jujjuri (JV)         if (err == -1) {
7044750a96fSVenkateswararao Jujjuri (JV)             serrno = errno;
7054750a96fSVenkateswararao Jujjuri (JV)             goto err_end;
7064750a96fSVenkateswararao Jujjuri (JV)         }
7074750a96fSVenkateswararao Jujjuri (JV)     }
7082289be19SAneesh Kumar K.V     err = fd;
709cc720ddbSAneesh Kumar K.V     fs->fd = fd;
7102289be19SAneesh Kumar K.V     goto out;
7114750a96fSVenkateswararao Jujjuri (JV) 
7124750a96fSVenkateswararao Jujjuri (JV) err_end:
7134750a96fSVenkateswararao Jujjuri (JV)     close(fd);
7144fa4ce71SChen Gang     remove(buffer);
7154750a96fSVenkateswararao Jujjuri (JV)     errno = serrno;
7162289be19SAneesh Kumar K.V out:
7174ed7b2c3SStefan Weil     g_free(buffer);
7182289be19SAneesh Kumar K.V     v9fs_string_free(&fullname);
7194750a96fSVenkateswararao Jujjuri (JV)     return err;
720c494dd6fSAnthony Liguori }
721c494dd6fSAnthony Liguori 
722758e8e38SVenkateswararao Jujjuri (JV) 
723879c2813SVenkateswararao Jujjuri (JV) static int local_symlink(FsContext *fs_ctx, const char *oldpath,
7242289be19SAneesh Kumar K.V                          V9fsPath *dir_path, const char *name, FsCred *credp)
725c494dd6fSAnthony Liguori {
726879c2813SVenkateswararao Jujjuri (JV)     int err = -1;
727879c2813SVenkateswararao Jujjuri (JV)     int serrno = 0;
7282289be19SAneesh Kumar K.V     char *newpath;
7292289be19SAneesh Kumar K.V     V9fsString fullname;
7304ed7b2c3SStefan Weil     char *buffer = NULL;
731879c2813SVenkateswararao Jujjuri (JV) 
7322289be19SAneesh Kumar K.V     v9fs_string_init(&fullname);
7332289be19SAneesh Kumar K.V     v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
7342289be19SAneesh Kumar K.V     newpath = fullname.data;
7352289be19SAneesh Kumar K.V 
736879c2813SVenkateswararao Jujjuri (JV)     /* Determine the security model */
737b97400caSAneesh Kumar K.V     if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
738879c2813SVenkateswararao Jujjuri (JV)         int fd;
739879c2813SVenkateswararao Jujjuri (JV)         ssize_t oldpath_size, write_size;
7404fa4ce71SChen Gang         buffer = rpath(fs_ctx, newpath);
7414fa4ce71SChen Gang         fd = open(buffer, O_CREAT|O_EXCL|O_RDWR|O_NOFOLLOW, SM_LOCAL_MODE_BITS);
742879c2813SVenkateswararao Jujjuri (JV)         if (fd == -1) {
7432289be19SAneesh Kumar K.V             err = fd;
7442289be19SAneesh Kumar K.V             goto out;
745879c2813SVenkateswararao Jujjuri (JV)         }
746879c2813SVenkateswararao Jujjuri (JV)         /* Write the oldpath (target) to the file. */
747f35bde2fSHarsh Prateek Bora         oldpath_size = strlen(oldpath);
748879c2813SVenkateswararao Jujjuri (JV)         do {
749879c2813SVenkateswararao Jujjuri (JV)             write_size = write(fd, (void *)oldpath, oldpath_size);
750879c2813SVenkateswararao Jujjuri (JV)         } while (write_size == -1 && errno == EINTR);
751879c2813SVenkateswararao Jujjuri (JV) 
752879c2813SVenkateswararao Jujjuri (JV)         if (write_size != oldpath_size) {
753879c2813SVenkateswararao Jujjuri (JV)             serrno = errno;
754879c2813SVenkateswararao Jujjuri (JV)             close(fd);
755879c2813SVenkateswararao Jujjuri (JV)             err = -1;
756879c2813SVenkateswararao Jujjuri (JV)             goto err_end;
757879c2813SVenkateswararao Jujjuri (JV)         }
758879c2813SVenkateswararao Jujjuri (JV)         close(fd);
759879c2813SVenkateswararao Jujjuri (JV)         /* Set cleint credentials in symlink's xattr */
760879c2813SVenkateswararao Jujjuri (JV)         credp->fc_mode = credp->fc_mode|S_IFLNK;
7614fa4ce71SChen Gang         err = local_set_xattr(buffer, credp);
762879c2813SVenkateswararao Jujjuri (JV)         if (err == -1) {
763879c2813SVenkateswararao Jujjuri (JV)             serrno = errno;
764879c2813SVenkateswararao Jujjuri (JV)             goto err_end;
765879c2813SVenkateswararao Jujjuri (JV)         }
7662c30dd74SAneesh Kumar K.V     } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
7672c30dd74SAneesh Kumar K.V         int fd;
7682c30dd74SAneesh Kumar K.V         ssize_t oldpath_size, write_size;
7694fa4ce71SChen Gang         buffer = rpath(fs_ctx, newpath);
7704fa4ce71SChen Gang         fd = open(buffer, O_CREAT|O_EXCL|O_RDWR|O_NOFOLLOW, SM_LOCAL_MODE_BITS);
7712c30dd74SAneesh Kumar K.V         if (fd == -1) {
7722c30dd74SAneesh Kumar K.V             err = fd;
7732c30dd74SAneesh Kumar K.V             goto out;
7742c30dd74SAneesh Kumar K.V         }
7752c30dd74SAneesh Kumar K.V         /* Write the oldpath (target) to the file. */
7762c30dd74SAneesh Kumar K.V         oldpath_size = strlen(oldpath);
7772c30dd74SAneesh Kumar K.V         do {
7782c30dd74SAneesh Kumar K.V             write_size = write(fd, (void *)oldpath, oldpath_size);
7792c30dd74SAneesh Kumar K.V         } while (write_size == -1 && errno == EINTR);
7802c30dd74SAneesh Kumar K.V 
7812c30dd74SAneesh Kumar K.V         if (write_size != oldpath_size) {
7822c30dd74SAneesh Kumar K.V             serrno = errno;
7832c30dd74SAneesh Kumar K.V             close(fd);
7842c30dd74SAneesh Kumar K.V             err = -1;
7852c30dd74SAneesh Kumar K.V             goto err_end;
7862c30dd74SAneesh Kumar K.V         }
7872c30dd74SAneesh Kumar K.V         close(fd);
7882c30dd74SAneesh Kumar K.V         /* Set cleint credentials in symlink's xattr */
7892c30dd74SAneesh Kumar K.V         credp->fc_mode = credp->fc_mode|S_IFLNK;
7902c30dd74SAneesh Kumar K.V         err = local_set_mapped_file_attr(fs_ctx, newpath, credp);
7912c30dd74SAneesh Kumar K.V         if (err == -1) {
7922c30dd74SAneesh Kumar K.V             serrno = errno;
7932c30dd74SAneesh Kumar K.V             goto err_end;
7942c30dd74SAneesh Kumar K.V         }
795b97400caSAneesh Kumar K.V     } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
796b97400caSAneesh Kumar K.V                (fs_ctx->export_flags & V9FS_SM_NONE)) {
7974fa4ce71SChen Gang         buffer = rpath(fs_ctx, newpath);
7984fa4ce71SChen Gang         err = symlink(oldpath, buffer);
799879c2813SVenkateswararao Jujjuri (JV)         if (err) {
8002289be19SAneesh Kumar K.V             goto out;
801879c2813SVenkateswararao Jujjuri (JV)         }
8024fa4ce71SChen Gang         err = lchown(buffer, credp->fc_uid, credp->fc_gid);
803879c2813SVenkateswararao Jujjuri (JV)         if (err == -1) {
80412848bfcSAneesh Kumar K.V             /*
80512848bfcSAneesh Kumar K.V              * If we fail to change ownership and if we are
80612848bfcSAneesh Kumar K.V              * using security model none. Ignore the error
80712848bfcSAneesh Kumar K.V              */
808b97400caSAneesh Kumar K.V             if ((fs_ctx->export_flags & V9FS_SEC_MASK) != V9FS_SM_NONE) {
809879c2813SVenkateswararao Jujjuri (JV)                 serrno = errno;
810879c2813SVenkateswararao Jujjuri (JV)                 goto err_end;
81112848bfcSAneesh Kumar K.V             } else
81212848bfcSAneesh Kumar K.V                 err = 0;
813879c2813SVenkateswararao Jujjuri (JV)         }
814879c2813SVenkateswararao Jujjuri (JV)     }
8152289be19SAneesh Kumar K.V     goto out;
816879c2813SVenkateswararao Jujjuri (JV) 
817879c2813SVenkateswararao Jujjuri (JV) err_end:
8184fa4ce71SChen Gang     remove(buffer);
819879c2813SVenkateswararao Jujjuri (JV)     errno = serrno;
8202289be19SAneesh Kumar K.V out:
8214ed7b2c3SStefan Weil     g_free(buffer);
8222289be19SAneesh Kumar K.V     v9fs_string_free(&fullname);
823879c2813SVenkateswararao Jujjuri (JV)     return err;
824c494dd6fSAnthony Liguori }
825c494dd6fSAnthony Liguori 
8262289be19SAneesh Kumar K.V static int local_link(FsContext *ctx, V9fsPath *oldpath,
8272289be19SAneesh Kumar K.V                       V9fsPath *dirpath, const char *name)
828c494dd6fSAnthony Liguori {
8292289be19SAneesh Kumar K.V     int ret;
8302289be19SAneesh Kumar K.V     V9fsString newpath;
8314fa4ce71SChen Gang     char *buffer, *buffer1;
832c494dd6fSAnthony Liguori 
8332289be19SAneesh Kumar K.V     v9fs_string_init(&newpath);
8342289be19SAneesh Kumar K.V     v9fs_string_sprintf(&newpath, "%s/%s", dirpath->data, name);
8352289be19SAneesh Kumar K.V 
8364fa4ce71SChen Gang     buffer = rpath(ctx, oldpath->data);
8374fa4ce71SChen Gang     buffer1 = rpath(ctx, newpath.data);
8384fa4ce71SChen Gang     ret = link(buffer, buffer1);
8394fa4ce71SChen Gang     g_free(buffer);
8404fa4ce71SChen Gang     g_free(buffer1);
8412c30dd74SAneesh Kumar K.V 
8422c30dd74SAneesh Kumar K.V     /* now link the virtfs_metadata files */
8432c30dd74SAneesh Kumar K.V     if (!ret && (ctx->export_flags & V9FS_SM_MAPPED_FILE)) {
8442c30dd74SAneesh Kumar K.V         /* Link the .virtfs_metadata files. Create the metada directory */
8452c30dd74SAneesh Kumar K.V         ret = local_create_mapped_attr_dir(ctx, newpath.data);
8462c30dd74SAneesh Kumar K.V         if (ret < 0) {
8472c30dd74SAneesh Kumar K.V             goto err_out;
8482c30dd74SAneesh Kumar K.V         }
8494fa4ce71SChen Gang         buffer = local_mapped_attr_path(ctx, oldpath->data);
8504fa4ce71SChen Gang         buffer1 = local_mapped_attr_path(ctx, newpath.data);
8514fa4ce71SChen Gang         ret = link(buffer, buffer1);
8524fa4ce71SChen Gang         g_free(buffer);
8534fa4ce71SChen Gang         g_free(buffer1);
8542c30dd74SAneesh Kumar K.V         if (ret < 0 && errno != ENOENT) {
8552c30dd74SAneesh Kumar K.V             goto err_out;
8562c30dd74SAneesh Kumar K.V         }
8572c30dd74SAneesh Kumar K.V     }
8582c30dd74SAneesh Kumar K.V err_out:
8592289be19SAneesh Kumar K.V     v9fs_string_free(&newpath);
8602289be19SAneesh Kumar K.V     return ret;
861c494dd6fSAnthony Liguori }
862c494dd6fSAnthony Liguori 
8632289be19SAneesh Kumar K.V static int local_truncate(FsContext *ctx, V9fsPath *fs_path, off_t size)
8648cf89e00SAnthony Liguori {
8654fa4ce71SChen Gang     char *buffer;
8664fa4ce71SChen Gang     int ret;
8672289be19SAneesh Kumar K.V     char *path = fs_path->data;
8682289be19SAneesh Kumar K.V 
8694fa4ce71SChen Gang     buffer = rpath(ctx, path);
8704fa4ce71SChen Gang     ret = truncate(buffer, size);
8714fa4ce71SChen Gang     g_free(buffer);
8724fa4ce71SChen Gang     return ret;
8738cf89e00SAnthony Liguori }
8748cf89e00SAnthony Liguori 
8758cf89e00SAnthony Liguori static int local_rename(FsContext *ctx, const char *oldpath,
8768cf89e00SAnthony Liguori                         const char *newpath)
8778cf89e00SAnthony Liguori {
8782c30dd74SAneesh Kumar K.V     int err;
8794fa4ce71SChen Gang     char *buffer, *buffer1;
8808cf89e00SAnthony Liguori 
8812c30dd74SAneesh Kumar K.V     if (ctx->export_flags & V9FS_SM_MAPPED_FILE) {
8822c30dd74SAneesh Kumar K.V         err = local_create_mapped_attr_dir(ctx, newpath);
8832c30dd74SAneesh Kumar K.V         if (err < 0) {
8842c30dd74SAneesh Kumar K.V             return err;
8852c30dd74SAneesh Kumar K.V         }
8862c30dd74SAneesh Kumar K.V         /* rename the .virtfs_metadata files */
8874fa4ce71SChen Gang         buffer = local_mapped_attr_path(ctx, oldpath);
8884fa4ce71SChen Gang         buffer1 = local_mapped_attr_path(ctx, newpath);
8894fa4ce71SChen Gang         err = rename(buffer, buffer1);
8904fa4ce71SChen Gang         g_free(buffer);
8914fa4ce71SChen Gang         g_free(buffer1);
8922c30dd74SAneesh Kumar K.V         if (err < 0 && errno != ENOENT) {
8932c30dd74SAneesh Kumar K.V             return err;
8942c30dd74SAneesh Kumar K.V         }
8952c30dd74SAneesh Kumar K.V     }
8964fa4ce71SChen Gang 
8974fa4ce71SChen Gang     buffer = rpath(ctx, oldpath);
8984fa4ce71SChen Gang     buffer1 = rpath(ctx, newpath);
8994fa4ce71SChen Gang     err = rename(buffer, buffer1);
9004fa4ce71SChen Gang     g_free(buffer);
9014fa4ce71SChen Gang     g_free(buffer1);
9024fa4ce71SChen Gang     return err;
9038cf89e00SAnthony Liguori }
9048cf89e00SAnthony Liguori 
9052289be19SAneesh Kumar K.V static int local_chown(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
9068cf89e00SAnthony Liguori {
9074fa4ce71SChen Gang     char *buffer;
9084fa4ce71SChen Gang     int ret = -1;
9092289be19SAneesh Kumar K.V     char *path = fs_path->data;
9102289be19SAneesh Kumar K.V 
911c79ce737SSripathi Kodi     if ((credp->fc_uid == -1 && credp->fc_gid == -1) ||
91217b1971fSAneesh Kumar K.V         (fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
91317b1971fSAneesh Kumar K.V         (fs_ctx->export_flags & V9FS_SM_NONE)) {
9144fa4ce71SChen Gang         buffer = rpath(fs_ctx, path);
9154fa4ce71SChen Gang         ret = lchown(buffer, credp->fc_uid, credp->fc_gid);
9164fa4ce71SChen Gang         g_free(buffer);
917b97400caSAneesh Kumar K.V     } else if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
9184fa4ce71SChen Gang         buffer = rpath(fs_ctx, path);
9194fa4ce71SChen Gang         ret = local_set_xattr(buffer, credp);
9204fa4ce71SChen Gang         g_free(buffer);
9212c30dd74SAneesh Kumar K.V     } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
9222c30dd74SAneesh Kumar K.V         return local_set_mapped_file_attr(fs_ctx, path, credp);
923f7613beeSVenkateswararao Jujjuri (JV)     }
9244fa4ce71SChen Gang     return ret;
9258cf89e00SAnthony Liguori }
9268cf89e00SAnthony Liguori 
9272289be19SAneesh Kumar K.V static int local_utimensat(FsContext *s, V9fsPath *fs_path,
92874bc02b2SM. Mohan Kumar                            const struct timespec *buf)
9298cf89e00SAnthony Liguori {
9304fa4ce71SChen Gang     char *buffer;
9314fa4ce71SChen Gang     int ret;
9322289be19SAneesh Kumar K.V     char *path = fs_path->data;
9332289be19SAneesh Kumar K.V 
9344fa4ce71SChen Gang     buffer = rpath(s, path);
9354fa4ce71SChen Gang     ret = qemu_utimens(buffer, buf);
9364fa4ce71SChen Gang     g_free(buffer);
9374fa4ce71SChen Gang     return ret;
9388cf89e00SAnthony Liguori }
9398cf89e00SAnthony Liguori 
9405bae1900SAnthony Liguori static int local_remove(FsContext *ctx, const char *path)
9415bae1900SAnthony Liguori {
9422c30dd74SAneesh Kumar K.V     int err;
9432c30dd74SAneesh Kumar K.V     struct stat stbuf;
9444fa4ce71SChen Gang     char *buffer;
9452c30dd74SAneesh Kumar K.V 
9462c30dd74SAneesh Kumar K.V     if (ctx->export_flags & V9FS_SM_MAPPED_FILE) {
9474fa4ce71SChen Gang         buffer = rpath(ctx, path);
9484fa4ce71SChen Gang         err =  lstat(buffer, &stbuf);
9494fa4ce71SChen Gang         g_free(buffer);
9502c30dd74SAneesh Kumar K.V         if (err) {
9512c30dd74SAneesh Kumar K.V             goto err_out;
9522c30dd74SAneesh Kumar K.V         }
9532c30dd74SAneesh Kumar K.V         /*
9542c30dd74SAneesh Kumar K.V          * If directory remove .virtfs_metadata contained in the
9552c30dd74SAneesh Kumar K.V          * directory
9562c30dd74SAneesh Kumar K.V          */
9572c30dd74SAneesh Kumar K.V         if (S_ISDIR(stbuf.st_mode)) {
9584fa4ce71SChen Gang             buffer = g_strdup_printf("%s/%s/%s", ctx->fs_root,
9594fa4ce71SChen Gang                                      path, VIRTFS_META_DIR);
9602c30dd74SAneesh Kumar K.V             err = remove(buffer);
9614fa4ce71SChen Gang             g_free(buffer);
9622c30dd74SAneesh Kumar K.V             if (err < 0 && errno != ENOENT) {
9632c30dd74SAneesh Kumar K.V                 /*
9642c30dd74SAneesh Kumar K.V                  * We didn't had the .virtfs_metadata file. May be file created
9652c30dd74SAneesh Kumar K.V                  * in non-mapped mode ?. Ignore ENOENT.
9662c30dd74SAneesh Kumar K.V                  */
9672c30dd74SAneesh Kumar K.V                 goto err_out;
9682c30dd74SAneesh Kumar K.V             }
9692c30dd74SAneesh Kumar K.V         }
9702c30dd74SAneesh Kumar K.V         /*
9712c30dd74SAneesh Kumar K.V          * Now remove the name from parent directory
9722c30dd74SAneesh Kumar K.V          * .virtfs_metadata directory
9732c30dd74SAneesh Kumar K.V          */
9744fa4ce71SChen Gang         buffer = local_mapped_attr_path(ctx, path);
9754fa4ce71SChen Gang         err = remove(buffer);
9764fa4ce71SChen Gang         g_free(buffer);
9772c30dd74SAneesh Kumar K.V         if (err < 0 && errno != ENOENT) {
9782c30dd74SAneesh Kumar K.V             /*
9792c30dd74SAneesh Kumar K.V              * We didn't had the .virtfs_metadata file. May be file created
9802c30dd74SAneesh Kumar K.V              * in non-mapped mode ?. Ignore ENOENT.
9812c30dd74SAneesh Kumar K.V              */
9822c30dd74SAneesh Kumar K.V             goto err_out;
9832c30dd74SAneesh Kumar K.V         }
9842c30dd74SAneesh Kumar K.V     }
9854fa4ce71SChen Gang 
9864fa4ce71SChen Gang     buffer = rpath(ctx, path);
9874fa4ce71SChen Gang     err = remove(buffer);
9884fa4ce71SChen Gang     g_free(buffer);
9892c30dd74SAneesh Kumar K.V err_out:
9902c30dd74SAneesh Kumar K.V     return err;
9915bae1900SAnthony Liguori }
9925bae1900SAnthony Liguori 
9938b888272SAneesh Kumar K.V static int local_fsync(FsContext *ctx, int fid_type,
9948b888272SAneesh Kumar K.V                        V9fsFidOpenState *fs, int datasync)
9958cf89e00SAnthony Liguori {
9968b888272SAneesh Kumar K.V     int fd;
9978b888272SAneesh Kumar K.V 
9988b888272SAneesh Kumar K.V     if (fid_type == P9_FID_DIR) {
9998b888272SAneesh Kumar K.V         fd = dirfd(fs->dir);
100049594973SVenkateswararao Jujjuri (JV)     } else {
10018b888272SAneesh Kumar K.V         fd = fs->fd;
10028b888272SAneesh Kumar K.V     }
10038b888272SAneesh Kumar K.V 
10048b888272SAneesh Kumar K.V     if (datasync) {
10058b888272SAneesh Kumar K.V         return qemu_fdatasync(fd);
10068b888272SAneesh Kumar K.V     } else {
10078b888272SAneesh Kumar K.V         return fsync(fd);
10088cf89e00SAnthony Liguori     }
100949594973SVenkateswararao Jujjuri (JV) }
10108cf89e00SAnthony Liguori 
10112289be19SAneesh Kumar K.V static int local_statfs(FsContext *s, V9fsPath *fs_path, struct statfs *stbuf)
1012be940c87SM. Mohan Kumar {
10134fa4ce71SChen Gang     char *buffer;
10144fa4ce71SChen Gang     int ret;
10152289be19SAneesh Kumar K.V     char *path = fs_path->data;
10162289be19SAneesh Kumar K.V 
10174fa4ce71SChen Gang     buffer = rpath(s, path);
10184fa4ce71SChen Gang     ret = statfs(buffer, stbuf);
10194fa4ce71SChen Gang     g_free(buffer);
10204fa4ce71SChen Gang     return ret;
1021be940c87SM. Mohan Kumar }
1022be940c87SM. Mohan Kumar 
10232289be19SAneesh Kumar K.V static ssize_t local_lgetxattr(FsContext *ctx, V9fsPath *fs_path,
1024fa32ef88SAneesh Kumar K.V                                const char *name, void *value, size_t size)
1025fa32ef88SAneesh Kumar K.V {
10262289be19SAneesh Kumar K.V     char *path = fs_path->data;
10272289be19SAneesh Kumar K.V 
1028fc22118dSAneesh Kumar K.V     return v9fs_get_xattr(ctx, path, name, value, size);
1029fa32ef88SAneesh Kumar K.V }
1030fa32ef88SAneesh Kumar K.V 
10312289be19SAneesh Kumar K.V static ssize_t local_llistxattr(FsContext *ctx, V9fsPath *fs_path,
1032fa32ef88SAneesh Kumar K.V                                 void *value, size_t size)
1033fa32ef88SAneesh Kumar K.V {
10342289be19SAneesh Kumar K.V     char *path = fs_path->data;
10352289be19SAneesh Kumar K.V 
1036fc22118dSAneesh Kumar K.V     return v9fs_list_xattr(ctx, path, value, size);
103761b6c499SAneesh Kumar K.V }
103861b6c499SAneesh Kumar K.V 
10392289be19SAneesh Kumar K.V static int local_lsetxattr(FsContext *ctx, V9fsPath *fs_path, const char *name,
104010b468bdSAneesh Kumar K.V                            void *value, size_t size, int flags)
104110b468bdSAneesh Kumar K.V {
10422289be19SAneesh Kumar K.V     char *path = fs_path->data;
10432289be19SAneesh Kumar K.V 
1044fc22118dSAneesh Kumar K.V     return v9fs_set_xattr(ctx, path, name, value, size, flags);
104510b468bdSAneesh Kumar K.V }
104610b468bdSAneesh Kumar K.V 
10472289be19SAneesh Kumar K.V static int local_lremovexattr(FsContext *ctx, V9fsPath *fs_path,
10482289be19SAneesh Kumar K.V                               const char *name)
10499ed3ef26SAneesh Kumar K.V {
10502289be19SAneesh Kumar K.V     char *path = fs_path->data;
10512289be19SAneesh Kumar K.V 
1052fc22118dSAneesh Kumar K.V     return v9fs_remove_xattr(ctx, path, name);
10539ed3ef26SAneesh Kumar K.V }
10549ed3ef26SAneesh Kumar K.V 
10552289be19SAneesh Kumar K.V static int local_name_to_path(FsContext *ctx, V9fsPath *dir_path,
10562289be19SAneesh Kumar K.V                               const char *name, V9fsPath *target)
10572289be19SAneesh Kumar K.V {
10582289be19SAneesh Kumar K.V     if (dir_path) {
10592289be19SAneesh Kumar K.V         v9fs_string_sprintf((V9fsString *)target, "%s/%s",
10602289be19SAneesh Kumar K.V                             dir_path->data, name);
10612289be19SAneesh Kumar K.V     } else {
10622289be19SAneesh Kumar K.V         v9fs_string_sprintf((V9fsString *)target, "%s", name);
10632289be19SAneesh Kumar K.V     }
10642289be19SAneesh Kumar K.V     /* Bump the size for including terminating NULL */
10652289be19SAneesh Kumar K.V     target->size++;
10662289be19SAneesh Kumar K.V     return 0;
10672289be19SAneesh Kumar K.V }
10682289be19SAneesh Kumar K.V 
10692289be19SAneesh Kumar K.V static int local_renameat(FsContext *ctx, V9fsPath *olddir,
10702289be19SAneesh Kumar K.V                           const char *old_name, V9fsPath *newdir,
10712289be19SAneesh Kumar K.V                           const char *new_name)
10722289be19SAneesh Kumar K.V {
10732289be19SAneesh Kumar K.V     int ret;
10742289be19SAneesh Kumar K.V     V9fsString old_full_name, new_full_name;
10752289be19SAneesh Kumar K.V 
10762289be19SAneesh Kumar K.V     v9fs_string_init(&old_full_name);
10772289be19SAneesh Kumar K.V     v9fs_string_init(&new_full_name);
10782289be19SAneesh Kumar K.V 
10792289be19SAneesh Kumar K.V     v9fs_string_sprintf(&old_full_name, "%s/%s", olddir->data, old_name);
10802289be19SAneesh Kumar K.V     v9fs_string_sprintf(&new_full_name, "%s/%s", newdir->data, new_name);
10812289be19SAneesh Kumar K.V 
10822289be19SAneesh Kumar K.V     ret = local_rename(ctx, old_full_name.data, new_full_name.data);
10832289be19SAneesh Kumar K.V     v9fs_string_free(&old_full_name);
10842289be19SAneesh Kumar K.V     v9fs_string_free(&new_full_name);
10852289be19SAneesh Kumar K.V     return ret;
10862289be19SAneesh Kumar K.V }
10872289be19SAneesh Kumar K.V 
10882289be19SAneesh Kumar K.V static int local_unlinkat(FsContext *ctx, V9fsPath *dir,
10892289be19SAneesh Kumar K.V                           const char *name, int flags)
10902289be19SAneesh Kumar K.V {
10912289be19SAneesh Kumar K.V     int ret;
10922289be19SAneesh Kumar K.V     V9fsString fullname;
10934fa4ce71SChen Gang     char *buffer;
10942c30dd74SAneesh Kumar K.V 
10952289be19SAneesh Kumar K.V     v9fs_string_init(&fullname);
10962289be19SAneesh Kumar K.V 
10972289be19SAneesh Kumar K.V     v9fs_string_sprintf(&fullname, "%s/%s", dir->data, name);
10982c30dd74SAneesh Kumar K.V     if (ctx->export_flags & V9FS_SM_MAPPED_FILE) {
10992c30dd74SAneesh Kumar K.V         if (flags == AT_REMOVEDIR) {
11002c30dd74SAneesh Kumar K.V             /*
11012c30dd74SAneesh Kumar K.V              * If directory remove .virtfs_metadata contained in the
11022c30dd74SAneesh Kumar K.V              * directory
11032c30dd74SAneesh Kumar K.V              */
11044fa4ce71SChen Gang             buffer = g_strdup_printf("%s/%s/%s", ctx->fs_root,
11052c30dd74SAneesh Kumar K.V                                      fullname.data, VIRTFS_META_DIR);
11062c30dd74SAneesh Kumar K.V             ret = remove(buffer);
11074fa4ce71SChen Gang             g_free(buffer);
11082c30dd74SAneesh Kumar K.V             if (ret < 0 && errno != ENOENT) {
11092c30dd74SAneesh Kumar K.V                 /*
11102c30dd74SAneesh Kumar K.V                  * We didn't had the .virtfs_metadata file. May be file created
11112c30dd74SAneesh Kumar K.V                  * in non-mapped mode ?. Ignore ENOENT.
11122c30dd74SAneesh Kumar K.V                  */
11132c30dd74SAneesh Kumar K.V                 goto err_out;
11142c30dd74SAneesh Kumar K.V             }
11152c30dd74SAneesh Kumar K.V         }
11162c30dd74SAneesh Kumar K.V         /*
11172c30dd74SAneesh Kumar K.V          * Now remove the name from parent directory
11182c30dd74SAneesh Kumar K.V          * .virtfs_metadata directory.
11192c30dd74SAneesh Kumar K.V          */
11204fa4ce71SChen Gang         buffer = local_mapped_attr_path(ctx, fullname.data);
11214fa4ce71SChen Gang         ret = remove(buffer);
11224fa4ce71SChen Gang         g_free(buffer);
11232c30dd74SAneesh Kumar K.V         if (ret < 0 && errno != ENOENT) {
11242c30dd74SAneesh Kumar K.V             /*
11252c30dd74SAneesh Kumar K.V              * We didn't had the .virtfs_metadata file. May be file created
11262c30dd74SAneesh Kumar K.V              * in non-mapped mode ?. Ignore ENOENT.
11272c30dd74SAneesh Kumar K.V              */
11282c30dd74SAneesh Kumar K.V             goto err_out;
11292c30dd74SAneesh Kumar K.V         }
11302c30dd74SAneesh Kumar K.V     }
11312c30dd74SAneesh Kumar K.V     /* Remove the name finally */
11324fa4ce71SChen Gang     buffer = rpath(ctx, fullname.data);
11334fa4ce71SChen Gang     ret = remove(buffer);
11344fa4ce71SChen Gang     g_free(buffer);
11352289be19SAneesh Kumar K.V 
11362c30dd74SAneesh Kumar K.V err_out:
113775b7931eSChen Gang     v9fs_string_free(&fullname);
11382289be19SAneesh Kumar K.V     return ret;
11392289be19SAneesh Kumar K.V }
11409ed3ef26SAneesh Kumar K.V 
1141e06a765eSHarsh Prateek Bora static int local_ioc_getversion(FsContext *ctx, V9fsPath *path,
1142e06a765eSHarsh Prateek Bora                                 mode_t st_mode, uint64_t *st_gen)
1143e06a765eSHarsh Prateek Bora {
1144ae0f940eSPaolo Bonzini #ifdef FS_IOC_GETVERSION
11450e5fc994SKirill A. Shutemov     int err;
1146cc720ddbSAneesh Kumar K.V     V9fsFidOpenState fid_open;
1147cc720ddbSAneesh Kumar K.V 
1148e06a765eSHarsh Prateek Bora     /*
1149e06a765eSHarsh Prateek Bora      * Do not try to open special files like device nodes, fifos etc
1150e06a765eSHarsh Prateek Bora      * We can get fd for regular files and directories only
1151e06a765eSHarsh Prateek Bora      */
1152e06a765eSHarsh Prateek Bora     if (!S_ISREG(st_mode) && !S_ISDIR(st_mode)) {
11531a9978a5SKirill A. Shutemov         errno = ENOTTY;
11541a9978a5SKirill A. Shutemov         return -1;
1155e06a765eSHarsh Prateek Bora     }
1156cc720ddbSAneesh Kumar K.V     err = local_open(ctx, path, O_RDONLY, &fid_open);
1157cc720ddbSAneesh Kumar K.V     if (err < 0) {
1158cc720ddbSAneesh Kumar K.V         return err;
1159e06a765eSHarsh Prateek Bora     }
1160cc720ddbSAneesh Kumar K.V     err = ioctl(fid_open.fd, FS_IOC_GETVERSION, st_gen);
1161cc720ddbSAneesh Kumar K.V     local_close(ctx, &fid_open);
1162e06a765eSHarsh Prateek Bora     return err;
11630e5fc994SKirill A. Shutemov #else
11640e5fc994SKirill A. Shutemov     errno = ENOTTY;
11650e5fc994SKirill A. Shutemov     return -1;
11660e5fc994SKirill A. Shutemov #endif
1167e06a765eSHarsh Prateek Bora }
1168e06a765eSHarsh Prateek Bora 
11690174fe73SAneesh Kumar K.V static int local_init(FsContext *ctx)
11700174fe73SAneesh Kumar K.V {
11712507718bSAneesh Kumar K.V     int err = 0;
1172e06a765eSHarsh Prateek Bora     struct statfs stbuf;
1173e06a765eSHarsh Prateek Bora 
11742c30dd74SAneesh Kumar K.V     if (ctx->export_flags & V9FS_SM_PASSTHROUGH) {
11752c30dd74SAneesh Kumar K.V         ctx->xops = passthrough_xattr_ops;
11762c30dd74SAneesh Kumar K.V     } else if (ctx->export_flags & V9FS_SM_MAPPED) {
11772c30dd74SAneesh Kumar K.V         ctx->xops = mapped_xattr_ops;
11782c30dd74SAneesh Kumar K.V     } else if (ctx->export_flags & V9FS_SM_NONE) {
11792c30dd74SAneesh Kumar K.V         ctx->xops = none_xattr_ops;
11802c30dd74SAneesh Kumar K.V     } else if (ctx->export_flags & V9FS_SM_MAPPED_FILE) {
11812c30dd74SAneesh Kumar K.V         /*
11822c30dd74SAneesh Kumar K.V          * xattr operation for mapped-file and passthrough
11832c30dd74SAneesh Kumar K.V          * remain same.
11842c30dd74SAneesh Kumar K.V          */
11852c30dd74SAneesh Kumar K.V         ctx->xops = passthrough_xattr_ops;
11862c30dd74SAneesh Kumar K.V     }
1187c98f1d4aSAneesh Kumar K.V     ctx->export_flags |= V9FS_PATHNAME_FSCONTEXT;
11882507718bSAneesh Kumar K.V #ifdef FS_IOC_GETVERSION
11892507718bSAneesh Kumar K.V     /*
11902507718bSAneesh Kumar K.V      * use ioc_getversion only if the iocl is definied
11912507718bSAneesh Kumar K.V      */
1192e06a765eSHarsh Prateek Bora     err = statfs(ctx->fs_root, &stbuf);
1193e06a765eSHarsh Prateek Bora     if (!err) {
1194e06a765eSHarsh Prateek Bora         switch (stbuf.f_type) {
1195e06a765eSHarsh Prateek Bora         case EXT2_SUPER_MAGIC:
1196e06a765eSHarsh Prateek Bora         case BTRFS_SUPER_MAGIC:
1197e06a765eSHarsh Prateek Bora         case REISERFS_SUPER_MAGIC:
1198e06a765eSHarsh Prateek Bora         case XFS_SUPER_MAGIC:
1199e06a765eSHarsh Prateek Bora             ctx->exops.get_st_gen = local_ioc_getversion;
1200e06a765eSHarsh Prateek Bora             break;
1201e06a765eSHarsh Prateek Bora         }
1202e06a765eSHarsh Prateek Bora     }
12032507718bSAneesh Kumar K.V #endif
1204e06a765eSHarsh Prateek Bora     return err;
12050174fe73SAneesh Kumar K.V }
12060174fe73SAneesh Kumar K.V 
120799519f0aSAneesh Kumar K.V static int local_parse_opts(QemuOpts *opts, struct FsDriverEntry *fse)
120899519f0aSAneesh Kumar K.V {
120999519f0aSAneesh Kumar K.V     const char *sec_model = qemu_opt_get(opts, "security_model");
121099519f0aSAneesh Kumar K.V     const char *path = qemu_opt_get(opts, "path");
121199519f0aSAneesh Kumar K.V 
121299519f0aSAneesh Kumar K.V     if (!sec_model) {
1213*63325b18SGreg Kurz         error_report("Security model not specified, local fs needs security model");
1214*63325b18SGreg Kurz         error_printf("valid options are:"
1215*63325b18SGreg Kurz                      "\tsecurity_model=[passthrough|mapped-xattr|mapped-file|none]\n");
121699519f0aSAneesh Kumar K.V         return -1;
121799519f0aSAneesh Kumar K.V     }
121899519f0aSAneesh Kumar K.V 
121999519f0aSAneesh Kumar K.V     if (!strcmp(sec_model, "passthrough")) {
122099519f0aSAneesh Kumar K.V         fse->export_flags |= V9FS_SM_PASSTHROUGH;
12212c30dd74SAneesh Kumar K.V     } else if (!strcmp(sec_model, "mapped") ||
12222c30dd74SAneesh Kumar K.V                !strcmp(sec_model, "mapped-xattr")) {
122399519f0aSAneesh Kumar K.V         fse->export_flags |= V9FS_SM_MAPPED;
122499519f0aSAneesh Kumar K.V     } else if (!strcmp(sec_model, "none")) {
122599519f0aSAneesh Kumar K.V         fse->export_flags |= V9FS_SM_NONE;
12262c30dd74SAneesh Kumar K.V     } else if (!strcmp(sec_model, "mapped-file")) {
12272c30dd74SAneesh Kumar K.V         fse->export_flags |= V9FS_SM_MAPPED_FILE;
122899519f0aSAneesh Kumar K.V     } else {
1229*63325b18SGreg Kurz         error_report("Invalid security model %s specified", sec_model);
1230*63325b18SGreg Kurz         error_printf("valid options are:"
1231*63325b18SGreg Kurz                      "\t[passthrough|mapped-xattr|mapped-file|none]\n");
123299519f0aSAneesh Kumar K.V         return -1;
123399519f0aSAneesh Kumar K.V     }
123499519f0aSAneesh Kumar K.V 
123599519f0aSAneesh Kumar K.V     if (!path) {
1236*63325b18SGreg Kurz         error_report("fsdev: No path specified");
123799519f0aSAneesh Kumar K.V         return -1;
123899519f0aSAneesh Kumar K.V     }
123999519f0aSAneesh Kumar K.V     fse->path = g_strdup(path);
124099519f0aSAneesh Kumar K.V 
124199519f0aSAneesh Kumar K.V     return 0;
124299519f0aSAneesh Kumar K.V }
124399519f0aSAneesh Kumar K.V 
12449f107513SAnthony Liguori FileOperations local_ops = {
124599519f0aSAneesh Kumar K.V     .parse_opts = local_parse_opts,
12460174fe73SAneesh Kumar K.V     .init  = local_init,
1247131dcb25SAnthony Liguori     .lstat = local_lstat,
1248131dcb25SAnthony Liguori     .readlink = local_readlink,
1249131dcb25SAnthony Liguori     .close = local_close,
1250131dcb25SAnthony Liguori     .closedir = local_closedir,
1251a6568fe2SAnthony Liguori     .open = local_open,
1252a6568fe2SAnthony Liguori     .opendir = local_opendir,
1253a9231555SAnthony Liguori     .rewinddir = local_rewinddir,
1254a9231555SAnthony Liguori     .telldir = local_telldir,
12555f524c1eSHarsh Prateek Bora     .readdir_r = local_readdir_r,
1256a9231555SAnthony Liguori     .seekdir = local_seekdir,
125756d15a53SSanchit Garg     .preadv = local_preadv,
125856d15a53SSanchit Garg     .pwritev = local_pwritev,
1259c494dd6fSAnthony Liguori     .chmod = local_chmod,
1260c494dd6fSAnthony Liguori     .mknod = local_mknod,
1261c494dd6fSAnthony Liguori     .mkdir = local_mkdir,
1262c494dd6fSAnthony Liguori     .fstat = local_fstat,
1263c494dd6fSAnthony Liguori     .open2 = local_open2,
1264c494dd6fSAnthony Liguori     .symlink = local_symlink,
1265c494dd6fSAnthony Liguori     .link = local_link,
12668cf89e00SAnthony Liguori     .truncate = local_truncate,
12678cf89e00SAnthony Liguori     .rename = local_rename,
12688cf89e00SAnthony Liguori     .chown = local_chown,
126974bc02b2SM. Mohan Kumar     .utimensat = local_utimensat,
12705bae1900SAnthony Liguori     .remove = local_remove,
12718cf89e00SAnthony Liguori     .fsync = local_fsync,
1272be940c87SM. Mohan Kumar     .statfs = local_statfs,
1273fa32ef88SAneesh Kumar K.V     .lgetxattr = local_lgetxattr,
1274fa32ef88SAneesh Kumar K.V     .llistxattr = local_llistxattr,
127510b468bdSAneesh Kumar K.V     .lsetxattr = local_lsetxattr,
12769ed3ef26SAneesh Kumar K.V     .lremovexattr = local_lremovexattr,
12772289be19SAneesh Kumar K.V     .name_to_path = local_name_to_path,
12782289be19SAneesh Kumar K.V     .renameat  = local_renameat,
12792289be19SAneesh Kumar K.V     .unlinkat = local_unlinkat,
12809f107513SAnthony Liguori };
1281