1*9e564957SAndroid Build Coastguard Worker /*
2*9e564957SAndroid Build Coastguard Worker FUSE: Filesystem in Userspace
3*9e564957SAndroid Build Coastguard Worker Copyright (C) 2001-2007 Miklos Szeredi <[email protected]>
4*9e564957SAndroid Build Coastguard Worker
5*9e564957SAndroid Build Coastguard Worker Implementation of (most of) the low-level FUSE API. The session loop
6*9e564957SAndroid Build Coastguard Worker functions are implemented in separate files.
7*9e564957SAndroid Build Coastguard Worker
8*9e564957SAndroid Build Coastguard Worker This program can be distributed under the terms of the GNU LGPLv2.
9*9e564957SAndroid Build Coastguard Worker See the file COPYING.LIB
10*9e564957SAndroid Build Coastguard Worker */
11*9e564957SAndroid Build Coastguard Worker
12*9e564957SAndroid Build Coastguard Worker #define _GNU_SOURCE
13*9e564957SAndroid Build Coastguard Worker
14*9e564957SAndroid Build Coastguard Worker #include "fuse_config.h"
15*9e564957SAndroid Build Coastguard Worker #include "fuse_i.h"
16*9e564957SAndroid Build Coastguard Worker #include "fuse_kernel.h"
17*9e564957SAndroid Build Coastguard Worker #include "fuse_opt.h"
18*9e564957SAndroid Build Coastguard Worker #include "fuse_misc.h"
19*9e564957SAndroid Build Coastguard Worker #include "mount_util.h"
20*9e564957SAndroid Build Coastguard Worker
21*9e564957SAndroid Build Coastguard Worker #include <stdio.h>
22*9e564957SAndroid Build Coastguard Worker #include <stdlib.h>
23*9e564957SAndroid Build Coastguard Worker #include <stddef.h>
24*9e564957SAndroid Build Coastguard Worker #include <string.h>
25*9e564957SAndroid Build Coastguard Worker #include <unistd.h>
26*9e564957SAndroid Build Coastguard Worker #include <limits.h>
27*9e564957SAndroid Build Coastguard Worker #include <errno.h>
28*9e564957SAndroid Build Coastguard Worker #include <assert.h>
29*9e564957SAndroid Build Coastguard Worker #include <sys/file.h>
30*9e564957SAndroid Build Coastguard Worker #include <sys/ioctl.h>
31*9e564957SAndroid Build Coastguard Worker
32*9e564957SAndroid Build Coastguard Worker #ifndef F_LINUX_SPECIFIC_BASE
33*9e564957SAndroid Build Coastguard Worker #define F_LINUX_SPECIFIC_BASE 1024
34*9e564957SAndroid Build Coastguard Worker #endif
35*9e564957SAndroid Build Coastguard Worker #ifndef F_SETPIPE_SZ
36*9e564957SAndroid Build Coastguard Worker #define F_SETPIPE_SZ (F_LINUX_SPECIFIC_BASE + 7)
37*9e564957SAndroid Build Coastguard Worker #endif
38*9e564957SAndroid Build Coastguard Worker
39*9e564957SAndroid Build Coastguard Worker
40*9e564957SAndroid Build Coastguard Worker #define PARAM(inarg) (((char *)(inarg)) + sizeof(*(inarg)))
41*9e564957SAndroid Build Coastguard Worker #define OFFSET_MAX 0x7fffffffffffffffLL
42*9e564957SAndroid Build Coastguard Worker
43*9e564957SAndroid Build Coastguard Worker #define container_of(ptr, type, member) ({ \
44*9e564957SAndroid Build Coastguard Worker const typeof( ((type *)0)->member ) *__mptr = (ptr); \
45*9e564957SAndroid Build Coastguard Worker (type *)( (char *)__mptr - offsetof(type,member) );})
46*9e564957SAndroid Build Coastguard Worker
47*9e564957SAndroid Build Coastguard Worker struct fuse_pollhandle {
48*9e564957SAndroid Build Coastguard Worker uint64_t kh;
49*9e564957SAndroid Build Coastguard Worker struct fuse_session *se;
50*9e564957SAndroid Build Coastguard Worker };
51*9e564957SAndroid Build Coastguard Worker
52*9e564957SAndroid Build Coastguard Worker static size_t pagesize;
53*9e564957SAndroid Build Coastguard Worker
fuse_ll_init_pagesize(void)54*9e564957SAndroid Build Coastguard Worker static __attribute__((constructor)) void fuse_ll_init_pagesize(void)
55*9e564957SAndroid Build Coastguard Worker {
56*9e564957SAndroid Build Coastguard Worker pagesize = getpagesize();
57*9e564957SAndroid Build Coastguard Worker }
58*9e564957SAndroid Build Coastguard Worker
convert_stat(const struct stat * stbuf,struct fuse_attr * attr)59*9e564957SAndroid Build Coastguard Worker static void convert_stat(const struct stat *stbuf, struct fuse_attr *attr)
60*9e564957SAndroid Build Coastguard Worker {
61*9e564957SAndroid Build Coastguard Worker attr->ino = stbuf->st_ino;
62*9e564957SAndroid Build Coastguard Worker attr->mode = stbuf->st_mode;
63*9e564957SAndroid Build Coastguard Worker attr->nlink = stbuf->st_nlink;
64*9e564957SAndroid Build Coastguard Worker attr->uid = stbuf->st_uid;
65*9e564957SAndroid Build Coastguard Worker attr->gid = stbuf->st_gid;
66*9e564957SAndroid Build Coastguard Worker attr->rdev = stbuf->st_rdev;
67*9e564957SAndroid Build Coastguard Worker attr->size = stbuf->st_size;
68*9e564957SAndroid Build Coastguard Worker attr->blksize = stbuf->st_blksize;
69*9e564957SAndroid Build Coastguard Worker attr->blocks = stbuf->st_blocks;
70*9e564957SAndroid Build Coastguard Worker attr->atime = stbuf->st_atime;
71*9e564957SAndroid Build Coastguard Worker attr->mtime = stbuf->st_mtime;
72*9e564957SAndroid Build Coastguard Worker attr->ctime = stbuf->st_ctime;
73*9e564957SAndroid Build Coastguard Worker attr->atimensec = ST_ATIM_NSEC(stbuf);
74*9e564957SAndroid Build Coastguard Worker attr->mtimensec = ST_MTIM_NSEC(stbuf);
75*9e564957SAndroid Build Coastguard Worker attr->ctimensec = ST_CTIM_NSEC(stbuf);
76*9e564957SAndroid Build Coastguard Worker }
77*9e564957SAndroid Build Coastguard Worker
convert_attr(const struct fuse_setattr_in * attr,struct stat * stbuf)78*9e564957SAndroid Build Coastguard Worker static void convert_attr(const struct fuse_setattr_in *attr, struct stat *stbuf)
79*9e564957SAndroid Build Coastguard Worker {
80*9e564957SAndroid Build Coastguard Worker stbuf->st_mode = attr->mode;
81*9e564957SAndroid Build Coastguard Worker stbuf->st_uid = attr->uid;
82*9e564957SAndroid Build Coastguard Worker stbuf->st_gid = attr->gid;
83*9e564957SAndroid Build Coastguard Worker stbuf->st_size = attr->size;
84*9e564957SAndroid Build Coastguard Worker stbuf->st_atime = attr->atime;
85*9e564957SAndroid Build Coastguard Worker stbuf->st_mtime = attr->mtime;
86*9e564957SAndroid Build Coastguard Worker stbuf->st_ctime = attr->ctime;
87*9e564957SAndroid Build Coastguard Worker ST_ATIM_NSEC_SET(stbuf, attr->atimensec);
88*9e564957SAndroid Build Coastguard Worker ST_MTIM_NSEC_SET(stbuf, attr->mtimensec);
89*9e564957SAndroid Build Coastguard Worker ST_CTIM_NSEC_SET(stbuf, attr->ctimensec);
90*9e564957SAndroid Build Coastguard Worker }
91*9e564957SAndroid Build Coastguard Worker
iov_length(const struct iovec * iov,size_t count)92*9e564957SAndroid Build Coastguard Worker static size_t iov_length(const struct iovec *iov, size_t count)
93*9e564957SAndroid Build Coastguard Worker {
94*9e564957SAndroid Build Coastguard Worker size_t seg;
95*9e564957SAndroid Build Coastguard Worker size_t ret = 0;
96*9e564957SAndroid Build Coastguard Worker
97*9e564957SAndroid Build Coastguard Worker for (seg = 0; seg < count; seg++)
98*9e564957SAndroid Build Coastguard Worker ret += iov[seg].iov_len;
99*9e564957SAndroid Build Coastguard Worker return ret;
100*9e564957SAndroid Build Coastguard Worker }
101*9e564957SAndroid Build Coastguard Worker
list_init_req(struct fuse_req * req)102*9e564957SAndroid Build Coastguard Worker static void list_init_req(struct fuse_req *req)
103*9e564957SAndroid Build Coastguard Worker {
104*9e564957SAndroid Build Coastguard Worker req->next = req;
105*9e564957SAndroid Build Coastguard Worker req->prev = req;
106*9e564957SAndroid Build Coastguard Worker }
107*9e564957SAndroid Build Coastguard Worker
list_del_req(struct fuse_req * req)108*9e564957SAndroid Build Coastguard Worker static void list_del_req(struct fuse_req *req)
109*9e564957SAndroid Build Coastguard Worker {
110*9e564957SAndroid Build Coastguard Worker struct fuse_req *prev = req->prev;
111*9e564957SAndroid Build Coastguard Worker struct fuse_req *next = req->next;
112*9e564957SAndroid Build Coastguard Worker prev->next = next;
113*9e564957SAndroid Build Coastguard Worker next->prev = prev;
114*9e564957SAndroid Build Coastguard Worker }
115*9e564957SAndroid Build Coastguard Worker
list_add_req(struct fuse_req * req,struct fuse_req * next)116*9e564957SAndroid Build Coastguard Worker static void list_add_req(struct fuse_req *req, struct fuse_req *next)
117*9e564957SAndroid Build Coastguard Worker {
118*9e564957SAndroid Build Coastguard Worker struct fuse_req *prev = next->prev;
119*9e564957SAndroid Build Coastguard Worker req->next = next;
120*9e564957SAndroid Build Coastguard Worker req->prev = prev;
121*9e564957SAndroid Build Coastguard Worker prev->next = req;
122*9e564957SAndroid Build Coastguard Worker next->prev = req;
123*9e564957SAndroid Build Coastguard Worker }
124*9e564957SAndroid Build Coastguard Worker
destroy_req(fuse_req_t req)125*9e564957SAndroid Build Coastguard Worker static void destroy_req(fuse_req_t req)
126*9e564957SAndroid Build Coastguard Worker {
127*9e564957SAndroid Build Coastguard Worker assert(req->ch == NULL);
128*9e564957SAndroid Build Coastguard Worker pthread_mutex_destroy(&req->lock);
129*9e564957SAndroid Build Coastguard Worker free(req);
130*9e564957SAndroid Build Coastguard Worker }
131*9e564957SAndroid Build Coastguard Worker
fuse_free_req(fuse_req_t req)132*9e564957SAndroid Build Coastguard Worker void fuse_free_req(fuse_req_t req)
133*9e564957SAndroid Build Coastguard Worker {
134*9e564957SAndroid Build Coastguard Worker int ctr;
135*9e564957SAndroid Build Coastguard Worker struct fuse_session *se = req->se;
136*9e564957SAndroid Build Coastguard Worker
137*9e564957SAndroid Build Coastguard Worker pthread_mutex_lock(&se->lock);
138*9e564957SAndroid Build Coastguard Worker req->u.ni.func = NULL;
139*9e564957SAndroid Build Coastguard Worker req->u.ni.data = NULL;
140*9e564957SAndroid Build Coastguard Worker list_del_req(req);
141*9e564957SAndroid Build Coastguard Worker ctr = --req->ctr;
142*9e564957SAndroid Build Coastguard Worker fuse_chan_put(req->ch);
143*9e564957SAndroid Build Coastguard Worker req->ch = NULL;
144*9e564957SAndroid Build Coastguard Worker pthread_mutex_unlock(&se->lock);
145*9e564957SAndroid Build Coastguard Worker if (!ctr)
146*9e564957SAndroid Build Coastguard Worker destroy_req(req);
147*9e564957SAndroid Build Coastguard Worker }
148*9e564957SAndroid Build Coastguard Worker
fuse_ll_alloc_req(struct fuse_session * se)149*9e564957SAndroid Build Coastguard Worker static struct fuse_req *fuse_ll_alloc_req(struct fuse_session *se)
150*9e564957SAndroid Build Coastguard Worker {
151*9e564957SAndroid Build Coastguard Worker struct fuse_req *req;
152*9e564957SAndroid Build Coastguard Worker
153*9e564957SAndroid Build Coastguard Worker req = (struct fuse_req *) calloc(1, sizeof(struct fuse_req));
154*9e564957SAndroid Build Coastguard Worker if (req == NULL) {
155*9e564957SAndroid Build Coastguard Worker fuse_log(FUSE_LOG_ERR, "fuse: failed to allocate request\n");
156*9e564957SAndroid Build Coastguard Worker } else {
157*9e564957SAndroid Build Coastguard Worker req->se = se;
158*9e564957SAndroid Build Coastguard Worker req->ctr = 1;
159*9e564957SAndroid Build Coastguard Worker list_init_req(req);
160*9e564957SAndroid Build Coastguard Worker pthread_mutex_init(&req->lock, NULL);
161*9e564957SAndroid Build Coastguard Worker }
162*9e564957SAndroid Build Coastguard Worker
163*9e564957SAndroid Build Coastguard Worker return req;
164*9e564957SAndroid Build Coastguard Worker }
165*9e564957SAndroid Build Coastguard Worker
166*9e564957SAndroid Build Coastguard Worker /* Send data. If *ch* is NULL, send via session master fd */
fuse_send_msg(struct fuse_session * se,struct fuse_chan * ch,struct iovec * iov,int count)167*9e564957SAndroid Build Coastguard Worker static int fuse_send_msg(struct fuse_session *se, struct fuse_chan *ch,
168*9e564957SAndroid Build Coastguard Worker struct iovec *iov, int count)
169*9e564957SAndroid Build Coastguard Worker {
170*9e564957SAndroid Build Coastguard Worker struct fuse_out_header *out = iov[0].iov_base;
171*9e564957SAndroid Build Coastguard Worker
172*9e564957SAndroid Build Coastguard Worker assert(se != NULL);
173*9e564957SAndroid Build Coastguard Worker out->len = iov_length(iov, count);
174*9e564957SAndroid Build Coastguard Worker if (se->debug) {
175*9e564957SAndroid Build Coastguard Worker if (out->unique == 0) {
176*9e564957SAndroid Build Coastguard Worker fuse_log(FUSE_LOG_DEBUG, "NOTIFY: code=%d length=%u\n",
177*9e564957SAndroid Build Coastguard Worker out->error, out->len);
178*9e564957SAndroid Build Coastguard Worker } else if (out->error) {
179*9e564957SAndroid Build Coastguard Worker fuse_log(FUSE_LOG_DEBUG,
180*9e564957SAndroid Build Coastguard Worker " unique: %llu, error: %i (%s), outsize: %i\n",
181*9e564957SAndroid Build Coastguard Worker (unsigned long long) out->unique, out->error,
182*9e564957SAndroid Build Coastguard Worker strerror(-out->error), out->len);
183*9e564957SAndroid Build Coastguard Worker } else {
184*9e564957SAndroid Build Coastguard Worker fuse_log(FUSE_LOG_DEBUG,
185*9e564957SAndroid Build Coastguard Worker " unique: %llu, success, outsize: %i\n",
186*9e564957SAndroid Build Coastguard Worker (unsigned long long) out->unique, out->len);
187*9e564957SAndroid Build Coastguard Worker }
188*9e564957SAndroid Build Coastguard Worker }
189*9e564957SAndroid Build Coastguard Worker
190*9e564957SAndroid Build Coastguard Worker ssize_t res;
191*9e564957SAndroid Build Coastguard Worker if (se->io != NULL)
192*9e564957SAndroid Build Coastguard Worker /* se->io->writev is never NULL if se->io is not NULL as
193*9e564957SAndroid Build Coastguard Worker specified by fuse_session_custom_io()*/
194*9e564957SAndroid Build Coastguard Worker res = se->io->writev(ch ? ch->fd : se->fd, iov, count,
195*9e564957SAndroid Build Coastguard Worker se->userdata);
196*9e564957SAndroid Build Coastguard Worker else
197*9e564957SAndroid Build Coastguard Worker res = writev(ch ? ch->fd : se->fd, iov, count);
198*9e564957SAndroid Build Coastguard Worker
199*9e564957SAndroid Build Coastguard Worker int err = errno;
200*9e564957SAndroid Build Coastguard Worker
201*9e564957SAndroid Build Coastguard Worker if (res == -1) {
202*9e564957SAndroid Build Coastguard Worker /* ENOENT means the operation was interrupted */
203*9e564957SAndroid Build Coastguard Worker if (!fuse_session_exited(se) && err != ENOENT)
204*9e564957SAndroid Build Coastguard Worker perror("fuse: writing device");
205*9e564957SAndroid Build Coastguard Worker return -err;
206*9e564957SAndroid Build Coastguard Worker }
207*9e564957SAndroid Build Coastguard Worker
208*9e564957SAndroid Build Coastguard Worker return 0;
209*9e564957SAndroid Build Coastguard Worker }
210*9e564957SAndroid Build Coastguard Worker
211*9e564957SAndroid Build Coastguard Worker
fuse_send_reply_iov_nofree(fuse_req_t req,int error,struct iovec * iov,int count)212*9e564957SAndroid Build Coastguard Worker int fuse_send_reply_iov_nofree(fuse_req_t req, int error, struct iovec *iov,
213*9e564957SAndroid Build Coastguard Worker int count)
214*9e564957SAndroid Build Coastguard Worker {
215*9e564957SAndroid Build Coastguard Worker struct fuse_out_header out;
216*9e564957SAndroid Build Coastguard Worker
217*9e564957SAndroid Build Coastguard Worker #if __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 32
218*9e564957SAndroid Build Coastguard Worker const char *str = strerrordesc_np(error * -1);
219*9e564957SAndroid Build Coastguard Worker if ((str == NULL && error != 0) || error > 0) {
220*9e564957SAndroid Build Coastguard Worker #else
221*9e564957SAndroid Build Coastguard Worker if (error <= -1000 || error > 0) {
222*9e564957SAndroid Build Coastguard Worker #endif
223*9e564957SAndroid Build Coastguard Worker fuse_log(FUSE_LOG_ERR, "fuse: bad error value: %i\n", error);
224*9e564957SAndroid Build Coastguard Worker error = -ERANGE;
225*9e564957SAndroid Build Coastguard Worker }
226*9e564957SAndroid Build Coastguard Worker
227*9e564957SAndroid Build Coastguard Worker out.unique = req->unique;
228*9e564957SAndroid Build Coastguard Worker out.error = error;
229*9e564957SAndroid Build Coastguard Worker
230*9e564957SAndroid Build Coastguard Worker iov[0].iov_base = &out;
231*9e564957SAndroid Build Coastguard Worker iov[0].iov_len = sizeof(struct fuse_out_header);
232*9e564957SAndroid Build Coastguard Worker
233*9e564957SAndroid Build Coastguard Worker return fuse_send_msg(req->se, req->ch, iov, count);
234*9e564957SAndroid Build Coastguard Worker }
235*9e564957SAndroid Build Coastguard Worker
236*9e564957SAndroid Build Coastguard Worker static int send_reply_iov(fuse_req_t req, int error, struct iovec *iov,
237*9e564957SAndroid Build Coastguard Worker int count)
238*9e564957SAndroid Build Coastguard Worker {
239*9e564957SAndroid Build Coastguard Worker int res;
240*9e564957SAndroid Build Coastguard Worker
241*9e564957SAndroid Build Coastguard Worker res = fuse_send_reply_iov_nofree(req, error, iov, count);
242*9e564957SAndroid Build Coastguard Worker fuse_free_req(req);
243*9e564957SAndroid Build Coastguard Worker return res;
244*9e564957SAndroid Build Coastguard Worker }
245*9e564957SAndroid Build Coastguard Worker
246*9e564957SAndroid Build Coastguard Worker static int send_reply(fuse_req_t req, int error, const void *arg,
247*9e564957SAndroid Build Coastguard Worker size_t argsize)
248*9e564957SAndroid Build Coastguard Worker {
249*9e564957SAndroid Build Coastguard Worker struct iovec iov[2];
250*9e564957SAndroid Build Coastguard Worker int count = 1;
251*9e564957SAndroid Build Coastguard Worker if (argsize) {
252*9e564957SAndroid Build Coastguard Worker iov[1].iov_base = (void *) arg;
253*9e564957SAndroid Build Coastguard Worker iov[1].iov_len = argsize;
254*9e564957SAndroid Build Coastguard Worker count++;
255*9e564957SAndroid Build Coastguard Worker }
256*9e564957SAndroid Build Coastguard Worker return send_reply_iov(req, error, iov, count);
257*9e564957SAndroid Build Coastguard Worker }
258*9e564957SAndroid Build Coastguard Worker
259*9e564957SAndroid Build Coastguard Worker int fuse_reply_iov(fuse_req_t req, const struct iovec *iov, int count)
260*9e564957SAndroid Build Coastguard Worker {
261*9e564957SAndroid Build Coastguard Worker int res;
262*9e564957SAndroid Build Coastguard Worker struct iovec *padded_iov;
263*9e564957SAndroid Build Coastguard Worker
264*9e564957SAndroid Build Coastguard Worker padded_iov = malloc((count + 1) * sizeof(struct iovec));
265*9e564957SAndroid Build Coastguard Worker if (padded_iov == NULL)
266*9e564957SAndroid Build Coastguard Worker return fuse_reply_err(req, ENOMEM);
267*9e564957SAndroid Build Coastguard Worker
268*9e564957SAndroid Build Coastguard Worker memcpy(padded_iov + 1, iov, count * sizeof(struct iovec));
269*9e564957SAndroid Build Coastguard Worker count++;
270*9e564957SAndroid Build Coastguard Worker
271*9e564957SAndroid Build Coastguard Worker res = send_reply_iov(req, 0, padded_iov, count);
272*9e564957SAndroid Build Coastguard Worker free(padded_iov);
273*9e564957SAndroid Build Coastguard Worker
274*9e564957SAndroid Build Coastguard Worker return res;
275*9e564957SAndroid Build Coastguard Worker }
276*9e564957SAndroid Build Coastguard Worker
277*9e564957SAndroid Build Coastguard Worker
278*9e564957SAndroid Build Coastguard Worker /* `buf` is allowed to be empty so that the proper size may be
279*9e564957SAndroid Build Coastguard Worker allocated by the caller */
280*9e564957SAndroid Build Coastguard Worker size_t fuse_add_direntry(fuse_req_t req, char *buf, size_t bufsize,
281*9e564957SAndroid Build Coastguard Worker const char *name, const struct stat *stbuf, off_t off)
282*9e564957SAndroid Build Coastguard Worker {
283*9e564957SAndroid Build Coastguard Worker (void)req;
284*9e564957SAndroid Build Coastguard Worker size_t namelen;
285*9e564957SAndroid Build Coastguard Worker size_t entlen;
286*9e564957SAndroid Build Coastguard Worker size_t entlen_padded;
287*9e564957SAndroid Build Coastguard Worker struct fuse_dirent *dirent;
288*9e564957SAndroid Build Coastguard Worker
289*9e564957SAndroid Build Coastguard Worker namelen = strlen(name);
290*9e564957SAndroid Build Coastguard Worker entlen = FUSE_NAME_OFFSET + namelen;
291*9e564957SAndroid Build Coastguard Worker entlen_padded = FUSE_DIRENT_ALIGN(entlen);
292*9e564957SAndroid Build Coastguard Worker
293*9e564957SAndroid Build Coastguard Worker if ((buf == NULL) || (entlen_padded > bufsize))
294*9e564957SAndroid Build Coastguard Worker return entlen_padded;
295*9e564957SAndroid Build Coastguard Worker
296*9e564957SAndroid Build Coastguard Worker dirent = (struct fuse_dirent*) buf;
297*9e564957SAndroid Build Coastguard Worker dirent->ino = stbuf->st_ino;
298*9e564957SAndroid Build Coastguard Worker dirent->off = off;
299*9e564957SAndroid Build Coastguard Worker dirent->namelen = namelen;
300*9e564957SAndroid Build Coastguard Worker dirent->type = (stbuf->st_mode & S_IFMT) >> 12;
301*9e564957SAndroid Build Coastguard Worker memcpy(dirent->name, name, namelen);
302*9e564957SAndroid Build Coastguard Worker memset(dirent->name + namelen, 0, entlen_padded - entlen);
303*9e564957SAndroid Build Coastguard Worker
304*9e564957SAndroid Build Coastguard Worker return entlen_padded;
305*9e564957SAndroid Build Coastguard Worker }
306*9e564957SAndroid Build Coastguard Worker
307*9e564957SAndroid Build Coastguard Worker static void convert_statfs(const struct statvfs *stbuf,
308*9e564957SAndroid Build Coastguard Worker struct fuse_kstatfs *kstatfs)
309*9e564957SAndroid Build Coastguard Worker {
310*9e564957SAndroid Build Coastguard Worker kstatfs->bsize = stbuf->f_bsize;
311*9e564957SAndroid Build Coastguard Worker kstatfs->frsize = stbuf->f_frsize;
312*9e564957SAndroid Build Coastguard Worker kstatfs->blocks = stbuf->f_blocks;
313*9e564957SAndroid Build Coastguard Worker kstatfs->bfree = stbuf->f_bfree;
314*9e564957SAndroid Build Coastguard Worker kstatfs->bavail = stbuf->f_bavail;
315*9e564957SAndroid Build Coastguard Worker kstatfs->files = stbuf->f_files;
316*9e564957SAndroid Build Coastguard Worker kstatfs->ffree = stbuf->f_ffree;
317*9e564957SAndroid Build Coastguard Worker kstatfs->namelen = stbuf->f_namemax;
318*9e564957SAndroid Build Coastguard Worker }
319*9e564957SAndroid Build Coastguard Worker
320*9e564957SAndroid Build Coastguard Worker static int send_reply_ok(fuse_req_t req, const void *arg, size_t argsize)
321*9e564957SAndroid Build Coastguard Worker {
322*9e564957SAndroid Build Coastguard Worker return send_reply(req, 0, arg, argsize);
323*9e564957SAndroid Build Coastguard Worker }
324*9e564957SAndroid Build Coastguard Worker
325*9e564957SAndroid Build Coastguard Worker int fuse_reply_err(fuse_req_t req, int err)
326*9e564957SAndroid Build Coastguard Worker {
327*9e564957SAndroid Build Coastguard Worker return send_reply(req, -err, NULL, 0);
328*9e564957SAndroid Build Coastguard Worker }
329*9e564957SAndroid Build Coastguard Worker
330*9e564957SAndroid Build Coastguard Worker void fuse_reply_none(fuse_req_t req)
331*9e564957SAndroid Build Coastguard Worker {
332*9e564957SAndroid Build Coastguard Worker fuse_free_req(req);
333*9e564957SAndroid Build Coastguard Worker }
334*9e564957SAndroid Build Coastguard Worker
335*9e564957SAndroid Build Coastguard Worker static unsigned long calc_timeout_sec(double t)
336*9e564957SAndroid Build Coastguard Worker {
337*9e564957SAndroid Build Coastguard Worker if (t > (double) ULONG_MAX)
338*9e564957SAndroid Build Coastguard Worker return ULONG_MAX;
339*9e564957SAndroid Build Coastguard Worker else if (t < 0.0)
340*9e564957SAndroid Build Coastguard Worker return 0;
341*9e564957SAndroid Build Coastguard Worker else
342*9e564957SAndroid Build Coastguard Worker return (unsigned long) t;
343*9e564957SAndroid Build Coastguard Worker }
344*9e564957SAndroid Build Coastguard Worker
345*9e564957SAndroid Build Coastguard Worker static unsigned int calc_timeout_nsec(double t)
346*9e564957SAndroid Build Coastguard Worker {
347*9e564957SAndroid Build Coastguard Worker double f = t - (double) calc_timeout_sec(t);
348*9e564957SAndroid Build Coastguard Worker if (f < 0.0)
349*9e564957SAndroid Build Coastguard Worker return 0;
350*9e564957SAndroid Build Coastguard Worker else if (f >= 0.999999999)
351*9e564957SAndroid Build Coastguard Worker return 999999999;
352*9e564957SAndroid Build Coastguard Worker else
353*9e564957SAndroid Build Coastguard Worker return (unsigned int) (f * 1.0e9);
354*9e564957SAndroid Build Coastguard Worker }
355*9e564957SAndroid Build Coastguard Worker
356*9e564957SAndroid Build Coastguard Worker static void fill_entry(struct fuse_entry_out *arg,
357*9e564957SAndroid Build Coastguard Worker const struct fuse_entry_param *e)
358*9e564957SAndroid Build Coastguard Worker {
359*9e564957SAndroid Build Coastguard Worker arg->nodeid = e->ino;
360*9e564957SAndroid Build Coastguard Worker arg->generation = e->generation;
361*9e564957SAndroid Build Coastguard Worker arg->entry_valid = calc_timeout_sec(e->entry_timeout);
362*9e564957SAndroid Build Coastguard Worker arg->entry_valid_nsec = calc_timeout_nsec(e->entry_timeout);
363*9e564957SAndroid Build Coastguard Worker arg->attr_valid = calc_timeout_sec(e->attr_timeout);
364*9e564957SAndroid Build Coastguard Worker arg->attr_valid_nsec = calc_timeout_nsec(e->attr_timeout);
365*9e564957SAndroid Build Coastguard Worker convert_stat(&e->attr, &arg->attr);
366*9e564957SAndroid Build Coastguard Worker }
367*9e564957SAndroid Build Coastguard Worker
368*9e564957SAndroid Build Coastguard Worker /* `buf` is allowed to be empty so that the proper size may be
369*9e564957SAndroid Build Coastguard Worker allocated by the caller */
370*9e564957SAndroid Build Coastguard Worker size_t fuse_add_direntry_plus(fuse_req_t req, char *buf, size_t bufsize,
371*9e564957SAndroid Build Coastguard Worker const char *name,
372*9e564957SAndroid Build Coastguard Worker const struct fuse_entry_param *e, off_t off)
373*9e564957SAndroid Build Coastguard Worker {
374*9e564957SAndroid Build Coastguard Worker (void)req;
375*9e564957SAndroid Build Coastguard Worker size_t namelen;
376*9e564957SAndroid Build Coastguard Worker size_t entlen;
377*9e564957SAndroid Build Coastguard Worker size_t entlen_padded;
378*9e564957SAndroid Build Coastguard Worker
379*9e564957SAndroid Build Coastguard Worker namelen = strlen(name);
380*9e564957SAndroid Build Coastguard Worker entlen = FUSE_NAME_OFFSET_DIRENTPLUS + namelen;
381*9e564957SAndroid Build Coastguard Worker entlen_padded = FUSE_DIRENT_ALIGN(entlen);
382*9e564957SAndroid Build Coastguard Worker if ((buf == NULL) || (entlen_padded > bufsize))
383*9e564957SAndroid Build Coastguard Worker return entlen_padded;
384*9e564957SAndroid Build Coastguard Worker
385*9e564957SAndroid Build Coastguard Worker struct fuse_direntplus *dp = (struct fuse_direntplus *) buf;
386*9e564957SAndroid Build Coastguard Worker memset(&dp->entry_out, 0, sizeof(dp->entry_out));
387*9e564957SAndroid Build Coastguard Worker fill_entry(&dp->entry_out, e);
388*9e564957SAndroid Build Coastguard Worker
389*9e564957SAndroid Build Coastguard Worker struct fuse_dirent *dirent = &dp->dirent;
390*9e564957SAndroid Build Coastguard Worker dirent->ino = e->attr.st_ino;
391*9e564957SAndroid Build Coastguard Worker dirent->off = off;
392*9e564957SAndroid Build Coastguard Worker dirent->namelen = namelen;
393*9e564957SAndroid Build Coastguard Worker dirent->type = (e->attr.st_mode & S_IFMT) >> 12;
394*9e564957SAndroid Build Coastguard Worker memcpy(dirent->name, name, namelen);
395*9e564957SAndroid Build Coastguard Worker memset(dirent->name + namelen, 0, entlen_padded - entlen);
396*9e564957SAndroid Build Coastguard Worker
397*9e564957SAndroid Build Coastguard Worker return entlen_padded;
398*9e564957SAndroid Build Coastguard Worker }
399*9e564957SAndroid Build Coastguard Worker
400*9e564957SAndroid Build Coastguard Worker static void fill_open(struct fuse_open_out *arg,
401*9e564957SAndroid Build Coastguard Worker const struct fuse_file_info *f,
402*9e564957SAndroid Build Coastguard Worker int use_upstream_passthrough)
403*9e564957SAndroid Build Coastguard Worker {
404*9e564957SAndroid Build Coastguard Worker arg->fh = f->fh;
405*9e564957SAndroid Build Coastguard Worker if (use_upstream_passthrough) {
406*9e564957SAndroid Build Coastguard Worker if (f->backing_id > 0) {
407*9e564957SAndroid Build Coastguard Worker arg->backing_id = f->backing_id;
408*9e564957SAndroid Build Coastguard Worker arg->open_flags |= FOPEN_PASSTHROUGH;
409*9e564957SAndroid Build Coastguard Worker }
410*9e564957SAndroid Build Coastguard Worker } else {
411*9e564957SAndroid Build Coastguard Worker arg->passthrough_fh = f->passthrough_fh;
412*9e564957SAndroid Build Coastguard Worker }
413*9e564957SAndroid Build Coastguard Worker
414*9e564957SAndroid Build Coastguard Worker if (f->direct_io)
415*9e564957SAndroid Build Coastguard Worker arg->open_flags |= FOPEN_DIRECT_IO;
416*9e564957SAndroid Build Coastguard Worker if (f->keep_cache)
417*9e564957SAndroid Build Coastguard Worker arg->open_flags |= FOPEN_KEEP_CACHE;
418*9e564957SAndroid Build Coastguard Worker if (f->cache_readdir)
419*9e564957SAndroid Build Coastguard Worker arg->open_flags |= FOPEN_CACHE_DIR;
420*9e564957SAndroid Build Coastguard Worker if (f->nonseekable)
421*9e564957SAndroid Build Coastguard Worker arg->open_flags |= FOPEN_NONSEEKABLE;
422*9e564957SAndroid Build Coastguard Worker if (f->noflush)
423*9e564957SAndroid Build Coastguard Worker arg->open_flags |= FOPEN_NOFLUSH;
424*9e564957SAndroid Build Coastguard Worker if (f->parallel_direct_writes)
425*9e564957SAndroid Build Coastguard Worker arg->open_flags |= FOPEN_PARALLEL_DIRECT_WRITES;
426*9e564957SAndroid Build Coastguard Worker }
427*9e564957SAndroid Build Coastguard Worker
428*9e564957SAndroid Build Coastguard Worker int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param* e) {
429*9e564957SAndroid Build Coastguard Worker struct {
430*9e564957SAndroid Build Coastguard Worker struct fuse_entry_out arg;
431*9e564957SAndroid Build Coastguard Worker struct fuse_entry_bpf_out bpf_arg;
432*9e564957SAndroid Build Coastguard Worker } __attribute__((packed)) arg_ext = {0};
433*9e564957SAndroid Build Coastguard Worker
434*9e564957SAndroid Build Coastguard Worker struct fuse_entry_out arg;
435*9e564957SAndroid Build Coastguard Worker struct fuse_entry_bpf_out bpf_arg;
436*9e564957SAndroid Build Coastguard Worker size_t size;
437*9e564957SAndroid Build Coastguard Worker int extended_args = e->bpf_action || bpf_arg.bpf_fd || e->backing_action || e->backing_fd;
438*9e564957SAndroid Build Coastguard Worker
439*9e564957SAndroid Build Coastguard Worker if (extended_args) {
440*9e564957SAndroid Build Coastguard Worker size = req->se->conn.proto_minor < 9 ? FUSE_COMPAT_ENTRY_OUT_SIZE : sizeof(arg_ext);
441*9e564957SAndroid Build Coastguard Worker } else {
442*9e564957SAndroid Build Coastguard Worker size = req->se->conn.proto_minor < 9 ? FUSE_COMPAT_ENTRY_OUT_SIZE : sizeof(arg);
443*9e564957SAndroid Build Coastguard Worker }
444*9e564957SAndroid Build Coastguard Worker
445*9e564957SAndroid Build Coastguard Worker /* before ABI 7.4 e->ino == 0 was invalid, only ENOENT meant
446*9e564957SAndroid Build Coastguard Worker negative entry */
447*9e564957SAndroid Build Coastguard Worker if (!e->ino && req->se->conn.proto_minor < 4) return fuse_reply_err(req, ENOENT);
448*9e564957SAndroid Build Coastguard Worker
449*9e564957SAndroid Build Coastguard Worker memset(&arg, 0, sizeof(arg));
450*9e564957SAndroid Build Coastguard Worker fill_entry(&arg, e);
451*9e564957SAndroid Build Coastguard Worker
452*9e564957SAndroid Build Coastguard Worker if (extended_args) {
453*9e564957SAndroid Build Coastguard Worker memset(&bpf_arg, 0, sizeof(bpf_arg));
454*9e564957SAndroid Build Coastguard Worker
455*9e564957SAndroid Build Coastguard Worker bpf_arg.bpf_action = e->bpf_action;
456*9e564957SAndroid Build Coastguard Worker bpf_arg.bpf_fd = e->bpf_fd;
457*9e564957SAndroid Build Coastguard Worker bpf_arg.backing_action = e->backing_action;
458*9e564957SAndroid Build Coastguard Worker bpf_arg.backing_fd = e->backing_fd;
459*9e564957SAndroid Build Coastguard Worker
460*9e564957SAndroid Build Coastguard Worker arg_ext.arg = arg;
461*9e564957SAndroid Build Coastguard Worker arg_ext.bpf_arg = bpf_arg;
462*9e564957SAndroid Build Coastguard Worker
463*9e564957SAndroid Build Coastguard Worker return send_reply_ok(req, &arg_ext, size);
464*9e564957SAndroid Build Coastguard Worker } else {
465*9e564957SAndroid Build Coastguard Worker return send_reply_ok(req, &arg, size);
466*9e564957SAndroid Build Coastguard Worker }
467*9e564957SAndroid Build Coastguard Worker }
468*9e564957SAndroid Build Coastguard Worker
469*9e564957SAndroid Build Coastguard Worker int fuse_reply_create(fuse_req_t req, const struct fuse_entry_param *e,
470*9e564957SAndroid Build Coastguard Worker const struct fuse_file_info *f)
471*9e564957SAndroid Build Coastguard Worker {
472*9e564957SAndroid Build Coastguard Worker char buf[sizeof(struct fuse_entry_out) + sizeof(struct fuse_open_out)];
473*9e564957SAndroid Build Coastguard Worker size_t entrysize = req->se->conn.proto_minor < 9 ?
474*9e564957SAndroid Build Coastguard Worker FUSE_COMPAT_ENTRY_OUT_SIZE : sizeof(struct fuse_entry_out);
475*9e564957SAndroid Build Coastguard Worker struct fuse_entry_out *earg = (struct fuse_entry_out *) buf;
476*9e564957SAndroid Build Coastguard Worker struct fuse_open_out *oarg = (struct fuse_open_out *) (buf + entrysize);
477*9e564957SAndroid Build Coastguard Worker
478*9e564957SAndroid Build Coastguard Worker memset(buf, 0, sizeof(buf));
479*9e564957SAndroid Build Coastguard Worker fill_entry(earg, e);
480*9e564957SAndroid Build Coastguard Worker fill_open(oarg, f, req->se->conn.capable & FUSE_CAP_PASSTHROUGH_UPSTREAM);
481*9e564957SAndroid Build Coastguard Worker return send_reply_ok(req, buf,
482*9e564957SAndroid Build Coastguard Worker entrysize + sizeof(struct fuse_open_out));
483*9e564957SAndroid Build Coastguard Worker }
484*9e564957SAndroid Build Coastguard Worker
485*9e564957SAndroid Build Coastguard Worker int fuse_reply_attr(fuse_req_t req, const struct stat *attr,
486*9e564957SAndroid Build Coastguard Worker double attr_timeout)
487*9e564957SAndroid Build Coastguard Worker {
488*9e564957SAndroid Build Coastguard Worker struct fuse_attr_out arg;
489*9e564957SAndroid Build Coastguard Worker size_t size = req->se->conn.proto_minor < 9 ?
490*9e564957SAndroid Build Coastguard Worker FUSE_COMPAT_ATTR_OUT_SIZE : sizeof(arg);
491*9e564957SAndroid Build Coastguard Worker
492*9e564957SAndroid Build Coastguard Worker memset(&arg, 0, sizeof(arg));
493*9e564957SAndroid Build Coastguard Worker arg.attr_valid = calc_timeout_sec(attr_timeout);
494*9e564957SAndroid Build Coastguard Worker arg.attr_valid_nsec = calc_timeout_nsec(attr_timeout);
495*9e564957SAndroid Build Coastguard Worker convert_stat(attr, &arg.attr);
496*9e564957SAndroid Build Coastguard Worker
497*9e564957SAndroid Build Coastguard Worker return send_reply_ok(req, &arg, size);
498*9e564957SAndroid Build Coastguard Worker }
499*9e564957SAndroid Build Coastguard Worker
500*9e564957SAndroid Build Coastguard Worker int fuse_reply_readlink(fuse_req_t req, const char *linkname)
501*9e564957SAndroid Build Coastguard Worker {
502*9e564957SAndroid Build Coastguard Worker return send_reply_ok(req, linkname, strlen(linkname));
503*9e564957SAndroid Build Coastguard Worker }
504*9e564957SAndroid Build Coastguard Worker
505*9e564957SAndroid Build Coastguard Worker int fuse_reply_canonical_path(fuse_req_t req, const char *path)
506*9e564957SAndroid Build Coastguard Worker {
507*9e564957SAndroid Build Coastguard Worker // The kernel expects a buffer containing the null terminator for this op
508*9e564957SAndroid Build Coastguard Worker // So we add the null terminator size to strlen
509*9e564957SAndroid Build Coastguard Worker return send_reply_ok(req, path, strlen(path) + 1);
510*9e564957SAndroid Build Coastguard Worker }
511*9e564957SAndroid Build Coastguard Worker
512*9e564957SAndroid Build Coastguard Worker enum {
513*9e564957SAndroid Build Coastguard Worker FUSE_PASSTHROUGH_API_UNAVAILABLE,
514*9e564957SAndroid Build Coastguard Worker FUSE_PASSTHROUGH_API_V0,
515*9e564957SAndroid Build Coastguard Worker FUSE_PASSTHROUGH_API_V1,
516*9e564957SAndroid Build Coastguard Worker FUSE_PASSTHROUGH_API_V2,
517*9e564957SAndroid Build Coastguard Worker FUSE_PASSTHROUGH_API_STABLE,
518*9e564957SAndroid Build Coastguard Worker };
519*9e564957SAndroid Build Coastguard Worker
520*9e564957SAndroid Build Coastguard Worker /*
521*9e564957SAndroid Build Coastguard Worker * Requests the FUSE passthrough feature to be enabled on a specific file
522*9e564957SAndroid Build Coastguard Worker * through the passed fd.
523*9e564957SAndroid Build Coastguard Worker * This function returns an identifier that must be used as passthrough_fh
524*9e564957SAndroid Build Coastguard Worker * when the open/create_open request reply is sent back to /dev/fuse.
525*9e564957SAndroid Build Coastguard Worker * As for the current FUSE passthrough implementation, passthrough_fh values
526*9e564957SAndroid Build Coastguard Worker * are only valid if > 0, so in case the FUSE passthrough open ioctl returns
527*9e564957SAndroid Build Coastguard Worker * a value <= 0, this must be considered an error and is returned as-is by
528*9e564957SAndroid Build Coastguard Worker * this function.
529*9e564957SAndroid Build Coastguard Worker */
530*9e564957SAndroid Build Coastguard Worker int fuse_passthrough_enable(fuse_req_t req, unsigned int fd) {
531*9e564957SAndroid Build Coastguard Worker static sig_atomic_t passthrough_version = FUSE_PASSTHROUGH_API_STABLE;
532*9e564957SAndroid Build Coastguard Worker int ret = 0; /* values <= 0 represent errors in FUSE passthrough */
533*9e564957SAndroid Build Coastguard Worker
534*9e564957SAndroid Build Coastguard Worker if (!(req->se->conn.capable & FUSE_CAP_PASSTHROUGH))
535*9e564957SAndroid Build Coastguard Worker return -ENOTTY;
536*9e564957SAndroid Build Coastguard Worker /*
537*9e564957SAndroid Build Coastguard Worker * The interface of FUSE passthrough is still unstable in the kernel,
538*9e564957SAndroid Build Coastguard Worker * so the following solution is to search for the most updated API
539*9e564957SAndroid Build Coastguard Worker * version and, if not found, fall back to an older one.
540*9e564957SAndroid Build Coastguard Worker * This happens when ioctl() returns -1 and errno is set to ENOTTY,
541*9e564957SAndroid Build Coastguard Worker * an error code that corresponds to the lack of a specific ioctl.
542*9e564957SAndroid Build Coastguard Worker */
543*9e564957SAndroid Build Coastguard Worker switch (passthrough_version) {
544*9e564957SAndroid Build Coastguard Worker case FUSE_PASSTHROUGH_API_STABLE:
545*9e564957SAndroid Build Coastguard Worker /* There is not a stable API yet */
546*9e564957SAndroid Build Coastguard Worker passthrough_version = FUSE_PASSTHROUGH_API_V2;
547*9e564957SAndroid Build Coastguard Worker case FUSE_PASSTHROUGH_API_V2: {
548*9e564957SAndroid Build Coastguard Worker ret = ioctl(req->se->fd, FUSE_DEV_IOC_PASSTHROUGH_OPEN_V2, &fd);
549*9e564957SAndroid Build Coastguard Worker if (ret == -1 && errno == ENOTTY)
550*9e564957SAndroid Build Coastguard Worker passthrough_version = FUSE_PASSTHROUGH_API_V1;
551*9e564957SAndroid Build Coastguard Worker else
552*9e564957SAndroid Build Coastguard Worker break;
553*9e564957SAndroid Build Coastguard Worker }
554*9e564957SAndroid Build Coastguard Worker case FUSE_PASSTHROUGH_API_V1: {
555*9e564957SAndroid Build Coastguard Worker struct fuse_passthrough_out_v0 out = {};
556*9e564957SAndroid Build Coastguard Worker out.fd = fd;
557*9e564957SAndroid Build Coastguard Worker
558*9e564957SAndroid Build Coastguard Worker ret = ioctl(req->se->fd, FUSE_DEV_IOC_PASSTHROUGH_OPEN_V1, &out);
559*9e564957SAndroid Build Coastguard Worker if (ret == -1 && errno == ENOTTY)
560*9e564957SAndroid Build Coastguard Worker passthrough_version = FUSE_PASSTHROUGH_API_V0;
561*9e564957SAndroid Build Coastguard Worker else
562*9e564957SAndroid Build Coastguard Worker break;
563*9e564957SAndroid Build Coastguard Worker }
564*9e564957SAndroid Build Coastguard Worker case FUSE_PASSTHROUGH_API_V0: {
565*9e564957SAndroid Build Coastguard Worker struct fuse_passthrough_out_v0 out = {};
566*9e564957SAndroid Build Coastguard Worker out.fd = fd;
567*9e564957SAndroid Build Coastguard Worker
568*9e564957SAndroid Build Coastguard Worker ret = ioctl(req->se->fd, FUSE_DEV_IOC_PASSTHROUGH_OPEN_V0, &out);
569*9e564957SAndroid Build Coastguard Worker if (ret == -1 && errno == ENOTTY)
570*9e564957SAndroid Build Coastguard Worker passthrough_version = FUSE_PASSTHROUGH_API_UNAVAILABLE;
571*9e564957SAndroid Build Coastguard Worker else
572*9e564957SAndroid Build Coastguard Worker break;
573*9e564957SAndroid Build Coastguard Worker }
574*9e564957SAndroid Build Coastguard Worker default:
575*9e564957SAndroid Build Coastguard Worker fuse_log(FUSE_LOG_ERR, "fuse: passthrough_enable no valid API\n");
576*9e564957SAndroid Build Coastguard Worker return -ENOTTY;
577*9e564957SAndroid Build Coastguard Worker }
578*9e564957SAndroid Build Coastguard Worker
579*9e564957SAndroid Build Coastguard Worker if (ret <= 0)
580*9e564957SAndroid Build Coastguard Worker fuse_log(FUSE_LOG_ERR, "fuse: passthrough_enable: %s\n", strerror(errno));
581*9e564957SAndroid Build Coastguard Worker return ret;
582*9e564957SAndroid Build Coastguard Worker }
583*9e564957SAndroid Build Coastguard Worker
584*9e564957SAndroid Build Coastguard Worker int fuse_passthrough_open(fuse_req_t req, int fd)
585*9e564957SAndroid Build Coastguard Worker {
586*9e564957SAndroid Build Coastguard Worker struct fuse_backing_map map = { .fd = fd };
587*9e564957SAndroid Build Coastguard Worker int ret;
588*9e564957SAndroid Build Coastguard Worker
589*9e564957SAndroid Build Coastguard Worker ret = ioctl(req->se->fd, FUSE_DEV_IOC_BACKING_OPEN, &map);
590*9e564957SAndroid Build Coastguard Worker if (ret <= 0) {
591*9e564957SAndroid Build Coastguard Worker fuse_log(FUSE_LOG_ERR, "fuse: passthrough_open: %s\n", strerror(errno));
592*9e564957SAndroid Build Coastguard Worker return 0;
593*9e564957SAndroid Build Coastguard Worker }
594*9e564957SAndroid Build Coastguard Worker
595*9e564957SAndroid Build Coastguard Worker return ret;
596*9e564957SAndroid Build Coastguard Worker }
597*9e564957SAndroid Build Coastguard Worker
598*9e564957SAndroid Build Coastguard Worker int fuse_passthrough_close(fuse_req_t req, int backing_id)
599*9e564957SAndroid Build Coastguard Worker {
600*9e564957SAndroid Build Coastguard Worker int ret;
601*9e564957SAndroid Build Coastguard Worker
602*9e564957SAndroid Build Coastguard Worker ret = ioctl(req->se->fd, FUSE_DEV_IOC_BACKING_CLOSE, &backing_id);
603*9e564957SAndroid Build Coastguard Worker if (ret < 0)
604*9e564957SAndroid Build Coastguard Worker fuse_log(FUSE_LOG_ERR, "fuse: passthrough_close: %s\n", strerror(errno));
605*9e564957SAndroid Build Coastguard Worker
606*9e564957SAndroid Build Coastguard Worker return ret;
607*9e564957SAndroid Build Coastguard Worker }
608*9e564957SAndroid Build Coastguard Worker
609*9e564957SAndroid Build Coastguard Worker int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *f)
610*9e564957SAndroid Build Coastguard Worker {
611*9e564957SAndroid Build Coastguard Worker struct fuse_open_out arg;
612*9e564957SAndroid Build Coastguard Worker
613*9e564957SAndroid Build Coastguard Worker memset(&arg, 0, sizeof(arg));
614*9e564957SAndroid Build Coastguard Worker fill_open(&arg, f, req->se->conn.capable & FUSE_CAP_PASSTHROUGH_UPSTREAM);
615*9e564957SAndroid Build Coastguard Worker return send_reply_ok(req, &arg, sizeof(arg));
616*9e564957SAndroid Build Coastguard Worker }
617*9e564957SAndroid Build Coastguard Worker
618*9e564957SAndroid Build Coastguard Worker int fuse_reply_write(fuse_req_t req, size_t count)
619*9e564957SAndroid Build Coastguard Worker {
620*9e564957SAndroid Build Coastguard Worker struct fuse_write_out arg;
621*9e564957SAndroid Build Coastguard Worker
622*9e564957SAndroid Build Coastguard Worker memset(&arg, 0, sizeof(arg));
623*9e564957SAndroid Build Coastguard Worker arg.size = count;
624*9e564957SAndroid Build Coastguard Worker
625*9e564957SAndroid Build Coastguard Worker return send_reply_ok(req, &arg, sizeof(arg));
626*9e564957SAndroid Build Coastguard Worker }
627*9e564957SAndroid Build Coastguard Worker
628*9e564957SAndroid Build Coastguard Worker int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size)
629*9e564957SAndroid Build Coastguard Worker {
630*9e564957SAndroid Build Coastguard Worker return send_reply_ok(req, buf, size);
631*9e564957SAndroid Build Coastguard Worker }
632*9e564957SAndroid Build Coastguard Worker
633*9e564957SAndroid Build Coastguard Worker static int fuse_send_data_iov_fallback(struct fuse_session *se,
634*9e564957SAndroid Build Coastguard Worker struct fuse_chan *ch,
635*9e564957SAndroid Build Coastguard Worker struct iovec *iov, int iov_count,
636*9e564957SAndroid Build Coastguard Worker struct fuse_bufvec *buf,
637*9e564957SAndroid Build Coastguard Worker size_t len)
638*9e564957SAndroid Build Coastguard Worker {
639*9e564957SAndroid Build Coastguard Worker struct fuse_bufvec mem_buf = FUSE_BUFVEC_INIT(len);
640*9e564957SAndroid Build Coastguard Worker void *mbuf;
641*9e564957SAndroid Build Coastguard Worker int res;
642*9e564957SAndroid Build Coastguard Worker
643*9e564957SAndroid Build Coastguard Worker /* Optimize common case */
644*9e564957SAndroid Build Coastguard Worker if (buf->count == 1 && buf->idx == 0 && buf->off == 0 &&
645*9e564957SAndroid Build Coastguard Worker !(buf->buf[0].flags & FUSE_BUF_IS_FD)) {
646*9e564957SAndroid Build Coastguard Worker /* FIXME: also avoid memory copy if there are multiple buffers
647*9e564957SAndroid Build Coastguard Worker but none of them contain an fd */
648*9e564957SAndroid Build Coastguard Worker
649*9e564957SAndroid Build Coastguard Worker iov[iov_count].iov_base = buf->buf[0].mem;
650*9e564957SAndroid Build Coastguard Worker iov[iov_count].iov_len = len;
651*9e564957SAndroid Build Coastguard Worker iov_count++;
652*9e564957SAndroid Build Coastguard Worker return fuse_send_msg(se, ch, iov, iov_count);
653*9e564957SAndroid Build Coastguard Worker }
654*9e564957SAndroid Build Coastguard Worker
655*9e564957SAndroid Build Coastguard Worker res = posix_memalign(&mbuf, pagesize, len);
656*9e564957SAndroid Build Coastguard Worker if (res != 0)
657*9e564957SAndroid Build Coastguard Worker return res;
658*9e564957SAndroid Build Coastguard Worker
659*9e564957SAndroid Build Coastguard Worker mem_buf.buf[0].mem = mbuf;
660*9e564957SAndroid Build Coastguard Worker res = fuse_buf_copy(&mem_buf, buf, 0);
661*9e564957SAndroid Build Coastguard Worker if (res < 0) {
662*9e564957SAndroid Build Coastguard Worker free(mbuf);
663*9e564957SAndroid Build Coastguard Worker return -res;
664*9e564957SAndroid Build Coastguard Worker }
665*9e564957SAndroid Build Coastguard Worker len = res;
666*9e564957SAndroid Build Coastguard Worker
667*9e564957SAndroid Build Coastguard Worker iov[iov_count].iov_base = mbuf;
668*9e564957SAndroid Build Coastguard Worker iov[iov_count].iov_len = len;
669*9e564957SAndroid Build Coastguard Worker iov_count++;
670*9e564957SAndroid Build Coastguard Worker res = fuse_send_msg(se, ch, iov, iov_count);
671*9e564957SAndroid Build Coastguard Worker free(mbuf);
672*9e564957SAndroid Build Coastguard Worker
673*9e564957SAndroid Build Coastguard Worker return res;
674*9e564957SAndroid Build Coastguard Worker }
675*9e564957SAndroid Build Coastguard Worker
676*9e564957SAndroid Build Coastguard Worker struct fuse_ll_pipe {
677*9e564957SAndroid Build Coastguard Worker size_t size;
678*9e564957SAndroid Build Coastguard Worker int can_grow;
679*9e564957SAndroid Build Coastguard Worker int pipe[2];
680*9e564957SAndroid Build Coastguard Worker };
681*9e564957SAndroid Build Coastguard Worker
682*9e564957SAndroid Build Coastguard Worker static void fuse_ll_pipe_free(struct fuse_ll_pipe *llp)
683*9e564957SAndroid Build Coastguard Worker {
684*9e564957SAndroid Build Coastguard Worker close(llp->pipe[0]);
685*9e564957SAndroid Build Coastguard Worker close(llp->pipe[1]);
686*9e564957SAndroid Build Coastguard Worker free(llp);
687*9e564957SAndroid Build Coastguard Worker }
688*9e564957SAndroid Build Coastguard Worker
689*9e564957SAndroid Build Coastguard Worker #ifdef HAVE_SPLICE
690*9e564957SAndroid Build Coastguard Worker #if !defined(HAVE_PIPE2) || !defined(O_CLOEXEC)
691*9e564957SAndroid Build Coastguard Worker static int fuse_pipe(int fds[2])
692*9e564957SAndroid Build Coastguard Worker {
693*9e564957SAndroid Build Coastguard Worker int rv = pipe(fds);
694*9e564957SAndroid Build Coastguard Worker
695*9e564957SAndroid Build Coastguard Worker if (rv == -1)
696*9e564957SAndroid Build Coastguard Worker return rv;
697*9e564957SAndroid Build Coastguard Worker
698*9e564957SAndroid Build Coastguard Worker if (fcntl(fds[0], F_SETFL, O_NONBLOCK) == -1 ||
699*9e564957SAndroid Build Coastguard Worker fcntl(fds[1], F_SETFL, O_NONBLOCK) == -1 ||
700*9e564957SAndroid Build Coastguard Worker fcntl(fds[0], F_SETFD, FD_CLOEXEC) == -1 ||
701*9e564957SAndroid Build Coastguard Worker fcntl(fds[1], F_SETFD, FD_CLOEXEC) == -1) {
702*9e564957SAndroid Build Coastguard Worker close(fds[0]);
703*9e564957SAndroid Build Coastguard Worker close(fds[1]);
704*9e564957SAndroid Build Coastguard Worker rv = -1;
705*9e564957SAndroid Build Coastguard Worker }
706*9e564957SAndroid Build Coastguard Worker return rv;
707*9e564957SAndroid Build Coastguard Worker }
708*9e564957SAndroid Build Coastguard Worker #else
709*9e564957SAndroid Build Coastguard Worker static int fuse_pipe(int fds[2])
710*9e564957SAndroid Build Coastguard Worker {
711*9e564957SAndroid Build Coastguard Worker return pipe2(fds, O_CLOEXEC | O_NONBLOCK);
712*9e564957SAndroid Build Coastguard Worker }
713*9e564957SAndroid Build Coastguard Worker #endif
714*9e564957SAndroid Build Coastguard Worker
715*9e564957SAndroid Build Coastguard Worker static struct fuse_ll_pipe *fuse_ll_get_pipe(struct fuse_session *se)
716*9e564957SAndroid Build Coastguard Worker {
717*9e564957SAndroid Build Coastguard Worker struct fuse_ll_pipe *llp = pthread_getspecific(se->pipe_key);
718*9e564957SAndroid Build Coastguard Worker if (llp == NULL) {
719*9e564957SAndroid Build Coastguard Worker int res;
720*9e564957SAndroid Build Coastguard Worker
721*9e564957SAndroid Build Coastguard Worker llp = malloc(sizeof(struct fuse_ll_pipe));
722*9e564957SAndroid Build Coastguard Worker if (llp == NULL)
723*9e564957SAndroid Build Coastguard Worker return NULL;
724*9e564957SAndroid Build Coastguard Worker
725*9e564957SAndroid Build Coastguard Worker res = fuse_pipe(llp->pipe);
726*9e564957SAndroid Build Coastguard Worker if (res == -1) {
727*9e564957SAndroid Build Coastguard Worker free(llp);
728*9e564957SAndroid Build Coastguard Worker return NULL;
729*9e564957SAndroid Build Coastguard Worker }
730*9e564957SAndroid Build Coastguard Worker
731*9e564957SAndroid Build Coastguard Worker /*
732*9e564957SAndroid Build Coastguard Worker *the default size is 16 pages on linux
733*9e564957SAndroid Build Coastguard Worker */
734*9e564957SAndroid Build Coastguard Worker llp->size = pagesize * 16;
735*9e564957SAndroid Build Coastguard Worker llp->can_grow = 1;
736*9e564957SAndroid Build Coastguard Worker
737*9e564957SAndroid Build Coastguard Worker pthread_setspecific(se->pipe_key, llp);
738*9e564957SAndroid Build Coastguard Worker }
739*9e564957SAndroid Build Coastguard Worker
740*9e564957SAndroid Build Coastguard Worker return llp;
741*9e564957SAndroid Build Coastguard Worker }
742*9e564957SAndroid Build Coastguard Worker #endif
743*9e564957SAndroid Build Coastguard Worker
744*9e564957SAndroid Build Coastguard Worker static void fuse_ll_clear_pipe(struct fuse_session *se)
745*9e564957SAndroid Build Coastguard Worker {
746*9e564957SAndroid Build Coastguard Worker struct fuse_ll_pipe *llp = pthread_getspecific(se->pipe_key);
747*9e564957SAndroid Build Coastguard Worker if (llp) {
748*9e564957SAndroid Build Coastguard Worker pthread_setspecific(se->pipe_key, NULL);
749*9e564957SAndroid Build Coastguard Worker fuse_ll_pipe_free(llp);
750*9e564957SAndroid Build Coastguard Worker }
751*9e564957SAndroid Build Coastguard Worker }
752*9e564957SAndroid Build Coastguard Worker
753*9e564957SAndroid Build Coastguard Worker #if defined(HAVE_SPLICE) && defined(HAVE_VMSPLICE)
754*9e564957SAndroid Build Coastguard Worker static int read_back(int fd, char *buf, size_t len)
755*9e564957SAndroid Build Coastguard Worker {
756*9e564957SAndroid Build Coastguard Worker int res;
757*9e564957SAndroid Build Coastguard Worker
758*9e564957SAndroid Build Coastguard Worker res = read(fd, buf, len);
759*9e564957SAndroid Build Coastguard Worker if (res == -1) {
760*9e564957SAndroid Build Coastguard Worker fuse_log(FUSE_LOG_ERR, "fuse: internal error: failed to read back from pipe: %s\n", strerror(errno));
761*9e564957SAndroid Build Coastguard Worker return -EIO;
762*9e564957SAndroid Build Coastguard Worker }
763*9e564957SAndroid Build Coastguard Worker if (res != len) {
764*9e564957SAndroid Build Coastguard Worker fuse_log(FUSE_LOG_ERR, "fuse: internal error: short read back from pipe: %i from %zi\n", res, len);
765*9e564957SAndroid Build Coastguard Worker return -EIO;
766*9e564957SAndroid Build Coastguard Worker }
767*9e564957SAndroid Build Coastguard Worker return 0;
768*9e564957SAndroid Build Coastguard Worker }
769*9e564957SAndroid Build Coastguard Worker
770*9e564957SAndroid Build Coastguard Worker static int grow_pipe_to_max(int pipefd)
771*9e564957SAndroid Build Coastguard Worker {
772*9e564957SAndroid Build Coastguard Worker int max;
773*9e564957SAndroid Build Coastguard Worker int res;
774*9e564957SAndroid Build Coastguard Worker int maxfd;
775*9e564957SAndroid Build Coastguard Worker char buf[32];
776*9e564957SAndroid Build Coastguard Worker
777*9e564957SAndroid Build Coastguard Worker maxfd = open("/proc/sys/fs/pipe-max-size", O_RDONLY);
778*9e564957SAndroid Build Coastguard Worker if (maxfd < 0)
779*9e564957SAndroid Build Coastguard Worker return -errno;
780*9e564957SAndroid Build Coastguard Worker
781*9e564957SAndroid Build Coastguard Worker res = read(maxfd, buf, sizeof(buf) - 1);
782*9e564957SAndroid Build Coastguard Worker if (res < 0) {
783*9e564957SAndroid Build Coastguard Worker int saved_errno;
784*9e564957SAndroid Build Coastguard Worker
785*9e564957SAndroid Build Coastguard Worker saved_errno = errno;
786*9e564957SAndroid Build Coastguard Worker close(maxfd);
787*9e564957SAndroid Build Coastguard Worker return -saved_errno;
788*9e564957SAndroid Build Coastguard Worker }
789*9e564957SAndroid Build Coastguard Worker close(maxfd);
790*9e564957SAndroid Build Coastguard Worker buf[res] = '\0';
791*9e564957SAndroid Build Coastguard Worker
792*9e564957SAndroid Build Coastguard Worker max = atoi(buf);
793*9e564957SAndroid Build Coastguard Worker res = fcntl(pipefd, F_SETPIPE_SZ, max);
794*9e564957SAndroid Build Coastguard Worker if (res < 0)
795*9e564957SAndroid Build Coastguard Worker return -errno;
796*9e564957SAndroid Build Coastguard Worker return max;
797*9e564957SAndroid Build Coastguard Worker }
798*9e564957SAndroid Build Coastguard Worker
799*9e564957SAndroid Build Coastguard Worker static int fuse_send_data_iov(struct fuse_session *se, struct fuse_chan *ch,
800*9e564957SAndroid Build Coastguard Worker struct iovec *iov, int iov_count,
801*9e564957SAndroid Build Coastguard Worker struct fuse_bufvec *buf, unsigned int flags)
802*9e564957SAndroid Build Coastguard Worker {
803*9e564957SAndroid Build Coastguard Worker int res;
804*9e564957SAndroid Build Coastguard Worker size_t len = fuse_buf_size(buf);
805*9e564957SAndroid Build Coastguard Worker struct fuse_out_header *out = iov[0].iov_base;
806*9e564957SAndroid Build Coastguard Worker struct fuse_ll_pipe *llp;
807*9e564957SAndroid Build Coastguard Worker int splice_flags;
808*9e564957SAndroid Build Coastguard Worker size_t pipesize;
809*9e564957SAndroid Build Coastguard Worker size_t total_buf_size;
810*9e564957SAndroid Build Coastguard Worker size_t idx;
811*9e564957SAndroid Build Coastguard Worker size_t headerlen;
812*9e564957SAndroid Build Coastguard Worker struct fuse_bufvec pipe_buf = FUSE_BUFVEC_INIT(len);
813*9e564957SAndroid Build Coastguard Worker
814*9e564957SAndroid Build Coastguard Worker if (se->broken_splice_nonblock)
815*9e564957SAndroid Build Coastguard Worker goto fallback;
816*9e564957SAndroid Build Coastguard Worker
817*9e564957SAndroid Build Coastguard Worker if (flags & FUSE_BUF_NO_SPLICE)
818*9e564957SAndroid Build Coastguard Worker goto fallback;
819*9e564957SAndroid Build Coastguard Worker
820*9e564957SAndroid Build Coastguard Worker total_buf_size = 0;
821*9e564957SAndroid Build Coastguard Worker for (idx = buf->idx; idx < buf->count; idx++) {
822*9e564957SAndroid Build Coastguard Worker total_buf_size += buf->buf[idx].size;
823*9e564957SAndroid Build Coastguard Worker if (idx == buf->idx)
824*9e564957SAndroid Build Coastguard Worker total_buf_size -= buf->off;
825*9e564957SAndroid Build Coastguard Worker }
826*9e564957SAndroid Build Coastguard Worker if (total_buf_size < 2 * pagesize)
827*9e564957SAndroid Build Coastguard Worker goto fallback;
828*9e564957SAndroid Build Coastguard Worker
829*9e564957SAndroid Build Coastguard Worker if (se->conn.proto_minor < 14 ||
830*9e564957SAndroid Build Coastguard Worker !(se->conn.want & FUSE_CAP_SPLICE_WRITE))
831*9e564957SAndroid Build Coastguard Worker goto fallback;
832*9e564957SAndroid Build Coastguard Worker
833*9e564957SAndroid Build Coastguard Worker llp = fuse_ll_get_pipe(se);
834*9e564957SAndroid Build Coastguard Worker if (llp == NULL)
835*9e564957SAndroid Build Coastguard Worker goto fallback;
836*9e564957SAndroid Build Coastguard Worker
837*9e564957SAndroid Build Coastguard Worker
838*9e564957SAndroid Build Coastguard Worker headerlen = iov_length(iov, iov_count);
839*9e564957SAndroid Build Coastguard Worker
840*9e564957SAndroid Build Coastguard Worker out->len = headerlen + len;
841*9e564957SAndroid Build Coastguard Worker
842*9e564957SAndroid Build Coastguard Worker /*
843*9e564957SAndroid Build Coastguard Worker * Heuristic for the required pipe size, does not work if the
844*9e564957SAndroid Build Coastguard Worker * source contains less than page size fragments
845*9e564957SAndroid Build Coastguard Worker */
846*9e564957SAndroid Build Coastguard Worker pipesize = pagesize * (iov_count + buf->count + 1) + out->len;
847*9e564957SAndroid Build Coastguard Worker
848*9e564957SAndroid Build Coastguard Worker if (llp->size < pipesize) {
849*9e564957SAndroid Build Coastguard Worker if (llp->can_grow) {
850*9e564957SAndroid Build Coastguard Worker res = fcntl(llp->pipe[0], F_SETPIPE_SZ, pipesize);
851*9e564957SAndroid Build Coastguard Worker if (res == -1) {
852*9e564957SAndroid Build Coastguard Worker res = grow_pipe_to_max(llp->pipe[0]);
853*9e564957SAndroid Build Coastguard Worker if (res > 0)
854*9e564957SAndroid Build Coastguard Worker llp->size = res;
855*9e564957SAndroid Build Coastguard Worker llp->can_grow = 0;
856*9e564957SAndroid Build Coastguard Worker goto fallback;
857*9e564957SAndroid Build Coastguard Worker }
858*9e564957SAndroid Build Coastguard Worker llp->size = res;
859*9e564957SAndroid Build Coastguard Worker }
860*9e564957SAndroid Build Coastguard Worker if (llp->size < pipesize)
861*9e564957SAndroid Build Coastguard Worker goto fallback;
862*9e564957SAndroid Build Coastguard Worker }
863*9e564957SAndroid Build Coastguard Worker
864*9e564957SAndroid Build Coastguard Worker
865*9e564957SAndroid Build Coastguard Worker res = vmsplice(llp->pipe[1], iov, iov_count, SPLICE_F_NONBLOCK);
866*9e564957SAndroid Build Coastguard Worker if (res == -1)
867*9e564957SAndroid Build Coastguard Worker goto fallback;
868*9e564957SAndroid Build Coastguard Worker
869*9e564957SAndroid Build Coastguard Worker if (res != headerlen) {
870*9e564957SAndroid Build Coastguard Worker res = -EIO;
871*9e564957SAndroid Build Coastguard Worker fuse_log(FUSE_LOG_ERR, "fuse: short vmsplice to pipe: %u/%zu\n", res,
872*9e564957SAndroid Build Coastguard Worker headerlen);
873*9e564957SAndroid Build Coastguard Worker goto clear_pipe;
874*9e564957SAndroid Build Coastguard Worker }
875*9e564957SAndroid Build Coastguard Worker
876*9e564957SAndroid Build Coastguard Worker pipe_buf.buf[0].flags = FUSE_BUF_IS_FD;
877*9e564957SAndroid Build Coastguard Worker pipe_buf.buf[0].fd = llp->pipe[1];
878*9e564957SAndroid Build Coastguard Worker
879*9e564957SAndroid Build Coastguard Worker res = fuse_buf_copy(&pipe_buf, buf,
880*9e564957SAndroid Build Coastguard Worker FUSE_BUF_FORCE_SPLICE | FUSE_BUF_SPLICE_NONBLOCK);
881*9e564957SAndroid Build Coastguard Worker if (res < 0) {
882*9e564957SAndroid Build Coastguard Worker if (res == -EAGAIN || res == -EINVAL) {
883*9e564957SAndroid Build Coastguard Worker /*
884*9e564957SAndroid Build Coastguard Worker * Should only get EAGAIN on kernels with
885*9e564957SAndroid Build Coastguard Worker * broken SPLICE_F_NONBLOCK support (<=
886*9e564957SAndroid Build Coastguard Worker * 2.6.35) where this error or a short read is
887*9e564957SAndroid Build Coastguard Worker * returned even if the pipe itself is not
888*9e564957SAndroid Build Coastguard Worker * full
889*9e564957SAndroid Build Coastguard Worker *
890*9e564957SAndroid Build Coastguard Worker * EINVAL might mean that splice can't handle
891*9e564957SAndroid Build Coastguard Worker * this combination of input and output.
892*9e564957SAndroid Build Coastguard Worker */
893*9e564957SAndroid Build Coastguard Worker if (res == -EAGAIN)
894*9e564957SAndroid Build Coastguard Worker se->broken_splice_nonblock = 1;
895*9e564957SAndroid Build Coastguard Worker
896*9e564957SAndroid Build Coastguard Worker pthread_setspecific(se->pipe_key, NULL);
897*9e564957SAndroid Build Coastguard Worker fuse_ll_pipe_free(llp);
898*9e564957SAndroid Build Coastguard Worker goto fallback;
899*9e564957SAndroid Build Coastguard Worker }
900*9e564957SAndroid Build Coastguard Worker res = -res;
901*9e564957SAndroid Build Coastguard Worker goto clear_pipe;
902*9e564957SAndroid Build Coastguard Worker }
903*9e564957SAndroid Build Coastguard Worker
904*9e564957SAndroid Build Coastguard Worker if (res != 0 && res < len) {
905*9e564957SAndroid Build Coastguard Worker struct fuse_bufvec mem_buf = FUSE_BUFVEC_INIT(len);
906*9e564957SAndroid Build Coastguard Worker void *mbuf;
907*9e564957SAndroid Build Coastguard Worker size_t now_len = res;
908*9e564957SAndroid Build Coastguard Worker /*
909*9e564957SAndroid Build Coastguard Worker * For regular files a short count is either
910*9e564957SAndroid Build Coastguard Worker * 1) due to EOF, or
911*9e564957SAndroid Build Coastguard Worker * 2) because of broken SPLICE_F_NONBLOCK (see above)
912*9e564957SAndroid Build Coastguard Worker *
913*9e564957SAndroid Build Coastguard Worker * For other inputs it's possible that we overflowed
914*9e564957SAndroid Build Coastguard Worker * the pipe because of small buffer fragments.
915*9e564957SAndroid Build Coastguard Worker */
916*9e564957SAndroid Build Coastguard Worker
917*9e564957SAndroid Build Coastguard Worker res = posix_memalign(&mbuf, pagesize, len);
918*9e564957SAndroid Build Coastguard Worker if (res != 0)
919*9e564957SAndroid Build Coastguard Worker goto clear_pipe;
920*9e564957SAndroid Build Coastguard Worker
921*9e564957SAndroid Build Coastguard Worker mem_buf.buf[0].mem = mbuf;
922*9e564957SAndroid Build Coastguard Worker mem_buf.off = now_len;
923*9e564957SAndroid Build Coastguard Worker res = fuse_buf_copy(&mem_buf, buf, 0);
924*9e564957SAndroid Build Coastguard Worker if (res > 0) {
925*9e564957SAndroid Build Coastguard Worker char *tmpbuf;
926*9e564957SAndroid Build Coastguard Worker size_t extra_len = res;
927*9e564957SAndroid Build Coastguard Worker /*
928*9e564957SAndroid Build Coastguard Worker * Trickiest case: got more data. Need to get
929*9e564957SAndroid Build Coastguard Worker * back the data from the pipe and then fall
930*9e564957SAndroid Build Coastguard Worker * back to regular write.
931*9e564957SAndroid Build Coastguard Worker */
932*9e564957SAndroid Build Coastguard Worker tmpbuf = malloc(headerlen);
933*9e564957SAndroid Build Coastguard Worker if (tmpbuf == NULL) {
934*9e564957SAndroid Build Coastguard Worker free(mbuf);
935*9e564957SAndroid Build Coastguard Worker res = ENOMEM;
936*9e564957SAndroid Build Coastguard Worker goto clear_pipe;
937*9e564957SAndroid Build Coastguard Worker }
938*9e564957SAndroid Build Coastguard Worker res = read_back(llp->pipe[0], tmpbuf, headerlen);
939*9e564957SAndroid Build Coastguard Worker free(tmpbuf);
940*9e564957SAndroid Build Coastguard Worker if (res != 0) {
941*9e564957SAndroid Build Coastguard Worker free(mbuf);
942*9e564957SAndroid Build Coastguard Worker goto clear_pipe;
943*9e564957SAndroid Build Coastguard Worker }
944*9e564957SAndroid Build Coastguard Worker res = read_back(llp->pipe[0], mbuf, now_len);
945*9e564957SAndroid Build Coastguard Worker if (res != 0) {
946*9e564957SAndroid Build Coastguard Worker free(mbuf);
947*9e564957SAndroid Build Coastguard Worker goto clear_pipe;
948*9e564957SAndroid Build Coastguard Worker }
949*9e564957SAndroid Build Coastguard Worker len = now_len + extra_len;
950*9e564957SAndroid Build Coastguard Worker iov[iov_count].iov_base = mbuf;
951*9e564957SAndroid Build Coastguard Worker iov[iov_count].iov_len = len;
952*9e564957SAndroid Build Coastguard Worker iov_count++;
953*9e564957SAndroid Build Coastguard Worker res = fuse_send_msg(se, ch, iov, iov_count);
954*9e564957SAndroid Build Coastguard Worker free(mbuf);
955*9e564957SAndroid Build Coastguard Worker return res;
956*9e564957SAndroid Build Coastguard Worker }
957*9e564957SAndroid Build Coastguard Worker free(mbuf);
958*9e564957SAndroid Build Coastguard Worker res = now_len;
959*9e564957SAndroid Build Coastguard Worker }
960*9e564957SAndroid Build Coastguard Worker len = res;
961*9e564957SAndroid Build Coastguard Worker out->len = headerlen + len;
962*9e564957SAndroid Build Coastguard Worker
963*9e564957SAndroid Build Coastguard Worker if (se->debug) {
964*9e564957SAndroid Build Coastguard Worker fuse_log(FUSE_LOG_DEBUG,
965*9e564957SAndroid Build Coastguard Worker " unique: %llu, success, outsize: %i (splice)\n",
966*9e564957SAndroid Build Coastguard Worker (unsigned long long) out->unique, out->len);
967*9e564957SAndroid Build Coastguard Worker }
968*9e564957SAndroid Build Coastguard Worker
969*9e564957SAndroid Build Coastguard Worker splice_flags = 0;
970*9e564957SAndroid Build Coastguard Worker if ((flags & FUSE_BUF_SPLICE_MOVE) &&
971*9e564957SAndroid Build Coastguard Worker (se->conn.want & FUSE_CAP_SPLICE_MOVE))
972*9e564957SAndroid Build Coastguard Worker splice_flags |= SPLICE_F_MOVE;
973*9e564957SAndroid Build Coastguard Worker
974*9e564957SAndroid Build Coastguard Worker if (se->io != NULL && se->io->splice_send != NULL) {
975*9e564957SAndroid Build Coastguard Worker res = se->io->splice_send(llp->pipe[0], NULL,
976*9e564957SAndroid Build Coastguard Worker ch ? ch->fd : se->fd, NULL, out->len,
977*9e564957SAndroid Build Coastguard Worker splice_flags, se->userdata);
978*9e564957SAndroid Build Coastguard Worker } else {
979*9e564957SAndroid Build Coastguard Worker res = splice(llp->pipe[0], NULL, ch ? ch->fd : se->fd, NULL,
980*9e564957SAndroid Build Coastguard Worker out->len, splice_flags);
981*9e564957SAndroid Build Coastguard Worker }
982*9e564957SAndroid Build Coastguard Worker if (res == -1) {
983*9e564957SAndroid Build Coastguard Worker res = -errno;
984*9e564957SAndroid Build Coastguard Worker perror("fuse: splice from pipe");
985*9e564957SAndroid Build Coastguard Worker goto clear_pipe;
986*9e564957SAndroid Build Coastguard Worker }
987*9e564957SAndroid Build Coastguard Worker if (res != out->len) {
988*9e564957SAndroid Build Coastguard Worker res = -EIO;
989*9e564957SAndroid Build Coastguard Worker fuse_log(FUSE_LOG_ERR, "fuse: short splice from pipe: %u/%u\n",
990*9e564957SAndroid Build Coastguard Worker res, out->len);
991*9e564957SAndroid Build Coastguard Worker goto clear_pipe;
992*9e564957SAndroid Build Coastguard Worker }
993*9e564957SAndroid Build Coastguard Worker return 0;
994*9e564957SAndroid Build Coastguard Worker
995*9e564957SAndroid Build Coastguard Worker clear_pipe:
996*9e564957SAndroid Build Coastguard Worker fuse_ll_clear_pipe(se);
997*9e564957SAndroid Build Coastguard Worker return res;
998*9e564957SAndroid Build Coastguard Worker
999*9e564957SAndroid Build Coastguard Worker fallback:
1000*9e564957SAndroid Build Coastguard Worker return fuse_send_data_iov_fallback(se, ch, iov, iov_count, buf, len);
1001*9e564957SAndroid Build Coastguard Worker }
1002*9e564957SAndroid Build Coastguard Worker #else
1003*9e564957SAndroid Build Coastguard Worker static int fuse_send_data_iov(struct fuse_session *se, struct fuse_chan *ch,
1004*9e564957SAndroid Build Coastguard Worker struct iovec *iov, int iov_count,
1005*9e564957SAndroid Build Coastguard Worker struct fuse_bufvec *buf, unsigned int flags)
1006*9e564957SAndroid Build Coastguard Worker {
1007*9e564957SAndroid Build Coastguard Worker size_t len = fuse_buf_size(buf);
1008*9e564957SAndroid Build Coastguard Worker (void) flags;
1009*9e564957SAndroid Build Coastguard Worker
1010*9e564957SAndroid Build Coastguard Worker return fuse_send_data_iov_fallback(se, ch, iov, iov_count, buf, len);
1011*9e564957SAndroid Build Coastguard Worker }
1012*9e564957SAndroid Build Coastguard Worker #endif
1013*9e564957SAndroid Build Coastguard Worker
1014*9e564957SAndroid Build Coastguard Worker int fuse_reply_data(fuse_req_t req, struct fuse_bufvec *bufv,
1015*9e564957SAndroid Build Coastguard Worker enum fuse_buf_copy_flags flags)
1016*9e564957SAndroid Build Coastguard Worker {
1017*9e564957SAndroid Build Coastguard Worker struct iovec iov[2];
1018*9e564957SAndroid Build Coastguard Worker struct fuse_out_header out;
1019*9e564957SAndroid Build Coastguard Worker int res;
1020*9e564957SAndroid Build Coastguard Worker
1021*9e564957SAndroid Build Coastguard Worker iov[0].iov_base = &out;
1022*9e564957SAndroid Build Coastguard Worker iov[0].iov_len = sizeof(struct fuse_out_header);
1023*9e564957SAndroid Build Coastguard Worker
1024*9e564957SAndroid Build Coastguard Worker out.unique = req->unique;
1025*9e564957SAndroid Build Coastguard Worker out.error = 0;
1026*9e564957SAndroid Build Coastguard Worker
1027*9e564957SAndroid Build Coastguard Worker res = fuse_send_data_iov(req->se, req->ch, iov, 1, bufv, flags);
1028*9e564957SAndroid Build Coastguard Worker if (res <= 0) {
1029*9e564957SAndroid Build Coastguard Worker fuse_free_req(req);
1030*9e564957SAndroid Build Coastguard Worker return res;
1031*9e564957SAndroid Build Coastguard Worker } else {
1032*9e564957SAndroid Build Coastguard Worker return fuse_reply_err(req, res);
1033*9e564957SAndroid Build Coastguard Worker }
1034*9e564957SAndroid Build Coastguard Worker }
1035*9e564957SAndroid Build Coastguard Worker
1036*9e564957SAndroid Build Coastguard Worker int fuse_reply_statfs(fuse_req_t req, const struct statvfs *stbuf)
1037*9e564957SAndroid Build Coastguard Worker {
1038*9e564957SAndroid Build Coastguard Worker struct fuse_statfs_out arg;
1039*9e564957SAndroid Build Coastguard Worker size_t size = req->se->conn.proto_minor < 4 ?
1040*9e564957SAndroid Build Coastguard Worker FUSE_COMPAT_STATFS_SIZE : sizeof(arg);
1041*9e564957SAndroid Build Coastguard Worker
1042*9e564957SAndroid Build Coastguard Worker memset(&arg, 0, sizeof(arg));
1043*9e564957SAndroid Build Coastguard Worker convert_statfs(stbuf, &arg.st);
1044*9e564957SAndroid Build Coastguard Worker
1045*9e564957SAndroid Build Coastguard Worker return send_reply_ok(req, &arg, size);
1046*9e564957SAndroid Build Coastguard Worker }
1047*9e564957SAndroid Build Coastguard Worker
1048*9e564957SAndroid Build Coastguard Worker int fuse_reply_xattr(fuse_req_t req, size_t count)
1049*9e564957SAndroid Build Coastguard Worker {
1050*9e564957SAndroid Build Coastguard Worker struct fuse_getxattr_out arg;
1051*9e564957SAndroid Build Coastguard Worker
1052*9e564957SAndroid Build Coastguard Worker memset(&arg, 0, sizeof(arg));
1053*9e564957SAndroid Build Coastguard Worker arg.size = count;
1054*9e564957SAndroid Build Coastguard Worker
1055*9e564957SAndroid Build Coastguard Worker return send_reply_ok(req, &arg, sizeof(arg));
1056*9e564957SAndroid Build Coastguard Worker }
1057*9e564957SAndroid Build Coastguard Worker
1058*9e564957SAndroid Build Coastguard Worker int fuse_reply_lock(fuse_req_t req, const struct flock *lock)
1059*9e564957SAndroid Build Coastguard Worker {
1060*9e564957SAndroid Build Coastguard Worker struct fuse_lk_out arg;
1061*9e564957SAndroid Build Coastguard Worker
1062*9e564957SAndroid Build Coastguard Worker memset(&arg, 0, sizeof(arg));
1063*9e564957SAndroid Build Coastguard Worker arg.lk.type = lock->l_type;
1064*9e564957SAndroid Build Coastguard Worker if (lock->l_type != F_UNLCK) {
1065*9e564957SAndroid Build Coastguard Worker arg.lk.start = lock->l_start;
1066*9e564957SAndroid Build Coastguard Worker if (lock->l_len == 0)
1067*9e564957SAndroid Build Coastguard Worker arg.lk.end = OFFSET_MAX;
1068*9e564957SAndroid Build Coastguard Worker else
1069*9e564957SAndroid Build Coastguard Worker arg.lk.end = lock->l_start + lock->l_len - 1;
1070*9e564957SAndroid Build Coastguard Worker }
1071*9e564957SAndroid Build Coastguard Worker arg.lk.pid = lock->l_pid;
1072*9e564957SAndroid Build Coastguard Worker return send_reply_ok(req, &arg, sizeof(arg));
1073*9e564957SAndroid Build Coastguard Worker }
1074*9e564957SAndroid Build Coastguard Worker
1075*9e564957SAndroid Build Coastguard Worker int fuse_reply_bmap(fuse_req_t req, uint64_t idx)
1076*9e564957SAndroid Build Coastguard Worker {
1077*9e564957SAndroid Build Coastguard Worker struct fuse_bmap_out arg;
1078*9e564957SAndroid Build Coastguard Worker
1079*9e564957SAndroid Build Coastguard Worker memset(&arg, 0, sizeof(arg));
1080*9e564957SAndroid Build Coastguard Worker arg.block = idx;
1081*9e564957SAndroid Build Coastguard Worker
1082*9e564957SAndroid Build Coastguard Worker return send_reply_ok(req, &arg, sizeof(arg));
1083*9e564957SAndroid Build Coastguard Worker }
1084*9e564957SAndroid Build Coastguard Worker
1085*9e564957SAndroid Build Coastguard Worker static struct fuse_ioctl_iovec *fuse_ioctl_iovec_copy(const struct iovec *iov,
1086*9e564957SAndroid Build Coastguard Worker size_t count)
1087*9e564957SAndroid Build Coastguard Worker {
1088*9e564957SAndroid Build Coastguard Worker struct fuse_ioctl_iovec *fiov;
1089*9e564957SAndroid Build Coastguard Worker size_t i;
1090*9e564957SAndroid Build Coastguard Worker
1091*9e564957SAndroid Build Coastguard Worker fiov = malloc(sizeof(fiov[0]) * count);
1092*9e564957SAndroid Build Coastguard Worker if (!fiov)
1093*9e564957SAndroid Build Coastguard Worker return NULL;
1094*9e564957SAndroid Build Coastguard Worker
1095*9e564957SAndroid Build Coastguard Worker for (i = 0; i < count; i++) {
1096*9e564957SAndroid Build Coastguard Worker fiov[i].base = (uintptr_t) iov[i].iov_base;
1097*9e564957SAndroid Build Coastguard Worker fiov[i].len = iov[i].iov_len;
1098*9e564957SAndroid Build Coastguard Worker }
1099*9e564957SAndroid Build Coastguard Worker
1100*9e564957SAndroid Build Coastguard Worker return fiov;
1101*9e564957SAndroid Build Coastguard Worker }
1102*9e564957SAndroid Build Coastguard Worker
1103*9e564957SAndroid Build Coastguard Worker int fuse_reply_ioctl_retry(fuse_req_t req,
1104*9e564957SAndroid Build Coastguard Worker const struct iovec *in_iov, size_t in_count,
1105*9e564957SAndroid Build Coastguard Worker const struct iovec *out_iov, size_t out_count)
1106*9e564957SAndroid Build Coastguard Worker {
1107*9e564957SAndroid Build Coastguard Worker struct fuse_ioctl_out arg;
1108*9e564957SAndroid Build Coastguard Worker struct fuse_ioctl_iovec *in_fiov = NULL;
1109*9e564957SAndroid Build Coastguard Worker struct fuse_ioctl_iovec *out_fiov = NULL;
1110*9e564957SAndroid Build Coastguard Worker struct iovec iov[4];
1111*9e564957SAndroid Build Coastguard Worker size_t count = 1;
1112*9e564957SAndroid Build Coastguard Worker int res;
1113*9e564957SAndroid Build Coastguard Worker
1114*9e564957SAndroid Build Coastguard Worker memset(&arg, 0, sizeof(arg));
1115*9e564957SAndroid Build Coastguard Worker arg.flags |= FUSE_IOCTL_RETRY;
1116*9e564957SAndroid Build Coastguard Worker arg.in_iovs = in_count;
1117*9e564957SAndroid Build Coastguard Worker arg.out_iovs = out_count;
1118*9e564957SAndroid Build Coastguard Worker iov[count].iov_base = &arg;
1119*9e564957SAndroid Build Coastguard Worker iov[count].iov_len = sizeof(arg);
1120*9e564957SAndroid Build Coastguard Worker count++;
1121*9e564957SAndroid Build Coastguard Worker
1122*9e564957SAndroid Build Coastguard Worker if (req->se->conn.proto_minor < 16) {
1123*9e564957SAndroid Build Coastguard Worker if (in_count) {
1124*9e564957SAndroid Build Coastguard Worker iov[count].iov_base = (void *)in_iov;
1125*9e564957SAndroid Build Coastguard Worker iov[count].iov_len = sizeof(in_iov[0]) * in_count;
1126*9e564957SAndroid Build Coastguard Worker count++;
1127*9e564957SAndroid Build Coastguard Worker }
1128*9e564957SAndroid Build Coastguard Worker
1129*9e564957SAndroid Build Coastguard Worker if (out_count) {
1130*9e564957SAndroid Build Coastguard Worker iov[count].iov_base = (void *)out_iov;
1131*9e564957SAndroid Build Coastguard Worker iov[count].iov_len = sizeof(out_iov[0]) * out_count;
1132*9e564957SAndroid Build Coastguard Worker count++;
1133*9e564957SAndroid Build Coastguard Worker }
1134*9e564957SAndroid Build Coastguard Worker } else {
1135*9e564957SAndroid Build Coastguard Worker /* Can't handle non-compat 64bit ioctls on 32bit */
1136*9e564957SAndroid Build Coastguard Worker if (sizeof(void *) == 4 && req->ioctl_64bit) {
1137*9e564957SAndroid Build Coastguard Worker res = fuse_reply_err(req, EINVAL);
1138*9e564957SAndroid Build Coastguard Worker goto out;
1139*9e564957SAndroid Build Coastguard Worker }
1140*9e564957SAndroid Build Coastguard Worker
1141*9e564957SAndroid Build Coastguard Worker if (in_count) {
1142*9e564957SAndroid Build Coastguard Worker in_fiov = fuse_ioctl_iovec_copy(in_iov, in_count);
1143*9e564957SAndroid Build Coastguard Worker if (!in_fiov)
1144*9e564957SAndroid Build Coastguard Worker goto enomem;
1145*9e564957SAndroid Build Coastguard Worker
1146*9e564957SAndroid Build Coastguard Worker iov[count].iov_base = (void *)in_fiov;
1147*9e564957SAndroid Build Coastguard Worker iov[count].iov_len = sizeof(in_fiov[0]) * in_count;
1148*9e564957SAndroid Build Coastguard Worker count++;
1149*9e564957SAndroid Build Coastguard Worker }
1150*9e564957SAndroid Build Coastguard Worker if (out_count) {
1151*9e564957SAndroid Build Coastguard Worker out_fiov = fuse_ioctl_iovec_copy(out_iov, out_count);
1152*9e564957SAndroid Build Coastguard Worker if (!out_fiov)
1153*9e564957SAndroid Build Coastguard Worker goto enomem;
1154*9e564957SAndroid Build Coastguard Worker
1155*9e564957SAndroid Build Coastguard Worker iov[count].iov_base = (void *)out_fiov;
1156*9e564957SAndroid Build Coastguard Worker iov[count].iov_len = sizeof(out_fiov[0]) * out_count;
1157*9e564957SAndroid Build Coastguard Worker count++;
1158*9e564957SAndroid Build Coastguard Worker }
1159*9e564957SAndroid Build Coastguard Worker }
1160*9e564957SAndroid Build Coastguard Worker
1161*9e564957SAndroid Build Coastguard Worker res = send_reply_iov(req, 0, iov, count);
1162*9e564957SAndroid Build Coastguard Worker out:
1163*9e564957SAndroid Build Coastguard Worker free(in_fiov);
1164*9e564957SAndroid Build Coastguard Worker free(out_fiov);
1165*9e564957SAndroid Build Coastguard Worker
1166*9e564957SAndroid Build Coastguard Worker return res;
1167*9e564957SAndroid Build Coastguard Worker
1168*9e564957SAndroid Build Coastguard Worker enomem:
1169*9e564957SAndroid Build Coastguard Worker res = fuse_reply_err(req, ENOMEM);
1170*9e564957SAndroid Build Coastguard Worker goto out;
1171*9e564957SAndroid Build Coastguard Worker }
1172*9e564957SAndroid Build Coastguard Worker
1173*9e564957SAndroid Build Coastguard Worker int fuse_reply_ioctl(fuse_req_t req, int result, const void *buf, size_t size)
1174*9e564957SAndroid Build Coastguard Worker {
1175*9e564957SAndroid Build Coastguard Worker struct fuse_ioctl_out arg;
1176*9e564957SAndroid Build Coastguard Worker struct iovec iov[3];
1177*9e564957SAndroid Build Coastguard Worker size_t count = 1;
1178*9e564957SAndroid Build Coastguard Worker
1179*9e564957SAndroid Build Coastguard Worker memset(&arg, 0, sizeof(arg));
1180*9e564957SAndroid Build Coastguard Worker arg.result = result;
1181*9e564957SAndroid Build Coastguard Worker iov[count].iov_base = &arg;
1182*9e564957SAndroid Build Coastguard Worker iov[count].iov_len = sizeof(arg);
1183*9e564957SAndroid Build Coastguard Worker count++;
1184*9e564957SAndroid Build Coastguard Worker
1185*9e564957SAndroid Build Coastguard Worker if (size) {
1186*9e564957SAndroid Build Coastguard Worker iov[count].iov_base = (char *) buf;
1187*9e564957SAndroid Build Coastguard Worker iov[count].iov_len = size;
1188*9e564957SAndroid Build Coastguard Worker count++;
1189*9e564957SAndroid Build Coastguard Worker }
1190*9e564957SAndroid Build Coastguard Worker
1191*9e564957SAndroid Build Coastguard Worker return send_reply_iov(req, 0, iov, count);
1192*9e564957SAndroid Build Coastguard Worker }
1193*9e564957SAndroid Build Coastguard Worker
1194*9e564957SAndroid Build Coastguard Worker int fuse_reply_ioctl_iov(fuse_req_t req, int result, const struct iovec *iov,
1195*9e564957SAndroid Build Coastguard Worker int count)
1196*9e564957SAndroid Build Coastguard Worker {
1197*9e564957SAndroid Build Coastguard Worker struct iovec *padded_iov;
1198*9e564957SAndroid Build Coastguard Worker struct fuse_ioctl_out arg;
1199*9e564957SAndroid Build Coastguard Worker int res;
1200*9e564957SAndroid Build Coastguard Worker
1201*9e564957SAndroid Build Coastguard Worker padded_iov = malloc((count + 2) * sizeof(struct iovec));
1202*9e564957SAndroid Build Coastguard Worker if (padded_iov == NULL)
1203*9e564957SAndroid Build Coastguard Worker return fuse_reply_err(req, ENOMEM);
1204*9e564957SAndroid Build Coastguard Worker
1205*9e564957SAndroid Build Coastguard Worker memset(&arg, 0, sizeof(arg));
1206*9e564957SAndroid Build Coastguard Worker arg.result = result;
1207*9e564957SAndroid Build Coastguard Worker padded_iov[1].iov_base = &arg;
1208*9e564957SAndroid Build Coastguard Worker padded_iov[1].iov_len = sizeof(arg);
1209*9e564957SAndroid Build Coastguard Worker
1210*9e564957SAndroid Build Coastguard Worker memcpy(&padded_iov[2], iov, count * sizeof(struct iovec));
1211*9e564957SAndroid Build Coastguard Worker
1212*9e564957SAndroid Build Coastguard Worker res = send_reply_iov(req, 0, padded_iov, count + 2);
1213*9e564957SAndroid Build Coastguard Worker free(padded_iov);
1214*9e564957SAndroid Build Coastguard Worker
1215*9e564957SAndroid Build Coastguard Worker return res;
1216*9e564957SAndroid Build Coastguard Worker }
1217*9e564957SAndroid Build Coastguard Worker
1218*9e564957SAndroid Build Coastguard Worker int fuse_reply_poll(fuse_req_t req, unsigned revents)
1219*9e564957SAndroid Build Coastguard Worker {
1220*9e564957SAndroid Build Coastguard Worker struct fuse_poll_out arg;
1221*9e564957SAndroid Build Coastguard Worker
1222*9e564957SAndroid Build Coastguard Worker memset(&arg, 0, sizeof(arg));
1223*9e564957SAndroid Build Coastguard Worker arg.revents = revents;
1224*9e564957SAndroid Build Coastguard Worker
1225*9e564957SAndroid Build Coastguard Worker return send_reply_ok(req, &arg, sizeof(arg));
1226*9e564957SAndroid Build Coastguard Worker }
1227*9e564957SAndroid Build Coastguard Worker
1228*9e564957SAndroid Build Coastguard Worker int fuse_reply_lseek(fuse_req_t req, off_t off)
1229*9e564957SAndroid Build Coastguard Worker {
1230*9e564957SAndroid Build Coastguard Worker struct fuse_lseek_out arg;
1231*9e564957SAndroid Build Coastguard Worker
1232*9e564957SAndroid Build Coastguard Worker memset(&arg, 0, sizeof(arg));
1233*9e564957SAndroid Build Coastguard Worker arg.offset = off;
1234*9e564957SAndroid Build Coastguard Worker
1235*9e564957SAndroid Build Coastguard Worker return send_reply_ok(req, &arg, sizeof(arg));
1236*9e564957SAndroid Build Coastguard Worker }
1237*9e564957SAndroid Build Coastguard Worker
1238*9e564957SAndroid Build Coastguard Worker static void do_lookup(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1239*9e564957SAndroid Build Coastguard Worker {
1240*9e564957SAndroid Build Coastguard Worker char *name = (char *) inarg;
1241*9e564957SAndroid Build Coastguard Worker
1242*9e564957SAndroid Build Coastguard Worker if (req->se->op.lookup)
1243*9e564957SAndroid Build Coastguard Worker req->se->op.lookup(req, nodeid, name);
1244*9e564957SAndroid Build Coastguard Worker else
1245*9e564957SAndroid Build Coastguard Worker fuse_reply_err(req, ENOSYS);
1246*9e564957SAndroid Build Coastguard Worker }
1247*9e564957SAndroid Build Coastguard Worker
1248*9e564957SAndroid Build Coastguard Worker static void do_lookup_postfilter(fuse_req_t req, fuse_ino_t nodeid, uint32_t error_in,
1249*9e564957SAndroid Build Coastguard Worker const void *inarg, size_t size)
1250*9e564957SAndroid Build Coastguard Worker {
1251*9e564957SAndroid Build Coastguard Worker if (req->se->op.lookup_postfilter) {
1252*9e564957SAndroid Build Coastguard Worker char *name = (char *) inarg;
1253*9e564957SAndroid Build Coastguard Worker size_t namelen = strlen(name);
1254*9e564957SAndroid Build Coastguard Worker
1255*9e564957SAndroid Build Coastguard Worker if (size != namelen + 1 + sizeof(struct fuse_entry_out)
1256*9e564957SAndroid Build Coastguard Worker + sizeof(struct fuse_entry_bpf_out)) {
1257*9e564957SAndroid Build Coastguard Worker fuse_log(FUSE_LOG_ERR, "%s: Bad size", __func__);
1258*9e564957SAndroid Build Coastguard Worker fuse_reply_err(req, EIO);
1259*9e564957SAndroid Build Coastguard Worker } else {
1260*9e564957SAndroid Build Coastguard Worker struct fuse_entry_out *feo = (void *) (name + namelen + 1);
1261*9e564957SAndroid Build Coastguard Worker struct fuse_entry_bpf_out *febo = (char *) feo + sizeof(*feo);
1262*9e564957SAndroid Build Coastguard Worker
1263*9e564957SAndroid Build Coastguard Worker req->se->op.lookup_postfilter(req, nodeid, error_in, name, feo,
1264*9e564957SAndroid Build Coastguard Worker febo);
1265*9e564957SAndroid Build Coastguard Worker }
1266*9e564957SAndroid Build Coastguard Worker } else
1267*9e564957SAndroid Build Coastguard Worker fuse_reply_err(req, ENOSYS);
1268*9e564957SAndroid Build Coastguard Worker }
1269*9e564957SAndroid Build Coastguard Worker
1270*9e564957SAndroid Build Coastguard Worker static void do_forget(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1271*9e564957SAndroid Build Coastguard Worker {
1272*9e564957SAndroid Build Coastguard Worker struct fuse_forget_in *arg = (struct fuse_forget_in *) inarg;
1273*9e564957SAndroid Build Coastguard Worker
1274*9e564957SAndroid Build Coastguard Worker if (req->se->op.forget)
1275*9e564957SAndroid Build Coastguard Worker req->se->op.forget(req, nodeid, arg->nlookup);
1276*9e564957SAndroid Build Coastguard Worker else
1277*9e564957SAndroid Build Coastguard Worker fuse_reply_none(req);
1278*9e564957SAndroid Build Coastguard Worker }
1279*9e564957SAndroid Build Coastguard Worker
1280*9e564957SAndroid Build Coastguard Worker static void do_batch_forget(fuse_req_t req, fuse_ino_t nodeid,
1281*9e564957SAndroid Build Coastguard Worker const void *inarg)
1282*9e564957SAndroid Build Coastguard Worker {
1283*9e564957SAndroid Build Coastguard Worker struct fuse_batch_forget_in *arg = (void *) inarg;
1284*9e564957SAndroid Build Coastguard Worker struct fuse_forget_one *param = (void *) PARAM(arg);
1285*9e564957SAndroid Build Coastguard Worker unsigned int i;
1286*9e564957SAndroid Build Coastguard Worker
1287*9e564957SAndroid Build Coastguard Worker (void) nodeid;
1288*9e564957SAndroid Build Coastguard Worker
1289*9e564957SAndroid Build Coastguard Worker if (req->se->op.forget_multi) {
1290*9e564957SAndroid Build Coastguard Worker req->se->op.forget_multi(req, arg->count,
1291*9e564957SAndroid Build Coastguard Worker (struct fuse_forget_data *) param);
1292*9e564957SAndroid Build Coastguard Worker } else if (req->se->op.forget) {
1293*9e564957SAndroid Build Coastguard Worker for (i = 0; i < arg->count; i++) {
1294*9e564957SAndroid Build Coastguard Worker struct fuse_forget_one *forget = ¶m[i];
1295*9e564957SAndroid Build Coastguard Worker struct fuse_req *dummy_req;
1296*9e564957SAndroid Build Coastguard Worker
1297*9e564957SAndroid Build Coastguard Worker dummy_req = fuse_ll_alloc_req(req->se);
1298*9e564957SAndroid Build Coastguard Worker if (dummy_req == NULL)
1299*9e564957SAndroid Build Coastguard Worker break;
1300*9e564957SAndroid Build Coastguard Worker
1301*9e564957SAndroid Build Coastguard Worker dummy_req->unique = req->unique;
1302*9e564957SAndroid Build Coastguard Worker dummy_req->ctx = req->ctx;
1303*9e564957SAndroid Build Coastguard Worker dummy_req->ch = NULL;
1304*9e564957SAndroid Build Coastguard Worker
1305*9e564957SAndroid Build Coastguard Worker req->se->op.forget(dummy_req, forget->nodeid,
1306*9e564957SAndroid Build Coastguard Worker forget->nlookup);
1307*9e564957SAndroid Build Coastguard Worker }
1308*9e564957SAndroid Build Coastguard Worker fuse_reply_none(req);
1309*9e564957SAndroid Build Coastguard Worker } else {
1310*9e564957SAndroid Build Coastguard Worker fuse_reply_none(req);
1311*9e564957SAndroid Build Coastguard Worker }
1312*9e564957SAndroid Build Coastguard Worker }
1313*9e564957SAndroid Build Coastguard Worker
1314*9e564957SAndroid Build Coastguard Worker static void do_getattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1315*9e564957SAndroid Build Coastguard Worker {
1316*9e564957SAndroid Build Coastguard Worker struct fuse_file_info *fip = NULL;
1317*9e564957SAndroid Build Coastguard Worker struct fuse_file_info fi;
1318*9e564957SAndroid Build Coastguard Worker
1319*9e564957SAndroid Build Coastguard Worker if (req->se->conn.proto_minor >= 9) {
1320*9e564957SAndroid Build Coastguard Worker struct fuse_getattr_in *arg = (struct fuse_getattr_in *) inarg;
1321*9e564957SAndroid Build Coastguard Worker
1322*9e564957SAndroid Build Coastguard Worker if (arg->getattr_flags & FUSE_GETATTR_FH) {
1323*9e564957SAndroid Build Coastguard Worker memset(&fi, 0, sizeof(fi));
1324*9e564957SAndroid Build Coastguard Worker fi.fh = arg->fh;
1325*9e564957SAndroid Build Coastguard Worker fip = &fi;
1326*9e564957SAndroid Build Coastguard Worker }
1327*9e564957SAndroid Build Coastguard Worker }
1328*9e564957SAndroid Build Coastguard Worker
1329*9e564957SAndroid Build Coastguard Worker if (req->se->op.getattr)
1330*9e564957SAndroid Build Coastguard Worker req->se->op.getattr(req, nodeid, fip);
1331*9e564957SAndroid Build Coastguard Worker else
1332*9e564957SAndroid Build Coastguard Worker fuse_reply_err(req, ENOSYS);
1333*9e564957SAndroid Build Coastguard Worker }
1334*9e564957SAndroid Build Coastguard Worker
1335*9e564957SAndroid Build Coastguard Worker static void do_setattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1336*9e564957SAndroid Build Coastguard Worker {
1337*9e564957SAndroid Build Coastguard Worker struct fuse_setattr_in *arg = (struct fuse_setattr_in *) inarg;
1338*9e564957SAndroid Build Coastguard Worker
1339*9e564957SAndroid Build Coastguard Worker if (req->se->op.setattr) {
1340*9e564957SAndroid Build Coastguard Worker struct fuse_file_info *fi = NULL;
1341*9e564957SAndroid Build Coastguard Worker struct fuse_file_info fi_store;
1342*9e564957SAndroid Build Coastguard Worker struct stat stbuf;
1343*9e564957SAndroid Build Coastguard Worker memset(&stbuf, 0, sizeof(stbuf));
1344*9e564957SAndroid Build Coastguard Worker convert_attr(arg, &stbuf);
1345*9e564957SAndroid Build Coastguard Worker if (arg->valid & FATTR_FH) {
1346*9e564957SAndroid Build Coastguard Worker arg->valid &= ~FATTR_FH;
1347*9e564957SAndroid Build Coastguard Worker memset(&fi_store, 0, sizeof(fi_store));
1348*9e564957SAndroid Build Coastguard Worker fi = &fi_store;
1349*9e564957SAndroid Build Coastguard Worker fi->fh = arg->fh;
1350*9e564957SAndroid Build Coastguard Worker }
1351*9e564957SAndroid Build Coastguard Worker arg->valid &=
1352*9e564957SAndroid Build Coastguard Worker FUSE_SET_ATTR_MODE |
1353*9e564957SAndroid Build Coastguard Worker FUSE_SET_ATTR_UID |
1354*9e564957SAndroid Build Coastguard Worker FUSE_SET_ATTR_GID |
1355*9e564957SAndroid Build Coastguard Worker FUSE_SET_ATTR_SIZE |
1356*9e564957SAndroid Build Coastguard Worker FUSE_SET_ATTR_ATIME |
1357*9e564957SAndroid Build Coastguard Worker FUSE_SET_ATTR_MTIME |
1358*9e564957SAndroid Build Coastguard Worker FUSE_SET_ATTR_KILL_SUID |
1359*9e564957SAndroid Build Coastguard Worker FUSE_SET_ATTR_KILL_SGID |
1360*9e564957SAndroid Build Coastguard Worker FUSE_SET_ATTR_ATIME_NOW |
1361*9e564957SAndroid Build Coastguard Worker FUSE_SET_ATTR_MTIME_NOW |
1362*9e564957SAndroid Build Coastguard Worker FUSE_SET_ATTR_CTIME;
1363*9e564957SAndroid Build Coastguard Worker
1364*9e564957SAndroid Build Coastguard Worker req->se->op.setattr(req, nodeid, &stbuf, arg->valid, fi);
1365*9e564957SAndroid Build Coastguard Worker } else
1366*9e564957SAndroid Build Coastguard Worker fuse_reply_err(req, ENOSYS);
1367*9e564957SAndroid Build Coastguard Worker }
1368*9e564957SAndroid Build Coastguard Worker
1369*9e564957SAndroid Build Coastguard Worker static void do_access(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1370*9e564957SAndroid Build Coastguard Worker {
1371*9e564957SAndroid Build Coastguard Worker struct fuse_access_in *arg = (struct fuse_access_in *) inarg;
1372*9e564957SAndroid Build Coastguard Worker
1373*9e564957SAndroid Build Coastguard Worker if (req->se->op.access)
1374*9e564957SAndroid Build Coastguard Worker req->se->op.access(req, nodeid, arg->mask);
1375*9e564957SAndroid Build Coastguard Worker else
1376*9e564957SAndroid Build Coastguard Worker fuse_reply_err(req, ENOSYS);
1377*9e564957SAndroid Build Coastguard Worker }
1378*9e564957SAndroid Build Coastguard Worker
1379*9e564957SAndroid Build Coastguard Worker static void do_readlink(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1380*9e564957SAndroid Build Coastguard Worker {
1381*9e564957SAndroid Build Coastguard Worker (void) inarg;
1382*9e564957SAndroid Build Coastguard Worker
1383*9e564957SAndroid Build Coastguard Worker if (req->se->op.readlink)
1384*9e564957SAndroid Build Coastguard Worker req->se->op.readlink(req, nodeid);
1385*9e564957SAndroid Build Coastguard Worker else
1386*9e564957SAndroid Build Coastguard Worker fuse_reply_err(req, ENOSYS);
1387*9e564957SAndroid Build Coastguard Worker }
1388*9e564957SAndroid Build Coastguard Worker
1389*9e564957SAndroid Build Coastguard Worker static void do_canonical_path(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1390*9e564957SAndroid Build Coastguard Worker {
1391*9e564957SAndroid Build Coastguard Worker (void) inarg;
1392*9e564957SAndroid Build Coastguard Worker
1393*9e564957SAndroid Build Coastguard Worker if (req->se->op.canonical_path)
1394*9e564957SAndroid Build Coastguard Worker req->se->op.canonical_path(req, nodeid);
1395*9e564957SAndroid Build Coastguard Worker else
1396*9e564957SAndroid Build Coastguard Worker fuse_reply_err(req, ENOSYS);
1397*9e564957SAndroid Build Coastguard Worker }
1398*9e564957SAndroid Build Coastguard Worker
1399*9e564957SAndroid Build Coastguard Worker static void do_mknod(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1400*9e564957SAndroid Build Coastguard Worker {
1401*9e564957SAndroid Build Coastguard Worker struct fuse_mknod_in *arg = (struct fuse_mknod_in *) inarg;
1402*9e564957SAndroid Build Coastguard Worker char *name = PARAM(arg);
1403*9e564957SAndroid Build Coastguard Worker
1404*9e564957SAndroid Build Coastguard Worker if (req->se->conn.proto_minor >= 12)
1405*9e564957SAndroid Build Coastguard Worker req->ctx.umask = arg->umask;
1406*9e564957SAndroid Build Coastguard Worker else
1407*9e564957SAndroid Build Coastguard Worker name = (char *) inarg + FUSE_COMPAT_MKNOD_IN_SIZE;
1408*9e564957SAndroid Build Coastguard Worker
1409*9e564957SAndroid Build Coastguard Worker if (req->se->op.mknod)
1410*9e564957SAndroid Build Coastguard Worker req->se->op.mknod(req, nodeid, name, arg->mode, arg->rdev);
1411*9e564957SAndroid Build Coastguard Worker else
1412*9e564957SAndroid Build Coastguard Worker fuse_reply_err(req, ENOSYS);
1413*9e564957SAndroid Build Coastguard Worker }
1414*9e564957SAndroid Build Coastguard Worker
1415*9e564957SAndroid Build Coastguard Worker static void do_mkdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1416*9e564957SAndroid Build Coastguard Worker {
1417*9e564957SAndroid Build Coastguard Worker struct fuse_mkdir_in *arg = (struct fuse_mkdir_in *) inarg;
1418*9e564957SAndroid Build Coastguard Worker
1419*9e564957SAndroid Build Coastguard Worker if (req->se->conn.proto_minor >= 12)
1420*9e564957SAndroid Build Coastguard Worker req->ctx.umask = arg->umask;
1421*9e564957SAndroid Build Coastguard Worker
1422*9e564957SAndroid Build Coastguard Worker if (req->se->op.mkdir)
1423*9e564957SAndroid Build Coastguard Worker req->se->op.mkdir(req, nodeid, PARAM(arg), arg->mode);
1424*9e564957SAndroid Build Coastguard Worker else
1425*9e564957SAndroid Build Coastguard Worker fuse_reply_err(req, ENOSYS);
1426*9e564957SAndroid Build Coastguard Worker }
1427*9e564957SAndroid Build Coastguard Worker
1428*9e564957SAndroid Build Coastguard Worker static void do_unlink(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1429*9e564957SAndroid Build Coastguard Worker {
1430*9e564957SAndroid Build Coastguard Worker char *name = (char *) inarg;
1431*9e564957SAndroid Build Coastguard Worker
1432*9e564957SAndroid Build Coastguard Worker if (req->se->op.unlink)
1433*9e564957SAndroid Build Coastguard Worker req->se->op.unlink(req, nodeid, name);
1434*9e564957SAndroid Build Coastguard Worker else
1435*9e564957SAndroid Build Coastguard Worker fuse_reply_err(req, ENOSYS);
1436*9e564957SAndroid Build Coastguard Worker }
1437*9e564957SAndroid Build Coastguard Worker
1438*9e564957SAndroid Build Coastguard Worker static void do_rmdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1439*9e564957SAndroid Build Coastguard Worker {
1440*9e564957SAndroid Build Coastguard Worker char *name = (char *) inarg;
1441*9e564957SAndroid Build Coastguard Worker
1442*9e564957SAndroid Build Coastguard Worker if (req->se->op.rmdir)
1443*9e564957SAndroid Build Coastguard Worker req->se->op.rmdir(req, nodeid, name);
1444*9e564957SAndroid Build Coastguard Worker else
1445*9e564957SAndroid Build Coastguard Worker fuse_reply_err(req, ENOSYS);
1446*9e564957SAndroid Build Coastguard Worker }
1447*9e564957SAndroid Build Coastguard Worker
1448*9e564957SAndroid Build Coastguard Worker static void do_symlink(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1449*9e564957SAndroid Build Coastguard Worker {
1450*9e564957SAndroid Build Coastguard Worker char *name = (char *) inarg;
1451*9e564957SAndroid Build Coastguard Worker char *linkname = ((char *) inarg) + strlen((char *) inarg) + 1;
1452*9e564957SAndroid Build Coastguard Worker
1453*9e564957SAndroid Build Coastguard Worker if (req->se->op.symlink)
1454*9e564957SAndroid Build Coastguard Worker req->se->op.symlink(req, linkname, nodeid, name);
1455*9e564957SAndroid Build Coastguard Worker else
1456*9e564957SAndroid Build Coastguard Worker fuse_reply_err(req, ENOSYS);
1457*9e564957SAndroid Build Coastguard Worker }
1458*9e564957SAndroid Build Coastguard Worker
1459*9e564957SAndroid Build Coastguard Worker static void do_rename(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1460*9e564957SAndroid Build Coastguard Worker {
1461*9e564957SAndroid Build Coastguard Worker struct fuse_rename_in *arg = (struct fuse_rename_in *) inarg;
1462*9e564957SAndroid Build Coastguard Worker char *oldname = PARAM(arg);
1463*9e564957SAndroid Build Coastguard Worker char *newname = oldname + strlen(oldname) + 1;
1464*9e564957SAndroid Build Coastguard Worker
1465*9e564957SAndroid Build Coastguard Worker if (req->se->op.rename)
1466*9e564957SAndroid Build Coastguard Worker req->se->op.rename(req, nodeid, oldname, arg->newdir, newname,
1467*9e564957SAndroid Build Coastguard Worker 0);
1468*9e564957SAndroid Build Coastguard Worker else
1469*9e564957SAndroid Build Coastguard Worker fuse_reply_err(req, ENOSYS);
1470*9e564957SAndroid Build Coastguard Worker }
1471*9e564957SAndroid Build Coastguard Worker
1472*9e564957SAndroid Build Coastguard Worker static void do_rename2(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1473*9e564957SAndroid Build Coastguard Worker {
1474*9e564957SAndroid Build Coastguard Worker struct fuse_rename2_in *arg = (struct fuse_rename2_in *) inarg;
1475*9e564957SAndroid Build Coastguard Worker char *oldname = PARAM(arg);
1476*9e564957SAndroid Build Coastguard Worker char *newname = oldname + strlen(oldname) + 1;
1477*9e564957SAndroid Build Coastguard Worker
1478*9e564957SAndroid Build Coastguard Worker if (req->se->op.rename)
1479*9e564957SAndroid Build Coastguard Worker req->se->op.rename(req, nodeid, oldname, arg->newdir, newname,
1480*9e564957SAndroid Build Coastguard Worker arg->flags);
1481*9e564957SAndroid Build Coastguard Worker else
1482*9e564957SAndroid Build Coastguard Worker fuse_reply_err(req, ENOSYS);
1483*9e564957SAndroid Build Coastguard Worker }
1484*9e564957SAndroid Build Coastguard Worker
1485*9e564957SAndroid Build Coastguard Worker static void do_link(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1486*9e564957SAndroid Build Coastguard Worker {
1487*9e564957SAndroid Build Coastguard Worker struct fuse_link_in *arg = (struct fuse_link_in *) inarg;
1488*9e564957SAndroid Build Coastguard Worker
1489*9e564957SAndroid Build Coastguard Worker if (req->se->op.link)
1490*9e564957SAndroid Build Coastguard Worker req->se->op.link(req, arg->oldnodeid, nodeid, PARAM(arg));
1491*9e564957SAndroid Build Coastguard Worker else
1492*9e564957SAndroid Build Coastguard Worker fuse_reply_err(req, ENOSYS);
1493*9e564957SAndroid Build Coastguard Worker }
1494*9e564957SAndroid Build Coastguard Worker
1495*9e564957SAndroid Build Coastguard Worker static void do_create(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1496*9e564957SAndroid Build Coastguard Worker {
1497*9e564957SAndroid Build Coastguard Worker struct fuse_create_in *arg = (struct fuse_create_in *) inarg;
1498*9e564957SAndroid Build Coastguard Worker
1499*9e564957SAndroid Build Coastguard Worker if (req->se->op.create) {
1500*9e564957SAndroid Build Coastguard Worker struct fuse_file_info fi;
1501*9e564957SAndroid Build Coastguard Worker char *name = PARAM(arg);
1502*9e564957SAndroid Build Coastguard Worker
1503*9e564957SAndroid Build Coastguard Worker memset(&fi, 0, sizeof(fi));
1504*9e564957SAndroid Build Coastguard Worker fi.flags = arg->flags;
1505*9e564957SAndroid Build Coastguard Worker
1506*9e564957SAndroid Build Coastguard Worker if (req->se->conn.proto_minor >= 12)
1507*9e564957SAndroid Build Coastguard Worker req->ctx.umask = arg->umask;
1508*9e564957SAndroid Build Coastguard Worker else
1509*9e564957SAndroid Build Coastguard Worker name = (char *) inarg + sizeof(struct fuse_open_in);
1510*9e564957SAndroid Build Coastguard Worker
1511*9e564957SAndroid Build Coastguard Worker req->se->op.create(req, nodeid, name, arg->mode, &fi);
1512*9e564957SAndroid Build Coastguard Worker } else
1513*9e564957SAndroid Build Coastguard Worker fuse_reply_err(req, ENOSYS);
1514*9e564957SAndroid Build Coastguard Worker }
1515*9e564957SAndroid Build Coastguard Worker
1516*9e564957SAndroid Build Coastguard Worker static void do_open(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1517*9e564957SAndroid Build Coastguard Worker {
1518*9e564957SAndroid Build Coastguard Worker struct fuse_open_in *arg = (struct fuse_open_in *) inarg;
1519*9e564957SAndroid Build Coastguard Worker struct fuse_file_info fi;
1520*9e564957SAndroid Build Coastguard Worker
1521*9e564957SAndroid Build Coastguard Worker memset(&fi, 0, sizeof(fi));
1522*9e564957SAndroid Build Coastguard Worker fi.flags = arg->flags;
1523*9e564957SAndroid Build Coastguard Worker
1524*9e564957SAndroid Build Coastguard Worker if (req->se->op.open)
1525*9e564957SAndroid Build Coastguard Worker req->se->op.open(req, nodeid, &fi);
1526*9e564957SAndroid Build Coastguard Worker else if (req->se->conn.want & FUSE_CAP_NO_OPEN_SUPPORT)
1527*9e564957SAndroid Build Coastguard Worker fuse_reply_err(req, ENOSYS);
1528*9e564957SAndroid Build Coastguard Worker else
1529*9e564957SAndroid Build Coastguard Worker fuse_reply_open(req, &fi);
1530*9e564957SAndroid Build Coastguard Worker }
1531*9e564957SAndroid Build Coastguard Worker
1532*9e564957SAndroid Build Coastguard Worker static void do_read(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1533*9e564957SAndroid Build Coastguard Worker {
1534*9e564957SAndroid Build Coastguard Worker struct fuse_read_in *arg = (struct fuse_read_in *) inarg;
1535*9e564957SAndroid Build Coastguard Worker
1536*9e564957SAndroid Build Coastguard Worker if (req->se->op.read) {
1537*9e564957SAndroid Build Coastguard Worker struct fuse_file_info fi;
1538*9e564957SAndroid Build Coastguard Worker
1539*9e564957SAndroid Build Coastguard Worker memset(&fi, 0, sizeof(fi));
1540*9e564957SAndroid Build Coastguard Worker fi.fh = arg->fh;
1541*9e564957SAndroid Build Coastguard Worker if (req->se->conn.proto_minor >= 9) {
1542*9e564957SAndroid Build Coastguard Worker fi.lock_owner = arg->lock_owner;
1543*9e564957SAndroid Build Coastguard Worker fi.flags = arg->flags;
1544*9e564957SAndroid Build Coastguard Worker }
1545*9e564957SAndroid Build Coastguard Worker req->se->op.read(req, nodeid, arg->size, arg->offset, &fi);
1546*9e564957SAndroid Build Coastguard Worker } else
1547*9e564957SAndroid Build Coastguard Worker fuse_reply_err(req, ENOSYS);
1548*9e564957SAndroid Build Coastguard Worker }
1549*9e564957SAndroid Build Coastguard Worker
1550*9e564957SAndroid Build Coastguard Worker static void do_write(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1551*9e564957SAndroid Build Coastguard Worker {
1552*9e564957SAndroid Build Coastguard Worker struct fuse_write_in *arg = (struct fuse_write_in *) inarg;
1553*9e564957SAndroid Build Coastguard Worker struct fuse_file_info fi;
1554*9e564957SAndroid Build Coastguard Worker char *param;
1555*9e564957SAndroid Build Coastguard Worker
1556*9e564957SAndroid Build Coastguard Worker memset(&fi, 0, sizeof(fi));
1557*9e564957SAndroid Build Coastguard Worker fi.fh = arg->fh;
1558*9e564957SAndroid Build Coastguard Worker fi.writepage = (arg->write_flags & FUSE_WRITE_CACHE) != 0;
1559*9e564957SAndroid Build Coastguard Worker
1560*9e564957SAndroid Build Coastguard Worker if (req->se->conn.proto_minor < 9) {
1561*9e564957SAndroid Build Coastguard Worker param = ((char *) arg) + FUSE_COMPAT_WRITE_IN_SIZE;
1562*9e564957SAndroid Build Coastguard Worker } else {
1563*9e564957SAndroid Build Coastguard Worker fi.lock_owner = arg->lock_owner;
1564*9e564957SAndroid Build Coastguard Worker fi.flags = arg->flags;
1565*9e564957SAndroid Build Coastguard Worker param = PARAM(arg);
1566*9e564957SAndroid Build Coastguard Worker }
1567*9e564957SAndroid Build Coastguard Worker
1568*9e564957SAndroid Build Coastguard Worker if (req->se->op.write)
1569*9e564957SAndroid Build Coastguard Worker req->se->op.write(req, nodeid, param, arg->size,
1570*9e564957SAndroid Build Coastguard Worker arg->offset, &fi);
1571*9e564957SAndroid Build Coastguard Worker else
1572*9e564957SAndroid Build Coastguard Worker fuse_reply_err(req, ENOSYS);
1573*9e564957SAndroid Build Coastguard Worker }
1574*9e564957SAndroid Build Coastguard Worker
1575*9e564957SAndroid Build Coastguard Worker static void do_write_buf(fuse_req_t req, fuse_ino_t nodeid, const void *inarg,
1576*9e564957SAndroid Build Coastguard Worker const struct fuse_buf *ibuf)
1577*9e564957SAndroid Build Coastguard Worker {
1578*9e564957SAndroid Build Coastguard Worker struct fuse_session *se = req->se;
1579*9e564957SAndroid Build Coastguard Worker struct fuse_bufvec bufv = {
1580*9e564957SAndroid Build Coastguard Worker .buf[0] = *ibuf,
1581*9e564957SAndroid Build Coastguard Worker .count = 1,
1582*9e564957SAndroid Build Coastguard Worker };
1583*9e564957SAndroid Build Coastguard Worker struct fuse_write_in *arg = (struct fuse_write_in *) inarg;
1584*9e564957SAndroid Build Coastguard Worker struct fuse_file_info fi;
1585*9e564957SAndroid Build Coastguard Worker
1586*9e564957SAndroid Build Coastguard Worker memset(&fi, 0, sizeof(fi));
1587*9e564957SAndroid Build Coastguard Worker fi.fh = arg->fh;
1588*9e564957SAndroid Build Coastguard Worker fi.writepage = arg->write_flags & FUSE_WRITE_CACHE;
1589*9e564957SAndroid Build Coastguard Worker
1590*9e564957SAndroid Build Coastguard Worker if (se->conn.proto_minor < 9) {
1591*9e564957SAndroid Build Coastguard Worker bufv.buf[0].mem = ((char *) arg) + FUSE_COMPAT_WRITE_IN_SIZE;
1592*9e564957SAndroid Build Coastguard Worker bufv.buf[0].size -= sizeof(struct fuse_in_header) +
1593*9e564957SAndroid Build Coastguard Worker FUSE_COMPAT_WRITE_IN_SIZE;
1594*9e564957SAndroid Build Coastguard Worker assert(!(bufv.buf[0].flags & FUSE_BUF_IS_FD));
1595*9e564957SAndroid Build Coastguard Worker } else {
1596*9e564957SAndroid Build Coastguard Worker fi.lock_owner = arg->lock_owner;
1597*9e564957SAndroid Build Coastguard Worker fi.flags = arg->flags;
1598*9e564957SAndroid Build Coastguard Worker if (!(bufv.buf[0].flags & FUSE_BUF_IS_FD))
1599*9e564957SAndroid Build Coastguard Worker bufv.buf[0].mem = PARAM(arg);
1600*9e564957SAndroid Build Coastguard Worker
1601*9e564957SAndroid Build Coastguard Worker bufv.buf[0].size -= sizeof(struct fuse_in_header) +
1602*9e564957SAndroid Build Coastguard Worker sizeof(struct fuse_write_in);
1603*9e564957SAndroid Build Coastguard Worker }
1604*9e564957SAndroid Build Coastguard Worker if (bufv.buf[0].size < arg->size) {
1605*9e564957SAndroid Build Coastguard Worker fuse_log(FUSE_LOG_ERR, "fuse: do_write_buf: buffer size too small\n");
1606*9e564957SAndroid Build Coastguard Worker fuse_reply_err(req, EIO);
1607*9e564957SAndroid Build Coastguard Worker goto out;
1608*9e564957SAndroid Build Coastguard Worker }
1609*9e564957SAndroid Build Coastguard Worker bufv.buf[0].size = arg->size;
1610*9e564957SAndroid Build Coastguard Worker
1611*9e564957SAndroid Build Coastguard Worker se->op.write_buf(req, nodeid, &bufv, arg->offset, &fi);
1612*9e564957SAndroid Build Coastguard Worker
1613*9e564957SAndroid Build Coastguard Worker out:
1614*9e564957SAndroid Build Coastguard Worker /* Need to reset the pipe if ->write_buf() didn't consume all data */
1615*9e564957SAndroid Build Coastguard Worker if ((ibuf->flags & FUSE_BUF_IS_FD) && bufv.idx < bufv.count)
1616*9e564957SAndroid Build Coastguard Worker fuse_ll_clear_pipe(se);
1617*9e564957SAndroid Build Coastguard Worker }
1618*9e564957SAndroid Build Coastguard Worker
1619*9e564957SAndroid Build Coastguard Worker static void do_flush(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1620*9e564957SAndroid Build Coastguard Worker {
1621*9e564957SAndroid Build Coastguard Worker struct fuse_flush_in *arg = (struct fuse_flush_in *) inarg;
1622*9e564957SAndroid Build Coastguard Worker struct fuse_file_info fi;
1623*9e564957SAndroid Build Coastguard Worker
1624*9e564957SAndroid Build Coastguard Worker memset(&fi, 0, sizeof(fi));
1625*9e564957SAndroid Build Coastguard Worker fi.fh = arg->fh;
1626*9e564957SAndroid Build Coastguard Worker fi.flush = 1;
1627*9e564957SAndroid Build Coastguard Worker if (req->se->conn.proto_minor >= 7)
1628*9e564957SAndroid Build Coastguard Worker fi.lock_owner = arg->lock_owner;
1629*9e564957SAndroid Build Coastguard Worker
1630*9e564957SAndroid Build Coastguard Worker if (req->se->op.flush)
1631*9e564957SAndroid Build Coastguard Worker req->se->op.flush(req, nodeid, &fi);
1632*9e564957SAndroid Build Coastguard Worker else
1633*9e564957SAndroid Build Coastguard Worker fuse_reply_err(req, ENOSYS);
1634*9e564957SAndroid Build Coastguard Worker }
1635*9e564957SAndroid Build Coastguard Worker
1636*9e564957SAndroid Build Coastguard Worker static void do_release(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1637*9e564957SAndroid Build Coastguard Worker {
1638*9e564957SAndroid Build Coastguard Worker struct fuse_release_in *arg = (struct fuse_release_in *) inarg;
1639*9e564957SAndroid Build Coastguard Worker struct fuse_file_info fi;
1640*9e564957SAndroid Build Coastguard Worker
1641*9e564957SAndroid Build Coastguard Worker memset(&fi, 0, sizeof(fi));
1642*9e564957SAndroid Build Coastguard Worker fi.flags = arg->flags;
1643*9e564957SAndroid Build Coastguard Worker fi.fh = arg->fh;
1644*9e564957SAndroid Build Coastguard Worker if (req->se->conn.proto_minor >= 8) {
1645*9e564957SAndroid Build Coastguard Worker fi.flush = (arg->release_flags & FUSE_RELEASE_FLUSH) ? 1 : 0;
1646*9e564957SAndroid Build Coastguard Worker fi.lock_owner = arg->lock_owner;
1647*9e564957SAndroid Build Coastguard Worker }
1648*9e564957SAndroid Build Coastguard Worker if (arg->release_flags & FUSE_RELEASE_FLOCK_UNLOCK) {
1649*9e564957SAndroid Build Coastguard Worker fi.flock_release = 1;
1650*9e564957SAndroid Build Coastguard Worker fi.lock_owner = arg->lock_owner;
1651*9e564957SAndroid Build Coastguard Worker }
1652*9e564957SAndroid Build Coastguard Worker
1653*9e564957SAndroid Build Coastguard Worker if (req->se->op.release)
1654*9e564957SAndroid Build Coastguard Worker req->se->op.release(req, nodeid, &fi);
1655*9e564957SAndroid Build Coastguard Worker else
1656*9e564957SAndroid Build Coastguard Worker fuse_reply_err(req, 0);
1657*9e564957SAndroid Build Coastguard Worker }
1658*9e564957SAndroid Build Coastguard Worker
1659*9e564957SAndroid Build Coastguard Worker static void do_fsync(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1660*9e564957SAndroid Build Coastguard Worker {
1661*9e564957SAndroid Build Coastguard Worker struct fuse_fsync_in *arg = (struct fuse_fsync_in *) inarg;
1662*9e564957SAndroid Build Coastguard Worker struct fuse_file_info fi;
1663*9e564957SAndroid Build Coastguard Worker int datasync = arg->fsync_flags & 1;
1664*9e564957SAndroid Build Coastguard Worker
1665*9e564957SAndroid Build Coastguard Worker memset(&fi, 0, sizeof(fi));
1666*9e564957SAndroid Build Coastguard Worker fi.fh = arg->fh;
1667*9e564957SAndroid Build Coastguard Worker
1668*9e564957SAndroid Build Coastguard Worker if (req->se->op.fsync)
1669*9e564957SAndroid Build Coastguard Worker req->se->op.fsync(req, nodeid, datasync, &fi);
1670*9e564957SAndroid Build Coastguard Worker else
1671*9e564957SAndroid Build Coastguard Worker fuse_reply_err(req, ENOSYS);
1672*9e564957SAndroid Build Coastguard Worker }
1673*9e564957SAndroid Build Coastguard Worker
1674*9e564957SAndroid Build Coastguard Worker static void do_opendir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1675*9e564957SAndroid Build Coastguard Worker {
1676*9e564957SAndroid Build Coastguard Worker struct fuse_open_in *arg = (struct fuse_open_in *) inarg;
1677*9e564957SAndroid Build Coastguard Worker struct fuse_file_info fi;
1678*9e564957SAndroid Build Coastguard Worker
1679*9e564957SAndroid Build Coastguard Worker memset(&fi, 0, sizeof(fi));
1680*9e564957SAndroid Build Coastguard Worker fi.flags = arg->flags;
1681*9e564957SAndroid Build Coastguard Worker
1682*9e564957SAndroid Build Coastguard Worker if (req->se->op.opendir)
1683*9e564957SAndroid Build Coastguard Worker req->se->op.opendir(req, nodeid, &fi);
1684*9e564957SAndroid Build Coastguard Worker else if (req->se->conn.want & FUSE_CAP_NO_OPENDIR_SUPPORT)
1685*9e564957SAndroid Build Coastguard Worker fuse_reply_err(req, ENOSYS);
1686*9e564957SAndroid Build Coastguard Worker else
1687*9e564957SAndroid Build Coastguard Worker fuse_reply_open(req, &fi);
1688*9e564957SAndroid Build Coastguard Worker }
1689*9e564957SAndroid Build Coastguard Worker
1690*9e564957SAndroid Build Coastguard Worker static void do_readdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1691*9e564957SAndroid Build Coastguard Worker {
1692*9e564957SAndroid Build Coastguard Worker struct fuse_read_in *arg = (struct fuse_read_in *) inarg;
1693*9e564957SAndroid Build Coastguard Worker struct fuse_file_info fi;
1694*9e564957SAndroid Build Coastguard Worker
1695*9e564957SAndroid Build Coastguard Worker memset(&fi, 0, sizeof(fi));
1696*9e564957SAndroid Build Coastguard Worker fi.fh = arg->fh;
1697*9e564957SAndroid Build Coastguard Worker
1698*9e564957SAndroid Build Coastguard Worker if (req->se->op.readdir)
1699*9e564957SAndroid Build Coastguard Worker req->se->op.readdir(req, nodeid, arg->size, arg->offset, &fi);
1700*9e564957SAndroid Build Coastguard Worker else
1701*9e564957SAndroid Build Coastguard Worker fuse_reply_err(req, ENOSYS);
1702*9e564957SAndroid Build Coastguard Worker }
1703*9e564957SAndroid Build Coastguard Worker
1704*9e564957SAndroid Build Coastguard Worker static void do_readdirplus(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1705*9e564957SAndroid Build Coastguard Worker {
1706*9e564957SAndroid Build Coastguard Worker struct fuse_read_in *arg = (struct fuse_read_in *) inarg;
1707*9e564957SAndroid Build Coastguard Worker struct fuse_file_info fi;
1708*9e564957SAndroid Build Coastguard Worker
1709*9e564957SAndroid Build Coastguard Worker memset(&fi, 0, sizeof(fi));
1710*9e564957SAndroid Build Coastguard Worker fi.fh = arg->fh;
1711*9e564957SAndroid Build Coastguard Worker
1712*9e564957SAndroid Build Coastguard Worker if (req->se->op.readdirplus)
1713*9e564957SAndroid Build Coastguard Worker req->se->op.readdirplus(req, nodeid, arg->size, arg->offset, &fi);
1714*9e564957SAndroid Build Coastguard Worker else
1715*9e564957SAndroid Build Coastguard Worker fuse_reply_err(req, ENOSYS);
1716*9e564957SAndroid Build Coastguard Worker }
1717*9e564957SAndroid Build Coastguard Worker
1718*9e564957SAndroid Build Coastguard Worker static void do_readdir_postfilter(fuse_req_t req, fuse_ino_t nodeid,
1719*9e564957SAndroid Build Coastguard Worker uint32_t error_in, const void *inarg,
1720*9e564957SAndroid Build Coastguard Worker size_t size) {
1721*9e564957SAndroid Build Coastguard Worker struct fuse_read_in *fri = (struct fuse_read_in *) inarg;
1722*9e564957SAndroid Build Coastguard Worker struct fuse_read_out *fro = (struct fuse_read_out *) (fri + 1);
1723*9e564957SAndroid Build Coastguard Worker struct fuse_dirent *dirents = (struct fuse_dirent *) (fro + 1);
1724*9e564957SAndroid Build Coastguard Worker struct fuse_file_info fi;
1725*9e564957SAndroid Build Coastguard Worker
1726*9e564957SAndroid Build Coastguard Worker memset(&fi, 0, sizeof(fi));
1727*9e564957SAndroid Build Coastguard Worker fi.fh = fri->fh;
1728*9e564957SAndroid Build Coastguard Worker
1729*9e564957SAndroid Build Coastguard Worker if (req->se->op.readdirpostfilter)
1730*9e564957SAndroid Build Coastguard Worker req->se->op.readdirpostfilter(req, nodeid, error_in, fri->offset,
1731*9e564957SAndroid Build Coastguard Worker fro->offset,
1732*9e564957SAndroid Build Coastguard Worker size - sizeof(*fri) - sizeof(*fro),
1733*9e564957SAndroid Build Coastguard Worker dirents, &fi);
1734*9e564957SAndroid Build Coastguard Worker else
1735*9e564957SAndroid Build Coastguard Worker fuse_reply_err(req, ENOSYS);
1736*9e564957SAndroid Build Coastguard Worker }
1737*9e564957SAndroid Build Coastguard Worker
1738*9e564957SAndroid Build Coastguard Worker static void do_releasedir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1739*9e564957SAndroid Build Coastguard Worker {
1740*9e564957SAndroid Build Coastguard Worker struct fuse_release_in *arg = (struct fuse_release_in *) inarg;
1741*9e564957SAndroid Build Coastguard Worker struct fuse_file_info fi;
1742*9e564957SAndroid Build Coastguard Worker
1743*9e564957SAndroid Build Coastguard Worker memset(&fi, 0, sizeof(fi));
1744*9e564957SAndroid Build Coastguard Worker fi.flags = arg->flags;
1745*9e564957SAndroid Build Coastguard Worker fi.fh = arg->fh;
1746*9e564957SAndroid Build Coastguard Worker
1747*9e564957SAndroid Build Coastguard Worker if (req->se->op.releasedir)
1748*9e564957SAndroid Build Coastguard Worker req->se->op.releasedir(req, nodeid, &fi);
1749*9e564957SAndroid Build Coastguard Worker else
1750*9e564957SAndroid Build Coastguard Worker fuse_reply_err(req, 0);
1751*9e564957SAndroid Build Coastguard Worker }
1752*9e564957SAndroid Build Coastguard Worker
1753*9e564957SAndroid Build Coastguard Worker static void do_fsyncdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1754*9e564957SAndroid Build Coastguard Worker {
1755*9e564957SAndroid Build Coastguard Worker struct fuse_fsync_in *arg = (struct fuse_fsync_in *) inarg;
1756*9e564957SAndroid Build Coastguard Worker struct fuse_file_info fi;
1757*9e564957SAndroid Build Coastguard Worker int datasync = arg->fsync_flags & 1;
1758*9e564957SAndroid Build Coastguard Worker
1759*9e564957SAndroid Build Coastguard Worker memset(&fi, 0, sizeof(fi));
1760*9e564957SAndroid Build Coastguard Worker fi.fh = arg->fh;
1761*9e564957SAndroid Build Coastguard Worker
1762*9e564957SAndroid Build Coastguard Worker if (req->se->op.fsyncdir)
1763*9e564957SAndroid Build Coastguard Worker req->se->op.fsyncdir(req, nodeid, datasync, &fi);
1764*9e564957SAndroid Build Coastguard Worker else
1765*9e564957SAndroid Build Coastguard Worker fuse_reply_err(req, ENOSYS);
1766*9e564957SAndroid Build Coastguard Worker }
1767*9e564957SAndroid Build Coastguard Worker
1768*9e564957SAndroid Build Coastguard Worker static void do_statfs(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1769*9e564957SAndroid Build Coastguard Worker {
1770*9e564957SAndroid Build Coastguard Worker (void) nodeid;
1771*9e564957SAndroid Build Coastguard Worker (void) inarg;
1772*9e564957SAndroid Build Coastguard Worker
1773*9e564957SAndroid Build Coastguard Worker if (req->se->op.statfs)
1774*9e564957SAndroid Build Coastguard Worker req->se->op.statfs(req, nodeid);
1775*9e564957SAndroid Build Coastguard Worker else {
1776*9e564957SAndroid Build Coastguard Worker struct statvfs buf = {
1777*9e564957SAndroid Build Coastguard Worker .f_namemax = 255,
1778*9e564957SAndroid Build Coastguard Worker .f_bsize = 512,
1779*9e564957SAndroid Build Coastguard Worker };
1780*9e564957SAndroid Build Coastguard Worker fuse_reply_statfs(req, &buf);
1781*9e564957SAndroid Build Coastguard Worker }
1782*9e564957SAndroid Build Coastguard Worker }
1783*9e564957SAndroid Build Coastguard Worker
1784*9e564957SAndroid Build Coastguard Worker static void do_setxattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1785*9e564957SAndroid Build Coastguard Worker {
1786*9e564957SAndroid Build Coastguard Worker struct fuse_session *se = req->se;
1787*9e564957SAndroid Build Coastguard Worker unsigned int xattr_ext = !!(se->conn.want & FUSE_CAP_SETXATTR_EXT);
1788*9e564957SAndroid Build Coastguard Worker struct fuse_setxattr_in *arg = (struct fuse_setxattr_in *) inarg;
1789*9e564957SAndroid Build Coastguard Worker char *name = xattr_ext ? PARAM(arg) :
1790*9e564957SAndroid Build Coastguard Worker (char *)arg + FUSE_COMPAT_SETXATTR_IN_SIZE;
1791*9e564957SAndroid Build Coastguard Worker char *value = name + strlen(name) + 1;
1792*9e564957SAndroid Build Coastguard Worker
1793*9e564957SAndroid Build Coastguard Worker /* XXX:The API should be extended to support extra_flags/setxattr_flags */
1794*9e564957SAndroid Build Coastguard Worker if (req->se->op.setxattr)
1795*9e564957SAndroid Build Coastguard Worker req->se->op.setxattr(req, nodeid, name, value, arg->size,
1796*9e564957SAndroid Build Coastguard Worker arg->flags);
1797*9e564957SAndroid Build Coastguard Worker else
1798*9e564957SAndroid Build Coastguard Worker fuse_reply_err(req, ENOSYS);
1799*9e564957SAndroid Build Coastguard Worker }
1800*9e564957SAndroid Build Coastguard Worker
1801*9e564957SAndroid Build Coastguard Worker static void do_getxattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1802*9e564957SAndroid Build Coastguard Worker {
1803*9e564957SAndroid Build Coastguard Worker struct fuse_getxattr_in *arg = (struct fuse_getxattr_in *) inarg;
1804*9e564957SAndroid Build Coastguard Worker
1805*9e564957SAndroid Build Coastguard Worker if (req->se->op.getxattr)
1806*9e564957SAndroid Build Coastguard Worker req->se->op.getxattr(req, nodeid, PARAM(arg), arg->size);
1807*9e564957SAndroid Build Coastguard Worker else
1808*9e564957SAndroid Build Coastguard Worker fuse_reply_err(req, ENOSYS);
1809*9e564957SAndroid Build Coastguard Worker }
1810*9e564957SAndroid Build Coastguard Worker
1811*9e564957SAndroid Build Coastguard Worker static void do_listxattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1812*9e564957SAndroid Build Coastguard Worker {
1813*9e564957SAndroid Build Coastguard Worker struct fuse_getxattr_in *arg = (struct fuse_getxattr_in *) inarg;
1814*9e564957SAndroid Build Coastguard Worker
1815*9e564957SAndroid Build Coastguard Worker if (req->se->op.listxattr)
1816*9e564957SAndroid Build Coastguard Worker req->se->op.listxattr(req, nodeid, arg->size);
1817*9e564957SAndroid Build Coastguard Worker else
1818*9e564957SAndroid Build Coastguard Worker fuse_reply_err(req, ENOSYS);
1819*9e564957SAndroid Build Coastguard Worker }
1820*9e564957SAndroid Build Coastguard Worker
1821*9e564957SAndroid Build Coastguard Worker static void do_removexattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1822*9e564957SAndroid Build Coastguard Worker {
1823*9e564957SAndroid Build Coastguard Worker char *name = (char *) inarg;
1824*9e564957SAndroid Build Coastguard Worker
1825*9e564957SAndroid Build Coastguard Worker if (req->se->op.removexattr)
1826*9e564957SAndroid Build Coastguard Worker req->se->op.removexattr(req, nodeid, name);
1827*9e564957SAndroid Build Coastguard Worker else
1828*9e564957SAndroid Build Coastguard Worker fuse_reply_err(req, ENOSYS);
1829*9e564957SAndroid Build Coastguard Worker }
1830*9e564957SAndroid Build Coastguard Worker
1831*9e564957SAndroid Build Coastguard Worker static void convert_fuse_file_lock(struct fuse_file_lock *fl,
1832*9e564957SAndroid Build Coastguard Worker struct flock *flock)
1833*9e564957SAndroid Build Coastguard Worker {
1834*9e564957SAndroid Build Coastguard Worker memset(flock, 0, sizeof(struct flock));
1835*9e564957SAndroid Build Coastguard Worker flock->l_type = fl->type;
1836*9e564957SAndroid Build Coastguard Worker flock->l_whence = SEEK_SET;
1837*9e564957SAndroid Build Coastguard Worker flock->l_start = fl->start;
1838*9e564957SAndroid Build Coastguard Worker if (fl->end == OFFSET_MAX)
1839*9e564957SAndroid Build Coastguard Worker flock->l_len = 0;
1840*9e564957SAndroid Build Coastguard Worker else
1841*9e564957SAndroid Build Coastguard Worker flock->l_len = fl->end - fl->start + 1;
1842*9e564957SAndroid Build Coastguard Worker flock->l_pid = fl->pid;
1843*9e564957SAndroid Build Coastguard Worker }
1844*9e564957SAndroid Build Coastguard Worker
1845*9e564957SAndroid Build Coastguard Worker static void do_getlk(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1846*9e564957SAndroid Build Coastguard Worker {
1847*9e564957SAndroid Build Coastguard Worker struct fuse_lk_in *arg = (struct fuse_lk_in *) inarg;
1848*9e564957SAndroid Build Coastguard Worker struct fuse_file_info fi;
1849*9e564957SAndroid Build Coastguard Worker struct flock flock;
1850*9e564957SAndroid Build Coastguard Worker
1851*9e564957SAndroid Build Coastguard Worker memset(&fi, 0, sizeof(fi));
1852*9e564957SAndroid Build Coastguard Worker fi.fh = arg->fh;
1853*9e564957SAndroid Build Coastguard Worker fi.lock_owner = arg->owner;
1854*9e564957SAndroid Build Coastguard Worker
1855*9e564957SAndroid Build Coastguard Worker convert_fuse_file_lock(&arg->lk, &flock);
1856*9e564957SAndroid Build Coastguard Worker if (req->se->op.getlk)
1857*9e564957SAndroid Build Coastguard Worker req->se->op.getlk(req, nodeid, &fi, &flock);
1858*9e564957SAndroid Build Coastguard Worker else
1859*9e564957SAndroid Build Coastguard Worker fuse_reply_err(req, ENOSYS);
1860*9e564957SAndroid Build Coastguard Worker }
1861*9e564957SAndroid Build Coastguard Worker
1862*9e564957SAndroid Build Coastguard Worker static void do_setlk_common(fuse_req_t req, fuse_ino_t nodeid,
1863*9e564957SAndroid Build Coastguard Worker const void *inarg, int sleep)
1864*9e564957SAndroid Build Coastguard Worker {
1865*9e564957SAndroid Build Coastguard Worker struct fuse_lk_in *arg = (struct fuse_lk_in *) inarg;
1866*9e564957SAndroid Build Coastguard Worker struct fuse_file_info fi;
1867*9e564957SAndroid Build Coastguard Worker struct flock flock;
1868*9e564957SAndroid Build Coastguard Worker
1869*9e564957SAndroid Build Coastguard Worker memset(&fi, 0, sizeof(fi));
1870*9e564957SAndroid Build Coastguard Worker fi.fh = arg->fh;
1871*9e564957SAndroid Build Coastguard Worker fi.lock_owner = arg->owner;
1872*9e564957SAndroid Build Coastguard Worker
1873*9e564957SAndroid Build Coastguard Worker if (arg->lk_flags & FUSE_LK_FLOCK) {
1874*9e564957SAndroid Build Coastguard Worker int op = 0;
1875*9e564957SAndroid Build Coastguard Worker
1876*9e564957SAndroid Build Coastguard Worker switch (arg->lk.type) {
1877*9e564957SAndroid Build Coastguard Worker case F_RDLCK:
1878*9e564957SAndroid Build Coastguard Worker op = LOCK_SH;
1879*9e564957SAndroid Build Coastguard Worker break;
1880*9e564957SAndroid Build Coastguard Worker case F_WRLCK:
1881*9e564957SAndroid Build Coastguard Worker op = LOCK_EX;
1882*9e564957SAndroid Build Coastguard Worker break;
1883*9e564957SAndroid Build Coastguard Worker case F_UNLCK:
1884*9e564957SAndroid Build Coastguard Worker op = LOCK_UN;
1885*9e564957SAndroid Build Coastguard Worker break;
1886*9e564957SAndroid Build Coastguard Worker }
1887*9e564957SAndroid Build Coastguard Worker if (!sleep)
1888*9e564957SAndroid Build Coastguard Worker op |= LOCK_NB;
1889*9e564957SAndroid Build Coastguard Worker
1890*9e564957SAndroid Build Coastguard Worker if (req->se->op.flock)
1891*9e564957SAndroid Build Coastguard Worker req->se->op.flock(req, nodeid, &fi, op);
1892*9e564957SAndroid Build Coastguard Worker else
1893*9e564957SAndroid Build Coastguard Worker fuse_reply_err(req, ENOSYS);
1894*9e564957SAndroid Build Coastguard Worker } else {
1895*9e564957SAndroid Build Coastguard Worker convert_fuse_file_lock(&arg->lk, &flock);
1896*9e564957SAndroid Build Coastguard Worker if (req->se->op.setlk)
1897*9e564957SAndroid Build Coastguard Worker req->se->op.setlk(req, nodeid, &fi, &flock, sleep);
1898*9e564957SAndroid Build Coastguard Worker else
1899*9e564957SAndroid Build Coastguard Worker fuse_reply_err(req, ENOSYS);
1900*9e564957SAndroid Build Coastguard Worker }
1901*9e564957SAndroid Build Coastguard Worker }
1902*9e564957SAndroid Build Coastguard Worker
1903*9e564957SAndroid Build Coastguard Worker static void do_setlk(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1904*9e564957SAndroid Build Coastguard Worker {
1905*9e564957SAndroid Build Coastguard Worker do_setlk_common(req, nodeid, inarg, 0);
1906*9e564957SAndroid Build Coastguard Worker }
1907*9e564957SAndroid Build Coastguard Worker
1908*9e564957SAndroid Build Coastguard Worker static void do_setlkw(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1909*9e564957SAndroid Build Coastguard Worker {
1910*9e564957SAndroid Build Coastguard Worker do_setlk_common(req, nodeid, inarg, 1);
1911*9e564957SAndroid Build Coastguard Worker }
1912*9e564957SAndroid Build Coastguard Worker
1913*9e564957SAndroid Build Coastguard Worker static int find_interrupted(struct fuse_session *se, struct fuse_req *req)
1914*9e564957SAndroid Build Coastguard Worker {
1915*9e564957SAndroid Build Coastguard Worker struct fuse_req *curr;
1916*9e564957SAndroid Build Coastguard Worker
1917*9e564957SAndroid Build Coastguard Worker for (curr = se->list.next; curr != &se->list; curr = curr->next) {
1918*9e564957SAndroid Build Coastguard Worker if (curr->unique == req->u.i.unique) {
1919*9e564957SAndroid Build Coastguard Worker fuse_interrupt_func_t func;
1920*9e564957SAndroid Build Coastguard Worker void *data;
1921*9e564957SAndroid Build Coastguard Worker
1922*9e564957SAndroid Build Coastguard Worker curr->ctr++;
1923*9e564957SAndroid Build Coastguard Worker pthread_mutex_unlock(&se->lock);
1924*9e564957SAndroid Build Coastguard Worker
1925*9e564957SAndroid Build Coastguard Worker /* Ugh, ugly locking */
1926*9e564957SAndroid Build Coastguard Worker pthread_mutex_lock(&curr->lock);
1927*9e564957SAndroid Build Coastguard Worker pthread_mutex_lock(&se->lock);
1928*9e564957SAndroid Build Coastguard Worker curr->interrupted = 1;
1929*9e564957SAndroid Build Coastguard Worker func = curr->u.ni.func;
1930*9e564957SAndroid Build Coastguard Worker data = curr->u.ni.data;
1931*9e564957SAndroid Build Coastguard Worker pthread_mutex_unlock(&se->lock);
1932*9e564957SAndroid Build Coastguard Worker if (func)
1933*9e564957SAndroid Build Coastguard Worker func(curr, data);
1934*9e564957SAndroid Build Coastguard Worker pthread_mutex_unlock(&curr->lock);
1935*9e564957SAndroid Build Coastguard Worker
1936*9e564957SAndroid Build Coastguard Worker pthread_mutex_lock(&se->lock);
1937*9e564957SAndroid Build Coastguard Worker curr->ctr--;
1938*9e564957SAndroid Build Coastguard Worker if (!curr->ctr) {
1939*9e564957SAndroid Build Coastguard Worker destroy_req(curr);
1940*9e564957SAndroid Build Coastguard Worker }
1941*9e564957SAndroid Build Coastguard Worker
1942*9e564957SAndroid Build Coastguard Worker return 1;
1943*9e564957SAndroid Build Coastguard Worker }
1944*9e564957SAndroid Build Coastguard Worker }
1945*9e564957SAndroid Build Coastguard Worker for (curr = se->interrupts.next; curr != &se->interrupts;
1946*9e564957SAndroid Build Coastguard Worker curr = curr->next) {
1947*9e564957SAndroid Build Coastguard Worker if (curr->u.i.unique == req->u.i.unique)
1948*9e564957SAndroid Build Coastguard Worker return 1;
1949*9e564957SAndroid Build Coastguard Worker }
1950*9e564957SAndroid Build Coastguard Worker return 0;
1951*9e564957SAndroid Build Coastguard Worker }
1952*9e564957SAndroid Build Coastguard Worker
1953*9e564957SAndroid Build Coastguard Worker static void do_interrupt(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1954*9e564957SAndroid Build Coastguard Worker {
1955*9e564957SAndroid Build Coastguard Worker struct fuse_interrupt_in *arg = (struct fuse_interrupt_in *) inarg;
1956*9e564957SAndroid Build Coastguard Worker struct fuse_session *se = req->se;
1957*9e564957SAndroid Build Coastguard Worker
1958*9e564957SAndroid Build Coastguard Worker (void) nodeid;
1959*9e564957SAndroid Build Coastguard Worker if (se->debug)
1960*9e564957SAndroid Build Coastguard Worker fuse_log(FUSE_LOG_DEBUG, "INTERRUPT: %llu\n",
1961*9e564957SAndroid Build Coastguard Worker (unsigned long long) arg->unique);
1962*9e564957SAndroid Build Coastguard Worker
1963*9e564957SAndroid Build Coastguard Worker req->u.i.unique = arg->unique;
1964*9e564957SAndroid Build Coastguard Worker
1965*9e564957SAndroid Build Coastguard Worker pthread_mutex_lock(&se->lock);
1966*9e564957SAndroid Build Coastguard Worker if (find_interrupted(se, req)) {
1967*9e564957SAndroid Build Coastguard Worker fuse_chan_put(req->ch);
1968*9e564957SAndroid Build Coastguard Worker req->ch = NULL;
1969*9e564957SAndroid Build Coastguard Worker destroy_req(req);
1970*9e564957SAndroid Build Coastguard Worker } else
1971*9e564957SAndroid Build Coastguard Worker list_add_req(req, &se->interrupts);
1972*9e564957SAndroid Build Coastguard Worker pthread_mutex_unlock(&se->lock);
1973*9e564957SAndroid Build Coastguard Worker }
1974*9e564957SAndroid Build Coastguard Worker
1975*9e564957SAndroid Build Coastguard Worker static struct fuse_req *check_interrupt(struct fuse_session *se,
1976*9e564957SAndroid Build Coastguard Worker struct fuse_req *req)
1977*9e564957SAndroid Build Coastguard Worker {
1978*9e564957SAndroid Build Coastguard Worker struct fuse_req *curr;
1979*9e564957SAndroid Build Coastguard Worker
1980*9e564957SAndroid Build Coastguard Worker for (curr = se->interrupts.next; curr != &se->interrupts;
1981*9e564957SAndroid Build Coastguard Worker curr = curr->next) {
1982*9e564957SAndroid Build Coastguard Worker if (curr->u.i.unique == req->unique) {
1983*9e564957SAndroid Build Coastguard Worker req->interrupted = 1;
1984*9e564957SAndroid Build Coastguard Worker list_del_req(curr);
1985*9e564957SAndroid Build Coastguard Worker fuse_chan_put(curr->ch);
1986*9e564957SAndroid Build Coastguard Worker curr->ch = NULL;
1987*9e564957SAndroid Build Coastguard Worker destroy_req(curr);
1988*9e564957SAndroid Build Coastguard Worker return NULL;
1989*9e564957SAndroid Build Coastguard Worker }
1990*9e564957SAndroid Build Coastguard Worker }
1991*9e564957SAndroid Build Coastguard Worker curr = se->interrupts.next;
1992*9e564957SAndroid Build Coastguard Worker if (curr != &se->interrupts) {
1993*9e564957SAndroid Build Coastguard Worker list_del_req(curr);
1994*9e564957SAndroid Build Coastguard Worker list_init_req(curr);
1995*9e564957SAndroid Build Coastguard Worker return curr;
1996*9e564957SAndroid Build Coastguard Worker } else
1997*9e564957SAndroid Build Coastguard Worker return NULL;
1998*9e564957SAndroid Build Coastguard Worker }
1999*9e564957SAndroid Build Coastguard Worker
2000*9e564957SAndroid Build Coastguard Worker static void do_bmap(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
2001*9e564957SAndroid Build Coastguard Worker {
2002*9e564957SAndroid Build Coastguard Worker struct fuse_bmap_in *arg = (struct fuse_bmap_in *) inarg;
2003*9e564957SAndroid Build Coastguard Worker
2004*9e564957SAndroid Build Coastguard Worker if (req->se->op.bmap)
2005*9e564957SAndroid Build Coastguard Worker req->se->op.bmap(req, nodeid, arg->blocksize, arg->block);
2006*9e564957SAndroid Build Coastguard Worker else
2007*9e564957SAndroid Build Coastguard Worker fuse_reply_err(req, ENOSYS);
2008*9e564957SAndroid Build Coastguard Worker }
2009*9e564957SAndroid Build Coastguard Worker
2010*9e564957SAndroid Build Coastguard Worker static void do_ioctl(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
2011*9e564957SAndroid Build Coastguard Worker {
2012*9e564957SAndroid Build Coastguard Worker struct fuse_ioctl_in *arg = (struct fuse_ioctl_in *) inarg;
2013*9e564957SAndroid Build Coastguard Worker unsigned int flags = arg->flags;
2014*9e564957SAndroid Build Coastguard Worker void *in_buf = arg->in_size ? PARAM(arg) : NULL;
2015*9e564957SAndroid Build Coastguard Worker struct fuse_file_info fi;
2016*9e564957SAndroid Build Coastguard Worker
2017*9e564957SAndroid Build Coastguard Worker if (flags & FUSE_IOCTL_DIR &&
2018*9e564957SAndroid Build Coastguard Worker !(req->se->conn.want & FUSE_CAP_IOCTL_DIR)) {
2019*9e564957SAndroid Build Coastguard Worker fuse_reply_err(req, ENOTTY);
2020*9e564957SAndroid Build Coastguard Worker return;
2021*9e564957SAndroid Build Coastguard Worker }
2022*9e564957SAndroid Build Coastguard Worker
2023*9e564957SAndroid Build Coastguard Worker memset(&fi, 0, sizeof(fi));
2024*9e564957SAndroid Build Coastguard Worker fi.fh = arg->fh;
2025*9e564957SAndroid Build Coastguard Worker
2026*9e564957SAndroid Build Coastguard Worker if (sizeof(void *) == 4 && req->se->conn.proto_minor >= 16 &&
2027*9e564957SAndroid Build Coastguard Worker !(flags & FUSE_IOCTL_32BIT)) {
2028*9e564957SAndroid Build Coastguard Worker req->ioctl_64bit = 1;
2029*9e564957SAndroid Build Coastguard Worker }
2030*9e564957SAndroid Build Coastguard Worker
2031*9e564957SAndroid Build Coastguard Worker if (req->se->op.ioctl)
2032*9e564957SAndroid Build Coastguard Worker req->se->op.ioctl(req, nodeid, arg->cmd,
2033*9e564957SAndroid Build Coastguard Worker (void *)(uintptr_t)arg->arg, &fi, flags,
2034*9e564957SAndroid Build Coastguard Worker in_buf, arg->in_size, arg->out_size);
2035*9e564957SAndroid Build Coastguard Worker else
2036*9e564957SAndroid Build Coastguard Worker fuse_reply_err(req, ENOSYS);
2037*9e564957SAndroid Build Coastguard Worker }
2038*9e564957SAndroid Build Coastguard Worker
2039*9e564957SAndroid Build Coastguard Worker void fuse_pollhandle_destroy(struct fuse_pollhandle *ph)
2040*9e564957SAndroid Build Coastguard Worker {
2041*9e564957SAndroid Build Coastguard Worker free(ph);
2042*9e564957SAndroid Build Coastguard Worker }
2043*9e564957SAndroid Build Coastguard Worker
2044*9e564957SAndroid Build Coastguard Worker static void do_poll(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
2045*9e564957SAndroid Build Coastguard Worker {
2046*9e564957SAndroid Build Coastguard Worker struct fuse_poll_in *arg = (struct fuse_poll_in *) inarg;
2047*9e564957SAndroid Build Coastguard Worker struct fuse_file_info fi;
2048*9e564957SAndroid Build Coastguard Worker
2049*9e564957SAndroid Build Coastguard Worker memset(&fi, 0, sizeof(fi));
2050*9e564957SAndroid Build Coastguard Worker fi.fh = arg->fh;
2051*9e564957SAndroid Build Coastguard Worker fi.poll_events = arg->events;
2052*9e564957SAndroid Build Coastguard Worker
2053*9e564957SAndroid Build Coastguard Worker if (req->se->op.poll) {
2054*9e564957SAndroid Build Coastguard Worker struct fuse_pollhandle *ph = NULL;
2055*9e564957SAndroid Build Coastguard Worker
2056*9e564957SAndroid Build Coastguard Worker if (arg->flags & FUSE_POLL_SCHEDULE_NOTIFY) {
2057*9e564957SAndroid Build Coastguard Worker ph = malloc(sizeof(struct fuse_pollhandle));
2058*9e564957SAndroid Build Coastguard Worker if (ph == NULL) {
2059*9e564957SAndroid Build Coastguard Worker fuse_reply_err(req, ENOMEM);
2060*9e564957SAndroid Build Coastguard Worker return;
2061*9e564957SAndroid Build Coastguard Worker }
2062*9e564957SAndroid Build Coastguard Worker ph->kh = arg->kh;
2063*9e564957SAndroid Build Coastguard Worker ph->se = req->se;
2064*9e564957SAndroid Build Coastguard Worker }
2065*9e564957SAndroid Build Coastguard Worker
2066*9e564957SAndroid Build Coastguard Worker req->se->op.poll(req, nodeid, &fi, ph);
2067*9e564957SAndroid Build Coastguard Worker } else {
2068*9e564957SAndroid Build Coastguard Worker fuse_reply_err(req, ENOSYS);
2069*9e564957SAndroid Build Coastguard Worker }
2070*9e564957SAndroid Build Coastguard Worker }
2071*9e564957SAndroid Build Coastguard Worker
2072*9e564957SAndroid Build Coastguard Worker static void do_fallocate(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
2073*9e564957SAndroid Build Coastguard Worker {
2074*9e564957SAndroid Build Coastguard Worker struct fuse_fallocate_in *arg = (struct fuse_fallocate_in *) inarg;
2075*9e564957SAndroid Build Coastguard Worker struct fuse_file_info fi;
2076*9e564957SAndroid Build Coastguard Worker
2077*9e564957SAndroid Build Coastguard Worker memset(&fi, 0, sizeof(fi));
2078*9e564957SAndroid Build Coastguard Worker fi.fh = arg->fh;
2079*9e564957SAndroid Build Coastguard Worker
2080*9e564957SAndroid Build Coastguard Worker if (req->se->op.fallocate)
2081*9e564957SAndroid Build Coastguard Worker req->se->op.fallocate(req, nodeid, arg->mode, arg->offset, arg->length, &fi);
2082*9e564957SAndroid Build Coastguard Worker else
2083*9e564957SAndroid Build Coastguard Worker fuse_reply_err(req, ENOSYS);
2084*9e564957SAndroid Build Coastguard Worker }
2085*9e564957SAndroid Build Coastguard Worker
2086*9e564957SAndroid Build Coastguard Worker static void do_copy_file_range(fuse_req_t req, fuse_ino_t nodeid_in, const void *inarg)
2087*9e564957SAndroid Build Coastguard Worker {
2088*9e564957SAndroid Build Coastguard Worker struct fuse_copy_file_range_in *arg = (struct fuse_copy_file_range_in *) inarg;
2089*9e564957SAndroid Build Coastguard Worker struct fuse_file_info fi_in, fi_out;
2090*9e564957SAndroid Build Coastguard Worker
2091*9e564957SAndroid Build Coastguard Worker memset(&fi_in, 0, sizeof(fi_in));
2092*9e564957SAndroid Build Coastguard Worker fi_in.fh = arg->fh_in;
2093*9e564957SAndroid Build Coastguard Worker
2094*9e564957SAndroid Build Coastguard Worker memset(&fi_out, 0, sizeof(fi_out));
2095*9e564957SAndroid Build Coastguard Worker fi_out.fh = arg->fh_out;
2096*9e564957SAndroid Build Coastguard Worker
2097*9e564957SAndroid Build Coastguard Worker
2098*9e564957SAndroid Build Coastguard Worker if (req->se->op.copy_file_range)
2099*9e564957SAndroid Build Coastguard Worker req->se->op.copy_file_range(req, nodeid_in, arg->off_in,
2100*9e564957SAndroid Build Coastguard Worker &fi_in, arg->nodeid_out,
2101*9e564957SAndroid Build Coastguard Worker arg->off_out, &fi_out, arg->len,
2102*9e564957SAndroid Build Coastguard Worker arg->flags);
2103*9e564957SAndroid Build Coastguard Worker else
2104*9e564957SAndroid Build Coastguard Worker fuse_reply_err(req, ENOSYS);
2105*9e564957SAndroid Build Coastguard Worker }
2106*9e564957SAndroid Build Coastguard Worker
2107*9e564957SAndroid Build Coastguard Worker static void do_lseek(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
2108*9e564957SAndroid Build Coastguard Worker {
2109*9e564957SAndroid Build Coastguard Worker struct fuse_lseek_in *arg = (struct fuse_lseek_in *) inarg;
2110*9e564957SAndroid Build Coastguard Worker struct fuse_file_info fi;
2111*9e564957SAndroid Build Coastguard Worker
2112*9e564957SAndroid Build Coastguard Worker memset(&fi, 0, sizeof(fi));
2113*9e564957SAndroid Build Coastguard Worker fi.fh = arg->fh;
2114*9e564957SAndroid Build Coastguard Worker
2115*9e564957SAndroid Build Coastguard Worker if (req->se->op.lseek)
2116*9e564957SAndroid Build Coastguard Worker req->se->op.lseek(req, nodeid, arg->offset, arg->whence, &fi);
2117*9e564957SAndroid Build Coastguard Worker else
2118*9e564957SAndroid Build Coastguard Worker fuse_reply_err(req, ENOSYS);
2119*9e564957SAndroid Build Coastguard Worker }
2120*9e564957SAndroid Build Coastguard Worker
2121*9e564957SAndroid Build Coastguard Worker /* Prevent bogus data races (bogus since "init" is called before
2122*9e564957SAndroid Build Coastguard Worker * multi-threading becomes relevant */
2123*9e564957SAndroid Build Coastguard Worker static __attribute__((no_sanitize("thread")))
2124*9e564957SAndroid Build Coastguard Worker void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
2125*9e564957SAndroid Build Coastguard Worker {
2126*9e564957SAndroid Build Coastguard Worker struct fuse_init_in *arg = (struct fuse_init_in *) inarg;
2127*9e564957SAndroid Build Coastguard Worker struct fuse_init_out outarg;
2128*9e564957SAndroid Build Coastguard Worker struct fuse_session *se = req->se;
2129*9e564957SAndroid Build Coastguard Worker size_t bufsize = se->bufsize;
2130*9e564957SAndroid Build Coastguard Worker size_t outargsize = sizeof(outarg);
2131*9e564957SAndroid Build Coastguard Worker uint64_t inargflags = 0;
2132*9e564957SAndroid Build Coastguard Worker uint64_t outargflags = 0;
2133*9e564957SAndroid Build Coastguard Worker (void) nodeid;
2134*9e564957SAndroid Build Coastguard Worker if (se->debug) {
2135*9e564957SAndroid Build Coastguard Worker fuse_log(FUSE_LOG_DEBUG, "INIT: %u.%u\n", arg->major, arg->minor);
2136*9e564957SAndroid Build Coastguard Worker if (arg->major == 7 && arg->minor >= 6) {
2137*9e564957SAndroid Build Coastguard Worker fuse_log(FUSE_LOG_DEBUG, "flags=0x%08x\n", arg->flags);
2138*9e564957SAndroid Build Coastguard Worker fuse_log(FUSE_LOG_DEBUG, "max_readahead=0x%08x\n",
2139*9e564957SAndroid Build Coastguard Worker arg->max_readahead);
2140*9e564957SAndroid Build Coastguard Worker }
2141*9e564957SAndroid Build Coastguard Worker }
2142*9e564957SAndroid Build Coastguard Worker se->conn.proto_major = arg->major;
2143*9e564957SAndroid Build Coastguard Worker se->conn.proto_minor = arg->minor;
2144*9e564957SAndroid Build Coastguard Worker se->conn.capable = 0;
2145*9e564957SAndroid Build Coastguard Worker se->conn.want = 0;
2146*9e564957SAndroid Build Coastguard Worker
2147*9e564957SAndroid Build Coastguard Worker memset(&outarg, 0, sizeof(outarg));
2148*9e564957SAndroid Build Coastguard Worker outarg.major = FUSE_KERNEL_VERSION;
2149*9e564957SAndroid Build Coastguard Worker outarg.minor = FUSE_KERNEL_MINOR_VERSION;
2150*9e564957SAndroid Build Coastguard Worker
2151*9e564957SAndroid Build Coastguard Worker if (arg->major < 7) {
2152*9e564957SAndroid Build Coastguard Worker fuse_log(FUSE_LOG_ERR, "fuse: unsupported protocol version: %u.%u\n",
2153*9e564957SAndroid Build Coastguard Worker arg->major, arg->minor);
2154*9e564957SAndroid Build Coastguard Worker fuse_reply_err(req, EPROTO);
2155*9e564957SAndroid Build Coastguard Worker return;
2156*9e564957SAndroid Build Coastguard Worker }
2157*9e564957SAndroid Build Coastguard Worker
2158*9e564957SAndroid Build Coastguard Worker if (arg->major > 7) {
2159*9e564957SAndroid Build Coastguard Worker /* Wait for a second INIT request with a 7.X version */
2160*9e564957SAndroid Build Coastguard Worker send_reply_ok(req, &outarg, sizeof(outarg));
2161*9e564957SAndroid Build Coastguard Worker return;
2162*9e564957SAndroid Build Coastguard Worker }
2163*9e564957SAndroid Build Coastguard Worker
2164*9e564957SAndroid Build Coastguard Worker if (arg->minor >= 6) {
2165*9e564957SAndroid Build Coastguard Worker if (arg->max_readahead < se->conn.max_readahead)
2166*9e564957SAndroid Build Coastguard Worker se->conn.max_readahead = arg->max_readahead;
2167*9e564957SAndroid Build Coastguard Worker inargflags = arg->flags;
2168*9e564957SAndroid Build Coastguard Worker if (inargflags & FUSE_INIT_EXT)
2169*9e564957SAndroid Build Coastguard Worker inargflags = inargflags | (uint64_t) arg->flags2 << 32;
2170*9e564957SAndroid Build Coastguard Worker if (inargflags & FUSE_ASYNC_READ)
2171*9e564957SAndroid Build Coastguard Worker se->conn.capable |= FUSE_CAP_ASYNC_READ;
2172*9e564957SAndroid Build Coastguard Worker if (inargflags & FUSE_POSIX_LOCKS)
2173*9e564957SAndroid Build Coastguard Worker se->conn.capable |= FUSE_CAP_POSIX_LOCKS;
2174*9e564957SAndroid Build Coastguard Worker if (inargflags & FUSE_ATOMIC_O_TRUNC)
2175*9e564957SAndroid Build Coastguard Worker se->conn.capable |= FUSE_CAP_ATOMIC_O_TRUNC;
2176*9e564957SAndroid Build Coastguard Worker if (inargflags & FUSE_EXPORT_SUPPORT)
2177*9e564957SAndroid Build Coastguard Worker se->conn.capable |= FUSE_CAP_EXPORT_SUPPORT;
2178*9e564957SAndroid Build Coastguard Worker if (inargflags & FUSE_DONT_MASK)
2179*9e564957SAndroid Build Coastguard Worker se->conn.capable |= FUSE_CAP_DONT_MASK;
2180*9e564957SAndroid Build Coastguard Worker if (inargflags & FUSE_FLOCK_LOCKS)
2181*9e564957SAndroid Build Coastguard Worker se->conn.capable |= FUSE_CAP_FLOCK_LOCKS;
2182*9e564957SAndroid Build Coastguard Worker if (inargflags & FUSE_AUTO_INVAL_DATA)
2183*9e564957SAndroid Build Coastguard Worker se->conn.capable |= FUSE_CAP_AUTO_INVAL_DATA;
2184*9e564957SAndroid Build Coastguard Worker if (inargflags & FUSE_DO_READDIRPLUS)
2185*9e564957SAndroid Build Coastguard Worker se->conn.capable |= FUSE_CAP_READDIRPLUS;
2186*9e564957SAndroid Build Coastguard Worker if (inargflags & FUSE_READDIRPLUS_AUTO)
2187*9e564957SAndroid Build Coastguard Worker se->conn.capable |= FUSE_CAP_READDIRPLUS_AUTO;
2188*9e564957SAndroid Build Coastguard Worker if (inargflags & FUSE_ASYNC_DIO)
2189*9e564957SAndroid Build Coastguard Worker se->conn.capable |= FUSE_CAP_ASYNC_DIO;
2190*9e564957SAndroid Build Coastguard Worker if (inargflags & FUSE_WRITEBACK_CACHE)
2191*9e564957SAndroid Build Coastguard Worker se->conn.capable |= FUSE_CAP_WRITEBACK_CACHE;
2192*9e564957SAndroid Build Coastguard Worker if (inargflags & FUSE_NO_OPEN_SUPPORT)
2193*9e564957SAndroid Build Coastguard Worker se->conn.capable |= FUSE_CAP_NO_OPEN_SUPPORT;
2194*9e564957SAndroid Build Coastguard Worker if (inargflags & FUSE_PARALLEL_DIROPS)
2195*9e564957SAndroid Build Coastguard Worker se->conn.capable |= FUSE_CAP_PARALLEL_DIROPS;
2196*9e564957SAndroid Build Coastguard Worker if (inargflags & FUSE_POSIX_ACL)
2197*9e564957SAndroid Build Coastguard Worker se->conn.capable |= FUSE_CAP_POSIX_ACL;
2198*9e564957SAndroid Build Coastguard Worker if (inargflags & FUSE_HANDLE_KILLPRIV)
2199*9e564957SAndroid Build Coastguard Worker se->conn.capable |= FUSE_CAP_HANDLE_KILLPRIV;
2200*9e564957SAndroid Build Coastguard Worker if (inargflags & FUSE_HANDLE_KILLPRIV_V2)
2201*9e564957SAndroid Build Coastguard Worker se->conn.capable |= FUSE_CAP_HANDLE_KILLPRIV_V2;
2202*9e564957SAndroid Build Coastguard Worker if (inargflags & FUSE_CACHE_SYMLINKS)
2203*9e564957SAndroid Build Coastguard Worker se->conn.capable |= FUSE_CAP_CACHE_SYMLINKS;
2204*9e564957SAndroid Build Coastguard Worker if (inargflags & FUSE_NO_OPENDIR_SUPPORT)
2205*9e564957SAndroid Build Coastguard Worker se->conn.capable |= FUSE_CAP_NO_OPENDIR_SUPPORT;
2206*9e564957SAndroid Build Coastguard Worker if (inargflags & FUSE_EXPLICIT_INVAL_DATA)
2207*9e564957SAndroid Build Coastguard Worker se->conn.capable |= FUSE_CAP_EXPLICIT_INVAL_DATA;
2208*9e564957SAndroid Build Coastguard Worker if (inargflags & FUSE_SETXATTR_EXT)
2209*9e564957SAndroid Build Coastguard Worker se->conn.capable |= FUSE_CAP_SETXATTR_EXT;
2210*9e564957SAndroid Build Coastguard Worker if (!(inargflags & FUSE_MAX_PAGES)) {
2211*9e564957SAndroid Build Coastguard Worker size_t max_bufsize =
2212*9e564957SAndroid Build Coastguard Worker FUSE_DEFAULT_MAX_PAGES_PER_REQ * getpagesize()
2213*9e564957SAndroid Build Coastguard Worker + FUSE_BUFFER_HEADER_SIZE;
2214*9e564957SAndroid Build Coastguard Worker if (bufsize > max_bufsize) {
2215*9e564957SAndroid Build Coastguard Worker bufsize = max_bufsize;
2216*9e564957SAndroid Build Coastguard Worker }
2217*9e564957SAndroid Build Coastguard Worker }
2218*9e564957SAndroid Build Coastguard Worker if (inargflags & FUSE_DIRECT_IO_ALLOW_MMAP)
2219*9e564957SAndroid Build Coastguard Worker se->conn.capable |= FUSE_CAP_DIRECT_IO_ALLOW_MMAP;
2220*9e564957SAndroid Build Coastguard Worker if (arg->minor >= 38 || (inargflags & FUSE_HAS_EXPIRE_ONLY))
2221*9e564957SAndroid Build Coastguard Worker se->conn.capable |= FUSE_CAP_EXPIRE_ONLY;
2222*9e564957SAndroid Build Coastguard Worker if (inargflags & FUSE_PASSTHROUGH_UPSTREAM)
2223*9e564957SAndroid Build Coastguard Worker se->conn.capable |= FUSE_CAP_PASSTHROUGH_UPSTREAM;
2224*9e564957SAndroid Build Coastguard Worker if (inargflags & FUSE_INIT_EXT) {
2225*9e564957SAndroid Build Coastguard Worker if (inargflags & (1ULL << 63))
2226*9e564957SAndroid Build Coastguard Worker se->conn.capable |= FUSE_CAP_PASSTHROUGH;
2227*9e564957SAndroid Build Coastguard Worker } else {
2228*9e564957SAndroid Build Coastguard Worker if (inargflags & (1 << 31))
2229*9e564957SAndroid Build Coastguard Worker se->conn.capable |= FUSE_CAP_PASSTHROUGH;
2230*9e564957SAndroid Build Coastguard Worker }
2231*9e564957SAndroid Build Coastguard Worker } else {
2232*9e564957SAndroid Build Coastguard Worker se->conn.max_readahead = 0;
2233*9e564957SAndroid Build Coastguard Worker }
2234*9e564957SAndroid Build Coastguard Worker
2235*9e564957SAndroid Build Coastguard Worker if (se->conn.proto_minor >= 14) {
2236*9e564957SAndroid Build Coastguard Worker #ifdef HAVE_SPLICE
2237*9e564957SAndroid Build Coastguard Worker #ifdef HAVE_VMSPLICE
2238*9e564957SAndroid Build Coastguard Worker if ((se->io == NULL) || (se->io->splice_send != NULL)) {
2239*9e564957SAndroid Build Coastguard Worker se->conn.capable |= FUSE_CAP_SPLICE_WRITE | FUSE_CAP_SPLICE_MOVE;
2240*9e564957SAndroid Build Coastguard Worker }
2241*9e564957SAndroid Build Coastguard Worker #endif
2242*9e564957SAndroid Build Coastguard Worker if ((se->io == NULL) || (se->io->splice_receive != NULL)) {
2243*9e564957SAndroid Build Coastguard Worker se->conn.capable |= FUSE_CAP_SPLICE_READ;
2244*9e564957SAndroid Build Coastguard Worker }
2245*9e564957SAndroid Build Coastguard Worker #endif
2246*9e564957SAndroid Build Coastguard Worker }
2247*9e564957SAndroid Build Coastguard Worker if (se->conn.proto_minor >= 18)
2248*9e564957SAndroid Build Coastguard Worker se->conn.capable |= FUSE_CAP_IOCTL_DIR;
2249*9e564957SAndroid Build Coastguard Worker
2250*9e564957SAndroid Build Coastguard Worker /* Default settings for modern filesystems.
2251*9e564957SAndroid Build Coastguard Worker *
2252*9e564957SAndroid Build Coastguard Worker * Most of these capabilities were disabled by default in
2253*9e564957SAndroid Build Coastguard Worker * libfuse2 for backwards compatibility reasons. In libfuse3,
2254*9e564957SAndroid Build Coastguard Worker * we can finally enable them by default (as long as they're
2255*9e564957SAndroid Build Coastguard Worker * supported by the kernel).
2256*9e564957SAndroid Build Coastguard Worker */
2257*9e564957SAndroid Build Coastguard Worker #define LL_SET_DEFAULT(cond, cap) \
2258*9e564957SAndroid Build Coastguard Worker if ((cond) && (se->conn.capable & (cap))) \
2259*9e564957SAndroid Build Coastguard Worker se->conn.want |= (cap)
2260*9e564957SAndroid Build Coastguard Worker LL_SET_DEFAULT(1, FUSE_CAP_ASYNC_READ);
2261*9e564957SAndroid Build Coastguard Worker LL_SET_DEFAULT(1, FUSE_CAP_AUTO_INVAL_DATA);
2262*9e564957SAndroid Build Coastguard Worker LL_SET_DEFAULT(1, FUSE_CAP_ASYNC_DIO);
2263*9e564957SAndroid Build Coastguard Worker LL_SET_DEFAULT(1, FUSE_CAP_IOCTL_DIR);
2264*9e564957SAndroid Build Coastguard Worker LL_SET_DEFAULT(1, FUSE_CAP_ATOMIC_O_TRUNC);
2265*9e564957SAndroid Build Coastguard Worker LL_SET_DEFAULT(se->op.write_buf, FUSE_CAP_SPLICE_READ);
2266*9e564957SAndroid Build Coastguard Worker LL_SET_DEFAULT(se->op.getlk && se->op.setlk,
2267*9e564957SAndroid Build Coastguard Worker FUSE_CAP_POSIX_LOCKS);
2268*9e564957SAndroid Build Coastguard Worker LL_SET_DEFAULT(se->op.flock, FUSE_CAP_FLOCK_LOCKS);
2269*9e564957SAndroid Build Coastguard Worker LL_SET_DEFAULT(se->op.readdirplus, FUSE_CAP_READDIRPLUS);
2270*9e564957SAndroid Build Coastguard Worker LL_SET_DEFAULT(se->op.readdirplus && se->op.readdir,
2271*9e564957SAndroid Build Coastguard Worker FUSE_CAP_READDIRPLUS_AUTO);
2272*9e564957SAndroid Build Coastguard Worker
2273*9e564957SAndroid Build Coastguard Worker /* This could safely become default, but libfuse needs an API extension
2274*9e564957SAndroid Build Coastguard Worker * to support it
2275*9e564957SAndroid Build Coastguard Worker * LL_SET_DEFAULT(1, FUSE_CAP_SETXATTR_EXT);
2276*9e564957SAndroid Build Coastguard Worker */
2277*9e564957SAndroid Build Coastguard Worker
2278*9e564957SAndroid Build Coastguard Worker se->conn.time_gran = 1;
2279*9e564957SAndroid Build Coastguard Worker
2280*9e564957SAndroid Build Coastguard Worker if (bufsize < FUSE_MIN_READ_BUFFER) {
2281*9e564957SAndroid Build Coastguard Worker fuse_log(FUSE_LOG_ERR, "fuse: warning: buffer size too small: %zu\n",
2282*9e564957SAndroid Build Coastguard Worker bufsize);
2283*9e564957SAndroid Build Coastguard Worker bufsize = FUSE_MIN_READ_BUFFER;
2284*9e564957SAndroid Build Coastguard Worker }
2285*9e564957SAndroid Build Coastguard Worker se->bufsize = bufsize;
2286*9e564957SAndroid Build Coastguard Worker
2287*9e564957SAndroid Build Coastguard Worker se->got_init = 1;
2288*9e564957SAndroid Build Coastguard Worker if (se->op.init)
2289*9e564957SAndroid Build Coastguard Worker se->op.init(se->userdata, &se->conn);
2290*9e564957SAndroid Build Coastguard Worker
2291*9e564957SAndroid Build Coastguard Worker if (se->conn.max_write > bufsize - FUSE_BUFFER_HEADER_SIZE)
2292*9e564957SAndroid Build Coastguard Worker se->conn.max_write = bufsize - FUSE_BUFFER_HEADER_SIZE;
2293*9e564957SAndroid Build Coastguard Worker
2294*9e564957SAndroid Build Coastguard Worker if (se->conn.want & (~se->conn.capable)) {
2295*9e564957SAndroid Build Coastguard Worker fuse_log(FUSE_LOG_ERR, "fuse: error: filesystem requested capabilities "
2296*9e564957SAndroid Build Coastguard Worker "0x%x that are not supported by kernel, aborting.\n",
2297*9e564957SAndroid Build Coastguard Worker se->conn.want & (~se->conn.capable));
2298*9e564957SAndroid Build Coastguard Worker fuse_reply_err(req, EPROTO);
2299*9e564957SAndroid Build Coastguard Worker se->error = -EPROTO;
2300*9e564957SAndroid Build Coastguard Worker fuse_session_exit(se);
2301*9e564957SAndroid Build Coastguard Worker return;
2302*9e564957SAndroid Build Coastguard Worker }
2303*9e564957SAndroid Build Coastguard Worker
2304*9e564957SAndroid Build Coastguard Worker unsigned max_read_mo = get_max_read(se->mo);
2305*9e564957SAndroid Build Coastguard Worker if (se->conn.max_read != max_read_mo) {
2306*9e564957SAndroid Build Coastguard Worker fuse_log(FUSE_LOG_ERR, "fuse: error: init() and fuse_session_new() "
2307*9e564957SAndroid Build Coastguard Worker "requested different maximum read size (%u vs %u)\n",
2308*9e564957SAndroid Build Coastguard Worker se->conn.max_read, max_read_mo);
2309*9e564957SAndroid Build Coastguard Worker fuse_reply_err(req, EPROTO);
2310*9e564957SAndroid Build Coastguard Worker se->error = -EPROTO;
2311*9e564957SAndroid Build Coastguard Worker fuse_session_exit(se);
2312*9e564957SAndroid Build Coastguard Worker return;
2313*9e564957SAndroid Build Coastguard Worker }
2314*9e564957SAndroid Build Coastguard Worker
2315*9e564957SAndroid Build Coastguard Worker if (se->conn.max_write < bufsize - FUSE_BUFFER_HEADER_SIZE) {
2316*9e564957SAndroid Build Coastguard Worker se->bufsize = se->conn.max_write + FUSE_BUFFER_HEADER_SIZE;
2317*9e564957SAndroid Build Coastguard Worker }
2318*9e564957SAndroid Build Coastguard Worker if (arg->flags & FUSE_MAX_PAGES) {
2319*9e564957SAndroid Build Coastguard Worker outarg.flags |= FUSE_MAX_PAGES;
2320*9e564957SAndroid Build Coastguard Worker outarg.max_pages = (se->conn.max_write - 1) / getpagesize() + 1;
2321*9e564957SAndroid Build Coastguard Worker }
2322*9e564957SAndroid Build Coastguard Worker outargflags = outarg.flags;
2323*9e564957SAndroid Build Coastguard Worker /* Always enable big writes, this is superseded
2324*9e564957SAndroid Build Coastguard Worker by the max_write option */
2325*9e564957SAndroid Build Coastguard Worker outargflags |= FUSE_BIG_WRITES;
2326*9e564957SAndroid Build Coastguard Worker
2327*9e564957SAndroid Build Coastguard Worker if (se->conn.want & FUSE_CAP_ASYNC_READ)
2328*9e564957SAndroid Build Coastguard Worker outargflags |= FUSE_ASYNC_READ;
2329*9e564957SAndroid Build Coastguard Worker if (se->conn.want & FUSE_CAP_POSIX_LOCKS)
2330*9e564957SAndroid Build Coastguard Worker outargflags |= FUSE_POSIX_LOCKS;
2331*9e564957SAndroid Build Coastguard Worker if (se->conn.want & FUSE_CAP_ATOMIC_O_TRUNC)
2332*9e564957SAndroid Build Coastguard Worker outargflags |= FUSE_ATOMIC_O_TRUNC;
2333*9e564957SAndroid Build Coastguard Worker if (se->conn.want & FUSE_CAP_EXPORT_SUPPORT)
2334*9e564957SAndroid Build Coastguard Worker outargflags |= FUSE_EXPORT_SUPPORT;
2335*9e564957SAndroid Build Coastguard Worker if (se->conn.want & FUSE_CAP_DONT_MASK)
2336*9e564957SAndroid Build Coastguard Worker outargflags |= FUSE_DONT_MASK;
2337*9e564957SAndroid Build Coastguard Worker if (se->conn.want & FUSE_CAP_FLOCK_LOCKS)
2338*9e564957SAndroid Build Coastguard Worker outargflags |= FUSE_FLOCK_LOCKS;
2339*9e564957SAndroid Build Coastguard Worker if (se->conn.want & FUSE_CAP_AUTO_INVAL_DATA)
2340*9e564957SAndroid Build Coastguard Worker outargflags |= FUSE_AUTO_INVAL_DATA;
2341*9e564957SAndroid Build Coastguard Worker if (se->conn.want & FUSE_CAP_READDIRPLUS)
2342*9e564957SAndroid Build Coastguard Worker outargflags |= FUSE_DO_READDIRPLUS;
2343*9e564957SAndroid Build Coastguard Worker if (se->conn.want & FUSE_CAP_READDIRPLUS_AUTO)
2344*9e564957SAndroid Build Coastguard Worker outargflags |= FUSE_READDIRPLUS_AUTO;
2345*9e564957SAndroid Build Coastguard Worker if (se->conn.want & FUSE_CAP_ASYNC_DIO)
2346*9e564957SAndroid Build Coastguard Worker outargflags |= FUSE_ASYNC_DIO;
2347*9e564957SAndroid Build Coastguard Worker if (se->conn.want & FUSE_CAP_WRITEBACK_CACHE)
2348*9e564957SAndroid Build Coastguard Worker outargflags |= FUSE_WRITEBACK_CACHE;
2349*9e564957SAndroid Build Coastguard Worker if (se->conn.want & FUSE_CAP_PARALLEL_DIROPS)
2350*9e564957SAndroid Build Coastguard Worker outargflags |= FUSE_PARALLEL_DIROPS;
2351*9e564957SAndroid Build Coastguard Worker if (se->conn.want & FUSE_CAP_POSIX_ACL)
2352*9e564957SAndroid Build Coastguard Worker outargflags |= FUSE_POSIX_ACL;
2353*9e564957SAndroid Build Coastguard Worker if (se->conn.want & FUSE_CAP_HANDLE_KILLPRIV)
2354*9e564957SAndroid Build Coastguard Worker outargflags |= FUSE_HANDLE_KILLPRIV;
2355*9e564957SAndroid Build Coastguard Worker if (se->conn.want & FUSE_CAP_HANDLE_KILLPRIV_V2)
2356*9e564957SAndroid Build Coastguard Worker outargflags |= FUSE_HANDLE_KILLPRIV_V2;
2357*9e564957SAndroid Build Coastguard Worker if (se->conn.want & FUSE_CAP_CACHE_SYMLINKS)
2358*9e564957SAndroid Build Coastguard Worker outargflags |= FUSE_CACHE_SYMLINKS;
2359*9e564957SAndroid Build Coastguard Worker if (se->conn.want & FUSE_CAP_EXPLICIT_INVAL_DATA)
2360*9e564957SAndroid Build Coastguard Worker outargflags |= FUSE_EXPLICIT_INVAL_DATA;
2361*9e564957SAndroid Build Coastguard Worker if (se->conn.want & FUSE_CAP_SETXATTR_EXT)
2362*9e564957SAndroid Build Coastguard Worker outargflags |= FUSE_SETXATTR_EXT;
2363*9e564957SAndroid Build Coastguard Worker if (se->conn.want & FUSE_CAP_DIRECT_IO_ALLOW_MMAP)
2364*9e564957SAndroid Build Coastguard Worker outargflags |= FUSE_DIRECT_IO_ALLOW_MMAP;
2365*9e564957SAndroid Build Coastguard Worker if (se->conn.want & FUSE_CAP_PASSTHROUGH_UPSTREAM) {
2366*9e564957SAndroid Build Coastguard Worker outargflags |= FUSE_PASSTHROUGH_UPSTREAM;
2367*9e564957SAndroid Build Coastguard Worker /*
2368*9e564957SAndroid Build Coastguard Worker * outarg.max_stack_depth includes the fuse stack layer,
2369*9e564957SAndroid Build Coastguard Worker * so it is one more than max_backing_stack_depth.
2370*9e564957SAndroid Build Coastguard Worker */
2371*9e564957SAndroid Build Coastguard Worker outarg.max_stack_depth = se->conn.max_backing_stack_depth + 1;
2372*9e564957SAndroid Build Coastguard Worker }
2373*9e564957SAndroid Build Coastguard Worker if (se->conn.want & FUSE_CAP_PASSTHROUGH) {
2374*9e564957SAndroid Build Coastguard Worker if (inargflags & FUSE_INIT_EXT)
2375*9e564957SAndroid Build Coastguard Worker outargflags |= (1ULL << 63);
2376*9e564957SAndroid Build Coastguard Worker else
2377*9e564957SAndroid Build Coastguard Worker outargflags |= (1 << 31);
2378*9e564957SAndroid Build Coastguard Worker }
2379*9e564957SAndroid Build Coastguard Worker if (inargflags & FUSE_INIT_EXT) {
2380*9e564957SAndroid Build Coastguard Worker outargflags |= FUSE_INIT_EXT;
2381*9e564957SAndroid Build Coastguard Worker outarg.flags2 = outargflags >> 32;
2382*9e564957SAndroid Build Coastguard Worker }
2383*9e564957SAndroid Build Coastguard Worker
2384*9e564957SAndroid Build Coastguard Worker outarg.flags = outargflags;
2385*9e564957SAndroid Build Coastguard Worker
2386*9e564957SAndroid Build Coastguard Worker outarg.max_readahead = se->conn.max_readahead;
2387*9e564957SAndroid Build Coastguard Worker outarg.max_write = se->conn.max_write;
2388*9e564957SAndroid Build Coastguard Worker if (se->conn.proto_minor >= 13) {
2389*9e564957SAndroid Build Coastguard Worker if (se->conn.max_background >= (1 << 16))
2390*9e564957SAndroid Build Coastguard Worker se->conn.max_background = (1 << 16) - 1;
2391*9e564957SAndroid Build Coastguard Worker if (se->conn.congestion_threshold > se->conn.max_background)
2392*9e564957SAndroid Build Coastguard Worker se->conn.congestion_threshold = se->conn.max_background;
2393*9e564957SAndroid Build Coastguard Worker if (!se->conn.congestion_threshold) {
2394*9e564957SAndroid Build Coastguard Worker se->conn.congestion_threshold =
2395*9e564957SAndroid Build Coastguard Worker se->conn.max_background * 3 / 4;
2396*9e564957SAndroid Build Coastguard Worker }
2397*9e564957SAndroid Build Coastguard Worker
2398*9e564957SAndroid Build Coastguard Worker outarg.max_background = se->conn.max_background;
2399*9e564957SAndroid Build Coastguard Worker outarg.congestion_threshold = se->conn.congestion_threshold;
2400*9e564957SAndroid Build Coastguard Worker }
2401*9e564957SAndroid Build Coastguard Worker if (se->conn.proto_minor >= 23)
2402*9e564957SAndroid Build Coastguard Worker outarg.time_gran = se->conn.time_gran;
2403*9e564957SAndroid Build Coastguard Worker
2404*9e564957SAndroid Build Coastguard Worker if (se->debug) {
2405*9e564957SAndroid Build Coastguard Worker fuse_log(FUSE_LOG_DEBUG, " INIT: %u.%u\n", outarg.major, outarg.minor);
2406*9e564957SAndroid Build Coastguard Worker fuse_log(FUSE_LOG_DEBUG, " flags=0x%08x\n", outarg.flags);
2407*9e564957SAndroid Build Coastguard Worker fuse_log(FUSE_LOG_DEBUG, " max_readahead=0x%08x\n",
2408*9e564957SAndroid Build Coastguard Worker outarg.max_readahead);
2409*9e564957SAndroid Build Coastguard Worker fuse_log(FUSE_LOG_DEBUG, " max_write=0x%08x\n", outarg.max_write);
2410*9e564957SAndroid Build Coastguard Worker fuse_log(FUSE_LOG_DEBUG, " max_background=%i\n",
2411*9e564957SAndroid Build Coastguard Worker outarg.max_background);
2412*9e564957SAndroid Build Coastguard Worker fuse_log(FUSE_LOG_DEBUG, " congestion_threshold=%i\n",
2413*9e564957SAndroid Build Coastguard Worker outarg.congestion_threshold);
2414*9e564957SAndroid Build Coastguard Worker fuse_log(FUSE_LOG_DEBUG, " time_gran=%u\n",
2415*9e564957SAndroid Build Coastguard Worker outarg.time_gran);
2416*9e564957SAndroid Build Coastguard Worker if (se->conn.want & FUSE_CAP_PASSTHROUGH)
2417*9e564957SAndroid Build Coastguard Worker fuse_log(FUSE_LOG_DEBUG, " max_stack_depth=%u\n",
2418*9e564957SAndroid Build Coastguard Worker outarg.max_stack_depth);
2419*9e564957SAndroid Build Coastguard Worker }
2420*9e564957SAndroid Build Coastguard Worker if (arg->minor < 5)
2421*9e564957SAndroid Build Coastguard Worker outargsize = FUSE_COMPAT_INIT_OUT_SIZE;
2422*9e564957SAndroid Build Coastguard Worker else if (arg->minor < 23)
2423*9e564957SAndroid Build Coastguard Worker outargsize = FUSE_COMPAT_22_INIT_OUT_SIZE;
2424*9e564957SAndroid Build Coastguard Worker
2425*9e564957SAndroid Build Coastguard Worker send_reply_ok(req, &outarg, outargsize);
2426*9e564957SAndroid Build Coastguard Worker }
2427*9e564957SAndroid Build Coastguard Worker
2428*9e564957SAndroid Build Coastguard Worker static void do_destroy(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
2429*9e564957SAndroid Build Coastguard Worker {
2430*9e564957SAndroid Build Coastguard Worker struct fuse_session *se = req->se;
2431*9e564957SAndroid Build Coastguard Worker
2432*9e564957SAndroid Build Coastguard Worker (void) nodeid;
2433*9e564957SAndroid Build Coastguard Worker (void) inarg;
2434*9e564957SAndroid Build Coastguard Worker
2435*9e564957SAndroid Build Coastguard Worker se->got_destroy = 1;
2436*9e564957SAndroid Build Coastguard Worker se->got_init = 0;
2437*9e564957SAndroid Build Coastguard Worker if (se->op.destroy)
2438*9e564957SAndroid Build Coastguard Worker se->op.destroy(se->userdata);
2439*9e564957SAndroid Build Coastguard Worker
2440*9e564957SAndroid Build Coastguard Worker send_reply_ok(req, NULL, 0);
2441*9e564957SAndroid Build Coastguard Worker }
2442*9e564957SAndroid Build Coastguard Worker
2443*9e564957SAndroid Build Coastguard Worker static void list_del_nreq(struct fuse_notify_req *nreq)
2444*9e564957SAndroid Build Coastguard Worker {
2445*9e564957SAndroid Build Coastguard Worker struct fuse_notify_req *prev = nreq->prev;
2446*9e564957SAndroid Build Coastguard Worker struct fuse_notify_req *next = nreq->next;
2447*9e564957SAndroid Build Coastguard Worker prev->next = next;
2448*9e564957SAndroid Build Coastguard Worker next->prev = prev;
2449*9e564957SAndroid Build Coastguard Worker }
2450*9e564957SAndroid Build Coastguard Worker
2451*9e564957SAndroid Build Coastguard Worker static void list_add_nreq(struct fuse_notify_req *nreq,
2452*9e564957SAndroid Build Coastguard Worker struct fuse_notify_req *next)
2453*9e564957SAndroid Build Coastguard Worker {
2454*9e564957SAndroid Build Coastguard Worker struct fuse_notify_req *prev = next->prev;
2455*9e564957SAndroid Build Coastguard Worker nreq->next = next;
2456*9e564957SAndroid Build Coastguard Worker nreq->prev = prev;
2457*9e564957SAndroid Build Coastguard Worker prev->next = nreq;
2458*9e564957SAndroid Build Coastguard Worker next->prev = nreq;
2459*9e564957SAndroid Build Coastguard Worker }
2460*9e564957SAndroid Build Coastguard Worker
2461*9e564957SAndroid Build Coastguard Worker static void list_init_nreq(struct fuse_notify_req *nreq)
2462*9e564957SAndroid Build Coastguard Worker {
2463*9e564957SAndroid Build Coastguard Worker nreq->next = nreq;
2464*9e564957SAndroid Build Coastguard Worker nreq->prev = nreq;
2465*9e564957SAndroid Build Coastguard Worker }
2466*9e564957SAndroid Build Coastguard Worker
2467*9e564957SAndroid Build Coastguard Worker static void do_notify_reply(fuse_req_t req, fuse_ino_t nodeid,
2468*9e564957SAndroid Build Coastguard Worker const void *inarg, const struct fuse_buf *buf)
2469*9e564957SAndroid Build Coastguard Worker {
2470*9e564957SAndroid Build Coastguard Worker struct fuse_session *se = req->se;
2471*9e564957SAndroid Build Coastguard Worker struct fuse_notify_req *nreq;
2472*9e564957SAndroid Build Coastguard Worker struct fuse_notify_req *head;
2473*9e564957SAndroid Build Coastguard Worker
2474*9e564957SAndroid Build Coastguard Worker pthread_mutex_lock(&se->lock);
2475*9e564957SAndroid Build Coastguard Worker head = &se->notify_list;
2476*9e564957SAndroid Build Coastguard Worker for (nreq = head->next; nreq != head; nreq = nreq->next) {
2477*9e564957SAndroid Build Coastguard Worker if (nreq->unique == req->unique) {
2478*9e564957SAndroid Build Coastguard Worker list_del_nreq(nreq);
2479*9e564957SAndroid Build Coastguard Worker break;
2480*9e564957SAndroid Build Coastguard Worker }
2481*9e564957SAndroid Build Coastguard Worker }
2482*9e564957SAndroid Build Coastguard Worker pthread_mutex_unlock(&se->lock);
2483*9e564957SAndroid Build Coastguard Worker
2484*9e564957SAndroid Build Coastguard Worker if (nreq != head)
2485*9e564957SAndroid Build Coastguard Worker nreq->reply(nreq, req, nodeid, inarg, buf);
2486*9e564957SAndroid Build Coastguard Worker }
2487*9e564957SAndroid Build Coastguard Worker
2488*9e564957SAndroid Build Coastguard Worker static int send_notify_iov(struct fuse_session *se, int notify_code,
2489*9e564957SAndroid Build Coastguard Worker struct iovec *iov, int count)
2490*9e564957SAndroid Build Coastguard Worker {
2491*9e564957SAndroid Build Coastguard Worker struct fuse_out_header out;
2492*9e564957SAndroid Build Coastguard Worker
2493*9e564957SAndroid Build Coastguard Worker if (!se->got_init)
2494*9e564957SAndroid Build Coastguard Worker return -ENOTCONN;
2495*9e564957SAndroid Build Coastguard Worker
2496*9e564957SAndroid Build Coastguard Worker out.unique = 0;
2497*9e564957SAndroid Build Coastguard Worker out.error = notify_code;
2498*9e564957SAndroid Build Coastguard Worker iov[0].iov_base = &out;
2499*9e564957SAndroid Build Coastguard Worker iov[0].iov_len = sizeof(struct fuse_out_header);
2500*9e564957SAndroid Build Coastguard Worker
2501*9e564957SAndroid Build Coastguard Worker return fuse_send_msg(se, NULL, iov, count);
2502*9e564957SAndroid Build Coastguard Worker }
2503*9e564957SAndroid Build Coastguard Worker
2504*9e564957SAndroid Build Coastguard Worker int fuse_lowlevel_notify_poll(struct fuse_pollhandle *ph)
2505*9e564957SAndroid Build Coastguard Worker {
2506*9e564957SAndroid Build Coastguard Worker if (ph != NULL) {
2507*9e564957SAndroid Build Coastguard Worker struct fuse_notify_poll_wakeup_out outarg;
2508*9e564957SAndroid Build Coastguard Worker struct iovec iov[2];
2509*9e564957SAndroid Build Coastguard Worker
2510*9e564957SAndroid Build Coastguard Worker outarg.kh = ph->kh;
2511*9e564957SAndroid Build Coastguard Worker
2512*9e564957SAndroid Build Coastguard Worker iov[1].iov_base = &outarg;
2513*9e564957SAndroid Build Coastguard Worker iov[1].iov_len = sizeof(outarg);
2514*9e564957SAndroid Build Coastguard Worker
2515*9e564957SAndroid Build Coastguard Worker return send_notify_iov(ph->se, FUSE_NOTIFY_POLL, iov, 2);
2516*9e564957SAndroid Build Coastguard Worker } else {
2517*9e564957SAndroid Build Coastguard Worker return 0;
2518*9e564957SAndroid Build Coastguard Worker }
2519*9e564957SAndroid Build Coastguard Worker }
2520*9e564957SAndroid Build Coastguard Worker
2521*9e564957SAndroid Build Coastguard Worker int fuse_lowlevel_notify_inval_inode(struct fuse_session *se, fuse_ino_t ino,
2522*9e564957SAndroid Build Coastguard Worker off_t off, off_t len)
2523*9e564957SAndroid Build Coastguard Worker {
2524*9e564957SAndroid Build Coastguard Worker struct fuse_notify_inval_inode_out outarg;
2525*9e564957SAndroid Build Coastguard Worker struct iovec iov[2];
2526*9e564957SAndroid Build Coastguard Worker
2527*9e564957SAndroid Build Coastguard Worker if (!se)
2528*9e564957SAndroid Build Coastguard Worker return -EINVAL;
2529*9e564957SAndroid Build Coastguard Worker
2530*9e564957SAndroid Build Coastguard Worker if (se->conn.proto_minor < 12)
2531*9e564957SAndroid Build Coastguard Worker return -ENOSYS;
2532*9e564957SAndroid Build Coastguard Worker
2533*9e564957SAndroid Build Coastguard Worker outarg.ino = ino;
2534*9e564957SAndroid Build Coastguard Worker outarg.off = off;
2535*9e564957SAndroid Build Coastguard Worker outarg.len = len;
2536*9e564957SAndroid Build Coastguard Worker
2537*9e564957SAndroid Build Coastguard Worker iov[1].iov_base = &outarg;
2538*9e564957SAndroid Build Coastguard Worker iov[1].iov_len = sizeof(outarg);
2539*9e564957SAndroid Build Coastguard Worker
2540*9e564957SAndroid Build Coastguard Worker return send_notify_iov(se, FUSE_NOTIFY_INVAL_INODE, iov, 2);
2541*9e564957SAndroid Build Coastguard Worker }
2542*9e564957SAndroid Build Coastguard Worker
2543*9e564957SAndroid Build Coastguard Worker /**
2544*9e564957SAndroid Build Coastguard Worker * Notify parent attributes and the dentry matching parent/name
2545*9e564957SAndroid Build Coastguard Worker *
2546*9e564957SAndroid Build Coastguard Worker * Underlying base function for fuse_lowlevel_notify_inval_entry() and
2547*9e564957SAndroid Build Coastguard Worker * fuse_lowlevel_notify_expire_entry().
2548*9e564957SAndroid Build Coastguard Worker *
2549*9e564957SAndroid Build Coastguard Worker * @warning
2550*9e564957SAndroid Build Coastguard Worker * Only checks if fuse_lowlevel_notify_inval_entry() is supported by
2551*9e564957SAndroid Build Coastguard Worker * the kernel. All other flags will fall back to
2552*9e564957SAndroid Build Coastguard Worker * fuse_lowlevel_notify_inval_entry() if not supported!
2553*9e564957SAndroid Build Coastguard Worker * DO THE PROPER CHECKS IN THE DERIVED FUNCTION!
2554*9e564957SAndroid Build Coastguard Worker *
2555*9e564957SAndroid Build Coastguard Worker * @param se the session object
2556*9e564957SAndroid Build Coastguard Worker * @param parent inode number
2557*9e564957SAndroid Build Coastguard Worker * @param name file name
2558*9e564957SAndroid Build Coastguard Worker * @param namelen strlen() of file name
2559*9e564957SAndroid Build Coastguard Worker * @param flags flags to control if the entry should be expired or invalidated
2560*9e564957SAndroid Build Coastguard Worker * @return zero for success, -errno for failure
2561*9e564957SAndroid Build Coastguard Worker */
2562*9e564957SAndroid Build Coastguard Worker static int fuse_lowlevel_notify_entry(struct fuse_session *se, fuse_ino_t parent,
2563*9e564957SAndroid Build Coastguard Worker const char *name, size_t namelen,
2564*9e564957SAndroid Build Coastguard Worker enum fuse_notify_entry_flags flags)
2565*9e564957SAndroid Build Coastguard Worker {
2566*9e564957SAndroid Build Coastguard Worker struct fuse_notify_inval_entry_out outarg;
2567*9e564957SAndroid Build Coastguard Worker struct iovec iov[3];
2568*9e564957SAndroid Build Coastguard Worker
2569*9e564957SAndroid Build Coastguard Worker if (!se)
2570*9e564957SAndroid Build Coastguard Worker return -EINVAL;
2571*9e564957SAndroid Build Coastguard Worker
2572*9e564957SAndroid Build Coastguard Worker if (se->conn.proto_minor < 12)
2573*9e564957SAndroid Build Coastguard Worker return -ENOSYS;
2574*9e564957SAndroid Build Coastguard Worker
2575*9e564957SAndroid Build Coastguard Worker outarg.parent = parent;
2576*9e564957SAndroid Build Coastguard Worker outarg.namelen = namelen;
2577*9e564957SAndroid Build Coastguard Worker outarg.flags = 0;
2578*9e564957SAndroid Build Coastguard Worker if (flags & FUSE_LL_EXPIRE_ONLY)
2579*9e564957SAndroid Build Coastguard Worker outarg.flags |= FUSE_EXPIRE_ONLY;
2580*9e564957SAndroid Build Coastguard Worker
2581*9e564957SAndroid Build Coastguard Worker iov[1].iov_base = &outarg;
2582*9e564957SAndroid Build Coastguard Worker iov[1].iov_len = sizeof(outarg);
2583*9e564957SAndroid Build Coastguard Worker iov[2].iov_base = (void *)name;
2584*9e564957SAndroid Build Coastguard Worker iov[2].iov_len = namelen + 1;
2585*9e564957SAndroid Build Coastguard Worker
2586*9e564957SAndroid Build Coastguard Worker return send_notify_iov(se, FUSE_NOTIFY_INVAL_ENTRY, iov, 3);
2587*9e564957SAndroid Build Coastguard Worker }
2588*9e564957SAndroid Build Coastguard Worker
2589*9e564957SAndroid Build Coastguard Worker int fuse_lowlevel_notify_inval_entry(struct fuse_session *se, fuse_ino_t parent,
2590*9e564957SAndroid Build Coastguard Worker const char *name, size_t namelen)
2591*9e564957SAndroid Build Coastguard Worker {
2592*9e564957SAndroid Build Coastguard Worker return fuse_lowlevel_notify_entry(se, parent, name, namelen, FUSE_LL_INVALIDATE);
2593*9e564957SAndroid Build Coastguard Worker }
2594*9e564957SAndroid Build Coastguard Worker
2595*9e564957SAndroid Build Coastguard Worker int fuse_lowlevel_notify_expire_entry(struct fuse_session *se, fuse_ino_t parent,
2596*9e564957SAndroid Build Coastguard Worker const char *name, size_t namelen)
2597*9e564957SAndroid Build Coastguard Worker {
2598*9e564957SAndroid Build Coastguard Worker if (!se)
2599*9e564957SAndroid Build Coastguard Worker return -EINVAL;
2600*9e564957SAndroid Build Coastguard Worker
2601*9e564957SAndroid Build Coastguard Worker if (!(se->conn.capable & FUSE_CAP_EXPIRE_ONLY))
2602*9e564957SAndroid Build Coastguard Worker return -ENOSYS;
2603*9e564957SAndroid Build Coastguard Worker
2604*9e564957SAndroid Build Coastguard Worker return fuse_lowlevel_notify_entry(se, parent, name, namelen, FUSE_LL_EXPIRE_ONLY);
2605*9e564957SAndroid Build Coastguard Worker }
2606*9e564957SAndroid Build Coastguard Worker
2607*9e564957SAndroid Build Coastguard Worker
2608*9e564957SAndroid Build Coastguard Worker int fuse_lowlevel_notify_delete(struct fuse_session *se,
2609*9e564957SAndroid Build Coastguard Worker fuse_ino_t parent, fuse_ino_t child,
2610*9e564957SAndroid Build Coastguard Worker const char *name, size_t namelen)
2611*9e564957SAndroid Build Coastguard Worker {
2612*9e564957SAndroid Build Coastguard Worker struct fuse_notify_delete_out outarg;
2613*9e564957SAndroid Build Coastguard Worker struct iovec iov[3];
2614*9e564957SAndroid Build Coastguard Worker
2615*9e564957SAndroid Build Coastguard Worker if (!se)
2616*9e564957SAndroid Build Coastguard Worker return -EINVAL;
2617*9e564957SAndroid Build Coastguard Worker
2618*9e564957SAndroid Build Coastguard Worker if (se->conn.proto_minor < 18)
2619*9e564957SAndroid Build Coastguard Worker return -ENOSYS;
2620*9e564957SAndroid Build Coastguard Worker
2621*9e564957SAndroid Build Coastguard Worker outarg.parent = parent;
2622*9e564957SAndroid Build Coastguard Worker outarg.child = child;
2623*9e564957SAndroid Build Coastguard Worker outarg.namelen = namelen;
2624*9e564957SAndroid Build Coastguard Worker outarg.padding = 0;
2625*9e564957SAndroid Build Coastguard Worker
2626*9e564957SAndroid Build Coastguard Worker iov[1].iov_base = &outarg;
2627*9e564957SAndroid Build Coastguard Worker iov[1].iov_len = sizeof(outarg);
2628*9e564957SAndroid Build Coastguard Worker iov[2].iov_base = (void *)name;
2629*9e564957SAndroid Build Coastguard Worker iov[2].iov_len = namelen + 1;
2630*9e564957SAndroid Build Coastguard Worker
2631*9e564957SAndroid Build Coastguard Worker return send_notify_iov(se, FUSE_NOTIFY_DELETE, iov, 3);
2632*9e564957SAndroid Build Coastguard Worker }
2633*9e564957SAndroid Build Coastguard Worker
2634*9e564957SAndroid Build Coastguard Worker int fuse_lowlevel_notify_store(struct fuse_session *se, fuse_ino_t ino,
2635*9e564957SAndroid Build Coastguard Worker off_t offset, struct fuse_bufvec *bufv,
2636*9e564957SAndroid Build Coastguard Worker enum fuse_buf_copy_flags flags)
2637*9e564957SAndroid Build Coastguard Worker {
2638*9e564957SAndroid Build Coastguard Worker struct fuse_out_header out;
2639*9e564957SAndroid Build Coastguard Worker struct fuse_notify_store_out outarg;
2640*9e564957SAndroid Build Coastguard Worker struct iovec iov[3];
2641*9e564957SAndroid Build Coastguard Worker size_t size = fuse_buf_size(bufv);
2642*9e564957SAndroid Build Coastguard Worker int res;
2643*9e564957SAndroid Build Coastguard Worker
2644*9e564957SAndroid Build Coastguard Worker if (!se)
2645*9e564957SAndroid Build Coastguard Worker return -EINVAL;
2646*9e564957SAndroid Build Coastguard Worker
2647*9e564957SAndroid Build Coastguard Worker if (se->conn.proto_minor < 15)
2648*9e564957SAndroid Build Coastguard Worker return -ENOSYS;
2649*9e564957SAndroid Build Coastguard Worker
2650*9e564957SAndroid Build Coastguard Worker out.unique = 0;
2651*9e564957SAndroid Build Coastguard Worker out.error = FUSE_NOTIFY_STORE;
2652*9e564957SAndroid Build Coastguard Worker
2653*9e564957SAndroid Build Coastguard Worker outarg.nodeid = ino;
2654*9e564957SAndroid Build Coastguard Worker outarg.offset = offset;
2655*9e564957SAndroid Build Coastguard Worker outarg.size = size;
2656*9e564957SAndroid Build Coastguard Worker outarg.padding = 0;
2657*9e564957SAndroid Build Coastguard Worker
2658*9e564957SAndroid Build Coastguard Worker iov[0].iov_base = &out;
2659*9e564957SAndroid Build Coastguard Worker iov[0].iov_len = sizeof(out);
2660*9e564957SAndroid Build Coastguard Worker iov[1].iov_base = &outarg;
2661*9e564957SAndroid Build Coastguard Worker iov[1].iov_len = sizeof(outarg);
2662*9e564957SAndroid Build Coastguard Worker
2663*9e564957SAndroid Build Coastguard Worker res = fuse_send_data_iov(se, NULL, iov, 2, bufv, flags);
2664*9e564957SAndroid Build Coastguard Worker if (res > 0)
2665*9e564957SAndroid Build Coastguard Worker res = -res;
2666*9e564957SAndroid Build Coastguard Worker
2667*9e564957SAndroid Build Coastguard Worker return res;
2668*9e564957SAndroid Build Coastguard Worker }
2669*9e564957SAndroid Build Coastguard Worker
2670*9e564957SAndroid Build Coastguard Worker struct fuse_retrieve_req {
2671*9e564957SAndroid Build Coastguard Worker struct fuse_notify_req nreq;
2672*9e564957SAndroid Build Coastguard Worker void *cookie;
2673*9e564957SAndroid Build Coastguard Worker };
2674*9e564957SAndroid Build Coastguard Worker
2675*9e564957SAndroid Build Coastguard Worker static void fuse_ll_retrieve_reply(struct fuse_notify_req *nreq,
2676*9e564957SAndroid Build Coastguard Worker fuse_req_t req, fuse_ino_t ino,
2677*9e564957SAndroid Build Coastguard Worker const void *inarg,
2678*9e564957SAndroid Build Coastguard Worker const struct fuse_buf *ibuf)
2679*9e564957SAndroid Build Coastguard Worker {
2680*9e564957SAndroid Build Coastguard Worker struct fuse_session *se = req->se;
2681*9e564957SAndroid Build Coastguard Worker struct fuse_retrieve_req *rreq =
2682*9e564957SAndroid Build Coastguard Worker container_of(nreq, struct fuse_retrieve_req, nreq);
2683*9e564957SAndroid Build Coastguard Worker const struct fuse_notify_retrieve_in *arg = inarg;
2684*9e564957SAndroid Build Coastguard Worker struct fuse_bufvec bufv = {
2685*9e564957SAndroid Build Coastguard Worker .buf[0] = *ibuf,
2686*9e564957SAndroid Build Coastguard Worker .count = 1,
2687*9e564957SAndroid Build Coastguard Worker };
2688*9e564957SAndroid Build Coastguard Worker
2689*9e564957SAndroid Build Coastguard Worker if (!(bufv.buf[0].flags & FUSE_BUF_IS_FD))
2690*9e564957SAndroid Build Coastguard Worker bufv.buf[0].mem = PARAM(arg);
2691*9e564957SAndroid Build Coastguard Worker
2692*9e564957SAndroid Build Coastguard Worker bufv.buf[0].size -= sizeof(struct fuse_in_header) +
2693*9e564957SAndroid Build Coastguard Worker sizeof(struct fuse_notify_retrieve_in);
2694*9e564957SAndroid Build Coastguard Worker
2695*9e564957SAndroid Build Coastguard Worker if (bufv.buf[0].size < arg->size) {
2696*9e564957SAndroid Build Coastguard Worker fuse_log(FUSE_LOG_ERR, "fuse: retrieve reply: buffer size too small\n");
2697*9e564957SAndroid Build Coastguard Worker fuse_reply_none(req);
2698*9e564957SAndroid Build Coastguard Worker goto out;
2699*9e564957SAndroid Build Coastguard Worker }
2700*9e564957SAndroid Build Coastguard Worker bufv.buf[0].size = arg->size;
2701*9e564957SAndroid Build Coastguard Worker
2702*9e564957SAndroid Build Coastguard Worker if (se->op.retrieve_reply) {
2703*9e564957SAndroid Build Coastguard Worker se->op.retrieve_reply(req, rreq->cookie, ino,
2704*9e564957SAndroid Build Coastguard Worker arg->offset, &bufv);
2705*9e564957SAndroid Build Coastguard Worker } else {
2706*9e564957SAndroid Build Coastguard Worker fuse_reply_none(req);
2707*9e564957SAndroid Build Coastguard Worker }
2708*9e564957SAndroid Build Coastguard Worker out:
2709*9e564957SAndroid Build Coastguard Worker free(rreq);
2710*9e564957SAndroid Build Coastguard Worker if ((ibuf->flags & FUSE_BUF_IS_FD) && bufv.idx < bufv.count)
2711*9e564957SAndroid Build Coastguard Worker fuse_ll_clear_pipe(se);
2712*9e564957SAndroid Build Coastguard Worker }
2713*9e564957SAndroid Build Coastguard Worker
2714*9e564957SAndroid Build Coastguard Worker int fuse_lowlevel_notify_retrieve(struct fuse_session *se, fuse_ino_t ino,
2715*9e564957SAndroid Build Coastguard Worker size_t size, off_t offset, void *cookie)
2716*9e564957SAndroid Build Coastguard Worker {
2717*9e564957SAndroid Build Coastguard Worker struct fuse_notify_retrieve_out outarg;
2718*9e564957SAndroid Build Coastguard Worker struct iovec iov[2];
2719*9e564957SAndroid Build Coastguard Worker struct fuse_retrieve_req *rreq;
2720*9e564957SAndroid Build Coastguard Worker int err;
2721*9e564957SAndroid Build Coastguard Worker
2722*9e564957SAndroid Build Coastguard Worker if (!se)
2723*9e564957SAndroid Build Coastguard Worker return -EINVAL;
2724*9e564957SAndroid Build Coastguard Worker
2725*9e564957SAndroid Build Coastguard Worker if (se->conn.proto_minor < 15)
2726*9e564957SAndroid Build Coastguard Worker return -ENOSYS;
2727*9e564957SAndroid Build Coastguard Worker
2728*9e564957SAndroid Build Coastguard Worker rreq = malloc(sizeof(*rreq));
2729*9e564957SAndroid Build Coastguard Worker if (rreq == NULL)
2730*9e564957SAndroid Build Coastguard Worker return -ENOMEM;
2731*9e564957SAndroid Build Coastguard Worker
2732*9e564957SAndroid Build Coastguard Worker pthread_mutex_lock(&se->lock);
2733*9e564957SAndroid Build Coastguard Worker rreq->cookie = cookie;
2734*9e564957SAndroid Build Coastguard Worker rreq->nreq.unique = se->notify_ctr++;
2735*9e564957SAndroid Build Coastguard Worker rreq->nreq.reply = fuse_ll_retrieve_reply;
2736*9e564957SAndroid Build Coastguard Worker list_add_nreq(&rreq->nreq, &se->notify_list);
2737*9e564957SAndroid Build Coastguard Worker pthread_mutex_unlock(&se->lock);
2738*9e564957SAndroid Build Coastguard Worker
2739*9e564957SAndroid Build Coastguard Worker outarg.notify_unique = rreq->nreq.unique;
2740*9e564957SAndroid Build Coastguard Worker outarg.nodeid = ino;
2741*9e564957SAndroid Build Coastguard Worker outarg.offset = offset;
2742*9e564957SAndroid Build Coastguard Worker outarg.size = size;
2743*9e564957SAndroid Build Coastguard Worker outarg.padding = 0;
2744*9e564957SAndroid Build Coastguard Worker
2745*9e564957SAndroid Build Coastguard Worker iov[1].iov_base = &outarg;
2746*9e564957SAndroid Build Coastguard Worker iov[1].iov_len = sizeof(outarg);
2747*9e564957SAndroid Build Coastguard Worker
2748*9e564957SAndroid Build Coastguard Worker err = send_notify_iov(se, FUSE_NOTIFY_RETRIEVE, iov, 2);
2749*9e564957SAndroid Build Coastguard Worker if (err) {
2750*9e564957SAndroid Build Coastguard Worker pthread_mutex_lock(&se->lock);
2751*9e564957SAndroid Build Coastguard Worker list_del_nreq(&rreq->nreq);
2752*9e564957SAndroid Build Coastguard Worker pthread_mutex_unlock(&se->lock);
2753*9e564957SAndroid Build Coastguard Worker free(rreq);
2754*9e564957SAndroid Build Coastguard Worker }
2755*9e564957SAndroid Build Coastguard Worker
2756*9e564957SAndroid Build Coastguard Worker return err;
2757*9e564957SAndroid Build Coastguard Worker }
2758*9e564957SAndroid Build Coastguard Worker
2759*9e564957SAndroid Build Coastguard Worker void *fuse_req_userdata(fuse_req_t req)
2760*9e564957SAndroid Build Coastguard Worker {
2761*9e564957SAndroid Build Coastguard Worker return req->se->userdata;
2762*9e564957SAndroid Build Coastguard Worker }
2763*9e564957SAndroid Build Coastguard Worker
2764*9e564957SAndroid Build Coastguard Worker const struct fuse_ctx *fuse_req_ctx(fuse_req_t req)
2765*9e564957SAndroid Build Coastguard Worker {
2766*9e564957SAndroid Build Coastguard Worker return &req->ctx;
2767*9e564957SAndroid Build Coastguard Worker }
2768*9e564957SAndroid Build Coastguard Worker
2769*9e564957SAndroid Build Coastguard Worker void fuse_req_interrupt_func(fuse_req_t req, fuse_interrupt_func_t func,
2770*9e564957SAndroid Build Coastguard Worker void *data)
2771*9e564957SAndroid Build Coastguard Worker {
2772*9e564957SAndroid Build Coastguard Worker pthread_mutex_lock(&req->lock);
2773*9e564957SAndroid Build Coastguard Worker pthread_mutex_lock(&req->se->lock);
2774*9e564957SAndroid Build Coastguard Worker req->u.ni.func = func;
2775*9e564957SAndroid Build Coastguard Worker req->u.ni.data = data;
2776*9e564957SAndroid Build Coastguard Worker pthread_mutex_unlock(&req->se->lock);
2777*9e564957SAndroid Build Coastguard Worker if (req->interrupted && func)
2778*9e564957SAndroid Build Coastguard Worker func(req, data);
2779*9e564957SAndroid Build Coastguard Worker pthread_mutex_unlock(&req->lock);
2780*9e564957SAndroid Build Coastguard Worker }
2781*9e564957SAndroid Build Coastguard Worker
2782*9e564957SAndroid Build Coastguard Worker int fuse_req_interrupted(fuse_req_t req)
2783*9e564957SAndroid Build Coastguard Worker {
2784*9e564957SAndroid Build Coastguard Worker int interrupted;
2785*9e564957SAndroid Build Coastguard Worker
2786*9e564957SAndroid Build Coastguard Worker pthread_mutex_lock(&req->se->lock);
2787*9e564957SAndroid Build Coastguard Worker interrupted = req->interrupted;
2788*9e564957SAndroid Build Coastguard Worker pthread_mutex_unlock(&req->se->lock);
2789*9e564957SAndroid Build Coastguard Worker
2790*9e564957SAndroid Build Coastguard Worker return interrupted;
2791*9e564957SAndroid Build Coastguard Worker }
2792*9e564957SAndroid Build Coastguard Worker
2793*9e564957SAndroid Build Coastguard Worker static struct {
2794*9e564957SAndroid Build Coastguard Worker void (*func)(fuse_req_t, fuse_ino_t, const void *);
2795*9e564957SAndroid Build Coastguard Worker const char *name;
2796*9e564957SAndroid Build Coastguard Worker } fuse_ll_ops[] = {
2797*9e564957SAndroid Build Coastguard Worker [FUSE_LOOKUP] = { do_lookup, "LOOKUP" },
2798*9e564957SAndroid Build Coastguard Worker [FUSE_FORGET] = { do_forget, "FORGET" },
2799*9e564957SAndroid Build Coastguard Worker [FUSE_GETATTR] = { do_getattr, "GETATTR" },
2800*9e564957SAndroid Build Coastguard Worker [FUSE_SETATTR] = { do_setattr, "SETATTR" },
2801*9e564957SAndroid Build Coastguard Worker [FUSE_READLINK] = { do_readlink, "READLINK" },
2802*9e564957SAndroid Build Coastguard Worker [FUSE_CANONICAL_PATH] = { do_canonical_path, "CANONICAL_PATH" },
2803*9e564957SAndroid Build Coastguard Worker [FUSE_SYMLINK] = { do_symlink, "SYMLINK" },
2804*9e564957SAndroid Build Coastguard Worker [FUSE_MKNOD] = { do_mknod, "MKNOD" },
2805*9e564957SAndroid Build Coastguard Worker [FUSE_MKDIR] = { do_mkdir, "MKDIR" },
2806*9e564957SAndroid Build Coastguard Worker [FUSE_UNLINK] = { do_unlink, "UNLINK" },
2807*9e564957SAndroid Build Coastguard Worker [FUSE_RMDIR] = { do_rmdir, "RMDIR" },
2808*9e564957SAndroid Build Coastguard Worker [FUSE_RENAME] = { do_rename, "RENAME" },
2809*9e564957SAndroid Build Coastguard Worker [FUSE_LINK] = { do_link, "LINK" },
2810*9e564957SAndroid Build Coastguard Worker [FUSE_OPEN] = { do_open, "OPEN" },
2811*9e564957SAndroid Build Coastguard Worker [FUSE_READ] = { do_read, "READ" },
2812*9e564957SAndroid Build Coastguard Worker [FUSE_WRITE] = { do_write, "WRITE" },
2813*9e564957SAndroid Build Coastguard Worker [FUSE_STATFS] = { do_statfs, "STATFS" },
2814*9e564957SAndroid Build Coastguard Worker [FUSE_RELEASE] = { do_release, "RELEASE" },
2815*9e564957SAndroid Build Coastguard Worker [FUSE_FSYNC] = { do_fsync, "FSYNC" },
2816*9e564957SAndroid Build Coastguard Worker [FUSE_SETXATTR] = { do_setxattr, "SETXATTR" },
2817*9e564957SAndroid Build Coastguard Worker [FUSE_GETXATTR] = { do_getxattr, "GETXATTR" },
2818*9e564957SAndroid Build Coastguard Worker [FUSE_LISTXATTR] = { do_listxattr, "LISTXATTR" },
2819*9e564957SAndroid Build Coastguard Worker [FUSE_REMOVEXATTR] = { do_removexattr, "REMOVEXATTR" },
2820*9e564957SAndroid Build Coastguard Worker [FUSE_FLUSH] = { do_flush, "FLUSH" },
2821*9e564957SAndroid Build Coastguard Worker [FUSE_INIT] = { do_init, "INIT" },
2822*9e564957SAndroid Build Coastguard Worker [FUSE_OPENDIR] = { do_opendir, "OPENDIR" },
2823*9e564957SAndroid Build Coastguard Worker [FUSE_READDIR] = { do_readdir, "READDIR" },
2824*9e564957SAndroid Build Coastguard Worker [FUSE_RELEASEDIR] = { do_releasedir, "RELEASEDIR" },
2825*9e564957SAndroid Build Coastguard Worker [FUSE_FSYNCDIR] = { do_fsyncdir, "FSYNCDIR" },
2826*9e564957SAndroid Build Coastguard Worker [FUSE_GETLK] = { do_getlk, "GETLK" },
2827*9e564957SAndroid Build Coastguard Worker [FUSE_SETLK] = { do_setlk, "SETLK" },
2828*9e564957SAndroid Build Coastguard Worker [FUSE_SETLKW] = { do_setlkw, "SETLKW" },
2829*9e564957SAndroid Build Coastguard Worker [FUSE_ACCESS] = { do_access, "ACCESS" },
2830*9e564957SAndroid Build Coastguard Worker [FUSE_CREATE] = { do_create, "CREATE" },
2831*9e564957SAndroid Build Coastguard Worker [FUSE_INTERRUPT] = { do_interrupt, "INTERRUPT" },
2832*9e564957SAndroid Build Coastguard Worker [FUSE_BMAP] = { do_bmap, "BMAP" },
2833*9e564957SAndroid Build Coastguard Worker [FUSE_IOCTL] = { do_ioctl, "IOCTL" },
2834*9e564957SAndroid Build Coastguard Worker [FUSE_POLL] = { do_poll, "POLL" },
2835*9e564957SAndroid Build Coastguard Worker [FUSE_FALLOCATE] = { do_fallocate, "FALLOCATE" },
2836*9e564957SAndroid Build Coastguard Worker [FUSE_DESTROY] = { do_destroy, "DESTROY" },
2837*9e564957SAndroid Build Coastguard Worker [FUSE_NOTIFY_REPLY] = { (void *) 1, "NOTIFY_REPLY" },
2838*9e564957SAndroid Build Coastguard Worker [FUSE_BATCH_FORGET] = { do_batch_forget, "BATCH_FORGET" },
2839*9e564957SAndroid Build Coastguard Worker [FUSE_READDIRPLUS] = { do_readdirplus, "READDIRPLUS"},
2840*9e564957SAndroid Build Coastguard Worker [FUSE_RENAME2] = { do_rename2, "RENAME2" },
2841*9e564957SAndroid Build Coastguard Worker [FUSE_COPY_FILE_RANGE] = { do_copy_file_range, "COPY_FILE_RANGE" },
2842*9e564957SAndroid Build Coastguard Worker [FUSE_LSEEK] = { do_lseek, "LSEEK" },
2843*9e564957SAndroid Build Coastguard Worker [CUSE_INIT] = { cuse_lowlevel_init, "CUSE_INIT" },
2844*9e564957SAndroid Build Coastguard Worker };
2845*9e564957SAndroid Build Coastguard Worker
2846*9e564957SAndroid Build Coastguard Worker static struct {
2847*9e564957SAndroid Build Coastguard Worker void (*func)( fuse_req_t, fuse_ino_t, const void *);
2848*9e564957SAndroid Build Coastguard Worker const char *name;
2849*9e564957SAndroid Build Coastguard Worker } fuse_ll_prefilter_ops[] = {};
2850*9e564957SAndroid Build Coastguard Worker
2851*9e564957SAndroid Build Coastguard Worker static struct {
2852*9e564957SAndroid Build Coastguard Worker void (*func)( fuse_req_t, fuse_ino_t, uint32_t, const void *, size_t size);
2853*9e564957SAndroid Build Coastguard Worker } fuse_ll_postfilter_ops[] = {
2854*9e564957SAndroid Build Coastguard Worker [FUSE_LOOKUP] = {do_lookup_postfilter},
2855*9e564957SAndroid Build Coastguard Worker [FUSE_READDIR] = {do_readdir_postfilter},
2856*9e564957SAndroid Build Coastguard Worker };
2857*9e564957SAndroid Build Coastguard Worker
2858*9e564957SAndroid Build Coastguard Worker #define FUSE_MAXOP (sizeof(fuse_ll_ops) / sizeof(fuse_ll_ops[0]))
2859*9e564957SAndroid Build Coastguard Worker
2860*9e564957SAndroid Build Coastguard Worker static const char *opname(enum fuse_opcode opcode)
2861*9e564957SAndroid Build Coastguard Worker {
2862*9e564957SAndroid Build Coastguard Worker if (opcode >= FUSE_MAXOP || !fuse_ll_ops[opcode].name)
2863*9e564957SAndroid Build Coastguard Worker return "???";
2864*9e564957SAndroid Build Coastguard Worker else
2865*9e564957SAndroid Build Coastguard Worker return fuse_ll_ops[opcode].name;
2866*9e564957SAndroid Build Coastguard Worker }
2867*9e564957SAndroid Build Coastguard Worker
2868*9e564957SAndroid Build Coastguard Worker static const char *opfiltername(int filter)
2869*9e564957SAndroid Build Coastguard Worker {
2870*9e564957SAndroid Build Coastguard Worker switch (filter) {
2871*9e564957SAndroid Build Coastguard Worker case 0:
2872*9e564957SAndroid Build Coastguard Worker return "NONE";
2873*9e564957SAndroid Build Coastguard Worker case FUSE_PREFILTER:
2874*9e564957SAndroid Build Coastguard Worker return "FUSE_PREFILTER";
2875*9e564957SAndroid Build Coastguard Worker case FUSE_POSTFILTER:
2876*9e564957SAndroid Build Coastguard Worker return "FUSE_POSTFILTER";
2877*9e564957SAndroid Build Coastguard Worker case FUSE_PREFILTER | FUSE_POSTFILTER:
2878*9e564957SAndroid Build Coastguard Worker return "FUSE_PREFILTER | FUSE_POSTFILTER";
2879*9e564957SAndroid Build Coastguard Worker default:
2880*9e564957SAndroid Build Coastguard Worker return "???";
2881*9e564957SAndroid Build Coastguard Worker }
2882*9e564957SAndroid Build Coastguard Worker }
2883*9e564957SAndroid Build Coastguard Worker
2884*9e564957SAndroid Build Coastguard Worker static int fuse_ll_copy_from_pipe(struct fuse_bufvec *dst,
2885*9e564957SAndroid Build Coastguard Worker struct fuse_bufvec *src)
2886*9e564957SAndroid Build Coastguard Worker {
2887*9e564957SAndroid Build Coastguard Worker ssize_t res = fuse_buf_copy(dst, src, 0);
2888*9e564957SAndroid Build Coastguard Worker if (res < 0) {
2889*9e564957SAndroid Build Coastguard Worker fuse_log(FUSE_LOG_ERR, "fuse: copy from pipe: %s\n", strerror(-res));
2890*9e564957SAndroid Build Coastguard Worker return res;
2891*9e564957SAndroid Build Coastguard Worker }
2892*9e564957SAndroid Build Coastguard Worker if ((size_t)res < fuse_buf_size(dst)) {
2893*9e564957SAndroid Build Coastguard Worker fuse_log(FUSE_LOG_ERR, "fuse: copy from pipe: short read\n");
2894*9e564957SAndroid Build Coastguard Worker return -1;
2895*9e564957SAndroid Build Coastguard Worker }
2896*9e564957SAndroid Build Coastguard Worker return 0;
2897*9e564957SAndroid Build Coastguard Worker }
2898*9e564957SAndroid Build Coastguard Worker
2899*9e564957SAndroid Build Coastguard Worker void fuse_session_process_buf(struct fuse_session *se,
2900*9e564957SAndroid Build Coastguard Worker const struct fuse_buf *buf)
2901*9e564957SAndroid Build Coastguard Worker {
2902*9e564957SAndroid Build Coastguard Worker fuse_session_process_buf_int(se, buf, NULL);
2903*9e564957SAndroid Build Coastguard Worker }
2904*9e564957SAndroid Build Coastguard Worker
2905*9e564957SAndroid Build Coastguard Worker void fuse_session_process_buf_int(struct fuse_session *se,
2906*9e564957SAndroid Build Coastguard Worker const struct fuse_buf *buf, struct fuse_chan *ch)
2907*9e564957SAndroid Build Coastguard Worker {
2908*9e564957SAndroid Build Coastguard Worker const size_t write_header_size = sizeof(struct fuse_in_header) +
2909*9e564957SAndroid Build Coastguard Worker sizeof(struct fuse_write_in);
2910*9e564957SAndroid Build Coastguard Worker struct fuse_bufvec bufv = { .buf[0] = *buf, .count = 1 };
2911*9e564957SAndroid Build Coastguard Worker struct fuse_bufvec tmpbuf = FUSE_BUFVEC_INIT(write_header_size);
2912*9e564957SAndroid Build Coastguard Worker struct fuse_in_header *in;
2913*9e564957SAndroid Build Coastguard Worker const void *inarg;
2914*9e564957SAndroid Build Coastguard Worker struct fuse_req *req;
2915*9e564957SAndroid Build Coastguard Worker void *mbuf = NULL;
2916*9e564957SAndroid Build Coastguard Worker int err;
2917*9e564957SAndroid Build Coastguard Worker int res;
2918*9e564957SAndroid Build Coastguard Worker int opcode_filter;
2919*9e564957SAndroid Build Coastguard Worker
2920*9e564957SAndroid Build Coastguard Worker if (buf->flags & FUSE_BUF_IS_FD) {
2921*9e564957SAndroid Build Coastguard Worker if (buf->size < tmpbuf.buf[0].size)
2922*9e564957SAndroid Build Coastguard Worker tmpbuf.buf[0].size = buf->size;
2923*9e564957SAndroid Build Coastguard Worker
2924*9e564957SAndroid Build Coastguard Worker mbuf = malloc(tmpbuf.buf[0].size);
2925*9e564957SAndroid Build Coastguard Worker if (mbuf == NULL) {
2926*9e564957SAndroid Build Coastguard Worker fuse_log(FUSE_LOG_ERR, "fuse: failed to allocate header\n");
2927*9e564957SAndroid Build Coastguard Worker goto clear_pipe;
2928*9e564957SAndroid Build Coastguard Worker }
2929*9e564957SAndroid Build Coastguard Worker tmpbuf.buf[0].mem = mbuf;
2930*9e564957SAndroid Build Coastguard Worker
2931*9e564957SAndroid Build Coastguard Worker res = fuse_ll_copy_from_pipe(&tmpbuf, &bufv);
2932*9e564957SAndroid Build Coastguard Worker if (res < 0)
2933*9e564957SAndroid Build Coastguard Worker goto clear_pipe;
2934*9e564957SAndroid Build Coastguard Worker
2935*9e564957SAndroid Build Coastguard Worker in = mbuf;
2936*9e564957SAndroid Build Coastguard Worker } else {
2937*9e564957SAndroid Build Coastguard Worker in = buf->mem;
2938*9e564957SAndroid Build Coastguard Worker }
2939*9e564957SAndroid Build Coastguard Worker
2940*9e564957SAndroid Build Coastguard Worker /* Cleanup opcode most significant bits used by FUSE BPF */
2941*9e564957SAndroid Build Coastguard Worker opcode_filter = in->opcode & ~FUSE_OPCODE_FILTER;
2942*9e564957SAndroid Build Coastguard Worker in->opcode &= FUSE_OPCODE_FILTER;
2943*9e564957SAndroid Build Coastguard Worker
2944*9e564957SAndroid Build Coastguard Worker if (se->debug) {
2945*9e564957SAndroid Build Coastguard Worker fuse_log(FUSE_LOG_DEBUG,
2946*9e564957SAndroid Build Coastguard Worker "unique: %llu, opcode: %s (%i), opcode filter: %s (%i), nodeid: %llu, insize: %zu, pid: %u\n",
2947*9e564957SAndroid Build Coastguard Worker (unsigned long long) in->unique,
2948*9e564957SAndroid Build Coastguard Worker opname((enum fuse_opcode) in->opcode), in->opcode,
2949*9e564957SAndroid Build Coastguard Worker opfiltername((enum fuse_opcode) opcode_filter), opcode_filter,
2950*9e564957SAndroid Build Coastguard Worker (unsigned long long) in->nodeid, buf->size, in->pid);
2951*9e564957SAndroid Build Coastguard Worker }
2952*9e564957SAndroid Build Coastguard Worker
2953*9e564957SAndroid Build Coastguard Worker req = fuse_ll_alloc_req(se);
2954*9e564957SAndroid Build Coastguard Worker if (req == NULL) {
2955*9e564957SAndroid Build Coastguard Worker struct fuse_out_header out = {
2956*9e564957SAndroid Build Coastguard Worker .unique = in->unique,
2957*9e564957SAndroid Build Coastguard Worker .error = -ENOMEM,
2958*9e564957SAndroid Build Coastguard Worker };
2959*9e564957SAndroid Build Coastguard Worker struct iovec iov = {
2960*9e564957SAndroid Build Coastguard Worker .iov_base = &out,
2961*9e564957SAndroid Build Coastguard Worker .iov_len = sizeof(struct fuse_out_header),
2962*9e564957SAndroid Build Coastguard Worker };
2963*9e564957SAndroid Build Coastguard Worker
2964*9e564957SAndroid Build Coastguard Worker fuse_send_msg(se, ch, &iov, 1);
2965*9e564957SAndroid Build Coastguard Worker goto clear_pipe;
2966*9e564957SAndroid Build Coastguard Worker }
2967*9e564957SAndroid Build Coastguard Worker
2968*9e564957SAndroid Build Coastguard Worker req->unique = in->unique;
2969*9e564957SAndroid Build Coastguard Worker req->ctx.uid = in->uid;
2970*9e564957SAndroid Build Coastguard Worker req->ctx.gid = in->gid;
2971*9e564957SAndroid Build Coastguard Worker req->ctx.pid = in->pid;
2972*9e564957SAndroid Build Coastguard Worker req->ch = ch ? fuse_chan_get(ch) : NULL;
2973*9e564957SAndroid Build Coastguard Worker
2974*9e564957SAndroid Build Coastguard Worker err = EIO;
2975*9e564957SAndroid Build Coastguard Worker if (!se->got_init) {
2976*9e564957SAndroid Build Coastguard Worker enum fuse_opcode expected;
2977*9e564957SAndroid Build Coastguard Worker
2978*9e564957SAndroid Build Coastguard Worker expected = se->cuse_data ? CUSE_INIT : FUSE_INIT;
2979*9e564957SAndroid Build Coastguard Worker if (in->opcode != expected)
2980*9e564957SAndroid Build Coastguard Worker goto reply_err;
2981*9e564957SAndroid Build Coastguard Worker } else if (in->opcode == FUSE_INIT || in->opcode == CUSE_INIT)
2982*9e564957SAndroid Build Coastguard Worker goto reply_err;
2983*9e564957SAndroid Build Coastguard Worker
2984*9e564957SAndroid Build Coastguard Worker err = EACCES;
2985*9e564957SAndroid Build Coastguard Worker /* Implement -o allow_root */
2986*9e564957SAndroid Build Coastguard Worker if (se->deny_others && in->uid != se->owner && in->uid != 0 &&
2987*9e564957SAndroid Build Coastguard Worker in->opcode != FUSE_INIT && in->opcode != FUSE_READ &&
2988*9e564957SAndroid Build Coastguard Worker in->opcode != FUSE_WRITE && in->opcode != FUSE_FSYNC &&
2989*9e564957SAndroid Build Coastguard Worker in->opcode != FUSE_RELEASE && in->opcode != FUSE_READDIR &&
2990*9e564957SAndroid Build Coastguard Worker in->opcode != FUSE_FSYNCDIR && in->opcode != FUSE_RELEASEDIR &&
2991*9e564957SAndroid Build Coastguard Worker in->opcode != FUSE_NOTIFY_REPLY &&
2992*9e564957SAndroid Build Coastguard Worker in->opcode != FUSE_READDIRPLUS)
2993*9e564957SAndroid Build Coastguard Worker goto reply_err;
2994*9e564957SAndroid Build Coastguard Worker
2995*9e564957SAndroid Build Coastguard Worker err = ENOSYS;
2996*9e564957SAndroid Build Coastguard Worker if (in->opcode >= FUSE_MAXOP || !fuse_ll_ops[in->opcode].func)
2997*9e564957SAndroid Build Coastguard Worker goto reply_err;
2998*9e564957SAndroid Build Coastguard Worker if (in->opcode != FUSE_INTERRUPT) {
2999*9e564957SAndroid Build Coastguard Worker struct fuse_req *intr;
3000*9e564957SAndroid Build Coastguard Worker pthread_mutex_lock(&se->lock);
3001*9e564957SAndroid Build Coastguard Worker intr = check_interrupt(se, req);
3002*9e564957SAndroid Build Coastguard Worker list_add_req(req, &se->list);
3003*9e564957SAndroid Build Coastguard Worker pthread_mutex_unlock(&se->lock);
3004*9e564957SAndroid Build Coastguard Worker if (intr)
3005*9e564957SAndroid Build Coastguard Worker fuse_reply_err(intr, EAGAIN);
3006*9e564957SAndroid Build Coastguard Worker }
3007*9e564957SAndroid Build Coastguard Worker
3008*9e564957SAndroid Build Coastguard Worker if ((buf->flags & FUSE_BUF_IS_FD) && write_header_size < buf->size &&
3009*9e564957SAndroid Build Coastguard Worker (in->opcode != FUSE_WRITE || !se->op.write_buf) &&
3010*9e564957SAndroid Build Coastguard Worker in->opcode != FUSE_NOTIFY_REPLY) {
3011*9e564957SAndroid Build Coastguard Worker void *newmbuf;
3012*9e564957SAndroid Build Coastguard Worker
3013*9e564957SAndroid Build Coastguard Worker err = ENOMEM;
3014*9e564957SAndroid Build Coastguard Worker newmbuf = realloc(mbuf, buf->size);
3015*9e564957SAndroid Build Coastguard Worker if (newmbuf == NULL)
3016*9e564957SAndroid Build Coastguard Worker goto reply_err;
3017*9e564957SAndroid Build Coastguard Worker mbuf = newmbuf;
3018*9e564957SAndroid Build Coastguard Worker
3019*9e564957SAndroid Build Coastguard Worker tmpbuf = FUSE_BUFVEC_INIT(buf->size - write_header_size);
3020*9e564957SAndroid Build Coastguard Worker tmpbuf.buf[0].mem = (char *)mbuf + write_header_size;
3021*9e564957SAndroid Build Coastguard Worker
3022*9e564957SAndroid Build Coastguard Worker res = fuse_ll_copy_from_pipe(&tmpbuf, &bufv);
3023*9e564957SAndroid Build Coastguard Worker err = -res;
3024*9e564957SAndroid Build Coastguard Worker if (res < 0)
3025*9e564957SAndroid Build Coastguard Worker goto reply_err;
3026*9e564957SAndroid Build Coastguard Worker
3027*9e564957SAndroid Build Coastguard Worker in = mbuf;
3028*9e564957SAndroid Build Coastguard Worker }
3029*9e564957SAndroid Build Coastguard Worker
3030*9e564957SAndroid Build Coastguard Worker inarg = (void *) &in[1];
3031*9e564957SAndroid Build Coastguard Worker if (in->opcode == FUSE_WRITE && se->op.write_buf)
3032*9e564957SAndroid Build Coastguard Worker do_write_buf(req, in->nodeid, inarg, buf);
3033*9e564957SAndroid Build Coastguard Worker else if (in->opcode == FUSE_NOTIFY_REPLY)
3034*9e564957SAndroid Build Coastguard Worker do_notify_reply(req, in->nodeid, inarg, buf);
3035*9e564957SAndroid Build Coastguard Worker else if (!opcode_filter)
3036*9e564957SAndroid Build Coastguard Worker fuse_ll_ops[in->opcode].func(req, in->nodeid, inarg);
3037*9e564957SAndroid Build Coastguard Worker else if (opcode_filter == FUSE_PREFILTER && fuse_ll_prefilter_ops[in->opcode].func)
3038*9e564957SAndroid Build Coastguard Worker fuse_ll_prefilter_ops[in->opcode].func(req, in->nodeid, inarg);
3039*9e564957SAndroid Build Coastguard Worker else if (opcode_filter == FUSE_POSTFILTER
3040*9e564957SAndroid Build Coastguard Worker && fuse_ll_postfilter_ops[in->opcode].func)
3041*9e564957SAndroid Build Coastguard Worker fuse_ll_postfilter_ops[in->opcode].func(
3042*9e564957SAndroid Build Coastguard Worker req, in->nodeid, in->error_in, inarg,
3043*9e564957SAndroid Build Coastguard Worker buf->size - sizeof(struct fuse_in_header));
3044*9e564957SAndroid Build Coastguard Worker else {
3045*9e564957SAndroid Build Coastguard Worker fuse_log(FUSE_LOG_ERR, "Bad opcode");
3046*9e564957SAndroid Build Coastguard Worker err = ENOSYS;
3047*9e564957SAndroid Build Coastguard Worker goto reply_err;
3048*9e564957SAndroid Build Coastguard Worker }
3049*9e564957SAndroid Build Coastguard Worker
3050*9e564957SAndroid Build Coastguard Worker out_free:
3051*9e564957SAndroid Build Coastguard Worker free(mbuf);
3052*9e564957SAndroid Build Coastguard Worker return;
3053*9e564957SAndroid Build Coastguard Worker
3054*9e564957SAndroid Build Coastguard Worker reply_err:
3055*9e564957SAndroid Build Coastguard Worker fuse_reply_err(req, err);
3056*9e564957SAndroid Build Coastguard Worker clear_pipe:
3057*9e564957SAndroid Build Coastguard Worker if (buf->flags & FUSE_BUF_IS_FD)
3058*9e564957SAndroid Build Coastguard Worker fuse_ll_clear_pipe(se);
3059*9e564957SAndroid Build Coastguard Worker goto out_free;
3060*9e564957SAndroid Build Coastguard Worker }
3061*9e564957SAndroid Build Coastguard Worker
3062*9e564957SAndroid Build Coastguard Worker #define LL_OPTION(n,o,v) \
3063*9e564957SAndroid Build Coastguard Worker { n, offsetof(struct fuse_session, o), v }
3064*9e564957SAndroid Build Coastguard Worker
3065*9e564957SAndroid Build Coastguard Worker static const struct fuse_opt fuse_ll_opts[] = {
3066*9e564957SAndroid Build Coastguard Worker LL_OPTION("debug", debug, 1),
3067*9e564957SAndroid Build Coastguard Worker LL_OPTION("-d", debug, 1),
3068*9e564957SAndroid Build Coastguard Worker LL_OPTION("--debug", debug, 1),
3069*9e564957SAndroid Build Coastguard Worker LL_OPTION("allow_root", deny_others, 1),
3070*9e564957SAndroid Build Coastguard Worker FUSE_OPT_END
3071*9e564957SAndroid Build Coastguard Worker };
3072*9e564957SAndroid Build Coastguard Worker
3073*9e564957SAndroid Build Coastguard Worker void fuse_lowlevel_version(void)
3074*9e564957SAndroid Build Coastguard Worker {
3075*9e564957SAndroid Build Coastguard Worker printf("using FUSE kernel interface version %i.%i\n",
3076*9e564957SAndroid Build Coastguard Worker FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
3077*9e564957SAndroid Build Coastguard Worker fuse_mount_version();
3078*9e564957SAndroid Build Coastguard Worker }
3079*9e564957SAndroid Build Coastguard Worker
3080*9e564957SAndroid Build Coastguard Worker void fuse_lowlevel_help(void)
3081*9e564957SAndroid Build Coastguard Worker {
3082*9e564957SAndroid Build Coastguard Worker /* These are not all options, but the ones that are
3083*9e564957SAndroid Build Coastguard Worker potentially of interest to an end-user */
3084*9e564957SAndroid Build Coastguard Worker printf(
3085*9e564957SAndroid Build Coastguard Worker " -o allow_other allow access by all users\n"
3086*9e564957SAndroid Build Coastguard Worker " -o allow_root allow access by root\n"
3087*9e564957SAndroid Build Coastguard Worker " -o auto_unmount auto unmount on process termination\n");
3088*9e564957SAndroid Build Coastguard Worker }
3089*9e564957SAndroid Build Coastguard Worker
3090*9e564957SAndroid Build Coastguard Worker void fuse_session_destroy(struct fuse_session *se)
3091*9e564957SAndroid Build Coastguard Worker {
3092*9e564957SAndroid Build Coastguard Worker struct fuse_ll_pipe *llp;
3093*9e564957SAndroid Build Coastguard Worker
3094*9e564957SAndroid Build Coastguard Worker if (se->got_init && !se->got_destroy) {
3095*9e564957SAndroid Build Coastguard Worker if (se->op.destroy)
3096*9e564957SAndroid Build Coastguard Worker se->op.destroy(se->userdata);
3097*9e564957SAndroid Build Coastguard Worker }
3098*9e564957SAndroid Build Coastguard Worker llp = pthread_getspecific(se->pipe_key);
3099*9e564957SAndroid Build Coastguard Worker if (llp != NULL)
3100*9e564957SAndroid Build Coastguard Worker fuse_ll_pipe_free(llp);
3101*9e564957SAndroid Build Coastguard Worker pthread_key_delete(se->pipe_key);
3102*9e564957SAndroid Build Coastguard Worker pthread_mutex_destroy(&se->lock);
3103*9e564957SAndroid Build Coastguard Worker free(se->cuse_data);
3104*9e564957SAndroid Build Coastguard Worker if (se->fd != -1)
3105*9e564957SAndroid Build Coastguard Worker close(se->fd);
3106*9e564957SAndroid Build Coastguard Worker if (se->io != NULL)
3107*9e564957SAndroid Build Coastguard Worker free(se->io);
3108*9e564957SAndroid Build Coastguard Worker destroy_mount_opts(se->mo);
3109*9e564957SAndroid Build Coastguard Worker free(se);
3110*9e564957SAndroid Build Coastguard Worker }
3111*9e564957SAndroid Build Coastguard Worker
3112*9e564957SAndroid Build Coastguard Worker
3113*9e564957SAndroid Build Coastguard Worker static void fuse_ll_pipe_destructor(void *data)
3114*9e564957SAndroid Build Coastguard Worker {
3115*9e564957SAndroid Build Coastguard Worker struct fuse_ll_pipe *llp = data;
3116*9e564957SAndroid Build Coastguard Worker fuse_ll_pipe_free(llp);
3117*9e564957SAndroid Build Coastguard Worker }
3118*9e564957SAndroid Build Coastguard Worker
3119*9e564957SAndroid Build Coastguard Worker int fuse_session_receive_buf(struct fuse_session *se, struct fuse_buf *buf)
3120*9e564957SAndroid Build Coastguard Worker {
3121*9e564957SAndroid Build Coastguard Worker return fuse_session_receive_buf_int(se, buf, NULL);
3122*9e564957SAndroid Build Coastguard Worker }
3123*9e564957SAndroid Build Coastguard Worker
3124*9e564957SAndroid Build Coastguard Worker int fuse_session_receive_buf_int(struct fuse_session *se, struct fuse_buf *buf,
3125*9e564957SAndroid Build Coastguard Worker struct fuse_chan *ch)
3126*9e564957SAndroid Build Coastguard Worker {
3127*9e564957SAndroid Build Coastguard Worker int err;
3128*9e564957SAndroid Build Coastguard Worker ssize_t res;
3129*9e564957SAndroid Build Coastguard Worker #ifdef HAVE_SPLICE
3130*9e564957SAndroid Build Coastguard Worker size_t bufsize = se->bufsize;
3131*9e564957SAndroid Build Coastguard Worker struct fuse_ll_pipe *llp;
3132*9e564957SAndroid Build Coastguard Worker struct fuse_buf tmpbuf;
3133*9e564957SAndroid Build Coastguard Worker
3134*9e564957SAndroid Build Coastguard Worker if (se->conn.proto_minor < 14 || !(se->conn.want & FUSE_CAP_SPLICE_READ))
3135*9e564957SAndroid Build Coastguard Worker goto fallback;
3136*9e564957SAndroid Build Coastguard Worker
3137*9e564957SAndroid Build Coastguard Worker llp = fuse_ll_get_pipe(se);
3138*9e564957SAndroid Build Coastguard Worker if (llp == NULL)
3139*9e564957SAndroid Build Coastguard Worker goto fallback;
3140*9e564957SAndroid Build Coastguard Worker
3141*9e564957SAndroid Build Coastguard Worker if (llp->size < bufsize) {
3142*9e564957SAndroid Build Coastguard Worker if (llp->can_grow) {
3143*9e564957SAndroid Build Coastguard Worker res = fcntl(llp->pipe[0], F_SETPIPE_SZ, bufsize);
3144*9e564957SAndroid Build Coastguard Worker if (res == -1) {
3145*9e564957SAndroid Build Coastguard Worker llp->can_grow = 0;
3146*9e564957SAndroid Build Coastguard Worker res = grow_pipe_to_max(llp->pipe[0]);
3147*9e564957SAndroid Build Coastguard Worker if (res > 0)
3148*9e564957SAndroid Build Coastguard Worker llp->size = res;
3149*9e564957SAndroid Build Coastguard Worker goto fallback;
3150*9e564957SAndroid Build Coastguard Worker }
3151*9e564957SAndroid Build Coastguard Worker llp->size = res;
3152*9e564957SAndroid Build Coastguard Worker }
3153*9e564957SAndroid Build Coastguard Worker if (llp->size < bufsize)
3154*9e564957SAndroid Build Coastguard Worker goto fallback;
3155*9e564957SAndroid Build Coastguard Worker }
3156*9e564957SAndroid Build Coastguard Worker
3157*9e564957SAndroid Build Coastguard Worker if (se->io != NULL && se->io->splice_receive != NULL) {
3158*9e564957SAndroid Build Coastguard Worker res = se->io->splice_receive(ch ? ch->fd : se->fd, NULL,
3159*9e564957SAndroid Build Coastguard Worker llp->pipe[1], NULL, bufsize, 0,
3160*9e564957SAndroid Build Coastguard Worker se->userdata);
3161*9e564957SAndroid Build Coastguard Worker } else {
3162*9e564957SAndroid Build Coastguard Worker res = splice(ch ? ch->fd : se->fd, NULL, llp->pipe[1], NULL,
3163*9e564957SAndroid Build Coastguard Worker bufsize, 0);
3164*9e564957SAndroid Build Coastguard Worker }
3165*9e564957SAndroid Build Coastguard Worker err = errno;
3166*9e564957SAndroid Build Coastguard Worker
3167*9e564957SAndroid Build Coastguard Worker if (fuse_session_exited(se))
3168*9e564957SAndroid Build Coastguard Worker return 0;
3169*9e564957SAndroid Build Coastguard Worker
3170*9e564957SAndroid Build Coastguard Worker if (res == -1) {
3171*9e564957SAndroid Build Coastguard Worker if (err == ENODEV) {
3172*9e564957SAndroid Build Coastguard Worker /* Filesystem was unmounted, or connection was aborted
3173*9e564957SAndroid Build Coastguard Worker via /sys/fs/fuse/connections */
3174*9e564957SAndroid Build Coastguard Worker fuse_session_exit(se);
3175*9e564957SAndroid Build Coastguard Worker return 0;
3176*9e564957SAndroid Build Coastguard Worker }
3177*9e564957SAndroid Build Coastguard Worker if (err != EINTR && err != EAGAIN)
3178*9e564957SAndroid Build Coastguard Worker perror("fuse: splice from device");
3179*9e564957SAndroid Build Coastguard Worker return -err;
3180*9e564957SAndroid Build Coastguard Worker }
3181*9e564957SAndroid Build Coastguard Worker
3182*9e564957SAndroid Build Coastguard Worker if (res < sizeof(struct fuse_in_header)) {
3183*9e564957SAndroid Build Coastguard Worker fuse_log(FUSE_LOG_ERR, "short splice from fuse device\n");
3184*9e564957SAndroid Build Coastguard Worker return -EIO;
3185*9e564957SAndroid Build Coastguard Worker }
3186*9e564957SAndroid Build Coastguard Worker
3187*9e564957SAndroid Build Coastguard Worker tmpbuf = (struct fuse_buf) {
3188*9e564957SAndroid Build Coastguard Worker .size = res,
3189*9e564957SAndroid Build Coastguard Worker .flags = FUSE_BUF_IS_FD,
3190*9e564957SAndroid Build Coastguard Worker .fd = llp->pipe[0],
3191*9e564957SAndroid Build Coastguard Worker };
3192*9e564957SAndroid Build Coastguard Worker
3193*9e564957SAndroid Build Coastguard Worker /*
3194*9e564957SAndroid Build Coastguard Worker * Don't bother with zero copy for small requests.
3195*9e564957SAndroid Build Coastguard Worker * fuse_loop_mt() needs to check for FORGET so this more than
3196*9e564957SAndroid Build Coastguard Worker * just an optimization.
3197*9e564957SAndroid Build Coastguard Worker */
3198*9e564957SAndroid Build Coastguard Worker if (res < sizeof(struct fuse_in_header) +
3199*9e564957SAndroid Build Coastguard Worker sizeof(struct fuse_write_in) + pagesize) {
3200*9e564957SAndroid Build Coastguard Worker struct fuse_bufvec src = { .buf[0] = tmpbuf, .count = 1 };
3201*9e564957SAndroid Build Coastguard Worker struct fuse_bufvec dst = { .count = 1 };
3202*9e564957SAndroid Build Coastguard Worker
3203*9e564957SAndroid Build Coastguard Worker if (!buf->mem) {
3204*9e564957SAndroid Build Coastguard Worker buf->mem = malloc(se->bufsize);
3205*9e564957SAndroid Build Coastguard Worker if (!buf->mem) {
3206*9e564957SAndroid Build Coastguard Worker fuse_log(FUSE_LOG_ERR,
3207*9e564957SAndroid Build Coastguard Worker "fuse: failed to allocate read buffer\n");
3208*9e564957SAndroid Build Coastguard Worker return -ENOMEM;
3209*9e564957SAndroid Build Coastguard Worker }
3210*9e564957SAndroid Build Coastguard Worker }
3211*9e564957SAndroid Build Coastguard Worker buf->size = se->bufsize;
3212*9e564957SAndroid Build Coastguard Worker buf->flags = 0;
3213*9e564957SAndroid Build Coastguard Worker dst.buf[0] = *buf;
3214*9e564957SAndroid Build Coastguard Worker
3215*9e564957SAndroid Build Coastguard Worker res = fuse_buf_copy(&dst, &src, 0);
3216*9e564957SAndroid Build Coastguard Worker if (res < 0) {
3217*9e564957SAndroid Build Coastguard Worker fuse_log(FUSE_LOG_ERR, "fuse: copy from pipe: %s\n",
3218*9e564957SAndroid Build Coastguard Worker strerror(-res));
3219*9e564957SAndroid Build Coastguard Worker fuse_ll_clear_pipe(se);
3220*9e564957SAndroid Build Coastguard Worker return res;
3221*9e564957SAndroid Build Coastguard Worker }
3222*9e564957SAndroid Build Coastguard Worker if (res < tmpbuf.size) {
3223*9e564957SAndroid Build Coastguard Worker fuse_log(FUSE_LOG_ERR, "fuse: copy from pipe: short read\n");
3224*9e564957SAndroid Build Coastguard Worker fuse_ll_clear_pipe(se);
3225*9e564957SAndroid Build Coastguard Worker return -EIO;
3226*9e564957SAndroid Build Coastguard Worker }
3227*9e564957SAndroid Build Coastguard Worker assert(res == tmpbuf.size);
3228*9e564957SAndroid Build Coastguard Worker
3229*9e564957SAndroid Build Coastguard Worker } else {
3230*9e564957SAndroid Build Coastguard Worker /* Don't overwrite buf->mem, as that would cause a leak */
3231*9e564957SAndroid Build Coastguard Worker buf->fd = tmpbuf.fd;
3232*9e564957SAndroid Build Coastguard Worker buf->flags = tmpbuf.flags;
3233*9e564957SAndroid Build Coastguard Worker }
3234*9e564957SAndroid Build Coastguard Worker buf->size = tmpbuf.size;
3235*9e564957SAndroid Build Coastguard Worker
3236*9e564957SAndroid Build Coastguard Worker return res;
3237*9e564957SAndroid Build Coastguard Worker
3238*9e564957SAndroid Build Coastguard Worker fallback:
3239*9e564957SAndroid Build Coastguard Worker #endif
3240*9e564957SAndroid Build Coastguard Worker if (!buf->mem) {
3241*9e564957SAndroid Build Coastguard Worker buf->mem = malloc(se->bufsize);
3242*9e564957SAndroid Build Coastguard Worker if (!buf->mem) {
3243*9e564957SAndroid Build Coastguard Worker fuse_log(FUSE_LOG_ERR,
3244*9e564957SAndroid Build Coastguard Worker "fuse: failed to allocate read buffer\n");
3245*9e564957SAndroid Build Coastguard Worker return -ENOMEM;
3246*9e564957SAndroid Build Coastguard Worker }
3247*9e564957SAndroid Build Coastguard Worker }
3248*9e564957SAndroid Build Coastguard Worker
3249*9e564957SAndroid Build Coastguard Worker restart:
3250*9e564957SAndroid Build Coastguard Worker if (se->io != NULL) {
3251*9e564957SAndroid Build Coastguard Worker /* se->io->read is never NULL if se->io is not NULL as
3252*9e564957SAndroid Build Coastguard Worker specified by fuse_session_custom_io()*/
3253*9e564957SAndroid Build Coastguard Worker res = se->io->read(ch ? ch->fd : se->fd, buf->mem, se->bufsize,
3254*9e564957SAndroid Build Coastguard Worker se->userdata);
3255*9e564957SAndroid Build Coastguard Worker } else {
3256*9e564957SAndroid Build Coastguard Worker res = read(ch ? ch->fd : se->fd, buf->mem, se->bufsize);
3257*9e564957SAndroid Build Coastguard Worker }
3258*9e564957SAndroid Build Coastguard Worker err = errno;
3259*9e564957SAndroid Build Coastguard Worker
3260*9e564957SAndroid Build Coastguard Worker if (fuse_session_exited(se))
3261*9e564957SAndroid Build Coastguard Worker return 0;
3262*9e564957SAndroid Build Coastguard Worker if (res == -1) {
3263*9e564957SAndroid Build Coastguard Worker /* ENOENT means the operation was interrupted, it's safe
3264*9e564957SAndroid Build Coastguard Worker to restart */
3265*9e564957SAndroid Build Coastguard Worker if (err == ENOENT)
3266*9e564957SAndroid Build Coastguard Worker goto restart;
3267*9e564957SAndroid Build Coastguard Worker
3268*9e564957SAndroid Build Coastguard Worker if (err == ENODEV) {
3269*9e564957SAndroid Build Coastguard Worker /* Filesystem was unmounted, or connection was aborted
3270*9e564957SAndroid Build Coastguard Worker via /sys/fs/fuse/connections */
3271*9e564957SAndroid Build Coastguard Worker fuse_session_exit(se);
3272*9e564957SAndroid Build Coastguard Worker return 0;
3273*9e564957SAndroid Build Coastguard Worker }
3274*9e564957SAndroid Build Coastguard Worker /* Errors occurring during normal operation: EINTR (read
3275*9e564957SAndroid Build Coastguard Worker interrupted), EAGAIN (nonblocking I/O), ENODEV (filesystem
3276*9e564957SAndroid Build Coastguard Worker umounted) */
3277*9e564957SAndroid Build Coastguard Worker if (err != EINTR && err != EAGAIN)
3278*9e564957SAndroid Build Coastguard Worker perror("fuse: reading device");
3279*9e564957SAndroid Build Coastguard Worker return -err;
3280*9e564957SAndroid Build Coastguard Worker }
3281*9e564957SAndroid Build Coastguard Worker if ((size_t) res < sizeof(struct fuse_in_header)) {
3282*9e564957SAndroid Build Coastguard Worker fuse_log(FUSE_LOG_ERR, "short read on fuse device\n");
3283*9e564957SAndroid Build Coastguard Worker return -EIO;
3284*9e564957SAndroid Build Coastguard Worker }
3285*9e564957SAndroid Build Coastguard Worker
3286*9e564957SAndroid Build Coastguard Worker buf->size = res;
3287*9e564957SAndroid Build Coastguard Worker
3288*9e564957SAndroid Build Coastguard Worker return res;
3289*9e564957SAndroid Build Coastguard Worker }
3290*9e564957SAndroid Build Coastguard Worker
3291*9e564957SAndroid Build Coastguard Worker FUSE_SYMVER("_fuse_session_new_317", "_fuse_session_new@@FUSE_3.17")
3292*9e564957SAndroid Build Coastguard Worker struct fuse_session *_fuse_session_new_317(struct fuse_args *args,
3293*9e564957SAndroid Build Coastguard Worker const struct fuse_lowlevel_ops *op,
3294*9e564957SAndroid Build Coastguard Worker size_t op_size,
3295*9e564957SAndroid Build Coastguard Worker struct libfuse_version *version,
3296*9e564957SAndroid Build Coastguard Worker void *userdata)
3297*9e564957SAndroid Build Coastguard Worker {
3298*9e564957SAndroid Build Coastguard Worker int err;
3299*9e564957SAndroid Build Coastguard Worker struct fuse_session *se;
3300*9e564957SAndroid Build Coastguard Worker struct mount_opts *mo;
3301*9e564957SAndroid Build Coastguard Worker
3302*9e564957SAndroid Build Coastguard Worker if (sizeof(struct fuse_lowlevel_ops) < op_size) {
3303*9e564957SAndroid Build Coastguard Worker fuse_log(FUSE_LOG_ERR, "fuse: warning: library too old, some operations may not work\n");
3304*9e564957SAndroid Build Coastguard Worker op_size = sizeof(struct fuse_lowlevel_ops);
3305*9e564957SAndroid Build Coastguard Worker }
3306*9e564957SAndroid Build Coastguard Worker
3307*9e564957SAndroid Build Coastguard Worker if (args->argc == 0) {
3308*9e564957SAndroid Build Coastguard Worker fuse_log(FUSE_LOG_ERR, "fuse: empty argv passed to fuse_session_new().\n");
3309*9e564957SAndroid Build Coastguard Worker return NULL;
3310*9e564957SAndroid Build Coastguard Worker }
3311*9e564957SAndroid Build Coastguard Worker
3312*9e564957SAndroid Build Coastguard Worker se = (struct fuse_session *) calloc(1, sizeof(struct fuse_session));
3313*9e564957SAndroid Build Coastguard Worker if (se == NULL) {
3314*9e564957SAndroid Build Coastguard Worker fuse_log(FUSE_LOG_ERR, "fuse: failed to allocate fuse object\n");
3315*9e564957SAndroid Build Coastguard Worker goto out1;
3316*9e564957SAndroid Build Coastguard Worker }
3317*9e564957SAndroid Build Coastguard Worker se->fd = -1;
3318*9e564957SAndroid Build Coastguard Worker se->conn.max_write = UINT_MAX;
3319*9e564957SAndroid Build Coastguard Worker se->conn.max_readahead = UINT_MAX;
3320*9e564957SAndroid Build Coastguard Worker
3321*9e564957SAndroid Build Coastguard Worker /* Parse options */
3322*9e564957SAndroid Build Coastguard Worker if(fuse_opt_parse(args, se, fuse_ll_opts, NULL) == -1)
3323*9e564957SAndroid Build Coastguard Worker goto out2;
3324*9e564957SAndroid Build Coastguard Worker if(se->deny_others) {
3325*9e564957SAndroid Build Coastguard Worker /* Allowing access only by root is done by instructing
3326*9e564957SAndroid Build Coastguard Worker * kernel to allow access by everyone, and then restricting
3327*9e564957SAndroid Build Coastguard Worker * access to root and mountpoint owner in libfuse.
3328*9e564957SAndroid Build Coastguard Worker */
3329*9e564957SAndroid Build Coastguard Worker // We may be adding the option a second time, but
3330*9e564957SAndroid Build Coastguard Worker // that doesn't hurt.
3331*9e564957SAndroid Build Coastguard Worker if(fuse_opt_add_arg(args, "-oallow_other") == -1)
3332*9e564957SAndroid Build Coastguard Worker goto out2;
3333*9e564957SAndroid Build Coastguard Worker }
3334*9e564957SAndroid Build Coastguard Worker mo = parse_mount_opts(args);
3335*9e564957SAndroid Build Coastguard Worker if (mo == NULL)
3336*9e564957SAndroid Build Coastguard Worker goto out3;
3337*9e564957SAndroid Build Coastguard Worker
3338*9e564957SAndroid Build Coastguard Worker if(args->argc == 1 &&
3339*9e564957SAndroid Build Coastguard Worker args->argv[0][0] == '-') {
3340*9e564957SAndroid Build Coastguard Worker fuse_log(FUSE_LOG_ERR, "fuse: warning: argv[0] looks like an option, but "
3341*9e564957SAndroid Build Coastguard Worker "will be ignored\n");
3342*9e564957SAndroid Build Coastguard Worker } else if (args->argc != 1) {
3343*9e564957SAndroid Build Coastguard Worker int i;
3344*9e564957SAndroid Build Coastguard Worker fuse_log(FUSE_LOG_ERR, "fuse: unknown option(s): `");
3345*9e564957SAndroid Build Coastguard Worker for(i = 1; i < args->argc-1; i++)
3346*9e564957SAndroid Build Coastguard Worker fuse_log(FUSE_LOG_ERR, "%s ", args->argv[i]);
3347*9e564957SAndroid Build Coastguard Worker fuse_log(FUSE_LOG_ERR, "%s'\n", args->argv[i]);
3348*9e564957SAndroid Build Coastguard Worker goto out4;
3349*9e564957SAndroid Build Coastguard Worker }
3350*9e564957SAndroid Build Coastguard Worker
3351*9e564957SAndroid Build Coastguard Worker if (se->debug)
3352*9e564957SAndroid Build Coastguard Worker fuse_log(FUSE_LOG_DEBUG, "FUSE library version: %s\n", PACKAGE_VERSION);
3353*9e564957SAndroid Build Coastguard Worker
3354*9e564957SAndroid Build Coastguard Worker se->bufsize = FUSE_MAX_MAX_PAGES * getpagesize() +
3355*9e564957SAndroid Build Coastguard Worker FUSE_BUFFER_HEADER_SIZE;
3356*9e564957SAndroid Build Coastguard Worker
3357*9e564957SAndroid Build Coastguard Worker list_init_req(&se->list);
3358*9e564957SAndroid Build Coastguard Worker list_init_req(&se->interrupts);
3359*9e564957SAndroid Build Coastguard Worker list_init_nreq(&se->notify_list);
3360*9e564957SAndroid Build Coastguard Worker se->notify_ctr = 1;
3361*9e564957SAndroid Build Coastguard Worker pthread_mutex_init(&se->lock, NULL);
3362*9e564957SAndroid Build Coastguard Worker
3363*9e564957SAndroid Build Coastguard Worker err = pthread_key_create(&se->pipe_key, fuse_ll_pipe_destructor);
3364*9e564957SAndroid Build Coastguard Worker if (err) {
3365*9e564957SAndroid Build Coastguard Worker fuse_log(FUSE_LOG_ERR, "fuse: failed to create thread specific key: %s\n",
3366*9e564957SAndroid Build Coastguard Worker strerror(err));
3367*9e564957SAndroid Build Coastguard Worker goto out5;
3368*9e564957SAndroid Build Coastguard Worker }
3369*9e564957SAndroid Build Coastguard Worker
3370*9e564957SAndroid Build Coastguard Worker memcpy(&se->op, op, op_size);
3371*9e564957SAndroid Build Coastguard Worker se->owner = getuid();
3372*9e564957SAndroid Build Coastguard Worker se->userdata = userdata;
3373*9e564957SAndroid Build Coastguard Worker
3374*9e564957SAndroid Build Coastguard Worker se->mo = mo;
3375*9e564957SAndroid Build Coastguard Worker
3376*9e564957SAndroid Build Coastguard Worker /* Fuse server application should pass the version it was compiled
3377*9e564957SAndroid Build Coastguard Worker * against and pass it. If a libfuse version accidentally introduces an
3378*9e564957SAndroid Build Coastguard Worker * ABI incompatibility, it might be possible to 'fix' that at run time,
3379*9e564957SAndroid Build Coastguard Worker * by checking the version numbers.
3380*9e564957SAndroid Build Coastguard Worker */
3381*9e564957SAndroid Build Coastguard Worker se->version = *version;
3382*9e564957SAndroid Build Coastguard Worker
3383*9e564957SAndroid Build Coastguard Worker return se;
3384*9e564957SAndroid Build Coastguard Worker
3385*9e564957SAndroid Build Coastguard Worker out5:
3386*9e564957SAndroid Build Coastguard Worker pthread_mutex_destroy(&se->lock);
3387*9e564957SAndroid Build Coastguard Worker out4:
3388*9e564957SAndroid Build Coastguard Worker fuse_opt_free_args(args);
3389*9e564957SAndroid Build Coastguard Worker out3:
3390*9e564957SAndroid Build Coastguard Worker if (mo != NULL)
3391*9e564957SAndroid Build Coastguard Worker destroy_mount_opts(mo);
3392*9e564957SAndroid Build Coastguard Worker out2:
3393*9e564957SAndroid Build Coastguard Worker free(se);
3394*9e564957SAndroid Build Coastguard Worker out1:
3395*9e564957SAndroid Build Coastguard Worker return NULL;
3396*9e564957SAndroid Build Coastguard Worker }
3397*9e564957SAndroid Build Coastguard Worker
3398*9e564957SAndroid Build Coastguard Worker struct fuse_session *fuse_session_new_30(struct fuse_args *args,
3399*9e564957SAndroid Build Coastguard Worker const struct fuse_lowlevel_ops *op,
3400*9e564957SAndroid Build Coastguard Worker size_t op_size,
3401*9e564957SAndroid Build Coastguard Worker void *userdata);
3402*9e564957SAndroid Build Coastguard Worker FUSE_SYMVER("fuse_session_new_30", "fuse_session_new@FUSE_3.0")
3403*9e564957SAndroid Build Coastguard Worker struct fuse_session *fuse_session_new_30(struct fuse_args *args,
3404*9e564957SAndroid Build Coastguard Worker const struct fuse_lowlevel_ops *op,
3405*9e564957SAndroid Build Coastguard Worker size_t op_size,
3406*9e564957SAndroid Build Coastguard Worker void *userdata)
3407*9e564957SAndroid Build Coastguard Worker {
3408*9e564957SAndroid Build Coastguard Worker /* unknown version */
3409*9e564957SAndroid Build Coastguard Worker struct libfuse_version version = { 0 };
3410*9e564957SAndroid Build Coastguard Worker
3411*9e564957SAndroid Build Coastguard Worker return _fuse_session_new_317(args, op, op_size, &version, userdata);
3412*9e564957SAndroid Build Coastguard Worker }
3413*9e564957SAndroid Build Coastguard Worker
3414*9e564957SAndroid Build Coastguard Worker int fuse_session_custom_io(struct fuse_session *se, const struct fuse_custom_io *io,
3415*9e564957SAndroid Build Coastguard Worker int fd)
3416*9e564957SAndroid Build Coastguard Worker {
3417*9e564957SAndroid Build Coastguard Worker if (fd < 0) {
3418*9e564957SAndroid Build Coastguard Worker fuse_log(FUSE_LOG_ERR, "Invalid file descriptor value %d passed to "
3419*9e564957SAndroid Build Coastguard Worker "fuse_session_custom_io()\n", fd);
3420*9e564957SAndroid Build Coastguard Worker return -EBADF;
3421*9e564957SAndroid Build Coastguard Worker }
3422*9e564957SAndroid Build Coastguard Worker if (io == NULL) {
3423*9e564957SAndroid Build Coastguard Worker fuse_log(FUSE_LOG_ERR, "No custom IO passed to "
3424*9e564957SAndroid Build Coastguard Worker "fuse_session_custom_io()\n");
3425*9e564957SAndroid Build Coastguard Worker return -EINVAL;
3426*9e564957SAndroid Build Coastguard Worker } else if (io->read == NULL || io->writev == NULL) {
3427*9e564957SAndroid Build Coastguard Worker /* If the user provides their own file descriptor, we can't
3428*9e564957SAndroid Build Coastguard Worker guarantee that the default behavior of the io operations made
3429*9e564957SAndroid Build Coastguard Worker in libfuse will function properly. Therefore, we enforce the
3430*9e564957SAndroid Build Coastguard Worker user to implement these io operations when using custom io. */
3431*9e564957SAndroid Build Coastguard Worker fuse_log(FUSE_LOG_ERR, "io passed to fuse_session_custom_io() must "
3432*9e564957SAndroid Build Coastguard Worker "implement both io->read() and io->writev\n");
3433*9e564957SAndroid Build Coastguard Worker return -EINVAL;
3434*9e564957SAndroid Build Coastguard Worker }
3435*9e564957SAndroid Build Coastguard Worker
3436*9e564957SAndroid Build Coastguard Worker se->io = malloc(sizeof(struct fuse_custom_io));
3437*9e564957SAndroid Build Coastguard Worker if (se->io == NULL) {
3438*9e564957SAndroid Build Coastguard Worker fuse_log(FUSE_LOG_ERR, "Failed to allocate memory for custom io. "
3439*9e564957SAndroid Build Coastguard Worker "Error: %s\n", strerror(errno));
3440*9e564957SAndroid Build Coastguard Worker return -errno;
3441*9e564957SAndroid Build Coastguard Worker }
3442*9e564957SAndroid Build Coastguard Worker
3443*9e564957SAndroid Build Coastguard Worker se->fd = fd;
3444*9e564957SAndroid Build Coastguard Worker *se->io = *io;
3445*9e564957SAndroid Build Coastguard Worker return 0;
3446*9e564957SAndroid Build Coastguard Worker }
3447*9e564957SAndroid Build Coastguard Worker
3448*9e564957SAndroid Build Coastguard Worker int fuse_session_mount(struct fuse_session *se, const char *mountpoint)
3449*9e564957SAndroid Build Coastguard Worker {
3450*9e564957SAndroid Build Coastguard Worker int fd;
3451*9e564957SAndroid Build Coastguard Worker
3452*9e564957SAndroid Build Coastguard Worker /*
3453*9e564957SAndroid Build Coastguard Worker * Make sure file descriptors 0, 1 and 2 are open, otherwise chaos
3454*9e564957SAndroid Build Coastguard Worker * would ensue.
3455*9e564957SAndroid Build Coastguard Worker */
3456*9e564957SAndroid Build Coastguard Worker do {
3457*9e564957SAndroid Build Coastguard Worker fd = open("/dev/null", O_RDWR);
3458*9e564957SAndroid Build Coastguard Worker if (fd > 2)
3459*9e564957SAndroid Build Coastguard Worker close(fd);
3460*9e564957SAndroid Build Coastguard Worker } while (fd >= 0 && fd <= 2);
3461*9e564957SAndroid Build Coastguard Worker
3462*9e564957SAndroid Build Coastguard Worker /*
3463*9e564957SAndroid Build Coastguard Worker * To allow FUSE daemons to run without privileges, the caller may open
3464*9e564957SAndroid Build Coastguard Worker * /dev/fuse before launching the file system and pass on the file
3465*9e564957SAndroid Build Coastguard Worker * descriptor by specifying /dev/fd/N as the mount point. Note that the
3466*9e564957SAndroid Build Coastguard Worker * parent process takes care of performing the mount in this case.
3467*9e564957SAndroid Build Coastguard Worker */
3468*9e564957SAndroid Build Coastguard Worker fd = fuse_mnt_parse_fuse_fd(mountpoint);
3469*9e564957SAndroid Build Coastguard Worker if (fd != -1) {
3470*9e564957SAndroid Build Coastguard Worker if (fcntl(fd, F_GETFD) == -1) {
3471*9e564957SAndroid Build Coastguard Worker fuse_log(FUSE_LOG_ERR,
3472*9e564957SAndroid Build Coastguard Worker "fuse: Invalid file descriptor /dev/fd/%u\n",
3473*9e564957SAndroid Build Coastguard Worker fd);
3474*9e564957SAndroid Build Coastguard Worker return -1;
3475*9e564957SAndroid Build Coastguard Worker }
3476*9e564957SAndroid Build Coastguard Worker se->fd = fd;
3477*9e564957SAndroid Build Coastguard Worker return 0;
3478*9e564957SAndroid Build Coastguard Worker }
3479*9e564957SAndroid Build Coastguard Worker
3480*9e564957SAndroid Build Coastguard Worker /* Open channel */
3481*9e564957SAndroid Build Coastguard Worker fd = fuse_kern_mount(mountpoint, se->mo);
3482*9e564957SAndroid Build Coastguard Worker if (fd == -1)
3483*9e564957SAndroid Build Coastguard Worker return -1;
3484*9e564957SAndroid Build Coastguard Worker se->fd = fd;
3485*9e564957SAndroid Build Coastguard Worker
3486*9e564957SAndroid Build Coastguard Worker /* Save mountpoint */
3487*9e564957SAndroid Build Coastguard Worker se->mountpoint = strdup(mountpoint);
3488*9e564957SAndroid Build Coastguard Worker if (se->mountpoint == NULL)
3489*9e564957SAndroid Build Coastguard Worker goto error_out;
3490*9e564957SAndroid Build Coastguard Worker
3491*9e564957SAndroid Build Coastguard Worker return 0;
3492*9e564957SAndroid Build Coastguard Worker
3493*9e564957SAndroid Build Coastguard Worker error_out:
3494*9e564957SAndroid Build Coastguard Worker fuse_kern_unmount(mountpoint, fd);
3495*9e564957SAndroid Build Coastguard Worker return -1;
3496*9e564957SAndroid Build Coastguard Worker }
3497*9e564957SAndroid Build Coastguard Worker
3498*9e564957SAndroid Build Coastguard Worker int fuse_session_fd(struct fuse_session *se)
3499*9e564957SAndroid Build Coastguard Worker {
3500*9e564957SAndroid Build Coastguard Worker return se->fd;
3501*9e564957SAndroid Build Coastguard Worker }
3502*9e564957SAndroid Build Coastguard Worker
3503*9e564957SAndroid Build Coastguard Worker void fuse_session_unmount(struct fuse_session *se)
3504*9e564957SAndroid Build Coastguard Worker {
3505*9e564957SAndroid Build Coastguard Worker if (se->mountpoint != NULL) {
3506*9e564957SAndroid Build Coastguard Worker fuse_kern_unmount(se->mountpoint, se->fd);
3507*9e564957SAndroid Build Coastguard Worker se->fd = -1;
3508*9e564957SAndroid Build Coastguard Worker free(se->mountpoint);
3509*9e564957SAndroid Build Coastguard Worker se->mountpoint = NULL;
3510*9e564957SAndroid Build Coastguard Worker }
3511*9e564957SAndroid Build Coastguard Worker }
3512*9e564957SAndroid Build Coastguard Worker
3513*9e564957SAndroid Build Coastguard Worker #ifdef linux
3514*9e564957SAndroid Build Coastguard Worker int fuse_req_getgroups(fuse_req_t req, int size, gid_t list[])
3515*9e564957SAndroid Build Coastguard Worker {
3516*9e564957SAndroid Build Coastguard Worker char *buf;
3517*9e564957SAndroid Build Coastguard Worker size_t bufsize = 1024;
3518*9e564957SAndroid Build Coastguard Worker char path[128];
3519*9e564957SAndroid Build Coastguard Worker int ret;
3520*9e564957SAndroid Build Coastguard Worker int fd;
3521*9e564957SAndroid Build Coastguard Worker unsigned long pid = req->ctx.pid;
3522*9e564957SAndroid Build Coastguard Worker char *s;
3523*9e564957SAndroid Build Coastguard Worker
3524*9e564957SAndroid Build Coastguard Worker sprintf(path, "/proc/%lu/task/%lu/status", pid, pid);
3525*9e564957SAndroid Build Coastguard Worker
3526*9e564957SAndroid Build Coastguard Worker retry:
3527*9e564957SAndroid Build Coastguard Worker buf = malloc(bufsize);
3528*9e564957SAndroid Build Coastguard Worker if (buf == NULL)
3529*9e564957SAndroid Build Coastguard Worker return -ENOMEM;
3530*9e564957SAndroid Build Coastguard Worker
3531*9e564957SAndroid Build Coastguard Worker ret = -EIO;
3532*9e564957SAndroid Build Coastguard Worker fd = open(path, O_RDONLY);
3533*9e564957SAndroid Build Coastguard Worker if (fd == -1)
3534*9e564957SAndroid Build Coastguard Worker goto out_free;
3535*9e564957SAndroid Build Coastguard Worker
3536*9e564957SAndroid Build Coastguard Worker ret = read(fd, buf, bufsize);
3537*9e564957SAndroid Build Coastguard Worker close(fd);
3538*9e564957SAndroid Build Coastguard Worker if (ret < 0) {
3539*9e564957SAndroid Build Coastguard Worker ret = -EIO;
3540*9e564957SAndroid Build Coastguard Worker goto out_free;
3541*9e564957SAndroid Build Coastguard Worker }
3542*9e564957SAndroid Build Coastguard Worker
3543*9e564957SAndroid Build Coastguard Worker if ((size_t)ret == bufsize) {
3544*9e564957SAndroid Build Coastguard Worker free(buf);
3545*9e564957SAndroid Build Coastguard Worker bufsize *= 4;
3546*9e564957SAndroid Build Coastguard Worker goto retry;
3547*9e564957SAndroid Build Coastguard Worker }
3548*9e564957SAndroid Build Coastguard Worker
3549*9e564957SAndroid Build Coastguard Worker ret = -EIO;
3550*9e564957SAndroid Build Coastguard Worker s = strstr(buf, "\nGroups:");
3551*9e564957SAndroid Build Coastguard Worker if (s == NULL)
3552*9e564957SAndroid Build Coastguard Worker goto out_free;
3553*9e564957SAndroid Build Coastguard Worker
3554*9e564957SAndroid Build Coastguard Worker s += 8;
3555*9e564957SAndroid Build Coastguard Worker ret = 0;
3556*9e564957SAndroid Build Coastguard Worker while (1) {
3557*9e564957SAndroid Build Coastguard Worker char *end;
3558*9e564957SAndroid Build Coastguard Worker unsigned long val = strtoul(s, &end, 0);
3559*9e564957SAndroid Build Coastguard Worker if (end == s)
3560*9e564957SAndroid Build Coastguard Worker break;
3561*9e564957SAndroid Build Coastguard Worker
3562*9e564957SAndroid Build Coastguard Worker s = end;
3563*9e564957SAndroid Build Coastguard Worker if (ret < size)
3564*9e564957SAndroid Build Coastguard Worker list[ret] = val;
3565*9e564957SAndroid Build Coastguard Worker ret++;
3566*9e564957SAndroid Build Coastguard Worker }
3567*9e564957SAndroid Build Coastguard Worker
3568*9e564957SAndroid Build Coastguard Worker out_free:
3569*9e564957SAndroid Build Coastguard Worker free(buf);
3570*9e564957SAndroid Build Coastguard Worker return ret;
3571*9e564957SAndroid Build Coastguard Worker }
3572*9e564957SAndroid Build Coastguard Worker #else /* linux */
3573*9e564957SAndroid Build Coastguard Worker /*
3574*9e564957SAndroid Build Coastguard Worker * This is currently not implemented on other than Linux...
3575*9e564957SAndroid Build Coastguard Worker */
3576*9e564957SAndroid Build Coastguard Worker int fuse_req_getgroups(fuse_req_t req, int size, gid_t list[])
3577*9e564957SAndroid Build Coastguard Worker {
3578*9e564957SAndroid Build Coastguard Worker (void) req; (void) size; (void) list;
3579*9e564957SAndroid Build Coastguard Worker return -ENOSYS;
3580*9e564957SAndroid Build Coastguard Worker }
3581*9e564957SAndroid Build Coastguard Worker #endif
3582*9e564957SAndroid Build Coastguard Worker
3583*9e564957SAndroid Build Coastguard Worker /* Prevent spurious data race warning - we don't care
3584*9e564957SAndroid Build Coastguard Worker * about races for this flag */
3585*9e564957SAndroid Build Coastguard Worker __attribute__((no_sanitize_thread))
3586*9e564957SAndroid Build Coastguard Worker void fuse_session_exit(struct fuse_session *se)
3587*9e564957SAndroid Build Coastguard Worker {
3588*9e564957SAndroid Build Coastguard Worker se->exited = 1;
3589*9e564957SAndroid Build Coastguard Worker }
3590*9e564957SAndroid Build Coastguard Worker
3591*9e564957SAndroid Build Coastguard Worker __attribute__((no_sanitize_thread))
3592*9e564957SAndroid Build Coastguard Worker void fuse_session_reset(struct fuse_session *se)
3593*9e564957SAndroid Build Coastguard Worker {
3594*9e564957SAndroid Build Coastguard Worker se->exited = 0;
3595*9e564957SAndroid Build Coastguard Worker se->error = 0;
3596*9e564957SAndroid Build Coastguard Worker }
3597*9e564957SAndroid Build Coastguard Worker
3598*9e564957SAndroid Build Coastguard Worker __attribute__((no_sanitize_thread))
3599*9e564957SAndroid Build Coastguard Worker int fuse_session_exited(struct fuse_session *se)
3600*9e564957SAndroid Build Coastguard Worker {
3601*9e564957SAndroid Build Coastguard Worker return se->exited;
3602*9e564957SAndroid Build Coastguard Worker }
3603