1/*
2  FUSE: Filesystem in Userspace
3  Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
4
5  This program can be distributed under the terms of the GNU GPLv2.
6  See the file COPYING.
7*/
8
9/** @file
10 *
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
20 * more complicated.
21 *
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).
28 *
29 * Compile with:
30 *
31 *     gcc -Wall passthrough_ll.c `pkg-config fuse3 --cflags --libs` -o passthrough_ll
32 *
33 * ## Source code ##
34 * \include passthrough_ll.c
35 */
36
37#define _GNU_SOURCE
38#define FUSE_USE_VERSION 34
39
40#include <fuse_lowlevel.h>
41#include <unistd.h>
42#include <stdlib.h>
43#include <stdio.h>
44#include <stddef.h>
45#include <stdbool.h>
46#include <string.h>
47#include <limits.h>
48#include <dirent.h>
49#include <assert.h>
50#include <errno.h>
51#include <inttypes.h>
52#include <pthread.h>
53#include <sys/file.h>
54#include <sys/xattr.h>
55
56#include "passthrough_helpers.h"
57
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. */
62#if defined(__GNUC__) && (__GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ >= 6) && !defined __cplusplus
63_Static_assert(sizeof(fuse_ino_t) >= sizeof(uintptr_t),
64	       "fuse_ino_t too small to hold uintptr_t values!");
65#else
66struct _uintptr_to_must_hold_fuse_ino_t_dummy_struct \
67	{ unsigned _uintptr_to_must_hold_fuse_ino_t:
68			((sizeof(fuse_ino_t) >= sizeof(uintptr_t)) ? 1 : -1); };
69#endif
70
71struct lo_inode {
72	struct lo_inode *next; /* protected by lo->mutex */
73	struct lo_inode *prev; /* protected by lo->mutex */
74	int fd;
75	ino_t ino;
76	dev_t dev;
77	uint64_t refcount; /* protected by lo->mutex */
78};
79
80enum {
81	CACHE_NEVER,
82	CACHE_NORMAL,
83	CACHE_ALWAYS,
84};
85
86struct lo_data {
87	pthread_mutex_t mutex;
88	int debug;
89	int writeback;
90	int flock;
91	int xattr;
92	char *source;
93	double timeout;
94	int cache;
95	int timeout_set;
96	struct lo_inode root; /* protected by lo->mutex */
97};
98
99static const struct fuse_opt lo_opts[] = {
100	{ "writeback",
101	  offsetof(struct lo_data, writeback), 1 },
102	{ "no_writeback",
103	  offsetof(struct lo_data, writeback), 0 },
104	{ "source=%s",
105	  offsetof(struct lo_data, source), 0 },
106	{ "flock",
107	  offsetof(struct lo_data, flock), 1 },
108	{ "no_flock",
109	  offsetof(struct lo_data, flock), 0 },
110	{ "xattr",
111	  offsetof(struct lo_data, xattr), 1 },
112	{ "no_xattr",
113	  offsetof(struct lo_data, xattr), 0 },
114	{ "timeout=%lf",
115	  offsetof(struct lo_data, timeout), 0 },
116	{ "timeout=",
117	  offsetof(struct lo_data, timeout_set), 1 },
118	{ "cache=never",
119	  offsetof(struct lo_data, cache), CACHE_NEVER },
120	{ "cache=auto",
121	  offsetof(struct lo_data, cache), CACHE_NORMAL },
122	{ "cache=always",
123	  offsetof(struct lo_data, cache), CACHE_ALWAYS },
124
125	FUSE_OPT_END
126};
127
128static void passthrough_ll_help(void)
129{
130	printf(
131"    -o writeback           Enable writeback\n"
132"    -o no_writeback        Disable write back\n"
133"    -o source=/home/dir    Source directory to be mounted\n"
134"    -o flock               Enable flock\n"
135"    -o no_flock            Disable flock\n"
136"    -o xattr               Enable xattr\n"
137"    -o no_xattr            Disable xattr\n"
138"    -o timeout=1.0         Caching timeout\n"
139"    -o timeout=0/1         Timeout is set\n"
140"    -o cache=never         Disable cache\n"
141"    -o cache=auto          Auto enable cache\n"
142"    -o cache=always        Cache always\n");
143}
144
145static struct lo_data *lo_data(fuse_req_t req)
146{
147	return (struct lo_data *) fuse_req_userdata(req);
148}
149
150static struct lo_inode *lo_inode(fuse_req_t req, fuse_ino_t ino)
151{
152	if (ino == FUSE_ROOT_ID)
153		return &lo_data(req)->root;
154	else
155		return (struct lo_inode *) (uintptr_t) ino;
156}
157
158static int lo_fd(fuse_req_t req, fuse_ino_t ino)
159{
160	return lo_inode(req, ino)->fd;
161}
162
163static bool lo_debug(fuse_req_t req)
164{
165	return lo_data(req)->debug != 0;
166}
167
168static void lo_init(void *userdata,
169		    struct fuse_conn_info *conn)
170{
171	struct lo_data *lo = (struct lo_data*) userdata;
172
173	if(conn->capable & FUSE_CAP_EXPORT_SUPPORT)
174		conn->want |= FUSE_CAP_EXPORT_SUPPORT;
175
176	if (lo->writeback &&
177	    conn->capable & FUSE_CAP_WRITEBACK_CACHE) {
178		if (lo->debug)
179			fuse_log(FUSE_LOG_DEBUG, "lo_init: activating writeback\n");
180		conn->want |= FUSE_CAP_WRITEBACK_CACHE;
181	}
182	if (lo->flock && conn->capable & FUSE_CAP_FLOCK_LOCKS) {
183		if (lo->debug)
184			fuse_log(FUSE_LOG_DEBUG, "lo_init: activating flock locks\n");
185		conn->want |= FUSE_CAP_FLOCK_LOCKS;
186	}
187}
188
189static void lo_destroy(void *userdata)
190{
191	struct lo_data *lo = (struct lo_data*) userdata;
192
193	while (lo->root.next != &lo->root) {
194		struct lo_inode* next = lo->root.next;
195		lo->root.next = next->next;
196		free(next);
197	}
198}
199
200static void lo_getattr(fuse_req_t req, fuse_ino_t ino,
201			     struct fuse_file_info *fi)
202{
203	int res;
204	struct stat buf;
205	struct lo_data *lo = lo_data(req);
206
207	(void) fi;
208
209	res = fstatat(lo_fd(req, ino), "", &buf, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW);
210	if (res == -1)
211		return (void) fuse_reply_err(req, errno);
212
213	fuse_reply_attr(req, &buf, lo->timeout);
214}
215
216static void lo_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
217		       int valid, struct fuse_file_info *fi)
218{
219	int saverr;
220	char procname[64];
221	struct lo_inode *inode = lo_inode(req, ino);
222	int ifd = inode->fd;
223	int res;
224
225	if (valid & FUSE_SET_ATTR_MODE) {
226		if (fi) {
227			res = fchmod(fi->fh, attr->st_mode);
228		} else {
229			sprintf(procname, "/proc/self/fd/%i", ifd);
230			res = chmod(procname, attr->st_mode);
231		}
232		if (res == -1)
233			goto out_err;
234	}
235	if (valid & (FUSE_SET_ATTR_UID | FUSE_SET_ATTR_GID)) {
236		uid_t uid = (valid & FUSE_SET_ATTR_UID) ?
237			attr->st_uid : (uid_t) -1;
238		gid_t gid = (valid & FUSE_SET_ATTR_GID) ?
239			attr->st_gid : (gid_t) -1;
240
241		res = fchownat(ifd, "", uid, gid,
242			       AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW);
243		if (res == -1)
244			goto out_err;
245	}
246	if (valid & FUSE_SET_ATTR_SIZE) {
247		if (fi) {
248			res = ftruncate(fi->fh, attr->st_size);
249		} else {
250			sprintf(procname, "/proc/self/fd/%i", ifd);
251			res = truncate(procname, attr->st_size);
252		}
253		if (res == -1)
254			goto out_err;
255	}
256	if (valid & (FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME)) {
257		struct timespec tv[2];
258
259		tv[0].tv_sec = 0;
260		tv[1].tv_sec = 0;
261		tv[0].tv_nsec = UTIME_OMIT;
262		tv[1].tv_nsec = UTIME_OMIT;
263
264		if (valid & FUSE_SET_ATTR_ATIME_NOW)
265			tv[0].tv_nsec = UTIME_NOW;
266		else if (valid & FUSE_SET_ATTR_ATIME)
267			tv[0] = attr->st_atim;
268
269		if (valid & FUSE_SET_ATTR_MTIME_NOW)
270			tv[1].tv_nsec = UTIME_NOW;
271		else if (valid & FUSE_SET_ATTR_MTIME)
272			tv[1] = attr->st_mtim;
273
274		if (fi)
275			res = futimens(fi->fh, tv);
276		else {
277			sprintf(procname, "/proc/self/fd/%i", ifd);
278			res = utimensat(AT_FDCWD, procname, tv, 0);
279		}
280		if (res == -1)
281			goto out_err;
282	}
283
284	return lo_getattr(req, ino, fi);
285
286out_err:
287	saverr = errno;
288	fuse_reply_err(req, saverr);
289}
290
291static struct lo_inode *lo_find(struct lo_data *lo, struct stat *st)
292{
293	struct lo_inode *p;
294	struct lo_inode *ret = NULL;
295
296	pthread_mutex_lock(&lo->mutex);
297	for (p = lo->root.next; p != &lo->root; p = p->next) {
298		if (p->ino == st->st_ino && p->dev == st->st_dev) {
299			assert(p->refcount > 0);
300			ret = p;
301			ret->refcount++;
302			break;
303		}
304	}
305	pthread_mutex_unlock(&lo->mutex);
306	return ret;
307}
308
309static int lo_do_lookup(fuse_req_t req, fuse_ino_t parent, const char *name,
310			 struct fuse_entry_param *e)
311{
312	int newfd;
313	int res;
314	int saverr;
315	struct lo_data *lo = lo_data(req);
316	struct lo_inode *inode;
317
318	memset(e, 0, sizeof(*e));
319	e->attr_timeout = lo->timeout;
320	e->entry_timeout = lo->timeout;
321
322	newfd = openat(lo_fd(req, parent), name, O_PATH | O_NOFOLLOW);
323	if (newfd == -1)
324		goto out_err;
325
326	res = fstatat(newfd, "", &e->attr, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW);
327	if (res == -1)
328		goto out_err;
329
330	inode = lo_find(lo_data(req), &e->attr);
331	if (inode) {
332		close(newfd);
333		newfd = -1;
334	} else {
335		struct lo_inode *prev, *next;
336
337		saverr = ENOMEM;
338		inode = calloc(1, sizeof(struct lo_inode));
339		if (!inode)
340			goto out_err;
341
342		inode->refcount = 1;
343		inode->fd = newfd;
344		inode->ino = e->attr.st_ino;
345		inode->dev = e->attr.st_dev;
346
347		pthread_mutex_lock(&lo->mutex);
348		prev = &lo->root;
349		next = prev->next;
350		next->prev = inode;
351		inode->next = next;
352		inode->prev = prev;
353		prev->next = inode;
354		pthread_mutex_unlock(&lo->mutex);
355	}
356	e->ino = (uintptr_t) inode;
357
358	if (lo_debug(req))
359		fuse_log(FUSE_LOG_DEBUG, "  %lli/%s -> %lli\n",
360			(unsigned long long) parent, name, (unsigned long long) e->ino);
361
362	return 0;
363
364out_err:
365	saverr = errno;
366	if (newfd != -1)
367		close(newfd);
368	return saverr;
369}
370
371static void lo_lookup(fuse_req_t req, fuse_ino_t parent, const char *name)
372{
373	struct fuse_entry_param e;
374	int err;
375
376	if (lo_debug(req))
377		fuse_log(FUSE_LOG_DEBUG, "lo_lookup(parent=%" PRIu64 ", name=%s)\n",
378			parent, name);
379
380	err = lo_do_lookup(req, parent, name, &e);
381	if (err)
382		fuse_reply_err(req, err);
383	else
384		fuse_reply_entry(req, &e);
385}
386
387static void lo_mknod_symlink(fuse_req_t req, fuse_ino_t parent,
388			     const char *name, mode_t mode, dev_t rdev,
389			     const char *link)
390{
391	int res;
392	int saverr;
393	struct lo_inode *dir = lo_inode(req, parent);
394	struct fuse_entry_param e;
395
396	res = mknod_wrapper(dir->fd, name, link, mode, rdev);
397
398	saverr = errno;
399	if (res == -1)
400		goto out;
401
402	saverr = lo_do_lookup(req, parent, name, &e);
403	if (saverr)
404		goto out;
405
406	if (lo_debug(req))
407		fuse_log(FUSE_LOG_DEBUG, "  %lli/%s -> %lli\n",
408			(unsigned long long) parent, name, (unsigned long long) e.ino);
409
410	fuse_reply_entry(req, &e);
411	return;
412
413out:
414	fuse_reply_err(req, saverr);
415}
416
417static void lo_mknod(fuse_req_t req, fuse_ino_t parent,
418		     const char *name, mode_t mode, dev_t rdev)
419{
420	lo_mknod_symlink(req, parent, name, mode, rdev, NULL);
421}
422
423static void lo_mkdir(fuse_req_t req, fuse_ino_t parent, const char *name,
424		     mode_t mode)
425{
426	lo_mknod_symlink(req, parent, name, S_IFDIR | mode, 0, NULL);
427}
428
429static void lo_symlink(fuse_req_t req, const char *link,
430		       fuse_ino_t parent, const char *name)
431{
432	lo_mknod_symlink(req, parent, name, S_IFLNK, 0, link);
433}
434
435static void lo_link(fuse_req_t req, fuse_ino_t ino, fuse_ino_t parent,
436		    const char *name)
437{
438	int res;
439	struct lo_data *lo = lo_data(req);
440	struct lo_inode *inode = lo_inode(req, ino);
441	struct fuse_entry_param e;
442	char procname[64];
443	int saverr;
444
445	memset(&e, 0, sizeof(struct fuse_entry_param));
446	e.attr_timeout = lo->timeout;
447	e.entry_timeout = lo->timeout;
448
449	sprintf(procname, "/proc/self/fd/%i", inode->fd);
450	res = linkat(AT_FDCWD, procname, lo_fd(req, parent), name,
451		     AT_SYMLINK_FOLLOW);
452	if (res == -1)
453		goto out_err;
454
455	res = fstatat(inode->fd, "", &e.attr, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW);
456	if (res == -1)
457		goto out_err;
458
459	pthread_mutex_lock(&lo->mutex);
460	inode->refcount++;
461	pthread_mutex_unlock(&lo->mutex);
462	e.ino = (uintptr_t) inode;
463
464	if (lo_debug(req))
465		fuse_log(FUSE_LOG_DEBUG, "  %lli/%s -> %lli\n",
466			(unsigned long long) parent, name,
467			(unsigned long long) e.ino);
468
469	fuse_reply_entry(req, &e);
470	return;
471
472out_err:
473	saverr = errno;
474	fuse_reply_err(req, saverr);
475}
476
477static void lo_rmdir(fuse_req_t req, fuse_ino_t parent, const char *name)
478{
479	int res;
480
481	res = unlinkat(lo_fd(req, parent), name, AT_REMOVEDIR);
482
483	fuse_reply_err(req, res == -1 ? errno : 0);
484}
485
486static void lo_rename(fuse_req_t req, fuse_ino_t parent, const char *name,
487		      fuse_ino_t newparent, const char *newname,
488		      unsigned int flags)
489{
490	int res;
491
492	if (flags) {
493		fuse_reply_err(req, EINVAL);
494		return;
495	}
496
497	res = renameat(lo_fd(req, parent), name,
498			lo_fd(req, newparent), newname);
499
500	fuse_reply_err(req, res == -1 ? errno : 0);
501}
502
503static void lo_unlink(fuse_req_t req, fuse_ino_t parent, const char *name)
504{
505	int res;
506
507	res = unlinkat(lo_fd(req, parent), name, 0);
508
509	fuse_reply_err(req, res == -1 ? errno : 0);
510}
511
512static void unref_inode(struct lo_data *lo, struct lo_inode *inode, uint64_t n)
513{
514	if (!inode)
515		return;
516
517	pthread_mutex_lock(&lo->mutex);
518	assert(inode->refcount >= n);
519	inode->refcount -= n;
520	if (!inode->refcount) {
521		struct lo_inode *prev, *next;
522
523		prev = inode->prev;
524		next = inode->next;
525		next->prev = prev;
526		prev->next = next;
527
528		pthread_mutex_unlock(&lo->mutex);
529		close(inode->fd);
530		free(inode);
531
532	} else {
533		pthread_mutex_unlock(&lo->mutex);
534	}
535}
536
537static void lo_forget_one(fuse_req_t req, fuse_ino_t ino, uint64_t nlookup)
538{
539	struct lo_data *lo = lo_data(req);
540	struct lo_inode *inode = lo_inode(req, ino);
541
542	if (lo_debug(req)) {
543		fuse_log(FUSE_LOG_DEBUG, "  forget %lli %lli -%lli\n",
544			(unsigned long long) ino,
545			(unsigned long long) inode->refcount,
546			(unsigned long long) nlookup);
547	}
548
549	unref_inode(lo, inode, nlookup);
550}
551
552static void lo_forget(fuse_req_t req, fuse_ino_t ino, uint64_t nlookup)
553{
554	lo_forget_one(req, ino, nlookup);
555	fuse_reply_none(req);
556}
557
558static void lo_forget_multi(fuse_req_t req, size_t count,
559				struct fuse_forget_data *forgets)
560{
561	int i;
562
563	for (i = 0; i < count; i++)
564		lo_forget_one(req, forgets[i].ino, forgets[i].nlookup);
565	fuse_reply_none(req);
566}
567
568static void lo_readlink(fuse_req_t req, fuse_ino_t ino)
569{
570	char buf[PATH_MAX + 1];
571	int res;
572
573	res = readlinkat(lo_fd(req, ino), "", buf, sizeof(buf));
574	if (res == -1)
575		return (void) fuse_reply_err(req, errno);
576
577	if (res == sizeof(buf))
578		return (void) fuse_reply_err(req, ENAMETOOLONG);
579
580	buf[res] = '\0';
581
582	fuse_reply_readlink(req, buf);
583}
584
585struct lo_dirp {
586	DIR *dp;
587	struct dirent *entry;
588	off_t offset;
589};
590
591static struct lo_dirp *lo_dirp(struct fuse_file_info *fi)
592{
593	return (struct lo_dirp *) (uintptr_t) fi->fh;
594}
595
596static void lo_opendir(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
597{
598	int error = ENOMEM;
599	struct lo_data *lo = lo_data(req);
600	struct lo_dirp *d;
601	int fd;
602
603	d = calloc(1, sizeof(struct lo_dirp));
604	if (d == NULL)
605		goto out_err;
606
607	fd = openat(lo_fd(req, ino), ".", O_RDONLY);
608	if (fd == -1)
609		goto out_errno;
610
611	d->dp = fdopendir(fd);
612	if (d->dp == NULL)
613		goto out_errno;
614
615	d->offset = 0;
616	d->entry = NULL;
617
618	fi->fh = (uintptr_t) d;
619	if (lo->cache == CACHE_ALWAYS)
620		fi->cache_readdir = 1;
621	fuse_reply_open(req, fi);
622	return;
623
624out_errno:
625	error = errno;
626out_err:
627	if (d) {
628		if (fd != -1)
629			close(fd);
630		free(d);
631	}
632	fuse_reply_err(req, error);
633}
634
635static int is_dot_or_dotdot(const char *name)
636{
637	return name[0] == '.' && (name[1] == '\0' ||
638				  (name[1] == '.' && name[2] == '\0'));
639}
640
641static void lo_do_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
642			  off_t offset, struct fuse_file_info *fi, int plus)
643{
644	struct lo_dirp *d = lo_dirp(fi);
645	char *buf;
646	char *p;
647	size_t rem = size;
648	int err;
649
650	(void) ino;
651
652	buf = calloc(1, size);
653	if (!buf) {
654		err = ENOMEM;
655		goto error;
656	}
657	p = buf;
658
659	if (offset != d->offset) {
660		seekdir(d->dp, offset);
661		d->entry = NULL;
662		d->offset = offset;
663	}
664	while (1) {
665		size_t entsize;
666		off_t nextoff;
667		const char *name;
668
669		if (!d->entry) {
670			errno = 0;
671			d->entry = readdir(d->dp);
672			if (!d->entry) {
673				if (errno) {  // Error
674					err = errno;
675					goto error;
676				} else {  // End of stream
677					break;
678				}
679			}
680		}
681		nextoff = d->entry->d_off;
682		name = d->entry->d_name;
683		fuse_ino_t entry_ino = 0;
684		if (plus) {
685			struct fuse_entry_param e;
686			if (is_dot_or_dotdot(name)) {
687				e = (struct fuse_entry_param) {
688					.attr.st_ino = d->entry->d_ino,
689					.attr.st_mode = d->entry->d_type << 12,
690				};
691			} else {
692				err = lo_do_lookup(req, ino, name, &e);
693				if (err)
694					goto error;
695				entry_ino = e.ino;
696			}
697
698			entsize = fuse_add_direntry_plus(req, p, rem, name,
699							 &e, nextoff);
700		} else {
701			struct stat st = {
702				.st_ino = d->entry->d_ino,
703				.st_mode = d->entry->d_type << 12,
704			};
705			entsize = fuse_add_direntry(req, p, rem, name,
706						    &st, nextoff);
707		}
708		if (entsize > rem) {
709			if (entry_ino != 0)
710				lo_forget_one(req, entry_ino, 1);
711			break;
712		}
713
714		p += entsize;
715		rem -= entsize;
716
717		d->entry = NULL;
718		d->offset = nextoff;
719	}
720
721    err = 0;
722error:
723    // If there's an error, we can only signal it if we haven't stored
724    // any entries yet - otherwise we'd end up with wrong lookup
725    // counts for the entries that are already in the buffer. So we
726    // return what we've collected until that point.
727    if (err && rem == size)
728	    fuse_reply_err(req, err);
729    else
730	    fuse_reply_buf(req, buf, size - rem);
731    free(buf);
732}
733
734static void lo_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
735		       off_t offset, struct fuse_file_info *fi)
736{
737	lo_do_readdir(req, ino, size, offset, fi, 0);
738}
739
740static void lo_readdirplus(fuse_req_t req, fuse_ino_t ino, size_t size,
741			   off_t offset, struct fuse_file_info *fi)
742{
743	lo_do_readdir(req, ino, size, offset, fi, 1);
744}
745
746static void lo_releasedir(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
747{
748	struct lo_dirp *d = lo_dirp(fi);
749	(void) ino;
750	closedir(d->dp);
751	free(d);
752	fuse_reply_err(req, 0);
753}
754
755static void lo_create(fuse_req_t req, fuse_ino_t parent, const char *name,
756		      mode_t mode, struct fuse_file_info *fi)
757{
758	int fd;
759	struct lo_data *lo = lo_data(req);
760	struct fuse_entry_param e;
761	int err;
762
763	if (lo_debug(req))
764		fuse_log(FUSE_LOG_DEBUG, "lo_create(parent=%" PRIu64 ", name=%s)\n",
765			parent, name);
766
767	fd = openat(lo_fd(req, parent), name,
768		    (fi->flags | O_CREAT) & ~O_NOFOLLOW, mode);
769	if (fd == -1)
770		return (void) fuse_reply_err(req, errno);
771
772	fi->fh = fd;
773	if (lo->cache == CACHE_NEVER)
774		fi->direct_io = 1;
775	else if (lo->cache == CACHE_ALWAYS)
776		fi->keep_cache = 1;
777
778	err = lo_do_lookup(req, parent, name, &e);
779	if (err)
780		fuse_reply_err(req, err);
781	else
782		fuse_reply_create(req, &e, fi);
783}
784
785static void lo_fsyncdir(fuse_req_t req, fuse_ino_t ino, int datasync,
786			struct fuse_file_info *fi)
787{
788	int res;
789	int fd = dirfd(lo_dirp(fi)->dp);
790	(void) ino;
791	if (datasync)
792		res = fdatasync(fd);
793	else
794		res = fsync(fd);
795	fuse_reply_err(req, res == -1 ? errno : 0);
796}
797
798static void lo_open(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
799{
800	int fd;
801	char buf[64];
802	struct lo_data *lo = lo_data(req);
803
804	if (lo_debug(req))
805		fuse_log(FUSE_LOG_DEBUG, "lo_open(ino=%" PRIu64 ", flags=%d)\n",
806			ino, fi->flags);
807
808	/* With writeback cache, kernel may send read requests even
809	   when userspace opened write-only */
810	if (lo->writeback && (fi->flags & O_ACCMODE) == O_WRONLY) {
811		fi->flags &= ~O_ACCMODE;
812		fi->flags |= O_RDWR;
813	}
814
815	/* With writeback cache, O_APPEND is handled by the kernel.
816	   This breaks atomicity (since the file may change in the
817	   underlying filesystem, so that the kernel's idea of the
818	   end of the file isn't accurate anymore). In this example,
819	   we just accept that. A more rigorous filesystem may want
820	   to return an error here */
821	if (lo->writeback && (fi->flags & O_APPEND))
822		fi->flags &= ~O_APPEND;
823
824	sprintf(buf, "/proc/self/fd/%i", lo_fd(req, ino));
825	fd = open(buf, fi->flags & ~O_NOFOLLOW);
826	if (fd == -1)
827		return (void) fuse_reply_err(req, errno);
828
829	fi->fh = fd;
830	if (lo->cache == CACHE_NEVER)
831		fi->direct_io = 1;
832	else if (lo->cache == CACHE_ALWAYS)
833		fi->keep_cache = 1;
834	fuse_reply_open(req, fi);
835}
836
837static void lo_release(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
838{
839	(void) ino;
840
841	close(fi->fh);
842	fuse_reply_err(req, 0);
843}
844
845static void lo_flush(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
846{
847	int res;
848	(void) ino;
849	res = close(dup(fi->fh));
850	fuse_reply_err(req, res == -1 ? errno : 0);
851}
852
853static void lo_fsync(fuse_req_t req, fuse_ino_t ino, int datasync,
854		     struct fuse_file_info *fi)
855{
856	int res;
857	(void) ino;
858	if (datasync)
859		res = fdatasync(fi->fh);
860	else
861		res = fsync(fi->fh);
862	fuse_reply_err(req, res == -1 ? errno : 0);
863}
864
865static void lo_read(fuse_req_t req, fuse_ino_t ino, size_t size,
866		    off_t offset, struct fuse_file_info *fi)
867{
868	struct fuse_bufvec buf = FUSE_BUFVEC_INIT(size);
869
870	if (lo_debug(req))
871		fuse_log(FUSE_LOG_DEBUG, "lo_read(ino=%" PRIu64 ", size=%zd, "
872			"off=%lu)\n", ino, size, (unsigned long) offset);
873
874	buf.buf[0].flags = FUSE_BUF_IS_FD | FUSE_BUF_FD_SEEK;
875	buf.buf[0].fd = fi->fh;
876	buf.buf[0].pos = offset;
877
878	fuse_reply_data(req, &buf, FUSE_BUF_SPLICE_MOVE);
879}
880
881static void lo_write_buf(fuse_req_t req, fuse_ino_t ino,
882			 struct fuse_bufvec *in_buf, off_t off,
883			 struct fuse_file_info *fi)
884{
885	(void) ino;
886	ssize_t res;
887	struct fuse_bufvec out_buf = FUSE_BUFVEC_INIT(fuse_buf_size(in_buf));
888
889	out_buf.buf[0].flags = FUSE_BUF_IS_FD | FUSE_BUF_FD_SEEK;
890	out_buf.buf[0].fd = fi->fh;
891	out_buf.buf[0].pos = off;
892
893	if (lo_debug(req))
894		fuse_log(FUSE_LOG_DEBUG, "lo_write(ino=%" PRIu64 ", size=%zd, off=%lu)\n",
895			ino, out_buf.buf[0].size, (unsigned long) off);
896
897	res = fuse_buf_copy(&out_buf, in_buf, 0);
898	if(res < 0)
899		fuse_reply_err(req, -res);
900	else
901		fuse_reply_write(req, (size_t) res);
902}
903
904static void lo_statfs(fuse_req_t req, fuse_ino_t ino)
905{
906	int res;
907	struct statvfs stbuf;
908
909	res = fstatvfs(lo_fd(req, ino), &stbuf);
910	if (res == -1)
911		fuse_reply_err(req, errno);
912	else
913		fuse_reply_statfs(req, &stbuf);
914}
915
916static void lo_fallocate(fuse_req_t req, fuse_ino_t ino, int mode,
917			 off_t offset, off_t length, struct fuse_file_info *fi)
918{
919	int err = EOPNOTSUPP;
920	(void) ino;
921
922#ifdef HAVE_FALLOCATE
923	err = fallocate(fi->fh, mode, offset, length);
924	if (err < 0)
925		err = errno;
926
927#elif defined(HAVE_POSIX_FALLOCATE)
928	if (mode) {
929		fuse_reply_err(req, EOPNOTSUPP);
930		return;
931	}
932
933	err = posix_fallocate(fi->fh, offset, length);
934#endif
935
936	fuse_reply_err(req, err);
937}
938
939static void lo_flock(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi,
940		     int op)
941{
942	int res;
943	(void) ino;
944
945	res = flock(fi->fh, op);
946
947	fuse_reply_err(req, res == -1 ? errno : 0);
948}
949
950static void lo_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
951			size_t size)
952{
953	char *value = NULL;
954	char procname[64];
955	struct lo_inode *inode = lo_inode(req, ino);
956	ssize_t ret;
957	int saverr;
958
959	saverr = ENOSYS;
960	if (!lo_data(req)->xattr)
961		goto out;
962
963	if (lo_debug(req)) {
964		fuse_log(FUSE_LOG_DEBUG, "lo_getxattr(ino=%" PRIu64 ", name=%s size=%zd)\n",
965			ino, name, size);
966	}
967
968	sprintf(procname, "/proc/self/fd/%i", inode->fd);
969
970	if (size) {
971		value = malloc(size);
972		if (!value)
973			goto out_err;
974
975		ret = getxattr(procname, name, value, size);
976		if (ret == -1)
977			goto out_err;
978		saverr = 0;
979		if (ret == 0)
980			goto out;
981
982		fuse_reply_buf(req, value, ret);
983	} else {
984		ret = getxattr(procname, name, NULL, 0);
985		if (ret == -1)
986			goto out_err;
987
988		fuse_reply_xattr(req, ret);
989	}
990out_free:
991	free(value);
992	return;
993
994out_err:
995	saverr = errno;
996out:
997	fuse_reply_err(req, saverr);
998	goto out_free;
999}
1000
1001static void lo_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size)
1002{
1003	char *value = NULL;
1004	char procname[64];
1005	struct lo_inode *inode = lo_inode(req, ino);
1006	ssize_t ret;
1007	int saverr;
1008
1009	saverr = ENOSYS;
1010	if (!lo_data(req)->xattr)
1011		goto out;
1012
1013	if (lo_debug(req)) {
1014		fuse_log(FUSE_LOG_DEBUG, "lo_listxattr(ino=%" PRIu64 ", size=%zd)\n",
1015			ino, size);
1016	}
1017
1018	sprintf(procname, "/proc/self/fd/%i", inode->fd);
1019
1020	if (size) {
1021		value = malloc(size);
1022		if (!value)
1023			goto out_err;
1024
1025		ret = listxattr(procname, value, size);
1026		if (ret == -1)
1027			goto out_err;
1028		saverr = 0;
1029		if (ret == 0)
1030			goto out;
1031
1032		fuse_reply_buf(req, value, ret);
1033	} else {
1034		ret = listxattr(procname, NULL, 0);
1035		if (ret == -1)
1036			goto out_err;
1037
1038		fuse_reply_xattr(req, ret);
1039	}
1040out_free:
1041	free(value);
1042	return;
1043
1044out_err:
1045	saverr = errno;
1046out:
1047	fuse_reply_err(req, saverr);
1048	goto out_free;
1049}
1050
1051static void lo_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
1052			const char *value, size_t size, int flags)
1053{
1054	char procname[64];
1055	struct lo_inode *inode = lo_inode(req, ino);
1056	ssize_t ret;
1057	int saverr;
1058
1059	saverr = ENOSYS;
1060	if (!lo_data(req)->xattr)
1061		goto out;
1062
1063	if (lo_debug(req)) {
1064		fuse_log(FUSE_LOG_DEBUG, "lo_setxattr(ino=%" PRIu64 ", name=%s value=%s size=%zd)\n",
1065			ino, name, value, size);
1066	}
1067
1068	sprintf(procname, "/proc/self/fd/%i", inode->fd);
1069
1070	ret = setxattr(procname, name, value, size, flags);
1071	saverr = ret == -1 ? errno : 0;
1072
1073out:
1074	fuse_reply_err(req, saverr);
1075}
1076
1077static void lo_removexattr(fuse_req_t req, fuse_ino_t ino, const char *name)
1078{
1079	char procname[64];
1080	struct lo_inode *inode = lo_inode(req, ino);
1081	ssize_t ret;
1082	int saverr;
1083
1084	saverr = ENOSYS;
1085	if (!lo_data(req)->xattr)
1086		goto out;
1087
1088	if (lo_debug(req)) {
1089		fuse_log(FUSE_LOG_DEBUG, "lo_removexattr(ino=%" PRIu64 ", name=%s)\n",
1090			ino, name);
1091	}
1092
1093	sprintf(procname, "/proc/self/fd/%i", inode->fd);
1094
1095	ret = removexattr(procname, name);
1096	saverr = ret == -1 ? errno : 0;
1097
1098out:
1099	fuse_reply_err(req, saverr);
1100}
1101
1102#ifdef HAVE_COPY_FILE_RANGE
1103static void lo_copy_file_range(fuse_req_t req, fuse_ino_t ino_in, off_t off_in,
1104			       struct fuse_file_info *fi_in,
1105			       fuse_ino_t ino_out, off_t off_out,
1106			       struct fuse_file_info *fi_out, size_t len,
1107			       int flags)
1108{
1109	ssize_t res;
1110
1111	if (lo_debug(req))
1112		fuse_log(FUSE_LOG_DEBUG, "lo_copy_file_range(ino=%" PRIu64 "/fd=%lu, "
1113				"off=%lu, ino=%" PRIu64 "/fd=%lu, "
1114				"off=%lu, size=%zd, flags=0x%x)\n",
1115			ino_in, fi_in->fh, off_in, ino_out, fi_out->fh, off_out,
1116			len, flags);
1117
1118	res = copy_file_range(fi_in->fh, &off_in, fi_out->fh, &off_out, len,
1119			      flags);
1120	if (res < 0)
1121		fuse_reply_err(req, errno);
1122	else
1123		fuse_reply_write(req, res);
1124}
1125#endif
1126
1127static void lo_lseek(fuse_req_t req, fuse_ino_t ino, off_t off, int whence,
1128		     struct fuse_file_info *fi)
1129{
1130	off_t res;
1131
1132	(void)ino;
1133	res = lseek(fi->fh, off, whence);
1134	if (res != -1)
1135		fuse_reply_lseek(req, res);
1136	else
1137		fuse_reply_err(req, errno);
1138}
1139
1140static const struct fuse_lowlevel_ops lo_oper = {
1141	.init		= lo_init,
1142	.destroy	= lo_destroy,
1143	.lookup		= lo_lookup,
1144	.mkdir		= lo_mkdir,
1145	.mknod		= lo_mknod,
1146	.symlink	= lo_symlink,
1147	.link		= lo_link,
1148	.unlink		= lo_unlink,
1149	.rmdir		= lo_rmdir,
1150	.rename		= lo_rename,
1151	.forget		= lo_forget,
1152	.forget_multi	= lo_forget_multi,
1153	.getattr	= lo_getattr,
1154	.setattr	= lo_setattr,
1155	.readlink	= lo_readlink,
1156	.opendir	= lo_opendir,
1157	.readdir	= lo_readdir,
1158	.readdirplus	= lo_readdirplus,
1159	.releasedir	= lo_releasedir,
1160	.fsyncdir	= lo_fsyncdir,
1161	.create		= lo_create,
1162	.open		= lo_open,
1163	.release	= lo_release,
1164	.flush		= lo_flush,
1165	.fsync		= lo_fsync,
1166	.read		= lo_read,
1167	.write_buf      = lo_write_buf,
1168	.statfs		= lo_statfs,
1169	.fallocate	= lo_fallocate,
1170	.flock		= lo_flock,
1171	.getxattr	= lo_getxattr,
1172	.listxattr	= lo_listxattr,
1173	.setxattr	= lo_setxattr,
1174	.removexattr	= lo_removexattr,
1175#ifdef HAVE_COPY_FILE_RANGE
1176	.copy_file_range = lo_copy_file_range,
1177#endif
1178	.lseek		= lo_lseek,
1179};
1180
1181int main(int argc, char *argv[])
1182{
1183	struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
1184	struct fuse_session *se;
1185	struct fuse_cmdline_opts opts;
1186	struct fuse_loop_config config;
1187	struct lo_data lo = { .debug = 0,
1188	                      .writeback = 0 };
1189	int ret = -1;
1190
1191	/* Don't mask creation mode, kernel already did that */
1192	umask(0);
1193
1194	pthread_mutex_init(&lo.mutex, NULL);
1195	lo.root.next = lo.root.prev = &lo.root;
1196	lo.root.fd = -1;
1197	lo.cache = CACHE_NORMAL;
1198
1199	if (fuse_parse_cmdline(&args, &opts) != 0)
1200		return 1;
1201	if (opts.show_help) {
1202		printf("usage: %s [options] <mountpoint>\n\n", argv[0]);
1203		fuse_cmdline_help();
1204		fuse_lowlevel_help();
1205		passthrough_ll_help();
1206		ret = 0;
1207		goto err_out1;
1208	} else if (opts.show_version) {
1209		printf("FUSE library version %s\n", fuse_pkgversion());
1210		fuse_lowlevel_version();
1211		ret = 0;
1212		goto err_out1;
1213	}
1214
1215	if(opts.mountpoint == NULL) {
1216		printf("usage: %s [options] <mountpoint>\n", argv[0]);
1217		printf("       %s --help\n", argv[0]);
1218		ret = 1;
1219		goto err_out1;
1220	}
1221
1222	if (fuse_opt_parse(&args, &lo, lo_opts, NULL)== -1)
1223		return 1;
1224
1225	lo.debug = opts.debug;
1226	lo.root.refcount = 2;
1227	if (lo.source) {
1228		struct stat stat;
1229		int res;
1230
1231		res = lstat(lo.source, &stat);
1232		if (res == -1) {
1233			fuse_log(FUSE_LOG_ERR, "failed to stat source (\"%s\"): %m\n",
1234				 lo.source);
1235			exit(1);
1236		}
1237		if (!S_ISDIR(stat.st_mode)) {
1238			fuse_log(FUSE_LOG_ERR, "source is not a directory\n");
1239			exit(1);
1240		}
1241
1242	} else {
1243		lo.source = strdup("/");
1244		if(!lo.source) {
1245			fuse_log(FUSE_LOG_ERR, "fuse: memory allocation failed\n");
1246			exit(1);
1247		}
1248	}
1249	if (!lo.timeout_set) {
1250		switch (lo.cache) {
1251		case CACHE_NEVER:
1252			lo.timeout = 0.0;
1253			break;
1254
1255		case CACHE_NORMAL:
1256			lo.timeout = 1.0;
1257			break;
1258
1259		case CACHE_ALWAYS:
1260			lo.timeout = 86400.0;
1261			break;
1262		}
1263	} else if (lo.timeout < 0) {
1264		fuse_log(FUSE_LOG_ERR, "timeout is negative (%lf)\n",
1265			 lo.timeout);
1266		exit(1);
1267	}
1268
1269	lo.root.fd = open(lo.source, O_PATH);
1270	if (lo.root.fd == -1) {
1271		fuse_log(FUSE_LOG_ERR, "open(\"%s\", O_PATH): %m\n",
1272			 lo.source);
1273		exit(1);
1274	}
1275
1276	se = fuse_session_new(&args, &lo_oper, sizeof(lo_oper), &lo);
1277	if (se == NULL)
1278	    goto err_out1;
1279
1280	if (fuse_set_signal_handlers(se) != 0)
1281	    goto err_out2;
1282
1283	if (fuse_session_mount(se, opts.mountpoint) != 0)
1284	    goto err_out3;
1285
1286	fuse_daemonize(opts.foreground);
1287
1288	/* Block until ctrl+c or fusermount -u */
1289	if (opts.singlethread)
1290		ret = fuse_session_loop(se);
1291	else {
1292		config.clone_fd = opts.clone_fd;
1293		config.max_idle_threads = opts.max_idle_threads;
1294		ret = fuse_session_loop_mt(se, &config);
1295	}
1296
1297	fuse_session_unmount(se);
1298err_out3:
1299	fuse_remove_signal_handlers(se);
1300err_out2:
1301	fuse_session_destroy(se);
1302err_out1:
1303	free(opts.mountpoint);
1304	fuse_opt_free_args(&args);
1305
1306	if (lo.root.fd >= 0)
1307		close(lo.root.fd);
1308
1309	free(lo.source);
1310	return ret ? 1 : 0;
1311}
1312