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

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>
        !            22: #include <attr/xattr.h>
        !            23: 
        !            24: 
        !            25: static int local_lstat(FsContext *fs_ctx, const char *path, struct stat *stbuf)
        !            26: {
        !            27:     int err;
        !            28:     char buffer[PATH_MAX];
        !            29:     err =  lstat(rpath(fs_ctx, path, buffer), stbuf);
        !            30:     if (err) {
        !            31:         return err;
        !            32:     }
        !            33:     if (fs_ctx->fs_sm == SM_MAPPED) {
        !            34:         /* Actual credentials are part of extended attrs */
        !            35:         uid_t tmp_uid;
        !            36:         gid_t tmp_gid;
        !            37:         mode_t tmp_mode;
        !            38:         dev_t tmp_dev;
        !            39:         if (getxattr(rpath(fs_ctx, path, buffer), "user.virtfs.uid", &tmp_uid,
        !            40:                     sizeof(uid_t)) > 0) {
        !            41:             stbuf->st_uid = tmp_uid;
        !            42:         }
        !            43:         if (getxattr(rpath(fs_ctx, path, buffer), "user.virtfs.gid", &tmp_gid,
        !            44:                     sizeof(gid_t)) > 0) {
        !            45:             stbuf->st_gid = tmp_gid;
        !            46:         }
        !            47:         if (getxattr(rpath(fs_ctx, path, buffer), "user.virtfs.mode",
        !            48:                     &tmp_mode, sizeof(mode_t)) > 0) {
        !            49:             stbuf->st_mode = tmp_mode;
        !            50:         }
        !            51:         if (getxattr(rpath(fs_ctx, path, buffer), "user.virtfs.rdev", &tmp_dev,
        !            52:                         sizeof(dev_t)) > 0) {
        !            53:                 stbuf->st_rdev = tmp_dev;
        !            54:         }
        !            55:     }
        !            56:     return err;
        !            57: }
        !            58: 
        !            59: static int local_set_xattr(const char *path, FsCred *credp)
        !            60: {
        !            61:     int err;
        !            62:     if (credp->fc_uid != -1) {
        !            63:         err = setxattr(path, "user.virtfs.uid", &credp->fc_uid, sizeof(uid_t),
        !            64:                 0);
        !            65:         if (err) {
        !            66:             return err;
        !            67:         }
        !            68:     }
        !            69:     if (credp->fc_gid != -1) {
        !            70:         err = setxattr(path, "user.virtfs.gid", &credp->fc_gid, sizeof(gid_t),
        !            71:                 0);
        !            72:         if (err) {
        !            73:             return err;
        !            74:         }
        !            75:     }
        !            76:     if (credp->fc_mode != -1) {
        !            77:         err = setxattr(path, "user.virtfs.mode", &credp->fc_mode,
        !            78:                 sizeof(mode_t), 0);
        !            79:         if (err) {
        !            80:             return err;
        !            81:         }
        !            82:     }
        !            83:     if (credp->fc_rdev != -1) {
        !            84:         err = setxattr(path, "user.virtfs.rdev", &credp->fc_rdev,
        !            85:                 sizeof(dev_t), 0);
        !            86:         if (err) {
        !            87:             return err;
        !            88:         }
        !            89:     }
        !            90:     return 0;
        !            91: }
        !            92: 
        !            93: static int local_post_create_passthrough(FsContext *fs_ctx, const char *path,
        !            94:         FsCred *credp)
        !            95: {
        !            96:     char buffer[PATH_MAX];
        !            97:     if (chmod(rpath(fs_ctx, path, buffer), credp->fc_mode & 07777) < 0) {
        !            98:         return -1;
        !            99:     }
        !           100:     if (lchown(rpath(fs_ctx, path, buffer), credp->fc_uid,
        !           101:                 credp->fc_gid) < 0) {
        !           102:         /*
        !           103:          * If we fail to change ownership and if we are
        !           104:          * using security model none. Ignore the error
        !           105:          */
        !           106:         if (fs_ctx->fs_sm != SM_NONE) {
        !           107:             return -1;
        !           108:         }
        !           109:     }
        !           110:     return 0;
        !           111: }
        !           112: 
        !           113: static ssize_t local_readlink(FsContext *fs_ctx, const char *path,
        !           114:         char *buf, size_t bufsz)
        !           115: {
        !           116:     ssize_t tsize = -1;
        !           117:     char buffer[PATH_MAX];
        !           118:     if (fs_ctx->fs_sm == SM_MAPPED) {
        !           119:         int fd;
        !           120:         fd = open(rpath(fs_ctx, path, buffer), O_RDONLY);
        !           121:         if (fd == -1) {
        !           122:             return -1;
        !           123:         }
        !           124:         do {
        !           125:             tsize = read(fd, (void *)buf, bufsz);
        !           126:         } while (tsize == -1 && errno == EINTR);
        !           127:         close(fd);
        !           128:         return tsize;
        !           129:     } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
        !           130:                (fs_ctx->fs_sm == SM_NONE)) {
        !           131:         tsize = readlink(rpath(fs_ctx, path, buffer), buf, bufsz);
        !           132:     }
        !           133:     return tsize;
        !           134: }
        !           135: 
        !           136: static int local_close(FsContext *ctx, int fd)
        !           137: {
        !           138:     return close(fd);
        !           139: }
        !           140: 
        !           141: static int local_closedir(FsContext *ctx, DIR *dir)
        !           142: {
        !           143:     return closedir(dir);
        !           144: }
        !           145: 
        !           146: static int local_open(FsContext *ctx, const char *path, int flags)
        !           147: {
        !           148:     char buffer[PATH_MAX];
        !           149:     return open(rpath(ctx, path, buffer), flags);
        !           150: }
        !           151: 
        !           152: static DIR *local_opendir(FsContext *ctx, const char *path)
        !           153: {
        !           154:     char buffer[PATH_MAX];
        !           155:     return opendir(rpath(ctx, path, buffer));
        !           156: }
        !           157: 
        !           158: static void local_rewinddir(FsContext *ctx, DIR *dir)
        !           159: {
        !           160:     return rewinddir(dir);
        !           161: }
        !           162: 
        !           163: static off_t local_telldir(FsContext *ctx, DIR *dir)
        !           164: {
        !           165:     return telldir(dir);
        !           166: }
        !           167: 
        !           168: static struct dirent *local_readdir(FsContext *ctx, DIR *dir)
        !           169: {
        !           170:     return readdir(dir);
        !           171: }
        !           172: 
        !           173: static void local_seekdir(FsContext *ctx, DIR *dir, off_t off)
        !           174: {
        !           175:     return seekdir(dir, off);
        !           176: }
        !           177: 
        !           178: static ssize_t local_preadv(FsContext *ctx, int fd, const struct iovec *iov,
        !           179:                             int iovcnt, off_t offset)
        !           180: {
        !           181: #ifdef CONFIG_PREADV
        !           182:     return preadv(fd, iov, iovcnt, offset);
        !           183: #else
        !           184:     int err = lseek(fd, offset, SEEK_SET);
        !           185:     if (err == -1) {
        !           186:         return err;
        !           187:     } else {
        !           188:         return readv(fd, iov, iovcnt);
        !           189:     }
        !           190: #endif
        !           191: }
        !           192: 
        !           193: static ssize_t local_pwritev(FsContext *ctx, int fd, const struct iovec *iov,
        !           194:                             int iovcnt, off_t offset)
        !           195: {
        !           196: #ifdef CONFIG_PREADV
        !           197:     return pwritev(fd, iov, iovcnt, offset);
        !           198: #else
        !           199:     int err = lseek(fd, offset, SEEK_SET);
        !           200:     if (err == -1) {
        !           201:         return err;
        !           202:     } else {
        !           203:         return writev(fd, iov, iovcnt);
        !           204:     }
        !           205: #endif
        !           206: }
        !           207: 
        !           208: static int local_chmod(FsContext *fs_ctx, const char *path, FsCred *credp)
        !           209: {
        !           210:     char buffer[PATH_MAX];
        !           211:     if (fs_ctx->fs_sm == SM_MAPPED) {
        !           212:         return local_set_xattr(rpath(fs_ctx, path, buffer), credp);
        !           213:     } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
        !           214:                (fs_ctx->fs_sm == SM_NONE)) {
        !           215:         return chmod(rpath(fs_ctx, path, buffer), credp->fc_mode);
        !           216:     }
        !           217:     return -1;
        !           218: }
        !           219: 
        !           220: static int local_mknod(FsContext *fs_ctx, const char *path, FsCred *credp)
        !           221: {
        !           222:     int err = -1;
        !           223:     int serrno = 0;
        !           224:     char buffer[PATH_MAX];
        !           225: 
        !           226:     /* Determine the security model */
        !           227:     if (fs_ctx->fs_sm == SM_MAPPED) {
        !           228:         err = mknod(rpath(fs_ctx, path, buffer),
        !           229:                 SM_LOCAL_MODE_BITS|S_IFREG, 0);
        !           230:         if (err == -1) {
        !           231:             return err;
        !           232:         }
        !           233:         local_set_xattr(rpath(fs_ctx, path, buffer), credp);
        !           234:         if (err == -1) {
        !           235:             serrno = errno;
        !           236:             goto err_end;
        !           237:         }
        !           238:     } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
        !           239:                (fs_ctx->fs_sm == SM_NONE)) {
        !           240:         err = mknod(rpath(fs_ctx, path, buffer), credp->fc_mode,
        !           241:                 credp->fc_rdev);
        !           242:         if (err == -1) {
        !           243:             return err;
        !           244:         }
        !           245:         err = local_post_create_passthrough(fs_ctx, path, credp);
        !           246:         if (err == -1) {
        !           247:             serrno = errno;
        !           248:             goto err_end;
        !           249:         }
        !           250:     }
        !           251:     return err;
        !           252: 
        !           253: err_end:
        !           254:     remove(rpath(fs_ctx, path, buffer));
        !           255:     errno = serrno;
        !           256:     return err;
        !           257: }
        !           258: 
        !           259: static int local_mkdir(FsContext *fs_ctx, const char *path, FsCred *credp)
        !           260: {
        !           261:     int err = -1;
        !           262:     int serrno = 0;
        !           263:     char buffer[PATH_MAX];
        !           264: 
        !           265:     /* Determine the security model */
        !           266:     if (fs_ctx->fs_sm == SM_MAPPED) {
        !           267:         err = mkdir(rpath(fs_ctx, path, buffer), SM_LOCAL_DIR_MODE_BITS);
        !           268:         if (err == -1) {
        !           269:             return err;
        !           270:         }
        !           271:         credp->fc_mode = credp->fc_mode|S_IFDIR;
        !           272:         err = local_set_xattr(rpath(fs_ctx, path, buffer), credp);
        !           273:         if (err == -1) {
        !           274:             serrno = errno;
        !           275:             goto err_end;
        !           276:         }
        !           277:     } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
        !           278:                (fs_ctx->fs_sm == SM_NONE)) {
        !           279:         err = mkdir(rpath(fs_ctx, path, buffer), credp->fc_mode);
        !           280:         if (err == -1) {
        !           281:             return err;
        !           282:         }
        !           283:         err = local_post_create_passthrough(fs_ctx, path, credp);
        !           284:         if (err == -1) {
        !           285:             serrno = errno;
        !           286:             goto err_end;
        !           287:         }
        !           288:     }
        !           289:     return err;
        !           290: 
        !           291: err_end:
        !           292:     remove(rpath(fs_ctx, path, buffer));
        !           293:     errno = serrno;
        !           294:     return err;
        !           295: }
        !           296: 
        !           297: static int local_fstat(FsContext *fs_ctx, int fd, struct stat *stbuf)
        !           298: {
        !           299:     int err;
        !           300:     err = fstat(fd, stbuf);
        !           301:     if (err) {
        !           302:         return err;
        !           303:     }
        !           304:     if (fs_ctx->fs_sm == SM_MAPPED) {
        !           305:         /* Actual credentials are part of extended attrs */
        !           306:         uid_t tmp_uid;
        !           307:         gid_t tmp_gid;
        !           308:         mode_t tmp_mode;
        !           309:         dev_t tmp_dev;
        !           310: 
        !           311:         if (fgetxattr(fd, "user.virtfs.uid", &tmp_uid, sizeof(uid_t)) > 0) {
        !           312:             stbuf->st_uid = tmp_uid;
        !           313:         }
        !           314:         if (fgetxattr(fd, "user.virtfs.gid", &tmp_gid, sizeof(gid_t)) > 0) {
        !           315:             stbuf->st_gid = tmp_gid;
        !           316:         }
        !           317:         if (fgetxattr(fd, "user.virtfs.mode", &tmp_mode, sizeof(mode_t)) > 0) {
        !           318:             stbuf->st_mode = tmp_mode;
        !           319:         }
        !           320:         if (fgetxattr(fd, "user.virtfs.rdev", &tmp_dev, sizeof(dev_t)) > 0) {
        !           321:                 stbuf->st_rdev = tmp_dev;
        !           322:         }
        !           323:     }
        !           324:     return err;
        !           325: }
        !           326: 
        !           327: static int local_open2(FsContext *fs_ctx, const char *path, int flags,
        !           328:         FsCred *credp)
        !           329: {
        !           330:     int fd = -1;
        !           331:     int err = -1;
        !           332:     int serrno = 0;
        !           333:     char buffer[PATH_MAX];
        !           334: 
        !           335:     /* Determine the security model */
        !           336:     if (fs_ctx->fs_sm == SM_MAPPED) {
        !           337:         fd = open(rpath(fs_ctx, path, buffer), flags, SM_LOCAL_MODE_BITS);
        !           338:         if (fd == -1) {
        !           339:             return fd;
        !           340:         }
        !           341:         credp->fc_mode = credp->fc_mode|S_IFREG;
        !           342:         /* Set cleint credentials in xattr */
        !           343:         err = local_set_xattr(rpath(fs_ctx, path, buffer), credp);
        !           344:         if (err == -1) {
        !           345:             serrno = errno;
        !           346:             goto err_end;
        !           347:         }
        !           348:     } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
        !           349:                (fs_ctx->fs_sm == SM_NONE)) {
        !           350:         fd = open(rpath(fs_ctx, path, buffer), flags, credp->fc_mode);
        !           351:         if (fd == -1) {
        !           352:             return fd;
        !           353:         }
        !           354:         err = local_post_create_passthrough(fs_ctx, path, credp);
        !           355:         if (err == -1) {
        !           356:             serrno = errno;
        !           357:             goto err_end;
        !           358:         }
        !           359:     }
        !           360:     return fd;
        !           361: 
        !           362: err_end:
        !           363:     close(fd);
        !           364:     remove(rpath(fs_ctx, path, buffer));
        !           365:     errno = serrno;
        !           366:     return err;
        !           367: }
        !           368: 
        !           369: 
        !           370: static int local_symlink(FsContext *fs_ctx, const char *oldpath,
        !           371:         const char *newpath, FsCred *credp)
        !           372: {
        !           373:     int err = -1;
        !           374:     int serrno = 0;
        !           375:     char buffer[PATH_MAX];
        !           376: 
        !           377:     /* Determine the security model */
        !           378:     if (fs_ctx->fs_sm == SM_MAPPED) {
        !           379:         int fd;
        !           380:         ssize_t oldpath_size, write_size;
        !           381:         fd = open(rpath(fs_ctx, newpath, buffer), O_CREAT|O_EXCL|O_RDWR,
        !           382:                 SM_LOCAL_MODE_BITS);
        !           383:         if (fd == -1) {
        !           384:             return fd;
        !           385:         }
        !           386:         /* Write the oldpath (target) to the file. */
        !           387:         oldpath_size = strlen(oldpath);
        !           388:         do {
        !           389:             write_size = write(fd, (void *)oldpath, oldpath_size);
        !           390:         } while (write_size == -1 && errno == EINTR);
        !           391: 
        !           392:         if (write_size != oldpath_size) {
        !           393:             serrno = errno;
        !           394:             close(fd);
        !           395:             err = -1;
        !           396:             goto err_end;
        !           397:         }
        !           398:         close(fd);
        !           399:         /* Set cleint credentials in symlink's xattr */
        !           400:         credp->fc_mode = credp->fc_mode|S_IFLNK;
        !           401:         err = local_set_xattr(rpath(fs_ctx, newpath, buffer), credp);
        !           402:         if (err == -1) {
        !           403:             serrno = errno;
        !           404:             goto err_end;
        !           405:         }
        !           406:     } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
        !           407:                (fs_ctx->fs_sm == SM_NONE)) {
        !           408:         err = symlink(oldpath, rpath(fs_ctx, newpath, buffer));
        !           409:         if (err) {
        !           410:             return err;
        !           411:         }
        !           412:         err = lchown(rpath(fs_ctx, newpath, buffer), credp->fc_uid,
        !           413:                 credp->fc_gid);
        !           414:         if (err == -1) {
        !           415:             /*
        !           416:              * If we fail to change ownership and if we are
        !           417:              * using security model none. Ignore the error
        !           418:              */
        !           419:             if (fs_ctx->fs_sm != SM_NONE) {
        !           420:                 serrno = errno;
        !           421:                 goto err_end;
        !           422:             } else
        !           423:                 err = 0;
        !           424:         }
        !           425:     }
        !           426:     return err;
        !           427: 
        !           428: err_end:
        !           429:     remove(rpath(fs_ctx, newpath, buffer));
        !           430:     errno = serrno;
        !           431:     return err;
        !           432: }
        !           433: 
        !           434: static int local_link(FsContext *ctx, const char *oldpath, const char *newpath)
        !           435: {
        !           436:     char buffer[PATH_MAX], buffer1[PATH_MAX];
        !           437: 
        !           438:     return link(rpath(ctx, oldpath, buffer), rpath(ctx, newpath, buffer1));
        !           439: }
        !           440: 
        !           441: static int local_truncate(FsContext *ctx, const char *path, off_t size)
        !           442: {
        !           443:     char buffer[PATH_MAX];
        !           444:     return truncate(rpath(ctx, path, buffer), size);
        !           445: }
        !           446: 
        !           447: static int local_rename(FsContext *ctx, const char *oldpath,
        !           448:                         const char *newpath)
        !           449: {
        !           450:     char buffer[PATH_MAX], buffer1[PATH_MAX];
        !           451: 
        !           452:     return rename(rpath(ctx, oldpath, buffer), rpath(ctx, newpath, buffer1));
        !           453: }
        !           454: 
        !           455: static int local_chown(FsContext *fs_ctx, const char *path, FsCred *credp)
        !           456: {
        !           457:     char buffer[PATH_MAX];
        !           458:     if ((credp->fc_uid == -1 && credp->fc_gid == -1) ||
        !           459:             (fs_ctx->fs_sm == SM_PASSTHROUGH)) {
        !           460:         return lchown(rpath(fs_ctx, path, buffer), credp->fc_uid,
        !           461:                 credp->fc_gid);
        !           462:     } else if (fs_ctx->fs_sm == SM_MAPPED) {
        !           463:         return local_set_xattr(rpath(fs_ctx, path, buffer), credp);
        !           464:     } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
        !           465:                (fs_ctx->fs_sm == SM_NONE)) {
        !           466:         return lchown(rpath(fs_ctx, path, buffer), credp->fc_uid,
        !           467:                 credp->fc_gid);
        !           468:     }
        !           469:     return -1;
        !           470: }
        !           471: 
        !           472: static int local_utimensat(FsContext *s, const char *path,
        !           473:                            const struct timespec *buf)
        !           474: {
        !           475:     char buffer[PATH_MAX];
        !           476:     return qemu_utimensat(AT_FDCWD, rpath(s, path, buffer), buf,
        !           477:             AT_SYMLINK_NOFOLLOW);
        !           478: }
        !           479: 
        !           480: static int local_remove(FsContext *ctx, const char *path)
        !           481: {
        !           482:     char buffer[PATH_MAX];
        !           483:     return remove(rpath(ctx, path, buffer));
        !           484: }
        !           485: 
        !           486: static int local_fsync(FsContext *ctx, int fd, int datasync)
        !           487: {
        !           488:     if (datasync) {
        !           489:         return qemu_fdatasync(fd);
        !           490:     } else {
        !           491:         return fsync(fd);
        !           492:     }
        !           493: }
        !           494: 
        !           495: static int local_statfs(FsContext *s, const char *path, struct statfs *stbuf)
        !           496: {
        !           497:     char buffer[PATH_MAX];
        !           498:    return statfs(rpath(s, path, buffer), stbuf);
        !           499: }
        !           500: 
        !           501: static ssize_t local_lgetxattr(FsContext *ctx, const char *path,
        !           502:                                const char *name, void *value, size_t size)
        !           503: {
        !           504:     return v9fs_get_xattr(ctx, path, name, value, size);
        !           505: }
        !           506: 
        !           507: static ssize_t local_llistxattr(FsContext *ctx, const char *path,
        !           508:                                 void *value, size_t size)
        !           509: {
        !           510:     return v9fs_list_xattr(ctx, path, value, size);
        !           511: }
        !           512: 
        !           513: static int local_lsetxattr(FsContext *ctx, const char *path, const char *name,
        !           514:                            void *value, size_t size, int flags)
        !           515: {
        !           516:     return v9fs_set_xattr(ctx, path, name, value, size, flags);
        !           517: }
        !           518: 
        !           519: static int local_lremovexattr(FsContext *ctx,
        !           520:                               const char *path, const char *name)
        !           521: {
        !           522:     return v9fs_remove_xattr(ctx, path, name);
        !           523: }
        !           524: 
        !           525: 
        !           526: FileOperations local_ops = {
        !           527:     .lstat = local_lstat,
        !           528:     .readlink = local_readlink,
        !           529:     .close = local_close,
        !           530:     .closedir = local_closedir,
        !           531:     .open = local_open,
        !           532:     .opendir = local_opendir,
        !           533:     .rewinddir = local_rewinddir,
        !           534:     .telldir = local_telldir,
        !           535:     .readdir = local_readdir,
        !           536:     .seekdir = local_seekdir,
        !           537:     .preadv = local_preadv,
        !           538:     .pwritev = local_pwritev,
        !           539:     .chmod = local_chmod,
        !           540:     .mknod = local_mknod,
        !           541:     .mkdir = local_mkdir,
        !           542:     .fstat = local_fstat,
        !           543:     .open2 = local_open2,
        !           544:     .symlink = local_symlink,
        !           545:     .link = local_link,
        !           546:     .truncate = local_truncate,
        !           547:     .rename = local_rename,
        !           548:     .chown = local_chown,
        !           549:     .utimensat = local_utimensat,
        !           550:     .remove = local_remove,
        !           551:     .fsync = local_fsync,
        !           552:     .statfs = local_statfs,
        !           553:     .lgetxattr = local_lgetxattr,
        !           554:     .llistxattr = local_llistxattr,
        !           555:     .lsetxattr = local_lsetxattr,
        !           556:     .lremovexattr = local_lremovexattr,
        !           557: };

unix.superglobalmegacorp.com

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