Annotation of qemu/hw/9pfs/virtio-9p-local.c, revision 1.1.1.3

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.