1*f00d4f59SWei Liu /* 2*f00d4f59SWei Liu * 9p Posix callback 3*f00d4f59SWei Liu * 4*f00d4f59SWei Liu * Copyright IBM, Corp. 2010 5*f00d4f59SWei Liu * 6*f00d4f59SWei Liu * Authors: 7*f00d4f59SWei Liu * Anthony Liguori <aliguori@us.ibm.com> 8*f00d4f59SWei Liu * 9*f00d4f59SWei Liu * This work is licensed under the terms of the GNU GPL, version 2. See 10*f00d4f59SWei Liu * the COPYING file in the top-level directory. 11*f00d4f59SWei Liu * 12*f00d4f59SWei Liu */ 13*f00d4f59SWei Liu 14*f00d4f59SWei Liu #include "virtio-9p.h" 15*f00d4f59SWei Liu #include "virtio-9p-xattr.h" 16*f00d4f59SWei Liu #include "fsdev/qemu-fsdev.h" /* local_ops */ 17*f00d4f59SWei Liu #include <arpa/inet.h> 18*f00d4f59SWei Liu #include <pwd.h> 19*f00d4f59SWei Liu #include <grp.h> 20*f00d4f59SWei Liu #include <sys/socket.h> 21*f00d4f59SWei Liu #include <sys/un.h> 22*f00d4f59SWei Liu #include "qemu/xattr.h" 23*f00d4f59SWei Liu #include <libgen.h> 24*f00d4f59SWei Liu #include <linux/fs.h> 25*f00d4f59SWei Liu #ifdef CONFIG_LINUX_MAGIC_H 26*f00d4f59SWei Liu #include <linux/magic.h> 27*f00d4f59SWei Liu #endif 28*f00d4f59SWei Liu #include <sys/ioctl.h> 29*f00d4f59SWei Liu 30*f00d4f59SWei Liu #ifndef XFS_SUPER_MAGIC 31*f00d4f59SWei Liu #define XFS_SUPER_MAGIC 0x58465342 32*f00d4f59SWei Liu #endif 33*f00d4f59SWei Liu #ifndef EXT2_SUPER_MAGIC 34*f00d4f59SWei Liu #define EXT2_SUPER_MAGIC 0xEF53 35*f00d4f59SWei Liu #endif 36*f00d4f59SWei Liu #ifndef REISERFS_SUPER_MAGIC 37*f00d4f59SWei Liu #define REISERFS_SUPER_MAGIC 0x52654973 38*f00d4f59SWei Liu #endif 39*f00d4f59SWei Liu #ifndef BTRFS_SUPER_MAGIC 40*f00d4f59SWei Liu #define BTRFS_SUPER_MAGIC 0x9123683E 41*f00d4f59SWei Liu #endif 42*f00d4f59SWei Liu 43*f00d4f59SWei Liu #define VIRTFS_META_DIR ".virtfs_metadata" 44*f00d4f59SWei Liu 45*f00d4f59SWei Liu static char *local_mapped_attr_path(FsContext *ctx, const char *path) 46*f00d4f59SWei Liu { 47*f00d4f59SWei Liu int dirlen; 48*f00d4f59SWei Liu const char *name = strrchr(path, '/'); 49*f00d4f59SWei Liu if (name) { 50*f00d4f59SWei Liu dirlen = name - path; 51*f00d4f59SWei Liu ++name; 52*f00d4f59SWei Liu } else { 53*f00d4f59SWei Liu name = path; 54*f00d4f59SWei Liu dirlen = 0; 55*f00d4f59SWei Liu } 56*f00d4f59SWei Liu return g_strdup_printf("%s/%.*s/%s/%s", ctx->fs_root, 57*f00d4f59SWei Liu dirlen, path, VIRTFS_META_DIR, name); 58*f00d4f59SWei Liu } 59*f00d4f59SWei Liu 60*f00d4f59SWei Liu static FILE *local_fopen(const char *path, const char *mode) 61*f00d4f59SWei Liu { 62*f00d4f59SWei Liu int fd, o_mode = 0; 63*f00d4f59SWei Liu FILE *fp; 64*f00d4f59SWei Liu int flags = O_NOFOLLOW; 65*f00d4f59SWei Liu /* 66*f00d4f59SWei Liu * only supports two modes 67*f00d4f59SWei Liu */ 68*f00d4f59SWei Liu if (mode[0] == 'r') { 69*f00d4f59SWei Liu flags |= O_RDONLY; 70*f00d4f59SWei Liu } else if (mode[0] == 'w') { 71*f00d4f59SWei Liu flags |= O_WRONLY | O_TRUNC | O_CREAT; 72*f00d4f59SWei Liu o_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; 73*f00d4f59SWei Liu } else { 74*f00d4f59SWei Liu return NULL; 75*f00d4f59SWei Liu } 76*f00d4f59SWei Liu fd = open(path, flags, o_mode); 77*f00d4f59SWei Liu if (fd == -1) { 78*f00d4f59SWei Liu return NULL; 79*f00d4f59SWei Liu } 80*f00d4f59SWei Liu fp = fdopen(fd, mode); 81*f00d4f59SWei Liu if (!fp) { 82*f00d4f59SWei Liu close(fd); 83*f00d4f59SWei Liu } 84*f00d4f59SWei Liu return fp; 85*f00d4f59SWei Liu } 86*f00d4f59SWei Liu 87*f00d4f59SWei Liu #define ATTR_MAX 100 88*f00d4f59SWei Liu static void local_mapped_file_attr(FsContext *ctx, const char *path, 89*f00d4f59SWei Liu struct stat *stbuf) 90*f00d4f59SWei Liu { 91*f00d4f59SWei Liu FILE *fp; 92*f00d4f59SWei Liu char buf[ATTR_MAX]; 93*f00d4f59SWei Liu char *attr_path; 94*f00d4f59SWei Liu 95*f00d4f59SWei Liu attr_path = local_mapped_attr_path(ctx, path); 96*f00d4f59SWei Liu fp = local_fopen(attr_path, "r"); 97*f00d4f59SWei Liu g_free(attr_path); 98*f00d4f59SWei Liu if (!fp) { 99*f00d4f59SWei Liu return; 100*f00d4f59SWei Liu } 101*f00d4f59SWei Liu memset(buf, 0, ATTR_MAX); 102*f00d4f59SWei Liu while (fgets(buf, ATTR_MAX, fp)) { 103*f00d4f59SWei Liu if (!strncmp(buf, "virtfs.uid", 10)) { 104*f00d4f59SWei Liu stbuf->st_uid = atoi(buf+11); 105*f00d4f59SWei Liu } else if (!strncmp(buf, "virtfs.gid", 10)) { 106*f00d4f59SWei Liu stbuf->st_gid = atoi(buf+11); 107*f00d4f59SWei Liu } else if (!strncmp(buf, "virtfs.mode", 11)) { 108*f00d4f59SWei Liu stbuf->st_mode = atoi(buf+12); 109*f00d4f59SWei Liu } else if (!strncmp(buf, "virtfs.rdev", 11)) { 110*f00d4f59SWei Liu stbuf->st_rdev = atoi(buf+12); 111*f00d4f59SWei Liu } 112*f00d4f59SWei Liu memset(buf, 0, ATTR_MAX); 113*f00d4f59SWei Liu } 114*f00d4f59SWei Liu fclose(fp); 115*f00d4f59SWei Liu } 116*f00d4f59SWei Liu 117*f00d4f59SWei Liu static int local_lstat(FsContext *fs_ctx, V9fsPath *fs_path, struct stat *stbuf) 118*f00d4f59SWei Liu { 119*f00d4f59SWei Liu int err; 120*f00d4f59SWei Liu char *buffer; 121*f00d4f59SWei Liu char *path = fs_path->data; 122*f00d4f59SWei Liu 123*f00d4f59SWei Liu buffer = rpath(fs_ctx, path); 124*f00d4f59SWei Liu err = lstat(buffer, stbuf); 125*f00d4f59SWei Liu if (err) { 126*f00d4f59SWei Liu goto err_out; 127*f00d4f59SWei Liu } 128*f00d4f59SWei Liu if (fs_ctx->export_flags & V9FS_SM_MAPPED) { 129*f00d4f59SWei Liu /* Actual credentials are part of extended attrs */ 130*f00d4f59SWei Liu uid_t tmp_uid; 131*f00d4f59SWei Liu gid_t tmp_gid; 132*f00d4f59SWei Liu mode_t tmp_mode; 133*f00d4f59SWei Liu dev_t tmp_dev; 134*f00d4f59SWei Liu if (getxattr(buffer, "user.virtfs.uid", &tmp_uid, sizeof(uid_t)) > 0) { 135*f00d4f59SWei Liu stbuf->st_uid = le32_to_cpu(tmp_uid); 136*f00d4f59SWei Liu } 137*f00d4f59SWei Liu if (getxattr(buffer, "user.virtfs.gid", &tmp_gid, sizeof(gid_t)) > 0) { 138*f00d4f59SWei Liu stbuf->st_gid = le32_to_cpu(tmp_gid); 139*f00d4f59SWei Liu } 140*f00d4f59SWei Liu if (getxattr(buffer, "user.virtfs.mode", 141*f00d4f59SWei Liu &tmp_mode, sizeof(mode_t)) > 0) { 142*f00d4f59SWei Liu stbuf->st_mode = le32_to_cpu(tmp_mode); 143*f00d4f59SWei Liu } 144*f00d4f59SWei Liu if (getxattr(buffer, "user.virtfs.rdev", &tmp_dev, sizeof(dev_t)) > 0) { 145*f00d4f59SWei Liu stbuf->st_rdev = le64_to_cpu(tmp_dev); 146*f00d4f59SWei Liu } 147*f00d4f59SWei Liu } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) { 148*f00d4f59SWei Liu local_mapped_file_attr(fs_ctx, path, stbuf); 149*f00d4f59SWei Liu } 150*f00d4f59SWei Liu 151*f00d4f59SWei Liu err_out: 152*f00d4f59SWei Liu g_free(buffer); 153*f00d4f59SWei Liu return err; 154*f00d4f59SWei Liu } 155*f00d4f59SWei Liu 156*f00d4f59SWei Liu static int local_create_mapped_attr_dir(FsContext *ctx, const char *path) 157*f00d4f59SWei Liu { 158*f00d4f59SWei Liu int err; 159*f00d4f59SWei Liu char *attr_dir; 160*f00d4f59SWei Liu char *tmp_path = g_strdup(path); 161*f00d4f59SWei Liu 162*f00d4f59SWei Liu attr_dir = g_strdup_printf("%s/%s/%s", 163*f00d4f59SWei Liu ctx->fs_root, dirname(tmp_path), VIRTFS_META_DIR); 164*f00d4f59SWei Liu 165*f00d4f59SWei Liu err = mkdir(attr_dir, 0700); 166*f00d4f59SWei Liu if (err < 0 && errno == EEXIST) { 167*f00d4f59SWei Liu err = 0; 168*f00d4f59SWei Liu } 169*f00d4f59SWei Liu g_free(attr_dir); 170*f00d4f59SWei Liu g_free(tmp_path); 171*f00d4f59SWei Liu return err; 172*f00d4f59SWei Liu } 173*f00d4f59SWei Liu 174*f00d4f59SWei Liu static int local_set_mapped_file_attr(FsContext *ctx, 175*f00d4f59SWei Liu const char *path, FsCred *credp) 176*f00d4f59SWei Liu { 177*f00d4f59SWei Liu FILE *fp; 178*f00d4f59SWei Liu int ret = 0; 179*f00d4f59SWei Liu char buf[ATTR_MAX]; 180*f00d4f59SWei Liu char *attr_path; 181*f00d4f59SWei Liu int uid = -1, gid = -1, mode = -1, rdev = -1; 182*f00d4f59SWei Liu 183*f00d4f59SWei Liu attr_path = local_mapped_attr_path(ctx, path); 184*f00d4f59SWei Liu fp = local_fopen(attr_path, "r"); 185*f00d4f59SWei Liu if (!fp) { 186*f00d4f59SWei Liu goto create_map_file; 187*f00d4f59SWei Liu } 188*f00d4f59SWei Liu memset(buf, 0, ATTR_MAX); 189*f00d4f59SWei Liu while (fgets(buf, ATTR_MAX, fp)) { 190*f00d4f59SWei Liu if (!strncmp(buf, "virtfs.uid", 10)) { 191*f00d4f59SWei Liu uid = atoi(buf+11); 192*f00d4f59SWei Liu } else if (!strncmp(buf, "virtfs.gid", 10)) { 193*f00d4f59SWei Liu gid = atoi(buf+11); 194*f00d4f59SWei Liu } else if (!strncmp(buf, "virtfs.mode", 11)) { 195*f00d4f59SWei Liu mode = atoi(buf+12); 196*f00d4f59SWei Liu } else if (!strncmp(buf, "virtfs.rdev", 11)) { 197*f00d4f59SWei Liu rdev = atoi(buf+12); 198*f00d4f59SWei Liu } 199*f00d4f59SWei Liu memset(buf, 0, ATTR_MAX); 200*f00d4f59SWei Liu } 201*f00d4f59SWei Liu fclose(fp); 202*f00d4f59SWei Liu goto update_map_file; 203*f00d4f59SWei Liu 204*f00d4f59SWei Liu create_map_file: 205*f00d4f59SWei Liu ret = local_create_mapped_attr_dir(ctx, path); 206*f00d4f59SWei Liu if (ret < 0) { 207*f00d4f59SWei Liu goto err_out; 208*f00d4f59SWei Liu } 209*f00d4f59SWei Liu 210*f00d4f59SWei Liu update_map_file: 211*f00d4f59SWei Liu fp = local_fopen(attr_path, "w"); 212*f00d4f59SWei Liu if (!fp) { 213*f00d4f59SWei Liu ret = -1; 214*f00d4f59SWei Liu goto err_out; 215*f00d4f59SWei Liu } 216*f00d4f59SWei Liu 217*f00d4f59SWei Liu if (credp->fc_uid != -1) { 218*f00d4f59SWei Liu uid = credp->fc_uid; 219*f00d4f59SWei Liu } 220*f00d4f59SWei Liu if (credp->fc_gid != -1) { 221*f00d4f59SWei Liu gid = credp->fc_gid; 222*f00d4f59SWei Liu } 223*f00d4f59SWei Liu if (credp->fc_mode != -1) { 224*f00d4f59SWei Liu mode = credp->fc_mode; 225*f00d4f59SWei Liu } 226*f00d4f59SWei Liu if (credp->fc_rdev != -1) { 227*f00d4f59SWei Liu rdev = credp->fc_rdev; 228*f00d4f59SWei Liu } 229*f00d4f59SWei Liu 230*f00d4f59SWei Liu 231*f00d4f59SWei Liu if (uid != -1) { 232*f00d4f59SWei Liu fprintf(fp, "virtfs.uid=%d\n", uid); 233*f00d4f59SWei Liu } 234*f00d4f59SWei Liu if (gid != -1) { 235*f00d4f59SWei Liu fprintf(fp, "virtfs.gid=%d\n", gid); 236*f00d4f59SWei Liu } 237*f00d4f59SWei Liu if (mode != -1) { 238*f00d4f59SWei Liu fprintf(fp, "virtfs.mode=%d\n", mode); 239*f00d4f59SWei Liu } 240*f00d4f59SWei Liu if (rdev != -1) { 241*f00d4f59SWei Liu fprintf(fp, "virtfs.rdev=%d\n", rdev); 242*f00d4f59SWei Liu } 243*f00d4f59SWei Liu fclose(fp); 244*f00d4f59SWei Liu 245*f00d4f59SWei Liu err_out: 246*f00d4f59SWei Liu g_free(attr_path); 247*f00d4f59SWei Liu return ret; 248*f00d4f59SWei Liu } 249*f00d4f59SWei Liu 250*f00d4f59SWei Liu static int local_set_xattr(const char *path, FsCred *credp) 251*f00d4f59SWei Liu { 252*f00d4f59SWei Liu int err; 253*f00d4f59SWei Liu 254*f00d4f59SWei Liu if (credp->fc_uid != -1) { 255*f00d4f59SWei Liu uint32_t tmp_uid = cpu_to_le32(credp->fc_uid); 256*f00d4f59SWei Liu err = setxattr(path, "user.virtfs.uid", &tmp_uid, sizeof(uid_t), 0); 257*f00d4f59SWei Liu if (err) { 258*f00d4f59SWei Liu return err; 259*f00d4f59SWei Liu } 260*f00d4f59SWei Liu } 261*f00d4f59SWei Liu if (credp->fc_gid != -1) { 262*f00d4f59SWei Liu uint32_t tmp_gid = cpu_to_le32(credp->fc_gid); 263*f00d4f59SWei Liu err = setxattr(path, "user.virtfs.gid", &tmp_gid, sizeof(gid_t), 0); 264*f00d4f59SWei Liu if (err) { 265*f00d4f59SWei Liu return err; 266*f00d4f59SWei Liu } 267*f00d4f59SWei Liu } 268*f00d4f59SWei Liu if (credp->fc_mode != -1) { 269*f00d4f59SWei Liu uint32_t tmp_mode = cpu_to_le32(credp->fc_mode); 270*f00d4f59SWei Liu err = setxattr(path, "user.virtfs.mode", &tmp_mode, sizeof(mode_t), 0); 271*f00d4f59SWei Liu if (err) { 272*f00d4f59SWei Liu return err; 273*f00d4f59SWei Liu } 274*f00d4f59SWei Liu } 275*f00d4f59SWei Liu if (credp->fc_rdev != -1) { 276*f00d4f59SWei Liu uint64_t tmp_rdev = cpu_to_le64(credp->fc_rdev); 277*f00d4f59SWei Liu err = setxattr(path, "user.virtfs.rdev", &tmp_rdev, sizeof(dev_t), 0); 278*f00d4f59SWei Liu if (err) { 279*f00d4f59SWei Liu return err; 280*f00d4f59SWei Liu } 281*f00d4f59SWei Liu } 282*f00d4f59SWei Liu return 0; 283*f00d4f59SWei Liu } 284*f00d4f59SWei Liu 285*f00d4f59SWei Liu static int local_post_create_passthrough(FsContext *fs_ctx, const char *path, 286*f00d4f59SWei Liu FsCred *credp) 287*f00d4f59SWei Liu { 288*f00d4f59SWei Liu char *buffer; 289*f00d4f59SWei Liu 290*f00d4f59SWei Liu buffer = rpath(fs_ctx, path); 291*f00d4f59SWei Liu if (lchown(buffer, credp->fc_uid, credp->fc_gid) < 0) { 292*f00d4f59SWei Liu /* 293*f00d4f59SWei Liu * If we fail to change ownership and if we are 294*f00d4f59SWei Liu * using security model none. Ignore the error 295*f00d4f59SWei Liu */ 296*f00d4f59SWei Liu if ((fs_ctx->export_flags & V9FS_SEC_MASK) != V9FS_SM_NONE) { 297*f00d4f59SWei Liu goto err; 298*f00d4f59SWei Liu } 299*f00d4f59SWei Liu } 300*f00d4f59SWei Liu 301*f00d4f59SWei Liu if (chmod(buffer, credp->fc_mode & 07777) < 0) { 302*f00d4f59SWei Liu goto err; 303*f00d4f59SWei Liu } 304*f00d4f59SWei Liu 305*f00d4f59SWei Liu g_free(buffer); 306*f00d4f59SWei Liu return 0; 307*f00d4f59SWei Liu err: 308*f00d4f59SWei Liu g_free(buffer); 309*f00d4f59SWei Liu return -1; 310*f00d4f59SWei Liu } 311*f00d4f59SWei Liu 312*f00d4f59SWei Liu static ssize_t local_readlink(FsContext *fs_ctx, V9fsPath *fs_path, 313*f00d4f59SWei Liu char *buf, size_t bufsz) 314*f00d4f59SWei Liu { 315*f00d4f59SWei Liu ssize_t tsize = -1; 316*f00d4f59SWei Liu char *buffer; 317*f00d4f59SWei Liu char *path = fs_path->data; 318*f00d4f59SWei Liu 319*f00d4f59SWei Liu if ((fs_ctx->export_flags & V9FS_SM_MAPPED) || 320*f00d4f59SWei Liu (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE)) { 321*f00d4f59SWei Liu int fd; 322*f00d4f59SWei Liu buffer = rpath(fs_ctx, path); 323*f00d4f59SWei Liu fd = open(buffer, O_RDONLY | O_NOFOLLOW); 324*f00d4f59SWei Liu g_free(buffer); 325*f00d4f59SWei Liu if (fd == -1) { 326*f00d4f59SWei Liu return -1; 327*f00d4f59SWei Liu } 328*f00d4f59SWei Liu do { 329*f00d4f59SWei Liu tsize = read(fd, (void *)buf, bufsz); 330*f00d4f59SWei Liu } while (tsize == -1 && errno == EINTR); 331*f00d4f59SWei Liu close(fd); 332*f00d4f59SWei Liu } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) || 333*f00d4f59SWei Liu (fs_ctx->export_flags & V9FS_SM_NONE)) { 334*f00d4f59SWei Liu buffer = rpath(fs_ctx, path); 335*f00d4f59SWei Liu tsize = readlink(buffer, buf, bufsz); 336*f00d4f59SWei Liu g_free(buffer); 337*f00d4f59SWei Liu } 338*f00d4f59SWei Liu return tsize; 339*f00d4f59SWei Liu } 340*f00d4f59SWei Liu 341*f00d4f59SWei Liu static int local_close(FsContext *ctx, V9fsFidOpenState *fs) 342*f00d4f59SWei Liu { 343*f00d4f59SWei Liu return close(fs->fd); 344*f00d4f59SWei Liu } 345*f00d4f59SWei Liu 346*f00d4f59SWei Liu static int local_closedir(FsContext *ctx, V9fsFidOpenState *fs) 347*f00d4f59SWei Liu { 348*f00d4f59SWei Liu return closedir(fs->dir); 349*f00d4f59SWei Liu } 350*f00d4f59SWei Liu 351*f00d4f59SWei Liu static int local_open(FsContext *ctx, V9fsPath *fs_path, 352*f00d4f59SWei Liu int flags, V9fsFidOpenState *fs) 353*f00d4f59SWei Liu { 354*f00d4f59SWei Liu char *buffer; 355*f00d4f59SWei Liu char *path = fs_path->data; 356*f00d4f59SWei Liu 357*f00d4f59SWei Liu buffer = rpath(ctx, path); 358*f00d4f59SWei Liu fs->fd = open(buffer, flags | O_NOFOLLOW); 359*f00d4f59SWei Liu g_free(buffer); 360*f00d4f59SWei Liu return fs->fd; 361*f00d4f59SWei Liu } 362*f00d4f59SWei Liu 363*f00d4f59SWei Liu static int local_opendir(FsContext *ctx, 364*f00d4f59SWei Liu V9fsPath *fs_path, V9fsFidOpenState *fs) 365*f00d4f59SWei Liu { 366*f00d4f59SWei Liu char *buffer; 367*f00d4f59SWei Liu char *path = fs_path->data; 368*f00d4f59SWei Liu 369*f00d4f59SWei Liu buffer = rpath(ctx, path); 370*f00d4f59SWei Liu fs->dir = opendir(buffer); 371*f00d4f59SWei Liu g_free(buffer); 372*f00d4f59SWei Liu if (!fs->dir) { 373*f00d4f59SWei Liu return -1; 374*f00d4f59SWei Liu } 375*f00d4f59SWei Liu return 0; 376*f00d4f59SWei Liu } 377*f00d4f59SWei Liu 378*f00d4f59SWei Liu static void local_rewinddir(FsContext *ctx, V9fsFidOpenState *fs) 379*f00d4f59SWei Liu { 380*f00d4f59SWei Liu rewinddir(fs->dir); 381*f00d4f59SWei Liu } 382*f00d4f59SWei Liu 383*f00d4f59SWei Liu static off_t local_telldir(FsContext *ctx, V9fsFidOpenState *fs) 384*f00d4f59SWei Liu { 385*f00d4f59SWei Liu return telldir(fs->dir); 386*f00d4f59SWei Liu } 387*f00d4f59SWei Liu 388*f00d4f59SWei Liu static int local_readdir_r(FsContext *ctx, V9fsFidOpenState *fs, 389*f00d4f59SWei Liu struct dirent *entry, 390*f00d4f59SWei Liu struct dirent **result) 391*f00d4f59SWei Liu { 392*f00d4f59SWei Liu int ret; 393*f00d4f59SWei Liu 394*f00d4f59SWei Liu again: 395*f00d4f59SWei Liu ret = readdir_r(fs->dir, entry, result); 396*f00d4f59SWei Liu if (ctx->export_flags & V9FS_SM_MAPPED) { 397*f00d4f59SWei Liu entry->d_type = DT_UNKNOWN; 398*f00d4f59SWei Liu } else if (ctx->export_flags & V9FS_SM_MAPPED_FILE) { 399*f00d4f59SWei Liu if (!ret && *result != NULL && 400*f00d4f59SWei Liu !strcmp(entry->d_name, VIRTFS_META_DIR)) { 401*f00d4f59SWei Liu /* skp the meta data directory */ 402*f00d4f59SWei Liu goto again; 403*f00d4f59SWei Liu } 404*f00d4f59SWei Liu entry->d_type = DT_UNKNOWN; 405*f00d4f59SWei Liu } 406*f00d4f59SWei Liu return ret; 407*f00d4f59SWei Liu } 408*f00d4f59SWei Liu 409*f00d4f59SWei Liu static void local_seekdir(FsContext *ctx, V9fsFidOpenState *fs, off_t off) 410*f00d4f59SWei Liu { 411*f00d4f59SWei Liu seekdir(fs->dir, off); 412*f00d4f59SWei Liu } 413*f00d4f59SWei Liu 414*f00d4f59SWei Liu static ssize_t local_preadv(FsContext *ctx, V9fsFidOpenState *fs, 415*f00d4f59SWei Liu const struct iovec *iov, 416*f00d4f59SWei Liu int iovcnt, off_t offset) 417*f00d4f59SWei Liu { 418*f00d4f59SWei Liu #ifdef CONFIG_PREADV 419*f00d4f59SWei Liu return preadv(fs->fd, iov, iovcnt, offset); 420*f00d4f59SWei Liu #else 421*f00d4f59SWei Liu int err = lseek(fs->fd, offset, SEEK_SET); 422*f00d4f59SWei Liu if (err == -1) { 423*f00d4f59SWei Liu return err; 424*f00d4f59SWei Liu } else { 425*f00d4f59SWei Liu return readv(fs->fd, iov, iovcnt); 426*f00d4f59SWei Liu } 427*f00d4f59SWei Liu #endif 428*f00d4f59SWei Liu } 429*f00d4f59SWei Liu 430*f00d4f59SWei Liu static ssize_t local_pwritev(FsContext *ctx, V9fsFidOpenState *fs, 431*f00d4f59SWei Liu const struct iovec *iov, 432*f00d4f59SWei Liu int iovcnt, off_t offset) 433*f00d4f59SWei Liu { 434*f00d4f59SWei Liu ssize_t ret 435*f00d4f59SWei Liu ; 436*f00d4f59SWei Liu #ifdef CONFIG_PREADV 437*f00d4f59SWei Liu ret = pwritev(fs->fd, iov, iovcnt, offset); 438*f00d4f59SWei Liu #else 439*f00d4f59SWei Liu int err = lseek(fs->fd, offset, SEEK_SET); 440*f00d4f59SWei Liu if (err == -1) { 441*f00d4f59SWei Liu return err; 442*f00d4f59SWei Liu } else { 443*f00d4f59SWei Liu ret = writev(fs->fd, iov, iovcnt); 444*f00d4f59SWei Liu } 445*f00d4f59SWei Liu #endif 446*f00d4f59SWei Liu #ifdef CONFIG_SYNC_FILE_RANGE 447*f00d4f59SWei Liu if (ret > 0 && ctx->export_flags & V9FS_IMMEDIATE_WRITEOUT) { 448*f00d4f59SWei Liu /* 449*f00d4f59SWei Liu * Initiate a writeback. This is not a data integrity sync. 450*f00d4f59SWei Liu * We want to ensure that we don't leave dirty pages in the cache 451*f00d4f59SWei Liu * after write when writeout=immediate is sepcified. 452*f00d4f59SWei Liu */ 453*f00d4f59SWei Liu sync_file_range(fs->fd, offset, ret, 454*f00d4f59SWei Liu SYNC_FILE_RANGE_WAIT_BEFORE | SYNC_FILE_RANGE_WRITE); 455*f00d4f59SWei Liu } 456*f00d4f59SWei Liu #endif 457*f00d4f59SWei Liu return ret; 458*f00d4f59SWei Liu } 459*f00d4f59SWei Liu 460*f00d4f59SWei Liu static int local_chmod(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp) 461*f00d4f59SWei Liu { 462*f00d4f59SWei Liu char *buffer; 463*f00d4f59SWei Liu int ret = -1; 464*f00d4f59SWei Liu char *path = fs_path->data; 465*f00d4f59SWei Liu 466*f00d4f59SWei Liu if (fs_ctx->export_flags & V9FS_SM_MAPPED) { 467*f00d4f59SWei Liu buffer = rpath(fs_ctx, path); 468*f00d4f59SWei Liu ret = local_set_xattr(buffer, credp); 469*f00d4f59SWei Liu g_free(buffer); 470*f00d4f59SWei Liu } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) { 471*f00d4f59SWei Liu return local_set_mapped_file_attr(fs_ctx, path, credp); 472*f00d4f59SWei Liu } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) || 473*f00d4f59SWei Liu (fs_ctx->export_flags & V9FS_SM_NONE)) { 474*f00d4f59SWei Liu buffer = rpath(fs_ctx, path); 475*f00d4f59SWei Liu ret = chmod(buffer, credp->fc_mode); 476*f00d4f59SWei Liu g_free(buffer); 477*f00d4f59SWei Liu } 478*f00d4f59SWei Liu return ret; 479*f00d4f59SWei Liu } 480*f00d4f59SWei Liu 481*f00d4f59SWei Liu static int local_mknod(FsContext *fs_ctx, V9fsPath *dir_path, 482*f00d4f59SWei Liu const char *name, FsCred *credp) 483*f00d4f59SWei Liu { 484*f00d4f59SWei Liu char *path; 485*f00d4f59SWei Liu int err = -1; 486*f00d4f59SWei Liu int serrno = 0; 487*f00d4f59SWei Liu V9fsString fullname; 488*f00d4f59SWei Liu char *buffer = NULL; 489*f00d4f59SWei Liu 490*f00d4f59SWei Liu v9fs_string_init(&fullname); 491*f00d4f59SWei Liu v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name); 492*f00d4f59SWei Liu path = fullname.data; 493*f00d4f59SWei Liu 494*f00d4f59SWei Liu /* Determine the security model */ 495*f00d4f59SWei Liu if (fs_ctx->export_flags & V9FS_SM_MAPPED) { 496*f00d4f59SWei Liu buffer = rpath(fs_ctx, path); 497*f00d4f59SWei Liu err = mknod(buffer, SM_LOCAL_MODE_BITS|S_IFREG, 0); 498*f00d4f59SWei Liu if (err == -1) { 499*f00d4f59SWei Liu goto out; 500*f00d4f59SWei Liu } 501*f00d4f59SWei Liu err = local_set_xattr(buffer, credp); 502*f00d4f59SWei Liu if (err == -1) { 503*f00d4f59SWei Liu serrno = errno; 504*f00d4f59SWei Liu goto err_end; 505*f00d4f59SWei Liu } 506*f00d4f59SWei Liu } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) { 507*f00d4f59SWei Liu 508*f00d4f59SWei Liu buffer = rpath(fs_ctx, path); 509*f00d4f59SWei Liu err = mknod(buffer, SM_LOCAL_MODE_BITS|S_IFREG, 0); 510*f00d4f59SWei Liu if (err == -1) { 511*f00d4f59SWei Liu goto out; 512*f00d4f59SWei Liu } 513*f00d4f59SWei Liu err = local_set_mapped_file_attr(fs_ctx, path, credp); 514*f00d4f59SWei Liu if (err == -1) { 515*f00d4f59SWei Liu serrno = errno; 516*f00d4f59SWei Liu goto err_end; 517*f00d4f59SWei Liu } 518*f00d4f59SWei Liu } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) || 519*f00d4f59SWei Liu (fs_ctx->export_flags & V9FS_SM_NONE)) { 520*f00d4f59SWei Liu buffer = rpath(fs_ctx, path); 521*f00d4f59SWei Liu err = mknod(buffer, credp->fc_mode, credp->fc_rdev); 522*f00d4f59SWei Liu if (err == -1) { 523*f00d4f59SWei Liu goto out; 524*f00d4f59SWei Liu } 525*f00d4f59SWei Liu err = local_post_create_passthrough(fs_ctx, path, credp); 526*f00d4f59SWei Liu if (err == -1) { 527*f00d4f59SWei Liu serrno = errno; 528*f00d4f59SWei Liu goto err_end; 529*f00d4f59SWei Liu } 530*f00d4f59SWei Liu } 531*f00d4f59SWei Liu goto out; 532*f00d4f59SWei Liu 533*f00d4f59SWei Liu err_end: 534*f00d4f59SWei Liu remove(buffer); 535*f00d4f59SWei Liu errno = serrno; 536*f00d4f59SWei Liu out: 537*f00d4f59SWei Liu g_free(buffer); 538*f00d4f59SWei Liu v9fs_string_free(&fullname); 539*f00d4f59SWei Liu return err; 540*f00d4f59SWei Liu } 541*f00d4f59SWei Liu 542*f00d4f59SWei Liu static int local_mkdir(FsContext *fs_ctx, V9fsPath *dir_path, 543*f00d4f59SWei Liu const char *name, FsCred *credp) 544*f00d4f59SWei Liu { 545*f00d4f59SWei Liu char *path; 546*f00d4f59SWei Liu int err = -1; 547*f00d4f59SWei Liu int serrno = 0; 548*f00d4f59SWei Liu V9fsString fullname; 549*f00d4f59SWei Liu char *buffer = NULL; 550*f00d4f59SWei Liu 551*f00d4f59SWei Liu v9fs_string_init(&fullname); 552*f00d4f59SWei Liu v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name); 553*f00d4f59SWei Liu path = fullname.data; 554*f00d4f59SWei Liu 555*f00d4f59SWei Liu /* Determine the security model */ 556*f00d4f59SWei Liu if (fs_ctx->export_flags & V9FS_SM_MAPPED) { 557*f00d4f59SWei Liu buffer = rpath(fs_ctx, path); 558*f00d4f59SWei Liu err = mkdir(buffer, SM_LOCAL_DIR_MODE_BITS); 559*f00d4f59SWei Liu if (err == -1) { 560*f00d4f59SWei Liu goto out; 561*f00d4f59SWei Liu } 562*f00d4f59SWei Liu credp->fc_mode = credp->fc_mode|S_IFDIR; 563*f00d4f59SWei Liu err = local_set_xattr(buffer, credp); 564*f00d4f59SWei Liu if (err == -1) { 565*f00d4f59SWei Liu serrno = errno; 566*f00d4f59SWei Liu goto err_end; 567*f00d4f59SWei Liu } 568*f00d4f59SWei Liu } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) { 569*f00d4f59SWei Liu buffer = rpath(fs_ctx, path); 570*f00d4f59SWei Liu err = mkdir(buffer, SM_LOCAL_DIR_MODE_BITS); 571*f00d4f59SWei Liu if (err == -1) { 572*f00d4f59SWei Liu goto out; 573*f00d4f59SWei Liu } 574*f00d4f59SWei Liu credp->fc_mode = credp->fc_mode|S_IFDIR; 575*f00d4f59SWei Liu err = local_set_mapped_file_attr(fs_ctx, path, credp); 576*f00d4f59SWei Liu if (err == -1) { 577*f00d4f59SWei Liu serrno = errno; 578*f00d4f59SWei Liu goto err_end; 579*f00d4f59SWei Liu } 580*f00d4f59SWei Liu } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) || 581*f00d4f59SWei Liu (fs_ctx->export_flags & V9FS_SM_NONE)) { 582*f00d4f59SWei Liu buffer = rpath(fs_ctx, path); 583*f00d4f59SWei Liu err = mkdir(buffer, credp->fc_mode); 584*f00d4f59SWei Liu if (err == -1) { 585*f00d4f59SWei Liu goto out; 586*f00d4f59SWei Liu } 587*f00d4f59SWei Liu err = local_post_create_passthrough(fs_ctx, path, credp); 588*f00d4f59SWei Liu if (err == -1) { 589*f00d4f59SWei Liu serrno = errno; 590*f00d4f59SWei Liu goto err_end; 591*f00d4f59SWei Liu } 592*f00d4f59SWei Liu } 593*f00d4f59SWei Liu goto out; 594*f00d4f59SWei Liu 595*f00d4f59SWei Liu err_end: 596*f00d4f59SWei Liu remove(buffer); 597*f00d4f59SWei Liu errno = serrno; 598*f00d4f59SWei Liu out: 599*f00d4f59SWei Liu g_free(buffer); 600*f00d4f59SWei Liu v9fs_string_free(&fullname); 601*f00d4f59SWei Liu return err; 602*f00d4f59SWei Liu } 603*f00d4f59SWei Liu 604*f00d4f59SWei Liu static int local_fstat(FsContext *fs_ctx, int fid_type, 605*f00d4f59SWei Liu V9fsFidOpenState *fs, struct stat *stbuf) 606*f00d4f59SWei Liu { 607*f00d4f59SWei Liu int err, fd; 608*f00d4f59SWei Liu 609*f00d4f59SWei Liu if (fid_type == P9_FID_DIR) { 610*f00d4f59SWei Liu fd = dirfd(fs->dir); 611*f00d4f59SWei Liu } else { 612*f00d4f59SWei Liu fd = fs->fd; 613*f00d4f59SWei Liu } 614*f00d4f59SWei Liu 615*f00d4f59SWei Liu err = fstat(fd, stbuf); 616*f00d4f59SWei Liu if (err) { 617*f00d4f59SWei Liu return err; 618*f00d4f59SWei Liu } 619*f00d4f59SWei Liu if (fs_ctx->export_flags & V9FS_SM_MAPPED) { 620*f00d4f59SWei Liu /* Actual credentials are part of extended attrs */ 621*f00d4f59SWei Liu uid_t tmp_uid; 622*f00d4f59SWei Liu gid_t tmp_gid; 623*f00d4f59SWei Liu mode_t tmp_mode; 624*f00d4f59SWei Liu dev_t tmp_dev; 625*f00d4f59SWei Liu 626*f00d4f59SWei Liu if (fgetxattr(fd, "user.virtfs.uid", &tmp_uid, sizeof(uid_t)) > 0) { 627*f00d4f59SWei Liu stbuf->st_uid = le32_to_cpu(tmp_uid); 628*f00d4f59SWei Liu } 629*f00d4f59SWei Liu if (fgetxattr(fd, "user.virtfs.gid", &tmp_gid, sizeof(gid_t)) > 0) { 630*f00d4f59SWei Liu stbuf->st_gid = le32_to_cpu(tmp_gid); 631*f00d4f59SWei Liu } 632*f00d4f59SWei Liu if (fgetxattr(fd, "user.virtfs.mode", &tmp_mode, sizeof(mode_t)) > 0) { 633*f00d4f59SWei Liu stbuf->st_mode = le32_to_cpu(tmp_mode); 634*f00d4f59SWei Liu } 635*f00d4f59SWei Liu if (fgetxattr(fd, "user.virtfs.rdev", &tmp_dev, sizeof(dev_t)) > 0) { 636*f00d4f59SWei Liu stbuf->st_rdev = le64_to_cpu(tmp_dev); 637*f00d4f59SWei Liu } 638*f00d4f59SWei Liu } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) { 639*f00d4f59SWei Liu errno = EOPNOTSUPP; 640*f00d4f59SWei Liu return -1; 641*f00d4f59SWei Liu } 642*f00d4f59SWei Liu return err; 643*f00d4f59SWei Liu } 644*f00d4f59SWei Liu 645*f00d4f59SWei Liu static int local_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name, 646*f00d4f59SWei Liu int flags, FsCred *credp, V9fsFidOpenState *fs) 647*f00d4f59SWei Liu { 648*f00d4f59SWei Liu char *path; 649*f00d4f59SWei Liu int fd = -1; 650*f00d4f59SWei Liu int err = -1; 651*f00d4f59SWei Liu int serrno = 0; 652*f00d4f59SWei Liu V9fsString fullname; 653*f00d4f59SWei Liu char *buffer = NULL; 654*f00d4f59SWei Liu 655*f00d4f59SWei Liu /* 656*f00d4f59SWei Liu * Mark all the open to not follow symlinks 657*f00d4f59SWei Liu */ 658*f00d4f59SWei Liu flags |= O_NOFOLLOW; 659*f00d4f59SWei Liu 660*f00d4f59SWei Liu v9fs_string_init(&fullname); 661*f00d4f59SWei Liu v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name); 662*f00d4f59SWei Liu path = fullname.data; 663*f00d4f59SWei Liu 664*f00d4f59SWei Liu /* Determine the security model */ 665*f00d4f59SWei Liu if (fs_ctx->export_flags & V9FS_SM_MAPPED) { 666*f00d4f59SWei Liu buffer = rpath(fs_ctx, path); 667*f00d4f59SWei Liu fd = open(buffer, flags, SM_LOCAL_MODE_BITS); 668*f00d4f59SWei Liu if (fd == -1) { 669*f00d4f59SWei Liu err = fd; 670*f00d4f59SWei Liu goto out; 671*f00d4f59SWei Liu } 672*f00d4f59SWei Liu credp->fc_mode = credp->fc_mode|S_IFREG; 673*f00d4f59SWei Liu /* Set cleint credentials in xattr */ 674*f00d4f59SWei Liu err = local_set_xattr(buffer, credp); 675*f00d4f59SWei Liu if (err == -1) { 676*f00d4f59SWei Liu serrno = errno; 677*f00d4f59SWei Liu goto err_end; 678*f00d4f59SWei Liu } 679*f00d4f59SWei Liu } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) { 680*f00d4f59SWei Liu buffer = rpath(fs_ctx, path); 681*f00d4f59SWei Liu fd = open(buffer, flags, SM_LOCAL_MODE_BITS); 682*f00d4f59SWei Liu if (fd == -1) { 683*f00d4f59SWei Liu err = fd; 684*f00d4f59SWei Liu goto out; 685*f00d4f59SWei Liu } 686*f00d4f59SWei Liu credp->fc_mode = credp->fc_mode|S_IFREG; 687*f00d4f59SWei Liu /* Set client credentials in .virtfs_metadata directory files */ 688*f00d4f59SWei Liu err = local_set_mapped_file_attr(fs_ctx, path, credp); 689*f00d4f59SWei Liu if (err == -1) { 690*f00d4f59SWei Liu serrno = errno; 691*f00d4f59SWei Liu goto err_end; 692*f00d4f59SWei Liu } 693*f00d4f59SWei Liu } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) || 694*f00d4f59SWei Liu (fs_ctx->export_flags & V9FS_SM_NONE)) { 695*f00d4f59SWei Liu buffer = rpath(fs_ctx, path); 696*f00d4f59SWei Liu fd = open(buffer, flags, credp->fc_mode); 697*f00d4f59SWei Liu if (fd == -1) { 698*f00d4f59SWei Liu err = fd; 699*f00d4f59SWei Liu goto out; 700*f00d4f59SWei Liu } 701*f00d4f59SWei Liu err = local_post_create_passthrough(fs_ctx, path, credp); 702*f00d4f59SWei Liu if (err == -1) { 703*f00d4f59SWei Liu serrno = errno; 704*f00d4f59SWei Liu goto err_end; 705*f00d4f59SWei Liu } 706*f00d4f59SWei Liu } 707*f00d4f59SWei Liu err = fd; 708*f00d4f59SWei Liu fs->fd = fd; 709*f00d4f59SWei Liu goto out; 710*f00d4f59SWei Liu 711*f00d4f59SWei Liu err_end: 712*f00d4f59SWei Liu close(fd); 713*f00d4f59SWei Liu remove(buffer); 714*f00d4f59SWei Liu errno = serrno; 715*f00d4f59SWei Liu out: 716*f00d4f59SWei Liu g_free(buffer); 717*f00d4f59SWei Liu v9fs_string_free(&fullname); 718*f00d4f59SWei Liu return err; 719*f00d4f59SWei Liu } 720*f00d4f59SWei Liu 721*f00d4f59SWei Liu 722*f00d4f59SWei Liu static int local_symlink(FsContext *fs_ctx, const char *oldpath, 723*f00d4f59SWei Liu V9fsPath *dir_path, const char *name, FsCred *credp) 724*f00d4f59SWei Liu { 725*f00d4f59SWei Liu int err = -1; 726*f00d4f59SWei Liu int serrno = 0; 727*f00d4f59SWei Liu char *newpath; 728*f00d4f59SWei Liu V9fsString fullname; 729*f00d4f59SWei Liu char *buffer = NULL; 730*f00d4f59SWei Liu 731*f00d4f59SWei Liu v9fs_string_init(&fullname); 732*f00d4f59SWei Liu v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name); 733*f00d4f59SWei Liu newpath = fullname.data; 734*f00d4f59SWei Liu 735*f00d4f59SWei Liu /* Determine the security model */ 736*f00d4f59SWei Liu if (fs_ctx->export_flags & V9FS_SM_MAPPED) { 737*f00d4f59SWei Liu int fd; 738*f00d4f59SWei Liu ssize_t oldpath_size, write_size; 739*f00d4f59SWei Liu buffer = rpath(fs_ctx, newpath); 740*f00d4f59SWei Liu fd = open(buffer, O_CREAT|O_EXCL|O_RDWR|O_NOFOLLOW, SM_LOCAL_MODE_BITS); 741*f00d4f59SWei Liu if (fd == -1) { 742*f00d4f59SWei Liu err = fd; 743*f00d4f59SWei Liu goto out; 744*f00d4f59SWei Liu } 745*f00d4f59SWei Liu /* Write the oldpath (target) to the file. */ 746*f00d4f59SWei Liu oldpath_size = strlen(oldpath); 747*f00d4f59SWei Liu do { 748*f00d4f59SWei Liu write_size = write(fd, (void *)oldpath, oldpath_size); 749*f00d4f59SWei Liu } while (write_size == -1 && errno == EINTR); 750*f00d4f59SWei Liu 751*f00d4f59SWei Liu if (write_size != oldpath_size) { 752*f00d4f59SWei Liu serrno = errno; 753*f00d4f59SWei Liu close(fd); 754*f00d4f59SWei Liu err = -1; 755*f00d4f59SWei Liu goto err_end; 756*f00d4f59SWei Liu } 757*f00d4f59SWei Liu close(fd); 758*f00d4f59SWei Liu /* Set cleint credentials in symlink's xattr */ 759*f00d4f59SWei Liu credp->fc_mode = credp->fc_mode|S_IFLNK; 760*f00d4f59SWei Liu err = local_set_xattr(buffer, credp); 761*f00d4f59SWei Liu if (err == -1) { 762*f00d4f59SWei Liu serrno = errno; 763*f00d4f59SWei Liu goto err_end; 764*f00d4f59SWei Liu } 765*f00d4f59SWei Liu } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) { 766*f00d4f59SWei Liu int fd; 767*f00d4f59SWei Liu ssize_t oldpath_size, write_size; 768*f00d4f59SWei Liu buffer = rpath(fs_ctx, newpath); 769*f00d4f59SWei Liu fd = open(buffer, O_CREAT|O_EXCL|O_RDWR|O_NOFOLLOW, SM_LOCAL_MODE_BITS); 770*f00d4f59SWei Liu if (fd == -1) { 771*f00d4f59SWei Liu err = fd; 772*f00d4f59SWei Liu goto out; 773*f00d4f59SWei Liu } 774*f00d4f59SWei Liu /* Write the oldpath (target) to the file. */ 775*f00d4f59SWei Liu oldpath_size = strlen(oldpath); 776*f00d4f59SWei Liu do { 777*f00d4f59SWei Liu write_size = write(fd, (void *)oldpath, oldpath_size); 778*f00d4f59SWei Liu } while (write_size == -1 && errno == EINTR); 779*f00d4f59SWei Liu 780*f00d4f59SWei Liu if (write_size != oldpath_size) { 781*f00d4f59SWei Liu serrno = errno; 782*f00d4f59SWei Liu close(fd); 783*f00d4f59SWei Liu err = -1; 784*f00d4f59SWei Liu goto err_end; 785*f00d4f59SWei Liu } 786*f00d4f59SWei Liu close(fd); 787*f00d4f59SWei Liu /* Set cleint credentials in symlink's xattr */ 788*f00d4f59SWei Liu credp->fc_mode = credp->fc_mode|S_IFLNK; 789*f00d4f59SWei Liu err = local_set_mapped_file_attr(fs_ctx, newpath, credp); 790*f00d4f59SWei Liu if (err == -1) { 791*f00d4f59SWei Liu serrno = errno; 792*f00d4f59SWei Liu goto err_end; 793*f00d4f59SWei Liu } 794*f00d4f59SWei Liu } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) || 795*f00d4f59SWei Liu (fs_ctx->export_flags & V9FS_SM_NONE)) { 796*f00d4f59SWei Liu buffer = rpath(fs_ctx, newpath); 797*f00d4f59SWei Liu err = symlink(oldpath, buffer); 798*f00d4f59SWei Liu if (err) { 799*f00d4f59SWei Liu goto out; 800*f00d4f59SWei Liu } 801*f00d4f59SWei Liu err = lchown(buffer, credp->fc_uid, credp->fc_gid); 802*f00d4f59SWei Liu if (err == -1) { 803*f00d4f59SWei Liu /* 804*f00d4f59SWei Liu * If we fail to change ownership and if we are 805*f00d4f59SWei Liu * using security model none. Ignore the error 806*f00d4f59SWei Liu */ 807*f00d4f59SWei Liu if ((fs_ctx->export_flags & V9FS_SEC_MASK) != V9FS_SM_NONE) { 808*f00d4f59SWei Liu serrno = errno; 809*f00d4f59SWei Liu goto err_end; 810*f00d4f59SWei Liu } else 811*f00d4f59SWei Liu err = 0; 812*f00d4f59SWei Liu } 813*f00d4f59SWei Liu } 814*f00d4f59SWei Liu goto out; 815*f00d4f59SWei Liu 816*f00d4f59SWei Liu err_end: 817*f00d4f59SWei Liu remove(buffer); 818*f00d4f59SWei Liu errno = serrno; 819*f00d4f59SWei Liu out: 820*f00d4f59SWei Liu g_free(buffer); 821*f00d4f59SWei Liu v9fs_string_free(&fullname); 822*f00d4f59SWei Liu return err; 823*f00d4f59SWei Liu } 824*f00d4f59SWei Liu 825*f00d4f59SWei Liu static int local_link(FsContext *ctx, V9fsPath *oldpath, 826*f00d4f59SWei Liu V9fsPath *dirpath, const char *name) 827*f00d4f59SWei Liu { 828*f00d4f59SWei Liu int ret; 829*f00d4f59SWei Liu V9fsString newpath; 830*f00d4f59SWei Liu char *buffer, *buffer1; 831*f00d4f59SWei Liu 832*f00d4f59SWei Liu v9fs_string_init(&newpath); 833*f00d4f59SWei Liu v9fs_string_sprintf(&newpath, "%s/%s", dirpath->data, name); 834*f00d4f59SWei Liu 835*f00d4f59SWei Liu buffer = rpath(ctx, oldpath->data); 836*f00d4f59SWei Liu buffer1 = rpath(ctx, newpath.data); 837*f00d4f59SWei Liu ret = link(buffer, buffer1); 838*f00d4f59SWei Liu g_free(buffer); 839*f00d4f59SWei Liu g_free(buffer1); 840*f00d4f59SWei Liu 841*f00d4f59SWei Liu /* now link the virtfs_metadata files */ 842*f00d4f59SWei Liu if (!ret && (ctx->export_flags & V9FS_SM_MAPPED_FILE)) { 843*f00d4f59SWei Liu /* Link the .virtfs_metadata files. Create the metada directory */ 844*f00d4f59SWei Liu ret = local_create_mapped_attr_dir(ctx, newpath.data); 845*f00d4f59SWei Liu if (ret < 0) { 846*f00d4f59SWei Liu goto err_out; 847*f00d4f59SWei Liu } 848*f00d4f59SWei Liu buffer = local_mapped_attr_path(ctx, oldpath->data); 849*f00d4f59SWei Liu buffer1 = local_mapped_attr_path(ctx, newpath.data); 850*f00d4f59SWei Liu ret = link(buffer, buffer1); 851*f00d4f59SWei Liu g_free(buffer); 852*f00d4f59SWei Liu g_free(buffer1); 853*f00d4f59SWei Liu if (ret < 0 && errno != ENOENT) { 854*f00d4f59SWei Liu goto err_out; 855*f00d4f59SWei Liu } 856*f00d4f59SWei Liu } 857*f00d4f59SWei Liu err_out: 858*f00d4f59SWei Liu v9fs_string_free(&newpath); 859*f00d4f59SWei Liu return ret; 860*f00d4f59SWei Liu } 861*f00d4f59SWei Liu 862*f00d4f59SWei Liu static int local_truncate(FsContext *ctx, V9fsPath *fs_path, off_t size) 863*f00d4f59SWei Liu { 864*f00d4f59SWei Liu char *buffer; 865*f00d4f59SWei Liu int ret; 866*f00d4f59SWei Liu char *path = fs_path->data; 867*f00d4f59SWei Liu 868*f00d4f59SWei Liu buffer = rpath(ctx, path); 869*f00d4f59SWei Liu ret = truncate(buffer, size); 870*f00d4f59SWei Liu g_free(buffer); 871*f00d4f59SWei Liu return ret; 872*f00d4f59SWei Liu } 873*f00d4f59SWei Liu 874*f00d4f59SWei Liu static int local_rename(FsContext *ctx, const char *oldpath, 875*f00d4f59SWei Liu const char *newpath) 876*f00d4f59SWei Liu { 877*f00d4f59SWei Liu int err; 878*f00d4f59SWei Liu char *buffer, *buffer1; 879*f00d4f59SWei Liu 880*f00d4f59SWei Liu if (ctx->export_flags & V9FS_SM_MAPPED_FILE) { 881*f00d4f59SWei Liu err = local_create_mapped_attr_dir(ctx, newpath); 882*f00d4f59SWei Liu if (err < 0) { 883*f00d4f59SWei Liu return err; 884*f00d4f59SWei Liu } 885*f00d4f59SWei Liu /* rename the .virtfs_metadata files */ 886*f00d4f59SWei Liu buffer = local_mapped_attr_path(ctx, oldpath); 887*f00d4f59SWei Liu buffer1 = local_mapped_attr_path(ctx, newpath); 888*f00d4f59SWei Liu err = rename(buffer, buffer1); 889*f00d4f59SWei Liu g_free(buffer); 890*f00d4f59SWei Liu g_free(buffer1); 891*f00d4f59SWei Liu if (err < 0 && errno != ENOENT) { 892*f00d4f59SWei Liu return err; 893*f00d4f59SWei Liu } 894*f00d4f59SWei Liu } 895*f00d4f59SWei Liu 896*f00d4f59SWei Liu buffer = rpath(ctx, oldpath); 897*f00d4f59SWei Liu buffer1 = rpath(ctx, newpath); 898*f00d4f59SWei Liu err = rename(buffer, buffer1); 899*f00d4f59SWei Liu g_free(buffer); 900*f00d4f59SWei Liu g_free(buffer1); 901*f00d4f59SWei Liu return err; 902*f00d4f59SWei Liu } 903*f00d4f59SWei Liu 904*f00d4f59SWei Liu static int local_chown(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp) 905*f00d4f59SWei Liu { 906*f00d4f59SWei Liu char *buffer; 907*f00d4f59SWei Liu int ret = -1; 908*f00d4f59SWei Liu char *path = fs_path->data; 909*f00d4f59SWei Liu 910*f00d4f59SWei Liu if ((credp->fc_uid == -1 && credp->fc_gid == -1) || 911*f00d4f59SWei Liu (fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) || 912*f00d4f59SWei Liu (fs_ctx->export_flags & V9FS_SM_NONE)) { 913*f00d4f59SWei Liu buffer = rpath(fs_ctx, path); 914*f00d4f59SWei Liu ret = lchown(buffer, credp->fc_uid, credp->fc_gid); 915*f00d4f59SWei Liu g_free(buffer); 916*f00d4f59SWei Liu } else if (fs_ctx->export_flags & V9FS_SM_MAPPED) { 917*f00d4f59SWei Liu buffer = rpath(fs_ctx, path); 918*f00d4f59SWei Liu ret = local_set_xattr(buffer, credp); 919*f00d4f59SWei Liu g_free(buffer); 920*f00d4f59SWei Liu } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) { 921*f00d4f59SWei Liu return local_set_mapped_file_attr(fs_ctx, path, credp); 922*f00d4f59SWei Liu } 923*f00d4f59SWei Liu return ret; 924*f00d4f59SWei Liu } 925*f00d4f59SWei Liu 926*f00d4f59SWei Liu static int local_utimensat(FsContext *s, V9fsPath *fs_path, 927*f00d4f59SWei Liu const struct timespec *buf) 928*f00d4f59SWei Liu { 929*f00d4f59SWei Liu char *buffer; 930*f00d4f59SWei Liu int ret; 931*f00d4f59SWei Liu char *path = fs_path->data; 932*f00d4f59SWei Liu 933*f00d4f59SWei Liu buffer = rpath(s, path); 934*f00d4f59SWei Liu ret = qemu_utimens(buffer, buf); 935*f00d4f59SWei Liu g_free(buffer); 936*f00d4f59SWei Liu return ret; 937*f00d4f59SWei Liu } 938*f00d4f59SWei Liu 939*f00d4f59SWei Liu static int local_remove(FsContext *ctx, const char *path) 940*f00d4f59SWei Liu { 941*f00d4f59SWei Liu int err; 942*f00d4f59SWei Liu struct stat stbuf; 943*f00d4f59SWei Liu char *buffer; 944*f00d4f59SWei Liu 945*f00d4f59SWei Liu if (ctx->export_flags & V9FS_SM_MAPPED_FILE) { 946*f00d4f59SWei Liu buffer = rpath(ctx, path); 947*f00d4f59SWei Liu err = lstat(buffer, &stbuf); 948*f00d4f59SWei Liu g_free(buffer); 949*f00d4f59SWei Liu if (err) { 950*f00d4f59SWei Liu goto err_out; 951*f00d4f59SWei Liu } 952*f00d4f59SWei Liu /* 953*f00d4f59SWei Liu * If directory remove .virtfs_metadata contained in the 954*f00d4f59SWei Liu * directory 955*f00d4f59SWei Liu */ 956*f00d4f59SWei Liu if (S_ISDIR(stbuf.st_mode)) { 957*f00d4f59SWei Liu buffer = g_strdup_printf("%s/%s/%s", ctx->fs_root, 958*f00d4f59SWei Liu path, VIRTFS_META_DIR); 959*f00d4f59SWei Liu err = remove(buffer); 960*f00d4f59SWei Liu g_free(buffer); 961*f00d4f59SWei Liu if (err < 0 && errno != ENOENT) { 962*f00d4f59SWei Liu /* 963*f00d4f59SWei Liu * We didn't had the .virtfs_metadata file. May be file created 964*f00d4f59SWei Liu * in non-mapped mode ?. Ignore ENOENT. 965*f00d4f59SWei Liu */ 966*f00d4f59SWei Liu goto err_out; 967*f00d4f59SWei Liu } 968*f00d4f59SWei Liu } 969*f00d4f59SWei Liu /* 970*f00d4f59SWei Liu * Now remove the name from parent directory 971*f00d4f59SWei Liu * .virtfs_metadata directory 972*f00d4f59SWei Liu */ 973*f00d4f59SWei Liu buffer = local_mapped_attr_path(ctx, path); 974*f00d4f59SWei Liu err = remove(buffer); 975*f00d4f59SWei Liu g_free(buffer); 976*f00d4f59SWei Liu if (err < 0 && errno != ENOENT) { 977*f00d4f59SWei Liu /* 978*f00d4f59SWei Liu * We didn't had the .virtfs_metadata file. May be file created 979*f00d4f59SWei Liu * in non-mapped mode ?. Ignore ENOENT. 980*f00d4f59SWei Liu */ 981*f00d4f59SWei Liu goto err_out; 982*f00d4f59SWei Liu } 983*f00d4f59SWei Liu } 984*f00d4f59SWei Liu 985*f00d4f59SWei Liu buffer = rpath(ctx, path); 986*f00d4f59SWei Liu err = remove(buffer); 987*f00d4f59SWei Liu g_free(buffer); 988*f00d4f59SWei Liu err_out: 989*f00d4f59SWei Liu return err; 990*f00d4f59SWei Liu } 991*f00d4f59SWei Liu 992*f00d4f59SWei Liu static int local_fsync(FsContext *ctx, int fid_type, 993*f00d4f59SWei Liu V9fsFidOpenState *fs, int datasync) 994*f00d4f59SWei Liu { 995*f00d4f59SWei Liu int fd; 996*f00d4f59SWei Liu 997*f00d4f59SWei Liu if (fid_type == P9_FID_DIR) { 998*f00d4f59SWei Liu fd = dirfd(fs->dir); 999*f00d4f59SWei Liu } else { 1000*f00d4f59SWei Liu fd = fs->fd; 1001*f00d4f59SWei Liu } 1002*f00d4f59SWei Liu 1003*f00d4f59SWei Liu if (datasync) { 1004*f00d4f59SWei Liu return qemu_fdatasync(fd); 1005*f00d4f59SWei Liu } else { 1006*f00d4f59SWei Liu return fsync(fd); 1007*f00d4f59SWei Liu } 1008*f00d4f59SWei Liu } 1009*f00d4f59SWei Liu 1010*f00d4f59SWei Liu static int local_statfs(FsContext *s, V9fsPath *fs_path, struct statfs *stbuf) 1011*f00d4f59SWei Liu { 1012*f00d4f59SWei Liu char *buffer; 1013*f00d4f59SWei Liu int ret; 1014*f00d4f59SWei Liu char *path = fs_path->data; 1015*f00d4f59SWei Liu 1016*f00d4f59SWei Liu buffer = rpath(s, path); 1017*f00d4f59SWei Liu ret = statfs(buffer, stbuf); 1018*f00d4f59SWei Liu g_free(buffer); 1019*f00d4f59SWei Liu return ret; 1020*f00d4f59SWei Liu } 1021*f00d4f59SWei Liu 1022*f00d4f59SWei Liu static ssize_t local_lgetxattr(FsContext *ctx, V9fsPath *fs_path, 1023*f00d4f59SWei Liu const char *name, void *value, size_t size) 1024*f00d4f59SWei Liu { 1025*f00d4f59SWei Liu char *path = fs_path->data; 1026*f00d4f59SWei Liu 1027*f00d4f59SWei Liu return v9fs_get_xattr(ctx, path, name, value, size); 1028*f00d4f59SWei Liu } 1029*f00d4f59SWei Liu 1030*f00d4f59SWei Liu static ssize_t local_llistxattr(FsContext *ctx, V9fsPath *fs_path, 1031*f00d4f59SWei Liu void *value, size_t size) 1032*f00d4f59SWei Liu { 1033*f00d4f59SWei Liu char *path = fs_path->data; 1034*f00d4f59SWei Liu 1035*f00d4f59SWei Liu return v9fs_list_xattr(ctx, path, value, size); 1036*f00d4f59SWei Liu } 1037*f00d4f59SWei Liu 1038*f00d4f59SWei Liu static int local_lsetxattr(FsContext *ctx, V9fsPath *fs_path, const char *name, 1039*f00d4f59SWei Liu void *value, size_t size, int flags) 1040*f00d4f59SWei Liu { 1041*f00d4f59SWei Liu char *path = fs_path->data; 1042*f00d4f59SWei Liu 1043*f00d4f59SWei Liu return v9fs_set_xattr(ctx, path, name, value, size, flags); 1044*f00d4f59SWei Liu } 1045*f00d4f59SWei Liu 1046*f00d4f59SWei Liu static int local_lremovexattr(FsContext *ctx, V9fsPath *fs_path, 1047*f00d4f59SWei Liu const char *name) 1048*f00d4f59SWei Liu { 1049*f00d4f59SWei Liu char *path = fs_path->data; 1050*f00d4f59SWei Liu 1051*f00d4f59SWei Liu return v9fs_remove_xattr(ctx, path, name); 1052*f00d4f59SWei Liu } 1053*f00d4f59SWei Liu 1054*f00d4f59SWei Liu static int local_name_to_path(FsContext *ctx, V9fsPath *dir_path, 1055*f00d4f59SWei Liu const char *name, V9fsPath *target) 1056*f00d4f59SWei Liu { 1057*f00d4f59SWei Liu if (dir_path) { 1058*f00d4f59SWei Liu v9fs_string_sprintf((V9fsString *)target, "%s/%s", 1059*f00d4f59SWei Liu dir_path->data, name); 1060*f00d4f59SWei Liu } else { 1061*f00d4f59SWei Liu v9fs_string_sprintf((V9fsString *)target, "%s", name); 1062*f00d4f59SWei Liu } 1063*f00d4f59SWei Liu /* Bump the size for including terminating NULL */ 1064*f00d4f59SWei Liu target->size++; 1065*f00d4f59SWei Liu return 0; 1066*f00d4f59SWei Liu } 1067*f00d4f59SWei Liu 1068*f00d4f59SWei Liu static int local_renameat(FsContext *ctx, V9fsPath *olddir, 1069*f00d4f59SWei Liu const char *old_name, V9fsPath *newdir, 1070*f00d4f59SWei Liu const char *new_name) 1071*f00d4f59SWei Liu { 1072*f00d4f59SWei Liu int ret; 1073*f00d4f59SWei Liu V9fsString old_full_name, new_full_name; 1074*f00d4f59SWei Liu 1075*f00d4f59SWei Liu v9fs_string_init(&old_full_name); 1076*f00d4f59SWei Liu v9fs_string_init(&new_full_name); 1077*f00d4f59SWei Liu 1078*f00d4f59SWei Liu v9fs_string_sprintf(&old_full_name, "%s/%s", olddir->data, old_name); 1079*f00d4f59SWei Liu v9fs_string_sprintf(&new_full_name, "%s/%s", newdir->data, new_name); 1080*f00d4f59SWei Liu 1081*f00d4f59SWei Liu ret = local_rename(ctx, old_full_name.data, new_full_name.data); 1082*f00d4f59SWei Liu v9fs_string_free(&old_full_name); 1083*f00d4f59SWei Liu v9fs_string_free(&new_full_name); 1084*f00d4f59SWei Liu return ret; 1085*f00d4f59SWei Liu } 1086*f00d4f59SWei Liu 1087*f00d4f59SWei Liu static int local_unlinkat(FsContext *ctx, V9fsPath *dir, 1088*f00d4f59SWei Liu const char *name, int flags) 1089*f00d4f59SWei Liu { 1090*f00d4f59SWei Liu int ret; 1091*f00d4f59SWei Liu V9fsString fullname; 1092*f00d4f59SWei Liu char *buffer; 1093*f00d4f59SWei Liu 1094*f00d4f59SWei Liu v9fs_string_init(&fullname); 1095*f00d4f59SWei Liu 1096*f00d4f59SWei Liu v9fs_string_sprintf(&fullname, "%s/%s", dir->data, name); 1097*f00d4f59SWei Liu if (ctx->export_flags & V9FS_SM_MAPPED_FILE) { 1098*f00d4f59SWei Liu if (flags == AT_REMOVEDIR) { 1099*f00d4f59SWei Liu /* 1100*f00d4f59SWei Liu * If directory remove .virtfs_metadata contained in the 1101*f00d4f59SWei Liu * directory 1102*f00d4f59SWei Liu */ 1103*f00d4f59SWei Liu buffer = g_strdup_printf("%s/%s/%s", ctx->fs_root, 1104*f00d4f59SWei Liu fullname.data, VIRTFS_META_DIR); 1105*f00d4f59SWei Liu ret = remove(buffer); 1106*f00d4f59SWei Liu g_free(buffer); 1107*f00d4f59SWei Liu if (ret < 0 && errno != ENOENT) { 1108*f00d4f59SWei Liu /* 1109*f00d4f59SWei Liu * We didn't had the .virtfs_metadata file. May be file created 1110*f00d4f59SWei Liu * in non-mapped mode ?. Ignore ENOENT. 1111*f00d4f59SWei Liu */ 1112*f00d4f59SWei Liu goto err_out; 1113*f00d4f59SWei Liu } 1114*f00d4f59SWei Liu } 1115*f00d4f59SWei Liu /* 1116*f00d4f59SWei Liu * Now remove the name from parent directory 1117*f00d4f59SWei Liu * .virtfs_metadata directory. 1118*f00d4f59SWei Liu */ 1119*f00d4f59SWei Liu buffer = local_mapped_attr_path(ctx, fullname.data); 1120*f00d4f59SWei Liu ret = remove(buffer); 1121*f00d4f59SWei Liu g_free(buffer); 1122*f00d4f59SWei Liu if (ret < 0 && errno != ENOENT) { 1123*f00d4f59SWei Liu /* 1124*f00d4f59SWei Liu * We didn't had the .virtfs_metadata file. May be file created 1125*f00d4f59SWei Liu * in non-mapped mode ?. Ignore ENOENT. 1126*f00d4f59SWei Liu */ 1127*f00d4f59SWei Liu goto err_out; 1128*f00d4f59SWei Liu } 1129*f00d4f59SWei Liu } 1130*f00d4f59SWei Liu /* Remove the name finally */ 1131*f00d4f59SWei Liu buffer = rpath(ctx, fullname.data); 1132*f00d4f59SWei Liu ret = remove(buffer); 1133*f00d4f59SWei Liu g_free(buffer); 1134*f00d4f59SWei Liu 1135*f00d4f59SWei Liu err_out: 1136*f00d4f59SWei Liu v9fs_string_free(&fullname); 1137*f00d4f59SWei Liu return ret; 1138*f00d4f59SWei Liu } 1139*f00d4f59SWei Liu 1140*f00d4f59SWei Liu static int local_ioc_getversion(FsContext *ctx, V9fsPath *path, 1141*f00d4f59SWei Liu mode_t st_mode, uint64_t *st_gen) 1142*f00d4f59SWei Liu { 1143*f00d4f59SWei Liu #ifdef FS_IOC_GETVERSION 1144*f00d4f59SWei Liu int err; 1145*f00d4f59SWei Liu V9fsFidOpenState fid_open; 1146*f00d4f59SWei Liu 1147*f00d4f59SWei Liu /* 1148*f00d4f59SWei Liu * Do not try to open special files like device nodes, fifos etc 1149*f00d4f59SWei Liu * We can get fd for regular files and directories only 1150*f00d4f59SWei Liu */ 1151*f00d4f59SWei Liu if (!S_ISREG(st_mode) && !S_ISDIR(st_mode)) { 1152*f00d4f59SWei Liu errno = ENOTTY; 1153*f00d4f59SWei Liu return -1; 1154*f00d4f59SWei Liu } 1155*f00d4f59SWei Liu err = local_open(ctx, path, O_RDONLY, &fid_open); 1156*f00d4f59SWei Liu if (err < 0) { 1157*f00d4f59SWei Liu return err; 1158*f00d4f59SWei Liu } 1159*f00d4f59SWei Liu err = ioctl(fid_open.fd, FS_IOC_GETVERSION, st_gen); 1160*f00d4f59SWei Liu local_close(ctx, &fid_open); 1161*f00d4f59SWei Liu return err; 1162*f00d4f59SWei Liu #else 1163*f00d4f59SWei Liu errno = ENOTTY; 1164*f00d4f59SWei Liu return -1; 1165*f00d4f59SWei Liu #endif 1166*f00d4f59SWei Liu } 1167*f00d4f59SWei Liu 1168*f00d4f59SWei Liu static int local_init(FsContext *ctx) 1169*f00d4f59SWei Liu { 1170*f00d4f59SWei Liu int err = 0; 1171*f00d4f59SWei Liu struct statfs stbuf; 1172*f00d4f59SWei Liu 1173*f00d4f59SWei Liu if (ctx->export_flags & V9FS_SM_PASSTHROUGH) { 1174*f00d4f59SWei Liu ctx->xops = passthrough_xattr_ops; 1175*f00d4f59SWei Liu } else if (ctx->export_flags & V9FS_SM_MAPPED) { 1176*f00d4f59SWei Liu ctx->xops = mapped_xattr_ops; 1177*f00d4f59SWei Liu } else if (ctx->export_flags & V9FS_SM_NONE) { 1178*f00d4f59SWei Liu ctx->xops = none_xattr_ops; 1179*f00d4f59SWei Liu } else if (ctx->export_flags & V9FS_SM_MAPPED_FILE) { 1180*f00d4f59SWei Liu /* 1181*f00d4f59SWei Liu * xattr operation for mapped-file and passthrough 1182*f00d4f59SWei Liu * remain same. 1183*f00d4f59SWei Liu */ 1184*f00d4f59SWei Liu ctx->xops = passthrough_xattr_ops; 1185*f00d4f59SWei Liu } 1186*f00d4f59SWei Liu ctx->export_flags |= V9FS_PATHNAME_FSCONTEXT; 1187*f00d4f59SWei Liu #ifdef FS_IOC_GETVERSION 1188*f00d4f59SWei Liu /* 1189*f00d4f59SWei Liu * use ioc_getversion only if the iocl is definied 1190*f00d4f59SWei Liu */ 1191*f00d4f59SWei Liu err = statfs(ctx->fs_root, &stbuf); 1192*f00d4f59SWei Liu if (!err) { 1193*f00d4f59SWei Liu switch (stbuf.f_type) { 1194*f00d4f59SWei Liu case EXT2_SUPER_MAGIC: 1195*f00d4f59SWei Liu case BTRFS_SUPER_MAGIC: 1196*f00d4f59SWei Liu case REISERFS_SUPER_MAGIC: 1197*f00d4f59SWei Liu case XFS_SUPER_MAGIC: 1198*f00d4f59SWei Liu ctx->exops.get_st_gen = local_ioc_getversion; 1199*f00d4f59SWei Liu break; 1200*f00d4f59SWei Liu } 1201*f00d4f59SWei Liu } 1202*f00d4f59SWei Liu #endif 1203*f00d4f59SWei Liu return err; 1204*f00d4f59SWei Liu } 1205*f00d4f59SWei Liu 1206*f00d4f59SWei Liu static int local_parse_opts(QemuOpts *opts, struct FsDriverEntry *fse) 1207*f00d4f59SWei Liu { 1208*f00d4f59SWei Liu const char *sec_model = qemu_opt_get(opts, "security_model"); 1209*f00d4f59SWei Liu const char *path = qemu_opt_get(opts, "path"); 1210*f00d4f59SWei Liu 1211*f00d4f59SWei Liu if (!sec_model) { 1212*f00d4f59SWei Liu fprintf(stderr, "security model not specified, " 1213*f00d4f59SWei Liu "local fs needs security model\nvalid options are:" 1214*f00d4f59SWei Liu "\tsecurity_model=[passthrough|mapped|none]\n"); 1215*f00d4f59SWei Liu return -1; 1216*f00d4f59SWei Liu } 1217*f00d4f59SWei Liu 1218*f00d4f59SWei Liu if (!strcmp(sec_model, "passthrough")) { 1219*f00d4f59SWei Liu fse->export_flags |= V9FS_SM_PASSTHROUGH; 1220*f00d4f59SWei Liu } else if (!strcmp(sec_model, "mapped") || 1221*f00d4f59SWei Liu !strcmp(sec_model, "mapped-xattr")) { 1222*f00d4f59SWei Liu fse->export_flags |= V9FS_SM_MAPPED; 1223*f00d4f59SWei Liu } else if (!strcmp(sec_model, "none")) { 1224*f00d4f59SWei Liu fse->export_flags |= V9FS_SM_NONE; 1225*f00d4f59SWei Liu } else if (!strcmp(sec_model, "mapped-file")) { 1226*f00d4f59SWei Liu fse->export_flags |= V9FS_SM_MAPPED_FILE; 1227*f00d4f59SWei Liu } else { 1228*f00d4f59SWei Liu fprintf(stderr, "Invalid security model %s specified, valid options are" 1229*f00d4f59SWei Liu "\n\t [passthrough|mapped-xattr|mapped-file|none]\n", 1230*f00d4f59SWei Liu sec_model); 1231*f00d4f59SWei Liu return -1; 1232*f00d4f59SWei Liu } 1233*f00d4f59SWei Liu 1234*f00d4f59SWei Liu if (!path) { 1235*f00d4f59SWei Liu fprintf(stderr, "fsdev: No path specified.\n"); 1236*f00d4f59SWei Liu return -1; 1237*f00d4f59SWei Liu } 1238*f00d4f59SWei Liu fse->path = g_strdup(path); 1239*f00d4f59SWei Liu 1240*f00d4f59SWei Liu return 0; 1241*f00d4f59SWei Liu } 1242*f00d4f59SWei Liu 1243*f00d4f59SWei Liu FileOperations local_ops = { 1244*f00d4f59SWei Liu .parse_opts = local_parse_opts, 1245*f00d4f59SWei Liu .init = local_init, 1246*f00d4f59SWei Liu .lstat = local_lstat, 1247*f00d4f59SWei Liu .readlink = local_readlink, 1248*f00d4f59SWei Liu .close = local_close, 1249*f00d4f59SWei Liu .closedir = local_closedir, 1250*f00d4f59SWei Liu .open = local_open, 1251*f00d4f59SWei Liu .opendir = local_opendir, 1252*f00d4f59SWei Liu .rewinddir = local_rewinddir, 1253*f00d4f59SWei Liu .telldir = local_telldir, 1254*f00d4f59SWei Liu .readdir_r = local_readdir_r, 1255*f00d4f59SWei Liu .seekdir = local_seekdir, 1256*f00d4f59SWei Liu .preadv = local_preadv, 1257*f00d4f59SWei Liu .pwritev = local_pwritev, 1258*f00d4f59SWei Liu .chmod = local_chmod, 1259*f00d4f59SWei Liu .mknod = local_mknod, 1260*f00d4f59SWei Liu .mkdir = local_mkdir, 1261*f00d4f59SWei Liu .fstat = local_fstat, 1262*f00d4f59SWei Liu .open2 = local_open2, 1263*f00d4f59SWei Liu .symlink = local_symlink, 1264*f00d4f59SWei Liu .link = local_link, 1265*f00d4f59SWei Liu .truncate = local_truncate, 1266*f00d4f59SWei Liu .rename = local_rename, 1267*f00d4f59SWei Liu .chown = local_chown, 1268*f00d4f59SWei Liu .utimensat = local_utimensat, 1269*f00d4f59SWei Liu .remove = local_remove, 1270*f00d4f59SWei Liu .fsync = local_fsync, 1271*f00d4f59SWei Liu .statfs = local_statfs, 1272*f00d4f59SWei Liu .lgetxattr = local_lgetxattr, 1273*f00d4f59SWei Liu .llistxattr = local_llistxattr, 1274*f00d4f59SWei Liu .lsetxattr = local_lsetxattr, 1275*f00d4f59SWei Liu .lremovexattr = local_lremovexattr, 1276*f00d4f59SWei Liu .name_to_path = local_name_to_path, 1277*f00d4f59SWei Liu .renameat = local_renameat, 1278*f00d4f59SWei Liu .unlinkat = local_unlinkat, 1279*f00d4f59SWei Liu }; 1280