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_lowlevel.h"
52 #include <sys/xattr.h>
55 #include "passthrough_helpers.h"
58 * We are re-using pointers to our `struct lo_inode` and `struct
59 * lo_dirp` elements as inodes. This means that we must be able to
60 * store uintptr_t values in a fuse_ino_t variable. The following
61 * incantation checks this condition at compile time.
63 #if defined(__GNUC__) && \
64 (__GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ >= 6) && \
66 _Static_assert(sizeof(fuse_ino_t
) >= sizeof(uintptr_t),
67 "fuse_ino_t too small to hold uintptr_t values!");
69 struct _uintptr_to_must_hold_fuse_ino_t_dummy_struct
{
70 unsigned _uintptr_to_must_hold_fuse_ino_t
71 : ((sizeof(fuse_ino_t
) >= sizeof(uintptr_t)) ? 1 : -1);
76 struct lo_inode
*next
; /* protected by lo->mutex */
77 struct lo_inode
*prev
; /* protected by lo->mutex */
82 uint64_t refcount
; /* protected by lo->mutex */
92 pthread_mutex_t mutex
;
101 struct lo_inode root
; /* protected by lo->mutex */
104 static const struct fuse_opt lo_opts
[] = {
105 { "writeback", offsetof(struct lo_data
, writeback
), 1 },
106 { "no_writeback", offsetof(struct lo_data
, writeback
), 0 },
107 { "source=%s", offsetof(struct lo_data
, source
), 0 },
108 { "flock", offsetof(struct lo_data
, flock
), 1 },
109 { "no_flock", offsetof(struct lo_data
, flock
), 0 },
110 { "xattr", offsetof(struct lo_data
, xattr
), 1 },
111 { "no_xattr", offsetof(struct lo_data
, xattr
), 0 },
112 { "timeout=%lf", offsetof(struct lo_data
, timeout
), 0 },
113 { "timeout=", offsetof(struct lo_data
, timeout_set
), 1 },
114 { "cache=never", offsetof(struct lo_data
, cache
), CACHE_NEVER
},
115 { "cache=auto", offsetof(struct lo_data
, cache
), CACHE_NORMAL
},
116 { "cache=always", offsetof(struct lo_data
, cache
), CACHE_ALWAYS
},
121 static struct lo_data
*lo_data(fuse_req_t req
)
123 return (struct lo_data
*)fuse_req_userdata(req
);
126 static struct lo_inode
*lo_inode(fuse_req_t req
, fuse_ino_t ino
)
128 if (ino
== FUSE_ROOT_ID
) {
129 return &lo_data(req
)->root
;
131 return (struct lo_inode
*)(uintptr_t)ino
;
135 static int lo_fd(fuse_req_t req
, fuse_ino_t ino
)
137 return lo_inode(req
, ino
)->fd
;
140 static bool lo_debug(fuse_req_t req
)
142 return lo_data(req
)->debug
!= 0;
145 static void lo_init(void *userdata
, struct fuse_conn_info
*conn
)
147 struct lo_data
*lo
= (struct lo_data
*)userdata
;
149 if (conn
->capable
& FUSE_CAP_EXPORT_SUPPORT
) {
150 conn
->want
|= FUSE_CAP_EXPORT_SUPPORT
;
153 if (lo
->writeback
&& conn
->capable
& FUSE_CAP_WRITEBACK_CACHE
) {
155 fuse_log(FUSE_LOG_DEBUG
, "lo_init: activating writeback\n");
157 conn
->want
|= FUSE_CAP_WRITEBACK_CACHE
;
159 if (lo
->flock
&& conn
->capable
& FUSE_CAP_FLOCK_LOCKS
) {
161 fuse_log(FUSE_LOG_DEBUG
, "lo_init: activating flock locks\n");
163 conn
->want
|= FUSE_CAP_FLOCK_LOCKS
;
167 static void lo_getattr(fuse_req_t req
, fuse_ino_t ino
,
168 struct fuse_file_info
*fi
)
172 struct lo_data
*lo
= lo_data(req
);
177 fstatat(lo_fd(req
, ino
), "", &buf
, AT_EMPTY_PATH
| AT_SYMLINK_NOFOLLOW
);
179 return (void)fuse_reply_err(req
, errno
);
182 fuse_reply_attr(req
, &buf
, lo
->timeout
);
185 static int utimensat_empty_nofollow(struct lo_inode
*inode
,
186 const struct timespec
*tv
)
191 if (inode
->is_symlink
) {
192 res
= utimensat(inode
->fd
, "", tv
, AT_EMPTY_PATH
| AT_SYMLINK_NOFOLLOW
);
193 if (res
== -1 && errno
== EINVAL
) {
194 /* Sorry, no race free way to set times on symlink. */
199 sprintf(procname
, "/proc/self/fd/%i", inode
->fd
);
201 return utimensat(AT_FDCWD
, procname
, tv
, 0);
204 static void lo_setattr(fuse_req_t req
, fuse_ino_t ino
, struct stat
*attr
,
205 int valid
, struct fuse_file_info
*fi
)
209 struct lo_inode
*inode
= lo_inode(req
, ino
);
213 if (valid
& FUSE_SET_ATTR_MODE
) {
215 res
= fchmod(fi
->fh
, attr
->st_mode
);
217 sprintf(procname
, "/proc/self/fd/%i", ifd
);
218 res
= chmod(procname
, attr
->st_mode
);
224 if (valid
& (FUSE_SET_ATTR_UID
| FUSE_SET_ATTR_GID
)) {
225 uid_t uid
= (valid
& FUSE_SET_ATTR_UID
) ? attr
->st_uid
: (uid_t
)-1;
226 gid_t gid
= (valid
& FUSE_SET_ATTR_GID
) ? attr
->st_gid
: (gid_t
)-1;
228 res
= fchownat(ifd
, "", uid
, gid
, AT_EMPTY_PATH
| AT_SYMLINK_NOFOLLOW
);
233 if (valid
& FUSE_SET_ATTR_SIZE
) {
235 res
= ftruncate(fi
->fh
, attr
->st_size
);
237 sprintf(procname
, "/proc/self/fd/%i", ifd
);
238 res
= truncate(procname
, attr
->st_size
);
244 if (valid
& (FUSE_SET_ATTR_ATIME
| FUSE_SET_ATTR_MTIME
)) {
245 struct timespec tv
[2];
249 tv
[0].tv_nsec
= UTIME_OMIT
;
250 tv
[1].tv_nsec
= UTIME_OMIT
;
252 if (valid
& FUSE_SET_ATTR_ATIME_NOW
) {
253 tv
[0].tv_nsec
= UTIME_NOW
;
254 } else if (valid
& FUSE_SET_ATTR_ATIME
) {
255 tv
[0] = attr
->st_atim
;
258 if (valid
& FUSE_SET_ATTR_MTIME_NOW
) {
259 tv
[1].tv_nsec
= UTIME_NOW
;
260 } else if (valid
& FUSE_SET_ATTR_MTIME
) {
261 tv
[1] = attr
->st_mtim
;
265 res
= futimens(fi
->fh
, tv
);
267 res
= utimensat_empty_nofollow(inode
, tv
);
274 return lo_getattr(req
, ino
, fi
);
278 fuse_reply_err(req
, saverr
);
281 static struct lo_inode
*lo_find(struct lo_data
*lo
, struct stat
*st
)
284 struct lo_inode
*ret
= NULL
;
286 pthread_mutex_lock(&lo
->mutex
);
287 for (p
= lo
->root
.next
; p
!= &lo
->root
; p
= p
->next
) {
288 if (p
->ino
== st
->st_ino
&& p
->dev
== st
->st_dev
) {
289 assert(p
->refcount
> 0);
295 pthread_mutex_unlock(&lo
->mutex
);
299 static int lo_do_lookup(fuse_req_t req
, fuse_ino_t parent
, const char *name
,
300 struct fuse_entry_param
*e
)
305 struct lo_data
*lo
= lo_data(req
);
306 struct lo_inode
*inode
;
308 memset(e
, 0, sizeof(*e
));
309 e
->attr_timeout
= lo
->timeout
;
310 e
->entry_timeout
= lo
->timeout
;
312 newfd
= openat(lo_fd(req
, parent
), name
, O_PATH
| O_NOFOLLOW
);
317 res
= fstatat(newfd
, "", &e
->attr
, AT_EMPTY_PATH
| AT_SYMLINK_NOFOLLOW
);
322 inode
= lo_find(lo_data(req
), &e
->attr
);
327 struct lo_inode
*prev
, *next
;
330 inode
= calloc(1, sizeof(struct lo_inode
));
335 inode
->is_symlink
= S_ISLNK(e
->attr
.st_mode
);
338 inode
->ino
= e
->attr
.st_ino
;
339 inode
->dev
= e
->attr
.st_dev
;
341 pthread_mutex_lock(&lo
->mutex
);
348 pthread_mutex_unlock(&lo
->mutex
);
350 e
->ino
= (uintptr_t)inode
;
353 fuse_log(FUSE_LOG_DEBUG
, " %lli/%s -> %lli\n",
354 (unsigned long long)parent
, name
, (unsigned long long)e
->ino
);
367 static void lo_lookup(fuse_req_t req
, fuse_ino_t parent
, const char *name
)
369 struct fuse_entry_param e
;
373 fuse_log(FUSE_LOG_DEBUG
, "lo_lookup(parent=%" PRIu64
", name=%s)\n",
377 err
= lo_do_lookup(req
, parent
, name
, &e
);
379 fuse_reply_err(req
, err
);
381 fuse_reply_entry(req
, &e
);
385 static void lo_mknod_symlink(fuse_req_t req
, fuse_ino_t parent
,
386 const char *name
, mode_t mode
, dev_t rdev
,
391 struct lo_inode
*dir
= lo_inode(req
, parent
);
392 struct fuse_entry_param e
;
396 res
= mknod_wrapper(dir
->fd
, name
, link
, mode
, rdev
);
403 saverr
= lo_do_lookup(req
, parent
, name
, &e
);
409 fuse_log(FUSE_LOG_DEBUG
, " %lli/%s -> %lli\n",
410 (unsigned long long)parent
, name
, (unsigned long long)e
.ino
);
413 fuse_reply_entry(req
, &e
);
417 fuse_reply_err(req
, saverr
);
420 static void lo_mknod(fuse_req_t req
, fuse_ino_t parent
, const char *name
,
421 mode_t mode
, dev_t rdev
)
423 lo_mknod_symlink(req
, parent
, name
, mode
, rdev
, NULL
);
426 static void lo_mkdir(fuse_req_t req
, fuse_ino_t parent
, const char *name
,
429 lo_mknod_symlink(req
, parent
, name
, S_IFDIR
| mode
, 0, NULL
);
432 static void lo_symlink(fuse_req_t req
, const char *link
, fuse_ino_t parent
,
435 lo_mknod_symlink(req
, parent
, name
, S_IFLNK
, 0, link
);
438 static int linkat_empty_nofollow(struct lo_inode
*inode
, int dfd
,
444 if (inode
->is_symlink
) {
445 res
= linkat(inode
->fd
, "", dfd
, name
, AT_EMPTY_PATH
);
446 if (res
== -1 && (errno
== ENOENT
|| errno
== EINVAL
)) {
447 /* Sorry, no race free way to hard-link a symlink. */
453 sprintf(procname
, "/proc/self/fd/%i", inode
->fd
);
455 return linkat(AT_FDCWD
, procname
, dfd
, name
, AT_SYMLINK_FOLLOW
);
458 static void lo_link(fuse_req_t req
, fuse_ino_t ino
, fuse_ino_t parent
,
462 struct lo_data
*lo
= lo_data(req
);
463 struct lo_inode
*inode
= lo_inode(req
, ino
);
464 struct fuse_entry_param e
;
467 memset(&e
, 0, sizeof(struct fuse_entry_param
));
468 e
.attr_timeout
= lo
->timeout
;
469 e
.entry_timeout
= lo
->timeout
;
471 res
= linkat_empty_nofollow(inode
, lo_fd(req
, parent
), name
);
476 res
= fstatat(inode
->fd
, "", &e
.attr
, AT_EMPTY_PATH
| AT_SYMLINK_NOFOLLOW
);
481 pthread_mutex_lock(&lo
->mutex
);
483 pthread_mutex_unlock(&lo
->mutex
);
484 e
.ino
= (uintptr_t)inode
;
487 fuse_log(FUSE_LOG_DEBUG
, " %lli/%s -> %lli\n",
488 (unsigned long long)parent
, name
, (unsigned long long)e
.ino
);
491 fuse_reply_entry(req
, &e
);
496 fuse_reply_err(req
, saverr
);
499 static void lo_rmdir(fuse_req_t req
, fuse_ino_t parent
, const char *name
)
503 res
= unlinkat(lo_fd(req
, parent
), name
, AT_REMOVEDIR
);
505 fuse_reply_err(req
, res
== -1 ? errno
: 0);
508 static void lo_rename(fuse_req_t req
, fuse_ino_t parent
, const char *name
,
509 fuse_ino_t newparent
, const char *newname
,
515 fuse_reply_err(req
, EINVAL
);
519 res
= renameat(lo_fd(req
, parent
), name
, lo_fd(req
, newparent
), newname
);
521 fuse_reply_err(req
, res
== -1 ? errno
: 0);
524 static void lo_unlink(fuse_req_t req
, fuse_ino_t parent
, const char *name
)
528 res
= unlinkat(lo_fd(req
, parent
), name
, 0);
530 fuse_reply_err(req
, res
== -1 ? errno
: 0);
533 static void unref_inode(struct lo_data
*lo
, struct lo_inode
*inode
, uint64_t n
)
539 pthread_mutex_lock(&lo
->mutex
);
540 assert(inode
->refcount
>= n
);
541 inode
->refcount
-= n
;
542 if (!inode
->refcount
) {
543 struct lo_inode
*prev
, *next
;
550 pthread_mutex_unlock(&lo
->mutex
);
555 pthread_mutex_unlock(&lo
->mutex
);
559 static void lo_forget_one(fuse_req_t req
, fuse_ino_t ino
, uint64_t nlookup
)
561 struct lo_data
*lo
= lo_data(req
);
562 struct lo_inode
*inode
= lo_inode(req
, ino
);
565 fuse_log(FUSE_LOG_DEBUG
, " forget %lli %lli -%lli\n",
566 (unsigned long long)ino
, (unsigned long long)inode
->refcount
,
567 (unsigned long long)nlookup
);
570 unref_inode(lo
, inode
, nlookup
);
573 static void lo_forget(fuse_req_t req
, fuse_ino_t ino
, uint64_t nlookup
)
575 lo_forget_one(req
, ino
, nlookup
);
576 fuse_reply_none(req
);
579 static void lo_forget_multi(fuse_req_t req
, size_t count
,
580 struct fuse_forget_data
*forgets
)
584 for (i
= 0; i
< count
; i
++) {
585 lo_forget_one(req
, forgets
[i
].ino
, forgets
[i
].nlookup
);
587 fuse_reply_none(req
);
590 static void lo_readlink(fuse_req_t req
, fuse_ino_t ino
)
592 char buf
[PATH_MAX
+ 1];
595 res
= readlinkat(lo_fd(req
, ino
), "", buf
, sizeof(buf
));
597 return (void)fuse_reply_err(req
, errno
);
600 if (res
== sizeof(buf
)) {
601 return (void)fuse_reply_err(req
, ENAMETOOLONG
);
606 fuse_reply_readlink(req
, buf
);
611 struct dirent
*entry
;
615 static struct lo_dirp
*lo_dirp(struct fuse_file_info
*fi
)
617 return (struct lo_dirp
*)(uintptr_t)fi
->fh
;
620 static void lo_opendir(fuse_req_t req
, fuse_ino_t ino
,
621 struct fuse_file_info
*fi
)
624 struct lo_data
*lo
= lo_data(req
);
628 d
= calloc(1, sizeof(struct lo_dirp
));
633 fd
= openat(lo_fd(req
, ino
), ".", O_RDONLY
);
638 d
->dp
= fdopendir(fd
);
646 fi
->fh
= (uintptr_t)d
;
647 if (lo
->cache
== CACHE_ALWAYS
) {
650 fuse_reply_open(req
, fi
);
662 fuse_reply_err(req
, error
);
665 static int is_dot_or_dotdot(const char *name
)
667 return name
[0] == '.' &&
668 (name
[1] == '\0' || (name
[1] == '.' && name
[2] == '\0'));
671 static void lo_do_readdir(fuse_req_t req
, fuse_ino_t ino
, size_t size
,
672 off_t offset
, struct fuse_file_info
*fi
, int plus
)
674 struct lo_dirp
*d
= lo_dirp(fi
);
682 buf
= calloc(1, size
);
689 if (offset
!= d
->offset
) {
690 seekdir(d
->dp
, offset
);
701 d
->entry
= readdir(d
->dp
);
703 if (errno
) { /* Error */
706 } else { /* End of stream */
711 nextoff
= d
->entry
->d_off
;
712 name
= d
->entry
->d_name
;
713 fuse_ino_t entry_ino
= 0;
715 struct fuse_entry_param e
;
716 if (is_dot_or_dotdot(name
)) {
717 e
= (struct fuse_entry_param
){
718 .attr
.st_ino
= d
->entry
->d_ino
,
719 .attr
.st_mode
= d
->entry
->d_type
<< 12,
722 err
= lo_do_lookup(req
, ino
, name
, &e
);
729 entsize
= fuse_add_direntry_plus(req
, p
, rem
, name
, &e
, nextoff
);
732 .st_ino
= d
->entry
->d_ino
,
733 .st_mode
= d
->entry
->d_type
<< 12,
735 entsize
= fuse_add_direntry(req
, p
, rem
, name
, &st
, nextoff
);
738 if (entry_ino
!= 0) {
739 lo_forget_one(req
, entry_ino
, 1);
754 * If there's an error, we can only signal it if we haven't stored
755 * any entries yet - otherwise we'd end up with wrong lookup
756 * counts for the entries that are already in the buffer. So we
757 * return what we've collected until that point.
759 if (err
&& rem
== size
) {
760 fuse_reply_err(req
, err
);
762 fuse_reply_buf(req
, buf
, size
- rem
);
767 static void lo_readdir(fuse_req_t req
, fuse_ino_t ino
, size_t size
,
768 off_t offset
, struct fuse_file_info
*fi
)
770 lo_do_readdir(req
, ino
, size
, offset
, fi
, 0);
773 static void lo_readdirplus(fuse_req_t req
, fuse_ino_t ino
, size_t size
,
774 off_t offset
, struct fuse_file_info
*fi
)
776 lo_do_readdir(req
, ino
, size
, offset
, fi
, 1);
779 static void lo_releasedir(fuse_req_t req
, fuse_ino_t ino
,
780 struct fuse_file_info
*fi
)
782 struct lo_dirp
*d
= lo_dirp(fi
);
786 fuse_reply_err(req
, 0);
789 static void lo_create(fuse_req_t req
, fuse_ino_t parent
, const char *name
,
790 mode_t mode
, struct fuse_file_info
*fi
)
793 struct lo_data
*lo
= lo_data(req
);
794 struct fuse_entry_param e
;
798 fuse_log(FUSE_LOG_DEBUG
, "lo_create(parent=%" PRIu64
", name=%s)\n",
802 fd
= openat(lo_fd(req
, parent
), name
, (fi
->flags
| O_CREAT
) & ~O_NOFOLLOW
,
805 return (void)fuse_reply_err(req
, errno
);
809 if (lo
->cache
== CACHE_NEVER
) {
811 } else if (lo
->cache
== CACHE_ALWAYS
) {
815 err
= lo_do_lookup(req
, parent
, name
, &e
);
817 fuse_reply_err(req
, err
);
819 fuse_reply_create(req
, &e
, fi
);
823 static void lo_fsyncdir(fuse_req_t req
, fuse_ino_t ino
, int datasync
,
824 struct fuse_file_info
*fi
)
827 int fd
= dirfd(lo_dirp(fi
)->dp
);
834 fuse_reply_err(req
, res
== -1 ? errno
: 0);
837 static void lo_open(fuse_req_t req
, fuse_ino_t ino
, struct fuse_file_info
*fi
)
841 struct lo_data
*lo
= lo_data(req
);
844 fuse_log(FUSE_LOG_DEBUG
, "lo_open(ino=%" PRIu64
", flags=%d)\n", ino
,
849 * With writeback cache, kernel may send read requests even
850 * when userspace opened write-only
852 if (lo
->writeback
&& (fi
->flags
& O_ACCMODE
) == O_WRONLY
) {
853 fi
->flags
&= ~O_ACCMODE
;
858 * With writeback cache, O_APPEND is handled by the kernel.
859 * This breaks atomicity (since the file may change in the
860 * underlying filesystem, so that the kernel's idea of the
861 * end of the file isn't accurate anymore). In this example,
862 * we just accept that. A more rigorous filesystem may want
863 * to return an error here
865 if (lo
->writeback
&& (fi
->flags
& O_APPEND
)) {
866 fi
->flags
&= ~O_APPEND
;
869 sprintf(buf
, "/proc/self/fd/%i", lo_fd(req
, ino
));
870 fd
= open(buf
, fi
->flags
& ~O_NOFOLLOW
);
872 return (void)fuse_reply_err(req
, errno
);
876 if (lo
->cache
== CACHE_NEVER
) {
878 } else if (lo
->cache
== CACHE_ALWAYS
) {
881 fuse_reply_open(req
, fi
);
884 static void lo_release(fuse_req_t req
, fuse_ino_t ino
,
885 struct fuse_file_info
*fi
)
890 fuse_reply_err(req
, 0);
893 static void lo_flush(fuse_req_t req
, fuse_ino_t ino
, struct fuse_file_info
*fi
)
897 res
= close(dup(fi
->fh
));
898 fuse_reply_err(req
, res
== -1 ? errno
: 0);
901 static void lo_fsync(fuse_req_t req
, fuse_ino_t ino
, int datasync
,
902 struct fuse_file_info
*fi
)
909 fuse_log(FUSE_LOG_DEBUG
, "lo_fsync(ino=%" PRIu64
", fi=0x%p)\n", ino
,
913 res
= asprintf(&buf
, "/proc/self/fd/%i", lo_fd(req
, ino
));
915 return (void)fuse_reply_err(req
, errno
);
918 fd
= open(buf
, O_RDWR
);
921 return (void)fuse_reply_err(req
, errno
);
935 fuse_reply_err(req
, res
== -1 ? errno
: 0);
938 static void lo_read(fuse_req_t req
, fuse_ino_t ino
, size_t size
, off_t offset
,
939 struct fuse_file_info
*fi
)
941 struct fuse_bufvec buf
= FUSE_BUFVEC_INIT(size
);
944 fuse_log(FUSE_LOG_DEBUG
,
945 "lo_read(ino=%" PRIu64
", size=%zd, "
947 ino
, size
, (unsigned long)offset
);
950 buf
.buf
[0].flags
= FUSE_BUF_IS_FD
| FUSE_BUF_FD_SEEK
;
951 buf
.buf
[0].fd
= fi
->fh
;
952 buf
.buf
[0].pos
= offset
;
954 fuse_reply_data(req
, &buf
);
957 static void lo_write_buf(fuse_req_t req
, fuse_ino_t ino
,
958 struct fuse_bufvec
*in_buf
, off_t off
,
959 struct fuse_file_info
*fi
)
963 struct fuse_bufvec out_buf
= FUSE_BUFVEC_INIT(fuse_buf_size(in_buf
));
965 out_buf
.buf
[0].flags
= FUSE_BUF_IS_FD
| FUSE_BUF_FD_SEEK
;
966 out_buf
.buf
[0].fd
= fi
->fh
;
967 out_buf
.buf
[0].pos
= off
;
970 fuse_log(FUSE_LOG_DEBUG
,
971 "lo_write(ino=%" PRIu64
", size=%zd, off=%lu)\n", ino
,
972 out_buf
.buf
[0].size
, (unsigned long)off
);
975 res
= fuse_buf_copy(&out_buf
, in_buf
);
977 fuse_reply_err(req
, -res
);
979 fuse_reply_write(req
, (size_t)res
);
983 static void lo_statfs(fuse_req_t req
, fuse_ino_t ino
)
986 struct statvfs stbuf
;
988 res
= fstatvfs(lo_fd(req
, ino
), &stbuf
);
990 fuse_reply_err(req
, errno
);
992 fuse_reply_statfs(req
, &stbuf
);
996 static void lo_fallocate(fuse_req_t req
, fuse_ino_t ino
, int mode
, off_t offset
,
997 off_t length
, struct fuse_file_info
*fi
)
999 int err
= EOPNOTSUPP
;
1002 #ifdef CONFIG_FALLOCATE
1003 err
= fallocate(fi
->fh
, mode
, offset
, length
);
1008 #elif defined(CONFIG_POSIX_FALLOCATE)
1010 fuse_reply_err(req
, EOPNOTSUPP
);
1014 err
= posix_fallocate(fi
->fh
, offset
, length
);
1017 fuse_reply_err(req
, err
);
1020 static void lo_flock(fuse_req_t req
, fuse_ino_t ino
, struct fuse_file_info
*fi
,
1026 res
= flock(fi
->fh
, op
);
1028 fuse_reply_err(req
, res
== -1 ? errno
: 0);
1031 static void lo_getxattr(fuse_req_t req
, fuse_ino_t ino
, const char *name
,
1036 struct lo_inode
*inode
= lo_inode(req
, ino
);
1041 if (!lo_data(req
)->xattr
) {
1045 if (lo_debug(req
)) {
1046 fuse_log(FUSE_LOG_DEBUG
,
1047 "lo_getxattr(ino=%" PRIu64
", name=%s size=%zd)\n", ino
, name
,
1051 if (inode
->is_symlink
) {
1052 /* Sorry, no race free way to getxattr on symlink. */
1057 sprintf(procname
, "/proc/self/fd/%i", inode
->fd
);
1060 value
= malloc(size
);
1065 ret
= getxattr(procname
, name
, value
, size
);
1074 fuse_reply_buf(req
, value
, ret
);
1076 ret
= getxattr(procname
, name
, NULL
, 0);
1081 fuse_reply_xattr(req
, ret
);
1090 fuse_reply_err(req
, saverr
);
1094 static void lo_listxattr(fuse_req_t req
, fuse_ino_t ino
, size_t size
)
1098 struct lo_inode
*inode
= lo_inode(req
, ino
);
1103 if (!lo_data(req
)->xattr
) {
1107 if (lo_debug(req
)) {
1108 fuse_log(FUSE_LOG_DEBUG
, "lo_listxattr(ino=%" PRIu64
", size=%zd)\n",
1112 if (inode
->is_symlink
) {
1113 /* Sorry, no race free way to listxattr on symlink. */
1118 sprintf(procname
, "/proc/self/fd/%i", inode
->fd
);
1121 value
= malloc(size
);
1126 ret
= listxattr(procname
, value
, size
);
1135 fuse_reply_buf(req
, value
, ret
);
1137 ret
= listxattr(procname
, NULL
, 0);
1142 fuse_reply_xattr(req
, ret
);
1151 fuse_reply_err(req
, saverr
);
1155 static void lo_setxattr(fuse_req_t req
, fuse_ino_t ino
, const char *name
,
1156 const char *value
, size_t size
, int flags
)
1159 struct lo_inode
*inode
= lo_inode(req
, ino
);
1164 if (!lo_data(req
)->xattr
) {
1168 if (lo_debug(req
)) {
1169 fuse_log(FUSE_LOG_DEBUG
,
1170 "lo_setxattr(ino=%" PRIu64
", name=%s value=%s size=%zd)\n",
1171 ino
, name
, value
, size
);
1174 if (inode
->is_symlink
) {
1175 /* Sorry, no race free way to setxattr on symlink. */
1180 sprintf(procname
, "/proc/self/fd/%i", inode
->fd
);
1182 ret
= setxattr(procname
, name
, value
, size
, flags
);
1183 saverr
= ret
== -1 ? errno
: 0;
1186 fuse_reply_err(req
, saverr
);
1189 static void lo_removexattr(fuse_req_t req
, fuse_ino_t ino
, const char *name
)
1192 struct lo_inode
*inode
= lo_inode(req
, ino
);
1197 if (!lo_data(req
)->xattr
) {
1201 if (lo_debug(req
)) {
1202 fuse_log(FUSE_LOG_DEBUG
, "lo_removexattr(ino=%" PRIu64
", name=%s)\n",
1206 if (inode
->is_symlink
) {
1207 /* Sorry, no race free way to setxattr on symlink. */
1212 sprintf(procname
, "/proc/self/fd/%i", inode
->fd
);
1214 ret
= removexattr(procname
, name
);
1215 saverr
= ret
== -1 ? errno
: 0;
1218 fuse_reply_err(req
, saverr
);
1221 #ifdef HAVE_COPY_FILE_RANGE
1222 static void lo_copy_file_range(fuse_req_t req
, fuse_ino_t ino_in
, off_t off_in
,
1223 struct fuse_file_info
*fi_in
, fuse_ino_t ino_out
,
1224 off_t off_out
, struct fuse_file_info
*fi_out
,
1225 size_t len
, int flags
)
1230 fuse_log(FUSE_LOG_DEBUG
,
1231 "lo_copy_file_range(ino=%" PRIu64
"/fd=%lu, "
1232 "off=%lu, ino=%" PRIu64
"/fd=%lu, "
1233 "off=%lu, size=%zd, flags=0x%x)\n",
1234 ino_in
, fi_in
->fh
, off_in
, ino_out
, fi_out
->fh
, off_out
, len
,
1237 res
= copy_file_range(fi_in
->fh
, &off_in
, fi_out
->fh
, &off_out
, len
, flags
);
1239 fuse_reply_err(req
, -errno
);
1241 fuse_reply_write(req
, res
);
1246 static void lo_lseek(fuse_req_t req
, fuse_ino_t ino
, off_t off
, int whence
,
1247 struct fuse_file_info
*fi
)
1252 res
= lseek(fi
->fh
, off
, whence
);
1254 fuse_reply_lseek(req
, res
);
1256 fuse_reply_err(req
, errno
);
1260 static struct fuse_lowlevel_ops lo_oper
= {
1262 .lookup
= lo_lookup
,
1265 .symlink
= lo_symlink
,
1267 .unlink
= lo_unlink
,
1269 .rename
= lo_rename
,
1270 .forget
= lo_forget
,
1271 .forget_multi
= lo_forget_multi
,
1272 .getattr
= lo_getattr
,
1273 .setattr
= lo_setattr
,
1274 .readlink
= lo_readlink
,
1275 .opendir
= lo_opendir
,
1276 .readdir
= lo_readdir
,
1277 .readdirplus
= lo_readdirplus
,
1278 .releasedir
= lo_releasedir
,
1279 .fsyncdir
= lo_fsyncdir
,
1280 .create
= lo_create
,
1282 .release
= lo_release
,
1286 .write_buf
= lo_write_buf
,
1287 .statfs
= lo_statfs
,
1288 .fallocate
= lo_fallocate
,
1290 .getxattr
= lo_getxattr
,
1291 .listxattr
= lo_listxattr
,
1292 .setxattr
= lo_setxattr
,
1293 .removexattr
= lo_removexattr
,
1294 #ifdef HAVE_COPY_FILE_RANGE
1295 .copy_file_range
= lo_copy_file_range
,
1300 int main(int argc
, char *argv
[])
1302 struct fuse_args args
= FUSE_ARGS_INIT(argc
, argv
);
1303 struct fuse_session
*se
;
1304 struct fuse_cmdline_opts opts
;
1305 struct lo_data lo
= { .debug
= 0, .writeback
= 0 };
1308 /* Don't mask creation mode, kernel already did that */
1311 pthread_mutex_init(&lo
.mutex
, NULL
);
1312 lo
.root
.next
= lo
.root
.prev
= &lo
.root
;
1314 lo
.cache
= CACHE_NORMAL
;
1316 if (fuse_parse_cmdline(&args
, &opts
) != 0) {
1319 if (opts
.show_help
) {
1320 printf("usage: %s [options]\n\n", argv
[0]);
1321 fuse_cmdline_help();
1322 printf(" -o source=PATH shared directory tree\n");
1323 fuse_lowlevel_help();
1326 } else if (opts
.show_version
) {
1327 fuse_lowlevel_version();
1332 if (fuse_opt_parse(&args
, &lo
, lo_opts
, NULL
) == -1) {
1336 lo
.debug
= opts
.debug
;
1337 lo
.root
.refcount
= 2;
1342 res
= lstat(lo
.source
, &stat
);
1344 fuse_log(FUSE_LOG_ERR
, "failed to stat source (\"%s\"): %m\n",
1348 if (!S_ISDIR(stat
.st_mode
)) {
1349 fuse_log(FUSE_LOG_ERR
, "source is not a directory\n");
1356 lo
.root
.is_symlink
= false;
1357 if (!lo
.timeout_set
) {
1368 lo
.timeout
= 86400.0;
1371 } else if (lo
.timeout
< 0) {
1372 fuse_log(FUSE_LOG_ERR
, "timeout is negative (%lf)\n", lo
.timeout
);
1376 lo
.root
.fd
= open(lo
.source
, O_PATH
);
1377 if (lo
.root
.fd
== -1) {
1378 fuse_log(FUSE_LOG_ERR
, "open(\"%s\", O_PATH): %m\n", lo
.source
);
1382 se
= fuse_session_new(&args
, &lo_oper
, sizeof(lo_oper
), &lo
);
1387 if (fuse_set_signal_handlers(se
) != 0) {
1391 if (fuse_session_mount(se
) != 0) {
1395 fuse_daemonize(opts
.foreground
);
1397 /* Block until ctrl+c or fusermount -u */
1398 if (opts
.singlethread
) {
1399 ret
= fuse_session_loop(se
);
1401 ret
= fuse_session_loop_mt(se
, opts
.clone_fd
);
1404 fuse_session_unmount(se
);
1406 fuse_remove_signal_handlers(se
);
1408 fuse_session_destroy(se
);
1410 fuse_opt_free_args(&args
);
1412 if (lo
.root
.fd
>= 0) {