16881f68fSopenharmony_ci/*
26881f68fSopenharmony_ci  FUSE: Filesystem in Userspace
36881f68fSopenharmony_ci  Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
46881f68fSopenharmony_ci
56881f68fSopenharmony_ci  Implementation of (most of) the low-level FUSE API. The session loop
66881f68fSopenharmony_ci  functions are implemented in separate files.
76881f68fSopenharmony_ci
86881f68fSopenharmony_ci  This program can be distributed under the terms of the GNU LGPLv2.
96881f68fSopenharmony_ci  See the file COPYING.LIB
106881f68fSopenharmony_ci*/
116881f68fSopenharmony_ci
126881f68fSopenharmony_ci#define _GNU_SOURCE
136881f68fSopenharmony_ci
146881f68fSopenharmony_ci#include "fuse_config.h"
156881f68fSopenharmony_ci#include "fuse_i.h"
166881f68fSopenharmony_ci#include "fuse_kernel.h"
176881f68fSopenharmony_ci#include "fuse_opt.h"
186881f68fSopenharmony_ci#include "fuse_misc.h"
196881f68fSopenharmony_ci#include "mount_util.h"
206881f68fSopenharmony_ci
216881f68fSopenharmony_ci#include <stdio.h>
226881f68fSopenharmony_ci#include <stdlib.h>
236881f68fSopenharmony_ci#include <stddef.h>
246881f68fSopenharmony_ci#include <string.h>
256881f68fSopenharmony_ci#include <unistd.h>
266881f68fSopenharmony_ci#include <limits.h>
276881f68fSopenharmony_ci#include <errno.h>
286881f68fSopenharmony_ci#include <assert.h>
296881f68fSopenharmony_ci#include <sys/file.h>
306881f68fSopenharmony_ci
316881f68fSopenharmony_ci#ifndef F_LINUX_SPECIFIC_BASE
326881f68fSopenharmony_ci#define F_LINUX_SPECIFIC_BASE       1024
336881f68fSopenharmony_ci#endif
346881f68fSopenharmony_ci#ifndef F_SETPIPE_SZ
356881f68fSopenharmony_ci#define F_SETPIPE_SZ	(F_LINUX_SPECIFIC_BASE + 7)
366881f68fSopenharmony_ci#endif
376881f68fSopenharmony_ci
386881f68fSopenharmony_ci
396881f68fSopenharmony_ci#define PARAM(inarg) (((char *)(inarg)) + sizeof(*(inarg)))
406881f68fSopenharmony_ci#define OFFSET_MAX 0x7fffffffffffffffLL
416881f68fSopenharmony_ci
426881f68fSopenharmony_ci#define container_of(ptr, type, member) ({				\
436881f68fSopenharmony_ci			const typeof( ((type *)0)->member ) *__mptr = (ptr); \
446881f68fSopenharmony_ci			(type *)( (char *)__mptr - offsetof(type,member) );})
456881f68fSopenharmony_ci
466881f68fSopenharmony_cistruct fuse_pollhandle {
476881f68fSopenharmony_ci	uint64_t kh;
486881f68fSopenharmony_ci	struct fuse_session *se;
496881f68fSopenharmony_ci};
506881f68fSopenharmony_ci
516881f68fSopenharmony_cistatic size_t pagesize;
526881f68fSopenharmony_ci
536881f68fSopenharmony_cistatic __attribute__((constructor)) void fuse_ll_init_pagesize(void)
546881f68fSopenharmony_ci{
556881f68fSopenharmony_ci	pagesize = getpagesize();
566881f68fSopenharmony_ci}
576881f68fSopenharmony_ci
586881f68fSopenharmony_cistatic void convert_stat(const struct stat *stbuf, struct fuse_attr *attr)
596881f68fSopenharmony_ci{
606881f68fSopenharmony_ci	attr->ino	= stbuf->st_ino;
616881f68fSopenharmony_ci	attr->mode	= stbuf->st_mode;
626881f68fSopenharmony_ci	attr->nlink	= stbuf->st_nlink;
636881f68fSopenharmony_ci	attr->uid	= stbuf->st_uid;
646881f68fSopenharmony_ci	attr->gid	= stbuf->st_gid;
656881f68fSopenharmony_ci	attr->rdev	= stbuf->st_rdev;
666881f68fSopenharmony_ci	attr->size	= stbuf->st_size;
676881f68fSopenharmony_ci	attr->blksize	= stbuf->st_blksize;
686881f68fSopenharmony_ci	attr->blocks	= stbuf->st_blocks;
696881f68fSopenharmony_ci	attr->atime	= stbuf->st_atime;
706881f68fSopenharmony_ci	attr->mtime	= stbuf->st_mtime;
716881f68fSopenharmony_ci	attr->ctime	= stbuf->st_ctime;
726881f68fSopenharmony_ci	attr->atimensec = ST_ATIM_NSEC(stbuf);
736881f68fSopenharmony_ci	attr->mtimensec = ST_MTIM_NSEC(stbuf);
746881f68fSopenharmony_ci	attr->ctimensec = ST_CTIM_NSEC(stbuf);
756881f68fSopenharmony_ci}
766881f68fSopenharmony_ci
776881f68fSopenharmony_cistatic void convert_attr(const struct fuse_setattr_in *attr, struct stat *stbuf)
786881f68fSopenharmony_ci{
796881f68fSopenharmony_ci	stbuf->st_mode	       = attr->mode;
806881f68fSopenharmony_ci	stbuf->st_uid	       = attr->uid;
816881f68fSopenharmony_ci	stbuf->st_gid	       = attr->gid;
826881f68fSopenharmony_ci	stbuf->st_size	       = attr->size;
836881f68fSopenharmony_ci	stbuf->st_atime	       = attr->atime;
846881f68fSopenharmony_ci	stbuf->st_mtime	       = attr->mtime;
856881f68fSopenharmony_ci	stbuf->st_ctime        = attr->ctime;
866881f68fSopenharmony_ci	ST_ATIM_NSEC_SET(stbuf, attr->atimensec);
876881f68fSopenharmony_ci	ST_MTIM_NSEC_SET(stbuf, attr->mtimensec);
886881f68fSopenharmony_ci	ST_CTIM_NSEC_SET(stbuf, attr->ctimensec);
896881f68fSopenharmony_ci}
906881f68fSopenharmony_ci
916881f68fSopenharmony_cistatic	size_t iov_length(const struct iovec *iov, size_t count)
926881f68fSopenharmony_ci{
936881f68fSopenharmony_ci	size_t seg;
946881f68fSopenharmony_ci	size_t ret = 0;
956881f68fSopenharmony_ci
966881f68fSopenharmony_ci	for (seg = 0; seg < count; seg++)
976881f68fSopenharmony_ci		ret += iov[seg].iov_len;
986881f68fSopenharmony_ci	return ret;
996881f68fSopenharmony_ci}
1006881f68fSopenharmony_ci
1016881f68fSopenharmony_cistatic void list_init_req(struct fuse_req *req)
1026881f68fSopenharmony_ci{
1036881f68fSopenharmony_ci	req->next = req;
1046881f68fSopenharmony_ci	req->prev = req;
1056881f68fSopenharmony_ci}
1066881f68fSopenharmony_ci
1076881f68fSopenharmony_cistatic void list_del_req(struct fuse_req *req)
1086881f68fSopenharmony_ci{
1096881f68fSopenharmony_ci	struct fuse_req *prev = req->prev;
1106881f68fSopenharmony_ci	struct fuse_req *next = req->next;
1116881f68fSopenharmony_ci	prev->next = next;
1126881f68fSopenharmony_ci	next->prev = prev;
1136881f68fSopenharmony_ci}
1146881f68fSopenharmony_ci
1156881f68fSopenharmony_cistatic void list_add_req(struct fuse_req *req, struct fuse_req *next)
1166881f68fSopenharmony_ci{
1176881f68fSopenharmony_ci	struct fuse_req *prev = next->prev;
1186881f68fSopenharmony_ci	req->next = next;
1196881f68fSopenharmony_ci	req->prev = prev;
1206881f68fSopenharmony_ci	prev->next = req;
1216881f68fSopenharmony_ci	next->prev = req;
1226881f68fSopenharmony_ci}
1236881f68fSopenharmony_ci
1246881f68fSopenharmony_cistatic void destroy_req(fuse_req_t req)
1256881f68fSopenharmony_ci{
1266881f68fSopenharmony_ci	assert(req->ch == NULL);
1276881f68fSopenharmony_ci	pthread_mutex_destroy(&req->lock);
1286881f68fSopenharmony_ci	free(req);
1296881f68fSopenharmony_ci}
1306881f68fSopenharmony_ci
1316881f68fSopenharmony_civoid fuse_free_req(fuse_req_t req)
1326881f68fSopenharmony_ci{
1336881f68fSopenharmony_ci	int ctr;
1346881f68fSopenharmony_ci	struct fuse_session *se = req->se;
1356881f68fSopenharmony_ci
1366881f68fSopenharmony_ci	pthread_mutex_lock(&se->lock);
1376881f68fSopenharmony_ci	req->u.ni.func = NULL;
1386881f68fSopenharmony_ci	req->u.ni.data = NULL;
1396881f68fSopenharmony_ci	list_del_req(req);
1406881f68fSopenharmony_ci	ctr = --req->ctr;
1416881f68fSopenharmony_ci	fuse_chan_put(req->ch);
1426881f68fSopenharmony_ci	req->ch = NULL;
1436881f68fSopenharmony_ci	pthread_mutex_unlock(&se->lock);
1446881f68fSopenharmony_ci	if (!ctr)
1456881f68fSopenharmony_ci		destroy_req(req);
1466881f68fSopenharmony_ci}
1476881f68fSopenharmony_ci
1486881f68fSopenharmony_cistatic struct fuse_req *fuse_ll_alloc_req(struct fuse_session *se)
1496881f68fSopenharmony_ci{
1506881f68fSopenharmony_ci	struct fuse_req *req;
1516881f68fSopenharmony_ci
1526881f68fSopenharmony_ci	req = (struct fuse_req *) calloc(1, sizeof(struct fuse_req));
1536881f68fSopenharmony_ci	if (req == NULL) {
1546881f68fSopenharmony_ci		fuse_log(FUSE_LOG_ERR, "fuse: failed to allocate request\n");
1556881f68fSopenharmony_ci	} else {
1566881f68fSopenharmony_ci		req->se = se;
1576881f68fSopenharmony_ci		req->ctr = 1;
1586881f68fSopenharmony_ci		list_init_req(req);
1596881f68fSopenharmony_ci		pthread_mutex_init(&req->lock, NULL);
1606881f68fSopenharmony_ci	}
1616881f68fSopenharmony_ci
1626881f68fSopenharmony_ci	return req;
1636881f68fSopenharmony_ci}
1646881f68fSopenharmony_ci
1656881f68fSopenharmony_ci/* Send data. If *ch* is NULL, send via session master fd */
1666881f68fSopenharmony_cistatic int fuse_send_msg(struct fuse_session *se, struct fuse_chan *ch,
1676881f68fSopenharmony_ci			 struct iovec *iov, int count)
1686881f68fSopenharmony_ci{
1696881f68fSopenharmony_ci	struct fuse_out_header *out = iov[0].iov_base;
1706881f68fSopenharmony_ci
1716881f68fSopenharmony_ci	assert(se != NULL);
1726881f68fSopenharmony_ci	out->len = iov_length(iov, count);
1736881f68fSopenharmony_ci	if (se->debug) {
1746881f68fSopenharmony_ci		if (out->unique == 0) {
1756881f68fSopenharmony_ci			fuse_log(FUSE_LOG_DEBUG, "NOTIFY: code=%d length=%u\n",
1766881f68fSopenharmony_ci				out->error, out->len);
1776881f68fSopenharmony_ci		} else if (out->error) {
1786881f68fSopenharmony_ci			fuse_log(FUSE_LOG_DEBUG,
1796881f68fSopenharmony_ci				"   unique: %llu, error: %i (%s), outsize: %i\n",
1806881f68fSopenharmony_ci				(unsigned long long) out->unique, out->error,
1816881f68fSopenharmony_ci				strerror(-out->error), out->len);
1826881f68fSopenharmony_ci		} else {
1836881f68fSopenharmony_ci			fuse_log(FUSE_LOG_DEBUG,
1846881f68fSopenharmony_ci				"   unique: %llu, success, outsize: %i\n",
1856881f68fSopenharmony_ci				(unsigned long long) out->unique, out->len);
1866881f68fSopenharmony_ci		}
1876881f68fSopenharmony_ci	}
1886881f68fSopenharmony_ci
1896881f68fSopenharmony_ci	ssize_t res;
1906881f68fSopenharmony_ci	if (se->io != NULL)
1916881f68fSopenharmony_ci		/* se->io->writev is never NULL if se->io is not NULL as
1926881f68fSopenharmony_ci		specified by fuse_session_custom_io()*/
1936881f68fSopenharmony_ci		res = se->io->writev(ch ? ch->fd : se->fd, iov, count,
1946881f68fSopenharmony_ci					   se->userdata);
1956881f68fSopenharmony_ci	else
1966881f68fSopenharmony_ci		res = writev(ch ? ch->fd : se->fd, iov, count);
1976881f68fSopenharmony_ci
1986881f68fSopenharmony_ci	int err = errno;
1996881f68fSopenharmony_ci
2006881f68fSopenharmony_ci	if (res == -1) {
2016881f68fSopenharmony_ci		/* ENOENT means the operation was interrupted */
2026881f68fSopenharmony_ci		if (!fuse_session_exited(se) && err != ENOENT)
2036881f68fSopenharmony_ci			perror("fuse: writing device");
2046881f68fSopenharmony_ci		return -err;
2056881f68fSopenharmony_ci	}
2066881f68fSopenharmony_ci
2076881f68fSopenharmony_ci	return 0;
2086881f68fSopenharmony_ci}
2096881f68fSopenharmony_ci
2106881f68fSopenharmony_ci
2116881f68fSopenharmony_ciint fuse_send_reply_iov_nofree(fuse_req_t req, int error, struct iovec *iov,
2126881f68fSopenharmony_ci			       int count)
2136881f68fSopenharmony_ci{
2146881f68fSopenharmony_ci	struct fuse_out_header out;
2156881f68fSopenharmony_ci
2166881f68fSopenharmony_ci#if __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 32
2176881f68fSopenharmony_ci	const char *str = strerrordesc_np(error * -1);
2186881f68fSopenharmony_ci	if ((str == NULL && error != 0) || error > 0) {
2196881f68fSopenharmony_ci#else
2206881f68fSopenharmony_ci	if (error <= -1000 || error > 0) {
2216881f68fSopenharmony_ci#endif
2226881f68fSopenharmony_ci		fuse_log(FUSE_LOG_ERR, "fuse: bad error value: %i\n",	error);
2236881f68fSopenharmony_ci		error = -ERANGE;
2246881f68fSopenharmony_ci	}
2256881f68fSopenharmony_ci
2266881f68fSopenharmony_ci	out.unique = req->unique;
2276881f68fSopenharmony_ci	out.error = error;
2286881f68fSopenharmony_ci
2296881f68fSopenharmony_ci	iov[0].iov_base = &out;
2306881f68fSopenharmony_ci	iov[0].iov_len = sizeof(struct fuse_out_header);
2316881f68fSopenharmony_ci
2326881f68fSopenharmony_ci	return fuse_send_msg(req->se, req->ch, iov, count);
2336881f68fSopenharmony_ci}
2346881f68fSopenharmony_ci
2356881f68fSopenharmony_cistatic int send_reply_iov(fuse_req_t req, int error, struct iovec *iov,
2366881f68fSopenharmony_ci			  int count)
2376881f68fSopenharmony_ci{
2386881f68fSopenharmony_ci	int res;
2396881f68fSopenharmony_ci
2406881f68fSopenharmony_ci	res = fuse_send_reply_iov_nofree(req, error, iov, count);
2416881f68fSopenharmony_ci	fuse_free_req(req);
2426881f68fSopenharmony_ci	return res;
2436881f68fSopenharmony_ci}
2446881f68fSopenharmony_ci
2456881f68fSopenharmony_cistatic int send_reply(fuse_req_t req, int error, const void *arg,
2466881f68fSopenharmony_ci		      size_t argsize)
2476881f68fSopenharmony_ci{
2486881f68fSopenharmony_ci	struct iovec iov[2];
2496881f68fSopenharmony_ci	int count = 1;
2506881f68fSopenharmony_ci	if (argsize) {
2516881f68fSopenharmony_ci		iov[1].iov_base = (void *) arg;
2526881f68fSopenharmony_ci		iov[1].iov_len = argsize;
2536881f68fSopenharmony_ci		count++;
2546881f68fSopenharmony_ci	}
2556881f68fSopenharmony_ci	return send_reply_iov(req, error, iov, count);
2566881f68fSopenharmony_ci}
2576881f68fSopenharmony_ci
2586881f68fSopenharmony_ciint fuse_reply_iov(fuse_req_t req, const struct iovec *iov, int count)
2596881f68fSopenharmony_ci{
2606881f68fSopenharmony_ci	int res;
2616881f68fSopenharmony_ci	struct iovec *padded_iov;
2626881f68fSopenharmony_ci
2636881f68fSopenharmony_ci	padded_iov = malloc((count + 1) * sizeof(struct iovec));
2646881f68fSopenharmony_ci	if (padded_iov == NULL)
2656881f68fSopenharmony_ci		return fuse_reply_err(req, ENOMEM);
2666881f68fSopenharmony_ci
2676881f68fSopenharmony_ci	memcpy(padded_iov + 1, iov, count * sizeof(struct iovec));
2686881f68fSopenharmony_ci	count++;
2696881f68fSopenharmony_ci
2706881f68fSopenharmony_ci	res = send_reply_iov(req, 0, padded_iov, count);
2716881f68fSopenharmony_ci	free(padded_iov);
2726881f68fSopenharmony_ci
2736881f68fSopenharmony_ci	return res;
2746881f68fSopenharmony_ci}
2756881f68fSopenharmony_ci
2766881f68fSopenharmony_ci
2776881f68fSopenharmony_ci/* `buf` is allowed to be empty so that the proper size may be
2786881f68fSopenharmony_ci   allocated by the caller */
2796881f68fSopenharmony_cisize_t fuse_add_direntry(fuse_req_t req, char *buf, size_t bufsize,
2806881f68fSopenharmony_ci			 const char *name, const struct stat *stbuf, off_t off)
2816881f68fSopenharmony_ci{
2826881f68fSopenharmony_ci	(void)req;
2836881f68fSopenharmony_ci	size_t namelen;
2846881f68fSopenharmony_ci	size_t entlen;
2856881f68fSopenharmony_ci	size_t entlen_padded;
2866881f68fSopenharmony_ci	struct fuse_dirent *dirent;
2876881f68fSopenharmony_ci
2886881f68fSopenharmony_ci	namelen = strlen(name);
2896881f68fSopenharmony_ci	entlen = FUSE_NAME_OFFSET + namelen;
2906881f68fSopenharmony_ci	entlen_padded = FUSE_DIRENT_ALIGN(entlen);
2916881f68fSopenharmony_ci
2926881f68fSopenharmony_ci	if ((buf == NULL) || (entlen_padded > bufsize))
2936881f68fSopenharmony_ci	  return entlen_padded;
2946881f68fSopenharmony_ci
2956881f68fSopenharmony_ci	dirent = (struct fuse_dirent*) buf;
2966881f68fSopenharmony_ci	dirent->ino = stbuf->st_ino;
2976881f68fSopenharmony_ci	dirent->off = off;
2986881f68fSopenharmony_ci	dirent->namelen = namelen;
2996881f68fSopenharmony_ci	dirent->type = (stbuf->st_mode & S_IFMT) >> 12;
3006881f68fSopenharmony_ci	memcpy(dirent->name, name, namelen);
3016881f68fSopenharmony_ci	memset(dirent->name + namelen, 0, entlen_padded - entlen);
3026881f68fSopenharmony_ci
3036881f68fSopenharmony_ci	return entlen_padded;
3046881f68fSopenharmony_ci}
3056881f68fSopenharmony_ci
3066881f68fSopenharmony_cistatic void convert_statfs(const struct statvfs *stbuf,
3076881f68fSopenharmony_ci			   struct fuse_kstatfs *kstatfs)
3086881f68fSopenharmony_ci{
3096881f68fSopenharmony_ci	kstatfs->bsize	 = stbuf->f_bsize;
3106881f68fSopenharmony_ci	kstatfs->frsize	 = stbuf->f_frsize;
3116881f68fSopenharmony_ci	kstatfs->blocks	 = stbuf->f_blocks;
3126881f68fSopenharmony_ci	kstatfs->bfree	 = stbuf->f_bfree;
3136881f68fSopenharmony_ci	kstatfs->bavail	 = stbuf->f_bavail;
3146881f68fSopenharmony_ci	kstatfs->files	 = stbuf->f_files;
3156881f68fSopenharmony_ci	kstatfs->ffree	 = stbuf->f_ffree;
3166881f68fSopenharmony_ci	kstatfs->namelen = stbuf->f_namemax;
3176881f68fSopenharmony_ci}
3186881f68fSopenharmony_ci
3196881f68fSopenharmony_cistatic int send_reply_ok(fuse_req_t req, const void *arg, size_t argsize)
3206881f68fSopenharmony_ci{
3216881f68fSopenharmony_ci	return send_reply(req, 0, arg, argsize);
3226881f68fSopenharmony_ci}
3236881f68fSopenharmony_ci
3246881f68fSopenharmony_ciint fuse_reply_err(fuse_req_t req, int err)
3256881f68fSopenharmony_ci{
3266881f68fSopenharmony_ci	return send_reply(req, -err, NULL, 0);
3276881f68fSopenharmony_ci}
3286881f68fSopenharmony_ci
3296881f68fSopenharmony_civoid fuse_reply_none(fuse_req_t req)
3306881f68fSopenharmony_ci{
3316881f68fSopenharmony_ci	fuse_free_req(req);
3326881f68fSopenharmony_ci}
3336881f68fSopenharmony_ci
3346881f68fSopenharmony_cistatic unsigned long calc_timeout_sec(double t)
3356881f68fSopenharmony_ci{
3366881f68fSopenharmony_ci	if (t > (double) ULONG_MAX)
3376881f68fSopenharmony_ci		return ULONG_MAX;
3386881f68fSopenharmony_ci	else if (t < 0.0)
3396881f68fSopenharmony_ci		return 0;
3406881f68fSopenharmony_ci	else
3416881f68fSopenharmony_ci		return (unsigned long) t;
3426881f68fSopenharmony_ci}
3436881f68fSopenharmony_ci
3446881f68fSopenharmony_cistatic unsigned int calc_timeout_nsec(double t)
3456881f68fSopenharmony_ci{
3466881f68fSopenharmony_ci	double f = t - (double) calc_timeout_sec(t);
3476881f68fSopenharmony_ci	if (f < 0.0)
3486881f68fSopenharmony_ci		return 0;
3496881f68fSopenharmony_ci	else if (f >= 0.999999999)
3506881f68fSopenharmony_ci		return 999999999;
3516881f68fSopenharmony_ci	else
3526881f68fSopenharmony_ci		return (unsigned int) (f * 1.0e9);
3536881f68fSopenharmony_ci}
3546881f68fSopenharmony_ci
3556881f68fSopenharmony_cistatic void fill_entry(struct fuse_entry_out *arg,
3566881f68fSopenharmony_ci		       const struct fuse_entry_param *e)
3576881f68fSopenharmony_ci{
3586881f68fSopenharmony_ci	arg->nodeid = e->ino;
3596881f68fSopenharmony_ci	arg->generation = e->generation;
3606881f68fSopenharmony_ci	arg->entry_valid = calc_timeout_sec(e->entry_timeout);
3616881f68fSopenharmony_ci	arg->entry_valid_nsec = calc_timeout_nsec(e->entry_timeout);
3626881f68fSopenharmony_ci	arg->attr_valid = calc_timeout_sec(e->attr_timeout);
3636881f68fSopenharmony_ci	arg->attr_valid_nsec = calc_timeout_nsec(e->attr_timeout);
3646881f68fSopenharmony_ci	convert_stat(&e->attr, &arg->attr);
3656881f68fSopenharmony_ci}
3666881f68fSopenharmony_ci
3676881f68fSopenharmony_ci/* `buf` is allowed to be empty so that the proper size may be
3686881f68fSopenharmony_ci   allocated by the caller */
3696881f68fSopenharmony_cisize_t fuse_add_direntry_plus(fuse_req_t req, char *buf, size_t bufsize,
3706881f68fSopenharmony_ci			      const char *name,
3716881f68fSopenharmony_ci			      const struct fuse_entry_param *e, off_t off)
3726881f68fSopenharmony_ci{
3736881f68fSopenharmony_ci	(void)req;
3746881f68fSopenharmony_ci	size_t namelen;
3756881f68fSopenharmony_ci	size_t entlen;
3766881f68fSopenharmony_ci	size_t entlen_padded;
3776881f68fSopenharmony_ci
3786881f68fSopenharmony_ci	namelen = strlen(name);
3796881f68fSopenharmony_ci	entlen = FUSE_NAME_OFFSET_DIRENTPLUS + namelen;
3806881f68fSopenharmony_ci	entlen_padded = FUSE_DIRENT_ALIGN(entlen);
3816881f68fSopenharmony_ci	if ((buf == NULL) || (entlen_padded > bufsize))
3826881f68fSopenharmony_ci	  return entlen_padded;
3836881f68fSopenharmony_ci
3846881f68fSopenharmony_ci	struct fuse_direntplus *dp = (struct fuse_direntplus *) buf;
3856881f68fSopenharmony_ci	memset(&dp->entry_out, 0, sizeof(dp->entry_out));
3866881f68fSopenharmony_ci	fill_entry(&dp->entry_out, e);
3876881f68fSopenharmony_ci
3886881f68fSopenharmony_ci	struct fuse_dirent *dirent = &dp->dirent;
3896881f68fSopenharmony_ci	dirent->ino = e->attr.st_ino;
3906881f68fSopenharmony_ci	dirent->off = off;
3916881f68fSopenharmony_ci	dirent->namelen = namelen;
3926881f68fSopenharmony_ci	dirent->type = (e->attr.st_mode & S_IFMT) >> 12;
3936881f68fSopenharmony_ci	memcpy(dirent->name, name, namelen);
3946881f68fSopenharmony_ci	memset(dirent->name + namelen, 0, entlen_padded - entlen);
3956881f68fSopenharmony_ci
3966881f68fSopenharmony_ci	return entlen_padded;
3976881f68fSopenharmony_ci}
3986881f68fSopenharmony_ci
3996881f68fSopenharmony_cistatic void fill_open(struct fuse_open_out *arg,
4006881f68fSopenharmony_ci		      const struct fuse_file_info *f)
4016881f68fSopenharmony_ci{
4026881f68fSopenharmony_ci	arg->fh = f->fh;
4036881f68fSopenharmony_ci	if (f->direct_io)
4046881f68fSopenharmony_ci		arg->open_flags |= FOPEN_DIRECT_IO;
4056881f68fSopenharmony_ci	if (f->keep_cache)
4066881f68fSopenharmony_ci		arg->open_flags |= FOPEN_KEEP_CACHE;
4076881f68fSopenharmony_ci	if (f->cache_readdir)
4086881f68fSopenharmony_ci		arg->open_flags |= FOPEN_CACHE_DIR;
4096881f68fSopenharmony_ci	if (f->nonseekable)
4106881f68fSopenharmony_ci		arg->open_flags |= FOPEN_NONSEEKABLE;
4116881f68fSopenharmony_ci	if (f->noflush)
4126881f68fSopenharmony_ci		arg->open_flags |= FOPEN_NOFLUSH;
4136881f68fSopenharmony_ci	if (f->parallel_direct_writes)
4146881f68fSopenharmony_ci		arg->open_flags |= FOPEN_PARALLEL_DIRECT_WRITES;
4156881f68fSopenharmony_ci}
4166881f68fSopenharmony_ci
4176881f68fSopenharmony_ciint fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e)
4186881f68fSopenharmony_ci{
4196881f68fSopenharmony_ci	struct fuse_entry_out arg;
4206881f68fSopenharmony_ci	size_t size = req->se->conn.proto_minor < 9 ?
4216881f68fSopenharmony_ci		FUSE_COMPAT_ENTRY_OUT_SIZE : sizeof(arg);
4226881f68fSopenharmony_ci
4236881f68fSopenharmony_ci	/* before ABI 7.4 e->ino == 0 was invalid, only ENOENT meant
4246881f68fSopenharmony_ci	   negative entry */
4256881f68fSopenharmony_ci	if (!e->ino && req->se->conn.proto_minor < 4)
4266881f68fSopenharmony_ci		return fuse_reply_err(req, ENOENT);
4276881f68fSopenharmony_ci
4286881f68fSopenharmony_ci	memset(&arg, 0, sizeof(arg));
4296881f68fSopenharmony_ci	fill_entry(&arg, e);
4306881f68fSopenharmony_ci	return send_reply_ok(req, &arg, size);
4316881f68fSopenharmony_ci}
4326881f68fSopenharmony_ci
4336881f68fSopenharmony_ciint fuse_reply_create(fuse_req_t req, const struct fuse_entry_param *e,
4346881f68fSopenharmony_ci		      const struct fuse_file_info *f)
4356881f68fSopenharmony_ci{
4366881f68fSopenharmony_ci	char buf[sizeof(struct fuse_entry_out) + sizeof(struct fuse_open_out)];
4376881f68fSopenharmony_ci	size_t entrysize = req->se->conn.proto_minor < 9 ?
4386881f68fSopenharmony_ci		FUSE_COMPAT_ENTRY_OUT_SIZE : sizeof(struct fuse_entry_out);
4396881f68fSopenharmony_ci	struct fuse_entry_out *earg = (struct fuse_entry_out *) buf;
4406881f68fSopenharmony_ci	struct fuse_open_out *oarg = (struct fuse_open_out *) (buf + entrysize);
4416881f68fSopenharmony_ci
4426881f68fSopenharmony_ci	memset(buf, 0, sizeof(buf));
4436881f68fSopenharmony_ci	fill_entry(earg, e);
4446881f68fSopenharmony_ci	fill_open(oarg, f);
4456881f68fSopenharmony_ci	return send_reply_ok(req, buf,
4466881f68fSopenharmony_ci			     entrysize + sizeof(struct fuse_open_out));
4476881f68fSopenharmony_ci}
4486881f68fSopenharmony_ci
4496881f68fSopenharmony_ciint fuse_reply_attr(fuse_req_t req, const struct stat *attr,
4506881f68fSopenharmony_ci		    double attr_timeout)
4516881f68fSopenharmony_ci{
4526881f68fSopenharmony_ci	struct fuse_attr_out arg;
4536881f68fSopenharmony_ci	size_t size = req->se->conn.proto_minor < 9 ?
4546881f68fSopenharmony_ci		FUSE_COMPAT_ATTR_OUT_SIZE : sizeof(arg);
4556881f68fSopenharmony_ci
4566881f68fSopenharmony_ci	memset(&arg, 0, sizeof(arg));
4576881f68fSopenharmony_ci	arg.attr_valid = calc_timeout_sec(attr_timeout);
4586881f68fSopenharmony_ci	arg.attr_valid_nsec = calc_timeout_nsec(attr_timeout);
4596881f68fSopenharmony_ci	convert_stat(attr, &arg.attr);
4606881f68fSopenharmony_ci
4616881f68fSopenharmony_ci	return send_reply_ok(req, &arg, size);
4626881f68fSopenharmony_ci}
4636881f68fSopenharmony_ci
4646881f68fSopenharmony_ciint fuse_reply_readlink(fuse_req_t req, const char *linkname)
4656881f68fSopenharmony_ci{
4666881f68fSopenharmony_ci	return send_reply_ok(req, linkname, strlen(linkname));
4676881f68fSopenharmony_ci}
4686881f68fSopenharmony_ci
4696881f68fSopenharmony_ciint fuse_reply_open(fuse_req_t req, const struct fuse_file_info *f)
4706881f68fSopenharmony_ci{
4716881f68fSopenharmony_ci	struct fuse_open_out arg;
4726881f68fSopenharmony_ci
4736881f68fSopenharmony_ci	memset(&arg, 0, sizeof(arg));
4746881f68fSopenharmony_ci	fill_open(&arg, f);
4756881f68fSopenharmony_ci	return send_reply_ok(req, &arg, sizeof(arg));
4766881f68fSopenharmony_ci}
4776881f68fSopenharmony_ci
4786881f68fSopenharmony_ciint fuse_reply_write(fuse_req_t req, size_t count)
4796881f68fSopenharmony_ci{
4806881f68fSopenharmony_ci	struct fuse_write_out arg;
4816881f68fSopenharmony_ci
4826881f68fSopenharmony_ci	memset(&arg, 0, sizeof(arg));
4836881f68fSopenharmony_ci	arg.size = count;
4846881f68fSopenharmony_ci
4856881f68fSopenharmony_ci	return send_reply_ok(req, &arg, sizeof(arg));
4866881f68fSopenharmony_ci}
4876881f68fSopenharmony_ci
4886881f68fSopenharmony_ciint fuse_reply_buf(fuse_req_t req, const char *buf, size_t size)
4896881f68fSopenharmony_ci{
4906881f68fSopenharmony_ci	return send_reply_ok(req, buf, size);
4916881f68fSopenharmony_ci}
4926881f68fSopenharmony_ci
4936881f68fSopenharmony_cistatic int fuse_send_data_iov_fallback(struct fuse_session *se,
4946881f68fSopenharmony_ci				       struct fuse_chan *ch,
4956881f68fSopenharmony_ci				       struct iovec *iov, int iov_count,
4966881f68fSopenharmony_ci				       struct fuse_bufvec *buf,
4976881f68fSopenharmony_ci				       size_t len)
4986881f68fSopenharmony_ci{
4996881f68fSopenharmony_ci	struct fuse_bufvec mem_buf = FUSE_BUFVEC_INIT(len);
5006881f68fSopenharmony_ci	void *mbuf;
5016881f68fSopenharmony_ci	int res;
5026881f68fSopenharmony_ci
5036881f68fSopenharmony_ci	/* Optimize common case */
5046881f68fSopenharmony_ci	if (buf->count == 1 && buf->idx == 0 && buf->off == 0 &&
5056881f68fSopenharmony_ci	    !(buf->buf[0].flags & FUSE_BUF_IS_FD)) {
5066881f68fSopenharmony_ci		/* FIXME: also avoid memory copy if there are multiple buffers
5076881f68fSopenharmony_ci		   but none of them contain an fd */
5086881f68fSopenharmony_ci
5096881f68fSopenharmony_ci		iov[iov_count].iov_base = buf->buf[0].mem;
5106881f68fSopenharmony_ci		iov[iov_count].iov_len = len;
5116881f68fSopenharmony_ci		iov_count++;
5126881f68fSopenharmony_ci		return fuse_send_msg(se, ch, iov, iov_count);
5136881f68fSopenharmony_ci	}
5146881f68fSopenharmony_ci
5156881f68fSopenharmony_ci	res = posix_memalign(&mbuf, pagesize, len);
5166881f68fSopenharmony_ci	if (res != 0)
5176881f68fSopenharmony_ci		return res;
5186881f68fSopenharmony_ci
5196881f68fSopenharmony_ci	mem_buf.buf[0].mem = mbuf;
5206881f68fSopenharmony_ci	res = fuse_buf_copy(&mem_buf, buf, 0);
5216881f68fSopenharmony_ci	if (res < 0) {
5226881f68fSopenharmony_ci		free(mbuf);
5236881f68fSopenharmony_ci		return -res;
5246881f68fSopenharmony_ci	}
5256881f68fSopenharmony_ci	len = res;
5266881f68fSopenharmony_ci
5276881f68fSopenharmony_ci	iov[iov_count].iov_base = mbuf;
5286881f68fSopenharmony_ci	iov[iov_count].iov_len = len;
5296881f68fSopenharmony_ci	iov_count++;
5306881f68fSopenharmony_ci	res = fuse_send_msg(se, ch, iov, iov_count);
5316881f68fSopenharmony_ci	free(mbuf);
5326881f68fSopenharmony_ci
5336881f68fSopenharmony_ci	return res;
5346881f68fSopenharmony_ci}
5356881f68fSopenharmony_ci
5366881f68fSopenharmony_cistruct fuse_ll_pipe {
5376881f68fSopenharmony_ci	size_t size;
5386881f68fSopenharmony_ci	int can_grow;
5396881f68fSopenharmony_ci	int pipe[2];
5406881f68fSopenharmony_ci};
5416881f68fSopenharmony_ci
5426881f68fSopenharmony_cistatic void fuse_ll_pipe_free(struct fuse_ll_pipe *llp)
5436881f68fSopenharmony_ci{
5446881f68fSopenharmony_ci	close(llp->pipe[0]);
5456881f68fSopenharmony_ci	close(llp->pipe[1]);
5466881f68fSopenharmony_ci	free(llp);
5476881f68fSopenharmony_ci}
5486881f68fSopenharmony_ci
5496881f68fSopenharmony_ci#ifdef HAVE_SPLICE
5506881f68fSopenharmony_ci#if !defined(HAVE_PIPE2) || !defined(O_CLOEXEC)
5516881f68fSopenharmony_cistatic int fuse_pipe(int fds[2])
5526881f68fSopenharmony_ci{
5536881f68fSopenharmony_ci	int rv = pipe(fds);
5546881f68fSopenharmony_ci
5556881f68fSopenharmony_ci	if (rv == -1)
5566881f68fSopenharmony_ci		return rv;
5576881f68fSopenharmony_ci
5586881f68fSopenharmony_ci	if (fcntl(fds[0], F_SETFL, O_NONBLOCK) == -1 ||
5596881f68fSopenharmony_ci	    fcntl(fds[1], F_SETFL, O_NONBLOCK) == -1 ||
5606881f68fSopenharmony_ci	    fcntl(fds[0], F_SETFD, FD_CLOEXEC) == -1 ||
5616881f68fSopenharmony_ci	    fcntl(fds[1], F_SETFD, FD_CLOEXEC) == -1) {
5626881f68fSopenharmony_ci		close(fds[0]);
5636881f68fSopenharmony_ci		close(fds[1]);
5646881f68fSopenharmony_ci		rv = -1;
5656881f68fSopenharmony_ci	}
5666881f68fSopenharmony_ci	return rv;
5676881f68fSopenharmony_ci}
5686881f68fSopenharmony_ci#else
5696881f68fSopenharmony_cistatic int fuse_pipe(int fds[2])
5706881f68fSopenharmony_ci{
5716881f68fSopenharmony_ci	return pipe2(fds, O_CLOEXEC | O_NONBLOCK);
5726881f68fSopenharmony_ci}
5736881f68fSopenharmony_ci#endif
5746881f68fSopenharmony_ci
5756881f68fSopenharmony_cistatic struct fuse_ll_pipe *fuse_ll_get_pipe(struct fuse_session *se)
5766881f68fSopenharmony_ci{
5776881f68fSopenharmony_ci	struct fuse_ll_pipe *llp = pthread_getspecific(se->pipe_key);
5786881f68fSopenharmony_ci	if (llp == NULL) {
5796881f68fSopenharmony_ci		int res;
5806881f68fSopenharmony_ci
5816881f68fSopenharmony_ci		llp = malloc(sizeof(struct fuse_ll_pipe));
5826881f68fSopenharmony_ci		if (llp == NULL)
5836881f68fSopenharmony_ci			return NULL;
5846881f68fSopenharmony_ci
5856881f68fSopenharmony_ci		res = fuse_pipe(llp->pipe);
5866881f68fSopenharmony_ci		if (res == -1) {
5876881f68fSopenharmony_ci			free(llp);
5886881f68fSopenharmony_ci			return NULL;
5896881f68fSopenharmony_ci		}
5906881f68fSopenharmony_ci
5916881f68fSopenharmony_ci		/*
5926881f68fSopenharmony_ci		 *the default size is 16 pages on linux
5936881f68fSopenharmony_ci		 */
5946881f68fSopenharmony_ci		llp->size = pagesize * 16;
5956881f68fSopenharmony_ci		llp->can_grow = 1;
5966881f68fSopenharmony_ci
5976881f68fSopenharmony_ci		pthread_setspecific(se->pipe_key, llp);
5986881f68fSopenharmony_ci	}
5996881f68fSopenharmony_ci
6006881f68fSopenharmony_ci	return llp;
6016881f68fSopenharmony_ci}
6026881f68fSopenharmony_ci#endif
6036881f68fSopenharmony_ci
6046881f68fSopenharmony_cistatic void fuse_ll_clear_pipe(struct fuse_session *se)
6056881f68fSopenharmony_ci{
6066881f68fSopenharmony_ci	struct fuse_ll_pipe *llp = pthread_getspecific(se->pipe_key);
6076881f68fSopenharmony_ci	if (llp) {
6086881f68fSopenharmony_ci		pthread_setspecific(se->pipe_key, NULL);
6096881f68fSopenharmony_ci		fuse_ll_pipe_free(llp);
6106881f68fSopenharmony_ci	}
6116881f68fSopenharmony_ci}
6126881f68fSopenharmony_ci
6136881f68fSopenharmony_ci#if defined(HAVE_SPLICE) && defined(HAVE_VMSPLICE)
6146881f68fSopenharmony_cistatic int read_back(int fd, char *buf, size_t len)
6156881f68fSopenharmony_ci{
6166881f68fSopenharmony_ci	int res;
6176881f68fSopenharmony_ci
6186881f68fSopenharmony_ci	res = read(fd, buf, len);
6196881f68fSopenharmony_ci	if (res == -1) {
6206881f68fSopenharmony_ci		fuse_log(FUSE_LOG_ERR, "fuse: internal error: failed to read back from pipe: %s\n", strerror(errno));
6216881f68fSopenharmony_ci		return -EIO;
6226881f68fSopenharmony_ci	}
6236881f68fSopenharmony_ci	if (res != len) {
6246881f68fSopenharmony_ci		fuse_log(FUSE_LOG_ERR, "fuse: internal error: short read back from pipe: %i from %zi\n", res, len);
6256881f68fSopenharmony_ci		return -EIO;
6266881f68fSopenharmony_ci	}
6276881f68fSopenharmony_ci	return 0;
6286881f68fSopenharmony_ci}
6296881f68fSopenharmony_ci
6306881f68fSopenharmony_cistatic int grow_pipe_to_max(int pipefd)
6316881f68fSopenharmony_ci{
6326881f68fSopenharmony_ci	int max;
6336881f68fSopenharmony_ci	int res;
6346881f68fSopenharmony_ci	int maxfd;
6356881f68fSopenharmony_ci	char buf[32];
6366881f68fSopenharmony_ci
6376881f68fSopenharmony_ci	maxfd = open("/proc/sys/fs/pipe-max-size", O_RDONLY);
6386881f68fSopenharmony_ci	if (maxfd < 0)
6396881f68fSopenharmony_ci		return -errno;
6406881f68fSopenharmony_ci
6416881f68fSopenharmony_ci	res = read(maxfd, buf, sizeof(buf) - 1);
6426881f68fSopenharmony_ci	if (res < 0) {
6436881f68fSopenharmony_ci		int saved_errno;
6446881f68fSopenharmony_ci
6456881f68fSopenharmony_ci		saved_errno = errno;
6466881f68fSopenharmony_ci		close(maxfd);
6476881f68fSopenharmony_ci		return -saved_errno;
6486881f68fSopenharmony_ci	}
6496881f68fSopenharmony_ci	close(maxfd);
6506881f68fSopenharmony_ci	buf[res] = '\0';
6516881f68fSopenharmony_ci
6526881f68fSopenharmony_ci	max = atoi(buf);
6536881f68fSopenharmony_ci	res = fcntl(pipefd, F_SETPIPE_SZ, max);
6546881f68fSopenharmony_ci	if (res < 0)
6556881f68fSopenharmony_ci		return -errno;
6566881f68fSopenharmony_ci	return max;
6576881f68fSopenharmony_ci}
6586881f68fSopenharmony_ci
6596881f68fSopenharmony_cistatic int fuse_send_data_iov(struct fuse_session *se, struct fuse_chan *ch,
6606881f68fSopenharmony_ci			       struct iovec *iov, int iov_count,
6616881f68fSopenharmony_ci			       struct fuse_bufvec *buf, unsigned int flags)
6626881f68fSopenharmony_ci{
6636881f68fSopenharmony_ci	int res;
6646881f68fSopenharmony_ci	size_t len = fuse_buf_size(buf);
6656881f68fSopenharmony_ci	struct fuse_out_header *out = iov[0].iov_base;
6666881f68fSopenharmony_ci	struct fuse_ll_pipe *llp;
6676881f68fSopenharmony_ci	int splice_flags;
6686881f68fSopenharmony_ci	size_t pipesize;
6696881f68fSopenharmony_ci	size_t total_buf_size;
6706881f68fSopenharmony_ci	size_t idx;
6716881f68fSopenharmony_ci	size_t headerlen;
6726881f68fSopenharmony_ci	struct fuse_bufvec pipe_buf = FUSE_BUFVEC_INIT(len);
6736881f68fSopenharmony_ci
6746881f68fSopenharmony_ci	if (se->broken_splice_nonblock)
6756881f68fSopenharmony_ci		goto fallback;
6766881f68fSopenharmony_ci
6776881f68fSopenharmony_ci	if (flags & FUSE_BUF_NO_SPLICE)
6786881f68fSopenharmony_ci		goto fallback;
6796881f68fSopenharmony_ci
6806881f68fSopenharmony_ci	total_buf_size = 0;
6816881f68fSopenharmony_ci	for (idx = buf->idx; idx < buf->count; idx++) {
6826881f68fSopenharmony_ci		total_buf_size += buf->buf[idx].size;
6836881f68fSopenharmony_ci		if (idx == buf->idx)
6846881f68fSopenharmony_ci			total_buf_size -= buf->off;
6856881f68fSopenharmony_ci	}
6866881f68fSopenharmony_ci	if (total_buf_size < 2 * pagesize)
6876881f68fSopenharmony_ci		goto fallback;
6886881f68fSopenharmony_ci
6896881f68fSopenharmony_ci	if (se->conn.proto_minor < 14 ||
6906881f68fSopenharmony_ci	    !(se->conn.want & FUSE_CAP_SPLICE_WRITE))
6916881f68fSopenharmony_ci		goto fallback;
6926881f68fSopenharmony_ci
6936881f68fSopenharmony_ci	llp = fuse_ll_get_pipe(se);
6946881f68fSopenharmony_ci	if (llp == NULL)
6956881f68fSopenharmony_ci		goto fallback;
6966881f68fSopenharmony_ci
6976881f68fSopenharmony_ci
6986881f68fSopenharmony_ci	headerlen = iov_length(iov, iov_count);
6996881f68fSopenharmony_ci
7006881f68fSopenharmony_ci	out->len = headerlen + len;
7016881f68fSopenharmony_ci
7026881f68fSopenharmony_ci	/*
7036881f68fSopenharmony_ci	 * Heuristic for the required pipe size, does not work if the
7046881f68fSopenharmony_ci	 * source contains less than page size fragments
7056881f68fSopenharmony_ci	 */
7066881f68fSopenharmony_ci	pipesize = pagesize * (iov_count + buf->count + 1) + out->len;
7076881f68fSopenharmony_ci
7086881f68fSopenharmony_ci	if (llp->size < pipesize) {
7096881f68fSopenharmony_ci		if (llp->can_grow) {
7106881f68fSopenharmony_ci			res = fcntl(llp->pipe[0], F_SETPIPE_SZ, pipesize);
7116881f68fSopenharmony_ci			if (res == -1) {
7126881f68fSopenharmony_ci				res = grow_pipe_to_max(llp->pipe[0]);
7136881f68fSopenharmony_ci				if (res > 0)
7146881f68fSopenharmony_ci					llp->size = res;
7156881f68fSopenharmony_ci				llp->can_grow = 0;
7166881f68fSopenharmony_ci				goto fallback;
7176881f68fSopenharmony_ci			}
7186881f68fSopenharmony_ci			llp->size = res;
7196881f68fSopenharmony_ci		}
7206881f68fSopenharmony_ci		if (llp->size < pipesize)
7216881f68fSopenharmony_ci			goto fallback;
7226881f68fSopenharmony_ci	}
7236881f68fSopenharmony_ci
7246881f68fSopenharmony_ci
7256881f68fSopenharmony_ci	res = vmsplice(llp->pipe[1], iov, iov_count, SPLICE_F_NONBLOCK);
7266881f68fSopenharmony_ci	if (res == -1)
7276881f68fSopenharmony_ci		goto fallback;
7286881f68fSopenharmony_ci
7296881f68fSopenharmony_ci	if (res != headerlen) {
7306881f68fSopenharmony_ci		res = -EIO;
7316881f68fSopenharmony_ci		fuse_log(FUSE_LOG_ERR, "fuse: short vmsplice to pipe: %u/%zu\n", res,
7326881f68fSopenharmony_ci			headerlen);
7336881f68fSopenharmony_ci		goto clear_pipe;
7346881f68fSopenharmony_ci	}
7356881f68fSopenharmony_ci
7366881f68fSopenharmony_ci	pipe_buf.buf[0].flags = FUSE_BUF_IS_FD;
7376881f68fSopenharmony_ci	pipe_buf.buf[0].fd = llp->pipe[1];
7386881f68fSopenharmony_ci
7396881f68fSopenharmony_ci	res = fuse_buf_copy(&pipe_buf, buf,
7406881f68fSopenharmony_ci			    FUSE_BUF_FORCE_SPLICE | FUSE_BUF_SPLICE_NONBLOCK);
7416881f68fSopenharmony_ci	if (res < 0) {
7426881f68fSopenharmony_ci		if (res == -EAGAIN || res == -EINVAL) {
7436881f68fSopenharmony_ci			/*
7446881f68fSopenharmony_ci			 * Should only get EAGAIN on kernels with
7456881f68fSopenharmony_ci			 * broken SPLICE_F_NONBLOCK support (<=
7466881f68fSopenharmony_ci			 * 2.6.35) where this error or a short read is
7476881f68fSopenharmony_ci			 * returned even if the pipe itself is not
7486881f68fSopenharmony_ci			 * full
7496881f68fSopenharmony_ci			 *
7506881f68fSopenharmony_ci			 * EINVAL might mean that splice can't handle
7516881f68fSopenharmony_ci			 * this combination of input and output.
7526881f68fSopenharmony_ci			 */
7536881f68fSopenharmony_ci			if (res == -EAGAIN)
7546881f68fSopenharmony_ci				se->broken_splice_nonblock = 1;
7556881f68fSopenharmony_ci
7566881f68fSopenharmony_ci			pthread_setspecific(se->pipe_key, NULL);
7576881f68fSopenharmony_ci			fuse_ll_pipe_free(llp);
7586881f68fSopenharmony_ci			goto fallback;
7596881f68fSopenharmony_ci		}
7606881f68fSopenharmony_ci		res = -res;
7616881f68fSopenharmony_ci		goto clear_pipe;
7626881f68fSopenharmony_ci	}
7636881f68fSopenharmony_ci
7646881f68fSopenharmony_ci	if (res != 0 && res < len) {
7656881f68fSopenharmony_ci		struct fuse_bufvec mem_buf = FUSE_BUFVEC_INIT(len);
7666881f68fSopenharmony_ci		void *mbuf;
7676881f68fSopenharmony_ci		size_t now_len = res;
7686881f68fSopenharmony_ci		/*
7696881f68fSopenharmony_ci		 * For regular files a short count is either
7706881f68fSopenharmony_ci		 *  1) due to EOF, or
7716881f68fSopenharmony_ci		 *  2) because of broken SPLICE_F_NONBLOCK (see above)
7726881f68fSopenharmony_ci		 *
7736881f68fSopenharmony_ci		 * For other inputs it's possible that we overflowed
7746881f68fSopenharmony_ci		 * the pipe because of small buffer fragments.
7756881f68fSopenharmony_ci		 */
7766881f68fSopenharmony_ci
7776881f68fSopenharmony_ci		res = posix_memalign(&mbuf, pagesize, len);
7786881f68fSopenharmony_ci		if (res != 0)
7796881f68fSopenharmony_ci			goto clear_pipe;
7806881f68fSopenharmony_ci
7816881f68fSopenharmony_ci		mem_buf.buf[0].mem = mbuf;
7826881f68fSopenharmony_ci		mem_buf.off = now_len;
7836881f68fSopenharmony_ci		res = fuse_buf_copy(&mem_buf, buf, 0);
7846881f68fSopenharmony_ci		if (res > 0) {
7856881f68fSopenharmony_ci			char *tmpbuf;
7866881f68fSopenharmony_ci			size_t extra_len = res;
7876881f68fSopenharmony_ci			/*
7886881f68fSopenharmony_ci			 * Trickiest case: got more data.  Need to get
7896881f68fSopenharmony_ci			 * back the data from the pipe and then fall
7906881f68fSopenharmony_ci			 * back to regular write.
7916881f68fSopenharmony_ci			 */
7926881f68fSopenharmony_ci			tmpbuf = malloc(headerlen);
7936881f68fSopenharmony_ci			if (tmpbuf == NULL) {
7946881f68fSopenharmony_ci				free(mbuf);
7956881f68fSopenharmony_ci				res = ENOMEM;
7966881f68fSopenharmony_ci				goto clear_pipe;
7976881f68fSopenharmony_ci			}
7986881f68fSopenharmony_ci			res = read_back(llp->pipe[0], tmpbuf, headerlen);
7996881f68fSopenharmony_ci			free(tmpbuf);
8006881f68fSopenharmony_ci			if (res != 0) {
8016881f68fSopenharmony_ci				free(mbuf);
8026881f68fSopenharmony_ci				goto clear_pipe;
8036881f68fSopenharmony_ci			}
8046881f68fSopenharmony_ci			res = read_back(llp->pipe[0], mbuf, now_len);
8056881f68fSopenharmony_ci			if (res != 0) {
8066881f68fSopenharmony_ci				free(mbuf);
8076881f68fSopenharmony_ci				goto clear_pipe;
8086881f68fSopenharmony_ci			}
8096881f68fSopenharmony_ci			len = now_len + extra_len;
8106881f68fSopenharmony_ci			iov[iov_count].iov_base = mbuf;
8116881f68fSopenharmony_ci			iov[iov_count].iov_len = len;
8126881f68fSopenharmony_ci			iov_count++;
8136881f68fSopenharmony_ci			res = fuse_send_msg(se, ch, iov, iov_count);
8146881f68fSopenharmony_ci			free(mbuf);
8156881f68fSopenharmony_ci			return res;
8166881f68fSopenharmony_ci		}
8176881f68fSopenharmony_ci		free(mbuf);
8186881f68fSopenharmony_ci		res = now_len;
8196881f68fSopenharmony_ci	}
8206881f68fSopenharmony_ci	len = res;
8216881f68fSopenharmony_ci	out->len = headerlen + len;
8226881f68fSopenharmony_ci
8236881f68fSopenharmony_ci	if (se->debug) {
8246881f68fSopenharmony_ci		fuse_log(FUSE_LOG_DEBUG,
8256881f68fSopenharmony_ci			"   unique: %llu, success, outsize: %i (splice)\n",
8266881f68fSopenharmony_ci			(unsigned long long) out->unique, out->len);
8276881f68fSopenharmony_ci	}
8286881f68fSopenharmony_ci
8296881f68fSopenharmony_ci	splice_flags = 0;
8306881f68fSopenharmony_ci	if ((flags & FUSE_BUF_SPLICE_MOVE) &&
8316881f68fSopenharmony_ci	    (se->conn.want & FUSE_CAP_SPLICE_MOVE))
8326881f68fSopenharmony_ci		splice_flags |= SPLICE_F_MOVE;
8336881f68fSopenharmony_ci
8346881f68fSopenharmony_ci	if (se->io != NULL && se->io->splice_send != NULL) {
8356881f68fSopenharmony_ci		res = se->io->splice_send(llp->pipe[0], NULL,
8366881f68fSopenharmony_ci						  ch ? ch->fd : se->fd, NULL, out->len,
8376881f68fSopenharmony_ci					  	  splice_flags, se->userdata);
8386881f68fSopenharmony_ci	} else {
8396881f68fSopenharmony_ci		res = splice(llp->pipe[0], NULL, ch ? ch->fd : se->fd, NULL,
8406881f68fSopenharmony_ci			       out->len, splice_flags);
8416881f68fSopenharmony_ci	}
8426881f68fSopenharmony_ci	if (res == -1) {
8436881f68fSopenharmony_ci		res = -errno;
8446881f68fSopenharmony_ci		perror("fuse: splice from pipe");
8456881f68fSopenharmony_ci		goto clear_pipe;
8466881f68fSopenharmony_ci	}
8476881f68fSopenharmony_ci	if (res != out->len) {
8486881f68fSopenharmony_ci		res = -EIO;
8496881f68fSopenharmony_ci		fuse_log(FUSE_LOG_ERR, "fuse: short splice from pipe: %u/%u\n",
8506881f68fSopenharmony_ci			res, out->len);
8516881f68fSopenharmony_ci		goto clear_pipe;
8526881f68fSopenharmony_ci	}
8536881f68fSopenharmony_ci	return 0;
8546881f68fSopenharmony_ci
8556881f68fSopenharmony_ciclear_pipe:
8566881f68fSopenharmony_ci	fuse_ll_clear_pipe(se);
8576881f68fSopenharmony_ci	return res;
8586881f68fSopenharmony_ci
8596881f68fSopenharmony_cifallback:
8606881f68fSopenharmony_ci	return fuse_send_data_iov_fallback(se, ch, iov, iov_count, buf, len);
8616881f68fSopenharmony_ci}
8626881f68fSopenharmony_ci#else
8636881f68fSopenharmony_cistatic int fuse_send_data_iov(struct fuse_session *se, struct fuse_chan *ch,
8646881f68fSopenharmony_ci			       struct iovec *iov, int iov_count,
8656881f68fSopenharmony_ci			       struct fuse_bufvec *buf, unsigned int flags)
8666881f68fSopenharmony_ci{
8676881f68fSopenharmony_ci	size_t len = fuse_buf_size(buf);
8686881f68fSopenharmony_ci	(void) flags;
8696881f68fSopenharmony_ci
8706881f68fSopenharmony_ci	return fuse_send_data_iov_fallback(se, ch, iov, iov_count, buf, len);
8716881f68fSopenharmony_ci}
8726881f68fSopenharmony_ci#endif
8736881f68fSopenharmony_ci
8746881f68fSopenharmony_ciint fuse_reply_data(fuse_req_t req, struct fuse_bufvec *bufv,
8756881f68fSopenharmony_ci		    enum fuse_buf_copy_flags flags)
8766881f68fSopenharmony_ci{
8776881f68fSopenharmony_ci	struct iovec iov[2];
8786881f68fSopenharmony_ci	struct fuse_out_header out;
8796881f68fSopenharmony_ci	int res;
8806881f68fSopenharmony_ci
8816881f68fSopenharmony_ci	iov[0].iov_base = &out;
8826881f68fSopenharmony_ci	iov[0].iov_len = sizeof(struct fuse_out_header);
8836881f68fSopenharmony_ci
8846881f68fSopenharmony_ci	out.unique = req->unique;
8856881f68fSopenharmony_ci	out.error = 0;
8866881f68fSopenharmony_ci
8876881f68fSopenharmony_ci	res = fuse_send_data_iov(req->se, req->ch, iov, 1, bufv, flags);
8886881f68fSopenharmony_ci	if (res <= 0) {
8896881f68fSopenharmony_ci		fuse_free_req(req);
8906881f68fSopenharmony_ci		return res;
8916881f68fSopenharmony_ci	} else {
8926881f68fSopenharmony_ci		return fuse_reply_err(req, res);
8936881f68fSopenharmony_ci	}
8946881f68fSopenharmony_ci}
8956881f68fSopenharmony_ci
8966881f68fSopenharmony_ciint fuse_reply_statfs(fuse_req_t req, const struct statvfs *stbuf)
8976881f68fSopenharmony_ci{
8986881f68fSopenharmony_ci	struct fuse_statfs_out arg;
8996881f68fSopenharmony_ci	size_t size = req->se->conn.proto_minor < 4 ?
9006881f68fSopenharmony_ci		FUSE_COMPAT_STATFS_SIZE : sizeof(arg);
9016881f68fSopenharmony_ci
9026881f68fSopenharmony_ci	memset(&arg, 0, sizeof(arg));
9036881f68fSopenharmony_ci	convert_statfs(stbuf, &arg.st);
9046881f68fSopenharmony_ci
9056881f68fSopenharmony_ci	return send_reply_ok(req, &arg, size);
9066881f68fSopenharmony_ci}
9076881f68fSopenharmony_ci
9086881f68fSopenharmony_ciint fuse_reply_xattr(fuse_req_t req, size_t count)
9096881f68fSopenharmony_ci{
9106881f68fSopenharmony_ci	struct fuse_getxattr_out arg;
9116881f68fSopenharmony_ci
9126881f68fSopenharmony_ci	memset(&arg, 0, sizeof(arg));
9136881f68fSopenharmony_ci	arg.size = count;
9146881f68fSopenharmony_ci
9156881f68fSopenharmony_ci	return send_reply_ok(req, &arg, sizeof(arg));
9166881f68fSopenharmony_ci}
9176881f68fSopenharmony_ci
9186881f68fSopenharmony_ciint fuse_reply_lock(fuse_req_t req, const struct flock *lock)
9196881f68fSopenharmony_ci{
9206881f68fSopenharmony_ci	struct fuse_lk_out arg;
9216881f68fSopenharmony_ci
9226881f68fSopenharmony_ci	memset(&arg, 0, sizeof(arg));
9236881f68fSopenharmony_ci	arg.lk.type = lock->l_type;
9246881f68fSopenharmony_ci	if (lock->l_type != F_UNLCK) {
9256881f68fSopenharmony_ci		arg.lk.start = lock->l_start;
9266881f68fSopenharmony_ci		if (lock->l_len == 0)
9276881f68fSopenharmony_ci			arg.lk.end = OFFSET_MAX;
9286881f68fSopenharmony_ci		else
9296881f68fSopenharmony_ci			arg.lk.end = lock->l_start + lock->l_len - 1;
9306881f68fSopenharmony_ci	}
9316881f68fSopenharmony_ci	arg.lk.pid = lock->l_pid;
9326881f68fSopenharmony_ci	return send_reply_ok(req, &arg, sizeof(arg));
9336881f68fSopenharmony_ci}
9346881f68fSopenharmony_ci
9356881f68fSopenharmony_ciint fuse_reply_bmap(fuse_req_t req, uint64_t idx)
9366881f68fSopenharmony_ci{
9376881f68fSopenharmony_ci	struct fuse_bmap_out arg;
9386881f68fSopenharmony_ci
9396881f68fSopenharmony_ci	memset(&arg, 0, sizeof(arg));
9406881f68fSopenharmony_ci	arg.block = idx;
9416881f68fSopenharmony_ci
9426881f68fSopenharmony_ci	return send_reply_ok(req, &arg, sizeof(arg));
9436881f68fSopenharmony_ci}
9446881f68fSopenharmony_ci
9456881f68fSopenharmony_cistatic struct fuse_ioctl_iovec *fuse_ioctl_iovec_copy(const struct iovec *iov,
9466881f68fSopenharmony_ci						      size_t count)
9476881f68fSopenharmony_ci{
9486881f68fSopenharmony_ci	struct fuse_ioctl_iovec *fiov;
9496881f68fSopenharmony_ci	size_t i;
9506881f68fSopenharmony_ci
9516881f68fSopenharmony_ci	fiov = malloc(sizeof(fiov[0]) * count);
9526881f68fSopenharmony_ci	if (!fiov)
9536881f68fSopenharmony_ci		return NULL;
9546881f68fSopenharmony_ci
9556881f68fSopenharmony_ci	for (i = 0; i < count; i++) {
9566881f68fSopenharmony_ci		fiov[i].base = (uintptr_t) iov[i].iov_base;
9576881f68fSopenharmony_ci		fiov[i].len = iov[i].iov_len;
9586881f68fSopenharmony_ci	}
9596881f68fSopenharmony_ci
9606881f68fSopenharmony_ci	return fiov;
9616881f68fSopenharmony_ci}
9626881f68fSopenharmony_ci
9636881f68fSopenharmony_ciint fuse_reply_ioctl_retry(fuse_req_t req,
9646881f68fSopenharmony_ci			   const struct iovec *in_iov, size_t in_count,
9656881f68fSopenharmony_ci			   const struct iovec *out_iov, size_t out_count)
9666881f68fSopenharmony_ci{
9676881f68fSopenharmony_ci	struct fuse_ioctl_out arg;
9686881f68fSopenharmony_ci	struct fuse_ioctl_iovec *in_fiov = NULL;
9696881f68fSopenharmony_ci	struct fuse_ioctl_iovec *out_fiov = NULL;
9706881f68fSopenharmony_ci	struct iovec iov[4];
9716881f68fSopenharmony_ci	size_t count = 1;
9726881f68fSopenharmony_ci	int res;
9736881f68fSopenharmony_ci
9746881f68fSopenharmony_ci	memset(&arg, 0, sizeof(arg));
9756881f68fSopenharmony_ci	arg.flags |= FUSE_IOCTL_RETRY;
9766881f68fSopenharmony_ci	arg.in_iovs = in_count;
9776881f68fSopenharmony_ci	arg.out_iovs = out_count;
9786881f68fSopenharmony_ci	iov[count].iov_base = &arg;
9796881f68fSopenharmony_ci	iov[count].iov_len = sizeof(arg);
9806881f68fSopenharmony_ci	count++;
9816881f68fSopenharmony_ci
9826881f68fSopenharmony_ci	if (req->se->conn.proto_minor < 16) {
9836881f68fSopenharmony_ci		if (in_count) {
9846881f68fSopenharmony_ci			iov[count].iov_base = (void *)in_iov;
9856881f68fSopenharmony_ci			iov[count].iov_len = sizeof(in_iov[0]) * in_count;
9866881f68fSopenharmony_ci			count++;
9876881f68fSopenharmony_ci		}
9886881f68fSopenharmony_ci
9896881f68fSopenharmony_ci		if (out_count) {
9906881f68fSopenharmony_ci			iov[count].iov_base = (void *)out_iov;
9916881f68fSopenharmony_ci			iov[count].iov_len = sizeof(out_iov[0]) * out_count;
9926881f68fSopenharmony_ci			count++;
9936881f68fSopenharmony_ci		}
9946881f68fSopenharmony_ci	} else {
9956881f68fSopenharmony_ci		/* Can't handle non-compat 64bit ioctls on 32bit */
9966881f68fSopenharmony_ci		if (sizeof(void *) == 4 && req->ioctl_64bit) {
9976881f68fSopenharmony_ci			res = fuse_reply_err(req, EINVAL);
9986881f68fSopenharmony_ci			goto out;
9996881f68fSopenharmony_ci		}
10006881f68fSopenharmony_ci
10016881f68fSopenharmony_ci		if (in_count) {
10026881f68fSopenharmony_ci			in_fiov = fuse_ioctl_iovec_copy(in_iov, in_count);
10036881f68fSopenharmony_ci			if (!in_fiov)
10046881f68fSopenharmony_ci				goto enomem;
10056881f68fSopenharmony_ci
10066881f68fSopenharmony_ci			iov[count].iov_base = (void *)in_fiov;
10076881f68fSopenharmony_ci			iov[count].iov_len = sizeof(in_fiov[0]) * in_count;
10086881f68fSopenharmony_ci			count++;
10096881f68fSopenharmony_ci		}
10106881f68fSopenharmony_ci		if (out_count) {
10116881f68fSopenharmony_ci			out_fiov = fuse_ioctl_iovec_copy(out_iov, out_count);
10126881f68fSopenharmony_ci			if (!out_fiov)
10136881f68fSopenharmony_ci				goto enomem;
10146881f68fSopenharmony_ci
10156881f68fSopenharmony_ci			iov[count].iov_base = (void *)out_fiov;
10166881f68fSopenharmony_ci			iov[count].iov_len = sizeof(out_fiov[0]) * out_count;
10176881f68fSopenharmony_ci			count++;
10186881f68fSopenharmony_ci		}
10196881f68fSopenharmony_ci	}
10206881f68fSopenharmony_ci
10216881f68fSopenharmony_ci	res = send_reply_iov(req, 0, iov, count);
10226881f68fSopenharmony_ciout:
10236881f68fSopenharmony_ci	free(in_fiov);
10246881f68fSopenharmony_ci	free(out_fiov);
10256881f68fSopenharmony_ci
10266881f68fSopenharmony_ci	return res;
10276881f68fSopenharmony_ci
10286881f68fSopenharmony_cienomem:
10296881f68fSopenharmony_ci	res = fuse_reply_err(req, ENOMEM);
10306881f68fSopenharmony_ci	goto out;
10316881f68fSopenharmony_ci}
10326881f68fSopenharmony_ci
10336881f68fSopenharmony_ciint fuse_reply_ioctl(fuse_req_t req, int result, const void *buf, size_t size)
10346881f68fSopenharmony_ci{
10356881f68fSopenharmony_ci	struct fuse_ioctl_out arg;
10366881f68fSopenharmony_ci	struct iovec iov[3];
10376881f68fSopenharmony_ci	size_t count = 1;
10386881f68fSopenharmony_ci
10396881f68fSopenharmony_ci	memset(&arg, 0, sizeof(arg));
10406881f68fSopenharmony_ci	arg.result = result;
10416881f68fSopenharmony_ci	iov[count].iov_base = &arg;
10426881f68fSopenharmony_ci	iov[count].iov_len = sizeof(arg);
10436881f68fSopenharmony_ci	count++;
10446881f68fSopenharmony_ci
10456881f68fSopenharmony_ci	if (size) {
10466881f68fSopenharmony_ci		iov[count].iov_base = (char *) buf;
10476881f68fSopenharmony_ci		iov[count].iov_len = size;
10486881f68fSopenharmony_ci		count++;
10496881f68fSopenharmony_ci	}
10506881f68fSopenharmony_ci
10516881f68fSopenharmony_ci	return send_reply_iov(req, 0, iov, count);
10526881f68fSopenharmony_ci}
10536881f68fSopenharmony_ci
10546881f68fSopenharmony_ciint fuse_reply_ioctl_iov(fuse_req_t req, int result, const struct iovec *iov,
10556881f68fSopenharmony_ci			 int count)
10566881f68fSopenharmony_ci{
10576881f68fSopenharmony_ci	struct iovec *padded_iov;
10586881f68fSopenharmony_ci	struct fuse_ioctl_out arg;
10596881f68fSopenharmony_ci	int res;
10606881f68fSopenharmony_ci
10616881f68fSopenharmony_ci	padded_iov = malloc((count + 2) * sizeof(struct iovec));
10626881f68fSopenharmony_ci	if (padded_iov == NULL)
10636881f68fSopenharmony_ci		return fuse_reply_err(req, ENOMEM);
10646881f68fSopenharmony_ci
10656881f68fSopenharmony_ci	memset(&arg, 0, sizeof(arg));
10666881f68fSopenharmony_ci	arg.result = result;
10676881f68fSopenharmony_ci	padded_iov[1].iov_base = &arg;
10686881f68fSopenharmony_ci	padded_iov[1].iov_len = sizeof(arg);
10696881f68fSopenharmony_ci
10706881f68fSopenharmony_ci	memcpy(&padded_iov[2], iov, count * sizeof(struct iovec));
10716881f68fSopenharmony_ci
10726881f68fSopenharmony_ci	res = send_reply_iov(req, 0, padded_iov, count + 2);
10736881f68fSopenharmony_ci	free(padded_iov);
10746881f68fSopenharmony_ci
10756881f68fSopenharmony_ci	return res;
10766881f68fSopenharmony_ci}
10776881f68fSopenharmony_ci
10786881f68fSopenharmony_ciint fuse_reply_poll(fuse_req_t req, unsigned revents)
10796881f68fSopenharmony_ci{
10806881f68fSopenharmony_ci	struct fuse_poll_out arg;
10816881f68fSopenharmony_ci
10826881f68fSopenharmony_ci	memset(&arg, 0, sizeof(arg));
10836881f68fSopenharmony_ci	arg.revents = revents;
10846881f68fSopenharmony_ci
10856881f68fSopenharmony_ci	return send_reply_ok(req, &arg, sizeof(arg));
10866881f68fSopenharmony_ci}
10876881f68fSopenharmony_ci
10886881f68fSopenharmony_ciint fuse_reply_lseek(fuse_req_t req, off_t off)
10896881f68fSopenharmony_ci{
10906881f68fSopenharmony_ci	struct fuse_lseek_out arg;
10916881f68fSopenharmony_ci
10926881f68fSopenharmony_ci	memset(&arg, 0, sizeof(arg));
10936881f68fSopenharmony_ci	arg.offset = off;
10946881f68fSopenharmony_ci
10956881f68fSopenharmony_ci	return send_reply_ok(req, &arg, sizeof(arg));
10966881f68fSopenharmony_ci}
10976881f68fSopenharmony_ci
10986881f68fSopenharmony_cistatic void do_lookup(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
10996881f68fSopenharmony_ci{
11006881f68fSopenharmony_ci	char *name = (char *) inarg;
11016881f68fSopenharmony_ci
11026881f68fSopenharmony_ci	if (req->se->op.lookup)
11036881f68fSopenharmony_ci		req->se->op.lookup(req, nodeid, name);
11046881f68fSopenharmony_ci	else
11056881f68fSopenharmony_ci		fuse_reply_err(req, ENOSYS);
11066881f68fSopenharmony_ci}
11076881f68fSopenharmony_ci
11086881f68fSopenharmony_cistatic void do_forget(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
11096881f68fSopenharmony_ci{
11106881f68fSopenharmony_ci	struct fuse_forget_in *arg = (struct fuse_forget_in *) inarg;
11116881f68fSopenharmony_ci
11126881f68fSopenharmony_ci	if (req->se->op.forget)
11136881f68fSopenharmony_ci		req->se->op.forget(req, nodeid, arg->nlookup);
11146881f68fSopenharmony_ci	else
11156881f68fSopenharmony_ci		fuse_reply_none(req);
11166881f68fSopenharmony_ci}
11176881f68fSopenharmony_ci
11186881f68fSopenharmony_cistatic void do_batch_forget(fuse_req_t req, fuse_ino_t nodeid,
11196881f68fSopenharmony_ci			    const void *inarg)
11206881f68fSopenharmony_ci{
11216881f68fSopenharmony_ci	struct fuse_batch_forget_in *arg = (void *) inarg;
11226881f68fSopenharmony_ci	struct fuse_forget_one *param = (void *) PARAM(arg);
11236881f68fSopenharmony_ci	unsigned int i;
11246881f68fSopenharmony_ci
11256881f68fSopenharmony_ci	(void) nodeid;
11266881f68fSopenharmony_ci
11276881f68fSopenharmony_ci	if (req->se->op.forget_multi) {
11286881f68fSopenharmony_ci		req->se->op.forget_multi(req, arg->count,
11296881f68fSopenharmony_ci				     (struct fuse_forget_data *) param);
11306881f68fSopenharmony_ci	} else if (req->se->op.forget) {
11316881f68fSopenharmony_ci		for (i = 0; i < arg->count; i++) {
11326881f68fSopenharmony_ci			struct fuse_forget_one *forget = &param[i];
11336881f68fSopenharmony_ci			struct fuse_req *dummy_req;
11346881f68fSopenharmony_ci
11356881f68fSopenharmony_ci			dummy_req = fuse_ll_alloc_req(req->se);
11366881f68fSopenharmony_ci			if (dummy_req == NULL)
11376881f68fSopenharmony_ci				break;
11386881f68fSopenharmony_ci
11396881f68fSopenharmony_ci			dummy_req->unique = req->unique;
11406881f68fSopenharmony_ci			dummy_req->ctx = req->ctx;
11416881f68fSopenharmony_ci			dummy_req->ch = NULL;
11426881f68fSopenharmony_ci
11436881f68fSopenharmony_ci			req->se->op.forget(dummy_req, forget->nodeid,
11446881f68fSopenharmony_ci					  forget->nlookup);
11456881f68fSopenharmony_ci		}
11466881f68fSopenharmony_ci		fuse_reply_none(req);
11476881f68fSopenharmony_ci	} else {
11486881f68fSopenharmony_ci		fuse_reply_none(req);
11496881f68fSopenharmony_ci	}
11506881f68fSopenharmony_ci}
11516881f68fSopenharmony_ci
11526881f68fSopenharmony_cistatic void do_getattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
11536881f68fSopenharmony_ci{
11546881f68fSopenharmony_ci	struct fuse_file_info *fip = NULL;
11556881f68fSopenharmony_ci	struct fuse_file_info fi;
11566881f68fSopenharmony_ci
11576881f68fSopenharmony_ci	if (req->se->conn.proto_minor >= 9) {
11586881f68fSopenharmony_ci		struct fuse_getattr_in *arg = (struct fuse_getattr_in *) inarg;
11596881f68fSopenharmony_ci
11606881f68fSopenharmony_ci		if (arg->getattr_flags & FUSE_GETATTR_FH) {
11616881f68fSopenharmony_ci			memset(&fi, 0, sizeof(fi));
11626881f68fSopenharmony_ci			fi.fh = arg->fh;
11636881f68fSopenharmony_ci			fip = &fi;
11646881f68fSopenharmony_ci		}
11656881f68fSopenharmony_ci	}
11666881f68fSopenharmony_ci
11676881f68fSopenharmony_ci	if (req->se->op.getattr)
11686881f68fSopenharmony_ci		req->se->op.getattr(req, nodeid, fip);
11696881f68fSopenharmony_ci	else
11706881f68fSopenharmony_ci		fuse_reply_err(req, ENOSYS);
11716881f68fSopenharmony_ci}
11726881f68fSopenharmony_ci
11736881f68fSopenharmony_cistatic void do_setattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
11746881f68fSopenharmony_ci{
11756881f68fSopenharmony_ci	struct fuse_setattr_in *arg = (struct fuse_setattr_in *) inarg;
11766881f68fSopenharmony_ci
11776881f68fSopenharmony_ci	if (req->se->op.setattr) {
11786881f68fSopenharmony_ci		struct fuse_file_info *fi = NULL;
11796881f68fSopenharmony_ci		struct fuse_file_info fi_store;
11806881f68fSopenharmony_ci		struct stat stbuf;
11816881f68fSopenharmony_ci		memset(&stbuf, 0, sizeof(stbuf));
11826881f68fSopenharmony_ci		convert_attr(arg, &stbuf);
11836881f68fSopenharmony_ci		if (arg->valid & FATTR_FH) {
11846881f68fSopenharmony_ci			arg->valid &= ~FATTR_FH;
11856881f68fSopenharmony_ci			memset(&fi_store, 0, sizeof(fi_store));
11866881f68fSopenharmony_ci			fi = &fi_store;
11876881f68fSopenharmony_ci			fi->fh = arg->fh;
11886881f68fSopenharmony_ci		}
11896881f68fSopenharmony_ci		arg->valid &=
11906881f68fSopenharmony_ci			FUSE_SET_ATTR_MODE	|
11916881f68fSopenharmony_ci			FUSE_SET_ATTR_UID	|
11926881f68fSopenharmony_ci			FUSE_SET_ATTR_GID	|
11936881f68fSopenharmony_ci			FUSE_SET_ATTR_SIZE	|
11946881f68fSopenharmony_ci			FUSE_SET_ATTR_ATIME	|
11956881f68fSopenharmony_ci			FUSE_SET_ATTR_MTIME	|
11966881f68fSopenharmony_ci			FUSE_SET_ATTR_KILL_SUID |
11976881f68fSopenharmony_ci			FUSE_SET_ATTR_KILL_SGID |
11986881f68fSopenharmony_ci			FUSE_SET_ATTR_ATIME_NOW	|
11996881f68fSopenharmony_ci			FUSE_SET_ATTR_MTIME_NOW |
12006881f68fSopenharmony_ci			FUSE_SET_ATTR_CTIME;
12016881f68fSopenharmony_ci
12026881f68fSopenharmony_ci		req->se->op.setattr(req, nodeid, &stbuf, arg->valid, fi);
12036881f68fSopenharmony_ci	} else
12046881f68fSopenharmony_ci		fuse_reply_err(req, ENOSYS);
12056881f68fSopenharmony_ci}
12066881f68fSopenharmony_ci
12076881f68fSopenharmony_cistatic void do_access(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
12086881f68fSopenharmony_ci{
12096881f68fSopenharmony_ci	struct fuse_access_in *arg = (struct fuse_access_in *) inarg;
12106881f68fSopenharmony_ci
12116881f68fSopenharmony_ci	if (req->se->op.access)
12126881f68fSopenharmony_ci		req->se->op.access(req, nodeid, arg->mask);
12136881f68fSopenharmony_ci	else
12146881f68fSopenharmony_ci		fuse_reply_err(req, ENOSYS);
12156881f68fSopenharmony_ci}
12166881f68fSopenharmony_ci
12176881f68fSopenharmony_cistatic void do_readlink(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
12186881f68fSopenharmony_ci{
12196881f68fSopenharmony_ci	(void) inarg;
12206881f68fSopenharmony_ci
12216881f68fSopenharmony_ci	if (req->se->op.readlink)
12226881f68fSopenharmony_ci		req->se->op.readlink(req, nodeid);
12236881f68fSopenharmony_ci	else
12246881f68fSopenharmony_ci		fuse_reply_err(req, ENOSYS);
12256881f68fSopenharmony_ci}
12266881f68fSopenharmony_ci
12276881f68fSopenharmony_cistatic void do_mknod(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
12286881f68fSopenharmony_ci{
12296881f68fSopenharmony_ci	struct fuse_mknod_in *arg = (struct fuse_mknod_in *) inarg;
12306881f68fSopenharmony_ci	char *name = PARAM(arg);
12316881f68fSopenharmony_ci
12326881f68fSopenharmony_ci	if (req->se->conn.proto_minor >= 12)
12336881f68fSopenharmony_ci		req->ctx.umask = arg->umask;
12346881f68fSopenharmony_ci	else
12356881f68fSopenharmony_ci		name = (char *) inarg + FUSE_COMPAT_MKNOD_IN_SIZE;
12366881f68fSopenharmony_ci
12376881f68fSopenharmony_ci	if (req->se->op.mknod)
12386881f68fSopenharmony_ci		req->se->op.mknod(req, nodeid, name, arg->mode, arg->rdev);
12396881f68fSopenharmony_ci	else
12406881f68fSopenharmony_ci		fuse_reply_err(req, ENOSYS);
12416881f68fSopenharmony_ci}
12426881f68fSopenharmony_ci
12436881f68fSopenharmony_cistatic void do_mkdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
12446881f68fSopenharmony_ci{
12456881f68fSopenharmony_ci	struct fuse_mkdir_in *arg = (struct fuse_mkdir_in *) inarg;
12466881f68fSopenharmony_ci
12476881f68fSopenharmony_ci	if (req->se->conn.proto_minor >= 12)
12486881f68fSopenharmony_ci		req->ctx.umask = arg->umask;
12496881f68fSopenharmony_ci
12506881f68fSopenharmony_ci	if (req->se->op.mkdir)
12516881f68fSopenharmony_ci		req->se->op.mkdir(req, nodeid, PARAM(arg), arg->mode);
12526881f68fSopenharmony_ci	else
12536881f68fSopenharmony_ci		fuse_reply_err(req, ENOSYS);
12546881f68fSopenharmony_ci}
12556881f68fSopenharmony_ci
12566881f68fSopenharmony_cistatic void do_unlink(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
12576881f68fSopenharmony_ci{
12586881f68fSopenharmony_ci	char *name = (char *) inarg;
12596881f68fSopenharmony_ci
12606881f68fSopenharmony_ci	if (req->se->op.unlink)
12616881f68fSopenharmony_ci		req->se->op.unlink(req, nodeid, name);
12626881f68fSopenharmony_ci	else
12636881f68fSopenharmony_ci		fuse_reply_err(req, ENOSYS);
12646881f68fSopenharmony_ci}
12656881f68fSopenharmony_ci
12666881f68fSopenharmony_cistatic void do_rmdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
12676881f68fSopenharmony_ci{
12686881f68fSopenharmony_ci	char *name = (char *) inarg;
12696881f68fSopenharmony_ci
12706881f68fSopenharmony_ci	if (req->se->op.rmdir)
12716881f68fSopenharmony_ci		req->se->op.rmdir(req, nodeid, name);
12726881f68fSopenharmony_ci	else
12736881f68fSopenharmony_ci		fuse_reply_err(req, ENOSYS);
12746881f68fSopenharmony_ci}
12756881f68fSopenharmony_ci
12766881f68fSopenharmony_cistatic void do_symlink(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
12776881f68fSopenharmony_ci{
12786881f68fSopenharmony_ci	char *name = (char *) inarg;
12796881f68fSopenharmony_ci	char *linkname = ((char *) inarg) + strlen((char *) inarg) + 1;
12806881f68fSopenharmony_ci
12816881f68fSopenharmony_ci	if (req->se->op.symlink)
12826881f68fSopenharmony_ci		req->se->op.symlink(req, linkname, nodeid, name);
12836881f68fSopenharmony_ci	else
12846881f68fSopenharmony_ci		fuse_reply_err(req, ENOSYS);
12856881f68fSopenharmony_ci}
12866881f68fSopenharmony_ci
12876881f68fSopenharmony_cistatic void do_rename(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
12886881f68fSopenharmony_ci{
12896881f68fSopenharmony_ci	struct fuse_rename_in *arg = (struct fuse_rename_in *) inarg;
12906881f68fSopenharmony_ci	char *oldname = PARAM(arg);
12916881f68fSopenharmony_ci	char *newname = oldname + strlen(oldname) + 1;
12926881f68fSopenharmony_ci
12936881f68fSopenharmony_ci	if (req->se->op.rename)
12946881f68fSopenharmony_ci		req->se->op.rename(req, nodeid, oldname, arg->newdir, newname,
12956881f68fSopenharmony_ci				  0);
12966881f68fSopenharmony_ci	else
12976881f68fSopenharmony_ci		fuse_reply_err(req, ENOSYS);
12986881f68fSopenharmony_ci}
12996881f68fSopenharmony_ci
13006881f68fSopenharmony_cistatic void do_rename2(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
13016881f68fSopenharmony_ci{
13026881f68fSopenharmony_ci	struct fuse_rename2_in *arg = (struct fuse_rename2_in *) inarg;
13036881f68fSopenharmony_ci	char *oldname = PARAM(arg);
13046881f68fSopenharmony_ci	char *newname = oldname + strlen(oldname) + 1;
13056881f68fSopenharmony_ci
13066881f68fSopenharmony_ci	if (req->se->op.rename)
13076881f68fSopenharmony_ci		req->se->op.rename(req, nodeid, oldname, arg->newdir, newname,
13086881f68fSopenharmony_ci				  arg->flags);
13096881f68fSopenharmony_ci	else
13106881f68fSopenharmony_ci		fuse_reply_err(req, ENOSYS);
13116881f68fSopenharmony_ci}
13126881f68fSopenharmony_ci
13136881f68fSopenharmony_cistatic void do_link(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
13146881f68fSopenharmony_ci{
13156881f68fSopenharmony_ci	struct fuse_link_in *arg = (struct fuse_link_in *) inarg;
13166881f68fSopenharmony_ci
13176881f68fSopenharmony_ci	if (req->se->op.link)
13186881f68fSopenharmony_ci		req->se->op.link(req, arg->oldnodeid, nodeid, PARAM(arg));
13196881f68fSopenharmony_ci	else
13206881f68fSopenharmony_ci		fuse_reply_err(req, ENOSYS);
13216881f68fSopenharmony_ci}
13226881f68fSopenharmony_ci
13236881f68fSopenharmony_cistatic void do_create(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
13246881f68fSopenharmony_ci{
13256881f68fSopenharmony_ci	struct fuse_create_in *arg = (struct fuse_create_in *) inarg;
13266881f68fSopenharmony_ci
13276881f68fSopenharmony_ci	if (req->se->op.create) {
13286881f68fSopenharmony_ci		struct fuse_file_info fi;
13296881f68fSopenharmony_ci		char *name = PARAM(arg);
13306881f68fSopenharmony_ci
13316881f68fSopenharmony_ci		memset(&fi, 0, sizeof(fi));
13326881f68fSopenharmony_ci		fi.flags = arg->flags;
13336881f68fSopenharmony_ci
13346881f68fSopenharmony_ci		if (req->se->conn.proto_minor >= 12)
13356881f68fSopenharmony_ci			req->ctx.umask = arg->umask;
13366881f68fSopenharmony_ci		else
13376881f68fSopenharmony_ci			name = (char *) inarg + sizeof(struct fuse_open_in);
13386881f68fSopenharmony_ci
13396881f68fSopenharmony_ci		req->se->op.create(req, nodeid, name, arg->mode, &fi);
13406881f68fSopenharmony_ci	} else
13416881f68fSopenharmony_ci		fuse_reply_err(req, ENOSYS);
13426881f68fSopenharmony_ci}
13436881f68fSopenharmony_ci
13446881f68fSopenharmony_cistatic void do_open(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
13456881f68fSopenharmony_ci{
13466881f68fSopenharmony_ci	struct fuse_open_in *arg = (struct fuse_open_in *) inarg;
13476881f68fSopenharmony_ci	struct fuse_file_info fi;
13486881f68fSopenharmony_ci
13496881f68fSopenharmony_ci	memset(&fi, 0, sizeof(fi));
13506881f68fSopenharmony_ci	fi.flags = arg->flags;
13516881f68fSopenharmony_ci
13526881f68fSopenharmony_ci	if (req->se->op.open)
13536881f68fSopenharmony_ci		req->se->op.open(req, nodeid, &fi);
13546881f68fSopenharmony_ci	else
13556881f68fSopenharmony_ci		fuse_reply_open(req, &fi);
13566881f68fSopenharmony_ci}
13576881f68fSopenharmony_ci
13586881f68fSopenharmony_cistatic void do_read(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
13596881f68fSopenharmony_ci{
13606881f68fSopenharmony_ci	struct fuse_read_in *arg = (struct fuse_read_in *) inarg;
13616881f68fSopenharmony_ci
13626881f68fSopenharmony_ci	if (req->se->op.read) {
13636881f68fSopenharmony_ci		struct fuse_file_info fi;
13646881f68fSopenharmony_ci
13656881f68fSopenharmony_ci		memset(&fi, 0, sizeof(fi));
13666881f68fSopenharmony_ci		fi.fh = arg->fh;
13676881f68fSopenharmony_ci		if (req->se->conn.proto_minor >= 9) {
13686881f68fSopenharmony_ci			fi.lock_owner = arg->lock_owner;
13696881f68fSopenharmony_ci			fi.flags = arg->flags;
13706881f68fSopenharmony_ci		}
13716881f68fSopenharmony_ci		req->se->op.read(req, nodeid, arg->size, arg->offset, &fi);
13726881f68fSopenharmony_ci	} else
13736881f68fSopenharmony_ci		fuse_reply_err(req, ENOSYS);
13746881f68fSopenharmony_ci}
13756881f68fSopenharmony_ci
13766881f68fSopenharmony_cistatic void do_write(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
13776881f68fSopenharmony_ci{
13786881f68fSopenharmony_ci	struct fuse_write_in *arg = (struct fuse_write_in *) inarg;
13796881f68fSopenharmony_ci	struct fuse_file_info fi;
13806881f68fSopenharmony_ci	char *param;
13816881f68fSopenharmony_ci
13826881f68fSopenharmony_ci	memset(&fi, 0, sizeof(fi));
13836881f68fSopenharmony_ci	fi.fh = arg->fh;
13846881f68fSopenharmony_ci	fi.writepage = (arg->write_flags & FUSE_WRITE_CACHE) != 0;
13856881f68fSopenharmony_ci
13866881f68fSopenharmony_ci	if (req->se->conn.proto_minor < 9) {
13876881f68fSopenharmony_ci		param = ((char *) arg) + FUSE_COMPAT_WRITE_IN_SIZE;
13886881f68fSopenharmony_ci	} else {
13896881f68fSopenharmony_ci		fi.lock_owner = arg->lock_owner;
13906881f68fSopenharmony_ci		fi.flags = arg->flags;
13916881f68fSopenharmony_ci		param = PARAM(arg);
13926881f68fSopenharmony_ci	}
13936881f68fSopenharmony_ci
13946881f68fSopenharmony_ci	if (req->se->op.write)
13956881f68fSopenharmony_ci		req->se->op.write(req, nodeid, param, arg->size,
13966881f68fSopenharmony_ci				 arg->offset, &fi);
13976881f68fSopenharmony_ci	else
13986881f68fSopenharmony_ci		fuse_reply_err(req, ENOSYS);
13996881f68fSopenharmony_ci}
14006881f68fSopenharmony_ci
14016881f68fSopenharmony_cistatic void do_write_buf(fuse_req_t req, fuse_ino_t nodeid, const void *inarg,
14026881f68fSopenharmony_ci			 const struct fuse_buf *ibuf)
14036881f68fSopenharmony_ci{
14046881f68fSopenharmony_ci	struct fuse_session *se = req->se;
14056881f68fSopenharmony_ci	struct fuse_bufvec bufv = {
14066881f68fSopenharmony_ci		.buf[0] = *ibuf,
14076881f68fSopenharmony_ci		.count = 1,
14086881f68fSopenharmony_ci	};
14096881f68fSopenharmony_ci	struct fuse_write_in *arg = (struct fuse_write_in *) inarg;
14106881f68fSopenharmony_ci	struct fuse_file_info fi;
14116881f68fSopenharmony_ci
14126881f68fSopenharmony_ci	memset(&fi, 0, sizeof(fi));
14136881f68fSopenharmony_ci	fi.fh = arg->fh;
14146881f68fSopenharmony_ci	fi.writepage = arg->write_flags & FUSE_WRITE_CACHE;
14156881f68fSopenharmony_ci
14166881f68fSopenharmony_ci	if (se->conn.proto_minor < 9) {
14176881f68fSopenharmony_ci		bufv.buf[0].mem = ((char *) arg) + FUSE_COMPAT_WRITE_IN_SIZE;
14186881f68fSopenharmony_ci		bufv.buf[0].size -= sizeof(struct fuse_in_header) +
14196881f68fSopenharmony_ci			FUSE_COMPAT_WRITE_IN_SIZE;
14206881f68fSopenharmony_ci		assert(!(bufv.buf[0].flags & FUSE_BUF_IS_FD));
14216881f68fSopenharmony_ci	} else {
14226881f68fSopenharmony_ci		fi.lock_owner = arg->lock_owner;
14236881f68fSopenharmony_ci		fi.flags = arg->flags;
14246881f68fSopenharmony_ci		if (!(bufv.buf[0].flags & FUSE_BUF_IS_FD))
14256881f68fSopenharmony_ci			bufv.buf[0].mem = PARAM(arg);
14266881f68fSopenharmony_ci
14276881f68fSopenharmony_ci		bufv.buf[0].size -= sizeof(struct fuse_in_header) +
14286881f68fSopenharmony_ci			sizeof(struct fuse_write_in);
14296881f68fSopenharmony_ci	}
14306881f68fSopenharmony_ci	if (bufv.buf[0].size < arg->size) {
14316881f68fSopenharmony_ci		fuse_log(FUSE_LOG_ERR, "fuse: do_write_buf: buffer size too small\n");
14326881f68fSopenharmony_ci		fuse_reply_err(req, EIO);
14336881f68fSopenharmony_ci		goto out;
14346881f68fSopenharmony_ci	}
14356881f68fSopenharmony_ci	bufv.buf[0].size = arg->size;
14366881f68fSopenharmony_ci
14376881f68fSopenharmony_ci	se->op.write_buf(req, nodeid, &bufv, arg->offset, &fi);
14386881f68fSopenharmony_ci
14396881f68fSopenharmony_ciout:
14406881f68fSopenharmony_ci	/* Need to reset the pipe if ->write_buf() didn't consume all data */
14416881f68fSopenharmony_ci	if ((ibuf->flags & FUSE_BUF_IS_FD) && bufv.idx < bufv.count)
14426881f68fSopenharmony_ci		fuse_ll_clear_pipe(se);
14436881f68fSopenharmony_ci}
14446881f68fSopenharmony_ci
14456881f68fSopenharmony_cistatic void do_flush(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
14466881f68fSopenharmony_ci{
14476881f68fSopenharmony_ci	struct fuse_flush_in *arg = (struct fuse_flush_in *) inarg;
14486881f68fSopenharmony_ci	struct fuse_file_info fi;
14496881f68fSopenharmony_ci
14506881f68fSopenharmony_ci	memset(&fi, 0, sizeof(fi));
14516881f68fSopenharmony_ci	fi.fh = arg->fh;
14526881f68fSopenharmony_ci	fi.flush = 1;
14536881f68fSopenharmony_ci	if (req->se->conn.proto_minor >= 7)
14546881f68fSopenharmony_ci		fi.lock_owner = arg->lock_owner;
14556881f68fSopenharmony_ci
14566881f68fSopenharmony_ci	if (req->se->op.flush)
14576881f68fSopenharmony_ci		req->se->op.flush(req, nodeid, &fi);
14586881f68fSopenharmony_ci	else
14596881f68fSopenharmony_ci		fuse_reply_err(req, ENOSYS);
14606881f68fSopenharmony_ci}
14616881f68fSopenharmony_ci
14626881f68fSopenharmony_cistatic void do_release(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
14636881f68fSopenharmony_ci{
14646881f68fSopenharmony_ci	struct fuse_release_in *arg = (struct fuse_release_in *) inarg;
14656881f68fSopenharmony_ci	struct fuse_file_info fi;
14666881f68fSopenharmony_ci
14676881f68fSopenharmony_ci	memset(&fi, 0, sizeof(fi));
14686881f68fSopenharmony_ci	fi.flags = arg->flags;
14696881f68fSopenharmony_ci	fi.fh = arg->fh;
14706881f68fSopenharmony_ci	if (req->se->conn.proto_minor >= 8) {
14716881f68fSopenharmony_ci		fi.flush = (arg->release_flags & FUSE_RELEASE_FLUSH) ? 1 : 0;
14726881f68fSopenharmony_ci		fi.lock_owner = arg->lock_owner;
14736881f68fSopenharmony_ci	}
14746881f68fSopenharmony_ci	if (arg->release_flags & FUSE_RELEASE_FLOCK_UNLOCK) {
14756881f68fSopenharmony_ci		fi.flock_release = 1;
14766881f68fSopenharmony_ci		fi.lock_owner = arg->lock_owner;
14776881f68fSopenharmony_ci	}
14786881f68fSopenharmony_ci
14796881f68fSopenharmony_ci	if (req->se->op.release)
14806881f68fSopenharmony_ci		req->se->op.release(req, nodeid, &fi);
14816881f68fSopenharmony_ci	else
14826881f68fSopenharmony_ci		fuse_reply_err(req, 0);
14836881f68fSopenharmony_ci}
14846881f68fSopenharmony_ci
14856881f68fSopenharmony_cistatic void do_fsync(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
14866881f68fSopenharmony_ci{
14876881f68fSopenharmony_ci	struct fuse_fsync_in *arg = (struct fuse_fsync_in *) inarg;
14886881f68fSopenharmony_ci	struct fuse_file_info fi;
14896881f68fSopenharmony_ci	int datasync = arg->fsync_flags & 1;
14906881f68fSopenharmony_ci
14916881f68fSopenharmony_ci	memset(&fi, 0, sizeof(fi));
14926881f68fSopenharmony_ci	fi.fh = arg->fh;
14936881f68fSopenharmony_ci
14946881f68fSopenharmony_ci	if (req->se->op.fsync)
14956881f68fSopenharmony_ci		req->se->op.fsync(req, nodeid, datasync, &fi);
14966881f68fSopenharmony_ci	else
14976881f68fSopenharmony_ci		fuse_reply_err(req, ENOSYS);
14986881f68fSopenharmony_ci}
14996881f68fSopenharmony_ci
15006881f68fSopenharmony_cistatic void do_opendir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
15016881f68fSopenharmony_ci{
15026881f68fSopenharmony_ci	struct fuse_open_in *arg = (struct fuse_open_in *) inarg;
15036881f68fSopenharmony_ci	struct fuse_file_info fi;
15046881f68fSopenharmony_ci
15056881f68fSopenharmony_ci	memset(&fi, 0, sizeof(fi));
15066881f68fSopenharmony_ci	fi.flags = arg->flags;
15076881f68fSopenharmony_ci
15086881f68fSopenharmony_ci	if (req->se->op.opendir)
15096881f68fSopenharmony_ci		req->se->op.opendir(req, nodeid, &fi);
15106881f68fSopenharmony_ci	else
15116881f68fSopenharmony_ci		fuse_reply_open(req, &fi);
15126881f68fSopenharmony_ci}
15136881f68fSopenharmony_ci
15146881f68fSopenharmony_cistatic void do_readdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
15156881f68fSopenharmony_ci{
15166881f68fSopenharmony_ci	struct fuse_read_in *arg = (struct fuse_read_in *) inarg;
15176881f68fSopenharmony_ci	struct fuse_file_info fi;
15186881f68fSopenharmony_ci
15196881f68fSopenharmony_ci	memset(&fi, 0, sizeof(fi));
15206881f68fSopenharmony_ci	fi.fh = arg->fh;
15216881f68fSopenharmony_ci
15226881f68fSopenharmony_ci	if (req->se->op.readdir)
15236881f68fSopenharmony_ci		req->se->op.readdir(req, nodeid, arg->size, arg->offset, &fi);
15246881f68fSopenharmony_ci	else
15256881f68fSopenharmony_ci		fuse_reply_err(req, ENOSYS);
15266881f68fSopenharmony_ci}
15276881f68fSopenharmony_ci
15286881f68fSopenharmony_cistatic void do_readdirplus(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
15296881f68fSopenharmony_ci{
15306881f68fSopenharmony_ci	struct fuse_read_in *arg = (struct fuse_read_in *) inarg;
15316881f68fSopenharmony_ci	struct fuse_file_info fi;
15326881f68fSopenharmony_ci
15336881f68fSopenharmony_ci	memset(&fi, 0, sizeof(fi));
15346881f68fSopenharmony_ci	fi.fh = arg->fh;
15356881f68fSopenharmony_ci
15366881f68fSopenharmony_ci	if (req->se->op.readdirplus)
15376881f68fSopenharmony_ci		req->se->op.readdirplus(req, nodeid, arg->size, arg->offset, &fi);
15386881f68fSopenharmony_ci	else
15396881f68fSopenharmony_ci		fuse_reply_err(req, ENOSYS);
15406881f68fSopenharmony_ci}
15416881f68fSopenharmony_ci
15426881f68fSopenharmony_cistatic void do_releasedir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
15436881f68fSopenharmony_ci{
15446881f68fSopenharmony_ci	struct fuse_release_in *arg = (struct fuse_release_in *) inarg;
15456881f68fSopenharmony_ci	struct fuse_file_info fi;
15466881f68fSopenharmony_ci
15476881f68fSopenharmony_ci	memset(&fi, 0, sizeof(fi));
15486881f68fSopenharmony_ci	fi.flags = arg->flags;
15496881f68fSopenharmony_ci	fi.fh = arg->fh;
15506881f68fSopenharmony_ci
15516881f68fSopenharmony_ci	if (req->se->op.releasedir)
15526881f68fSopenharmony_ci		req->se->op.releasedir(req, nodeid, &fi);
15536881f68fSopenharmony_ci	else
15546881f68fSopenharmony_ci		fuse_reply_err(req, 0);
15556881f68fSopenharmony_ci}
15566881f68fSopenharmony_ci
15576881f68fSopenharmony_cistatic void do_fsyncdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
15586881f68fSopenharmony_ci{
15596881f68fSopenharmony_ci	struct fuse_fsync_in *arg = (struct fuse_fsync_in *) inarg;
15606881f68fSopenharmony_ci	struct fuse_file_info fi;
15616881f68fSopenharmony_ci	int datasync = arg->fsync_flags & 1;
15626881f68fSopenharmony_ci
15636881f68fSopenharmony_ci	memset(&fi, 0, sizeof(fi));
15646881f68fSopenharmony_ci	fi.fh = arg->fh;
15656881f68fSopenharmony_ci
15666881f68fSopenharmony_ci	if (req->se->op.fsyncdir)
15676881f68fSopenharmony_ci		req->se->op.fsyncdir(req, nodeid, datasync, &fi);
15686881f68fSopenharmony_ci	else
15696881f68fSopenharmony_ci		fuse_reply_err(req, ENOSYS);
15706881f68fSopenharmony_ci}
15716881f68fSopenharmony_ci
15726881f68fSopenharmony_cistatic void do_statfs(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
15736881f68fSopenharmony_ci{
15746881f68fSopenharmony_ci	(void) nodeid;
15756881f68fSopenharmony_ci	(void) inarg;
15766881f68fSopenharmony_ci
15776881f68fSopenharmony_ci	if (req->se->op.statfs)
15786881f68fSopenharmony_ci		req->se->op.statfs(req, nodeid);
15796881f68fSopenharmony_ci	else {
15806881f68fSopenharmony_ci		struct statvfs buf = {
15816881f68fSopenharmony_ci			.f_namemax = 255,
15826881f68fSopenharmony_ci			.f_bsize = 512,
15836881f68fSopenharmony_ci		};
15846881f68fSopenharmony_ci		fuse_reply_statfs(req, &buf);
15856881f68fSopenharmony_ci	}
15866881f68fSopenharmony_ci}
15876881f68fSopenharmony_ci
15886881f68fSopenharmony_cistatic void do_setxattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
15896881f68fSopenharmony_ci{
15906881f68fSopenharmony_ci	struct fuse_session *se = req->se;
15916881f68fSopenharmony_ci	unsigned int xattr_ext = !!(se->conn.want & FUSE_CAP_SETXATTR_EXT);
15926881f68fSopenharmony_ci	struct fuse_setxattr_in *arg = (struct fuse_setxattr_in *) inarg;
15936881f68fSopenharmony_ci	char *name = xattr_ext ? PARAM(arg) :
15946881f68fSopenharmony_ci		     (char *)arg + FUSE_COMPAT_SETXATTR_IN_SIZE;
15956881f68fSopenharmony_ci	char *value = name + strlen(name) + 1;
15966881f68fSopenharmony_ci
15976881f68fSopenharmony_ci	/* XXX:The API should be extended to support extra_flags/setxattr_flags */
15986881f68fSopenharmony_ci	if (req->se->op.setxattr)
15996881f68fSopenharmony_ci		req->se->op.setxattr(req, nodeid, name, value, arg->size,
16006881f68fSopenharmony_ci				    arg->flags);
16016881f68fSopenharmony_ci	else
16026881f68fSopenharmony_ci		fuse_reply_err(req, ENOSYS);
16036881f68fSopenharmony_ci}
16046881f68fSopenharmony_ci
16056881f68fSopenharmony_cistatic void do_getxattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
16066881f68fSopenharmony_ci{
16076881f68fSopenharmony_ci	struct fuse_getxattr_in *arg = (struct fuse_getxattr_in *) inarg;
16086881f68fSopenharmony_ci
16096881f68fSopenharmony_ci	if (req->se->op.getxattr)
16106881f68fSopenharmony_ci		req->se->op.getxattr(req, nodeid, PARAM(arg), arg->size);
16116881f68fSopenharmony_ci	else
16126881f68fSopenharmony_ci		fuse_reply_err(req, ENOSYS);
16136881f68fSopenharmony_ci}
16146881f68fSopenharmony_ci
16156881f68fSopenharmony_cistatic void do_listxattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
16166881f68fSopenharmony_ci{
16176881f68fSopenharmony_ci	struct fuse_getxattr_in *arg = (struct fuse_getxattr_in *) inarg;
16186881f68fSopenharmony_ci
16196881f68fSopenharmony_ci	if (req->se->op.listxattr)
16206881f68fSopenharmony_ci		req->se->op.listxattr(req, nodeid, arg->size);
16216881f68fSopenharmony_ci	else
16226881f68fSopenharmony_ci		fuse_reply_err(req, ENOSYS);
16236881f68fSopenharmony_ci}
16246881f68fSopenharmony_ci
16256881f68fSopenharmony_cistatic void do_removexattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
16266881f68fSopenharmony_ci{
16276881f68fSopenharmony_ci	char *name = (char *) inarg;
16286881f68fSopenharmony_ci
16296881f68fSopenharmony_ci	if (req->se->op.removexattr)
16306881f68fSopenharmony_ci		req->se->op.removexattr(req, nodeid, name);
16316881f68fSopenharmony_ci	else
16326881f68fSopenharmony_ci		fuse_reply_err(req, ENOSYS);
16336881f68fSopenharmony_ci}
16346881f68fSopenharmony_ci
16356881f68fSopenharmony_cistatic void convert_fuse_file_lock(struct fuse_file_lock *fl,
16366881f68fSopenharmony_ci				   struct flock *flock)
16376881f68fSopenharmony_ci{
16386881f68fSopenharmony_ci	memset(flock, 0, sizeof(struct flock));
16396881f68fSopenharmony_ci	flock->l_type = fl->type;
16406881f68fSopenharmony_ci	flock->l_whence = SEEK_SET;
16416881f68fSopenharmony_ci	flock->l_start = fl->start;
16426881f68fSopenharmony_ci	if (fl->end == OFFSET_MAX)
16436881f68fSopenharmony_ci		flock->l_len = 0;
16446881f68fSopenharmony_ci	else
16456881f68fSopenharmony_ci		flock->l_len = fl->end - fl->start + 1;
16466881f68fSopenharmony_ci	flock->l_pid = fl->pid;
16476881f68fSopenharmony_ci}
16486881f68fSopenharmony_ci
16496881f68fSopenharmony_cistatic void do_getlk(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
16506881f68fSopenharmony_ci{
16516881f68fSopenharmony_ci	struct fuse_lk_in *arg = (struct fuse_lk_in *) inarg;
16526881f68fSopenharmony_ci	struct fuse_file_info fi;
16536881f68fSopenharmony_ci	struct flock flock;
16546881f68fSopenharmony_ci
16556881f68fSopenharmony_ci	memset(&fi, 0, sizeof(fi));
16566881f68fSopenharmony_ci	fi.fh = arg->fh;
16576881f68fSopenharmony_ci	fi.lock_owner = arg->owner;
16586881f68fSopenharmony_ci
16596881f68fSopenharmony_ci	convert_fuse_file_lock(&arg->lk, &flock);
16606881f68fSopenharmony_ci	if (req->se->op.getlk)
16616881f68fSopenharmony_ci		req->se->op.getlk(req, nodeid, &fi, &flock);
16626881f68fSopenharmony_ci	else
16636881f68fSopenharmony_ci		fuse_reply_err(req, ENOSYS);
16646881f68fSopenharmony_ci}
16656881f68fSopenharmony_ci
16666881f68fSopenharmony_cistatic void do_setlk_common(fuse_req_t req, fuse_ino_t nodeid,
16676881f68fSopenharmony_ci			    const void *inarg, int sleep)
16686881f68fSopenharmony_ci{
16696881f68fSopenharmony_ci	struct fuse_lk_in *arg = (struct fuse_lk_in *) inarg;
16706881f68fSopenharmony_ci	struct fuse_file_info fi;
16716881f68fSopenharmony_ci	struct flock flock;
16726881f68fSopenharmony_ci
16736881f68fSopenharmony_ci	memset(&fi, 0, sizeof(fi));
16746881f68fSopenharmony_ci	fi.fh = arg->fh;
16756881f68fSopenharmony_ci	fi.lock_owner = arg->owner;
16766881f68fSopenharmony_ci
16776881f68fSopenharmony_ci	if (arg->lk_flags & FUSE_LK_FLOCK) {
16786881f68fSopenharmony_ci		int op = 0;
16796881f68fSopenharmony_ci
16806881f68fSopenharmony_ci		switch (arg->lk.type) {
16816881f68fSopenharmony_ci		case F_RDLCK:
16826881f68fSopenharmony_ci			op = LOCK_SH;
16836881f68fSopenharmony_ci			break;
16846881f68fSopenharmony_ci		case F_WRLCK:
16856881f68fSopenharmony_ci			op = LOCK_EX;
16866881f68fSopenharmony_ci			break;
16876881f68fSopenharmony_ci		case F_UNLCK:
16886881f68fSopenharmony_ci			op = LOCK_UN;
16896881f68fSopenharmony_ci			break;
16906881f68fSopenharmony_ci		}
16916881f68fSopenharmony_ci		if (!sleep)
16926881f68fSopenharmony_ci			op |= LOCK_NB;
16936881f68fSopenharmony_ci
16946881f68fSopenharmony_ci		if (req->se->op.flock)
16956881f68fSopenharmony_ci			req->se->op.flock(req, nodeid, &fi, op);
16966881f68fSopenharmony_ci		else
16976881f68fSopenharmony_ci			fuse_reply_err(req, ENOSYS);
16986881f68fSopenharmony_ci	} else {
16996881f68fSopenharmony_ci		convert_fuse_file_lock(&arg->lk, &flock);
17006881f68fSopenharmony_ci		if (req->se->op.setlk)
17016881f68fSopenharmony_ci			req->se->op.setlk(req, nodeid, &fi, &flock, sleep);
17026881f68fSopenharmony_ci		else
17036881f68fSopenharmony_ci			fuse_reply_err(req, ENOSYS);
17046881f68fSopenharmony_ci	}
17056881f68fSopenharmony_ci}
17066881f68fSopenharmony_ci
17076881f68fSopenharmony_cistatic void do_setlk(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
17086881f68fSopenharmony_ci{
17096881f68fSopenharmony_ci	do_setlk_common(req, nodeid, inarg, 0);
17106881f68fSopenharmony_ci}
17116881f68fSopenharmony_ci
17126881f68fSopenharmony_cistatic void do_setlkw(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
17136881f68fSopenharmony_ci{
17146881f68fSopenharmony_ci	do_setlk_common(req, nodeid, inarg, 1);
17156881f68fSopenharmony_ci}
17166881f68fSopenharmony_ci
17176881f68fSopenharmony_cistatic int find_interrupted(struct fuse_session *se, struct fuse_req *req)
17186881f68fSopenharmony_ci{
17196881f68fSopenharmony_ci	struct fuse_req *curr;
17206881f68fSopenharmony_ci
17216881f68fSopenharmony_ci	for (curr = se->list.next; curr != &se->list; curr = curr->next) {
17226881f68fSopenharmony_ci		if (curr->unique == req->u.i.unique) {
17236881f68fSopenharmony_ci			fuse_interrupt_func_t func;
17246881f68fSopenharmony_ci			void *data;
17256881f68fSopenharmony_ci
17266881f68fSopenharmony_ci			curr->ctr++;
17276881f68fSopenharmony_ci			pthread_mutex_unlock(&se->lock);
17286881f68fSopenharmony_ci
17296881f68fSopenharmony_ci			/* Ugh, ugly locking */
17306881f68fSopenharmony_ci			pthread_mutex_lock(&curr->lock);
17316881f68fSopenharmony_ci			pthread_mutex_lock(&se->lock);
17326881f68fSopenharmony_ci			curr->interrupted = 1;
17336881f68fSopenharmony_ci			func = curr->u.ni.func;
17346881f68fSopenharmony_ci			data = curr->u.ni.data;
17356881f68fSopenharmony_ci			pthread_mutex_unlock(&se->lock);
17366881f68fSopenharmony_ci			if (func)
17376881f68fSopenharmony_ci				func(curr, data);
17386881f68fSopenharmony_ci			pthread_mutex_unlock(&curr->lock);
17396881f68fSopenharmony_ci
17406881f68fSopenharmony_ci			pthread_mutex_lock(&se->lock);
17416881f68fSopenharmony_ci			curr->ctr--;
17426881f68fSopenharmony_ci			if (!curr->ctr) {
17436881f68fSopenharmony_ci				fuse_chan_put(req->ch);
17446881f68fSopenharmony_ci				req->ch = NULL;
17456881f68fSopenharmony_ci				destroy_req(curr);
17466881f68fSopenharmony_ci			}
17476881f68fSopenharmony_ci
17486881f68fSopenharmony_ci			return 1;
17496881f68fSopenharmony_ci		}
17506881f68fSopenharmony_ci	}
17516881f68fSopenharmony_ci	for (curr = se->interrupts.next; curr != &se->interrupts;
17526881f68fSopenharmony_ci	     curr = curr->next) {
17536881f68fSopenharmony_ci		if (curr->u.i.unique == req->u.i.unique)
17546881f68fSopenharmony_ci			return 1;
17556881f68fSopenharmony_ci	}
17566881f68fSopenharmony_ci	return 0;
17576881f68fSopenharmony_ci}
17586881f68fSopenharmony_ci
17596881f68fSopenharmony_cistatic void do_interrupt(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
17606881f68fSopenharmony_ci{
17616881f68fSopenharmony_ci	struct fuse_interrupt_in *arg = (struct fuse_interrupt_in *) inarg;
17626881f68fSopenharmony_ci	struct fuse_session *se = req->se;
17636881f68fSopenharmony_ci
17646881f68fSopenharmony_ci	(void) nodeid;
17656881f68fSopenharmony_ci	if (se->debug)
17666881f68fSopenharmony_ci		fuse_log(FUSE_LOG_DEBUG, "INTERRUPT: %llu\n",
17676881f68fSopenharmony_ci			(unsigned long long) arg->unique);
17686881f68fSopenharmony_ci
17696881f68fSopenharmony_ci	req->u.i.unique = arg->unique;
17706881f68fSopenharmony_ci
17716881f68fSopenharmony_ci	pthread_mutex_lock(&se->lock);
17726881f68fSopenharmony_ci	if (find_interrupted(se, req)) {
17736881f68fSopenharmony_ci		fuse_chan_put(req->ch);
17746881f68fSopenharmony_ci		req->ch = NULL;
17756881f68fSopenharmony_ci		destroy_req(req);
17766881f68fSopenharmony_ci	} else
17776881f68fSopenharmony_ci		list_add_req(req, &se->interrupts);
17786881f68fSopenharmony_ci	pthread_mutex_unlock(&se->lock);
17796881f68fSopenharmony_ci}
17806881f68fSopenharmony_ci
17816881f68fSopenharmony_cistatic struct fuse_req *check_interrupt(struct fuse_session *se,
17826881f68fSopenharmony_ci					struct fuse_req *req)
17836881f68fSopenharmony_ci{
17846881f68fSopenharmony_ci	struct fuse_req *curr;
17856881f68fSopenharmony_ci
17866881f68fSopenharmony_ci	for (curr = se->interrupts.next; curr != &se->interrupts;
17876881f68fSopenharmony_ci	     curr = curr->next) {
17886881f68fSopenharmony_ci		if (curr->u.i.unique == req->unique) {
17896881f68fSopenharmony_ci			req->interrupted = 1;
17906881f68fSopenharmony_ci			list_del_req(curr);
17916881f68fSopenharmony_ci			fuse_chan_put(curr->ch);
17926881f68fSopenharmony_ci			curr->ch = NULL;
17936881f68fSopenharmony_ci			destroy_req(curr);
17946881f68fSopenharmony_ci			return NULL;
17956881f68fSopenharmony_ci		}
17966881f68fSopenharmony_ci	}
17976881f68fSopenharmony_ci	curr = se->interrupts.next;
17986881f68fSopenharmony_ci	if (curr != &se->interrupts) {
17996881f68fSopenharmony_ci		list_del_req(curr);
18006881f68fSopenharmony_ci		list_init_req(curr);
18016881f68fSopenharmony_ci		return curr;
18026881f68fSopenharmony_ci	} else
18036881f68fSopenharmony_ci		return NULL;
18046881f68fSopenharmony_ci}
18056881f68fSopenharmony_ci
18066881f68fSopenharmony_cistatic void do_bmap(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
18076881f68fSopenharmony_ci{
18086881f68fSopenharmony_ci	struct fuse_bmap_in *arg = (struct fuse_bmap_in *) inarg;
18096881f68fSopenharmony_ci
18106881f68fSopenharmony_ci	if (req->se->op.bmap)
18116881f68fSopenharmony_ci		req->se->op.bmap(req, nodeid, arg->blocksize, arg->block);
18126881f68fSopenharmony_ci	else
18136881f68fSopenharmony_ci		fuse_reply_err(req, ENOSYS);
18146881f68fSopenharmony_ci}
18156881f68fSopenharmony_ci
18166881f68fSopenharmony_cistatic void do_ioctl(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
18176881f68fSopenharmony_ci{
18186881f68fSopenharmony_ci	struct fuse_ioctl_in *arg = (struct fuse_ioctl_in *) inarg;
18196881f68fSopenharmony_ci	unsigned int flags = arg->flags;
18206881f68fSopenharmony_ci	void *in_buf = arg->in_size ? PARAM(arg) : NULL;
18216881f68fSopenharmony_ci	struct fuse_file_info fi;
18226881f68fSopenharmony_ci
18236881f68fSopenharmony_ci	if (flags & FUSE_IOCTL_DIR &&
18246881f68fSopenharmony_ci	    !(req->se->conn.want & FUSE_CAP_IOCTL_DIR)) {
18256881f68fSopenharmony_ci		fuse_reply_err(req, ENOTTY);
18266881f68fSopenharmony_ci		return;
18276881f68fSopenharmony_ci	}
18286881f68fSopenharmony_ci
18296881f68fSopenharmony_ci	memset(&fi, 0, sizeof(fi));
18306881f68fSopenharmony_ci	fi.fh = arg->fh;
18316881f68fSopenharmony_ci
18326881f68fSopenharmony_ci	if (sizeof(void *) == 4 && req->se->conn.proto_minor >= 16 &&
18336881f68fSopenharmony_ci	    !(flags & FUSE_IOCTL_32BIT)) {
18346881f68fSopenharmony_ci		req->ioctl_64bit = 1;
18356881f68fSopenharmony_ci	}
18366881f68fSopenharmony_ci
18376881f68fSopenharmony_ci	if (req->se->op.ioctl)
18386881f68fSopenharmony_ci		req->se->op.ioctl(req, nodeid, arg->cmd,
18396881f68fSopenharmony_ci				 (void *)(uintptr_t)arg->arg, &fi, flags,
18406881f68fSopenharmony_ci				 in_buf, arg->in_size, arg->out_size);
18416881f68fSopenharmony_ci	else
18426881f68fSopenharmony_ci		fuse_reply_err(req, ENOSYS);
18436881f68fSopenharmony_ci}
18446881f68fSopenharmony_ci
18456881f68fSopenharmony_civoid fuse_pollhandle_destroy(struct fuse_pollhandle *ph)
18466881f68fSopenharmony_ci{
18476881f68fSopenharmony_ci	free(ph);
18486881f68fSopenharmony_ci}
18496881f68fSopenharmony_ci
18506881f68fSopenharmony_cistatic void do_poll(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
18516881f68fSopenharmony_ci{
18526881f68fSopenharmony_ci	struct fuse_poll_in *arg = (struct fuse_poll_in *) inarg;
18536881f68fSopenharmony_ci	struct fuse_file_info fi;
18546881f68fSopenharmony_ci
18556881f68fSopenharmony_ci	memset(&fi, 0, sizeof(fi));
18566881f68fSopenharmony_ci	fi.fh = arg->fh;
18576881f68fSopenharmony_ci	fi.poll_events = arg->events;
18586881f68fSopenharmony_ci
18596881f68fSopenharmony_ci	if (req->se->op.poll) {
18606881f68fSopenharmony_ci		struct fuse_pollhandle *ph = NULL;
18616881f68fSopenharmony_ci
18626881f68fSopenharmony_ci		if (arg->flags & FUSE_POLL_SCHEDULE_NOTIFY) {
18636881f68fSopenharmony_ci			ph = malloc(sizeof(struct fuse_pollhandle));
18646881f68fSopenharmony_ci			if (ph == NULL) {
18656881f68fSopenharmony_ci				fuse_reply_err(req, ENOMEM);
18666881f68fSopenharmony_ci				return;
18676881f68fSopenharmony_ci			}
18686881f68fSopenharmony_ci			ph->kh = arg->kh;
18696881f68fSopenharmony_ci			ph->se = req->se;
18706881f68fSopenharmony_ci		}
18716881f68fSopenharmony_ci
18726881f68fSopenharmony_ci		req->se->op.poll(req, nodeid, &fi, ph);
18736881f68fSopenharmony_ci	} else {
18746881f68fSopenharmony_ci		fuse_reply_err(req, ENOSYS);
18756881f68fSopenharmony_ci	}
18766881f68fSopenharmony_ci}
18776881f68fSopenharmony_ci
18786881f68fSopenharmony_cistatic void do_fallocate(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
18796881f68fSopenharmony_ci{
18806881f68fSopenharmony_ci	struct fuse_fallocate_in *arg = (struct fuse_fallocate_in *) inarg;
18816881f68fSopenharmony_ci	struct fuse_file_info fi;
18826881f68fSopenharmony_ci
18836881f68fSopenharmony_ci	memset(&fi, 0, sizeof(fi));
18846881f68fSopenharmony_ci	fi.fh = arg->fh;
18856881f68fSopenharmony_ci
18866881f68fSopenharmony_ci	if (req->se->op.fallocate)
18876881f68fSopenharmony_ci		req->se->op.fallocate(req, nodeid, arg->mode, arg->offset, arg->length, &fi);
18886881f68fSopenharmony_ci	else
18896881f68fSopenharmony_ci		fuse_reply_err(req, ENOSYS);
18906881f68fSopenharmony_ci}
18916881f68fSopenharmony_ci
18926881f68fSopenharmony_cistatic void do_copy_file_range(fuse_req_t req, fuse_ino_t nodeid_in, const void *inarg)
18936881f68fSopenharmony_ci{
18946881f68fSopenharmony_ci	struct fuse_copy_file_range_in *arg = (struct fuse_copy_file_range_in *) inarg;
18956881f68fSopenharmony_ci	struct fuse_file_info fi_in, fi_out;
18966881f68fSopenharmony_ci
18976881f68fSopenharmony_ci	memset(&fi_in, 0, sizeof(fi_in));
18986881f68fSopenharmony_ci	fi_in.fh = arg->fh_in;
18996881f68fSopenharmony_ci
19006881f68fSopenharmony_ci	memset(&fi_out, 0, sizeof(fi_out));
19016881f68fSopenharmony_ci	fi_out.fh = arg->fh_out;
19026881f68fSopenharmony_ci
19036881f68fSopenharmony_ci
19046881f68fSopenharmony_ci	if (req->se->op.copy_file_range)
19056881f68fSopenharmony_ci		req->se->op.copy_file_range(req, nodeid_in, arg->off_in,
19066881f68fSopenharmony_ci					    &fi_in, arg->nodeid_out,
19076881f68fSopenharmony_ci					    arg->off_out, &fi_out, arg->len,
19086881f68fSopenharmony_ci					    arg->flags);
19096881f68fSopenharmony_ci	else
19106881f68fSopenharmony_ci		fuse_reply_err(req, ENOSYS);
19116881f68fSopenharmony_ci}
19126881f68fSopenharmony_ci
19136881f68fSopenharmony_cistatic void do_lseek(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
19146881f68fSopenharmony_ci{
19156881f68fSopenharmony_ci	struct fuse_lseek_in *arg = (struct fuse_lseek_in *) inarg;
19166881f68fSopenharmony_ci	struct fuse_file_info fi;
19176881f68fSopenharmony_ci
19186881f68fSopenharmony_ci	memset(&fi, 0, sizeof(fi));
19196881f68fSopenharmony_ci	fi.fh = arg->fh;
19206881f68fSopenharmony_ci
19216881f68fSopenharmony_ci	if (req->se->op.lseek)
19226881f68fSopenharmony_ci		req->se->op.lseek(req, nodeid, arg->offset, arg->whence, &fi);
19236881f68fSopenharmony_ci	else
19246881f68fSopenharmony_ci		fuse_reply_err(req, ENOSYS);
19256881f68fSopenharmony_ci}
19266881f68fSopenharmony_ci
19276881f68fSopenharmony_ci/* Prevent bogus data races (bogus since "init" is called before
19286881f68fSopenharmony_ci * multi-threading becomes relevant */
19296881f68fSopenharmony_cistatic __attribute__((no_sanitize("thread")))
19306881f68fSopenharmony_civoid do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
19316881f68fSopenharmony_ci{
19326881f68fSopenharmony_ci	struct fuse_init_in *arg = (struct fuse_init_in *) inarg;
19336881f68fSopenharmony_ci	struct fuse_init_out outarg;
19346881f68fSopenharmony_ci	struct fuse_session *se = req->se;
19356881f68fSopenharmony_ci	size_t bufsize = se->bufsize;
19366881f68fSopenharmony_ci	size_t outargsize = sizeof(outarg);
19376881f68fSopenharmony_ci	uint64_t inargflags = 0;
19386881f68fSopenharmony_ci	uint64_t outargflags = 0;
19396881f68fSopenharmony_ci	(void) nodeid;
19406881f68fSopenharmony_ci	if (se->debug) {
19416881f68fSopenharmony_ci		fuse_log(FUSE_LOG_DEBUG, "INIT: %u.%u\n", arg->major, arg->minor);
19426881f68fSopenharmony_ci		if (arg->major == 7 && arg->minor >= 6) {
19436881f68fSopenharmony_ci			fuse_log(FUSE_LOG_DEBUG, "flags=0x%08x\n", arg->flags);
19446881f68fSopenharmony_ci			fuse_log(FUSE_LOG_DEBUG, "max_readahead=0x%08x\n",
19456881f68fSopenharmony_ci				arg->max_readahead);
19466881f68fSopenharmony_ci		}
19476881f68fSopenharmony_ci	}
19486881f68fSopenharmony_ci	se->conn.proto_major = arg->major;
19496881f68fSopenharmony_ci	se->conn.proto_minor = arg->minor;
19506881f68fSopenharmony_ci	se->conn.capable = 0;
19516881f68fSopenharmony_ci	se->conn.want = 0;
19526881f68fSopenharmony_ci
19536881f68fSopenharmony_ci	memset(&outarg, 0, sizeof(outarg));
19546881f68fSopenharmony_ci	outarg.major = FUSE_KERNEL_VERSION;
19556881f68fSopenharmony_ci	outarg.minor = FUSE_KERNEL_MINOR_VERSION;
19566881f68fSopenharmony_ci
19576881f68fSopenharmony_ci	if (arg->major < 7) {
19586881f68fSopenharmony_ci		fuse_log(FUSE_LOG_ERR, "fuse: unsupported protocol version: %u.%u\n",
19596881f68fSopenharmony_ci			arg->major, arg->minor);
19606881f68fSopenharmony_ci		fuse_reply_err(req, EPROTO);
19616881f68fSopenharmony_ci		return;
19626881f68fSopenharmony_ci	}
19636881f68fSopenharmony_ci
19646881f68fSopenharmony_ci	if (arg->major > 7) {
19656881f68fSopenharmony_ci		/* Wait for a second INIT request with a 7.X version */
19666881f68fSopenharmony_ci		send_reply_ok(req, &outarg, sizeof(outarg));
19676881f68fSopenharmony_ci		return;
19686881f68fSopenharmony_ci	}
19696881f68fSopenharmony_ci
19706881f68fSopenharmony_ci	if (arg->minor >= 6) {
19716881f68fSopenharmony_ci		if (arg->max_readahead < se->conn.max_readahead)
19726881f68fSopenharmony_ci			se->conn.max_readahead = arg->max_readahead;
19736881f68fSopenharmony_ci		inargflags = arg->flags;
19746881f68fSopenharmony_ci		if (inargflags & FUSE_INIT_EXT)
19756881f68fSopenharmony_ci			inargflags = inargflags | (uint64_t) arg->flags2 << 32;
19766881f68fSopenharmony_ci		if (inargflags & FUSE_ASYNC_READ)
19776881f68fSopenharmony_ci			se->conn.capable |= FUSE_CAP_ASYNC_READ;
19786881f68fSopenharmony_ci		if (inargflags & FUSE_POSIX_LOCKS)
19796881f68fSopenharmony_ci			se->conn.capable |= FUSE_CAP_POSIX_LOCKS;
19806881f68fSopenharmony_ci		if (inargflags & FUSE_ATOMIC_O_TRUNC)
19816881f68fSopenharmony_ci			se->conn.capable |= FUSE_CAP_ATOMIC_O_TRUNC;
19826881f68fSopenharmony_ci		if (inargflags & FUSE_EXPORT_SUPPORT)
19836881f68fSopenharmony_ci			se->conn.capable |= FUSE_CAP_EXPORT_SUPPORT;
19846881f68fSopenharmony_ci		if (inargflags & FUSE_DONT_MASK)
19856881f68fSopenharmony_ci			se->conn.capable |= FUSE_CAP_DONT_MASK;
19866881f68fSopenharmony_ci		if (inargflags & FUSE_FLOCK_LOCKS)
19876881f68fSopenharmony_ci			se->conn.capable |= FUSE_CAP_FLOCK_LOCKS;
19886881f68fSopenharmony_ci		if (inargflags & FUSE_AUTO_INVAL_DATA)
19896881f68fSopenharmony_ci			se->conn.capable |= FUSE_CAP_AUTO_INVAL_DATA;
19906881f68fSopenharmony_ci		if (inargflags & FUSE_DO_READDIRPLUS)
19916881f68fSopenharmony_ci			se->conn.capable |= FUSE_CAP_READDIRPLUS;
19926881f68fSopenharmony_ci		if (inargflags & FUSE_READDIRPLUS_AUTO)
19936881f68fSopenharmony_ci			se->conn.capable |= FUSE_CAP_READDIRPLUS_AUTO;
19946881f68fSopenharmony_ci		if (inargflags & FUSE_ASYNC_DIO)
19956881f68fSopenharmony_ci			se->conn.capable |= FUSE_CAP_ASYNC_DIO;
19966881f68fSopenharmony_ci		if (inargflags & FUSE_WRITEBACK_CACHE)
19976881f68fSopenharmony_ci			se->conn.capable |= FUSE_CAP_WRITEBACK_CACHE;
19986881f68fSopenharmony_ci		if (inargflags & FUSE_NO_OPEN_SUPPORT)
19996881f68fSopenharmony_ci			se->conn.capable |= FUSE_CAP_NO_OPEN_SUPPORT;
20006881f68fSopenharmony_ci		if (inargflags & FUSE_PARALLEL_DIROPS)
20016881f68fSopenharmony_ci			se->conn.capable |= FUSE_CAP_PARALLEL_DIROPS;
20026881f68fSopenharmony_ci		if (inargflags & FUSE_POSIX_ACL)
20036881f68fSopenharmony_ci			se->conn.capable |= FUSE_CAP_POSIX_ACL;
20046881f68fSopenharmony_ci		if (inargflags & FUSE_HANDLE_KILLPRIV)
20056881f68fSopenharmony_ci			se->conn.capable |= FUSE_CAP_HANDLE_KILLPRIV;
20066881f68fSopenharmony_ci		if (inargflags & FUSE_CACHE_SYMLINKS)
20076881f68fSopenharmony_ci			se->conn.capable |= FUSE_CAP_CACHE_SYMLINKS;
20086881f68fSopenharmony_ci		if (inargflags & FUSE_NO_OPENDIR_SUPPORT)
20096881f68fSopenharmony_ci			se->conn.capable |= FUSE_CAP_NO_OPENDIR_SUPPORT;
20106881f68fSopenharmony_ci		if (inargflags & FUSE_EXPLICIT_INVAL_DATA)
20116881f68fSopenharmony_ci			se->conn.capable |= FUSE_CAP_EXPLICIT_INVAL_DATA;
20126881f68fSopenharmony_ci		if (inargflags & FUSE_SETXATTR_EXT)
20136881f68fSopenharmony_ci			se->conn.capable |= FUSE_CAP_SETXATTR_EXT;
20146881f68fSopenharmony_ci		if (!(inargflags & FUSE_MAX_PAGES)) {
20156881f68fSopenharmony_ci			size_t max_bufsize =
20166881f68fSopenharmony_ci				FUSE_DEFAULT_MAX_PAGES_PER_REQ * getpagesize()
20176881f68fSopenharmony_ci				+ FUSE_BUFFER_HEADER_SIZE;
20186881f68fSopenharmony_ci			if (bufsize > max_bufsize) {
20196881f68fSopenharmony_ci				bufsize = max_bufsize;
20206881f68fSopenharmony_ci			}
20216881f68fSopenharmony_ci		}
20226881f68fSopenharmony_ci		if (arg->minor >= 38)
20236881f68fSopenharmony_ci			se->conn.capable |= FUSE_CAP_EXPIRE_ONLY;
20246881f68fSopenharmony_ci	} else {
20256881f68fSopenharmony_ci		se->conn.max_readahead = 0;
20266881f68fSopenharmony_ci	}
20276881f68fSopenharmony_ci
20286881f68fSopenharmony_ci	if (se->conn.proto_minor >= 14) {
20296881f68fSopenharmony_ci#ifdef HAVE_SPLICE
20306881f68fSopenharmony_ci#ifdef HAVE_VMSPLICE
20316881f68fSopenharmony_ci		if ((se->io == NULL) || (se->io->splice_send != NULL)) {
20326881f68fSopenharmony_ci			se->conn.capable |= FUSE_CAP_SPLICE_WRITE | FUSE_CAP_SPLICE_MOVE;
20336881f68fSopenharmony_ci		}
20346881f68fSopenharmony_ci#endif
20356881f68fSopenharmony_ci		if ((se->io == NULL) || (se->io->splice_receive != NULL)) {
20366881f68fSopenharmony_ci			se->conn.capable |= FUSE_CAP_SPLICE_READ;
20376881f68fSopenharmony_ci		}
20386881f68fSopenharmony_ci#endif
20396881f68fSopenharmony_ci	}
20406881f68fSopenharmony_ci	if (se->conn.proto_minor >= 18)
20416881f68fSopenharmony_ci		se->conn.capable |= FUSE_CAP_IOCTL_DIR;
20426881f68fSopenharmony_ci
20436881f68fSopenharmony_ci	/* Default settings for modern filesystems.
20446881f68fSopenharmony_ci	 *
20456881f68fSopenharmony_ci	 * Most of these capabilities were disabled by default in
20466881f68fSopenharmony_ci	 * libfuse2 for backwards compatibility reasons. In libfuse3,
20476881f68fSopenharmony_ci	 * we can finally enable them by default (as long as they're
20486881f68fSopenharmony_ci	 * supported by the kernel).
20496881f68fSopenharmony_ci	 */
20506881f68fSopenharmony_ci#define LL_SET_DEFAULT(cond, cap) \
20516881f68fSopenharmony_ci	if ((cond) && (se->conn.capable & (cap))) \
20526881f68fSopenharmony_ci		se->conn.want |= (cap)
20536881f68fSopenharmony_ci	LL_SET_DEFAULT(1, FUSE_CAP_ASYNC_READ);
20546881f68fSopenharmony_ci	LL_SET_DEFAULT(1, FUSE_CAP_PARALLEL_DIROPS);
20556881f68fSopenharmony_ci	LL_SET_DEFAULT(1, FUSE_CAP_AUTO_INVAL_DATA);
20566881f68fSopenharmony_ci	LL_SET_DEFAULT(1, FUSE_CAP_HANDLE_KILLPRIV);
20576881f68fSopenharmony_ci	LL_SET_DEFAULT(1, FUSE_CAP_ASYNC_DIO);
20586881f68fSopenharmony_ci	LL_SET_DEFAULT(1, FUSE_CAP_IOCTL_DIR);
20596881f68fSopenharmony_ci	LL_SET_DEFAULT(1, FUSE_CAP_ATOMIC_O_TRUNC);
20606881f68fSopenharmony_ci	LL_SET_DEFAULT(se->op.write_buf, FUSE_CAP_SPLICE_READ);
20616881f68fSopenharmony_ci	LL_SET_DEFAULT(se->op.getlk && se->op.setlk,
20626881f68fSopenharmony_ci		       FUSE_CAP_POSIX_LOCKS);
20636881f68fSopenharmony_ci	LL_SET_DEFAULT(se->op.flock, FUSE_CAP_FLOCK_LOCKS);
20646881f68fSopenharmony_ci	LL_SET_DEFAULT(se->op.readdirplus, FUSE_CAP_READDIRPLUS);
20656881f68fSopenharmony_ci	LL_SET_DEFAULT(se->op.readdirplus && se->op.readdir,
20666881f68fSopenharmony_ci		       FUSE_CAP_READDIRPLUS_AUTO);
20676881f68fSopenharmony_ci
20686881f68fSopenharmony_ci	/* This could safely become default, but libfuse needs an API extension
20696881f68fSopenharmony_ci	 * to support it
20706881f68fSopenharmony_ci	 * LL_SET_DEFAULT(1, FUSE_CAP_SETXATTR_EXT);
20716881f68fSopenharmony_ci	 */
20726881f68fSopenharmony_ci
20736881f68fSopenharmony_ci	se->conn.time_gran = 1;
20746881f68fSopenharmony_ci
20756881f68fSopenharmony_ci	if (bufsize < FUSE_MIN_READ_BUFFER) {
20766881f68fSopenharmony_ci		fuse_log(FUSE_LOG_ERR, "fuse: warning: buffer size too small: %zu\n",
20776881f68fSopenharmony_ci			bufsize);
20786881f68fSopenharmony_ci		bufsize = FUSE_MIN_READ_BUFFER;
20796881f68fSopenharmony_ci	}
20806881f68fSopenharmony_ci	se->bufsize = bufsize;
20816881f68fSopenharmony_ci
20826881f68fSopenharmony_ci	if (se->conn.max_write > bufsize - FUSE_BUFFER_HEADER_SIZE)
20836881f68fSopenharmony_ci		se->conn.max_write = bufsize - FUSE_BUFFER_HEADER_SIZE;
20846881f68fSopenharmony_ci
20856881f68fSopenharmony_ci	se->got_init = 1;
20866881f68fSopenharmony_ci	if (se->op.init)
20876881f68fSopenharmony_ci		se->op.init(se->userdata, &se->conn);
20886881f68fSopenharmony_ci
20896881f68fSopenharmony_ci	if (se->conn.want & (~se->conn.capable)) {
20906881f68fSopenharmony_ci		fuse_log(FUSE_LOG_ERR, "fuse: error: filesystem requested capabilities "
20916881f68fSopenharmony_ci			"0x%x that are not supported by kernel, aborting.\n",
20926881f68fSopenharmony_ci			se->conn.want & (~se->conn.capable));
20936881f68fSopenharmony_ci		fuse_reply_err(req, EPROTO);
20946881f68fSopenharmony_ci		se->error = -EPROTO;
20956881f68fSopenharmony_ci		fuse_session_exit(se);
20966881f68fSopenharmony_ci		return;
20976881f68fSopenharmony_ci	}
20986881f68fSopenharmony_ci
20996881f68fSopenharmony_ci	unsigned max_read_mo = get_max_read(se->mo);
21006881f68fSopenharmony_ci	if (se->conn.max_read != max_read_mo) {
21016881f68fSopenharmony_ci		fuse_log(FUSE_LOG_ERR, "fuse: error: init() and fuse_session_new() "
21026881f68fSopenharmony_ci			"requested different maximum read size (%u vs %u)\n",
21036881f68fSopenharmony_ci			se->conn.max_read, max_read_mo);
21046881f68fSopenharmony_ci		fuse_reply_err(req, EPROTO);
21056881f68fSopenharmony_ci		se->error = -EPROTO;
21066881f68fSopenharmony_ci		fuse_session_exit(se);
21076881f68fSopenharmony_ci		return;
21086881f68fSopenharmony_ci	}
21096881f68fSopenharmony_ci
21106881f68fSopenharmony_ci	if (se->conn.max_write < bufsize - FUSE_BUFFER_HEADER_SIZE) {
21116881f68fSopenharmony_ci		se->bufsize = se->conn.max_write + FUSE_BUFFER_HEADER_SIZE;
21126881f68fSopenharmony_ci	}
21136881f68fSopenharmony_ci	if (arg->flags & FUSE_MAX_PAGES) {
21146881f68fSopenharmony_ci		outarg.flags |= FUSE_MAX_PAGES;
21156881f68fSopenharmony_ci		outarg.max_pages = (se->conn.max_write - 1) / getpagesize() + 1;
21166881f68fSopenharmony_ci	}
21176881f68fSopenharmony_ci	outargflags = outarg.flags;
21186881f68fSopenharmony_ci	/* Always enable big writes, this is superseded
21196881f68fSopenharmony_ci	   by the max_write option */
21206881f68fSopenharmony_ci	outargflags |= FUSE_BIG_WRITES;
21216881f68fSopenharmony_ci
21226881f68fSopenharmony_ci	if (se->conn.want & FUSE_CAP_ASYNC_READ)
21236881f68fSopenharmony_ci		outargflags |= FUSE_ASYNC_READ;
21246881f68fSopenharmony_ci	if (se->conn.want & FUSE_CAP_POSIX_LOCKS)
21256881f68fSopenharmony_ci		outargflags |= FUSE_POSIX_LOCKS;
21266881f68fSopenharmony_ci	if (se->conn.want & FUSE_CAP_ATOMIC_O_TRUNC)
21276881f68fSopenharmony_ci		outargflags |= FUSE_ATOMIC_O_TRUNC;
21286881f68fSopenharmony_ci	if (se->conn.want & FUSE_CAP_EXPORT_SUPPORT)
21296881f68fSopenharmony_ci		outargflags |= FUSE_EXPORT_SUPPORT;
21306881f68fSopenharmony_ci	if (se->conn.want & FUSE_CAP_DONT_MASK)
21316881f68fSopenharmony_ci		outargflags |= FUSE_DONT_MASK;
21326881f68fSopenharmony_ci	if (se->conn.want & FUSE_CAP_FLOCK_LOCKS)
21336881f68fSopenharmony_ci		outargflags |= FUSE_FLOCK_LOCKS;
21346881f68fSopenharmony_ci	if (se->conn.want & FUSE_CAP_AUTO_INVAL_DATA)
21356881f68fSopenharmony_ci		outargflags |= FUSE_AUTO_INVAL_DATA;
21366881f68fSopenharmony_ci	if (se->conn.want & FUSE_CAP_READDIRPLUS)
21376881f68fSopenharmony_ci		outargflags |= FUSE_DO_READDIRPLUS;
21386881f68fSopenharmony_ci	if (se->conn.want & FUSE_CAP_READDIRPLUS_AUTO)
21396881f68fSopenharmony_ci		outargflags |= FUSE_READDIRPLUS_AUTO;
21406881f68fSopenharmony_ci	if (se->conn.want & FUSE_CAP_ASYNC_DIO)
21416881f68fSopenharmony_ci		outargflags |= FUSE_ASYNC_DIO;
21426881f68fSopenharmony_ci	if (se->conn.want & FUSE_CAP_WRITEBACK_CACHE)
21436881f68fSopenharmony_ci		outargflags |= FUSE_WRITEBACK_CACHE;
21446881f68fSopenharmony_ci	if (se->conn.want & FUSE_CAP_POSIX_ACL)
21456881f68fSopenharmony_ci		outargflags |= FUSE_POSIX_ACL;
21466881f68fSopenharmony_ci	if (se->conn.want & FUSE_CAP_CACHE_SYMLINKS)
21476881f68fSopenharmony_ci		outargflags |= FUSE_CACHE_SYMLINKS;
21486881f68fSopenharmony_ci	if (se->conn.want & FUSE_CAP_EXPLICIT_INVAL_DATA)
21496881f68fSopenharmony_ci		outargflags |= FUSE_EXPLICIT_INVAL_DATA;
21506881f68fSopenharmony_ci	if (se->conn.want & FUSE_CAP_SETXATTR_EXT)
21516881f68fSopenharmony_ci		outargflags |= FUSE_SETXATTR_EXT;
21526881f68fSopenharmony_ci
21536881f68fSopenharmony_ci	if (inargflags & FUSE_INIT_EXT) {
21546881f68fSopenharmony_ci		outargflags |= FUSE_INIT_EXT;
21556881f68fSopenharmony_ci		outarg.flags2 = outargflags >> 32;
21566881f68fSopenharmony_ci	}
21576881f68fSopenharmony_ci
21586881f68fSopenharmony_ci	outarg.flags = outargflags;
21596881f68fSopenharmony_ci
21606881f68fSopenharmony_ci	outarg.max_readahead = se->conn.max_readahead;
21616881f68fSopenharmony_ci	outarg.max_write = se->conn.max_write;
21626881f68fSopenharmony_ci	if (se->conn.proto_minor >= 13) {
21636881f68fSopenharmony_ci		if (se->conn.max_background >= (1 << 16))
21646881f68fSopenharmony_ci			se->conn.max_background = (1 << 16) - 1;
21656881f68fSopenharmony_ci		if (se->conn.congestion_threshold > se->conn.max_background)
21666881f68fSopenharmony_ci			se->conn.congestion_threshold = se->conn.max_background;
21676881f68fSopenharmony_ci		if (!se->conn.congestion_threshold) {
21686881f68fSopenharmony_ci			se->conn.congestion_threshold =
21696881f68fSopenharmony_ci				se->conn.max_background * 3 / 4;
21706881f68fSopenharmony_ci		}
21716881f68fSopenharmony_ci
21726881f68fSopenharmony_ci		outarg.max_background = se->conn.max_background;
21736881f68fSopenharmony_ci		outarg.congestion_threshold = se->conn.congestion_threshold;
21746881f68fSopenharmony_ci	}
21756881f68fSopenharmony_ci	if (se->conn.proto_minor >= 23)
21766881f68fSopenharmony_ci		outarg.time_gran = se->conn.time_gran;
21776881f68fSopenharmony_ci
21786881f68fSopenharmony_ci	if (se->debug) {
21796881f68fSopenharmony_ci		fuse_log(FUSE_LOG_DEBUG, "   INIT: %u.%u\n", outarg.major, outarg.minor);
21806881f68fSopenharmony_ci		fuse_log(FUSE_LOG_DEBUG, "   flags=0x%08x\n", outarg.flags);
21816881f68fSopenharmony_ci		fuse_log(FUSE_LOG_DEBUG, "   max_readahead=0x%08x\n",
21826881f68fSopenharmony_ci			outarg.max_readahead);
21836881f68fSopenharmony_ci		fuse_log(FUSE_LOG_DEBUG, "   max_write=0x%08x\n", outarg.max_write);
21846881f68fSopenharmony_ci		fuse_log(FUSE_LOG_DEBUG, "   max_background=%i\n",
21856881f68fSopenharmony_ci			outarg.max_background);
21866881f68fSopenharmony_ci		fuse_log(FUSE_LOG_DEBUG, "   congestion_threshold=%i\n",
21876881f68fSopenharmony_ci			outarg.congestion_threshold);
21886881f68fSopenharmony_ci		fuse_log(FUSE_LOG_DEBUG, "   time_gran=%u\n",
21896881f68fSopenharmony_ci			outarg.time_gran);
21906881f68fSopenharmony_ci	}
21916881f68fSopenharmony_ci	if (arg->minor < 5)
21926881f68fSopenharmony_ci		outargsize = FUSE_COMPAT_INIT_OUT_SIZE;
21936881f68fSopenharmony_ci	else if (arg->minor < 23)
21946881f68fSopenharmony_ci		outargsize = FUSE_COMPAT_22_INIT_OUT_SIZE;
21956881f68fSopenharmony_ci
21966881f68fSopenharmony_ci	send_reply_ok(req, &outarg, outargsize);
21976881f68fSopenharmony_ci}
21986881f68fSopenharmony_ci
21996881f68fSopenharmony_cistatic void do_destroy(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
22006881f68fSopenharmony_ci{
22016881f68fSopenharmony_ci	struct fuse_session *se = req->se;
22026881f68fSopenharmony_ci
22036881f68fSopenharmony_ci	(void) nodeid;
22046881f68fSopenharmony_ci	(void) inarg;
22056881f68fSopenharmony_ci
22066881f68fSopenharmony_ci	se->got_destroy = 1;
22076881f68fSopenharmony_ci	if (se->op.destroy)
22086881f68fSopenharmony_ci		se->op.destroy(se->userdata);
22096881f68fSopenharmony_ci
22106881f68fSopenharmony_ci	send_reply_ok(req, NULL, 0);
22116881f68fSopenharmony_ci}
22126881f68fSopenharmony_ci
22136881f68fSopenharmony_cistatic void list_del_nreq(struct fuse_notify_req *nreq)
22146881f68fSopenharmony_ci{
22156881f68fSopenharmony_ci	struct fuse_notify_req *prev = nreq->prev;
22166881f68fSopenharmony_ci	struct fuse_notify_req *next = nreq->next;
22176881f68fSopenharmony_ci	prev->next = next;
22186881f68fSopenharmony_ci	next->prev = prev;
22196881f68fSopenharmony_ci}
22206881f68fSopenharmony_ci
22216881f68fSopenharmony_cistatic void list_add_nreq(struct fuse_notify_req *nreq,
22226881f68fSopenharmony_ci			  struct fuse_notify_req *next)
22236881f68fSopenharmony_ci{
22246881f68fSopenharmony_ci	struct fuse_notify_req *prev = next->prev;
22256881f68fSopenharmony_ci	nreq->next = next;
22266881f68fSopenharmony_ci	nreq->prev = prev;
22276881f68fSopenharmony_ci	prev->next = nreq;
22286881f68fSopenharmony_ci	next->prev = nreq;
22296881f68fSopenharmony_ci}
22306881f68fSopenharmony_ci
22316881f68fSopenharmony_cistatic void list_init_nreq(struct fuse_notify_req *nreq)
22326881f68fSopenharmony_ci{
22336881f68fSopenharmony_ci	nreq->next = nreq;
22346881f68fSopenharmony_ci	nreq->prev = nreq;
22356881f68fSopenharmony_ci}
22366881f68fSopenharmony_ci
22376881f68fSopenharmony_cistatic void do_notify_reply(fuse_req_t req, fuse_ino_t nodeid,
22386881f68fSopenharmony_ci			    const void *inarg, const struct fuse_buf *buf)
22396881f68fSopenharmony_ci{
22406881f68fSopenharmony_ci	struct fuse_session *se = req->se;
22416881f68fSopenharmony_ci	struct fuse_notify_req *nreq;
22426881f68fSopenharmony_ci	struct fuse_notify_req *head;
22436881f68fSopenharmony_ci
22446881f68fSopenharmony_ci	pthread_mutex_lock(&se->lock);
22456881f68fSopenharmony_ci	head = &se->notify_list;
22466881f68fSopenharmony_ci	for (nreq = head->next; nreq != head; nreq = nreq->next) {
22476881f68fSopenharmony_ci		if (nreq->unique == req->unique) {
22486881f68fSopenharmony_ci			list_del_nreq(nreq);
22496881f68fSopenharmony_ci			break;
22506881f68fSopenharmony_ci		}
22516881f68fSopenharmony_ci	}
22526881f68fSopenharmony_ci	pthread_mutex_unlock(&se->lock);
22536881f68fSopenharmony_ci
22546881f68fSopenharmony_ci	if (nreq != head)
22556881f68fSopenharmony_ci		nreq->reply(nreq, req, nodeid, inarg, buf);
22566881f68fSopenharmony_ci}
22576881f68fSopenharmony_ci
22586881f68fSopenharmony_cistatic int send_notify_iov(struct fuse_session *se, int notify_code,
22596881f68fSopenharmony_ci			   struct iovec *iov, int count)
22606881f68fSopenharmony_ci{
22616881f68fSopenharmony_ci	struct fuse_out_header out;
22626881f68fSopenharmony_ci
22636881f68fSopenharmony_ci	if (!se->got_init)
22646881f68fSopenharmony_ci		return -ENOTCONN;
22656881f68fSopenharmony_ci
22666881f68fSopenharmony_ci	out.unique = 0;
22676881f68fSopenharmony_ci	out.error = notify_code;
22686881f68fSopenharmony_ci	iov[0].iov_base = &out;
22696881f68fSopenharmony_ci	iov[0].iov_len = sizeof(struct fuse_out_header);
22706881f68fSopenharmony_ci
22716881f68fSopenharmony_ci	return fuse_send_msg(se, NULL, iov, count);
22726881f68fSopenharmony_ci}
22736881f68fSopenharmony_ci
22746881f68fSopenharmony_ciint fuse_lowlevel_notify_poll(struct fuse_pollhandle *ph)
22756881f68fSopenharmony_ci{
22766881f68fSopenharmony_ci	if (ph != NULL) {
22776881f68fSopenharmony_ci		struct fuse_notify_poll_wakeup_out outarg;
22786881f68fSopenharmony_ci		struct iovec iov[2];
22796881f68fSopenharmony_ci
22806881f68fSopenharmony_ci		outarg.kh = ph->kh;
22816881f68fSopenharmony_ci
22826881f68fSopenharmony_ci		iov[1].iov_base = &outarg;
22836881f68fSopenharmony_ci		iov[1].iov_len = sizeof(outarg);
22846881f68fSopenharmony_ci
22856881f68fSopenharmony_ci		return send_notify_iov(ph->se, FUSE_NOTIFY_POLL, iov, 2);
22866881f68fSopenharmony_ci	} else {
22876881f68fSopenharmony_ci		return 0;
22886881f68fSopenharmony_ci	}
22896881f68fSopenharmony_ci}
22906881f68fSopenharmony_ci
22916881f68fSopenharmony_ciint fuse_lowlevel_notify_inval_inode(struct fuse_session *se, fuse_ino_t ino,
22926881f68fSopenharmony_ci				     off_t off, off_t len)
22936881f68fSopenharmony_ci{
22946881f68fSopenharmony_ci	struct fuse_notify_inval_inode_out outarg;
22956881f68fSopenharmony_ci	struct iovec iov[2];
22966881f68fSopenharmony_ci
22976881f68fSopenharmony_ci	if (!se)
22986881f68fSopenharmony_ci		return -EINVAL;
22996881f68fSopenharmony_ci
23006881f68fSopenharmony_ci	if (se->conn.proto_minor < 12)
23016881f68fSopenharmony_ci		return -ENOSYS;
23026881f68fSopenharmony_ci
23036881f68fSopenharmony_ci	outarg.ino = ino;
23046881f68fSopenharmony_ci	outarg.off = off;
23056881f68fSopenharmony_ci	outarg.len = len;
23066881f68fSopenharmony_ci
23076881f68fSopenharmony_ci	iov[1].iov_base = &outarg;
23086881f68fSopenharmony_ci	iov[1].iov_len = sizeof(outarg);
23096881f68fSopenharmony_ci
23106881f68fSopenharmony_ci	return send_notify_iov(se, FUSE_NOTIFY_INVAL_INODE, iov, 2);
23116881f68fSopenharmony_ci}
23126881f68fSopenharmony_ci
23136881f68fSopenharmony_ci/**
23146881f68fSopenharmony_ci * Notify parent attributes and the dentry matching parent/name
23156881f68fSopenharmony_ci *
23166881f68fSopenharmony_ci * Underlying base function for fuse_lowlevel_notify_inval_entry() and
23176881f68fSopenharmony_ci * fuse_lowlevel_notify_expire_entry().
23186881f68fSopenharmony_ci *
23196881f68fSopenharmony_ci * @warning
23206881f68fSopenharmony_ci * Only checks if fuse_lowlevel_notify_inval_entry() is supported by
23216881f68fSopenharmony_ci * the kernel. All other flags will fall back to
23226881f68fSopenharmony_ci * fuse_lowlevel_notify_inval_entry() if not supported!
23236881f68fSopenharmony_ci * DO THE PROPER CHECKS IN THE DERIVED FUNCTION!
23246881f68fSopenharmony_ci *
23256881f68fSopenharmony_ci * @param se the session object
23266881f68fSopenharmony_ci * @param parent inode number
23276881f68fSopenharmony_ci * @param name file name
23286881f68fSopenharmony_ci * @param namelen strlen() of file name
23296881f68fSopenharmony_ci * @param flags flags to control if the entry should be expired or invalidated
23306881f68fSopenharmony_ci * @return zero for success, -errno for failure
23316881f68fSopenharmony_ci*/
23326881f68fSopenharmony_cistatic int fuse_lowlevel_notify_entry(struct fuse_session *se, fuse_ino_t parent,
23336881f68fSopenharmony_ci							const char *name, size_t namelen,
23346881f68fSopenharmony_ci							enum fuse_notify_entry_flags flags)
23356881f68fSopenharmony_ci{
23366881f68fSopenharmony_ci	struct fuse_notify_inval_entry_out outarg;
23376881f68fSopenharmony_ci	struct iovec iov[3];
23386881f68fSopenharmony_ci
23396881f68fSopenharmony_ci	if (!se)
23406881f68fSopenharmony_ci		return -EINVAL;
23416881f68fSopenharmony_ci
23426881f68fSopenharmony_ci	if (se->conn.proto_minor < 12)
23436881f68fSopenharmony_ci		return -ENOSYS;
23446881f68fSopenharmony_ci
23456881f68fSopenharmony_ci	outarg.parent = parent;
23466881f68fSopenharmony_ci	outarg.namelen = namelen;
23476881f68fSopenharmony_ci	outarg.flags = 0;
23486881f68fSopenharmony_ci	if (flags & FUSE_LL_EXPIRE_ONLY)
23496881f68fSopenharmony_ci		outarg.flags |= FUSE_EXPIRE_ONLY;
23506881f68fSopenharmony_ci
23516881f68fSopenharmony_ci	iov[1].iov_base = &outarg;
23526881f68fSopenharmony_ci	iov[1].iov_len = sizeof(outarg);
23536881f68fSopenharmony_ci	iov[2].iov_base = (void *)name;
23546881f68fSopenharmony_ci	iov[2].iov_len = namelen + 1;
23556881f68fSopenharmony_ci
23566881f68fSopenharmony_ci	return send_notify_iov(se, FUSE_NOTIFY_INVAL_ENTRY, iov, 3);
23576881f68fSopenharmony_ci}
23586881f68fSopenharmony_ci
23596881f68fSopenharmony_ciint fuse_lowlevel_notify_inval_entry(struct fuse_session *se, fuse_ino_t parent,
23606881f68fSopenharmony_ci						 const char *name, size_t namelen)
23616881f68fSopenharmony_ci{
23626881f68fSopenharmony_ci	return fuse_lowlevel_notify_entry(se, parent, name, namelen, FUSE_LL_INVALIDATE);
23636881f68fSopenharmony_ci}
23646881f68fSopenharmony_ci
23656881f68fSopenharmony_ciint fuse_lowlevel_notify_expire_entry(struct fuse_session *se, fuse_ino_t parent,
23666881f68fSopenharmony_ci							const char *name, size_t namelen)
23676881f68fSopenharmony_ci{
23686881f68fSopenharmony_ci	if (!se)
23696881f68fSopenharmony_ci		return -EINVAL;
23706881f68fSopenharmony_ci
23716881f68fSopenharmony_ci	if (!(se->conn.capable & FUSE_CAP_EXPIRE_ONLY))
23726881f68fSopenharmony_ci		return -ENOSYS;
23736881f68fSopenharmony_ci
23746881f68fSopenharmony_ci	return fuse_lowlevel_notify_entry(se, parent, name, namelen, FUSE_LL_EXPIRE_ONLY);
23756881f68fSopenharmony_ci}
23766881f68fSopenharmony_ci
23776881f68fSopenharmony_ci
23786881f68fSopenharmony_ciint fuse_lowlevel_notify_delete(struct fuse_session *se,
23796881f68fSopenharmony_ci				fuse_ino_t parent, fuse_ino_t child,
23806881f68fSopenharmony_ci				const char *name, size_t namelen)
23816881f68fSopenharmony_ci{
23826881f68fSopenharmony_ci	struct fuse_notify_delete_out outarg;
23836881f68fSopenharmony_ci	struct iovec iov[3];
23846881f68fSopenharmony_ci
23856881f68fSopenharmony_ci	if (!se)
23866881f68fSopenharmony_ci		return -EINVAL;
23876881f68fSopenharmony_ci
23886881f68fSopenharmony_ci	if (se->conn.proto_minor < 18)
23896881f68fSopenharmony_ci		return -ENOSYS;
23906881f68fSopenharmony_ci
23916881f68fSopenharmony_ci	outarg.parent = parent;
23926881f68fSopenharmony_ci	outarg.child = child;
23936881f68fSopenharmony_ci	outarg.namelen = namelen;
23946881f68fSopenharmony_ci	outarg.padding = 0;
23956881f68fSopenharmony_ci
23966881f68fSopenharmony_ci	iov[1].iov_base = &outarg;
23976881f68fSopenharmony_ci	iov[1].iov_len = sizeof(outarg);
23986881f68fSopenharmony_ci	iov[2].iov_base = (void *)name;
23996881f68fSopenharmony_ci	iov[2].iov_len = namelen + 1;
24006881f68fSopenharmony_ci
24016881f68fSopenharmony_ci	return send_notify_iov(se, FUSE_NOTIFY_DELETE, iov, 3);
24026881f68fSopenharmony_ci}
24036881f68fSopenharmony_ci
24046881f68fSopenharmony_ciint fuse_lowlevel_notify_store(struct fuse_session *se, fuse_ino_t ino,
24056881f68fSopenharmony_ci			       off_t offset, struct fuse_bufvec *bufv,
24066881f68fSopenharmony_ci			       enum fuse_buf_copy_flags flags)
24076881f68fSopenharmony_ci{
24086881f68fSopenharmony_ci	struct fuse_out_header out;
24096881f68fSopenharmony_ci	struct fuse_notify_store_out outarg;
24106881f68fSopenharmony_ci	struct iovec iov[3];
24116881f68fSopenharmony_ci	size_t size = fuse_buf_size(bufv);
24126881f68fSopenharmony_ci	int res;
24136881f68fSopenharmony_ci
24146881f68fSopenharmony_ci	if (!se)
24156881f68fSopenharmony_ci		return -EINVAL;
24166881f68fSopenharmony_ci
24176881f68fSopenharmony_ci	if (se->conn.proto_minor < 15)
24186881f68fSopenharmony_ci		return -ENOSYS;
24196881f68fSopenharmony_ci
24206881f68fSopenharmony_ci	out.unique = 0;
24216881f68fSopenharmony_ci	out.error = FUSE_NOTIFY_STORE;
24226881f68fSopenharmony_ci
24236881f68fSopenharmony_ci	outarg.nodeid = ino;
24246881f68fSopenharmony_ci	outarg.offset = offset;
24256881f68fSopenharmony_ci	outarg.size = size;
24266881f68fSopenharmony_ci	outarg.padding = 0;
24276881f68fSopenharmony_ci
24286881f68fSopenharmony_ci	iov[0].iov_base = &out;
24296881f68fSopenharmony_ci	iov[0].iov_len = sizeof(out);
24306881f68fSopenharmony_ci	iov[1].iov_base = &outarg;
24316881f68fSopenharmony_ci	iov[1].iov_len = sizeof(outarg);
24326881f68fSopenharmony_ci
24336881f68fSopenharmony_ci	res = fuse_send_data_iov(se, NULL, iov, 2, bufv, flags);
24346881f68fSopenharmony_ci	if (res > 0)
24356881f68fSopenharmony_ci		res = -res;
24366881f68fSopenharmony_ci
24376881f68fSopenharmony_ci	return res;
24386881f68fSopenharmony_ci}
24396881f68fSopenharmony_ci
24406881f68fSopenharmony_cistruct fuse_retrieve_req {
24416881f68fSopenharmony_ci	struct fuse_notify_req nreq;
24426881f68fSopenharmony_ci	void *cookie;
24436881f68fSopenharmony_ci};
24446881f68fSopenharmony_ci
24456881f68fSopenharmony_cistatic void fuse_ll_retrieve_reply(struct fuse_notify_req *nreq,
24466881f68fSopenharmony_ci				   fuse_req_t req, fuse_ino_t ino,
24476881f68fSopenharmony_ci				   const void *inarg,
24486881f68fSopenharmony_ci				   const struct fuse_buf *ibuf)
24496881f68fSopenharmony_ci{
24506881f68fSopenharmony_ci	struct fuse_session *se = req->se;
24516881f68fSopenharmony_ci	struct fuse_retrieve_req *rreq =
24526881f68fSopenharmony_ci		container_of(nreq, struct fuse_retrieve_req, nreq);
24536881f68fSopenharmony_ci	const struct fuse_notify_retrieve_in *arg = inarg;
24546881f68fSopenharmony_ci	struct fuse_bufvec bufv = {
24556881f68fSopenharmony_ci		.buf[0] = *ibuf,
24566881f68fSopenharmony_ci		.count = 1,
24576881f68fSopenharmony_ci	};
24586881f68fSopenharmony_ci
24596881f68fSopenharmony_ci	if (!(bufv.buf[0].flags & FUSE_BUF_IS_FD))
24606881f68fSopenharmony_ci		bufv.buf[0].mem = PARAM(arg);
24616881f68fSopenharmony_ci
24626881f68fSopenharmony_ci	bufv.buf[0].size -= sizeof(struct fuse_in_header) +
24636881f68fSopenharmony_ci		sizeof(struct fuse_notify_retrieve_in);
24646881f68fSopenharmony_ci
24656881f68fSopenharmony_ci	if (bufv.buf[0].size < arg->size) {
24666881f68fSopenharmony_ci		fuse_log(FUSE_LOG_ERR, "fuse: retrieve reply: buffer size too small\n");
24676881f68fSopenharmony_ci		fuse_reply_none(req);
24686881f68fSopenharmony_ci		goto out;
24696881f68fSopenharmony_ci	}
24706881f68fSopenharmony_ci	bufv.buf[0].size = arg->size;
24716881f68fSopenharmony_ci
24726881f68fSopenharmony_ci	if (se->op.retrieve_reply) {
24736881f68fSopenharmony_ci		se->op.retrieve_reply(req, rreq->cookie, ino,
24746881f68fSopenharmony_ci					  arg->offset, &bufv);
24756881f68fSopenharmony_ci	} else {
24766881f68fSopenharmony_ci		fuse_reply_none(req);
24776881f68fSopenharmony_ci	}
24786881f68fSopenharmony_ciout:
24796881f68fSopenharmony_ci	free(rreq);
24806881f68fSopenharmony_ci	if ((ibuf->flags & FUSE_BUF_IS_FD) && bufv.idx < bufv.count)
24816881f68fSopenharmony_ci		fuse_ll_clear_pipe(se);
24826881f68fSopenharmony_ci}
24836881f68fSopenharmony_ci
24846881f68fSopenharmony_ciint fuse_lowlevel_notify_retrieve(struct fuse_session *se, fuse_ino_t ino,
24856881f68fSopenharmony_ci				  size_t size, off_t offset, void *cookie)
24866881f68fSopenharmony_ci{
24876881f68fSopenharmony_ci	struct fuse_notify_retrieve_out outarg;
24886881f68fSopenharmony_ci	struct iovec iov[2];
24896881f68fSopenharmony_ci	struct fuse_retrieve_req *rreq;
24906881f68fSopenharmony_ci	int err;
24916881f68fSopenharmony_ci
24926881f68fSopenharmony_ci	if (!se)
24936881f68fSopenharmony_ci		return -EINVAL;
24946881f68fSopenharmony_ci
24956881f68fSopenharmony_ci	if (se->conn.proto_minor < 15)
24966881f68fSopenharmony_ci		return -ENOSYS;
24976881f68fSopenharmony_ci
24986881f68fSopenharmony_ci	rreq = malloc(sizeof(*rreq));
24996881f68fSopenharmony_ci	if (rreq == NULL)
25006881f68fSopenharmony_ci		return -ENOMEM;
25016881f68fSopenharmony_ci
25026881f68fSopenharmony_ci	pthread_mutex_lock(&se->lock);
25036881f68fSopenharmony_ci	rreq->cookie = cookie;
25046881f68fSopenharmony_ci	rreq->nreq.unique = se->notify_ctr++;
25056881f68fSopenharmony_ci	rreq->nreq.reply = fuse_ll_retrieve_reply;
25066881f68fSopenharmony_ci	list_add_nreq(&rreq->nreq, &se->notify_list);
25076881f68fSopenharmony_ci	pthread_mutex_unlock(&se->lock);
25086881f68fSopenharmony_ci
25096881f68fSopenharmony_ci	outarg.notify_unique = rreq->nreq.unique;
25106881f68fSopenharmony_ci	outarg.nodeid = ino;
25116881f68fSopenharmony_ci	outarg.offset = offset;
25126881f68fSopenharmony_ci	outarg.size = size;
25136881f68fSopenharmony_ci	outarg.padding = 0;
25146881f68fSopenharmony_ci
25156881f68fSopenharmony_ci	iov[1].iov_base = &outarg;
25166881f68fSopenharmony_ci	iov[1].iov_len = sizeof(outarg);
25176881f68fSopenharmony_ci
25186881f68fSopenharmony_ci	err = send_notify_iov(se, FUSE_NOTIFY_RETRIEVE, iov, 2);
25196881f68fSopenharmony_ci	if (err) {
25206881f68fSopenharmony_ci		pthread_mutex_lock(&se->lock);
25216881f68fSopenharmony_ci		list_del_nreq(&rreq->nreq);
25226881f68fSopenharmony_ci		pthread_mutex_unlock(&se->lock);
25236881f68fSopenharmony_ci		free(rreq);
25246881f68fSopenharmony_ci	}
25256881f68fSopenharmony_ci
25266881f68fSopenharmony_ci	return err;
25276881f68fSopenharmony_ci}
25286881f68fSopenharmony_ci
25296881f68fSopenharmony_civoid *fuse_req_userdata(fuse_req_t req)
25306881f68fSopenharmony_ci{
25316881f68fSopenharmony_ci	return req->se->userdata;
25326881f68fSopenharmony_ci}
25336881f68fSopenharmony_ci
25346881f68fSopenharmony_ciconst struct fuse_ctx *fuse_req_ctx(fuse_req_t req)
25356881f68fSopenharmony_ci{
25366881f68fSopenharmony_ci	return &req->ctx;
25376881f68fSopenharmony_ci}
25386881f68fSopenharmony_ci
25396881f68fSopenharmony_civoid fuse_req_interrupt_func(fuse_req_t req, fuse_interrupt_func_t func,
25406881f68fSopenharmony_ci			     void *data)
25416881f68fSopenharmony_ci{
25426881f68fSopenharmony_ci	pthread_mutex_lock(&req->lock);
25436881f68fSopenharmony_ci	pthread_mutex_lock(&req->se->lock);
25446881f68fSopenharmony_ci	req->u.ni.func = func;
25456881f68fSopenharmony_ci	req->u.ni.data = data;
25466881f68fSopenharmony_ci	pthread_mutex_unlock(&req->se->lock);
25476881f68fSopenharmony_ci	if (req->interrupted && func)
25486881f68fSopenharmony_ci		func(req, data);
25496881f68fSopenharmony_ci	pthread_mutex_unlock(&req->lock);
25506881f68fSopenharmony_ci}
25516881f68fSopenharmony_ci
25526881f68fSopenharmony_ciint fuse_req_interrupted(fuse_req_t req)
25536881f68fSopenharmony_ci{
25546881f68fSopenharmony_ci	int interrupted;
25556881f68fSopenharmony_ci
25566881f68fSopenharmony_ci	pthread_mutex_lock(&req->se->lock);
25576881f68fSopenharmony_ci	interrupted = req->interrupted;
25586881f68fSopenharmony_ci	pthread_mutex_unlock(&req->se->lock);
25596881f68fSopenharmony_ci
25606881f68fSopenharmony_ci	return interrupted;
25616881f68fSopenharmony_ci}
25626881f68fSopenharmony_ci
25636881f68fSopenharmony_cistatic struct {
25646881f68fSopenharmony_ci	void (*func)(fuse_req_t, fuse_ino_t, const void *);
25656881f68fSopenharmony_ci	const char *name;
25666881f68fSopenharmony_ci} fuse_ll_ops[] = {
25676881f68fSopenharmony_ci	[FUSE_LOOKUP]	   = { do_lookup,      "LOOKUP"	     },
25686881f68fSopenharmony_ci	[FUSE_FORGET]	   = { do_forget,      "FORGET"	     },
25696881f68fSopenharmony_ci	[FUSE_GETATTR]	   = { do_getattr,     "GETATTR"     },
25706881f68fSopenharmony_ci	[FUSE_SETATTR]	   = { do_setattr,     "SETATTR"     },
25716881f68fSopenharmony_ci	[FUSE_READLINK]	   = { do_readlink,    "READLINK"    },
25726881f68fSopenharmony_ci	[FUSE_SYMLINK]	   = { do_symlink,     "SYMLINK"     },
25736881f68fSopenharmony_ci	[FUSE_MKNOD]	   = { do_mknod,       "MKNOD"	     },
25746881f68fSopenharmony_ci	[FUSE_MKDIR]	   = { do_mkdir,       "MKDIR"	     },
25756881f68fSopenharmony_ci	[FUSE_UNLINK]	   = { do_unlink,      "UNLINK"	     },
25766881f68fSopenharmony_ci	[FUSE_RMDIR]	   = { do_rmdir,       "RMDIR"	     },
25776881f68fSopenharmony_ci	[FUSE_RENAME]	   = { do_rename,      "RENAME"	     },
25786881f68fSopenharmony_ci	[FUSE_LINK]	   = { do_link,	       "LINK"	     },
25796881f68fSopenharmony_ci	[FUSE_OPEN]	   = { do_open,	       "OPEN"	     },
25806881f68fSopenharmony_ci	[FUSE_READ]	   = { do_read,	       "READ"	     },
25816881f68fSopenharmony_ci	[FUSE_WRITE]	   = { do_write,       "WRITE"	     },
25826881f68fSopenharmony_ci	[FUSE_STATFS]	   = { do_statfs,      "STATFS"	     },
25836881f68fSopenharmony_ci	[FUSE_RELEASE]	   = { do_release,     "RELEASE"     },
25846881f68fSopenharmony_ci	[FUSE_FSYNC]	   = { do_fsync,       "FSYNC"	     },
25856881f68fSopenharmony_ci	[FUSE_SETXATTR]	   = { do_setxattr,    "SETXATTR"    },
25866881f68fSopenharmony_ci	[FUSE_GETXATTR]	   = { do_getxattr,    "GETXATTR"    },
25876881f68fSopenharmony_ci	[FUSE_LISTXATTR]   = { do_listxattr,   "LISTXATTR"   },
25886881f68fSopenharmony_ci	[FUSE_REMOVEXATTR] = { do_removexattr, "REMOVEXATTR" },
25896881f68fSopenharmony_ci	[FUSE_FLUSH]	   = { do_flush,       "FLUSH"	     },
25906881f68fSopenharmony_ci	[FUSE_INIT]	   = { do_init,	       "INIT"	     },
25916881f68fSopenharmony_ci	[FUSE_OPENDIR]	   = { do_opendir,     "OPENDIR"     },
25926881f68fSopenharmony_ci	[FUSE_READDIR]	   = { do_readdir,     "READDIR"     },
25936881f68fSopenharmony_ci	[FUSE_RELEASEDIR]  = { do_releasedir,  "RELEASEDIR"  },
25946881f68fSopenharmony_ci	[FUSE_FSYNCDIR]	   = { do_fsyncdir,    "FSYNCDIR"    },
25956881f68fSopenharmony_ci	[FUSE_GETLK]	   = { do_getlk,       "GETLK"	     },
25966881f68fSopenharmony_ci	[FUSE_SETLK]	   = { do_setlk,       "SETLK"	     },
25976881f68fSopenharmony_ci	[FUSE_SETLKW]	   = { do_setlkw,      "SETLKW"	     },
25986881f68fSopenharmony_ci	[FUSE_ACCESS]	   = { do_access,      "ACCESS"	     },
25996881f68fSopenharmony_ci	[FUSE_CREATE]	   = { do_create,      "CREATE"	     },
26006881f68fSopenharmony_ci	[FUSE_INTERRUPT]   = { do_interrupt,   "INTERRUPT"   },
26016881f68fSopenharmony_ci	[FUSE_BMAP]	   = { do_bmap,	       "BMAP"	     },
26026881f68fSopenharmony_ci	[FUSE_IOCTL]	   = { do_ioctl,       "IOCTL"	     },
26036881f68fSopenharmony_ci	[FUSE_POLL]	   = { do_poll,        "POLL"	     },
26046881f68fSopenharmony_ci	[FUSE_FALLOCATE]   = { do_fallocate,   "FALLOCATE"   },
26056881f68fSopenharmony_ci	[FUSE_DESTROY]	   = { do_destroy,     "DESTROY"     },
26066881f68fSopenharmony_ci	[FUSE_NOTIFY_REPLY] = { (void *) 1,    "NOTIFY_REPLY" },
26076881f68fSopenharmony_ci	[FUSE_BATCH_FORGET] = { do_batch_forget, "BATCH_FORGET" },
26086881f68fSopenharmony_ci	[FUSE_READDIRPLUS] = { do_readdirplus,	"READDIRPLUS"},
26096881f68fSopenharmony_ci	[FUSE_RENAME2]     = { do_rename2,      "RENAME2"    },
26106881f68fSopenharmony_ci	[FUSE_COPY_FILE_RANGE] = { do_copy_file_range, "COPY_FILE_RANGE" },
26116881f68fSopenharmony_ci	[FUSE_LSEEK]	   = { do_lseek,       "LSEEK"	     },
26126881f68fSopenharmony_ci	[CUSE_INIT]	   = { cuse_lowlevel_init, "CUSE_INIT"   },
26136881f68fSopenharmony_ci};
26146881f68fSopenharmony_ci
26156881f68fSopenharmony_ci#define FUSE_MAXOP (sizeof(fuse_ll_ops) / sizeof(fuse_ll_ops[0]))
26166881f68fSopenharmony_ci
26176881f68fSopenharmony_cistatic const char *opname(enum fuse_opcode opcode)
26186881f68fSopenharmony_ci{
26196881f68fSopenharmony_ci	if (opcode >= FUSE_MAXOP || !fuse_ll_ops[opcode].name)
26206881f68fSopenharmony_ci		return "???";
26216881f68fSopenharmony_ci	else
26226881f68fSopenharmony_ci		return fuse_ll_ops[opcode].name;
26236881f68fSopenharmony_ci}
26246881f68fSopenharmony_ci
26256881f68fSopenharmony_cistatic int fuse_ll_copy_from_pipe(struct fuse_bufvec *dst,
26266881f68fSopenharmony_ci				  struct fuse_bufvec *src)
26276881f68fSopenharmony_ci{
26286881f68fSopenharmony_ci	ssize_t res = fuse_buf_copy(dst, src, 0);
26296881f68fSopenharmony_ci	if (res < 0) {
26306881f68fSopenharmony_ci		fuse_log(FUSE_LOG_ERR, "fuse: copy from pipe: %s\n", strerror(-res));
26316881f68fSopenharmony_ci		return res;
26326881f68fSopenharmony_ci	}
26336881f68fSopenharmony_ci	if ((size_t)res < fuse_buf_size(dst)) {
26346881f68fSopenharmony_ci		fuse_log(FUSE_LOG_ERR, "fuse: copy from pipe: short read\n");
26356881f68fSopenharmony_ci		return -1;
26366881f68fSopenharmony_ci	}
26376881f68fSopenharmony_ci	return 0;
26386881f68fSopenharmony_ci}
26396881f68fSopenharmony_ci
26406881f68fSopenharmony_civoid fuse_session_process_buf(struct fuse_session *se,
26416881f68fSopenharmony_ci			      const struct fuse_buf *buf)
26426881f68fSopenharmony_ci{
26436881f68fSopenharmony_ci	fuse_session_process_buf_int(se, buf, NULL);
26446881f68fSopenharmony_ci}
26456881f68fSopenharmony_ci
26466881f68fSopenharmony_civoid fuse_session_process_buf_int(struct fuse_session *se,
26476881f68fSopenharmony_ci				  const struct fuse_buf *buf, struct fuse_chan *ch)
26486881f68fSopenharmony_ci{
26496881f68fSopenharmony_ci	const size_t write_header_size = sizeof(struct fuse_in_header) +
26506881f68fSopenharmony_ci		sizeof(struct fuse_write_in);
26516881f68fSopenharmony_ci	struct fuse_bufvec bufv = { .buf[0] = *buf, .count = 1 };
26526881f68fSopenharmony_ci	struct fuse_bufvec tmpbuf = FUSE_BUFVEC_INIT(write_header_size);
26536881f68fSopenharmony_ci	struct fuse_in_header *in;
26546881f68fSopenharmony_ci	const void *inarg;
26556881f68fSopenharmony_ci	struct fuse_req *req;
26566881f68fSopenharmony_ci	void *mbuf = NULL;
26576881f68fSopenharmony_ci	int err;
26586881f68fSopenharmony_ci	int res;
26596881f68fSopenharmony_ci
26606881f68fSopenharmony_ci	if (buf->flags & FUSE_BUF_IS_FD) {
26616881f68fSopenharmony_ci		if (buf->size < tmpbuf.buf[0].size)
26626881f68fSopenharmony_ci			tmpbuf.buf[0].size = buf->size;
26636881f68fSopenharmony_ci
26646881f68fSopenharmony_ci		mbuf = malloc(tmpbuf.buf[0].size);
26656881f68fSopenharmony_ci		if (mbuf == NULL) {
26666881f68fSopenharmony_ci			fuse_log(FUSE_LOG_ERR, "fuse: failed to allocate header\n");
26676881f68fSopenharmony_ci			goto clear_pipe;
26686881f68fSopenharmony_ci		}
26696881f68fSopenharmony_ci		tmpbuf.buf[0].mem = mbuf;
26706881f68fSopenharmony_ci
26716881f68fSopenharmony_ci		res = fuse_ll_copy_from_pipe(&tmpbuf, &bufv);
26726881f68fSopenharmony_ci		if (res < 0)
26736881f68fSopenharmony_ci			goto clear_pipe;
26746881f68fSopenharmony_ci
26756881f68fSopenharmony_ci		in = mbuf;
26766881f68fSopenharmony_ci	} else {
26776881f68fSopenharmony_ci		in = buf->mem;
26786881f68fSopenharmony_ci	}
26796881f68fSopenharmony_ci
26806881f68fSopenharmony_ci	if (se->debug) {
26816881f68fSopenharmony_ci		fuse_log(FUSE_LOG_DEBUG,
26826881f68fSopenharmony_ci			"unique: %llu, opcode: %s (%i), nodeid: %llu, insize: %zu, pid: %u\n",
26836881f68fSopenharmony_ci			(unsigned long long) in->unique,
26846881f68fSopenharmony_ci			opname((enum fuse_opcode) in->opcode), in->opcode,
26856881f68fSopenharmony_ci			(unsigned long long) in->nodeid, buf->size, in->pid);
26866881f68fSopenharmony_ci	}
26876881f68fSopenharmony_ci
26886881f68fSopenharmony_ci	req = fuse_ll_alloc_req(se);
26896881f68fSopenharmony_ci	if (req == NULL) {
26906881f68fSopenharmony_ci		struct fuse_out_header out = {
26916881f68fSopenharmony_ci			.unique = in->unique,
26926881f68fSopenharmony_ci			.error = -ENOMEM,
26936881f68fSopenharmony_ci		};
26946881f68fSopenharmony_ci		struct iovec iov = {
26956881f68fSopenharmony_ci			.iov_base = &out,
26966881f68fSopenharmony_ci			.iov_len = sizeof(struct fuse_out_header),
26976881f68fSopenharmony_ci		};
26986881f68fSopenharmony_ci
26996881f68fSopenharmony_ci		fuse_send_msg(se, ch, &iov, 1);
27006881f68fSopenharmony_ci		goto clear_pipe;
27016881f68fSopenharmony_ci	}
27026881f68fSopenharmony_ci
27036881f68fSopenharmony_ci	req->unique = in->unique;
27046881f68fSopenharmony_ci	req->ctx.uid = in->uid;
27056881f68fSopenharmony_ci	req->ctx.gid = in->gid;
27066881f68fSopenharmony_ci	req->ctx.pid = in->pid;
27076881f68fSopenharmony_ci	req->ch = ch ? fuse_chan_get(ch) : NULL;
27086881f68fSopenharmony_ci
27096881f68fSopenharmony_ci	err = EIO;
27106881f68fSopenharmony_ci	if (!se->got_init) {
27116881f68fSopenharmony_ci		enum fuse_opcode expected;
27126881f68fSopenharmony_ci
27136881f68fSopenharmony_ci		expected = se->cuse_data ? CUSE_INIT : FUSE_INIT;
27146881f68fSopenharmony_ci		if (in->opcode != expected)
27156881f68fSopenharmony_ci			goto reply_err;
27166881f68fSopenharmony_ci	} else if (in->opcode == FUSE_INIT || in->opcode == CUSE_INIT)
27176881f68fSopenharmony_ci		goto reply_err;
27186881f68fSopenharmony_ci
27196881f68fSopenharmony_ci	err = EACCES;
27206881f68fSopenharmony_ci	/* Implement -o allow_root */
27216881f68fSopenharmony_ci	if (se->deny_others && in->uid != se->owner && in->uid != 0 &&
27226881f68fSopenharmony_ci		 in->opcode != FUSE_INIT && in->opcode != FUSE_READ &&
27236881f68fSopenharmony_ci		 in->opcode != FUSE_WRITE && in->opcode != FUSE_FSYNC &&
27246881f68fSopenharmony_ci		 in->opcode != FUSE_RELEASE && in->opcode != FUSE_READDIR &&
27256881f68fSopenharmony_ci		 in->opcode != FUSE_FSYNCDIR && in->opcode != FUSE_RELEASEDIR &&
27266881f68fSopenharmony_ci		 in->opcode != FUSE_NOTIFY_REPLY &&
27276881f68fSopenharmony_ci		 in->opcode != FUSE_READDIRPLUS)
27286881f68fSopenharmony_ci		goto reply_err;
27296881f68fSopenharmony_ci
27306881f68fSopenharmony_ci	err = ENOSYS;
27316881f68fSopenharmony_ci	if (in->opcode >= FUSE_MAXOP || !fuse_ll_ops[in->opcode].func)
27326881f68fSopenharmony_ci		goto reply_err;
27336881f68fSopenharmony_ci	if (in->opcode != FUSE_INTERRUPT) {
27346881f68fSopenharmony_ci		struct fuse_req *intr;
27356881f68fSopenharmony_ci		pthread_mutex_lock(&se->lock);
27366881f68fSopenharmony_ci		intr = check_interrupt(se, req);
27376881f68fSopenharmony_ci		list_add_req(req, &se->list);
27386881f68fSopenharmony_ci		pthread_mutex_unlock(&se->lock);
27396881f68fSopenharmony_ci		if (intr)
27406881f68fSopenharmony_ci			fuse_reply_err(intr, EAGAIN);
27416881f68fSopenharmony_ci	}
27426881f68fSopenharmony_ci
27436881f68fSopenharmony_ci	if ((buf->flags & FUSE_BUF_IS_FD) && write_header_size < buf->size &&
27446881f68fSopenharmony_ci	    (in->opcode != FUSE_WRITE || !se->op.write_buf) &&
27456881f68fSopenharmony_ci	    in->opcode != FUSE_NOTIFY_REPLY) {
27466881f68fSopenharmony_ci		void *newmbuf;
27476881f68fSopenharmony_ci
27486881f68fSopenharmony_ci		err = ENOMEM;
27496881f68fSopenharmony_ci		newmbuf = realloc(mbuf, buf->size);
27506881f68fSopenharmony_ci		if (newmbuf == NULL)
27516881f68fSopenharmony_ci			goto reply_err;
27526881f68fSopenharmony_ci		mbuf = newmbuf;
27536881f68fSopenharmony_ci
27546881f68fSopenharmony_ci		tmpbuf = FUSE_BUFVEC_INIT(buf->size - write_header_size);
27556881f68fSopenharmony_ci		tmpbuf.buf[0].mem = (char *)mbuf + write_header_size;
27566881f68fSopenharmony_ci
27576881f68fSopenharmony_ci		res = fuse_ll_copy_from_pipe(&tmpbuf, &bufv);
27586881f68fSopenharmony_ci		err = -res;
27596881f68fSopenharmony_ci		if (res < 0)
27606881f68fSopenharmony_ci			goto reply_err;
27616881f68fSopenharmony_ci
27626881f68fSopenharmony_ci		in = mbuf;
27636881f68fSopenharmony_ci	}
27646881f68fSopenharmony_ci
27656881f68fSopenharmony_ci	inarg = (void *) &in[1];
27666881f68fSopenharmony_ci	if (in->opcode == FUSE_WRITE && se->op.write_buf)
27676881f68fSopenharmony_ci		do_write_buf(req, in->nodeid, inarg, buf);
27686881f68fSopenharmony_ci	else if (in->opcode == FUSE_NOTIFY_REPLY)
27696881f68fSopenharmony_ci		do_notify_reply(req, in->nodeid, inarg, buf);
27706881f68fSopenharmony_ci	else
27716881f68fSopenharmony_ci		fuse_ll_ops[in->opcode].func(req, in->nodeid, inarg);
27726881f68fSopenharmony_ci
27736881f68fSopenharmony_ciout_free:
27746881f68fSopenharmony_ci	free(mbuf);
27756881f68fSopenharmony_ci	return;
27766881f68fSopenharmony_ci
27776881f68fSopenharmony_cireply_err:
27786881f68fSopenharmony_ci	fuse_reply_err(req, err);
27796881f68fSopenharmony_ciclear_pipe:
27806881f68fSopenharmony_ci	if (buf->flags & FUSE_BUF_IS_FD)
27816881f68fSopenharmony_ci		fuse_ll_clear_pipe(se);
27826881f68fSopenharmony_ci	goto out_free;
27836881f68fSopenharmony_ci}
27846881f68fSopenharmony_ci
27856881f68fSopenharmony_ci#define LL_OPTION(n,o,v) \
27866881f68fSopenharmony_ci	{ n, offsetof(struct fuse_session, o), v }
27876881f68fSopenharmony_ci
27886881f68fSopenharmony_cistatic const struct fuse_opt fuse_ll_opts[] = {
27896881f68fSopenharmony_ci	LL_OPTION("debug", debug, 1),
27906881f68fSopenharmony_ci	LL_OPTION("-d", debug, 1),
27916881f68fSopenharmony_ci	LL_OPTION("--debug", debug, 1),
27926881f68fSopenharmony_ci	LL_OPTION("allow_root", deny_others, 1),
27936881f68fSopenharmony_ci	FUSE_OPT_END
27946881f68fSopenharmony_ci};
27956881f68fSopenharmony_ci
27966881f68fSopenharmony_civoid fuse_lowlevel_version(void)
27976881f68fSopenharmony_ci{
27986881f68fSopenharmony_ci	printf("using FUSE kernel interface version %i.%i\n",
27996881f68fSopenharmony_ci	       FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
28006881f68fSopenharmony_ci	fuse_mount_version();
28016881f68fSopenharmony_ci}
28026881f68fSopenharmony_ci
28036881f68fSopenharmony_civoid fuse_lowlevel_help(void)
28046881f68fSopenharmony_ci{
28056881f68fSopenharmony_ci	/* These are not all options, but the ones that are
28066881f68fSopenharmony_ci	   potentially of interest to an end-user */
28076881f68fSopenharmony_ci	printf(
28086881f68fSopenharmony_ci"    -o allow_other         allow access by all users\n"
28096881f68fSopenharmony_ci"    -o allow_root          allow access by root\n"
28106881f68fSopenharmony_ci"    -o auto_unmount        auto unmount on process termination\n");
28116881f68fSopenharmony_ci}
28126881f68fSopenharmony_ci
28136881f68fSopenharmony_civoid fuse_session_destroy(struct fuse_session *se)
28146881f68fSopenharmony_ci{
28156881f68fSopenharmony_ci	struct fuse_ll_pipe *llp;
28166881f68fSopenharmony_ci
28176881f68fSopenharmony_ci	if (se->got_init && !se->got_destroy) {
28186881f68fSopenharmony_ci		if (se->op.destroy)
28196881f68fSopenharmony_ci			se->op.destroy(se->userdata);
28206881f68fSopenharmony_ci	}
28216881f68fSopenharmony_ci	llp = pthread_getspecific(se->pipe_key);
28226881f68fSopenharmony_ci	if (llp != NULL)
28236881f68fSopenharmony_ci		fuse_ll_pipe_free(llp);
28246881f68fSopenharmony_ci	pthread_key_delete(se->pipe_key);
28256881f68fSopenharmony_ci	pthread_mutex_destroy(&se->lock);
28266881f68fSopenharmony_ci	free(se->cuse_data);
28276881f68fSopenharmony_ci	if (se->fd != -1)
28286881f68fSopenharmony_ci		close(se->fd);
28296881f68fSopenharmony_ci	if (se->io != NULL)
28306881f68fSopenharmony_ci		free(se->io);
28316881f68fSopenharmony_ci	destroy_mount_opts(se->mo);
28326881f68fSopenharmony_ci	free(se);
28336881f68fSopenharmony_ci}
28346881f68fSopenharmony_ci
28356881f68fSopenharmony_ci
28366881f68fSopenharmony_cistatic void fuse_ll_pipe_destructor(void *data)
28376881f68fSopenharmony_ci{
28386881f68fSopenharmony_ci	struct fuse_ll_pipe *llp = data;
28396881f68fSopenharmony_ci	fuse_ll_pipe_free(llp);
28406881f68fSopenharmony_ci}
28416881f68fSopenharmony_ci
28426881f68fSopenharmony_ciint fuse_session_receive_buf(struct fuse_session *se, struct fuse_buf *buf)
28436881f68fSopenharmony_ci{
28446881f68fSopenharmony_ci	return fuse_session_receive_buf_int(se, buf, NULL);
28456881f68fSopenharmony_ci}
28466881f68fSopenharmony_ci
28476881f68fSopenharmony_ciint fuse_session_receive_buf_int(struct fuse_session *se, struct fuse_buf *buf,
28486881f68fSopenharmony_ci				 struct fuse_chan *ch)
28496881f68fSopenharmony_ci{
28506881f68fSopenharmony_ci	int err;
28516881f68fSopenharmony_ci	ssize_t res;
28526881f68fSopenharmony_ci#ifdef HAVE_SPLICE
28536881f68fSopenharmony_ci	size_t bufsize = se->bufsize;
28546881f68fSopenharmony_ci	struct fuse_ll_pipe *llp;
28556881f68fSopenharmony_ci	struct fuse_buf tmpbuf;
28566881f68fSopenharmony_ci
28576881f68fSopenharmony_ci	if (se->conn.proto_minor < 14 || !(se->conn.want & FUSE_CAP_SPLICE_READ))
28586881f68fSopenharmony_ci		goto fallback;
28596881f68fSopenharmony_ci
28606881f68fSopenharmony_ci	llp = fuse_ll_get_pipe(se);
28616881f68fSopenharmony_ci	if (llp == NULL)
28626881f68fSopenharmony_ci		goto fallback;
28636881f68fSopenharmony_ci
28646881f68fSopenharmony_ci	if (llp->size < bufsize) {
28656881f68fSopenharmony_ci		if (llp->can_grow) {
28666881f68fSopenharmony_ci			res = fcntl(llp->pipe[0], F_SETPIPE_SZ, bufsize);
28676881f68fSopenharmony_ci			if (res == -1) {
28686881f68fSopenharmony_ci				llp->can_grow = 0;
28696881f68fSopenharmony_ci				res = grow_pipe_to_max(llp->pipe[0]);
28706881f68fSopenharmony_ci				if (res > 0)
28716881f68fSopenharmony_ci					llp->size = res;
28726881f68fSopenharmony_ci				goto fallback;
28736881f68fSopenharmony_ci			}
28746881f68fSopenharmony_ci			llp->size = res;
28756881f68fSopenharmony_ci		}
28766881f68fSopenharmony_ci		if (llp->size < bufsize)
28776881f68fSopenharmony_ci			goto fallback;
28786881f68fSopenharmony_ci	}
28796881f68fSopenharmony_ci
28806881f68fSopenharmony_ci	if (se->io != NULL && se->io->splice_receive != NULL) {
28816881f68fSopenharmony_ci		res = se->io->splice_receive(ch ? ch->fd : se->fd, NULL,
28826881f68fSopenharmony_ci						     llp->pipe[1], NULL, bufsize, 0,
28836881f68fSopenharmony_ci						     se->userdata);
28846881f68fSopenharmony_ci	} else {
28856881f68fSopenharmony_ci		res = splice(ch ? ch->fd : se->fd, NULL, llp->pipe[1], NULL,
28866881f68fSopenharmony_ci				 bufsize, 0);
28876881f68fSopenharmony_ci	}
28886881f68fSopenharmony_ci	err = errno;
28896881f68fSopenharmony_ci
28906881f68fSopenharmony_ci	if (fuse_session_exited(se))
28916881f68fSopenharmony_ci		return 0;
28926881f68fSopenharmony_ci
28936881f68fSopenharmony_ci	if (res == -1) {
28946881f68fSopenharmony_ci		if (err == ENODEV) {
28956881f68fSopenharmony_ci			/* Filesystem was unmounted, or connection was aborted
28966881f68fSopenharmony_ci			   via /sys/fs/fuse/connections */
28976881f68fSopenharmony_ci			fuse_session_exit(se);
28986881f68fSopenharmony_ci			return 0;
28996881f68fSopenharmony_ci		}
29006881f68fSopenharmony_ci		if (err != EINTR && err != EAGAIN)
29016881f68fSopenharmony_ci			perror("fuse: splice from device");
29026881f68fSopenharmony_ci		return -err;
29036881f68fSopenharmony_ci	}
29046881f68fSopenharmony_ci
29056881f68fSopenharmony_ci	if (res < sizeof(struct fuse_in_header)) {
29066881f68fSopenharmony_ci		fuse_log(FUSE_LOG_ERR, "short splice from fuse device\n");
29076881f68fSopenharmony_ci		return -EIO;
29086881f68fSopenharmony_ci	}
29096881f68fSopenharmony_ci
29106881f68fSopenharmony_ci	tmpbuf = (struct fuse_buf) {
29116881f68fSopenharmony_ci		.size = res,
29126881f68fSopenharmony_ci		.flags = FUSE_BUF_IS_FD,
29136881f68fSopenharmony_ci		.fd = llp->pipe[0],
29146881f68fSopenharmony_ci	};
29156881f68fSopenharmony_ci
29166881f68fSopenharmony_ci	/*
29176881f68fSopenharmony_ci	 * Don't bother with zero copy for small requests.
29186881f68fSopenharmony_ci	 * fuse_loop_mt() needs to check for FORGET so this more than
29196881f68fSopenharmony_ci	 * just an optimization.
29206881f68fSopenharmony_ci	 */
29216881f68fSopenharmony_ci	if (res < sizeof(struct fuse_in_header) +
29226881f68fSopenharmony_ci	    sizeof(struct fuse_write_in) + pagesize) {
29236881f68fSopenharmony_ci		struct fuse_bufvec src = { .buf[0] = tmpbuf, .count = 1 };
29246881f68fSopenharmony_ci		struct fuse_bufvec dst = { .count = 1 };
29256881f68fSopenharmony_ci
29266881f68fSopenharmony_ci		if (!buf->mem) {
29276881f68fSopenharmony_ci			buf->mem = malloc(se->bufsize);
29286881f68fSopenharmony_ci			if (!buf->mem) {
29296881f68fSopenharmony_ci				fuse_log(FUSE_LOG_ERR,
29306881f68fSopenharmony_ci					"fuse: failed to allocate read buffer\n");
29316881f68fSopenharmony_ci				return -ENOMEM;
29326881f68fSopenharmony_ci			}
29336881f68fSopenharmony_ci		}
29346881f68fSopenharmony_ci		buf->size = se->bufsize;
29356881f68fSopenharmony_ci		buf->flags = 0;
29366881f68fSopenharmony_ci		dst.buf[0] = *buf;
29376881f68fSopenharmony_ci
29386881f68fSopenharmony_ci		res = fuse_buf_copy(&dst, &src, 0);
29396881f68fSopenharmony_ci		if (res < 0) {
29406881f68fSopenharmony_ci			fuse_log(FUSE_LOG_ERR, "fuse: copy from pipe: %s\n",
29416881f68fSopenharmony_ci				strerror(-res));
29426881f68fSopenharmony_ci			fuse_ll_clear_pipe(se);
29436881f68fSopenharmony_ci			return res;
29446881f68fSopenharmony_ci		}
29456881f68fSopenharmony_ci		if (res < tmpbuf.size) {
29466881f68fSopenharmony_ci			fuse_log(FUSE_LOG_ERR, "fuse: copy from pipe: short read\n");
29476881f68fSopenharmony_ci			fuse_ll_clear_pipe(se);
29486881f68fSopenharmony_ci			return -EIO;
29496881f68fSopenharmony_ci		}
29506881f68fSopenharmony_ci		assert(res == tmpbuf.size);
29516881f68fSopenharmony_ci
29526881f68fSopenharmony_ci	} else {
29536881f68fSopenharmony_ci		/* Don't overwrite buf->mem, as that would cause a leak */
29546881f68fSopenharmony_ci		buf->fd = tmpbuf.fd;
29556881f68fSopenharmony_ci		buf->flags = tmpbuf.flags;
29566881f68fSopenharmony_ci	}
29576881f68fSopenharmony_ci	buf->size = tmpbuf.size;
29586881f68fSopenharmony_ci
29596881f68fSopenharmony_ci	return res;
29606881f68fSopenharmony_ci
29616881f68fSopenharmony_cifallback:
29626881f68fSopenharmony_ci#endif
29636881f68fSopenharmony_ci	if (!buf->mem) {
29646881f68fSopenharmony_ci		buf->mem = malloc(se->bufsize);
29656881f68fSopenharmony_ci		if (!buf->mem) {
29666881f68fSopenharmony_ci			fuse_log(FUSE_LOG_ERR,
29676881f68fSopenharmony_ci				"fuse: failed to allocate read buffer\n");
29686881f68fSopenharmony_ci			return -ENOMEM;
29696881f68fSopenharmony_ci		}
29706881f68fSopenharmony_ci	}
29716881f68fSopenharmony_ci
29726881f68fSopenharmony_cirestart:
29736881f68fSopenharmony_ci	if (se->io != NULL) {
29746881f68fSopenharmony_ci		/* se->io->read is never NULL if se->io is not NULL as
29756881f68fSopenharmony_ci		specified by fuse_session_custom_io()*/
29766881f68fSopenharmony_ci		res = se->io->read(ch ? ch->fd : se->fd, buf->mem, se->bufsize,
29776881f68fSopenharmony_ci					 se->userdata);
29786881f68fSopenharmony_ci	} else {
29796881f68fSopenharmony_ci		res = read(ch ? ch->fd : se->fd, buf->mem, se->bufsize);
29806881f68fSopenharmony_ci	}
29816881f68fSopenharmony_ci	err = errno;
29826881f68fSopenharmony_ci
29836881f68fSopenharmony_ci	if (fuse_session_exited(se))
29846881f68fSopenharmony_ci		return 0;
29856881f68fSopenharmony_ci	if (res == -1) {
29866881f68fSopenharmony_ci		/* ENOENT means the operation was interrupted, it's safe
29876881f68fSopenharmony_ci		   to restart */
29886881f68fSopenharmony_ci		if (err == ENOENT)
29896881f68fSopenharmony_ci			goto restart;
29906881f68fSopenharmony_ci
29916881f68fSopenharmony_ci		if (err == ENODEV) {
29926881f68fSopenharmony_ci			/* Filesystem was unmounted, or connection was aborted
29936881f68fSopenharmony_ci			   via /sys/fs/fuse/connections */
29946881f68fSopenharmony_ci			fuse_session_exit(se);
29956881f68fSopenharmony_ci			return 0;
29966881f68fSopenharmony_ci		}
29976881f68fSopenharmony_ci		/* Errors occurring during normal operation: EINTR (read
29986881f68fSopenharmony_ci		   interrupted), EAGAIN (nonblocking I/O), ENODEV (filesystem
29996881f68fSopenharmony_ci		   umounted) */
30006881f68fSopenharmony_ci		if (err != EINTR && err != EAGAIN)
30016881f68fSopenharmony_ci			perror("fuse: reading device");
30026881f68fSopenharmony_ci		return -err;
30036881f68fSopenharmony_ci	}
30046881f68fSopenharmony_ci	if ((size_t) res < sizeof(struct fuse_in_header)) {
30056881f68fSopenharmony_ci		fuse_log(FUSE_LOG_ERR, "short read on fuse device\n");
30066881f68fSopenharmony_ci		return -EIO;
30076881f68fSopenharmony_ci	}
30086881f68fSopenharmony_ci
30096881f68fSopenharmony_ci	buf->size = res;
30106881f68fSopenharmony_ci
30116881f68fSopenharmony_ci	return res;
30126881f68fSopenharmony_ci}
30136881f68fSopenharmony_ci
30146881f68fSopenharmony_cistruct fuse_session *fuse_session_new(struct fuse_args *args,
30156881f68fSopenharmony_ci				      const struct fuse_lowlevel_ops *op,
30166881f68fSopenharmony_ci				      size_t op_size, void *userdata)
30176881f68fSopenharmony_ci{
30186881f68fSopenharmony_ci	int err;
30196881f68fSopenharmony_ci	struct fuse_session *se;
30206881f68fSopenharmony_ci	struct mount_opts *mo;
30216881f68fSopenharmony_ci
30226881f68fSopenharmony_ci	if (sizeof(struct fuse_lowlevel_ops) < op_size) {
30236881f68fSopenharmony_ci		fuse_log(FUSE_LOG_ERR, "fuse: warning: library too old, some operations may not work\n");
30246881f68fSopenharmony_ci		op_size = sizeof(struct fuse_lowlevel_ops);
30256881f68fSopenharmony_ci	}
30266881f68fSopenharmony_ci
30276881f68fSopenharmony_ci	if (args->argc == 0) {
30286881f68fSopenharmony_ci		fuse_log(FUSE_LOG_ERR, "fuse: empty argv passed to fuse_session_new().\n");
30296881f68fSopenharmony_ci		return NULL;
30306881f68fSopenharmony_ci	}
30316881f68fSopenharmony_ci
30326881f68fSopenharmony_ci	se = (struct fuse_session *) calloc(1, sizeof(struct fuse_session));
30336881f68fSopenharmony_ci	if (se == NULL) {
30346881f68fSopenharmony_ci		fuse_log(FUSE_LOG_ERR, "fuse: failed to allocate fuse object\n");
30356881f68fSopenharmony_ci		goto out1;
30366881f68fSopenharmony_ci	}
30376881f68fSopenharmony_ci	se->fd = -1;
30386881f68fSopenharmony_ci	se->conn.max_write = UINT_MAX;
30396881f68fSopenharmony_ci	se->conn.max_readahead = UINT_MAX;
30406881f68fSopenharmony_ci
30416881f68fSopenharmony_ci	/* Parse options */
30426881f68fSopenharmony_ci	if(fuse_opt_parse(args, se, fuse_ll_opts, NULL) == -1)
30436881f68fSopenharmony_ci		goto out2;
30446881f68fSopenharmony_ci	if(se->deny_others) {
30456881f68fSopenharmony_ci		/* Allowing access only by root is done by instructing
30466881f68fSopenharmony_ci		 * kernel to allow access by everyone, and then restricting
30476881f68fSopenharmony_ci		 * access to root and mountpoint owner in libfuse.
30486881f68fSopenharmony_ci		 */
30496881f68fSopenharmony_ci		// We may be adding the option a second time, but
30506881f68fSopenharmony_ci		// that doesn't hurt.
30516881f68fSopenharmony_ci		if(fuse_opt_add_arg(args, "-oallow_other") == -1)
30526881f68fSopenharmony_ci			goto out2;
30536881f68fSopenharmony_ci	}
30546881f68fSopenharmony_ci	mo = parse_mount_opts(args);
30556881f68fSopenharmony_ci	if (mo == NULL)
30566881f68fSopenharmony_ci		goto out3;
30576881f68fSopenharmony_ci
30586881f68fSopenharmony_ci	if(args->argc == 1 &&
30596881f68fSopenharmony_ci	   args->argv[0][0] == '-') {
30606881f68fSopenharmony_ci		fuse_log(FUSE_LOG_ERR, "fuse: warning: argv[0] looks like an option, but "
30616881f68fSopenharmony_ci			"will be ignored\n");
30626881f68fSopenharmony_ci	} else if (args->argc != 1) {
30636881f68fSopenharmony_ci		int i;
30646881f68fSopenharmony_ci		fuse_log(FUSE_LOG_ERR, "fuse: unknown option(s): `");
30656881f68fSopenharmony_ci		for(i = 1; i < args->argc-1; i++)
30666881f68fSopenharmony_ci			fuse_log(FUSE_LOG_ERR, "%s ", args->argv[i]);
30676881f68fSopenharmony_ci		fuse_log(FUSE_LOG_ERR, "%s'\n", args->argv[i]);
30686881f68fSopenharmony_ci		goto out4;
30696881f68fSopenharmony_ci	}
30706881f68fSopenharmony_ci
30716881f68fSopenharmony_ci	if (se->debug)
30726881f68fSopenharmony_ci		fuse_log(FUSE_LOG_DEBUG, "FUSE library version: %s\n", PACKAGE_VERSION);
30736881f68fSopenharmony_ci
30746881f68fSopenharmony_ci	se->bufsize = FUSE_MAX_MAX_PAGES * getpagesize() +
30756881f68fSopenharmony_ci		FUSE_BUFFER_HEADER_SIZE;
30766881f68fSopenharmony_ci
30776881f68fSopenharmony_ci	list_init_req(&se->list);
30786881f68fSopenharmony_ci	list_init_req(&se->interrupts);
30796881f68fSopenharmony_ci	list_init_nreq(&se->notify_list);
30806881f68fSopenharmony_ci	se->notify_ctr = 1;
30816881f68fSopenharmony_ci	pthread_mutex_init(&se->lock, NULL);
30826881f68fSopenharmony_ci
30836881f68fSopenharmony_ci	err = pthread_key_create(&se->pipe_key, fuse_ll_pipe_destructor);
30846881f68fSopenharmony_ci	if (err) {
30856881f68fSopenharmony_ci		fuse_log(FUSE_LOG_ERR, "fuse: failed to create thread specific key: %s\n",
30866881f68fSopenharmony_ci			strerror(err));
30876881f68fSopenharmony_ci		goto out5;
30886881f68fSopenharmony_ci	}
30896881f68fSopenharmony_ci
30906881f68fSopenharmony_ci	memcpy(&se->op, op, op_size);
30916881f68fSopenharmony_ci	se->owner = getuid();
30926881f68fSopenharmony_ci	se->userdata = userdata;
30936881f68fSopenharmony_ci
30946881f68fSopenharmony_ci	se->mo = mo;
30956881f68fSopenharmony_ci	return se;
30966881f68fSopenharmony_ci
30976881f68fSopenharmony_ciout5:
30986881f68fSopenharmony_ci	pthread_mutex_destroy(&se->lock);
30996881f68fSopenharmony_ciout4:
31006881f68fSopenharmony_ci	fuse_opt_free_args(args);
31016881f68fSopenharmony_ciout3:
31026881f68fSopenharmony_ci	if (mo != NULL)
31036881f68fSopenharmony_ci		destroy_mount_opts(mo);
31046881f68fSopenharmony_ciout2:
31056881f68fSopenharmony_ci	free(se);
31066881f68fSopenharmony_ciout1:
31076881f68fSopenharmony_ci	return NULL;
31086881f68fSopenharmony_ci}
31096881f68fSopenharmony_ci
31106881f68fSopenharmony_ciint fuse_session_custom_io(struct fuse_session *se, const struct fuse_custom_io *io,
31116881f68fSopenharmony_ci			   int fd)
31126881f68fSopenharmony_ci{
31136881f68fSopenharmony_ci	if (fd < 0) {
31146881f68fSopenharmony_ci		fuse_log(FUSE_LOG_ERR, "Invalid file descriptor value %d passed to "
31156881f68fSopenharmony_ci			"fuse_session_custom_io()\n", fd);
31166881f68fSopenharmony_ci		return -EBADF;
31176881f68fSopenharmony_ci	}
31186881f68fSopenharmony_ci	if (io == NULL) {
31196881f68fSopenharmony_ci		fuse_log(FUSE_LOG_ERR, "No custom IO passed to "
31206881f68fSopenharmony_ci			"fuse_session_custom_io()\n");
31216881f68fSopenharmony_ci		return -EINVAL;
31226881f68fSopenharmony_ci	} else if (io->read == NULL || io->writev == NULL) {
31236881f68fSopenharmony_ci		/* If the user provides their own file descriptor, we can't
31246881f68fSopenharmony_ci		guarantee that the default behavior of the io operations made
31256881f68fSopenharmony_ci		in libfuse will function properly. Therefore, we enforce the
31266881f68fSopenharmony_ci		user to implement these io operations when using custom io. */
31276881f68fSopenharmony_ci		fuse_log(FUSE_LOG_ERR, "io passed to fuse_session_custom_io() must "
31286881f68fSopenharmony_ci			"implement both io->read() and io->writev\n");
31296881f68fSopenharmony_ci		return -EINVAL;
31306881f68fSopenharmony_ci	}
31316881f68fSopenharmony_ci
31326881f68fSopenharmony_ci	se->io = malloc(sizeof(struct fuse_custom_io));
31336881f68fSopenharmony_ci	if (se->io == NULL) {
31346881f68fSopenharmony_ci		fuse_log(FUSE_LOG_ERR, "Failed to allocate memory for custom io. "
31356881f68fSopenharmony_ci			"Error: %s\n", strerror(errno));
31366881f68fSopenharmony_ci		return -errno;
31376881f68fSopenharmony_ci	}
31386881f68fSopenharmony_ci
31396881f68fSopenharmony_ci	se->fd = fd;
31406881f68fSopenharmony_ci	*se->io = *io;
31416881f68fSopenharmony_ci	return 0;
31426881f68fSopenharmony_ci}
31436881f68fSopenharmony_ci
31446881f68fSopenharmony_ciint fuse_session_mount(struct fuse_session *se, const char *mountpoint)
31456881f68fSopenharmony_ci{
31466881f68fSopenharmony_ci	int fd;
31476881f68fSopenharmony_ci
31486881f68fSopenharmony_ci	/*
31496881f68fSopenharmony_ci	 * Make sure file descriptors 0, 1 and 2 are open, otherwise chaos
31506881f68fSopenharmony_ci	 * would ensue.
31516881f68fSopenharmony_ci	 */
31526881f68fSopenharmony_ci	do {
31536881f68fSopenharmony_ci		fd = open("/dev/null", O_RDWR);
31546881f68fSopenharmony_ci		if (fd > 2)
31556881f68fSopenharmony_ci			close(fd);
31566881f68fSopenharmony_ci	} while (fd >= 0 && fd <= 2);
31576881f68fSopenharmony_ci
31586881f68fSopenharmony_ci	/*
31596881f68fSopenharmony_ci	 * To allow FUSE daemons to run without privileges, the caller may open
31606881f68fSopenharmony_ci	 * /dev/fuse before launching the file system and pass on the file
31616881f68fSopenharmony_ci	 * descriptor by specifying /dev/fd/N as the mount point. Note that the
31626881f68fSopenharmony_ci	 * parent process takes care of performing the mount in this case.
31636881f68fSopenharmony_ci	 */
31646881f68fSopenharmony_ci	fd = fuse_mnt_parse_fuse_fd(mountpoint);
31656881f68fSopenharmony_ci	if (fd != -1) {
31666881f68fSopenharmony_ci		if (fcntl(fd, F_GETFD) == -1) {
31676881f68fSopenharmony_ci			fuse_log(FUSE_LOG_ERR,
31686881f68fSopenharmony_ci				"fuse: Invalid file descriptor /dev/fd/%u\n",
31696881f68fSopenharmony_ci				fd);
31706881f68fSopenharmony_ci			return -1;
31716881f68fSopenharmony_ci		}
31726881f68fSopenharmony_ci		se->fd = fd;
31736881f68fSopenharmony_ci		return 0;
31746881f68fSopenharmony_ci	}
31756881f68fSopenharmony_ci
31766881f68fSopenharmony_ci	/* Open channel */
31776881f68fSopenharmony_ci	fd = fuse_kern_mount(mountpoint, se->mo);
31786881f68fSopenharmony_ci	if (fd == -1)
31796881f68fSopenharmony_ci		return -1;
31806881f68fSopenharmony_ci	se->fd = fd;
31816881f68fSopenharmony_ci
31826881f68fSopenharmony_ci	/* Save mountpoint */
31836881f68fSopenharmony_ci	se->mountpoint = strdup(mountpoint);
31846881f68fSopenharmony_ci	if (se->mountpoint == NULL)
31856881f68fSopenharmony_ci		goto error_out;
31866881f68fSopenharmony_ci
31876881f68fSopenharmony_ci	return 0;
31886881f68fSopenharmony_ci
31896881f68fSopenharmony_cierror_out:
31906881f68fSopenharmony_ci	fuse_kern_unmount(mountpoint, fd);
31916881f68fSopenharmony_ci	return -1;
31926881f68fSopenharmony_ci}
31936881f68fSopenharmony_ci
31946881f68fSopenharmony_ciint fuse_session_fd(struct fuse_session *se)
31956881f68fSopenharmony_ci{
31966881f68fSopenharmony_ci	return se->fd;
31976881f68fSopenharmony_ci}
31986881f68fSopenharmony_ci
31996881f68fSopenharmony_civoid fuse_session_unmount(struct fuse_session *se)
32006881f68fSopenharmony_ci{
32016881f68fSopenharmony_ci	if (se->mountpoint != NULL) {
32026881f68fSopenharmony_ci		fuse_kern_unmount(se->mountpoint, se->fd);
32036881f68fSopenharmony_ci		se->fd = -1;
32046881f68fSopenharmony_ci		free(se->mountpoint);
32056881f68fSopenharmony_ci		se->mountpoint = NULL;
32066881f68fSopenharmony_ci	}
32076881f68fSopenharmony_ci}
32086881f68fSopenharmony_ci
32096881f68fSopenharmony_ci#ifdef linux
32106881f68fSopenharmony_ciint fuse_req_getgroups(fuse_req_t req, int size, gid_t list[])
32116881f68fSopenharmony_ci{
32126881f68fSopenharmony_ci	char *buf;
32136881f68fSopenharmony_ci	size_t bufsize = 1024;
32146881f68fSopenharmony_ci	char path[128];
32156881f68fSopenharmony_ci	int ret;
32166881f68fSopenharmony_ci	int fd;
32176881f68fSopenharmony_ci	unsigned long pid = req->ctx.pid;
32186881f68fSopenharmony_ci	char *s;
32196881f68fSopenharmony_ci
32206881f68fSopenharmony_ci	sprintf(path, "/proc/%lu/task/%lu/status", pid, pid);
32216881f68fSopenharmony_ci
32226881f68fSopenharmony_ciretry:
32236881f68fSopenharmony_ci	buf = malloc(bufsize);
32246881f68fSopenharmony_ci	if (buf == NULL)
32256881f68fSopenharmony_ci		return -ENOMEM;
32266881f68fSopenharmony_ci
32276881f68fSopenharmony_ci	ret = -EIO;
32286881f68fSopenharmony_ci	fd = open(path, O_RDONLY);
32296881f68fSopenharmony_ci	if (fd == -1)
32306881f68fSopenharmony_ci		goto out_free;
32316881f68fSopenharmony_ci
32326881f68fSopenharmony_ci	ret = read(fd, buf, bufsize);
32336881f68fSopenharmony_ci	close(fd);
32346881f68fSopenharmony_ci	if (ret < 0) {
32356881f68fSopenharmony_ci		ret = -EIO;
32366881f68fSopenharmony_ci		goto out_free;
32376881f68fSopenharmony_ci	}
32386881f68fSopenharmony_ci
32396881f68fSopenharmony_ci	if ((size_t)ret == bufsize) {
32406881f68fSopenharmony_ci		free(buf);
32416881f68fSopenharmony_ci		bufsize *= 4;
32426881f68fSopenharmony_ci		goto retry;
32436881f68fSopenharmony_ci	}
32446881f68fSopenharmony_ci
32456881f68fSopenharmony_ci	ret = -EIO;
32466881f68fSopenharmony_ci	s = strstr(buf, "\nGroups:");
32476881f68fSopenharmony_ci	if (s == NULL)
32486881f68fSopenharmony_ci		goto out_free;
32496881f68fSopenharmony_ci
32506881f68fSopenharmony_ci	s += 8;
32516881f68fSopenharmony_ci	ret = 0;
32526881f68fSopenharmony_ci	while (1) {
32536881f68fSopenharmony_ci		char *end;
32546881f68fSopenharmony_ci		unsigned long val = strtoul(s, &end, 0);
32556881f68fSopenharmony_ci		if (end == s)
32566881f68fSopenharmony_ci			break;
32576881f68fSopenharmony_ci
32586881f68fSopenharmony_ci		s = end;
32596881f68fSopenharmony_ci		if (ret < size)
32606881f68fSopenharmony_ci			list[ret] = val;
32616881f68fSopenharmony_ci		ret++;
32626881f68fSopenharmony_ci	}
32636881f68fSopenharmony_ci
32646881f68fSopenharmony_ciout_free:
32656881f68fSopenharmony_ci	free(buf);
32666881f68fSopenharmony_ci	return ret;
32676881f68fSopenharmony_ci}
32686881f68fSopenharmony_ci#else /* linux */
32696881f68fSopenharmony_ci/*
32706881f68fSopenharmony_ci * This is currently not implemented on other than Linux...
32716881f68fSopenharmony_ci */
32726881f68fSopenharmony_ciint fuse_req_getgroups(fuse_req_t req, int size, gid_t list[])
32736881f68fSopenharmony_ci{
32746881f68fSopenharmony_ci	(void) req; (void) size; (void) list;
32756881f68fSopenharmony_ci	return -ENOSYS;
32766881f68fSopenharmony_ci}
32776881f68fSopenharmony_ci#endif
32786881f68fSopenharmony_ci
32796881f68fSopenharmony_ci/* Prevent spurious data race warning - we don't care
32806881f68fSopenharmony_ci * about races for this flag */
32816881f68fSopenharmony_ci__attribute__((no_sanitize_thread))
32826881f68fSopenharmony_civoid fuse_session_exit(struct fuse_session *se)
32836881f68fSopenharmony_ci{
32846881f68fSopenharmony_ci	se->exited = 1;
32856881f68fSopenharmony_ci}
32866881f68fSopenharmony_ci
32876881f68fSopenharmony_ci__attribute__((no_sanitize_thread))
32886881f68fSopenharmony_civoid fuse_session_reset(struct fuse_session *se)
32896881f68fSopenharmony_ci{
32906881f68fSopenharmony_ci	se->exited = 0;
32916881f68fSopenharmony_ci	se->error = 0;
32926881f68fSopenharmony_ci}
32936881f68fSopenharmony_ci
32946881f68fSopenharmony_ci__attribute__((no_sanitize_thread))
32956881f68fSopenharmony_ciint fuse_session_exited(struct fuse_session *se)
32966881f68fSopenharmony_ci{
32976881f68fSopenharmony_ci	return se->exited;
32986881f68fSopenharmony_ci}
3299