16881f68fSopenharmony_ci/*
26881f68fSopenharmony_ci  FUSE: Filesystem in Userspace
36881f68fSopenharmony_ci  Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
46881f68fSopenharmony_ci
56881f68fSopenharmony_ci  This program can be distributed under the terms of the GNU GPLv2.
66881f68fSopenharmony_ci  See the file COPYING.
76881f68fSopenharmony_ci*/
86881f68fSopenharmony_ci
96881f68fSopenharmony_ci/** @file
106881f68fSopenharmony_ci *
116881f68fSopenharmony_ci * This file system mirrors the existing file system hierarchy of the
126881f68fSopenharmony_ci * system, starting at the root file system. This is implemented by
136881f68fSopenharmony_ci * just "passing through" all requests to the corresponding user-space
146881f68fSopenharmony_ci * libc functions. In contrast to passthrough.c and passthrough_fh.c,
156881f68fSopenharmony_ci * this implementation uses the low-level API. Its performance should
166881f68fSopenharmony_ci * be the least bad among the three, but many operations are not
176881f68fSopenharmony_ci * implemented. In particular, it is not possible to remove files (or
186881f68fSopenharmony_ci * directories) because the code necessary to defer actual removal
196881f68fSopenharmony_ci * until the file is not opened anymore would make the example much
206881f68fSopenharmony_ci * more complicated.
216881f68fSopenharmony_ci *
226881f68fSopenharmony_ci * When writeback caching is enabled (-o writeback mount option), it
236881f68fSopenharmony_ci * is only possible to write to files for which the mounting user has
246881f68fSopenharmony_ci * read permissions. This is because the writeback cache requires the
256881f68fSopenharmony_ci * kernel to be able to issue read requests for all files (which the
266881f68fSopenharmony_ci * passthrough filesystem cannot satisfy if it can't read the file in
276881f68fSopenharmony_ci * the underlying filesystem).
286881f68fSopenharmony_ci *
296881f68fSopenharmony_ci * Compile with:
306881f68fSopenharmony_ci *
316881f68fSopenharmony_ci *     gcc -Wall passthrough_ll.c `pkg-config fuse3 --cflags --libs` -o passthrough_ll
326881f68fSopenharmony_ci *
336881f68fSopenharmony_ci * ## Source code ##
346881f68fSopenharmony_ci * \include passthrough_ll.c
356881f68fSopenharmony_ci */
366881f68fSopenharmony_ci
376881f68fSopenharmony_ci#define _GNU_SOURCE
386881f68fSopenharmony_ci#define FUSE_USE_VERSION 34
396881f68fSopenharmony_ci
406881f68fSopenharmony_ci#include <fuse_lowlevel.h>
416881f68fSopenharmony_ci#include <unistd.h>
426881f68fSopenharmony_ci#include <stdlib.h>
436881f68fSopenharmony_ci#include <stdio.h>
446881f68fSopenharmony_ci#include <stddef.h>
456881f68fSopenharmony_ci#include <stdbool.h>
466881f68fSopenharmony_ci#include <string.h>
476881f68fSopenharmony_ci#include <limits.h>
486881f68fSopenharmony_ci#include <dirent.h>
496881f68fSopenharmony_ci#include <assert.h>
506881f68fSopenharmony_ci#include <errno.h>
516881f68fSopenharmony_ci#include <inttypes.h>
526881f68fSopenharmony_ci#include <pthread.h>
536881f68fSopenharmony_ci#include <sys/file.h>
546881f68fSopenharmony_ci#include <sys/xattr.h>
556881f68fSopenharmony_ci
566881f68fSopenharmony_ci#include "passthrough_helpers.h"
576881f68fSopenharmony_ci
586881f68fSopenharmony_ci/* We are re-using pointers to our `struct lo_inode` and `struct
596881f68fSopenharmony_ci   lo_dirp` elements as inodes. This means that we must be able to
606881f68fSopenharmony_ci   store uintptr_t values in a fuse_ino_t variable. The following
616881f68fSopenharmony_ci   incantation checks this condition at compile time. */
626881f68fSopenharmony_ci#if defined(__GNUC__) && (__GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ >= 6) && !defined __cplusplus
636881f68fSopenharmony_ci_Static_assert(sizeof(fuse_ino_t) >= sizeof(uintptr_t),
646881f68fSopenharmony_ci	       "fuse_ino_t too small to hold uintptr_t values!");
656881f68fSopenharmony_ci#else
666881f68fSopenharmony_cistruct _uintptr_to_must_hold_fuse_ino_t_dummy_struct \
676881f68fSopenharmony_ci	{ unsigned _uintptr_to_must_hold_fuse_ino_t:
686881f68fSopenharmony_ci			((sizeof(fuse_ino_t) >= sizeof(uintptr_t)) ? 1 : -1); };
696881f68fSopenharmony_ci#endif
706881f68fSopenharmony_ci
716881f68fSopenharmony_cistruct lo_inode {
726881f68fSopenharmony_ci	struct lo_inode *next; /* protected by lo->mutex */
736881f68fSopenharmony_ci	struct lo_inode *prev; /* protected by lo->mutex */
746881f68fSopenharmony_ci	int fd;
756881f68fSopenharmony_ci	ino_t ino;
766881f68fSopenharmony_ci	dev_t dev;
776881f68fSopenharmony_ci	uint64_t refcount; /* protected by lo->mutex */
786881f68fSopenharmony_ci};
796881f68fSopenharmony_ci
806881f68fSopenharmony_cienum {
816881f68fSopenharmony_ci	CACHE_NEVER,
826881f68fSopenharmony_ci	CACHE_NORMAL,
836881f68fSopenharmony_ci	CACHE_ALWAYS,
846881f68fSopenharmony_ci};
856881f68fSopenharmony_ci
866881f68fSopenharmony_cistruct lo_data {
876881f68fSopenharmony_ci	pthread_mutex_t mutex;
886881f68fSopenharmony_ci	int debug;
896881f68fSopenharmony_ci	int writeback;
906881f68fSopenharmony_ci	int flock;
916881f68fSopenharmony_ci	int xattr;
926881f68fSopenharmony_ci	char *source;
936881f68fSopenharmony_ci	double timeout;
946881f68fSopenharmony_ci	int cache;
956881f68fSopenharmony_ci	int timeout_set;
966881f68fSopenharmony_ci	struct lo_inode root; /* protected by lo->mutex */
976881f68fSopenharmony_ci};
986881f68fSopenharmony_ci
996881f68fSopenharmony_cistatic const struct fuse_opt lo_opts[] = {
1006881f68fSopenharmony_ci	{ "writeback",
1016881f68fSopenharmony_ci	  offsetof(struct lo_data, writeback), 1 },
1026881f68fSopenharmony_ci	{ "no_writeback",
1036881f68fSopenharmony_ci	  offsetof(struct lo_data, writeback), 0 },
1046881f68fSopenharmony_ci	{ "source=%s",
1056881f68fSopenharmony_ci	  offsetof(struct lo_data, source), 0 },
1066881f68fSopenharmony_ci	{ "flock",
1076881f68fSopenharmony_ci	  offsetof(struct lo_data, flock), 1 },
1086881f68fSopenharmony_ci	{ "no_flock",
1096881f68fSopenharmony_ci	  offsetof(struct lo_data, flock), 0 },
1106881f68fSopenharmony_ci	{ "xattr",
1116881f68fSopenharmony_ci	  offsetof(struct lo_data, xattr), 1 },
1126881f68fSopenharmony_ci	{ "no_xattr",
1136881f68fSopenharmony_ci	  offsetof(struct lo_data, xattr), 0 },
1146881f68fSopenharmony_ci	{ "timeout=%lf",
1156881f68fSopenharmony_ci	  offsetof(struct lo_data, timeout), 0 },
1166881f68fSopenharmony_ci	{ "timeout=",
1176881f68fSopenharmony_ci	  offsetof(struct lo_data, timeout_set), 1 },
1186881f68fSopenharmony_ci	{ "cache=never",
1196881f68fSopenharmony_ci	  offsetof(struct lo_data, cache), CACHE_NEVER },
1206881f68fSopenharmony_ci	{ "cache=auto",
1216881f68fSopenharmony_ci	  offsetof(struct lo_data, cache), CACHE_NORMAL },
1226881f68fSopenharmony_ci	{ "cache=always",
1236881f68fSopenharmony_ci	  offsetof(struct lo_data, cache), CACHE_ALWAYS },
1246881f68fSopenharmony_ci
1256881f68fSopenharmony_ci	FUSE_OPT_END
1266881f68fSopenharmony_ci};
1276881f68fSopenharmony_ci
1286881f68fSopenharmony_cistatic void passthrough_ll_help(void)
1296881f68fSopenharmony_ci{
1306881f68fSopenharmony_ci	printf(
1316881f68fSopenharmony_ci"    -o writeback           Enable writeback\n"
1326881f68fSopenharmony_ci"    -o no_writeback        Disable write back\n"
1336881f68fSopenharmony_ci"    -o source=/home/dir    Source directory to be mounted\n"
1346881f68fSopenharmony_ci"    -o flock               Enable flock\n"
1356881f68fSopenharmony_ci"    -o no_flock            Disable flock\n"
1366881f68fSopenharmony_ci"    -o xattr               Enable xattr\n"
1376881f68fSopenharmony_ci"    -o no_xattr            Disable xattr\n"
1386881f68fSopenharmony_ci"    -o timeout=1.0         Caching timeout\n"
1396881f68fSopenharmony_ci"    -o timeout=0/1         Timeout is set\n"
1406881f68fSopenharmony_ci"    -o cache=never         Disable cache\n"
1416881f68fSopenharmony_ci"    -o cache=auto          Auto enable cache\n"
1426881f68fSopenharmony_ci"    -o cache=always        Cache always\n");
1436881f68fSopenharmony_ci}
1446881f68fSopenharmony_ci
1456881f68fSopenharmony_cistatic struct lo_data *lo_data(fuse_req_t req)
1466881f68fSopenharmony_ci{
1476881f68fSopenharmony_ci	return (struct lo_data *) fuse_req_userdata(req);
1486881f68fSopenharmony_ci}
1496881f68fSopenharmony_ci
1506881f68fSopenharmony_cistatic struct lo_inode *lo_inode(fuse_req_t req, fuse_ino_t ino)
1516881f68fSopenharmony_ci{
1526881f68fSopenharmony_ci	if (ino == FUSE_ROOT_ID)
1536881f68fSopenharmony_ci		return &lo_data(req)->root;
1546881f68fSopenharmony_ci	else
1556881f68fSopenharmony_ci		return (struct lo_inode *) (uintptr_t) ino;
1566881f68fSopenharmony_ci}
1576881f68fSopenharmony_ci
1586881f68fSopenharmony_cistatic int lo_fd(fuse_req_t req, fuse_ino_t ino)
1596881f68fSopenharmony_ci{
1606881f68fSopenharmony_ci	return lo_inode(req, ino)->fd;
1616881f68fSopenharmony_ci}
1626881f68fSopenharmony_ci
1636881f68fSopenharmony_cistatic bool lo_debug(fuse_req_t req)
1646881f68fSopenharmony_ci{
1656881f68fSopenharmony_ci	return lo_data(req)->debug != 0;
1666881f68fSopenharmony_ci}
1676881f68fSopenharmony_ci
1686881f68fSopenharmony_cistatic void lo_init(void *userdata,
1696881f68fSopenharmony_ci		    struct fuse_conn_info *conn)
1706881f68fSopenharmony_ci{
1716881f68fSopenharmony_ci	struct lo_data *lo = (struct lo_data*) userdata;
1726881f68fSopenharmony_ci
1736881f68fSopenharmony_ci	if(conn->capable & FUSE_CAP_EXPORT_SUPPORT)
1746881f68fSopenharmony_ci		conn->want |= FUSE_CAP_EXPORT_SUPPORT;
1756881f68fSopenharmony_ci
1766881f68fSopenharmony_ci	if (lo->writeback &&
1776881f68fSopenharmony_ci	    conn->capable & FUSE_CAP_WRITEBACK_CACHE) {
1786881f68fSopenharmony_ci		if (lo->debug)
1796881f68fSopenharmony_ci			fuse_log(FUSE_LOG_DEBUG, "lo_init: activating writeback\n");
1806881f68fSopenharmony_ci		conn->want |= FUSE_CAP_WRITEBACK_CACHE;
1816881f68fSopenharmony_ci	}
1826881f68fSopenharmony_ci	if (lo->flock && conn->capable & FUSE_CAP_FLOCK_LOCKS) {
1836881f68fSopenharmony_ci		if (lo->debug)
1846881f68fSopenharmony_ci			fuse_log(FUSE_LOG_DEBUG, "lo_init: activating flock locks\n");
1856881f68fSopenharmony_ci		conn->want |= FUSE_CAP_FLOCK_LOCKS;
1866881f68fSopenharmony_ci	}
1876881f68fSopenharmony_ci}
1886881f68fSopenharmony_ci
1896881f68fSopenharmony_cistatic void lo_destroy(void *userdata)
1906881f68fSopenharmony_ci{
1916881f68fSopenharmony_ci	struct lo_data *lo = (struct lo_data*) userdata;
1926881f68fSopenharmony_ci
1936881f68fSopenharmony_ci	while (lo->root.next != &lo->root) {
1946881f68fSopenharmony_ci		struct lo_inode* next = lo->root.next;
1956881f68fSopenharmony_ci		lo->root.next = next->next;
1966881f68fSopenharmony_ci		free(next);
1976881f68fSopenharmony_ci	}
1986881f68fSopenharmony_ci}
1996881f68fSopenharmony_ci
2006881f68fSopenharmony_cistatic void lo_getattr(fuse_req_t req, fuse_ino_t ino,
2016881f68fSopenharmony_ci			     struct fuse_file_info *fi)
2026881f68fSopenharmony_ci{
2036881f68fSopenharmony_ci	int res;
2046881f68fSopenharmony_ci	struct stat buf;
2056881f68fSopenharmony_ci	struct lo_data *lo = lo_data(req);
2066881f68fSopenharmony_ci
2076881f68fSopenharmony_ci	(void) fi;
2086881f68fSopenharmony_ci
2096881f68fSopenharmony_ci	res = fstatat(lo_fd(req, ino), "", &buf, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW);
2106881f68fSopenharmony_ci	if (res == -1)
2116881f68fSopenharmony_ci		return (void) fuse_reply_err(req, errno);
2126881f68fSopenharmony_ci
2136881f68fSopenharmony_ci	fuse_reply_attr(req, &buf, lo->timeout);
2146881f68fSopenharmony_ci}
2156881f68fSopenharmony_ci
2166881f68fSopenharmony_cistatic void lo_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
2176881f68fSopenharmony_ci		       int valid, struct fuse_file_info *fi)
2186881f68fSopenharmony_ci{
2196881f68fSopenharmony_ci	int saverr;
2206881f68fSopenharmony_ci	char procname[64];
2216881f68fSopenharmony_ci	struct lo_inode *inode = lo_inode(req, ino);
2226881f68fSopenharmony_ci	int ifd = inode->fd;
2236881f68fSopenharmony_ci	int res;
2246881f68fSopenharmony_ci
2256881f68fSopenharmony_ci	if (valid & FUSE_SET_ATTR_MODE) {
2266881f68fSopenharmony_ci		if (fi) {
2276881f68fSopenharmony_ci			res = fchmod(fi->fh, attr->st_mode);
2286881f68fSopenharmony_ci		} else {
2296881f68fSopenharmony_ci			sprintf(procname, "/proc/self/fd/%i", ifd);
2306881f68fSopenharmony_ci			res = chmod(procname, attr->st_mode);
2316881f68fSopenharmony_ci		}
2326881f68fSopenharmony_ci		if (res == -1)
2336881f68fSopenharmony_ci			goto out_err;
2346881f68fSopenharmony_ci	}
2356881f68fSopenharmony_ci	if (valid & (FUSE_SET_ATTR_UID | FUSE_SET_ATTR_GID)) {
2366881f68fSopenharmony_ci		uid_t uid = (valid & FUSE_SET_ATTR_UID) ?
2376881f68fSopenharmony_ci			attr->st_uid : (uid_t) -1;
2386881f68fSopenharmony_ci		gid_t gid = (valid & FUSE_SET_ATTR_GID) ?
2396881f68fSopenharmony_ci			attr->st_gid : (gid_t) -1;
2406881f68fSopenharmony_ci
2416881f68fSopenharmony_ci		res = fchownat(ifd, "", uid, gid,
2426881f68fSopenharmony_ci			       AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW);
2436881f68fSopenharmony_ci		if (res == -1)
2446881f68fSopenharmony_ci			goto out_err;
2456881f68fSopenharmony_ci	}
2466881f68fSopenharmony_ci	if (valid & FUSE_SET_ATTR_SIZE) {
2476881f68fSopenharmony_ci		if (fi) {
2486881f68fSopenharmony_ci			res = ftruncate(fi->fh, attr->st_size);
2496881f68fSopenharmony_ci		} else {
2506881f68fSopenharmony_ci			sprintf(procname, "/proc/self/fd/%i", ifd);
2516881f68fSopenharmony_ci			res = truncate(procname, attr->st_size);
2526881f68fSopenharmony_ci		}
2536881f68fSopenharmony_ci		if (res == -1)
2546881f68fSopenharmony_ci			goto out_err;
2556881f68fSopenharmony_ci	}
2566881f68fSopenharmony_ci	if (valid & (FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME)) {
2576881f68fSopenharmony_ci		struct timespec tv[2];
2586881f68fSopenharmony_ci
2596881f68fSopenharmony_ci		tv[0].tv_sec = 0;
2606881f68fSopenharmony_ci		tv[1].tv_sec = 0;
2616881f68fSopenharmony_ci		tv[0].tv_nsec = UTIME_OMIT;
2626881f68fSopenharmony_ci		tv[1].tv_nsec = UTIME_OMIT;
2636881f68fSopenharmony_ci
2646881f68fSopenharmony_ci		if (valid & FUSE_SET_ATTR_ATIME_NOW)
2656881f68fSopenharmony_ci			tv[0].tv_nsec = UTIME_NOW;
2666881f68fSopenharmony_ci		else if (valid & FUSE_SET_ATTR_ATIME)
2676881f68fSopenharmony_ci			tv[0] = attr->st_atim;
2686881f68fSopenharmony_ci
2696881f68fSopenharmony_ci		if (valid & FUSE_SET_ATTR_MTIME_NOW)
2706881f68fSopenharmony_ci			tv[1].tv_nsec = UTIME_NOW;
2716881f68fSopenharmony_ci		else if (valid & FUSE_SET_ATTR_MTIME)
2726881f68fSopenharmony_ci			tv[1] = attr->st_mtim;
2736881f68fSopenharmony_ci
2746881f68fSopenharmony_ci		if (fi)
2756881f68fSopenharmony_ci			res = futimens(fi->fh, tv);
2766881f68fSopenharmony_ci		else {
2776881f68fSopenharmony_ci			sprintf(procname, "/proc/self/fd/%i", ifd);
2786881f68fSopenharmony_ci			res = utimensat(AT_FDCWD, procname, tv, 0);
2796881f68fSopenharmony_ci		}
2806881f68fSopenharmony_ci		if (res == -1)
2816881f68fSopenharmony_ci			goto out_err;
2826881f68fSopenharmony_ci	}
2836881f68fSopenharmony_ci
2846881f68fSopenharmony_ci	return lo_getattr(req, ino, fi);
2856881f68fSopenharmony_ci
2866881f68fSopenharmony_ciout_err:
2876881f68fSopenharmony_ci	saverr = errno;
2886881f68fSopenharmony_ci	fuse_reply_err(req, saverr);
2896881f68fSopenharmony_ci}
2906881f68fSopenharmony_ci
2916881f68fSopenharmony_cistatic struct lo_inode *lo_find(struct lo_data *lo, struct stat *st)
2926881f68fSopenharmony_ci{
2936881f68fSopenharmony_ci	struct lo_inode *p;
2946881f68fSopenharmony_ci	struct lo_inode *ret = NULL;
2956881f68fSopenharmony_ci
2966881f68fSopenharmony_ci	pthread_mutex_lock(&lo->mutex);
2976881f68fSopenharmony_ci	for (p = lo->root.next; p != &lo->root; p = p->next) {
2986881f68fSopenharmony_ci		if (p->ino == st->st_ino && p->dev == st->st_dev) {
2996881f68fSopenharmony_ci			assert(p->refcount > 0);
3006881f68fSopenharmony_ci			ret = p;
3016881f68fSopenharmony_ci			ret->refcount++;
3026881f68fSopenharmony_ci			break;
3036881f68fSopenharmony_ci		}
3046881f68fSopenharmony_ci	}
3056881f68fSopenharmony_ci	pthread_mutex_unlock(&lo->mutex);
3066881f68fSopenharmony_ci	return ret;
3076881f68fSopenharmony_ci}
3086881f68fSopenharmony_ci
3096881f68fSopenharmony_cistatic int lo_do_lookup(fuse_req_t req, fuse_ino_t parent, const char *name,
3106881f68fSopenharmony_ci			 struct fuse_entry_param *e)
3116881f68fSopenharmony_ci{
3126881f68fSopenharmony_ci	int newfd;
3136881f68fSopenharmony_ci	int res;
3146881f68fSopenharmony_ci	int saverr;
3156881f68fSopenharmony_ci	struct lo_data *lo = lo_data(req);
3166881f68fSopenharmony_ci	struct lo_inode *inode;
3176881f68fSopenharmony_ci
3186881f68fSopenharmony_ci	memset(e, 0, sizeof(*e));
3196881f68fSopenharmony_ci	e->attr_timeout = lo->timeout;
3206881f68fSopenharmony_ci	e->entry_timeout = lo->timeout;
3216881f68fSopenharmony_ci
3226881f68fSopenharmony_ci	newfd = openat(lo_fd(req, parent), name, O_PATH | O_NOFOLLOW);
3236881f68fSopenharmony_ci	if (newfd == -1)
3246881f68fSopenharmony_ci		goto out_err;
3256881f68fSopenharmony_ci
3266881f68fSopenharmony_ci	res = fstatat(newfd, "", &e->attr, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW);
3276881f68fSopenharmony_ci	if (res == -1)
3286881f68fSopenharmony_ci		goto out_err;
3296881f68fSopenharmony_ci
3306881f68fSopenharmony_ci	inode = lo_find(lo_data(req), &e->attr);
3316881f68fSopenharmony_ci	if (inode) {
3326881f68fSopenharmony_ci		close(newfd);
3336881f68fSopenharmony_ci		newfd = -1;
3346881f68fSopenharmony_ci	} else {
3356881f68fSopenharmony_ci		struct lo_inode *prev, *next;
3366881f68fSopenharmony_ci
3376881f68fSopenharmony_ci		saverr = ENOMEM;
3386881f68fSopenharmony_ci		inode = calloc(1, sizeof(struct lo_inode));
3396881f68fSopenharmony_ci		if (!inode)
3406881f68fSopenharmony_ci			goto out_err;
3416881f68fSopenharmony_ci
3426881f68fSopenharmony_ci		inode->refcount = 1;
3436881f68fSopenharmony_ci		inode->fd = newfd;
3446881f68fSopenharmony_ci		inode->ino = e->attr.st_ino;
3456881f68fSopenharmony_ci		inode->dev = e->attr.st_dev;
3466881f68fSopenharmony_ci
3476881f68fSopenharmony_ci		pthread_mutex_lock(&lo->mutex);
3486881f68fSopenharmony_ci		prev = &lo->root;
3496881f68fSopenharmony_ci		next = prev->next;
3506881f68fSopenharmony_ci		next->prev = inode;
3516881f68fSopenharmony_ci		inode->next = next;
3526881f68fSopenharmony_ci		inode->prev = prev;
3536881f68fSopenharmony_ci		prev->next = inode;
3546881f68fSopenharmony_ci		pthread_mutex_unlock(&lo->mutex);
3556881f68fSopenharmony_ci	}
3566881f68fSopenharmony_ci	e->ino = (uintptr_t) inode;
3576881f68fSopenharmony_ci
3586881f68fSopenharmony_ci	if (lo_debug(req))
3596881f68fSopenharmony_ci		fuse_log(FUSE_LOG_DEBUG, "  %lli/%s -> %lli\n",
3606881f68fSopenharmony_ci			(unsigned long long) parent, name, (unsigned long long) e->ino);
3616881f68fSopenharmony_ci
3626881f68fSopenharmony_ci	return 0;
3636881f68fSopenharmony_ci
3646881f68fSopenharmony_ciout_err:
3656881f68fSopenharmony_ci	saverr = errno;
3666881f68fSopenharmony_ci	if (newfd != -1)
3676881f68fSopenharmony_ci		close(newfd);
3686881f68fSopenharmony_ci	return saverr;
3696881f68fSopenharmony_ci}
3706881f68fSopenharmony_ci
3716881f68fSopenharmony_cistatic void lo_lookup(fuse_req_t req, fuse_ino_t parent, const char *name)
3726881f68fSopenharmony_ci{
3736881f68fSopenharmony_ci	struct fuse_entry_param e;
3746881f68fSopenharmony_ci	int err;
3756881f68fSopenharmony_ci
3766881f68fSopenharmony_ci	if (lo_debug(req))
3776881f68fSopenharmony_ci		fuse_log(FUSE_LOG_DEBUG, "lo_lookup(parent=%" PRIu64 ", name=%s)\n",
3786881f68fSopenharmony_ci			parent, name);
3796881f68fSopenharmony_ci
3806881f68fSopenharmony_ci	err = lo_do_lookup(req, parent, name, &e);
3816881f68fSopenharmony_ci	if (err)
3826881f68fSopenharmony_ci		fuse_reply_err(req, err);
3836881f68fSopenharmony_ci	else
3846881f68fSopenharmony_ci		fuse_reply_entry(req, &e);
3856881f68fSopenharmony_ci}
3866881f68fSopenharmony_ci
3876881f68fSopenharmony_cistatic void lo_mknod_symlink(fuse_req_t req, fuse_ino_t parent,
3886881f68fSopenharmony_ci			     const char *name, mode_t mode, dev_t rdev,
3896881f68fSopenharmony_ci			     const char *link)
3906881f68fSopenharmony_ci{
3916881f68fSopenharmony_ci	int res;
3926881f68fSopenharmony_ci	int saverr;
3936881f68fSopenharmony_ci	struct lo_inode *dir = lo_inode(req, parent);
3946881f68fSopenharmony_ci	struct fuse_entry_param e;
3956881f68fSopenharmony_ci
3966881f68fSopenharmony_ci	res = mknod_wrapper(dir->fd, name, link, mode, rdev);
3976881f68fSopenharmony_ci
3986881f68fSopenharmony_ci	saverr = errno;
3996881f68fSopenharmony_ci	if (res == -1)
4006881f68fSopenharmony_ci		goto out;
4016881f68fSopenharmony_ci
4026881f68fSopenharmony_ci	saverr = lo_do_lookup(req, parent, name, &e);
4036881f68fSopenharmony_ci	if (saverr)
4046881f68fSopenharmony_ci		goto out;
4056881f68fSopenharmony_ci
4066881f68fSopenharmony_ci	if (lo_debug(req))
4076881f68fSopenharmony_ci		fuse_log(FUSE_LOG_DEBUG, "  %lli/%s -> %lli\n",
4086881f68fSopenharmony_ci			(unsigned long long) parent, name, (unsigned long long) e.ino);
4096881f68fSopenharmony_ci
4106881f68fSopenharmony_ci	fuse_reply_entry(req, &e);
4116881f68fSopenharmony_ci	return;
4126881f68fSopenharmony_ci
4136881f68fSopenharmony_ciout:
4146881f68fSopenharmony_ci	fuse_reply_err(req, saverr);
4156881f68fSopenharmony_ci}
4166881f68fSopenharmony_ci
4176881f68fSopenharmony_cistatic void lo_mknod(fuse_req_t req, fuse_ino_t parent,
4186881f68fSopenharmony_ci		     const char *name, mode_t mode, dev_t rdev)
4196881f68fSopenharmony_ci{
4206881f68fSopenharmony_ci	lo_mknod_symlink(req, parent, name, mode, rdev, NULL);
4216881f68fSopenharmony_ci}
4226881f68fSopenharmony_ci
4236881f68fSopenharmony_cistatic void lo_mkdir(fuse_req_t req, fuse_ino_t parent, const char *name,
4246881f68fSopenharmony_ci		     mode_t mode)
4256881f68fSopenharmony_ci{
4266881f68fSopenharmony_ci	lo_mknod_symlink(req, parent, name, S_IFDIR | mode, 0, NULL);
4276881f68fSopenharmony_ci}
4286881f68fSopenharmony_ci
4296881f68fSopenharmony_cistatic void lo_symlink(fuse_req_t req, const char *link,
4306881f68fSopenharmony_ci		       fuse_ino_t parent, const char *name)
4316881f68fSopenharmony_ci{
4326881f68fSopenharmony_ci	lo_mknod_symlink(req, parent, name, S_IFLNK, 0, link);
4336881f68fSopenharmony_ci}
4346881f68fSopenharmony_ci
4356881f68fSopenharmony_cistatic void lo_link(fuse_req_t req, fuse_ino_t ino, fuse_ino_t parent,
4366881f68fSopenharmony_ci		    const char *name)
4376881f68fSopenharmony_ci{
4386881f68fSopenharmony_ci	int res;
4396881f68fSopenharmony_ci	struct lo_data *lo = lo_data(req);
4406881f68fSopenharmony_ci	struct lo_inode *inode = lo_inode(req, ino);
4416881f68fSopenharmony_ci	struct fuse_entry_param e;
4426881f68fSopenharmony_ci	char procname[64];
4436881f68fSopenharmony_ci	int saverr;
4446881f68fSopenharmony_ci
4456881f68fSopenharmony_ci	memset(&e, 0, sizeof(struct fuse_entry_param));
4466881f68fSopenharmony_ci	e.attr_timeout = lo->timeout;
4476881f68fSopenharmony_ci	e.entry_timeout = lo->timeout;
4486881f68fSopenharmony_ci
4496881f68fSopenharmony_ci	sprintf(procname, "/proc/self/fd/%i", inode->fd);
4506881f68fSopenharmony_ci	res = linkat(AT_FDCWD, procname, lo_fd(req, parent), name,
4516881f68fSopenharmony_ci		     AT_SYMLINK_FOLLOW);
4526881f68fSopenharmony_ci	if (res == -1)
4536881f68fSopenharmony_ci		goto out_err;
4546881f68fSopenharmony_ci
4556881f68fSopenharmony_ci	res = fstatat(inode->fd, "", &e.attr, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW);
4566881f68fSopenharmony_ci	if (res == -1)
4576881f68fSopenharmony_ci		goto out_err;
4586881f68fSopenharmony_ci
4596881f68fSopenharmony_ci	pthread_mutex_lock(&lo->mutex);
4606881f68fSopenharmony_ci	inode->refcount++;
4616881f68fSopenharmony_ci	pthread_mutex_unlock(&lo->mutex);
4626881f68fSopenharmony_ci	e.ino = (uintptr_t) inode;
4636881f68fSopenharmony_ci
4646881f68fSopenharmony_ci	if (lo_debug(req))
4656881f68fSopenharmony_ci		fuse_log(FUSE_LOG_DEBUG, "  %lli/%s -> %lli\n",
4666881f68fSopenharmony_ci			(unsigned long long) parent, name,
4676881f68fSopenharmony_ci			(unsigned long long) e.ino);
4686881f68fSopenharmony_ci
4696881f68fSopenharmony_ci	fuse_reply_entry(req, &e);
4706881f68fSopenharmony_ci	return;
4716881f68fSopenharmony_ci
4726881f68fSopenharmony_ciout_err:
4736881f68fSopenharmony_ci	saverr = errno;
4746881f68fSopenharmony_ci	fuse_reply_err(req, saverr);
4756881f68fSopenharmony_ci}
4766881f68fSopenharmony_ci
4776881f68fSopenharmony_cistatic void lo_rmdir(fuse_req_t req, fuse_ino_t parent, const char *name)
4786881f68fSopenharmony_ci{
4796881f68fSopenharmony_ci	int res;
4806881f68fSopenharmony_ci
4816881f68fSopenharmony_ci	res = unlinkat(lo_fd(req, parent), name, AT_REMOVEDIR);
4826881f68fSopenharmony_ci
4836881f68fSopenharmony_ci	fuse_reply_err(req, res == -1 ? errno : 0);
4846881f68fSopenharmony_ci}
4856881f68fSopenharmony_ci
4866881f68fSopenharmony_cistatic void lo_rename(fuse_req_t req, fuse_ino_t parent, const char *name,
4876881f68fSopenharmony_ci		      fuse_ino_t newparent, const char *newname,
4886881f68fSopenharmony_ci		      unsigned int flags)
4896881f68fSopenharmony_ci{
4906881f68fSopenharmony_ci	int res;
4916881f68fSopenharmony_ci
4926881f68fSopenharmony_ci	if (flags) {
4936881f68fSopenharmony_ci		fuse_reply_err(req, EINVAL);
4946881f68fSopenharmony_ci		return;
4956881f68fSopenharmony_ci	}
4966881f68fSopenharmony_ci
4976881f68fSopenharmony_ci	res = renameat(lo_fd(req, parent), name,
4986881f68fSopenharmony_ci			lo_fd(req, newparent), newname);
4996881f68fSopenharmony_ci
5006881f68fSopenharmony_ci	fuse_reply_err(req, res == -1 ? errno : 0);
5016881f68fSopenharmony_ci}
5026881f68fSopenharmony_ci
5036881f68fSopenharmony_cistatic void lo_unlink(fuse_req_t req, fuse_ino_t parent, const char *name)
5046881f68fSopenharmony_ci{
5056881f68fSopenharmony_ci	int res;
5066881f68fSopenharmony_ci
5076881f68fSopenharmony_ci	res = unlinkat(lo_fd(req, parent), name, 0);
5086881f68fSopenharmony_ci
5096881f68fSopenharmony_ci	fuse_reply_err(req, res == -1 ? errno : 0);
5106881f68fSopenharmony_ci}
5116881f68fSopenharmony_ci
5126881f68fSopenharmony_cistatic void unref_inode(struct lo_data *lo, struct lo_inode *inode, uint64_t n)
5136881f68fSopenharmony_ci{
5146881f68fSopenharmony_ci	if (!inode)
5156881f68fSopenharmony_ci		return;
5166881f68fSopenharmony_ci
5176881f68fSopenharmony_ci	pthread_mutex_lock(&lo->mutex);
5186881f68fSopenharmony_ci	assert(inode->refcount >= n);
5196881f68fSopenharmony_ci	inode->refcount -= n;
5206881f68fSopenharmony_ci	if (!inode->refcount) {
5216881f68fSopenharmony_ci		struct lo_inode *prev, *next;
5226881f68fSopenharmony_ci
5236881f68fSopenharmony_ci		prev = inode->prev;
5246881f68fSopenharmony_ci		next = inode->next;
5256881f68fSopenharmony_ci		next->prev = prev;
5266881f68fSopenharmony_ci		prev->next = next;
5276881f68fSopenharmony_ci
5286881f68fSopenharmony_ci		pthread_mutex_unlock(&lo->mutex);
5296881f68fSopenharmony_ci		close(inode->fd);
5306881f68fSopenharmony_ci		free(inode);
5316881f68fSopenharmony_ci
5326881f68fSopenharmony_ci	} else {
5336881f68fSopenharmony_ci		pthread_mutex_unlock(&lo->mutex);
5346881f68fSopenharmony_ci	}
5356881f68fSopenharmony_ci}
5366881f68fSopenharmony_ci
5376881f68fSopenharmony_cistatic void lo_forget_one(fuse_req_t req, fuse_ino_t ino, uint64_t nlookup)
5386881f68fSopenharmony_ci{
5396881f68fSopenharmony_ci	struct lo_data *lo = lo_data(req);
5406881f68fSopenharmony_ci	struct lo_inode *inode = lo_inode(req, ino);
5416881f68fSopenharmony_ci
5426881f68fSopenharmony_ci	if (lo_debug(req)) {
5436881f68fSopenharmony_ci		fuse_log(FUSE_LOG_DEBUG, "  forget %lli %lli -%lli\n",
5446881f68fSopenharmony_ci			(unsigned long long) ino,
5456881f68fSopenharmony_ci			(unsigned long long) inode->refcount,
5466881f68fSopenharmony_ci			(unsigned long long) nlookup);
5476881f68fSopenharmony_ci	}
5486881f68fSopenharmony_ci
5496881f68fSopenharmony_ci	unref_inode(lo, inode, nlookup);
5506881f68fSopenharmony_ci}
5516881f68fSopenharmony_ci
5526881f68fSopenharmony_cistatic void lo_forget(fuse_req_t req, fuse_ino_t ino, uint64_t nlookup)
5536881f68fSopenharmony_ci{
5546881f68fSopenharmony_ci	lo_forget_one(req, ino, nlookup);
5556881f68fSopenharmony_ci	fuse_reply_none(req);
5566881f68fSopenharmony_ci}
5576881f68fSopenharmony_ci
5586881f68fSopenharmony_cistatic void lo_forget_multi(fuse_req_t req, size_t count,
5596881f68fSopenharmony_ci				struct fuse_forget_data *forgets)
5606881f68fSopenharmony_ci{
5616881f68fSopenharmony_ci	int i;
5626881f68fSopenharmony_ci
5636881f68fSopenharmony_ci	for (i = 0; i < count; i++)
5646881f68fSopenharmony_ci		lo_forget_one(req, forgets[i].ino, forgets[i].nlookup);
5656881f68fSopenharmony_ci	fuse_reply_none(req);
5666881f68fSopenharmony_ci}
5676881f68fSopenharmony_ci
5686881f68fSopenharmony_cistatic void lo_readlink(fuse_req_t req, fuse_ino_t ino)
5696881f68fSopenharmony_ci{
5706881f68fSopenharmony_ci	char buf[PATH_MAX + 1];
5716881f68fSopenharmony_ci	int res;
5726881f68fSopenharmony_ci
5736881f68fSopenharmony_ci	res = readlinkat(lo_fd(req, ino), "", buf, sizeof(buf));
5746881f68fSopenharmony_ci	if (res == -1)
5756881f68fSopenharmony_ci		return (void) fuse_reply_err(req, errno);
5766881f68fSopenharmony_ci
5776881f68fSopenharmony_ci	if (res == sizeof(buf))
5786881f68fSopenharmony_ci		return (void) fuse_reply_err(req, ENAMETOOLONG);
5796881f68fSopenharmony_ci
5806881f68fSopenharmony_ci	buf[res] = '\0';
5816881f68fSopenharmony_ci
5826881f68fSopenharmony_ci	fuse_reply_readlink(req, buf);
5836881f68fSopenharmony_ci}
5846881f68fSopenharmony_ci
5856881f68fSopenharmony_cistruct lo_dirp {
5866881f68fSopenharmony_ci	DIR *dp;
5876881f68fSopenharmony_ci	struct dirent *entry;
5886881f68fSopenharmony_ci	off_t offset;
5896881f68fSopenharmony_ci};
5906881f68fSopenharmony_ci
5916881f68fSopenharmony_cistatic struct lo_dirp *lo_dirp(struct fuse_file_info *fi)
5926881f68fSopenharmony_ci{
5936881f68fSopenharmony_ci	return (struct lo_dirp *) (uintptr_t) fi->fh;
5946881f68fSopenharmony_ci}
5956881f68fSopenharmony_ci
5966881f68fSopenharmony_cistatic void lo_opendir(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
5976881f68fSopenharmony_ci{
5986881f68fSopenharmony_ci	int error = ENOMEM;
5996881f68fSopenharmony_ci	struct lo_data *lo = lo_data(req);
6006881f68fSopenharmony_ci	struct lo_dirp *d;
6016881f68fSopenharmony_ci	int fd;
6026881f68fSopenharmony_ci
6036881f68fSopenharmony_ci	d = calloc(1, sizeof(struct lo_dirp));
6046881f68fSopenharmony_ci	if (d == NULL)
6056881f68fSopenharmony_ci		goto out_err;
6066881f68fSopenharmony_ci
6076881f68fSopenharmony_ci	fd = openat(lo_fd(req, ino), ".", O_RDONLY);
6086881f68fSopenharmony_ci	if (fd == -1)
6096881f68fSopenharmony_ci		goto out_errno;
6106881f68fSopenharmony_ci
6116881f68fSopenharmony_ci	d->dp = fdopendir(fd);
6126881f68fSopenharmony_ci	if (d->dp == NULL)
6136881f68fSopenharmony_ci		goto out_errno;
6146881f68fSopenharmony_ci
6156881f68fSopenharmony_ci	d->offset = 0;
6166881f68fSopenharmony_ci	d->entry = NULL;
6176881f68fSopenharmony_ci
6186881f68fSopenharmony_ci	fi->fh = (uintptr_t) d;
6196881f68fSopenharmony_ci	if (lo->cache == CACHE_ALWAYS)
6206881f68fSopenharmony_ci		fi->cache_readdir = 1;
6216881f68fSopenharmony_ci	fuse_reply_open(req, fi);
6226881f68fSopenharmony_ci	return;
6236881f68fSopenharmony_ci
6246881f68fSopenharmony_ciout_errno:
6256881f68fSopenharmony_ci	error = errno;
6266881f68fSopenharmony_ciout_err:
6276881f68fSopenharmony_ci	if (d) {
6286881f68fSopenharmony_ci		if (fd != -1)
6296881f68fSopenharmony_ci			close(fd);
6306881f68fSopenharmony_ci		free(d);
6316881f68fSopenharmony_ci	}
6326881f68fSopenharmony_ci	fuse_reply_err(req, error);
6336881f68fSopenharmony_ci}
6346881f68fSopenharmony_ci
6356881f68fSopenharmony_cistatic int is_dot_or_dotdot(const char *name)
6366881f68fSopenharmony_ci{
6376881f68fSopenharmony_ci	return name[0] == '.' && (name[1] == '\0' ||
6386881f68fSopenharmony_ci				  (name[1] == '.' && name[2] == '\0'));
6396881f68fSopenharmony_ci}
6406881f68fSopenharmony_ci
6416881f68fSopenharmony_cistatic void lo_do_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
6426881f68fSopenharmony_ci			  off_t offset, struct fuse_file_info *fi, int plus)
6436881f68fSopenharmony_ci{
6446881f68fSopenharmony_ci	struct lo_dirp *d = lo_dirp(fi);
6456881f68fSopenharmony_ci	char *buf;
6466881f68fSopenharmony_ci	char *p;
6476881f68fSopenharmony_ci	size_t rem = size;
6486881f68fSopenharmony_ci	int err;
6496881f68fSopenharmony_ci
6506881f68fSopenharmony_ci	(void) ino;
6516881f68fSopenharmony_ci
6526881f68fSopenharmony_ci	buf = calloc(1, size);
6536881f68fSopenharmony_ci	if (!buf) {
6546881f68fSopenharmony_ci		err = ENOMEM;
6556881f68fSopenharmony_ci		goto error;
6566881f68fSopenharmony_ci	}
6576881f68fSopenharmony_ci	p = buf;
6586881f68fSopenharmony_ci
6596881f68fSopenharmony_ci	if (offset != d->offset) {
6606881f68fSopenharmony_ci		seekdir(d->dp, offset);
6616881f68fSopenharmony_ci		d->entry = NULL;
6626881f68fSopenharmony_ci		d->offset = offset;
6636881f68fSopenharmony_ci	}
6646881f68fSopenharmony_ci	while (1) {
6656881f68fSopenharmony_ci		size_t entsize;
6666881f68fSopenharmony_ci		off_t nextoff;
6676881f68fSopenharmony_ci		const char *name;
6686881f68fSopenharmony_ci
6696881f68fSopenharmony_ci		if (!d->entry) {
6706881f68fSopenharmony_ci			errno = 0;
6716881f68fSopenharmony_ci			d->entry = readdir(d->dp);
6726881f68fSopenharmony_ci			if (!d->entry) {
6736881f68fSopenharmony_ci				if (errno) {  // Error
6746881f68fSopenharmony_ci					err = errno;
6756881f68fSopenharmony_ci					goto error;
6766881f68fSopenharmony_ci				} else {  // End of stream
6776881f68fSopenharmony_ci					break;
6786881f68fSopenharmony_ci				}
6796881f68fSopenharmony_ci			}
6806881f68fSopenharmony_ci		}
6816881f68fSopenharmony_ci		nextoff = d->entry->d_off;
6826881f68fSopenharmony_ci		name = d->entry->d_name;
6836881f68fSopenharmony_ci		fuse_ino_t entry_ino = 0;
6846881f68fSopenharmony_ci		if (plus) {
6856881f68fSopenharmony_ci			struct fuse_entry_param e;
6866881f68fSopenharmony_ci			if (is_dot_or_dotdot(name)) {
6876881f68fSopenharmony_ci				e = (struct fuse_entry_param) {
6886881f68fSopenharmony_ci					.attr.st_ino = d->entry->d_ino,
6896881f68fSopenharmony_ci					.attr.st_mode = d->entry->d_type << 12,
6906881f68fSopenharmony_ci				};
6916881f68fSopenharmony_ci			} else {
6926881f68fSopenharmony_ci				err = lo_do_lookup(req, ino, name, &e);
6936881f68fSopenharmony_ci				if (err)
6946881f68fSopenharmony_ci					goto error;
6956881f68fSopenharmony_ci				entry_ino = e.ino;
6966881f68fSopenharmony_ci			}
6976881f68fSopenharmony_ci
6986881f68fSopenharmony_ci			entsize = fuse_add_direntry_plus(req, p, rem, name,
6996881f68fSopenharmony_ci							 &e, nextoff);
7006881f68fSopenharmony_ci		} else {
7016881f68fSopenharmony_ci			struct stat st = {
7026881f68fSopenharmony_ci				.st_ino = d->entry->d_ino,
7036881f68fSopenharmony_ci				.st_mode = d->entry->d_type << 12,
7046881f68fSopenharmony_ci			};
7056881f68fSopenharmony_ci			entsize = fuse_add_direntry(req, p, rem, name,
7066881f68fSopenharmony_ci						    &st, nextoff);
7076881f68fSopenharmony_ci		}
7086881f68fSopenharmony_ci		if (entsize > rem) {
7096881f68fSopenharmony_ci			if (entry_ino != 0)
7106881f68fSopenharmony_ci				lo_forget_one(req, entry_ino, 1);
7116881f68fSopenharmony_ci			break;
7126881f68fSopenharmony_ci		}
7136881f68fSopenharmony_ci
7146881f68fSopenharmony_ci		p += entsize;
7156881f68fSopenharmony_ci		rem -= entsize;
7166881f68fSopenharmony_ci
7176881f68fSopenharmony_ci		d->entry = NULL;
7186881f68fSopenharmony_ci		d->offset = nextoff;
7196881f68fSopenharmony_ci	}
7206881f68fSopenharmony_ci
7216881f68fSopenharmony_ci    err = 0;
7226881f68fSopenharmony_cierror:
7236881f68fSopenharmony_ci    // If there's an error, we can only signal it if we haven't stored
7246881f68fSopenharmony_ci    // any entries yet - otherwise we'd end up with wrong lookup
7256881f68fSopenharmony_ci    // counts for the entries that are already in the buffer. So we
7266881f68fSopenharmony_ci    // return what we've collected until that point.
7276881f68fSopenharmony_ci    if (err && rem == size)
7286881f68fSopenharmony_ci	    fuse_reply_err(req, err);
7296881f68fSopenharmony_ci    else
7306881f68fSopenharmony_ci	    fuse_reply_buf(req, buf, size - rem);
7316881f68fSopenharmony_ci    free(buf);
7326881f68fSopenharmony_ci}
7336881f68fSopenharmony_ci
7346881f68fSopenharmony_cistatic void lo_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
7356881f68fSopenharmony_ci		       off_t offset, struct fuse_file_info *fi)
7366881f68fSopenharmony_ci{
7376881f68fSopenharmony_ci	lo_do_readdir(req, ino, size, offset, fi, 0);
7386881f68fSopenharmony_ci}
7396881f68fSopenharmony_ci
7406881f68fSopenharmony_cistatic void lo_readdirplus(fuse_req_t req, fuse_ino_t ino, size_t size,
7416881f68fSopenharmony_ci			   off_t offset, struct fuse_file_info *fi)
7426881f68fSopenharmony_ci{
7436881f68fSopenharmony_ci	lo_do_readdir(req, ino, size, offset, fi, 1);
7446881f68fSopenharmony_ci}
7456881f68fSopenharmony_ci
7466881f68fSopenharmony_cistatic void lo_releasedir(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
7476881f68fSopenharmony_ci{
7486881f68fSopenharmony_ci	struct lo_dirp *d = lo_dirp(fi);
7496881f68fSopenharmony_ci	(void) ino;
7506881f68fSopenharmony_ci	closedir(d->dp);
7516881f68fSopenharmony_ci	free(d);
7526881f68fSopenharmony_ci	fuse_reply_err(req, 0);
7536881f68fSopenharmony_ci}
7546881f68fSopenharmony_ci
7556881f68fSopenharmony_cistatic void lo_create(fuse_req_t req, fuse_ino_t parent, const char *name,
7566881f68fSopenharmony_ci		      mode_t mode, struct fuse_file_info *fi)
7576881f68fSopenharmony_ci{
7586881f68fSopenharmony_ci	int fd;
7596881f68fSopenharmony_ci	struct lo_data *lo = lo_data(req);
7606881f68fSopenharmony_ci	struct fuse_entry_param e;
7616881f68fSopenharmony_ci	int err;
7626881f68fSopenharmony_ci
7636881f68fSopenharmony_ci	if (lo_debug(req))
7646881f68fSopenharmony_ci		fuse_log(FUSE_LOG_DEBUG, "lo_create(parent=%" PRIu64 ", name=%s)\n",
7656881f68fSopenharmony_ci			parent, name);
7666881f68fSopenharmony_ci
7676881f68fSopenharmony_ci	fd = openat(lo_fd(req, parent), name,
7686881f68fSopenharmony_ci		    (fi->flags | O_CREAT) & ~O_NOFOLLOW, mode);
7696881f68fSopenharmony_ci	if (fd == -1)
7706881f68fSopenharmony_ci		return (void) fuse_reply_err(req, errno);
7716881f68fSopenharmony_ci
7726881f68fSopenharmony_ci	fi->fh = fd;
7736881f68fSopenharmony_ci	if (lo->cache == CACHE_NEVER)
7746881f68fSopenharmony_ci		fi->direct_io = 1;
7756881f68fSopenharmony_ci	else if (lo->cache == CACHE_ALWAYS)
7766881f68fSopenharmony_ci		fi->keep_cache = 1;
7776881f68fSopenharmony_ci
7786881f68fSopenharmony_ci	err = lo_do_lookup(req, parent, name, &e);
7796881f68fSopenharmony_ci	if (err)
7806881f68fSopenharmony_ci		fuse_reply_err(req, err);
7816881f68fSopenharmony_ci	else
7826881f68fSopenharmony_ci		fuse_reply_create(req, &e, fi);
7836881f68fSopenharmony_ci}
7846881f68fSopenharmony_ci
7856881f68fSopenharmony_cistatic void lo_fsyncdir(fuse_req_t req, fuse_ino_t ino, int datasync,
7866881f68fSopenharmony_ci			struct fuse_file_info *fi)
7876881f68fSopenharmony_ci{
7886881f68fSopenharmony_ci	int res;
7896881f68fSopenharmony_ci	int fd = dirfd(lo_dirp(fi)->dp);
7906881f68fSopenharmony_ci	(void) ino;
7916881f68fSopenharmony_ci	if (datasync)
7926881f68fSopenharmony_ci		res = fdatasync(fd);
7936881f68fSopenharmony_ci	else
7946881f68fSopenharmony_ci		res = fsync(fd);
7956881f68fSopenharmony_ci	fuse_reply_err(req, res == -1 ? errno : 0);
7966881f68fSopenharmony_ci}
7976881f68fSopenharmony_ci
7986881f68fSopenharmony_cistatic void lo_open(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
7996881f68fSopenharmony_ci{
8006881f68fSopenharmony_ci	int fd;
8016881f68fSopenharmony_ci	char buf[64];
8026881f68fSopenharmony_ci	struct lo_data *lo = lo_data(req);
8036881f68fSopenharmony_ci
8046881f68fSopenharmony_ci	if (lo_debug(req))
8056881f68fSopenharmony_ci		fuse_log(FUSE_LOG_DEBUG, "lo_open(ino=%" PRIu64 ", flags=%d)\n",
8066881f68fSopenharmony_ci			ino, fi->flags);
8076881f68fSopenharmony_ci
8086881f68fSopenharmony_ci	/* With writeback cache, kernel may send read requests even
8096881f68fSopenharmony_ci	   when userspace opened write-only */
8106881f68fSopenharmony_ci	if (lo->writeback && (fi->flags & O_ACCMODE) == O_WRONLY) {
8116881f68fSopenharmony_ci		fi->flags &= ~O_ACCMODE;
8126881f68fSopenharmony_ci		fi->flags |= O_RDWR;
8136881f68fSopenharmony_ci	}
8146881f68fSopenharmony_ci
8156881f68fSopenharmony_ci	/* With writeback cache, O_APPEND is handled by the kernel.
8166881f68fSopenharmony_ci	   This breaks atomicity (since the file may change in the
8176881f68fSopenharmony_ci	   underlying filesystem, so that the kernel's idea of the
8186881f68fSopenharmony_ci	   end of the file isn't accurate anymore). In this example,
8196881f68fSopenharmony_ci	   we just accept that. A more rigorous filesystem may want
8206881f68fSopenharmony_ci	   to return an error here */
8216881f68fSopenharmony_ci	if (lo->writeback && (fi->flags & O_APPEND))
8226881f68fSopenharmony_ci		fi->flags &= ~O_APPEND;
8236881f68fSopenharmony_ci
8246881f68fSopenharmony_ci	sprintf(buf, "/proc/self/fd/%i", lo_fd(req, ino));
8256881f68fSopenharmony_ci	fd = open(buf, fi->flags & ~O_NOFOLLOW);
8266881f68fSopenharmony_ci	if (fd == -1)
8276881f68fSopenharmony_ci		return (void) fuse_reply_err(req, errno);
8286881f68fSopenharmony_ci
8296881f68fSopenharmony_ci	fi->fh = fd;
8306881f68fSopenharmony_ci	if (lo->cache == CACHE_NEVER)
8316881f68fSopenharmony_ci		fi->direct_io = 1;
8326881f68fSopenharmony_ci	else if (lo->cache == CACHE_ALWAYS)
8336881f68fSopenharmony_ci		fi->keep_cache = 1;
8346881f68fSopenharmony_ci	fuse_reply_open(req, fi);
8356881f68fSopenharmony_ci}
8366881f68fSopenharmony_ci
8376881f68fSopenharmony_cistatic void lo_release(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
8386881f68fSopenharmony_ci{
8396881f68fSopenharmony_ci	(void) ino;
8406881f68fSopenharmony_ci
8416881f68fSopenharmony_ci	close(fi->fh);
8426881f68fSopenharmony_ci	fuse_reply_err(req, 0);
8436881f68fSopenharmony_ci}
8446881f68fSopenharmony_ci
8456881f68fSopenharmony_cistatic void lo_flush(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
8466881f68fSopenharmony_ci{
8476881f68fSopenharmony_ci	int res;
8486881f68fSopenharmony_ci	(void) ino;
8496881f68fSopenharmony_ci	res = close(dup(fi->fh));
8506881f68fSopenharmony_ci	fuse_reply_err(req, res == -1 ? errno : 0);
8516881f68fSopenharmony_ci}
8526881f68fSopenharmony_ci
8536881f68fSopenharmony_cistatic void lo_fsync(fuse_req_t req, fuse_ino_t ino, int datasync,
8546881f68fSopenharmony_ci		     struct fuse_file_info *fi)
8556881f68fSopenharmony_ci{
8566881f68fSopenharmony_ci	int res;
8576881f68fSopenharmony_ci	(void) ino;
8586881f68fSopenharmony_ci	if (datasync)
8596881f68fSopenharmony_ci		res = fdatasync(fi->fh);
8606881f68fSopenharmony_ci	else
8616881f68fSopenharmony_ci		res = fsync(fi->fh);
8626881f68fSopenharmony_ci	fuse_reply_err(req, res == -1 ? errno : 0);
8636881f68fSopenharmony_ci}
8646881f68fSopenharmony_ci
8656881f68fSopenharmony_cistatic void lo_read(fuse_req_t req, fuse_ino_t ino, size_t size,
8666881f68fSopenharmony_ci		    off_t offset, struct fuse_file_info *fi)
8676881f68fSopenharmony_ci{
8686881f68fSopenharmony_ci	struct fuse_bufvec buf = FUSE_BUFVEC_INIT(size);
8696881f68fSopenharmony_ci
8706881f68fSopenharmony_ci	if (lo_debug(req))
8716881f68fSopenharmony_ci		fuse_log(FUSE_LOG_DEBUG, "lo_read(ino=%" PRIu64 ", size=%zd, "
8726881f68fSopenharmony_ci			"off=%lu)\n", ino, size, (unsigned long) offset);
8736881f68fSopenharmony_ci
8746881f68fSopenharmony_ci	buf.buf[0].flags = FUSE_BUF_IS_FD | FUSE_BUF_FD_SEEK;
8756881f68fSopenharmony_ci	buf.buf[0].fd = fi->fh;
8766881f68fSopenharmony_ci	buf.buf[0].pos = offset;
8776881f68fSopenharmony_ci
8786881f68fSopenharmony_ci	fuse_reply_data(req, &buf, FUSE_BUF_SPLICE_MOVE);
8796881f68fSopenharmony_ci}
8806881f68fSopenharmony_ci
8816881f68fSopenharmony_cistatic void lo_write_buf(fuse_req_t req, fuse_ino_t ino,
8826881f68fSopenharmony_ci			 struct fuse_bufvec *in_buf, off_t off,
8836881f68fSopenharmony_ci			 struct fuse_file_info *fi)
8846881f68fSopenharmony_ci{
8856881f68fSopenharmony_ci	(void) ino;
8866881f68fSopenharmony_ci	ssize_t res;
8876881f68fSopenharmony_ci	struct fuse_bufvec out_buf = FUSE_BUFVEC_INIT(fuse_buf_size(in_buf));
8886881f68fSopenharmony_ci
8896881f68fSopenharmony_ci	out_buf.buf[0].flags = FUSE_BUF_IS_FD | FUSE_BUF_FD_SEEK;
8906881f68fSopenharmony_ci	out_buf.buf[0].fd = fi->fh;
8916881f68fSopenharmony_ci	out_buf.buf[0].pos = off;
8926881f68fSopenharmony_ci
8936881f68fSopenharmony_ci	if (lo_debug(req))
8946881f68fSopenharmony_ci		fuse_log(FUSE_LOG_DEBUG, "lo_write(ino=%" PRIu64 ", size=%zd, off=%lu)\n",
8956881f68fSopenharmony_ci			ino, out_buf.buf[0].size, (unsigned long) off);
8966881f68fSopenharmony_ci
8976881f68fSopenharmony_ci	res = fuse_buf_copy(&out_buf, in_buf, 0);
8986881f68fSopenharmony_ci	if(res < 0)
8996881f68fSopenharmony_ci		fuse_reply_err(req, -res);
9006881f68fSopenharmony_ci	else
9016881f68fSopenharmony_ci		fuse_reply_write(req, (size_t) res);
9026881f68fSopenharmony_ci}
9036881f68fSopenharmony_ci
9046881f68fSopenharmony_cistatic void lo_statfs(fuse_req_t req, fuse_ino_t ino)
9056881f68fSopenharmony_ci{
9066881f68fSopenharmony_ci	int res;
9076881f68fSopenharmony_ci	struct statvfs stbuf;
9086881f68fSopenharmony_ci
9096881f68fSopenharmony_ci	res = fstatvfs(lo_fd(req, ino), &stbuf);
9106881f68fSopenharmony_ci	if (res == -1)
9116881f68fSopenharmony_ci		fuse_reply_err(req, errno);
9126881f68fSopenharmony_ci	else
9136881f68fSopenharmony_ci		fuse_reply_statfs(req, &stbuf);
9146881f68fSopenharmony_ci}
9156881f68fSopenharmony_ci
9166881f68fSopenharmony_cistatic void lo_fallocate(fuse_req_t req, fuse_ino_t ino, int mode,
9176881f68fSopenharmony_ci			 off_t offset, off_t length, struct fuse_file_info *fi)
9186881f68fSopenharmony_ci{
9196881f68fSopenharmony_ci	int err = EOPNOTSUPP;
9206881f68fSopenharmony_ci	(void) ino;
9216881f68fSopenharmony_ci
9226881f68fSopenharmony_ci#ifdef HAVE_FALLOCATE
9236881f68fSopenharmony_ci	err = fallocate(fi->fh, mode, offset, length);
9246881f68fSopenharmony_ci	if (err < 0)
9256881f68fSopenharmony_ci		err = errno;
9266881f68fSopenharmony_ci
9276881f68fSopenharmony_ci#elif defined(HAVE_POSIX_FALLOCATE)
9286881f68fSopenharmony_ci	if (mode) {
9296881f68fSopenharmony_ci		fuse_reply_err(req, EOPNOTSUPP);
9306881f68fSopenharmony_ci		return;
9316881f68fSopenharmony_ci	}
9326881f68fSopenharmony_ci
9336881f68fSopenharmony_ci	err = posix_fallocate(fi->fh, offset, length);
9346881f68fSopenharmony_ci#endif
9356881f68fSopenharmony_ci
9366881f68fSopenharmony_ci	fuse_reply_err(req, err);
9376881f68fSopenharmony_ci}
9386881f68fSopenharmony_ci
9396881f68fSopenharmony_cistatic void lo_flock(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi,
9406881f68fSopenharmony_ci		     int op)
9416881f68fSopenharmony_ci{
9426881f68fSopenharmony_ci	int res;
9436881f68fSopenharmony_ci	(void) ino;
9446881f68fSopenharmony_ci
9456881f68fSopenharmony_ci	res = flock(fi->fh, op);
9466881f68fSopenharmony_ci
9476881f68fSopenharmony_ci	fuse_reply_err(req, res == -1 ? errno : 0);
9486881f68fSopenharmony_ci}
9496881f68fSopenharmony_ci
9506881f68fSopenharmony_cistatic void lo_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
9516881f68fSopenharmony_ci			size_t size)
9526881f68fSopenharmony_ci{
9536881f68fSopenharmony_ci	char *value = NULL;
9546881f68fSopenharmony_ci	char procname[64];
9556881f68fSopenharmony_ci	struct lo_inode *inode = lo_inode(req, ino);
9566881f68fSopenharmony_ci	ssize_t ret;
9576881f68fSopenharmony_ci	int saverr;
9586881f68fSopenharmony_ci
9596881f68fSopenharmony_ci	saverr = ENOSYS;
9606881f68fSopenharmony_ci	if (!lo_data(req)->xattr)
9616881f68fSopenharmony_ci		goto out;
9626881f68fSopenharmony_ci
9636881f68fSopenharmony_ci	if (lo_debug(req)) {
9646881f68fSopenharmony_ci		fuse_log(FUSE_LOG_DEBUG, "lo_getxattr(ino=%" PRIu64 ", name=%s size=%zd)\n",
9656881f68fSopenharmony_ci			ino, name, size);
9666881f68fSopenharmony_ci	}
9676881f68fSopenharmony_ci
9686881f68fSopenharmony_ci	sprintf(procname, "/proc/self/fd/%i", inode->fd);
9696881f68fSopenharmony_ci
9706881f68fSopenharmony_ci	if (size) {
9716881f68fSopenharmony_ci		value = malloc(size);
9726881f68fSopenharmony_ci		if (!value)
9736881f68fSopenharmony_ci			goto out_err;
9746881f68fSopenharmony_ci
9756881f68fSopenharmony_ci		ret = getxattr(procname, name, value, size);
9766881f68fSopenharmony_ci		if (ret == -1)
9776881f68fSopenharmony_ci			goto out_err;
9786881f68fSopenharmony_ci		saverr = 0;
9796881f68fSopenharmony_ci		if (ret == 0)
9806881f68fSopenharmony_ci			goto out;
9816881f68fSopenharmony_ci
9826881f68fSopenharmony_ci		fuse_reply_buf(req, value, ret);
9836881f68fSopenharmony_ci	} else {
9846881f68fSopenharmony_ci		ret = getxattr(procname, name, NULL, 0);
9856881f68fSopenharmony_ci		if (ret == -1)
9866881f68fSopenharmony_ci			goto out_err;
9876881f68fSopenharmony_ci
9886881f68fSopenharmony_ci		fuse_reply_xattr(req, ret);
9896881f68fSopenharmony_ci	}
9906881f68fSopenharmony_ciout_free:
9916881f68fSopenharmony_ci	free(value);
9926881f68fSopenharmony_ci	return;
9936881f68fSopenharmony_ci
9946881f68fSopenharmony_ciout_err:
9956881f68fSopenharmony_ci	saverr = errno;
9966881f68fSopenharmony_ciout:
9976881f68fSopenharmony_ci	fuse_reply_err(req, saverr);
9986881f68fSopenharmony_ci	goto out_free;
9996881f68fSopenharmony_ci}
10006881f68fSopenharmony_ci
10016881f68fSopenharmony_cistatic void lo_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size)
10026881f68fSopenharmony_ci{
10036881f68fSopenharmony_ci	char *value = NULL;
10046881f68fSopenharmony_ci	char procname[64];
10056881f68fSopenharmony_ci	struct lo_inode *inode = lo_inode(req, ino);
10066881f68fSopenharmony_ci	ssize_t ret;
10076881f68fSopenharmony_ci	int saverr;
10086881f68fSopenharmony_ci
10096881f68fSopenharmony_ci	saverr = ENOSYS;
10106881f68fSopenharmony_ci	if (!lo_data(req)->xattr)
10116881f68fSopenharmony_ci		goto out;
10126881f68fSopenharmony_ci
10136881f68fSopenharmony_ci	if (lo_debug(req)) {
10146881f68fSopenharmony_ci		fuse_log(FUSE_LOG_DEBUG, "lo_listxattr(ino=%" PRIu64 ", size=%zd)\n",
10156881f68fSopenharmony_ci			ino, size);
10166881f68fSopenharmony_ci	}
10176881f68fSopenharmony_ci
10186881f68fSopenharmony_ci	sprintf(procname, "/proc/self/fd/%i", inode->fd);
10196881f68fSopenharmony_ci
10206881f68fSopenharmony_ci	if (size) {
10216881f68fSopenharmony_ci		value = malloc(size);
10226881f68fSopenharmony_ci		if (!value)
10236881f68fSopenharmony_ci			goto out_err;
10246881f68fSopenharmony_ci
10256881f68fSopenharmony_ci		ret = listxattr(procname, value, size);
10266881f68fSopenharmony_ci		if (ret == -1)
10276881f68fSopenharmony_ci			goto out_err;
10286881f68fSopenharmony_ci		saverr = 0;
10296881f68fSopenharmony_ci		if (ret == 0)
10306881f68fSopenharmony_ci			goto out;
10316881f68fSopenharmony_ci
10326881f68fSopenharmony_ci		fuse_reply_buf(req, value, ret);
10336881f68fSopenharmony_ci	} else {
10346881f68fSopenharmony_ci		ret = listxattr(procname, NULL, 0);
10356881f68fSopenharmony_ci		if (ret == -1)
10366881f68fSopenharmony_ci			goto out_err;
10376881f68fSopenharmony_ci
10386881f68fSopenharmony_ci		fuse_reply_xattr(req, ret);
10396881f68fSopenharmony_ci	}
10406881f68fSopenharmony_ciout_free:
10416881f68fSopenharmony_ci	free(value);
10426881f68fSopenharmony_ci	return;
10436881f68fSopenharmony_ci
10446881f68fSopenharmony_ciout_err:
10456881f68fSopenharmony_ci	saverr = errno;
10466881f68fSopenharmony_ciout:
10476881f68fSopenharmony_ci	fuse_reply_err(req, saverr);
10486881f68fSopenharmony_ci	goto out_free;
10496881f68fSopenharmony_ci}
10506881f68fSopenharmony_ci
10516881f68fSopenharmony_cistatic void lo_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
10526881f68fSopenharmony_ci			const char *value, size_t size, int flags)
10536881f68fSopenharmony_ci{
10546881f68fSopenharmony_ci	char procname[64];
10556881f68fSopenharmony_ci	struct lo_inode *inode = lo_inode(req, ino);
10566881f68fSopenharmony_ci	ssize_t ret;
10576881f68fSopenharmony_ci	int saverr;
10586881f68fSopenharmony_ci
10596881f68fSopenharmony_ci	saverr = ENOSYS;
10606881f68fSopenharmony_ci	if (!lo_data(req)->xattr)
10616881f68fSopenharmony_ci		goto out;
10626881f68fSopenharmony_ci
10636881f68fSopenharmony_ci	if (lo_debug(req)) {
10646881f68fSopenharmony_ci		fuse_log(FUSE_LOG_DEBUG, "lo_setxattr(ino=%" PRIu64 ", name=%s value=%s size=%zd)\n",
10656881f68fSopenharmony_ci			ino, name, value, size);
10666881f68fSopenharmony_ci	}
10676881f68fSopenharmony_ci
10686881f68fSopenharmony_ci	sprintf(procname, "/proc/self/fd/%i", inode->fd);
10696881f68fSopenharmony_ci
10706881f68fSopenharmony_ci	ret = setxattr(procname, name, value, size, flags);
10716881f68fSopenharmony_ci	saverr = ret == -1 ? errno : 0;
10726881f68fSopenharmony_ci
10736881f68fSopenharmony_ciout:
10746881f68fSopenharmony_ci	fuse_reply_err(req, saverr);
10756881f68fSopenharmony_ci}
10766881f68fSopenharmony_ci
10776881f68fSopenharmony_cistatic void lo_removexattr(fuse_req_t req, fuse_ino_t ino, const char *name)
10786881f68fSopenharmony_ci{
10796881f68fSopenharmony_ci	char procname[64];
10806881f68fSopenharmony_ci	struct lo_inode *inode = lo_inode(req, ino);
10816881f68fSopenharmony_ci	ssize_t ret;
10826881f68fSopenharmony_ci	int saverr;
10836881f68fSopenharmony_ci
10846881f68fSopenharmony_ci	saverr = ENOSYS;
10856881f68fSopenharmony_ci	if (!lo_data(req)->xattr)
10866881f68fSopenharmony_ci		goto out;
10876881f68fSopenharmony_ci
10886881f68fSopenharmony_ci	if (lo_debug(req)) {
10896881f68fSopenharmony_ci		fuse_log(FUSE_LOG_DEBUG, "lo_removexattr(ino=%" PRIu64 ", name=%s)\n",
10906881f68fSopenharmony_ci			ino, name);
10916881f68fSopenharmony_ci	}
10926881f68fSopenharmony_ci
10936881f68fSopenharmony_ci	sprintf(procname, "/proc/self/fd/%i", inode->fd);
10946881f68fSopenharmony_ci
10956881f68fSopenharmony_ci	ret = removexattr(procname, name);
10966881f68fSopenharmony_ci	saverr = ret == -1 ? errno : 0;
10976881f68fSopenharmony_ci
10986881f68fSopenharmony_ciout:
10996881f68fSopenharmony_ci	fuse_reply_err(req, saverr);
11006881f68fSopenharmony_ci}
11016881f68fSopenharmony_ci
11026881f68fSopenharmony_ci#ifdef HAVE_COPY_FILE_RANGE
11036881f68fSopenharmony_cistatic void lo_copy_file_range(fuse_req_t req, fuse_ino_t ino_in, off_t off_in,
11046881f68fSopenharmony_ci			       struct fuse_file_info *fi_in,
11056881f68fSopenharmony_ci			       fuse_ino_t ino_out, off_t off_out,
11066881f68fSopenharmony_ci			       struct fuse_file_info *fi_out, size_t len,
11076881f68fSopenharmony_ci			       int flags)
11086881f68fSopenharmony_ci{
11096881f68fSopenharmony_ci	ssize_t res;
11106881f68fSopenharmony_ci
11116881f68fSopenharmony_ci	if (lo_debug(req))
11126881f68fSopenharmony_ci		fuse_log(FUSE_LOG_DEBUG, "lo_copy_file_range(ino=%" PRIu64 "/fd=%lu, "
11136881f68fSopenharmony_ci				"off=%lu, ino=%" PRIu64 "/fd=%lu, "
11146881f68fSopenharmony_ci				"off=%lu, size=%zd, flags=0x%x)\n",
11156881f68fSopenharmony_ci			ino_in, fi_in->fh, off_in, ino_out, fi_out->fh, off_out,
11166881f68fSopenharmony_ci			len, flags);
11176881f68fSopenharmony_ci
11186881f68fSopenharmony_ci	res = copy_file_range(fi_in->fh, &off_in, fi_out->fh, &off_out, len,
11196881f68fSopenharmony_ci			      flags);
11206881f68fSopenharmony_ci	if (res < 0)
11216881f68fSopenharmony_ci		fuse_reply_err(req, errno);
11226881f68fSopenharmony_ci	else
11236881f68fSopenharmony_ci		fuse_reply_write(req, res);
11246881f68fSopenharmony_ci}
11256881f68fSopenharmony_ci#endif
11266881f68fSopenharmony_ci
11276881f68fSopenharmony_cistatic void lo_lseek(fuse_req_t req, fuse_ino_t ino, off_t off, int whence,
11286881f68fSopenharmony_ci		     struct fuse_file_info *fi)
11296881f68fSopenharmony_ci{
11306881f68fSopenharmony_ci	off_t res;
11316881f68fSopenharmony_ci
11326881f68fSopenharmony_ci	(void)ino;
11336881f68fSopenharmony_ci	res = lseek(fi->fh, off, whence);
11346881f68fSopenharmony_ci	if (res != -1)
11356881f68fSopenharmony_ci		fuse_reply_lseek(req, res);
11366881f68fSopenharmony_ci	else
11376881f68fSopenharmony_ci		fuse_reply_err(req, errno);
11386881f68fSopenharmony_ci}
11396881f68fSopenharmony_ci
11406881f68fSopenharmony_cistatic const struct fuse_lowlevel_ops lo_oper = {
11416881f68fSopenharmony_ci	.init		= lo_init,
11426881f68fSopenharmony_ci	.destroy	= lo_destroy,
11436881f68fSopenharmony_ci	.lookup		= lo_lookup,
11446881f68fSopenharmony_ci	.mkdir		= lo_mkdir,
11456881f68fSopenharmony_ci	.mknod		= lo_mknod,
11466881f68fSopenharmony_ci	.symlink	= lo_symlink,
11476881f68fSopenharmony_ci	.link		= lo_link,
11486881f68fSopenharmony_ci	.unlink		= lo_unlink,
11496881f68fSopenharmony_ci	.rmdir		= lo_rmdir,
11506881f68fSopenharmony_ci	.rename		= lo_rename,
11516881f68fSopenharmony_ci	.forget		= lo_forget,
11526881f68fSopenharmony_ci	.forget_multi	= lo_forget_multi,
11536881f68fSopenharmony_ci	.getattr	= lo_getattr,
11546881f68fSopenharmony_ci	.setattr	= lo_setattr,
11556881f68fSopenharmony_ci	.readlink	= lo_readlink,
11566881f68fSopenharmony_ci	.opendir	= lo_opendir,
11576881f68fSopenharmony_ci	.readdir	= lo_readdir,
11586881f68fSopenharmony_ci	.readdirplus	= lo_readdirplus,
11596881f68fSopenharmony_ci	.releasedir	= lo_releasedir,
11606881f68fSopenharmony_ci	.fsyncdir	= lo_fsyncdir,
11616881f68fSopenharmony_ci	.create		= lo_create,
11626881f68fSopenharmony_ci	.open		= lo_open,
11636881f68fSopenharmony_ci	.release	= lo_release,
11646881f68fSopenharmony_ci	.flush		= lo_flush,
11656881f68fSopenharmony_ci	.fsync		= lo_fsync,
11666881f68fSopenharmony_ci	.read		= lo_read,
11676881f68fSopenharmony_ci	.write_buf      = lo_write_buf,
11686881f68fSopenharmony_ci	.statfs		= lo_statfs,
11696881f68fSopenharmony_ci	.fallocate	= lo_fallocate,
11706881f68fSopenharmony_ci	.flock		= lo_flock,
11716881f68fSopenharmony_ci	.getxattr	= lo_getxattr,
11726881f68fSopenharmony_ci	.listxattr	= lo_listxattr,
11736881f68fSopenharmony_ci	.setxattr	= lo_setxattr,
11746881f68fSopenharmony_ci	.removexattr	= lo_removexattr,
11756881f68fSopenharmony_ci#ifdef HAVE_COPY_FILE_RANGE
11766881f68fSopenharmony_ci	.copy_file_range = lo_copy_file_range,
11776881f68fSopenharmony_ci#endif
11786881f68fSopenharmony_ci	.lseek		= lo_lseek,
11796881f68fSopenharmony_ci};
11806881f68fSopenharmony_ci
11816881f68fSopenharmony_ciint main(int argc, char *argv[])
11826881f68fSopenharmony_ci{
11836881f68fSopenharmony_ci	struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
11846881f68fSopenharmony_ci	struct fuse_session *se;
11856881f68fSopenharmony_ci	struct fuse_cmdline_opts opts;
11866881f68fSopenharmony_ci	struct fuse_loop_config config;
11876881f68fSopenharmony_ci	struct lo_data lo = { .debug = 0,
11886881f68fSopenharmony_ci	                      .writeback = 0 };
11896881f68fSopenharmony_ci	int ret = -1;
11906881f68fSopenharmony_ci
11916881f68fSopenharmony_ci	/* Don't mask creation mode, kernel already did that */
11926881f68fSopenharmony_ci	umask(0);
11936881f68fSopenharmony_ci
11946881f68fSopenharmony_ci	pthread_mutex_init(&lo.mutex, NULL);
11956881f68fSopenharmony_ci	lo.root.next = lo.root.prev = &lo.root;
11966881f68fSopenharmony_ci	lo.root.fd = -1;
11976881f68fSopenharmony_ci	lo.cache = CACHE_NORMAL;
11986881f68fSopenharmony_ci
11996881f68fSopenharmony_ci	if (fuse_parse_cmdline(&args, &opts) != 0)
12006881f68fSopenharmony_ci		return 1;
12016881f68fSopenharmony_ci	if (opts.show_help) {
12026881f68fSopenharmony_ci		printf("usage: %s [options] <mountpoint>\n\n", argv[0]);
12036881f68fSopenharmony_ci		fuse_cmdline_help();
12046881f68fSopenharmony_ci		fuse_lowlevel_help();
12056881f68fSopenharmony_ci		passthrough_ll_help();
12066881f68fSopenharmony_ci		ret = 0;
12076881f68fSopenharmony_ci		goto err_out1;
12086881f68fSopenharmony_ci	} else if (opts.show_version) {
12096881f68fSopenharmony_ci		printf("FUSE library version %s\n", fuse_pkgversion());
12106881f68fSopenharmony_ci		fuse_lowlevel_version();
12116881f68fSopenharmony_ci		ret = 0;
12126881f68fSopenharmony_ci		goto err_out1;
12136881f68fSopenharmony_ci	}
12146881f68fSopenharmony_ci
12156881f68fSopenharmony_ci	if(opts.mountpoint == NULL) {
12166881f68fSopenharmony_ci		printf("usage: %s [options] <mountpoint>\n", argv[0]);
12176881f68fSopenharmony_ci		printf("       %s --help\n", argv[0]);
12186881f68fSopenharmony_ci		ret = 1;
12196881f68fSopenharmony_ci		goto err_out1;
12206881f68fSopenharmony_ci	}
12216881f68fSopenharmony_ci
12226881f68fSopenharmony_ci	if (fuse_opt_parse(&args, &lo, lo_opts, NULL)== -1)
12236881f68fSopenharmony_ci		return 1;
12246881f68fSopenharmony_ci
12256881f68fSopenharmony_ci	lo.debug = opts.debug;
12266881f68fSopenharmony_ci	lo.root.refcount = 2;
12276881f68fSopenharmony_ci	if (lo.source) {
12286881f68fSopenharmony_ci		struct stat stat;
12296881f68fSopenharmony_ci		int res;
12306881f68fSopenharmony_ci
12316881f68fSopenharmony_ci		res = lstat(lo.source, &stat);
12326881f68fSopenharmony_ci		if (res == -1) {
12336881f68fSopenharmony_ci			fuse_log(FUSE_LOG_ERR, "failed to stat source (\"%s\"): %m\n",
12346881f68fSopenharmony_ci				 lo.source);
12356881f68fSopenharmony_ci			exit(1);
12366881f68fSopenharmony_ci		}
12376881f68fSopenharmony_ci		if (!S_ISDIR(stat.st_mode)) {
12386881f68fSopenharmony_ci			fuse_log(FUSE_LOG_ERR, "source is not a directory\n");
12396881f68fSopenharmony_ci			exit(1);
12406881f68fSopenharmony_ci		}
12416881f68fSopenharmony_ci
12426881f68fSopenharmony_ci	} else {
12436881f68fSopenharmony_ci		lo.source = strdup("/");
12446881f68fSopenharmony_ci		if(!lo.source) {
12456881f68fSopenharmony_ci			fuse_log(FUSE_LOG_ERR, "fuse: memory allocation failed\n");
12466881f68fSopenharmony_ci			exit(1);
12476881f68fSopenharmony_ci		}
12486881f68fSopenharmony_ci	}
12496881f68fSopenharmony_ci	if (!lo.timeout_set) {
12506881f68fSopenharmony_ci		switch (lo.cache) {
12516881f68fSopenharmony_ci		case CACHE_NEVER:
12526881f68fSopenharmony_ci			lo.timeout = 0.0;
12536881f68fSopenharmony_ci			break;
12546881f68fSopenharmony_ci
12556881f68fSopenharmony_ci		case CACHE_NORMAL:
12566881f68fSopenharmony_ci			lo.timeout = 1.0;
12576881f68fSopenharmony_ci			break;
12586881f68fSopenharmony_ci
12596881f68fSopenharmony_ci		case CACHE_ALWAYS:
12606881f68fSopenharmony_ci			lo.timeout = 86400.0;
12616881f68fSopenharmony_ci			break;
12626881f68fSopenharmony_ci		}
12636881f68fSopenharmony_ci	} else if (lo.timeout < 0) {
12646881f68fSopenharmony_ci		fuse_log(FUSE_LOG_ERR, "timeout is negative (%lf)\n",
12656881f68fSopenharmony_ci			 lo.timeout);
12666881f68fSopenharmony_ci		exit(1);
12676881f68fSopenharmony_ci	}
12686881f68fSopenharmony_ci
12696881f68fSopenharmony_ci	lo.root.fd = open(lo.source, O_PATH);
12706881f68fSopenharmony_ci	if (lo.root.fd == -1) {
12716881f68fSopenharmony_ci		fuse_log(FUSE_LOG_ERR, "open(\"%s\", O_PATH): %m\n",
12726881f68fSopenharmony_ci			 lo.source);
12736881f68fSopenharmony_ci		exit(1);
12746881f68fSopenharmony_ci	}
12756881f68fSopenharmony_ci
12766881f68fSopenharmony_ci	se = fuse_session_new(&args, &lo_oper, sizeof(lo_oper), &lo);
12776881f68fSopenharmony_ci	if (se == NULL)
12786881f68fSopenharmony_ci	    goto err_out1;
12796881f68fSopenharmony_ci
12806881f68fSopenharmony_ci	if (fuse_set_signal_handlers(se) != 0)
12816881f68fSopenharmony_ci	    goto err_out2;
12826881f68fSopenharmony_ci
12836881f68fSopenharmony_ci	if (fuse_session_mount(se, opts.mountpoint) != 0)
12846881f68fSopenharmony_ci	    goto err_out3;
12856881f68fSopenharmony_ci
12866881f68fSopenharmony_ci	fuse_daemonize(opts.foreground);
12876881f68fSopenharmony_ci
12886881f68fSopenharmony_ci	/* Block until ctrl+c or fusermount -u */
12896881f68fSopenharmony_ci	if (opts.singlethread)
12906881f68fSopenharmony_ci		ret = fuse_session_loop(se);
12916881f68fSopenharmony_ci	else {
12926881f68fSopenharmony_ci		config.clone_fd = opts.clone_fd;
12936881f68fSopenharmony_ci		config.max_idle_threads = opts.max_idle_threads;
12946881f68fSopenharmony_ci		ret = fuse_session_loop_mt(se, &config);
12956881f68fSopenharmony_ci	}
12966881f68fSopenharmony_ci
12976881f68fSopenharmony_ci	fuse_session_unmount(se);
12986881f68fSopenharmony_cierr_out3:
12996881f68fSopenharmony_ci	fuse_remove_signal_handlers(se);
13006881f68fSopenharmony_cierr_out2:
13016881f68fSopenharmony_ci	fuse_session_destroy(se);
13026881f68fSopenharmony_cierr_out1:
13036881f68fSopenharmony_ci	free(opts.mountpoint);
13046881f68fSopenharmony_ci	fuse_opt_free_args(&args);
13056881f68fSopenharmony_ci
13066881f68fSopenharmony_ci	if (lo.root.fd >= 0)
13076881f68fSopenharmony_ci		close(lo.root.fd);
13086881f68fSopenharmony_ci
13096881f68fSopenharmony_ci	free(lo.source);
13106881f68fSopenharmony_ci	return ret ? 1 : 0;
13116881f68fSopenharmony_ci}
1312