2 * Virtio 9p Posix callback
4 * Copyright IBM, Corp. 2010
7 * Anthony Liguori <aliguori@us.ibm.com>
9 * This work is licensed under the terms of the GNU GPL, version 2. See
10 * the COPYING file in the top-level directory.
14 #include "virtio-9p.h"
15 #include "virtio-9p-xattr.h"
16 #include <arpa/inet.h>
19 #include <sys/socket.h>
21 #include <attr/xattr.h>
24 static int local_lstat(FsContext
*fs_ctx
, const char *path
, struct stat
*stbuf
)
27 err
= lstat(rpath(fs_ctx
, path
), stbuf
);
31 if (fs_ctx
->fs_sm
== SM_MAPPED
) {
32 /* Actual credentials are part of extended attrs */
37 if (getxattr(rpath(fs_ctx
, path
), "user.virtfs.uid", &tmp_uid
,
39 stbuf
->st_uid
= tmp_uid
;
41 if (getxattr(rpath(fs_ctx
, path
), "user.virtfs.gid", &tmp_gid
,
43 stbuf
->st_gid
= tmp_gid
;
45 if (getxattr(rpath(fs_ctx
, path
), "user.virtfs.mode", &tmp_mode
,
46 sizeof(mode_t
)) > 0) {
47 stbuf
->st_mode
= tmp_mode
;
49 if (getxattr(rpath(fs_ctx
, path
), "user.virtfs.rdev", &tmp_dev
,
51 stbuf
->st_rdev
= tmp_dev
;
57 static int local_set_xattr(const char *path
, FsCred
*credp
)
60 if (credp
->fc_uid
!= -1) {
61 err
= setxattr(path
, "user.virtfs.uid", &credp
->fc_uid
, sizeof(uid_t
),
67 if (credp
->fc_gid
!= -1) {
68 err
= setxattr(path
, "user.virtfs.gid", &credp
->fc_gid
, sizeof(gid_t
),
74 if (credp
->fc_mode
!= -1) {
75 err
= setxattr(path
, "user.virtfs.mode", &credp
->fc_mode
,
81 if (credp
->fc_rdev
!= -1) {
82 err
= setxattr(path
, "user.virtfs.rdev", &credp
->fc_rdev
,
91 static int local_post_create_passthrough(FsContext
*fs_ctx
, const char *path
,
94 if (chmod(rpath(fs_ctx
, path
), credp
->fc_mode
& 07777) < 0) {
97 if (lchown(rpath(fs_ctx
, path
), credp
->fc_uid
, credp
->fc_gid
) < 0) {
99 * If we fail to change ownership and if we are
100 * using security model none. Ignore the error
102 if (fs_ctx
->fs_sm
!= SM_NONE
) {
109 static ssize_t
local_readlink(FsContext
*fs_ctx
, const char *path
,
110 char *buf
, size_t bufsz
)
113 if (fs_ctx
->fs_sm
== SM_MAPPED
) {
115 fd
= open(rpath(fs_ctx
, path
), O_RDONLY
);
120 tsize
= read(fd
, (void *)buf
, bufsz
);
121 } while (tsize
== -1 && errno
== EINTR
);
124 } else if ((fs_ctx
->fs_sm
== SM_PASSTHROUGH
) ||
125 (fs_ctx
->fs_sm
== SM_NONE
)) {
126 tsize
= readlink(rpath(fs_ctx
, path
), buf
, bufsz
);
131 static int local_close(FsContext
*ctx
, int fd
)
136 static int local_closedir(FsContext
*ctx
, DIR *dir
)
138 return closedir(dir
);
141 static int local_open(FsContext
*ctx
, const char *path
, int flags
)
143 return open(rpath(ctx
, path
), flags
);
146 static DIR *local_opendir(FsContext
*ctx
, const char *path
)
148 return opendir(rpath(ctx
, path
));
151 static void local_rewinddir(FsContext
*ctx
, DIR *dir
)
153 return rewinddir(dir
);
156 static off_t
local_telldir(FsContext
*ctx
, DIR *dir
)
161 static struct dirent
*local_readdir(FsContext
*ctx
, DIR *dir
)
166 static void local_seekdir(FsContext
*ctx
, DIR *dir
, off_t off
)
168 return seekdir(dir
, off
);
171 static ssize_t
local_preadv(FsContext
*ctx
, int fd
, const struct iovec
*iov
,
172 int iovcnt
, off_t offset
)
175 return preadv(fd
, iov
, iovcnt
, offset
);
177 int err
= lseek(fd
, offset
, SEEK_SET
);
181 return readv(fd
, iov
, iovcnt
);
186 static ssize_t
local_pwritev(FsContext
*ctx
, int fd
, const struct iovec
*iov
,
187 int iovcnt
, off_t offset
)
190 return pwritev(fd
, iov
, iovcnt
, offset
);
192 int err
= lseek(fd
, offset
, SEEK_SET
);
196 return writev(fd
, iov
, iovcnt
);
201 static int local_chmod(FsContext
*fs_ctx
, const char *path
, FsCred
*credp
)
203 if (fs_ctx
->fs_sm
== SM_MAPPED
) {
204 return local_set_xattr(rpath(fs_ctx
, path
), credp
);
205 } else if ((fs_ctx
->fs_sm
== SM_PASSTHROUGH
) ||
206 (fs_ctx
->fs_sm
== SM_NONE
)) {
207 return chmod(rpath(fs_ctx
, path
), credp
->fc_mode
);
212 static int local_mknod(FsContext
*fs_ctx
, const char *path
, FsCred
*credp
)
217 /* Determine the security model */
218 if (fs_ctx
->fs_sm
== SM_MAPPED
) {
219 err
= mknod(rpath(fs_ctx
, path
), SM_LOCAL_MODE_BITS
|S_IFREG
, 0);
223 local_set_xattr(rpath(fs_ctx
, path
), credp
);
228 } else if ((fs_ctx
->fs_sm
== SM_PASSTHROUGH
) ||
229 (fs_ctx
->fs_sm
== SM_NONE
)) {
230 err
= mknod(rpath(fs_ctx
, path
), credp
->fc_mode
, credp
->fc_rdev
);
234 err
= local_post_create_passthrough(fs_ctx
, path
, credp
);
243 remove(rpath(fs_ctx
, path
));
248 static int local_mkdir(FsContext
*fs_ctx
, const char *path
, FsCred
*credp
)
253 /* Determine the security model */
254 if (fs_ctx
->fs_sm
== SM_MAPPED
) {
255 err
= mkdir(rpath(fs_ctx
, path
), SM_LOCAL_DIR_MODE_BITS
);
259 credp
->fc_mode
= credp
->fc_mode
|S_IFDIR
;
260 err
= local_set_xattr(rpath(fs_ctx
, path
), credp
);
265 } else if ((fs_ctx
->fs_sm
== SM_PASSTHROUGH
) ||
266 (fs_ctx
->fs_sm
== SM_NONE
)) {
267 err
= mkdir(rpath(fs_ctx
, path
), credp
->fc_mode
);
271 err
= local_post_create_passthrough(fs_ctx
, path
, credp
);
280 remove(rpath(fs_ctx
, path
));
285 static int local_fstat(FsContext
*fs_ctx
, int fd
, struct stat
*stbuf
)
288 err
= fstat(fd
, stbuf
);
292 if (fs_ctx
->fs_sm
== SM_MAPPED
) {
293 /* Actual credentials are part of extended attrs */
299 if (fgetxattr(fd
, "user.virtfs.uid", &tmp_uid
, sizeof(uid_t
)) > 0) {
300 stbuf
->st_uid
= tmp_uid
;
302 if (fgetxattr(fd
, "user.virtfs.gid", &tmp_gid
, sizeof(gid_t
)) > 0) {
303 stbuf
->st_gid
= tmp_gid
;
305 if (fgetxattr(fd
, "user.virtfs.mode", &tmp_mode
, sizeof(mode_t
)) > 0) {
306 stbuf
->st_mode
= tmp_mode
;
308 if (fgetxattr(fd
, "user.virtfs.rdev", &tmp_dev
, sizeof(dev_t
)) > 0) {
309 stbuf
->st_rdev
= tmp_dev
;
315 static int local_open2(FsContext
*fs_ctx
, const char *path
, int flags
,
322 /* Determine the security model */
323 if (fs_ctx
->fs_sm
== SM_MAPPED
) {
324 fd
= open(rpath(fs_ctx
, path
), flags
, SM_LOCAL_MODE_BITS
);
328 credp
->fc_mode
= credp
->fc_mode
|S_IFREG
;
329 /* Set cleint credentials in xattr */
330 err
= local_set_xattr(rpath(fs_ctx
, path
), credp
);
335 } else if ((fs_ctx
->fs_sm
== SM_PASSTHROUGH
) ||
336 (fs_ctx
->fs_sm
== SM_NONE
)) {
337 fd
= open(rpath(fs_ctx
, path
), flags
, credp
->fc_mode
);
341 err
= local_post_create_passthrough(fs_ctx
, path
, credp
);
351 remove(rpath(fs_ctx
, path
));
357 static int local_symlink(FsContext
*fs_ctx
, const char *oldpath
,
358 const char *newpath
, FsCred
*credp
)
363 /* Determine the security model */
364 if (fs_ctx
->fs_sm
== SM_MAPPED
) {
366 ssize_t oldpath_size
, write_size
;
367 fd
= open(rpath(fs_ctx
, newpath
), O_CREAT
|O_EXCL
|O_RDWR
,
372 /* Write the oldpath (target) to the file. */
373 oldpath_size
= strlen(oldpath
) + 1;
375 write_size
= write(fd
, (void *)oldpath
, oldpath_size
);
376 } while (write_size
== -1 && errno
== EINTR
);
378 if (write_size
!= oldpath_size
) {
385 /* Set cleint credentials in symlink's xattr */
386 credp
->fc_mode
= credp
->fc_mode
|S_IFLNK
;
387 err
= local_set_xattr(rpath(fs_ctx
, newpath
), credp
);
392 } else if ((fs_ctx
->fs_sm
== SM_PASSTHROUGH
) ||
393 (fs_ctx
->fs_sm
== SM_NONE
)) {
394 err
= symlink(oldpath
, rpath(fs_ctx
, newpath
));
398 err
= lchown(rpath(fs_ctx
, newpath
), credp
->fc_uid
, credp
->fc_gid
);
401 * If we fail to change ownership and if we are
402 * using security model none. Ignore the error
404 if (fs_ctx
->fs_sm
!= SM_NONE
) {
414 remove(rpath(fs_ctx
, newpath
));
419 static int local_link(FsContext
*ctx
, const char *oldpath
, const char *newpath
)
421 char *tmp
= qemu_strdup(rpath(ctx
, oldpath
));
428 err
= link(tmp
, rpath(ctx
, newpath
));
442 static int local_truncate(FsContext
*ctx
, const char *path
, off_t size
)
444 return truncate(rpath(ctx
, path
), size
);
447 static int local_rename(FsContext
*ctx
, const char *oldpath
,
453 tmp
= qemu_strdup(rpath(ctx
, oldpath
));
455 err
= rename(tmp
, rpath(ctx
, newpath
));
468 static int local_chown(FsContext
*fs_ctx
, const char *path
, FsCred
*credp
)
470 if ((credp
->fc_uid
== -1 && credp
->fc_gid
== -1) ||
471 (fs_ctx
->fs_sm
== SM_PASSTHROUGH
)) {
472 return lchown(rpath(fs_ctx
, path
), credp
->fc_uid
, credp
->fc_gid
);
473 } else if (fs_ctx
->fs_sm
== SM_MAPPED
) {
474 return local_set_xattr(rpath(fs_ctx
, path
), credp
);
475 } else if ((fs_ctx
->fs_sm
== SM_PASSTHROUGH
) ||
476 (fs_ctx
->fs_sm
== SM_NONE
)) {
477 return lchown(rpath(fs_ctx
, path
), credp
->fc_uid
, credp
->fc_gid
);
482 static int local_utimensat(FsContext
*s
, const char *path
,
483 const struct timespec
*buf
)
485 return qemu_utimensat(AT_FDCWD
, rpath(s
, path
), buf
, AT_SYMLINK_NOFOLLOW
);
488 static int local_remove(FsContext
*ctx
, const char *path
)
490 return remove(rpath(ctx
, path
));
493 static int local_fsync(FsContext
*ctx
, int fd
, int datasync
)
496 return qemu_fdatasync(fd
);
502 static int local_statfs(FsContext
*s
, const char *path
, struct statfs
*stbuf
)
504 return statfs(rpath(s
, path
), stbuf
);
507 static ssize_t
local_lgetxattr(FsContext
*ctx
, const char *path
,
508 const char *name
, void *value
, size_t size
)
510 return v9fs_get_xattr(ctx
, path
, name
, value
, size
);
513 static ssize_t
local_llistxattr(FsContext
*ctx
, const char *path
,
514 void *value
, size_t size
)
516 return v9fs_list_xattr(ctx
, path
, value
, size
);
519 static int local_lsetxattr(FsContext
*ctx
, const char *path
, const char *name
,
520 void *value
, size_t size
, int flags
)
522 return v9fs_set_xattr(ctx
, path
, name
, value
, size
, flags
);
525 static int local_lremovexattr(FsContext
*ctx
,
526 const char *path
, const char *name
)
528 return v9fs_remove_xattr(ctx
, path
, name
);
532 FileOperations local_ops
= {
533 .lstat
= local_lstat
,
534 .readlink
= local_readlink
,
535 .close
= local_close
,
536 .closedir
= local_closedir
,
538 .opendir
= local_opendir
,
539 .rewinddir
= local_rewinddir
,
540 .telldir
= local_telldir
,
541 .readdir
= local_readdir
,
542 .seekdir
= local_seekdir
,
543 .preadv
= local_preadv
,
544 .pwritev
= local_pwritev
,
545 .chmod
= local_chmod
,
546 .mknod
= local_mknod
,
547 .mkdir
= local_mkdir
,
548 .fstat
= local_fstat
,
549 .open2
= local_open2
,
550 .symlink
= local_symlink
,
552 .truncate
= local_truncate
,
553 .rename
= local_rename
,
554 .chown
= local_chown
,
555 .utimensat
= local_utimensat
,
556 .remove
= local_remove
,
557 .fsync
= local_fsync
,
558 .statfs
= local_statfs
,
559 .lgetxattr
= local_lgetxattr
,
560 .llistxattr
= local_llistxattr
,
561 .lsetxattr
= local_lsetxattr
,
562 .lremovexattr
= local_lremovexattr
,