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 = ¶m[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