2 * FUSE: Filesystem in Userspace
3 * Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
5 * This program can be distributed under the terms of the GNU GPLv2.
6 * See the file COPYING.
11 * This file system mirrors the existing file system hierarchy of the
12 * system, starting at the root file system. This is implemented by
13 * just "passing through" all requests to the corresponding user-space
14 * libc functions. In contrast to passthrough.c and passthrough_fh.c,
15 * this implementation uses the low-level API. Its performance should
16 * be the least bad among the three, but many operations are not
17 * implemented. In particular, it is not possible to remove files (or
18 * directories) because the code necessary to defer actual removal
19 * until the file is not opened anymore would make the example much
22 * When writeback caching is enabled (-o writeback mount option), it
23 * is only possible to write to files for which the mounting user has
24 * read permissions. This is because the writeback cache requires the
25 * kernel to be able to issue read requests for all files (which the
26 * passthrough filesystem cannot satisfy if it can't read the file in
27 * the underlying filesystem).
31 * gcc -Wall passthrough_ll.c `pkg-config fuse3 --cflags --libs` -o
35 * \include passthrough_ll.c
38 #include "qemu/osdep.h"
39 #include "fuse_virtio.h"
40 #include "fuse_lowlevel.h"
53 #include <sys/xattr.h>
56 #include "passthrough_helpers.h"
59 * We are re-using pointers to our `struct lo_inode` and `struct
60 * lo_dirp` elements as inodes. This means that we must be able to
61 * store uintptr_t values in a fuse_ino_t variable. The following
62 * incantation checks this condition at compile time.
64 #if defined(__GNUC__) && \
65 (__GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ >= 6) && \
67 _Static_assert(sizeof(fuse_ino_t
) >= sizeof(uintptr_t),
68 "fuse_ino_t too small to hold uintptr_t values!");
70 struct _uintptr_to_must_hold_fuse_ino_t_dummy_struct
{
71 unsigned _uintptr_to_must_hold_fuse_ino_t
72 : ((sizeof(fuse_ino_t
) >= sizeof(uintptr_t)) ? 1 : -1);
77 struct lo_inode
*next
; /* protected by lo->mutex */
78 struct lo_inode
*prev
; /* protected by lo->mutex */
83 uint64_t refcount
; /* protected by lo->mutex */
93 pthread_mutex_t mutex
;
102 struct lo_inode root
; /* protected by lo->mutex */
105 static const struct fuse_opt lo_opts
[] = {
106 { "writeback", offsetof(struct lo_data
, writeback
), 1 },
107 { "no_writeback", offsetof(struct lo_data
, writeback
), 0 },
108 { "source=%s", offsetof(struct lo_data
, source
), 0 },
109 { "flock", offsetof(struct lo_data
, flock
), 1 },
110 { "no_flock", offsetof(struct lo_data
, flock
), 0 },
111 { "xattr", offsetof(struct lo_data
, xattr
), 1 },
112 { "no_xattr", offsetof(struct lo_data
, xattr
), 0 },
113 { "timeout=%lf", offsetof(struct lo_data
, timeout
), 0 },
114 { "timeout=", offsetof(struct lo_data
, timeout_set
), 1 },
115 { "cache=never", offsetof(struct lo_data
, cache
), CACHE_NEVER
},
116 { "cache=auto", offsetof(struct lo_data
, cache
), CACHE_NORMAL
},
117 { "cache=always", offsetof(struct lo_data
, cache
), CACHE_ALWAYS
},
122 static struct lo_data
*lo_data(fuse_req_t req
)
124 return (struct lo_data
*)fuse_req_userdata(req
);
127 static struct lo_inode
*lo_inode(fuse_req_t req
, fuse_ino_t ino
)
129 if (ino
== FUSE_ROOT_ID
) {
130 return &lo_data(req
)->root
;
132 return (struct lo_inode
*)(uintptr_t)ino
;
136 static int lo_fd(fuse_req_t req
, fuse_ino_t ino
)
138 return lo_inode(req
, ino
)->fd
;
141 static bool lo_debug(fuse_req_t req
)
143 return lo_data(req
)->debug
!= 0;
146 static void lo_init(void *userdata
, struct fuse_conn_info
*conn
)
148 struct lo_data
*lo
= (struct lo_data
*)userdata
;
150 if (conn
->capable
& FUSE_CAP_EXPORT_SUPPORT
) {
151 conn
->want
|= FUSE_CAP_EXPORT_SUPPORT
;
154 if (lo
->writeback
&& conn
->capable
& FUSE_CAP_WRITEBACK_CACHE
) {
156 fuse_log(FUSE_LOG_DEBUG
, "lo_init: activating writeback\n");
158 conn
->want
|= FUSE_CAP_WRITEBACK_CACHE
;
160 if (lo
->flock
&& conn
->capable
& FUSE_CAP_FLOCK_LOCKS
) {
162 fuse_log(FUSE_LOG_DEBUG
, "lo_init: activating flock locks\n");
164 conn
->want
|= FUSE_CAP_FLOCK_LOCKS
;
168 static void lo_getattr(fuse_req_t req
, fuse_ino_t ino
,
169 struct fuse_file_info
*fi
)
173 struct lo_data
*lo
= lo_data(req
);
178 fstatat(lo_fd(req
, ino
), "", &buf
, AT_EMPTY_PATH
| AT_SYMLINK_NOFOLLOW
);
180 return (void)fuse_reply_err(req
, errno
);
183 fuse_reply_attr(req
, &buf
, lo
->timeout
);
186 static int utimensat_empty_nofollow(struct lo_inode
*inode
,
187 const struct timespec
*tv
)
192 if (inode
->is_symlink
) {
193 res
= utimensat(inode
->fd
, "", tv
, AT_EMPTY_PATH
| AT_SYMLINK_NOFOLLOW
);
194 if (res
== -1 && errno
== EINVAL
) {
195 /* Sorry, no race free way to set times on symlink. */
200 sprintf(procname
, "/proc/self/fd/%i", inode
->fd
);
202 return utimensat(AT_FDCWD
, procname
, tv
, 0);
205 static void lo_setattr(fuse_req_t req
, fuse_ino_t ino
, struct stat
*attr
,
206 int valid
, struct fuse_file_info
*fi
)
210 struct lo_inode
*inode
= lo_inode(req
, ino
);
214 if (valid
& FUSE_SET_ATTR_MODE
) {
216 res
= fchmod(fi
->fh
, attr
->st_mode
);
218 sprintf(procname
, "/proc/self/fd/%i", ifd
);
219 res
= chmod(procname
, attr
->st_mode
);
225 if (valid
& (FUSE_SET_ATTR_UID
| FUSE_SET_ATTR_GID
)) {
226 uid_t uid
= (valid
& FUSE_SET_ATTR_UID
) ? attr
->st_uid
: (uid_t
)-1;
227 gid_t gid
= (valid
& FUSE_SET_ATTR_GID
) ? attr
->st_gid
: (gid_t
)-1;
229 res
= fchownat(ifd
, "", uid
, gid
, AT_EMPTY_PATH
| AT_SYMLINK_NOFOLLOW
);
234 if (valid
& FUSE_SET_ATTR_SIZE
) {
236 res
= ftruncate(fi
->fh
, attr
->st_size
);
238 sprintf(procname
, "/proc/self/fd/%i", ifd
);
239 res
= truncate(procname
, attr
->st_size
);
245 if (valid
& (FUSE_SET_ATTR_ATIME
| FUSE_SET_ATTR_MTIME
)) {
246 struct timespec tv
[2];
250 tv
[0].tv_nsec
= UTIME_OMIT
;
251 tv
[1].tv_nsec
= UTIME_OMIT
;
253 if (valid
& FUSE_SET_ATTR_ATIME_NOW
) {
254 tv
[0].tv_nsec
= UTIME_NOW
;
255 } else if (valid
& FUSE_SET_ATTR_ATIME
) {
256 tv
[0] = attr
->st_atim
;
259 if (valid
& FUSE_SET_ATTR_MTIME_NOW
) {
260 tv
[1].tv_nsec
= UTIME_NOW
;
261 } else if (valid
& FUSE_SET_ATTR_MTIME
) {
262 tv
[1] = attr
->st_mtim
;
266 res
= futimens(fi
->fh
, tv
);
268 res
= utimensat_empty_nofollow(inode
, tv
);
275 return lo_getattr(req
, ino
, fi
);
279 fuse_reply_err(req
, saverr
);
282 static struct lo_inode
*lo_find(struct lo_data
*lo
, struct stat
*st
)
285 struct lo_inode
*ret
= NULL
;
287 pthread_mutex_lock(&lo
->mutex
);
288 for (p
= lo
->root
.next
; p
!= &lo
->root
; p
= p
->next
) {
289 if (p
->ino
== st
->st_ino
&& p
->dev
== st
->st_dev
) {
290 assert(p
->refcount
> 0);
296 pthread_mutex_unlock(&lo
->mutex
);
300 static int lo_do_lookup(fuse_req_t req
, fuse_ino_t parent
, const char *name
,
301 struct fuse_entry_param
*e
)
306 struct lo_data
*lo
= lo_data(req
);
307 struct lo_inode
*inode
;
309 memset(e
, 0, sizeof(*e
));
310 e
->attr_timeout
= lo
->timeout
;
311 e
->entry_timeout
= lo
->timeout
;
313 newfd
= openat(lo_fd(req
, parent
), name
, O_PATH
| O_NOFOLLOW
);
318 res
= fstatat(newfd
, "", &e
->attr
, AT_EMPTY_PATH
| AT_SYMLINK_NOFOLLOW
);
323 inode
= lo_find(lo_data(req
), &e
->attr
);
328 struct lo_inode
*prev
, *next
;
331 inode
= calloc(1, sizeof(struct lo_inode
));
336 inode
->is_symlink
= S_ISLNK(e
->attr
.st_mode
);
339 inode
->ino
= e
->attr
.st_ino
;
340 inode
->dev
= e
->attr
.st_dev
;
342 pthread_mutex_lock(&lo
->mutex
);
349 pthread_mutex_unlock(&lo
->mutex
);
351 e
->ino
= (uintptr_t)inode
;
354 fuse_log(FUSE_LOG_DEBUG
, " %lli/%s -> %lli\n",
355 (unsigned long long)parent
, name
, (unsigned long long)e
->ino
);
368 static void lo_lookup(fuse_req_t req
, fuse_ino_t parent
, const char *name
)
370 struct fuse_entry_param e
;
374 fuse_log(FUSE_LOG_DEBUG
, "lo_lookup(parent=%" PRIu64
", name=%s)\n",
378 err
= lo_do_lookup(req
, parent
, name
, &e
);
380 fuse_reply_err(req
, err
);
382 fuse_reply_entry(req
, &e
);
386 static void lo_mknod_symlink(fuse_req_t req
, fuse_ino_t parent
,
387 const char *name
, mode_t mode
, dev_t rdev
,
392 struct lo_inode
*dir
= lo_inode(req
, parent
);
393 struct fuse_entry_param e
;
397 res
= mknod_wrapper(dir
->fd
, name
, link
, mode
, rdev
);
404 saverr
= lo_do_lookup(req
, parent
, name
, &e
);
410 fuse_log(FUSE_LOG_DEBUG
, " %lli/%s -> %lli\n",
411 (unsigned long long)parent
, name
, (unsigned long long)e
.ino
);
414 fuse_reply_entry(req
, &e
);
418 fuse_reply_err(req
, saverr
);
421 static void lo_mknod(fuse_req_t req
, fuse_ino_t parent
, const char *name
,
422 mode_t mode
, dev_t rdev
)
424 lo_mknod_symlink(req
, parent
, name
, mode
, rdev
, NULL
);
427 static void lo_mkdir(fuse_req_t req
, fuse_ino_t parent
, const char *name
,
430 lo_mknod_symlink(req
, parent
, name
, S_IFDIR
| mode
, 0, NULL
);
433 static void lo_symlink(fuse_req_t req
, const char *link
, fuse_ino_t parent
,
436 lo_mknod_symlink(req
, parent
, name
, S_IFLNK
, 0, link
);
439 static int linkat_empty_nofollow(struct lo_inode
*inode
, int dfd
,
445 if (inode
->is_symlink
) {
446 res
= linkat(inode
->fd
, "", dfd
, name
, AT_EMPTY_PATH
);
447 if (res
== -1 && (errno
== ENOENT
|| errno
== EINVAL
)) {
448 /* Sorry, no race free way to hard-link a symlink. */
454 sprintf(procname
, "/proc/self/fd/%i", inode
->fd
);
456 return linkat(AT_FDCWD
, procname
, dfd
, name
, AT_SYMLINK_FOLLOW
);
459 static void lo_link(fuse_req_t req
, fuse_ino_t ino
, fuse_ino_t parent
,
463 struct lo_data
*lo
= lo_data(req
);
464 struct lo_inode
*inode
= lo_inode(req
, ino
);
465 struct fuse_entry_param e
;
468 memset(&e
, 0, sizeof(struct fuse_entry_param
));
469 e
.attr_timeout
= lo
->timeout
;
470 e
.entry_timeout
= lo
->timeout
;
472 res
= linkat_empty_nofollow(inode
, lo_fd(req
, parent
), name
);
477 res
= fstatat(inode
->fd
, "", &e
.attr
, AT_EMPTY_PATH
| AT_SYMLINK_NOFOLLOW
);
482 pthread_mutex_lock(&lo
->mutex
);
484 pthread_mutex_unlock(&lo
->mutex
);
485 e
.ino
= (uintptr_t)inode
;
488 fuse_log(FUSE_LOG_DEBUG
, " %lli/%s -> %lli\n",
489 (unsigned long long)parent
, name
, (unsigned long long)e
.ino
);
492 fuse_reply_entry(req
, &e
);
497 fuse_reply_err(req
, saverr
);
500 static void lo_rmdir(fuse_req_t req
, fuse_ino_t parent
, const char *name
)
504 res
= unlinkat(lo_fd(req
, parent
), name
, AT_REMOVEDIR
);
506 fuse_reply_err(req
, res
== -1 ? errno
: 0);
509 static void lo_rename(fuse_req_t req
, fuse_ino_t parent
, const char *name
,
510 fuse_ino_t newparent
, const char *newname
,
516 fuse_reply_err(req
, EINVAL
);
520 res
= renameat(lo_fd(req
, parent
), name
, lo_fd(req
, newparent
), newname
);
522 fuse_reply_err(req
, res
== -1 ? errno
: 0);
525 static void lo_unlink(fuse_req_t req
, fuse_ino_t parent
, const char *name
)
529 res
= unlinkat(lo_fd(req
, parent
), name
, 0);
531 fuse_reply_err(req
, res
== -1 ? errno
: 0);
534 static void unref_inode(struct lo_data
*lo
, struct lo_inode
*inode
, uint64_t n
)
540 pthread_mutex_lock(&lo
->mutex
);
541 assert(inode
->refcount
>= n
);
542 inode
->refcount
-= n
;
543 if (!inode
->refcount
) {
544 struct lo_inode
*prev
, *next
;
551 pthread_mutex_unlock(&lo
->mutex
);
556 pthread_mutex_unlock(&lo
->mutex
);
560 static void lo_forget_one(fuse_req_t req
, fuse_ino_t ino
, uint64_t nlookup
)
562 struct lo_data
*lo
= lo_data(req
);
563 struct lo_inode
*inode
= lo_inode(req
, ino
);
566 fuse_log(FUSE_LOG_DEBUG
, " forget %lli %lli -%lli\n",
567 (unsigned long long)ino
, (unsigned long long)inode
->refcount
,
568 (unsigned long long)nlookup
);
571 unref_inode(lo
, inode
, nlookup
);
574 static void lo_forget(fuse_req_t req
, fuse_ino_t ino
, uint64_t nlookup
)
576 lo_forget_one(req
, ino
, nlookup
);
577 fuse_reply_none(req
);
580 static void lo_forget_multi(fuse_req_t req
, size_t count
,
581 struct fuse_forget_data
*forgets
)
585 for (i
= 0; i
< count
; i
++) {
586 lo_forget_one(req
, forgets
[i
].ino
, forgets
[i
].nlookup
);
588 fuse_reply_none(req
);
591 static void lo_readlink(fuse_req_t req
, fuse_ino_t ino
)
593 char buf
[PATH_MAX
+ 1];
596 res
= readlinkat(lo_fd(req
, ino
), "", buf
, sizeof(buf
));
598 return (void)fuse_reply_err(req
, errno
);
601 if (res
== sizeof(buf
)) {
602 return (void)fuse_reply_err(req
, ENAMETOOLONG
);
607 fuse_reply_readlink(req
, buf
);
612 struct dirent
*entry
;
616 static struct lo_dirp
*lo_dirp(struct fuse_file_info
*fi
)
618 return (struct lo_dirp
*)(uintptr_t)fi
->fh
;
621 static void lo_opendir(fuse_req_t req
, fuse_ino_t ino
,
622 struct fuse_file_info
*fi
)
625 struct lo_data
*lo
= lo_data(req
);
629 d
= calloc(1, sizeof(struct lo_dirp
));
634 fd
= openat(lo_fd(req
, ino
), ".", O_RDONLY
);
639 d
->dp
= fdopendir(fd
);
647 fi
->fh
= (uintptr_t)d
;
648 if (lo
->cache
== CACHE_ALWAYS
) {
651 fuse_reply_open(req
, fi
);
663 fuse_reply_err(req
, error
);
666 static int is_dot_or_dotdot(const char *name
)
668 return name
[0] == '.' &&
669 (name
[1] == '\0' || (name
[1] == '.' && name
[2] == '\0'));
672 static void lo_do_readdir(fuse_req_t req
, fuse_ino_t ino
, size_t size
,
673 off_t offset
, struct fuse_file_info
*fi
, int plus
)
675 struct lo_dirp
*d
= lo_dirp(fi
);
683 buf
= calloc(1, size
);
690 if (offset
!= d
->offset
) {
691 seekdir(d
->dp
, offset
);
702 d
->entry
= readdir(d
->dp
);
704 if (errno
) { /* Error */
707 } else { /* End of stream */
712 nextoff
= d
->entry
->d_off
;
713 name
= d
->entry
->d_name
;
714 fuse_ino_t entry_ino
= 0;
716 struct fuse_entry_param e
;
717 if (is_dot_or_dotdot(name
)) {
718 e
= (struct fuse_entry_param
){
719 .attr
.st_ino
= d
->entry
->d_ino
,
720 .attr
.st_mode
= d
->entry
->d_type
<< 12,
723 err
= lo_do_lookup(req
, ino
, name
, &e
);
730 entsize
= fuse_add_direntry_plus(req
, p
, rem
, name
, &e
, nextoff
);
733 .st_ino
= d
->entry
->d_ino
,
734 .st_mode
= d
->entry
->d_type
<< 12,
736 entsize
= fuse_add_direntry(req
, p
, rem
, name
, &st
, nextoff
);
739 if (entry_ino
!= 0) {
740 lo_forget_one(req
, entry_ino
, 1);
755 * If there's an error, we can only signal it if we haven't stored
756 * any entries yet - otherwise we'd end up with wrong lookup
757 * counts for the entries that are already in the buffer. So we
758 * return what we've collected until that point.
760 if (err
&& rem
== size
) {
761 fuse_reply_err(req
, err
);
763 fuse_reply_buf(req
, buf
, size
- rem
);
768 static void lo_readdir(fuse_req_t req
, fuse_ino_t ino
, size_t size
,
769 off_t offset
, struct fuse_file_info
*fi
)
771 lo_do_readdir(req
, ino
, size
, offset
, fi
, 0);
774 static void lo_readdirplus(fuse_req_t req
, fuse_ino_t ino
, size_t size
,
775 off_t offset
, struct fuse_file_info
*fi
)
777 lo_do_readdir(req
, ino
, size
, offset
, fi
, 1);
780 static void lo_releasedir(fuse_req_t req
, fuse_ino_t ino
,
781 struct fuse_file_info
*fi
)
783 struct lo_dirp
*d
= lo_dirp(fi
);
787 fuse_reply_err(req
, 0);
790 static void lo_create(fuse_req_t req
, fuse_ino_t parent
, const char *name
,
791 mode_t mode
, struct fuse_file_info
*fi
)
794 struct lo_data
*lo
= lo_data(req
);
795 struct fuse_entry_param e
;
799 fuse_log(FUSE_LOG_DEBUG
, "lo_create(parent=%" PRIu64
", name=%s)\n",
803 fd
= openat(lo_fd(req
, parent
), name
, (fi
->flags
| O_CREAT
) & ~O_NOFOLLOW
,
806 return (void)fuse_reply_err(req
, errno
);
810 if (lo
->cache
== CACHE_NEVER
) {
812 } else if (lo
->cache
== CACHE_ALWAYS
) {
816 err
= lo_do_lookup(req
, parent
, name
, &e
);
818 fuse_reply_err(req
, err
);
820 fuse_reply_create(req
, &e
, fi
);
824 static void lo_fsyncdir(fuse_req_t req
, fuse_ino_t ino
, int datasync
,
825 struct fuse_file_info
*fi
)
828 int fd
= dirfd(lo_dirp(fi
)->dp
);
835 fuse_reply_err(req
, res
== -1 ? errno
: 0);
838 static void lo_open(fuse_req_t req
, fuse_ino_t ino
, struct fuse_file_info
*fi
)
842 struct lo_data
*lo
= lo_data(req
);
845 fuse_log(FUSE_LOG_DEBUG
, "lo_open(ino=%" PRIu64
", flags=%d)\n", ino
,
850 * With writeback cache, kernel may send read requests even
851 * when userspace opened write-only
853 if (lo
->writeback
&& (fi
->flags
& O_ACCMODE
) == O_WRONLY
) {
854 fi
->flags
&= ~O_ACCMODE
;
859 * With writeback cache, O_APPEND is handled by the kernel.
860 * This breaks atomicity (since the file may change in the
861 * underlying filesystem, so that the kernel's idea of the
862 * end of the file isn't accurate anymore). In this example,
863 * we just accept that. A more rigorous filesystem may want
864 * to return an error here
866 if (lo
->writeback
&& (fi
->flags
& O_APPEND
)) {
867 fi
->flags
&= ~O_APPEND
;
870 sprintf(buf
, "/proc/self/fd/%i", lo_fd(req
, ino
));
871 fd
= open(buf
, fi
->flags
& ~O_NOFOLLOW
);
873 return (void)fuse_reply_err(req
, errno
);
877 if (lo
->cache
== CACHE_NEVER
) {
879 } else if (lo
->cache
== CACHE_ALWAYS
) {
882 fuse_reply_open(req
, fi
);
885 static void lo_release(fuse_req_t req
, fuse_ino_t ino
,
886 struct fuse_file_info
*fi
)
891 fuse_reply_err(req
, 0);
894 static void lo_flush(fuse_req_t req
, fuse_ino_t ino
, struct fuse_file_info
*fi
)
898 res
= close(dup(fi
->fh
));
899 fuse_reply_err(req
, res
== -1 ? errno
: 0);
902 static void lo_fsync(fuse_req_t req
, fuse_ino_t ino
, int datasync
,
903 struct fuse_file_info
*fi
)
910 fuse_log(FUSE_LOG_DEBUG
, "lo_fsync(ino=%" PRIu64
", fi=0x%p)\n", ino
,
914 res
= asprintf(&buf
, "/proc/self/fd/%i", lo_fd(req
, ino
));
916 return (void)fuse_reply_err(req
, errno
);
919 fd
= open(buf
, O_RDWR
);
922 return (void)fuse_reply_err(req
, errno
);
936 fuse_reply_err(req
, res
== -1 ? errno
: 0);
939 static void lo_read(fuse_req_t req
, fuse_ino_t ino
, size_t size
, off_t offset
,
940 struct fuse_file_info
*fi
)
942 struct fuse_bufvec buf
= FUSE_BUFVEC_INIT(size
);
945 fuse_log(FUSE_LOG_DEBUG
,
946 "lo_read(ino=%" PRIu64
", size=%zd, "
948 ino
, size
, (unsigned long)offset
);
951 buf
.buf
[0].flags
= FUSE_BUF_IS_FD
| FUSE_BUF_FD_SEEK
;
952 buf
.buf
[0].fd
= fi
->fh
;
953 buf
.buf
[0].pos
= offset
;
955 fuse_reply_data(req
, &buf
);
958 static void lo_write_buf(fuse_req_t req
, fuse_ino_t ino
,
959 struct fuse_bufvec
*in_buf
, off_t off
,
960 struct fuse_file_info
*fi
)
964 struct fuse_bufvec out_buf
= FUSE_BUFVEC_INIT(fuse_buf_size(in_buf
));
966 out_buf
.buf
[0].flags
= FUSE_BUF_IS_FD
| FUSE_BUF_FD_SEEK
;
967 out_buf
.buf
[0].fd
= fi
->fh
;
968 out_buf
.buf
[0].pos
= off
;
971 fuse_log(FUSE_LOG_DEBUG
,
972 "lo_write(ino=%" PRIu64
", size=%zd, off=%lu)\n", ino
,
973 out_buf
.buf
[0].size
, (unsigned long)off
);
976 res
= fuse_buf_copy(&out_buf
, in_buf
);
978 fuse_reply_err(req
, -res
);
980 fuse_reply_write(req
, (size_t)res
);
984 static void lo_statfs(fuse_req_t req
, fuse_ino_t ino
)
987 struct statvfs stbuf
;
989 res
= fstatvfs(lo_fd(req
, ino
), &stbuf
);
991 fuse_reply_err(req
, errno
);
993 fuse_reply_statfs(req
, &stbuf
);
997 static void lo_fallocate(fuse_req_t req
, fuse_ino_t ino
, int mode
, off_t offset
,
998 off_t length
, struct fuse_file_info
*fi
)
1000 int err
= EOPNOTSUPP
;
1003 #ifdef CONFIG_FALLOCATE
1004 err
= fallocate(fi
->fh
, mode
, offset
, length
);
1009 #elif defined(CONFIG_POSIX_FALLOCATE)
1011 fuse_reply_err(req
, EOPNOTSUPP
);
1015 err
= posix_fallocate(fi
->fh
, offset
, length
);
1018 fuse_reply_err(req
, err
);
1021 static void lo_flock(fuse_req_t req
, fuse_ino_t ino
, struct fuse_file_info
*fi
,
1027 res
= flock(fi
->fh
, op
);
1029 fuse_reply_err(req
, res
== -1 ? errno
: 0);
1032 static void lo_getxattr(fuse_req_t req
, fuse_ino_t ino
, const char *name
,
1037 struct lo_inode
*inode
= lo_inode(req
, ino
);
1042 if (!lo_data(req
)->xattr
) {
1046 if (lo_debug(req
)) {
1047 fuse_log(FUSE_LOG_DEBUG
,
1048 "lo_getxattr(ino=%" PRIu64
", name=%s size=%zd)\n", ino
, name
,
1052 if (inode
->is_symlink
) {
1053 /* Sorry, no race free way to getxattr on symlink. */
1058 sprintf(procname
, "/proc/self/fd/%i", inode
->fd
);
1061 value
= malloc(size
);
1066 ret
= getxattr(procname
, name
, value
, size
);
1075 fuse_reply_buf(req
, value
, ret
);
1077 ret
= getxattr(procname
, name
, NULL
, 0);
1082 fuse_reply_xattr(req
, ret
);
1091 fuse_reply_err(req
, saverr
);
1095 static void lo_listxattr(fuse_req_t req
, fuse_ino_t ino
, size_t size
)
1099 struct lo_inode
*inode
= lo_inode(req
, ino
);
1104 if (!lo_data(req
)->xattr
) {
1108 if (lo_debug(req
)) {
1109 fuse_log(FUSE_LOG_DEBUG
, "lo_listxattr(ino=%" PRIu64
", size=%zd)\n",
1113 if (inode
->is_symlink
) {
1114 /* Sorry, no race free way to listxattr on symlink. */
1119 sprintf(procname
, "/proc/self/fd/%i", inode
->fd
);
1122 value
= malloc(size
);
1127 ret
= listxattr(procname
, value
, size
);
1136 fuse_reply_buf(req
, value
, ret
);
1138 ret
= listxattr(procname
, NULL
, 0);
1143 fuse_reply_xattr(req
, ret
);
1152 fuse_reply_err(req
, saverr
);
1156 static void lo_setxattr(fuse_req_t req
, fuse_ino_t ino
, const char *name
,
1157 const char *value
, size_t size
, int flags
)
1160 struct lo_inode
*inode
= lo_inode(req
, ino
);
1165 if (!lo_data(req
)->xattr
) {
1169 if (lo_debug(req
)) {
1170 fuse_log(FUSE_LOG_DEBUG
,
1171 "lo_setxattr(ino=%" PRIu64
", name=%s value=%s size=%zd)\n",
1172 ino
, name
, value
, size
);
1175 if (inode
->is_symlink
) {
1176 /* Sorry, no race free way to setxattr on symlink. */
1181 sprintf(procname
, "/proc/self/fd/%i", inode
->fd
);
1183 ret
= setxattr(procname
, name
, value
, size
, flags
);
1184 saverr
= ret
== -1 ? errno
: 0;
1187 fuse_reply_err(req
, saverr
);
1190 static void lo_removexattr(fuse_req_t req
, fuse_ino_t ino
, const char *name
)
1193 struct lo_inode
*inode
= lo_inode(req
, ino
);
1198 if (!lo_data(req
)->xattr
) {
1202 if (lo_debug(req
)) {
1203 fuse_log(FUSE_LOG_DEBUG
, "lo_removexattr(ino=%" PRIu64
", name=%s)\n",
1207 if (inode
->is_symlink
) {
1208 /* Sorry, no race free way to setxattr on symlink. */
1213 sprintf(procname
, "/proc/self/fd/%i", inode
->fd
);
1215 ret
= removexattr(procname
, name
);
1216 saverr
= ret
== -1 ? errno
: 0;
1219 fuse_reply_err(req
, saverr
);
1222 #ifdef HAVE_COPY_FILE_RANGE
1223 static void lo_copy_file_range(fuse_req_t req
, fuse_ino_t ino_in
, off_t off_in
,
1224 struct fuse_file_info
*fi_in
, fuse_ino_t ino_out
,
1225 off_t off_out
, struct fuse_file_info
*fi_out
,
1226 size_t len
, int flags
)
1231 fuse_log(FUSE_LOG_DEBUG
,
1232 "lo_copy_file_range(ino=%" PRIu64
"/fd=%lu, "
1233 "off=%lu, ino=%" PRIu64
"/fd=%lu, "
1234 "off=%lu, size=%zd, flags=0x%x)\n",
1235 ino_in
, fi_in
->fh
, off_in
, ino_out
, fi_out
->fh
, off_out
, len
,
1238 res
= copy_file_range(fi_in
->fh
, &off_in
, fi_out
->fh
, &off_out
, len
, flags
);
1240 fuse_reply_err(req
, -errno
);
1242 fuse_reply_write(req
, res
);
1247 static void lo_lseek(fuse_req_t req
, fuse_ino_t ino
, off_t off
, int whence
,
1248 struct fuse_file_info
*fi
)
1253 res
= lseek(fi
->fh
, off
, whence
);
1255 fuse_reply_lseek(req
, res
);
1257 fuse_reply_err(req
, errno
);
1261 static struct fuse_lowlevel_ops lo_oper
= {
1263 .lookup
= lo_lookup
,
1266 .symlink
= lo_symlink
,
1268 .unlink
= lo_unlink
,
1270 .rename
= lo_rename
,
1271 .forget
= lo_forget
,
1272 .forget_multi
= lo_forget_multi
,
1273 .getattr
= lo_getattr
,
1274 .setattr
= lo_setattr
,
1275 .readlink
= lo_readlink
,
1276 .opendir
= lo_opendir
,
1277 .readdir
= lo_readdir
,
1278 .readdirplus
= lo_readdirplus
,
1279 .releasedir
= lo_releasedir
,
1280 .fsyncdir
= lo_fsyncdir
,
1281 .create
= lo_create
,
1283 .release
= lo_release
,
1287 .write_buf
= lo_write_buf
,
1288 .statfs
= lo_statfs
,
1289 .fallocate
= lo_fallocate
,
1291 .getxattr
= lo_getxattr
,
1292 .listxattr
= lo_listxattr
,
1293 .setxattr
= lo_setxattr
,
1294 .removexattr
= lo_removexattr
,
1295 #ifdef HAVE_COPY_FILE_RANGE
1296 .copy_file_range
= lo_copy_file_range
,
1301 /* Print vhost-user.json backend program capabilities */
1302 static void print_capabilities(void)
1305 printf(" \"type\": \"fs\"\n");
1309 int main(int argc
, char *argv
[])
1311 struct fuse_args args
= FUSE_ARGS_INIT(argc
, argv
);
1312 struct fuse_session
*se
;
1313 struct fuse_cmdline_opts opts
;
1314 struct lo_data lo
= { .debug
= 0, .writeback
= 0 };
1317 /* Don't mask creation mode, kernel already did that */
1320 pthread_mutex_init(&lo
.mutex
, NULL
);
1321 lo
.root
.next
= lo
.root
.prev
= &lo
.root
;
1323 lo
.cache
= CACHE_NORMAL
;
1325 if (fuse_parse_cmdline(&args
, &opts
) != 0) {
1328 if (opts
.show_help
) {
1329 printf("usage: %s [options]\n\n", argv
[0]);
1330 fuse_cmdline_help();
1331 printf(" -o source=PATH shared directory tree\n");
1332 fuse_lowlevel_help();
1335 } else if (opts
.show_version
) {
1336 fuse_lowlevel_version();
1339 } else if (opts
.print_capabilities
) {
1340 print_capabilities();
1345 if (fuse_opt_parse(&args
, &lo
, lo_opts
, NULL
) == -1) {
1349 lo
.debug
= opts
.debug
;
1350 lo
.root
.refcount
= 2;
1355 res
= lstat(lo
.source
, &stat
);
1357 fuse_log(FUSE_LOG_ERR
, "failed to stat source (\"%s\"): %m\n",
1361 if (!S_ISDIR(stat
.st_mode
)) {
1362 fuse_log(FUSE_LOG_ERR
, "source is not a directory\n");
1369 lo
.root
.is_symlink
= false;
1370 if (!lo
.timeout_set
) {
1381 lo
.timeout
= 86400.0;
1384 } else if (lo
.timeout
< 0) {
1385 fuse_log(FUSE_LOG_ERR
, "timeout is negative (%lf)\n", lo
.timeout
);
1389 lo
.root
.fd
= open(lo
.source
, O_PATH
);
1390 if (lo
.root
.fd
== -1) {
1391 fuse_log(FUSE_LOG_ERR
, "open(\"%s\", O_PATH): %m\n", lo
.source
);
1395 se
= fuse_session_new(&args
, &lo_oper
, sizeof(lo_oper
), &lo
);
1400 if (fuse_set_signal_handlers(se
) != 0) {
1404 if (fuse_session_mount(se
) != 0) {
1408 fuse_daemonize(opts
.foreground
);
1410 /* Block until ctrl+c or fusermount -u */
1411 ret
= virtio_loop(se
);
1413 fuse_session_unmount(se
);
1415 fuse_remove_signal_handlers(se
);
1417 fuse_session_destroy(se
);
1419 fuse_opt_free_args(&args
);
1421 if (lo
.root
.fd
>= 0) {