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 "hw/virtio.h"
15 #include "virtio-9p.h"
16 #include "virtio-9p-xattr.h"
17 #include <arpa/inet.h>
20 #include <sys/socket.h>
22 #include <attr/xattr.h>
25 static int local_lstat(FsContext
*fs_ctx
, const char *path
, struct stat
*stbuf
)
28 char buffer
[PATH_MAX
];
29 err
= lstat(rpath(fs_ctx
, path
, buffer
), stbuf
);
33 if (fs_ctx
->fs_sm
== SM_MAPPED
) {
34 /* Actual credentials are part of extended attrs */
39 if (getxattr(rpath(fs_ctx
, path
, buffer
), "user.virtfs.uid", &tmp_uid
,
41 stbuf
->st_uid
= tmp_uid
;
43 if (getxattr(rpath(fs_ctx
, path
, buffer
), "user.virtfs.gid", &tmp_gid
,
45 stbuf
->st_gid
= tmp_gid
;
47 if (getxattr(rpath(fs_ctx
, path
, buffer
), "user.virtfs.mode",
48 &tmp_mode
, sizeof(mode_t
)) > 0) {
49 stbuf
->st_mode
= tmp_mode
;
51 if (getxattr(rpath(fs_ctx
, path
, buffer
), "user.virtfs.rdev", &tmp_dev
,
53 stbuf
->st_rdev
= tmp_dev
;
59 static int local_set_xattr(const char *path
, FsCred
*credp
)
62 if (credp
->fc_uid
!= -1) {
63 err
= setxattr(path
, "user.virtfs.uid", &credp
->fc_uid
, sizeof(uid_t
),
69 if (credp
->fc_gid
!= -1) {
70 err
= setxattr(path
, "user.virtfs.gid", &credp
->fc_gid
, sizeof(gid_t
),
76 if (credp
->fc_mode
!= -1) {
77 err
= setxattr(path
, "user.virtfs.mode", &credp
->fc_mode
,
83 if (credp
->fc_rdev
!= -1) {
84 err
= setxattr(path
, "user.virtfs.rdev", &credp
->fc_rdev
,
93 static int local_post_create_passthrough(FsContext
*fs_ctx
, const char *path
,
96 char buffer
[PATH_MAX
];
97 if (chmod(rpath(fs_ctx
, path
, buffer
), credp
->fc_mode
& 07777) < 0) {
100 if (lchown(rpath(fs_ctx
, path
, buffer
), credp
->fc_uid
,
101 credp
->fc_gid
) < 0) {
103 * If we fail to change ownership and if we are
104 * using security model none. Ignore the error
106 if (fs_ctx
->fs_sm
!= SM_NONE
) {
113 static ssize_t
local_readlink(FsContext
*fs_ctx
, const char *path
,
114 char *buf
, size_t bufsz
)
117 char buffer
[PATH_MAX
];
118 if (fs_ctx
->fs_sm
== SM_MAPPED
) {
120 fd
= open(rpath(fs_ctx
, path
, buffer
), O_RDONLY
);
125 tsize
= read(fd
, (void *)buf
, bufsz
);
126 } while (tsize
== -1 && errno
== EINTR
);
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
);
136 static int local_close(FsContext
*ctx
, int fd
)
141 static int local_closedir(FsContext
*ctx
, DIR *dir
)
143 return closedir(dir
);
146 static int local_open(FsContext
*ctx
, const char *path
, int flags
)
148 char buffer
[PATH_MAX
];
149 return open(rpath(ctx
, path
, buffer
), flags
);
152 static DIR *local_opendir(FsContext
*ctx
, const char *path
)
154 char buffer
[PATH_MAX
];
155 return opendir(rpath(ctx
, path
, buffer
));
158 static void local_rewinddir(FsContext
*ctx
, DIR *dir
)
160 return rewinddir(dir
);
163 static off_t
local_telldir(FsContext
*ctx
, DIR *dir
)
168 static int local_readdir_r(FsContext
*ctx
, DIR *dir
, struct dirent
*entry
,
169 struct dirent
**result
)
171 return readdir_r(dir
, entry
, result
);
174 static void local_seekdir(FsContext
*ctx
, DIR *dir
, off_t off
)
176 return seekdir(dir
, off
);
179 static ssize_t
local_preadv(FsContext
*ctx
, int fd
, const struct iovec
*iov
,
180 int iovcnt
, off_t offset
)
183 return preadv(fd
, iov
, iovcnt
, offset
);
185 int err
= lseek(fd
, offset
, SEEK_SET
);
189 return readv(fd
, iov
, iovcnt
);
194 static ssize_t
local_pwritev(FsContext
*ctx
, int fd
, const struct iovec
*iov
,
195 int iovcnt
, off_t offset
)
198 return pwritev(fd
, iov
, iovcnt
, offset
);
200 int err
= lseek(fd
, offset
, SEEK_SET
);
204 return writev(fd
, iov
, iovcnt
);
209 static int local_chmod(FsContext
*fs_ctx
, const char *path
, FsCred
*credp
)
211 char buffer
[PATH_MAX
];
212 if (fs_ctx
->fs_sm
== SM_MAPPED
) {
213 return local_set_xattr(rpath(fs_ctx
, path
, buffer
), credp
);
214 } else if ((fs_ctx
->fs_sm
== SM_PASSTHROUGH
) ||
215 (fs_ctx
->fs_sm
== SM_NONE
)) {
216 return chmod(rpath(fs_ctx
, path
, buffer
), credp
->fc_mode
);
221 static int local_mknod(FsContext
*fs_ctx
, const char *path
, FsCred
*credp
)
225 char buffer
[PATH_MAX
];
227 /* Determine the security model */
228 if (fs_ctx
->fs_sm
== SM_MAPPED
) {
229 err
= mknod(rpath(fs_ctx
, path
, buffer
),
230 SM_LOCAL_MODE_BITS
|S_IFREG
, 0);
234 local_set_xattr(rpath(fs_ctx
, path
, buffer
), credp
);
239 } else if ((fs_ctx
->fs_sm
== SM_PASSTHROUGH
) ||
240 (fs_ctx
->fs_sm
== SM_NONE
)) {
241 err
= mknod(rpath(fs_ctx
, path
, buffer
), credp
->fc_mode
,
246 err
= local_post_create_passthrough(fs_ctx
, path
, credp
);
255 remove(rpath(fs_ctx
, path
, buffer
));
260 static int local_mkdir(FsContext
*fs_ctx
, const char *path
, FsCred
*credp
)
264 char buffer
[PATH_MAX
];
266 /* Determine the security model */
267 if (fs_ctx
->fs_sm
== SM_MAPPED
) {
268 err
= mkdir(rpath(fs_ctx
, path
, buffer
), SM_LOCAL_DIR_MODE_BITS
);
272 credp
->fc_mode
= credp
->fc_mode
|S_IFDIR
;
273 err
= local_set_xattr(rpath(fs_ctx
, path
, buffer
), credp
);
278 } else if ((fs_ctx
->fs_sm
== SM_PASSTHROUGH
) ||
279 (fs_ctx
->fs_sm
== SM_NONE
)) {
280 err
= mkdir(rpath(fs_ctx
, path
, buffer
), credp
->fc_mode
);
284 err
= local_post_create_passthrough(fs_ctx
, path
, credp
);
293 remove(rpath(fs_ctx
, path
, buffer
));
298 static int local_fstat(FsContext
*fs_ctx
, int fd
, struct stat
*stbuf
)
301 err
= fstat(fd
, stbuf
);
305 if (fs_ctx
->fs_sm
== SM_MAPPED
) {
306 /* Actual credentials are part of extended attrs */
312 if (fgetxattr(fd
, "user.virtfs.uid", &tmp_uid
, sizeof(uid_t
)) > 0) {
313 stbuf
->st_uid
= tmp_uid
;
315 if (fgetxattr(fd
, "user.virtfs.gid", &tmp_gid
, sizeof(gid_t
)) > 0) {
316 stbuf
->st_gid
= tmp_gid
;
318 if (fgetxattr(fd
, "user.virtfs.mode", &tmp_mode
, sizeof(mode_t
)) > 0) {
319 stbuf
->st_mode
= tmp_mode
;
321 if (fgetxattr(fd
, "user.virtfs.rdev", &tmp_dev
, sizeof(dev_t
)) > 0) {
322 stbuf
->st_rdev
= tmp_dev
;
328 static int local_open2(FsContext
*fs_ctx
, const char *path
, int flags
,
334 char buffer
[PATH_MAX
];
336 /* Determine the security model */
337 if (fs_ctx
->fs_sm
== SM_MAPPED
) {
338 fd
= open(rpath(fs_ctx
, path
, buffer
), flags
, SM_LOCAL_MODE_BITS
);
342 credp
->fc_mode
= credp
->fc_mode
|S_IFREG
;
343 /* Set cleint credentials in xattr */
344 err
= local_set_xattr(rpath(fs_ctx
, path
, buffer
), credp
);
349 } else if ((fs_ctx
->fs_sm
== SM_PASSTHROUGH
) ||
350 (fs_ctx
->fs_sm
== SM_NONE
)) {
351 fd
= open(rpath(fs_ctx
, path
, buffer
), flags
, credp
->fc_mode
);
355 err
= local_post_create_passthrough(fs_ctx
, path
, credp
);
365 remove(rpath(fs_ctx
, path
, buffer
));
371 static int local_symlink(FsContext
*fs_ctx
, const char *oldpath
,
372 const char *newpath
, FsCred
*credp
)
376 char buffer
[PATH_MAX
];
378 /* Determine the security model */
379 if (fs_ctx
->fs_sm
== SM_MAPPED
) {
381 ssize_t oldpath_size
, write_size
;
382 fd
= open(rpath(fs_ctx
, newpath
, buffer
), O_CREAT
|O_EXCL
|O_RDWR
,
387 /* Write the oldpath (target) to the file. */
388 oldpath_size
= strlen(oldpath
);
390 write_size
= write(fd
, (void *)oldpath
, oldpath_size
);
391 } while (write_size
== -1 && errno
== EINTR
);
393 if (write_size
!= oldpath_size
) {
400 /* Set cleint credentials in symlink's xattr */
401 credp
->fc_mode
= credp
->fc_mode
|S_IFLNK
;
402 err
= local_set_xattr(rpath(fs_ctx
, newpath
, buffer
), credp
);
407 } else if ((fs_ctx
->fs_sm
== SM_PASSTHROUGH
) ||
408 (fs_ctx
->fs_sm
== SM_NONE
)) {
409 err
= symlink(oldpath
, rpath(fs_ctx
, newpath
, buffer
));
413 err
= lchown(rpath(fs_ctx
, newpath
, buffer
), credp
->fc_uid
,
417 * If we fail to change ownership and if we are
418 * using security model none. Ignore the error
420 if (fs_ctx
->fs_sm
!= SM_NONE
) {
430 remove(rpath(fs_ctx
, newpath
, buffer
));
435 static int local_link(FsContext
*ctx
, const char *oldpath
, const char *newpath
)
437 char buffer
[PATH_MAX
], buffer1
[PATH_MAX
];
439 return link(rpath(ctx
, oldpath
, buffer
), rpath(ctx
, newpath
, buffer1
));
442 static int local_truncate(FsContext
*ctx
, const char *path
, off_t size
)
444 char buffer
[PATH_MAX
];
445 return truncate(rpath(ctx
, path
, buffer
), size
);
448 static int local_rename(FsContext
*ctx
, const char *oldpath
,
451 char buffer
[PATH_MAX
], buffer1
[PATH_MAX
];
453 return rename(rpath(ctx
, oldpath
, buffer
), rpath(ctx
, newpath
, buffer1
));
456 static int local_chown(FsContext
*fs_ctx
, const char *path
, FsCred
*credp
)
458 char buffer
[PATH_MAX
];
459 if ((credp
->fc_uid
== -1 && credp
->fc_gid
== -1) ||
460 (fs_ctx
->fs_sm
== SM_PASSTHROUGH
)) {
461 return lchown(rpath(fs_ctx
, path
, buffer
), credp
->fc_uid
,
463 } else if (fs_ctx
->fs_sm
== SM_MAPPED
) {
464 return local_set_xattr(rpath(fs_ctx
, path
, buffer
), credp
);
465 } else if ((fs_ctx
->fs_sm
== SM_PASSTHROUGH
) ||
466 (fs_ctx
->fs_sm
== SM_NONE
)) {
467 return lchown(rpath(fs_ctx
, path
, buffer
), credp
->fc_uid
,
473 static int local_utimensat(FsContext
*s
, const char *path
,
474 const struct timespec
*buf
)
476 char buffer
[PATH_MAX
];
477 return qemu_utimensat(AT_FDCWD
, rpath(s
, path
, buffer
), buf
,
478 AT_SYMLINK_NOFOLLOW
);
481 static int local_remove(FsContext
*ctx
, const char *path
)
483 char buffer
[PATH_MAX
];
484 return remove(rpath(ctx
, path
, buffer
));
487 static int local_fsync(FsContext
*ctx
, int fd
, int datasync
)
490 return qemu_fdatasync(fd
);
496 static int local_statfs(FsContext
*s
, const char *path
, struct statfs
*stbuf
)
498 char buffer
[PATH_MAX
];
499 return statfs(rpath(s
, path
, buffer
), stbuf
);
502 static ssize_t
local_lgetxattr(FsContext
*ctx
, const char *path
,
503 const char *name
, void *value
, size_t size
)
505 return v9fs_get_xattr(ctx
, path
, name
, value
, size
);
508 static ssize_t
local_llistxattr(FsContext
*ctx
, const char *path
,
509 void *value
, size_t size
)
511 return v9fs_list_xattr(ctx
, path
, value
, size
);
514 static int local_lsetxattr(FsContext
*ctx
, const char *path
, const char *name
,
515 void *value
, size_t size
, int flags
)
517 return v9fs_set_xattr(ctx
, path
, name
, value
, size
, flags
);
520 static int local_lremovexattr(FsContext
*ctx
,
521 const char *path
, const char *name
)
523 return v9fs_remove_xattr(ctx
, path
, name
);
527 FileOperations local_ops
= {
528 .lstat
= local_lstat
,
529 .readlink
= local_readlink
,
530 .close
= local_close
,
531 .closedir
= local_closedir
,
533 .opendir
= local_opendir
,
534 .rewinddir
= local_rewinddir
,
535 .telldir
= local_telldir
,
536 .readdir_r
= local_readdir_r
,
537 .seekdir
= local_seekdir
,
538 .preadv
= local_preadv
,
539 .pwritev
= local_pwritev
,
540 .chmod
= local_chmod
,
541 .mknod
= local_mknod
,
542 .mkdir
= local_mkdir
,
543 .fstat
= local_fstat
,
544 .open2
= local_open2
,
545 .symlink
= local_symlink
,
547 .truncate
= local_truncate
,
548 .rename
= local_rename
,
549 .chown
= local_chown
,
550 .utimensat
= local_utimensat
,
551 .remove
= local_remove
,
552 .fsync
= local_fsync
,
553 .statfs
= local_statfs
,
554 .lgetxattr
= local_lgetxattr
,
555 .llistxattr
= local_llistxattr
,
556 .lsetxattr
= local_lsetxattr
,
557 .lremovexattr
= local_lremovexattr
,