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 <arpa/inet.h>
18 #include <sys/socket.h>
20 #include <attr/xattr.h>
22 static const char *rpath(FsContext
*ctx
, const char *path
)
24 /* FIXME: so wrong... */
25 static char buffer
[4096];
26 snprintf(buffer
, sizeof(buffer
), "%s/%s", ctx
->fs_root
, path
);
31 static int local_lstat(FsContext
*fs_ctx
, const char *path
, struct stat
*stbuf
)
34 err
= lstat(rpath(fs_ctx
, path
), stbuf
);
38 if (fs_ctx
->fs_sm
== SM_MAPPED
) {
39 /* Actual credentials are part of extended attrs */
44 if (getxattr(rpath(fs_ctx
, path
), "user.virtfs.uid", &tmp_uid
,
46 stbuf
->st_uid
= tmp_uid
;
48 if (getxattr(rpath(fs_ctx
, path
), "user.virtfs.gid", &tmp_gid
,
50 stbuf
->st_gid
= tmp_gid
;
52 if (getxattr(rpath(fs_ctx
, path
), "user.virtfs.mode", &tmp_mode
,
53 sizeof(mode_t
)) > 0) {
54 stbuf
->st_mode
= tmp_mode
;
56 if (getxattr(rpath(fs_ctx
, path
), "user.virtfs.rdev", &tmp_dev
,
58 stbuf
->st_rdev
= tmp_dev
;
64 static int local_set_xattr(const char *path
, FsCred
*credp
)
67 if (credp
->fc_uid
!= -1) {
68 err
= setxattr(path
, "user.virtfs.uid", &credp
->fc_uid
, sizeof(uid_t
),
74 if (credp
->fc_gid
!= -1) {
75 err
= setxattr(path
, "user.virtfs.gid", &credp
->fc_gid
, sizeof(gid_t
),
81 if (credp
->fc_mode
!= -1) {
82 err
= setxattr(path
, "user.virtfs.mode", &credp
->fc_mode
,
88 if (credp
->fc_rdev
!= -1) {
89 err
= setxattr(path
, "user.virtfs.rdev", &credp
->fc_rdev
,
98 static int local_post_create_passthrough(FsContext
*fs_ctx
, const char *path
,
101 if (chmod(rpath(fs_ctx
, path
), credp
->fc_mode
& 07777) < 0) {
104 if (chown(rpath(fs_ctx
, path
), credp
->fc_uid
, credp
->fc_gid
) < 0) {
110 static ssize_t
local_readlink(FsContext
*fs_ctx
, const char *path
,
111 char *buf
, size_t bufsz
)
114 if (fs_ctx
->fs_sm
== SM_MAPPED
) {
116 fd
= open(rpath(fs_ctx
, path
), O_RDONLY
);
121 tsize
= read(fd
, (void *)buf
, bufsz
);
122 } while (tsize
== -1 && errno
== EINTR
);
125 } else if (fs_ctx
->fs_sm
== SM_PASSTHROUGH
) {
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_readv(FsContext
*ctx
, int fd
, const struct iovec
*iov
,
174 return readv(fd
, iov
, iovcnt
);
177 static off_t
local_lseek(FsContext
*ctx
, int fd
, off_t offset
, int whence
)
179 return lseek(fd
, offset
, whence
);
182 static ssize_t
local_writev(FsContext
*ctx
, int fd
, const struct iovec
*iov
,
185 return writev(fd
, iov
, iovcnt
);
188 static int local_chmod(FsContext
*fs_ctx
, const char *path
, FsCred
*credp
)
190 if (fs_ctx
->fs_sm
== SM_MAPPED
) {
191 return local_set_xattr(rpath(fs_ctx
, path
), credp
);
192 } else if (fs_ctx
->fs_sm
== SM_PASSTHROUGH
) {
193 return chmod(rpath(fs_ctx
, path
), credp
->fc_mode
);
198 static int local_mknod(FsContext
*fs_ctx
, const char *path
, FsCred
*credp
)
203 /* Determine the security model */
204 if (fs_ctx
->fs_sm
== SM_MAPPED
) {
205 err
= mknod(rpath(fs_ctx
, path
), SM_LOCAL_MODE_BITS
|S_IFREG
, 0);
209 local_set_xattr(rpath(fs_ctx
, path
), credp
);
214 } else if (fs_ctx
->fs_sm
== SM_PASSTHROUGH
) {
215 err
= mknod(rpath(fs_ctx
, path
), credp
->fc_mode
, credp
->fc_rdev
);
219 err
= local_post_create_passthrough(fs_ctx
, path
, credp
);
228 remove(rpath(fs_ctx
, path
));
233 static int local_mkdir(FsContext
*fs_ctx
, const char *path
, FsCred
*credp
)
238 /* Determine the security model */
239 if (fs_ctx
->fs_sm
== SM_MAPPED
) {
240 err
= mkdir(rpath(fs_ctx
, path
), SM_LOCAL_DIR_MODE_BITS
);
244 credp
->fc_mode
= credp
->fc_mode
|S_IFDIR
;
245 err
= local_set_xattr(rpath(fs_ctx
, path
), credp
);
250 } else if (fs_ctx
->fs_sm
== SM_PASSTHROUGH
) {
251 err
= mkdir(rpath(fs_ctx
, path
), credp
->fc_mode
);
255 err
= local_post_create_passthrough(fs_ctx
, path
, credp
);
264 remove(rpath(fs_ctx
, path
));
269 static int local_fstat(FsContext
*fs_ctx
, int fd
, struct stat
*stbuf
)
272 err
= fstat(fd
, stbuf
);
276 if (fs_ctx
->fs_sm
== SM_MAPPED
) {
277 /* Actual credentials are part of extended attrs */
283 if (fgetxattr(fd
, "user.virtfs.uid", &tmp_uid
, sizeof(uid_t
)) > 0) {
284 stbuf
->st_uid
= tmp_uid
;
286 if (fgetxattr(fd
, "user.virtfs.gid", &tmp_gid
, sizeof(gid_t
)) > 0) {
287 stbuf
->st_gid
= tmp_gid
;
289 if (fgetxattr(fd
, "user.virtfs.mode", &tmp_mode
, sizeof(mode_t
)) > 0) {
290 stbuf
->st_mode
= tmp_mode
;
292 if (fgetxattr(fd
, "user.virtfs.rdev", &tmp_dev
, sizeof(dev_t
)) > 0) {
293 stbuf
->st_rdev
= tmp_dev
;
299 static int local_open2(FsContext
*fs_ctx
, const char *path
, int flags
,
306 /* Determine the security model */
307 if (fs_ctx
->fs_sm
== SM_MAPPED
) {
308 fd
= open(rpath(fs_ctx
, path
), flags
, SM_LOCAL_MODE_BITS
);
312 credp
->fc_mode
= credp
->fc_mode
|S_IFREG
;
313 /* Set cleint credentials in xattr */
314 err
= local_set_xattr(rpath(fs_ctx
, path
), credp
);
319 } else if (fs_ctx
->fs_sm
== SM_PASSTHROUGH
) {
320 fd
= open(rpath(fs_ctx
, path
), flags
, credp
->fc_mode
);
324 err
= local_post_create_passthrough(fs_ctx
, path
, credp
);
334 remove(rpath(fs_ctx
, path
));
340 static int local_symlink(FsContext
*fs_ctx
, const char *oldpath
,
341 const char *newpath
, FsCred
*credp
)
346 /* Determine the security model */
347 if (fs_ctx
->fs_sm
== SM_MAPPED
) {
349 ssize_t oldpath_size
, write_size
;
350 fd
= open(rpath(fs_ctx
, newpath
), O_CREAT
|O_EXCL
|O_RDWR
,
355 /* Write the oldpath (target) to the file. */
356 oldpath_size
= strlen(oldpath
) + 1;
358 write_size
= write(fd
, (void *)oldpath
, oldpath_size
);
359 } while (write_size
== -1 && errno
== EINTR
);
361 if (write_size
!= oldpath_size
) {
368 /* Set cleint credentials in symlink's xattr */
369 credp
->fc_mode
= credp
->fc_mode
|S_IFLNK
;
370 err
= local_set_xattr(rpath(fs_ctx
, newpath
), credp
);
375 } else if (fs_ctx
->fs_sm
== SM_PASSTHROUGH
) {
376 err
= symlink(oldpath
, rpath(fs_ctx
, newpath
));
380 err
= lchown(rpath(fs_ctx
, newpath
), credp
->fc_uid
, credp
->fc_gid
);
389 remove(rpath(fs_ctx
, newpath
));
394 static int local_link(FsContext
*ctx
, const char *oldpath
, const char *newpath
)
396 char *tmp
= qemu_strdup(rpath(ctx
, oldpath
));
403 err
= link(tmp
, rpath(ctx
, newpath
));
417 static int local_truncate(FsContext
*ctx
, const char *path
, off_t size
)
419 return truncate(rpath(ctx
, path
), size
);
422 static int local_rename(FsContext
*ctx
, const char *oldpath
,
428 tmp
= qemu_strdup(rpath(ctx
, oldpath
));
430 err
= rename(tmp
, rpath(ctx
, newpath
));
443 static int local_chown(FsContext
*fs_ctx
, const char *path
, FsCred
*credp
)
445 if ((credp
->fc_uid
== -1 && credp
->fc_gid
== -1) ||
446 (fs_ctx
->fs_sm
== SM_PASSTHROUGH
)) {
447 return lchown(rpath(fs_ctx
, path
), credp
->fc_uid
, credp
->fc_gid
);
448 } else if (fs_ctx
->fs_sm
== SM_MAPPED
) {
449 return local_set_xattr(rpath(fs_ctx
, path
), credp
);
450 } else if (fs_ctx
->fs_sm
== SM_PASSTHROUGH
) {
451 return lchown(rpath(fs_ctx
, path
), credp
->fc_uid
, credp
->fc_gid
);
456 static int local_utimensat(FsContext
*s
, const char *path
,
457 const struct timespec
*buf
)
459 return utimensat(AT_FDCWD
, rpath(s
, path
), buf
, AT_SYMLINK_NOFOLLOW
);
462 static int local_remove(FsContext
*ctx
, const char *path
)
464 return remove(rpath(ctx
, path
));
467 static int local_fsync(FsContext
*ctx
, int fd
)
472 static int local_statfs(FsContext
*s
, const char *path
, struct statfs
*stbuf
)
474 return statfs(rpath(s
, path
), stbuf
);
477 FileOperations local_ops
= {
478 .lstat
= local_lstat
,
479 .readlink
= local_readlink
,
480 .close
= local_close
,
481 .closedir
= local_closedir
,
483 .opendir
= local_opendir
,
484 .rewinddir
= local_rewinddir
,
485 .telldir
= local_telldir
,
486 .readdir
= local_readdir
,
487 .seekdir
= local_seekdir
,
488 .readv
= local_readv
,
489 .lseek
= local_lseek
,
490 .writev
= local_writev
,
491 .chmod
= local_chmod
,
492 .mknod
= local_mknod
,
493 .mkdir
= local_mkdir
,
494 .fstat
= local_fstat
,
495 .open2
= local_open2
,
496 .symlink
= local_symlink
,
498 .truncate
= local_truncate
,
499 .rename
= local_rename
,
500 .chown
= local_chown
,
501 .utimensat
= local_utimensat
,
502 .remove
= local_remove
,
503 .fsync
= local_fsync
,
504 .statfs
= local_statfs
,